#!/usr/bin/env zsh vars+=(skip_arm_generic_root skip_arm_device_root force_packages_option base_packages_option extra_packages_option) # shellcheck shell=bash # Copyright (c) 2016-2021 Ivan J. # This file is part of libdevuansdk # # This source code is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this source code. If not, see . # Put image_connect_raw after image_partition_${parted_type} # Change image_partition_${parted_type} to image_partition_raw_${parted_type} # to alternative behaviour of the parted_type=gpt (use sgdisk instead of cgpt to # employ rootckchip standard layout) build_arm_dist() { fn build_arm_dist "(override)" req=(workdir strapdir os arch size parted_type) ckreq || return 1 case "$parted_type" in gpt) req+=(gpt_boot gpt_root) ;; dos) req+=(dos_boot dos_root) ;; *) die "Unknown parted_type: $parted_type. Supported is gpt|dos." zerr; return 1 ;; esac notice "Building complete Arm image(s)" image_prepare_raw || { zerr; return 1; } image_partition_raw_${parted_type} || { zerr; return 1; } image_connect_raw || { zerr; return 1; } image_format_partitions || { zerr; return 1; } image_raw_mount $strapdir || { zerr; return 1; } bootstrap_complete_base || { zerr; return 1; } blend_preinst || { zerr; return 1; } # image_prepare_raw || { zerr; return 1; } # image_partition_raw_${parted_type} || { zerr; return 1; } # image_connect_raw || { zerr; return 1; } # image_format_partitions || { zerr; return 1; } apply_fstab || { zerr; return 1; } build_zfs || { zerr; return 1; } build_kernel_${arch} || { zerr; return 1; } # uboot_image_${uboot_image_format} || { zerr; return 1; } blend_postinst || { zerr; return 1; } # image_raw_mount $workdir/mnt || { zerr; return 1; } # # tar_strapdir || { zerr; return 1; } # rsync_to_raw_image || { zerr; return 1; } configure_bootloader || { zerr; return 1; } # image_raw_umount $workdir/mnt || { zerr; return 1; } image_raw_umount $strapdir || { zerr; return 1; } image_pack_dist || { zerr; return 1; } image_disconnect_raw || { zerr; return 1; } # clean_strapdir || { zerr; return 1; } } # Changes to make grub-install work findloopdev() { fn findloopdev req=(workdir image_name) ckreq || return 1 notice "finding a free loopdevice" loopdevice=$(sudo losetup --find --show $workdir/${image_name}.img) sudo partx --add --verbose $loopdevice || zerr func "loopdevice: $loopdevice" } # Change partition numbers from p1 and p2 to p4 p5 for rockchip layout. # Get uuid for The loop device and partitions. # Add a symlink to /dev/disk-by/uuid for the loopback device. image_connect_raw() { fn image_connect_raw "(override)" notice "Connecting raw image to loop device" findloopdev if [[ -z "$loopdevice" ]]; then die "Did not find a free loop device" zerr; return 1 fi # FIXME: These are set in the blend config, for sdcards for arm it should # probably be set in arm-sdk/boards/ bootpart="${loopdevice}p${boot_part_number}" rootpart="${loopdevice}p${root_part_number}" esppart="${loopdevice}p${esp_part_number}" bootpart_partuuid=$(blkid --match-tag PARTUUID --output value ${bootpart}) rootpart_partuuid=$(blkid --match-tag PARTUUID --output value ${rootpart}) esppart_partuuid=$(blkid --match-tag PARTUUID --output value ${esppart}) # act "Create a symlink to /dev/disk-by/uuid for the loopback device." # loopdevice_uuid=$(blkid -s UUID -o value ${loopdevice}) # ln -s ${loopdevice} /dev/disk/by-uuid/${loopdevice_uuid} || { zerr; return 1; } } image_disconnect_raw() { fn image_disconnect_raw "(override)" req=(loopdevice bootpart rootpart esppart) ckreq || return 1 notice "Disconnect raw image from loop device." act "Ensuring no process is using the loop device." fuser --kill ${loopdevice} act "unmounting partitions." for mount in ${bootpart} ${rootpart} ${esppart}; do if grep -qs "${mount}" /proc/mounts; then act "umounting ${mount}." umount ${mount} || { zerr; return 1; } fi done act "removing the loop device." losetup -d "$loopdevice" || { zerr; return 1; } # Remove loopback device # act "remove the symlink to /dev/disk-by/uuid." # rm -f /dev/disk/by-uuid/${loopdevice_uuid} || { zerr; return 1; } } # Add mounting of /boot/grub|/boot/efi and a mountpoint. # The allows The function to be used to mount on strapdir and workdir/mnt image_raw_mount() { fn image_raw_mount "(override)" req=(workdir uefi bootpart rootpart bootfs esppart espfs) ckreq || return 1 if [[ -n $1 ]]; then mountpoint=${1} || { zerr; return 1; } else act "This function must be called with a mountpoint argument." fi mkdir -p $mountpoint sudo mount $rootpart $mountpoint && \ act "mounted root partition" || zerr [[ "$bootfs" == none ]] || { sudo mkdir -p $mountpoint/boot sudo mount $bootpart $mountpoint/boot && \ act "mounted boot partition" || zerr } if [[ "$uefi" != none ]]; then [[ "$espfs" == none ]] || { sudo mkdir -p $mountpoint/boot/efi sudo mount $esppart $mountpoint/boot/efi && \ act "mounted efi partition" || zerr } else [[ "$espfs" == none ]] || { sudo mkdir -p $mountpoint/boot/grub sudo mount $esppart $mountpoint/boot/grub && \ act "mounted grub partition" || zerr } fi } # Add unmounting of /boot/grub|/boot/efi image_raw_umount() { fn image_raw_umount "(override)" req=(workdir bootpart rootpart esppart) ckreq || return 1 if [[ -n $1 ]]; then mountpoint=${1} || { zerr; return 1; } else notice "This function must be called with a mountpoint argument." fi notice "umounting raw image from ${mountpoint}." # discover if the directories are unmounted if [[ -d $mountpoint/boot/efi ]]; then $(mountpoint -q $mountpoint/boot/efi); esp_retval=$?; fi if [[ -d $workdir/mnt/boot/grub ]]; then $(mountpoint -q $mountpoint/boot/grub); grub_retval=$?; fi if [[ "$uefi" != none ]] && [[ $esp_retval -eq 0 ]]; then act "umounting efi partition" [[ "$espfs" == none ]] || { sudo umount --lazy $mountpoint/boot/efi && act "unmounted efi system partition" || zerr sleep 1 } elif [[ "$uefi" == false ]] && [[ $grub_retval -eq 0 ]]; then act "umounting grub partition" [[ "$espfs" == none ]] || { sudo umount --lazy $mountpoint/boot/grub && act "unmounted grub partition" || zerr sleep 1 } fi [[ "$bootfs" == none ]] || { sudo umount --lazy $mountpoint/boot && act "unmounted boot partition" || zerr sleep 1 } sudo umount --lazy $mountpoint && act "unmounted root partition" || zerr } # the release version is qemu specific this is for the raw image created by image_prepare_raw. image_raw_as_strapdir() { fn image_raw_as_strapdir "(override)" req=(workdir strapdir loopdevice) ckreq || return 1 pushd "$workdir" notice "mounting raw image to strapdir" image_raw_mount $strapdir echo 1 | sudo tee ${strapdir}/.keep >/dev/null popd } # For pros and cons of using PARTUUID see: # https://bbs.archlinux.org/viewtopic.php?pid=1863861#p1863861 # calls conf_print_ in blends: sysconf apply_fstab() { fn apply_fstab "(override)" req=(strapdir bootpart rootpart esppart parted_type) ckreq || return 1 notice "Injecting rootfs overrides" case "$parted_type" in gpt) conf_print_PARTUUID_fstab ;; dos) # The UUID of the device on which root and boot partitions reside. # Use these variables in fstab entries if your using MBR as its pseudo # PARTUUID can change if the partition number changes bootuuid="$(lsblk "$bootpart" -no UUID)" rootuuid="$(lsblk "$rootpart" -no UUID)" espuuid="$(lsblk "$esppart" -no UUID)" conf_print_UUID_fstab ;; *) die "Unknown parted_type: $parted_type. Supported is gpt|dos." zerr; return 1 ;; esac } build_image_dist() { fn build_image_dist "(override)" req=(arch size parted_type) req+=(workdir strapdir image_name) case "$parted_type" in gpt) req+=(gpt_boot gpt_root) ;; dos) req+=(dos_boot dos_root) ;; *) die "Unknown parted_type: $parted_type. Supported is gpt|dos." zerr; return 1 ;; esac ckreq || return 1 notice "building complete dist image" act "$image_name" bootstrap_complete_base || { zerr; wrapup } blend_preinst || { zerr; wrapup } image_prepare_raw || { zerr; wrapup } image_partition_raw_${parted_type} || { zerr; wrapup } build_kernel_${arch} || { zerr; wrapup } blend_postinst || { zerr; wrapup } rsync_to_raw_image || { zerr; wrapup } image_pack_dist || { zerr; wrapup } } build_metal_dist() { fn build_metal_dist req=(arch) req+=(workdir strapdir disk_name) ckreq || return 1 notice "installing complete dist" act "add release symlink to debootstrap scripts." if [[ ! -f /usr/share/debootstrap/scripts/${release} ]]; then ln -sf /usr/share/debootstrap/scripts/ceres \ /usr/share/debootstrap/scripts/${release} fi image_partition_disk_zfs || { zerr; wrapup } image_format_partitions_zfs || { zerr; wrapup } bootstrap_complete_base || { zerr; wrapup } blend_preinst || { zerr; wrapup } blend_postinst || { zerr; wrapup } } # Overide the post 'debootstrap stage 2' placeholder function of zlib/debootstrap bootstrap_complete_base. # The default is just to return 0 blend_bootstrap_setup() { fn blend_bootstrap_setup "noop" return 0 } ## Override the helper function: # takes the 'apt-get -f' out of the loop so that dependency provided by other debs can be resolved. # inside the loop it just uninstalls the deb because of unfullfilled deps. install-custdebs() { fn install-custdebs "(override)" req=(R strapdir custom_deb_packages) ckreq || return 1 sudo mkdir -p ${strapdir}/debs sudo cp $R/extra/custom-packages/*.deb ${strapdir}/debs/ cat <<-EOF | sudo tee ${strapdir}/install-debs >/dev/null #!/bin/sh cd /debs for deb in ${custom_deb_packages}; do dpkg -i \$deb done apt-get --yes ${force_packages_option} -f install cd / apt-get --yes ${force_packages_option} autoremove #rm -rf /debs EOF chroot-script -d install-debs || zerr } ## Added function: # In the style of install-custdebs above but for a collection of arbitrary scripts placed in a # directory alongside the blend custom debs called automate. # The scripts are copied from the blends scripts directory to extra/custom-scripts in blend_preinst() above. # Called after install-customdebs because some need checkinstall which disappears from archives. install-custscripts() { fn install-custscripts req=(R strapdir custom_scripts) ckreq || return 1 sudo mkdir -p ${strapdir}/var/tmp/automate sudo cp $R/extra/custom-scripts/*.sh ${strapdir}/var/tmp/automate/ cat <<-EOF | sudo tee ${strapdir}/install-scripts >/dev/null #!/bin/sh cd /var/tmp/automate for script in ${custom_scripts}; do touch \${script}.log bash \$script done apt-get --yes ${force_packages_option} -f install cd / apt-get --yes ${force_packages_option} autoremove #rm -rf /var/tmp/automate EOF chroot-script -d install-scripts || zerr } ## Override the helper function: # Allow an alternative skel directory add-user() { fn add-user $* "(override)" local user="$1" local pass="$2" local skel="${3:-/etc/skel}" req=(strapdir user pass skel) ckreq || return 1 notice "adding user $user:$pass using $skel" cat <<-EOF | sudo tee ${strapdir}/adduser >/dev/null #!/bin/sh set -x if [ $(id -u ${user} 2>&1 >/dev/null) ]; then echo "user not present, creating account." useradd -m ${user} -k ${userskel:-/etc/skel} echo "${user}:${pass}" | chpasswd fi EOF chroot-script adduser || { zerr; return 0; } } copy-kernel-config() { fn copy-kernel-config "(override)" req=(device_name gitbranch) ckreq || return 1 notice "copying available kernel config" act "remove any .config file from the kernel source directory." local kernel_home="$R/tmp/kernels/$device_name/${device_name}-linux_$gitbranch" kernel_config="${kernel_home}/.config" if [ -f "${kernel_config}" ]; then rm "${kernel_home}"/.config* fi if [ -f "$R/boards/kernel-configs/${device_name}.config_${gitbranch}" ]; then act "$R/boards/kernel-configs/${device_name}.config_${gitbranch}" cp -f "$R/boards/kernel-configs/${device_name}.config_${gitbranch}" \ "${kernel_config}" else act "copying previous kernel config" cp -f $(ls -v $R/boards/kernel-configs/${device_name}.config_* | tail -n 1) \ "$R/boards/kernel-configs/${device_name}.config_${gitbranch}" cp -f "$R/boards/kernel-configs/${device_name}.config_${gitbranch}" \ "${kernel_config}" fi } copy-root-overlay() { fn copy-root-overlay req=(strapdir device_name R) ckreq || return 1 if [ -z "$skip_arm_generic_root" ]; then if [ -d "$R/extra/generic-root" ]; then notice "copying generic-root" sudo cp -rfv "$R/extra/generic-root"/* "$strapdir" sudo sed -e "s/{{{BOOTFS}}}/$bootfs/" -i "$strapdir/etc/fstab" sudo sed -e "s/\/dev\/mmcblk0p1/PARTUUID=$bootpart_partuuid/" -i "$strapdir/etc/fstab" fi fi if [ -z "$skip_arm_device_root" ]; then if [ -d "$R/extra/$device_name" ]; then notice "copyring ${device_name}-root" sudo cp -rfv "$R/extra/$device_name"/* "$strapdir" fi fi return 0 } ## apt related functions # point apt at a local apt-proxy like apt-cacher-ng enable_apt-proxy() { fn enable_apt-proxy req=(strapdir apt_proxy) ckreq || return 1 cat <<-EOF | sudo tee ${strapdir}/add_apt-proxy #!/bin/sh cat > '/etc/apt/apt.conf.d/02proxy' << 'FOE' Acquire::http { Proxy "${apt_proxy}"; }; FOE EOF chroot-script add_apt-proxy || zerr } disable_apt-proxy() { fn disable_apt-proxy req=(strapdir) ckreq || return 1 cat <<-EOF | sudo tee ${strapdir}/del_apt-proxy #!/bin/sh rm -f /etc/apt/apt.conf.d/02proxy EOF chroot-script del_apt-proxy || zerr } # When the release changes its suite (ie. from stable to oldstable) by default # apt asks for explicite acceptance, which you might not want in your image, # turn this on and off. enable_apt-allow-releaseinfo-change() { fn enable_apt-allow-releaseinfo-change req=(strapdir) ckreq || return 1 cat <<-EOF | sudo tee ${strapdir}/add_apt-releaseinfo-change #!/bin/sh cat > '/etc/apt/apt.conf.d/10no-check-valid-until' << 'FOE' Acquire::AllowReleaseInfoChange::Suite "true"; FOE EOF chroot-script add_apt-releaseinfo-change || zerr } disable_apt-allow-releaseinfo-change() { fn disable_apt-allow-releaseinfo-change req=(strapdir) ckreq || return 1 cat <<-EOF | sudo tee ${strapdir}/del_apt-allow-releaseinfo-change #!/bin/sh # rm -f /etc/apt/apt.conf.d/10no-check-valid-until EOF chroot-script del_apt-allow-releaseinfo-change || zerr } # apt checks the valid-util and refuses to install from repositories that are too old, which you might not want if building an old release, turn this on or off. disable_apt-valid-until() { fn disable_apt-valid-until req=(strapdir) ckreq || return 1 cat <<-EOF | sudo tee ${strapdir}/add_apt-check-valid #!/bin/sh cat > '/etc/apt/apt.conf.d/10no-check-valid-until' << 'FOE' Acquire::Check-Valid-Until "false"; FOE EOF chroot-script add_apt-check-valid || zerr } enable_apt-valid-until() { fn enable_apt-valid-until req=(strapdir) ckreq || return 1 cat <<-EOF | sudo tee ${strapdir}/del_apt-check-valid #!/bin/sh rm -f /etc/apt/apt.conf.d/10no-check-valid-until EOF chroot-script del_apt-check-valid || zerr } # Overide the sdk version of this function to prevent deletion # prior to unpacking the cpio as we have mountpoints in place # when installing to hardrive. bootstrap_cpio_unpack() { fn bootstrap_cpio_unpack "$*" "(override)" req=(_bootstrap_cpio strapdir) local _bootstrap_cpio="$1" ckreq || return 1 notice "Unpacking bootstrap cpio archive: $_bootstrap_cpio" #sudo rm -rf "${strapdir}"/* pushd "$strapdir" || { zerr; return 1; } zcat "$_bootstrap_cpio" | sudo cpio -idmn --format=newc || { zerr; return 1; } popd sudo mkdir -p "$strapdir"/{boot,dev,proc,sys} } # Overide the sdk version of this function to prevent mount/unmounting of The # raw image so operations requiring a block device (grub-install) can be run # before we pack the image file with image_pack_dist. rsync_to_raw_image() { fn rsync_to_raw_image "(override)" req=(workdir strapdir bootpart rootpart) ckreq || return 1 notice "Preparing to rsync the rootfs..." # image_raw_mount # mkdir -p $R/dist pushd $strapdir # tar_strapdir || zerr act "rsyncing strapdir to raw image..." sudo rsync -HPavz -q ./* $workdir/mnt || { image_raw_umount die "not enough space, please report a bug" zerr } popd # image_raw_umount } image_partition_raw_gpt() { fn image_partition_raw_gpt req=(workdir image_name IDBLOADER_START IDBLOADER_OFFSET UBOOT_START BOOT_SIZE TRUST_SIZE ESP_SIZE) ckreq || return 1 # FIXME:Combine this and image_partitions_disk_zfs to use: # https://github.com/uapi-group/specifications/blob/main/specs/discoverable_partitions_specification.md # to iterate over the defined partions and apply the correct partition UUID based on target cpu. # the uuid variable are currently defined at the top of the rockpro64 board file. # Assign them to local variable using a case statement # (arch in amd64 arm64 armhf the TARGET="ARM64" TARGET="X86_64" TARGET="ARM32" etc.) # SD_GPT_ROOT=SD_GPT_ROOT_${TARGET} # SD_GPT_KERNEL=SD_GPT_KERNEL_${TARGET} # SD_GPT_USR=SD_GPT_USR_${TARGET} notice "partitioning raw gpt image..." notice "workdir: $workdir" notice "image_name: $image_name" echo "Generate System image : ${image_name} !" # Create partitions notice "Updating GPT..." TARGET="$workdir/${image_name}.img" /sbin/sgdisk --zap-all "${TARGET}" notice "Partition 1 of 6 - Create partition using start and end values for partitioning the idbloader partition." STARTSECTOR="${IDBLOADER_START}" PARTNUM=1 PARTLABEL="loader1" /sbin/sgdisk --print --set-alignment=1 --mbrtogpt --new="${PARTNUM}":"${IDBLOADER_START}":+"${IDBLOADER_OFFSET}" "${TARGET}" /sbin/sgdisk --print --change-name="${PARTNUM}":"${PARTLABEL}" --typecode="${PARTNUM}":"${SD_GPT_LOADER}" "${TARGET}" notice "Partition 2 of 6 - Create partition using start and end values for partitioning the uboot partition to leave space for reserved1 and reserved2" PARTNUM=2 PARTLABEL="loader2" /sbin/sgdisk --print --new="${PARTNUM}":${UBOOT_START}:+"${UBOOT_SIZE}"MB "${TARGET}" /sbin/sgdisk --print --change-name="${PARTNUM}":"${PARTLABEL}" --typecode=${PARTNUM}:"${SD_GPT_UBOOT}" "${TARGET}" notice "Partition 3 of 6 - the 12MB partition for trust partition" PARTNUM=3 PARTLABEL="trust" /sbin/sgdisk --print --new="${PARTNUM}"::+"${TRUST_SIZE}"MB "${TARGET}" /sbin/sgdisk --print --change-name="${PARTNUM}":"${PARTLABEL}" --typecode="${PARTNUM}":"${SD_GPT_ATF}" "${TARGET}" notice "Partition 4 of 6 - the 16MB partition for EFI System Partition" PARTNUM=4 PARTLABEL="ESP" /sbin/sgdisk --print --new="${PARTNUM}"::+"${ESP_SIZE}"MB "${TARGET}" /sbin/sgdisk --print --change-name="${PARTNUM}":"${PARTLABEL}" --typecode="${PARTNUM}":"${SD_GPT_ESP}" "${TARGET}" notice "Partition 5 of 6 - the 16MB partition for bootfs" PARTNUM=5 PARTLABEL="boot" /sbin/sgdisk --print --new="${PARTNUM}"::+"${BOOT_SIZE}"MB "${TARGET}" /sbin/sgdisk --print --change-name="${PARTNUM}":"${PARTLABEL}" --typecode="${PARTNUM}":"${SD_GPT_BOOT}" "${TARGET}" /sbin/sgdisk --attribute="${PARTNUM}":=:"${SD_GPT_FLAG_LEGACY_BOOT}" ${TARGET} notice "Partition 6 of 6 - the main partition for root" PARTNUM=6 PARTLABEL="rootfs" /sbin/sgdisk --print --largest-new="${PARTNUM}" "${TARGET}" /sbin/sgdisk --print --change-name="${PARTNUM}":${PARTLABEL} --typecode="${PARTNUM}":${SD_GPT_ROOT_ARM64} "${TARGET}" /sbin/sgdisk --attribute="${PARTNUM}":=:"${SD_GPT_FLAG_GROWFS}" ${TARGET} /usr/bin/cgpt show "${TARGET}" } image_partition_disk_zfs() { fn image_partition_disk_zfs req=(strapdir disk_name esp_start esp_part_size swap_part_size boot_part_size available_disks) ckreq || return 1 # FIXME:Combine this and image_partitions_disk_gpt to use: # https://github.com/uapi-group/specifications/blob/main/specs/discoverable_partitions_specification.md # to iterate over the defined partions and apply the correct partition UUID based on target cpu. # the uuid variable are currently defined at the top of the rockpro64 board file. # Assign them to local variable using a case statement # (arch in amd64 arm64 armhf the TARGET="ARM64" TARGET="X86_64" TARGET="ARM32" etc.) # SD_GPT_ROOT=SD_GPT_ROOT_${TARGET} # SD_GPT_KERNEL=SD_GPT_KERNEL_${TARGET} # SD_GPT_USR=SD_GPT_USR_${TARGET} notice "partitioning disks" # See: https://didrocks.fr/2020/06/11/zfs-focus-on-ubuntu-20.04-lts-zsys-partition-layout/ for disk in "${available_disks[@]}"; do TARGET="/dev/disk/by-id/${disk}" act "partitioning ${TARGET}" /sbin/sgdisk --zap-all ${TARGET} act "Partition 1 - Create partition using start and end values for partitioning the 'Bios boot' partition." FIRST_USABLE_SECTOR=34 ((ENDSECTOR = ${esp_start} - 1)) /sbin/sgdisk --print --set-alignment=1 --new=1:${FIRST_USABLE_SECTOR}:${ENDSECTOR} ${TARGET} /sbin/sgdisk --print --change-name=1:"BIOS_Boot_Partition" --typecode=1:EF02 ${TARGET} act "Partition 2 - Create partition using start and end values for partitioning the 'EFI' partition." STARTSECTOR=${esp_start} /sbin/sgdisk --print --set-alignment=${STARTSECTOR} --mbrtogpt --new=2:${STARTSECTOR}:+${esp_part_size} ${TARGET} /sbin/sgdisk --print --change-name=2:"EFI_System_Partition" --typecode=2:EF00 ${TARGET} act "Partition 3 - Create partition using start and end values for partitioning the 'swap' partition." STARTSECTOR=`/sbin/sgdisk --first-in-largest ${TARGET}|sed -sn 2p` /sbin/sgdisk --print --new=3:${STARTSECTOR}:+${swap_part_size} ${TARGET} /sbin/sgdisk --print --change-name=3:"Linux_swap" --typecode=3:8200 ${TARGET} act "Partition 4 - upto 2GB partition for boot." STARTSECTOR=`/sbin/sgdisk --first-in-largest ${TARGET}|sed -sn 2p` /sbin/sgdisk --print --new=4:${STARTSECTOR}:+${boot_part_size} ${TARGET} /sbin/sgdisk --print --change-name=4:boot --typecode=4:BE00 ${TARGET} act "Partition 5 - the main partition for root." /sbin/sgdisk --print --largest-new=5 ${TARGET} /sbin/sgdisk --print --change-name=5:root --typecode=5:BF00 ${TARGET} act "Reread the current partition tables with partprobe." # the second drive fails to update the kernel until reboot so added 2> #partprobe ${TARGET} 2>/dev/null || true hdparm -z ${TARGET} done } image_format_partitions () { fn image_format_partitions "(override)" req=(bootfs bootpart rootpart) ckreq || return 1 notice "formatting partitions..." act "formatting boot partition." case "$bootfs" in (none) act "skipping boot partition" ;; (vfat | fat | dos) act "formatting boot as vfat" act "mkfs.vfat ${=bootopts} ${bootpart}" sudo mkfs.vfat ${=bootopts} ${bootpart} ;; (ext4) act "formatting boot as ext4" act "mkfs.ext4 -L linux-boot ${=bootopts} ${bootpart}" sudo mkfs.ext4 -L linux-boot ${=bootopts} ${bootpart} ;; (ext2) act "formating boot as ext2" act "mkfs.ext2 -L linux-boot ${=bootopts} ${bootpart}" sudo mkfs.ext2 -L linux-boot ${=bootopts} ${bootpart} ;; (*) error "unknown parted_bootfs type '$bootfs'" zerr ;; esac [[ -z "$rootfs" ]] && rootfs=ext4 act "formatting root partition." case "$rootfs" in (none) act "skipping root partition" ;; (vfat | fat | dos) act "formatting root as vfat" act "mkfs.vfat ${=rootopts} ${rootpart}" sudo mkfs.vfat ${=rootopts} ${rootpart} ;; (ext4) act "formatting root as ext4" act "mkfs.ext4 -L linux-root ${=rootopts} ${rootpart}" sudo mkfs.ext4 -L linux-root ${=rootopts} ${rootpart} ;; (ext2) act "formating root as ext2" act "mkfs.ext2 -L linux-root ${=rootopts} ${rootpart}" sudo mkfs.ext2 -L linux-root ${=rootopts} ${rootpart} ;; (btrfs) act "formatting root as btrfs" act "mfks.btrfs ${=rootopts} ${rootpart}" sudo mfks.btrfs ${=rootopts} ${rootpart} ;; (*) error "unknown parted_rootfs type '$rootfs'" zerr ;; esac if [[ -n $uefi ]]; then act "formatting efi system partition." act "mkfs.vfat ${=espopts} ${loopdevice}p${esp_part_number}" sudo mkfs.vfat ${=espopts} ${loopdevice}p${esp_part_number} fi } image_format_partitions_zfs() { fn image_format_partitions_zfs req=(disk_name available_disks esp_partitions swap_partitions root_part_number boot_part_number rpool_name bpool_name zpool_cache_dir strapdir) ckreq || return 1 act "format available esp partitions to vfat." for esp_partition in "${esp_partitions[@]}"; do act "format the esp partition to vfat." mkfs.fat -F32 ${esp_partition} done act "mkswap on available swap partitions." for swap_partition in "${swap_partitions[@]}"; do notice "making swap on ${swap_partition}" mkswap ${swap_partition} done notice "formatting zfs partitions..." for disk in "${available_disks[@]}"; do gdisk -l /dev/disk/by-id/${disk} done act "udev is slow recognize new partition so trigger sleep for 10 seconds" sleep 10 # create a separate boot pool for /boot with the features limited to only # those that GRUB supports allowing the root pool to use any/all features. if [[ ${raid} == "mirror" ]]; then mirror_disk=${available_disks[2]}; fi act "create the zfs boot pool" # Creating the bpool with limited features for grub compatibility so that # the rpool can becreated with any/all features. # # FIXME: is done using -o compatibility=grub2 now. # see: https://github.com/openzfs/zfs/tree/master/cmd/zpool/compatibility.d/grub2 # allocation_classes # async_destroy # block_cloning # bookmarks # device_rebuild # embedded_data # empty_bpobj # enabled_txg # extensible_dataset # filesystem_limits # hole_birth # large_blocks # livelist # log_spacemap # lz4_compress # project_quota # resilver_defer # spacemap_histogram # spacemap_v2 # userobj_accounting # zilsaxattr # zpool_checkpoint # #zpool create -f -m none \ zpool create -f \ -o cachefile=${zpool_cache_dir}/zpool.cache \ -o ashift=${ashift} -d \ -o feature@async_destroy=enabled \ -o feature@bookmarks=enabled \ -o feature@embedded_data=enabled \ -o feature@empty_bpobj=enabled \ -o feature@enabled_txg=enabled \ -o feature@extensible_dataset=enabled \ -o feature@filesystem_limits=enabled \ -o feature@hole_birth=enabled \ -o feature@large_blocks=enabled \ -o feature@lz4_compress=enabled \ -o feature@spacemap_histogram=enabled \ -o feature@zpool_checkpoint=enabled \ -O acltype=posixacl \ -O canmount=off \ -O compression=lz4 \ -O devices=off \ -O normalization=formD \ -O relatime=on \ -O xattr=sa \ -O mountpoint=legacy -o altroot=${strapdir} \ ${bpool_name} ${raid} /dev/disk/by-id/${disk_name}-part${boot_part_number} /dev/disk/by-id/${mirror_disk}-part${boot_part_number} act "create the zfs root pool" zpool create -f \ -o cachefile=${zpool_cache_dir}/zpool.cache \ -o ashift=${ashift} \ -O acltype=posixacl \ -O canmount=off \ -O compression=lz4 \ -O dnodesize=auto \ -O normalization=formD \ -O relatime=on \ -O xattr=sa \ -O mountpoint=/ -o altroot=${strapdir} \ ${rpool_name} ${raid} /dev/disk/by-id/${disk_name}-part${root_part_number} /dev/disk/by-id/${mirror_disk}-part${root_part_number} ## Physical swap used instead. # act "create the zfs zvol for swap" # zfs create -V ${swap_part_size} -b $(getconf PAGESIZE) \ # -o compression=zle \ # -o logbias=throughput \ # -o sync=always \ # -o primarycache=metadata \ # -o secondarycache=none \ # -o com.sun:auto-snapshot=false \ # ${rpool_name}/swap # mkswap -f -L "Linux swap" /dev/zvol/${rpool_name}/swap notice "zfs system installation" act "create filesystem datasets to act as containers" zfs create -o canmount=off -o mountpoint=none ${rpool_name}/ROOT zfs create -o canmount=off -o mountpoint=none ${bpool_name}/BOOT act "create filesystem datasets for the root and boot filesystems" # Create the initial boot environment and mount ${rpool_name} at /${rpool_name} zfs create -o canmount=noauto -o mountpoint=/ ${rpool_name}/ROOT/${root_name} zfs mount ${rpool_name}/ROOT/${root_name} #zfs create -o canmount=noauto -o mountpoint=/boot ${bpool_name}/BOOT/${root_name} zfs create -o mountpoint=/boot ${bpool_name}/BOOT/${root_name} ## At this point rpool directory is created in the workdir # zfs set mountpoint=/${rpool_name} ${rpool_name} TMP_EXEC_STATE=on VAR_TMP_EXEC_STATE=on notice "create datasets" act "create zfs datasets for $rpool_name" zfs create -o mountpoint=/home ${rpool_name}/home zfs create -o mountpoint=/root ${rpool_name}/home/root zfs create -o mountpoint=/space ${rpool_name}/space zfs create -o mountpoint=/opt ${rpool_name}/opt zfs create -o mountpoint=/srv ${rpool_name}/srv zfs create -o mountpoint=/usr \ -o canmount=off \ ${rpool_name}/usr zfs create -o mountpoint=/usr/share ${rpool_name}/usr/share zfs create -o mountpoint=/usr/local ${rpool_name}/usr/local zfs create -o mountpoint=/tmp \ -o setuid=off \ -o exec=${TMP_EXEC_STATE} \ -o com.sun:autosnapshot=false \ ${rpool_name}/tmp zfs create -o mountpoint=/var \ -o canmount=off \ ${rpool_name}/var zfs create -o mountpoint=/var/lib ${rpool_name}/var/lib zfs create -o mountpoint=/var/lib/virt ${rpool_name}/var/lib/virt zfs create -o mountpoint=/var/tmp \ -o setuid=off \ -o com.sun:auto-snapshot=false \ -o exec=${VAR_TMP_EXEC_STATE} \ ${rpool_name}/var/tmp zfs create -o mountpoint=/var/cache \ -o com.sun:auto-snapshot=false \ ${rpool_name}/var/cache zfs create \ -o mountpoint=/var/lib/docker \ -o com.sun:autosnapshot=false \ ${rpool_name}/docker zfs create -o mountpoint=/var/log ${rpool_name}/var/log zfs create -o mountpoint=/var/snap ${rpool_name}/var/snap zfs create -o mountpoint=/var/spool ${rpool_name}/var/spool zfs create -o mountpoint=/var/www ${rpool_name}/var/www zfs list -t all -o name,type,mountpoint,compress,exec,setuid,atime,relatime chmod 700 ${strapdir}/root chmod 1777 ${strapdir}/tmp #chmod 1777 ${strapdir}/var/tmp act "mount the efi partition on ${grub_mount} before debootstrap." mkdir -p ${strapdir}${grub_mount} mount /dev/disk/by-id/${disk_name}-part${esp_part_number} -t vfat ${strapdir}${grub_mount} act "create zpool cache file" mkdir -p ${strapdir}/etc/zfs cp ${zpool_cache_dir}/zpool.cache ${strapdir}/etc/zfs/ } use_swap_partition() { fn use_swap_partition req=(swap_partitions) ckreq || return 1 for swap_partition in "${swap_partitions[@]}"; do act "Using swapon on ${swap_partition}" swapon ${swap_partition} done } image_zfs_mount() { fn image_zfs_mount req=(strapdir disk_name rpool_name bpool_name grub_mount) ckreq || return 1 notice "image_zfs_mount" act "importing zfs pools without mounting the filesystem" zpool import -N -R ${strapdir} ${rpool_name} zpool import -N -R ${strapdir} ${bpool_name} if [[ -n $encrypt ]]; then act "loading encryption keys of ZFS datasets from imported pools" zfs load-key -a fi act "mounting zfs datasets" zfs mount -v ${rpool_name}/ROOT/${root_name} zfs mount -v ${bpool_name}/BOOT/${root_name} zfs mount -v -a act "mount esp partition to /boot/grub" mkdir -p ${strapdir}${grub_mount} mount /dev/disk/by-id/${disk_name}-part${esp_part_number} -t vfat ${strapdir}${grub_mount} act "mount system directories" devprocsys mount ${strapdir} } image_zfs_umount() { fn image_zfs_umount req=(workdir strapdir rpool_name bpool_name) ckreq || return 1 notice "umount system directories" devprocsys umount ${strapdir} act "reaping chroot processes" PREFIX=${strapdir} FOUND=0 reap() { for ROOT in /proc/*/root; do LINK=$(readlink $ROOT) if [[ "x${LINK}" != "x" ]]; then if [[ "x${LINK:0:${#PREFIX}}" = "x${PREFIX}" ]]; then PID=$(basename $(dirname "$ROOT")) act "this process is in the chroot... $PID" kill -9 "$PID" FOUND=1 fi fi done } reap if [[ "x$FOUND" = "x1" ]]; then reap fi act "umount esp partition" esp_path=/dev/disk/by-id/${disk_name}-part${esp_part_number} if [[ $(/bin/mountpoint -q -- ${esp_path}) ]]; then umount --lazy ${esp_path} fi act "umount zfs partitions" COUNT=0 while grep -q "$PREFIX" /proc/mounts; do COUNT=$(($COUNT+1)) if [ $COUNT -ge 20 ]; then echo "failed to umount $PREFIX" if [ -x /usr/bin/lsof ]; then /usr/bin/lsof "$PREFIX" fi exit 1 fi grep "$PREFIX" /proc/mounts | \ cut -d\ -f2 | LANG=C sort -r | xargs -r -n 1 umount || sleep 1 done act "export zfs pools." zpool export ${bpool_name} zpool export ${rpool_name} } get_selections() { fn get_selections req=(strapdir blend_release_path) ckreq || return 1 notice "generating package list files to ${blend_release_path}" pushd "${blend_release_path}" dpkg --get-selections > packages.list debconf-get-selections > debconf-settings.list update-alternatives --get-selections > /var/tmp/alternatives-settings.list /usr/bin/apt-mark showauto > pkgs_auto.lst /usr/bin/apt-mark showmanual > pkgs_manual.lst popd } set_selections() { fn set_selections req=(strapdir blend_release_path) ckreq || return 1 pushd "${blend_release_path}" notice "copying set selections related files to ${strapdir}/var/tmp" if [[ -f ./packages.list ]]; then cp ./packages.list ${strapdir}/var/tmp else act "no package.list found in ${blend_release_path} " exit 0 fi if [[ -f ./debconf-settings.list ]]; then cp ./debconf-settings.list ${strapdir}/var/tmp else act "no debconf-settings.list found in ${blend_release_path} " exit 0 fi if [[ -f ./alternatives-settings.list ]]; then cp ./alternatives-settings.list ${strapdir}/var/tmp else act "no alternatives-settings.list found in ${blend_release_path} " exit 0 fi if [[ -f ./pkgs_auto.lst ]]; then cp ./pkgs_auto.lst ${strapdir}/var/tmp else act "no pkgs_auto.lst found in ${blend_release_path}" fi if [[ -f ./pkgs_auto.lst ]]; then cp ./pkgs_manual.lst ${strapdir}/var/tmp else act "no pkgs_manual.lst found in ${blend_release_path}" fi popd notice "upgrading using dselect" cat <<-EOF | sudo tee "$strapdir/install-set-selections" >/dev/null #!/bin/sh dpkg --set-selections 2>&1 < /var/tmp/packages.list debconfig-set-selections 2>&1 < /var/tmp/debconf-settings.list update-alternatives --set-selections 2>&1 < /var/tmp/alternatives-settings.list apt-get -y -u dselect-upgrade if [[ -f /var/tmp/pkgs_auto.lst ]]; then apt-mark auto $(cat /var/tmp/pkgs_auto.lst) fi if [[ -f /var/tmp/pkgs_manual.lst ]]; then apt-mark manual $(cat /var/tmp/pkgs_manual.lst) fi EOF chroot-script -d install-set-selections || { zerr; return 1; } } enablessh() { fn enablessh req=(strapdir) ckreq || return 1 notice "enabling ssh access without password." act "Use ssh-copy-id default@192.168.1.x to login on reboot." act "adding or creating keys (place keys in /etc/ssh/ssh_host_rsa_key.pub)" cat <<-EOF | sudo tee "$strapdir/etc/rc.local" >/dev/null #!/bin/sh # rc.local for base images [ -f /etc/ssh/ssh_host_rsa_key.pub ] || ssh-keygen -A exit 0 EOF sudo chmod +x "$strapdir/etc/rc.local" cat <<-EOF | sudo tee "$strapdir/enablessh" >/dev/null #!/usr/bin/env zsh set -x ; exec 2>${PWD}/enablessh.log config_file="/etc/ssh/sshd_config" typeset -A rules rules=( "LoginGraceTime" "1m" "PermitRootLogin" "yes" "PasswordAuthentication" "no" "AllowUsers" "${username}" ) EOF cat <<-'EOF' | sudo tee -a "$strapdir/enablessh" >/dev/null for rule in "${(@k)rules}"; do regex="s/^#\?\(${rule}\s*\).*$/\1 ${rules[${rule}]}/" sed -i "${regex}" ${config_file}; done EOF chroot-script -d enablessh || { zerr; return 1; } } install_kernel_headers() { fn install_kernel_headers req=(strapdir kernel_version arch) ckreq || return 1 # could go in blends/devuan-desktop-live/config $extra_packages and # remove headers in blends/devuan-desktop-live/chimaera/config $purge_packages notice "install kernel headers" cat <<-EOF | sudo tee "$strapdir/install-kernel-headers" >/dev/null #!/bin/sh apt-get install -y linux-image-${kernel_version}-${arch} apt-get install -y linux-headers-${kernel_version}-${arch} apt-get -y -f install EOF chroot-script -d install-kernel-headers || { zerr; return 1; } } install_zfs() { fn install_zfs req=(strapdir rpool_name bpool_name root_name grubversion) ckreq || return 1 act "install zfs to the $strapdir" act "install the zfs packages in the correct order before dselect upgrade" cat <<-EOF | sudo tee "$strapdir/install-zfs" >/dev/null #!/bin/sh apt-get remove -y live-config && apt-get -y autoremove apt-get install -y dh-autoreconf apt-get install -y zfs-dkms zfs-initramfs zfs-zed zfsnap zfsutils-linux ${grubversion} busybox console-setup apt-get -y -f install # add nouveau graphics setting before updating initramfs: add to the grub commandline with update-initramfs -u # zfs_autoimport_disable is now compiled as set to 1/true by default # At module load 0=read zpool.cache 1=do not read zpool.cache #echo '# https://openzfs.github.io/openzfs-docs/Performance and Tuning/Module Parameters.html' > /etc/modprobe.d/zfs.conf #echo 'options zfs zfs_autoimport_disable=0' >> /etc/modprobe.d/zfs.conf echo 'options zfs l2arc_write_max=50331648' >> /etc/modprobe.d/zfs.conf echo 'options zfs l2arc_write_boost=100663296' >> /etc/modprobe.d/zfs.conf # Additional datasets to /etc/default/zfs not created under ROOT sed -i "s/#ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\"/" /etc/default/zfs # sed -i "s/ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\1 ${rpool_name}\/home\"/" /etc/default/zfs sed -i "s/ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\1 ${rpool_name}\/space\"/" /etc/default/zfs sed -i "s/ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\1 ${rpool_name}\/tmp\"/" /etc/default/zfs #sed -i "s/ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\1 ${rpool_name}\/ROOT\/${root_name}\/opt\"/" /etc/default/zfs #sed -i "s/ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\1 ${rpool_name}\/ROOT\/${root_name}\/usr_share\"/" /etc/default/zfs #sed -i "s/ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\1 ${rpool_name}\/ROOT\/${root_name}\/usr_local\"/" /etc/default/zfs #sed -i "s/ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\1 ${rpool_name}\/ROOT\/${root_name}\/var_lib\"/" /etc/default/zfs #sed -i "s/ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\1 ${rpool_name}\/ROOT\/${root_name}\/var_lib_docker\"/" /etc/default/zfs #sed -i "s/ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\1 ${rpool_name}\/ROOT\/${root_name}\/var_lib_virt\"/" /etc/default/zfs #sed -i "s/ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\1 ${rpool_name}\/ROOT\/${root_name}\/var_tmp\"/" /etc/default/zfs #sed -i "s/ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\1 ${rpool_name}\/ROOT\/${root_name}\/usr\"/" /etc/default/zfs #sed -i "s/ZFS_INITRD_ADDITIONAL_DATASETS=\"\(.*\)\"/ZFS_INITRD_ADDITIONAL_DATASETS=\"\1 ${rpool_name}\/ROOT\/${root_name}\/var\"/" /etc/default/zfs EOF chroot-script -d install-zfs || { zerr; return 1; } } install_grub_metal(){ fn install_grub_metal req=(strapdir disk_path disk_name esp_partitions swap_part_number rpool_name bpool_name root_name grub_mount grub_theme grub_gfxmode) ckreq || return 1 notice "installing grub." act "move the grub theme to the grub partition, stops 'update-alternatives desktop-grub-theme' from working." mkdir -p /boot/grub/grub-themes cp -a /usr/share/desktop-base/grub-themes/${grub_theme} /boot/grub/grub-themes/ act "replace the pool name detection with zdb command in /etc/grub.d/10_linux." sed -i "s|rpool=.*|rpool=\`zdb -l \${GRUB_DEVICE} \| grep -E '[[:blank:]]name' \| cut -d\\\' -f 2\`|" $strapdir/etc/grub.d/10_linux act "change the grub kernel commandline" cat <<-EOF | sudo tee "$strapdir/write-default-grub" >/dev/null #!/bin/sh set -x # GRUB_CMDLINE_LINUX_DEFAULT="quiet resume=/dev/zvol/rpool/swap radeon:modeset=1 i915:modeset=1 cgroup_enable=memory swapaccount=1 net.ifnames=0 # set boot filesystem - duplicated by grub but misses rpool_name when grub-probe fails to read filesystem type. sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"|GRUB_CMDLINE_LINUX_DEFAULT=\"\1 zfs=${rpool_name}\"|" /etc/default/grub # set swap as the resume partition. sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"|GRUB_CMDLINE_LINUX_DEFAULT=\"\1 resume=/dev/disk/by-id/${disk_name}-part${swap_part_number}\"|" /etc/default/grub # set root - Not needed as the kernel and root are set before /etc/default/grub is added #sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"|GRUB_CMDLINE_LINUX_DEFAULT=\"\1 root=ZFS=${rpool_name}\/ROOT\/${root_name}\"|" /etc/default/grub # init_on_alloc=1 is a security hardening mechanism preventing a class of security issues from being exploitable. # init_on_alloc=1 causes big performance regression for zfs: ubuntu +bug/1862822 sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"|GRUB_CMDLINE_LINUX_DEFAULT=\"\1 init_on_alloc=0\"|" /etc/default/grub # enable udev "info" logging for block devices sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"|GRUB_CMDLINE_LINUX_DEFAULT=\"\1 rd.log.block=info\"|" /etc/default/grub sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"|GRUB_CMDLINE_LINUX_DEFAULT=\"\1 cgroup_enable=memory\"|" /etc/default/grub sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"|GRUB_CMDLINE_LINUX_DEFAULT=\"\1 swapaccount=1\"|" /etc/default/grub sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"|GRUB_CMDLINE_LINUX_DEFAULT=\"\1 net.ifnames=0\"|" /etc/default/grub sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"|GRUB_CMDLINE_LINUX_DEFAULT=\"\1 nouveau.modeset=1\"|" /etc/default/grub #sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"|GRUB_CMDLINE_LINUX_DEFAULT=\"\1 i915.modeset=1\"|" /etc/default/grub #sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"|GRUB_CMDLINE_LINUX_DEFAULT=\"\1 radeon.modeset=1\"|" /etc/default/grub sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=\"\(.*\)\"|GRUB_CMDLINE_LINUX_DEFAULT=\"\1 noplymouth nosplash\"|" /etc/default/grub sed -i '/^#GRUB_DISABLE_LINUX_UUID=.*/ s/.*/&\nGRUB_DISABLE_LINUX_UUID=true/' /etc/default/grub sed -i '/^#GRUB_TIMEOUT=.*/ s/.*/&\nGRUB_RECORDFAIL_TIMEOUT=5/' /etc/default/grub #sed -i "s|^#GRUB_DISABLE_LINUX_UUID=\"\(.*\)\"|GRUB_DISABLE_LINUX_UUID=\"\1 true\"|" /etc/default/grub echo "" >> /etc/default/grub echo "# Preload modules so that they are not missed." >> /etc/default/grub echo "GRUB_PRELOAD_MODULES=part_gpt" >> /etc/default/grub sed -i "s|^\(GRUB_GFXMODE=\).*|\1\"$grub_gfxmode\"|" /etc/default/grub sed -i '/^GRUB_GFXMODE=.*/ s/.*/&\nGRUB_GFXPAYLOAD_LINUX=\"keep\"/' /etc/default/grub sed -i "s|^\(GRUB_THEME=\).&|\1\"/boot/grub/grub-themes/${grub_theme}/theme.txt\"|" /etc/default/grub # debug grub sed -i "s/quiet//" /etc/default/grub #sed -i "s/#GRUB_TERMINAL/GRUB_TERMINAL/" /etc/default/grub EOF chroot-script -d write-default-grub || { zerr; return 1; } #umount -q ${strapdir}${grub_mount} if [[ -v $efi ]]; then mkdir -p ${grub_mount} act "write grub-efi to available esp partitions." for esp_partition in "${esp_partitions[@]}"; do notice "writing to efi partitions: ${esp_partitions}" act "mount the primary disks efi partition under ${grub_mount}" mount ${disk_path}/${disk_name}-part${esp_part_number} ${strapdir}${grub_mount} cat <<-EOF | sudo tee ${strapdir}/update-grub_${disk_name} > /dev/null #!/bin/sh echo "populate the ${grub_mount} with update-grub." grub-mkconfig -o ${grub_mount}/grub.cfg echo "install grub to disk name ${disk_name}, efi partition ${esp_partition}" grub-install --target=${grub_efi_target} \ --no-uefi-secure-boot \ --efi-directory=${grub_mount} \ --bootloader-id="Devuan ${release} (RAID disk ${disk_name})" --recheck \ --no-floppy EOF chroot-script -d update-grub_${disk_name} || { zerr; return 1; } umount ${strapdir}${grub_mount} done else mkdir -p ${grub_mount} for disk_name in "${available_disks[@]}"; do notice "writing grub to available disks:" act "mount the primary disks efi partition under ${grub_mount}" mount ${disk_path}/${disk_name}-part${esp_part_number} ${strapdir}${grub_mount} cat <<-EOF | sudo tee ${strapdir}/update-grub_${disk_name} > /dev/null #!/bin/sh echo "populate the ${grub_mount} with update-grub." grub-mkconfig -o ${grub_mount}/grub.cfg echo "install grub-pc to ${disk_name}" grub-install --target=i386-pc /dev/disk/by-id/${disk_name} EOF chroot-script -d update-grub_${disk_name} || { zerr; return 1; } umount ${strapdir}${grub_mount} done fi } install_grub_arm(){ fn install_grub_arm req=(strapdir disk_path disk_name efi_partitions swap_part_number root_name grub_mount grub_theme grub_gfxmode) ckreq || return 1 notice "installing grub." act "move the grub theme to the grub partition, stops 'update-alternatives desktop-grub-theme' from working." mkdir -p /boot/grub/grub-themes cp -a /usr/share/desktop-base/grub-themes/${grub_theme} /boot/grub/grub-themes/ #umount -q ${strapdir}${grub_mount} if [[ -v $efi ]]; then mkdir -p ${grub_mount} act "write grub-efi to available efi partitions." for efi_partition in "${efi_partitions[@]}"; do notice "writing to efi partitions: ${efi_partitions}" act "mount the primary disks efi partition under ${grub_mount}" mount ${disk_path}/${disk_name}-part${efi_part_number} ${strapdir}${grub_mount} cat <<-EOF | sudo tee ${strapdir}/update-grub_${disk_name} > /dev/null #!/bin/sh echo "populate the ${grub_mount} with update-grub." grub-mkconfig -o ${grub_mount}/grub.cfg echo "install grub to disk name ${disk_name}, efi partition ${efi_partition}" grub-install --target=${grub_efi_target} \ --${secure_boot} \ --efi-directory=${grub_mount} \ --bootloader-id="Devuan ${release} (RAID disk ${disk_name})" --recheck \ --no-floppy EOF chroot-script -d update-grub_${disk_name} || { zerr; return 1; } umount ${strapdir}${grub_mount} done else mkdir -p ${grub_mount} for disk_name in "${available_disks[@]}"; do notice "writing grub to available disks:" act "mount the primary disks efi partition under ${grub_mount}" mount ${disk_path}/${disk_name}-part${efi_part_number} ${strapdir}${grub_mount} cat <<-EOF | sudo tee ${strapdir}/update-grub_${disk_name} > /dev/null #!/bin/sh echo "populate the ${grub_mount} with update-grub." grub-mkconfig -o ${grub_mount}/grub.cfg echo "install grub-pc to ${disk_name}" grub-install --target=i386-pc /dev/disk/by-id/${disk_name} EOF chroot-script -d update-grub_${disk_name} || { zerr; return 1; } umount ${strapdir}${grub_mount} done fi } fun() { fn fun "(override)" req=() ckreq || return 1 } update_package() { fn update_package req=(strapdir) ckreq || return 1 # Get the package name from the function arguments local package_name="$1" local package_options="$2" notice "Updating ${package_name}" # Create a script to update the apt package list cat <<-EOF | sudo tee "${strapdir}/update-apt-before-upgrade" #!/bin/bash apt-get update EOF chroot-script -d update-apt-before-upgrade || zerr # Get the policy output for the package # local package_policy_output package_policy_output=$(chroot "${strapdir}" apt-cache policy "$package_name") package_madison_output=$(chroot "${strapdir}" apt-cache madison "$package_name") # Get the candidate version of the package # debian_package_candidate_version="$(echo "${package_policy_output}" | grep Candidate | grep -o "[[:digit:].-~]*")" debian_package_candidate_version="$(echo "${package_policy_output}" | grep Candidate | sed 's/: /:/' | awk '{split($0,a,":"); print a[2]}')" act "update_package: debian_package_candidate_version set to ${debian_package_candidate_version}" # Get the installed version of the package # debian_package_installed_version="$(echo "${package_policy_output}" | grep Installed | grep -o "[[:digit:].-~+]*")" debian_package_installed_version="$(echo "${package_policy_output}" | grep Installed | sed 's/: /:/' | awk '{split($0,a,":"); print a[2]}')" act "update_package: debian_package_installed_version set to ${debian_package_installed_version}" # Check if any extra repositories are enabled # set extra repos in blend/config eg apt_extra_repos+=("${release}-backports" "experimental") if [[ -n "${apt_extra_repos[*]}" ]]; then for repo in "${apt_extra_repos[@]}"; do # debian_package_extra_version="$(echo "${package_policy_output}" | grep -B1 "$repo/contrib" | grep -o "[[:digit:].-~+]*" | sed -n '1p')" debian_package_extra_version="$(echo "${package_madison_output}" | grep "$repo/contrib" | sed 's/| /|/' | awk '{split($0,a,"|"); print a[2]}')" if dpkg --compare-versions "${debian_package_candidate_version}" lt "${debian_package_extra_version}"; then debian_package_candidate_version="${debian_package_extra_version}" act "update_package:extra_repo: debian_package_candidate_version set to ${debian_package_candidate_version}" fi done # If a newer extra repo version is available, install it if dpkg --compare-versions "${debian_package_candidate_version}" ne "${debian_package_installed_version}"; then cat <<-EOF | sudo tee "${strapdir}/update-package-with-apt_extra" #!/bin/bash apt-get install -y "${package_options}" -t "${apt_extra_repos}" "${package_name}" apt-get --yes ${force_packages_option} autoremove EOF chroot-script -d update-package-with-apt_extra || zerr fi else # If a newer version is available, install it if dpkg --compare-versions "${debian_package_candidate_version}" ne "${debian_package_installed_version}"; then cat <<-EOF | sudo tee "${strapdir}/update-package-with-apt" #!/bin/bash apt-get install -y "${package_options}" "${package_name}" apt-get --yes ${force_packages_option} autoremove EOF chroot-script -d update-package-with-apt || zerr fi fi # we will have installed the candidate version so we are echoing the # installed version here. # echo "${debian_package_candidate_version}" } # FIXME: split the updating of debian packages from the setting of kernel # versions and zfs versions for building from source in the boards file # rockpro64_ayufan.sh zsh versions don't alway support avaiable kernels so we # discover the latest zfs version available and install it and return the latest # kernel it supports. The setting of gitbranch needs to be done with the strapdir # available so the call to get_supported_kernel_version has been moved to the # build_kernel function. set_zfs_supported_kernel_version() { # Sometimes the zfs-dkms will not install a locally built kernel so we pull # the version that ships with debian. # update to the latest version of zfs-dkms # update_package "zfs-dkms" "--download-only" # debian_zfs_installed_version="$(echo "${package_policy_output}" | grep Installed | sed 's/: /:/' | awk '{split($0,a,":"); print a[2]}')" # act "get_zfs_supported_kernel_version: debian_zfs_installed_version set to ${debian_zfs_installed_version}" # zfs_version="zfs-${debian_zfs_installed_version%%-*}" # act "get_zfs_supported_kernel_version: zfs_version set to ${zfs_version}" # Unpack only # chroot $strapdir dpkg --unpack --no-triggers /var/cache/apt/archives/zfs-dkms_${debian_zfs_installed_version}_all.deb # zfs_autoinstall_set "no" # turn back on in finalize # update_package "linux-image-arm64" # update_package "linux-headers-arm64" # meta_url="https://raw.githubusercontent.com/openzfs/zfs/${zfs_version}/META" # kernel_series="$(curl -sS "${meta_url}" | awk '$1 == "Linux-Maximum:" { print $2; exit }')" # act "get_zfs_supported_kernel_version: kernel_series set to ${kernel_series}" # gitbranch="$(lastversion --format=tag --only "${kernel_series}" gregkh/linux)" # act "get_zfs_supported_kernel_version: gitbranch set to ${gitbranch}" } # when build from source outside the choot this is the location of the dkms.mkconf # used to population the zfs-dkms sources in /usr/src # $R/tmp/kernels/rockpro64/zfs-upstream_${zfs_version}/scripts/dkms.mkconf zfs_autoinstall_set() { fn zfs_autoinstall_set req=(strapdir zfs_version) ckreq || return 1 local desired_state="no" local current_state="$(sudo chroot ${strapdir} bash -c "grep -oP '^AUTOINSTALL=\"\Kyes|no' /usr/src/"${zfs_version}"/dkms.conf | head -1")" if [[ -n $1 ]]; then desired_state=${1} fi sudo chroot ${strapdir} bash -c "sed -i 's/^AUTOINSTALL=\"${current_state}\"/AUTOINSTALL=\"${desired_state}\"/' /usr/src/"${zfs_version}"/dkms.conf" } dkms_on(){ fn dkms_on req=(strapdir) ckreq || return 1 if [[ -n $1 ]]; then local kversion=${1} || { zerr; return 1; } else act "This function must be called with the kernel version." fi if [[ -n $2 ]]; then local module_name=${2} || { zerr; return 1; } else act "This function must be called with the dkms module." fi notice "Turning zfs-dkms on for ${kversion}. This does not build the kernel module." act "Add zfs-dkms to DKMS." cat <<-EOF | sudo tee "${strapdir}/dkms_${module_name}-on_${kversion}" dkms add -m ${module_name} -v ${kversion} EOF chroot-script -d dkms_${module_name}-on_${kversion} || zerr } dkms_on_all(){ fn dkms_on_all req=(strapdir) ckreq || return 1 if [[ -n $1 ]]; then local module_name=${1} || { zerr; return 1; } else act "This function must be called with the dkms module." fi notice "Turning ${module_name}-dkms on for all kernel versions. This does not build the kernel module." act "Add zfs-dkms to DKMS." cat <<-EOF | sudo tee "${strapdir}/dkms_${module_name}-on_all" dkms add -m ${module_name} --all EOF chroot-script -d dkms_${module_name}-on_all || zerr } dkms_off(){ fn dkms_off req=(strapdir) ckreq || return 1 if [[ -n $1 ]]; then local kversion=${1} || { zerr; return 1; } else act "This function must be called with the kernel version." fi if [[ -n $2 ]]; then local module_name=${2} || { zerr; return 1; } else act "This function must be called with the dkms module." fi notice "Turning ${module_name}-dkms off for ${kversions}." act "Remove ${dkms_module}-dkms from DKMS." cat <<-EOF | sudo tee "${strapdir}/dkms_${module_name}-off_${kversion}" dkms remove -m ${module_name} -v ${kversion} EOF chroot-script -d dkms_${module_name}-off_${kversion} || zerr } dkms_off_all(){ fn dkms_off_all req=(strapdir) ckreq || return 1 if [[ -n $1 ]]; then local module_name=${1} || { zerr; return 1; } else act "This function must be called with the dkms module." fi notice "Turning ${module_name}-dkms off for all kernel versions." act "Remove ${module_name}-dkms from DKMS." cat <<-EOF | sudo tee "${strapdir}/dkms_${module_name}-off_all" dkms remove -m ${module_name} --all EOF chroot-script -d dkms_${module_name}-off_${kversion} || zerr } # Use the environment variables directly for zfs-dkms build. dkms_build_zfs(){ fn dkms_build_zfs req=(strapdir zfs_version kernel_version kernel_version_build local_version) ckreq || return 1 local module_name="zfs" || { zerr; return 1; } local module_version=${zfs_version} || { zerr; return 1; } local kversion=${kernel_version}${local_version} || { zerr; return 1; } # dkms build -m zfs -v 2.2.2 -k 6.6.10-arm64-devuan # dkms build -m zfs -v ${zfs_version} -k ${kernel_version}-${local_version} notice "Building the ${module_name}-dkms module for kernel version ${kversion}." act "Build and install ${module_name}-dkms." cat <<-EOF | sudo tee "${strapdir}/dkms_build_${module_name}_${module_version}_${kversion}" dkms build -m ${module_name} -v ${module_version} -k ${kversion} dkms install -m ${module_name} -v ${module_version} -k ${kversion} EOF chroot-script -d dkms_build_${module_name}_${module_version}_${kversion} || zerr } dkms_build(){ fn dkms_build req=(strapdir ) ckreq || return 1 if [[ -n $1 ]]; then local module_name=${1} || { zerr; return 1; } else act "This function must be called with the module name." fi if [[ -n $2 ]]; then local module_version=${2} || { zerr; return 1; } else act "This function must be called with the dkms module version." fi if [[ -n $3 ]]; then local kversion=${3} || { zerr; return 1; } else act "This function must be called with the kernel version found in /lib/modules." fi # dkms build -m zfs -v 2.2.2 -k 6.6.10-arm64-devuan # dkms build -m zfs -v ${zfs_version} -k ${kernel_version}-${local_version} # dkms_build zfs ${zfs_version} ${kernel_version}-${local_version} notice "Building the ${module_name}-dkms module for kernel version ${kversion}." act "Build and install ${module_name}-dkms." cat <<-EOF | sudo tee "${strapdir}/dkms_build_${module_name}_${modules_version}_${kversion}" dkms build -m ${module_name} -v ${module-version} -k ${kversion} dkms install -m ${module_name} -v ${module-version} -k ${kversion} EOF chroot-script -d dkms_build_${module_name}_${modules_version}_${kversion} || zerr } dkms_build_all(){ fn dkms_build_all req=(strapdir) ckreq || return 1 if [[ -n $1 ]]; then local module_name=${1} || { zerr; return 1; } else act "This function must be called with the dkms module name." fi if [[ -n $2 ]]; then local module_version=${2} || { zerr; return 1; } else act "This function must be called with the dkms module version." fi notice "Building the ${module_name}-dkms ${module_version} kernel module for all kernel versions." act "Build and install zfs-dkms." cat <<-EOF | sudo tee "${strapdir}/build_${module_name}_dkms_all" dkms build -m ${module_name} -v ${module_version}--all dkms install -m ${module_name} -v ${module_version} --all EOF chroot-script -d build_${module_name}_dkms_all || zerr } # schroot related helper functions, see the blends sysconf_schroot populate_schroot_custom_config() { fn populate_schroot_custom_config req=(schroot_config schroot_dir) ckreq || return 1 notice "Creating schroot config: ${schroot_dir}/${schroot_config}" mkdir -p ${schroot_dir}/${schroot_config}/chroot.d conf_print_schroot_fstab | sudo tee ${schroot_dir}/${schroot_config}/fstab >/dev/null conf_print_schroot_copyfiles | sudo tee ${scroot_dir}/${schroot_config}/copyfiles >/dev/null conf_print_schroot_nssdatabases | sudo tee ${schroot_dir}/${schroot_config}/nssdatabases >/dev/null conf_print_schroot_config | sudo tee ${schroot_dir}/${schroot_config}/config >/dev/null } remove_schroot_entry() { fn remove_schroot_entry req=(release arch) ckreq || return 1 sudo rm ${schroot_dir}/chroot.d/${release}_${arch} } remove_schroot_config_dir() { fn remove_schroot_config_dir req=(schroot_config schroot_dir) ckreq || return 1 sudo rm -r ${chroot_dir}/${schroot_config} } create_sbuild_chroot() { fn create_sbuild_chroot req=(release arch mirror) ckreq || return 1 chroot_dir="/srv/chroot/${release}" mkdir -p ${chroot_dir} sbuild-createchroot \ --arch=${arch} \ --include=debhelper,eatmydata \ --chroot-mode=schroot \ --components=main contrib non-free \ ${release} \ ${chroot_dir} \ ${mirror} } remove_sbuild_chroot() { fn remove_sbuild_chroot req=(release arch mirror) ckreq || return 1 chroot_dir="/srv/chroot/${release}" rm -rf ${chroot_dir} # Remove the schroot configuration config_file="${schroot_dir}/chroot.d/${release}-${arch}-sbuild-*" sudo rm ${config_file} } create_sbuild_zfs_chroot() { fn create_sbuild_chroot req=(release arch mirror) ckreq || return 1 zfs_snapshot="rpool/CHROOT/${release}" zfs snapshot ${zfs_snapshot}@initial zfs create ${zfs_snapshot} sbuild-createchroot \ --arch=${arch} \ --include=debhelper,eatmydata \ --chroot-mode=schroot \ --components=main contrib non-free \ ${release} \ ${zfs_snapshot} \ ${mirror} } remove_sbuild_chroot() { fn remove_sbuild_chroot req=(release arch mirror) ckreq || return 1 chroot_dir="/srv/chroot/${release}" rm -rf ${chroot_dir} # Remove the schroot configuration config_file="${schroot_dir}/chroot.d/${release}-${arch}-sbuild-*" sudo rm ${config_file} } remove_sbuild_zfs_chroot() { fn remove_sbuild_zfs_chroot req=(release arch mirror) ckreq || return 1 zfs_snapshot="rpool/CHROOT/${release}" zfs destroy ${zfs_snapshot} # Remove the schroot configuration config_file="${schroot_dir}/chroot.d/${release}-${arch}-sbuild-*" sudo rm ${config_file} } create_sbuild_btrfs_chroot() { fn create_sbuild_btrfs_chroot req=(release arch mirror) ckreq || return 1 btrfs_subvolume="/mnt/mybtrfs/CHROOT/${release}" mkdir -p ${btrfs_subvolume} btrfs subvolume create ${btrfs_subvolume} sbuild-createchroot \ --arch=${arch} \ --include=debhelper,eatmydata \ --chroot-mode=schroot \ --components=main contrib non-free \ ${release} \ ${btrfs_subvolume} \ ${mirror} } remove_sbuild_btrfs_chroot() { fn remove_sbuild_btrfs_chroot req=(release arch mirror) ckreq || return 1 btrfs_subvolume="/mnt/mybtrfs/CHROOT/${release}" btrfs subvolume delete ${btrfs_subvolume} # Remove the schroot configuration config_file="${schroot_dir}/chroot.d/${release}-${arch}-sbuild-*" sudo rm ${config_file} }