xref: /freebsd/usr.sbin/bsdinstall/scripts/auto (revision 494de51bc0074472d1b01604f085daea0844f240)
1#!/bin/sh
2#-
3# Copyright (c) 2011 Nathan Whitehorn
4# Copyright (c) 2013-2018 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#
29############################################################ INCLUDES
30
31BSDCFG_SHARE="/usr/share/bsdconfig"
32. $BSDCFG_SHARE/common.subr || exit 1
33f_include $BSDCFG_SHARE/dialog.subr
34
35############################################################ GLOBALS
36
37#
38# List of environment variables that may be defined by the user, but modified
39# during the installation process. They are then restored when restarting this
40# script.
41#
42user_env_vars="BSDINSTALL_DISTSITE DISTRIBUTIONS WORKAROUND_GPTACTIVE WORKAROUND_LENOVO ZFSBOOT_PARTITION_SCHEME"
43
44#
45# Strings that should be moved to an i18n file and loaded with f_include_lang()
46#
47hline_arrows_tab_enter="Press arrows, TAB or ENTER"
48hline_arrows_tab_space_enter="Press arrows, TAB, SPACE or ENTER"
49msg_abort="Abort"
50msg_an_installation_step_has_been_aborted="An installation step has been aborted. Would you like\nto restart the installation or exit the installer?"
51msg_auto_ufs="Auto (UFS)"
52msg_auto_ufs_desc="Guided UFS Disk Setup"
53msg_auto_ufs_help="Menu options help choose which disk to setup using UFS and standard partitions"
54msg_auto_zfs="Auto (ZFS)"
55msg_auto_zfs_desc="Guided Root-on-ZFS"
56msg_auto_zfs_help="To use ZFS with less than 8GB RAM, see https://wiki.freebsd.org/ZFSTuningGuide"
57msg_exit="Exit"
58msg_freebsd_installer="$OSNAME Installer"
59msg_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?"
60msg_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?"
61msg_manual="Manual"
62msg_manual_desc="Manual Disk Setup (experts)"
63msg_manual_help="Create customized partitions from menu options"
64msg_no="NO"
65msg_restart="Restart"
66msg_shell="Shell"
67msg_shell_desc="Open a shell and partition by hand"
68msg_shell_help="Create customized partitions using command-line utilities"
69msg_yes="YES"
70
71############################################################ FUNCTIONS
72
73# error [$msg]
74#
75# Display generic error message when a script fails. An optional message
76# argument can preceed the generic message. User is given the choice of
77# restarting the installer or exiting.
78#
79error()
80{
81	local title="$msg_abort"
82	local btitle="$msg_freebsd_installer"
83	local prompt="${1:+$1\n\n}$msg_an_installation_step_has_been_aborted"
84	local hline="$hline_arrows_tab_space_enter"
85
86	[ -f "$PATH_FSTAB" ] && bsdinstall umount
87
88	local height width
89	f_dialog_buttonbox_size height width \
90		"$title" "$btitle" "$prompt" "$hline"
91
92	if $DIALOG \
93		--title "$title"           \
94		--backtitle "$btitle"      \
95		--hline "$hline"           \
96		--no-label "$msg_exit"     \
97		--yes-label "$msg_restart" \
98		--yesno "$prompt" $height $width
99	then
100		environment_restore
101		exec $0
102		# NOTREACHED
103	fi
104	exit 1
105}
106
107# dialog_workaround
108#
109# Ask the user if they wish to apply a workaround
110#
111dialog_workaround()
112{
113	local passed_msg="$1"
114	local title="$DIALOG_TITLE"
115	local btitle="$DIALOG_BACKTITLE"
116	local prompt # Calculated below
117	local hline="$hline_arrows_tab_enter"
118
119	local height=8 width=50 prefix="   "
120	local plen=${#prefix} list= line=
121	local max_width=$(( $width - 3 - $plen ))
122
123	local yes no defaultno extra_args format
124	if [ "$USE_XDIALOG" ]; then
125		yes=ok no=cancel defaultno=default-no
126		extra_args="--wrap --left"
127		format="$passed_msg"
128	else
129		yes=yes no=no defaultno=defaultno
130		extra_args="--cr-wrap"
131		format="$passed_msg"
132	fi
133
134	# Add height for Xdialog(1)
135	[ "$USE_XDIALOG" ] && height=$(( $height + $height / 5 + 3 ))
136
137	prompt=$( printf "$format" )
138	f_dprintf "%s: Workaround prompt" "$0"
139	$DIALOG \
140		--title "$title"        \
141		--backtitle "$btitle"   \
142		--hline "$hline"        \
143		--$yes-label "$msg_yes" \
144		--$no-label "$msg_no"   \
145		$extra_args             \
146		--yesno "$prompt" $height $width
147}
148
149# environment_restore
150#
151# Restore a list of environment variables when this script is restarted.
152#
153environment_restore()
154{
155	for var in $user_env_vars; do
156		eval "if [ -n \"\${ORIG_$var}\" -o -z \"\${ORIG_$var-z}\" ]; then $var=\${ORIG_$var}; else unset $var; fi"
157	done
158}
159
160# environment_save
161#
162# Save any user-defined environment variable that may be modified during the
163# installation process. They are then restored when restarting this script.
164#
165environment_save()
166{
167	for var in $user_env_vars; do
168		eval "if [ -n \"\${$var}\" -o -z \"\${$var-z}\" ]; then ORIG_$var=\${$var}; else unset ORIG_$var; fi"
169	done
170}
171
172############################################################ MAIN
173
174f_dprintf "Began Installation at %s" "$( date )"
175
176environment_save
177
178rm -rf $BSDINSTALL_TMPETC
179mkdir $BSDINSTALL_TMPETC
180
181# Reset the ESP list
182: > ${TMPDIR:-"/tmp"}/bsdinstall-esps
183
184# With pkgbase, pkg OOM has been observed with QEMU-default 128 MiB memory size.
185# Ensure we have at least about 256 MiB (with an allowance for rounding etc.).
186physmem=$(($(sysctl -n hw.physmem) / 1048576))
187if [ $physmem -lt 200 ]; then
188        bsddialog --backtitle "$OSNAME Installer" --title "Warning" \
189	    --msgbox "Insufficient physical memory (${physmem} MiB) detected. At least 256 MiB is recommended. The installer or installed system may not function correctly." 0 0
190fi
191
192[ -f /usr/libexec/bsdinstall/local.pre-everything ] && f_dprintf "Running local.pre-everything" && sh /usr/libexec/bsdinstall/local.pre-everything "$BSDINSTALL_CHROOT"
193
194trap true SIGINT	# This section is optional
195[ -z "$BSDINSTALL_SKIP_KEYMAP" ] && bsdinstall keymap
196
197trap error SIGINT	# Catch cntrl-C here
198if [ -z "$BSDINSTALL_SKIP_HOSTNAME" ]; then bsdinstall hostname || error "Set hostname failed"; fi
199
200if [ -f /usr/freebsd-packages/repos/FreeBSD-base-offline.conf ]; then
201	HAVE_BASE_PACKAGES=yes
202	PKGBASE_DEFAULT_BUTTON=--default-no
203else
204	unset HAVE_BASE_PACKAGES
205	unset PKGBASE_DEFAULT_BUTTON
206fi
207
208if [ ! -f $BSDINSTALL_DISTDIR/MANIFEST ]; then
209	PKGBASE=yes
210else
211	bsddialog --backtitle "$OSNAME Installer" --title "Select Installation Type" \
212		--yes-label "Traditional" --no-label "Packages (Experimental)" --yesno \
213		$PKGBASE_DEFAULT_BUTTON \
214		"Would you like to install the base system using traditional distribution sets or packages (experimental)?" 0 0
215	if [ $? -eq 1 ]; then
216		PKGBASE=yes
217	fi
218fi
219
220if [ "$PKGBASE" == yes ]; then
221	if [ "$HAVE_BASE_PACKAGES" == yes ]; then
222		bsddialog --backtitle "$OSNAME Installer" --title "Network or Offline Installation" \
223		    --yes-label "Network" --no-label "Offline (Limited Packages)" --yesno \
224		    "Would you like to fetch packages from the internet or use the limited set of packages included in this installation media?" 0 0
225		if [ $? -eq 1 ]; then
226			export BSDINSTALL_PKG_REPOS_DIR=/usr/freebsd-packages/repos/
227		else
228			bsdinstall netconfig || error
229			NETCONFIG_DONE=yes
230		fi
231	else
232		bsddialog --backtitle "$OSNAME Installer" --title "Network Installation" \
233		    --msgbox "No base system packages are included in this installation media. The next few screens will allow you to configure networking." 0 0
234		bsdinstall netconfig || error
235		NETCONFIG_DONE=yes
236	fi
237else
238	export DISTRIBUTIONS="${DISTRIBUTIONS:-base.txz kernel.txz}"
239	if [ -f $BSDINSTALL_DISTDIR/MANIFEST ]; then
240		DISTMENU=`awk -F'\t' '!/^(kernel\.txz|base\.txz)/{print $1,$5,$6}' $BSDINSTALL_DISTDIR/MANIFEST`
241		DISTMENU="$(echo ${DISTMENU} | sed -E 's/\.txz//g')"
242
243		if [ -n "$DISTMENU" ]; then
244			exec 5>&1
245			EXTRA_DISTS=$( eval bsddialog \
246			    --backtitle \"$OSNAME Installer\" \
247			    --title \"Distribution Select\" --nocancel --separate-output \
248			    --checklist \"Choose optional system components to install:\" \
249			    0 0 0 $DISTMENU \
250			2>&1 1>&5 )
251			for dist in $EXTRA_DISTS; do
252				export DISTRIBUTIONS="$DISTRIBUTIONS $dist.txz"
253			done
254		fi
255	fi
256
257	FETCH_DISTRIBUTIONS=""
258	for dist in $DISTRIBUTIONS; do
259		if [ ! -f $BSDINSTALL_DISTDIR/$dist ]; then
260			FETCH_DISTRIBUTIONS="$FETCH_DISTRIBUTIONS $dist"
261		fi
262	done
263
264	if [ -n "$FETCH_DISTRIBUTIONS" -a -n "$BSDINSTALL_CONFIGCURRENT" ]; then
265		bsddialog --backtitle "$OSNAME 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
266		bsdinstall netconfig || error
267		NETCONFIG_DONE=yes
268	fi
269fi
270
271rm -f $PATH_FSTAB
272touch $PATH_FSTAB
273
274[ -f /usr/libexec/bsdinstall/local.pre-partition ] && f_dprintf "Running local.pre-partition" && sh /usr/libexec/bsdinstall/local.pre-partition "$BSDINSTALL_CHROOT"
275
276#
277# Try to detect known broken platforms and apply their workarounds
278#
279
280if f_interactive; then
281	sys_maker=$( kenv -q smbios.system.maker )
282	f_dprintf "smbios.system.maker=[%s]" "$sys_maker"
283	sys_model=$( kenv -q smbios.system.product )
284	f_dprintf "smbios.system.product=[%s]" "$sys_model"
285	sys_version=$( kenv -q smbios.system.version )
286	f_dprintf "smbios.system.version=[%s]" "$sys_version"
287	sys_mb_maker=$( kenv -q smbios.planar.maker )
288	f_dprintf "smbios.planar.maker=[%s]" "$sys_mb_maker"
289	sys_mb_product=$( kenv -q smbios.planar.product )
290	f_dprintf "smbios.planar.product=[%s]" "$sys_mb_product"
291
292	#
293	# Laptop Models
294	#
295	case "$sys_maker" in
296	"LENOVO")
297		case "$sys_version" in
298		"ThinkPad X220"|"ThinkPad T420"|"ThinkPad T520"|"ThinkPad W520"|"ThinkPad X1")
299			dialog_workaround "$msg_lenovo_fix"
300			retval=$?
301			f_dprintf "lenovofix_prompt=[%s]" "$retval"
302			if [ $retval -eq $DIALOG_OK ]; then
303				export ZFSBOOT_PARTITION_SCHEME="GPT + Lenovo Fix"
304				export WORKAROUND_LENOVO=1
305			fi
306			;;
307		esac
308		;;
309	"Dell Inc.")
310		case "$sys_model" in
311		"Latitude E6330"|"Latitude E7440"|"Latitude E7240"|"Precision Tower 5810")
312			dialog_workaround "$msg_gpt_active_fix"
313			retval=$?
314			f_dprintf "gpt_active_fix_prompt=[%s]" "$retval"
315			if [ $retval -eq $DIALOG_OK ]; then
316				export ZFSBOOT_PARTITION_SCHEME="GPT + Active"
317				export WORKAROUND_GPTACTIVE=1
318			fi
319			;;
320		esac
321		;;
322	"Hewlett-Packard")
323		case "$sys_model" in
324		"HP ProBook 4330s")
325			dialog_workaround "$msg_gpt_active_fix"
326			retval=$?
327			f_dprintf "gpt_active_fix_prompt=[%s]" "$retval"
328			if [ $retval -eq $DIALOG_OK ]; then
329				export ZFSBOOT_PARTITION_SCHEME="GPT + Active"
330				export WORKAROUND_GPTACTIVE=1
331			fi
332			;;
333		esac
334		;;
335	esac
336	#
337	# Motherboard Models
338	#
339	case "$sys_mb_maker" in
340	"Intel Corporation")
341		case "$sys_mb_product" in
342		"DP965LT"|"D510MO")
343			dialog_workaround "$msg_gpt_active_fix"
344			retval=$?
345			f_dprintf "gpt_active_fix_prompt=[%s]" "$retval"
346			if [ $retval -eq $DIALOG_OK ]; then
347				export ZFSBOOT_PARTITION_SCHEME="GPT + Active"
348				export WORKAROUND_GPTACTIVE=1
349			fi
350			;;
351		esac
352		;;
353	"Acer")
354		case "$sys_mb_product" in
355		"Veriton M6630G")
356			dialog_workaround "$msg_gpt_active_fix"
357			retval=$?
358			f_dprintf "gpt_active_fix_prompt=[%s]" "$retval"
359			if [ $retval -eq $DIALOG_OK ]; then
360				export ZFSBOOT_PARTITION_SCHEME="GPT + Active"
361				export WORKAROUND_GPTACTIVE=1
362			fi
363			;;
364		esac
365		;;
366	esac
367fi
368
369PMODES="
370	'$msg_auto_ufs' '$msg_auto_ufs_desc' '$msg_auto_ufs_help'
371	'$msg_manual' '$msg_manual_desc' '$msg_manual_help'
372	'$msg_shell' '$msg_shell_desc' '$msg_shell_help'
373" # END-QUOTE
374
375CURARCH=$( uname -m )
376case $CURARCH in
377	amd64|arm64|i386|riscv)	# Booting ZFS Supported
378		PMODES="
379			'$msg_auto_zfs' '$msg_auto_zfs_desc' '$msg_auto_zfs_help'
380			$PMODES
381		" # END-QUOTE
382		;;
383	*)			# Booting ZFS Unsupported
384		;;
385esac
386
387exec 5>&1
388PARTMODE=`echo $PMODES | xargs -o bsddialog --backtitle "$OSNAME Installer" \
389	--title "Partitioning" \
390	--item-help \
391	--menu "How would you like to partition your disk?" \
392	0 0 0 2>&1 1>&5` || exit 1
393exec 5>&-
394
395case "$PARTMODE" in
396"$msg_auto_zfs")	# ZFS
397	bsdinstall zfsboot || error "ZFS setup failed"
398	bsdinstall mount || error "Failed to mount filesystem"
399	;;
400"$msg_auto_ufs")	# Guided UFS
401	bsdinstall autopart || error "Partitioning error"
402	bsdinstall mount || error "Failed to mount filesystem"
403	;;
404"$msg_shell")		# Shell
405	clear
406	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'."
407	sh 2>&1
408	;;
409"$msg_manual")		# Manual
410	if f_isset debugFile; then
411		# Give partedit the path to our logfile so it can append
412		BSDINSTALL_LOG="${debugFile#+}" bsdinstall partedit || error "Partitioning error"
413	else
414		bsdinstall partedit || error "Partitioning error"
415	fi
416	bsdinstall mount || error "Failed to mount filesystem"
417	;;
418*)
419	error "Unknown partitioning mode"
420	;;
421esac
422
423[ -f /usr/libexec/bsdinstall/local.pre-fetch ] && f_dprintf "Running local.pre-fetch" && sh /usr/libexec/bsdinstall/local.pre-fetch "$BSDINSTALL_CHROOT"
424
425if [ "$PKGBASE" == yes ]; then
426	bsdinstall pkgbase || error "Installation of base system packages failed"
427else
428	if [ -n "$FETCH_DISTRIBUTIONS" ]; then
429		exec 5>&1
430		export BSDINSTALL_DISTDIR=$(`dirname $0`/fetchmissingdists 2>&1 1>&5)
431		FETCH_RESULT=$?
432		exec 5>&-
433
434		[ $FETCH_RESULT -ne 0 ] && error "Could not fetch remote distributions"
435	fi
436	bsdinstall checksum || error "Distribution checksum failed"
437	bsdinstall distextract || error "Distribution extract failed"
438fi
439
440# Set up boot loader
441bsdinstall bootconfig || error "Failed to configure bootloader"
442
443[ -f /usr/libexec/bsdinstall/local.pre-configure ] && f_dprintf "Running local.pre-configure" && sh /usr/libexec/bsdinstall/local.pre-configure "$BSDINSTALL_CHROOT"
444
445bsdinstall rootpass || error "Could not set root password"
446
447trap true SIGINT	# This section is optional
448if [ "$NETCONFIG_DONE" != yes ]; then
449	bsdinstall netconfig	# Don't check for errors -- the user may cancel
450fi
451[ -z "$BSDINSTALL_SKIP_TIME" ] && bsdinstall time
452[ -z "$BSDINSTALL_SKIP_SERVICES" ] && bsdinstall services
453[ -z "$BSDINSTALL_SKIP_HARDENING" ] && bsdinstall hardening
454[ -z "$BSDINSTALL_SKIP_FIRMWARE" ] && bsdinstall firmware
455
456[ -z "$BSDINSTALL_SKIP_USERS" ] && bsddialog --backtitle "$OSNAME Installer" \
457	--title "Add User Accounts" --yesno \
458    "Would you like to add users to the installed system now?" 0 0 && \
459    bsdinstall adduser
460
461# Allow user to change his mind
462[ -z "$BSDINSTALL_SKIP_FINALCONFIG" ] && bsdinstall finalconfig
463
464trap error SIGINT	# SIGINT is bad again
465bsdinstall config  || error "Failed to save config"
466
467if [ ! -z "$BSDINSTALL_FETCHDEST" ]; then
468	rm -rf "$BSDINSTALL_FETCHDEST"
469fi
470
471[ -f /usr/libexec/bsdinstall/local.post-configure ] && f_dprintf "Running local.post-configure" && sh /usr/libexec/bsdinstall/local.post-configure "$BSDINSTALL_CHROOT"
472
473if [ -z "$BSDINSTALL_SKIP_MANUAL" ]; then
474	bsddialog --backtitle "$OSNAME Installer" --title "Manual Configuration" \
475		--default-no --yesno \
476		"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
477	if [ $? -eq 0 ]; then
478		clear
479		echo This shell is operating in a chroot in the new system. \
480		    When finished making configuration changes, type \"exit\".
481		chroot "$BSDINSTALL_CHROOT" /bin/sh -l 2>&1
482	fi
483fi
484
485bsdinstall entropy
486bsdinstall umount
487
488f_dprintf "Installation Completed at %s" "$( date )"
489
490################################################################################
491# END
492################################################################################
493