<message>Add a new step-by-step guide for deploying the CM4 eMMC provisioning service on a new Proxmox instance, enhancing clarity for users. Update existing documentation to reflect changes in network configuration options, including the introduction of LAN subnet settings for DHCP and TFTP. Modify cloud-init scripts to ensure proper management of DNS settings and improve the handling of network interfaces. Additionally, enhance the toggle script for network boot to dynamically read the LAN gateway from configuration files, streamlining the setup process and improving user experience.
131 lines
3.9 KiB
Bash
Executable File
131 lines
3.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Mount a Raspberry Pi OS .img or .img.xz, edit cloud-init NoCloud files on the boot
|
|
# partition, then unmount and (if .img.xz) recompress. Requires sudo for loop/mount.
|
|
#
|
|
# Usage:
|
|
# ./edit-cloudinit-on-image.sh <path-to-image.img.xz>
|
|
# ./edit-cloudinit-on-image.sh <path-to-image.img>
|
|
#
|
|
# Options:
|
|
# --no-recompress If image was .img.xz, leave decompressed .img and do not overwrite
|
|
# --replace-with-repo Copy user-data, meta-data, network-config from repo before editing
|
|
#
|
|
# Example:
|
|
# ./edit-cloudinit-on-image.sh /path/to/gnss-bootstrap-20260223-215010.img.xz
|
|
#
|
|
# Backup the image before running if you want to keep the original.
|
|
|
|
set -e
|
|
|
|
REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
CLOUDINIT_SRC="$REPO_ROOT/emmc-provisioning/cloud-init"
|
|
NO_RECOMPRESS=""
|
|
REPLACE_WITH_REPO=""
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--no-recompress) NO_RECOMPRESS=1; shift ;;
|
|
--replace-with-repo) REPLACE_WITH_REPO=1; shift ;;
|
|
-*) echo "Unknown option: $1"; exit 1 ;;
|
|
*) break ;;
|
|
esac
|
|
done
|
|
|
|
IMAGE_IN="$1"
|
|
[[ -n "$IMAGE_IN" && -f "$IMAGE_IN" ]] || {
|
|
echo "Usage: $0 [--no-recompress] [--replace-with-repo] <path-to-image.img.xz|.img>"
|
|
echo "Example: $0 gnss-bootstrap-20260223-215010.img.xz"
|
|
exit 1
|
|
}
|
|
|
|
IMAGE_IN="$(realpath "$IMAGE_IN")"
|
|
WORK_DIR=""
|
|
IMG_FILE=""
|
|
ORIGINAL_XZ=""
|
|
cleanup() {
|
|
if [[ -n "$MNT" && -d "$MNT" ]]; then
|
|
sudo umount "$MNT" 2>/dev/null || true
|
|
fi
|
|
if [[ -n "$LOOP" && -b "$LOOP" ]]; then
|
|
sudo losetup -d "$LOOP" 2>/dev/null || true
|
|
fi
|
|
if [[ -n "$WORK_DIR" && -d "$WORK_DIR" ]]; then
|
|
if [[ -n "$NO_RECOMPRESS" && -n "$ORIGINAL_XZ" ]]; then
|
|
echo "Work dir left at: $WORK_DIR"
|
|
else
|
|
rm -rf "$WORK_DIR"
|
|
fi
|
|
fi
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
if [[ "$IMAGE_IN" == *.img.xz ]]; then
|
|
ORIGINAL_XZ="$IMAGE_IN"
|
|
echo "Decompressing $(basename "$ORIGINAL_XZ") (this may take a minute and needs ~3GB free)…"
|
|
WORK_DIR=$(mktemp -d -p "${TMPDIR:-/tmp}" edit-cloudinit.XXXXXX)
|
|
IMG_FILE="$WORK_DIR/image.img"
|
|
xz -T 0 -d -k -f -c "$ORIGINAL_XZ" > "$IMG_FILE"
|
|
else
|
|
WORK_DIR=$(mktemp -d -p "${TMPDIR:-/tmp}" edit-cloudinit.XXXXXX)
|
|
IMG_FILE="$IMAGE_IN"
|
|
fi
|
|
|
|
echo "Attaching image and mounting boot partition…"
|
|
LOOP=$(sudo losetup -f --show -P "$IMG_FILE")
|
|
# Force kernel to scan partition table so /dev/loopNp1, p2 etc. appear
|
|
sudo partprobe "$LOOP" 2>/dev/null || true
|
|
sleep 0.5
|
|
boot_part="${LOOP}p1"
|
|
[[ -b "$boot_part" ]] || boot_part="${LOOP}p2"
|
|
[[ -b "$boot_part" ]] || {
|
|
echo "Boot partition not found on image. Partitions on image:"
|
|
ls -la "${LOOP}"p* 2>/dev/null || true
|
|
sudo fdisk -l "$IMG_FILE" 2>/dev/null || true
|
|
exit 1
|
|
}
|
|
|
|
MNT="$WORK_DIR/mnt"
|
|
mkdir -p "$MNT"
|
|
sudo mount "$boot_part" "$MNT"
|
|
|
|
if [[ -n "$REPLACE_WITH_REPO" && -d "$CLOUDINIT_SRC" ]]; then
|
|
echo "Copying cloud-init files from repo into boot partition…"
|
|
for f in user-data meta-data network-config; do
|
|
if [[ -f "$CLOUDINIT_SRC/$f" ]]; then
|
|
sudo cp "$CLOUDINIT_SRC/$f" "$MNT/$f"
|
|
elif [[ -f "$CLOUDINIT_SRC/$f.bootstrap" ]]; then
|
|
sudo cp "$CLOUDINIT_SRC/$f.bootstrap" "$MNT/$f"
|
|
fi
|
|
done
|
|
fi
|
|
|
|
echo ""
|
|
echo "Boot partition is mounted at: $MNT"
|
|
echo "Cloud-init files to edit:"
|
|
echo " $MNT/user-data"
|
|
echo " $MNT/meta-data"
|
|
echo " $MNT/network-config"
|
|
echo ""
|
|
EDITOR="${EDITOR:-nano}"
|
|
echo "Opening editor ($EDITOR). Save and exit when done."
|
|
read -r -p "Press Enter to open $EDITOR on these files…"
|
|
sudo "$EDITOR" "$MNT/user-data" "$MNT/meta-data" "$MNT/network-config"
|
|
|
|
echo "Unmounting…"
|
|
sudo umount "$MNT"
|
|
MNT=""
|
|
sudo losetup -d "$LOOP"
|
|
LOOP=""
|
|
|
|
if [[ -n "$ORIGINAL_XZ" && -z "$NO_RECOMPRESS" ]]; then
|
|
echo "Recompressing to $(basename "$ORIGINAL_XZ")…"
|
|
xz -T 0 -z -f -k "$IMG_FILE"
|
|
mv -f "${IMG_FILE}.xz" "$ORIGINAL_XZ"
|
|
echo "Done. Updated: $ORIGINAL_XZ"
|
|
rm -rf "$WORK_DIR"
|
|
WORK_DIR=""
|
|
elif [[ -n "$NO_RECOMPRESS" && -n "$ORIGINAL_XZ" ]]; then
|
|
echo "Left decompressed image at: $IMG_FILE"
|
|
echo "Recompress manually: xz -z -k \"$IMG_FILE\""
|
|
fi
|