install.sub 87 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142
  1. #!/bin/ksh
  2. # $OpenBSD: install.sub,v 1.995 2017/04/07 22:53:25 rpe Exp $
  3. #
  4. # Copyright (c) 1997-2015 Todd Miller, Theo de Raadt, Ken Westerback
  5. # Copyright (c) 2015, Robert Peichaer <rpe@openbsd.org>
  6. #
  7. # All rights reserved.
  8. #
  9. # Redistribution and use in source and binary forms, with or without
  10. # modification, are permitted provided that the following conditions
  11. # are met:
  12. # 1. Redistributions of source code must retain the above copyright
  13. # notice, this list of conditions and the following disclaimer.
  14. # 2. Redistributions in binary form must reproduce the above copyright
  15. # notice, this list of conditions and the following disclaimer in the
  16. # documentation and/or other materials provided with the distribution.
  17. #
  18. # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  19. # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  20. # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  21. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  23. # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  24. # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  25. # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27. # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. #
  29. # Copyright (c) 1996 The NetBSD Foundation, Inc.
  30. # All rights reserved.
  31. #
  32. # This code is derived from software contributed to The NetBSD Foundation
  33. # by Jason R. Thorpe.
  34. #
  35. # Redistribution and use in source and binary forms, with or without
  36. # modification, are permitted provided that the following conditions
  37. # are met:
  38. # 1. Redistributions of source code must retain the above copyright
  39. # notice, this list of conditions and the following disclaimer.
  40. # 2. Redistributions in binary form must reproduce the above copyright
  41. # notice, this list of conditions and the following disclaimer in the
  42. # documentation and/or other materials provided with the distribution.
  43. #
  44. # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
  45. # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  46. # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  47. # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
  48. # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  49. # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  50. # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  51. # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  52. # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  53. # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  54. # POSSIBILITY OF SUCH DAMAGE.
  55. #
  56. # OpenBSD install/upgrade script common subroutines and initialization code
  57. # ------------------------------------------------------------------------------
  58. # Misc functions
  59. # ------------------------------------------------------------------------------
  60. # Show usage of the installer script and exit.
  61. usage() {
  62. echo "usage: ${0##*/} [-a] [-f filename] [-m install | upgrade]" >&2
  63. exit 1
  64. }
  65. # Wait for the ftp process to finish, or be killed after the timeout and
  66. # extract various informations from the ftplist.cgi output.
  67. wait_cgiinfo() {
  68. local _l _s _key _val
  69. # Wait for the ftp(1) process started in start_cgiinfo() to end and
  70. # ensure, there is actual data to extract info from.
  71. wait "$CGIPID" 2>/dev/null
  72. [[ -s $CGI_INFO ]] || return
  73. # Extract list of mirror servers from the ftplist.cgi output.
  74. sed -En 's,^https?://([[A-Za-z0-9:_][]A-Za-z0-9:._-]*),\1,p' \
  75. $CGI_INFO >$HTTP_LIST 2>/dev/null
  76. # Extract the previously selected mirror server (first entry in the
  77. # ftplist.cgi output, if that has no location info).
  78. read -r -- _s _l <$HTTP_LIST
  79. [[ -z $_l ]] && : ${HTTP_SERVER:=${_s%%/*}}
  80. # Extract the previously used install method, timezone information
  81. # and a reference timestamp.
  82. while IFS='=' read -r -- _key _val; do
  83. case $_key=$_val in
  84. method=+([a-z])*([0-9])) CGI_METHOD=$_val;;
  85. TIME=+([0-9])) CGI_TIME=$_val;;
  86. TZ=+([-_/+[:alnum:]])) CGI_TZ=$_val;;
  87. esac
  88. done <$CGI_INFO
  89. }
  90. # ------------------------------------------------------------------------------
  91. # Utils functions
  92. # ------------------------------------------------------------------------------
  93. # Sort and print unique list of provided arguments.
  94. bsort() {
  95. local _a=$1 _b _l
  96. (($#)) && shift || return
  97. for _b; do
  98. [[ $_a == "$_b" ]] && continue
  99. if [[ $_a > $_b ]]; then
  100. _l="$_a $_l" _a=$_b
  101. else
  102. _l="$_b $_l"
  103. fi
  104. done
  105. # Output the smallest value found.
  106. (($#)) && echo -n "$_a " || echo -n "$_a"
  107. # Sort remaining values.
  108. bsort $_l
  109. }
  110. # Test the first argument against the remaining ones, return success on a match.
  111. isin() {
  112. local _a=$1 _b
  113. shift
  114. for _b; do
  115. [[ $_a == "$_b" ]] && return 0
  116. done
  117. return 1
  118. }
  119. # Add first argument to list formed by the remaining arguments.
  120. # Adds to the tail if the element does not already exist.
  121. addel() {
  122. local _a=$1
  123. shift
  124. isin "$_a" $* && echo -n "$*" || echo -n "${*:+$* }$_a"
  125. }
  126. # Remove all occurrences of first argument from list formed by the remaining
  127. # arguments.
  128. rmel() {
  129. local _a=$1 _b _c
  130. shift
  131. for _b; do
  132. [[ $_a != "$_b" ]] && _c="${_c:+$_c }$_b"
  133. done
  134. echo -n "$_c"
  135. }
  136. # If possible, print the timestamp received from the ftplist.cgi output,
  137. # adjusted with the time elapsed since it was received.
  138. http_time() {
  139. local _sec=$(cat $HTTP_SEC 2>/dev/null)
  140. [[ -n $_sec && -n $CGI_TIME ]] &&
  141. echo $((CGI_TIME + SECONDS - _sec))
  142. }
  143. # Prints the supplied parameters properly escaped for future sh/ksh parsing.
  144. # Quotes are added if needed, so you should not do that yourself.
  145. quote() (
  146. # Since this is a subshell we won't pollute the calling namespace.
  147. for _a; do
  148. alias Q=$_a; _a=$(alias Q); print -rn -- " ${_a#Q=}"
  149. done | sed '1s/ //'
  150. echo
  151. )
  152. # Show a list (passed via ordered arguments) in column output using ls.
  153. show_cols() {
  154. local _l _cdir=/tmp/i/cdir _clist
  155. mkdir -p $_cdir
  156. rm -rf -- $_cdir/*
  157. while read _l; do
  158. [[ -n $_l ]] || continue
  159. mkdir -p /tmp/i/cdir/"$_l"
  160. _clist[${#_clist[*]}]="$_l"
  161. done
  162. (cd $_cdir; ls -Cdf "${_clist[@]}")
  163. rm -rf -- $_cdir
  164. }
  165. # Echo file $1 to stdout. Skip comment lines and delete everything
  166. # after the first '#' from other lines. Strip leading and trailing
  167. # whitespace if IFS is set.
  168. stripcom () {
  169. local _file=$1 _line
  170. [[ -f $_file ]] || return
  171. set -o noglob
  172. while read _line; do
  173. [[ -n ${_line%%#*} ]] && echo $_line
  174. done <$_file
  175. set +o noglob
  176. }
  177. # Create a temporary directory based on the supplied directory name prefix.
  178. tmpdir() {
  179. local _i=1 _dir
  180. until _dir="${1?}.$_i.$RANDOM" && mkdir -- "$_dir" 2>/dev/null; do
  181. ((++_i < 10000)) || return 1
  182. done
  183. echo "$_dir"
  184. }
  185. # Generate unique filename based on the supplied filename $1.
  186. unique_filename() {
  187. local _fn=$1 _ufn
  188. while _ufn=${_fn}.$RANDOM && [[ -e $_ufn ]]; do done
  189. print -- "$_ufn"
  190. }
  191. # Let rc.firsttime feed file $1 using $2 as subject to whatever mail system we
  192. # have at hand by then.
  193. prep_root_mail() {
  194. local _fn=$1 _subject=$2 _ufn
  195. [[ -s $_fn ]] || return
  196. _ufn=$(unique_filename /mnt/var/log/${_fn##*/})
  197. cp $_fn $_ufn
  198. chmod 600 $_ufn
  199. _ufn=${_ufn#/mnt}
  200. cat <<__EOT >>/mnt/etc/rc.firsttime
  201. ( /usr/bin/mail -s '$_subject' root <$_ufn && rm $_ufn ) >/dev/null 2>&1 &
  202. __EOT
  203. }
  204. # Examine the contents of the DHCP lease file $1 for a line containing the
  205. # field provided as parameters and return the value of the first field found.
  206. #
  207. # Note that strings are unescaped but not unvis()'d.
  208. lease_value () {
  209. local _lf=$1 _o
  210. shift
  211. for _o; do
  212. sed -E \
  213. -e '/^ *(option )?'"$_o"' (.*);$/!d;s//\2/' \
  214. -e '/^"(.*)"$/{s//\1/;s/\\(.)/\1/g;};q' "$_lf" \
  215. | grep ^ && return
  216. done
  217. }
  218. # ------------------------------------------------------------------------------
  219. # Device related functions
  220. # ------------------------------------------------------------------------------
  221. # Show device name, info, NAA and size for the provided list of disk devices.
  222. # Create device nodes as needed and cleanup afterwards.
  223. diskinfo() {
  224. local _d _i _n _s
  225. for _d; do
  226. # Extract disk information enclosed in <> from dmesg.
  227. _i=$(dmesg | sed -n '/^'$_d' at /h;${g;s/^.*<\(.*\)>.*$/\1/p;}')
  228. _i=${_i##+([[:space:],])}
  229. _i=${_i%%+([[:space:],])}
  230. # Extract Network Address Authority information from dmesg..
  231. _n=$(dmesg | sed -En '/^'$_d' at /h;${g;s/^.* ([a-z0-9]+\.[a-zA-Z0-9_]+)$/\1/p;}')
  232. # Extract disk size from disklabel output.
  233. make_dev $_d
  234. _s=$(disklabel -dpg $_d 2>/dev/null | sed -n '/.*# total bytes: \(.*\)/{s//(\1)/p;}')
  235. rm -f /dev/{r,}$_d?
  236. echo "$_d: $_i $_n $_s"
  237. done
  238. }
  239. # Create devices passed as arguments.
  240. make_dev() {
  241. [[ -z $(cd /dev && sh MAKEDEV "$@" 2>&1) ]]
  242. }
  243. # Sort and print information from dmesg.boot using sed expression $1.
  244. scan_dmesg() {
  245. bsort $(sed -n "$1" /var/run/dmesg.boot)
  246. }
  247. # Extract device names from hw.disknames matching sed expression $1.
  248. scan_disknames() {
  249. local IFS=, _disks=$(sysctl -n hw.disknames)
  250. bsort $(for _n in $_disks; do echo "${_n%%:*} "; done | sed -n "$1")
  251. }
  252. # Return disk devices found in hw.disknames.
  253. get_dkdevs () {
  254. echo $(scan_disknames "${MDDKDEVS:-/^[sw]d[0-9][0-9]* /s/ .*//p}")
  255. }
  256. # Return CDROM devices found in hw.disknames.
  257. get_cddevs () {
  258. echo $(scan_disknames "${MDCDDEVS:-/^cd[0-9][0-9]* /s/ .*//p}")
  259. }
  260. # Return list of disks not yet initialized.
  261. get_dkdevs_uninitialized() {
  262. local _disks=$(get_dkdevs) _d
  263. for _d in $DISKS_DONE; do
  264. _disks=$(rmel "$_d" $_disks)
  265. done
  266. bsort $_disks
  267. }
  268. # Return list of network devices. Filter out dynamically created network
  269. # pseudo-devices except vlan.
  270. get_ifs() {
  271. local _if _iflist=$(rmel vlan $(ifconfig -C))
  272. for _if in $(ifconfig "$@" 2>/dev/null |
  273. sed -n 's/^\([^[:space:]]*\):.*/\1/p'); do
  274. isin "${_if%%+([0-9])}" $_iflist || echo $_if
  275. done
  276. }
  277. # Return the device name of the disk device $1, which may be a disklabel UID.
  278. get_dkdev_name() {
  279. local _dev=${1#/dev/} _d
  280. _dev=${_dev%.[a-p]}
  281. ((${#_dev} < 16)) && _dev=${_dev%[a-p]}
  282. local IFS=,
  283. for _d in $(sysctl -n hw.disknames); do
  284. [[ $_dev == @(${_d%:*}|${_d#*:}) ]] && echo ${_d%:*} && break
  285. done
  286. }
  287. # Inspect disk $1 if it has a partition-table of type $2 and optionally
  288. # if it has a partition of type $3.
  289. disk_has() {
  290. local _disk=$1 _pttype=$2 _part=$3 _cmd _p_pttype _p_part
  291. [[ -n $_disk && -n $_pttype ]] || exit
  292. # Commands to inspect disk. Default: "fdisk $_disk"
  293. local _c_hfs="pdisk -l $_disk"
  294. local _c_sr="bioctl -q $_disk"
  295. # Patterns for partition-table-types and partition-types.
  296. local _p_gpt='Usable LBA:'
  297. local _p_gpt_openbsd='^[ *]...: OpenBSD '
  298. local _p_gpt_efisys='^[ *]...: EFI Sys '
  299. local _p_hfs='^Partition map '
  300. local _p_hfs_openbsd=' OpenBSD OpenBSD '
  301. local _p_mbr='Signature: 0xAA55'
  302. local _p_mbr_openbsd='^..: A6 '
  303. local _p_mbr_dos='^..: 06 '
  304. local _p_mbr_dos_active='^\*.: 06 '
  305. local _p_mbr_linux='^..: 83 '
  306. local _p_sr='OPENBSD, SR'
  307. local _p_sr_crypto='OPENBSD, SR CRYPTO'
  308. # Compose command and patterns based on the parameters.
  309. eval "_cmd=\"\$_c_${_pttype}\""
  310. eval "_p_pttype=\"\$_p_${_pttype}\""
  311. eval "_p_part=\"\$_p_${_pttype}_${_part}\""
  312. # Set the default command if none was defined before.
  313. _cmd=${_cmd:-fdisk $_disk}
  314. # Abort in case of undefined patterns.
  315. [[ -z $_p_pttype ]] && exit
  316. [[ -n $_part && -z $_p_part ]] && exit
  317. if [[ -z $_p_part ]]; then
  318. $_cmd 2>/dev/null | grep -Eq "$_p_pttype"
  319. else
  320. $_cmd 2>/dev/null | grep -Eq "$_p_pttype" &&
  321. $_cmd 2>/dev/null | grep -Eq "$_p_part"
  322. fi
  323. }
  324. # Handle disklabel auto-layout during interactive installation and
  325. # autopartitioning during unattended installation for the root disk.
  326. # In the latter case, ask for and download autopartitioning template.
  327. # Abort unattended installation if autopartitioning fails.
  328. #
  329. # Parameters:
  330. #
  331. # $1 = disk
  332. # $2 = /path/to/fstab
  333. #
  334. disklabel_autolayout() {
  335. local _disk=$1 _f=$2 _dl=/tmp/i/disklabel.auto _op _qst
  336. # Skip disklabel auto-layout for any disk except the root disk.
  337. [[ $_disk != $ROOTDISK ]] && return
  338. while $AUTO; do
  339. ask "URL to autopartitioning template for disklabel?" none
  340. [[ $resp == none ]] && break
  341. if ! $FTP_TLS && [[ $resp == https://* ]]; then
  342. echo "https not supported on this platform."
  343. exit 1
  344. fi
  345. echo "Fetching $resp"
  346. if unpriv ftp -Vo - "$resp" >$_dl && [[ -s $_dl ]]; then
  347. disklabel -T $_dl -F $_f -w -A $_disk && return
  348. echo "Autopartitioning failed"
  349. exit 1
  350. else
  351. echo "No autopartitioning template found."
  352. exit 1
  353. fi
  354. done
  355. _qst="Use (A)uto layout, (E)dit auto layout, or create (C)ustom layout?"
  356. while :; do
  357. echo "The auto-allocated layout for $_disk is:"
  358. disklabel -h -A $_disk | egrep "^# |^ [a-p]:"
  359. ask "$_qst" a
  360. case $resp in
  361. [aA]*) _op=-w;;
  362. [eE]*) _op=-E;;
  363. [cC]*) return 0;;
  364. *) continue;;
  365. esac
  366. disklabel -F $_f $_op -A $_disk
  367. return
  368. done
  369. }
  370. # Create a partition table and configure the partition layout for disk $1.
  371. configure_disk() {
  372. local _disk=$1 _fstab=/tmp/i/fstab.$1 _opt
  373. make_dev $_disk || return
  374. # Deal with disklabels, including editing the root disklabel
  375. # and labeling additional disks. This is machine-dependent since
  376. # some platforms may not be able to provide this functionality.
  377. # /tmp/i/fstab.$_disk is created here with 'disklabel -F'.
  378. rm -f /tmp/i/*.$_disk
  379. md_prep_disklabel $_disk || return
  380. # Make sure a '/' mount point exists on the root disk.
  381. if ! grep -qs ' / ffs ' /tmp/i/fstab.$ROOTDISK; then
  382. echo "'/' must be configured!"
  383. $AUTO && exit 1 || return 1
  384. fi
  385. if [[ -f $_fstab ]]; then
  386. # Avoid duplicate mount points on different disks.
  387. while read _pp _mp _rest; do
  388. if [[ $_mp == none ]]; then
  389. # Multiple swap partitions are ok.
  390. echo "$_pp $_mp $_rest" >>/tmp/i/fstab
  391. continue
  392. fi
  393. # Non-swap mountpoints must be in only one file.
  394. if [[ $_fstab != $(grep -l " $_mp " /tmp/i/fstab.*) ]]; then
  395. _rest=$_disk
  396. _disk=
  397. break
  398. fi
  399. done <$_fstab
  400. if [[ -z $_disk ]]; then
  401. # Duplicate mountpoint.
  402. # Allow disklabel(8) to read back mountpoint info
  403. # if it is immediately run against the same disk.
  404. cat /tmp/i/fstab.$_rest >/etc/fstab
  405. rm /tmp/i/fstab.$_rest
  406. set -- $(grep -h " $_mp " /tmp/i/fstab.*[0-9])
  407. echo "$_pp and $1 can't both be mounted at $_mp."
  408. $AUTO && exit 1 || return 1
  409. fi
  410. # Add ffs filesystems to list after newfs'ing them. Ignore
  411. # other filesystems.
  412. while read _pp _mp _fstype _rest; do
  413. [[ $_fstype == ffs ]] || continue
  414. _opt=
  415. [[ $_mp == / ]] && _opt=$MDROOTFSOPT
  416. newfs -q $_opt ${_pp##/dev/}
  417. # N.B.: '!' is lexically < '/'. That is
  418. # required for correct sorting of
  419. # mount points.
  420. FSENT="$FSENT $_mp!$_pp"
  421. done <$_fstab
  422. fi
  423. return 0
  424. }
  425. # ------------------------------------------------------------------------------
  426. # Functions for the dmesg listener
  427. # ------------------------------------------------------------------------------
  428. # Acquire lock.
  429. lock() {
  430. while ! mkdir /tmp/i/lock 2>/dev/null && sleep .1; do done
  431. }
  432. # Release lock.
  433. unlock() {
  434. rm -d /tmp/i/lock 2>/dev/null
  435. }
  436. # Add trap to kill the listener process.
  437. retrap() {
  438. trap 'kill -KILL $CPPID 2>/dev/null; echo; stty echo; exit 0' \
  439. INT EXIT TERM
  440. }
  441. # ------------------------------------------------------------------------------
  442. # Functions to ask (or auto-answer) questions
  443. # ------------------------------------------------------------------------------
  444. # Log installer questions and answers so that the resulting file can be used as
  445. # response file for an unattended install/upgrade.
  446. log_answers() {
  447. if [[ -n $1 && -n $2 ]]; then
  448. print -r -- "${1%%'?'*} = $2" >>/tmp/i/$MODE.resp
  449. fi
  450. }
  451. # Fetch response file for autoinstall.
  452. get_responsefile() {
  453. local _rf _if _mode _lf _hn _path _aifile
  454. export AI_MAC= AI_MODE= AI_SERVER=
  455. [[ -f /auto_upgrade.conf ]] && _rf=/auto_upgrade.conf _mode=upgrade
  456. [[ -f /auto_install.conf ]] && _rf=/auto_install.conf _mode=install
  457. [[ -f $_rf ]] && cp $_rf /tmp/ai/ai.$_mode.conf &&
  458. AI_MODE=$_mode && return
  459. for _if in ''; do
  460. [[ -x /sbin/dhclient ]] || break
  461. # Select a network interface for initial dhcp request.
  462. # Prefer the interface the system netbooted from.
  463. set -- $(get_ifs netboot)
  464. (($# == 0)) && set -- $(get_ifs)
  465. (($# == 1)) && _if=$1
  466. # Ask if multiple were found and system was not netbooted.
  467. while (($# > 1)); do
  468. ask_which "network interface" \
  469. "should be used for the initial DHCP request" \
  470. "$*"
  471. isin "$resp" $* && _if=$resp && break
  472. done
  473. # Issue initial dhcp request via the found interface.
  474. [[ -n $_if ]] && dhclient $_if || break
  475. _lf=/var/db/dhclient.leases.$_if
  476. # Extract installer mode and response file path from lease file.
  477. _aifile=$(lease_value $_lf filename bootfile-name)
  478. [[ $_aifile == ?(*/)auto_@(install|upgrade) ]] || _aifile=
  479. _path=${_aifile%auto_@(install|upgrade)}
  480. _mode=${_aifile##*?(/)auto_}
  481. # Extract installer server ip address from lease file.
  482. AI_SERVER=$(lease_value $_lf \
  483. server-name tftp-server-name next-server)
  484. # Prime hostname with host-name option from lease file.
  485. _hn=$(lease_value $_lf host-name)
  486. hostname "$_hn"
  487. done
  488. # Fetch response file if server and mode are known, otherwise tell which
  489. # one was missing. Try to fetch mac-mode.conf, then hostname-mode.conf,
  490. # and finally mode.conf.
  491. if [[ -n $AI_SERVER && -n $_mode ]]; then
  492. AI_MAC=$(ifconfig $_if | sed 's/.*lladdr \(.*\)/\1/p;d')
  493. for _rf in {$AI_MAC-,${_hn:+$_hn-,}}$_mode; do
  494. _url="http://$AI_SERVER/$_path$_rf.conf?path=$HTTP_SETDIR"
  495. echo "Fetching $_url"
  496. if unpriv ftp -Vo - "$_url" \
  497. >"/tmp/ai/ai.$_mode.conf" 2>/dev/null; then
  498. AI_MODE=$_mode
  499. ifconfig $_if delete down 2>/dev/null
  500. return 0
  501. fi
  502. done
  503. else
  504. [[ -z $AI_SERVER ]] && echo "Could not determine auto server."
  505. [[ -z $_mode ]] && echo "Could not determine auto mode."
  506. fi
  507. # Ask for url or local path to response file. Provide a default url if
  508. # server was found in lease file.
  509. while :; do
  510. ask "Response file location?" \
  511. "${AI_SERVER:+http://$AI_SERVER/install.conf}"
  512. [[ -n $resp ]] && _rf=$resp && break
  513. done
  514. # Ask for the installer mode only if auto-detection failed.
  515. _mode=$(echo "$_rf" | sed -En 's/^.*(install|upgrade).conf$/\1/p')
  516. while [[ -z $_mode ]]; do
  517. ask "(I)nstall or (U)pgrade?"
  518. [[ $resp == [iI]* ]] && _mode=install
  519. [[ $resp == [uU]* ]] && _mode=upgrade
  520. done
  521. echo "Fetching $_rf"
  522. [[ -f $_rf ]] && _rf="file://$_rf"
  523. unpriv ftp -Vo - "$_rf" >"/tmp/ai/ai.$_mode.conf" 2>/dev/null &&
  524. AI_MODE=$_mode
  525. ifconfig $_if delete down 2>/dev/null
  526. [[ -n $AI_MODE ]]
  527. }
  528. # Search question in $RESPFILE, return answer in $resp.
  529. #
  530. # 1) split question and answer at leftmost =
  531. # 2) strip leading/trailing blanks
  532. # 3) compare questions case insensitive
  533. # 4) ignore empty and comment lines and lines without =
  534. # 5) return default answer if provided and none is found in file
  535. # 6) treat empty/missing/multiple answers as error and exit
  536. #
  537. # Parameters:
  538. #
  539. # $1 = the question to search for
  540. # $2 = the default answer
  541. #
  542. _autorespond() {
  543. typeset -l _q=$1 _key
  544. local _def=$2 _l _val
  545. [[ -f $RESPFILE ]] || return
  546. # Find a suitable response in /tmp/ai/ai.conf and remove it if found.
  547. mv /tmp/ai/ai.conf /tmp/ai/ai.conf.tmp
  548. while IFS=' ' read -r _l; do
  549. [[ $_l == [!#=]*=?* ]] || continue
  550. _key=${_l%%*([[:blank:]])=*}
  551. _val=${_l##*([!=])=*([[:blank:]])}
  552. [[ $_q == @(|*[[:blank:]])"$_key"@([[:blank:]?]*|) ]] &&
  553. resp=$_val && cat && return
  554. print -r " $_l"
  555. done </tmp/ai/ai.conf.tmp >/tmp/ai/ai.conf
  556. [[ -n $_def ]] && resp=$_def && return
  557. echo "\nQuestion has no answer in response file."
  558. exit 1
  559. }
  560. # Issue a read into the global variable $resp. If the dmesg output is
  561. # changed while inside this function, the current read will be aborted
  562. # and the function will return a non-zero value. Normally, the caller
  563. # will then reprint any prompt and call the function again.
  564. #
  565. # Optional parameters:
  566. #
  567. # $1 = the question to ask the user
  568. # $2 = the default answer
  569. #
  570. _ask() {
  571. local _q=$1 _def=$2 _int _redo=0 _pid
  572. lock; dmesg >/tmp/i/update; unlock
  573. echo -n "${_q:+$_q }${_def:+[$_def] }"
  574. _autorespond "$_q" "$_def" && echo "$resp" && return
  575. trap "_int=1" INT
  576. trap "_redo=1" TERM
  577. read resp
  578. lock; rm /tmp/i/update; unlock
  579. if ((_redo)); then
  580. stty raw
  581. stty -raw
  582. else
  583. case $resp in
  584. !) echo "Type 'exit' to return to install."
  585. sh
  586. _redo=1
  587. ;;
  588. !*) eval "${resp#?}"
  589. _redo=1
  590. ;;
  591. esac
  592. fi
  593. retrap
  594. ((_int)) && kill -INT $$
  595. : ${resp:=$_def}
  596. return $_redo
  597. }
  598. # Ask for user input presenting question $1 with an optional default answer $2.
  599. # Save the answer in the global variable $resp. Additionally write the question
  600. # and the answer to a logfile. Parameters $1 and $2 are passed on to _ask(),
  601. # which is called repeatedly until it succeds.
  602. ask() {
  603. while ! _ask "$1" "$2"; do done
  604. log_answers "$1" "$resp"
  605. }
  606. # Ask the user a yes/no question, and insist on 'y', 'yes', 'n' or 'no'.
  607. # Return 'y' or 'n' in $resp.
  608. # Exit code: (y)es => 0, (n)o => 1
  609. #
  610. # Parameters:
  611. #
  612. # $1 = the question to ask the user
  613. # $2 = the default answer (assumed to be 'n' if empty).
  614. #
  615. ask_yn() {
  616. local _q=$1 _a=${2:-no}
  617. typeset -l _resp
  618. while :; do
  619. ask "$_q" "$_a"
  620. _resp=$resp
  621. case $_resp in
  622. y|yes) resp=y; return 0;;
  623. n|no) resp=n; return 1;;
  624. esac
  625. echo "'$resp' is not a valid choice."
  626. $AUTO && exit 1
  627. done
  628. }
  629. # Ask for the user to select one value from a list, or 'done'.
  630. # At exit $resp holds selected item, or 'done'.
  631. #
  632. # Parameters:
  633. #
  634. # $1 = name of the list items (disk, cd, etc.)
  635. # $2 = question to ask
  636. # $3 = list of valid choices
  637. # $4 = default choice, if it is not specified use the first item in $3
  638. #
  639. # N.B.! $3 and $4 will be "expanded" using eval, so be sure to escape them
  640. # if they contain spooky stuff
  641. ask_which() {
  642. local _name=$1 _query=$2 _list=$3 _def=$4 _dynlist _dyndef _key _q
  643. _key=$(echo "$_name" | sed 's/[^[:alnum:]]/_/g')
  644. while :; do
  645. eval "_dynlist=\"$_list\""
  646. eval "_dyndef=\"$_def\""
  647. # Clean away whitespace and determine the default.
  648. set -o noglob
  649. set -- $_dyndef; _dyndef="$1"
  650. set -- $_dynlist; _dynlist="$*"
  651. set +o noglob
  652. (($# < 1)) && resp=done && return
  653. : ${_dyndef:=$1}
  654. echo "Available ${_name}s are: $_dynlist."
  655. _q="Which $_name $_query?"
  656. echo -n "$_q (or 'done') ${_dyndef:+[$_dyndef] }"
  657. _autorespond "$_q" "${_dyndef-done}" && echo "$resp" \
  658. || _ask || continue
  659. [[ -z $resp ]] && resp="$_dyndef"
  660. # Quote $resp to prevent user from confusing isin() by
  661. # entering something like 'a a'.
  662. if isin "$resp" $_dynlist done; then
  663. log_answers "$_q" "$resp"
  664. break
  665. fi
  666. echo "'$resp' is not a valid choice."
  667. $AUTO && [[ -n $RESPFILE ]] && exit 1
  668. done
  669. }
  670. # Ask for user input until a non-empty reply is entered.
  671. # Save the user input (or the default) in $resp.
  672. #
  673. # Parameters:
  674. #
  675. # $1 = the question to ask the user
  676. # $2 = the default answer
  677. #
  678. function ask_until {
  679. resp=
  680. while true; do
  681. ask "$1" "$2"
  682. [[ -n $resp ]] && break
  683. echo "A response is required."
  684. $AUTO && exit 1
  685. done
  686. }
  687. # Ask for a password, saving the input in $resp.
  688. #
  689. # 1) Display $1 as the prompt.
  690. # 2) *Don't* allow the '!' options that ask does.
  691. # 3) *Don't* echo input.
  692. # 4) *Don't* interpret "\" as escape character.
  693. # 5) Preserve whitespace in input
  694. #
  695. ask_pass() {
  696. stty -echo
  697. IFS= read -r resp?"$1 "
  698. stty echo
  699. echo
  700. }
  701. # Ask for a password twice, saving the input in $_password.
  702. ask_password() {
  703. local _q=$1
  704. if $AUTO; then
  705. echo -n "$_q "
  706. _autorespond "$_q"
  707. echo '<provided>'
  708. _password=$resp
  709. return
  710. fi
  711. while :; do
  712. ask_pass "$_q (will not echo)"
  713. _password=$resp
  714. ask_pass "$_q (again)"
  715. [[ $resp == "$_password" ]] && break
  716. echo "Passwords do not match, try again."
  717. done
  718. }
  719. # ------------------------------------------------------------------------------
  720. # Support functions for donetconfig()
  721. # ------------------------------------------------------------------------------
  722. # Issue a DHCP request to configure interface $1 and add the host-name option to
  723. # /etc/dhclient.conf using $2.
  724. dhcp_request() {
  725. local _if=$1 _hn=$2
  726. echo "lookup file bind" >/etc/resolv.conf.tail
  727. echo "send host-name \"$_hn\";" >/etc/dhclient.conf
  728. ifconfig $_if group dhcp >/dev/null 2>&1
  729. dhclient -c /dev/stdin $_if <<__EOT
  730. initial-interval 1;
  731. backoff-cutoff 2;
  732. reboot 5;
  733. timeout 10;
  734. send host-name "$_hn";
  735. __EOT
  736. # Move configuration files to where they will be copied to the
  737. # installed system. Overwrites configuration information from
  738. # last successful dhcp attempt.
  739. mv /etc/dhclient.conf /tmp/i/dhclient.conf
  740. mv /etc/resolv.conf.tail /tmp/i/resolv.conf.tail
  741. }
  742. # Obtain and output the inet information related to interface $1.
  743. # Should output '<UP/DOWN> <addr> <netmask> <rest of inet line>'.
  744. v4_info() {
  745. ifconfig $1 inet | sed -n '
  746. 1s/.*<UP,.*/UP/p
  747. 1s/.*<.*/DOWN/p
  748. /inet/s/netmask//
  749. /inet/s///p'
  750. }
  751. # Convert a netmask in hex format ($1) to dotted decimal format.
  752. hextodec() {
  753. set -- $(echo ${1#0x} | sed 's/\(..\)/0x\1 /g')
  754. echo $(($1)).$(($2)).$(($3)).$(($4))
  755. }
  756. # Create an entry in the hosts file. If an entry with the same symbolic name and
  757. # address family already exists, delete it.
  758. #
  759. # Parameters:
  760. #
  761. # $1 = IP address (v6 if it contains ':', else v4)
  762. # $2 = symbolic name
  763. #
  764. add_hostent() {
  765. local _addr=$1 _name=$2 _delim="."
  766. [[ -z $_addr || -z $_name ]] && return
  767. [[ $_addr == *:* ]] && _delim=":"
  768. sed -i "/^[0-9a-fA-F]*[$_delim].*[ ]$_name\$/d" \
  769. /tmp/i/hosts 2>/dev/null
  770. echo "$_addr $_name" >>/tmp/i/hosts
  771. }
  772. # Configure IPv4 interface.
  773. #
  774. # Parameters:
  775. #
  776. # $1 = name of the network device
  777. # $2 = hostname to use for dhcp request
  778. # $3 = /path/to/hostname.if
  779. #
  780. v4_config() {
  781. local _if=$1 _name=$2 _hn=$3 _prompt _addr _mask
  782. if ifconfig $_if | grep -q 'groups:.* dhcp'; then
  783. _addr=dhcp
  784. else
  785. set -- $(v4_info $_if)
  786. if [[ -n $2 ]]; then
  787. _addr=$2; _mask=$(hextodec $3)
  788. ifconfig $_if inet $_addr delete
  789. fi
  790. fi
  791. if [[ -x /sbin/dhclient ]]; then
  792. _prompt="or 'dhcp' "
  793. # Don't make 'dhcp' the default if dhcp was already used.
  794. ifconfig dhcp >/dev/null 2>&1 || _addr=dhcp
  795. fi
  796. _prompt="IPv4 address for $_if? (${_prompt}or 'none')"
  797. ask_until "$_prompt" "$_addr"
  798. case $resp in
  799. none) ;;
  800. dhcp) if [[ ! -x /sbin/dhclient ]]; then
  801. echo "DHCP not possible - no /sbin/dhclient."
  802. else
  803. dhcp_request $_if "$_name"
  804. echo "dhcp" >>$_hn
  805. fi
  806. ;;
  807. *) _addr=$resp
  808. ask_until "Netmask for $_if?" "${_mask:=255.255.255.0}"
  809. ifconfig $_if -group dhcp >/dev/null 2>&1
  810. if ifconfig $_if inet $_addr netmask $resp up; then
  811. add_hostent "$_addr" "$_name"
  812. echo "inet $_addr $resp" >>$_hn
  813. fi
  814. ;;
  815. esac
  816. }
  817. # Obtain and output the inet6 information related to interface $1.
  818. # Should output '<UP/DOWN> <addr> <prefixlen> <rest of inet line> '.
  819. v6_info() {
  820. ifconfig $1 inet6 | sed -n '
  821. 1s/.*<UP,.*/UP/p
  822. 1s/.*<.*/DOWN/p
  823. /scopeid/d
  824. /inet6/s/prefixlen//
  825. /inet6/s///p'
  826. }
  827. # Set up IPv6 default route on interface $1.
  828. v6_defroute() {
  829. local _if=$1 _prompt _resp _routers PS3
  830. route -n show -inet6 | egrep -q '^default[[:space:]]' && return
  831. _routers=$(bsort $(ping6 -n -c 2 ff02::2%$_if 2>/dev/null |
  832. sed -n '/bytes from/{s/^.*from //;s/,.*$//;p;}' |
  833. sed -n 'G;s/\n/&&/;/^\(.*\n\).*\n\1/d;h;P'))
  834. _prompt="IPv6 default router?"
  835. if $AUTO; then
  836. _autorespond "$_prompt" && _resp=$resp && echo "$_prompt $_resp"
  837. else
  838. PS3="$_prompt (${_routers:+list #, }IPv6 address or 'none'): "
  839. select _resp in $_routers; do
  840. [[ ${_resp:=$REPLY} == *:* ]] && break
  841. [[ $_resp == none ]] && return
  842. done
  843. fi
  844. route -n add -inet6 -host default "$_resp" &&
  845. echo "$_resp" >>/tmp/i/mygate
  846. }
  847. # Configure IPv6 interface.
  848. #
  849. # Parameters:
  850. #
  851. # $1 = name of the network device
  852. # $2 = hostname to use for dhcp request
  853. # $3 = /path/to/hostname.if
  854. #
  855. v6_config() {
  856. local _if=$1 _name=$2 _hn=$3 _addr _prefixlen _prompt
  857. ifconfig lo0 inet6 >/dev/null 2>&1 || return
  858. set -- $(v6_info $_if)
  859. [[ -n $2 ]] && { _addr=$2; _prefixlen=$3; }
  860. ifconfig $_if inet6 >/dev/null 2>&1 && _prompt="or 'rtsol' "
  861. _prompt="IPv6 address for $_if? (${_prompt}or 'none')"
  862. ask_until "$_prompt" "${_addr:-none}"
  863. case $resp in
  864. none) return
  865. ;;
  866. rtsol) ifconfig $_if inet6 >/dev/null 2>&1 ||
  867. { echo "No INET6 support."; return; }
  868. ifconfig $_if up
  869. ifconfig $_if inet6 autoconf && echo "up\nrtsol" >>$_hn
  870. return
  871. ;;
  872. esac
  873. _addr=$resp
  874. ask_until "IPv6 prefix length for $_if?" "${_prefixlen:=64}"
  875. ifconfig $_if inet6 $_addr prefixlen $resp up || return
  876. echo "inet6 $_addr $resp" >>$_hn
  877. add_hostent "$_addr" "$_name"
  878. v6_defroute $_if
  879. }
  880. # Perform an 802.11 network scan on interface $1.
  881. # The result is cached in $WLANLIST.
  882. ieee80211_scan() {
  883. # N.B. Skipping quoted nwid's for now.
  884. [[ -f $WLANLIST ]] ||
  885. ifconfig $1 scan |
  886. sed -n 's/^ nwid \([^"]\)/\1/p' >$WLANLIST
  887. cat $WLANLIST
  888. }
  889. # Configure 802.11 interface $1 and append ifconfig options to hostname.if $2.
  890. ieee80211_config() {
  891. local _if=$1 _hn=$2 _prompt _nwid _haswpa=0 _err
  892. # Reset 802.11 settings and determine wpa capability.
  893. ifconfig $_if -nwid -nwkey
  894. ifconfig $_if -wpa 2>/dev/null && _haswpa=1
  895. # Empty scan cache.
  896. rm -f $WLANLIST
  897. while [[ -z $_nwid ]]; do
  898. ask_until "Access point? (ESSID, 'any', list# or '?')" "any"
  899. case "$resp" in
  900. +([0-9]))
  901. _nwid=$(ieee80211_scan $_if | sed -n "${resp}s/ .*//p")
  902. [[ -z $_nwid ]] && echo "There is no line $resp."
  903. ;;
  904. \?) ieee80211_scan $_if |
  905. sed -n 's/^\([^ ]*\) chan .* bssid \([^ ]*\) .*$/ \1 (\2)/p' |
  906. cat -n | more -c
  907. ;;
  908. *) _nwid=$resp
  909. ;;
  910. esac
  911. done
  912. # 'any' implies that only open access points are considered.
  913. if [[ $_nwid != any ]]; then
  914. ifconfig $_if nwid "$_nwid"
  915. quote nwid "$_nwid" >>$_hn
  916. _prompt="Security protocol? (O)pen, (W)EP"
  917. ((_haswpa == 1)) && _prompt="$_prompt, WPA-(P)SK"
  918. while :; do
  919. ask_until "$_prompt" "O"
  920. case "$_haswpa-$resp" in
  921. ?-[Oo]) break
  922. ;;
  923. ?-[Ww]) ask_until "WEP key? (will echo)"
  924. # Make sure ifconfig accepts the key.
  925. if _err=$(ifconfig $_if nwkey "$resp" 2>&1) &&
  926. [[ -z $_err ]]; then
  927. quote nwkey "$resp" >>$_hn
  928. break
  929. fi
  930. echo "$_err"
  931. ;;
  932. 1-[Pp]) ask_until "WPA passphrase? (will echo)"
  933. # Make sure ifconfig accepts the key.
  934. if ifconfig $_if wpakey "$resp"; then
  935. quote wpakey "$resp" >>$_hn
  936. break
  937. fi
  938. ;;
  939. *) echo "'$resp' is not a valid choice."
  940. ;;
  941. esac
  942. done
  943. fi
  944. }
  945. # Set up IPv4 and IPv6 interface configuration.
  946. configure_ifs() {
  947. local _first _ifs _if _name _hn _vl=0 _vd _vi _p _tags
  948. # In case of restart, discover last vlan configured.
  949. while :; do
  950. _vd=$(ifconfig vlan$_vl 2>&1)
  951. [[ $_vd == @(*no such interface*) ]] && break
  952. [[ $_vd == @(*vlan: +([[:digit:]]) parent interface:*) ]] ||
  953. break
  954. ((_vl++))
  955. done
  956. _vd=
  957. # Always need lo0 configured.
  958. ifconfig lo0 inet 127.0.0.1/8
  959. # In case of restart, delete previous default gateway config.
  960. rm -f /tmp/i/mygate
  961. while :; do
  962. # Create new vlan if possible.
  963. ifconfig vlan$_vl create >/dev/null 2>&1
  964. ask_which "network interface" "do you wish to configure" \
  965. '$(get_ifs)' \
  966. ${_p:-'$( (get_ifs netboot; get_ifs) | sed q )'}
  967. [[ $resp == done ]] && break
  968. _if=$resp
  969. _hn=/tmp/i/hostname.$_if
  970. rm -f $_hn
  971. # If the offered vlan is chosen, ask the relevant
  972. # questions and bring it up.
  973. if [[ $_if == vlan+([0-9]) ]]; then
  974. # Get existing tag for this vlan.
  975. _vi=$(ifconfig $_if 2>/dev/null |
  976. sed -n 's/vlan: \([0-9]*\).*/\1/p')
  977. # Get list of all in-use tags.
  978. _tags=$(ifconfig vlan 2>/dev/null |
  979. sed -n 's/vlan: \([0-9]*\).*/\1/p')
  980. # Current tag is a valid tag for this vlan.
  981. [[ -n $_tags ]] && _tags=$(rmel "$_vi" $_tags)
  982. if [[ -z $_vi ]]; then
  983. _vi=0
  984. while ((++_vi < 4096)); do
  985. ! isin "$_vi" $_tags && break
  986. done
  987. fi
  988. _ifs=$(get_ifs)
  989. set -- $_ifs
  990. while [[ $1 == vlan+([0-9]) ]]; do
  991. shift
  992. done
  993. ask "Which interface:tag should $_if be on?" \
  994. "${_vd:=$1}:$_vi"
  995. _vd=${resp%%:*}
  996. _vi=${resp##*:}
  997. # Validate that $_vd is a real interface.
  998. if ! (isin "$_vd" $_ifs &&
  999. [[ $_vd != vlan+([0-9]) ]]); then
  1000. echo "Invalid interface choice '$_vd'"
  1001. _vd=
  1002. continue
  1003. fi
  1004. # Validate range of $_vi as 1-4095, and $_vi not in use.
  1005. if ((_vi < 1 || _vi > 4095)) || isin "$_vi" $_tags; then
  1006. echo "Invalid or in-use vlan tag '$_vi'"
  1007. continue
  1008. fi
  1009. # hostname.$_vd must say something, anything, to
  1010. # make sure it is up.
  1011. grep -qs "^up" /tmp/i/hostname.$_vd ||
  1012. echo "up" >>/tmp/i/hostname.$_vd
  1013. chmod 640 /tmp/i/hostname.$_vd
  1014. ifconfig $_vd up
  1015. # Make sure a hostname.$_if is created with this info.
  1016. ifconfig $_if destroy >/dev/null 2>&1
  1017. ifconfig $_if vlan $_vi vlandev $_vd
  1018. echo "vlan $_vi vlandev $_vd" >>$_hn
  1019. # Create a new vlan if we just configured the highest.
  1020. [[ ${_if##vlan} == $_vl ]] && ((_vl++))
  1021. fi
  1022. # Test if it is an 802.11 interface.
  1023. ifconfig $_if 2>/dev/null | grep -q "^[[:space:]]*ieee80211:" &&
  1024. ieee80211_config $_if $_hn
  1025. # First interface configured will use the hostname without
  1026. # asking the user.
  1027. resp=$(hostname -s)
  1028. [[ -n $_first && $_first != $_if ]] &&
  1029. ask "Symbolic (host) name for $_if?" $resp
  1030. _name=$resp
  1031. v4_config $_if $_name $_hn
  1032. v6_config $_if $_name $_hn
  1033. if [[ -f $_hn ]]; then
  1034. chmod 640 $_hn
  1035. : ${_first:=$_if}
  1036. fi
  1037. NIFS=$(ls -1 /tmp/i/hostname.* 2>/dev/null | grep -c ^)
  1038. _p=done
  1039. done
  1040. }
  1041. # Set up IPv4 default route.
  1042. v4_defroute() {
  1043. local _dr
  1044. # Only configure a default route if an IPv4 address was configured.
  1045. [[ -n $(ifconfig | sed -n '/[ ]inet .* broadcast /p') ]] || return
  1046. # Check routing table to see if a default route ($1) already exists
  1047. # and if it is handled by dhclient ($2).
  1048. set -- $(route -nv show -inet |
  1049. { set -- $(grep '^default '); print $2 $9; })
  1050. [[ -n $1 ]] && _dr=$1
  1051. # Don't ask if a default route exits and is handled by dhclient.
  1052. [[ -n $_dr && $2 == \"DHCLIENT && -f /tmp/i/dhclient.conf ]] && return
  1053. while :; do
  1054. ask_until "Default IPv4 route? (IPv4 address or none)" "$_dr"
  1055. [[ $resp == none ]] && break
  1056. route delete -inet default >/dev/null 2>&1
  1057. route -n add -inet -host default "$resp" &&
  1058. { echo "$resp" >>/tmp/i/mygate; break; }
  1059. # Put the old default route back. The new one did not work.
  1060. route -n add -inet -host default $_dr >/dev/null 2>&1
  1061. done
  1062. }
  1063. # Extract fully qualified domain name from current hostname. If none is
  1064. # currently set, use 'my.domain'.
  1065. get_fqdn() {
  1066. local _dn
  1067. _dn=$(hostname)
  1068. _dn=${_dn#$(hostname -s)}
  1069. _dn=${_dn#.}
  1070. echo "${_dn:=my.domain}"
  1071. }
  1072. # ------------------------------------------------------------------------------
  1073. # Support functions for install_sets()
  1074. # ------------------------------------------------------------------------------
  1075. # Check that missing required sets were deliberately skipped.
  1076. # Care is taken to make sure the return value is correct.
  1077. sane_install() {
  1078. local _q=$1 _s
  1079. for _s in $SANESETS; do
  1080. isin "$_s" $DEFAULTSETS || continue
  1081. [[ -n $_q ]] && return 1
  1082. # If sane_install has no argument, harass the user.
  1083. if ! ask_yn "Are you *SURE* your $MODE is complete without '$_s'?"; then
  1084. $AUTO && exit 1 || return 1
  1085. fi
  1086. done
  1087. }
  1088. # Show list of available sets and let the user select which sets to install.
  1089. # Set $resp to list of selected sets.
  1090. #
  1091. # Parameters:
  1092. #
  1093. # $1 = available sets
  1094. # $2 = already selected sets
  1095. #
  1096. select_sets() {
  1097. local _avail=$1 _selected=$2 _f _action _col=$COLUMNS
  1098. # account for 4 spaces added to the sets list
  1099. let COLUMNS=_col-8
  1100. cat <<__EOT
  1101. Select sets by entering a set name, a file name pattern or 'all'. De-select
  1102. sets by prepending a '-' to the set name, file name pattern or 'all'. Selected
  1103. sets are labelled '[X]'.
  1104. __EOT
  1105. while :; do
  1106. for _f in $_avail; do
  1107. isin "$_f" $_selected && echo "[X] $_f" || echo "[ ] $_f"
  1108. done | show_cols | sed 's/^/ /'
  1109. ask "Set name(s)? (or 'abort' or 'done')" done
  1110. set -o noglob
  1111. for resp in $resp; do
  1112. case $resp in
  1113. abort) _selected=; break 2;;
  1114. done) break 2;;
  1115. -*) _action=rmel;;
  1116. *) _action=addel;;
  1117. esac
  1118. resp=${resp#[+-]}
  1119. [[ $resp == all ]] && resp=*
  1120. for _f in $_avail; do
  1121. [[ $_f == $resp ]] &&
  1122. _selected=$($_action $_f $_selected)
  1123. done
  1124. done
  1125. done
  1126. set +o noglob
  1127. COLUMNS=$_col
  1128. resp=$_selected
  1129. }
  1130. # Run a command ($2+) as unprivileged user ($1).
  1131. # Take extra care that after "cmd" no "user" processes exist.
  1132. #
  1133. # Optionally:
  1134. # - create "file" and chown it to "user"
  1135. # - after "cmd", chown "file" back to root
  1136. #
  1137. # Usage: do_as user [-f file] cmd
  1138. do_as() {
  1139. (( $# >= 2 )) || return
  1140. local _file _rc _user=$1
  1141. shift
  1142. if [[ $1 == -f ]]; then
  1143. _file=$2
  1144. shift 2
  1145. fi
  1146. if [[ -n $_file ]]; then
  1147. >$_file
  1148. chown "$_user" "$_file"
  1149. fi
  1150. doas -u "$_user" "$@"
  1151. _rc=$?
  1152. while doas -u "$_user" kill -9 -1 2>/dev/null; do
  1153. echo "Processes still running for user $_user after: $@"
  1154. sleep 1
  1155. done
  1156. [[ -n $_file ]] && chown root "$_file"
  1157. return $_rc
  1158. }
  1159. unpriv() {
  1160. do_as _sndio "$@"
  1161. }
  1162. unpriv2() {
  1163. do_as _file "$@"
  1164. }
  1165. # Install a user-selected subset of the files in $2 from the source
  1166. # named in $1. Display an error message for failed installs so the
  1167. # user will know to try again.
  1168. install_files() {
  1169. local _src=$1 _files=$2 _f _sets _get_sets _n _col=$COLUMNS \
  1170. _tmpfs _tmpsrc _cfile=/tmp/SHA256 _fsrc _unver _t _issue
  1171. local _srclocal=false _unpriv=unpriv
  1172. # Fetch sets from local sources (disk, cdrom, nfs) as root.
  1173. [[ $_src == file://* ]] && _srclocal=true _unpriv=
  1174. # Initialize _sets to the list of sets found in _src, and initialize
  1175. # _get_sets to the intersection of _sets and DEFAULTSETS.
  1176. #
  1177. # Sets will be installed in the order given in THESETS to ensure proper
  1178. # installation. So, to minimize user confusion display the sets in the
  1179. # order in which they will be installed.
  1180. for _f in $THESETS; do
  1181. isin "$_f" $_files || continue
  1182. _sets=$(addel $_f $_sets)
  1183. isin "$_f" $DEFAULTSETS "site$VERSION-$(hostname -s).tgz" &&
  1184. _get_sets=$(addel $_f $_get_sets)
  1185. done
  1186. if [[ -z $_sets ]]; then
  1187. echo -n "Looked at $_src "
  1188. echo "and found no $OBSD sets. The set names looked for were:"
  1189. let COLUMNS=_col-8
  1190. for _n in $THESETS; do echo $_n; done | show_cols | sed 's/^/ /'
  1191. COLUMNS=$_col
  1192. $AUTO && exit 1
  1193. echo
  1194. return
  1195. fi
  1196. isin "INSTALL.$ARCH" $_files ||
  1197. ask_yn "INSTALL.$ARCH not found. Use sets found here anyway?" ||
  1198. return
  1199. select_sets "$_sets" "$_get_sets"
  1200. [[ -n $resp ]] || return
  1201. _get_sets=$resp
  1202. # Reorder $_get_sets.
  1203. _get_sets=$(for s in $THESETS; do isin "$s" $_get_sets && echo $s; done)
  1204. # Note which sets didn't verify ok.
  1205. _unver=$_get_sets
  1206. # Try to prefetch and control checksum files.
  1207. # Use dummy for loop as combined assignment and do { ... } while(0).
  1208. for _issue in ''; do
  1209. ! isin SHA256.sig $_files &&
  1210. _issue="Directory does not contain SHA256.sig" && break
  1211. # For non-local sources find a filesystem to store the prefetched
  1212. # sets. Prefer filesystems which are not used during extraction.
  1213. # They need to have 512 MB free space. Otherwise use any other
  1214. # filesystem having 2 GB free space to prevent overflow during
  1215. # extraction.
  1216. $_srclocal || _tmpfs=$( (
  1217. for fs in /mnt/{{,var/}tmp,home,usr{/local,}}; do
  1218. df -k $fs 2>/dev/null | grep " $fs\$"
  1219. done
  1220. df -k
  1221. ) | (
  1222. while read a a a a m m; do
  1223. [[ $m == /mnt/@(@(|var/)tmp|home|usr/@(src,obj,xobj))@(|/*) ]] &&
  1224. ((a > 524288)) && echo $m && exit
  1225. [[ $m == /mnt@(|/*) ]] &&
  1226. ((a > 524288 * 4)) && echo $m && exit
  1227. done
  1228. ) )
  1229. if ! $_srclocal; then
  1230. if [[ -d $_tmpfs ]]; then
  1231. # Try to clean up from previous runs, assuming
  1232. # the _tmpfs selection yields the same mount
  1233. # point.
  1234. for _tmpsrc in $_tmpfs/sets.+([0-9]).+([0-9]); do
  1235. [[ -d $_tmpsrc ]] && rm -r $_tmpsrc
  1236. done
  1237. ! _tmpsrc=$(tmpdir "$_tmpfs/sets") &&
  1238. _issue="Cannot create prefetch area" && break
  1239. else
  1240. _issue="Cannot determine prefetch area" && break
  1241. fi
  1242. fi
  1243. # Cleanup from previous runs.
  1244. rm -f $_cfile $_cfile.sig
  1245. _t=Get/Verify
  1246. $_srclocal && _t='Verifying '
  1247. # Fetch signature file.
  1248. ! $_unpriv ftp -D "$_t" -Vmo - "$_src/SHA256.sig" >"$_cfile.sig" &&
  1249. _issue="Cannot fetch SHA256.sig" && break
  1250. # Verify signature file with public keys.
  1251. ! unpriv -f "$_cfile" \
  1252. signify -Vep $PUB_KEY -x "$_cfile.sig" -m "$_cfile" &&
  1253. _issue="Signature check of SHA256.sig failed" && break
  1254. for _f in $_get_sets; do
  1255. rm -f /tmp/h /tmp/fail
  1256. # Fetch set and create checksum by pipe through sha256.
  1257. # Create a flag file in case ftp failed. Sets from net
  1258. # are written to prefetch area, the output of local sets
  1259. # is discarded.
  1260. ( $_unpriv ftp -D "$_t" -Vmo - "$_src/$_f" || >/tmp/fail ) |
  1261. ( $_srclocal && unpriv2 sha256 >/tmp/h ||
  1262. unpriv2 -f /tmp/h sha256 -ph /tmp/h >"$_tmpsrc/$_f" )
  1263. # Handle failed transfer.
  1264. if [[ -f /tmp/fail ]]; then
  1265. rm -f "$_tmpsrc/$_f"
  1266. if ! ask_yn "Fetching of $_f failed. Continue anyway?"; then
  1267. [[ -d $_tmpsrc ]] && rm -rf "$_tmpsrc"
  1268. $AUTO && exit 1
  1269. return
  1270. fi
  1271. continue
  1272. fi
  1273. # Verify sets by comparing its checksum with SHA256.
  1274. if fgrep -qx "SHA256 ($_f) = $(</tmp/h)" "$_cfile"; then
  1275. _unver=$(rmel $_f $_unver)
  1276. else
  1277. if ! ask_yn "Checksum test for $_f failed. Continue anyway?"; then
  1278. [[ -d $_tmpsrc ]] && rm -rf "$_tmpsrc"
  1279. $AUTO && exit 1
  1280. return
  1281. fi
  1282. fi
  1283. done
  1284. done
  1285. [[ -n $_unver ]] && : ${_issue:="Unverified sets:" ${_unver% }}
  1286. if [[ -n $_issue ]] &&
  1287. ! ask_yn "$_issue. Continue without verification?"; then
  1288. [[ -d $_tmpsrc ]] && rm -rf "$_tmpsrc"
  1289. $AUTO && exit 1
  1290. return
  1291. fi
  1292. for _f in $_get_sets; do
  1293. _fsrc="$_src/$_f"
  1294. [[ -f $_tmpsrc/$_f ]] && _fsrc="file://$_tmpsrc/$_f"
  1295. case $_fsrc in
  1296. *.tgz) $_unpriv ftp -D Installing -Vmo - "$_fsrc" |
  1297. tar -zxphf - -C /mnt
  1298. if [[ $_f == ?(x)base*.tgz && $MODE == install ]]; then
  1299. ftp -D Extracting -Vmo - \
  1300. file:///mnt/var/sysmerge/${_f%%base*}etc.tgz |
  1301. tar -zxphf - -C /mnt
  1302. fi
  1303. ;;
  1304. *) $_unpriv ftp -D Installing -Vmo - "$_fsrc" >"/mnt/$_f"
  1305. ;;
  1306. esac
  1307. if (($?)); then
  1308. if ! ask_yn "Installation of $_f failed. Continue anyway?"; then
  1309. [[ -d $_tmpsrc ]] && rm -rf "$_tmpsrc"
  1310. $AUTO && exit 1
  1311. return
  1312. fi
  1313. else
  1314. DEFAULTSETS=$(rmel $_f $DEFAULTSETS)
  1315. fi
  1316. [[ -d $_tmpsrc ]] && rm -f "$_tmpsrc/$_f"
  1317. done
  1318. [[ -d $_tmpsrc ]] && rm -rf "$_tmpsrc" || true
  1319. }
  1320. # Fetch install sets from an HTTP server possibly using a proxy.
  1321. install_http() {
  1322. local _d _f _flist _file_list _prompt _tls _http_proto _url_base
  1323. local _idx=/tmp/i/index.txt _sha=/tmp/i/SHA256 _sig=/tmp/i/SHA256.sig
  1324. local _iu_url _iu_srv _iu_dir _mirror_url _mirror_srv _mirror_dir
  1325. # N.B.: Don't make INSTALL_MIRROR a local variable! It preserves the
  1326. # mirror information if install_http() is called multiple times with
  1327. # mirror and local servers. That ensures that the mirror server ends
  1328. # up in /etc/installurl file if one of the servers is not a mirror.
  1329. # N.B.: 'http_proxy' is an environment variable used by ftp(1).
  1330. # DON'T change the name or case!
  1331. ask "HTTP proxy URL? (e.g. 'http://proxy:8080', or 'none')" \
  1332. "${http_proxy:-none}"
  1333. unset http_proxy
  1334. [[ $resp == none ]] || export http_proxy=$resp
  1335. # If the mirror server listfile download failed, inform the user and
  1336. # show a reduced prompt.
  1337. if [[ -s $HTTP_LIST ]]; then
  1338. _prompt="HTTP Server? (hostname, list#, 'done' or '?')"
  1339. else
  1340. echo "(Unable to get list from libertybsd.net, but that is OK)"
  1341. _prompt="HTTP Server? (hostname or 'done')"
  1342. fi
  1343. # Use information from /etc/installurl as defaults for upgrades.
  1344. # Format of installurl: _http_proto://_iu_srv/_iu_dir
  1345. # ^--------- _iu_url ---------^
  1346. if [[ $MODE == upgrade ]] &&
  1347. _iu_url=$(stripcom /mnt/etc/installurl); then
  1348. _iu_srv=${_iu_url#*://}
  1349. _iu_srv=${_iu_srv%%/*}
  1350. _iu_dir=${_iu_url##*$_iu_srv*(/)}
  1351. fi
  1352. # Get server IP address or hostname and optionally the http protocol.
  1353. while :; do
  1354. ask_until "$_prompt" "${_iu_srv:-$HTTP_SERVER}"
  1355. case $resp in
  1356. done) return
  1357. ;;
  1358. "?") [[ -s $HTTP_LIST ]] || continue
  1359. # Show a numbered list of mirror servers.
  1360. cat -n < $HTTP_LIST | more -c
  1361. ;;
  1362. +([0-9]))
  1363. # A number is only used as a line number in $HTTP_LIST.
  1364. [[ -s $HTTP_LIST ]] || continue
  1365. # Extract the URL from the mirror server listfile.
  1366. set -- $(sed -n "${resp}p" $HTTP_LIST)
  1367. if (($# < 1)); then
  1368. echo "There is no line $resp."
  1369. continue
  1370. fi
  1371. HTTP_SERVER=${1%%/*}
  1372. # Repeat loop to get user to confirm server address.
  1373. ;;
  1374. ?(http?(s)://)+([A-Za-z0-9:.\[\]_-]))
  1375. case $resp in
  1376. https://*) _tls=force _http_proto=https;;
  1377. http://*) _tls=no _http_proto=http;;
  1378. *) _tls=try _http_proto=$HTTP_PROTO;;
  1379. esac
  1380. if ! $FTP_TLS && [[ $_tls == force ]]; then
  1381. echo "https not supported on this platform."
  1382. $AUTO && exit 1 || continue
  1383. fi
  1384. HTTP_SERVER=${resp#*://}
  1385. break
  1386. ;;
  1387. *) echo "'$resp' is not a valid hostname."
  1388. ;;
  1389. esac
  1390. done
  1391. # Get directory info from *last* line starting with the server
  1392. # name. This means the last install from a mirror will not keep
  1393. # the specific directory info. But an install from a local
  1394. # server *will* remember the specific directory info.
  1395. # Format: _mirror_srv/_mirror_dir location_info
  1396. # ^---- _mirror_url ----^
  1397. set -- $(grep -i "^$HTTP_SERVER" $HTTP_LIST 2>/dev/null | sed '$!d')
  1398. _mirror_url=${1%%*(/)}
  1399. _mirror_srv=${_mirror_url%%/*}
  1400. _mirror_dir=${_mirror_url##*$_mirror_srv*(/)}
  1401. # Decide on the default for the "Server directory" question.
  1402. if [[ -n $_mirror_url ]]; then
  1403. # Use directory information from cgi server if HTTP_SERVER was
  1404. # found in HTTP_LIST. That is either an official mirror or the
  1405. # server used in a previous installation or upgrade.
  1406. _d=$_mirror_dir/$HTTP_SETDIR
  1407. # Preserve the information that it is an official mirror if
  1408. # location is present in $2.
  1409. (($# > 1)) && INSTALL_MIRROR=$_mirror_url
  1410. elif [[ -n $_iu_url ]]; then
  1411. # Otherwise, if it exists, use directory information from
  1412. # installurl(5) during upgrade.
  1413. _d=$_iu_dir/$HTTP_SETDIR
  1414. else
  1415. _d=pub/LibertyBSD/$HTTP_SETDIR
  1416. fi
  1417. ask_until "Server directory?" "$_d"
  1418. HTTP_DIR=${resp##+(/)}
  1419. _url_base="$_http_proto://$HTTP_SERVER/$HTTP_DIR"
  1420. # Fetch SHA256.sig to create the list of files to select from.
  1421. rm -f $_idx $_sha $_sig
  1422. if ! unpriv -f $_sig \
  1423. ftp -w 15 -VMo $_sig "$_url_base/SHA256.sig" 2>/dev/null; then
  1424. case $_tls in
  1425. force) $AUTO && exit 1 || return
  1426. ;;
  1427. try) ask_yn "Unable to connect using https. Use http instead?" ||
  1428. return
  1429. _http_proto=http
  1430. _url_base="http://$HTTP_SERVER/$HTTP_DIR"
  1431. unpriv -f $_sig ftp -VMo $_sig "$_url_base/SHA256.sig" \
  1432. 2>/dev/null
  1433. ;;
  1434. esac
  1435. fi
  1436. # Verify SHA256.sig, write SHA256 and extract the list of files.
  1437. if unpriv -f $_sha \
  1438. signify -Vep $PUB_KEY -x $_sig -m $_sha >/dev/null 2>&1; then
  1439. _file_list="$(sed -n 's/^SHA256 (\(.*\)).*$/\1/p' $_sha)"
  1440. _file_list="SHA256.sig $_file_list"
  1441. else
  1442. echo "Unable to get a verified list of distribution sets."
  1443. # Deny this server, if it's a mirror without a valid SHA256.sig.
  1444. if [[ ${_url_base%/$HTTP_SETDIR} == "$INSTALL_MIRROR" ]]; then
  1445. $AUTO && exit 1 || return
  1446. fi
  1447. fi
  1448. # Fetch index.txt, extract file list but add only entries that are not
  1449. # already in _file_list. This allows for a verified list of distribution
  1450. # sets from SHA256.sig, siteXX sets or the whole set list from index.txt
  1451. # if SHA256.sig was not found (e.g. self compiled sets).
  1452. if unpriv -f $_idx \
  1453. ftp -VMo $_idx "$_url_base/index.txt" 2>/dev/null; then
  1454. _flist=$(sed -En 's/^.* ([a-zA-Z][a-zA-Z0-9._-]+)$/\1/p' $_idx)
  1455. for _f in $_flist; do
  1456. ! isin "$_f" $_file_list && _file_list="$_file_list $_f"
  1457. done
  1458. fi
  1459. rm -f $_idx $_sha $_sig
  1460. install_files "$_url_base" "$_file_list"
  1461. # Remember the sets location which is used later for creating the
  1462. # installurl(5) file and to tell the cgi server.
  1463. if [[ -n $INSTALL_MIRROR ]]; then
  1464. INSTALL_URL=$_http_proto://$INSTALL_MIRROR
  1465. else
  1466. # Remove the architecture and snaphots or version part.
  1467. INSTALL_URL=${_url_base%/$ARCH}
  1468. INSTALL_URL=${INSTALL_URL%@(/$VERSION|/snapshots)}
  1469. fi
  1470. }
  1471. # Ask for the path to the set files on an already mounted filesystem and start
  1472. # the set installation.
  1473. install_mounted_fs() {
  1474. local _dir
  1475. while :; do
  1476. ask_until "Pathname to the sets? (or 'done')" "$SETDIR"
  1477. [[ $resp == done ]] && return
  1478. # Accept a valid /mnt2 or /mnt relative path.
  1479. [[ -d /mnt2/$resp ]] && { _dir=/mnt2/$resp; break; }
  1480. [[ -d /mnt/$resp ]] && { _dir=/mnt/$resp; break; }
  1481. # Accept a valid absolute path.
  1482. [[ -d /$resp ]] && { _dir=/$resp; break; }
  1483. echo "The directory '$resp' does not exist."
  1484. $AUTO && exit 1
  1485. done
  1486. install_files "file://$_dir" "$(ls $_dir/)"
  1487. }
  1488. # Install sets from CD-ROM drive $1.
  1489. install_cdrom() {
  1490. local _drive=$1
  1491. make_dev $_drive && mount_mnt2 $_drive || return
  1492. install_mounted_fs
  1493. }
  1494. # Install sets from disk.
  1495. # Ask for the disk device containing the set files.
  1496. install_disk() {
  1497. if ! ask_yn "Is the disk partition already mounted?"; then
  1498. ask_which "disk" "contains the $MODE media" \
  1499. '$(bsort $(get_dkdevs))' \
  1500. '$(bsort $(rmel $ROOTDISK $(get_dkdevs)))'
  1501. [[ $resp == done ]] && return 1
  1502. # Ensure the device file exists and mount the fs on /mnt2.
  1503. make_dev $resp && mount_mnt2 $resp || return
  1504. fi
  1505. install_mounted_fs
  1506. }
  1507. # Ask for the nfs share details, mount it and start the set installation.
  1508. install_nfs() {
  1509. local _tcp
  1510. # Get the IP address of the server.
  1511. ask_until "Server IP address or hostname?" "$NFS_ADDR"
  1512. NFS_ADDR=$resp
  1513. # Get the server path to mount.
  1514. ask_until "Filesystem on server to mount?" "$NFS_PATH"
  1515. NFS_PATH=$resp
  1516. # Determine use of TCP.
  1517. ask_yn "Use TCP transport? (requires TCP-capable NFS server)" && _tcp=-T
  1518. # Mount the server.
  1519. mount_nfs $_tcp -o ro -R 5 $NFS_ADDR:$NFS_PATH /mnt2 || return
  1520. install_mounted_fs
  1521. }
  1522. # Mount filesystem containing the set files on device $1, optionally ask the
  1523. # user for the device name.
  1524. mount_mnt2() {
  1525. local _dev=$1 _opts _file=/tmp/i/parts.$1 _parts
  1526. disklabel $_dev 2>/dev/null |
  1527. sed -En '/swap|unused/d;/^ [a-p]: /p' >$_file
  1528. _parts=$(sed 's/^ \(.\): .*/\1/' $_file)
  1529. set -- $_parts
  1530. (($# == 0)) && { echo "No filesystems found on $_dev."; return 1; }
  1531. if isin "c" $_parts; then
  1532. # Don't ask questions if 'c' contains a filesystem.
  1533. resp=c
  1534. elif (($# == 1)); then
  1535. # Don't ask questions if there's only one choice.
  1536. resp=$1
  1537. else
  1538. # Display partitions with filesystems and ask which to use.
  1539. cat $_file
  1540. ask_which "$_dev partition" "has the $MODE sets" \
  1541. '$(disklabel '$_dev' 2>/dev/null |
  1542. sed -En '\''/swap|unused/d;/^ ([a-p]): .*/s//\1/p'\'')'
  1543. [[ $resp == done ]] && return 1
  1544. fi
  1545. # Always mount msdos partitions with -s to get lower case names.
  1546. grep -q "^ $resp: .*MSDOS" $_file && _opts="-s"
  1547. mount -o ro,$_opts /dev/$_dev$resp /mnt2
  1548. }
  1549. # ------------------------------------------------------------------------------
  1550. # Functions used in install.sh/upgrade.sh and it's associates
  1551. # ------------------------------------------------------------------------------
  1552. # Ask for terminal type if on console, otherwise ask for/set keyboard layout.
  1553. set_term() {
  1554. local _layouts
  1555. export TERM=${TERM:-${MDTERM:-vt220}}
  1556. if [[ -n $CONSOLE ]]; then
  1557. ask "Terminal type?" $TERM
  1558. TERM=$resp
  1559. else
  1560. [[ -x /sbin/kbd ]] || return
  1561. _layouts=$(bsort $(kbd -l | egrep -v "^(user|tables|encoding)"))
  1562. while :; do
  1563. ask "Choose your keyboard layout ('?' or 'L' for list)" default
  1564. case $resp in
  1565. [lL\?]) echo "Available layouts: $_layouts"
  1566. ;;
  1567. default) break
  1568. ;;
  1569. *) if kbd -q "$resp"; then
  1570. echo $resp >/tmp/i/kbdtype
  1571. break
  1572. fi
  1573. ;;
  1574. esac
  1575. done
  1576. fi
  1577. }
  1578. # Configure the network.
  1579. donetconfig() {
  1580. local _dn _ns _f1 _f2 _f3
  1581. configure_ifs
  1582. v4_defroute
  1583. # As dhclient will populate /etc/resolv.conf, a symbolic link to
  1584. # /tmp/i/resolv.conf.shadow, mv any such file to /tmp/i/resolv.conf
  1585. # so it will eventually be copied to /mnt/etc/resolv.conf and will
  1586. # not in the meantime remove the user's ability to choose to use it
  1587. # or not, during the rest of the install.
  1588. if [[ -f /tmp/i/resolv.conf.shadow ]]; then
  1589. mv /tmp/i/resolv.conf.shadow /tmp/i/resolv.conf
  1590. # Get/store nameserver address(es) as a blank separated list
  1591. # and the default fully qualified domain name from *first*
  1592. # domain given on *last* search or domain statement.
  1593. while read -r -- _f1 _f2 _f3; do
  1594. [[ $_f1 == nameserver ]] && _ns="${_ns:+$_ns }$_f2"
  1595. [[ $_f1 == @(domain|search) ]] && _dn=$_f2
  1596. done </tmp/i/resolv.conf
  1597. fi
  1598. # Get & apply fqdn to hostname. Don't ask if there's only one configured
  1599. # interface and if it's managed by dhclient and if the domain name is
  1600. # configured via dhclient too.
  1601. resp="${_dn:-$(get_fqdn)}"
  1602. if ifconfig dhcp >/dev/null 2>&1 && [[ $NIFS == 1 && -n $_dn ]]; then
  1603. echo "Using DNS domainname $resp"
  1604. else
  1605. ask "DNS domain name? (e.g. 'bar.com')" "$resp"
  1606. fi
  1607. hostname "$(hostname -s).$resp"
  1608. # Get & add nameservers to /tmp/i/resolv.conf. Don't ask if there's only
  1609. # one configured interface and if it's managed by dhclient and if the
  1610. # nameserver is configured via dhclient too.
  1611. resp="${_ns:-none}"
  1612. if ifconfig dhcp >/dev/null 2>&1 && [[ $NIFS == 1 && -n $_ns ]]; then
  1613. echo "Using DNS nameservers at $resp"
  1614. else
  1615. ask "DNS nameservers? (IP address list or 'none')" "$resp"
  1616. fi
  1617. # Construct appropriate resolv.conf.
  1618. if [[ $resp != none ]]; then
  1619. echo "lookup file bind" >/tmp/i/resolv.conf
  1620. for _ns in $resp; do
  1621. echo "nameserver $_ns" >>/tmp/i/resolv.conf
  1622. done
  1623. cp /tmp/i/resolv.conf /tmp/i/resolv.conf.shadow
  1624. fi
  1625. }
  1626. # Ask user about daemon startup on boot, X Window usage and console setup.
  1627. # The actual configuration is done later in apply().
  1628. questions() {
  1629. local _d _cdef=no
  1630. ask_yn "Start sshd(8) by default?" yes
  1631. START_SSHD=$resp
  1632. APERTURE=
  1633. resp=
  1634. START_XDM=
  1635. if [[ -n $DISPLAY ]]; then
  1636. if [[ -n $(scan_dmesg '/^[a-z]*[01]: aperture needed/p') ]]; then
  1637. ask_yn "Do you expect to run the X Window System?" yes &&
  1638. APERTURE=$MDXAPERTURE
  1639. fi
  1640. if [[ -n $MDXDM && $resp != n ]]; then
  1641. ask_yn "Do you want the X Window System to be started by xenodm(1)?"
  1642. START_XDM=$resp
  1643. fi
  1644. fi
  1645. if [[ -n $CDEV ]]; then
  1646. _d=${CPROM:-$CDEV}
  1647. [[ -n $CONSOLE ]] && _cdef=yes
  1648. ask_yn "Change the default console to $_d?" $_cdef
  1649. DEFCONS=$resp
  1650. if [[ $resp == y ]]; then
  1651. ask_which "speed" "should $_d use" \
  1652. "9600 19200 38400 57600 115200" $CSPEED
  1653. case $resp in
  1654. done) DEFCONS=n;;
  1655. *) CSPEED=$resp;;
  1656. esac
  1657. fi
  1658. fi
  1659. }
  1660. # Gather information for setting up the user later in do_install().
  1661. user_setup() {
  1662. local _q="Setup a user? (enter a lower-case loginname, or 'no')"
  1663. while :; do
  1664. ask "$_q" no
  1665. case $resp in
  1666. n|no) return
  1667. ;;
  1668. y|yes) _q="No really, what is the lower-case loginname, or 'no'?"
  1669. continue
  1670. ;;
  1671. root|daemon|operator|bin|sshd|www|nobody|ftp)
  1672. ;;
  1673. [a-z]*([a-z0-9_]))
  1674. ((${#resp} <= 31)) && break
  1675. ;;
  1676. esac
  1677. echo "$resp is not a useable loginname."
  1678. done
  1679. ADMIN=$resp
  1680. while :; do
  1681. ask "Full name for user $ADMIN?" $ADMIN
  1682. case $resp in
  1683. *[:\&,]*)
  1684. echo "':', '&' or ',' are not allowed."
  1685. ;;
  1686. *)
  1687. ((${#resp} <= 100)) && break
  1688. echo "Too long."
  1689. ;;
  1690. esac
  1691. done
  1692. ADMIN_NAME=$resp
  1693. ask_password "Password for user $ADMIN?"
  1694. ADMIN_PASS=$_password
  1695. ADMIN_KEY=
  1696. $AUTO && ask "Public ssh key for user $ADMIN" none &&
  1697. [[ $resp != none ]] && ADMIN_KEY=$resp
  1698. }
  1699. # Ask user whether or not to allow logins to root in case sshd(8) is enabled.
  1700. # If no user is setup, show a hint to enable root logins, but warn about risks
  1701. # of doing so.
  1702. ask_root_sshd() {
  1703. typeset -l _resp
  1704. [[ $START_SSHD == y ]] || return
  1705. if [[ -z $ADMIN ]]; then
  1706. echo "Since no user was setup, root logins via sshd(8) might be useful."
  1707. fi
  1708. echo "WARNING: root is targeted by password guessing attacks, pubkeys are safer."
  1709. while :; do
  1710. ask "Allow root ssh login? (yes, no, prohibit-password)" no
  1711. _resp=$resp
  1712. case $_resp in
  1713. y|yes) SSHD_ENABLEROOT=yes
  1714. ;;
  1715. n|no) SSHD_ENABLEROOT=no
  1716. ;;
  1717. w|p|without-password|prohibit-password)
  1718. SSHD_ENABLEROOT=prohibit-password
  1719. ;;
  1720. *) echo "'$resp' is not a valid choice."
  1721. $AUTO && exit 1
  1722. continue
  1723. ;;
  1724. esac
  1725. break
  1726. done
  1727. }
  1728. # Set TZ variable based on zonefile $1 and user selection.
  1729. set_timezone() {
  1730. local _zonefile=$1 _zonepath _zsed _zoneroot=/usr/share/zoneinfo
  1731. # If the timezone file is not available,
  1732. # return immediately.
  1733. [[ ! -f $_zonefile ]] && return
  1734. # If configured in a previous call, return immediately.
  1735. [[ -n $TZ ]] && return
  1736. if [[ -h /mnt/etc/localtime ]]; then
  1737. TZ=$(ls -l /mnt/etc/localtime 2>/dev/null)
  1738. TZ=${TZ#*${_zoneroot#/mnt}/}
  1739. fi
  1740. wait_cgiinfo
  1741. isin "$CGI_TZ" $(<$_zonefile) && TZ=$CGI_TZ
  1742. # If neither the base or HTTP_LIST gave a hint, and this is the
  1743. # early question, give up, and ask after the sets are installed.
  1744. [[ $_zonefile == /var/tzlist && -z $TZ ]] && return
  1745. while :; do
  1746. ask "What timezone are you in? ('?' for list)" "$TZ"
  1747. _zonepath=${resp%%*(/)}
  1748. case $_zonepath in
  1749. "") continue
  1750. ;;
  1751. "?") grep -v /. $_zonefile | show_cols
  1752. continue
  1753. ;;
  1754. esac
  1755. while isin "$_zonepath/" $(<$_zonefile); do
  1756. ask "What sub-timezone of '$_zonepath' are you in? ('?' for list)"
  1757. _zsed=$(echo $_zonepath/ | sed 's,/,\\/,g')
  1758. resp=${resp%%*(/)}
  1759. case $resp in
  1760. "") ;;
  1761. "?") sed -n "/^$_zsed/{s/$_zsed//;/\/./!p;}" $_zonefile | show_cols;;
  1762. *) _zonepath=$_zonepath/$resp;;
  1763. esac
  1764. done
  1765. if isin "$_zonepath" $(<$_zonefile); then
  1766. TZ=${_zonepath#$_zoneroot}
  1767. return
  1768. fi
  1769. echo -n "'${_zonepath}'"
  1770. echo " is not a valid timezone on this system."
  1771. done
  1772. }
  1773. # Determine if the supplied disk is a potential root disk, by:
  1774. # - Check the disklabel if there is an 'a' partition of type 4.2BSD
  1775. # - Mount the partition (read-only) and look for typical root filesystem layout
  1776. is_rootdisk() {
  1777. local _d=$1 _rc=1
  1778. (
  1779. make_dev $_d
  1780. if disklabel $_d | grep -q '^ a: .*4\.2BSD ' &&
  1781. mount -t ffs -r /dev/${_d}a /mnt; then
  1782. ls -d /mnt/{bin,dev,etc,home,mnt,root,sbin,tmp,usr,var}
  1783. _rc=$?
  1784. umount -f /mnt
  1785. fi
  1786. rm -f /dev/{r,}$_d?
  1787. return $_rc
  1788. ) >/dev/null 2>&1
  1789. }
  1790. # Get global root information. ie. ROOTDISK, ROOTDEV and SWAPDEV.
  1791. get_rootinfo() {
  1792. local _default=$(get_dkdevs)
  1793. local _q="Which disk is the root disk? ('?' for details)"
  1794. while :; do
  1795. echo "Available disks are: $(get_dkdevs | sed 's/^$/none/')."
  1796. _ask "$_q" $_default || continue
  1797. case $resp in
  1798. "?") diskinfo $(get_dkdevs);;
  1799. '') ;;
  1800. *) if isin "$resp" $(get_dkdevs); then
  1801. [[ $MODE == install ]] && break
  1802. is_rootdisk "$resp" && break
  1803. echo "$resp is not a valid root disk."
  1804. _default="$(rmel "$resp" $_default) $resp"
  1805. else
  1806. echo "no such disk"
  1807. fi
  1808. ;;
  1809. esac
  1810. $AUTO && exit 1
  1811. done
  1812. log_answers "$_q" "$resp"
  1813. make_dev $resp || exit
  1814. ROOTDISK=$resp
  1815. ROOTDEV=${ROOTDISK}a
  1816. SWAPDEV=${ROOTDISK}b
  1817. }
  1818. # Start interface using the on-disk hostname.if file passed as argument $1.
  1819. # Much of this is gratuitously stolen from /etc/netstart.
  1820. ifstart () {
  1821. # Note: Do not rename the 'if' variable which is documented as being
  1822. # usable in hostname.if(5) files.
  1823. local _hn=$1 if=${1#/mnt/etc/hostname.}
  1824. ((NIFS++))
  1825. while :; do
  1826. if [ "$cmd2" ]; then
  1827. # We are carrying over from the 'read dt dtaddr'
  1828. # last time.
  1829. set -- $cmd2
  1830. af=$1 name=$2 mask=$3 bcaddr=$4 ext1=$5 cmd2=
  1831. # Make sure and get any remaining args in ext2,
  1832. # like the read below.
  1833. i=1
  1834. while [ $i -lt 6 -a -n "$1" ]; do shift; let i=i+1; done
  1835. ext2="$@"
  1836. else
  1837. # Read the next line or exit the while loop.
  1838. read af name mask bcaddr ext1 ext2 || break
  1839. fi
  1840. # $af can be "dhcp", "up", "rtsol", an address family, commands,
  1841. # or a comment.
  1842. case "$af" in
  1843. "#"*|"!"*|"bridge"|"")
  1844. # Skip comments, user commands, bridges, and empty lines.
  1845. continue
  1846. ;;
  1847. "dhcp")
  1848. [ "$name" = "NONE" ] && name=
  1849. [ "$mask" = "NONE" ] && mask=
  1850. [ "$bcaddr" = "NONE" ] && bcaddr=
  1851. cmd="ifconfig $if $name $mask $bcaddr $ext1 $ext2 down"
  1852. if [[ -x /sbin/dhclient ]]; then
  1853. cmd="$cmd; dhclient $if"
  1854. else
  1855. cmd="$cmd; echo /sbin/dhclient missing - skipping dhcp request."
  1856. fi
  1857. dhcpif="$dhcpif $if"
  1858. ;;
  1859. "rtsol")
  1860. if ifconfig $if inet6 >/dev/null 2>&1; then
  1861. rtsolif="$rtsolif $if"
  1862. cmd="ifconfig $if $name $mask $bcaddr $ext1 $ext2 up"
  1863. else
  1864. cmd="$cmd; echo no INET6 support - skipping rtsol request."
  1865. fi
  1866. ;;
  1867. *)
  1868. read dt dtaddr
  1869. if [ "$name" = "alias" ]; then
  1870. # Perform a 'shift' of sorts.
  1871. alias=$name
  1872. name=$mask
  1873. mask=$bcaddr
  1874. bcaddr=$ext1
  1875. ext1=$ext2
  1876. ext2=
  1877. else
  1878. alias=
  1879. fi
  1880. cmd="ifconfig $if $af $alias $name"
  1881. case "$dt" in
  1882. dest)
  1883. cmd="$cmd $dtaddr"
  1884. ;;
  1885. *)
  1886. cmd2="$dt $dtaddr"
  1887. ;;
  1888. esac
  1889. case $af in
  1890. inet)
  1891. if [ ! -n "$name" ]; then
  1892. echo "/etc/hostname.$if: inet alone is invalid"
  1893. return
  1894. fi
  1895. [ "$mask" ] && cmd="$cmd netmask $mask"
  1896. if [ "$bcaddr" -a "X$bcaddr" != "XNONE" ]; then
  1897. cmd="$cmd broadcast $bcaddr"
  1898. fi
  1899. ;;
  1900. inet6)
  1901. if [ ! -n "$name" ]; then
  1902. echo "/etc/hostname.$if: inet6 alone is invalid"
  1903. return
  1904. fi
  1905. [ "$mask" ] && cmd="$cmd prefixlen $mask"
  1906. cmd="$cmd $bcaddr"
  1907. ;;
  1908. *)
  1909. cmd="$cmd $mask $bcaddr"
  1910. ;;
  1911. esac
  1912. cmd="$cmd $ext1 $ext2"
  1913. ;;
  1914. esac
  1915. eval "$cmd"
  1916. done <$_hn
  1917. }
  1918. # Configure the network during upgrade based on the on-disk configuration.
  1919. enable_network() {
  1920. local _f _gw _hn _if _trunks _svlans _vlans
  1921. # Copy any network configuration files.
  1922. for _f in dhclient.conf resolv.conf resolv.conf.tail; do
  1923. if [[ -f /mnt/etc/$_f ]]; then
  1924. cp /mnt/etc/$_f /etc/$_f
  1925. fi
  1926. done
  1927. # Create a minimal hosts file.
  1928. echo "127.0.0.1\tlocalhost" >/tmp/i/hosts
  1929. echo "::1\t\tlocalhost" >>/tmp/i/hosts
  1930. # Set the address for the loopback interface. Bringing the
  1931. # interface up, automatically invokes the IPv6 address ::1.
  1932. ifconfig lo0 inet 127.0.0.1/8
  1933. # Configure all of the non-loopback interfaces which we know about.
  1934. # Refer to hostname.if(5)
  1935. for _hn in /mnt/etc/hostname.*; do
  1936. # Strip off prefix to get interface name.
  1937. _if=${_hn#/mnt/etc/hostname.}
  1938. if isin "${_if%%+([0-9])}" $(ifconfig -C); then
  1939. # Dynamic interfaces must be done later.
  1940. case ${_if%%+([0-9])} in
  1941. trunk) _trunks="$_trunks $_hn";;
  1942. svlan) _svlans="$_svlans $_hn";;
  1943. vlan) _vlans="$_vlans $_hn";;
  1944. esac
  1945. else
  1946. # 'Real' interfaces (if available) are done now.
  1947. ifconfig $_if >/dev/null 2>&1 && ifstart $_hn
  1948. fi
  1949. done
  1950. # Configure any dynamic interfaces now that 'real' ones are up.
  1951. # ORDER IS IMPORTANT! (see /etc/netstart).
  1952. for _hn in $_trunks $_svlans $_vlans; do
  1953. ifstart $_hn
  1954. done
  1955. [[ -n $rtsolif ]] && ifconfig $rtsolif inet6 autoconf
  1956. # /mnt/etc/mygate, if it exists, contains the address(es) of my
  1957. # default gateway(s). Use for ipv4 if no interfaces configured via
  1958. # dhcp. Use for ipv6 if no interfaces configured via rtsol.
  1959. [[ -z $dhcpif ]] && stripcom /mnt/etc/mygate | while read _gw; do
  1960. [[ $_gw == @(*:*) ]] && continue
  1961. route -qn delete default >/dev/null 2>&1
  1962. route -qn add -host default $_gw && break
  1963. done
  1964. [[ -z $rtsolif ]] && stripcom /mnt/etc/mygate | while read _gw; do
  1965. [[ $_gw == !(*:*) ]] && continue
  1966. route -qn delete -inet6 default >/dev/null 2>&1
  1967. route -qn add -host -inet6 default $_gw && break
  1968. done
  1969. route -qn add -net 127 127.0.0.1 -reject >/dev/null
  1970. }
  1971. # Fetch the list of mirror servers and installer choices from previous runs if
  1972. # available from ftplist.cgi. Start the ftp process in the background, but kill
  1973. # it if it takes longer than 12 seconds.
  1974. start_cgiinfo() {
  1975. # If no networks are configured, we do not need the httplist file.
  1976. ((NIFS < 1)) && return
  1977. ftp -MVo /tmp/mirrors http://libertybsd.net/mirrors/6.1 2> /dev/null
  1978. HTTP_LIST=/tmp/mirrors
  1979. # Ensure proper name resolution in case there's no dns yet.
  1980. add_hostent 47.186.116.162 libertybsd.net
  1981. }
  1982. # Create a skeletal but useful /etc/fstab from /tmp/i/fstab by stripping all
  1983. # comment lines and dropping all filesystems which
  1984. #
  1985. # 1) can't be mounted (no mount_* command is found),
  1986. # 2) have 'xx' in the option field (usually /altroot),
  1987. # 3) have 'noauto' in the option field,
  1988. # 4) are nfs (since name resolution may not be present),
  1989. # 5) are on a vnd device.
  1990. #
  1991. # In addition,
  1992. #
  1993. # 1) delete 'softdep' options (no soft updates in ramdisk kernels),
  1994. # 2) mount non-ffs filesystems read only,
  1995. # 3) prepend '/mnt' to all mount points,
  1996. # 4) delete any trailing '/' from the mount point (e.g. root),
  1997. #
  1998. # If no /etc/fstab is created, do not proceed with install/upgrade.
  1999. munge_fstab() {
  2000. local _dev _mp _fstype _opt _rest
  2001. while read _dev _mp _fstype _opt _rest; do
  2002. # Drop irrelevant lines and filesystems.
  2003. [[ $_dev == @(/dev/vnd*|\#*) ||
  2004. $_fstype == nfs ||
  2005. ! -f /sbin/mount_$_fstype ||
  2006. $_opt == *noauto* ||
  2007. $_opt == *xx* ]] && continue
  2008. # Remove any softdep options, as soft updates are not
  2009. # available in the ramdisk kernels.
  2010. _opt=$(echo $_opt | sed 's/softdep//')
  2011. # Change read-only ffs to read-write since we'll potentially
  2012. # write to these filesystems.
  2013. # Mount non-ffs filesystems read only.
  2014. if [[ $_fstype == ffs ]]; then
  2015. _opt=$(echo $_opt | sed 's/[[:<:]]ro[[:>:]]/rw/')
  2016. else
  2017. _opt=$(echo $_opt | sed 's/[[:<:]]rw[[:>:]]/ro/')
  2018. fi
  2019. # Write fs entry in fstab.
  2020. # 1) prepend '/mnt' to the mount point.
  2021. # 2) remove a trailing '/' from the mount point (e.g. root).
  2022. echo $_dev /mnt${_mp%/} $_fstype $_opt $_rest
  2023. done </tmp/i/fstab >/etc/fstab
  2024. # If no /etc/fstab was created, we have nowhere to $MODE to.
  2025. if [[ ! -s /etc/fstab ]]; then
  2026. echo "Unable to create valid /etc/fstab."
  2027. exit
  2028. fi
  2029. }
  2030. # Preen all filesystems in /etc/fstab that have a /sbin/fsck_XXX and a
  2031. # fs_passno > 0, showing individual results, but skipping $ROOTDEV. This was
  2032. # already fsck'ed successfully.
  2033. #
  2034. # Exit if any fsck's fail (but do them all before exiting!).
  2035. check_fs() {
  2036. local _dev _dn _mp _fstype _rest _fail _f _passno
  2037. ask_yn "Force checking of clean non-root filesystems?" && _f=f
  2038. while read _dev _mp _fstype _rest _rest _passno _rest; do
  2039. _dn=$(get_dkdev_name "$_dev")
  2040. [[ $ROOTDEV == @(${_dev#/dev/}|$_dn${_dev##*.}) ]] && continue
  2041. [[ -f /sbin/fsck_$_fstype ]] || continue
  2042. # Make sure device exists before fsck'ing it.
  2043. make_dev "$_dn" || continue
  2044. ((_passno > 0)) || continue
  2045. echo -n "fsck -${_f}p $_dev..."
  2046. if ! fsck -${_f}p $_dev >/dev/null 2>&1; then
  2047. echo "FAILED. You must fsck $_dev manually."
  2048. _fail=y
  2049. else
  2050. echo "OK."
  2051. fi
  2052. done </etc/fstab
  2053. [[ -n $_fail ]] && exit
  2054. }
  2055. # Must mount filesystems manually, one at a time, so we can make sure the mount
  2056. # points exist.
  2057. mount_fs() {
  2058. local _async=$1 _dev _mp _fstype _opt _rest _msg _fail
  2059. while read _dev _mp _fstype _opt _rest; do
  2060. # If not the root filesystem, make sure the mount
  2061. # point is present.
  2062. [[ $_mp == /mnt ]] || mkdir -p $_mp
  2063. # Mount the filesystem. Remember any failure.
  2064. _msg=$(mount -v -t $_fstype $_async -o $_opt $_dev $_mp) ||
  2065. _fail="$_fail\n$_mp ($_dev)"
  2066. echo $_msg | sed 's/, ctime=[^,)]*//'
  2067. done </etc/fstab
  2068. if [[ -n $_fail ]]; then
  2069. # One or more mounts failed. Continue or abort?
  2070. echo "\nWARNING! The following filesystems were not properly mounted:$_fail"
  2071. ask_yn "Continue anyway?" || exit
  2072. fi
  2073. }
  2074. # Feed the random pool some entropy before we read from it.
  2075. feed_random() {
  2076. (dmesg; cat $CGI_INFO /*.conf; sysctl; route -n show; df;
  2077. ifconfig -A; hostname) >/dev/random 2>&1
  2078. if [[ -e /mnt/var/db/host.random ]]; then
  2079. dd if=/mnt/var/db/host.random of=/dev/random bs=65536 count=1 \
  2080. status=none
  2081. fi
  2082. }
  2083. # Ask the user for locations of sets, and then install whatever sets the user
  2084. # selects from that location. Repeat as many times as the user needs to get all
  2085. # desired sets.
  2086. install_sets() {
  2087. local _cddevs=$(get_cddevs) _d _im _locs="disk http" _src
  2088. echo
  2089. # Set default location to method recorded last time.
  2090. _d=$CGI_METHOD
  2091. # Set default location to HTTP in case we netbooted.
  2092. ifconfig netboot >/dev/null 2>&1 && : ${_d:=http}
  2093. # Set default location to HTTP if installurl(5) exists.
  2094. [[ -s /mnt/etc/installurl ]] && _d=http
  2095. # Set default location to the first cdrom device if any are found.
  2096. [[ -n $_cddevs ]] && : ${_d:=cd0}
  2097. # Add NFS to set locations if the boot kernel supports it.
  2098. [[ -x /sbin/mount_nfs ]] && _locs="$_locs nfs"
  2099. # In case none of the above applied, set HTTP as default location.
  2100. : ${_d:=http}
  2101. # If the default location set so far is not one of the cdrom devices or
  2102. # is not in the list of valid locations, set a sane default.
  2103. if ! isin "$_d" $_cddevs $_locs; then
  2104. for _src in http $_cddevs nfs disk; do
  2105. isin "$_src" $_cddevs $_locs && _d=$_src && break
  2106. done
  2107. fi
  2108. echo "Let's $MODE the sets!"
  2109. while :; do
  2110. # Get list of cdroms again in case one just got plugged in.
  2111. _cddevs=$(get_cddevs)
  2112. umount -f /mnt2 >/dev/null 2>&1
  2113. ask "Location of sets? (${_cddevs:+$_cddevs }$_locs or 'done')" "$_d"
  2114. case $resp in
  2115. done) sane_install && return
  2116. ;;
  2117. [cC]*) if [[ -n $_cddevs ]]; then
  2118. set -- $_cddevs
  2119. [[ $resp == [cC]?([dD]) ]] && resp=$1
  2120. _im=$resp
  2121. install_cdrom $resp && INSTALL_METHOD=$_im
  2122. fi
  2123. ;;
  2124. [dD]*) install_disk && INSTALL_METHOD=disk
  2125. ;;
  2126. [hH]*) isin http $_locs && install_http && INSTALL_METHOD=http
  2127. ;;
  2128. [nN]*) isin nfs $_locs && install_nfs && INSTALL_METHOD=nfs
  2129. ;;
  2130. *) $AUTO && echo "'$resp' is not a valid choice." && exit 1
  2131. ;;
  2132. esac
  2133. # Preserve the selected install source selection.
  2134. [[ -n $INSTALL_METHOD ]] && _d=$INSTALL_METHOD
  2135. # Set default to 'done' to leave the while-loop.
  2136. sane_install quiet || $AUTO && _d=done
  2137. done
  2138. }
  2139. # Apply configuration settings based on the previously gathered information.
  2140. apply() {
  2141. if [[ $START_SSHD == n ]]; then
  2142. echo "sshd_flags=NO" >>/mnt/etc/rc.conf.local
  2143. elif [[ -n $SSHD_ENABLEROOT ]]; then
  2144. # Only change sshd_config if the user choice is not the default.
  2145. if ! grep -q "^#PermitRootLogin $SSHD_ENABLEROOT\$" \
  2146. /mnt/etc/ssh/sshd_config; then
  2147. sed -i "s/^#\(PermitRootLogin\) .*/\1 $SSHD_ENABLEROOT/" \
  2148. /mnt/etc/ssh/sshd_config
  2149. fi
  2150. fi
  2151. [[ -n $APERTURE ]] &&
  2152. echo "machdep.allowaperture=$APERTURE # See xf86(4)" \
  2153. >>/mnt/etc/sysctl.conf
  2154. [[ $START_XDM == y && -x /mnt/usr/X11R6/bin/xenodm ]] &&
  2155. echo "xenodm_flags=" >>/mnt/etc/rc.conf.local
  2156. if [[ $DEFCONS == y ]]; then
  2157. cp /mnt/etc/ttys /tmp/i/ttys
  2158. sed -e "/^$CTTY/s/std.9600/std.${CSPEED}/" \
  2159. -e "/^$CTTY/s/unknown/vt220 /" \
  2160. -e "/$CTTY/s/off.*/on secure/" /tmp/i/ttys >/mnt/etc/ttys
  2161. [[ -n $CPROM ]] &&
  2162. echo "stty $CPROM $CSPEED\nset tty $CPROM" \
  2163. >>/mnt/etc/boot.conf
  2164. fi
  2165. ln -sf /usr/share/zoneinfo/$TZ /mnt/etc/localtime
  2166. }
  2167. # Return string suitable for the encrypted password field in master.passwd.
  2168. #
  2169. # 1) Without argument, return a single '*'.
  2170. # 2) Return argument unchanged if it looks like a encrypted password string
  2171. # or if it consists of just 13 asterisks.
  2172. # 3) Otherwise return encrypted password string.
  2173. #
  2174. encr_pwd() {
  2175. local _p=$1
  2176. if [[ -z $_p ]]; then
  2177. echo '*'
  2178. elif [[ $_p == \$2?\$[0-9][0-9]\$* && ${#_p} > 40 ||
  2179. $_p == '*************' ]]; then
  2180. echo "$_p"
  2181. else
  2182. encrypt -b a -- "$_p"
  2183. fi
  2184. }
  2185. # Store entropy for the next boot.
  2186. store_random() {
  2187. dd if=/dev/random of=/mnt/var/db/host.random bs=65536 count=1 \
  2188. status=none
  2189. dd if=/dev/random of=/mnt/etc/random.seed bs=512 count=1 status=none
  2190. chmod 600 /mnt/var/db/host.random /mnt/etc/random.seed
  2191. }
  2192. # Final steps common for installs and upgrades.
  2193. finish_up() {
  2194. local _dev _mp _fstype _rest _d
  2195. # Mount all known swap partitions. This gives systems with little
  2196. # memory a better chance at running 'MAKEDEV all'.
  2197. if [[ -x /mnt/sbin/swapctl ]]; then
  2198. /mnt/sbin/swapctl -a /dev/$SWAPDEV >/dev/null 2>&1
  2199. # Can't do chmod && swapctl -A because devices are not yet
  2200. # created on install'ed systems. On upgrade'ed system there
  2201. # is a small chance the device does not exist on the ramdisk
  2202. # and will thus not get mounted.
  2203. while read _dev _mp _fstype _rest; do
  2204. [[ $_fstype == swap ]] &&
  2205. /mnt/sbin/swapctl -a $_dev >/dev/null 2>&1
  2206. done </mnt/etc/fstab
  2207. fi
  2208. # Create /etc/installurl if it does not yet exist.
  2209. if [[ -n $INSTALL_URL && ! -f /mnt/etc/installurl ]]; then
  2210. echo "$INSTALL_URL" >/mnt/etc/installurl
  2211. fi
  2212. echo -n "Making all device nodes..."
  2213. (cd /mnt/dev; sh MAKEDEV all
  2214. # Make sure any devices we found during probe are created in the
  2215. # installed system.
  2216. for _dev in $(get_dkdevs) $(get_cddevs); do
  2217. sh MAKEDEV $_dev
  2218. done
  2219. )
  2220. echo "done."
  2221. # We may run some programs in chroot, and some of them might be
  2222. # dynamic. That is highly discouraged, but let us play it safe.
  2223. rm -f /mnt/var/run/ld.so.hints
  2224. # Conditionally create /usr/{src,obj,xobj} directories and set
  2225. # proper ownership and permissions during install.
  2226. if [[ $MODE == install ]]; then
  2227. mkdir -p /mnt/usr/{src,{,x}obj} && (
  2228. cd /mnt/usr
  2229. chmod 770 {,x}obj
  2230. chown build:wobj {,x}obj
  2231. chmod 775 src
  2232. chown root:wsrc src
  2233. )
  2234. fi
  2235. [[ -x /mnt/$MODE.site ]] && chroot /mnt /$MODE.site
  2236. # In case this is a softraid device, make sure all underlying
  2237. # device nodes exist before installing boot-blocks on disk.
  2238. make_dev $(bioctl $ROOTDISK 2>/dev/null | sed -n 's/.*<\(.*\)>$/\1/p')
  2239. md_installboot $ROOTDISK
  2240. if [[ -f /mnt/bsd.mp ]] && ((NCPU > 1)); then
  2241. echo "Multiprocessor machine; using bsd.mp instead of bsd."
  2242. mv /mnt/bsd /mnt/bsd.sp 2>/dev/null
  2243. mv /mnt/bsd.mp /mnt/bsd
  2244. fi
  2245. # Ensure that sysmerge in batch mode is run on reboot.
  2246. [[ $MODE == upgrade ]] &&
  2247. echo "/usr/sbin/sysmerge -b" >>/mnt/etc/rc.sysmerge
  2248. # Ensure that fw_update is run on reboot.
  2249. echo "/usr/sbin/fw_update -v" >>/mnt/etc/rc.firsttime
  2250. # Email installer questions and their answers to root on next boot.
  2251. prep_root_mail /tmp/i/$MODE.resp "$(hostname) $MODE response file"
  2252. # Store entropy for the next boot.
  2253. store_random
  2254. # Pat on the back.
  2255. cat <<__EOT
  2256. CONGRATULATIONS! Your LibertyBSD $MODE has been successfully completed!
  2257. To boot the new system, enter 'reboot' at the command prompt.
  2258. __EOT
  2259. [[ $MODE == install ]] && cat <<__EOT
  2260. When you login to your new system the first time, please read your mail
  2261. using the 'mail' command.
  2262. __EOT
  2263. md_congrats
  2264. $AUTO && >/tmp/ai/ai.done
  2265. }
  2266. do_install(){
  2267. local _rootkey _rootpass
  2268. # Ask for and set the system hostname and add the hostname specific
  2269. # siteXX set.
  2270. while :; do
  2271. ask_until "System hostname? (short form, e.g. 'foo')" \
  2272. "$(hostname -s)"
  2273. [[ $resp != *+([[:cntrl:]]|[[:space:]])* ]] && break
  2274. echo "Invalid hostname."
  2275. $AUTO && exit 1
  2276. done
  2277. [[ ${resp%%.*} != $(hostname -s) ]] && hostname "$resp"
  2278. THESETS="$THESETS site$VERSION-$(hostname -s).tgz"
  2279. echo
  2280. # Configure the network.
  2281. donetconfig
  2282. # If there's network connectivity, fetch list of mirror servers and
  2283. # installer choices from previous runs.
  2284. ((NIFS)) && start_cgiinfo
  2285. echo
  2286. while :; do
  2287. ask_password "Password for root account?"
  2288. _rootpass="$_password"
  2289. [[ -n "$_password" ]] && break
  2290. echo "The root password must be set."
  2291. done
  2292. # Ask for the root user public ssh key during autoinstall.
  2293. _rootkey=
  2294. if $AUTO; then
  2295. ask "Public ssh key for root account?" none
  2296. [[ $resp != none ]] && _rootkey=$resp
  2297. fi
  2298. # Ask user about daemon startup on boot, X Window usage and console
  2299. # setup.
  2300. questions
  2301. # Gather information for setting up the initial user account.
  2302. user_setup
  2303. ask_root_sshd
  2304. # Set TZ variable based on zonefile and user selection.
  2305. set_timezone /var/tzlist
  2306. echo
  2307. # Get information about ROOTDISK, etc.
  2308. get_rootinfo
  2309. DISKS_DONE=
  2310. FSENT=
  2311. # Remove traces of previous install attempt.
  2312. rm -f /tmp/i/fstab*
  2313. # Configure the disk(s).
  2314. while :; do
  2315. # Always do ROOTDISK first, and repeat until it is configured.
  2316. if ! isin "$ROOTDISK" $DISKS_DONE; then
  2317. resp=$ROOTDISK
  2318. rm -f /tmp/i/fstab
  2319. else
  2320. # Force the user to think and type in a disk name by
  2321. # making 'done' the default choice.
  2322. ask_which "disk" "do you wish to initialize" \
  2323. '$(get_dkdevs_uninitialized)' done
  2324. [[ $resp == done ]] && break
  2325. fi
  2326. _disk=$resp
  2327. configure_disk $_disk || continue
  2328. DISKS_DONE=$(addel $_disk $DISKS_DONE)
  2329. done
  2330. # Write fstab entries to fstab in mount point alphabetic order
  2331. # to enforce a rational mount order.
  2332. for _mp in $(bsort $FSENT); do
  2333. _pp=${_mp##*!}
  2334. _mp=${_mp%!*}
  2335. echo -n "$_pp $_mp ffs rw"
  2336. # Only '/' is neither nodev nor nosuid. i.e. it can obviously
  2337. # *always* contain devices or setuid programs.
  2338. [[ $_mp == / ]] && { echo " 1 1"; continue; }
  2339. # Every other mounted filesystem is nodev. If the user chooses
  2340. # to mount /dev as a separate filesystem, then on the user's
  2341. # head be it.
  2342. echo -n ",nodev"
  2343. # The only directories that the install puts suid binaries into
  2344. # (as of 3.2) are:
  2345. #
  2346. # /sbin
  2347. # /usr/bin
  2348. # /usr/sbin
  2349. # /usr/libexec
  2350. # /usr/libexec/auth
  2351. # /usr/X11R6/bin
  2352. #
  2353. # and ports and users can do who knows what to /usr/local and
  2354. # sub directories thereof.
  2355. #
  2356. # So try to ensure that only filesystems that are mounted at
  2357. # or above these directories can contain suid programs. In the
  2358. # case of /usr/libexec, give blanket permission for
  2359. # subdirectories.
  2360. case $_mp in
  2361. /sbin|/usr) ;;
  2362. /usr/bin|/usr/sbin) ;;
  2363. /usr/libexec|/usr/libexec/*) ;;
  2364. /usr/local|/usr/local/*) ;;
  2365. /usr/X11R6|/usr/X11R6/bin) ;;
  2366. *) echo -n ",nosuid" ;;
  2367. esac
  2368. echo " 1 2"
  2369. done >>/tmp/i/fstab
  2370. # Create a skeletal /etc/fstab which is usable for the installation
  2371. # process.
  2372. munge_fstab
  2373. # Use async options for faster mounts of the filesystems.
  2374. mount_fs "-o async"
  2375. # Feed the random pool some entropy before we read from it.
  2376. feed_random
  2377. # Ask the user for locations, and install whatever sets the user
  2378. # selected.
  2379. install_sets
  2380. # Set 'wxallowed' mount option for the filesystem /usr/local resides on.
  2381. _mp=$(df /mnt/usr/local | sed '$!d')
  2382. _mp=${_mp##*/mnt}
  2383. sed -i "s#\(${_mp:-/} ffs rw\)#\1,wxallowed#" /tmp/i/fstab
  2384. # If we did not succeed at setting TZ yet, we try again
  2385. # using the timezone names extracted from the base set.
  2386. if [[ -z $TZ ]]; then
  2387. (cd /mnt/usr/share/zoneinfo
  2388. ls -1dF $(tar cvf /dev/null [A-Za-y]*) >/mnt/tmp/tzlist )
  2389. echo
  2390. set_timezone /mnt/tmp/tzlist
  2391. rm -f /mnt/tmp/tzlist
  2392. fi
  2393. # If we got a timestamp from the cgi server, and that time diffs by more
  2394. # than 120 seconds, ask if the user wants to adjust the time.
  2395. if _time=$(http_time) && _now=$(date +%s) &&
  2396. (( _now - _time > 120 || _time - _now > 120 )); then
  2397. _tz=/mnt/usr/share/zoneinfo/$TZ
  2398. if ask_yn "Time appears wrong. Set to '$(TZ=$_tz date -r "$(http_time)")'?" yes; then
  2399. # We do not need to specify TZ below since both date
  2400. # invocations use the same one.
  2401. date $(date -r "$(http_time)" "+%Y%m%d%H%M.%S") >/dev/null
  2402. # N.B. This will screw up SECONDS.
  2403. fi
  2404. fi
  2405. # Ensure an enabled console has the correct speed in /etc/ttys.
  2406. sed "/^console.*on.*secure.*$/s/std\.[0-9]*/std.$(stty speed </dev/console)/" \
  2407. /mnt/etc/ttys >/tmp/i/ttys
  2408. mv /tmp/i/ttys /mnt/etc/ttys
  2409. echo -n "Saving configuration files..."
  2410. # Save any leases obtained during install.
  2411. (cd /var/db; for _f in dhclient.leases.*; do
  2412. [[ -f $_f ]] && mv $_f /mnt/var/db/.
  2413. done)
  2414. # Move configuration files from /tmp/i/ to /mnt/etc.
  2415. hostname >/tmp/i/myname
  2416. # Append entries to installed hosts file, changing '1.2.3.4 hostname'
  2417. # to '1.2.3.4 hostname.$FQDN hostname'. Leave untouched lines containing
  2418. # domain information or aliases. These are lines the user added/changed
  2419. # manually.
  2420. # Add common entries.
  2421. echo "127.0.0.1\tlocalhost" >/mnt/etc/hosts
  2422. echo "::1\t\tlocalhost" >>/mnt/etc/hosts
  2423. # Note we may have no hosts file if no interfaces were configured.
  2424. if [[ -f /tmp/i/hosts ]]; then
  2425. # Remove the entry for ftp.openbsd.org
  2426. sed -i '/^47\.186\.116\.162 /d' /tmp/i/hosts
  2427. _dn=$(get_fqdn)
  2428. while read _addr _hn _aliases; do
  2429. if [[ -n $_aliases || $_hn != ${_hn%%.*} || -z $_dn ]]; then
  2430. echo "$_addr\t$_hn $_aliases"
  2431. else
  2432. echo "$_addr\t$_hn.$_dn $_hn"
  2433. fi
  2434. done </tmp/i/hosts >>/mnt/etc/hosts
  2435. rm /tmp/i/hosts
  2436. fi
  2437. # Append dhclient.conf to installed dhclient.conf.
  2438. _f=dhclient.conf
  2439. [[ -f /tmp/i/$_f ]] && { cat /tmp/i/$_f >>/mnt/etc/$_f; rm /tmp/i/$_f; }
  2440. # Possible files to copy from /tmp/i/: fstab hostname.* kbdtype mygate
  2441. # myname ttys boot.conf resolv.conf sysctl.conf resolv.conf.tail
  2442. # Save only non-empty (-s) regular (-f) files.
  2443. (cd /tmp/i; for _f in fstab hostname* kbdtype my* ttys *.conf *.tail; do
  2444. [[ -f $_f && -s $_f ]] && mv $_f /mnt/etc/.
  2445. done)
  2446. echo "done."
  2447. # Apply configuration settings based on information from questions().
  2448. apply
  2449. # Create user account based on information from user_setup().
  2450. if [[ -n $ADMIN ]]; then
  2451. _encr=$(encr_pwd "$ADMIN_PASS")
  2452. _home=/home/$ADMIN
  2453. uline="${ADMIN}:${_encr}:1000:1000:staff:0:0:${ADMIN_NAME}:$_home:/bin/ksh"
  2454. echo "$uline" >>/mnt/etc/master.passwd
  2455. echo "${ADMIN}:*:1000:" >>/mnt/etc/group
  2456. echo $ADMIN >/mnt/root/.forward
  2457. _home=/mnt$_home
  2458. mkdir -p $_home
  2459. (cd /mnt/etc/skel; cp -pR . $_home)
  2460. (umask 077 && sed "s,^To: root\$,To: ${ADMIN_NAME} <${ADMIN}>," \
  2461. /mnt/var/mail/root >/mnt/var/mail/$ADMIN )
  2462. chown -R 1000:1000 $_home /mnt/var/mail/$ADMIN
  2463. sed -i -e "s@^wheel:.:0:root\$@wheel:\*:0:root,${ADMIN}@" \
  2464. /mnt/etc/group 2>/dev/null
  2465. # During autoinstall, add public ssh key to authorized_keys.
  2466. [[ -n "$ADMIN_KEY" ]] &&
  2467. print -r -- "$ADMIN_KEY" >>$_home/.ssh/authorized_keys
  2468. fi
  2469. # Store root password and rebuild password database.
  2470. if [[ -n "$_rootpass" ]]; then
  2471. _encr=$(encr_pwd "$_rootpass")
  2472. sed -i -e "s@^root::@root:${_encr}:@" /mnt/etc/master.passwd \
  2473. 2>/dev/null
  2474. fi
  2475. pwd_mkdb -p -d /mnt/etc /etc/master.passwd
  2476. # During autoinstall, add root user's public ssh key to authorized_keys.
  2477. [[ -n "$_rootkey" ]] && (
  2478. umask 077
  2479. print -r -- "$_rootkey" >>/mnt/root/.ssh/authorized_keys
  2480. )
  2481. # Perform final steps common to both an install and an upgrade.
  2482. finish_up
  2483. }
  2484. do_upgrade(){
  2485. # Get $ROOTDISK and $ROOTDEV
  2486. get_rootinfo
  2487. echo -n "Checking root filesystem (fsck -fp /dev/$ROOTDEV)..."
  2488. fsck -fp /dev/$ROOTDEV >/dev/null 2>&1 || { echo "FAILED."; exit; }
  2489. echo "OK."
  2490. echo -n "Mounting root filesystem (mount -o ro /dev/$ROOTDEV /mnt)..."
  2491. mount -o ro /dev/$ROOTDEV /mnt || { echo "FAILED."; exit; }
  2492. echo "OK."
  2493. # The fstab and myname files are required.
  2494. for _f in /mnt/etc/{fstab,myname}; do
  2495. [[ -f $_f ]] || { echo "No $_f!"; exit; }
  2496. cp $_f /tmp/i/${_f##*/}
  2497. done
  2498. hostname $(stripcom /tmp/i/myname)
  2499. THESETS="$THESETS site$VERSION-$(hostname -s).tgz"
  2500. # Configure the network.
  2501. enable_network
  2502. # Fetch the list of mirror servers and installer choices from previous
  2503. # runs.
  2504. start_cgiinfo
  2505. # Create a skeletal /etc/fstab which is usable for the upgrade process.
  2506. munge_fstab
  2507. # fsck -p non-root filesystems in /etc/fstab.
  2508. check_fs
  2509. # Mount filesystems in /etc/fstab.
  2510. umount /mnt || { echo "Can't umount $ROOTDEV!"; exit; }
  2511. mount_fs
  2512. # Feed the random pool some entropy before we read from it.
  2513. feed_random
  2514. # Ensure that previous installer choices (e.g. method) are available.
  2515. wait_cgiinfo
  2516. # Ask the user for locations, and install whatever sets the user
  2517. # selected.
  2518. install_sets
  2519. # Perform final steps common to both an install and an upgrade.
  2520. finish_up
  2521. }
  2522. # ------------------------------------------------------------------------------
  2523. # Initial actions common to both installs and upgrades.
  2524. #
  2525. # Some may require machine dependent routines, which may call functions defined
  2526. # above, so it's safest to put this code here rather than at the top.
  2527. # ------------------------------------------------------------------------------
  2528. # Parse parameters.
  2529. AUTO=false
  2530. MODE=
  2531. PROGNAME=${0##*/}
  2532. RESPFILE=
  2533. while getopts "af:m:" opt; do
  2534. case $opt in
  2535. a) AUTO=true;;
  2536. f) RESPFILE=$OPTARG;;
  2537. m) MODE=$OPTARG;;
  2538. *) usage;;
  2539. esac
  2540. done
  2541. shift $((OPTIND-1))
  2542. (($# == 0)) || usage
  2543. # The installer can be started by using the symbolic links 'install', 'upgrade'
  2544. # and 'autoinstall' pointing to this script. Set MODE and AUTO based on that.
  2545. if [[ -z $MODE ]]; then
  2546. case $PROGNAME in
  2547. autoinstall) AUTO=true;;
  2548. install|upgrade) MODE=$PROGNAME;;
  2549. *) exit 1;;
  2550. esac
  2551. fi
  2552. # Include machine-dependent functions and definitions.
  2553. #
  2554. # The following functions must be provided:
  2555. # md_congrats() - display friendly message
  2556. # md_installboot() - install boot-blocks on disk
  2557. # md_prep_disklabel() - put an OpenBSD disklabel on the disk
  2558. # md_consoleinfo() - set CDEV, CTTY, CSPEED, CPROM
  2559. #
  2560. # The following variables can be provided if required:
  2561. # MDEFI - set to 'y' on archs that support GPT partitioning
  2562. # MDROOTFSOPT - newfs options for the root partition
  2563. # MDSETS - list of files to add to THESETS
  2564. # MDTERM - 'vt220' assumed if not provided
  2565. # MDDKDEVS - '/^[sw]d[0-9][0-9]* /s/ .*//p' assumed if not provided
  2566. # MDCDDEVS - '/^cd[0-9][0-9]* /s/ .*//p' assumed if not provided
  2567. # MDXAPERTURE - set machdep.allowaperture=value in sysctl.conf
  2568. # MDXDM - ask if xdm should be started if set to 'y'
  2569. # NCPU - the number of cpus for mp capable arches
  2570. . install.md
  2571. # Make sure lock is initially released.
  2572. rm -df /tmp/i/lock
  2573. # The dmesg listener will check for the existence of this file and sends a
  2574. # signal to the child process if the dmesg output differs from the contents
  2575. # of that file.
  2576. rm -f /tmp/i/update
  2577. if ! $AUTO; then
  2578. # Start listener process looking for dmesg changes.
  2579. (
  2580. while :; do
  2581. lock
  2582. if [[ -e /tmp/i/update && "$(dmesg)" != "$(</tmp/i/update)" ]]; then
  2583. dmesg >/tmp/i/update
  2584. kill -TERM 2>/dev/null $$ || exit 1
  2585. fi
  2586. unlock
  2587. sleep .5
  2588. done
  2589. ) |&
  2590. CPPID=$!
  2591. # Kill the child on exit.
  2592. retrap
  2593. fi
  2594. ROOTDISK=
  2595. ROOTDEV=
  2596. SETDIR="$VNAME/$ARCH"
  2597. CGI_INFO=/tmp/i/cgiinfo
  2598. CGI_TZ=
  2599. CGI_TIME=
  2600. CGI_METHOD=
  2601. INSTALL_METHOD=
  2602. HTTP_DIR=
  2603. HTTP_SEC=/tmp/i/httpsec
  2604. HTTP_LIST=/tmp/i/httplist
  2605. WLANLIST=/tmp/i/wlanlist
  2606. PUB_KEY=/etc/signify/openbsd-${VERSION}-base.pub
  2607. # Do not limit ourselves during installs or upgrades.
  2608. for _opt in d f l m n p s; do
  2609. ulimit -$_opt unlimited
  2610. done
  2611. # Extract and save one boot's worth of dmesg.
  2612. dmesg | sed -n '/^LibertyBSD /h;/^LibertyBSD /!H;${g;p;}' >/var/run/dmesg.boot
  2613. # Are we in a real release, or a snapshot? If this is a snapshot
  2614. # install media, default us to a snapshot directory.
  2615. HTTP_SETDIR=$SETDIR
  2616. set -- $(scan_dmesg "/^LibertyBSD $VNAME\([^ ]*\).*$/s//\1/p")
  2617. [[ $1 == -!(stable) ]] && HTTP_SETDIR=snapshots/$ARCH
  2618. # Detect if ftp(1) has tls support and set defaults based on that.
  2619. if [[ -e /etc/ssl/cert.pem ]]; then
  2620. FTP_TLS=true
  2621. HTTP_PROTO=https
  2622. else
  2623. FTP_TLS=false
  2624. HTTP_PROTO=http
  2625. fi
  2626. # Scan /var/run/dmesg.boot for interesting devices.
  2627. NIFS=0
  2628. DISPLAY=$(scan_dmesg '/^wsdisplay[0-9]* /s/ .*//p')
  2629. CONSOLE=$(scan_dmesg '/^\([^ ]*\).*: console$/s//\1/p')
  2630. CONSOLE=${CONSOLE% }
  2631. [[ -n $CONSOLE ]] && CSPEED=$(stty speed </dev/console)
  2632. # Look for the serial device matching the console. If we are not installing
  2633. # from a serial console, just find the first serial device that could be used
  2634. # as a console. If a suitable device is found, set CDEV, CTTY, CSPEED, CPROM.
  2635. md_consoleinfo
  2636. # Selected sets will be installed in the order they are listed in $THESETS.
  2637. # Ensure that siteXX.tgz is the *last* set listed so its contents overwrite
  2638. # the contents of the other sets, not the other way around.
  2639. SETS=$(echo {base,comp,man,game,xbase,xshare,xfont,xserv}$VERSION.tgz)
  2640. DEFAULTSETS="${DEFAULTSETS:-bsd bsd.rd} $SETS"
  2641. THESETS="bsd bsd.rd bsd.mp $MDSETS $SETS site$VERSION.tgz"
  2642. SANESETS="${SANESETS:-bsd} base${VERSION}.tgz"
  2643. # Prepare COLUMNS sanely.
  2644. COLUMNS=$(stty -a </dev/console | sed -n '/columns/{s/^.* \([0-9]*\) columns.*$/\1/;p;}')
  2645. ((COLUMNS == 0)) && COLUMNS=80
  2646. EDITOR=ed
  2647. export EDITOR COLUMNS
  2648. # umount all filesystems, just in case we are re-running install or upgrade.
  2649. cd /
  2650. umount -af 1>/dev/null 2>&1
  2651. # Make sure only successful dhcp requests retain their state.
  2652. for _if in $(get_ifs dhcp); do
  2653. set -- $(v4_info $_if)
  2654. [[ $1 == UP && -n $2 ]] && continue
  2655. ifconfig $_if delete down -group dhcp 2>/dev/null
  2656. done
  2657. # Interactive or automatic installation?
  2658. if ! $AUTO; then
  2659. cat <<__EOT
  2660. At any prompt except password prompts you can escape to a shell by
  2661. typing '!'. Default answers are shown in []'s and are selected by
  2662. pressing RETURN. You can exit this program at any time by pressing
  2663. Control-C, but this can leave your system in an inconsistent state.
  2664. __EOT
  2665. elif [[ -z $RESPFILE ]]; then
  2666. if ! get_responsefile; then
  2667. echo "No response file found; non-interactive mode aborted."
  2668. exit 1
  2669. fi
  2670. rm -f /tmp/ai/ai.done
  2671. echo "Performing non-interactive $AI_MODE..."
  2672. /$AI_MODE -af /tmp/ai/ai.$AI_MODE.conf 2>&1 </dev/null |
  2673. sed "s/^.*$(echo '\r')//;w/tmp/ai/ai.log"
  2674. if [[ -f /tmp/ai/ai.done ]]; then
  2675. # Email /tmp/ai/ai.log to root on next boot.
  2676. prep_root_mail /tmp/ai/ai.log "$(hostname) $AI_MODE log"
  2677. exec reboot
  2678. else
  2679. echo "failed; check /tmp/ai/ai.log"
  2680. exit 1
  2681. fi
  2682. else
  2683. cp $RESPFILE /tmp/ai/ai.conf || exit
  2684. fi
  2685. # Configure the terminal and keyboard.
  2686. set_term
  2687. # In case of restart, delete previously logged answers.
  2688. rm -f /tmp/i/$MODE.resp
  2689. case $MODE in
  2690. install) do_install;;
  2691. upgrade) do_upgrade;;
  2692. esac