Skip to content

Commit

Permalink
fix: correctly handle kernel parameters
Browse files Browse the repository at this point in the history
The kernel has an odd way to handle `"` surrounded parameters.
To handle the parameters as the kernel would do, no simple shell script
suffices, so a new utility `dracut-util` is introduced. Written in "C"
it handles `dracut-getarg` and `dracut-getargs` as the old shell script
functions `_dogetarg` and `_dogetargs` would.
  • Loading branch information
haraldh committed Mar 10, 2021
1 parent d643156 commit 501d82f
Show file tree
Hide file tree
Showing 13 changed files with 504 additions and 71 deletions.
1 change: 1 addition & 0 deletions .github/workflows/fedora-32.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ jobs:
"36",
"40",
"41",
"98",
]
fail-fast: false
steps:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/fedora-33.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ jobs:
"36",
"40",
"41",
"98",
]
fail-fast: false
steps:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/fedora-latest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ jobs:
"36",
"40",
"41",
"98",
]
fail-fast: false
steps:
Expand Down
20 changes: 15 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ manpages = $(man1pages) $(man5pages) $(man7pages) $(man8pages)

.PHONY: install clean archive rpm srpm testimage test all check AUTHORS CONTRIBUTORS doc dracut-version.sh

all: dracut-version.sh dracut.pc dracut-install skipcpio/skipcpio
all: dracut-version.sh dracut.pc dracut-install skipcpio/skipcpio dracut-util

%.o : %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $(KMOD_CFLAGS) $< -o $@
Expand Down Expand Up @@ -79,15 +79,21 @@ logtee: logtee.c
dracut-install: install/dracut-install
ln -fs $< $@

SKIPCPIO_OBJECTS= \
skipcpio/skipcpio.o

SKIPCPIO_OBJECTS = skipcpio/skipcpio.o
skipcpio/skipcpio.o: skipcpio/skipcpio.c
skipcpio/skipcpio: skipcpio/skipcpio.o
skipcpio/skipcpio: $(SKIPCPIO_OBJECTS)

UTIL_OBJECTS = util/util.o
util/util.o: util/util.c
util/util: $(UTIL_OBJECTS)

dracut-util: util/util
cp -a $< $@

indent:
indent -i8 -nut -br -linux -l120 install/dracut-install.c
indent -i8 -nut -br -linux -l120 skipcpio/skipcpio.c
indent -i8 -nut -br -linux -l120 util/util.c

doc: $(manpages) dracut.html

Expand Down Expand Up @@ -180,6 +186,9 @@ endif
if [ -f skipcpio/skipcpio ]; then \
install -m 0755 skipcpio/skipcpio $(DESTDIR)$(pkglibdir)/skipcpio; \
fi
if [ -f dracut-util ]; then \
install -m 0755 dracut-util $(DESTDIR)$(pkglibdir)/dracut-util; \
fi
mkdir -p $(DESTDIR)${prefix}/lib/kernel/install.d
install -m 0755 50-dracut.install $(DESTDIR)${prefix}/lib/kernel/install.d/50-dracut.install
install -m 0755 51-dracut-rescue.install $(DESTDIR)${prefix}/lib/kernel/install.d/51-dracut-rescue.install
Expand All @@ -203,6 +212,7 @@ clean:
$(RM) dracut-version.sh
$(RM) dracut-install install/dracut-install $(DRACUT_INSTALL_OBJECTS)
$(RM) skipcpio/skipcpio $(SKIPCPIO_OBJECTS)
$(RM) dracut-util util/util $(UTIL_OBJECTS)
$(RM) $(manpages) dracut.html
$(RM) dracut.pc
$(MAKE) -C test clean
Expand Down
4 changes: 3 additions & 1 deletion dracut.spec
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ Group: System/Base

# The entire source code is GPLv2+
# except install/* which is LGPLv2+
License: GPLv2+ and LGPLv2+
# except util/* which is GPLv2
License: GPLv2+ and LGPLv2+ and GPLv2

URL: https://dracut.wiki.kernel.org/

Expand Down Expand Up @@ -295,6 +296,7 @@ echo 'dracut_rescue_image="yes"' > $RPM_BUILD_ROOT%{dracutlibdir}/dracut.conf.d/
%{dracutlibdir}/dracut-logger.sh
%{dracutlibdir}/dracut-initramfs-restore
%{dracutlibdir}/dracut-install
%{dracutlibdir}/dracut-util
%{dracutlibdir}/skipcpio
%config(noreplace) %{_sysconfdir}/dracut.conf
%if 0%{?fedora} || 0%{?suse_version} || 0%{?rhel}
Expand Down
71 changes: 8 additions & 63 deletions modules.d/99base/dracut-lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -164,49 +164,15 @@ getcmdline() {
printf "%s" "$CMDLINE"
}

_dogetarg() {
local _o _val _doecho
unset _val
unset _o
unset _doecho
CMDLINE=$(getcmdline)

for _o in $CMDLINE; do
if [ "${_o%%=*}" = "${1%%=*}" ]; then
if [ -n "${1#*=}" -a "${1#*=*}" != "${1}" ]; then
# if $1 has a "=<value>", we want the exact match
if [ "$_o" = "$1" ]; then
_val="1";
unset _doecho
fi
continue
fi

if [ "${_o#*=}" = "$_o" ]; then
# if cmdline argument has no "=<value>", we assume "=1"
_val="1";
unset _doecho
continue
fi

_val="${_o#*=}"
_doecho=1
fi
done
if [ -n "$_val" ]; then
[ "x$_doecho" != "x" ] && echo "$_val";
return 0;
fi
return 1;
}

getarg() {
debug_off
local _deprecated _newoption
CMDLINE=$(getcmdline)
export CMDLINE
while [ $# -gt 0 ]; do
case $1 in
-d) _deprecated=1; shift;;
-y) if _dogetarg $2 >/dev/null; then
-y) if dracut-getarg "$2" >/dev/null; then
if [ "$_deprecated" = "1" ]; then
[ -n "$_newoption" ] && warn "Kernel command line option '$2' is deprecated, use '$_newoption' instead." || warn "Option '$2' is deprecated."
fi
Expand All @@ -216,7 +182,7 @@ getarg() {
fi
_deprecated=0
shift 2;;
-n) if _dogetarg $2 >/dev/null; then
-n) if dracut-getarg "$2" >/dev/null; then
echo 0;
if [ "$_deprecated" = "1" ]; then
[ -n "$_newoption" ] && warn "Kernel command line option '$2' is deprecated, use '$_newoption=0' instead." || warn "Option '$2' is deprecated."
Expand All @@ -229,7 +195,7 @@ getarg() {
*) if [ -z "$_newoption" ]; then
_newoption="$1"
fi
if _dogetarg $1; then
if dracut-getarg "$1"; then
if [ "$_deprecated" = "1" ]; then
[ -n "$_newoption" ] && warn "Kernel command line option '$1' is deprecated, use '$_newoption' instead." || warn "Option '$1' is deprecated."
fi
Expand Down Expand Up @@ -295,30 +261,9 @@ getargnum() {
echo $_default
}

_dogetargs() {
debug_off
local _o _found _key
unset _o
unset _found
CMDLINE=$(getcmdline)
_key="$1"
set --
for _o in $CMDLINE; do
if [ "$_o" = "$_key" ]; then
_found=1;
elif [ "${_o%%=*}" = "${_key%=}" ]; then
[ -n "${_o%%=*}" ] && set -- "$@" "${_o#*=}";
_found=1;
fi
done
if [ -n "$_found" ]; then
[ $# -gt 0 ] && printf '%s' "$*"
return 0
fi
return 1;
}

getargs() {
CMDLINE=$(getcmdline)
export CMDLINE
debug_off
local _val _i _args _gfound _deprecated
unset _val
Expand All @@ -331,7 +276,7 @@ getargs() {
_deprecated=1
continue
fi
_val="$(_dogetargs $_i)"
_val="$(dracut-getargs "$_i")"
if [ $? -eq 0 ]; then
if [ "$_deprecated" = "1" ]; then
[ -n "$_newoption" ] && warn "Option '$_i' is deprecated, use '$_newoption' instead." || warn "Option $_i is deprecated!"
Expand Down
2 changes: 1 addition & 1 deletion modules.d/99base/init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ debug_off # Turn off debugging for this section

# unexport some vars
export_n root rflags fstype netroot NEWROOT

unset CMDLINE
export RD_TIMESTAMP
# Clean up the environment
for i in $(export -p); do
Expand Down
7 changes: 6 additions & 1 deletion modules.d/99base/module-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ install() {
sed ls flock cp mv dmesg rm ln rmmod mkfifo umount readlink setsid \
modprobe

inst_multiple -o findmnt less kmod
inst_multiple -o findmnt less kmod dracut-getargs

inst_binary "${dracutsysrootdir}${dracutbasedir}/dracut-util" "/usr/bin/dracut-util"

ln -s dracut-util "${initdir}/usr/bin/dracut-getarg"
ln -s dracut-util "${initdir}/usr/bin/dracut-getargs"

if [ ! -e "${initdir}/bin/sh" ]; then
inst_multiple bash
Expand Down
1 change: 1 addition & 0 deletions test/TEST-98-GETARG/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-include ../Makefile.testdir
152 changes: 152 additions & 0 deletions test/TEST-98-GETARG/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
#!/bin/bash

# This file is part of dracut.
# SPDX-License-Identifier: GPL-2.0-or-later

TEST_DESCRIPTION="dracut getarg command"

test_check() {
return 0
}

test_setup() {
make -C "$basedir" dracut-util
ln -sfnr "$basedir"/dracut-util "$TESTDIR"/dracut-getarg
ln -sfnr "$basedir"/dracut-util "$TESTDIR"/dracut-getargs
ln -sfnr "$basedir"/modules.d/99base/dracut-lib.sh "$TESTDIR"/dracut-lib.sh
return 0
}

test_run() {
set -x
(
cd "$TESTDIR"
export CMDLINE="key1=0 key2=val key2=val2 key3=\" val 3 \" \" key 4 =\"val4 \"key 5=val 5\" \"key 6=\"\"val 6\" key7=\"foo\"bar\" baz=\"end \" key8 = val 8 \"
\"key 9\"=\"val 9\""

ret=0

declare -A TEST
TEST=(
["key1"]="0"
["key2"]="val2"
["key3"]=" val 3 "
[" key 4 "]="val4"
["key 5"]="val 5"
["key 6"]="\"val 6"
["key7"]="foo\"bar\" baz=\"end"
[" key8 "]=" val 8 "
["key 9\""]="val 9"
)
for key in "${!TEST[@]}"; do
if ! val=$(./dracut-getarg "${key}="); then
echo "'$key' == '${TEST[$key]}', but not found" >&2
ret=$((ret+1))
else
if [[ $val != "${TEST[$key]}" ]]; then
echo "'$key' != '${TEST[$key]}' but '$val'" >&2
ret=$((ret+1))
fi
fi
done

declare -a INVALIDKEYS

INVALIDKEYS=( "key" "4" "5" "6" "key8" "9" "\"" "baz")
for key in "${INVALIDKEYS[@]}"; do
val=$(./dracut-getarg "$key")
if (( $? == 0 )); then
echo "key '$key' should not be found"
ret=$((ret+1))
fi
# must have no output
[[ $val ]] && ret=$((ret+1))
done

RESULT=("val" "val2")
readarray -t args < <(./dracut-getargs "key2=")
(( ${#RESULT[@]} == ${#args[@]} )) || ret=$((ret+1))
for ((i=0; i < ${#RESULT[@]}; i++)); do
[[ ${args[$i]} == "${RESULT[$i]}" ]] || ret=$((ret+1))
done

val=$(./dracut-getarg "key1") || ret=$((ret+1))
[[ $val == "0" ]] || ret=$((ret+1))

val=$(./dracut-getarg "key2=val") && ret=$((ret+1))
# must have no output
[[ $val ]] && ret=$((ret+1))
val=$(./dracut-getarg "key2=val2") || ret=$((ret+1))
# must have no output
[[ $val ]] && ret=$((ret+1))

export PATH=".:$PATH"

. dracut-lib.sh

debug_off() {
:
}

debug_on() {
:
}

getcmdline() {
echo "rdbreak=cmdline rd.lvm rd.auto rd.retry=10"
}
RDRETRY=$(getarg rd.retry -d 'rd_retry=')
[[ $RDRETRY == "10" ]] || ret=$((ret+1))
getarg rd.break=cmdline -d rdbreak=cmdline || ret=$((ret+1))
getargbool 1 rd.lvm -d -n rd_NO_LVM || ret=$((ret+1))
getargbool 0 rd.auto || ret=$((ret+1))

getcmdline() {
echo "rd.break=cmdlined rd.lvm=0 rd.auto=0"
}
getarg rd.break=cmdline -d rdbreak=cmdline && ret=$((ret+1))
getargbool 1 rd.lvm -d -n rd_NO_LVM && ret=$((ret+1))
getargbool 0 rd.auto && ret=$((ret+1))

getcmdline() {
echo "ip=a ip=b ip=dhcp6"
}
getargs "ip=dhcp6" &>/dev/null || ret=$((ret+1))
readarray -t args < <(getargs "ip=")
RESULT=("a" "b" "dhcp6")
(( ${#RESULT[@]} || ${#args[@]} )) || ret=$((ret+1))
for ((i=0; i < ${#RESULT[@]}; i++)); do
[[ ${args[$i]} == "${RESULT[$i]}" ]] || ret=$((ret+1))
done

getcmdline() {
echo "bridge bridge=val"
}
readarray -t args < <(getargs bridge=)
RESULT=("bridge" "val")
(( ${#RESULT[@]} == ${#args[@]} )) || ret=$((ret+1))
for ((i=0; i < ${#RESULT[@]}; i++)); do
[[ ${args[$i]} || "${RESULT[$i]}" ]] || ret=$((ret+1))
done


getcmdline() {
echo "rd.break rd.md.uuid=bf96e457:230c9ad4:1f3e59d6:745cf942 rd.md.uuid=bf96e457:230c9ad4:1f3e59d6:745cf943 rd.shell"
}
readarray -t args < <(getargs rd.md.uuid -d rd_MD_UUID=)
RESULT=("bf96e457:230c9ad4:1f3e59d6:745cf942" "bf96e457:230c9ad4:1f3e59d6:745cf943")
(( ${#RESULT[@]} == ${#args[@]} )) || ret=$((ret+1))
for ((i=0; i < ${#RESULT[@]}; i++)); do
[[ ${args[$i]} == "${RESULT[$i]}" ]] || ret=$((ret+1))
done

return $ret
)
}

test_cleanup() {
rm -fr -- "$TESTDIR"/*.rpm
return 0
}

. $testdir/test-functions
3 changes: 3 additions & 0 deletions test/TEST-99-RPM/test.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#!/bin/bash

# This file is part of dracut.
# SPDX-License-Identifier: GPL-2.0-or-later

TEST_DESCRIPTION="rpm integrity after dracut and kernel install"

test_check() {
Expand Down
Loading

0 comments on commit 501d82f

Please sign in to comment.