added rpi-lvm-imager
This commit is contained in:
39
README.md
39
README.md
@@ -6,9 +6,9 @@ are of any benefit to other enthusiasts. Use them freely and please let me know
|
|||||||
in case you encounter any issues or require changes.
|
in case you encounter any issues or require changes.
|
||||||
|
|
||||||
The latest versions, documentation and bugtracker available on my
|
The latest versions, documentation and bugtracker available on my
|
||||||
[GitLab instance](https://gitlab.lindenaar.net/scripts/raspberrypi)
|
[Gitea instance](https://gitea.lindenaar.net/scripts/raspberrypi)
|
||||||
|
|
||||||
Copyright (c) 2019 Frederik Lindenaar. free for distribution under
|
Copyright (c) 2019 - 2025 Frederik Lindenaar. free for distribution under
|
||||||
the GNU General Public License, see [below](#license)
|
the GNU General Public License, see [below](#license)
|
||||||
|
|
||||||
Contents
|
Contents
|
||||||
@@ -24,6 +24,8 @@ This repository contains the following scripts:
|
|||||||
is a systemd service to disable on-board WiFi on Raspberry Pi at boot
|
is a systemd service to disable on-board WiFi on Raspberry Pi at boot
|
||||||
* [rpi_poweroff_button.service](#services)
|
* [rpi_poweroff_button.service](#services)
|
||||||
is a systemd service to support a power-off button using [gpio_trigger.py](#gpio_trigger)
|
is a systemd service to support a power-off button using [gpio_trigger.py](#gpio_trigger)
|
||||||
|
* [rpi-lvm-imager.sh](#rpi-lvm-imager)
|
||||||
|
initialize an NVME drive with Raspberry Pi OS (Lite) on LVM
|
||||||
|
|
||||||
|
|
||||||
<a name=gpio_trigger>gpio_trigger.py</a>
|
<a name=gpio_trigger>gpio_trigger.py</a>
|
||||||
@@ -94,6 +96,37 @@ systemctl disable service <<filename without .service>>
|
|||||||
~~~
|
~~~
|
||||||
|
|
||||||
|
|
||||||
|
<a name=rpi-lvm-imager>rpi-lvm-imager.sh</a>
|
||||||
|
--------------------------------------------
|
||||||
|
This script will wipe and partition a (large) storage device with a small boot
|
||||||
|
partition, setup LVM for the rest of the disk, and then writes the latest
|
||||||
|
version of Raspbian Pi OS (Lite) or another OS image availabile via the
|
||||||
|
Raspberry Pi Imager to LVM managed partition(s) and makes the device bootable.
|
||||||
|
|
||||||
|
The reason I worte this script was that the Raspberry Pi Imager can only write
|
||||||
|
an image to a full disk and does not allow one to partition it nor perform the
|
||||||
|
installation on an LVM managed disk. This was needed for a Raspberry Pi 5 with
|
||||||
|
NVME SSD as the device had way more diskspace than would ever be needed/useful
|
||||||
|
for the system partition.
|
||||||
|
|
||||||
|
This script was inspired by the write-up found [here](https://raspberrypi.stackexchange.com/questions/7159/can-the-raspberry-boot-to-an-lvm-root-partition).
|
||||||
|
That was apparently superseded by [this approach](https://raspberrypi.stackexchange.com/questions/85958/easy-backups-and-snapshots-of-a-running-system-with-lvm),
|
||||||
|
hoever, I like the initial approach more. This script will write the OS to a
|
||||||
|
device after setting up LVM but before booting it so it is just quicker than
|
||||||
|
writing the OS and then moving it to an LVM managed partition.
|
||||||
|
|
||||||
|
To write the latest version of Raspberry Pi OS (64bit Lite) to an NVME SSD
|
||||||
|
device simply run:
|
||||||
|
|
||||||
|
~~~
|
||||||
|
sudo rpi-lvm-imager.sh --lvm-group nvme /dev/nvme0n1
|
||||||
|
~~~
|
||||||
|
|
||||||
|
Please note that this will unmound and wipe the specified device so be careful!
|
||||||
|
|
||||||
|
to see all aailable options, run: `./rpi-lvm-imager.sh -h`
|
||||||
|
|
||||||
|
|
||||||
<a name="license">License</a>
|
<a name="license">License</a>
|
||||||
-----------------------------
|
-----------------------------
|
||||||
These scripts, documentation & configration examples are free software: you can
|
These scripts, documentation & configration examples are free software: you can
|
||||||
@@ -107,4 +140,4 @@ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|||||||
General Public License for more details.
|
General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
You should have received a copy of the GNU General Public License along with
|
||||||
this program. If not, download it from <http://www.gnu.org/licenses/>.
|
this program. If not, download it from <http://www.gnu.org/licenses/>.
|
||||||
|
|||||||
417
rpi-lvm-imager.sh
Executable file
417
rpi-lvm-imager.sh
Executable file
@@ -0,0 +1,417 @@
|
|||||||
|
#! /bin/bash -e
|
||||||
|
|
||||||
|
#
|
||||||
|
# rpi-lvm-imager.sh - initialize NVME with Raspberry Pi OS (Lite) on LVM
|
||||||
|
#
|
||||||
|
# Version 1.0, latest version, documentation and bugtracker available at:
|
||||||
|
# https://gitea.lindenaar.net/scripts/raspberrypi
|
||||||
|
#
|
||||||
|
# Copyright (c) 2025 Frederik Lindenaar
|
||||||
|
#
|
||||||
|
# This script is free software: you can redistribute and/or modify it under the
|
||||||
|
# terms of version 3 of the GNU General Public License as published by the Free
|
||||||
|
# Software Foundation, or (at your option) any later version of the license.
|
||||||
|
#
|
||||||
|
# This script 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 program. If not, visit <http://www.gnu.org/licenses/> to download it.
|
||||||
|
#
|
||||||
|
|
||||||
|
# Inspired by: https://raspberrypi.stackexchange.com/questions/7159/can-the-raspberry-boot-to-an-lvm-root-partition
|
||||||
|
|
||||||
|
# Fetch the list of Raspberry Pi OS images, if required, and flatten it
|
||||||
|
# next return the url to download the specified image or list of images
|
||||||
|
PIOS_LIST_DOWNLOAD_URL=https://downloads.raspberrypi.com/os_list_imagingutility_v4.json
|
||||||
|
get_raspios() {
|
||||||
|
# Download the Raspberry Pi Imager catalog (if a newer version exists)
|
||||||
|
wget --quiet --timestamping --directory-prefix "${WORKDIR}" "${PIOS_LIST_DOWNLOAD_URL}"
|
||||||
|
RPI_IMAGER_CONFIG="${WORKDIR}/$(basename "${PIOS_LIST_DOWNLOAD_URL}" )"
|
||||||
|
|
||||||
|
# Extract and flatten the list of entries, if required
|
||||||
|
PIOS_LIST_FILE="${WORKDIR}/os_list.json"
|
||||||
|
if [ "${RPI_IMAGER_CONFIG}" -nt "${PIOS_LIST_FILE}" ]; then
|
||||||
|
jq '.os_list
|
||||||
|
| map(select( .url ))
|
||||||
|
+ map(select( .subitems ).subitems
|
||||||
|
| map(select( .url ))
|
||||||
|
+ map(select( .subitems ).subitems
|
||||||
|
| map(select( .url ))
|
||||||
|
+ map(select( .subitems ).subitems
|
||||||
|
| map(select( .url ))
|
||||||
|
+ map(select( .subitems ).subitems)
|
||||||
|
| flatten)
|
||||||
|
| flatten)
|
||||||
|
| flatten)
|
||||||
|
| flatten' "${RPI_IMAGER_CONFIG}" > "${PIOS_LIST_FILE}"
|
||||||
|
if fgrep -q '"subitems"' "${PIOS_LIST_FILE}"; then
|
||||||
|
echo >&2 Warning: structure of the Raspberry Pi Imager catalog has changed
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$1" -o "$1" = list ]; then
|
||||||
|
jq --raw-output "map(.name ) | .[]" "${PIOS_LIST_FILE}" | sort -u
|
||||||
|
else
|
||||||
|
echo $(jq --raw-output "map(select( .name == \"${1}\"))[0] | .url,.extract_size,.extract_sha256" "${PIOS_LIST_FILE}")
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# defaults for command line options
|
||||||
|
opt_raspios_lite=true
|
||||||
|
opt_raspios_bits=64
|
||||||
|
opt_raspios_image=
|
||||||
|
opt_raspios_checksum=
|
||||||
|
opt_check_image_checksum=true
|
||||||
|
opt_raspios_checksum=
|
||||||
|
opt_lvm_group_name=
|
||||||
|
opt_lvm_size=+
|
||||||
|
opt_boot_size=
|
||||||
|
opt_root_size=16G
|
||||||
|
opt_lvm_partitions=
|
||||||
|
opt_nvme_pcie_gen3=false
|
||||||
|
|
||||||
|
# parse command line parameters
|
||||||
|
while [ $# -gt 0 ]
|
||||||
|
do
|
||||||
|
case "$1" in
|
||||||
|
-h|--help) cat << EOT
|
||||||
|
Raspberry Pi LVM Imager - write Raspberry Pi OS image to an LVM-enabled device
|
||||||
|
|
||||||
|
Usage: $(baesename $0) [options] device
|
||||||
|
|
||||||
|
Where <<options>> can be one or more of:
|
||||||
|
|
||||||
|
-h, --help show this help and exit
|
||||||
|
|
||||||
|
-l, --list-images output the list of available Raspberry Pi images and exit
|
||||||
|
-L, --lite install Raspberry Pi OS Lite (default)
|
||||||
|
-R, --regular install the regular Raspberry Pi OS (with destktop)
|
||||||
|
-6, --64bit install a 64-bit version of Raspberry Pi OS
|
||||||
|
-3, --32bit install a 32-bit version of Raspberry Pi OS
|
||||||
|
-i, --image-name name of the image to install
|
||||||
|
-U, --url provide the download URL for Raspberry Pi OS
|
||||||
|
see https://www.raspberrypi.com/software/operating-systems
|
||||||
|
-C, --checksum provide sha256 checksum of image
|
||||||
|
-n, --no-checksum disable checking the sha256 checksum of the downloaded image
|
||||||
|
|
||||||
|
-g, --lvm-group name of the LVM volume group to create (required and must not exist!)
|
||||||
|
-s, --lvm-size size of the LVM volume group to create (defaults to the rest of the disk)
|
||||||
|
-b, --boot-size size of the boot filesystem (defaults to the size in the image)
|
||||||
|
-r, --root-size size of the root filesystem (defaults to 16G)
|
||||||
|
-p, --lvm-partition comma separated /path:size list to move to separate LVMs
|
||||||
|
|
||||||
|
-P, --nvme-pcie-gen3 enable PCIe Gen 3 mode for the NVMe
|
||||||
|
|
||||||
|
-w, --workdir (persistent) work directory to store files, not cleaned up
|
||||||
|
EOT
|
||||||
|
exit
|
||||||
|
;;
|
||||||
|
-l|--list-images) opt_raspios_image=list
|
||||||
|
;;
|
||||||
|
-i|--image-name) opt_raspios_image="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-L|--lite) opt_raspios_lite=true
|
||||||
|
;;
|
||||||
|
-R|--regular) opt_raspios_lite=false
|
||||||
|
;;
|
||||||
|
-3|--32-bit) opt_raspios_bits=32
|
||||||
|
;;
|
||||||
|
-6|--64-bit) opt_raspios_bits=64
|
||||||
|
;;
|
||||||
|
-U|--url) IMAGE_DOWNLOAD_URL="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-C|--checksum) opt_raspios_checksum="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-n|--no-checksum) opt_check_image_checksum=false
|
||||||
|
;;
|
||||||
|
-g|--lvm-group) opt_lvm_group_name="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-s|--lvm-size) opt_lvm_size="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-b|--boot-size) opt_boot_size="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-r|--root-size) opt_root_size="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-p|--lvm-partition) opt_lvm_partitions="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-P|--nvme-pcie-gen3) opt_nvme_pcie_gen3=true
|
||||||
|
;;
|
||||||
|
-w|--workdir) WORKDIR="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-*) echo Error: unknown option $1, run $0 -h for supported options
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
*) if [ -z "$opt_target_device" ]; then
|
||||||
|
opt_target_device=$1
|
||||||
|
else
|
||||||
|
echo Error: only one device is supported, run $0 -h for usage
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
# Ensure the script is run as root
|
||||||
|
if [ $(id -u) -gt 0 ]; then
|
||||||
|
echo "Error: $(basename $0) must be run as root"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure cleanup is done when we exist, irrespective how
|
||||||
|
cleanup() {
|
||||||
|
echo cleaning up
|
||||||
|
# Unmount the partitions under the rootfs in reverse order
|
||||||
|
if [ -n "${TARGET_ROOT_MOUNTPOINT}" ]; then
|
||||||
|
findmnt --raw --noheadings --output target --submounts "${TARGET_ROOT_MOUNTPOINT}" | sort -r | while read mountpoint
|
||||||
|
do
|
||||||
|
umount "${mountpoint}"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Unmount the image from the loopback when it was mounted
|
||||||
|
if [ -n "$RASPIOS_DEV" ]; then
|
||||||
|
losetup --detach ${RASPIOS_DEV}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove the temporary working directory (if created)
|
||||||
|
if [ -n "$TEMPDIR" ]; then
|
||||||
|
rm -rf $TEMPDIR
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
# Create a temporary working directory, if required
|
||||||
|
if [ -z "$WORKDIR" ]; then
|
||||||
|
TEMPDIR=$(mktemp --directory --tmpdir $(basename $0 .sh).XXXXXXXX)
|
||||||
|
WORKDIR=${TEMPDIR}
|
||||||
|
elif [ ! -d "${WORKDIR}" ]; then
|
||||||
|
mkdir "${WORKDIR}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If we need to print the list of available images, print it and exit
|
||||||
|
if [ "${opt_raspios_image}" = "list" ]; then
|
||||||
|
get_raspios list
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure the target is a valid disk
|
||||||
|
if [ -z "${opt_target_device}" ]; then
|
||||||
|
echo Error: target device is required, run $0 -h for usage
|
||||||
|
exit 2
|
||||||
|
elif [ "$(lsblk --nodeps --noheadings ${opt_target_device} -o type)" != "disk" ]; then
|
||||||
|
echo Error: target device ${opt_target_device} is not a disk
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure no partitions of the target device are still mounted
|
||||||
|
if [ -n "$(findmnt -D| fgrep "${opt_target_device}")" ]; then
|
||||||
|
echo Error: partitions of target device ${opt_target_device} are still mounted:
|
||||||
|
findmnt -D | egrep "^SOURCE|${opt_target_device}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure the LVM group (if one is to be setup) is provided and does not exist yet
|
||||||
|
if [ -z "${opt_lvm_group_name}" ]; then
|
||||||
|
echo Error: target LVM volume group name is required, run $0 -h for usage
|
||||||
|
exit 2
|
||||||
|
elif [ -n "${opt_lvm_group_name}" -a -n "$(pvdisplay --columns --options pv_name,vg_name --noheading | egrep "${opt_lvm_group_name}|${opt_target_device}")" ]; then
|
||||||
|
echo Existing LVM configuration found, cleaning up conflicting setup
|
||||||
|
TTY=$(tty)
|
||||||
|
pvdisplay --columns --options pv_name,vg_name --noheading | while read dev vg
|
||||||
|
do
|
||||||
|
if [ "${vg}" = "${opt_lvm_group_name}" ]; then
|
||||||
|
wipefs --quiet --all /dev/${vg}/*
|
||||||
|
vgremove --quiet ${vg} < ${TTY}
|
||||||
|
fi
|
||||||
|
if [[ "${dev}" == ${opt_target_device}* ]]; then
|
||||||
|
if ! [ "${vg}" != "${opt_lvm_group_name}" ] || vgreduce --quiet ${vg} ${dev} < ${TTY}; then
|
||||||
|
pvremove --quiet ${dev} < ${TTY}
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
lvm_dev=
|
||||||
|
|
||||||
|
# Ensure the partition table of the taget device is empty
|
||||||
|
if [ "$(sudo sfdisk --dump "${opt_target_device}" 2>/dev/null )" ]; then
|
||||||
|
echo Warning: target device ${opt_target_device} may contain data:
|
||||||
|
sfdisk --quiet --list "${opt_target_device}"
|
||||||
|
|
||||||
|
echo
|
||||||
|
read -p "erase everything and image ${opt_target_device}? (yes/no) [no]"
|
||||||
|
if [ "${REPLY}" != "yes" ]; then
|
||||||
|
echo Aborted.
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo Erasing data on "${opt_target_device}"
|
||||||
|
wipefs --quiet --all ${opt_target_device}*
|
||||||
|
sfdisk --quiet --wipe always --wipe-partitions always --delete "${opt_target_device}" && echo OK || echo NOK
|
||||||
|
# dd if=/dev/zero "of=${opt_target_device}" bs=512 count=1 2> /dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo partitioning target disk
|
||||||
|
echo 'label: dos' | sfdisk --quiet "${opt_target_device}"
|
||||||
|
|
||||||
|
# Ensure a Raspberry Pi OS download URL and local image name are set
|
||||||
|
if [ -z "${IMAGE_DOWNLOAD_URL}" ]; then
|
||||||
|
if [ -z "${opt_raspios_image}" ]; then
|
||||||
|
if ${opt_raspios_lite}; then
|
||||||
|
opt_raspios_image="Raspberry Pi OS Lite (${opt_raspios_bits}-bit)"
|
||||||
|
else
|
||||||
|
opt_raspios_image="Raspberry Pi OS (${opt_raspios_bits}-bit)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
read IMAGE_DOWNLOAD_URL IMAGE_EXTRACT_SIZE IMAGE_EXTRACT_SHA256 <<< $(get_raspios "${opt_raspios_image}")
|
||||||
|
if [ -z "${IMAGE_DOWNLOAD_URL}" -o "${IMAGE_DOWNLOAD_URL}" = "null" ]; then
|
||||||
|
echo "Error: no URL found for image name '${opt_raspios_image}'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
RASPIOS_IMG="${WORKDIR}/$(basename "${IMAGE_DOWNLOAD_URL}" .xz)"
|
||||||
|
|
||||||
|
# Download the image, if required, and/or verify its checksum (if possible)
|
||||||
|
if [ ! -f "${RASPIOS_IMG}" -o -n "${IMAGE_EXTRACT_SIZE}" -a "$(du -b "${RASPIOS_IMG}" 2>/dev/null | sed "s/[^0-9].*//")" != "${IMAGE_EXTRACT_SIZE}" ]; then
|
||||||
|
if $opt_check_image_checksum && [ -n "${opt_raspios_checksum:-$IMAGE_EXTRACT_SHA256}" ]; then
|
||||||
|
echo "${opt_raspios_checksum:-$IMAGE_EXTRACT_SHA256} -" > "${RASPIOS_IMG}.$$.sha256sum"
|
||||||
|
if ! wget --quiet --show-progress --output-document - "${IMAGE_DOWNLOAD_URL}" | xz --decompress | tee ${RASPIOS_IMG} | sha256sum --check --strict --quiet "${RASPIOS_IMG}.$$.sha256sum"; then
|
||||||
|
echo Error: downloading, extracting and verifying the image failed
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
rm ${RASPIOS_IMG}.*.sha256sum
|
||||||
|
else
|
||||||
|
if ! wget --quiet --show-progress --output-document - "${IMAGE_DOWNLOAD_URL}" | xz --decompress > ${RASPIOS_IMG}; then
|
||||||
|
echo Error: downloading the image failed
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
elif $opt_check_image_checksum && [ -n "${opt_raspios_checksum:-$IMAGE_EXTRACT_SHA256}" ]; then
|
||||||
|
if ! echo "${opt_raspios_checksum:-$IMAGE_EXTRACT_SHA256} ${RASPIOS_IMG}" | sha256sum --check --strict --quiet; then
|
||||||
|
echo Error: image checksum does not match with the Raspberry Pi catalog
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Mount the image as a loopback device and get it's device name
|
||||||
|
RASPIOS_DEV=$(losetup --find --show --partscan --read-only ${RASPIOS_IMG} )
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
# Get the partition sizes of the image
|
||||||
|
TTY=$(tty)
|
||||||
|
sfdisk --dump ${RASPIOS_DEV} | egrep "^/" | sed -E "s/[:,][^=]+=/ /g; s/ +/ /g" | while read part start size type
|
||||||
|
do
|
||||||
|
label=$(lsblk "${part}" --noheadings --output label)
|
||||||
|
echo Found $label partition $part with $start $size and type $type
|
||||||
|
|
||||||
|
if [ "${type}" = 'c' ]; then
|
||||||
|
echo ",${size},${type}" | sfdisk --quiet --append --wipe always --wipe-partition always "${opt_target_device}"
|
||||||
|
target_part=$(sfdisk --dump "${opt_target_device}" | tail -1 | cut -f1 -d\ )
|
||||||
|
elif [ "${type}" = '83' ]; then
|
||||||
|
if [ -z "${lvm_dev}" ]; then
|
||||||
|
echo ",${opt_lvm_size},8e" | sfdisk --quiet --append --wipe always "${opt_target_device}" 2>/dev/null
|
||||||
|
lvm_dev="$(sfdisk --dump "${opt_target_device}" | tail -1 | cut -f1 -d\ )"
|
||||||
|
pvcreate --quiet "${lvm_dev}"
|
||||||
|
vgcreate --quiet "${opt_lvm_group_name}" "${lvm_dev}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
lvcreate --name "${label}" --size "${opt_root_size}" --wipesignatures y "${opt_lvm_group_name}" <$TTY
|
||||||
|
target_part="/dev/${opt_lvm_group_name}/${label}"
|
||||||
|
|
||||||
|
else
|
||||||
|
echo Error: image contains unsupported partition ${part} with type 0x$type
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo Copying $label to ${target_part}
|
||||||
|
dd if=${part} of=$target_part 2>/dev/null
|
||||||
|
done
|
||||||
|
|
||||||
|
echo Setting up the root filesystem for its initial boot
|
||||||
|
|
||||||
|
TARGET_BOOTFS_DEV=$(lsblk --raw --noheadings --output path,label "${opt_target_device}" | fgrep bootfs | cut -d\ -f1)
|
||||||
|
TARGET_ROOTFS_DEV=$(lsblk --raw --noheadings --output path,label "${opt_target_device}" | fgrep rootfs | cut -d\ -f1)
|
||||||
|
|
||||||
|
# Mount the new root filesystem for post-processing
|
||||||
|
TARGET_ROOT_MOUNTPOINT="${WORKDIR}/rootfs"
|
||||||
|
echo mount "${filesystems[rootfs]}" "${TARGET_ROOT_MOUNTPOINT}"
|
||||||
|
mount -o noatime "${TARGET_ROOTFS_DEV}" "${TARGET_ROOT_MOUNTPOINT}"
|
||||||
|
mount "${TARGET_BOOTFS_DEV}" "${TARGET_ROOT_MOUNTPOINT}/boot/firmware"
|
||||||
|
mount -t proc /proc "${TARGET_ROOT_MOUNTPOINT}/proc"
|
||||||
|
mount -o bind /dev "${TARGET_ROOT_MOUNTPOINT}/dev"
|
||||||
|
mount -o bind /dev/pts "${TARGET_ROOT_MOUNTPOINT}/dev/pts"
|
||||||
|
mount -t sysfs /sys "${TARGET_ROOT_MOUNTPOINT}/sys"
|
||||||
|
|
||||||
|
# patch /boot/firmware/config.txt so tat it contains the correct root filesystem
|
||||||
|
sed -Ei "s|root=[^ \t]+|root=${TARGET_ROOTFS_DEV}|" "${TARGET_ROOT_MOUNTPOINT}/boot/firmware/cmdline.txt"
|
||||||
|
|
||||||
|
# patch /etc/fstab so that it contains the right devices
|
||||||
|
sed -Ei "s|^[^# \t]+([ \t]+/boot/firmware[ \t])|${TARGET_BOOTFS_DEV}\1|" "${TARGET_ROOT_MOUNTPOINT}/etc/fstab"
|
||||||
|
sed -Ei "s|^[^# \t]+([ \t]+/[ \t])|${TARGET_ROOTFS_DEV}\1|" "${TARGET_ROOT_MOUNTPOINT}/etc/fstab"
|
||||||
|
|
||||||
|
# move filesystems to separate LVMs and ensure these are automaticaly mounted
|
||||||
|
for p in ${opt_lvm_partitions//,/ }
|
||||||
|
do
|
||||||
|
IFS=: read path size <<< "${p}"
|
||||||
|
lvname=${path//*\//}fs
|
||||||
|
echo moving ${path} to a LVM ${lvmname} of ${size}
|
||||||
|
|
||||||
|
lvcreate --name "${lvname}" --size "${size}" --wipesignatures y "${opt_lvm_group_name}" <$TTY
|
||||||
|
lvpath=$(lsblk --raw --noheadings --output path,label "${opt_target_device}" | fgrep "${lvname}" | cut -d\ -f1)
|
||||||
|
mke2fs -L "${lvname}" "${lvpath}"
|
||||||
|
|
||||||
|
if ! [ -d "${TARGET_ROOT_MOUNTPOINT}${path}" ]; then
|
||||||
|
echo Error: direcory ${vpath} does not exist in the target environment
|
||||||
|
exit 1
|
||||||
|
# mkdir "${TARGET_ROOT_MOUNTPOINT}/${path}"
|
||||||
|
else
|
||||||
|
mount "${lvpath}" "${TARGET_ROOT_MOUNTPOINT}/mnt"
|
||||||
|
chroot "${TARGET_ROOT_MOUNTPOINT}" rsync -aAXH "${path}/" "/mnt/"
|
||||||
|
umount "${TARGET_ROOT_MOUNTPOINT}/mnt"
|
||||||
|
chroot "${TARGET_ROOT_MOUNTPOINT}" bash -c "rm -rf ${path}/* ${path}/.*"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if egrep -Eq "^[^# \t]+[ \t]+${path}[ \t]" "${TARGET_ROOT_MOUNTPOINT}/etc/fstab" ; then
|
||||||
|
sed -Ei "s|^[^# \t]+([ \t]+${path}[ \t])|${lvpath}\1|" "${TARGET_ROOT_MOUNTPOINT}/etc/fstab"
|
||||||
|
else
|
||||||
|
echo "${lvpath} ${path} ext4 defaults,noatime 0 2" >> "${TARGET_ROOT_MOUNTPOINT}/etc/fstab"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mount "${lvpath}" "${TARGET_ROOT_MOUNTPOINT}${path}"
|
||||||
|
done
|
||||||
|
|
||||||
|
cat "${TARGET_ROOT_MOUNTPOINT}/etc/fstab"
|
||||||
|
|
||||||
|
# install required packages for things to work
|
||||||
|
chroot "${TARGET_ROOT_MOUNTPOINT}" apt install lvm2
|
||||||
|
|
||||||
|
# generate password
|
||||||
|
# openssl passwd -6
|
||||||
|
|
||||||
|
# setup initial (defaultt) user
|
||||||
|
echo 'jfl:$6$EyEFwTRqBv16ws7j$/5qABGo7Bm3p44mml1/LmFp9b/VdkCURRHNsGxl9YOC3IdzZ7N5LdYFOF5nZjGFQONWGgwjBBIn.JGhGNdnP70' > "${TARGET_ROOT_MOUNTPOINT}/boot/firmware/userconf"
|
||||||
|
|
||||||
|
# enable SSH
|
||||||
|
touch "${TARGET_ROOT_MOUNTPOINT}/boot/firmware/ssh"
|
||||||
|
|
||||||
|
# Enable PCIe Gen 3 for NVMe, if requested
|
||||||
|
if ${opt_nvme_pcie_gen3}; then
|
||||||
|
if ! egrep -q "^\s*dtparam\s*=\s*pciex1_gen\s*=" "${TARGET_ROOT_MOUNTPOINT}/boot/firmware/config.txt"; then
|
||||||
|
echo dtparam=pciex1_gen=3 >> "${TARGET_ROOT_MOUNTPOINT}/boot/firmware/config.txt"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo Done!
|
||||||
Reference in New Issue
Block a user