Changeset View
Standalone View
tools/boot/install-boot.sh
#!/bin/sh | #!/bin/sh | ||||
# $FreeBSD$ | # $FreeBSD$ | ||||
# | # | ||||
# Installs/updates the necessary boot blocks for the desired boot environment | # Installs/updates the necessary boot blocks for the desired boot environment | ||||
# | # | ||||
# Lightly tested.. Intended to be installed, but until it matures, it will just | # Lightly tested.. Intended to be installed, but until it matures, it will just | ||||
# be a boot tool for regression testing. | # be a boot tool for regression testing. | ||||
# insert code here to guess what you have -- yikes! | # insert code here to guess what you have -- yikes! | ||||
die() { | die() { | ||||
imp: Add a comment that says what units these are in? | |||||
echo $* | echo $* | ||||
exit 1 | exit 1 | ||||
} | } | ||||
doit() { | doit() { | ||||
echo $* | echo $* | ||||
eval $* | eval $* | ||||
} | } | ||||
find-part() { | find-part() { | ||||
dev=$1 | dev=$1 | ||||
part=$2 | part=$2 | ||||
gpart show $dev | tail +2 | awk '$4 == "'$part'" { print $3; }' | gpart show $dev | tail +2 | awk '$4 == "'$part'" { print $3; }' | ||||
} | } | ||||
make_esp() { | get_uefi_bootname() { | ||||
if [ "$TARGET" == "" ]; then | |||||
if [ `uname -m` == amd64 ]; then | |||||
efibootfile=BOOTx64.EFI | |||||
elif [ `uname -m` == arm64 ]; then | |||||
efibootfile=BOOTaa64.EFI | |||||
elif [ `uname -m` == i386 ]; then | |||||
efibootfile=BOOTia32.EFI | |||||
else | |||||
efibootfile=BOOTarm.EFI | |||||
fi | |||||
else | |||||
if [ $TARGET == amd64 ]; then | |||||
efibootfile=BOOTx64.EFI | |||||
elif [ $TARGET == arm64 ]; then | |||||
efibootfile=BOOTaa64.EFI | |||||
elif [ $TARGET == i386 ]; then | |||||
efibootfile=BOOTia32.EFI | |||||
else | |||||
efibootfile=BOOTarm.EFI | |||||
Done Inline ActionsThis is better expressed as follows get_uefi_bootname() { generally shell scripts echo things rather than set global variables. Also, using the alternative value variable substitution lets you omit the repetition. imp: This is better expressed as follows
get_uefi_bootname() {
case ${TARGET:-$(uname -m)}
amd64)… | |||||
Done Inline ActionsSuch an approach looks beautiful but may have performance and correctness implications since it runs the function in a subshell environment. I think setting variables (either named via a parameter or with a hard-coded name) is a perfectly acceptable approach. jilles: Such an approach looks beautiful but may have performance and correctness implications since it… | |||||
Done Inline ActionsThis function is called once, and in the context my suggestions are fine. They won't cause any sort of regression in performance, and it's more likely to be correct (though I didn't change the { to ( to enforce the new sub-shell out of a desire to be efficient). imp: This function is called once, and in the context my suggestions are fine. They won't cause any… | |||||
fi | |||||
fi | |||||
} | |||||
make_esp_file() { | |||||
local file sizekb loader mntpt fatbits | |||||
Done Inline ActionsI'd add efibootfile here too, since it's just used in this function. imp: I'd add efibootfile here too, since it's just used in this function.
| |||||
file=$1 | |||||
sizekb=$2 | |||||
loader=$3 | |||||
if [ $sizekb -ge 33292 ]; then | |||||
fatbits=32 | |||||
elif [ $sizekb -ge 2100 ]; then | |||||
fatbits=16 | |||||
else | |||||
fatbits=12 | |||||
fi | |||||
dd if=/dev/zero of=${file} bs=1k count=${sizekb} | |||||
device=$(mdconfig -a -t vnode -f ${file}) | |||||
newfs_msdos -F ${fatbits} -c 1 -L EFISYS /dev/${device} | |||||
mntpt=$(mktemp -d /tmp/stand-test.XXXXXX) | |||||
mount -t msdosfs /dev/${device} ${mntpt} | |||||
mkdir -p ${mntpt}/EFI/BOOT | |||||
get_uefi_bootname | |||||
Done Inline Actionsefibootname=$(get_uefi_bootname) imp: efibootname=$(get_uefi_bootname)
per above | |||||
cp "${loader}" ${mntpt}/EFI/BOOT/${efibootfile} | |||||
umount ${mntpt} | |||||
rmdir ${mntpt} | |||||
mdconfig -d -u ${device} | |||||
} | |||||
make_esp_device() { | |||||
local dev dst mntpt | local dev dst mntpt | ||||
# ESP device node | |||||
dev=$1 | dev=$1 | ||||
# destdir | |||||
dst=$2 | dst=$2 | ||||
newfs_msdos -a 32 ${dev} | |||||
mntpt=$(mktemp -d /tmp/stand-test.XXXXXX) | mntpt=$(mktemp -d /tmp/stand-test.XXXXXX) | ||||
Done Inline Actionsdon't know if we have a 'panic' routine :) imp: don't know if we have a 'panic' routine :)
| |||||
Done Inline ActionsNo, but we do have die bcran: No, but we do have `die` | |||||
mount -t msdos ${dev} ${mntpt} | |||||
mkdir -p ${mntpt}/efi/boot | mount -t msdosfs ${dev} ${mntpt} | ||||
cp ${dst}/boot/loader.efi ${mntpt}/efi/boot/bootx64.efi | if [ $? -ne 0 ]; then | ||||
newfs_msdos -F 32 -c 1 -L EFISYS ${dev} | |||||
mount -t msdosfs ${dev} | |||||
fi | |||||
mkdir -p ${mntpt}/EFI/freebsd | |||||
cp ${dst}/boot/loader.efi ${mntpt}/EFI/freebsd/loader.efi | |||||
efibootmgr --create --label FreeBSD --loader ${mntpt}/freebsd/loader.efi | |||||
Done Inline ActionsI'd be tempted to create constants for these magic numbers. Then the user of this file can also use them to prevent their proliferation. imp: I'd be tempted to create constants for these magic numbers. Then the user of this file can also… | |||||
umount ${mntpt} | umount ${mntpt} | ||||
rmdir ${mntpt} | rmdir ${mntpt} | ||||
bootorder=`efivar --name 8be4df61-93ca-11d2-aa0d-00e098032b8c-BootOrder --print --no-name --hex` | |||||
bootentry=`echo ${bootorder} | cut -w -f 3``echo ${bootorder} | cut -w -f 2` | |||||
Done Inline ActionsAre these two locals? I'd add them to the local list if so. I don't see where else they are used. imp: Are these two locals? I'd add them to the local list if so. I don't see where else they are… | |||||
efibootmgr --activate ${bootentry} | |||||
} | } | ||||
make_esp() { | |||||
file=$1 | |||||
dst=$2 | |||||
if [ -f $file ]; then | |||||
make_esp_file ${file} 33292 ${dst}/boot/loader.efi | |||||
else | |||||
make_esp_device ${file} ${dst}/boot/loader.efi | |||||
fi | |||||
} | |||||
make_esp_mbr() { | make_esp_mbr() { | ||||
dev=$1 | dev=$1 | ||||
dst=$2 | dst=$2 | ||||
s=$(find-part $dev "!239") | s=$(find-part $dev "!239") | ||||
if [ -z "$s" ] ; then | if [ -z "$s" ] ; then | ||||
s=$(find-part $dev "efi") | s=$(find-part $dev "efi") | ||||
if [ -z "$s" ] ; then | if [ -z "$s" ] ; then | ||||
die "No ESP slice found" | die "No ESP slice found" | ||||
fi | fi | ||||
fi | fi | ||||
Done Inline ActionsI would be tempted to go a slightly more conservative route of renaming it instead. That would allow someone to recover back to this if they have a bad new loader. imp: I would be tempted to go a slightly more conservative route of renaming it instead. That would… | |||||
Done Inline ActionsThe problem is that many systems will o my have 800KB available on the ESP. So in those situations it’s not possible to have more than one copy. bcran: The problem is that many systems will o my have 800KB available on the ESP. So in those… | |||||
make_esp /dev/${dev}s${s} ${dst} | make_esp /dev/${dev}s${s} ${dst}/boot/loader.efi | ||||
} | } | ||||
make_esp_gpt() { | make_esp_gpt() { | ||||
dev=$1 | dev=$1 | ||||
dst=$2 | dst=$2 | ||||
idx=$(find-part $dev "efi") | idx=$(find-part $dev "efi") | ||||
if [ -z "$idx" ] ; then | if [ -z "$idx" ] ; then | ||||
die "No ESP partition found" | die "No ESP partition found" | ||||
fi | fi | ||||
make_esp /dev/${dev}p${idx} ${dst} | make_esp /dev/${dev}p${idx} ${dst}/boot/loader.efi | ||||
} | } | ||||
boot_nogeli_gpt_ufs_legacy() { | boot_nogeli_gpt_ufs_legacy() { | ||||
dev=$1 | dev=$1 | ||||
dst=$2 | dst=$2 | ||||
idx=$(find-part $dev "freebsd-boot") | idx=$(find-part $dev "freebsd-boot") | ||||
if [ -z "$idx" ] ; then | if [ -z "$idx" ] ; then | ||||
die "No freebsd-boot partition found" | die "No freebsd-boot partition found" | ||||
fi | fi | ||||
doit gpart bootcode -b ${gpt0} -p ${gpt2} -i $idx $dev | doit gpart bootcode -b ${gpt0} -p ${gpt2} -i $idx $dev | ||||
} | } | ||||
boot_nogeli_gpt_ufs_uefi() { | boot_nogeli_gpt_ufs_uefi() { | ||||
make_esp_gpt $1 $2 | make_esp_gpt $1 $2 | ||||
} | } | ||||
boot_nogeli_gpt_ufs_both() { | boot_nogeli_gpt_ufs_both() { | ||||
boot_nogeli_gpt_ufs_legacy $1 $2 $3 | boot_nogeli_gpt_ufs_legacy $1 $2 $3 | ||||
boot_nogeli_gpt_ufs_uefi $1 $2 $3 | boot_nogeli_gpt_ufs_uefi $1 $2 $3 | ||||
} | } | ||||
Done Inline ActionsThis looks weird... What are you trying to accomplish? imp: This looks weird... What are you trying to accomplish?
| |||||
Done Inline ActionsOh that needs a comment. bcran: Oh that needs a comment.
efibootmgr doesn’t mark new entries active, so this code figures out… | |||||
Done Inline ActionsI'm trying to see if there's an existing boot entry - filtering out other OSes that use different paths to their loader. If there is, we don't need to create a new one. bcran: I'm trying to see if there's an existing boot entry - filtering out other OSes that use… | |||||
boot_nogeli_gpt_zfs_legacy() { | boot_nogeli_gpt_zfs_legacy() { | ||||
dev=$1 | dev=$1 | ||||
dst=$2 | dst=$2 | ||||
idx=$(find-part $dev "freebsd-boot") | idx=$(find-part $dev "freebsd-boot") | ||||
if [ -z "$idx" ] ; then | if [ -z "$idx" ] ; then | ||||
die "No freebsd-boot partition found" | die "No freebsd-boot partition found" | ||||
▲ Show 20 Lines • Show All 116 Lines • ▼ Show 20 Lines | boot_nogeli_vtoc8_ufs_ofw() { | ||||
dev=$1 | dev=$1 | ||||
dst=$2 | dst=$2 | ||||
# For non-native builds, ensure that geom_part(4) supports VTOC8. | # For non-native builds, ensure that geom_part(4) supports VTOC8. | ||||
kldload geom_part_vtoc8.ko | kldload geom_part_vtoc8.ko | ||||
doit gpart bootcode -p ${vtoc8} ${dev} | doit gpart bootcode -p ${vtoc8} ${dev} | ||||
} | } | ||||
usage() { | |||||
printf '%s -b bios [-d destdir] -f fs [-g geli] -h [-o optargs] -s scheme bootdev\n\n' $0 | |||||
printf '\t bootdev: device to install the boot code on\n' | |||||
printf '\t -b bios bios type: legacy, uefi or both\n' | |||||
printf '\t -d destdir destination filesystem root\n' | |||||
printf '\t -f fs filesystem type: ufs or zfs\n' | |||||
printf '\t -g geli yes or no\n' | |||||
printf '\t -h help this help/usage text\n' | |||||
printf '\t -o optargs optional arguments\n' | |||||
printf '\t -s scheme mbr or gpt\n\n' | |||||
} | |||||
DESTDIR=/ | DESTDIR=/ | ||||
# Note: we really don't support geli boot in this script yet. | # Note: we really don't support geli boot in this script yet. | ||||
geli=nogeli | geli=nogeli | ||||
while getopts "b:d:f:g:o:s:" opt; do | while getopts "b:d:f:g:ho:s:" opt; do | ||||
case "$opt" in | case "$opt" in | ||||
b) | b) | ||||
bios=${OPTARG} | bios=${OPTARG} | ||||
;; | ;; | ||||
d) | d) | ||||
DESTDIR=${OPTARG} | DESTDIR=${OPTARG} | ||||
Done Inline ActionsThis doesn't look right at all. srcroot seems to be /usr/src, while DESTDIR is where we install into... Is that intentional? If so, that seems like a poorly named variable. imp: This doesn't look right at all. srcroot seems to be /usr/src, while DESTDIR is where we install… | |||||
Done Inline ActionsHere, srcroot is where we’re copying files from, to install onto the ESP. bcran: Here, srcroot is where we’re copying files from, to install onto the ESP. | |||||
;; | ;; | ||||
f) | f) | ||||
fs=${OPTARG} | fs=${OPTARG} | ||||
;; | ;; | ||||
g) | g) | ||||
case ${OPTARG} in | case ${OPTARG} in | ||||
[Yy][Ee][Ss]|geli) geli=geli ;; | [Yy][Ee][Ss]|geli) geli=geli ;; | ||||
*) geli=nogeli ;; | *) geli=nogeli ;; | ||||
esac | esac | ||||
;; | ;; | ||||
h) | |||||
Done Inline ActionsI'd also match ? here. getopts returns ? when there's no args in the getopt list that match. imp: I'd also match ? here. getopts returns ? when there's no args in the getopt list that match.
| |||||
usage | |||||
exit 0 | |||||
;; | |||||
o) | o) | ||||
opts=${OPTARG} | opts=${OPTARG} | ||||
;; | ;; | ||||
s) | s) | ||||
scheme=${OPTARG} | scheme=${OPTARG} | ||||
;; | ;; | ||||
esac | esac | ||||
done | done | ||||
shift $((OPTIND-1)) | dev=$((OPTIND-1)) | ||||
dev=$1 | |||||
# For gpt, we need to install pmbr as the primary boot loader | # For gpt, we need to install pmbr as the primary boot loader | ||||
# it knows about | # it knows about | ||||
gpt0=${DESTDIR}/boot/pmbr | gpt0=${DESTDIR}/boot/pmbr | ||||
gpt2=${DESTDIR}/boot/gptboot | gpt2=${DESTDIR}/boot/gptboot | ||||
gptzfs2=${DESTDIR}/boot/gptzfsboot | gptzfs2=${DESTDIR}/boot/gptzfsboot | ||||
# For MBR, we have lots of choices, but select mbr, boot0 has issues with UEFI | # For MBR, we have lots of choices, but select mbr, boot0 has issues with UEFI | ||||
mbr0=${DESTDIR}/boot/mbr | mbr0=${DESTDIR}/boot/mbr | ||||
mbr2=${DESTDIR}/boot/boot | mbr2=${DESTDIR}/boot/boot | ||||
# VTOC8 | # VTOC8 | ||||
vtoc8=${DESTDIR}/boot/boot1 | vtoc8=${DESTDIR}/boot/boot1 | ||||
# sanity check here | # sanity check here | ||||
if [ "${scheme}" != "" -a "${fs}" != "" -a "${bios}" != "" ]; then | |||||
eval boot_${geli}_${scheme}_${fs}_${bios} $dev $DESTDIR $opts || echo "Unsupported boot env: ${geli}-${scheme}-${fs}-${bios}" | eval boot_${geli}_${scheme}_${fs}_${bios} $dev $DESTDIR $opts || echo "Unsupported boot env: ${geli}-${scheme}-${fs}-${bios}" | ||||
fi |
Add a comment that says what units these are in?