1#!/bin/sh
2#-
3# Copyright (c) 2011 Nathan Whitehorn
4# Copyright (c) 2013 Devin Teske
5# All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10# 1. Redistributions of source code must retain the above copyright
11#    notice, this list of conditions and the following disclaimer.
12# 2. Redistributions in binary form must reproduce the above copyright
13#    notice, this list of conditions and the following disclaimer in the
14#    documentation and/or other materials provided with the distribution.
15#
16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26# SUCH DAMAGE.
27#
28# $FreeBSD: stable/11/usr.sbin/bsdinstall/scripts/auto 370209 2021-07-27 20:15:40Z gjb $
29#
30############################################################ INCLUDES
31
32BSDCFG_SHARE="/usr/share/bsdconfig"
33. $BSDCFG_SHARE/common.subr || exit 1
34f_include $BSDCFG_SHARE/dialog.subr
35
36############################################################ FUNCTIONS
37
38error() {
39	local msg
40	if [ -n "$1" ]; then
41		msg="$1\n\n"
42	fi
43	test -n "$DISTDIR_IS_UNIONFS" && umount -f $BSDINSTALL_DISTDIR
44	test -f $PATH_FSTAB && bsdinstall umount
45	dialog --backtitle "FreeBSD Installer" --title "Abort" \
46	    --no-label "Exit" --yes-label "Restart" --yesno \
47	    "${msg}An installation step has been aborted. Would you like to restart the installation or exit the installer?" 0 0
48	if [ $? -ne 0 ]; then
49		exit 1
50	else
51		exec $0
52	fi
53}
54
55hline_arrows_tab_enter="Press arrows, TAB or ENTER"
56msg_gpt_active_fix="Your hardware is known to have issues booting in CSM/Legacy/BIOS mode from GPT partitions that are not set active. Would you like the installer to apply this workaround for you?"
57msg_lenovo_fix="Your model of Lenovo is known to have a BIOS bug that prevents it booting from GPT partitions without UEFI. Would you like the installer to apply a workaround for you?"
58msg_no="NO"
59msg_yes="YES"
60
61# dialog_workaround
62#
63# Ask the user if they wish to apply a workaround
64#
65dialog_workaround()
66{
67	local passed_msg="$1"
68	local title="$DIALOG_TITLE"
69	local btitle="$DIALOG_BACKTITLE"
70	local prompt # Calculated below
71	local hline="$hline_arrows_tab_enter"
72
73	local height=8 width=50 prefix="   "
74	local plen=${#prefix} list= line=
75	local max_width=$(( $width - 3 - $plen ))
76
77	local yes no defaultno extra_args format
78	if [ "$USE_XDIALOG" ]; then
79		yes=ok no=cancel defaultno=default-no
80		extra_args="--wrap --left"
81		format="$passed_msg"
82	else
83		yes=yes no=no defaultno=defaultno
84		extra_args="--cr-wrap"
85		format="$passed_msg"
86	fi
87
88	# Add height for Xdialog(1)
89	[ "$USE_XDIALOG" ] && height=$(( $height + $height / 5 + 3 ))
90
91	prompt=$( printf "$format" )
92	f_dprintf "%s: Workaround prompt" "$0"
93	$DIALOG \
94		--title "$title"        \
95		--backtitle "$btitle"   \
96		--hline "$hline"        \
97		--$yes-label "$msg_yes" \
98		--$no-label "$msg_no"   \
99		$extra_args             \
100		--yesno "$prompt" $height $width
101}
102
103############################################################ MAIN
104
105f_dprintf "Began Installation at %s" "$( date )"
106
107rm -rf $BSDINSTALL_TMPETC
108mkdir $BSDINSTALL_TMPETC
109
110trap true SIGINT	# This section is optional
111bsdinstall keymap
112
113trap error SIGINT	# Catch cntrl-C here
114bsdinstall hostname || error "Set hostname failed"
115
116export DISTRIBUTIONS="base.txz kernel.txz"
117if [ -f $BSDINSTALL_DISTDIR/MANIFEST ]; then
118	DISTMENU=`awk -F'\t' '!/^(kernel\.txz|base\.txz)/{print $1,$5,$6}' $BSDINSTALL_DISTDIR/MANIFEST`
119	DISTMENU="$(echo ${DISTMENU} | sed -E 's/\.txz//g')"
120
121	if [ -n "$DISTMENU" ]; then
122		exec 3>&1
123		EXTRA_DISTS=$( eval dialog \
124		    --backtitle \"FreeBSD Installer\" \
125		    --title \"Distribution Select\" --nocancel --separate-output \
126		    --checklist \"Choose optional system components to install:\" \
127		    0 0 0 $DISTMENU \
128		2>&1 1>&3 )
129		for dist in $EXTRA_DISTS; do
130			export DISTRIBUTIONS="$DISTRIBUTIONS $dist.txz"
131		done
132	fi
133fi
134
135LOCAL_DISTRIBUTIONS="MANIFEST"
136FETCH_DISTRIBUTIONS=""
137for dist in $DISTRIBUTIONS; do
138	if [ ! -f $BSDINSTALL_DISTDIR/$dist ]; then
139		FETCH_DISTRIBUTIONS="$FETCH_DISTRIBUTIONS $dist"
140	else
141		LOCAL_DISTRIBUTIONS="$LOCAL_DISTRIBUTIONS $dist"
142	fi
143done
144LOCAL_DISTRIBUTIONS=`echo $LOCAL_DISTRIBUTIONS`	# Trim white space
145FETCH_DISTRIBUTIONS=`echo $FETCH_DISTRIBUTIONS`	# Trim white space
146
147if [ -n "$FETCH_DISTRIBUTIONS" -a -n "$BSDINSTALL_CONFIGCURRENT" ]; then
148	dialog --backtitle "FreeBSD Installer" --title "Network Installation" --msgbox "Some installation files were not found on the boot volume. The next few screens will allow you to configure networking so that they can be downloaded from the Internet." 0 0
149	bsdinstall netconfig || error
150	NETCONFIG_DONE=yes
151fi
152
153if [ -n "$FETCH_DISTRIBUTIONS" ]; then
154	exec 3>&1
155	BSDINSTALL_DISTSITE=$(`dirname $0`/mirrorselect 2>&1 1>&3)
156	MIRROR_BUTTON=$?
157	exec 3>&-
158	test $MIRROR_BUTTON -eq 0 || error "No mirror selected"
159	export BSDINSTALL_DISTSITE
160fi
161
162rm -f $PATH_FSTAB
163touch $PATH_FSTAB
164
165#
166# Try to detect known broken platforms and apply their workarounds
167#
168
169if f_interactive; then
170	sys_maker=$( kenv -q smbios.system.maker )
171	f_dprintf "smbios.system.maker=[%s]" "$sys_maker"
172	sys_model=$( kenv -q smbios.system.product )
173	f_dprintf "smbios.system.product=[%s]" "$sys_model"
174	sys_version=$( kenv -q smbios.system.version )
175	f_dprintf "smbios.system.version=[%s]" "$sys_version"
176	sys_mb_maker=$( kenv -q smbios.planar.maker )
177	f_dprintf "smbios.planar.maker=[%s]" "$sys_mb_maker"
178	sys_mb_product=$( kenv -q smbios.planar.product )
179	f_dprintf "smbios.planar.product=[%s]" "$sys_mb_product"
180
181	#
182	# Laptop Models
183	#
184	case "$sys_maker" in
185	"LENOVO")
186		case "$sys_version" in
187		"ThinkPad X220"|"ThinkPad T420"|"ThinkPad T520"|"ThinkPad W520"|"ThinkPad X1")
188			dialog_workaround "$msg_lenovo_fix"
189			retval=$?
190			f_dprintf "lenovofix_prompt=[%s]" "$retval"
191			if [ $retval -eq $DIALOG_OK ]; then
192				export ZFSBOOT_PARTITION_SCHEME="GPT + Lenovo Fix"
193				export WORKAROUND_LENOVO=1
194			fi
195			;;
196		esac
197		;;
198	"Dell Inc.")
199		case "$sys_model" in
200		"Latitude E6330"|"Latitude E7440"|"Latitude E7240"|"Precision Tower 5810")
201			dialog_workaround "$msg_gpt_active_fix"
202			retval=$?
203			f_dprintf "gpt_active_fix_prompt=[%s]" "$retval"
204			if [ $retval -eq $DIALOG_OK ]; then
205				export ZFSBOOT_PARTITION_SCHEME="GPT + Active"
206				export WORKAROUND_GPTACTIVE=1
207			fi
208			;;
209		esac
210		;;
211	"Hewlett-Packard")
212		case "$sys_model" in
213		"HP ProBook 4330s")
214			dialog_workaround "$msg_gpt_active_fix"
215			retval=$?
216			f_dprintf "gpt_active_fix_prompt=[%s]" "$retval"
217			if [ $retval -eq $DIALOG_OK ]; then
218				export ZFSBOOT_PARTITION_SCHEME="GPT + Active"
219				export WORKAROUND_GPTACTIVE=1
220			fi
221			;;
222		esac
223		;;
224	esac
225	#
226	# Motherboard Models
227	#
228	case "$sys_mb_maker" in
229	"Intel Corporation")
230		case "$sys_mb_product" in
231		"DP965LT"|"D510MO")
232			dialog_workaround "$msg_gpt_active_fix"
233			retval=$?
234			f_dprintf "gpt_active_fix_prompt=[%s]" "$retval"
235			if [ $retval -eq $DIALOG_OK ]; then
236				export ZFSBOOT_PARTITION_SCHEME="GPT + Active"
237				export WORKAROUND_GPTACTIVE=1
238			fi
239			;;
240		esac
241		;;
242	"Acer")
243		case "$sys_mb_product" in
244		"Veriton M6630G")
245			dialog_workaround "$msg_gpt_active_fix"
246			retval=$?
247			f_dprintf "gpt_active_fix_prompt=[%s]" "$retval"
248			if [ $retval -eq $DIALOG_OK ]; then
249				export ZFSBOOT_PARTITION_SCHEME="GPT + Active"
250				export WORKAROUND_GPTACTIVE=1
251			fi
252			;;
253		esac
254		;;
255	esac
256fi
257
258PMODES="\
259\"Auto (UFS)\" \"Guided Disk Setup\" \
260Manual \"Manual Disk Setup (experts)\" \
261Shell \"Open a shell and partition by hand\""
262
263CURARCH=$( uname -m )
264case $CURARCH in
265	amd64|arm64|i386)	# Booting ZFS Supported
266		PMODES="$PMODES \"Auto (ZFS)\" \"Guided Root-on-ZFS\""
267		;;
268	*)		# Booting ZFS Unspported
269		;;
270esac
271
272exec 3>&1
273PARTMODE=`echo $PMODES | xargs dialog --backtitle "FreeBSD Installer" \
274	--title "Partitioning" \
275	--menu "How would you like to partition your disk?" \
276	0 0 0 2>&1 1>&3` || exit 1
277exec 3>&-
278
279case "$PARTMODE" in
280"Auto (UFS)")	# Guided
281	bsdinstall autopart || error "Partitioning error"
282	bsdinstall mount || error "Failed to mount filesystem"
283	;;
284"Shell")	# Shell
285	clear
286	echo "Use this shell to set up partitions for the new system. When finished, mount the system at $BSDINSTALL_CHROOT and place an fstab file for the new system at $PATH_FSTAB. Then type 'exit'. You can also enter the partition editor at any time by entering 'bsdinstall partedit'."
287	sh 2>&1
288	;;
289"Manual")	# Manual
290	if f_isset debugFile; then
291		# Give partedit the path to our logfile so it can append
292		BSDINSTALL_LOG="${debugFile#+}" bsdinstall partedit || error "Partitioning error"
293	else
294		bsdinstall partedit || error "Partitioning error"
295	fi
296	bsdinstall mount || error "Failed to mount filesystem"
297	;;
298"Auto (ZFS)")	# ZFS
299	bsdinstall zfsboot || error "ZFS setup failed"
300	bsdinstall mount || error "Failed to mount filesystem"
301	;;
302*)
303	error "Unknown partitioning mode"
304	;;
305esac
306
307if [ ! -z "$FETCH_DISTRIBUTIONS" ]; then
308	ALL_DISTRIBUTIONS="$DISTRIBUTIONS"
309	WANT_DEBUG=
310
311	# Download to a directory in the new system as scratch space
312	BSDINSTALL_FETCHDEST="$BSDINSTALL_CHROOT/usr/freebsd-dist"
313	mkdir -p "$BSDINSTALL_FETCHDEST" || error "Could not create directory $BSDINSTALL_FETCHDEST"
314
315	export DISTRIBUTIONS="$FETCH_DISTRIBUTIONS"
316	# Try to use any existing distfiles
317	if [ -d $BSDINSTALL_DISTDIR ]; then
318		DISTDIR_IS_UNIONFS=1
319		mount_nullfs -o union "$BSDINSTALL_FETCHDEST" "$BSDINSTALL_DISTDIR"
320	else
321		export DISTRIBUTIONS="$FETCH_DISTRIBUTIONS"
322		export BSDINSTALL_DISTDIR="$BSDINSTALL_FETCHDEST"
323	fi
324		
325	export FTP_PASSIVE_MODE=YES
326	# Iterate through the distribution list and set a flag if debugging
327	# distributions have been selected.
328	for _DISTRIBUTION in $DISTRIBUTIONS; do
329		case $_DISTRIBUTION in
330			*-dbg.*)
331				[ -e $BSDINSTALL_DISTDIR/$_DISTRIBUTION ] \
332					&& continue
333				WANT_DEBUG=1
334				DEBUG_LIST="\n$DEBUG_LIST\n$_DISTRIBUTION"
335				;;
336			*)
337				;;
338		esac
339	done
340
341	# Fetch the distributions.
342	bsdinstall distfetch
343	rc=$?
344
345	if [ $rc -ne 0 ]; then
346		# If unable to fetch the remote distributions, recommend
347		# deselecting the debugging distributions, and retrying the
348		# installation, since failure to fetch *-dbg.txz should not
349		# be considered a fatal installation error.
350		msg="Failed to fetch remote distribution"
351		if [ ! -z "$WANT_DEBUG" ]; then
352			# Trim leading and trailing newlines.
353			DEBUG_LIST="${DEBUG_LIST%%\n}"
354			DEBUG_LIST="${DEBUG_LIST##\n}"
355			msg="$msg\n\nPlease deselect the following distributions"
356			msg="$msg and retry the installation:"
357			msg="$msg\n$DEBUG_LIST"
358		fi
359		error "$msg"
360	fi
361	export DISTRIBUTIONS="$ALL_DISTRIBUTIONS"
362fi
363
364if [ ! -z "$LOCAL_DISTRIBUTIONS" ]; then
365	# Download to a directory in the new system as scratch space
366	BSDINSTALL_FETCHDEST="$BSDINSTALL_CHROOT/usr/freebsd-dist"
367	mkdir -p "$BSDINSTALL_FETCHDEST" || error "Could not create directory $BSDINSTALL_FETCHDEST"
368	# Try to use any existing distfiles
369	if [ -d $BSDINSTALL_DISTDIR ]; then
370		DISTDIR_IS_UNIONFS=1
371		mount_nullfs -o union "$BSDINSTALL_FETCHDEST" "$BSDINSTALL_DISTDIR"
372		export BSDINSTALL_DISTDIR="$BSDINSTALL_FETCHDEST"
373	fi
374	env DISTRIBUTIONS="$LOCAL_DISTRIBUTIONS" \
375		BSDINSTALL_DISTSITE="file:///usr/freebsd-dist" \
376		bsdinstall distfetch || \
377		error "Failed to fetch distribution from local media"
378fi
379
380bsdinstall checksum || error "Distribution checksum failed"
381bsdinstall distextract || error "Distribution extract failed"
382bsdinstall rootpass || error "Could not set root password"
383
384trap true SIGINT	# This section is optional
385if [ "$NETCONFIG_DONE" != yes ]; then
386	bsdinstall netconfig	# Don't check for errors -- the user may cancel
387fi
388bsdinstall time
389bsdinstall services
390bsdinstall hardening
391
392dialog --backtitle "FreeBSD Installer" --title "Add User Accounts" --yesno \
393    "Would you like to add users to the installed system now?" 0 0 && \
394    bsdinstall adduser
395
396finalconfig() {
397	exec 3>&1
398	REVISIT=$(dialog --backtitle "FreeBSD Installer" \
399	    --title "Final Configuration" --no-cancel --menu \
400	    "Setup of your FreeBSD system is nearly complete. You can now modify your configuration choices. After this screen, you will have an opportunity to make more complex changes using a shell." 0 0 0 \
401		"Exit" "Apply configuration and exit installer" \
402		"Add User" "Add a user to the system" \
403		"Root Password" "Change root password" \
404		"Hostname" "Set system hostname" \
405		"Network" "Networking configuration" \
406		"Services" "Set daemons to run on startup" \
407		"System Hardening" "Set security options" \
408		"Time Zone" "Set system timezone" \
409		"Handbook" "Install FreeBSD Handbook (requires network)" 2>&1 1>&3)
410	exec 3>&-
411
412	case "$REVISIT" in
413	"Add User")
414		bsdinstall adduser
415		finalconfig
416		;;
417	"Root Password")
418		bsdinstall rootpass 
419		finalconfig
420		;;
421	"Hostname")
422		bsdinstall hostname
423		finalconfig
424		;;
425	"Network")
426		bsdinstall netconfig
427		finalconfig
428		;;
429	"Services")
430		bsdinstall services
431		finalconfig
432		;;
433	"System Hardening")
434		bsdinstall hardening
435		finalconfig
436		;;
437	"Time Zone")
438		bsdinstall time
439		finalconfig
440		;;
441	"Handbook")
442		bsdinstall docsinstall
443		finalconfig
444		;;
445	esac
446}
447
448# Allow user to change his mind
449finalconfig
450
451trap error SIGINT	# SIGINT is bad again
452bsdinstall config  || error "Failed to save config"
453
454if [ -n "$DISTDIR_IS_UNIONFS" ]; then
455	umount -f $BSDINSTALL_DISTDIR
456fi
457
458if [ ! -z "$BSDINSTALL_FETCHDEST" ]; then
459	rm -rf "$BSDINSTALL_FETCHDEST"
460fi
461
462dialog --backtitle "FreeBSD Installer" --title "Manual Configuration" \
463    --default-button no --yesno \
464   "The installation is now finished. Before exiting the installer, would you like to open a shell in the new system to make any final manual modifications?" 0 0
465if [ $? -eq 0 ]; then
466	clear
467	echo This shell is operating in a chroot in the new system. \
468	    When finished making configuration changes, type \"exit\".
469	chroot "$BSDINSTALL_CHROOT" /bin/sh 2>&1
470fi
471
472bsdinstall entropy
473bsdinstall umount
474
475f_dprintf "Installation Completed at %s" "$( date )"
476
477################################################################################
478# END
479################################################################################
480