#!/bin/sh PREFIX=@PREFIX@ : ${LIBDIR=$PREFIX/lib} . "$LIBDIR/libalpine.sh" . "$LIBDIR/dasd-functions.sh" MBR=${MBR:-"/usr/share/syslinux/mbr.bin"} ROOTFS=${ROOTFS:-ext4} BOOTFS=${BOOTFS:-ext4} VARFS=${VARFS:-ext4} DISKLABEL=${DISKLABEL:-dos} KERNELOPTS=${KERNELOPTS:-quiet} # default location for mounted root SYSROOT=${SYSROOT:-/mnt} in_list() { local i="$1" shift while [ $# -gt 0 ]; do [ "$i" = "$1" ] && return 0 shift done return 1 } all_in_list() { local needle="$1" local i [ -z "$needle" ] && return 1 shift for i in $needle; do in_list "$i" $@ || return 1 done return 0 } # wrapper to only show given device _blkid() { blkid | grep "^$1:" } # if given device have an UUID display it, otherwise return the device uuid_or_device() { local i= case "$1" in /dev/md*) echo "$1" && return 0;; esac for i in $(_blkid "$1"); do case "$i" in UUID=*) eval $i;; esac done if [ -n "$UUID" ]; then echo "UUID=$UUID" else echo "$1" fi } # generate an fstab from a given mountpoint. Convert to UUID if possible enumerate_fstab() { local mnt="$1" local fs_spec= fs_file= fs_vfstype= fs_mntops= fs_freq= fs_passno= [ -z "$mnt" ] && return local escaped_mnt=$(echo $mnt | sed -e 's:/*$::' -e 's:/:\\/:g') 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 fs_passno=1 else fs_passno=2 fi echo -e "$(uuid_or_device $fs_spec)\t${fs_file}\t${fs_vfstype}\t${fs_mntops} ${fs_freq} ${fs_passno}" done } # given an fstab on stdin, determine if any of the mountpoints are encrypted crypt_required() { while read -r devname mountpoint fstype mntops freq passno; do if [ -z "$devname" ] || [ "${devname###}" != "$devname" ]; then continue fi uuid="${devname##UUID=}" if [ "$uuid" != "$devname" ]; then devname="$(blkid --uuid "$uuid")" fi local devnames="$devname" if is_lvm "$devname"; then local vg=$(find_volume_group "$devname") devnames=$(find_pvs_in_vg $vg) fi for dev in $devnames; do mapname="${dev##/dev/mapper/}" if [ "$mapname" != "$dev" ]; then if cryptsetup status "$mapname" >&1 >/dev/null; then return 0 fi fi done done return 1 } is_vmware() { grep -q VMware /proc/scsi/scsi 2>/dev/null \ || grep -q VMware /proc/ide/hd*/model 2>/dev/null } # return true (0) if given device is lvm is_lvm() { lvs "$1" >/dev/null 2>&1 } is_efi() { [ -d "/sys/firmware/efi" ] && return 0 return 1 } is_rpi() { grep -q "Raspberry Pi" /proc/device-tree/model 2>/dev/null } # Find the disk device from given partition disk_from_part() { 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 ;; vfat) id=0c ;; *) die "Partition id \"$1\" is not supported!" ;; esac elif [ "$DISKLABEL" = "eckd" ]; then case "$1" in native|lvm|swap|raid|gpfs) id="$1" ;; 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= if is_dasd "$dev" eckd; then case "$type" in boot) echo "$dev"1 ;; *) fdasd -p "$dev" | grep "Linux $(partition_id "$type")" | awk '{print $1}' | tail -n 1 ;; esac return 0 fi 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() { local ovl="$1" local dest="$2" local suffix=${ovl##*.} local i ovlfiles=/tmp/ovlfiles if [ "$suffix" = "gz" ]; then if ! tar -C "$dest" --numeric-owner -zxvf "$ovl" > $ovlfiles; then if ! ask_yesno "Continue anyway? (y/n)"; then return 1 fi fi return 0 fi apk add --quiet openssl if ! openssl list-cipher-commands | grep "^$suffix$" > /dev/null; then errstr="Cipher $suffix is not supported" return 1 fi local count=0 # beep echo -e "\007" while [ $count -lt 3 ]; do openssl enc -d -$suffix -in "$ovl" | tar --numeric-owner \ -C "$dest" -zxv >$ovlfiles 2>/dev/null && return 0 count=$(( $count + 1 )) done ovlfiles= return 1 } # find filesystem of given mounted dir find_mount_fs() { local mount_point="$1" awk "\$2 == \"$mount_point\" {print \$3}" /proc/mounts | tail -n 1 } # find device for given mounted dir find_mount_dev() { local mnt="$1" awk "\$2 == \"$mnt\" { print \$1 }" /proc/mounts | tail -n 1 } supported_boot_fs() { local supported="ext2 ext3 ext4 btrfs xfs vfat" local fs= if is_rpi; then supported=vfat fi for fs in $supported; do [ "$fs" = "$1" ] && return 0 done echo "$1 is not supported. Only supported are: $supported" >&2 return 1 } supported_part_label() { case "$1" in dos|gpt|eckd) return 0 ;; *) die "Partition label \"$DISKLABEL\" is not supported!" ;; esac } find_volume_group() { local lv=${1##*/} lvs --noheadings "$1" | awk '{print $2}' } find_pvs_in_vg() { local vg="$1" pvs --noheadings | awk "\$2 == \"$vg\" {print \$1}" } init_chroot_mounts() { local mnt="$1" i= for i in proc dev; do mkdir -p "$mnt"/$i mount --bind /$i "$mnt"/$i done } cleanup_chroot_mounts() { local mnt="$1" i= for i in proc dev; do umount "$mnt"/$i done } get_bootopt() { local opt="$1" set -- $(cat /proc/cmdline) for i; do case "$i" in "$opt"|"$opt"=*) echo "${i#*=}"; break;; esac done } # setup GRUB bootloader setup_grub() { local mnt="$1" root="$2" modules="$3" kernel_opts="$4" bootdev="$5" # install GRUB efi mode if [ -n "$USE_EFI" ]; then local target fwa local efi_directory="$mnt"/boot/efi 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 ;; riscv64) target=riscv64-efi ; fwa=riscv64 ;; esac if [ -n "$USE_CRYPT" ]; then efi_directory="$mnt"/boot fi # currently disabling nvram so grub doesnt call efibootmgr # installing to alpine directory so other distros dont overwrite it grub-install --target=$target --efi-directory="$efi_directory" \ --bootloader-id=alpine --boot-directory="$mnt"/boot --no-nvram # fallback mode will use boot/boot${fw arch}.efi install -D "$efi_directory"/EFI/alpine/grub$fwa.efi \ "$efi_directory"/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 # setup GRUB config. trigger will generate final grub.cfg install -d "$mnt"/etc/default/ cat > "$mnt"/etc/default/grub <<- EOF GRUB_TIMEOUT=2 GRUB_DISABLE_SUBMENU=y GRUB_DISABLE_RECOVERY=true GRUB_CMDLINE_LINUX_DEFAULT="modules=$modules $kernel_opts" EOF } # setup syslinux bootloader setup_syslinux() { local mnt="$1" root="$2" modules="$3" kernel_opts="$4" bootdev="$5" local exlinux_raidopt= sed -e "s:^root=.*:root=$root:" \ -e "s:^default_kernel_opts=.*:default_kernel_opts=\"$kernel_opts\":" \ -e "s:^modules=.*:modules=$modules:" \ /etc/update-extlinux.conf > "$mnt"/etc/update-extlinux.conf # Check if we boot from raid so we can pass proper option to # extlinux later. if [ -e "/sys/block/${bootdev#/dev/}/md" ]; then extlinux_raidopt="--raid" fi extlinux $extlinux_raidopt --install "$mnt"/boot } # setup u-boot bootloader setup_uboot() { local mnt="$1" root="$2" modules="$3" kernel_opts="$4" local parameters="root=$root modules=$modules $kernel_opts" mkdir -p "$mnt"/boot/extlinux cat > "$mnt/boot/extlinux/extlinux.conf" <<- EOF menu title Alpine Linux timeout 50 default $KERNEL_FLAVOR label $KERNEL_FLAVOR menu label Linux $KERNEL_FLAVOR kernel /vmlinuz-$KERNEL_FLAVOR initrd /initramfs-$KERNEL_FLAVOR fdtdir /dtbs-$KERNEL_FLAVOR append $parameters EOF # Rely on update-u-boot to automatically determine the # board, imagedir, etc. this may not work in all cases. update-u-boot } rpi_gen_config() { cat <<-EOF # do not modify this file as it will be overwritten on upgrade. # create and/or modify usercfg.txt instead. # https://www.raspberrypi.com/documentation/computers/config_txt.html EOF case "$ARCH" in armhf) cat <<-EOF [pi0] kernel=vmlinuz-rpi initramfs initramfs-rpi [pi0w] kernel=vmlinuz-rpi initramfs initramfs-rpi [pi1] kernel=vmlinuz-rpi initramfs initramfs-rpi [pi02] kernel=vmlinuz-rpi2 initramfs initramfs-rpi2 [pi2] kernel=vmlinuz-rpi2 initramfs initramfs-rpi2 [pi3] kernel=vmlinuz-rpi2 initramfs initramfs-rpi2 [pi3+] kernel=vmlinuz-rpi2 initramfs initramfs-rpi2 [all] include usercfg.txt EOF ;; armv7) cat <<-EOF [pi02] kernel=vmlinuz-rpi2 initramfs initramfs-rpi2 [pi2] kernel=vmlinuz-rpi2 initramfs initramfs-rpi2 [pi3] kernel=vmlinuz-rpi2 initramfs initramfs-rpi2 [pi3+] kernel=vmlinuz-rpi2 initramfs initramfs-rpi2 [pi4] kernel=vmlinuz-rpi4 initramfs initramfs-rpi4 [all] include usercfg.txt EOF ;; aarch64) cat <<-EOF [pi02] kernel=vmlinuz-rpi initramfs initramfs-rpi [pi3] kernel=vmlinuz-rpi initramfs initramfs-rpi [pi3+] kernel=vmlinuz-rpi initramfs initramfs-rpi [pi4] enable_gic=1 kernel=vmlinuz-rpi4 initramfs initramfs-rpi4 [all] arm_64bit=1 include usercfg.txt EOF ;; esac } # setup rpi bootloader setup_raspberrypi_bootloader() { local mnt="$1" root="$2" modules="$3" kernel_opts="$4" rpi_gen_config > "$mnt"/boot/config.txt echo "root=$root modules=$modules $kernel_opts" > "$mnt"/boot/cmdline.txt } # detect which firmware packages to install, if any select_firmware_pkgs() { local firmware_pkgs=$( (cd /sys/module/ && echo *) \ | xargs modinfo -F firmware 2>/dev/null \ | awk -F/ '{print $1 == $0 ? "linux-firmware-other" : "linux-firmware-"$1}' \ | sort -u) echo ${firmware_pkgs:-linux-firmware-none} } is_nvme_dev() { local i for i; do case ${i##*/} in nvme*) return 0;; esac done return 1 } install_mounted_root() { local mnt="$1" shift 1 local disks="${@}" mnt_boot= boot_fs= root_fs= use_crypt= local initfs_features="ata base ide scsi usb virtio" local pvs= dev= rootdev= cryptdev= bootdev= extlinux_raidopt= root= modules= local kernel_opts="$KERNELOPTS" [ "$ARCH" = "s390x" ] && initfs_features="$initfs_features qeth dasd_mod" is_rpi && initfs_features="base mmc usb" rootdev=$(find_mount_dev "$mnt") if [ -z "$rootdev" ]; then echo "$mnt does not seem to be a mount point" >&2 return 1 fi root_fs=$(find_mount_fs "$mnt") initfs_features="$initfs_features $root_fs" if is_lvm "$rootdev"; then initfs_features="$initfs_features lvm" local vg=$(find_volume_group "$rootdev") pvs=$(find_pvs_in_vg $vg) cryptdev=$(cryptsetup status $pvs 2>&1 | awk '/device:/ { print $2 }') else cryptdev=$(cryptsetup status "$rootdev" 2>&1 | awk '/device:/ { print $2 }') fi bootdev=$(find_mount_dev "$mnt"/boot) if [ -z "$bootdev" ]; then bootdev=$rootdev mnt_boot="$mnt" else mnt_boot="$mnt"/boot fi boot_fs=$(find_mount_fs "$mnt_boot") if ! supported_boot_fs "$boot_fs"; then [ -z "$FORCE_BOOTFS" ] && return 1 echo "Continuing at your own risk." fi # check if our root is on raid so we can feed mkinitfs and # bootloader conf with the proper kernel module params for dev in $rootdev $pvs $cryptdev; do # check if we need hardware raid drivers case $dev in /dev/cciss/*) initfs_features="${initfs_features% raid} raid" ;; /dev/nvme*) initfs_features="${initfs_features% nvme} nvme" ;; /dev/mmc*) initfs_features="${initfs_features% mmc} mmc" ;; esac local md=${dev#/dev/} [ -e "/sys/block/$md/md" ] || continue if is_nvme_dev /sys/block/$md/slaves/*; then initfs_features="${initfs_features% nvme} nvme" fi initfs_features="${initfs_features% raid} raid" local level=$(cat /sys/block/$md/md/level) case "$level" in raid1) raidmod="${raidmod%,raid1},raid1";; raid[456]) raidmod="${raidmod%,raid456},raid456";; esac done if [ -n "$VERBOSE" ]; then echo "Root device: $rootdev" echo "Root filesystem: $root_fs" echo "Boot device: $bootdev" echo "Boot filesystem: $boot_fs" fi if [ -z "$APKOVL" ]; then ovlfiles=/tmp/ovlfiles lbu package - | tar -C "$mnt" -zxv > "$ovlfiles" # comment out local repositories if [ -f "$mnt"/etc/apk/repositories ]; then sed -i -e 's:^/:#/:' "$mnt"/etc/apk/repositories fi else echo "Restoring backup from $APKOVL to $rootdev..." unpack_apkovl "$APKOVL" "$mnt" || return 1 fi # we should not try start modloop on sys install rm -f "$mnt"/etc/runlevels/*/modloop # generate the fstab if [ -f "$mnt"/etc/fstab ]; then mv "$mnt"/etc/fstab "$mnt"/etc/fstab.old fi enumerate_fstab "$mnt" >> "$mnt"/etc/fstab if [ -n "$SWAP_DEVICES" ]; then local swap_dev for swap_dev in $SWAP_DEVICES; do echo -e "$(uuid_or_device ${swap_dev})\tswap\tswap\tdefaults\t0 0" \ >> "$mnt"/etc/fstab done fi cat >>"$mnt"/etc/fstab <<-__EOF__ /dev/cdrom /media/cdrom iso9660 noauto,ro 0 0 /dev/usbdisk /media/usb vfat noauto 0 0 tmpfs /tmp tmpfs nosuid,nodev 0 0 __EOF__ if crypt_required <"$mnt"/etc/fstab; then use_crypt=1 initfs_features="$initfs_features cryptsetup keymap" if is_nvme_dev /sys/block/dm-*/slaves/*; then initfs_features="$initfs_features nvme" fi fi # generate mkinitfs.conf mkdir -p "$mnt"/etc/mkinitfs/features.d echo "features=\"$initfs_features\"" > "$mnt"/etc/mkinitfs/mkinitfs.conf if [ -n "$raidmod" ]; then echo "/sbin/mdadm" > "$mnt"/etc/mkinitfs/features.d/raid.files echo "/etc/mdadm.conf" >> "$mnt"/etc/mkinitfs/features.d/raid.files fi # generate update-extlinux.conf root=$(uuid_or_device $rootdev) kernel_opts="$kernel_opts rootfstype=$root_fs" if [ -n "$(get_bootopt nomodeset)" ]; then kernel_opts="nomodeset $kernel_opts" fi if [ "$use_crypt" ]; then # Boot to encrypted root if [ $(echo "$pvs" | wc -w) -gt 1 ]; then echo "Root logical volume spans more than one physical volume." echo "This is currently unsupported." echo "Proceed manually or retry with root on a single physical volume." exit 1 fi local cryptroot=${pvs:-"$rootdev"} if cryptsetup status "$cryptroot" 2>&1 >/dev/null; then cryptroot=$(cryptsetup status "$cryptroot" | awk '/device:/ { print $2 }') cryptroot=$(uuid_or_device $cryptroot) kernel_opts="cryptroot=$cryptroot cryptdm=root $kernel_opts" root=$([ -n "$pvs" ] && echo "$rootdev" || echo "/dev/mapper/root") fi fi modules="sd-mod,usb-storage,${root_fs}${raidmod}" case "$initfs_features" in *nvme*) modules="$modules,nvme";; esac # 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 "$BOOTLOADER" in grub) setup_grub "$mnt" "$root" "$modules" "$kernel_opts" "$bootdev" $disks ;; syslinux) setup_syslinux "$mnt" "$root" "$modules" "$kernel_opts" "$bootdev" ;; zipl) setup_zipl "$mnt" "$root" "$modules" "$kernel_opts" ;; raspberrypi-bootloader) setup_raspberrypi_bootloader "$mnt" "$root" "$modules" "$kernel_opts" ;; u-boot) setup_uboot "$mnt" "$root" "$modules" "$kernel_opts" ;; *) 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/ cp /etc/apk/keys/* "$mnt"/etc/apk/keys/ local apkflags="--initdb --quiet --progress --update-cache --clean-protected" local pkgs=$(grep -h -v -w sfdisk "$mnt"/etc/apk/world \ "$mnt"/var/lib/apk/world 2>/dev/null) pkgs="$pkgs acct linux-$KERNEL_FLAVOR alpine-base $(select_bootloader_pkg) $(select_firmware_pkgs)" if [ "$(rc --sys)" = "XEN0" ]; then pkgs="$pkgs xen-hypervisor" fi if is_rpi; then pkgs="$pkgs dosfstools" fi local repos=$(sed -e 's/\#.*//' /etc/apk/repositories) local repoflags= for i in $repos; do repoflags="$repoflags --repository $i" done init_chroot_mounts "$mnt" apk add --root "$mnt" $apkflags --overlay-from-stdin \ $repoflags $pkgs <$ovlfiles local ret=$? cleanup_chroot_mounts "$mnt" return $ret } unmount_partitions() { local mnt="$1" # unmount the partitions umount $(awk '{print $2}' /proc/mounts | egrep "^$mnt(/|\$)" | sort -r) if [ -n "$USE_CRYPT" ]; then if [ -n "$USE_LVM" ]; then vgchange -a n fi cryptsetup close /dev/mapper/root fi } # figure out decent default swap size in mega bytes find_swap_size() { local memtotal_kb=$(awk '$1 == "MemTotal:" {print $2}' /proc/meminfo) # use 2 * avaiable ram or no more than 1/3 of smallest disk space local size=$(( $memtotal_kb * 2 / 1024 )) local disk= disksize= for disk in $@; do local sysfsdev=$(echo ${disk#/dev/} | sed 's:/:!:g') local sysfspath=/sys/block/$sysfsdev/size # disksize = x * 512 / (1024 * 1024) = x / 2048 # maxsize = $disksize / 4 = x / (2048 * 4) = x / 8192 maxsize=$(awk '{ printf "%i", $0 / 8192 }' $sysfspath ) if [ $size -gt $maxsize ]; then size=$maxsize fi done if [ $size -gt 4096 ]; then # dont ever use more than 4G size=4096 elif [ $size -lt 64 ]; then # dont bother create swap smaller than 64MB size=0 fi echo $size } has_mounted_part() { local p local sysfsdev=$(echo ${1#/dev/} | sed 's:/:!:g') # parse /proc/mounts for mounted devices for p in $(awk '$1 ~ /^\/dev\// {gsub("/dev/", "", $1); gsub("/", "!", $1); print $1}' \ /proc/mounts); do [ "$p" = "$sysfsdev" ] && return 0 [ -e /sys/block/$sysfsdev/$p ] && return 0 done return 1 } has_holders() { local i # check if device is used by any md devices for i in $1/holders/* $1/*/holders/*; do [ -e "$i" ] && return 0 done return 1 } is_available_disk() { local dev=$1 local b=$(echo $p | sed 's:/:!:g') # check if its a "root" block device and not a partition [ -e /sys/block/$b ] || return 1 # check so it does not have mounted partitions has_mounted_part $dev && return 1 # check so its not part of an md setup if has_holders /sys/block/$b; then [ -n "$USE_RAID" ] && echo "Warning: $dev is part of a running raid" >&2 return 1 fi # check so its not an md device [ -e /sys/block/$b/md ] && return 1 return 0 } find_disks() { local p= # filter out ramdisks (major=1) for p in $(awk '$1 != 1 && $1 ~ /[0-9]+/ {print $4}' /proc/partitions); do is_available_disk $p && echo -n " $p" done } stop_all_raid() { local rd for rd in /dev/md*; do [ -b $rd ] && mdadm --stop $rd done } select_bootloader_pkg() { local bootloader="$BOOTLOADER" if [ "$ARCH" = "ppc64le" ]; then bootloader=grub-ieee1275 elif [ "$ARCH" = "s390x" ]; then bootloader=s390-tools 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= cryptpkg= fs= fstools= grub= [ -n "$USE_RAID" ] && raidpkg="mdadm" [ -n "$USE_LVM" ] && lvmpkg="lvm2" [ -n "$USE_CRYPT" ] && cryptpkg="cryptsetup blkid" for fs in $BOOTFS $ROOTFS $VARFS; do # we need load btrfs module early to avoid the error message: # 'failed to open /dev/btrfs-control' if ! grep -q -w "$fs" /proc/filesystems; then modprobe $fs fi case $fs in xfs) fstools="$fstools xfsprogs";; ext*) fstools="$fstools e2fsprogs";; btrfs) fstools="$fstools btrfs-progs";; vfat) fstools="$fstools dosfstools";; esac done apk add --quiet sfdisk $cryptpkg $lvmpkg $raidpkg $fstools $@ } show_disk_info() { local disk= vendor= model= d= size= busid= for disk in $@; do local dev=${disk#/dev/} d=$(echo $dev | sed 's:/:!:g') vendor=$(cat /sys/block/$d/device/vendor 2>/dev/null) model=$(cat /sys/block/$d/device/model 2>/dev/null) busid=$(readlink -f /sys/block/$d/device 2>/dev/null) size=$(awk '{gb = ($1 * 512)/1000000000; printf "%.1f GB\n", gb}' /sys/block/$d/size 2>/dev/null) if is_dasd $dev eckd; then echo " $dev ($size $vendor ${busid##*/})" else echo " $dev ($size $vendor $model)" fi done } confirm_erase() { local erasedisks="$@" if [ "$ERASE_DISKS" = "$erasedisks" ]; then return 0 fi echo "WARNING: The following disk(s) will be erased:" show_disk_info $@ ask_yesno "WARNING: Erase the above disk(s) and continue? (y/n)" n } # setup partitions on given disk dev in $1. # usage: setup_partitions size1,type1 [size2,type2 ...] setup_partitions() { local diskdev="$1" start=1M line= shift supported_part_label "$DISKLABEL" || return 1 # initialize MBR for syslinux only if [ "$BOOTLOADER" = "syslinux" ] && [ -f "$MBR" ]; then cat "$MBR" > $diskdev fi # create new partitions ( for line in "$@"; do case "$line" in 0M*) ;; *) echo "$start,$line"; start= ;; esac done ) | sfdisk --quiet --label $DISKLABEL $diskdev || return 1 # create device nodes if not exist mdev -s } # set up optional raid and create filesystem on boot device. setup_boot_dev() { 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 if [ "$ARCH" = "ppc64le" ]; then # Change bootable partition to PReP partition for disk in $disks; do echo ',,,*' | sfdisk --quiet $disk -N1 echo ',,,-' | sfdisk --quiet $disk -N2 mdev -s done fi echo "Creating file systems..." if [ -n "$USE_RAID" ]; then local missing= local num=$# if [ $# -eq 1 ]; then missing="missing" num=2 fi # we only use raid level 1 for boot devices mdadm --create /dev/md0 --level=1 --raid-devices=$num \ --metadata=0.90 --quiet --run $@ $missing || return 1 bootdev=/dev/md0 fi case "$BOOTFS" in vfat) mkfs_args="-F 32";; # UEFI firmware often only support FAT32 btrfs) mkfs_args="";; ext4) mkfs_args="$mkfs_args -O ^64bit";; # pv-grub does not support 64bit esac mkfs.$BOOTFS $MKFS_OPTS_BOOT $mkfs_args $bootdev BOOT_DEV="$bootdev" } # $1 = index # $2 = partition type # $3... = disk devices find_nth_non_boot_parts() { local idx=$1 id=$2 disk= type=bootable shift 2 local disks="$@" [ -n "$USE_EFI" ] && type=$(partition_id esp) for disk in $disks; do if is_dasd $disk eckd; then fdasd -p $disk | grep "Linux $id" | awk '{print $1}' | tail -n 1 else sfdisk -d $disk | grep -v $type \ | awk "/(Id|type)=$id/ { i++; if (i==$idx) print \$1 }" fi done } setup_non_boot_raid_dev() { local md_dev=$1 local idx=${md_dev#/dev/md} [ -z "$md_dev" ] && return 0 if [ "$ARCH" = "ppc64le" ]; then # increment idx as PReP partition is # the bootable partition in ppc64le idx=$((idx+1)) fi shift local level=1 local missing= 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 0) echo "No Raid partitions found" >&2; return 1;; 1) level=1; missing="missing"; num=2;; 2) level=1; missing= ; num=2;; *) level=5; missing= ; num=$#;; esac mdadm --create $md_dev --level=$level --raid-devices=$num \ --quiet --run $@ $missing || return 1 } # setup device for lvm, create raid array if needed setup_lvm_volume_group() { local vgname="$1" shift local lvmdev= if [ -n "$USE_RAID" ]; then setup_non_boot_raid_dev /dev/md1 $@ || return 1 lvmdev=/dev/md1 else lvmdev=$(find_partitions "$1" "lvm") fi if [ -n "$USE_CRYPT" ] && [ "$DISK_MODE" = "data" ]; then echo -e "target=var\nsource='$lvmdev'" > /etc/conf.d/dmcrypt lvmdev=$(setup_crypt $lvmdev var) || return 1 rc-update add dmcrypt boot fi if [ -n "$USE_CRYPT" ] && [ "$DISK_MODE" = "sys" ]; then lvmdev=$(setup_crypt $lvmdev root) || return 1 fi # be quiet on success local errmsg=$(dd if=/dev/zero of=$lvmdev bs=1k count=1 2>&1) \ || echo "$errmsg" pvcreate --quiet $lvmdev \ && vgcreate --quiet $vgname $lvmdev >/dev/null } # set up swap on given device(s) setup_swap_dev() { local swap_dev= sed -i -e '/swap/d' /etc/fstab SWAP_DEVICES= for swap_dev in "$@"; do mkswap $swap_dev >/dev/null echo -e "$(uuid_or_device $swap_dev)\tswap\t\tswap\tdefaults 0 0" >> /etc/fstab SWAP_DEVICES="$SWAP_DEVICES $swap_dev" done swapon -a rc-update --quiet add swap boot } # setup and enable swap on given volumegroup if needed setup_lvm_swap() { local vgname="$1" local swapname=lv_swap if [ -z "$SWAP_SIZE" ] || [ "$SWAP_SIZE" -eq 0 ]; then return fi lvcreate --quiet -n $swapname -L ${SWAP_SIZE}MB $vgname setup_swap_dev /dev/$vgname/$swapname } # if /var is mounted, move out data and umount it reset_var() { [ -z "$(find_mount_dev /var)" ] && return 0 mkdir /.var mv /var/* /.var/ 2>/dev/null umount /var && rm -rf /var && mv /.var /var && rm -rf /var/lost+found } # set up /var on given device setup_var() { local var_dev="$1" local varfs=${VARFS} echo "Creating file systems..." mkfs.$varfs $MKFS_OPTS_VAR $var_dev >/dev/null || return 1 sed -i -e '/[[:space:]]\/var[[:space:]]/d' /etc/fstab echo -e "$(uuid_or_device ${var_dev})\t/var\t\t${varfs}\tdefaults 1 2" >> /etc/fstab mv /var /.var mkdir /var mount /var mv /.var/* /var/ rmdir /.var service syslog --quiet condrestart setup_mdadm_conf } setup_mdadm_conf() { local mods= mod= if [ -n "$USE_RAID" ]; then mdadm --detail --scan > /etc/mdadm.conf rc-update --quiet add mdadm-raid boot mods=$(awk '/^raid/ {print $1}' /proc/modules) for mod in $mods; do if ! grep -q "^$mod" /etc/modules; then echo $mod >> /etc/modules fi done fi } data_only_disk_install_lvm() { local diskdev= local vgname=vg0 local var_dev=/dev/$vgname/lv_var local lvm_part_type=$(partition_id lvm) local size=$LVM_SIZE unset BOOTLOADER init_progs || return 1 confirm_erase $@ || return 1 if [ "$USE_RAID" ]; then lvm_part_type=$(partition_id raid) stop_all_raid fi for diskdev in "$@"; do setup_partitions $diskdev "${size}${size:+M},$lvm_part_type" || return 1 done setup_lvm_volume_group $vgname $@ || return 1 setup_lvm_swap $vgname lvcreate --quiet -n ${var_dev##*/} -l 100%FREE $vgname setup_mdadm_conf rc-update add lvm boot setup_var $var_dev } data_only_disk_install() { local diskdev= local var_dev= local var_part_type=$(partition_id linux) local swap_part_type=$(partition_id swap) local size= local swap_dev= var_dev= unset BOOTLOADER init_progs || return 1 confirm_erase $@ || return 1 if [ "$USE_RAID" ]; then var_part_type=$(partition_id raid) swap_part_type=$(partition_id raid) stop_all_raid fi for diskdev in "$@"; do setup_partitions $diskdev \ "${SWAP_SIZE}M,$swap_part_type" \ "${size}${size:+M},$var_part_type" || return 1 done if [ "$USE_RAID" ]; then if [ $SWAP_SIZE -gt 0 ]; then swap_dev=/dev/md1 var_dev=/dev/md2 else swap_dev= var_dev=/dev/md1 fi setup_non_boot_raid_dev "$swap_dev" $@ || return 1 setup_non_boot_raid_dev "$var_dev" $@ || return 1 else swap_dev=$(find_nth_non_boot_parts 1 "$swap_part_type" $@) var_dev=$(find_nth_non_boot_parts 1 "$var_part_type" $@) fi if [ -n "$USE_CRYPT" ]; then echo -e "target=var\nsource='$var_dev'" > /etc/conf.d/dmcrypt var_dev=$(setup_crypt $var_dev var) || return 1 rc-update add dmcrypt boot fi [ $SWAP_SIZE -gt 0 ] && setup_swap_dev $swap_dev setup_var $var_dev } # setup setup_root() { local root_dev="$1" boot_dev="$2" shift 2 local disks="$@" mkfs_args="-q" [ "$ROOTFS" = "btrfs" ] && mkfs_args="" mkfs.$ROOTFS $MKFS_OPTS_ROOT $mkfs_args "$root_dev" mkdir -p "$SYSROOT" mount -t $ROOTFS $root_dev "$SYSROOT" || return 1 if [ -n "$boot_dev" ] && ([ -z "$USE_EFI" ] || [ -n "$USE_CRYPT" ]); then mkdir -p "$SYSROOT"/boot mount -t $BOOTFS $boot_dev "$SYSROOT"/boot || return 1 fi if [ -n "$boot_dev" ] && [ -n "$USE_EFI" ] && [ -z "$USE_CRYPT" ]; 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 swapoff -a unmount_partitions "$SYSROOT" echo "" echo "Installation is complete. Please reboot." } native_disk_install_lvm() { local diskdev= vgname=vg0 local lvm_part_type=$(partition_id lvm) local boot_part_type=$(partition_id linux) local boot_size=${BOOT_SIZE:-100} local lvm_size=$LVM_SIZE local root_dev=/dev/$vgname/lv_root init_progs $(select_bootloader_pkg) || return 1 confirm_erase $@ || return 1 if [ "$BOOTFS" = "vfat" ] && [ -z "$USE_EFI" ]; then boot_part_type=$(partition_id vfat) fi if [ -n "$USE_RAID" ]; then boot_part_type=$(partition_id raid) lvm_part_type=$(partition_id raid) stop_all_raid fi if [ -n "$USE_EFI" ]; then boot_part_type=$(partition_id esp) fi for diskdev in "$@"; do if is_dasd $diskdev eckd; then root_part_type="lvm" setup_partitions_eckd $diskdev \ $boot_size 0 $root_part_type || return 1 else setup_partitions $diskdev \ "${boot_size}M,$boot_part_type,*" \ "${lvm_size}${lvm_size:+M},$lvm_part_type" || return 1 fi done # will find BOOT_DEV for us setup_boot_dev $@ setup_lvm_volume_group $vgname $@ || return 1 setup_lvm_swap $vgname lvcreate --quiet -n ${root_dev##*/} -l ${ROOT_SIZE:-100%FREE} $vgname rc-update add lvm boot setup_root $root_dev $BOOT_DEV } setup_crypt() { local dev="$1" local dmname="$2" mkdir -p /run/cryptsetup while true; do echo "Preparing partition for encryption." >&2 echo "You will be prompted for your password at boot." >&2 echo "If you forget your password, your data will be lost." >&2 cryptsetup luksFormat --batch-mode --verify-passphrase \ --type luks2 "$dev" >&2 # Error codes are: 1 wrong parameters, 2 no permission (bad # passphrase), 3 out of memory, 4 wrong device specified, 5 device # already exists or device is busy. # https://man7.org/linux/man-pages/man8/cryptsetup.8.html#RETURN_CODES case $? in 2) continue;; 0) ;; *) return 1;; esac echo "Enter password again to unlock disk for installation." >&2 cryptsetup open "$dev" "$dmname" >&2 \ && break echo "" >&2 done echo "/dev/mapper/$dmname" return 0 } native_disk_install() { 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=${ROOT_SIZE} local root_dev= boot_dev= swap_dev= init_progs $(select_bootloader_pkg) || return 1 confirm_erase $@ || return 1 if [ "$BOOTFS" = "vfat" ] && [ -z "$USE_EFI" ]; then boot_part_type=$(partition_id vfat) fi if [ -n "$USE_RAID" ]; then 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 boot_part_type=$(partition_id esp) fi for diskdev in "$@"; do if [ "$ARCH" = "ppc64le" ]; then setup_partitions $diskdev \ "${prep_size}M,$prep_part_type" \ "${boot_size}M,$boot_part_type,*" \ "${swap_size}M,$swap_part_type" \ "${root_size}${root_size:+M},$root_part_type" \ || return 1 elif is_dasd $diskdev eckd; then swap_part_type="swap" root_part_type="native" setup_partitions_eckd $diskdev \ $boot_size $swap_size $root_part_type || return 1 else setup_partitions $diskdev \ "${boot_size}M,$boot_part_type,*" \ "${swap_size}M,$swap_part_type" \ "${root_size}${root_size:+M},$root_part_type" \ || return 1 fi done # will find BOOT_DEV for us setup_boot_dev $@ if [ "$USE_RAID" ]; then if [ $SWAP_SIZE -gt 0 ]; then swap_dev=/dev/md1 root_dev=/dev/md2 else swap_dev= root_dev=/dev/md1 fi setup_non_boot_raid_dev "$swap_dev" $@ || return 1 setup_non_boot_raid_dev "$root_dev" $@ || return 1 else swap_dev=$(find_nth_non_boot_parts 1 "$swap_part_type" $@) local index= case "$ARCH" in # use the second non-bootable partition on ppc64le, # as PReP partition is the bootable partition ppc64le) index=2;; *) index=1;; esac root_dev=$(find_nth_non_boot_parts $index "$root_part_type" $@) fi if [ -n "$USE_CRYPT" ]; then root_dev=$(setup_crypt $root_dev root) || return 1 fi [ $SWAP_SIZE -gt 0 ] && setup_swap_dev $swap_dev setup_root $root_dev $BOOT_DEV $@ } diskselect_help() { cat <<-__EOF__ The disk you select can be used for a traditional disk install or for a data-only install. The disk will be erased. Enter 'none' if you want to run diskless. __EOF__ } diskmode_help() { cat <<-__EOF__ You can select between 'sys', 'data', 'crypt', 'cryptsys', 'lvm', 'lvmsys' or 'lvmdata'. sys: This mode is a traditional disk install. The following partitions will be created on the disk: /boot, / (filesystem root) and swap. This mode may be used for development boxes, desktops, virtual servers, etc. data: This mode uses your disk(s) for data storage, not for the operating system. The system itself will run from tmpfs (RAM). Use this mode if you only want to use the disk(s) for a mailspool, databases, logs, etc. crypt: Enable encryption with cryptsetup and ask again for 'sys' or 'data'. You will be prompted to enter a decryption password, and will need to use this password to boot up the operating system after installation. cryptsys: Same as 'sys' but also enable encryption. lvm: Enable logical volume manager and ask again for 'sys' or 'data'. lvmsys: Same as 'sys' but use logical volume manager for partitioning. lvmdata: Same as 'data' but use logical volume manager for partitioning. __EOF__ } # ask for a root or data disk # returns response in global variable $resp ask_disk() { local prompt="$1" local help_func="$2" local i= shift 2 local default_disk=${DEFAULT_DISK:-$1} resp= while ! all_in_list "$resp" $@ "none" "abort"; do echo "Available disks are:" show_disk_info "$@" ask "$prompt" "$default_disk" case "$resp" in 'abort') exit 0;; 'none') return 0;; '?') $help_func;; *) for i in $resp; do if ! [ -b "/dev/$i" ]; then echo "/dev/$i is not a block device" >&2 resp= fi done;; esac done } usage() { cat <<-__EOF__ usage: setup-disk [-hLqrve] [-k kernelflavor] [-m MODE] [-o apkovl] [-s SWAPSIZE] [MOUNTPOINT | DISKDEV...] Install alpine on harddisk. If MOUNTPOINT is specified, then do a traditional disk install with MOUNTPOINT as root. If DISKDEV is specified, then use the specified disk(s) without asking. If multiple disks are specified then set them up in a RAID array. If there are mode than 2 disks, then use raid level 5 instead of raid level 1. options: -h Show this help -e Encrypt disk -m Use disk for MODE without asking, where MODE is either 'data' or 'sys' -o Restore system from given apkovl file -k Use kernelflavor instead of $KERNEL_FLAVOR -L Use LVM to manage partitions -q Exit quietly if no disks are found -r Enable software raid1 with single disk -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 KERNELOPTS is specified, it will be appended to the kernel boot parameters. Default is: quiet 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, vfat(EFI) root: ext2, ext3, ext4, btrfs, xfs var: ext2, ext3, ext4, btrfs, xfs __EOF__ exit $1 } kver=$(uname -r) case $kver in *-rc[0-9]*) KERNEL_FLAVOR=lts;; *-[a-z]*) KERNEL_FLAVOR=${kver##*-};; *) KERNEL_FLAVOR=lts;; esac USE_CRYPT= DISK_MODE= USE_LVM= # Parse args while getopts "hek:Lm:o:qrs:v" opt; do case $opt in e) USE_CRYPT="_crypt";; h) usage 0;; m) DISK_MODE="$OPTARG";; k) KERNEL_FLAVOR="$OPTARG";; L) USE_LVM="_lvm";; o) APKOVL="$OPTARG";; q) QUIET=1;; r) USE_RAID=1;; s) SWAP_SIZE="$OPTARG";; v) VERBOSE=1;; '?') usage "1" >&2;; esac done shift $(( $OPTIND - 1)) if [ "$DISK_MODE" = "none" ] || [ "$1" = "none" ]; then exit 0 fi if is_rpi; then : ${BOOTLOADER:=raspberrypi-bootloader} BOOTFS=vfat SWAP_SIZE=0 fi if is_efi || [ -n "$USE_EFI" ]; then USE_EFI=1 DISKLABEL=gpt BOOTFS=vfat : ${BOOTLOADER:=grub} fi # machine arch ARCH=$(apk --print-arch) case "$ARCH" in x86*) : ${BOOTLOADER:=syslinux};; ppc64le) : ${BOOTLOADER:=grub};; s390x) : ${BOOTLOADER:=zipl};; arm*|aarch64) : ${BOOTLOADER:=u-boot};; esac if [ -d "$1" ]; then # install to given mounted root [ "$BOOTLOADER" = "syslinux" ] && apk add --quiet syslinux [ "$BOOTLOADER" = "u-boot" ] && apk add --quiet u-boot install_mounted_root "${1%/}" \ && echo "You might need fix the MBR to be able to boot" >&2 exit $? fi reset_var swapoff -a # stop all volume groups in use vgchange --ignorelockingfailure -a n >/dev/null 2>&1 if [ -n "$USE_RAID" ]; then stop_all_raid fi check_dasd diskdevs= # no disks so lets exit quietly. while [ -z "$disks" ]; do disks=$(find_disks) [ -n "$disks" ] && break # ask to unmount the boot mmc for rpi and similar modloop_media=$(find_modloop_media) if [ -z "$modloop_media" ] || ! ask_yesno "No disks available. Try boot media $modloop_media? (y/n)" n; then [ -z "$QUIET" ] && echo "No disks found." >&2 exit 0 fi DO_UMOUNT=1 modloop_media=$modloop_media copy-modloop done if [ $# -gt 0 ]; then # check that they are for i in "$@"; do j=$(readlink -f "$i" | sed 's:^/dev/::; s:/:!:g') if ! [ -e "/sys/block/$j/device" ]; then die "$i is not a suitable for partitioning" fi diskdevs="$diskdevs /dev/${j//!//}" done else ask_disk "Which disk(s) would you like to use? (or '?' for help or 'none')" \ diskselect_help $disks if [ "$resp" != none ]; then for i in $resp; do diskdevs="$diskdevs /dev/$i" done else DISK_MODE="none" fi fi if [ -n "$diskdevs" ] && [ -z "$DISK_MODE" ]; then resp= disk_is_or_disks_are="disk is" it_them="it" set -- $diskdevs if [ $# -gt 1 ]; then disk_is_or_disks_are="disks are" it_them="them" fi while true; do echo -n "The following $disk_is_or_disks_are selected" [ -n "$USE_CRYPT" ] && [ -z "$USE_LVM" ] && echo -n " (with encryption)" [ -z "$USE_CRYPT" ] && [ -n "$USE_LVM" ] && echo -n " (with LVM)" [ -n "$USE_CRYPT" ] && [ -n "$USE_LVM" ] && echo -n " (with LVM on LUKS)" echo ":" show_disk_info $diskdevs _crypt=$([ -z "$USE_CRYPT" ] && [ -z "$USE_LVM" ] && echo ", 'crypt'") _lvm=${USE_LVM:-", 'lvm'"} ask "How would you like to use $it_them? ('sys', 'data'$_crypt${_lvm#_lvm} or '?' for help)" "?" case "$resp" in '?') diskmode_help;; sys|data) break;; lvm) USE_LVM="_lvm" ;; nolvm) USE_LVM="";; crypt) USE_CRYPT="_crypt" ;; nocrypt) USE_CRYPT="";; lvmsys|lvmdata) resp=${resp#lvm} USE_LVM="_lvm" break ;; cryptsys) resp=${resp#crypt} USE_CRYPT="_crypt" break ;; esac done DISK_MODE="$resp" fi if [ -z "$SWAP_SIZE" ]; then SWAP_SIZE=$(find_swap_size $diskdevs) fi if [ -n "$USE_EFI" ] && [ -z "$BOOT_SIZE" ]; then blocksize=$(cat $(echo $diskdevs | sed -E -e 's:/dev/([^ ]+):/sys/block/\1/queue/logical_block_size:g') | sort -n | tail -n 1) # calculate minimal FAT32 size # for block size 512 minimal size is 32MB # for block size 4096, minimal size is 260M BOOT_SIZE=$(( ${blocksize:-0} * 64 / 1000 + 2 )) fi set -- $diskdevs if is_dasd $1 eckd; then DISKLABEL=eckd fi if [ $# -gt 1 ]; then USE_RAID=1 fi dmesg -n1 if [ -n "$USE_LVM" ] && ! grep -w -q device-mapper /proc/misc; then modprobe dm-mod fi # native disk install case "$DISK_MODE" in sys) native_disk_install$USE_LVM $diskdevs;; data) data_only_disk_install$USE_LVM $diskdevs;; none) exit 0;; *) die "Not a valid install mode: $DISK_MODE" ;; esac RC=$? echo "$DISK_MODE" > /tmp/alpine-install-diskmode.out exit $RC