install.sub 98 KB

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