Commit 4aeefa04 authored by Carlo Landmeter's avatar Carlo Landmeter

setup-disk: add EFI and GPT support

New features:

* auto detect EFI boot and install EFI ESP (force with env USE_EFI=1)
* allow specifying bootloader by env BOOTLOADER (grub or syslinux)
* allow specifying disk label by env DISKLABEL (dos or gpt)

TODO:

* Make sure MBR is only overwritten on native installs.
* Do some more checks to prevent non standard/supported setup
  like GPT on BIOS installs.

TESTS run on ESXi 6.5:

Simple native install

* syslinux OK
* GRUB OK

Extended native install

* LVM OK
* RAID OK
* RAID+LVM OK

EFI install

* Default OK
* LVM OK see: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=592834
* RAID NOT SUPPORTED

Data install DOS

* Default OK
* LVM OK

Data install GPT

* Default OK
* LVM OK but: /lib/rc/sh/openrc-run.sh: line 273:
  can't create /sys/fs/cgroup/openrc/syslog/tasks: nonexistent directory
parent c3eeebd0
......@@ -7,6 +7,8 @@ MBR=${MBR:-"/usr/share/syslinux/mbr.bin"}
ROOTFS=${ROOTFS:-ext4}
BOOTFS=${BOOTFS:-ext4}
VARFS=${VARFS:-ext4}
BOOTLOADER=${BOOTLOADER:-syslinux}
DISKLABEL=${DISKLABEL:-dos}
# default location for mounted root
SYSROOT=${SYSROOT:-/mnt}
......@@ -67,7 +69,7 @@ enumerate_fstab() {
awk "\$2 ~ /^$escaped_mnt(\/|\$)/ {print \$0}" /proc/mounts | \
sed "s:$mnt:/:g; s: :\t:g" | sed -E 's:/+:/:g' | \
while read fs_spec fs_file fs_vfstype fs_mntops fs_freq fs_passno; do
if [ "$fs_file" = / ]; then
if [ "$fs_file" = / ]; then
fs_passno=1
else
fs_passno=2
......@@ -86,19 +88,63 @@ is_lvm() {
lvs "$1" >/dev/null 2>&1
}
is_efi() {
[ -d "/sys/firmware/efi" ] && return 0
return 1
}
# Find the disk device from given partition
disk_from_part() {
# we need convert cciss/c0d0* cciss!c0d0*...
local i= part=$(echo ${1#/dev/} | sed 's:/:!:g')
for i in /sys/block/*/$part; do
i=${i%/*}
# ...and back from cciss!c0d0 to cciss/c0d0
if [ -b "/dev/${i##*/}" ]; then
echo "/dev/${i##*/}" | sed 's:!:/:g'
return 0
fi
done
return 1
local path=${1%/*}
local dev=${1##*/}
echo $path/$(basename "$(readlink -f "/sys/class/block/$dev/..")")
}
# $1 partition type (swap,linux,raid,lvm,prep,esp)
# return partition type id based on table type
partition_id() {
local id
if [ "$DISKLABEL" = "gpt" ]; then
case "$1" in
swap) id=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F ;;
linux) id=0FC63DAF-8483-4772-8E79-3D69D8477DE4 ;;
raid) id=A19D880F-05FC-4D3B-A006-743F0F84911E ;;
lvm) id=E6D6D379-F507-44C2-A23C-238F2A3DF928 ;;
prep) id=9E1A2d38-C612-4316-AA26-8B49521E5A8B ;;
esp) id=C12A7328-F81F-11D2-BA4B-00A0C93EC93B ;;
*) die "Partition id \"$1\" is not supported!" ;;
esac
elif [ "$DISKLABEL" = "dos" ]; then
case "$1" in
swap) id=82 ;;
linux) id=83 ;;
raid) id=fd ;;
lvm) id=8e ;;
prep) id=41 ;;
esp) id=EF ;;
*) die "Partition id \"$1\" is not supported!" ;;
esac
else
die "Partition label \"$DISKLABEL\" is not supported!"
fi
echo $id
}
# find partitions based on partition type from specified disk
# type can be any type from partition_id or the literal string "boot"
find_partitions() {
local dev="$1" type="$2" search=
case "$type" in
boot)
search=bootable
[ -n "$USE_EFI" ] && search=$(partition_id esp)
sfdisk -d "$dev" | awk '/'$search'/ {print $1}'
;;
*)
search=$(partition_id "$type")
sfdisk -d "$dev" | awk '/type='$search'/ {print $1}'
;;
esac
}
unpack_apkovl() {
......@@ -149,7 +195,7 @@ find_mount_dev() {
}
supported_boot_fs() {
local supported="ext2 ext3 ext4 btrfs xfs"
local supported="ext2 ext3 ext4 btrfs xfs vfat"
local fs=
for fs in $supported; do
[ "$fs" = "$1" ] && return 0
......@@ -158,6 +204,13 @@ supported_boot_fs() {
return 1
}
supported_part_label() {
case "$1" in
dos|gpt) return 0 ;;
*) die "Partition label \"$DISKLABEL\" is not supported!" ;;
esac
}
find_volume_group() {
local lv=${1##*/}
lvs --noheadings "$1" | awk '{print $2}'
......@@ -202,24 +255,58 @@ has_bootopt() {
return 1
}
# setup grub bootloader
# setup GRUB bootloader
setup_grub() {
local mnt="$1" root="$2" modules="$3" kernel_opts="$4"
shift 4
local disks="${@}"
local mnt="$1" root="$2" modules="$3" kernel_opts="$4" bootdev="$5"
# install GRUB efi mode
if [ -n "$USE_EFI" ]; then
local target fwa
case "$ARCH" in
x86_64) target=x86_64-efi ; fwa=x64 ;;
x86) target=i386-efi ; fwa=ia32 ;;
arm*) target=arm-efi ; fwa=arm ;;
aarch64) target=arm64-efi ; fwa=aa64 ;;
esac
# currently disabling nvram so grub doesnt call efibootmgr
# installing to alpine directory so other distros dont overwrite it
grub-install --target=$target --efi-directory="$mnt"/boot/efi \
--bootloader-id=alpine --boot-directory="$mnt"/boot --no-nvram
# fallback mode will use boot/boot${fw arch}.efi
install -D "$mnt"/boot/efi/EFI/alpine/grub$fwa.efi \
"$mnt"/boot/efi/EFI/boot/boot$fwa.efi
# install GRUB for ppc64le
elif [ "$ARCH" = "ppc64le" ]; then
shift 5
local disks="${@}"
for disk in $disks; do
prep=$(find_partitions "$disk" "prep")
echo "Installing grub on $prep"
grub-install --boot-directory="$mnt"/boot $prep
done
# install GRUB in bios mode
else
local bootdisk=$(disk_from_part $bootdev)
case "$ARCH" in
x86|x86_64) grub-install --boot-directory="$mnt"/boot \
--target=i386-pc $bootdisk ;;
*) die "Cannot install GRUB in BIOS mode for $ARCH" ;;
esac
fi
for disk in $disks; do
# install grub
prep=$(find_prep_partition $disk)
echo "Installing grub on $prep"
grub-install --boot-directory="$mnt"/boot/ $prep
done
# create grub config
cat > "$mnt"/boot/grub/grub.cfg <<- EOF
# setup GRUB config
local kernel
case $KERNEL_FLAVOR in
vanilla) kernel=vmlinuz ;;
*) kernel=vmlinuz-$KERNEL_FLAVOR ;;
esac
# all_video is needed to remove the video error on boot
cat > "$mnt"/boot/grub/grub.cfg <<- EOF
set timeout=2
insmod all_video
menuentry "Alpine Linux" {
linux /boot/vmlinuz $modules root=$root $kernel_opts
initrd /boot/initramfs-$KERNEL_FLAVOR
linux /boot/$kernel modules=$modules root=$root $kernel_opts
initrd /boot/initramfs-$KERNEL_FLAVOR
}
EOF
}
......@@ -251,7 +338,10 @@ install_mounted_root() {
local mnt="$1"
shift 1
local disks="${@}" mnt_boot= boot_fs= root_fs=
local initfs_features="ata base cdrom ext2 ext3 ext4 keymap kms mmc raid scsi usb virtio nvme"
local initfs_features=$(. /etc/mkinitfs/mkinitfs.conf >/dev/null 2>&1 && echo "$features")
if [ -z "$initfs_features" ]; then
initfs_features="ata base cdrom ext2 ext3 ext4 keymap kms mmc raid scsi usb virtio nvme"
fi
local pvs= dev= rootdev= bootdev= extlinux_raidopt= root= modules=
local kernel_opts="quiet"
......@@ -361,10 +451,11 @@ install_mounted_root() {
# remove the installed db in case its there so we force re-install
rm -f "$mnt"/var/lib/apk/installed "$mnt"/lib/apk/db/installed
echo "Installing system on $rootdev:"
case "$ARCH" in
ppc64le) setup_grub "$mnt" "$root" "$modules" "$kernel_opts" $disks;;
*) setup_syslinux "$mnt" "$root" "$modules" "$kernel_opts" "$bootdev";;
esac
case "$BOOTLOADER" in
grub) setup_grub "$mnt" "$root" "$modules" "$kernel_opts" "$bootdev" $disks ;;
syslinux) setup_syslinux "$mnt" "$root" "$modules" "$kernel_opts" "$bootdev" ;;
*) die "Bootloader \"$BOOTLOADER\" not supported!" ;;
esac
# apk reads config from target root so we need to copy the config
mkdir -p "$mnt"/etc/apk/keys/
......@@ -485,9 +576,21 @@ stop_all_raid() {
done
}
select_bootloader() {
local bootloader=syslinux
if [ "$ARCH" = "ppc64le" ]; then
bootloader=grub-ieee1275
elif [ -n "$USE_EFI" ]; then
bootloader=grub-efi
elif [ "$BOOTLOADER" = "grub" ]; then
bootloader=grub-bios
fi
echo "$bootloader"
}
# install needed programs
init_progs() {
local raidpkg= lvmpkg= fs= fstools=
local raidpkg= lvmpkg= fs= fstools= grub=
[ -n "$USE_RAID" ] && raidpkg="mdadm"
[ -n "$USE_LVM" ] && lvmpkg="lvm2"
for fs in $BOOTFS $ROOTFS $VARFS; do
......@@ -538,57 +641,33 @@ confirm_erase() {
# setup partitions on given disk dev in $1.
# usage: setup_partitions <diskdev> size1,type1 [size2,type2 ...]
setup_partitions() {
local diskdev="$1"
local diskdev="$1" start=1M line=
shift
supported_part_label "$DISKLABEL" || return 1
echo "Initializing partitions on $diskdev..."
# new disks does not have an DOS signature in sector 0
# this makes sfdisk complain. We can workaround this by letting
# fdisk create that DOS signature, by just do a "w", a write.
# http://bugs.alpinelinux.org/issues/show/145
echo "w" | fdisk $diskdev >/dev/null
# fix the MBR while here so extlinux can boot
if [ -f "$MBR" ]; then
# initialize MBR for syslinux only
# FIXME: this should only by run by native install
if [ "$BOOTLOADER" = "syslinux" ] && [ -f "$MBR" ]; then
cat "$MBR" > $diskdev
fi
local start=1M
local line=
# create new partitions
(
for line in "$@"; do
echo "$start,$line"
start=
done
) | sfdisk --quiet $diskdev >/dev/null || return 1
) | sfdisk --quiet --label $DISKLABEL $diskdev
# create device nodes if not exist
mdev -s
}
# find the bootable partition on given disk
find_boot_partition() {
sfdisk -d $1 | awk '/bootable/ {print $1}'
}
# find partition from PReP type on given disk
find_prep_partition() {
sfdisk -d $1 | awk '/type=41/ {print $1}'
}
# find the partition(s) for LVM
# this is not marked as bootable and is type 8e
find_lvm_partition() {
local type=8e
sfdisk -d $1 | grep -v bootable | awk "/(Id|type)=$type/ {print \$1}"
}
# set up optional raid and create filesystem on boot device.
setup_boot_dev() {
local disks="$@" disk= bootdev= mkfs_args="-q"
local part=$(for disk in $disks; do find_boot_partition $disk; done)
local disks="$@" disk= bootdev= mkfs_args=
[ "$BOOTFS" != "vfat" ] && mkfs_args="-q"
local part=$(for disk in $disks; do find_partitions "$disk" "boot"; done)
set -- $part
bootdev=$1
[ -z "$bootdev" ] && return 1
......@@ -627,13 +706,12 @@ setup_boot_dev() {
# $2 = partition type
# $3... = disk devices
find_nth_non_boot_parts() {
local idx=$1
local id=$2
local disk=
shift
shift
for disk in $@; do
sfdisk -d $disk | grep -v bootable \
local idx=$1 id=$2 disk= type=bootable
shift 2
local disks="$@"
[ -n "$USE_EFI" ] && type=$(partition_id esp)
for disk in $disks; do
sfdisk -d $disk | grep -v $type \
| awk "/(Id|type)=$id/ { i++; if (i==$idx) print \$1 }"
done
}
......@@ -649,7 +727,8 @@ setup_non_boot_raid_dev() {
shift
local level=1
local missing=
local raid_parts=$(find_nth_non_boot_parts $idx "fd" $@)
local pid=$(partition_id raid)
local raid_parts=$(find_nth_non_boot_parts $idx $pid $@)
set -- $raid_parts
# how many disks do we have?
case $# in
......@@ -672,7 +751,7 @@ setup_lvm_volume_group() {
setup_non_boot_raid_dev /dev/md1 $@ || return 1
lvmdev=/dev/md1
else
lvmdev=$(find_lvm_partition $1)
lvmdev=$(find_partitions "$1" "lvm")
fi
# be quiet on success
......@@ -751,21 +830,19 @@ data_only_disk_install_lvm() {
local diskdev=
local vgname=vg0
local var_dev=/dev/$vgname/lv_var
local lvm_part_type="8e"
local part_type=$lvm_part_type
local lvm_part_type=$(partition_id lvm)
local size=
init_progs || return 1
confirm_erase $@ || return 1
if [ "$USE_RAID" ]; then
# the paritition type for raid is "fd"
part_type="fd"
lvm_part_type=$(partition_id raid)
stop_all_raid
fi
for diskdev in "$@"; do
setup_partitions $diskdev "${size}${size:+M},$part_type" || return 1
setup_partitions $diskdev "${size}${size:+M},$lvm_part_type" || return 1
done
setup_lvm_volume_group $vgname $@ || return 1
......@@ -779,8 +856,8 @@ data_only_disk_install_lvm() {
data_only_disk_install() {
local diskdev=
local var_dev=
local var_part_type="83"
local swap_part_type=82
local var_part_type=$(partition_id linux)
local swap_part_type=$(partition_id swap)
local size=
local swap_dev= var_dev=
......@@ -788,8 +865,8 @@ data_only_disk_install() {
confirm_erase $@ || return 1
if [ "$USE_RAID" ]; then
var_part_type="fd"
swap_part_type="fd"
var_part_type=$(partition_id raid)
swap_part_type=$(partition_id raid)
stop_all_raid
fi
......@@ -805,8 +882,8 @@ data_only_disk_install() {
swap_dev=/dev/md1
var_dev=/dev/md2
else
swap_dev=$(find_nth_non_boot_parts 1 82 $@)
var_dev=$(find_nth_non_boot_parts 1 83 $@)
swap_dev=$(find_nth_non_boot_parts 1 "$swap_part_type" $@)
var_dev=$(find_nth_non_boot_parts 1 "$var_part_type" $@)
fi
[ $SWAP_SIZE -gt 0 ] && setup_swap_dev $swap_dev
setup_var $var_dev
......@@ -821,10 +898,14 @@ setup_root() {
mkfs.$ROOTFS $MKFS_OPTS_ROOT $mkfs_args "$root_dev"
mkdir -p "$SYSROOT"
mount -t $ROOTFS $root_dev "$SYSROOT" || return 1
if [ -n "$boot_dev" ]; then
if [ -n "$boot_dev" ] && [ -z "$USE_EFI" ]; then
mkdir -p "$SYSROOT"/boot
mount -t $BOOTFS $boot_dev "$SYSROOT"/boot || return 1
fi
if [ -n "$boot_dev" ] && [ -n "$USE_EFI" ]; then
mkdir -p "$SYSROOT"/boot/efi
mount -t $BOOTFS $boot_dev "$SYSROOT"/boot/efi || return 1
fi
setup_mdadm_conf
install_mounted_root "$SYSROOT" "$disks" || return 1
......@@ -837,20 +918,26 @@ setup_root() {
native_disk_install_lvm() {
local diskdev= vgname=vg0
local lvm_part_type="8e"
local boot_part_type="83"
local lvm_part_type=$(partition_id lvm)
local boot_part_type=$(partition_id linux)
local boot_size=${BOOT_SIZE:-100}
local lvm_size=
local root_dev=/dev/$vgname/lv_root
init_progs syslinux || return 1
init_progs $(select_bootloader) || return 1
confirm_erase $@ || return 1
if [ -n "$USE_RAID" ]; then
boot_part_type="fd"
lvm_part_type="fd"
boot_part_type=$(partition_id raid)
lvm_part_type=$(partition_id raid)
stop_all_raid
fi
if [ -n "$USE_EFI" ]; then
[ -n "$USE_RAID" ] && die "EFI boot is not supported on RAID disks"
boot_part_type=$(partition_id esp)
fi
for diskdev in "$@"; do
setup_partitions $diskdev \
"${boot_size}M,$boot_part_type,*" \
......@@ -868,27 +955,30 @@ native_disk_install_lvm() {
}
native_disk_install() {
local prep_part_type="41" root_part_type="83" swap_part_type="82" boot_part_type="83"
local prep_part_type=$(partition_id prep)
local root_part_type=$(partition_id linux)
local swap_part_type=$(partition_id swap)
local boot_part_type=$(partition_id linux)
local prep_size=8
local boot_size=${BOOT_SIZE:-100}
local swap_size=${SWAP_SIZE}
local root_size=
local root_dev= boot_dev= swap_dev=
local bootloader=
case "$ARCH" in
ppc64le) bootloader=grub-ieee1275;;
*) bootloader=syslinux;;
esac
init_progs $bootloader || return 1
init_progs $(select_bootloader) || return 1
confirm_erase $@ || return 1
if [ -n "$USE_RAID" ]; then
boot_part_type="fd"
root_part_type="fd"
swap_part_type="fd"
boot_part_type=$(partition_id raid)
root_part_type=$(partition_id raid)
swap_part_type=$(partition_id raid)
stop_all_raid
fi
if [ -n "$USE_EFI" ]; then
[ -n "$USE_RAID" ] && die "EFI boot is not supported on RAID disks"
boot_part_type=$(partition_id esp)
fi
for diskdev in "$@"; do
if [ "$ARCH" = "ppc64le" ]; then
setup_partitions $diskdev \
......@@ -916,7 +1006,7 @@ native_disk_install() {
swap_dev=/dev/md1
root_dev=/dev/md2
else
swap_dev=$(find_nth_non_boot_parts 1 82 $@)
swap_dev=$(find_nth_non_boot_parts 1 "$swap_part_type" $@)
local index=
case "$ARCH" in
# use the second non botable partition on ppc64le,
......@@ -924,7 +1014,7 @@ native_disk_install() {
ppc64le) index=2;;
*) index=1;;
esac
root_dev=$(find_nth_non_boot_parts $index 83 $@)
root_dev=$(find_nth_non_boot_parts $index "$root_part_type" $@)
fi
[ $SWAP_SIZE -gt 0 ] && setup_swap_dev $swap_dev
......@@ -1028,10 +1118,20 @@ usage() {
-s Use SWAPSIZE MB instead of autodetecting swap size (Use 0 to disable swap)
-v Be more verbose about what is happening
If BOOTLOADER is specified, the specified bootloader will be used.
If no bootloader is specified, the default bootloader is syslinux(extlinux)
except when EFI is detected or explicitly set by USE_EFI which will select grub.
Supported bootloaders are: grub, syslinux
If DISKLABEL is specified, the specified partition label will be used.
if no partition label is specified, the default label will be dos
except when EFI is detected or explicitly set by USE_EFI which will select gpt.
Supported partition labels are: dos, gpt
If BOOTFS, ROOTFS, VARFS are specified, then format a partition with specified
filesystem. If not specified, the default filesystem is ext4.
Supported filesystems for
boot: ext2, ext3, ext4, btrfs, xfs
boot: ext2, ext3, ext4, btrfs, xfs, vfat(EFI)
root: ext2, ext3, ext4, btrfs, xfs
var: ext2, ext3, ext4, btrfs, xfs
__EOF__
......@@ -1095,8 +1195,7 @@ if [ $# -gt 0 ]; then
for i in "$@"; do
j=$(readlink -f "$i" | sed 's:^/dev/::; s:/:!:g')
if ! [ -e "/sys/block/$j/device" ]; then
echo "$i is not a suitable for partitioning"
exit 1
die "$i is not a suitable for partitioning"
fi
diskdevs="$diskdevs /dev/${j//!//}"
done
......@@ -1152,6 +1251,16 @@ if [ $# -gt 1 ]; then
USE_RAID=1
fi
if is_efi || [ -n "$USE_EFI" ]; then
USE_EFI=1
DISKLABEL=gpt
BOOTLOADER=grub
BOOT_SIZE=512
BOOTFS=vfat
fi
[ "$ARCH" = "ppc64le" ] && BOOTLOADER=grub
dmesg -n1
# native disk install
......@@ -1159,7 +1268,7 @@ case "$DISK_MODE" in
sys) native_disk_install$USE_LVM $diskdevs;;
data) data_only_disk_install$USE_LVM $diskdevs;;
none) exit 0;;
*) echo "Not a valid install mode: $DISK_MODE" >&2; exit 1;;
*) die "Not a valid install mode: $DISK_MODE" ;;
esac
RC=$?
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment