123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468 |
- #!/bin/ksh
- # $OpenBSD: install.sub,v 1.1144 2019/10/01 02:11:41 deraadt Exp $
- #
- # Copyright (c) 1997-2015 Todd Miller, Theo de Raadt, Ken Westerback
- # Copyright (c) 2015, Robert Peichaer <rpe@openbsd.org>
- #
- # All rights reserved.
- #
- # Redistribution and use in source and binary forms, with or without
- # modification, are permitted provided that the following conditions
- # are met:
- # 1. Redistributions of source code must retain the above copyright
- # notice, this list of conditions and the following disclaimer.
- # 2. Redistributions in binary form must reproduce the above copyright
- # notice, this list of conditions and the following disclaimer in the
- # documentation and/or other materials provided with the distribution.
- #
- # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- #
- # Copyright (c) 1996 The NetBSD Foundation, Inc.
- # All rights reserved.
- #
- # This code is derived from software contributed to The NetBSD Foundation
- # by Jason R. Thorpe.
- #
- # Redistribution and use in source and binary forms, with or without
- # modification, are permitted provided that the following conditions
- # are met:
- # 1. Redistributions of source code must retain the above copyright
- # notice, this list of conditions and the following disclaimer.
- # 2. Redistributions in binary form must reproduce the above copyright
- # notice, this list of conditions and the following disclaimer in the
- # documentation and/or other materials provided with the distribution.
- #
- # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
- # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- # POSSIBILITY OF SUCH DAMAGE.
- #
- # LibertyBSD install/upgrade script common subroutines and initialization code
- # ------------------------------------------------------------------------------
- # Misc functions
- # ------------------------------------------------------------------------------
- # Print error message to stderr and exit the script.
- err_exit() {
- print -u2 -- "$*"
- exit 1
- }
- # Show usage of the installer script and exit.
- usage() {
- err_exit "usage: ${0##*/} [-ax] [-f filename] [-m install | upgrade]"
- }
- # Wait for the ftp(1) process started in start_cgiinfo() to end and extract
- # various informations from the mirror list output.
- wait_cgiinfo() {
- local _l _s _key _val
- wait "$CGIPID" 2>/dev/null
- # Ensure, there is actual data to extract info from.
- [[ -s $CGI_INFO ]] || return
- # Extract the list of mirror servers.
- sed -En 's,^https?://([[A-Za-z0-9:_][]A-Za-z0-9:._-]*),\1,p' \
- $CGI_INFO >$HTTP_LIST 2>/dev/null
- # Extract the previously selected mirror server (first entry in the
- # ftplist.cgi output, if that has no location info).
- read -r -- _s _l <$HTTP_LIST
- [[ -z $_l ]] && : ${HTTP_SERVER:=${_s%%/*}}
- # Extract the previously used install method, timezone information
- # and a reference timestamp.
- while IFS='=' read -r -- _key _val; do
- case $_key=$_val in
- method=+([a-z])*([0-9])) CGI_METHOD=$_val;;
- TIME=+([0-9])) CGI_TIME=$_val;;
- TZ=+([-_/+[:alnum:]])) CGI_TZ=$_val;;
- esac
- done <$CGI_INFO
- }
- # ------------------------------------------------------------------------------
- # Utils functions
- # ------------------------------------------------------------------------------
- # Sort and print unique list of provided arguments.
- bsort() {
- local _a=$1 _b _l
- (($#)) && shift || return
- for _b; do
- [[ $_a == "$_b" ]] && continue
- if [[ $_a > $_b ]]; then
- _l="$_a $_l" _a=$_b
- else
- _l="$_b $_l"
- fi
- done
- # Output the smallest value found.
- (($#)) && echo -n "$_a " || echo -n "$_a"
- # Sort remaining values.
- bsort $_l
- }
- # Test the first argument against the remaining ones, return success on a match.
- isin() {
- local _a=$1 _b
- shift
- for _b; do
- [[ $_a == "$_b" ]] && return 0
- done
- return 1
- }
- # Add first argument to list formed by the remaining arguments.
- # Adds to the tail if the element does not already exist.
- addel() {
- local _a=$1
- shift
- isin "$_a" $* && echo -n "$*" || echo -n "${*:+$* }$_a"
- }
- # Remove all occurrences of first argument from list formed by the remaining
- # arguments.
- rmel() {
- local _a=$1 _b _c
- shift
- for _b; do
- [[ $_a != "$_b" ]] && _c="${_c:+$_c }$_b"
- done
- echo -n "$_c"
- }
- # If possible, print the timestamp received from the ftplist.cgi output,
- # adjusted with the time elapsed since it was received.
- http_time() {
- local _sec=$(cat $HTTP_SEC 2>/dev/null)
- [[ -n $_sec && -n $CGI_TIME ]] &&
- echo $((CGI_TIME + SECONDS - _sec))
- }
- # Prints the supplied parameters properly escaped for future sh/ksh parsing.
- # Quotes are added if needed, so you should not do that yourself.
- quote() (
- # Since this is a subshell we won't pollute the calling namespace.
- for _a; do
- alias Q=$_a; _a=$(alias Q); print -rn -- " ${_a#Q=}"
- done | sed '1s/ //'
- echo
- )
- # Show a list of ordered arguments (read line by line from stdin) in column
- # output using ls.
- show_cols() {
- local _l _cdir=/tmp/i/cdir _clist
- mkdir -p $_cdir
- rm -rf -- $_cdir/*
- while read _l; do
- [[ -n $_l ]] || continue
- mkdir -p /tmp/i/cdir/"$_l"
- _clist[${#_clist[*]}]="$_l"
- done
- (cd $_cdir; ls -Cdf "${_clist[@]}")
- rm -rf -- $_cdir
- }
- # Echo file $1 to stdout. Skip comment lines and delete everything
- # after the first '#' from other lines. Strip leading and trailing
- # whitespace if IFS is set.
- stripcom() {
- local _file=$1 _line
- [[ -f $_file ]] || return
- set -o noglob
- while read _line; do
- [[ -n ${_line%%#*} ]] && echo $_line
- done <$_file
- set +o noglob
- }
- # Create a temporary directory based on the supplied directory name prefix.
- tmpdir() {
- local _i=1 _dir
- until _dir="${1?}.$_i.$RANDOM" && mkdir -- "$_dir" 2>/dev/null; do
- ((++_i < 10000)) || return 1
- done
- echo "$_dir"
- }
- # Generate unique filename based on the supplied filename $1.
- unique_filename() {
- local _fn=$1 _ufn
- while _ufn=${_fn}.$RANDOM && [[ -e $_ufn ]]; do done
- print -- "$_ufn"
- }
- # Let rc.firsttime feed file $1 using $2 as subject to whatever mail system we
- # have at hand by then.
- prep_root_mail() {
- local _fn=$1 _subject=$2 _ufn
- [[ -s $_fn ]] || return
- _ufn=$(unique_filename /mnt/var/log/${_fn##*/})
- cp $_fn $_ufn
- chmod 600 $_ufn
- _ufn=${_ufn#/mnt}
- cat <<__EOT >>/mnt/etc/rc.firsttime
- ( /usr/bin/mail -s '$_subject' root <$_ufn && rm $_ufn ) >/dev/null 2>&1 &
- __EOT
- }
- # Examine the contents of the DHCP lease file $1 for a line containing the
- # field provided as parameters and return the value of the first field found.
- #
- # Note that strings are unescaped but not unvis()'d.
- lease_value() {
- local _lf=$1 _o
- [[ -s $_lf ]] || return
- shift
- for _o; do
- sed -E \
- -e '/^ *(option )?'"$_o"' (.*);$/!d;s//\2/' \
- -e '/^"(.*)"$/{s//\1/;s/\\(.)/\1/g;};q' "$_lf" \
- | grep ^ && return
- done
- }
- # Extract one boot's worth of dmesg.
- dmesgtail() {
- dmesg | sed -n 'H;/^LibertyBSD/h;${g;p;}'
- }
- # ------------------------------------------------------------------------------
- # Device related functions
- # ------------------------------------------------------------------------------
- # Show device name, info, NAA and size for the provided list of disk devices.
- # Create device nodes as needed and cleanup afterwards.
- diskinfo() {
- local _d _i _n _s
- for _d; do
- # Extract disk information enclosed in <> from dmesg.
- _i=$(dmesg | sed -n '/^'$_d' at /h;${g;s/^.*<\(.*\)>.*$/\1/p;}')
- _i=${_i##+([[:space:],])}
- _i=${_i%%+([[:space:],])}
- # Extract Network Address Authority information from dmesg.
- _n=$(dmesg | sed -En '/^'$_d' at /h;${g;s/^.* ([a-z0-9]+\.[a-zA-Z0-9_]+)$/\1/p;}')
- # Extract disk size from disklabel output.
- make_dev $_d
- _s=$(disklabel -dpg $_d 2>/dev/null | sed -n '/.*# total bytes: \(.*\)/{s//(\1)/p;}')
- rm -f /dev/{r,}$_d?
- echo "$_d: $_i $_n $_s"
- done
- }
- # Create devices passed as arguments.
- make_dev() {
- [[ -z $(cd /dev && sh MAKEDEV "$@" 2>&1) ]]
- }
- # Sort and print information from dmesg.boot using sed expression $1.
- scan_dmesg() {
- bsort $(sed -n "$1" /var/run/dmesg.boot)
- }
- # Extract device names from hw.disknames matching sed expression $1.
- scan_disknames() {
- local IFS=, _disks=$(sysctl -n hw.disknames)
- bsort $(for _n in $_disks; do echo "${_n%%:*} "; done | sed -n "$1")
- }
- # Return disk devices found in hw.disknames.
- get_dkdevs() {
- echo $(scan_disknames "${MDDKDEVS:-/^[sw]d[0-9][0-9]* /s/ .*//p}")
- }
- # Return CDROM devices found in hw.disknames.
- get_cddevs() {
- echo $(scan_disknames "${MDCDDEVS:-/^cd[0-9][0-9]* /s/ .*//p}")
- }
- # Return sorted list of disks not in DISKS_DONE which contains disks already
- # initialized during installation.
- get_dkdevs_uninitialized() {
- local _disks=$(get_dkdevs) _d
- for _d in $DISKS_DONE; do
- _disks=$(rmel "$_d" $_disks)
- done
- bsort $_disks
- }
- # Return list of valid root disks
- get_dkdevs_root() {
- local _disks=$(get_dkdevs) _d
- if [[ $MODE == upgrade ]]; then
- for _d in $_disks; do
- is_rootdisk "$_d" || _disks=$(rmel "$_d" $_disks)
- done
- fi
- echo -n $_disks
- }
- # Return list of all network devices, optionally limited by parameters to
- # ifconfig. Filter out dynamically created network pseudo-devices except vlan.
- get_ifs() {
- local _if _if_list=$(rmel vlan $(ifconfig -C))
- for _if in $(ifconfig "$@" 2>/dev/null | sed '/^[a-z]/!d;s/:.*//'); do
- isin "${_if%%+([0-9])}" $_if_list || echo $_if
- done
- }
- # Return the device name of the disk device $1, which may be a disklabel UID.
- get_dkdev_name() {
- local _dev=${1#/dev/} _d
- _dev=${_dev%.[a-p]}
- ((${#_dev} < 16)) && _dev=${_dev%[a-p]}
- local IFS=,
- for _d in $(sysctl -n hw.disknames); do
- [[ $_dev == @(${_d%:*}|${_d#*:}) ]] && echo ${_d%:*} && break
- done
- }
- # Inspect disk $1 if it has a partition-table of type $2 and optionally
- # if it has a partition of type $3.
- disk_has() {
- local _disk=$1 _pttype=$2 _part=$3 _cmd _p_pttype _p_part
- [[ -n $_disk && -n $_pttype ]] || exit
- # Commands to inspect disk. Default: "fdisk $_disk"
- local _c_hfs="pdisk -l $_disk"
- local _c_sr="bioctl -q $_disk"
- # Patterns for partition-table-types and partition-types.
- local _p_gpt='Usable LBA:'
- local _p_gpt_openbsd='^[ *]...: OpenBSD '
- local _p_gpt_efisys='^[ *]...: EFI Sys '
- local _p_hfs='^Partition map '
- local _p_hfs_openbsd=' OpenBSD OpenBSD '
- local _p_mbr='Signature: 0xAA55'
- local _p_mbr_openbsd='^..: A6 '
- local _p_mbr_dos='^..: 06 '
- local _p_mbr_dos_active='^\*.: 06 '
- local _p_mbr_linux='^..: 83 '
- local _p_sr='OPENBSD, SR'
- local _p_sr_crypto='OPENBSD, SR CRYPTO'
- # Compose command and patterns based on the parameters.
- eval "_cmd=\"\$_c_${_pttype}\""
- eval "_p_pttype=\"\$_p_${_pttype}\""
- eval "_p_part=\"\$_p_${_pttype}_${_part}\""
- # Set the default command if none was defined before.
- _cmd=${_cmd:-fdisk $_disk}
- # Abort in case of undefined patterns.
- [[ -z $_p_pttype ]] && exit
- [[ -n $_part && -z $_p_part ]] && exit
- if [[ -z $_p_part ]]; then
- $_cmd 2>/dev/null | grep -Eq "$_p_pttype"
- else
- $_cmd 2>/dev/null | grep -Eq "$_p_pttype" &&
- $_cmd 2>/dev/null | grep -Eq "$_p_part"
- fi
- }
- # Handle disklabel auto-layout for the root disk $1 during interactive install
- # and autopartitioning during unattended install by asking for and downloading
- # autopartitioning template. Write the resulting fstab to $2. Abort unattended
- # installation if autopartitioning fails.
- disklabel_autolayout() {
- local _disk=$1 _f=$2 _dl=/tmp/i/disklabel.auto _op _qst
- # Skip disklabel auto-layout for any disk except the root disk.
- [[ $_disk != $ROOTDISK ]] && return
- while $AI; do
- ask "URL to autopartitioning template for disklabel?" none
- [[ $resp == none ]] && break
- if ! $FTP_TLS && [[ $resp == https://* ]]; then
- err_exit "https not supported on this platform."
- fi
- echo "Fetching $resp"
- if unpriv ftp -Vo - "$resp" >$_dl && [[ -s $_dl ]]; then
- disklabel -T $_dl -F $_f -w -A $_disk && return
- err_exit "Autopartitioning failed."
- else
- err_exit "No autopartitioning template found."
- fi
- done
- _qst="Use (A)uto layout, (E)dit auto layout, or create (C)ustom layout?"
- while :; do
- echo "The auto-allocated layout for $_disk is:"
- disklabel -h -A $_disk | egrep "^# |^ [a-p]:"
- ask "$_qst" a
- case $resp in
- [aA]*) _op=-w;;
- [eE]*) _op=-E;;
- [cC]*) return 0;;
- *) continue;;
- esac
- disklabel -F $_f $_op -A $_disk
- return
- done
- }
- # Create a partition table and configure the partition layout for disk $1.
- configure_disk() {
- local _disk=$1 _fstab=/tmp/i/fstab.$1 _opt
- make_dev $_disk || return
- # Deal with disklabels, including editing the root disklabel
- # and labeling additional disks. This is machine-dependent since
- # some platforms may not be able to provide this functionality.
- # /tmp/i/fstab.$_disk is created here with 'disklabel -F'.
- rm -f /tmp/i/*.$_disk
- md_prep_disklabel $_disk || return
- # Make sure a '/' mount point exists on the root disk.
- if ! grep -qs ' / ffs ' /tmp/i/fstab.$ROOTDISK; then
- echo "'/' must be configured!"
- $AI && exit 1 || return 1
- fi
- if [[ -f $_fstab ]]; then
- # Avoid duplicate mount points on different disks.
- while read _pp _mp _rest; do
- # Multiple swap partitions are ok.
- if [[ $_mp == none ]]; then
- echo "$_pp $_mp $_rest" >>/tmp/i/fstab
- continue
- fi
- # Non-swap mountpoints must be in only one file.
- if [[ $_fstab != $(grep -l " $_mp " /tmp/i/fstab.*) ]]; then
- _rest=$_disk
- _disk=
- break
- fi
- done <$_fstab
- # Duplicate mountpoint.
- if [[ -z $_disk ]]; then
- # Allow disklabel(8) to read back mountpoint info
- # if it is immediately run against the same disk.
- cat /tmp/i/fstab.$_rest >/etc/fstab
- rm /tmp/i/fstab.$_rest
- set -- $(grep -h " $_mp " /tmp/i/fstab.*[0-9])
- echo "$_pp and $1 can't both be mounted at $_mp."
- $AI && exit 1 || return 1
- fi
- # Add ffs filesystems to list after newfs'ing them. Ignore
- # other filesystems.
- while read _pp _mp _fstype _rest; do
- [[ $_fstype == ffs ]] || continue
- # Use machine-dependent newfs options for the root
- # partition if defined.
- _opt=
- [[ $_mp == / ]] && _opt=$MDROOTFSOPT
- newfs -q $_opt ${_pp##/dev/}
- # N.B.: '!' is lexically < '/'.
- # That is required for correct sorting of mount points.
- FSENT="$FSENT $_mp!$_pp"
- done <$_fstab
- fi
- return 0
- }
- # ------------------------------------------------------------------------------
- # Functions for the dmesg listener
- # ------------------------------------------------------------------------------
- # Acquire lock.
- lock() {
- while ! mkdir /tmp/i/lock 2>/dev/null && sleep .1; do done
- }
- # Release lock.
- unlock() {
- rm -df /tmp/i/lock 2>/dev/null
- }
- # Add a trap to kill the dmesg listener co-process on exit of the installer.
- retrap() {
- trap 'kill -KILL $CPPID 2>/dev/null; echo; stty echo; exit 0' \
- INT EXIT TERM
- }
- # Start a listener process looking for dmesg changes which indicates a possible
- # plug-in/-out of devices (e.g. usb disks, cdroms, etc.). This is used to abort
- # and redraw question prompts, especially in ask_which().
- start_dmesg_listener() {
- local _update=/tmp/i/update
- # Ensure the lock is initially released and that no update files exists.
- unlock
- rm -f $_update
- # Do not start the listener if in non-interactive mode.
- $AI && return
- # To ensure that only one dmesg listener instance can be active, run it
- # in a co-process subshell of which there can always only be one active.
- (
- while :; do
- lock
- # The dmesg listener will continuously check for the existence of
- # the update file and sends a signal to the parent process (that
- # is the installer script) if the dmesg output differs from the
- # contents of that file.
- if [[ -e $_update && "$(dmesgtail)" != "$(<$_update)" ]]; then
- dmesgtail >$_update
- kill -TERM 2>/dev/null $$ || exit 1
- fi
- unlock
- sleep .5
- done
- ) |&
- # Save the co-process PID in a global variable so it can be used in
- # the retrap() function which adds a trap to kill the co-process on
- # exit of the installer script.
- CPPID=$!
- retrap
- }
- # ------------------------------------------------------------------------------
- # Functions to ask (or auto-answer) questions
- # ------------------------------------------------------------------------------
- # Log installer questions and answers so that the resulting file can be used as
- # response file for an unattended install/upgrade.
- log_answers() {
- if [[ -n $1 && -n $2 ]]; then
- print -r -- "${1%%'?'*} = $2" >>/tmp/i/$MODE.resp
- fi
- }
- # Fetch response file for autoinstall.
- get_responsefile() {
- local _rf _if _lf _path _aifile
- export AI_HOSTNAME= AI_MAC= AI_MODE= AI_SERVER=
- [[ -f /auto_upgrade.conf ]] && _rf=/auto_upgrade.conf AI_MODE=upgrade
- [[ -f /auto_install.conf ]] && _rf=/auto_install.conf AI_MODE=install
- [[ -f $_rf ]] && cp $_rf /tmp/ai/ai.$AI_MODE.conf && return
- for _if in ''; do
- [[ -x /sbin/dhclient ]] || break
- # Select a network interface for initial dhcp request.
- # Prefer the interface the system netbooted from.
- set -- $(get_ifs netboot)
- (($# == 0)) && set -- $(get_ifs)
- (($# == 1)) && _if=$1
- # Ask if multiple were found and system was not netbooted.
- while (($# > 1)); do
- ask_which "network interface" \
- "should be used for the initial DHCP request" \
- "$*"
- isin "$resp" $* && _if=$resp && break
- done
- # Issue initial dhcp request via the found interface.
- [[ -n $_if ]] && dhclient $_if || break
- _lf=/var/db/dhclient.leases.$_if
- # Extract installer mode and response file path from lease file.
- _aifile=$(lease_value $_lf filename bootfile-name)
- [[ $_aifile == ?(*/)auto_@(install|upgrade) ]] || _aifile=
- _path=${_aifile%auto_@(install|upgrade)}
- AI_MODE=${_aifile##*?(/)auto_}
- # Extract install server ip address from lease file.
- AI_SERVER=$(lease_value $_lf \
- server-name tftp-server-name next-server)
- # Prime hostname with host-name option from lease file.
- AI_HOSTNAME=$(lease_value $_lf host-name)
- hostname "$AI_HOSTNAME"
- done
- # Try to fetch mac-mode.conf, then hostname-mode.conf, and finally
- # mode.conf if install server and mode are known, otherwise tell which
- # one was missing.
- if [[ -n $AI_SERVER && -n $AI_MODE ]]; then
- AI_MAC=$(ifconfig $_if | sed 's/.*lladdr \(.*\)/\1/p;d')
- for _rf in {$AI_MAC-,${AI_HOSTNAME:+$AI_HOSTNAME-,}}$AI_MODE; do
- # Append HTTP_SETDIR as parameter to _url which can be
- # used by the webserver to return dynamically created
- # response files.
- _url="http://$AI_SERVER/$_path$_rf.conf?path=$HTTP_SETDIR"
- echo "Fetching $_url"
- if unpriv ftp -Vo - "$_url" \
- >"/tmp/ai/ai.$AI_MODE.conf" 2>/dev/null; then
- ifconfig $_if delete down 2>/dev/null
- return 0
- fi
- done
- else
- [[ -z $AI_SERVER ]] && echo "Could not determine auto server."
- [[ -z $AI_MODE ]] && echo "Could not determine auto mode."
- fi
- # Ask for url or local path to response file. Provide a default url if
- # server was found in lease file.
- while :; do
- ask "Response file location?" \
- "${AI_SERVER:+http://$AI_SERVER/install.conf}"
- [[ -n $resp ]] && _rf=$resp && break
- done
- # Ask for the installer mode only if auto-detection failed.
- AI_MODE=$(echo "$_rf" | sed -En 's/^.*(install|upgrade).conf$/\1/p')
- while [[ -z $AI_MODE ]]; do
- ask "(I)nstall?"
- [[ $resp == [iI]* ]] && AI_MODE=install
- done
- echo "Fetching $_rf"
- [[ -f $_rf ]] && _rf="file://$_rf"
- if unpriv ftp -Vo - "$_rf" >"/tmp/ai/ai.$AI_MODE.conf" 2>/dev/null; then
- ifconfig $_if delete down 2>/dev/null
- return 0
- fi
- return 1
- }
- # Find a response to question $1 in $AI_RESPFILE and return it via $resp.
- # Return default answer $2 if provided and none is found in the file.
- #
- # Move the existing ai.conf file to a tmp file, read from it line by line
- # and write a new ai.conf file skipping the line containing the response.
- #
- # 1) skip empty and comment lines and lines without =
- # 2) split question (_key) and answer (_val) at leftmost =
- # 3) strip leading/trailing blanks
- # 4) compare questions case insensitive (typeset -l)
- #
- _autorespond() {
- typeset -l _q=$1 _key
- local _def=$2 _l _val
- [[ -f $AI_RESPFILE && -n $_q ]] || return
- mv /tmp/ai/ai.conf /tmp/ai/ai.conf.tmp
- while IFS=' ' read -r _l; do
- [[ $_l == [!#=]*=?* ]] || continue
- _key=${_l%%*([[:blank:]])=*}
- _val=${_l##*([!=])=*([[:blank:]])}
- [[ $_q == @(|*[[:blank:]])"$_key"@([[:blank:]?]*|) ]] &&
- resp=$_val && cat && return
- print -r " $_l"
- done </tmp/ai/ai.conf.tmp >/tmp/ai/ai.conf
- [[ -n $_def ]] && resp=$_def && return
- err_exit "\nQuestion has no answer in response file: \"$_q\""
- }
- # Capture user response either by issuing an interactive read or by searching
- # the response file and store the response in the global variable $resp.
- #
- # Optionally present a question $1 and a default answer $2 shown in [].
- #
- # If the dmesg output is changed while waiting for the interactive response,
- # the current read will be aborted and the function will return a non-zero
- # value. Normally, the caller function will then reprint any prompt and call
- # the function again.
- _ask() {
- local _q=$1 _def=$2 _int _redo=0 _pid
- lock; dmesgtail >/tmp/i/update; unlock
- echo -n "${_q:+$_q }${_def:+[$_def] }"
- _autorespond "$_q" "$_def" && echo "$resp" && return
- trap "_int=1" INT
- trap "_redo=1" TERM
- read resp
- lock; rm /tmp/i/update; unlock
- if ((_redo)); then
- stty raw
- stty -raw
- else
- case $resp in
- !) echo "Type 'exit' to return to install."
- sh
- _redo=1
- ;;
- !*) eval "${resp#?}"
- _redo=1
- ;;
- esac
- fi
- retrap
- ((_int)) && kill -INT $$
- : ${resp:=$_def}
- return $_redo
- }
- # Ask for user response to question $1 with an optional default answer $2.
- # Write the question and the answer to a logfile.
- ask() {
- # Prompt again in case the dmesg listener detected a change.
- while ! _ask "$1" "$2"; do done
- log_answers "$1" "$resp"
- }
- # Ask the user a yes/no question $1 with 'no' as default answer unless $2 is
- # set to 'yes' and insist on 'y', 'yes', 'n' or 'no' as response.
- # Return response via $resp as 'y' with exit code 0 or 'n' with exit code 1.
- ask_yn() {
- local _q=$1 _a=${2:-no}
- typeset -l _resp
- while :; do
- ask "$_q" "$_a"
- _resp=$resp
- case $_resp in
- y|yes) resp=y; return 0;;
- n|no) resp=n; return 1;;
- esac
- echo "'$resp' is not a valid choice."
- $AI && exit 1
- done
- }
- # Ask for the user to select one value from a list, or 'done'.
- # At exit $resp holds selected item, or 'done'.
- #
- # Parameters:
- #
- # $1 = name of the list items (disk, cd, etc.)
- # $2 = question to ask
- # $3 = list of valid choices
- # $4 = default choice, if it is not specified use the first item in $3
- #
- # N.B.! $3 and $4 will be "expanded" using eval, so be sure to escape them
- # if they contain spooky stuff
- ask_which() {
- local _name=$1 _query=$2 _list=$3 _def=$4 _dynlist _dyndef _key _q
- _key=$(echo "$_name" | sed 's/[^[:alnum:]]/_/g')
- while :; do
- eval "_dynlist=\"$_list\""
- eval "_dyndef=\"$_def\""
- # Clean away whitespace and determine the default.
- set -o noglob
- set -- $_dyndef; _dyndef="$1"
- set -- $_dynlist; _dynlist="$*"
- set +o noglob
- (($# < 1)) && resp=done && return
- : ${_dyndef:=$1}
- echo "Available ${_name}s are: $_dynlist."
- _q="Which $_name $_query?"
- echo -n "$_q (or 'done') ${_dyndef:+[$_dyndef] }"
- _autorespond "$_q" "${_dyndef-done}" && echo "$resp" \
- || _ask || continue
- [[ -z $resp ]] && resp="$_dyndef"
- # Quote $resp to prevent user from confusing isin() by
- # entering something like 'a a'.
- if isin "$resp" $_dynlist done; then
- log_answers "$_q" "$resp"
- break
- fi
- echo "'$resp' is not a valid choice."
- $AI && [[ -n $AI_RESPFILE ]] && exit 1
- done
- }
- # Ask for user response to question $1 with an optional default answer $2
- # until a non-empty reply is entered.
- ask_until() {
- resp=
- while :; do
- ask "$1" "$2"
- [[ -n $resp ]] && break
- echo "A response is required."
- $AI && exit 1
- done
- }
- # Capture a user password and save it in $resp, optionally showing prompt $1.
- #
- # 1) *Don't* allow the '!' options that ask does.
- # 2) *Don't* echo input.
- # 3) *Don't* interpret "\" as escape character.
- # 4) Preserve whitespace in input
- #
- ask_pass() {
- stty -echo
- IFS= read -r resp?"$1 "
- stty echo
- echo
- }
- # Ask for a password twice showing prompt $1. Ensure both inputs are identical
- # and save it in $_password.
- ask_password() {
- local _q=$1
- if $AI; then
- echo -n "$_q "
- _autorespond "$_q"
- echo '<provided>'
- _password=$resp
- return
- fi
- while :; do
- ask_pass "$_q (will not echo)"
- _password=$resp
- ask_pass "$_q (again)"
- [[ $resp == "$_password" ]] && break
- echo "Passwords do not match, try again."
- done
- }
- # ------------------------------------------------------------------------------
- # Support functions for donetconfig()
- # ------------------------------------------------------------------------------
- # Issue a DHCP request to configure interface $1 and add it to group 'dhcp' to
- # later be able to identify DHCP configured interfaces.
- dhcp_request() {
- local _if=$1
- echo "lookup file bind" >/etc/resolv.conf.tail
- ifconfig $_if group dhcp >/dev/null 2>&1
- if [[ -x /sbin/dhclient ]]; then
- /sbin/dhclient -c /dev/stdin $_if <<__EOT
- initial-interval 1;
- backoff-cutoff 2;
- reboot 5;
- timeout 10;
- __EOT
- else
- echo "DHCP leases not available during install - no /sbin/dhclient."
- fi
- # Move resolv.conf to where it will be copied to the installed system.
- mv /etc/resolv.conf.tail /tmp/i/resolv.conf.tail
- }
- # Obtain and output the inet information related to interface $1.
- # Outputs:
- # <flags>\n<addr> <netmask> <rest of inet line>[\n<more inet lines>]
- v4_info() {
- ifconfig $1 inet | sed -n '
- 1s/.*flags=.*<\(.*\)>.*/\1/p
- /inet/s/netmask //
- /.inet /s///p'
- }
- # Convert a netmask in hex format ($1) to dotted decimal format.
- hextodec() {
- set -- $(echo ${1#0x} | sed 's/\(..\)/0x\1 /g')
- echo $(($1)).$(($2)).$(($3)).$(($4))
- }
- # Create an entry in the hosts file using IP address $1 and symbolic name $2.
- # Treat $1 as IPv6 address if it contains ':', otherwise as IPv4. If an entry
- # with the same name and address family already exists, delete it first.
- add_hostent() {
- local _addr=$1 _name=$2 _delim="."
- [[ -z $_addr || -z $_name ]] && return
- [[ $_addr == *:* ]] && _delim=":"
- sed -i "/^[0-9a-fA-F]*[$_delim].*[ ]$_name\$/d" \
- /tmp/i/hosts 2>/dev/null
- echo "$_addr $_name" >>/tmp/i/hosts
- }
- # Configure VLAN interface $1 and create the corresponding hostname.if(5) file.
- # Ask the user what parent network interface and vnetid to use.
- vlan_config() {
- local _if=$1 _hn=/tmp/i/hostname.$1 _hn_vd _vd _vdvi _vdvi_used _vi
- local _sed_vdvi='s/.encap: vnetid ([[:alnum:]]+) parent ([[:alnum:]]+)/\2:\1/p'
- # Use existing parent device and vnetid for this interface as default in
- # case of a restart.
- _vdvi=$(ifconfig $_if 2>/dev/null | sed -En "$_sed_vdvi")
- _vd=${_vdvi%%:*}
- _vi=${_vdvi##*:}
- # Use the vlan interface minor as the default vnetid. If it's 0, set it
- # to 'none' which equals to the default vlan.
- if [[ $_vi == @(|none) ]]; then
- ((${_if##vlan} == 0)) && _vi=none || _vi=${_if##vlan}
- fi
- # Use the first non vlan interface as the default parent.
- if [[ $_vd == @(|none) ]]; then
- _vd=$(get_ifs | sed '/^vlan/d' | sed q)
- fi
- ask "Which interface:tag should $_if be on?" "$_vd:$_vi"
- _vd=${resp%%:*}
- _vi=${resp##*:}
- # Ensure that the given parent is an existing (non vlan) interface.
- if ! isin "$_vd" $(get_ifs | sed '/^vlan/d'); then
- echo "Invalid parent interface choice '$_vd'."
- return 1
- fi
- # Get a list of parent:vnetid tuples of all configured vlan interfaces.
- _vdvi_used=$(ifconfig vlan 2>/dev/null | sed -En "$_sed_vdvi")
- # Ensure that the given vnetid is not already configured on the given
- # parent interface.
- for _vdvi in $_vdvi_used; do
- if [[ $_vdvi == $_vd:* && ${_vdvi##*:} == $_vi ]]; then
- echo "vlan tag '$_vi' already used on parent '$_vd'"
- return 1
- fi
- done
- # Further ensure that the given vnetid is 'none', or within 1-4095.
- if [[ $_vi == none ]]; then
- _vi="-vnetid"
- elif (($_vi > 0 && $_vi < 4096)); then
- _vi="vnetid $_vi"
- else
- echo "Invalid vlan tag '$_vi'."
- return 1
- fi
- # Write the config to the hostname.if files and set proper permissions.
- _hn_vd=/tmp/i/hostname.$_vd
- grep -qs "^up" $_hn_vd || echo up >>$_hn_vd
- echo "$_vi parent $_vd" >>$_hn
- chmod 640 $_hn_vd $_hn
- # Bring up the parent interface and configure the vlan interface.
- ifconfig $_vd up
- ifconfig $_if destroy >/dev/null 2>&1
- ifconfig $_if create >/dev/null 2>&1
- ifconfig $_if $_vi parent $_vd
- }
- # Configure IPv4 on interface $1.
- v4_config() {
- local _if=$1 _name=$2 _hn=$3 _addr _mask _newaddr
- # Set default answers based on any existing configuration.
- set -- $(v4_info $_if)
- if [[ -n $2 ]] && ! isin $_if $(get_ifs dhcp); then
- _addr=$2;
- _mask=$(hextodec $3)
- fi
- # Nuke existing inet configuration.
- ifconfig $_if -inet
- ifconfig $_if -group dhcp >/dev/null 2>&1
- while :; do
- ask_until "IPv4 address for $_if? (or 'dhcp' or 'none')" \
- "${_addr:-dhcp}"
- case $resp in
- none) return
- ;;
- dhcp) dhcp_request $_if
- echo "dhcp" >>$_hn
- return
- ;;
- esac
- _newaddr=$resp
- # Ask for the netmask if the user did not use CIDR notation.
- if [[ $_newaddr == */* ]]; then
- ifconfig $_if $_newaddr up
- else
- ask_until "Netmask for $_if?" "${_mask:-255.255.255.0}"
- ifconfig $_if $_newaddr netmask $resp
- fi
- set -- $(v4_info $_if)
- if [[ -n $2 ]]; then
- echo "inet $2 $3" >>$_hn
- add_hostent "$2" "$_name"
- return
- fi
- $AI && exit 1
- done
- }
- # Obtain and output the inet6 information related to interface $1.
- # <flags>\n<addr> <prefixlen> <rest of inet6 line>[\n<more inet6 lines>]
- v6_info() {
- ifconfig $1 inet6 | sed -n '
- 1s/.*flags=.*<\(.*\)>.*/\1/p
- /scopeid/d
- /inet6/s/prefixlen //
- /.inet6 /s///p'
- }
- # Configure an IPv6 default route on interface $1 and preserve that information
- # in the /etc/mygate file. Ask the user to either select from a list of default
- # router candidates or to enter a router IPv6 address.
- v6_defroute() {
- local _if _v6ifs _prompt _resp _routers _dr PS3
- # Only configure a default route if an IPv6 address was manually configured.
- for _if in $(get_ifs); do
- set -- $(v6_info $_if)
- [[ -z $2 || $1 == *AUTOCONF6* ]] || _v6ifs="$_v6ifs $_if"
- done
- [[ -n $_v6ifs ]] || return
- # Start with any existing default routes.
- _routers=$(route -n show -inet6 |
- sed -En 's/^default[[:space:]]+([^[:space:]]+).*/\1 /p')
- # Add more default router canditates by ping6'ing
- # the All-Routers multicast address.
- for _if in $_v6ifs; do
- _resp=$(ping6 -n -c 2 ff02::2%$_if 2>/dev/null |
- sed -En '/^[0-9]+ bytes from /{s///;s/: .*$//p;}')
- for _dr in $_resp; do
- _routers=$(addel $_dr $_routers)
- done
- done
- [[ -n $_routers ]] && _routers=$(bsort $_routers)
- _prompt="IPv6 default router?"
- if $AI; then
- _autorespond "$_prompt (IPv6 address or 'none')" none &&
- echo "$_prompt $resp"
- [[ $resp != none ]] &&
- route -n add -inet6 -host default $resp &&
- echo $resp >>/tmp/i/mygate
- else
- PS3="$_prompt (list #, IPv6 address or 'none') "
- select _resp in none $_routers; do
- [[ $REPLY == none || $_resp == none ]] && break
- [[ -z $_resp ]] && _resp=$REPLY
- # Avoid possible "file exists" errors
- route -n -q delete -inet6 -host default $_resp
- if route -n add -inet6 -host default $_resp; then
- echo $_resp >>/tmp/i/mygate
- break
- fi
- done
- fi
- }
- # Configure IPv6 interface $1, add hostname $2 to the hosts file,
- # create the hostname.if file $3. Ask the user for the IPv6 address
- # and prefix length if the address was not specified in CIDR notation,
- # unless he chooses 'autoconf'.
- v6_config() {
- local _if=$1 _name=$2 _hn=$3 _addr _newaddr _prefixlen
- ifconfig lo0 inet6 >/dev/null 2>&1 || return
- # Preset the default answers by preserving possibly existing
- # configuration from previous runs.
- set -- $(v6_info $_if)
- if [[ $1 == *AUTOCONF6* ]]; then
- _addr=autoconf
- elif [[ -n $2 ]]; then
- _addr=$2
- _prefixlen=$3
- fi
- # Nuke existing inet6 configuration.
- ifconfig $_if -inet6
- while :; do
- ask_until "IPv6 address for $_if? (or 'autoconf' or 'none')" \
- "${_addr:-none}"
- case $resp in
- none) return
- ;;
- autoconf)
- ifconfig $_if inet6 autoconf up
- echo "inet6 autoconf" >>$_hn
- return
- ;;
- esac
- _newaddr=$resp
- if [[ $_newaddr == */* ]]; then
- ifconfig $_if inet6 $_newaddr up
- else
- ask_until "IPv6 prefix length for $_if?" \
- "${_prefixlen:-64}"
- ifconfig $_if inet6 $_newaddr/$resp up
- fi
- set -- $(v6_info $_if)
- if [[ -n $2 ]]; then
- echo "inet6 $2 $3" >>$_hn
- add_hostent "$2" "$_name"
- return
- fi
- $AI && exit 1
- done
- }
- # Perform an 802.11 network scan on interface $1 and cache the result a file.
- ieee80211_scan() {
- [[ -f $WLANLIST ]] ||
- ifconfig $1 scan |
- sed -n 's/^[[:space:]]*nwid \(.*\) chan [0-9]* bssid \([[:xdigit:]:]*\).*/\1 (\2)/p' >$WLANLIST
- cat $WLANLIST
- }
- # Configure 802.11 interface $1 and append ifconfig options to hostname.if $2.
- # Ask the user for the access point ESSID, the security protocol and a secret.
- ieee80211_config() {
- local _if=$1 _hn=$2 _prompt _nwid _haswpa=0 _err
- # Reset 802.11 settings and determine wpa capability.
- ifconfig $_if -nwid -nwkey
- ifconfig $_if -wpa 2>/dev/null && _haswpa=1
- # Empty scan cache.
- rm -f $WLANLIST
- while [[ -z $_nwid ]]; do
- ask_until "Access point? (ESSID, 'any', list# or '?')" "any"
- case "$resp" in
- +([0-9]))
- _nwid=$(ieee80211_scan $_if |
- sed -n ${resp}'{s/ ([[:xdigit:]:]*)$//p;q;}')
- [[ -z $_nwid ]] && echo "There is no line $resp."
- [[ $_nwid = \"*\" ]] && _nwid=${_nwid#\"} _nwid=${_nwid%\"}
- ;;
- \?) ieee80211_scan $_if | cat -n | more -c
- ;;
- *) _nwid=$resp
- ;;
- esac
- done
- # 'any' implies that only open access points are considered.
- if [[ $_nwid != any ]]; then
- _prompt="Security protocol? (O)pen, (W)EP"
- ((_haswpa == 1)) && _prompt="$_prompt, WPA-(P)SK"
- while :; do
- ask_until "$_prompt" "O"
- case "$_haswpa-$resp" in
- ?-[Oo]) # No further questions
- ifconfig $_if nwid "$_nwid"
- quote nwid "$_nwid" >>$_hn
- break
- ;;
- ?-[Ww]) ask_until "WEP key? (will echo)"
- # Make sure ifconfig accepts the key.
- if _err=$(ifconfig $_if nwid "$_nwid" nwkey "$resp" 2>&1) &&
- [[ -z $_err ]]; then
- quote nwid "$_nwid" nwkey "$resp" >>$_hn
- break
- fi
- echo "$_err"
- ;;
- 1-[Pp]) ask_until "WPA passphrase? (will echo)"
- # Make sure ifconfig accepts the key.
- if ifconfig $_if nwid "$_nwid" wpakey "$resp"; then
- quote nwid "$_nwid" wpakey "$resp" >>$_hn
- break
- fi
- ;;
- *) echo "'$resp' is not a valid choice."
- ;;
- esac
- done
- fi
- }
- # Set up IPv4 and IPv6 interface configuration.
- configure_ifs() {
- local _first _hn _if _name _p _vi
- # Always need lo0 configured.
- ifconfig lo0 inet 127.0.0.1/8
- # In case of restart, delete previous default gateway config.
- rm -f /tmp/i/mygate
- while :; do
- # Discover last configured vlan interface and increment its
- # minor for the next offered vlan interface.
- _vi=$(get_ifs vlan | sed '$!d;s/^vlan//')
- [[ -n $_vi ]] && ((_vi++))
- ask_which "network interface" "do you wish to configure" \
- "\$(get_ifs) vlan${_vi:-0}" \
- ${_p:-'$( (get_ifs netboot; get_ifs) | sed q )'}
- [[ $resp == done ]] && break
- _if=$resp
- _hn=/tmp/i/hostname.$_if
- rm -f $_hn
- # If the offered vlan is chosen, ask the relevant
- # questions and bring it up.
- if [[ $_if == vlan+([0-9]) ]]; then
- vlan_config $_if || continue
- fi
- # Test if it is an 802.11 interface.
- ifconfig $_if 2>/dev/null | grep -q "^[[:space:]]*ieee80211:" &&
- ieee80211_config $_if $_hn
- # First interface configured will use the hostname without
- # asking the user.
- resp=$(hostname -s)
- [[ -n $_first && $_first != $_if ]] &&
- ask "Symbolic (host) name for $_if?" "$resp"
- _name=$resp
- v4_config $_if $_name $_hn
- v6_config $_if $_name $_hn
- if [[ -f $_hn ]]; then
- chmod 640 $_hn
- : ${_first:=$_if}
- fi
- NIFS=$(ls -1 /tmp/i/hostname.* 2>/dev/null | grep -c ^)
- _p=done
- done
- }
- # Set up IPv4 default route by asking the user for an IPv4 address and preserve
- # that information in /etc/mygate. If setting the default route fails, try to
- # revert to a possibly existing previous one.
- v4_defroute() {
- local _dr _dr_if
- # Only configure a default route if an IPv4 address was configured.
- [[ -n $(ifconfig | sed -n '/[ ]inet .* broadcast /p') ]] || return
- # Check routing table to see if a default route ($1) already exists
- # and what interface it is connected to ($2).
- set -- $(route -n show -inet |
- sed -En 's/^default +([0-9.]+) .* ([a-z0-9]+) *$/\1 \2/p')
- [[ -n $1 ]] && _dr=$1 _dr_if=$2
- # Don't ask if a default route exits and is handled by dhclient.
- [[ -n $_dr ]] && isin "$_dr_if" $(get_ifs dhcp) && return
- while :; do
- ask_until "Default IPv4 route? (IPv4 address or none)" "$_dr"
- [[ $resp == none ]] && break
- route delete -inet default >/dev/null 2>&1
- if route -n add -inet -host default "$resp"; then
- echo "$resp" >>/tmp/i/mygate
- break
- else
- route -n add -inet -host default $_dr >/dev/null 2>&1
- fi
- done
- }
- # Extract the domain part from currently configured fully qualified domain name.
- # If none is set, use 'my.domain'.
- get_fqdn() {
- local _dn
- _dn=$(hostname)
- _dn=${_dn#$(hostname -s)}
- _dn=${_dn#.}
- echo "${_dn:=my.domain}"
- }
- # ------------------------------------------------------------------------------
- # Support functions for install_sets()
- # ------------------------------------------------------------------------------
- # SANESETS defines the required list of set files for a sane install or upgrade.
- # During install_files(), each successfully installed set file is removed from
- # DEFAULTSETS. Check if there are SANESETS still in DEFAULTSETS and if they were
- # deliberately skipped. If $1 is not defined, ask the user about each skipped
- # set file. Care is taken to make sure the return value is correct.
- sane_install() {
- local _q=$1 _s
- for _s in $SANESETS; do
- isin "$_s" $DEFAULTSETS || continue
- [[ -n $_q ]] && return 1
- if ! ask_yn "Are you *SURE* your $MODE is complete without '$_s'?"; then
- $AI && exit 1 || return 1
- fi
- done
- }
- # Show list of available sets $1 and let the user select which sets to install.
- # Preselect sets listed in $2 and store the list of selected sets in $resp.
- #
- # If the list of available sets only contains kernels during an upgrade, assume
- # that the user booted into the installer using the currently installed bsd.rd
- # and specified a set location pointing to a new release. In this case, only
- # show and preselect bsd.rd. By setting UPGRADE_BSDRD the signify key for the
- # next release is used to verify the downloaded bsd.rd, the current bsd.rd is
- # preserved and no questions about missing sets are asked.
- select_sets() {
- local _avail=$1 _selected=$2 _f _action _col=$COLUMNS
- local _bsd_rd _no_sets=true
- if [[ $MODE == upgrade ]]; then
- for _f in $_avail; do
- [[ $_f != bsd* ]] && _no_sets=false
- [[ $_f == bsd.rd* ]] && _bsd_rd=$_f
- done
- $_no_sets && UPGRADE_BSDRD=true _avail=$_bsd_rd _selected=$_bsd_rd
- fi
- # account for 4 spaces added to the sets list
- let COLUMNS=_col-8
- cat <<__EOT
- Select sets by entering a set name, a file name pattern or 'all'. De-select
- sets by prepending a '-', e.g.: '-game*'. Selected sets are labelled '[X]'.
- __EOT
- while :; do
- for _f in $_avail; do
- isin "$_f" $_selected && echo "[X] $_f" || echo "[ ] $_f"
- done | show_cols | sed 's/^/ /'
- ask "Set name(s)? (or 'abort' or 'done')" done
- set -o noglob
- for resp in $resp; do
- case $resp in
- abort) _selected=; break 2;;
- done) break 2;;
- -*) _action=rmel;;
- *) _action=addel;;
- esac
- resp=${resp#[+-]}
- [[ $resp == all ]] && resp=*
- for _f in $_avail; do
- [[ $_f == $resp ]] &&
- _selected=$($_action $_f $_selected)
- done
- done
- done
- set +o noglob
- COLUMNS=$_col
- resp=$_selected
- }
- # Run a command ($2+) as unprivileged user ($1).
- # Take extra care that after "cmd" no "user" processes exist.
- #
- # Optionally:
- # - create "file" and chown it to "user"
- # - after "cmd", chown "file" back to root
- #
- # Usage: do_as user [-f file] cmd
- do_as() {
- (( $# >= 2 )) || return
- local _file _rc _user=$1
- shift
- if [[ $1 == -f ]]; then
- _file=$2
- shift 2
- fi
- if [[ -n $_file ]]; then
- >$_file
- chown "$_user" "$_file"
- fi
- doas -u "$_user" "$@"
- _rc=$?
- while doas -u "$_user" kill -9 -1 2>/dev/null; do
- echo "Processes still running for user $_user after: $@"
- sleep 1
- done
- [[ -n $_file ]] && chown root "$_file"
- return $_rc
- }
- unpriv() {
- do_as _sndio "$@"
- }
- unpriv2() {
- do_as _file "$@"
- }
- # Find and list filesystems to store the prefetched sets. Prefer filesystems
- # which are not used during extraction with 512M free space. Otherwise search
- # any other filesystem that has 2 GB free space to prevent overflow during
- # extraction.
- prefetcharea_fs_list() {
- local _fs_list
- _fs_list=$( (
- for fs in /mnt/{tmp,home,usr{/local,}}; do
- df -k $fs 2>/dev/null | grep " $fs\$"
- done
- df -k
- ) | (
- while read a a a a m m; do
- [[ $m == /mnt/@(tmp|home|usr/@(src,obj,xobj))@(|/*) ]] &&
- ((a > 524288)) && echo $m && continue
- [[ $m == /mnt@(|/*) ]] &&
- ((a > 524288 * 4)) && echo $m
- done
- ) | (
- while read fs; do
- isin "$fs" $list || list="$list${list:+ }$fs"
- done
- echo $list
- ) )
- [[ -n $_fs_list ]] && echo $_fs_list || return 1
- }
- # Install a user-selected subset of the files listed in $2 from the source $1.
- # Display an error message for each failed install and ask the user whether to
- # continue or not.
- install_files() {
- local _src=$1 _files=$2 _f _sets _get_sets _n _col=$COLUMNS _tmpfs \
- _tmpfs_list _tmpsrc _cfile=/tmp/SHA256 _fsrc _unver _t _issue
- local _srclocal=false _unpriv=unpriv
- # Fetch sets from local sources (disk, cdrom, nfs) as root.
- [[ $_src == file://* ]] && _srclocal=true _unpriv=
- # Based on the file list in $_files, create two lists for select_sets().
- # _sets: the list of files the user can select from
- # _get_sets: the list of files that are shown as pre-selected
- #
- # Sets will be installed in the order given in ALLSETS to ensure proper
- # installation. So, to minimize user confusion display the sets in the
- # order in which they will be installed.
- for _f in $ALLSETS; do
- isin "$_f" $_files || continue
- _sets=$(addel $_f $_sets)
- isin "$_f" $DEFAULTSETS "site$VERSION-$(hostname -s).tgz" &&
- _get_sets=$(addel $_f $_get_sets)
- done
- if [[ -z $_sets ]]; then
- echo -n "Looked at $_src "
- echo "and found no $OBSD sets. The set names looked for were:"
- let COLUMNS=_col-8
- for _n in $ALLSETS; do echo $_n; done | show_cols | sed 's/^/ /'
- COLUMNS=$_col
- $AI && exit 1
- echo
- return
- fi
- isin "INSTALL.$ARCH" $_files ||
- ask_yn "INSTALL.$ARCH not found. Use sets found here anyway?" ||
- return
- select_sets "$_sets" "$_get_sets"
- [[ -n $resp ]] || return
- _get_sets=$resp
- # Reorder $_get_sets.
- _get_sets=$(for s in $ALLSETS; do isin "$s" $_get_sets && echo $s; done)
- # Note which sets didn't verify ok.
- _unver=$_get_sets
- # Try to prefetch and control checksum of the set files.
- # Use dummy for loop as combined assignment and do { ... } while(0).
- for _issue in ''; do
- ! isin SHA256.sig $_files &&
- _issue="Directory does not contain SHA256.sig" && break
- if ! $_srclocal; then
- ! _tmpfs_list=$(prefetcharea_fs_list) &&
- _issue="Cannot determine prefetch area" && break
- for _tmpfs in $_tmpfs_list; do
- # Try to clean up from previous runs, assuming
- # the _tmpfs selection yields the same mount
- # point.
- for _tmpsrc in $_tmpfs/sets.+([0-9]).+([0-9]); do
- [[ -d $_tmpsrc ]] && rm -r $_tmpsrc
- done
- # Create a download directory for the sets and
- # check that the _sndio user can read files from
- # it. Otherwise cleanup and skip the filesystem.
- if _tmpsrc=$(tmpdir "$_tmpfs/sets"); then
- (
- >$_tmpsrc/t &&
- $_unpriv cat $_tmpsrc/t
- ) >/dev/null 2>&1 && break ||
- rm -r $_tmpsrc
- fi
- done
- [[ ! -d $_tmpsrc ]] &&
- _issue="Cannot create prefetch area" && break
- fi
- # Cleanup from previous runs.
- rm -f $_cfile $_cfile.sig
- _t=Get/Verify
- $_srclocal && _t='Verifying '
- # Fetch signature file.
- ! $_unpriv ftp -D "$_t" -Vmo - "$_src/SHA256.sig" >"$_cfile.sig" &&
- _issue="Cannot fetch SHA256.sig" && break
- # The bsd.rd only download/verify/install assumes the sets
- # location of the next release. So use the right signature file.
- $UPGRADE_BSDRD &&
- PUB_KEY=/mnt/etc/signify/libertybsd-$((VERSION + 1))-base.pub
- # Verify signature file with public keys.
- ! unpriv -f "$_cfile" \
- signify -Vep $PUB_KEY -x "$_cfile.sig" -m "$_cfile" &&
- _issue="Signature check of SHA256.sig failed" && break
- # Fetch and verify the set files.
- for _f in $_get_sets; do
- $UU && reset_watchdog
- rm -f /tmp/h /tmp/fail
- # Fetch set file and create a checksum by piping through
- # sha256. Create a flag file in case ftp failed. Sets
- # from net are written to the prefetch area, the output
- # of local sets is discarded.
- ( $_unpriv ftp -D "$_t" -Vmo - "$_src/$_f" || >/tmp/fail ) |
- ( $_srclocal && unpriv2 sha256 >/tmp/h ||
- unpriv2 -f /tmp/h sha256 -ph /tmp/h >"$_tmpsrc/$_f" )
- # Handle failed transfer.
- if [[ -f /tmp/fail ]]; then
- rm -f "$_tmpsrc/$_f"
- if ! ask_yn "Fetching of $_f failed. Continue anyway?"; then
- [[ -d $_tmpsrc ]] && rm -rf "$_tmpsrc"
- $AI && exit 1
- return
- fi
- _unver=$(rmel $_f $_unver)
- _get_sets=$(rmel $_f $_get_sets)
- continue
- fi
- # Verify sets by comparing its checksum with SHA256.
- if fgrep -qx "SHA256 ($_f) = $(</tmp/h)" "$_cfile"; then
- _unver=$(rmel $_f $_unver)
- else
- if ! ask_yn "Checksum test for $_f failed. Continue anyway?"; then
- [[ -d $_tmpsrc ]] && rm -rf "$_tmpsrc"
- $AI && exit 1
- return
- fi
- fi
- done
- done
- [[ -n $_unver ]] && : ${_issue:="Unverified sets:" ${_unver% }}
- if [[ -n $_issue ]] &&
- ! ask_yn "$_issue. Continue without verification?"; then
- [[ -d $_tmpsrc ]] && rm -rf "$_tmpsrc"
- $AI && exit 1
- return
- fi
- # We are committed to installing new files. Attempt to cope with
- # potential space shortage in /usr by deleting a few versioned
- # areas which will be replaced from the new sets
- if [[ $MODE == upgrade ]]; then
- if isin base$VERSION.tgz $_get_sets; then
- rm -f /mnt/usr/share/relink/usr/lib/*
- rm -rf /mnt/usr/lib/libLLVM.so.0.0
- rm -rf /mnt/usr/libdata/perl5
- fi
- if isin comp$VERSION.tgz $_get_sets; then
- rm -rf /mnt/usr/lib/{gcc-lib,clang}
- rm -rf /mnt/usr/include/g++
- fi
- rm -rf /mnt/var/syspatch/*
- fi
- # Install the set files.
- for _f in $_get_sets; do
- $UU && reset_watchdog
- _fsrc="$_src/$_f"
- # Take the set file from the prefetch area if possible.
- [[ -f $_tmpsrc/$_f ]] && _fsrc="file://$_tmpsrc/$_f"
- # Extract the set files and put the kernel files in place.
- case $_fsrc in
- *.tgz) $_unpriv ftp -D Installing -Vmo - "$_fsrc" |
- tar -zxphf - -C /mnt &&
- if [[ $_f == ?(x)base*.tgz && $MODE == install ]]; then
- ftp -D Extracting -Vmo - \
- file:///mnt/var/sysmerge/${_f%%base*}etc.tgz |
- tar -zxphf - -C /mnt
- fi
- ;;
- *) # Make a backup of the existing ramdisk kernel in the
- # bsd.rd only download/verify/install case.
- $UPGRADE_BSDRD && [[ $_f == bsd.rd* ]] &&
- cp /mnt/$_f /mnt/$_f.old.$VERSION
- $_unpriv ftp -D Installing -Vmo - "$_fsrc" >"/mnt/$_f"
- ;;
- esac
- if (($?)); then
- if ! ask_yn "Installation of $_f failed. Continue anyway?"; then
- [[ -d $_tmpsrc ]] && rm -rf "$_tmpsrc"
- $AI && exit 1
- return
- fi
- else
- # Remove each successfully installed set file from
- # DEFAULTSETS which is checked by sane_sets().
- DEFAULTSETS=$(rmel $_f $DEFAULTSETS)
- # Reset DEFAULTSETS to make sure that sane_sets() does
- # not complain about missing set files in the bsd.rd
- # only download/verify/install case,
- $UPGRADE_BSDRD && DEFAULTSETS=
- fi
- [[ -d $_tmpsrc ]] && rm -f "$_tmpsrc/$_f"
- done
- [[ -d $_tmpsrc ]] && rm -rf "$_tmpsrc" || true
- # Keep SHA256 from installed sets for sysupgrade(8).
- if [[ -f $_cfile ]]; then
- cp $_cfile /mnt/var/db/installed.SHA256
- elif $_srclocal && [[ -f ${_src#file://}/SHA256 ]]; then
- cp ${_src#file://}/SHA256 /mnt/var/db/installed.SHA256
- fi
- $UU && reset_watchdog
- }
- # Fetch install sets from an HTTP server possibly using a proxy.
- install_http() {
- local _d _f _flist _file_list _prompt _tls _http_proto _url_base
- local _idx=/tmp/i/index.txt _sha=/tmp/i/SHA256 _sig=/tmp/i/SHA256.sig
- local _iu_url _iu_srv _iu_dir _mirror_url _mirror_srv _mirror_dir
- local _ftp_stdout=/tmp/i/ftpstdout _rurl_base
- # N.B.: Don't make INSTALL_MIRROR a local variable! It preserves the
- # mirror information if install_http() is called multiple times with
- # mirror and local servers. That ensures that the mirror server ends
- # up in /etc/installurl file if one of the servers is not a mirror.
- # N.B.: 'http_proxy' is an environment variable used by ftp(1).
- # DON'T change the name or case!
- ask "HTTP proxy URL? (e.g. 'http://proxy:8080', or 'none')" \
- "${http_proxy:-none}"
- unset http_proxy
- [[ $resp == none ]] || export http_proxy=$resp
- # If the mirror server listfile download failed, inform the user and
- # show a reduced prompt.
- if [[ -s $HTTP_LIST ]]; then
- _prompt="HTTP Server? (hostname, list#, 'done' or '?')"
- else
- echo "(Unable to get list from ftp.libertybsd.net, but that is OK)"
- _prompt="HTTP Server? (hostname or 'done')"
- fi
- # Use information from /etc/installurl as defaults for upgrades.
- # Format of installurl: _http_proto://_iu_srv/_iu_dir
- # ^--------- _iu_url ---------^
- if [[ $MODE == upgrade ]] &&
- _iu_url=$(stripcom /mnt/etc/installurl); then
- _iu_srv=${_iu_url#*://}
- _iu_srv=${_iu_srv%%/*}
- _iu_dir=${_iu_url##*$_iu_srv*(/)}
- [[ -n $_iu_srv ]] && HTTP_SERVER=$_iu_srv
- fi
- # Get server IP address or hostname and optionally the http protocol.
- while :; do
- ask_until "$_prompt" "$HTTP_SERVER"
- case $resp in
- done) return
- ;;
- "?") [[ -s $HTTP_LIST ]] || continue
- # Show a numbered list of mirror servers.
- cat -n < $HTTP_LIST | more -c
- ;;
- +([0-9]))
- # A number is only used as a line number in $HTTP_LIST.
- [[ -s $HTTP_LIST ]] || continue
- # Extract the URL from the mirror server listfile.
- set -- $(sed -n "${resp}p" $HTTP_LIST)
- if (($# < 1)); then
- echo "There is no line $resp."
- continue
- fi
- HTTP_SERVER=${1%%/*}
- # Repeat loop to get user to confirm server address.
- ;;
- ?(http?(s)://)+([A-Za-z0-9:.\[\]_-]))
- case $resp in
- https://*) _tls=force _http_proto=https;;
- http://*) _tls=no _http_proto=http;;
- *) _tls=try _http_proto=$HTTP_PROTO;;
- esac
- if ! $FTP_TLS && [[ $_tls == force ]]; then
- echo "https not supported on this platform."
- $AI && exit 1 || continue
- fi
- HTTP_SERVER=${resp#*://}
- break
- ;;
- *) echo "'$resp' is not a valid hostname."
- ;;
- esac
- done
- # Get directory info from *last* line starting with the server
- # name. This means the last install from a mirror will not keep
- # the specific directory info. But an install from a local
- # server *will* remember the specific directory info.
- # Format: _mirror_srv/_mirror_dir location_info
- # ^---- _mirror_url ----^
- set -- $(grep -i "^$HTTP_SERVER" $HTTP_LIST 2>/dev/null | sed '$!d')
- _mirror_url=${1%%*(/)}
- _mirror_srv=${_mirror_url%%/*}
- _mirror_dir=${_mirror_url##*$_mirror_srv*(/)}
- # Decide on the default for the "Server directory" question.
- if [[ -n $_mirror_url ]]; then
- # Use directory information from cgi server if HTTP_SERVER was
- # found in HTTP_LIST. That is either an official mirror or the
- # server used in a previous installation or upgrade.
- _d=$_mirror_dir/$HTTP_SETDIR
- # Preserve the information that it is an official mirror if
- # location is present in $2.
- (($# > 1)) && INSTALL_MIRROR=$_mirror_url
- elif [[ -n $_iu_url ]]; then
- # Otherwise, if it exists, use directory information from
- # installurl(5) during upgrade.
- _d=$_iu_dir/$HTTP_SETDIR
- else
- _d=pub/LibertyBSD/$HTTP_SETDIR
- fi
- ask_until "Server directory?" "$_d"
- HTTP_DIR=${resp##+(/)}
- _url_base="$_http_proto://$HTTP_SERVER/$HTTP_DIR"
- # Fetch SHA256.sig to create the list of files to select from.
- rm -f $_idx $_sha $_sig $_ftp_stdout
- if ! unpriv -f $_sig \
- ftp -w 15 -vMo $_sig "$_url_base/SHA256.sig" \
- >$_ftp_stdout 2>/dev/null; then
- case $_tls in
- force) $AI && exit 1 || return
- ;;
- try) ask_yn "Unable to connect using https. Use http instead?" ||
- return
- _http_proto=http
- _url_base="http://$HTTP_SERVER/$HTTP_DIR"
- unpriv -f $_sig ftp -vMo $_sig "$_url_base/SHA256.sig" \
- >$_ftp_stdout 2>/dev/null
- ;;
- esac
- fi
- # In case of URL redirection, use the final location to retrieve the
- # rest of the files from. Redirection does not change INSTALL_MIRROR.
- _rurl_base=$(sed -n 's/^Requesting //p' $_ftp_stdout | sed '$!d')
- _rurl_base=${_rurl_base%/SHA256.sig*}
- # Verify SHA256.sig, write SHA256 and extract the list of files.
- if unpriv -f $_sha \
- signify -Vep $PUB_KEY -x $_sig -m $_sha >/dev/null 2>&1; then
- _file_list="$(sed -n 's/^SHA256 (\(.*\)).*$/\1/p' $_sha)"
- _file_list="SHA256.sig $_file_list"
- else
- echo "Unable to get a verified list of distribution sets."
- # Deny this server, if it's a mirror without a valid SHA256.sig.
- if [[ ${_rurl_base%/$HTTP_SETDIR} == "$_http_proto://$INSTALL_MIRROR" ]]; then
- $AI && exit 1 || return
- fi
- fi
- # Fetch index.txt, extract file list but add only entries that are not
- # already in _file_list. This allows for a verified list of distribution
- # sets from SHA256.sig, siteXX sets or the whole set list from index.txt
- # if SHA256.sig was not found (e.g. self compiled sets).
- if unpriv -f $_idx \
- ftp -VMo $_idx "$_rurl_base/index.txt" 2>/dev/null; then
- _flist=$(sed -En 's/^.* ([a-zA-Z][a-zA-Z0-9._-]+)$/\1/p' $_idx)
- for _f in $_flist; do
- ! isin "$_f" $_file_list && _file_list="$_file_list $_f"
- done
- fi
- rm -f $_idx $_sha $_sig $_ftp_stdout
- install_files "$_rurl_base" "$_file_list"
- # Remember the sets location which is used later for creating the
- # installurl(5) file and to tell the cgi server.
- if [[ -n $INSTALL_MIRROR ]]; then
- INSTALL_URL=$_http_proto://$INSTALL_MIRROR
- else
- # Remove the architecture and snaphots or version part.
- INSTALL_URL=${_url_base%/$ARCH}
- INSTALL_URL=${INSTALL_URL%@(/$VNAME|/snapshots)}
- fi
- }
- # Ask for the path to the set files on an already mounted filesystem and start
- # the set installation.
- install_mounted_fs() {
- local _dir
- while :; do
- ask_until "Pathname to the sets? (or 'done')" "$SETDIR"
- [[ $resp == done ]] && return
- # Accept a valid /mnt2 or /mnt relative path.
- [[ -d /mnt2/$resp ]] && { _dir=/mnt2/$resp; break; }
- [[ -d /mnt/$resp ]] && { _dir=/mnt/$resp; break; }
- # Accept a valid absolute path.
- [[ -d /$resp ]] && { _dir=/$resp; break; }
- echo "The directory '$resp' does not exist."
- $AI && exit 1
- done
- install_files "file://$_dir" "$(ls $_dir/)"
- }
- # Install sets from CD-ROM drive $1.
- install_cdrom() {
- local _drive=$1
- make_dev $_drive && mount_mnt2 $_drive || return
- install_mounted_fs
- }
- # Install sets from disk.
- # Ask for the disk device containing the set files.
- install_disk() {
- if ! ask_yn "Is the disk partition already mounted?" yes; then
- ask_which "disk" "contains the $MODE media" \
- '$(bsort $(get_dkdevs))' \
- '$(bsort $(rmel $ROOTDISK $(get_dkdevs)))'
- [[ $resp == done ]] && return 1
- # Ensure the device file exists and mount the fs on /mnt2.
- make_dev $resp && mount_mnt2 $resp || return
- fi
- install_mounted_fs
- }
- # Ask for the nfs share details, mount it and start the set installation.
- install_nfs() {
- local _tcp
- # Get the IP address of the server.
- ask_until "Server IP address or hostname?" "$NFS_ADDR"
- NFS_ADDR=$resp
- # Get the server path to mount.
- ask_until "Filesystem on server to mount?" "$NFS_PATH"
- NFS_PATH=$resp
- # Determine use of TCP.
- ask_yn "Use TCP transport? (requires TCP-capable NFS server)" && _tcp=-T
- # Mount the server.
- mount_nfs $_tcp -o ro -R 5 $NFS_ADDR:$NFS_PATH /mnt2 || return
- install_mounted_fs
- }
- # Mount filesystem containing the set files on device $1, optionally ask the
- # user for the device name.
- mount_mnt2() {
- local _dev=$1 _opts _file=/tmp/i/parts.$1 _parts
- disklabel $_dev 2>/dev/null |
- sed -En '/swap|unused/d;/^ [a-p]: /p' >$_file
- _parts=$(sed 's/^ \(.\): .*/\1/' $_file)
- set -- $_parts
- (($# == 0)) && { echo "No filesystems found on $_dev."; return 1; }
- if isin "c" $_parts; then
- # Don't ask questions if 'c' contains a filesystem.
- resp=c
- elif (($# == 1)); then
- # Don't ask questions if there's only one choice.
- resp=$1
- else
- # Display partitions with filesystems and ask which to use.
- cat $_file
- ask_which "$_dev partition" "has the $MODE sets" \
- '$(disklabel '$_dev' 2>/dev/null |
- sed -En '\''/swap|unused/d;/^ ([a-p]): .*/s//\1/p'\'')'
- [[ $resp == done ]] && return 1
- fi
- # Always mount msdos partitions with -s to get lower case names.
- grep -q "^ $resp: .*MSDOS" $_file && _opts="-s"
- mount -o ro,$_opts /dev/$_dev$resp /mnt2
- }
- # ------------------------------------------------------------------------------
- # Functions used in install.sh/upgrade.sh and its associates
- # ------------------------------------------------------------------------------
- # Ask for terminal type if on console, otherwise ask for/set keyboard layout.
- set_term() {
- local _layouts
- export TERM=${TERM:-${MDTERM:-vt220}}
- if [[ -n $CONSOLE ]]; then
- ask "Terminal type?" "$TERM"
- TERM=$resp
- else
- [[ -x /sbin/kbd ]] || return
- _layouts=$(bsort $(kbd -l | egrep -v "^(user|tables|encoding)"))
- while :; do
- ask "Choose your keyboard layout ('?' or 'L' for list)" default
- case $resp in
- [lL\?]) echo "Available layouts: $_layouts"
- ;;
- default) break
- ;;
- *) if kbd -q "$resp"; then
- echo $resp >/tmp/i/kbdtype
- break
- fi
- ;;
- esac
- done
- fi
- }
- # Configure the network.
- donetconfig() {
- local _dn _ns _f1 _f2 _f3
- configure_ifs
- v4_defroute
- v6_defroute
- # As dhclient will populate /etc/resolv.conf, a symbolic link to
- # /tmp/i/resolv.conf.shadow, mv any such file to /tmp/i/resolv.conf
- # so it will eventually be copied to /mnt/etc/resolv.conf and will
- # not in the meantime remove the user's ability to choose to use it
- # or not, during the rest of the install.
- if [[ -f /tmp/i/resolv.conf.shadow ]]; then
- mv /tmp/i/resolv.conf.shadow /tmp/i/resolv.conf
- # Get/store nameserver address(es) as a blank separated list
- # and the default fully qualified domain name from *first*
- # domain given on *last* search or domain statement.
- while read -r -- _f1 _f2 _f3; do
- [[ $_f1 == nameserver ]] && _ns="${_ns:+$_ns }$_f2"
- [[ $_f1 == @(domain|search) ]] && _dn=$_f2
- done </tmp/i/resolv.conf
- fi
- # Get & apply fqdn to hostname. Don't ask if there's only one configured
- # interface and if it's managed by dhclient and if the domain name is
- # configured via dhclient too.
- resp="${_dn:-$(get_fqdn)}"
- if ifconfig dhcp >/dev/null 2>&1 && [[ $NIFS == 1 && -n $_dn ]]; then
- # If we have a 'domain-name' option in the lease file use that.
- # It might *NOT* not be the same as the first domain in any
- # 'domain-search' option.
- set -- $(get_ifs dhcp)
- set -- $(lease_value /var/db/dhclient.leases.$1 domain-name)
- [[ -n $1 ]] && resp=$1
- echo "Using DNS domainname $resp"
- else
- ask "DNS domain name? (e.g. 'example.com')" "$resp"
- fi
- hostname "$(hostname -s).$resp"
- # Get & add nameservers to /tmp/i/resolv.conf. Don't ask if there's only
- # one configured interface and if it's managed by dhclient and if the
- # nameserver is configured via dhclient too.
- resp="${_ns:-none}"
- if ifconfig dhcp >/dev/null 2>&1 && [[ $NIFS == 1 && -n $_ns ]]; then
- echo "Using DNS nameservers at $resp"
- else
- ask "DNS nameservers? (IP address list or 'none')" "$resp"
- fi
- # Construct appropriate resolv.conf.
- if [[ $resp != none ]]; then
- echo "lookup file bind" >/tmp/i/resolv.conf
- for _ns in $resp; do
- echo "nameserver $_ns" >>/tmp/i/resolv.conf
- done
- cp /tmp/i/resolv.conf /tmp/i/resolv.conf.shadow
- fi
- }
- # Ask user about daemon startup on boot, X Window usage and console setup.
- # The actual configuration is done later in apply().
- questions() {
- local _d _cdef=no
- ask_yn "Start sshd(8) by default?" yes
- START_SSHD=$resp
- APERTURE=
- resp=
- START_XDM=
- if [[ -n $(scan_dmesg '/^wsdisplay[0-9]* /s/ .*//p') ]]; then
- if [[ -n $(scan_dmesg '/^[a-z]*[01]: aperture needed/p') ]]; then
- ask_yn "Do you expect to run the X Window System?" yes &&
- APERTURE=$MDXAPERTURE
- fi
- if [[ -n $MDXDM && $resp != n ]]; then
- ask_yn "Do you want the X Window System to be started by xenodm(1)?"
- START_XDM=$resp
- fi
- fi
- if [[ -n $CDEV ]]; then
- _d=${CPROM:-$CDEV}
- [[ -n $CONSOLE ]] && _cdef=yes
- ask_yn "Change the default console to $_d?" $_cdef
- DEFCONS=$resp
- if [[ $resp == y ]]; then
- ask_which "speed" "should $_d use" \
- "9600 19200 38400 57600 115200" $CSPEED
- case $resp in
- done) DEFCONS=n;;
- *) CSPEED=$resp;;
- esac
- fi
- fi
- }
- # Gather information for setting up the user later in do_install().
- user_setup() {
- local _q="Setup a user? (enter a lower-case loginname, or 'no')"
- while :; do
- ask "$_q" no
- case $resp in
- n|no) return
- ;;
- y|yes) _q="No really, what is the lower-case loginname, or 'no'?"
- continue
- ;;
- root|daemon|operator|bin|build|sshd|www|nobody|ftp)
- ;;
- [a-z]*([-a-z0-9_]))
- ((${#resp} <= 31)) && break
- ;;
- esac
- echo "$resp is not a usable loginname."
- done
- ADMIN=$resp
- while :; do
- ask "Full name for user $ADMIN?" "$ADMIN"
- case $resp in
- *[:\&,]*)
- echo "':', '&' or ',' are not allowed."
- ;;
- *)
- ((${#resp} <= 100)) && break
- echo "Too long."
- ;;
- esac
- done
- ADMIN_NAME=$resp
- ask_password "Password for user $ADMIN?"
- ADMIN_PASS=$_password
- ADMIN_KEY=
- $AI && ask "Public ssh key for user $ADMIN" none &&
- [[ $resp != none ]] && ADMIN_KEY=$resp
- }
- # Ask user whether or not to allow logins to root in case sshd(8) is enabled.
- # If no user is setup, show a hint to enable root logins, but warn about risks
- # of doing so.
- ask_root_sshd() {
- typeset -l _resp
- [[ $START_SSHD == y ]] || return
- if [[ -z $ADMIN ]]; then
- echo "Since no user was setup, root logins via sshd(8) might be useful."
- fi
- echo "WARNING: root is targeted by password guessing attacks, pubkeys are safer."
- while :; do
- ask "Allow root ssh login? (yes, no, prohibit-password)" no
- _resp=$resp
- case $_resp in
- y|yes) SSHD_ENABLEROOT=yes
- ;;
- n|no) SSHD_ENABLEROOT=no
- ;;
- w|p|without-password|prohibit-password)
- SSHD_ENABLEROOT=prohibit-password
- ;;
- *) echo "'$resp' is not a valid choice."
- $AI && exit 1
- continue
- ;;
- esac
- break
- done
- }
- # Set TZ variable based on zonefile $1 and user selection.
- set_timezone() {
- local _zonefile=$1 _zonepath _zsed _zoneroot=/usr/share/zoneinfo
- # If the timezone file is not available,
- # return immediately.
- [[ ! -f $_zonefile ]] && return
- # If configured in a previous call, return immediately.
- [[ -n $TZ ]] && return
- if [[ -h /mnt/etc/localtime ]]; then
- TZ=$(ls -l /mnt/etc/localtime 2>/dev/null)
- TZ=${TZ#*${_zoneroot#/mnt}/}
- fi
- wait_cgiinfo
- isin "$CGI_TZ" $(<$_zonefile) && TZ=$CGI_TZ
- # If neither the base or HTTP_LIST gave a hint, and this is the
- # early question, give up, and ask after the sets are installed.
- [[ $_zonefile == /var/tzlist && -z $TZ ]] && return
- while :; do
- ask "What timezone are you in? ('?' for list)" "$TZ"
- _zonepath=${resp%%*(/)}
- case $_zonepath in
- "") continue
- ;;
- "?") grep -v /. $_zonefile | show_cols
- continue
- ;;
- esac
- while isin "$_zonepath/" $(<$_zonefile); do
- ask "What sub-timezone of '$_zonepath' are you in? ('?' for list)"
- _zsed=$(echo $_zonepath/ | sed 's,/,\\/,g')
- resp=${resp%%*(/)}
- case $resp in
- "") ;;
- "?") sed -n "/^$_zsed/{s/$_zsed//;/\/./!p;}" $_zonefile | show_cols;;
- *) _zonepath=$_zonepath/$resp;;
- esac
- done
- if isin "$_zonepath" $(<$_zonefile); then
- TZ=${_zonepath#$_zoneroot}
- return
- fi
- echo -n "'${_zonepath}'"
- echo " is not a valid timezone on this system."
- done
- }
- # Determine if the supplied disk is a potential root disk, by:
- # - Check the disklabel if there is an 'a' partition of type 4.2BSD
- # - Mount the partition (read-only) and look for typical root filesystem layout
- is_rootdisk() {
- local _d=$1 _rc=1
- (
- make_dev $_d
- if disklabel $_d | grep -q '^ a: .*4\.2BSD ' &&
- mount -t ffs -r /dev/${_d}a /mnt; then
- ls -d /mnt/{bin,dev,etc,home,mnt,root,sbin,tmp,usr,var}
- _rc=$?
- umount -f /mnt
- fi
- rm -f /dev/{r,}$_d?
- return $_rc
- ) >/dev/null 2>&1
- }
- # Get global root information. ie. ROOTDISK, ROOTDEV and SWAPDEV.
- get_rootinfo() {
- local _default=$(get_dkdevs_root) _dkdev
- local _q="Which disk is the root disk? ('?' for details)"
- while :; do
- echo "Available disks are: $(get_dkdevs_root | sed 's/^$/none/')."
- _ask "$_q" $_default || continue
- case $resp in
- "?") diskinfo $(get_dkdevs);;
- '') ;;
- *) # Translate $resp to disk dev name in case it is a DUID.
- # get_dkdev_name bounces back the disk dev name if not.
- _dkdev=$(get_dkdev_name "$resp")
- if isin "$_dkdev" $(get_dkdevs); then
- [[ $MODE == install ]] && break
- is_rootdisk "$_dkdev" && break
- echo "$resp is not a valid root disk."
- _default="$(rmel "$_dkdev" $_default) $_dkdev"
- else
- echo "no such disk"
- fi
- ;;
- esac
- $AI && exit 1
- done
- log_answers "$_q" "$resp"
- make_dev $_dkdev || exit
- ROOTDISK=$_dkdev
- ROOTDEV=${ROOTDISK}a
- SWAPDEV=${ROOTDISK}b
- }
- # Parse and "unpack" a hostname.if(5) line given as positional parameters.
- # Fill the _cmds array with the resulting interface configuration commands.
- parse_hn_line() {
- local _af=0 _name=1 _mask=2 _bc=3 _prefix=2 _c _cmd _prev _daddr
- local _has_dhclient=false _has_inet6=false
- set -A _c -- "$@"
- set -o noglob
- ifconfig $_if inet6 >/dev/null 2>&1 && _has_inet6=true
- [[ -x /sbin/dhclient ]] && _has_dhclient=true
- case ${_c[_af]} in
- ''|*([[:blank:]])'#'*)
- return
- ;;
- inet) ((${#_c[*]} > 1)) || return
- [[ ${_c[_name]} == alias ]] && _mask=3 _bc=4
- [[ -n ${_c[_mask]} ]] && _c[_mask]="netmask ${_c[_mask]}"
- if [[ -n ${_c[_bc]} ]]; then
- _c[_bc]="broadcast ${_c[_bc]}"
- [[ ${_c[_bc]} == *NONE ]] && _c[_bc]=
- fi
- _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}"
- ;;
- inet6) ! $_has_inet6 && return
- ((${#_c[*]} > 1)) || return
- if [[ ${_c[_name]} == autoconf ]]; then
- _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}"
- V6_AUTOCONF=true
- return
- fi
- [[ ${_c[_name]} == alias ]] && _prefix=3
- [[ -n ${_c[_prefix]} ]] && _c[_prefix]="prefixlen ${_c[_prefix]}"
- _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}"
- ;;
- dest) ((${#_c[*]} == 2)) && _daddr=${_c[1]} || return
- ! $_has_inet6 && [[ $_daddr == @(*:*) ]] && return
- _prev=$((${#_cmds[*]} - 1))
- ((_prev >= 0)) || return
- set -A _c -- ${_cmds[_prev]}
- _name=3
- [[ ${_c[_name]} == alias ]] && _name=4
- _c[_name]="${_c[_name]} $_daddr"
- _cmds[$_prev]="${_c[@]}"
- ;;
- dhcp) ! $_has_dhclient && return
- _c[0]=
- _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]} up;dhclient $_if"
- V4_DHCPCONF=true
- ;;
- '!'*|bridge)
- # Skip shell commands and bridge in the installer.
- return
- ;;
- *) _cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}"
- ;;
- esac
- unset _c
- set +o noglob
- }
- # Start interface using the on-disk hostname.if file passed as argument $1.
- # Much of this is gratuitously stolen from /etc/netstart.
- ifstart() {
- local _if=$1 _hn=/mnt/etc/hostname.$1 _cmds _i=0 _line
- set -A _cmds
- # Create interface if it does not yet exist.
- { ifconfig $_if || ifconfig $_if create; } >/dev/null 2>&1 || return
- ((NIFS++))
- # Parse the hostname.if(5) file and fill _cmds array with interface
- # configuration commands.
- set -o noglob
- while IFS= read -- _line; do
- parse_hn_line $_line
- done <$_hn
- # Apply the interface configuration commands stored in _cmds array.
- while ((_i < ${#_cmds[*]})); do
- eval "${_cmds[_i]}"
- ((_i++))
- done
- unset _cmds
- set +o noglob
- }
- # Configure the network during upgrade based on the on-disk configuration.
- enable_network() {
- local _f _gw _hn _if _trunks _svlans _vlans
- # Use installed network configuration files during upgrade.
- for _f in resolv.conf resolv.conf.tail; do
- if [[ -f /mnt/etc/$_f ]]; then
- cp /mnt/etc/$_f /etc/$_f
- fi
- done
- # Create a minimal hosts file.
- echo "127.0.0.1\tlocalhost" >/tmp/i/hosts
- echo "::1\t\tlocalhost" >>/tmp/i/hosts
- _f=/mnt/etc/soii.key
- [[ -f $_f ]] && sysctl "net.inet6.ip6.soiikey=$(<$_f)"
- # Set the address for the loopback interface. Bringing the
- # interface up, automatically invokes the IPv6 address ::1.
- ifconfig lo0 inet 127.0.0.1/8
- # Configure all of the non-loopback interfaces which we know about.
- # Refer to hostname.if(5)
- for _hn in /mnt/etc/hostname.*; do
- # Strip off prefix to get interface name.
- _if=${_hn#/mnt/etc/hostname.}
- if isin "${_if%%+([0-9])}" $(ifconfig -C); then
- # Dynamic interfaces must be done later.
- case ${_if%%+([0-9])} in
- trunk) _trunks="$_trunks $_if";;
- svlan) _svlans="$_svlans $_if";;
- vlan) _vlans="$_vlans $_if";;
- esac
- else
- # 'Real' interfaces (if available) are done now.
- ifconfig $_if >/dev/null 2>&1 && ifstart $_if
- fi
- done
- # Configure any dynamic interfaces now that 'real' ones are up.
- # ORDER IS IMPORTANT! (see /etc/netstart).
- for _if in $_trunks $_svlans $_vlans; do
- ifstart $_if
- done
- # /mnt/etc/mygate, if it exists, contains the address(es) of my
- # default gateway(s). Use for ipv4 if no interfaces configured via
- # dhcp. Use for ipv6 if no interfaces configured via autoconf.
- ! $V4_DHCPCONF && stripcom /mnt/etc/mygate |
- while read _gw; do
- [[ $_gw == @(*:*) ]] && continue
- route -qn add -host default $_gw && break
- done
- ! $V6_AUTOCONF && stripcom /mnt/etc/mygate |
- while read _gw; do
- [[ $_gw == !(*:*) ]] && continue
- route -qn add -host -inet6 default $_gw && break
- done
- route -qn add -net 127 127.0.0.1 -reject >/dev/null
- }
- # Fetch the list of mirror servers and installer choices from previous runs if
- # available from ftplist.cgi. Start the ftp process in the background, but kill
- # it if it takes longer than 12 seconds.
- start_cgiinfo() {
- # If no networks are configured, we do not need the httplist file.
- ((NIFS < 1)) && return
- # Ensure proper name resolution in case there's no dns yet.
- add_hostent 47.186.116.162 libertybsd.net
- add_hostent 47.186.116.162 ftp.libertybsd.net
- # Make sure the ftp subshell gets its own process group.
- set -m
- (
- unpriv2 ftp -w 15 -Vao - \
- "$HTTP_PROTO://ftp.libertybsd.net/pub/mirrors.txt" \
- 2>/dev/null >$CGI_INFO
- # Remember finish time for adjusting the received timestamp.
- echo -n $SECONDS >$HTTP_SEC
- feed_random
- ) & CGIPID=$!
- set +m
- # If the ftp process takes more than 12 seconds, kill it.
- # XXX We are relying on the pid space not randomly biting us.
- # XXX ftp could terminate early, and the pid could be reused.
- (sleep 12; kill -INT -$CGIPID >/dev/null 2>&1) &
- }
- # Create a skeletal but useful /etc/fstab from /tmp/i/fstab by stripping all
- # comment lines and dropping all filesystems which
- #
- # 1) can't be mounted (no mount_* command is found),
- # 2) have 'xx' in the option field (usually /altroot),
- # 3) have 'noauto' in the option field,
- # 4) are nfs (since name resolution may not be present),
- # 5) are on a vnd device.
- #
- # In addition,
- #
- # 1) delete 'softdep' options (no soft updates in ramdisk kernels),
- # 2) mount non-ffs filesystems read only,
- # 3) prepend '/mnt' to all mount points,
- # 4) delete any trailing '/' from the mount point (e.g. root),
- #
- # If no /etc/fstab is created, do not proceed with install/upgrade.
- munge_fstab() {
- local _dev _mp _fstype _opt _rest
- while read _dev _mp _fstype _opt _rest; do
- # Drop irrelevant lines and filesystems.
- [[ $_dev == @(/dev/vnd*|\#*) ||
- $_fstype == nfs ||
- ! -f /sbin/mount_$_fstype ||
- $_opt == *noauto* ||
- $_opt == *xx* ]] && continue
- # Remove any softdep options, as soft updates are not
- # available in the ramdisk kernels.
- _opt=$(echo $_opt | sed 's/softdep//')
- # Change read-only ffs to read-write since we'll potentially
- # write to these filesystems.
- # Mount non-ffs filesystems read only.
- if [[ $_fstype == ffs ]]; then
- _opt=$(echo $_opt | sed 's/[[:<:]]ro[[:>:]]/rw/')
- else
- _opt=$(echo $_opt | sed 's/[[:<:]]rw[[:>:]]/ro/')
- fi
- # Write fs entry in fstab.
- # 1) prepend '/mnt' to the mount point.
- # 2) remove a trailing '/' from the mount point (e.g. root).
- echo $_dev /mnt${_mp%/} $_fstype $_opt $_rest
- done </tmp/i/fstab >/etc/fstab
- # If no /etc/fstab was created, we have nowhere to $MODE to.
- if [[ ! -s /etc/fstab ]]; then
- echo "Unable to create valid /etc/fstab."
- exit
- fi
- }
- # Preen all filesystems in /etc/fstab that have a /sbin/fsck_XXX and a
- # fs_passno > 0, showing individual results, but skipping $ROOTDEV. This was
- # already fsck'ed successfully.
- #
- # Exit if any fsck's fail (but do them all before exiting!).
- check_fs() {
- local _dev _dn _mp _fstype _rest _fail _f _passno
- ask_yn "Force checking of clean non-root filesystems?" && _f=f
- while read _dev _mp _fstype _rest _rest _passno _rest; do
- _dn=$(get_dkdev_name "$_dev")
- [[ $ROOTDEV == @(${_dev#/dev/}|$_dn${_dev##*.}) ]] && continue
- [[ -f /sbin/fsck_$_fstype ]] || continue
- # Make sure device exists before fsck'ing it.
- make_dev "$_dn" || continue
- ((_passno > 0)) || continue
- echo -n "fsck -${_f}p $_dev..."
- if ! fsck -${_f}p $_dev >/dev/null 2>&1; then
- echo " FAILED. You must fsck $_dev manually."
- _fail=y
- else
- echo " OK."
- fi
- done </etc/fstab
- [[ -n $_fail ]] && exit
- }
- # Must mount filesystems manually, one at a time, so we can make sure the mount
- # points exist.
- mount_fs() {
- local _async=$1 _dev _mp _fstype _opt _rest _msg _fail
- while read _dev _mp _fstype _opt _rest; do
- # If not the root filesystem, make sure the mount
- # point is present.
- [[ $_mp == /mnt ]] || mkdir -p $_mp
- # Mount the filesystem. Remember any failure.
- _msg=$(mount -v -t $_fstype $_async -o $_opt $_dev $_mp) ||
- _fail="$_fail\n$_mp ($_dev)"
- echo $_msg | sed 's/, ctime=[^,)]*//'
- done </etc/fstab
- if [[ -n $_fail ]]; then
- # One or more mounts failed. Continue or abort?
- echo "\nWARNING! The following filesystems were not properly mounted:$_fail"
- ask_yn "Continue anyway?" || exit
- fi
- }
- # Feed the random pool some entropy before we read from it.
- feed_random() {
- (dmesg; cat $CGI_INFO /*.conf; sysctl; route -n show; df;
- ifconfig -A; hostname) >/dev/random 2>&1
- if [[ -e /mnt/var/db/host.random ]]; then
- dd if=/mnt/var/db/host.random of=/dev/random bs=65536 count=1 \
- status=none
- fi
- }
- # Ask the user for locations of sets, and then install whatever sets the user
- # selects from that location. Repeat as many times as the user needs to get all
- # desired sets.
- install_sets() {
- local _cddevs=$(get_cddevs) _d _im _locs="disk http" _src
- echo
- # Set default location to method recorded last time.
- _d=$CGI_METHOD
- # Set default location to HTTP in case we netbooted.
- ifconfig netboot >/dev/null 2>&1 && : ${_d:=http}
- # Set default location to HTTP if installurl(5) exists.
- [[ -s /mnt/etc/installurl ]] && _d=http
- # Set default location to the first cdrom device if any are found.
- [[ -n $_cddevs ]] && : ${_d:=cd0}
- # Add NFS to set locations if the boot kernel supports it.
- [[ -x /sbin/mount_nfs ]] && _locs="$_locs nfs"
- # In case none of the above applied, set HTTP as default location.
- : ${_d:=http}
- # If the default location set so far is not one of the cdrom devices or
- # is not in the list of valid locations, set a sane default.
- if ! isin "$_d" $_cddevs $_locs; then
- for _src in http $_cddevs nfs disk; do
- isin "$_src" $_cddevs $_locs && _d=$_src && break
- done
- fi
- echo "Let's $MODE the sets!"
- while :; do
- # Get list of cdroms again in case one just got plugged in.
- _cddevs=$(get_cddevs)
- umount -f /mnt2 >/dev/null 2>&1
- ask "Location of sets? (${_cddevs:+$_cddevs }$_locs or 'done')" "$_d"
- case $resp in
- done) sane_install && return
- ;;
- [cC]*) if [[ -n $_cddevs ]]; then
- set -- $_cddevs
- [[ $resp == [cC]?([dD]) ]] && resp=$1
- _im=$resp
- install_cdrom $resp && INSTALL_METHOD=$_im
- fi
- ;;
- [dD]*) install_disk && INSTALL_METHOD=disk
- ;;
- [hH]*) isin http $_locs && install_http && INSTALL_METHOD=http
- ;;
- [nN]*) isin nfs $_locs && install_nfs && INSTALL_METHOD=nfs
- ;;
- *) $AI && err_exit "'$resp' is not a valid choice."
- ;;
- esac
- # Preserve the selected install source selection.
- [[ -n $INSTALL_METHOD ]] && _d=$INSTALL_METHOD
- # Set default to 'done' to leave the while-loop.
- sane_install quiet || $AI && _d=done
- done
- }
- # Apply configuration settings based on the previously gathered information.
- apply() {
- if [[ $START_SSHD == n ]]; then
- echo "sshd_flags=NO" >>/mnt/etc/rc.conf.local
- elif [[ -n $SSHD_ENABLEROOT ]]; then
- # Only change sshd_config if the user choice is not the default.
- if ! grep -q "^#PermitRootLogin $SSHD_ENABLEROOT\$" \
- /mnt/etc/ssh/sshd_config; then
- sed -i "s/^#\(PermitRootLogin\) .*/\1 $SSHD_ENABLEROOT/" \
- /mnt/etc/ssh/sshd_config
- fi
- fi
- [[ -n $APERTURE ]] &&
- echo "machdep.allowaperture=$APERTURE # See xf86(4)" \
- >>/mnt/etc/sysctl.conf
- [[ $START_XDM == y && -x /mnt/usr/X11R6/bin/xenodm ]] &&
- echo "xenodm_flags=" >>/mnt/etc/rc.conf.local
- if [[ $DEFCONS == y ]]; then
- cp /mnt/etc/ttys /tmp/i/ttys
- sed -e "/^$CTTY/s/std.9600/std.${CSPEED}/" \
- -e "/^$CTTY/s/std.115200/std.${CSPEED}/" \
- -e "/^$CTTY/s/unknown/vt220 /" \
- -e "/$CTTY/s/off.*/on secure/" /tmp/i/ttys >/mnt/etc/ttys
- [[ -n $CPROM ]] &&
- echo "stty $CPROM $CSPEED\nset tty $CPROM" \
- >>/mnt/etc/boot.conf
- fi
- ln -sf /usr/share/zoneinfo/$TZ /mnt/etc/localtime
- }
- # Return string suitable for the encrypted password field in master.passwd.
- #
- # 1) Without argument, return a single '*'.
- # 2) Return argument unchanged if it looks like a encrypted password string
- # or if it consists of just 13 asterisks.
- # 3) Otherwise return encrypted password string.
- #
- encr_pwd() {
- local _p=$1
- if [[ -z $_p ]]; then
- echo '*'
- elif [[ $_p == \$2?\$[0-9][0-9]\$* && ${#_p} > 40 ||
- $_p == '*************' ]]; then
- echo "$_p"
- else
- encrypt -b a -- "$_p"
- fi
- }
- # Store entropy for the next boot.
- store_random() {
- dd if=/dev/random of=/mnt/var/db/host.random bs=65536 count=1 \
- status=none
- dd if=/dev/random of=/mnt/etc/random.seed bs=512 count=1 status=none
- chmod 600 /mnt/var/db/host.random /mnt/etc/random.seed
- }
- # Final steps common for installs and upgrades.
- finish_up() {
- local _dev _mp _fstype _rest _d
- local _kernel_dir=/mnt/usr/share/relink/kernel
- local _kernel=${MDKERNEL:-GENERIC} _syspatch_archs="amd64 arm64 i386"
- # Mount all known swap partitions. This gives systems with little
- # memory a better chance at running 'MAKEDEV all'.
- if [[ -x /mnt/sbin/swapctl ]]; then
- /mnt/sbin/swapctl -a /dev/$SWAPDEV >/dev/null 2>&1
- # Can't do chmod && swapctl -A because devices are not yet
- # created on install'ed systems. On upgrade'ed system there
- # is a small chance the device does not exist on the ramdisk
- # and will thus not get mounted.
- while read _dev _mp _fstype _rest; do
- [[ $_fstype == swap ]] &&
- /mnt/sbin/swapctl -a $_dev >/dev/null 2>&1
- done </mnt/etc/fstab
- fi
- # Create /etc/installurl if it does not yet exist.
- if [[ ! -f /mnt/etc/installurl ]]; then
- echo "${INSTALL_URL:-https://ftp.libertybsd.net/pub/LibertyBSD}" \
- >/mnt/etc/installurl
- fi
- echo -n "Making all device nodes..."
- (cd /mnt/dev; sh MAKEDEV all
- # Make sure any devices we found during probe are created in the
- # installed system.
- for _dev in $(get_dkdevs) $(get_cddevs); do
- sh MAKEDEV $_dev
- done
- )
- echo " done."
- # We may run some programs in chroot, and some of them might be
- # dynamic. That is highly discouraged, but let us play it safe.
- rm -f /mnt/var/run/ld.so.hints
- # Conditionally create /usr/{src,obj,xobj} directories and set
- # proper ownership and permissions during install.
- if [[ $MODE == install ]]; then
- mkdir -p /mnt/usr/{src,{,x}obj} && (
- cd /mnt/usr
- chmod 770 {,x}obj
- chown build:wobj {,x}obj
- chmod 775 src
- chown root:wsrc src
- )
- fi
- # In case this is a softraid device, make sure all underlying
- # device nodes exist before installing boot-blocks on disk.
- make_dev $(bioctl $ROOTDISK 2>/dev/null | sed -n 's/.*<\(.*\)>$/\1/p')
- md_installboot $ROOTDISK
- chmod og-rwx /mnt/bsd{,.mp,.rd} 2>/dev/null
- if [[ -f /mnt/bsd.mp ]] && ((NCPU > 1)); then
- _kernel=$_kernel.MP
- echo "Multiprocessor machine; using bsd.mp instead of bsd."
- mv /mnt/bsd /mnt/bsd.sp 2>/dev/null
- mv /mnt/bsd.mp /mnt/bsd
- fi
- # Write kernel.SHA256 matching the just installed kernel and fix path to
- # ensure it references the kernel as /bsd.
- sha256 /mnt/bsd | (umask 077; sed 's,/mnt,,' >/mnt/var/db/kernel.SHA256)
- if [[ -f $_kernel_dir.tgz ]]; then
- echo -n "Relinking to create unique kernel..."
- (
- set -e
- rm -rf $_kernel_dir
- mkdir -m 700 -p $_kernel_dir
- tar -C $_kernel_dir -xzf $_kernel_dir.tgz $_kernel
- rm -f $_kernel_dir.tgz
- chroot /mnt /bin/ksh -e -c "cd ${_kernel_dir#/mnt}/$_kernel; \
- make newbsd; make newinstall"
- ) >/dev/null 2>&1 && echo " done." || echo " failed."
- fi
- # Ensure that sysmerge in batch mode is run on reboot.
- [[ $MODE == upgrade ]] &&
- echo "/usr/sbin/sysmerge -b" >>/mnt/etc/rc.sysmerge
- # If a proxy was needed to fetch the sets, use it for syspatch
- [[ -n $http_proxy ]] &&
- quote export "http_proxy=$http_proxy" >>/mnt/etc/rc.firsttime
- # Run syspatch -c on reboot if the arch is supported and if it is a
- # release system (not -stable or -current). List uninstalled syspatches
- # on the console and in the rc.firsttime output mail.
- isin "$ARCH" $_syspatch_archs && cat <<__EOT >>/mnt/etc/rc.firsttime
- set -A _KERNV -- \$(sysctl -n kern.version |
- sed 's/^OpenBSD \([0-9]\.[0-9]\)\([^ ]*\).*/\1 \2/;q')
- if ((\${#_KERNV[*]} == 1)) && [[ -s /etc/installurl ]] &&
- _CKPATCH=\$(mktemp /tmp/_ckpatch.XXXXXXXXXX); then
- echo "Checking for available binary patches..."
- syspatch -c > \$_CKPATCH
- if [[ -s \$_CKPATCH ]]; then
- echo "Run syspatch(8) to install:"
- column -xc 80 \$_CKPATCH
- fi
- rm -f \$_CKPATCH
- fi
- __EOT
- # Email installer questions and their answers to root on next boot.
- prep_root_mail /tmp/i/$MODE.resp "$(hostname) $MODE response file"
- if [[ -x /mnt/$MODE.site ]]; then
- if ! chroot /mnt /$MODE.site; then
- store_random
- err_exit "$MODE.site failed"
- fi
- fi
- # Store entropy for the next boot.
- store_random
- # Pat on the back.
- cat <<__EOT
- CONGRATULATIONS! Your LibertyBSD $MODE has been successfully completed!
- __EOT
- [[ $MODE == install ]] && cat <<__EOT
- When you login to your new system the first time, please read your mail
- using the 'mail' command.
- __EOT
- md_congrats
- $AI && >/tmp/ai/ai.done
- }
- do_autoinstall() {
- rm -f /tmp/ai/ai.done
- echo "Performing non-interactive $AI_MODE..."
- /$AI_MODE -af /tmp/ai/ai.$AI_MODE.conf 2>&1 </dev/null |
- tee /dev/stderr | sed "s/^.*$(echo '\r')//" >/tmp/ai/ai.log
- $UU || [[ -f /tmp/ai/ai.done ]] ||
- err_exit "failed; check /tmp/ai/ai.log"
- # Email autoinstall protocol to root on next boot.
- prep_root_mail /tmp/ai/ai.log "$(hostname) $AI_MODE log"
- # SYSUP-COMPAT
- if $UU; then
- cat <<__EOT >>/mnt/etc/rc.firsttime
- [[ ! -e /home/_sysupgrade/keep ]] && rm -f /home/_sysupgrade/*
- __EOT
- fi
- exec reboot
- }
- do_install() {
- local _rootkey _rootpass
- # Ask for and set the system hostname and add the hostname specific
- # siteXX set.
- while :; do
- ask_until "System hostname? (short form, e.g. 'foo')" \
- "$(hostname -s)"
- [[ $resp != *+([[:cntrl:]]|[[:space:]])* ]] && break
- echo "Invalid hostname."
- $AI && exit 1
- done
- [[ ${resp%%.*} != $(hostname -s) ]] && hostname "$resp"
- ALLSETS="$ALLSETS site$VERSION-$(hostname -s).tgz"
- export PS1='\h# '
- echo
- # Configure the network.
- donetconfig
- # Fetch list of mirror servers and installer choices from previous runs.
- start_cgiinfo
- echo
- while :; do
- ask_password "Password for root account?"
- _rootpass="$_password"
- [[ -n "$_password" ]] && break
- echo "The root password must be set."
- done
- # Ask for the root user public ssh key during autoinstall.
- _rootkey=
- if $AI; then
- ask "Public ssh key for root account?" none
- [[ $resp != none ]] && _rootkey=$resp
- fi
- # Ask user about daemon startup on boot, X Window usage and console
- # setup.
- questions
- # Gather information for setting up the initial user account.
- user_setup
- ask_root_sshd
- # Set TZ variable based on zonefile and user selection.
- set_timezone /var/tzlist
- echo
- # Get information about ROOTDISK, etc.
- get_rootinfo
- DISKS_DONE=
- FSENT=
- # Remove traces of previous install attempt.
- rm -f /tmp/i/fstab*
- # Configure the disk(s).
- while :; do
- # Always do ROOTDISK first, and repeat until it is configured.
- if ! isin "$ROOTDISK" $DISKS_DONE; then
- resp=$ROOTDISK
- rm -f /tmp/i/fstab
- else
- # Force the user to think and type in a disk name by
- # making 'done' the default choice.
- ask_which "disk" "do you wish to initialize" \
- '$(get_dkdevs_uninitialized)' done
- [[ $resp == done ]] && break
- fi
- _disk=$resp
- configure_disk $_disk || continue
- DISKS_DONE=$(addel $_disk $DISKS_DONE)
- done
- # Write fstab entries to fstab in mount point alphabetic order
- # to enforce a rational mount order.
- for _mp in $(bsort $FSENT); do
- _pp=${_mp##*!}
- _mp=${_mp%!*}
- echo -n "$_pp $_mp ffs rw"
- # Only '/' is neither nodev nor nosuid. i.e. it can obviously
- # *always* contain devices or setuid programs.
- [[ $_mp == / ]] && { echo " 1 1"; continue; }
- # Every other mounted filesystem is nodev. If the user chooses
- # to mount /dev as a separate filesystem, then on the user's
- # head be it.
- echo -n ",nodev"
- # The only directories that the install puts suid binaries into
- # (as of 3.2) are:
- #
- # /sbin
- # /usr/bin
- # /usr/sbin
- # /usr/libexec
- # /usr/libexec/auth
- # /usr/X11R6/bin
- #
- # and ports and users can do who knows what to /usr/local and
- # sub directories thereof.
- #
- # So try to ensure that only filesystems that are mounted at
- # or above these directories can contain suid programs. In the
- # case of /usr/libexec, give blanket permission for
- # subdirectories.
- case $_mp in
- /sbin|/usr) ;;
- /usr/bin|/usr/sbin) ;;
- /usr/libexec|/usr/libexec/*) ;;
- /usr/local|/usr/local/*) ;;
- /usr/X11R6|/usr/X11R6/bin) ;;
- *) echo -n ",nosuid" ;;
- esac
- echo " 1 2"
- done >>/tmp/i/fstab
- # Create a skeletal /etc/fstab which is usable for the installation
- # process.
- munge_fstab
- # Use async options for faster mounts of the filesystems.
- mount_fs "-o async"
- # Feed the random pool some entropy before we read from it.
- feed_random
- # Ask the user for locations, and install whatever sets the user
- # selected.
- install_sets
- # Set 'wxallowed' mount option for the filesystem /usr/local resides on.
- _mp=$(df /mnt/usr/local | sed '$!d')
- _mp=${_mp##*/mnt}
- sed -i "s#\(${_mp:-/} ffs rw\)#\1,wxallowed#" /tmp/i/fstab
- # If we did not succeed at setting TZ yet, we try again
- # using the timezone names extracted from the base set.
- if [[ -z $TZ ]]; then
- (cd /mnt/usr/share/zoneinfo
- ls -1dF $(tar cvf /dev/null [A-Za-y]*) >/mnt/tmp/tzlist )
- echo
- set_timezone /mnt/tmp/tzlist
- rm -f /mnt/tmp/tzlist
- fi
- # If we got a timestamp from the cgi server, and that time diffs by more
- # than 120 seconds, ask if the user wants to adjust the time.
- if _time=$(http_time) && _now=$(date +%s) &&
- (( _now - _time > 120 || _time - _now > 120 )); then
- _tz=/mnt/usr/share/zoneinfo/$TZ
- if ask_yn "Time appears wrong. Set to '$(TZ=$_tz date -r "$(http_time)")'?" yes; then
- # We do not need to specify TZ below since both date
- # invocations use the same one.
- date $(date -r "$(http_time)" "+%Y%m%d%H%M.%S") >/dev/null
- # N.B. This will screw up SECONDS.
- fi
- fi
- if [[ -s $HTTP_LIST ]]; then
- _i=${INSTALL_URL:+install=$INSTALL_URL&}
- _i=$_i${TZ:+TZ=$TZ&}
- _i=$_i${INSTALL_METHOD:+method=$INSTALL_METHOD}
- _i=${_i%&}
- [[ -n $_i ]] && unpriv2 ftp -w 15 -Vao - \
- "$HTTP_PROTO://ftp.libertybsd.net/pub/mirrors.txt" \
- >/dev/null 2>&1 &
- fi
- # Ensure an enabled console has the correct speed in /etc/ttys.
- sed "/^console.*on.*secure.*$/s/std\.[0-9]*/std.$(stty speed </dev/console)/" \
- /mnt/etc/ttys >/tmp/i/ttys
- mv /tmp/i/ttys /mnt/etc/ttys
- echo -n "Saving configuration files..."
- # Save any leases obtained during install.
- (cd /var/db; for _f in dhclient.leases.*; do
- [[ -f $_f ]] && mv $_f /mnt/var/db/.
- done)
- # Move configuration files from /tmp/i/ to /mnt/etc.
- hostname >/tmp/i/myname
- # Append entries to installed hosts file, changing '1.2.3.4 hostname'
- # to '1.2.3.4 hostname.$FQDN hostname'. Leave untouched lines containing
- # domain information or aliases. These are lines the user added/changed
- # manually.
- # Add common entries.
- echo "127.0.0.1\tlocalhost" >/mnt/etc/hosts
- echo "::1\t\tlocalhost" >>/mnt/etc/hosts
- # Note we may have no hosts file if no interfaces were configured.
- if [[ -f /tmp/i/hosts ]]; then
- # Remove the entry for *libertybsd.net
- sed -i '/^47\.186\.116\.162 /d' /tmp/i/hosts
- _dn=$(get_fqdn)
- while read _addr _hn _aliases; do
- if [[ -n $_aliases || $_hn != ${_hn%%.*} || -z $_dn ]]; then
- echo "$_addr\t$_hn $_aliases"
- else
- echo "$_addr\t$_hn.$_dn $_hn"
- fi
- done </tmp/i/hosts >>/mnt/etc/hosts
- rm /tmp/i/hosts
- fi
- # Possible files to copy from /tmp/i/: fstab hostname.* kbdtype mygate
- # myname ttys boot.conf resolv.conf sysctl.conf resolv.conf.tail
- # Save only non-empty (-s) regular (-f) files.
- (cd /tmp/i; for _f in fstab hostname* kbdtype my* ttys *.conf *.tail; do
- [[ -f $_f && -s $_f ]] && mv $_f /mnt/etc/.
- done)
- echo " done."
- # Apply configuration settings based on information from questions().
- apply
- # Create user account based on information from user_setup().
- if [[ -n $ADMIN ]]; then
- _encr=$(encr_pwd "$ADMIN_PASS")
- _home=/home/$ADMIN
- uline="${ADMIN}:${_encr}:1000:1000:staff:0:0:${ADMIN_NAME}:$_home:/bin/ksh"
- echo "$uline" >>/mnt/etc/master.passwd
- echo "${ADMIN}:*:1000:" >>/mnt/etc/group
- echo $ADMIN >/mnt/root/.forward
- _home=/mnt$_home
- mkdir -p $_home
- (cd /mnt/etc/skel; pax -rw -k -pe . $_home)
- (umask 077 && sed "s,^To: root\$,To: ${ADMIN_NAME} <${ADMIN}>," \
- /mnt/var/mail/root >/mnt/var/mail/$ADMIN )
- chown -R 1000:1000 $_home /mnt/var/mail/$ADMIN
- sed -i -e "s@^wheel:.:0:root\$@wheel:\*:0:root,${ADMIN}@" \
- /mnt/etc/group 2>/dev/null
- # During autoinstall, add public ssh key to authorized_keys.
- [[ -n "$ADMIN_KEY" ]] &&
- print -r -- "$ADMIN_KEY" >>$_home/.ssh/authorized_keys
- fi
- # Store root password and rebuild password database.
- if [[ -n "$_rootpass" ]]; then
- _encr=$(encr_pwd "$_rootpass")
- sed -i -e "s@^root::@root:${_encr}:@" /mnt/etc/master.passwd \
- 2>/dev/null
- fi
- pwd_mkdb -p -d /mnt/etc /etc/master.passwd
- # During autoinstall, add root user's public ssh key to authorized_keys.
- [[ -n "$_rootkey" ]] && (
- umask 077
- print -r -- "$_rootkey" >>/mnt/root/.ssh/authorized_keys
- )
- # Perform final steps common to both an install and an upgrade.
- finish_up
- }
- do_upgrade() {
- local _f
- # Get $ROOTDISK and $ROOTDEV
- get_rootinfo
- echo -n "Checking root filesystem (fsck -fp /dev/$ROOTDEV)..."
- fsck -fp /dev/$ROOTDEV >/dev/null 2>&1 || { echo "FAILED."; exit; }
- echo " OK."
- echo -n "Mounting root filesystem (mount -o ro /dev/$ROOTDEV /mnt)..."
- mount -o ro /dev/$ROOTDEV /mnt || { echo "FAILED."; exit; }
- echo " OK."
- # The fstab and myname files are required.
- for _f in /mnt/etc/{fstab,myname}; do
- [[ -f $_f ]] || { echo "No $_f!"; exit; }
- cp $_f /tmp/i/${_f##*/}
- done
- # Set system hostname and register hostname specific site set.
- hostname $(stripcom /tmp/i/myname)
- ALLSETS="$ALLSETS site$VERSION-$(hostname -s).tgz"
- export PS1='\h# '
- # Configure the network.
- enable_network
- # Fetch list of mirror servers and installer choices from previous runs.
- start_cgiinfo
- # Create a skeletal /etc/fstab which is usable for the upgrade process.
- munge_fstab
- # fsck -p non-root filesystems in /etc/fstab.
- check_fs
- # Mount filesystems in /etc/fstab.
- umount /mnt || { echo "Can't umount $ROOTDEV!"; exit; }
- mount_fs
- rm -f /mnt/bsd.upgrade /mnt/auto_upgrade.conf
- # Feed the random pool some entropy before we read from it.
- feed_random
- # Ensure that previous installer choices (e.g. method) are available.
- wait_cgiinfo
- # Ask the user for locations, and install whatever sets the user
- # selected.
- install_sets
- # Perform final steps common to both an install and an upgrade.
- finish_up
- }
- check_unattendedupgrade() {
- local _d=$(get_dkdevs_root) _rc=1
- _d=${_d%% *}
- (
- if [[ -n $_d ]]; then
- make_dev $_d
- if mount -t ffs -r /dev/${_d}a /mnt; then
- ### NOTYET (uncomment once SYSUP-COMPAT is gone)
- #[[ -f /mnt/bsd.upgrade && -f /mnt/auto_upgrade.conf ]]
- #_rc=$?
- #((_rc == 0)) && cp /mnt/auto_upgrade.conf /
- ### BEGIN SYSUP-COMPAT
- ls /mnt/bsd.upgrade
- _rc=$?
- if ((_rc == 0)); then
- if [[ -f /mnt/auto_upgrade.conf ]]; then
- cp /mnt/auto_upgrade.conf /
- else
- cat <<__EOT >/auto_upgrade.conf
- Location of sets = disk
- Pathname to the sets = /home/_sysupgrade/
- Set name(s) = done
- Directory does not contain SHA256.sig. Continue without verification = yes
- __EOT
- fi
- fi
- ### END SYSUP-COMPAT
- umount -f /mnt
- fi
- rm -f /dev/{r,}$_d?
- fi
- return $_rc
- ) > /dev/null 2>&1
- }
- WATCHDOG_PERIOD_SEC=$((30 * 60))
- # Restart the background timer.
- reset_watchdog() {
- kill -KILL $WDPID 2>/dev/null
- start_watchdog
- }
- # Start a co-process to reboot a stalled sysupgrade.
- # This mechanism is only used during non-interactive sysupgrade.
- start_watchdog() {
- (
- sleep $WATCHDOG_PERIOD_SEC && reboot
- ) |&
- WDPID=$!
- # Close standard input of the co-process.
- exec 3>&p; exec 3>&-
- }
- # ------------------------------------------------------------------------------
- # Initial actions common to both installs and upgrades.
- #
- # Some may require machine dependent routines, which may call functions defined
- # above, so it's safest to put this code here rather than at the top.
- # ------------------------------------------------------------------------------
- # Parse parameters.
- AI=false
- UU=false
- MODE=
- PROGNAME=${0##*/}
- AI_RESPFILE=
- while getopts "af:m:x" opt; do
- case $opt in
- a) AI=true;;
- f) AI_RESPFILE=$OPTARG;;
- m) MODE=$OPTARG;;
- x) UU=true;;
- *) usage;;
- esac
- done
- shift $((OPTIND-1))
- (($# == 0)) || usage
- # The installer can be started by using the symbolic links 'install', 'upgrade'
- # and 'autoinstall' pointing to this script. Set MODE and AI based on that.
- if [[ -z $MODE ]]; then
- case $PROGNAME in
- autoinstall) AI=true;;
- install|upgrade) MODE=$PROGNAME;;
- *) exit 1;;
- esac
- fi
- # Do not limit ourselves during installs or upgrades.
- for _opt in d f l m n p s; do
- ulimit -$_opt unlimited
- done
- # umount all filesystems, just in case we are re-running install or upgrade.
- cd /
- umount -af >/dev/null 2>&1
- # Include machine-dependent functions and definitions.
- #
- # The following functions must be provided:
- # md_congrats() - display friendly message
- # md_installboot() - install boot-blocks on disk
- # md_prep_disklabel() - put an OpenBSD disklabel on the disk
- # md_consoleinfo() - set CDEV, CTTY, CSPEED, CPROM
- #
- # The following variables can be provided if required:
- # MDEFI - set to 'y' on archs that support GPT partitioning
- # MDROOTFSOPT - newfs options for the root partition
- # MDSETS - list of files to add to DEFAULT and ALLSETS
- # MDSANESETS - list of files to add to SANESETS
- # MDTERM - 'vt220' assumed if not provided
- # MDDKDEVS - '/^[sw]d[0-9][0-9]* /s/ .*//p' assumed if not provided
- # MDCDDEVS - '/^cd[0-9][0-9]* /s/ .*//p' assumed if not provided
- # MDXAPERTURE - set machdep.allowaperture=value in sysctl.conf
- # MDXDM - ask if xdm should be started if set to 'y'
- # NCPU - the number of cpus for mp capable arches
- # MDKERNEL - the name of the boot kernel
- # MDHALT - default to 'halt' at the end of installs if set to 'y'
- . install.md
- # Start listener process looking for dmesg changes.
- start_dmesg_listener
- CGI_INFO=/tmp/i/cgiinfo
- CGI_METHOD=
- CGI_TIME=
- CGI_TZ=
- export EDITOR=ed
- HTTP_DIR=
- HTTP_LIST=/tmp/i/httplist
- HTTP_SEC=/tmp/i/httpsec
- INSTALL_METHOD=
- NIFS=0
- export PS1="$MODE# "
- PUB_KEY=/etc/signify/libertybsd-${VERSION}-base.pub
- ROOTDEV=
- ROOTDISK=
- SETDIR="$VNAME/$ARCH"
- UPGRADE_BSDRD=false
- V4_DHCPCONF=false
- V6_AUTOCONF=false
- WLANLIST=/tmp/i/wlanlist
- # Save one boot's worth of dmesg.
- dmesgtail >/var/run/dmesg.boot
- # Are we in a real release, or a snapshot? If this is a snapshot
- # install media, default us to a snapshot directory.
- HTTP_SETDIR=$SETDIR
- set -- $(scan_dmesg "/^LibertyBSD $VNAME\([^ ]*\).*$/s//\1/p")
- [[ $1 == -!(stable) ]] && HTTP_SETDIR=snapshots/$ARCH
- # Detect if ftp(1) has tls support and set defaults based on that.
- if [[ -e /etc/ssl/cert.pem ]]; then
- FTP_TLS=true
- HTTP_PROTO=https
- else
- FTP_TLS=false
- HTTP_PROTO=http
- fi
- # Scan /var/run/dmesg.boot for console device.
- CONSOLE=$(scan_dmesg '/^\([^ ]*\).*: console$/s//\1/p')
- [[ -n $CONSOLE ]] && CSPEED=$(stty speed </dev/console)
- # Look for the serial device matching the console. If we are not installing
- # from a serial console, just find the first serial device that could be used
- # as a console. If a suitable device is found, set CDEV, CTTY, CSPEED, CPROM.
- md_consoleinfo
- # Selected sets will be installed in the order they are listed in $ALLSETS.
- # Ensure that siteXX.tgz is the *last* set listed so its contents overwrite
- # the contents of the other sets, not the other way around.
- SETS=$(echo {base,comp,man,game,xbase,xshare,xfont,xserv}$VERSION.tgz)
- DEFAULTSETS="${MDSETS:-bsd bsd.rd} $SETS"
- ALLSETS="${MDSETS:-bsd bsd.rd} $SETS site$VERSION.tgz"
- SANESETS="${MDSANESETS:-bsd} base${VERSION}.tgz"
- if ((NCPU > 1)); then
- DEFAULTSETS="${MDSETS:-bsd bsd.mp bsd.rd} $SETS"
- ALLSETS="${MDSETS:-bsd bsd.mp bsd.rd} $SETS site$VERSION.tgz"
- SANESETS="${MDSANESETS:-bsd bsd.mp} base${VERSION}.tgz"
- fi
- # Prepare COLUMNS sanely.
- export COLUMNS=$(stty -a </dev/console |
- sed -n '/columns/{s/^.* \([0-9]*\) columns.*$/\1/;p;}')
- ((COLUMNS == 0)) && COLUMNS=80
- # Interactive or automatic installation?
- if ! $AI; then
- cat <<__EOT
- At any prompt except password prompts you can escape to a shell by
- typing '!'. Default answers are shown in []'s and are selected by
- pressing RETURN. You can exit this program at any time by pressing
- Control-C, but this can leave your system in an inconsistent state.
- __EOT
- elif $UU; then
- MODE=upgrade
- check_unattendedupgrade || exit 1
- start_watchdog
- get_responsefile
- do_autoinstall
- elif [[ -z $AI_RESPFILE ]]; then
- get_responsefile ||
- err_exit "No response file found; non-interactive mode aborted."
- do_autoinstall
- else
- cp $AI_RESPFILE /tmp/ai/ai.conf || exit
- fi
- # Configure the terminal and keyboard.
- set_term
- # In case of restart, delete previously logged answers.
- rm -f /tmp/i/$MODE.resp
- case $MODE in
- install) do_install;;
- upgrade) do_upgrade;;
- esac
- # In case of autoinstall, this is a second process of install.sub.
- # Exiting here returns to the original process, which handles the
- # automatic reboot in do_autoinstall().
- $AI && exit
- _d=reboot
- [[ $MODE == install && $MDHALT == y ]] && _d=halt
- while :; do
- ask "Exit to (S)hell, (H)alt or (R)eboot?" "$_d"
- case $resp in
- [hH]*) exec halt;;
- [rR]*) exec reboot;;
- [sS]*) break;;
- esac
- done
- # Fall through to .profile which leaves us at the command prompt.
- echo "To boot the new system, enter 'reboot' at the command prompt."
|