live-metal/blend_helpers

1058 lines
35 KiB
Bash

#!/usr/bin/env zsh
# shellcheck shell=bash
# Copyright (c) 2016-2021 Ivan J. <parazyd@dyne.org>
# 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 <http://www.gnu.org/licenses/>.
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-wrapper || { zerr; wrapup }
blend_preinst || { zerr; wrapup }
blend_postinst || { zerr; wrapup }
}
build_image_dist() {
fn build_image_dist
req=(arch size parted_type)
case "$parted_type" in
gpt) req+=(gpt_boot gpt_root) ;;
dos) req+=(parted_boot parted_root) ;;
*) die "Unknown parted_type: $parted_type. Supported is gpt|dos."
zerr; return 1
;;
esac
req+=(workdir strapdir image_name)
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_arm_dist()
{
fn build_arm_dist
req=(workdir strapdir os arch size parted_type)
case "$parted_type" in
gpt) req+=(gpt_boot gpt_root) ;;
dos) req+=(parted_boot parted_root) ;;
*) die "Unknown parted_type: $parted_type. Supported is gpt|dos."
zerr; return 1
;;
esac
ckreq || return 1
notice "Building complete Arm image(s)"
bootstrap_complete_base-wrapper || { zerr; return 1; }
blend_preinst || { zerr; return 1; }
image_prepare_raw || { zerr; return 1; }
image_connect_raw || { zerr; return 1; }
image_partition_raw_${parted_type} || { zerr; return 1; }
image_format_partitions || { zerr; return 1; }
build_kernel_${arch} || { zerr; return 1; }
image_mount || { zerr; return 1; }
strapdir_to_image || { zerr; return 1; }
blend_postinst || { zerr; return 1; }
image_umount || { zerr; return 1; }
image_disconnect_raw || { zerr; return 1; }
image_pack_dist || { zerr; return 1; }
clean_strapdir || { zerr; return 1; }
}
copy-root-overlay() {
fn copy-root-overlay "(override)"
req=(strapdir device_name bootpart_partuuid R)
ckreq || return 1
[[ -d $R/extra/generic-root ]] &&
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"
[[ -d $R/extra/$device_name ]] && \
notice "copying ${device_name}-root" && \
sudo cp -rfv $R/extra/$device_name/* $strapdir
return 0
}
# 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
}
# the local bootstrap wrapper just adds an options variable
# via an alias to the debootstrap command
bootstrap_complete_base-wrapper() {
mkdir -p "$debootstrap_cache"
alias debootstrap='debootstrap \
--cache-dir="$debootstrap_cache" \
--exclude="$debootstrap_purge_packages" \
${debootstrap_options}'
bootstrap_complete_base
}
image_partition_raw_gpt() {
fn image_partition_raw_gpt
req=(workdir image_name gpt_boot gpt_root bootpart_partuuid rootpart_partuuid)
ckreq || return 1
notice "partitioning raw gpt image..."
notice "workdir: $workdir"
notice "image_name: $image_name"
notice "gpt_boot: $gpt_boot"
notice "gpt_root: $gpt_root"
parted $workdir/${image_name}.img --script -- mklabel gpt || zerr
cgpt repair $workdir/${image_name}.img
cgpt create -z $workdir/${image_name}.img || zerr
cgpt create $workdir/${image_name}.img || zerr
notice 'cgpt add -i 1 -t kernel -b ${gpt_boot[1]} \
-s ${gpt_boot[2]} \
-l kernel -S 1 -T 5 -P 10 $workdir/${image_name}.img'
notice "cgpt add -i 1 -t kernel -b ${gpt_boot[1]} \
-s ${gpt_boot[2]} \
-l kernel -S 1 -T 5 -P 10 $workdir/${image_name}.img"
cgpt add -i 1 -t kernel -b ${gpt_boot[1]} \
-s ${gpt_boot[2]} \
-l kernel -S 1 -T 5 -P 10 $workdir/${image_name}.img
notice 'cgpt add -i 2 -t data -b ${gpt_root[1]} \
-s $(expr $(cgpt show $workdir/${image_name}.img | \
awk "/Sec GPT table/ {print $1}") - ${gpt_root[1]}) \
-l Root $workdir/${image_name}.img'
notice "cgpt add -i 2 -t data -b ${gpt_root[1]} \
-s $(expr $(cgpt show $workdir/${image_name}.img | \
awk '/Sec GPT table/ {print $1}') - ${gpt_root[1]}) \
-l Root $workdir/${image_name}.img"
cgpt add -i 2 -t data -b ${gpt_root[1]} \
-s $(expr $(cgpt show $workdir/${image_name}.img | \
awk '/Sec GPT table/ {print $1}') - ${gpt_root[1]}) \
-l Root $workdir/${image_name}.img
findloopdev
bootpart="${loopdevice}p1"
rootpart="${loopdevice}p2"
bootpart_partuuid=$(blkid -s PARTUUID -o value ${bootpart})
rootpart_partuuid=$(blkid -s PARTUUID -o value ${rootpart})
image_format_partitions
}
## 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-yes -f install
cd /
apt-get --yes --force-yes autoremove
#rm -rf /debs
EOF
chroot-script -d install-debs
}
## 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-yes -f install
cd /
apt-get --yes --force-yes autoremove
#rm -rf /var/tmp/automate
EOF
chroot-script -d install-scripts
}
copy-kernel-config() {
fn copy-kernel-config "(override)"
req=(device_name gitbranch)
ckreq || return 1
notice "copying available ${gitbranch} kernel config for ${device_name}"
notice "cp -f $R/boards/kernel-configs/${device_name}.config_${gitbranch} \
$R/tmp/kernels/$device_name/${device_name}-linux_$gitbranch/.config"
cp -f $R/boards/kernel-configs/${device_name}.config_${gitbranch} \
$R/tmp/kernels/$device_name/${device_name}-linux_$gitbranch/.config
}
## Override the helper function:
# Allow an alternative skel directory, defaults to /etc/skel
add-user() {
fn add-user
req=(strapdir username userpass user_shell)
ckreq || return 1
notice "adding user $user:$pass using $skel and shell $default_shell"
cat <<-EOF | sudo tee ${strapdir}/add-user >/dev/null
#!/bin/sh
set -x
if [ $(id -u ${username} 2>&1 >/dev/null) ]; then
echo "user not present, creating account."
sudo useradd --create-home \
--shell $usershell \
--groups $usergroups \
--password $(openssl passwd -1 $userpass) \
--skel ${user_skel:-/etc/skel} \
$username
echo "${username}:${userpass}" | chpasswd
usermod -a -G ${user_groups} ${username}
if grep -q "${user_shell}" /etc/shells; then
usermod --shell "${user_shell}" "${username}"
else
echo "${user_shell} is not available, leaving unchanged."
fi
fi
EOF
chroot-script add-user || { zerr; 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 "$*"
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}
}
image_partition_disk_zfs() {
fn image_partition_disk_zfs
req=(strapdir disk_name efi_start efi_part_size swap_part_size boot_part_size available_disks)
ckreq || return 1
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
local 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 = ${efi_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=${efi_start}
/sbin/sgdisk --print --set-alignment=${STARTSECTOR} --mbrtogpt --new=2:${STARTSECTOR}:+${efi_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
#partx --update ${TARGET}
#kpartx -a ${TARGET}
#hdparm -z ${TARGET}
#blockdev --rereadept ${TARGET}
#udevadm trigger --subsystem-match=block; udevadm settle --exit-if-exists=/dev/${TARGET}-part5
#echo 1 > /sys/block/sdX/device/rescan
done
}
image_format_partitions_zfs() {
fn image_format_partitions_zfs
req=(disk_name available_disks efi_partitions swap_partitions root_part_number boot_part_number rpool_name bpool_name zpool_cache_dir strapdir)
ckreq || return 1
act "format available efi partitions to vfat."
for efi_partition in "${efi_partitions[@]}"; do
act "format the efi partition to vfat."
mkfs.fat -F32 ${efi_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 recognizing new partitions 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"
#zpool create -f -m none \
zpool create -f \
-o cachefile=${zpool_cache_dir}/zpool.cache \
-o ashift=${ashift} \
-o autotrim=on \
-o compatibility=grub2 \
-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} \
-O recordsize=128K \
${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 ${rpool_name}/DATA
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
# Split docker data from images
zfs create \
-o mountpoint=/var/lib/docker \
-o com.sun:autosnapshot=false \
${rpool_name}/docker
zfs create \
-o mountpoint=/var/lib/docker/volumes \
${rpool_name}/DATA/docker-volumes
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${efi_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 efi partition to /boot/grub"
mkdir -p ${strapdir}${grub_mount}
mount /dev/disk/by-id/${disk_name}-part${efi_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 efi partition"
efi_path=/dev/disk/by-id/${disk_name}-part${efi_part_number}
if [[ $(/bin/mountpoint -q -- ${efi_path}) ]]; then
umount --lazy ${efi_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 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(){
fn install_grub
req=(strapdir disk_name efi_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 efi partitions."
for efi_partition in "${efi_partitions[@]}"; do
notice "writing to efi partitions: ${efi_partitions}"
if ! /bin/mountpoint -q "${strapdir}${grub_mount}"; then
act "mount the primary disks efi partition under ${grub_mount}"
mount ${disk_path}/${disk_name}-part${efi_part_number} ${strapdir}${grub_mount}
else
notice "the mountpoint ${grub_mount} already in use. Skipping mount operation."
fi
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} \
--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}
act "write grub to available efi partitions."
for disk_name in "${available_disks[@]}"; do
notice "writing grub to available ${disk_name}:"
if ! /bin/mountpoint -q "${strapdir}${grub_mount}"; then
act "mount the primary disks efi partition under ${grub_mount}"
mount ${disk_path}/${disk_name}-part${efi_part_number} ${strapdir}${grub_mount}
else
notice "The mount point ${grub_mount} is already in use. Skipping mount operation."
fi
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
}
dpkg-version() {
fn dpkg--version
req=(R strapdir)
ckreq || return 1
chroot-script bash -c "dpkg-query --show --showformat "\${Version}\n" dpkg"
}
apt-version() {
fn apt-version
req=(R strapdir)
ckreq || return 1
chroot-script bash -c "dpkg-query --show --showformat "\${Version}\n" apt"
}
#-----------
#zfs specific commands can be seen in the boot loader prompt using
# UBOOT #help
#
# zfsls - list files in a directory (default /)
# zfsload- load binary file from a ZFS file system
#
#2. To list the files in zfs pool, device or partition, execute
# zfsls <interface> <dev[:part]> [POOL/@/dir/file]
# For example:
# UBOOT #zfsls mmc 0:5 /rpool/@/usr/bin/
#
#3. To read and load a file from an ZFS formatted partition to RAM, execute
# zfsload <interface> <dev[:part]> [addr] [filename] [bytes]
# For example:
# UBOOT #zfsload mmc 2:2 0x30007fc0 /rpool/@/boot/uImage
#: