Hi everybody,
grml is a rescue system. I use it as such, and I like it very much. I think from the very beginning of my usage of grml, I wanted a rescue system iso that can boot autonomously, with a serial console, automatically brings up the network (configuration fitting the machine) and installs credentials so that I can log in to the rescue system via ssh with known credentials. This should especially cater to systems that do not have remote console access, making it necessary to travel to the machine or use remote hands when the rescue system doesn't come up.
I made various approaches, but always got tangled in complex procedures using mechanisms that were at best loosely documented.
But finally, I have a successful approach and would like to document this here, and ask for your opinion about how to document this (maybe inside the grml wiki) to allow people to use this, and whether some of my examples or scripts would be suitable to inclusion in some grml repository. Let me know where and I'll file PRs.
This has become way easier by grml now using grub for both BIOS and EFI. grub is something I understand reasonably well.
And I recently learned that you just need a single xorriso call to remaster a grml.iso while adding ("mapping") files to the image. I have written a small shell script which can be used to easily and quickly rebuild the iso with files from a local directory added. It is even possible to override files from the iso by placing a file in the map directory.
The idea is to have a grmlreplay-conf.sh in a directory and having a tree of files that would be mapped into the iso below that. grmlreplay can be invoked from anywhere in that tree and will cd upwards until grmlreplay_conf.sh is found. The paths to the isos can be absolute, so grmlreplay can directly store the modified image in a libvirt/images/cd directory to directly boot a VM from that without having to move the image.
With this mechanism, it is possible to build an image that does what I want it to. For the early boot part, https://github.com/grml/grml-live/pull/547 from earlier today is needed.
File names mentioned are all relative to the root of the iso, that's what 7zz l /path/to/grml.iso prints.
(1) quick, noninteractive boot with serial console Sadly, the bootparams mechanism does not work for things that are needed on the kernel command line. It is thus necessary to poke those into the actual boot process: ------ /boot/grub/grub_local_custom_pre_entry.cfg serial --unit=0 --speed=115200 --word=8 --stop=1 --parity=no terminal_input console serial terminal_output console serial set timeout=5 set extraopts="nodhcp console=tty1 console=ttyS0,115200n8" ------
(without #547 merged, apply the patches from there to grml-live and put the resulting /boot/grub/grub.cfg and map/boot/grub/grmlsmallamd64_default.cfg into map/boot/grub as well)
(2) scripts/grml.sh my map directory contains a scripts/grml.sh that controls the other special actions. The necessary snippets are given below. Maybe it would be a good idea to run-parts scripts/grml.d in addition to executing scripts/grml.sh so that different things could be invoked from different scripts. Please let me know if you'd want a PR for that.
(3) why not GRMLCFG? I would have needed some examples to understand how this works. I'd also wanted to avoid having a dedicated partition for GRMLCFG, avoiding the need to reparition existing systems to be able to use my rescue image. I therefore did things differently and am pretty satisfied with the simplicity of the result.
(4) network init This is the machine specific part and can only be in the iso if that iso is intended to be only for this machine. I implemented a more flexible way that executes a script from the EFI partition (which MUST be there or we wouldn't have gotten that far if our grml iso is chainloaded from another grub via grml-rescueboot). For a BIOS or CSM machine, another mechanism would be needed.
------ scripts/grml.sh snippet # excecute grml/network.sh from EFI partition # possible case issues here (fat32 can only have upper case # lebels). maybe look for partition type ESP instead? LABEL=esp DEVICE="$(blkid -t LABEL=$LABEL | cut -d: -f1)" if [ -z "$DEVICE" ]; then DEVICE="$(blkid -t PARTLABEL=$LABEL | cut -d: -f1)" fi
MOUNTDIR="/run/live/esp" mkdir "${MOUNTDIR}" mount -o ro "${DEVICE}" "${MOUNTDIR}" if [ -e "${MOUNTDIR}/grml/network.sh" ]; then . "${MOUNTDIR}/grml/network.sh" fi umount "${MOUNTDIR}" rmdir "${MOUNTDIR}" ------
See an example grml/network.sh below.
I might publish a python program soon that generates such a network.sh from the currently running system's network configuration.
(5) authorized_keys I decided to have the authorized_keys for the grml and root user in authorized_keys.d. ------ scripts/grml.sh snippet MEDIUMDIR="/run/live/medium"
# install ssh keys for tu in root grml; do hmd="$(getent passwd "$tu" | cut -d: -f6)" mkdir -p "${hmd}/.ssh" find "${MEDIUMDIR}"/authorized_keys.d -type f -print0 | \ xargs --no-run-if-empty --null cat > "${hmd}/.ssh/authorized_keys" chown "${tu}:${tu}" "${hmd}/.ssh" "${hmd}/.ssh/authorized_keys" done ------
(6) bootparams put a bootparams file into the iso that sets the password, starts ssh and allows grml.sh to run: ------ bootparams/zgrml-bootparams keyboard=de scripts ssh encpasswd=<passwordhash> ------
note that the encpasswd can be any hash, not just md5 as it is mentioned in some docs I found. Also note that some options are needed by the kernel and the bootparams file is only ready when the system is already running.
I am happy to discuss all this and am looking forward to your feedback.
Greetings Marc
------ grmlreplay #!/bin/bash set -euo pipefail
CONFFILE="grmlreplay_conf.sh" while [ ! -f "${CONFFILE}" ]; do [ "$PWD" = / ] && { echo "${CONFFILE} not found" >&2 exit 1 } cd .. done . "${CONFFILE}"
# --- sanity checks --- command -v xorriso >/dev/null || { echo "need xorriso installed" >&2; exit 1; } [ -f "$ORIG_ISO" ] || { echo "source iso not found: $ORIG_ISO" >&2; exit 1; } [ -d "$MAP_DIR" ] || { echo "add dir not found: $MAP_DIR" >&2; exit 1; }
xorriso -indev "$ORIG_ISO" -pkt_output off 2>&1 | grep -i -E "joliet|rock ?ridge"
# preserve original volume id (grml's live-boot looks for it) VOLID=$(xorriso -indev "$ORIG_ISO" -pkt_output off -find / -maxdepth 0 2>/dev/null \ | true; xorriso -indev "$ORIG_ISO" -pkt_output off 2>&1 \ | awk -F"'" '/Volume id/{print $2; exit}') [ -n "$VOLID" ] || VOLID="GRML_CUSTOM"
rm -f "$NEW_ISO"
xorriso \ -indev "$ORIG_ISO" \ -outdev "$NEW_ISO" \ -volid "$VOLID" \ -joliet on \ -rockridge on \ -map "$MAP_DIR" / \ -boot_image any replay \ -commit
xorriso -indev "$NEW_ISO" -pkt_output off 2>&1 | grep -i -E "joliet|rock ?ridge" echo "Done: $NEW_ISO" ------
------ example grmlreplay_conf.sh ORIG_ISO="/var/lib/libvirt/cd/grml-small-2026.04-amd64.iso" MAP_DIR="./map" NEW_ISO="/var/lib/libvirt/cd/zgrml-small-2026.04-amd64.iso" ------
------ ESP:grml/network.sh #!/bin/sh
set -u
PROG=${0##*/}
log() { printf '%s: %s\n' "$PROG" "$*" >&2; } die() { printf '%s: ERROR: %s\n' "$PROG" "$*" >&2; exit 1; }
run_cmd() { log "+ $*" "$@" || die "command failed: $*" }
command -v ip >/dev/null 2>&1 || die "ip(8) not found"
# --- enp1s0 --- run_cmd ip link set dev enp1s0 up run_cmd ip addr replace 192.0.2.134/28 dev enp1s0 run_cmd ip addr replace 2001:db8::43:100/64 dev enp1s0
# --- routes --- run_cmd ip route replace default via 192.0.2.129 dev enp1s0 run_cmd ip route replace default via 2001:db8::1 dev enp1s0 metric 1024 ------
------ example tree ./map/scripts/grml.sh ./map/authorized_keys.d/authorized_keys ./map/bootparams/zgrml-bootparams ./map/boot/grub/grub_local_custom_pre_entry.cfg ./grmlreplay_conf.sh ------
Teilnehmer (1)
-
Marc Haber