Browse code

Added new install.sub

Jaidyn Lev authored on 2018-08-26 06:31:34
Showing 1 changed files
... ...
@@ -1,5 +1,5 @@
1 1
 #!/bin/ksh
2
-#	$OpenBSD: install.sub,v 1.995 2017/04/07 22:53:25 rpe Exp $
2
+#	$OpenBSD: install.sub,v 1.1066 2018/03/15 17:43:54 anton Exp $
3 3
 #
4 4
 # Copyright (c) 1997-2015 Todd Miller, Theo de Raadt, Ken Westerback
5 5
 # Copyright (c) 2015, Robert Peichaer <rpe@openbsd.org>
... ...
@@ -60,10 +60,15 @@
60 60
 # Misc functions
61 61
 # ------------------------------------------------------------------------------
62 62
 
63
+# Print error message to stderr and exit the script.
64
+err_exit() {
65
+	print -u2 -- "$*"
66
+	exit 1
67
+}
68
+
63 69
 # Show usage of the installer script and exit.
64 70
 usage() {
65
-	echo "usage: ${0##*/} [-a] [-f filename] [-m install | upgrade]" >&2
66
-	exit 1
71
+	err_exit "usage: ${0##*/} [-a] [-f filename] [-m install | upgrade]"
67 72
 }
68 73
 
69 74
 # Wait for the ftp process to finish, or be killed after the timeout and
... ...
@@ -192,7 +197,7 @@ show_cols() {
192 197
 # Echo file $1 to stdout. Skip comment lines and delete everything
193 198
 # after the first '#' from other lines. Strip leading and trailing
194 199
 # whitespace if IFS is set.
195
-stripcom () {
200
+stripcom() {
196 201
 	local _file=$1 _line
197 202
 
198 203
 	[[ -f $_file ]] || return
... ...
@@ -243,10 +248,12 @@ __EOT
243 248
 # field provided as parameters and return the value of the first field found.
244 249
 #
245 250
 # Note that strings are unescaped but not unvis()'d.
246
-lease_value () {
251
+lease_value() {
247 252
 	local _lf=$1 _o
248 253
 
254
+	[[ -s $_lf ]] || return
249 255
 	shift
256
+
250 257
 	for _o; do
251 258
 		sed -E \
252 259
 			-e '/^ *(option )?'"$_o"' (.*);$/!d;s//\2/' \
... ...
@@ -270,7 +277,7 @@ diskinfo() {
270 277
 		_i=${_i##+([[:space:],])}
271 278
 		_i=${_i%%+([[:space:],])}
272 279
 
273
-		# Extract Network Address Authority information from dmesg..
280
+		# Extract Network Address Authority information from dmesg.
274 281
 		_n=$(dmesg | sed -En '/^'$_d' at /h;${g;s/^.* ([a-z0-9]+\.[a-zA-Z0-9_]+)$/\1/p;}')
275 282
 
276 283
 		# Extract disk size from disklabel output.
... ...
@@ -300,12 +307,12 @@ scan_disknames() {
300 307
 }
301 308
 
302 309
 # Return disk devices found in hw.disknames.
303
-get_dkdevs () {
310
+get_dkdevs() {
304 311
 	echo $(scan_disknames "${MDDKDEVS:-/^[sw]d[0-9][0-9]* /s/ .*//p}")
305 312
 }
306 313
 
307 314
 # Return CDROM devices found in hw.disknames.
308
-get_cddevs () {
315
+get_cddevs() {
309 316
 	echo $(scan_disknames "${MDCDDEVS:-/^cd[0-9][0-9]* /s/ .*//p}")
310 317
 }
311 318
 
... ...
@@ -324,8 +331,7 @@ get_dkdevs_uninitialized() {
324 331
 get_ifs() {
325 332
 	local _if _iflist=$(rmel vlan $(ifconfig -C))
326 333
 
327
-	for _if in $(ifconfig "$@" 2>/dev/null |
328
-		sed -n 's/^\([^[:space:]]*\):.*/\1/p'); do
334
+	for _if in $(ifconfig "$@" 2>/dev/null | sed '/^[a-z]/!d;s/:.*//'); do
329 335
 		isin "${_if%%+([0-9])}" $_iflist || echo $_if
330 336
 	done
331 337
 }
... ...
@@ -407,17 +413,14 @@ disklabel_autolayout() {
407 413
 		ask "URL to autopartitioning template for disklabel?" none
408 414
 		[[ $resp == none ]] && break
409 415
 		if ! $FTP_TLS && [[ $resp == https://* ]]; then
410
-			echo "https not supported on this platform."
411
-			exit 1
416
+			err_exit "https not supported on this platform."
412 417
 		fi
413 418
 		echo "Fetching $resp"
414 419
 		if unpriv ftp -Vo - "$resp" >$_dl && [[ -s $_dl ]]; then
415 420
 			disklabel -T $_dl -F $_f -w -A $_disk && return
416
-			echo "Autopartitioning failed"
417
-			exit 1
421
+			err_exit "Autopartitioning failed."
418 422
 		else
419
-			echo "No autopartitioning template found."
420
-			exit 1
423
+			err_exit "No autopartitioning template found."
421 424
 		fi
422 425
 	done
423 426
 
... ...
@@ -511,7 +514,7 @@ lock() {
511 514
 
512 515
 # Release lock.
513 516
 unlock() {
514
-	rm -d /tmp/i/lock 2>/dev/null
517
+	rm -df /tmp/i/lock 2>/dev/null
515 518
 }
516 519
 
517 520
 # Add trap to kill the listener process.
... ...
@@ -520,6 +523,36 @@ retrap() {
520 523
 		INT EXIT TERM
521 524
 }
522 525
 
526
+# Start listener process looking for dmesg changes.
527
+start_dmesg_listener() {
528
+	local _update=/tmp/i/update
529
+
530
+	# Make sure lock is initially released.
531
+	unlock
532
+
533
+	# The dmesg listener will check for the existence of this file and sends
534
+	# a signal to the child process if the dmesg output differs from the
535
+	# contents of that file.
536
+	rm -f $_update
537
+
538
+	$AUTO && return
539
+
540
+	(
541
+	while :; do
542
+		lock
543
+		if [[ -e $_update && "$(dmesg)" != "$(<$_update)" ]]; then
544
+			dmesg >$_update
545
+			kill -TERM 2>/dev/null $$ || exit 1
546
+		fi
547
+		unlock
548
+		sleep .5
549
+	done
550
+	) |&
551
+	CPPID=$!
552
+
553
+	# Kill the child on exit.
554
+	retrap
555
+}
523 556
 
524 557
 # ------------------------------------------------------------------------------
525 558
 # Functions to ask (or auto-answer) questions
... ...
@@ -535,13 +568,12 @@ log_answers() {
535 568
 
536 569
 # Fetch response file for autoinstall.
537 570
 get_responsefile() {
538
-	local _rf _if _mode _lf _hn _path _aifile
539
-	export AI_MAC= AI_MODE= AI_SERVER=
571
+	local _rf _if _lf _path _aifile
572
+	export AI_HOSTNAME= AI_MAC= AI_MODE= AI_SERVER=
540 573
 
541
-	[[ -f /auto_upgrade.conf ]] && _rf=/auto_upgrade.conf _mode=upgrade
542
-	[[ -f /auto_install.conf ]] && _rf=/auto_install.conf _mode=install
543
-	[[ -f $_rf ]] && cp $_rf /tmp/ai/ai.$_mode.conf &&
544
-		AI_MODE=$_mode && return
574
+	[[ -f /auto_upgrade.conf ]] && _rf=/auto_upgrade.conf AI_MODE=upgrade
575
+	[[ -f /auto_install.conf ]] && _rf=/auto_install.conf AI_MODE=install
576
+	[[ -f $_rf ]] && cp $_rf /tmp/ai/ai.$AI_MODE.conf && return
545 577
 
546 578
 	for _if in ''; do
547 579
 		[[ -x /sbin/dhclient ]] || break
... ...
@@ -568,35 +600,34 @@ get_responsefile() {
568 600
 		_aifile=$(lease_value $_lf filename bootfile-name)
569 601
 		[[ $_aifile == ?(*/)auto_@(install|upgrade) ]] || _aifile=
570 602
 		_path=${_aifile%auto_@(install|upgrade)}
571
-		_mode=${_aifile##*?(/)auto_}
603
+		AI_MODE=${_aifile##*?(/)auto_}
572 604
 
573 605
 		# Extract installer server ip address from lease file.
574 606
 		AI_SERVER=$(lease_value $_lf \
575 607
 			server-name tftp-server-name next-server)
576 608
 
577 609
 		# Prime hostname with host-name option from lease file.
578
-		_hn=$(lease_value $_lf host-name)
579
-		hostname "$_hn"
610
+		AI_HOSTNAME=$(lease_value $_lf host-name)
611
+		hostname "$AI_HOSTNAME"
580 612
 	done
581 613
 
582 614
 	# Fetch response file if server and mode are known, otherwise tell which
583 615
 	# one was missing. Try to fetch mac-mode.conf, then hostname-mode.conf,
584 616
 	# and finally mode.conf.
585
-	if [[ -n $AI_SERVER && -n $_mode ]]; then
617
+	if [[ -n $AI_SERVER && -n $AI_MODE ]]; then
586 618
 		AI_MAC=$(ifconfig $_if | sed 's/.*lladdr \(.*\)/\1/p;d')
587
-		for _rf in {$AI_MAC-,${_hn:+$_hn-,}}$_mode; do
619
+		for _rf in {$AI_MAC-,${AI_HOSTNAME:+$AI_HOSTNAME-,}}$AI_MODE; do
588 620
 			_url="http://$AI_SERVER/$_path$_rf.conf?path=$HTTP_SETDIR"
589 621
 			echo "Fetching $_url"
590 622
 			if unpriv ftp -Vo - "$_url" \
591
-				>"/tmp/ai/ai.$_mode.conf" 2>/dev/null; then
592
-				AI_MODE=$_mode
623
+				>"/tmp/ai/ai.$AI_MODE.conf" 2>/dev/null; then
593 624
 				ifconfig $_if delete down 2>/dev/null
594 625
 				return 0
595 626
 			fi
596 627
 		done
597 628
 	else
598 629
 		[[ -z $AI_SERVER ]] && echo "Could not determine auto server."
599
-		[[ -z $_mode ]] && echo "Could not determine auto mode."
630
+		[[ -z $AI_MODE ]] && echo "Could not determine auto mode."
600 631
 	fi
601 632
 
602 633
 	# Ask for url or local path to response file. Provide a default url if
... ...
@@ -608,22 +639,23 @@ get_responsefile() {
608 639
 	done
609 640
 
610 641
 	# Ask for the installer mode only if auto-detection failed.
611
-	_mode=$(echo "$_rf" | sed -En 's/^.*(install|upgrade).conf$/\1/p')
612
-	while [[ -z $_mode ]]; do
642
+	AI_MODE=$(echo "$_rf" | sed -En 's/^.*(install|upgrade).conf$/\1/p')
643
+	while [[ -z $AI_MODE ]]; do
613 644
 		ask "(I)nstall or (U)pgrade?"
614
-		[[ $resp == [iI]* ]] && _mode=install
615
-		[[ $resp == [uU]* ]] && _mode=upgrade
645
+		[[ $resp == [iI]* ]] && AI_MODE=install
646
+		[[ $resp == [uU]* ]] && AI_MODE=upgrade
616 647
 	done
617 648
 
618 649
 	echo "Fetching $_rf"
619 650
 	[[ -f $_rf ]] && _rf="file://$_rf"
620
-	unpriv ftp -Vo - "$_rf" >"/tmp/ai/ai.$_mode.conf" 2>/dev/null &&
621
-		 AI_MODE=$_mode
622
-	ifconfig $_if delete down 2>/dev/null
623
-	[[ -n $AI_MODE ]]
651
+	if unpriv ftp -Vo - "$_rf" >"/tmp/ai/ai.$AI_MODE.conf" 2>/dev/null; then
652
+		ifconfig $_if delete down 2>/dev/null
653
+		return 0
654
+	fi
655
+	return 1
624 656
 }
625 657
 
626
-# Search question in $RESPFILE, return answer in $resp.
658
+# Search question in $AI_RESPFILE, return answer in $resp.
627 659
 #
628 660
 # 1) split question and answer at leftmost =
629 661
 # 2) strip leading/trailing blanks
... ...
@@ -641,7 +673,7 @@ _autorespond() {
641 673
 	typeset -l _q=$1 _key
642 674
 	local _def=$2 _l _val
643 675
 
644
-	[[ -f $RESPFILE ]] || return
676
+	[[ -f $AI_RESPFILE ]] || return
645 677
 
646 678
 	# Find a suitable response in /tmp/ai/ai.conf and remove it if found.
647 679
 	mv /tmp/ai/ai.conf /tmp/ai/ai.conf.tmp
... ...
@@ -654,8 +686,7 @@ _autorespond() {
654 686
 		print -r " $_l"
655 687
 	done </tmp/ai/ai.conf.tmp >/tmp/ai/ai.conf
656 688
 	[[ -n $_def ]] && resp=$_def && return
657
-	echo "\nQuestion has no answer in response file."
658
-	exit 1
689
+	err_exit "\nQuestion has no answer in response file."
659 690
 }
660 691
 
661 692
 # Issue a read into the global variable $resp. If the dmesg output is
... ...
@@ -774,7 +805,7 @@ ask_which() {
774 805
 			break
775 806
 		fi
776 807
 		echo "'$resp' is not a valid choice."
777
-		$AUTO && [[ -n $RESPFILE ]] && exit 1
808
+		$AUTO && [[ -n $AI_RESPFILE ]] && exit 1
778 809
 	done
779 810
 }
780 811
 
... ...
@@ -840,13 +871,11 @@ ask_password() {
840 871
 # Support functions for donetconfig()
841 872
 # ------------------------------------------------------------------------------
842 873
 
843
-# Issue a DHCP request to configure interface $1 and add the host-name option to
844
-# /etc/dhclient.conf using $2.
874
+# Issue a DHCP request to configure interface $1.
845 875
 dhcp_request() {
846
-	local _if=$1 _hn=$2
876
+	local _if=$1
847 877
 
848 878
 	echo "lookup file bind" >/etc/resolv.conf.tail
849
-	echo "send host-name \"$_hn\";" >/etc/dhclient.conf
850 879
 
851 880
 	ifconfig $_if group dhcp >/dev/null 2>&1
852 881
 
... ...
@@ -855,24 +884,23 @@ initial-interval 1;
855 884
 backoff-cutoff 2;
856 885
 reboot 5;
857 886
 timeout 10;
858
-send host-name "$_hn";
859 887
 __EOT
860 888
 
861
-	# Move configuration files to where they will be copied to the
862
-	# installed system. Overwrites configuration information from
863
-	# last successful dhcp attempt.
864
-	mv /etc/dhclient.conf /tmp/i/dhclient.conf
889
+	# Move resolv.conf to where it will be copied to the installed system.
865 890
 	mv /etc/resolv.conf.tail /tmp/i/resolv.conf.tail
866 891
 }
867 892
 
868 893
 # Obtain and output the inet information related to interface $1.
869
-# Should output '<UP/DOWN> <addr> <netmask> <rest of inet line>'.
894
+# Outputs one of:
895
+# DOWN
896
+# UP
897
+# UP\n<addr> <netmask> <rest of inet line>[\n<more inet lines>]
870 898
 v4_info() {
871 899
 	ifconfig $1 inet | sed -n '
872 900
 		1s/.*<UP,.*/UP/p
873 901
 		1s/.*<.*/DOWN/p
874
-		/inet/s/netmask//
875
-		/inet/s///p'
902
+		/inet/s/netmask //
903
+		/.inet /s///p'
876 904
 }
877 905
 
878 906
 # Convert a netmask in hex format ($1) to dotted decimal format.
... ...
@@ -901,12 +929,84 @@ add_hostent() {
901 929
 	echo "$_addr $_name" >>/tmp/i/hosts
902 930
 }
903 931
 
932
+# Configure VLAN interface.
933
+#
934
+# Parameters:
935
+#
936
+# $1 = name of the network device
937
+#
938
+vlan_config() {
939
+	local _if=$1 _hn=/tmp/i/hostname.$1 _hn_vd _vd _vdvi _vdvi_used _vi
940
+	local _sed_vdvi='s/.encap: vnetid ([[:alnum:]]+) parent ([[:alnum:]]+)/\2:\1/p'
941
+
942
+	# Use existing parent device and vnetid for this interface as default in
943
+	# case of a restart.
944
+	_vdvi=$(ifconfig $_if 2>/dev/null | sed -En "$_sed_vdvi")
945
+	_vd=${_vdvi%%:*}
946
+	_vi=${_vdvi##*:}
947
+
948
+	# Use the vlan interface minor as the default vnetid. If it's 0, set it
949
+	# to 'none' which equals to the default vlan.
950
+	if [[ $_vi == @(|none) ]]; then
951
+		((${_if##vlan} == 0)) && _vi=none || _vi=${_if##vlan}
952
+	fi
953
+
954
+	# Use the first non vlan interface as the default parent.
955
+	if [[ $_vd == @(|none) ]]; then
956
+		_vd=$(get_ifs | sed '/^vlan/d' | sed q)
957
+	fi
958
+
959
+	ask "Which interface:tag should $_if be on?" "$_vd:$_vi"
960
+	_vd=${resp%%:*}
961
+	_vi=${resp##*:}
962
+
963
+	# Ensure that the given parent is an existing (non vlan) interface.
964
+	if ! isin "$_vd" $(get_ifs | sed '/^vlan/d'); then
965
+		echo "Invalid parent interface choice '$_vd'."
966
+		return 1
967
+	fi
968
+
969
+	# Get a list of parent:vnetid tuples of all configured vlan interfaces.
970
+	_vdvi_used=$(ifconfig vlan 2>/dev/null | sed -En "$_sed_vdvi")
971
+
972
+	# Ensure that the given vnetid is not already configured on the given
973
+	# parent interface.
974
+	for _vdvi in $_vdvi_used; do
975
+		if [[ $_vdvi == $_vd:* && ${_vdvi##*:} == $_vi ]]; then
976
+			echo "vlan tag '$_vi' already used on parent '$_vd'"
977
+			return 1
978
+		fi
979
+	done
980
+
981
+	# Further ensure that the given vnetid is 'none', or within 1-4095.
982
+	if [[ $_vi == none ]]; then
983
+		_vi="-vnetid"
984
+	elif (($_vi > 0 && $_vi < 4096)); then
985
+		_vi="vnetid $_vi"
986
+	else
987
+		echo "Invalid vlan tag '$_vi'."
988
+		return 1
989
+	fi
990
+
991
+	# Write the config to the hostname.if files and set proper permissions.
992
+	_hn_vd=/tmp/i/hostname.$_vd
993
+	grep -qs "^up" $_hn_vd || echo up >>$_hn_vd
994
+	echo "$_vi parent $_vd" >>$_hn
995
+	chmod 640 $_hn_vd $_hn
996
+
997
+	# Bring up the parent interface and configure the vlan interface.
998
+	ifconfig $_vd up
999
+	ifconfig $_if destroy >/dev/null 2>&1
1000
+	ifconfig $_if create >/dev/null 2>&1
1001
+	ifconfig $_if $_vi parent $_vd
1002
+}
1003
+
904 1004
 # Configure IPv4 interface.
905 1005
 #
906 1006
 # Parameters:
907 1007
 #
908 1008
 # $1 = name of the network device
909
-# $2 = hostname to use for dhcp request
1009
+# $2 = hostname to add to hosts file
910 1010
 # $3 = /path/to/hostname.if
911 1011
 #
912 1012
 v4_config() {
... ...
@@ -929,36 +1029,57 @@ v4_config() {
929 1029
 	fi
930 1030
 	_prompt="IPv4 address for $_if? (${_prompt}or 'none')"
931 1031
 
932
-	ask_until "$_prompt" "$_addr"
933
-	case $resp in
934
-	none)	;;
935
-	dhcp)	if [[ ! -x /sbin/dhclient ]]; then
936
-			echo "DHCP not possible - no /sbin/dhclient."
1032
+	while :; do
1033
+		ask_until "$_prompt" "$_addr"
1034
+		case $resp in
1035
+		none)	return
1036
+			;;
1037
+		dhcp)	if [[ ! -x /sbin/dhclient ]]; then
1038
+				echo "DHCP not possible - no /sbin/dhclient."
1039
+				$AUTO && exit 1 || continue
1040
+			else
1041
+				dhcp_request $_if
1042
+				echo "dhcp" >>$_hn
1043
+				return
1044
+			fi
1045
+			;;
1046
+		*)	_addr=$resp
1047
+			ifconfig $_if -group dhcp >/dev/null 2>&1
1048
+			;;
1049
+		esac
1050
+
1051
+		# Ask for the netmask if the user did not use CIDR notation.
1052
+		if [[ $_addr == */* ]]; then
1053
+			_mask=
937 1054
 		else
938
-			dhcp_request $_if "$_name"
939
-			echo "dhcp" >>$_hn
1055
+			ask_until "Netmask for $_if?" "${_mask:=255.255.255.0}"
1056
+			_mask=$resp
940 1057
 		fi
941
-		;;
942
-	*)	_addr=$resp
943
-		ask_until "Netmask for $_if?" "${_mask:=255.255.255.0}"
944
-		ifconfig $_if -group dhcp >/dev/null 2>&1
945
-		if ifconfig $_if inet $_addr netmask $resp up; then
946
-			add_hostent "$_addr" "$_name"
947
-			echo "inet $_addr $resp" >>$_hn
1058
+
1059
+		if ifconfig $_if inet $_addr ${_mask:+netmask $_mask} up; then
1060
+			echo "inet $_addr $_mask" >>$_hn
1061
+			add_hostent "${_addr%%/*}" "$_name"
1062
+			break
1063
+		else
1064
+			_addr=
1065
+			_mask=
1066
+			$AUTO && exit 1
948 1067
 		fi
949
-		;;
950
-	esac
1068
+	done
951 1069
 }
952 1070
 
953 1071
 # Obtain and output the inet6 information related to interface $1.
954
-# Should output '<UP/DOWN> <addr> <prefixlen> <rest of inet line> '.
1072
+# Outputs one of:
1073
+# DOWN
1074
+# UP
1075
+# UP\n<addr> <prefixlen> <rest of inet6 line>[\n<more inet6 lines>]
955 1076
 v6_info() {
956 1077
 	ifconfig $1 inet6 | sed -n '
957 1078
 		1s/.*<UP,.*/UP/p
958 1079
 		1s/.*<.*/DOWN/p
959 1080
 		/scopeid/d
960
-		/inet6/s/prefixlen//
961
-		/inet6/s///p'
1081
+		/inet6/s/prefixlen //
1082
+		/.inet6 /s///p'
962 1083
 }
963 1084
 
964 1085
 # Set up IPv6 default route on interface $1.
... ...
@@ -968,8 +1089,7 @@ v6_defroute() {
968 1089
 	route -n show -inet6 | egrep -q '^default[[:space:]]' && return
969 1090
 
970 1091
 	_routers=$(bsort $(ping6 -n -c 2 ff02::2%$_if 2>/dev/null |
971
-		sed -n '/bytes from/{s/^.*from //;s/,.*$//;p;}' |
972
-		sed -n 'G;s/\n/&&/;/^\(.*\n\).*\n\1/d;h;P'))
1092
+		sed -En '/^[0-9]+ bytes from /{s///;s/: .*$//p;}'))
973 1093
 
974 1094
 	_prompt="IPv6 default router?"
975 1095
 
... ...
@@ -992,7 +1112,7 @@ v6_defroute() {
992 1112
 # Parameters:
993 1113
 #
994 1114
 # $1 = name of the network device
995
-# $2 = hostname to use for dhcp request
1115
+# $2 = hostname to add to hosts file
996 1116
 # $3 = /path/to/hostname.if
997 1117
 #
998 1118
 v6_config() {
... ...
@@ -1003,26 +1123,49 @@ v6_config() {
1003 1123
 	set -- $(v6_info $_if)
1004 1124
 	[[ -n $2 ]] && { _addr=$2; _prefixlen=$3; }
1005 1125
 
1006
-	ifconfig $_if inet6 >/dev/null 2>&1 && _prompt="or 'rtsol' "
1126
+	ifconfig $_if inet6 >/dev/null 2>&1 && _prompt="or 'autoconf' "
1007 1127
 	_prompt="IPv6 address for $_if? (${_prompt}or 'none')"
1008
-	ask_until "$_prompt" "${_addr:-none}"
1009 1128
 
1010
-	case $resp in
1011
-	none)	return
1012
-		;;
1013
-	rtsol)	ifconfig $_if inet6 >/dev/null 2>&1 ||
1014
-			{ echo "No INET6 support."; return; }
1015
-		ifconfig $_if up
1016
-		ifconfig $_if inet6 autoconf && echo "up\nrtsol" >>$_hn
1017
-		return
1018
-		;;
1019
-	esac
1129
+	while :; do
1130
+		ask_until "$_prompt" "${_addr:-none}"
1131
+		case $resp in
1132
+		none)	return
1133
+			;;
1134
+		autoconf)
1135
+			if ! ifconfig $_if inet6 >/dev/null 2>&1; then
1136
+				echo "No INET6 support."
1137
+				$AUTO && exit 1 || return
1138
+			fi
1139
+			if ifconfig $_if inet6 autoconf; then
1140
+				echo "inet6 autoconf" >>$_hn
1141
+				return
1142
+			else
1143
+				echo "inet6 autoconf failed."
1144
+				$AUTO && exit 1 || return
1145
+			fi
1146
+			;;
1147
+		*)	_addr=$resp
1148
+			;;
1149
+		esac
1150
+	
1151
+		# Ask for prefix lenght if the user did not use CIDR notation.
1152
+		if [[ $_addr == */* ]]; then
1153
+			_prefixlen=
1154
+		else
1155
+			ask_until "IPv6 prefix length for $_if?" "${_prefixlen:=64}"
1156
+			_prefixlen=$resp
1157
+		fi
1020 1158
 
1021
-	_addr=$resp
1022
-	ask_until "IPv6 prefix length for $_if?" "${_prefixlen:=64}"
1023
-	ifconfig $_if inet6 $_addr prefixlen $resp up || return
1024
-	echo "inet6 $_addr $resp" >>$_hn
1025
-	add_hostent "$_addr" "$_name"
1159
+		if ifconfig $_if inet6 $_addr ${_prefixlen:+prefixlen $_prefixlen} up; then
1160
+			echo "inet6 $_addr $_prefixlen" >>$_hn
1161
+			add_hostent "${_addr%%/*}" "$_name"
1162
+			break
1163
+		else
1164
+			_addr=
1165
+			_prefixlen=
1166
+			$AUTO && exit 1
1167
+		fi
1168
+	done
1026 1169
 
1027 1170
 	v6_defroute $_if
1028 1171
 }
... ...
@@ -1101,17 +1244,7 @@ ieee80211_config() {
1101 1244
 
1102 1245
 # Set up IPv4 and IPv6 interface configuration.
1103 1246
 configure_ifs() {
1104
-	local _first _ifs _if _name _hn _vl=0 _vd _vi _p _tags
1105
-
1106
-	# In case of restart, discover last vlan configured.
1107
-	while :; do
1108
-		_vd=$(ifconfig vlan$_vl 2>&1)
1109
-		[[ $_vd == @(*no such interface*) ]] && break
1110
-		[[ $_vd == @(*vlan: +([[:digit:]]) parent interface:*) ]] ||
1111
-			break
1112
-		((_vl++))
1113
-	done
1114
-	_vd=
1247
+	local _first _hn _if _name _p _vi
1115 1248
 
1116 1249
 	# Always need lo0 configured.
1117 1250
 	ifconfig lo0 inet 127.0.0.1/8
... ...
@@ -1120,11 +1253,13 @@ configure_ifs() {
1120 1253
 	rm -f /tmp/i/mygate
1121 1254
 
1122 1255
 	while :; do
1123
-		# Create new vlan if possible.
1124
-		ifconfig vlan$_vl create >/dev/null 2>&1
1256
+		# Discover last configured vlan interface and increment it's
1257
+		# minor for the next offered vlan interface.
1258
+		_vi=$(get_ifs vlan | sed '$!d;s/^vlan//')
1259
+		[[ -n $_vi ]] && ((_vi++))
1125 1260
 
1126 1261
 		ask_which "network interface" "do you wish to configure" \
1127
-			'$(get_ifs)' \
1262
+			"\$(get_ifs) vlan${_vi:-0}" \
1128 1263
 			${_p:-'$( (get_ifs netboot; get_ifs) | sed q )'}
1129 1264
 		[[ $resp == done ]] && break
1130 1265
 
... ...
@@ -1135,57 +1270,7 @@ configure_ifs() {
1135 1270
 		# If the offered vlan is chosen, ask the relevant
1136 1271
 		# questions and bring it up.
1137 1272
 		if [[ $_if == vlan+([0-9]) ]]; then
1138
-			# Get existing tag for this vlan.
1139
-			_vi=$(ifconfig $_if 2>/dev/null |
1140
-				sed -n 's/vlan: \([0-9]*\).*/\1/p')
1141
-			# Get list of all in-use tags.
1142
-			_tags=$(ifconfig vlan 2>/dev/null |
1143
-				sed -n 's/vlan: \([0-9]*\).*/\1/p')
1144
-			# Current tag is a valid tag for this vlan.
1145
-			[[ -n $_tags ]] && _tags=$(rmel "$_vi" $_tags)
1146
-			if [[ -z $_vi ]]; then
1147
-				_vi=0
1148
-				while ((++_vi < 4096)); do
1149
-					! isin "$_vi" $_tags && break
1150
-				done
1151
-			fi
1152
-			_ifs=$(get_ifs)
1153
-			set -- $_ifs
1154
-			while [[ $1 == vlan+([0-9]) ]]; do
1155
-				shift
1156
-			done
1157
-			ask "Which interface:tag should $_if be on?" \
1158
-				"${_vd:=$1}:$_vi"
1159
-			_vd=${resp%%:*}
1160
-			_vi=${resp##*:}
1161
-
1162
-			# Validate that $_vd is a real interface.
1163
-			if ! (isin "$_vd" $_ifs &&
1164
-				[[ $_vd != vlan+([0-9]) ]]); then
1165
-				echo "Invalid interface choice '$_vd'"
1166
-				_vd=
1167
-				continue
1168
-			fi
1169
-
1170
-			# Validate range of $_vi as 1-4095, and $_vi not in use.
1171
-			if ((_vi < 1 || _vi > 4095)) || isin "$_vi" $_tags; then
1172
-				echo "Invalid or in-use vlan tag '$_vi'"
1173
-				continue
1174
-			fi
1175
-
1176
-			# hostname.$_vd must say something, anything, to
1177
-			# make sure it is up.
1178
-			grep -qs "^up" /tmp/i/hostname.$_vd ||
1179
-				echo "up" >>/tmp/i/hostname.$_vd
1180
-			chmod 640 /tmp/i/hostname.$_vd
1181
-			ifconfig $_vd up
1182
-
1183
-			# Make sure a hostname.$_if is created with this info.
1184
-			ifconfig $_if destroy >/dev/null 2>&1
1185
-			ifconfig $_if vlan $_vi vlandev $_vd
1186
-			echo "vlan $_vi vlandev $_vd" >>$_hn
1187
-			# Create a new vlan if we just configured the highest.
1188
-			[[ ${_if##vlan} == $_vl ]] && ((_vl++))
1273
+			vlan_config $_if || continue
1189 1274
 		fi
1190 1275
 
1191 1276
 		# Test if it is an 802.11 interface.
... ...
@@ -1214,19 +1299,19 @@ configure_ifs() {
1214 1299
 
1215 1300
 # Set up IPv4 default route.
1216 1301
 v4_defroute() {
1217
-	local _dr
1302
+	local _dr _dr_if
1218 1303
 
1219 1304
 	# Only configure a default route if an IPv4 address was configured.
1220 1305
 	[[ -n $(ifconfig | sed -n '/[ 	]inet .* broadcast /p') ]] || return
1221 1306
 
1222 1307
 	# Check routing table to see if a default route ($1) already exists
1223
-	# and if it is handled by dhclient ($2).
1224
-	set -- $(route -nv show -inet |
1225
-		{ set -- $(grep '^default '); print $2 $9; })
1226
-	[[ -n $1 ]] && _dr=$1
1308
+	# and what interface it is connected to ($2).
1309
+	set -- $(route -n show -inet |
1310
+		sed -En 's/^default +([0-9.]+) .* ([a-z0-9]+) *$/\1 \2/p')
1311
+	[[ -n $1 ]] && _dr=$1 _dr_if=$2
1227 1312
 
1228 1313
 	# Don't ask if a default route exits and is handled by dhclient.
1229
-	[[ -n $_dr && $2 == \"DHCLIENT && -f /tmp/i/dhclient.conf ]] && return
1314
+	[[ -n $_dr ]] && isin "$_dr_if" $(get_ifs dhcp) && return
1230 1315
 
1231 1316
 	while :; do
1232 1317
 		ask_until "Default IPv4 route? (IPv4 address or none)" "$_dr"
... ...
@@ -1281,6 +1366,15 @@ sane_install() {
1281 1366
 #
1282 1367
 select_sets() {
1283 1368
 	local _avail=$1 _selected=$2 _f _action _col=$COLUMNS
1369
+	local _bsd_rd _no_sets=true
1370
+
1371
+	if [[ $MODE == upgrade ]]; then
1372
+		for _f in $_avail; do
1373
+			[[ $_f != bsd* ]] && _no_sets=false
1374
+			[[ $_f == bsd.rd* ]] && _bsd_rd=$_f
1375
+		done
1376
+		$_no_sets && UPGRADE_BSDRD=true _avail=$_bsd_rd _selected=$_bsd_rd
1377
+	fi
1284 1378
 
1285 1379
 	# account for 4 spaces added to the sets list
1286 1380
 	let COLUMNS=_col-8
... ...
@@ -1288,8 +1382,7 @@ select_sets() {
1288 1382
 	cat <<__EOT
1289 1383
 
1290 1384
 Select sets by entering a set name, a file name pattern or 'all'. De-select
1291
-sets by prepending a '-' to the set name, file name pattern or 'all'. Selected
1292
-sets are labelled '[X]'.
1385
+sets by prepending a '-', e.g.: '-game*'. Selected sets are labelled '[X]'.
1293 1386
 __EOT
1294 1387
 	while :; do
1295 1388
 		for _f in $_avail; do
... ...
@@ -1366,12 +1459,41 @@ unpriv2() {
1366 1459
 	do_as _file "$@"
1367 1460
 }
1368 1461
 
1462
+# Find filesystems to store prefetched sets.
1463
+# Prefer filesystems which are not used during extraction with 512M free space.
1464
+# Otherwise use any other filesystem with 2 GB free space to prevent overflow
1465
+# during extraction.
1466
+prefetcharea_fs_list() {
1467
+	local _fs_list
1468
+
1469
+	_fs_list=$( (
1470
+		for fs in /mnt/{tmp,home,usr{/local,}}; do
1471
+			df -k $fs 2>/dev/null | grep " $fs\$"
1472
+		done
1473
+		df -k
1474
+	) | (
1475
+		while read a a a a m m; do
1476
+			[[ $m == /mnt/@(tmp|home|usr/@(src,obj,xobj))@(|/*) ]] &&
1477
+				((a > 524288)) && echo $m && continue
1478
+			[[ $m == /mnt@(|/*) ]] &&
1479
+				((a > 524288 * 4)) && echo $m
1480
+		done
1481
+	) | (
1482
+		while read fs; do
1483
+			isin "$fs" $list || list="$list${list:+ }$fs"
1484
+		done
1485
+		echo $list
1486
+	) )
1487
+
1488
+	[[ -n $_fs_list ]] && echo $_fs_list || return 1
1489
+}
1490
+
1369 1491
 # Install a user-selected subset of the files in $2 from the source
1370 1492
 # named in $1. Display an error message for failed installs so the
1371 1493
 # user will know to try again.
1372 1494
 install_files() {
1373
-	local _src=$1 _files=$2 _f _sets _get_sets _n _col=$COLUMNS \
1374
-		_tmpfs _tmpsrc _cfile=/tmp/SHA256 _fsrc _unver _t _issue
1495
+	local _src=$1 _files=$2 _f _sets _get_sets _n _col=$COLUMNS _tmpfs \
1496
+		_tmpfs_list _tmpsrc _cfile=/tmp/SHA256 _fsrc _unver _t _issue
1375 1497
 	local _srclocal=false _unpriv=unpriv
1376 1498
 
1377 1499
 	# Fetch sets from local sources (disk, cdrom, nfs) as root.
... ...
@@ -1424,38 +1546,32 @@ install_files() {
1424 1546
 		! isin SHA256.sig $_files &&
1425 1547
 			_issue="Directory does not contain SHA256.sig" && break
1426 1548
 
1427
-		# For non-local sources find a filesystem to store the prefetched
1428
-		# sets. Prefer filesystems which are not used during extraction.
1429
-		# They need to have 512 MB free space. Otherwise use any other
1430
-		# filesystem having 2 GB free space to prevent overflow during
1431
-		# extraction.
1432
-		$_srclocal || _tmpfs=$( (
1433
-			for fs in /mnt/{{,var/}tmp,home,usr{/local,}}; do
1434
-				df -k $fs 2>/dev/null | grep " $fs\$"
1435
-			done
1436
-			df -k
1437
-		) | (
1438
-			while read a a a a m m; do
1439
-				[[ $m == /mnt/@(@(|var/)tmp|home|usr/@(src,obj,xobj))@(|/*) ]] &&
1440
-					((a > 524288)) && echo $m && exit
1441
-				[[ $m == /mnt@(|/*) ]] &&
1442
-					((a > 524288 * 4)) && echo $m && exit
1443
-			done
1444
-		) )
1445
-
1446 1549
 		if ! $_srclocal; then
1447
-			if [[ -d $_tmpfs ]]; then
1550
+			! _tmpfs_list=$(prefetcharea_fs_list) &&
1551
+				_issue="Cannot determine prefetch area" && break
1552
+
1553
+			for _tmpfs in $_tmpfs_list; do
1448 1554
 				# Try to clean up from previous runs, assuming
1449 1555
 				# the _tmpfs selection yields the same mount
1450 1556
 				# point.
1451 1557
 				for _tmpsrc in $_tmpfs/sets.+([0-9]).+([0-9]); do
1452 1558
 					[[ -d $_tmpsrc ]] && rm -r $_tmpsrc
1453 1559
 				done
1454
-				! _tmpsrc=$(tmpdir "$_tmpfs/sets") &&
1560
+	
1561
+				# Create a download directory for the sets and
1562
+				# check that the _sndio user can read files from
1563
+				# it. Otherwise cleanup and skip the filesystem.
1564
+				if _tmpsrc=$(tmpdir "$_tmpfs/sets"); then
1565
+					(
1566
+					>$_tmpsrc/t &&
1567
+					$_unpriv cat $_tmpsrc/t
1568
+					) >/dev/null 2>&1 && break ||
1569
+						rm -r $_tmpsrc
1570
+				fi
1571
+			done
1572
+
1573
+			[[ ! -d $_tmpsrc ]] &&
1455 1574
 				_issue="Cannot create prefetch area" && break
1456
-			else
1457
-				_issue="Cannot determine prefetch area" && break
1458
-			fi
1459 1575
 		fi
1460 1576
 
1461 1577
 		# Cleanup from previous runs.
... ...
@@ -1468,6 +1584,9 @@ install_files() {
1468 1584
 		! $_unpriv ftp -D "$_t" -Vmo - "$_src/SHA256.sig" >"$_cfile.sig" &&
1469 1585
 			_issue="Cannot fetch SHA256.sig" && break
1470 1586
 
1587
+		$UPGRADE_BSDRD &&
1588
+			PUB_KEY=/mnt/etc/signify/libertybsd-$((VERSION + 1))-base.pub
1589
+
1471 1590
 		# Verify signature file with public keys.
1472 1591
 		! unpriv -f "$_cfile" \
1473 1592
 			signify -Vep $PUB_KEY -x "$_cfile.sig" -m "$_cfile" &&
... ...
@@ -1492,6 +1611,8 @@ install_files() {
1492 1611
 					$AUTO && exit 1
1493 1612
 					return
1494 1613
 				fi
1614
+				_unver=$(rmel $_f $_unver)
1615
+				_get_sets=$(rmel $_f $_get_sets)
1495 1616
 				continue
1496 1617
 			fi
1497 1618
 
... ...
@@ -1521,14 +1642,16 @@ install_files() {
1521 1642
 		[[ -f $_tmpsrc/$_f ]] && _fsrc="file://$_tmpsrc/$_f"
1522 1643
 		case $_fsrc in
1523 1644
 		*.tgz)	$_unpriv ftp -D Installing -Vmo - "$_fsrc" |
1524
-				tar -zxphf - -C /mnt
1645
+				tar -zxphf - -C /mnt &&
1525 1646
 			if [[ $_f == ?(x)base*.tgz && $MODE == install ]]; then
1526 1647
 				ftp -D Extracting -Vmo - \
1527 1648
 				file:///mnt/var/sysmerge/${_f%%base*}etc.tgz |
1528 1649
 				tar -zxphf - -C /mnt
1529 1650
 			fi
1530 1651
 			;;
1531
-		*)	$_unpriv ftp -D Installing -Vmo - "$_fsrc" >"/mnt/$_f"
1652
+		*)	$UPGRADE_BSDRD && [[ $_f == bsd.rd* ]] &&
1653
+				cp /mnt/$_f /mnt/$_f.old.$VERSION
1654
+			$_unpriv ftp -D Installing -Vmo - "$_fsrc" >"/mnt/$_f"
1532 1655
 			;;
1533 1656
 		esac
1534 1657
 		if (($?)); then
... ...
@@ -1539,6 +1662,7 @@ install_files() {
1539 1662
 			fi
1540 1663
 		else
1541 1664
 			DEFAULTSETS=$(rmel $_f $DEFAULTSETS)
1665
+			$UPGRADE_BSDRD && DEFAULTSETS=
1542 1666
 		fi
1543 1667
 		[[ -d $_tmpsrc ]] && rm -f "$_tmpsrc/$_f"
1544 1668
 	done
... ...
@@ -1550,6 +1674,7 @@ install_http() {
1550 1674
 	local _d _f _flist _file_list _prompt _tls _http_proto _url_base
1551 1675
 	local _idx=/tmp/i/index.txt _sha=/tmp/i/SHA256 _sig=/tmp/i/SHA256.sig
1552 1676
 	local _iu_url _iu_srv _iu_dir _mirror_url _mirror_srv _mirror_dir
1677
+	local _ftp_stdout=/tmp/i/ftpstdout _rurl_base
1553 1678
 
1554 1679
 	# N.B.: Don't make INSTALL_MIRROR a local variable! It preserves the
1555 1680
 	# mirror information if install_http() is called multiple times with
... ...
@@ -1580,11 +1705,12 @@ install_http() {
1580 1705
 		_iu_srv=${_iu_url#*://}
1581 1706
 		_iu_srv=${_iu_srv%%/*}
1582 1707
 		_iu_dir=${_iu_url##*$_iu_srv*(/)}
1708
+		[[ -n $_iu_srv ]] && HTTP_SERVER=$_iu_srv
1583 1709
 	fi
1584 1710
 
1585 1711
 	# Get server IP address or hostname and optionally the http protocol.
1586 1712
 	while :; do
1587
-		ask_until "$_prompt" "${_iu_srv:-$HTTP_SERVER}"
1713
+		ask_until "$_prompt" "$HTTP_SERVER"
1588 1714
 		case $resp in
1589 1715
 		done)	return
1590 1716
 			;;
... ...
@@ -1656,9 +1782,10 @@ install_http() {
1656 1782
 	_url_base="$_http_proto://$HTTP_SERVER/$HTTP_DIR"
1657 1783
 
1658 1784
 	# Fetch SHA256.sig to create the list of files to select from.
1659
-	rm -f $_idx $_sha $_sig
1785
+	rm -f $_idx $_sha $_sig $_ftp_stdout
1660 1786
 	if ! unpriv -f $_sig \
1661
-		ftp -w 15 -VMo $_sig "$_url_base/SHA256.sig" 2>/dev/null; then
1787
+		ftp -w 15 -vMo $_sig "$_url_base/SHA256.sig" \
1788
+			>$_ftp_stdout 2>/dev/null; then
1662 1789
 		case $_tls in
1663 1790
 		force)	$AUTO && exit 1 || return
1664 1791
 			;;
... ...
@@ -1666,12 +1793,17 @@ install_http() {
1666 1793
 				return
1667 1794
 			_http_proto=http
1668 1795
 			_url_base="http://$HTTP_SERVER/$HTTP_DIR"
1669
-			unpriv -f $_sig ftp -VMo $_sig "$_url_base/SHA256.sig" \
1670
-				2>/dev/null
1796
+			unpriv -f $_sig ftp -vMo $_sig "$_url_base/SHA256.sig" \
1797
+				>$_ftp_stdout 2>/dev/null
1671 1798
 			;;
1672 1799
 		esac
1673 1800
 	fi
1674 1801
 
1802
+	# In case of URL redirection, use the final location to retrieve the
1803
+	# rest of the files from. Redirection does not change INSTALL_MIRROR.
1804
+	_rurl_base=$(sed -n 's/^Requesting //p' $_ftp_stdout | sed '$!d')
1805
+	_rurl_base=${_rurl_base%/SHA256.sig}
1806
+
1675 1807
 	# Verify SHA256.sig, write SHA256 and extract the list of files.
1676 1808
 	if unpriv -f $_sha \
1677 1809
 		signify -Vep $PUB_KEY -x $_sig -m $_sha >/dev/null 2>&1; then
... ...
@@ -1680,7 +1812,7 @@ install_http() {
1680 1812
 	else
1681 1813
 		echo "Unable to get a verified list of distribution sets."
1682 1814
 		# Deny this server, if it's a mirror without a valid SHA256.sig.
1683
-		if [[ ${_url_base%/$HTTP_SETDIR} == "$INSTALL_MIRROR" ]]; then
1815
+		if [[ ${_rurl_base%/$HTTP_SETDIR} == "$_http_proto://$INSTALL_MIRROR" ]]; then
1684 1816
 			$AUTO && exit 1 || return
1685 1817
 		fi
1686 1818
 	fi
... ...
@@ -1690,15 +1822,15 @@ install_http() {
1690 1822
 	# sets from SHA256.sig, siteXX sets or the whole set list from index.txt
1691 1823
 	# if SHA256.sig was not found (e.g. self compiled sets).
1692 1824
 	if unpriv -f $_idx \
1693
-		ftp -VMo $_idx "$_url_base/index.txt" 2>/dev/null; then
1825
+		ftp -VMo $_idx "$_rurl_base/index.txt" 2>/dev/null; then
1694 1826
 		_flist=$(sed -En 's/^.* ([a-zA-Z][a-zA-Z0-9._-]+)$/\1/p' $_idx)
1695 1827
 		for _f in $_flist; do
1696 1828
 			! isin "$_f" $_file_list && _file_list="$_file_list $_f"
1697 1829
 		done
1698 1830
 	fi
1699
-	rm -f $_idx $_sha $_sig
1831
+	rm -f $_idx $_sha $_sig $_ftp_stdout
1700 1832
 
1701
-	install_files "$_url_base" "$_file_list"
1833
+	install_files "$_rurl_base" "$_file_list"
1702 1834
 
1703 1835
 	# Remember the sets location which is used later for creating the
1704 1836
 	# installurl(5) file and to tell the cgi server.
... ...
@@ -1707,7 +1839,7 @@ install_http() {
1707 1839
 	else
1708 1840
 		# Remove the architecture and snaphots or version part.
1709 1841
 		INSTALL_URL=${_url_base%/$ARCH}
1710
-		INSTALL_URL=${INSTALL_URL%@(/$VERSION|/snapshots)}
1842
+		INSTALL_URL=${INSTALL_URL%@(/$VNAME|/snapshots)}
1711 1843
 	fi
1712 1844
 }
1713 1845
 
... ...
@@ -1743,7 +1875,7 @@ install_cdrom() {
1743 1875
 # Install sets from disk.
1744 1876
 # Ask for the disk device containing the set files.
1745 1877
 install_disk() {
1746
-	if ! ask_yn "Is the disk partition already mounted?"; then
1878
+	if ! ask_yn "Is the disk partition already mounted?" yes; then
1747 1879
 		ask_which "disk" "contains the $MODE media" \
1748 1880
 			'$(bsort $(get_dkdevs))' \
1749 1881
 			'$(bsort $(rmel $ROOTDISK $(get_dkdevs)))'
... ...
@@ -1869,9 +2001,15 @@ donetconfig() {
1869 2001
 	# configured via dhclient too.
1870 2002
 	resp="${_dn:-$(get_fqdn)}"
1871 2003
 	if ifconfig dhcp >/dev/null 2>&1 && [[ $NIFS == 1 && -n $_dn ]]; then
2004
+		# If we have a 'domain-name' option in the lease file use that.
2005
+		# It might *NOT* not be the same as the first domain in any
2006
+		# 'domain-search' option.
2007
+		set -- $(get_ifs dhcp)
2008
+		set -- $(lease_value /var/db/dhclient.leases.$1 domain-name)
2009
+		[[ -n $1 ]] && resp=$1
1872 2010
 		echo "Using DNS domainname $resp"
1873 2011
 	else
1874
-		ask "DNS domain name? (e.g. 'bar.com')" "$resp"
2012
+		ask "DNS domain name? (e.g. 'example.com')" "$resp"
1875 2013
 	fi
1876 2014
 	hostname "$(hostname -s).$resp"
1877 2015
 
... ...
@@ -1906,7 +2044,7 @@ questions() {
1906 2044
 	APERTURE=
1907 2045
 	resp=
1908 2046
 	START_XDM=
1909
-	if [[ -n $DISPLAY ]]; then
2047
+	if [[ -n $(scan_dmesg '/^wsdisplay[0-9]* /s/ .*//p') ]]; then
1910 2048
 		if [[ -n $(scan_dmesg '/^[a-z]*[01]: aperture needed/p') ]]; then
1911 2049
 			ask_yn "Do you expect to run the X Window System?" yes &&
1912 2050
 				APERTURE=$MDXAPERTURE
... ...
@@ -1945,9 +2083,9 @@ user_setup() {
1945 2083
 		y|yes)	_q="No really, what is the lower-case loginname, or 'no'?"
1946 2084
 			continue
1947 2085
 			;;
1948
-		root|daemon|operator|bin|sshd|www|nobody|ftp)
2086
+		root|daemon|operator|bin|build|sshd|www|nobody|ftp)
1949 2087
 			;;
1950
-		[a-z]*([a-z0-9_]))
2088
+		[a-z]*([-a-z0-9_]))
1951 2089
 			((${#resp} <= 31)) && break
1952 2090
 			;;
1953 2091
 		esac
... ...
@@ -2114,114 +2252,100 @@ get_rootinfo() {
2114 2252
 	SWAPDEV=${ROOTDISK}b
2115 2253
 }
2116 2254
 
2255
+# Parse and "unpack" a hostname.if(5) line given as positional parameters.
2256
+# Fill the _cmds array with the resulting interface configuration commands.
2257
+parse_hn_line() {
2258
+	local _af=0 _name=1 _mask=2 _bc=3 _prefix=2 _c _cmd _prev _daddr
2259
+	local _has_dhclient=false _has_inet6=false
2260
+	set -A _c -- "$@"
2261
+	set -o noglob
2262
+
2263
+	ifconfig $_if inet6 >/dev/null 2>&1 && _has_inet6=true
2264
+	[[ -x /sbin/dhclient ]] && _has_dhclient=true
2265
+
2266
+	case ${_c[_af]} in
2267
+	''|*([[:blank:]])'#'*)
2268
+		return
2269
+		;;
2270
+	inet)	((${#_c[*]} > 1)) || return
2271
+		[[ ${_c[_name]} == alias ]] && _mask=3 _bc=4
2272
+		[[ -n ${_c[_mask]} ]] && _c[_mask]="netmask ${_c[_mask]}"
2273
+		if [[ -n ${_c[_bc]} ]]; then
2274
+			_c[_bc]="broadcast ${_c[_bc]}"
2275
+			[[ ${_c[_bc]} == *NONE ]] && _c[_bc]=
2276
+		fi
2277
+		_cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}"
2278
+		;;
2279
+	inet6)	! $_has_inet6 && return
2280
+		((${#_c[*]} > 1)) || return
2281
+		if [[ ${_c[_name]} == autoconf ]]; then
2282
+			_cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}"
2283
+			V6_AUTOCONF=true
2284
+			return
2285
+		fi
2286
+		[[ ${_c[_name]} == alias ]] && _prefix=3
2287
+		[[ -n ${_c[_prefix]} ]] && _c[_prefix]="prefixlen ${_c[_prefix]}"
2288
+		_cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}"
2289
+		;;
2290
+	dest)	((${#_c[*]} == 2)) && _daddr=${_c[1]} || return
2291
+		! $_has_inet6 && [[ $_daddr == @(*:*) ]] && return
2292
+		_prev=$((${#_cmds[*]} - 1))
2293
+		((_prev >= 0)) || return
2294
+		set -A _c -- ${_cmds[_prev]}
2295
+		_name=3
2296
+		[[ ${_c[_name]} == alias ]] && _name=4
2297
+		_c[_name]="${_c[_name]} $_daddr"
2298
+		_cmds[$_prev]="${_c[@]}"
2299
+		;;
2300
+	dhcp)	! $_has_dhclient && return
2301
+		_c[0]=
2302
+		_cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]} down;dhclient $_if"
2303
+		V4_DHCPCONF=true
2304
+		;;
2305
+	'!'*|bridge)
2306
+		# Skip shell commands and bridge in the installer.
2307
+		return
2308
+		;;
2309
+	*)	_cmds[${#_cmds[*]}]="ifconfig $_if ${_c[@]}"
2310
+		;;
2311
+	esac
2312
+	unset _c
2313
+	set +o noglob
2314
+}
2315
+
2117 2316
 # Start interface using the on-disk hostname.if file passed as argument $1.
2118 2317
 # Much of this is gratuitously stolen from /etc/netstart.
2119
-ifstart () {
2120
-	# Note: Do not rename the 'if' variable which is documented as being
2121
-	# usable in hostname.if(5) files.
2122
-	local _hn=$1 if=${1#/mnt/etc/hostname.}
2318
+ifstart() {
2319
+	local _if=$1 _hn=/mnt/etc/hostname.$1 _cmds _i=0 _line
2320
+	set -A _cmds
2321
+
2322
+	# Create interface if it does not yet exist.
2323
+	{ ifconfig $_if || ifconfig $_if create; } >/dev/null 2>&1 || return
2123 2324
 
2124 2325
 	((NIFS++))
2125
-	while :; do
2126
-		if [ "$cmd2" ]; then
2127
-			# We are carrying over from the 'read dt dtaddr'
2128
-			# last time.
2129
-			set -- $cmd2
2130
-			af=$1 name=$2 mask=$3 bcaddr=$4 ext1=$5 cmd2=
2131
-			# Make sure and get any remaining args in ext2,
2132
-			# like the read below.
2133
-			i=1
2134
-			while [ $i -lt 6 -a -n "$1" ]; do shift; let i=i+1; done
2135
-			ext2="$@"
2136
-		else
2137
-			# Read the next line or exit the while loop.
2138
-			read af name mask bcaddr ext1 ext2 || break
2139
-		fi
2140
-		# $af can be "dhcp", "up", "rtsol", an address family, commands,
2141
-		# or a comment.
2142
-		case "$af" in
2143
-		"#"*|"!"*|"bridge"|"")
2144
-			# Skip comments, user commands, bridges, and empty lines.
2145
-			continue
2146
-			;;
2147
-		"dhcp")
2148
-			[ "$name" = "NONE" ] && name=
2149
-			[ "$mask" = "NONE" ] && mask=
2150
-			[ "$bcaddr" = "NONE" ] && bcaddr=
2151
-			cmd="ifconfig $if $name $mask $bcaddr $ext1 $ext2 down"
2152
-			if [[ -x /sbin/dhclient ]]; then
2153
-				cmd="$cmd; dhclient $if"
2154
-			else
2155
-				cmd="$cmd; echo /sbin/dhclient missing - skipping dhcp request."
2156
-			fi
2157
-			dhcpif="$dhcpif $if"
2158
-			;;
2159
-		"rtsol")
2160
-			if ifconfig $if inet6 >/dev/null 2>&1; then
2161
-				rtsolif="$rtsolif $if"
2162
-				cmd="ifconfig $if $name $mask $bcaddr $ext1 $ext2 up"
2163
-			else
2164
-				cmd="$cmd; echo no INET6 support - skipping rtsol request."
2165
-			fi
2166
-			;;
2167
-		*)
2168
-			read dt dtaddr
2169
-			if [ "$name" = "alias" ]; then
2170
-				# Perform a 'shift' of sorts.
2171
-				alias=$name
2172
-				name=$mask
2173
-				mask=$bcaddr
2174
-				bcaddr=$ext1
2175
-				ext1=$ext2
2176
-				ext2=
2177
-			else
2178
-				alias=
2179
-			fi
2180
-			cmd="ifconfig $if $af $alias $name"
2181
-			case "$dt" in
2182
-			dest)
2183
-				cmd="$cmd $dtaddr"
2184
-				;;
2185
-			*)
2186
-				cmd2="$dt $dtaddr"
2187
-				;;
2188
-			esac
2189
-			case $af in
2190
-			inet)
2191
-				if [ ! -n "$name" ]; then
2192
-					echo "/etc/hostname.$if: inet alone is invalid"
2193
-					return
2194
-				fi
2195
-				[ "$mask" ] && cmd="$cmd netmask $mask"
2196
-				if [ "$bcaddr" -a "X$bcaddr" != "XNONE" ]; then
2197
-					cmd="$cmd broadcast $bcaddr"
2198
-				fi
2199
-				;;
2200
-			inet6)
2201
-				if [ ! -n "$name" ]; then
2202
-					echo "/etc/hostname.$if: inet6 alone is invalid"
2203
-					return
2204
-				fi
2205
-				[ "$mask" ] && cmd="$cmd prefixlen $mask"
2206
-				cmd="$cmd $bcaddr"
2207
-				;;
2208
-			*)
2209
-				cmd="$cmd $mask $bcaddr"
2210
-				;;
2211
-			esac
2212
-			cmd="$cmd $ext1 $ext2"
2213
-			;;
2214
-		esac
2215
-		eval "$cmd"
2326
+
2327
+	# Parse the hostname.if(5) file and fill _cmds array with interface
2328
+	# configuration commands.
2329
+	set -o noglob
2330
+	while IFS= read -- _line; do
2331
+		parse_hn_line $_line
2216 2332
 	done <$_hn
2333
+
2334
+	# Apply the interface configuration commands stored in _cmds array.
2335
+	while ((_i < ${#_cmds[*]})); do
2336
+		eval "${_cmds[_i]}"
2337
+		((_i++))
2338
+	done
2339
+	unset _cmds
2340
+	set +o noglob
2217 2341
 }
2218 2342
 
2219 2343
 # Configure the network during upgrade based on the on-disk configuration.
2220 2344
 enable_network() {
2221 2345
 	local _f _gw _hn _if _trunks _svlans _vlans
2222 2346
 
2223
-	# Copy any network configuration files.
2224
-	for _f in dhclient.conf resolv.conf resolv.conf.tail; do
2347
+	# Use installed network configuration files during upgrade.
2348
+	for _f in resolv.conf resolv.conf.tail; do
2225 2349
 		if [[ -f /mnt/etc/$_f ]]; then
2226 2350
 			cp /mnt/etc/$_f /etc/$_f
2227 2351
 		fi
... ...
@@ -2243,34 +2367,32 @@ enable_network() {
2243 2367
 		if isin "${_if%%+([0-9])}" $(ifconfig -C); then
2244 2368
 			# Dynamic interfaces must be done later.
2245 2369
 			case ${_if%%+([0-9])} in
2246
-			trunk)	_trunks="$_trunks $_hn";;
2247
-			svlan)	_svlans="$_svlans $_hn";;
2248
-			vlan)	_vlans="$_vlans $_hn";;
2370
+			trunk)	_trunks="$_trunks $_if";;
2371
+			svlan)	_svlans="$_svlans $_if";;
2372
+			vlan)	_vlans="$_vlans $_if";;
2249 2373
 			esac
2250 2374
 		else
2251 2375
 			# 'Real' interfaces (if available) are done now.
2252
-			ifconfig $_if >/dev/null 2>&1 && ifstart $_hn
2376
+			ifconfig $_if >/dev/null 2>&1 && ifstart $_if
2253 2377
 		fi
2254 2378
 	done
2255 2379
 	# Configure any dynamic interfaces now that 'real' ones are up.
2256 2380
 	# ORDER IS IMPORTANT! (see /etc/netstart).
2257
-	for _hn in $_trunks $_svlans $_vlans; do
2258
-		ifstart $_hn
2381
+	for _if in $_trunks $_svlans $_vlans; do
2382
+		ifstart $_if
2259 2383
 	done
2260 2384
 
2261
-	[[ -n $rtsolif ]] && ifconfig $rtsolif inet6 autoconf
2262
-
2263 2385
 	# /mnt/etc/mygate, if it exists, contains the address(es) of my
2264 2386
 	# default gateway(s). Use for ipv4 if no interfaces configured via
2265
-	# dhcp. Use for ipv6 if no interfaces configured via rtsol.
2266
-	[[ -z $dhcpif ]] && stripcom /mnt/etc/mygate | while read _gw; do
2387
+	# dhcp. Use for ipv6 if no interfaces configured via autoconf.
2388
+	! $V4_DHCPCONF && stripcom /mnt/etc/mygate |
2389
+	while read _gw; do
2267 2390
 		[[ $_gw == @(*:*) ]] && continue
2268
-		route -qn delete default >/dev/null 2>&1
2269 2391
 		route -qn add -host default $_gw && break
2270 2392
 	done
2271
-	[[ -z $rtsolif ]] && stripcom /mnt/etc/mygate | while read _gw; do
2393
+	! $V6_AUTOCONF && stripcom /mnt/etc/mygate |
2394
+	while read _gw; do
2272 2395
 		[[ $_gw == !(*:*) ]] && continue
2273
-		route -qn delete -inet6 default >/dev/null 2>&1
2274 2396
 		route -qn add -host -inet6 default $_gw && break
2275 2397
 	done
2276 2398
 
... ...
@@ -2284,11 +2406,27 @@ start_cgiinfo() {
2284 2406
 	# If no networks are configured, we do not need the httplist file.
2285 2407
 	((NIFS < 1)) && return
2286 2408
 
2287
-	ftp -MVo /tmp/mirrors http://libertybsd.net/mirrors/6.1 2> /dev/null
2288
-	HTTP_LIST=/tmp/mirrors
2289
-
2290 2409
 	# Ensure proper name resolution in case there's no dns yet.
2291 2410
 	add_hostent 47.186.116.162 libertybsd.net
2411
+	add_hostent 47.186.116.162 ftp.libertybsd.net
2412
+
2413
+	# Make sure the ftp subshell gets its own process group.
2414
+	set -m
2415
+	(
2416
+		unpriv2 ftp -w 15 -Vao - \
2417
+			"$HTTP_PROTO://libertybsd.net/mirrors.txt" \
2418
+			2>/dev/null >$CGI_INFO
2419
+
2420
+		# Remember finish time for adjusting the received timestamp.
2421
+		echo -n $SECONDS >$HTTP_SEC
2422
+		feed_random
2423
+	) & CGIPID=$!
2424
+	set +m
2425
+
2426
+	# If the ftp process takes more than 12 seconds, kill it.
2427
+	# XXX We are relying on the pid space not randomly biting us.
2428
+	# XXX ftp could terminate early, and the pid could be reused.
2429
+	(sleep 12; kill -INT -$CGIPID >/dev/null 2>&1) &
2292 2430
 }
2293 2431
 
2294 2432
 # Create a skeletal but useful /etc/fstab from /tmp/i/fstab by stripping all
... ...
@@ -2465,7 +2603,7 @@ install_sets() {
2465 2603
 			;;
2466 2604
 		[nN]*)	isin nfs $_locs && install_nfs && INSTALL_METHOD=nfs
2467 2605
 			;;
2468
-		*)	$AUTO && echo "'$resp' is not a valid choice." && exit 1
2606
+		*)	$AUTO && err_exit "'$resp' is not a valid choice."
2469 2607
 			;;
2470 2608
 		esac
2471 2609
 
... ...
@@ -2541,6 +2679,8 @@ store_random() {
2541 2679
 # Final steps common for installs and upgrades.
2542 2680
 finish_up() {
2543 2681
 	local _dev _mp _fstype _rest _d
2682
+	local _kernel_dir=/mnt/usr/share/relink/kernel
2683
+	local _kernel=${MDKERNEL:-GENERIC} _syspatch_archs="amd64 arm64 i386"
2544 2684
 
2545 2685
 	# Mount all known swap partitions.  This gives systems with little
2546 2686
 	# memory a better chance at running 'MAKEDEV all'.
... ...
@@ -2587,29 +2727,74 @@ finish_up() {
2587 2727
 		)
2588 2728
 	fi
2589 2729
 
2590
-	[[ -x /mnt/$MODE.site ]] && chroot /mnt /$MODE.site
2591
-
2592 2730
 	# In case this is a softraid device, make sure all underlying
2593 2731
 	# device nodes exist before installing boot-blocks on disk.
2594 2732
 	make_dev $(bioctl $ROOTDISK 2>/dev/null | sed -n 's/.*<\(.*\)>$/\1/p')
2595 2733
 	md_installboot $ROOTDISK
2596 2734
 
2735
+	chmod og-rwx /mnt/bsd{,.mp,.rd} 2>/dev/null
2597 2736
 	if [[ -f /mnt/bsd.mp ]] && ((NCPU > 1)); then
2737
+		_kernel=$_kernel.MP
2598 2738
 		echo "Multiprocessor machine; using bsd.mp instead of bsd."
2599 2739
 		mv /mnt/bsd /mnt/bsd.sp 2>/dev/null
2600 2740
 		mv /mnt/bsd.mp /mnt/bsd
2601 2741
 	fi
2602 2742
 
2743
+	# Write kernel.SHA256 matching the just installed kernel and fix path to
2744
+	# ensure it references the kernel as /bsd.
2745
+	sha256 /mnt/bsd | (umask 077; sed 's,/mnt,,' >/mnt/var/db/kernel.SHA256)
2746
+
2747
+	if [[ -f $_kernel_dir.tgz ]]; then
2748
+		echo -n "Relinking to create unique kernel..."
2749
+		(
2750
+		set -e
2751
+		rm -rf $_kernel_dir
2752
+		mkdir -m 700 -p $_kernel_dir
2753
+		tar -C $_kernel_dir -xzf $_kernel_dir.tgz $_kernel
2754
+		rm -f $_kernel_dir.tgz
2755
+		chroot /mnt /bin/ksh -e -c "cd ${_kernel_dir#/mnt}/$_kernel; \
2756
+			make newbsd; make newinstall"
2757
+		) >/dev/null 2>&1 && echo "done." || echo "failed."
2758
+	fi
2759
+
2603 2760
 	# Ensure that sysmerge in batch mode is run on reboot.
2604 2761
 	[[ $MODE == upgrade ]] &&
2605 2762
 		echo "/usr/sbin/sysmerge -b" >>/mnt/etc/rc.sysmerge
2606 2763
 
2607
-	# Ensure that fw_update is run on reboot.
2608
-	echo "/usr/sbin/fw_update -v" >>/mnt/etc/rc.firsttime
2764
+	# If a proxy was needed to fetch the sets, use it for fw_update and syspatch
2765
+	[[ -n $http_proxy ]] &&
2766
+		quote export "http_proxy=$http_proxy" >>/mnt/etc/rc.firsttime
2767
+
2768
+
2769
+	# Run syspatch -c on reboot if the arch is supported and if it is a
2770
+	# release system (not -stable or -current). List uninstalled syspatches
2771
+	# on the console and in the rc.firsttime output mail.
2772
+	isin $ARCH $_syspatch_archs && cat <<__EOT >>/mnt/etc/rc.firsttime
2773
+set -A _KERNV -- \$(sysctl -n kern.version |
2774
+	sed 's/^OpenBSD \([0-9]\.[0-9]\)\([^ ]*\).*/\1 \2/;q')
2775
+if ((\${#_KERNV[*]} == 1)) && [[ -s /etc/installurl ]] &&
2776
+	_CKPATCH=\$(mktemp /tmp/_ckpatch.XXXXXXXXXX); then
2777
+	echo -n "Checking for available binary patches... "
2778
+	syspatch -c > \$_CKPATCH && echo -n "done."
2779
+	echo
2780
+	if [[ -s \$_CKPATCH ]]; then
2781
+		echo "Run syspatch(8) to install:"
2782
+		cat \$_CKPATCH
2783
+	fi
2784
+	rm -f \$_CKPATCH
2785
+fi
2786
+__EOT
2609 2787
 
2610 2788
 	# Email installer questions and their answers to root on next boot.
2611 2789
 	prep_root_mail /tmp/i/$MODE.resp "$(hostname) $MODE response file"
2612 2790
 
2791
+	if [[ -x /mnt/$MODE.site ]]; then
2792
+		if ! chroot /mnt /$MODE.site; then
2793
+			store_random
2794
+			err_exit "$MODE.site failed"
2795
+		fi
2796
+	fi
2797
+
2613 2798
 	# Store entropy for the next boot.
2614 2799
 	store_random
2615 2800
 
... ...
@@ -2617,18 +2802,34 @@ finish_up() {
2617 2802
 	cat <<__EOT
2618 2803
 
2619 2804
 CONGRATULATIONS! Your LibertyBSD $MODE has been successfully completed!
2620
-To boot the new system, enter 'reboot' at the command prompt.
2805
+
2621 2806
 __EOT
2622 2807
 	[[ $MODE == install ]] && cat <<__EOT
2623 2808
 When you login to your new system the first time, please read your mail
2624 2809
 using the 'mail' command.
2810
+
2625 2811
 __EOT
2626 2812
 
2627 2813
 	md_congrats
2628 2814
 	$AUTO && >/tmp/ai/ai.done
2629 2815
 }
2630 2816
 
2631
-do_install(){
2817
+do_autoinstall() {
2818
+	rm -f /tmp/ai/ai.done
2819
+
2820
+	echo "Performing non-interactive $AI_MODE..."
2821
+	/$AI_MODE -af /tmp/ai/ai.$AI_MODE.conf 2>&1 </dev/null |
2822
+		sed "s/^.*$(echo '\r')//;w/tmp/ai/ai.log"
2823
+
2824
+	[[ -f /tmp/ai/ai.done ]] || err_exit "failed; check /tmp/ai/ai.log"
2825
+
2826
+	# Email autoinstall protocol to root on next boot.
2827
+	prep_root_mail /tmp/ai/ai.log "$(hostname) $AI_MODE log"
2828
+
2829
+	exec reboot
2830
+}
2831
+
2832
+do_install() {
2632 2833
 	local _rootkey _rootpass
2633 2834
 
2634 2835
 	# Ask for and set the system hostname and add the hostname specific
... ...
@@ -2642,15 +2843,15 @@ do_install(){
2642 2843
 	done
2643 2844
 	[[ ${resp%%.*} != $(hostname -s) ]] && hostname "$resp"
2644 2845
 	THESETS="$THESETS site$VERSION-$(hostname -s).tgz"
2846
+	export PS1='\h# '
2645 2847
 
2646 2848
 	echo
2647 2849
 
2648 2850
 	# Configure the network.
2649 2851
 	donetconfig
2650 2852
 
2651
-	# If there's network connectivity, fetch list of mirror servers and
2652
-	# installer choices from previous runs.
2653