From 3950f801e26a3aeb1e3bc91e31c7fd4591588252 Mon Sep 17 00:00:00 2001 From: Antonio Alvarez Feijoo Date: Tue, 16 Jan 2024 12:49:57 +0100 Subject: [PATCH 1/4] fix(dracut): correct regression with multiple `rd.break=` options Since the introduction of the `dracut-util` binary to parse kernel command line arguments, if the user inputs multiple `rd.break=` options, dracut only stops the boot process at the last one. ``` [ 0.985362] localhost dracut-cmdline[245]: /bin/dracut-cmdline@18(): info 'Using kernel command line parameters:' ' ... rd.debug rd.break=cmdline rd.break=pre-pivot' ... [ 1.044979] localhost dracut-cmdline[245]: /bin/dracut-cmdline@48(): getarg rd.break=cmdline -d rdbreak=cmdline [ 1.044979] localhost dracut-cmdline[245]: /lib/dracut-lib.sh@155(getarg): debug_off [ 1.044979] localhost dracut-cmdline[245]: /lib/dracut-lib.sh@23(debug_off): set +x [ 1.044979] localhost dracut-cmdline[245]: /lib/dracut-lib.sh@218(getarg): return 1 ``` For options that can be specified multiple times, `getargs` should be used instead. ``` master> export CMDLINE="rd.break=cmdline rd.break=pre-udev rd.break=pre-pivot" master> ./dracut-getarg rd.break=cmdline master> echo $? 1 master> ./dracut-getarg rd.break=pre-udev master> echo $? 1 master> ./dracut-getarg rd.break=pre-pivot master> echo $? 0 master> ./dracut-getargs rd.break=cmdline cmdline master> echo $? 0 master> ./dracut-getargs rd.break=pre-udev pre-udev master> echo $? 0 master> ./dracut-getargs rd.break=pre-pivot pre-pivot master> echo $? 0 ``` Fixes 501d82f79675a6bf9b37e8250152515863a80236 --- modules.d/98dracut-systemd/dracut-cmdline.sh | 2 +- modules.d/98dracut-systemd/dracut-initqueue.sh | 2 +- modules.d/98dracut-systemd/dracut-mount.sh | 2 +- modules.d/98dracut-systemd/dracut-pre-mount.sh | 2 +- modules.d/98dracut-systemd/dracut-pre-pivot.sh | 4 ++-- modules.d/98dracut-systemd/dracut-pre-trigger.sh | 2 +- modules.d/98dracut-systemd/dracut-pre-udev.sh | 2 +- modules.d/99base/init.sh | 16 ++++++++-------- modules.d/99shutdown/shutdown.sh | 4 ++-- 9 files changed, 18 insertions(+), 18 deletions(-) diff --git a/modules.d/98dracut-systemd/dracut-cmdline.sh b/modules.d/98dracut-systemd/dracut-cmdline.sh index cdfb19619c..13f91a1106 100755 --- a/modules.d/98dracut-systemd/dracut-cmdline.sh +++ b/modules.d/98dracut-systemd/dracut-cmdline.sh @@ -45,7 +45,7 @@ export fstype make_trace_mem "hook cmdline" '1+:mem' '1+:iomem' '3+:slab' # run scriptlets to parse the command line -getarg 'rd.break=cmdline' -d 'rdbreak=cmdline' && emergency_shell -n cmdline "Break before cmdline" +getargs 'rd.break=cmdline' -d 'rdbreak=cmdline' && emergency_shell -n cmdline "Break before cmdline" source_hook cmdline [ -f /lib/dracut/parse-resume.sh ] && . /lib/dracut/parse-resume.sh diff --git a/modules.d/98dracut-systemd/dracut-initqueue.sh b/modules.d/98dracut-systemd/dracut-initqueue.sh index ce919ce2e0..b0882dbe06 100755 --- a/modules.d/98dracut-systemd/dracut-initqueue.sh +++ b/modules.d/98dracut-systemd/dracut-initqueue.sh @@ -9,7 +9,7 @@ type getarg > /dev/null 2>&1 || . /lib/dracut-lib.sh source_conf /etc/conf.d make_trace_mem "hook initqueue" '1:shortmem' '2+:mem' '3+:slab' -getarg 'rd.break=initqueue' -d 'rdbreak=initqueue' && emergency_shell -n initqueue "Break before initqueue" +getargs 'rd.break=initqueue' -d 'rdbreak=initqueue' && emergency_shell -n initqueue "Break before initqueue" RDRETRY=$(getarg rd.retry -d 'rd_retry=') RDRETRY=${RDRETRY:-180} diff --git a/modules.d/98dracut-systemd/dracut-mount.sh b/modules.d/98dracut-systemd/dracut-mount.sh index 1fd061cd8c..c1fbf88232 100755 --- a/modules.d/98dracut-systemd/dracut-mount.sh +++ b/modules.d/98dracut-systemd/dracut-mount.sh @@ -9,7 +9,7 @@ source_conf /etc/conf.d make_trace_mem "hook mount" '1:shortmem' '2+:mem' '3+:slab' -getarg 'rd.break=mount' -d 'rdbreak=mount' && emergency_shell -n mount "Break before mount" +getargs 'rd.break=mount' -d 'rdbreak=mount' && emergency_shell -n mount "Break before mount" # mount scripts actually try to mount the root filesystem, and may # be sourced any number of times. As soon as one suceeds, no more are sourced. i=0 diff --git a/modules.d/98dracut-systemd/dracut-pre-mount.sh b/modules.d/98dracut-systemd/dracut-pre-mount.sh index ee516057c0..d7482c59d5 100755 --- a/modules.d/98dracut-systemd/dracut-pre-mount.sh +++ b/modules.d/98dracut-systemd/dracut-pre-mount.sh @@ -11,7 +11,7 @@ source_conf /etc/conf.d make_trace_mem "hook pre-mount" '1:shortmem' '2+:mem' '3+:slab' # pre pivot scripts are sourced just before we doing cleanup and switch over # to the new root. -getarg 'rd.break=pre-mount' 'rdbreak=pre-mount' && emergency_shell -n pre-mount "Break before pre-mount" +getargs 'rd.break=pre-mount' -d 'rdbreak=pre-mount' && emergency_shell -n pre-mount "Break before pre-mount" source_hook pre-mount export -p > /dracut-state.sh diff --git a/modules.d/98dracut-systemd/dracut-pre-pivot.sh b/modules.d/98dracut-systemd/dracut-pre-pivot.sh index 8bf232548b..fa81b33543 100755 --- a/modules.d/98dracut-systemd/dracut-pre-pivot.sh +++ b/modules.d/98dracut-systemd/dracut-pre-pivot.sh @@ -11,11 +11,11 @@ source_conf /etc/conf.d make_trace_mem "hook pre-pivot" '1:shortmem' '2+:mem' '3+:slab' # pre pivot scripts are sourced just before we doing cleanup and switch over # to the new root. -getarg 'rd.break=pre-pivot' 'rdbreak=pre-pivot' && emergency_shell -n pre-pivot "Break before pre-pivot" +getargs 'rd.break=pre-pivot' -d 'rdbreak=pre-pivot' && emergency_shell -n pre-pivot "Break before pre-pivot" source_hook pre-pivot # pre pivot cleanup scripts are sourced just before we switch over to the new root. -getarg 'rd.break=cleanup' 'rdbreak=cleanup' && emergency_shell -n cleanup "Break before cleanup" +getargs 'rd.break=cleanup' -d 'rdbreak=cleanup' && emergency_shell -n cleanup "Break before cleanup" source_hook cleanup _bv=$(getarg rd.break -d rdbreak) && [ -z "$_bv" ] \ diff --git a/modules.d/98dracut-systemd/dracut-pre-trigger.sh b/modules.d/98dracut-systemd/dracut-pre-trigger.sh index dd0215e432..8758ba9acc 100755 --- a/modules.d/98dracut-systemd/dracut-pre-trigger.sh +++ b/modules.d/98dracut-systemd/dracut-pre-trigger.sh @@ -12,7 +12,7 @@ make_trace_mem "hook pre-trigger" '1:shortmem' '2+:mem' '3+:slab' source_hook pre-trigger -getarg 'rd.break=pre-trigger' 'rdbreak=pre-trigger' && emergency_shell -n pre-trigger "Break before pre-trigger" +getargs 'rd.break=pre-trigger' -d 'rdbreak=pre-trigger' && emergency_shell -n pre-trigger "Break before pre-trigger" udevadm control --reload > /dev/null 2>&1 || : diff --git a/modules.d/98dracut-systemd/dracut-pre-udev.sh b/modules.d/98dracut-systemd/dracut-pre-udev.sh index feab32cb97..a08f0fc711 100755 --- a/modules.d/98dracut-systemd/dracut-pre-udev.sh +++ b/modules.d/98dracut-systemd/dracut-pre-udev.sh @@ -10,7 +10,7 @@ source_conf /etc/conf.d make_trace_mem "hook pre-udev" '1:shortmem' '2+:mem' '3+:slab' # pre pivot scripts are sourced just before we doing cleanup and switch over # to the new root. -getarg 'rd.break=pre-udev' 'rdbreak=pre-udev' && emergency_shell -n pre-udev "Break before pre-udev" +getargs 'rd.break=pre-udev' -d 'rdbreak=pre-udev' && emergency_shell -n pre-udev "Break before pre-udev" source_hook pre-udev _modprobe_d=/etc/modprobe.d diff --git a/modules.d/99base/init.sh b/modules.d/99base/init.sh index ca1df90d57..2390a791b7 100755 --- a/modules.d/99base/init.sh +++ b/modules.d/99base/init.sh @@ -123,7 +123,7 @@ fi # run scriptlets to parse the command line make_trace_mem "hook cmdline" '1+:mem' '1+:iomem' '3+:slab' -getarg 'rd.break=cmdline' -d 'rdbreak=cmdline' && emergency_shell -n cmdline "Break before cmdline" +getargs 'rd.break=cmdline' -d 'rdbreak=cmdline' && emergency_shell -n cmdline "Break before cmdline" source_hook cmdline [ -z "$root" ] && die "No or empty root= argument" @@ -133,7 +133,7 @@ export root rflags fstype netroot NEWROOT # pre-udev scripts run before udev starts, and are run only once. make_trace_mem "hook pre-udev" '1:shortmem' '2+:mem' '3+:slab' -getarg 'rd.break=pre-udev' -d 'rdbreak=pre-udev' && emergency_shell -n pre-udev "Break before pre-udev" +getargs 'rd.break=pre-udev' -d 'rdbreak=pre-udev' && emergency_shell -n pre-udev "Break before pre-udev" source_hook pre-udev UDEV_LOG=err @@ -148,7 +148,7 @@ UDEV_QUEUE_EMPTY="udevadm settle --timeout=0" udevproperty "hookdir=$hookdir" make_trace_mem "hook pre-trigger" '1:shortmem' '2+:mem' '3+:slab' -getarg 'rd.break=pre-trigger' -d 'rdbreak=pre-trigger' && emergency_shell -n pre-trigger "Break before pre-trigger" +getargs 'rd.break=pre-trigger' -d 'rdbreak=pre-trigger' && emergency_shell -n pre-trigger "Break before pre-trigger" source_hook pre-trigger udevadm control --reload > /dev/null 2>&1 || : @@ -157,7 +157,7 @@ udevadm trigger --type=subsystems --action=add > /dev/null 2>&1 udevadm trigger --type=devices --action=add > /dev/null 2>&1 make_trace_mem "hook initqueue" '1:shortmem' '2+:mem' '3+:slab' -getarg 'rd.break=initqueue' -d 'rdbreak=initqueue' && emergency_shell -n initqueue "Break before initqueue" +getargs 'rd.break=initqueue' -d 'rdbreak=initqueue' && emergency_shell -n initqueue "Break before initqueue" RDRETRY=$(getarg rd.retry -d 'rd_retry=') RDRETRY=${RDRETRY:-180} @@ -223,10 +223,10 @@ unset RDRETRY # pre-mount happens before we try to mount the root filesystem, # and happens once. make_trace_mem "hook pre-mount" '1:shortmem' '2+:mem' '3+:slab' -getarg 'rd.break=pre-mount' -d 'rdbreak=pre-mount' && emergency_shell -n pre-mount "Break before pre-mount" +getargs 'rd.break=pre-mount' -d 'rdbreak=pre-mount' && emergency_shell -n pre-mount "Break before pre-mount" source_hook pre-mount -getarg 'rd.break=mount' -d 'rdbreak=mount' && emergency_shell -n mount "Break before mount" +getargs 'rd.break=mount' -d 'rdbreak=mount' && emergency_shell -n mount "Break before mount" # mount scripts actually try to mount the root filesystem, and may # be sourced any number of times. As soon as one suceeds, no more are sourced. _i_mount=0 @@ -262,12 +262,12 @@ done # pre pivot scripts are sourced just before we doing cleanup and switch over # to the new root. make_trace_mem "hook pre-pivot" '1:shortmem' '2+:mem' '3+:slab' -getarg 'rd.break=pre-pivot' -d 'rdbreak=pre-pivot' && emergency_shell -n pre-pivot "Break before pre-pivot" +getargs 'rd.break=pre-pivot' -d 'rdbreak=pre-pivot' && emergency_shell -n pre-pivot "Break before pre-pivot" source_hook pre-pivot make_trace_mem "hook cleanup" '1:shortmem' '2+:mem' '3+:slab' # pre pivot cleanup scripts are sourced just before we switch over to the new root. -getarg 'rd.break=cleanup' -d 'rdbreak=cleanup' && emergency_shell -n cleanup "Break before cleanup" +getargs 'rd.break=cleanup' -d 'rdbreak=cleanup' && emergency_shell -n cleanup "Break before cleanup" source_hook cleanup # By the time we get here, the root filesystem should be mounted. diff --git a/modules.d/99shutdown/shutdown.sh b/modules.d/99shutdown/shutdown.sh index d611d44697..d48d7d1fb3 100755 --- a/modules.d/99shutdown/shutdown.sh +++ b/modules.d/99shutdown/shutdown.sh @@ -39,7 +39,7 @@ if [ "$ACTION" = "kexec" ] && ! command -v kexec > /dev/null 2>&1; then fi trap "emergency_shell --shutdown shutdown Signal caught!" 0 -getarg 'rd.break=pre-shutdown' && emergency_shell --shutdown pre-shutdown "Break before pre-shutdown" +getargs 'rd.break=pre-shutdown' && emergency_shell --shutdown pre-shutdown "Break before pre-shutdown" source_hook pre-shutdown @@ -155,7 +155,7 @@ elif [ -x /oldroot/bin/plymouth ]; then /oldroot/bin/plymouth --hide-splash fi -getarg 'rd.break=shutdown' && emergency_shell --shutdown shutdown "Break before shutdown" +getargs 'rd.break=shutdown' && emergency_shell --shutdown shutdown "Break before shutdown" case "$ACTION" in reboot | poweroff | halt) From 469faf76c26f80780ca85f17f45942cc72c76dc7 Mon Sep 17 00:00:00 2001 From: Antonio Alvarez Feijoo Date: Fri, 19 Jan 2024 18:01:16 +0100 Subject: [PATCH 2/4] fix(livenet): propagate error code --- modules.d/90livenet/livenetroot.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules.d/90livenet/livenetroot.sh b/modules.d/90livenet/livenetroot.sh index 66dd41b39a..8a0c19f59a 100755 --- a/modules.d/90livenet/livenetroot.sh +++ b/modules.d/90livenet/livenetroot.sh @@ -30,8 +30,9 @@ while [ "$i" -le "$RETRIES" ]; do imgfile=$(fetch_url "$liveurl") # shellcheck disable=SC2181 - if [ $? != 0 ]; then - warn "failed to download live image: error $?" + ret=$? + if [ $ret != 0 ]; then + warn "failed to download live image: error $ret" imgfile= fi From a572e23f2c5c7ccd43a2216eae51be858243e331 Mon Sep 17 00:00:00 2001 From: Antonio Alvarez Feijoo Date: Fri, 19 Jan 2024 18:02:07 +0100 Subject: [PATCH 3/4] fix(livenet): check also `content-length` from live image header Some servers send `content-length` instead of `Content-Length`, so ignore the case. E.g.: ``` > curl -sIL https://pkg.adfinis.com/opensuse/tumbleweed/iso/openSUSE-Tumbleweed-DVD-x86_64-Snapshot20240118-Media.iso HTTP/2 200 server: nginx date: Fri, 19 Jan 2024 16:29:54 GMT content-type: application/octet-stream content-length: 4643094528 last-modified: Fri, 19 Jan 2024 03:34:00 GMT etag: "65a9eda8-114c00000" accept-ranges: bytes ``` --- modules.d/90livenet/livenetroot.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules.d/90livenet/livenetroot.sh b/modules.d/90livenet/livenetroot.sh index 8a0c19f59a..96616f3bdc 100755 --- a/modules.d/90livenet/livenetroot.sh +++ b/modules.d/90livenet/livenetroot.sh @@ -18,7 +18,7 @@ info "fetching $liveurl" if getargbool 0 'rd.writable.fsimg'; then - imgsize=$(($(curl -sIL "$liveurl" | sed -n 's/Content-Length: *\([[:digit:]]*\).*/\1/p') / (1024 * 1024))) + imgsize=$(($(curl -sIL "$liveurl" | sed -n 's/[cC]ontent-[lL]ength: *\([[:digit:]]*\).*/\1/p') / (1024 * 1024))) check_live_ram $imgsize fi From 87c8f82d3ea7412213597a4b072ca4c8f125377c Mon Sep 17 00:00:00 2001 From: Antonio Alvarez Feijoo Date: Fri, 19 Jan 2024 18:03:03 +0100 Subject: [PATCH 4/4] fix(livenet): split `imgsize` calculation to avoid misleading error message If `curl` fails to reach the URL of the live image, or if the header received does not provide `Content-Length`, the error message displayed is misleading. ``` [ 8.118432] dracut-initqueue[800]: /usr/sbin/livenetroot: line 21: / (1024 * 1024): syntax error: operand expected (error token is "/ (1024 * 1024)") ``` Therefore, split the calculation and provide proper error messages. Reported-by: Knut Anderssen --- modules.d/90livenet/livenetroot.sh | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/modules.d/90livenet/livenetroot.sh b/modules.d/90livenet/livenetroot.sh index 96616f3bdc..34f91ff1d3 100755 --- a/modules.d/90livenet/livenetroot.sh +++ b/modules.d/90livenet/livenetroot.sh @@ -17,10 +17,21 @@ liveurl="${netroot#livenet:}" info "fetching $liveurl" if getargbool 0 'rd.writable.fsimg'; then + imgheader=$(curl -sIL "$liveurl") - imgsize=$(($(curl -sIL "$liveurl" | sed -n 's/[cC]ontent-[lL]ength: *\([[:digit:]]*\).*/\1/p') / (1024 * 1024))) - - check_live_ram $imgsize + # shellcheck disable=SC2181 + ret=$? + if [ $ret != 0 ]; then + warn "failed to get live image header: error $ret" + else + imgheaderlen=$(echo "$imgheader" | sed -n 's/[cC]ontent-[lL]ength: *\([[:digit:]]*\).*/\1/p') + if [ -z "$imgheaderlen" ]; then + warn "failed to get 'Content-Length' header from live image" + else + imgsize=$((imgheaderlen / (1024 * 1024))) + check_live_ram $imgsize + fi + fi fi imgfile=