install.sub 77 KB

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