+
+ if [[ $HOSTNAME == kd ]]; then
+ # note, having these with keyscript and initramfs causes a luks error in fai.log,
+ # but it is safely ignorable and gets us the ability to just type our password
+ # in once at boot. A downside is that they are probably needed to be plugged in to boot.
+ cat >>/tmp/fai/crypttab <<EOF
+crypt_dev_ata-Samsung_SSD_870_QVO_8TB_S5VUNG0N900656V-part${even_bign} /dev/disk/by-id/ata-Samsung_SSD_870_QVO_8TB_S5VUNG0N900656V-part${even_bign} none keyscript=decrypt_keyctl,discard,luks,initramfs
+crypt_dev_ata-TOSHIBA_MD04ACA500_84R2K773FS9A-part1 /dev/disk/by-id/ata-TOSHIBA_MD04ACA500_84R2K773FS9A-part1 none keyscript=decrypt_keyctl,discard,luks,initramfs
+crypt_dev_ata-ST6000DM001-1XY17Z_Z4D29EBL-part1 /dev/disk/by-id/ata-ST6000DM001-1XY17Z_Z4D29EBL-part1 none keyscript=decrypt_keyctl,discard,luks,initramfs
+EOF
+ cat >> /tmp/fai/fstab <<EOF
+# r7 = root partition7. it isnt actually #7 anymore, not a great name, but whatever
+/dev/mapper/crypt_dev_ata-Samsung_SSD_870_QVO_8TB_S5VUNG0N900656V-part${even_bign} /mnt/r7 btrfs nofail,$fstabstd,noatime,compress=zstd,subvolid=0 0 0
+/dev/mapper/crypt_dev_ata-TOSHIBA_MD04ACA500_84R2K773FS9A-part1 /mnt/rust1 btrfs nofail,$fstabstd,noatime,compress=zstd,subvolid=0 0 0
+/dev/mapper/crypt_dev_ata-ST6000DM001-1XY17Z_Z4D29EBL-part1 /mnt/rust2 btrfs nofail,$fstabstd,noatime,compress=zstd,subvolid=0 0 0
+EOF
+ fi
+ fi
+}
+
+
+
+getluks() {
+ if [[ ! $luks_dir ]]; then
+ # see README for docs about how to create these
+ luks_dir=$FAI/distro-install-common/luks
+ if [[ ! -d $luks_dir ]]; then
+ luks_dir=/q/root/luks
+ fi
+ if [[ ! -d $luks_dir ]]; then
+ echo "$0: error: no luks_dir found" >&2
+ exit 1
+ fi
+ fi
+
+ luks_file=$luks_dir/host-$HOSTNAME
+ if [[ ! -e $luks_file ]]; then
+ # shellcheck disable=SC2206 # globbing is intended
+ hostkeys=($luks_dir/host-*)
+ # if there is only one key, we might be deploying somewhere
+ # where dhcp doesnt give us a proper hostname, so use that.
+ if [[ ${#hostkeys[@]} == 1 && -e ${hostkeys[0]} ]]; then
+ luks_file=${hostkeys[0]}
+ else
+ echo "$0: error: no key for hostname at $luks_file" >&2
+ exit 1
+ fi
+ fi
+
+ # # note, corresponding changes in /b/ds/keyscript-{on,off}
+ if ifclass demohost; then
+ lukspw=x
+ elif [[ -e $luks_dir/$HOSTNAME ]]; then
+ lukspw=$(cat $luks_dir/$HOSTNAME)
+ else
+ lukspw=$(cat $luks_dir/iank)
+ fi
+
+ if $mkroot2; then
+ luks_file=$luks_dir/host-amy
+ lukspw=$(cat $luks_dir/amy)
+ fi
+}
+
+
+#### root2 non-fai run
+doroot2() {
+
+ # We write to these files instead of just /etc/fstab, /etc/crypttab,
+ # because these are filesystems created after our current root, and so
+ # this allows us to update other root filesystems too.
+ rm -f /mnt/root/root2-{fs,crypt}tab
+ if $partition; then
+ echo $0: error: found partition=true but have mkroot2 arg
+ exit 1
+ fi
+ for dev in ${devs[@]}; do
+ if $mkroot2; then
+ luks-setup $(root2dev)
+ fi
+ cat >>/mnt/root/root2-crypttab <<EOF
+$(root2-cryptname) $(root2dev) $luks_file discard,luks,initramfs
+EOF
+ done
+ if $mkroot2; then
+ bpart $(for dev in ${devs[@]}; do root2-cryptdev; done)
+ bpart ${boot2_devs[@]}
+ fi
+ mkdir -p /mnt/root2 /mnt/boot2
+ cat >>/mnt/root/root2-fstab <<EOF
+$(root2-cryptdev ${devs[0]}) /mnt/root2 btrfs nofail,x-systemd.device-timeout=30s,x-systemd.mount-timeout=30s,noatime,subvolid=0$mopts 0 0
+${boot2_devs[0]} /mnt/boot2 btrfs nofail,x-systemd.device-timeout=30s,x-systemd.mount-timeout=30s,noatime,subvolid=0 0 0
+EOF
+ exit 0
+}
+
+if $mkroot2 || $mkroot2tab; then
+ getluks
+ doroot2
+elif $mktab; then
+ mktab
+ exit 0
+else
+ mktab
+ getluks
+fi
+
+
+if $partition; then
+ ### begin wipefs
+ if [[ ! $SPECIAL_DISK ]]; then
+ for dev in ${devs[@]}; do
+ # if we repartition to the same as an old partition,
+ # we don't want any old fses hanging around.
+ for (( i=1; i <= lastn; i++ )); do
+ x=$(add-part $i)
+ [[ -e $x ]] || continue
+ count_down=10
+ # wipefs has failed, manual run works, google suggests timing issue
+ while ! wipefs -a $x; do
+ sleep 2
+ count_down=$((count_down - 1))
+ (( count_down > 0 )) || exit 1
+ done
+ done
+ done
+ fi
+ ### end wipefs
+
+
+ # When we have 2 disks of at least 100g difference in size,
+ # make an extra partition on the end of the bigger one.
+ even_big_part=false
+ even_diff_min=100000
+ if $even_raid; then
+ smalli=0
+ bigi=1
+ if (( $(dev-mib ${devs[0]}) >= $(dev-mib ${devs[1]}) )); then
+ smalli=1
+ bigi=0
+ fi
+ disk_mib=$(dev-mib ${devs[smalli]})
+ even_big_dev=${devs[bigi]}
+ even_big_mib=$(dev-mib $even_big_dev)
+ if (( even_big_mib - disk_mib > even_diff_min )); then
+ even_big_part=true
+ fi
+ fi
+
+ for dev in ${devs[@]}; do
+ if [[ $SPECIAL_DISK ]]; then
+ dev=$(devbyid $SPECIAL_DISK)
+ fi
+
+ # parted will round up the disk size. Do -1 so we can have
+ # fully 1MiB unit partitions for easy resizing of the last partition.
+ # Otherwise we would pass in -0 for the end argument for the last partition.
+ #
+ # Note: parted print error output is expected. example:
+ # Error: /dev/vda: unrecognised disk label
+ if ! $even_raid; then
+ disk_mib=$(dev-mib)
+ fi
+
+ boot_part_mib=$(( boot_mib / ${#boot_devs[@]} ))
+ boot2_part_mib=$(( boot2_mib / ${#boot_devs[@]} ))
+ root2_part_mib=$(( root2_mib / ${#root_devs[@]} ))
+ root_end=$(( disk_mib - root2_part_mib - swap_mib - boot_part_mib - boot2_part_mib ))
+ root2_end=$(( root_end + root2_part_mib ))
+ swap_end=$(( root2_end + swap_mib ))
+ boot_end=$(( swap_end + boot_part_mib ))
+
+ parted -s $dev mklabel gpt
+ # MiB because parted complains about alignment otherwise.
+ pcmd="parted -a optimal -s -- $dev"
+ # root partition, the main big one
+ $pcmd mkpart primary ext3 524MiB ${root_end}MiB
+ # without naming, systemd gives us misc errors like:
+ # dev-disk-by\x2dpartlabel-primary.device: Dev dev-disk-by\x2dpartlabel-primary.device appeared twice
+ $pcmd name $rootn root
+ # root2 partition
+ $pcmd mkpart primary ext3 ${root_end}MiB ${root2_end}MiB
+ $pcmd name $root2n root2
+ # normally a swap is type "linux-swap", but this is encrypted swap. using that
+ # label will confuse systemd.
+ # swap partition
+ $pcmd mkpart primary "" ${root2_end}MiB ${swap_end}MiB
+ $pcmd name $swapn swap
+ # boot partition
+ $pcmd mkpart primary "" ${swap_end}MiB ${boot_end}MiB
+ $pcmd name $bootn boot
+ # boot2 partition
+ $pcmd mkpart primary "" ${boot_end}MiB ${disk_mib}MiB
+ $pcmd name $boot2n boot2
+ # uefi partition. efi sucks, half a gig, rediculous.
+ $pcmd mkpart primary "fat32" 12MiB 524MiB
+ $pcmd name $efin efi
+ $pcmd set $efin esp on
+ # note, this is shown here: https://support.system76.com/articles/bootloader/
+ # but not mentioned https://wiki.archlinux.org/index.php/EFI_system_partition
+ # probably not needed
+ $pcmd set $bootn boot on
+ $pcmd set $boot2n boot on
+ # i only need a few k, but googling min size,
+ # I found someone saying that gparted required
+ # required at least 8 because of their hard drive cylinder size.
+ # And 8 is still very tiny.
+ # grub_ext partition
+ $pcmd mkpart primary "ext2" 4MiB 12MiB
+ $pcmd name $grub_extn grubext
+ # gpt ubuntu cloud image uses ~4 mb for this partition. fai uses 1 MiB.
+ # so, I use 3, whatever.
+ # note: parted manual saying cheap flash media
+ # should to start at 4.
+ # biols grub partition
+ $pcmd mkpart primary "" 1MiB 4MiB
+ $pcmd name $bios_grubn biosgrub
+ $pcmd set $bios_grubn bios_grub on
+ if $even_big_part && [[ $dev == "$even_big_dev" ]]; then
+ $pcmd mkpart primary ext3 ${disk_mib}MiB ${even_big_mib}MiB
+ $pcmd name $even_bign even_big
+ fi
+
+ # the mkfs failed before on a vm, which prompted me to add
+ # sleep .1
+ # then it failed again on a physical machine
+ # with:
+ # Device /dev/disk/by-id/foo doesn't exist or access denied,
+ # so I added a wait until it existed.
+ # Then I added the mkfs.ext2, which claimed to succeed,
+ # but then couldn't be found upon reboot. In that case we didn't
+ # wait at all. So I've added a 3 second minimum wait.
+ secs=0
+ while [[ ! -e $(bios_grubdev) ]] && (( secs < 10 )); do
+ sleep 1
+ secs=$((secs +1))
+ done
+ sleep 3
+
+ mkfs.fat -F32 $(efidev)
+
+ if $even_big_part && [[ $dev == "$even_big_dev" ]]; then
+ luks-setup $(even_bigdev)
+ mkfs.btrfs -f $(crypt-dev $(even_bigdev))
+ fi
+
+ # Holds just a single file, rarely written, so
+ # use ext2, like was often used for the /boot partition.
+ # This exists because grub can only persist data to a non-cow fs.
+ # And we use persisting a var in grub to do a one time boot.
+ # We could pass the data on the kernel command line and persist it
+ # to grubenv after booting, but that relies on the boot always succeeding.
+ # This is just a bit more robust, and it could work for booting
+ # into ipxe which can't persist data, if we ever got that working.
+ mkfs.ext2 $(grub_extdev)
+ luks-setup $(rootdev)
+
+ if [[ $SPECIAL_DISK ]]; then
+ exit 0
+ fi
+ done
+ ls -la /dev/btrfs-control # this was probably for debugging...
+ sleep 1
+ bpart $(for dev in ${devs[@]}; do root-cryptdev; done)
+ bpart ${boot_devs[@]}
+else
+ for dev in ${devs[@]}; do
+ if [[ -e /dev/mapper/$(root-cryptname) ]]; then
+ continue
+ fi
+ if $rerootfs; then
+ luks-setup $(rootdev)
+ sleep 1
+ bpart $(for dev in ${devs[@]}; do root-cryptdev; done)
+ else
+ cryptsetup luksOpen $(rootdev) $(root-cryptname) \
+ --key-file $luks_file
+ fi
+ done
+
+ if $rerootfs; then
+ sleep 1
+ bpart $(for dev in ${devs[@]}; do root-cryptdev; done)
+ fi
+ sleep 1
+fi
+
+
+if $wipe && [[ $DISTRO != debianbullseye_bootstrap ]]; then
+ # bootstrap distro doesn't use separate encrypted root.
+ mount -o subvolid=0 $first_root_crypt /mnt
+ # systemd creates subvolumes we want to delete.
+ mapfile -t s < <(btrfs subvolume list --sort=-path /mnt |
+ sed -rn "s#^.*path\s*(root_$DISTRO/\S+)\s*\$#\1#p")
+ for subvol in ${s[@]}; do btrfs subvolume delete /mnt/$subvol; done
+ btrfs subvolume set-default 0 /mnt
+ [[ ! -e /mnt/root_$DISTRO ]] || btrfs subvolume delete /mnt/root_$DISTRO
+
+ ## create subvols ##
+ cd /mnt
+
+ btrfs subvolume create root_$DISTRO
+
+ # could set default subvol like this, but no reason to.
+ # btrfs subvolume set-default \
+ # $(btrfs subvolume list . | grep "root_$DISTRO$" | awk '{print $2}') .
+
+ # For raid systems, cow allows for error correction, for non-raid systems,
+ # protects root fs from having the plug pulled. Reprovisioning a root
+ # subvol is not my favorite thing to do.
+ # # no cow on the root filesystem. it's setup is fully scripted,
+ # # if it's messed up, we will just recreated it,
+ # # and we can get better perf with this.
+ # # I can't remember exactly why, but this is preferable to mounting with
+ # # -o nodatacow, I think because subvolumes inherit that.
+ # chattr -Rf +C root_$DISTRO
+ cd /
+ umount /mnt
+fi
+
+mount -o subvolid=0 $first_boot_dev /mnt
+cd /mnt
+btrfs subvolume set-default 0 /mnt # already default, just ensuring it.
+
+# for libreboot systems. grub2 only reads from subvolid=0
+mkdir -p /mnt/grub2
+cp $FAI/distro-install-common/libreboot_grub.cfg /mnt/grub2
+
+if $wipe && [[ -e /mnt/$boot_vol ]]; then
+ btrfs subvolume delete /mnt/$boot_vol