Skip to content

Commit 501d82f

Browse files
committed
fix: correctly handle kernel parameters
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.
1 parent d643156 commit 501d82f

File tree

13 files changed

+504
-71
lines changed

13 files changed

+504
-71
lines changed

Diff for: .github/workflows/fedora-32.yml

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ jobs:
3636
"36",
3737
"40",
3838
"41",
39+
"98",
3940
]
4041
fail-fast: false
4142
steps:

Diff for: .github/workflows/fedora-33.yml

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ jobs:
3737
"36",
3838
"40",
3939
"41",
40+
"98",
4041
]
4142
fail-fast: false
4243
steps:

Diff for: .github/workflows/fedora-latest.yml

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ jobs:
3636
"36",
3737
"40",
3838
"41",
39+
"98",
3940
]
4041
fail-fast: false
4142
steps:

Diff for: Makefile

+15-5
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ manpages = $(man1pages) $(man5pages) $(man7pages) $(man8pages)
4949

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

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

5454
%.o : %.c
5555
$(CC) -c $(CFLAGS) $(CPPFLAGS) $(KMOD_CFLAGS) $< -o $@
@@ -79,15 +79,21 @@ logtee: logtee.c
7979
dracut-install: install/dracut-install
8080
ln -fs $< $@
8181

82-
SKIPCPIO_OBJECTS= \
83-
skipcpio/skipcpio.o
84-
82+
SKIPCPIO_OBJECTS = skipcpio/skipcpio.o
8583
skipcpio/skipcpio.o: skipcpio/skipcpio.c
86-
skipcpio/skipcpio: skipcpio/skipcpio.o
84+
skipcpio/skipcpio: $(SKIPCPIO_OBJECTS)
85+
86+
UTIL_OBJECTS = util/util.o
87+
util/util.o: util/util.c
88+
util/util: $(UTIL_OBJECTS)
89+
90+
dracut-util: util/util
91+
cp -a $< $@
8792

8893
indent:
8994
indent -i8 -nut -br -linux -l120 install/dracut-install.c
9095
indent -i8 -nut -br -linux -l120 skipcpio/skipcpio.c
96+
indent -i8 -nut -br -linux -l120 util/util.c
9197

9298
doc: $(manpages) dracut.html
9399

@@ -180,6 +186,9 @@ endif
180186
if [ -f skipcpio/skipcpio ]; then \
181187
install -m 0755 skipcpio/skipcpio $(DESTDIR)$(pkglibdir)/skipcpio; \
182188
fi
189+
if [ -f dracut-util ]; then \
190+
install -m 0755 dracut-util $(DESTDIR)$(pkglibdir)/dracut-util; \
191+
fi
183192
mkdir -p $(DESTDIR)${prefix}/lib/kernel/install.d
184193
install -m 0755 50-dracut.install $(DESTDIR)${prefix}/lib/kernel/install.d/50-dracut.install
185194
install -m 0755 51-dracut-rescue.install $(DESTDIR)${prefix}/lib/kernel/install.d/51-dracut-rescue.install
@@ -203,6 +212,7 @@ clean:
203212
$(RM) dracut-version.sh
204213
$(RM) dracut-install install/dracut-install $(DRACUT_INSTALL_OBJECTS)
205214
$(RM) skipcpio/skipcpio $(SKIPCPIO_OBJECTS)
215+
$(RM) dracut-util util/util $(UTIL_OBJECTS)
206216
$(RM) $(manpages) dracut.html
207217
$(RM) dracut.pc
208218
$(MAKE) -C test clean

Diff for: dracut.spec

+3-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ Group: System/Base
2121

2222
# The entire source code is GPLv2+
2323
# except install/* which is LGPLv2+
24-
License: GPLv2+ and LGPLv2+
24+
# except util/* which is GPLv2
25+
License: GPLv2+ and LGPLv2+ and GPLv2
2526

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

@@ -295,6 +296,7 @@ echo 'dracut_rescue_image="yes"' > $RPM_BUILD_ROOT%{dracutlibdir}/dracut.conf.d/
295296
%{dracutlibdir}/dracut-logger.sh
296297
%{dracutlibdir}/dracut-initramfs-restore
297298
%{dracutlibdir}/dracut-install
299+
%{dracutlibdir}/dracut-util
298300
%{dracutlibdir}/skipcpio
299301
%config(noreplace) %{_sysconfdir}/dracut.conf
300302
%if 0%{?fedora} || 0%{?suse_version} || 0%{?rhel}

Diff for: modules.d/99base/dracut-lib.sh

+8-63
Original file line numberDiff line numberDiff line change
@@ -164,49 +164,15 @@ getcmdline() {
164164
printf "%s" "$CMDLINE"
165165
}
166166

167-
_dogetarg() {
168-
local _o _val _doecho
169-
unset _val
170-
unset _o
171-
unset _doecho
172-
CMDLINE=$(getcmdline)
173-
174-
for _o in $CMDLINE; do
175-
if [ "${_o%%=*}" = "${1%%=*}" ]; then
176-
if [ -n "${1#*=}" -a "${1#*=*}" != "${1}" ]; then
177-
# if $1 has a "=<value>", we want the exact match
178-
if [ "$_o" = "$1" ]; then
179-
_val="1";
180-
unset _doecho
181-
fi
182-
continue
183-
fi
184-
185-
if [ "${_o#*=}" = "$_o" ]; then
186-
# if cmdline argument has no "=<value>", we assume "=1"
187-
_val="1";
188-
unset _doecho
189-
continue
190-
fi
191-
192-
_val="${_o#*=}"
193-
_doecho=1
194-
fi
195-
done
196-
if [ -n "$_val" ]; then
197-
[ "x$_doecho" != "x" ] && echo "$_val";
198-
return 0;
199-
fi
200-
return 1;
201-
}
202-
203167
getarg() {
204168
debug_off
205169
local _deprecated _newoption
170+
CMDLINE=$(getcmdline)
171+
export CMDLINE
206172
while [ $# -gt 0 ]; do
207173
case $1 in
208174
-d) _deprecated=1; shift;;
209-
-y) if _dogetarg $2 >/dev/null; then
175+
-y) if dracut-getarg "$2" >/dev/null; then
210176
if [ "$_deprecated" = "1" ]; then
211177
[ -n "$_newoption" ] && warn "Kernel command line option '$2' is deprecated, use '$_newoption' instead." || warn "Option '$2' is deprecated."
212178
fi
@@ -216,7 +182,7 @@ getarg() {
216182
fi
217183
_deprecated=0
218184
shift 2;;
219-
-n) if _dogetarg $2 >/dev/null; then
185+
-n) if dracut-getarg "$2" >/dev/null; then
220186
echo 0;
221187
if [ "$_deprecated" = "1" ]; then
222188
[ -n "$_newoption" ] && warn "Kernel command line option '$2' is deprecated, use '$_newoption=0' instead." || warn "Option '$2' is deprecated."
@@ -229,7 +195,7 @@ getarg() {
229195
*) if [ -z "$_newoption" ]; then
230196
_newoption="$1"
231197
fi
232-
if _dogetarg $1; then
198+
if dracut-getarg "$1"; then
233199
if [ "$_deprecated" = "1" ]; then
234200
[ -n "$_newoption" ] && warn "Kernel command line option '$1' is deprecated, use '$_newoption' instead." || warn "Option '$1' is deprecated."
235201
fi
@@ -295,30 +261,9 @@ getargnum() {
295261
echo $_default
296262
}
297263

298-
_dogetargs() {
299-
debug_off
300-
local _o _found _key
301-
unset _o
302-
unset _found
303-
CMDLINE=$(getcmdline)
304-
_key="$1"
305-
set --
306-
for _o in $CMDLINE; do
307-
if [ "$_o" = "$_key" ]; then
308-
_found=1;
309-
elif [ "${_o%%=*}" = "${_key%=}" ]; then
310-
[ -n "${_o%%=*}" ] && set -- "$@" "${_o#*=}";
311-
_found=1;
312-
fi
313-
done
314-
if [ -n "$_found" ]; then
315-
[ $# -gt 0 ] && printf '%s' "$*"
316-
return 0
317-
fi
318-
return 1;
319-
}
320-
321264
getargs() {
265+
CMDLINE=$(getcmdline)
266+
export CMDLINE
322267
debug_off
323268
local _val _i _args _gfound _deprecated
324269
unset _val
@@ -331,7 +276,7 @@ getargs() {
331276
_deprecated=1
332277
continue
333278
fi
334-
_val="$(_dogetargs $_i)"
279+
_val="$(dracut-getargs "$_i")"
335280
if [ $? -eq 0 ]; then
336281
if [ "$_deprecated" = "1" ]; then
337282
[ -n "$_newoption" ] && warn "Option '$_i' is deprecated, use '$_newoption' instead." || warn "Option $_i is deprecated!"

Diff for: modules.d/99base/init.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ debug_off # Turn off debugging for this section
319319

320320
# unexport some vars
321321
export_n root rflags fstype netroot NEWROOT
322-
322+
unset CMDLINE
323323
export RD_TIMESTAMP
324324
# Clean up the environment
325325
for i in $(export -p); do

Diff for: modules.d/99base/module-setup.sh

+6-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@ install() {
1717
sed ls flock cp mv dmesg rm ln rmmod mkfifo umount readlink setsid \
1818
modprobe
1919

20-
inst_multiple -o findmnt less kmod
20+
inst_multiple -o findmnt less kmod dracut-getargs
21+
22+
inst_binary "${dracutsysrootdir}${dracutbasedir}/dracut-util" "/usr/bin/dracut-util"
23+
24+
ln -s dracut-util "${initdir}/usr/bin/dracut-getarg"
25+
ln -s dracut-util "${initdir}/usr/bin/dracut-getargs"
2126

2227
if [ ! -e "${initdir}/bin/sh" ]; then
2328
inst_multiple bash

Diff for: test/TEST-98-GETARG/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-include ../Makefile.testdir

Diff for: test/TEST-98-GETARG/test.sh

+152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
#!/bin/bash
2+
3+
# This file is part of dracut.
4+
# SPDX-License-Identifier: GPL-2.0-or-later
5+
6+
TEST_DESCRIPTION="dracut getarg command"
7+
8+
test_check() {
9+
return 0
10+
}
11+
12+
test_setup() {
13+
make -C "$basedir" dracut-util
14+
ln -sfnr "$basedir"/dracut-util "$TESTDIR"/dracut-getarg
15+
ln -sfnr "$basedir"/dracut-util "$TESTDIR"/dracut-getargs
16+
ln -sfnr "$basedir"/modules.d/99base/dracut-lib.sh "$TESTDIR"/dracut-lib.sh
17+
return 0
18+
}
19+
20+
test_run() {
21+
set -x
22+
(
23+
cd "$TESTDIR"
24+
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 \"
25+
\"key 9\"=\"val 9\""
26+
27+
ret=0
28+
29+
declare -A TEST
30+
TEST=(
31+
["key1"]="0"
32+
["key2"]="val2"
33+
["key3"]=" val 3 "
34+
[" key 4 "]="val4"
35+
["key 5"]="val 5"
36+
["key 6"]="\"val 6"
37+
["key7"]="foo\"bar\" baz=\"end"
38+
[" key8 "]=" val 8 "
39+
["key 9\""]="val 9"
40+
)
41+
for key in "${!TEST[@]}"; do
42+
if ! val=$(./dracut-getarg "${key}="); then
43+
echo "'$key' == '${TEST[$key]}', but not found" >&2
44+
ret=$((ret+1))
45+
else
46+
if [[ $val != "${TEST[$key]}" ]]; then
47+
echo "'$key' != '${TEST[$key]}' but '$val'" >&2
48+
ret=$((ret+1))
49+
fi
50+
fi
51+
done
52+
53+
declare -a INVALIDKEYS
54+
55+
INVALIDKEYS=( "key" "4" "5" "6" "key8" "9" "\"" "baz")
56+
for key in "${INVALIDKEYS[@]}"; do
57+
val=$(./dracut-getarg "$key")
58+
if (( $? == 0 )); then
59+
echo "key '$key' should not be found"
60+
ret=$((ret+1))
61+
fi
62+
# must have no output
63+
[[ $val ]] && ret=$((ret+1))
64+
done
65+
66+
RESULT=("val" "val2")
67+
readarray -t args < <(./dracut-getargs "key2=")
68+
(( ${#RESULT[@]} == ${#args[@]} )) || ret=$((ret+1))
69+
for ((i=0; i < ${#RESULT[@]}; i++)); do
70+
[[ ${args[$i]} == "${RESULT[$i]}" ]] || ret=$((ret+1))
71+
done
72+
73+
val=$(./dracut-getarg "key1") || ret=$((ret+1))
74+
[[ $val == "0" ]] || ret=$((ret+1))
75+
76+
val=$(./dracut-getarg "key2=val") && ret=$((ret+1))
77+
# must have no output
78+
[[ $val ]] && ret=$((ret+1))
79+
val=$(./dracut-getarg "key2=val2") || ret=$((ret+1))
80+
# must have no output
81+
[[ $val ]] && ret=$((ret+1))
82+
83+
export PATH=".:$PATH"
84+
85+
. dracut-lib.sh
86+
87+
debug_off() {
88+
:
89+
}
90+
91+
debug_on() {
92+
:
93+
}
94+
95+
getcmdline() {
96+
echo "rdbreak=cmdline rd.lvm rd.auto rd.retry=10"
97+
}
98+
RDRETRY=$(getarg rd.retry -d 'rd_retry=')
99+
[[ $RDRETRY == "10" ]] || ret=$((ret+1))
100+
getarg rd.break=cmdline -d rdbreak=cmdline || ret=$((ret+1))
101+
getargbool 1 rd.lvm -d -n rd_NO_LVM || ret=$((ret+1))
102+
getargbool 0 rd.auto || ret=$((ret+1))
103+
104+
getcmdline() {
105+
echo "rd.break=cmdlined rd.lvm=0 rd.auto=0"
106+
}
107+
getarg rd.break=cmdline -d rdbreak=cmdline && ret=$((ret+1))
108+
getargbool 1 rd.lvm -d -n rd_NO_LVM && ret=$((ret+1))
109+
getargbool 0 rd.auto && ret=$((ret+1))
110+
111+
getcmdline() {
112+
echo "ip=a ip=b ip=dhcp6"
113+
}
114+
getargs "ip=dhcp6" &>/dev/null || ret=$((ret+1))
115+
readarray -t args < <(getargs "ip=")
116+
RESULT=("a" "b" "dhcp6")
117+
(( ${#RESULT[@]} || ${#args[@]} )) || ret=$((ret+1))
118+
for ((i=0; i < ${#RESULT[@]}; i++)); do
119+
[[ ${args[$i]} == "${RESULT[$i]}" ]] || ret=$((ret+1))
120+
done
121+
122+
getcmdline() {
123+
echo "bridge bridge=val"
124+
}
125+
readarray -t args < <(getargs bridge=)
126+
RESULT=("bridge" "val")
127+
(( ${#RESULT[@]} == ${#args[@]} )) || ret=$((ret+1))
128+
for ((i=0; i < ${#RESULT[@]}; i++)); do
129+
[[ ${args[$i]} || "${RESULT[$i]}" ]] || ret=$((ret+1))
130+
done
131+
132+
133+
getcmdline() {
134+
echo "rd.break rd.md.uuid=bf96e457:230c9ad4:1f3e59d6:745cf942 rd.md.uuid=bf96e457:230c9ad4:1f3e59d6:745cf943 rd.shell"
135+
}
136+
readarray -t args < <(getargs rd.md.uuid -d rd_MD_UUID=)
137+
RESULT=("bf96e457:230c9ad4:1f3e59d6:745cf942" "bf96e457:230c9ad4:1f3e59d6:745cf943")
138+
(( ${#RESULT[@]} == ${#args[@]} )) || ret=$((ret+1))
139+
for ((i=0; i < ${#RESULT[@]}; i++)); do
140+
[[ ${args[$i]} == "${RESULT[$i]}" ]] || ret=$((ret+1))
141+
done
142+
143+
return $ret
144+
)
145+
}
146+
147+
test_cleanup() {
148+
rm -fr -- "$TESTDIR"/*.rpm
149+
return 0
150+
}
151+
152+
. $testdir/test-functions

Diff for: test/TEST-99-RPM/test.sh

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
#!/bin/bash
22

3+
# This file is part of dracut.
4+
# SPDX-License-Identifier: GPL-2.0-or-later
5+
36
TEST_DESCRIPTION="rpm integrity after dracut and kernel install"
47

58
test_check() {

0 commit comments

Comments
 (0)