|
|
|
#!/bin/sh
|
|
|
|
|
|
|
|
export DRACUT_SYSTEMD
|
|
|
|
export NEWROOT
|
|
|
|
if [ -n "$NEWROOT" ]; then
|
|
|
|
[ -d $NEWROOT ] || mkdir -p -m 0755 $NEWROOT
|
|
|
|
fi
|
|
|
|
|
|
|
|
if ! [ -d /run/initramfs ]; then
|
|
|
|
mkdir -p -m 0755 /run/initramfs/log
|
|
|
|
ln -sfn /run/initramfs/log /var/log
|
|
|
|
fi
|
|
|
|
|
|
|
|
[ -d /run/lock ] || mkdir -p -m 0755 /run/lock
|
|
|
|
[ -d /run/log ] || mkdir -p -m 0755 /run/log
|
|
|
|
|
|
|
|
debug_off() {
|
|
|
|
set +x
|
|
|
|
}
|
|
|
|
|
|
|
|
debug_on() {
|
|
|
|
[ "$RD_DEBUG" = "yes" ] && set -x
|
|
|
|
}
|
|
|
|
|
Specify strstr tightly, add strglob/strglobin.
By convention, strstr should be a literal string match. Previously, it
would match as a glob pattern. Some code used that, so add new
functions strglob and strglobin to do what that code expects, and
specify them tightly too. strglob tests whether the glob pattern
matches the entire string (the name strglob is also used in the yorick
language, and that's what it does there), while strglobin tests whether
the glob pattern matches anywhere in the string.
Also tightens str_starts, str_ends, and str_replace to deal with
literal strings only. In a quick grep I did not find code that depended
on these functions matching globs.
Changes the call sites where strstr was used with glob patterns to use
strglobin or strglob as the intention seemed to be (or, in one case,
strstr with the * removed as it did not affect the result anyway).
11 years ago
|
|
|
# returns OK if $1 contains literal string $2 (and isn't empty)
|
|
|
|
strstr() {
|
dracut-lib.sh: quote variables in parameter expansion patterns
According to POSIX.1-2017, 2.6.2 Parameter Expansion:
${parameter%[word]} [...] The word shall be expanded to produce a
pattern.
This means if word contains variables that itself contain special
characters like asterisks or backslashes, these are treated as pattern
characters unless the variable is quoted. Try e.g. the following example
in bash, dash or (busybox) ash:
i='a\c'; j='\'; echo "${i%$j*}"
This prints "a\c" because "$j*" is expanded to "\*", escaping the
asterisk. In contrast,
i='a\c'; j='\'; echo "${i%"$j"*}"
produces the expected result "a" because the backslash is not specially
treated any more after quoting.
The quotes that this commit adds have been previously removed in commit
f9c96cf56fed390841eac05c43826e62014c9188, citing issues with busybox
hush without further specifying the actual error. I tested a recent
busybox build (upstream commit 9aa751b08ab03d6396f86c3df77937a19687981b)
and couldn't find any problems. Note that the above example always
produces "a\c" in hush regardless of quoting $j, making hush unsuitable
for use with dracut, but using quotes in parameter expansions generally
works.
The unquoted variables break the "rd.luks.uuid/name" kernel command line
options in dracut 050 because
str_replace "$luksname" '\' '\\'
in modules.d/90crypt/parse-crypt.sh is not able to escape the
backslashes any more, see GH-723, GH-727: backslashes in the
systemd-cryptsetup@.service unit name stay unescaped for use in udev
(cf. commit 0f6d93eb9d63695a64002ec8b0421fbc9fc8a7a3), leading to
failures in starting the unit.
This partially reverts commit f9c96cf56fed390841eac05c43826e62014c9188.
5 years ago
|
|
|
[ "${1##*"$2"*}" != "$1" ]
|
|
|
|
}
|
|
|
|
|
Specify strstr tightly, add strglob/strglobin.
By convention, strstr should be a literal string match. Previously, it
would match as a glob pattern. Some code used that, so add new
functions strglob and strglobin to do what that code expects, and
specify them tightly too. strglob tests whether the glob pattern
matches the entire string (the name strglob is also used in the yorick
language, and that's what it does there), while strglobin tests whether
the glob pattern matches anywhere in the string.
Also tightens str_starts, str_ends, and str_replace to deal with
literal strings only. In a quick grep I did not find code that depended
on these functions matching globs.
Changes the call sites where strstr was used with glob patterns to use
strglobin or strglob as the intention seemed to be (or, in one case,
strstr with the * removed as it did not affect the result anyway).
11 years ago
|
|
|
# returns OK if $1 matches (completely) glob pattern $2
|
|
|
|
# An empty $1 will not be considered matched, even if $2 is * which technically
|
|
|
|
# matches; as it would match anything, it's not an interesting case.
|
|
|
|
strglob() {
|
|
|
|
[ -n "$1" -a -z "${1##$2}" ]
|
|
|
|
}
|
|
|
|
|
|
|
|
# returns OK if $1 contains (anywhere) a match of glob pattern $2
|
|
|
|
# An empty $1 will not be considered matched, even if $2 is * which technically
|
|
|
|
# matches; as it would match anything, it's not an interesting case.
|
|
|
|
strglobin() {
|
|
|
|
[ -n "$1" -a -z "${1##*$2*}" ]
|
|
|
|
}
|
|
|
|
|
|
|
|
# returns OK if $1 contains literal string $2 at the beginning, and isn't empty
|
|
|
|
str_starts() {
|
dracut-lib.sh: quote variables in parameter expansion patterns
According to POSIX.1-2017, 2.6.2 Parameter Expansion:
${parameter%[word]} [...] The word shall be expanded to produce a
pattern.
This means if word contains variables that itself contain special
characters like asterisks or backslashes, these are treated as pattern
characters unless the variable is quoted. Try e.g. the following example
in bash, dash or (busybox) ash:
i='a\c'; j='\'; echo "${i%$j*}"
This prints "a\c" because "$j*" is expanded to "\*", escaping the
asterisk. In contrast,
i='a\c'; j='\'; echo "${i%"$j"*}"
produces the expected result "a" because the backslash is not specially
treated any more after quoting.
The quotes that this commit adds have been previously removed in commit
f9c96cf56fed390841eac05c43826e62014c9188, citing issues with busybox
hush without further specifying the actual error. I tested a recent
busybox build (upstream commit 9aa751b08ab03d6396f86c3df77937a19687981b)
and couldn't find any problems. Note that the above example always
produces "a\c" in hush regardless of quoting $j, making hush unsuitable
for use with dracut, but using quotes in parameter expansions generally
works.
The unquoted variables break the "rd.luks.uuid/name" kernel command line
options in dracut 050 because
str_replace "$luksname" '\' '\\'
in modules.d/90crypt/parse-crypt.sh is not able to escape the
backslashes any more, see GH-723, GH-727: backslashes in the
systemd-cryptsetup@.service unit name stay unescaped for use in udev
(cf. commit 0f6d93eb9d63695a64002ec8b0421fbc9fc8a7a3), leading to
failures in starting the unit.
This partially reverts commit f9c96cf56fed390841eac05c43826e62014c9188.
5 years ago
|
|
|
[ "${1#"$2"*}" != "$1" ]
|
|
|
|
}
|
|
|
|
|
Specify strstr tightly, add strglob/strglobin.
By convention, strstr should be a literal string match. Previously, it
would match as a glob pattern. Some code used that, so add new
functions strglob and strglobin to do what that code expects, and
specify them tightly too. strglob tests whether the glob pattern
matches the entire string (the name strglob is also used in the yorick
language, and that's what it does there), while strglobin tests whether
the glob pattern matches anywhere in the string.
Also tightens str_starts, str_ends, and str_replace to deal with
literal strings only. In a quick grep I did not find code that depended
on these functions matching globs.
Changes the call sites where strstr was used with glob patterns to use
strglobin or strglob as the intention seemed to be (or, in one case,
strstr with the * removed as it did not affect the result anyway).
11 years ago
|
|
|
# returns OK if $1 contains literal string $2 at the end, and isn't empty
|
|
|
|
str_ends() {
|
dracut-lib.sh: quote variables in parameter expansion patterns
According to POSIX.1-2017, 2.6.2 Parameter Expansion:
${parameter%[word]} [...] The word shall be expanded to produce a
pattern.
This means if word contains variables that itself contain special
characters like asterisks or backslashes, these are treated as pattern
characters unless the variable is quoted. Try e.g. the following example
in bash, dash or (busybox) ash:
i='a\c'; j='\'; echo "${i%$j*}"
This prints "a\c" because "$j*" is expanded to "\*", escaping the
asterisk. In contrast,
i='a\c'; j='\'; echo "${i%"$j"*}"
produces the expected result "a" because the backslash is not specially
treated any more after quoting.
The quotes that this commit adds have been previously removed in commit
f9c96cf56fed390841eac05c43826e62014c9188, citing issues with busybox
hush without further specifying the actual error. I tested a recent
busybox build (upstream commit 9aa751b08ab03d6396f86c3df77937a19687981b)
and couldn't find any problems. Note that the above example always
produces "a\c" in hush regardless of quoting $j, making hush unsuitable
for use with dracut, but using quotes in parameter expansions generally
works.
The unquoted variables break the "rd.luks.uuid/name" kernel command line
options in dracut 050 because
str_replace "$luksname" '\' '\\'
in modules.d/90crypt/parse-crypt.sh is not able to escape the
backslashes any more, see GH-723, GH-727: backslashes in the
systemd-cryptsetup@.service unit name stay unescaped for use in udev
(cf. commit 0f6d93eb9d63695a64002ec8b0421fbc9fc8a7a3), leading to
failures in starting the unit.
This partially reverts commit f9c96cf56fed390841eac05c43826e62014c9188.
5 years ago
|
|
|
[ "${1%*"$2"}" != "$1" ]
|
|
|
|
}
|
|
|
|
|
|
|
|
trim() {
|
|
|
|
local var="$*"
|
dracut-lib.sh: quote variables in parameter expansion patterns
According to POSIX.1-2017, 2.6.2 Parameter Expansion:
${parameter%[word]} [...] The word shall be expanded to produce a
pattern.
This means if word contains variables that itself contain special
characters like asterisks or backslashes, these are treated as pattern
characters unless the variable is quoted. Try e.g. the following example
in bash, dash or (busybox) ash:
i='a\c'; j='\'; echo "${i%$j*}"
This prints "a\c" because "$j*" is expanded to "\*", escaping the
asterisk. In contrast,
i='a\c'; j='\'; echo "${i%"$j"*}"
produces the expected result "a" because the backslash is not specially
treated any more after quoting.
The quotes that this commit adds have been previously removed in commit
f9c96cf56fed390841eac05c43826e62014c9188, citing issues with busybox
hush without further specifying the actual error. I tested a recent
busybox build (upstream commit 9aa751b08ab03d6396f86c3df77937a19687981b)
and couldn't find any problems. Note that the above example always
produces "a\c" in hush regardless of quoting $j, making hush unsuitable
for use with dracut, but using quotes in parameter expansions generally
works.
The unquoted variables break the "rd.luks.uuid/name" kernel command line
options in dracut 050 because
str_replace "$luksname" '\' '\\'
in modules.d/90crypt/parse-crypt.sh is not able to escape the
backslashes any more, see GH-723, GH-727: backslashes in the
systemd-cryptsetup@.service unit name stay unescaped for use in udev
(cf. commit 0f6d93eb9d63695a64002ec8b0421fbc9fc8a7a3), leading to
failures in starting the unit.
This partially reverts commit f9c96cf56fed390841eac05c43826e62014c9188.
5 years ago
|
|
|
var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters
|
|
|
|
var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters
|
|
|
|
printf "%s" "$var"
|
|
|
|
}
|
|
|
|
|
|
|
|
if [ -z "$DRACUT_SYSTEMD" ]; then
|
|
|
|
|
|
|
|
warn() {
|
|
|
|
check_quiet
|
|
|
|
echo "<28>dracut Warning: $*" > /dev/kmsg
|
|
|
|
echo "dracut Warning: $*" >&2
|
|
|
|
}
|
|
|
|
|
|
|
|
info() {
|
|
|
|
check_quiet
|
|
|
|
echo "<30>dracut: $*" > /dev/kmsg
|
|
|
|
[ "$DRACUT_QUIET" != "yes" ] && \
|
|
|
|
echo "dracut: $*" >&2 || :
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
warn() {
|
|
|
|
echo "Warning: $*" >&2
|
|
|
|
}
|
|
|
|
|
|
|
|
info() {
|
|
|
|
echo "$*"
|
|
|
|
}
|
|
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
vwarn() {
|
|
|
|
while read line || [ -n "$line" ]; do
|
|
|
|
warn $line;
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
vinfo() {
|
|
|
|
while read line || [ -n "$line" ]; do
|
|
|
|
info $line;
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
# replaces all occurrences of 'search' in 'str' with 'replacement'
|
|
|
|
#
|
|
|
|
# str_replace str search replacement
|
|
|
|
#
|
|
|
|
# example:
|
|
|
|
# str_replace ' one two three ' ' ' '_'
|
|
|
|
str_replace() {
|
|
|
|
local in="$1"; local s="$2"; local r="$3"
|
|
|
|
local out=''
|
|
|
|
|
|
|
|
while strstr "${in}" "$s"; do
|
dracut-lib.sh: quote variables in parameter expansion patterns
According to POSIX.1-2017, 2.6.2 Parameter Expansion:
${parameter%[word]} [...] The word shall be expanded to produce a
pattern.
This means if word contains variables that itself contain special
characters like asterisks or backslashes, these are treated as pattern
characters unless the variable is quoted. Try e.g. the following example
in bash, dash or (busybox) ash:
i='a\c'; j='\'; echo "${i%$j*}"
This prints "a\c" because "$j*" is expanded to "\*", escaping the
asterisk. In contrast,
i='a\c'; j='\'; echo "${i%"$j"*}"
produces the expected result "a" because the backslash is not specially
treated any more after quoting.
The quotes that this commit adds have been previously removed in commit
f9c96cf56fed390841eac05c43826e62014c9188, citing issues with busybox
hush without further specifying the actual error. I tested a recent
busybox build (upstream commit 9aa751b08ab03d6396f86c3df77937a19687981b)
and couldn't find any problems. Note that the above example always
produces "a\c" in hush regardless of quoting $j, making hush unsuitable
for use with dracut, but using quotes in parameter expansions generally
works.
The unquoted variables break the "rd.luks.uuid/name" kernel command line
options in dracut 050 because
str_replace "$luksname" '\' '\\'
in modules.d/90crypt/parse-crypt.sh is not able to escape the
backslashes any more, see GH-723, GH-727: backslashes in the
systemd-cryptsetup@.service unit name stay unescaped for use in udev
(cf. commit 0f6d93eb9d63695a64002ec8b0421fbc9fc8a7a3), leading to
failures in starting the unit.
This partially reverts commit f9c96cf56fed390841eac05c43826e62014c9188.
5 years ago
|
|
|
chop="${in%%"$s"*}"
|
|
|
|
out="${out}${chop}$r"
|
dracut-lib.sh: quote variables in parameter expansion patterns
According to POSIX.1-2017, 2.6.2 Parameter Expansion:
${parameter%[word]} [...] The word shall be expanded to produce a
pattern.
This means if word contains variables that itself contain special
characters like asterisks or backslashes, these are treated as pattern
characters unless the variable is quoted. Try e.g. the following example
in bash, dash or (busybox) ash:
i='a\c'; j='\'; echo "${i%$j*}"
This prints "a\c" because "$j*" is expanded to "\*", escaping the
asterisk. In contrast,
i='a\c'; j='\'; echo "${i%"$j"*}"
produces the expected result "a" because the backslash is not specially
treated any more after quoting.
The quotes that this commit adds have been previously removed in commit
f9c96cf56fed390841eac05c43826e62014c9188, citing issues with busybox
hush without further specifying the actual error. I tested a recent
busybox build (upstream commit 9aa751b08ab03d6396f86c3df77937a19687981b)
and couldn't find any problems. Note that the above example always
produces "a\c" in hush regardless of quoting $j, making hush unsuitable
for use with dracut, but using quotes in parameter expansions generally
works.
The unquoted variables break the "rd.luks.uuid/name" kernel command line
options in dracut 050 because
str_replace "$luksname" '\' '\\'
in modules.d/90crypt/parse-crypt.sh is not able to escape the
backslashes any more, see GH-723, GH-727: backslashes in the
systemd-cryptsetup@.service unit name stay unescaped for use in udev
(cf. commit 0f6d93eb9d63695a64002ec8b0421fbc9fc8a7a3), leading to
failures in starting the unit.
This partially reverts commit f9c96cf56fed390841eac05c43826e62014c9188.
5 years ago
|
|
|
in="${in#*"$s"}"
|
|
|
|
done
|
|
|
|
echo "${out}${in}"
|
|
|
|
}
|
|
|
|
|
|
|
|
killall_proc_mountpoint() {
|
|
|
|
local _pid
|
|
|
|
local _t
|
|
|
|
local _killed=0
|
|
|
|
for _pid in /proc/*; do
|
|
|
|
_pid=${_pid##/proc/}
|
|
|
|
case $_pid in
|
|
|
|
*[!0-9]*) continue;;
|
|
|
|
esac
|
|
|
|
[ -e "/proc/$_pid/exe" ] || continue
|
|
|
|
[ -e "/proc/$_pid/root" ] || continue
|
|
|
|
if strstr "$(ls -l -- "/proc/$_pid" "/proc/$_pid/fd" 2>/dev/null)" "$1" ; then
|
|
|
|
kill -9 "$_pid"
|
|
|
|
_killed=1
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
return $_killed
|
|
|
|
}
|
|
|
|
|
|
|
|
getcmdline() {
|
|
|
|
local _line
|
|
|
|
local _i
|
|
|
|
local CMDLINE_ETC_D
|
|
|
|
local CMDLINE_ETC
|
|
|
|
local CMDLINE_PROC
|
|
|
|
unset _line
|
dracut-lib: do not use cached CMDLINE in _getcmdline
Cached CMDLINE doesn't work 100%. For example the following case,
1. dracut starts to run dracut-cmdline.sh. CMDLINE is cached when calling
getarg 'rd.break=cmdline'.
2. In 92-parse-ibft.sh, ibft_to_cmdline() calls $(set_ifname ibft xx:xx..)
multiple times in each subshell.
3. In 1st call, set_ifname() will check $(getargs ifname) and write out
ifname=xxxx accordingly.
4. In 2nd call, set_ifname() will check $(getargs ifname) and it's wrong here.
Because in step 3, we introduce a new cmdline arg ifname=xxx, but CMDLINE
isn't updated. Thus we fail to get the new ifname arg.
It's doable to unset CMDLINE every time after a new cmdline arg is in. But
unset should be done in the parent process, because unset CMDLINE in a
subshell won't unset CMDLINE in its parent or sibling process. And also it's
painful to unset CMDLINE every time. In the future, functions and code
snippet could probably separate or move to other file, the unset CMDLINE could
malfunction again like this time.
So I'm thinking not to cache CMDLINE. It's doesn't hurt to re-read all the
cmdline args everytime. Because it's in initramfs, a non cached _getcmdline()
should be fast enough.
Please consider!
Thanks
WANG Chao
12 years ago
|
|
|
|
|
|
|
if [ -e /etc/cmdline ]; then
|
|
|
|
while read -r _line || [ -n "$_line" ]; do
|
dracut-lib: do not use cached CMDLINE in _getcmdline
Cached CMDLINE doesn't work 100%. For example the following case,
1. dracut starts to run dracut-cmdline.sh. CMDLINE is cached when calling
getarg 'rd.break=cmdline'.
2. In 92-parse-ibft.sh, ibft_to_cmdline() calls $(set_ifname ibft xx:xx..)
multiple times in each subshell.
3. In 1st call, set_ifname() will check $(getargs ifname) and write out
ifname=xxxx accordingly.
4. In 2nd call, set_ifname() will check $(getargs ifname) and it's wrong here.
Because in step 3, we introduce a new cmdline arg ifname=xxx, but CMDLINE
isn't updated. Thus we fail to get the new ifname arg.
It's doable to unset CMDLINE every time after a new cmdline arg is in. But
unset should be done in the parent process, because unset CMDLINE in a
subshell won't unset CMDLINE in its parent or sibling process. And also it's
painful to unset CMDLINE every time. In the future, functions and code
snippet could probably separate or move to other file, the unset CMDLINE could
malfunction again like this time.
So I'm thinking not to cache CMDLINE. It's doesn't hurt to re-read all the
cmdline args everytime. Because it's in initramfs, a non cached _getcmdline()
should be fast enough.
Please consider!
Thanks
WANG Chao
12 years ago
|
|
|
CMDLINE_ETC="$CMDLINE_ETC $_line";
|
|
|
|
done </etc/cmdline;
|
|
|
|
fi
|
|
|
|
for _i in /etc/cmdline.d/*.conf; do
|
|
|
|
[ -e "$_i" ] || continue
|
|
|
|
while read -r _line || [ -n "$_line" ]; do
|
dracut-lib: do not use cached CMDLINE in _getcmdline
Cached CMDLINE doesn't work 100%. For example the following case,
1. dracut starts to run dracut-cmdline.sh. CMDLINE is cached when calling
getarg 'rd.break=cmdline'.
2. In 92-parse-ibft.sh, ibft_to_cmdline() calls $(set_ifname ibft xx:xx..)
multiple times in each subshell.
3. In 1st call, set_ifname() will check $(getargs ifname) and write out
ifname=xxxx accordingly.
4. In 2nd call, set_ifname() will check $(getargs ifname) and it's wrong here.
Because in step 3, we introduce a new cmdline arg ifname=xxx, but CMDLINE
isn't updated. Thus we fail to get the new ifname arg.
It's doable to unset CMDLINE every time after a new cmdline arg is in. But
unset should be done in the parent process, because unset CMDLINE in a
subshell won't unset CMDLINE in its parent or sibling process. And also it's
painful to unset CMDLINE every time. In the future, functions and code
snippet could probably separate or move to other file, the unset CMDLINE could
malfunction again like this time.
So I'm thinking not to cache CMDLINE. It's doesn't hurt to re-read all the
cmdline args everytime. Because it's in initramfs, a non cached _getcmdline()
should be fast enough.
Please consider!
Thanks
WANG Chao
12 years ago
|
|
|
CMDLINE_ETC_D="$CMDLINE_ETC_D $_line";
|
|
|
|
done <"$_i";
|
|
|
|
done
|
|
|
|
if [ -e /proc/cmdline ]; then
|
|
|
|
while read -r _line || [ -n "$_line" ]; do
|
|
|
|
CMDLINE_PROC="$CMDLINE_PROC $_line"
|
|
|
|
done </proc/cmdline;
|
|
|
|
fi
|
|
|
|
CMDLINE="$CMDLINE_ETC_D $CMDLINE_ETC $CMDLINE_PROC"
|
|
|
|
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
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
case $1 in
|
|
|
|
-d) _deprecated=1; shift;;
|
|
|
|
-y) if _dogetarg $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
|
|
|
|
echo 1
|
|
|
|
debug_on
|
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
_deprecated=0
|
|
|
|
shift 2;;
|
|
|
|
-n) if _dogetarg $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."
|
|
|
|
fi
|
|
|
|
debug_on
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
_deprecated=0
|
|
|
|
shift 2;;
|
|
|
|
*) if [ -z "$_newoption" ]; then
|
|
|
|
_newoption="$1"
|
|
|
|
fi
|
|
|
|
if _dogetarg $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
|
|
|
|
debug_on
|
|
|
|
return 0;
|
|
|
|
fi
|
|
|
|
_deprecated=0
|
|
|
|
shift;;
|
|
|
|
esac
|
|
|
|
done
|
|
|
|
debug_on
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
# getargbool <defaultval> <args...>
|
|
|
|
# False if "getarg <args...>" returns "0", "no", or "off".
|
|
|
|
# True if getarg returns any other non-empty string.
|
|
|
|
# If not found, assumes <defaultval> - usually 0 for false, 1 for true.
|
|
|
|
# example: getargbool 0 rd.info
|
|
|
|
# true: rd.info, rd.info=1, rd.info=xxx
|
|
|
|
# false: rd.info=0, rd.info=off, rd.info not present (default val is 0)
|
|
|
|
getargbool() {
|
|
|
|
local _b
|
|
|
|
unset _b
|
|
|
|
local _default
|
|
|
|
_default="$1"; shift
|
|
|
|
_b=$(getarg "$@")
|
|
|
|
[ $? -ne 0 -a -z "$_b" ] && _b="$_default"
|
|
|
|
if [ -n "$_b" ]; then
|
|
|
|
[ $_b = "0" ] && return 1
|
|
|
|
[ $_b = "no" ] && return 1
|
|
|
|
[ $_b = "off" ] && return 1
|
|
|
|
fi
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
isdigit() {
|
|
|
|
case "$1" in
|
|
|
|
*[!0-9]*|"") return 1;;
|
|
|
|
esac
|
|
|
|
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
# getargnum <defaultval> <minval> <maxval> <arg>
|
|
|
|
# Will echo the arg if it's in range [minval - maxval].
|
|
|
|
# If it's not set or it's not valid, will set it <defaultval>.
|
|
|
|
# Note all values are required to be >= 0 here.
|
|
|
|
# <defaultval> should be with [minval -maxval].
|
|
|
|
getargnum() {
|
|
|
|
local _b
|
|
|
|
unset _b
|
|
|
|
local _default _min _max
|
|
|
|
_default="$1"; shift
|
|
|
|
_min="$1"; shift
|
|
|
|
_max="$1"; shift
|
|
|
|
_b=$(getarg "$1")
|
|
|
|
[ $? -ne 0 -a -z "$_b" ] && _b=$_default
|
|
|
|
if [ -n "$_b" ]; then
|
|
|
|
isdigit "$_b" && _b=$(($_b)) && \
|
|
|
|
[ $_b -ge $_min ] && [ $_b -le $_max ] && echo $_b && return
|
|
|
|
fi
|
|
|
|
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() {
|
|
|
|
debug_off
|
|
|
|
local _val _i _args _gfound _deprecated
|
|
|
|
unset _val
|
|
|
|
unset _gfound
|
|
|
|
_newoption="$1"
|
|
|
|
_args="$@"
|
|
|
|
set --
|
|
|
|
for _i in $_args; do
|
|
|
|
if [ "$_i" = "-d" ]; then
|
|
|
|
_deprecated=1
|
|
|
|
continue
|
|
|
|
fi
|
|
|
|
_val="$(_dogetargs $_i)"
|
|
|
|
if [ $? -eq 0 ]; then
|
|
|
|
if [ "$_deprecated" = "1" ]; then
|
|
|
|
[ -n "$_newoption" ] && warn "Option '$_i' is deprecated, use '$_newoption' instead." || warn "Option $_i is deprecated!"
|
|
|
|
fi
|
|
|
|
_gfound=1
|
|
|
|
fi
|
|
|
|
[ -n "$_val" ] && set -- "$@" "$_val"
|
|
|
|
_deprecated=0
|
|
|
|
done
|
|
|
|
if [ -n "$_gfound" ]; then
|
|
|
|
if [ $# -gt 0 ]; then
|
|
|
|
printf '%s' "$*"
|
|
|
|
fi
|
|
|
|
debug_on
|
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
debug_on
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Prints value of given option. If option is a flag and it's present,
|
|
|
|
# it just returns 0. Otherwise 1 is returned.
|
|
|
|
# $1 = options separated by commas
|
|
|
|
# $2 = option we are interested in
|
|
|
|
#
|
|
|
|
# Example:
|
|
|
|
# $1 = cipher=aes-cbc-essiv:sha256,hash=sha256,verify
|
|
|
|
# $2 = hash
|
|
|
|
# Output:
|
|
|
|
# sha256
|
|
|
|
getoptcomma() {
|
|
|
|
local line=",$1,"; local opt="$2"; local tmp
|
|
|
|
|
|
|
|
case "${line}" in
|
|
|
|
*,${opt}=*,*)
|
|
|
|
tmp="${line#*,${opt}=}"
|
|
|
|
echo "${tmp%%,*}"
|
|
|
|
return 0
|
|
|
|
;;
|
|
|
|
*,${opt},*) return 0;;
|
|
|
|
esac
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
# Splits given string 'str' with separator 'sep' into variables 'var1', 'var2',
|
|
|
|
# 'varN'. If number of fields is less than number of variables, remaining are
|
|
|
|
# not set. If number of fields is greater than number of variables, the last
|
|
|
|
# variable takes remaining fields. In short - it acts similary to 'read'.
|
|
|
|
#
|
|
|
|
# splitsep sep str var1 var2 varN
|
|
|
|
#
|
|
|
|
# example:
|
|
|
|
# splitsep ':' 'foo:bar:baz' v1 v2
|
|
|
|
# in result:
|
|
|
|
# v1='foo', v2='bar:baz'
|
|
|
|
#
|
|
|
|
# TODO: ':' inside fields.
|
|
|
|
splitsep() {
|
|
|
|
debug_off
|
|
|
|
local sep="$1"; local str="$2"; shift 2
|
|
|
|
local tmp
|
|
|
|
|
|
|
|
while [ -n "$str" -a "$#" -gt 1 ]; do
|
|
|
|
tmp="${str%%$sep*}"
|
|
|
|
eval "$1='${tmp}'"
|
dracut-lib.sh: quote variables in parameter expansion patterns
According to POSIX.1-2017, 2.6.2 Parameter Expansion:
${parameter%[word]} [...] The word shall be expanded to produce a
pattern.
This means if word contains variables that itself contain special
characters like asterisks or backslashes, these are treated as pattern
characters unless the variable is quoted. Try e.g. the following example
in bash, dash or (busybox) ash:
i='a\c'; j='\'; echo "${i%$j*}"
This prints "a\c" because "$j*" is expanded to "\*", escaping the
asterisk. In contrast,
i='a\c'; j='\'; echo "${i%"$j"*}"
produces the expected result "a" because the backslash is not specially
treated any more after quoting.
The quotes that this commit adds have been previously removed in commit
f9c96cf56fed390841eac05c43826e62014c9188, citing issues with busybox
hush without further specifying the actual error. I tested a recent
busybox build (upstream commit 9aa751b08ab03d6396f86c3df77937a19687981b)
and couldn't find any problems. Note that the above example always
produces "a\c" in hush regardless of quoting $j, making hush unsuitable
for use with dracut, but using quotes in parameter expansions generally
works.
The unquoted variables break the "rd.luks.uuid/name" kernel command line
options in dracut 050 because
str_replace "$luksname" '\' '\\'
in modules.d/90crypt/parse-crypt.sh is not able to escape the
backslashes any more, see GH-723, GH-727: backslashes in the
systemd-cryptsetup@.service unit name stay unescaped for use in udev
(cf. commit 0f6d93eb9d63695a64002ec8b0421fbc9fc8a7a3), leading to
failures in starting the unit.
This partially reverts commit f9c96cf56fed390841eac05c43826e62014c9188.
5 years ago
|
|
|
str="${str#"$tmp"}"
|
|
|
|
str="${str#$sep}"
|
|
|
|
shift
|
|
|
|
done
|
|
|
|
[ -n "$str" -a -n "$1" ] && eval "$1='$str'"
|
|
|
|
debug_on
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
setdebug() {
|
|
|
|
[ -f /usr/lib/initrd-release ] || return
|
|
|
|
if [ -z "$RD_DEBUG" ]; then
|
|
|
|
if [ -e /proc/cmdline ]; then
|
|
|
|
RD_DEBUG=no
|
|
|
|
if getargbool 0 rd.debug -d -y rdinitdebug -d -y rdnetdebug; then
|
|
|
|
RD_DEBUG=yes
|
|
|
|
[ -n "$BASH" ] && \
|
|
|
|
export PS4='${BASH_SOURCE}@${LINENO}(${FUNCNAME[0]}): ';
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
export RD_DEBUG
|
|
|
|
fi
|
|
|
|
debug_on
|
|
|
|
}
|
|
|
|
|
|
|
|
setdebug
|
|
|
|
|
|
|
|
source_all() {
|
|
|
|
local f
|
|
|
|
local _dir
|
|
|
|
_dir=$1; shift
|
|
|
|
[ "$_dir" ] && [ -d "/$_dir" ] || return
|
|
|
|
for f in "/$_dir"/*.sh; do [ -e "$f" ] && . "$f" "$@"; done
|
|
|
|
}
|
|
|
|
|
|
|
|
hookdir=/lib/dracut/hooks
|
|
|
|
export hookdir
|
|
|
|
|
|
|
|
source_hook() {
|
|
|
|
local _dir
|
|
|
|
_dir=$1; shift
|
|
|
|
source_all "/lib/dracut/hooks/$_dir" "$@"
|
|
|
|
}
|
|
|
|
|
|
|
|
check_finished() {
|
|
|
|
local f
|
|
|
|
for f in $hookdir/initqueue/finished/*.sh; do
|
|
|
|
[ "$f" = "$hookdir/initqueue/finished/*.sh" ] && return 0
|
|
|
|
{ [ -e "$f" ] && ( . "$f" ) ; } || return 1
|
|
|
|
done
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
source_conf() {
|
|
|
|
local f
|
|
|
|
[ "$1" ] && [ -d "/$1" ] || return
|
|
|
|
for f in "/$1"/*.conf; do [ -e "$f" ] && . "$f"; done
|
|
|
|
}
|
|
|
|
|
|
|
|
die() {
|
|
|
|
{
|
|
|
|
echo "<24>dracut: FATAL: $*";
|
|
|
|
echo "<24>dracut: Refusing to continue";
|
|
|
|
} > /dev/kmsg
|
|
|
|
|
|
|
|
{
|
|
|
|
echo "warn dracut: FATAL: \"$*\"";
|
|
|
|
echo "warn dracut: Refusing to continue";
|
|
|
|
} >> $hookdir/emergency/01-die.sh
|
|
|
|
[ -d /run/initramfs ] || mkdir -p -- /run/initramfs
|
|
|
|
|
|
|
|
> /run/initramfs/.die
|
|
|
|
|
|
|
|
if getargbool 0 "rd.shell"; then
|
|
|
|
emergency_shell
|
|
|
|
else
|
|
|
|
source_hook "shutdown-emergency"
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ -n "$DRACUT_SYSTEMD" ]; then
|
|
|
|
systemctl --no-block --force halt
|
|
|
|
fi
|
|
|
|
|
|
|
|
exit 1
|
|
|
|
}
|
|
|
|
|
|
|
|
check_quiet() {
|
|
|
|
if [ -z "$DRACUT_QUIET" ]; then
|
|
|
|
DRACUT_QUIET="yes"
|
|
|
|
getargbool 0 rd.info -d -y rdinfo && DRACUT_QUIET="no"
|
|
|
|
getargbool 0 rd.debug -d -y rdinitdebug && DRACUT_QUIET="no"
|
|
|
|
getarg quiet || DRACUT_QUIET="yes"
|
|
|
|
a=$(getarg loglevel=)
|
|
|
|
[ -n "$a" ] && [ $a -ge 28 ] && DRACUT_QUIET="yes"
|
|
|
|
export DRACUT_QUIET
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
check_occurances() {
|
|
|
|
# Count the number of times the character $ch occurs in $str
|
|
|
|
# Return 0 if the count matches the expected number, 1 otherwise
|
|
|
|
local str="$1"
|
|
|
|
local ch="$2"
|
|
|
|
local expected="$3"
|
|
|
|
local count=0
|
|
|
|
|
|
|
|
while [ "${str#*$ch}" != "${str}" ]; do
|
|
|
|
str="${str#*$ch}"
|
|
|
|
count=$(( $count + 1 ))
|
|
|
|
done
|
|
|
|
|
|
|
|
[ $count -eq $expected ]
|
|
|
|
}
|
|
|
|
|
|
|
|
incol2() {
|
|
|
|
debug_off
|
|
|
|
local dummy check;
|
|
|
|
local file="$1";
|
|
|
|
local str="$2";
|
|
|
|
|
|
|
|
[ -z "$file" ] && return 1;
|
|
|
|
[ -z "$str" ] && return 1;
|
|
|
|
|
|
|
|
while read dummy check restofline || [ -n "$check" ]; do
|
|
|
|
if [ "$check" = "$str" ]; then
|
|
|
|
debug_on
|
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
done < $file
|
|
|
|
debug_on
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
udevsettle() {
|
|
|
|
[ -z "$UDEVVERSION" ] && export UDEVVERSION=$(udevadm --version)
|
|
|
|
|
|
|
|
if [ $UDEVVERSION -ge 143 ]; then
|
|
|
|
udevadm settle --exit-if-exists=$hookdir/initqueue/work $settle_exit_if_exists
|
|
|
|
else
|
|
|
|
udevadm settle --timeout=30
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
udevproperty() {
|
|
|
|
[ -z "$UDEVVERSION" ] && export UDEVVERSION=$(udevadm --version)
|
|
|
|
|
|
|
|
if [ $UDEVVERSION -ge 143 ]; then
|
|
|
|
for i in "$@"; do udevadm control --property=$i; done
|
|
|
|
else
|
|
|
|
for i in "$@"; do udevadm control --env=$i; done
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
find_mount() {
|
|
|
|
local dev mnt etc wanted_dev
|
|
|
|
wanted_dev="$(readlink -e -q $1)"
|
|
|
|
while read dev mnt etc || [ -n "$dev" ]; do
|
|
|
|
[ "$dev" = "$wanted_dev" ] && echo "$dev" && return 0
|
|
|
|
done < /proc/mounts
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
# usage: ismounted <mountpoint>
|
|
|
|
# usage: ismounted /dev/<device>
|
|
|
|
if command -v findmnt >/dev/null; then
|
|
|
|
ismounted() {
|
|
|
|
findmnt "$1" > /dev/null 2>&1
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ismounted() {
|
|
|
|
if [ -b "$1" ]; then
|
|
|
|
find_mount "$1" > /dev/null && return 0
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
while read a m a || [ -n "$m" ]; do
|
|
|
|
[ "$m" = "$1" ] && return 0
|
|
|
|
done < /proc/mounts
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Create udev rule match for a device with its device name, or the udev property
|
|
|
|
# ID_FS_UUID or ID_FS_LABEL
|
|
|
|
#
|
|
|
|
# example:
|
|
|
|
# udevmatch LABEL=boot
|
|
|
|
# prints:
|
|
|
|
# ENV{ID_FS_LABEL}="boot"
|
|
|
|
#
|
|
|
|
# TODO: symlinks
|
|
|
|
udevmatch() {
|
|
|
|
case "$1" in
|
|
|
|
UUID=????????-????-????-????-????????????|LABEL=*|PARTLABEL=*|PARTUUID=????????-????-????-????-????????????)
|
|
|
|
printf 'ENV{ID_FS_%s}=="%s"' "${1%%=*}" "${1#*=}"
|
|
|
|
;;
|
|
|
|
UUID=*)
|
|
|
|
printf 'ENV{ID_FS_UUID}=="%s*"' "${1#*=}"
|
|
|
|
;;
|
|
|
|
PARTUUID=*)
|
|
|
|
printf 'ENV{ID_FS_PARTUUID}=="%s*"' "${1#*=}"
|
|
|
|
;;
|
|
|
|
/dev/?*) printf -- 'KERNEL=="%s"' "${1#/dev/}" ;;
|
|
|
|
*) return 255 ;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
|
|
|
# Prints unique path for potential file inside specified directory. It consists
|
|
|
|
# of specified directory, prefix and number at the end which is incremented
|
|
|
|
# until non-existing file is found.
|
|
|
|
#
|
|
|
|
# funiq dir prefix
|
|
|
|
#
|
|
|
|
# example:
|
|
|
|
# # ls /mnt
|
|
|
|
# cdrom0 cdrom1
|
|
|
|
#
|
|
|
|
# # funiq /mnt cdrom
|
|
|
|
# /mnt/cdrom2
|
|
|
|
funiq() {
|
|
|
|
local dir="$1"; local prefix="$2"
|
|
|
|
local i=0
|
|
|
|
|
|
|
|
[ -d "${dir}" ] || return 1
|
|
|
|
|
|
|
|
while [ -e "${dir}/${prefix}$i" ]; do
|
|
|
|
i=$(($i+1)) || return 1
|
|
|
|
done
|
|
|
|
|
|
|
|
echo "${dir}/${prefix}$i"
|
|
|
|
}
|
|
|
|
|
|
|
|
# Creates unique directory and prints its path. It's using funiq to generate
|
|
|
|
# path.
|
|
|
|
#
|
|
|
|
# mkuniqdir subdir new_dir_name
|
|
|
|
mkuniqdir() {
|
|
|
|
local dir="$1"; local prefix="$2"
|
|
|
|
local retdir; local retdir_new
|
|
|
|
|
|
|
|
[ -d "${dir}" ] || mkdir -m 0755 -p "${dir}" || return 1
|
|
|
|
|
|
|
|
retdir=$(funiq "${dir}" "${prefix}") || return 1
|
|
|
|
until mkdir -m 0755 "${retdir}" 2>/dev/null; do
|
|
|
|
retdir_new=$(funiq "${dir}" "${prefix}") || return 1
|
|
|
|
[ "$retdir_new" = "$retdir" ] && return 1
|
|
|
|
retdir="$retdir_new"
|
|
|
|
done
|
|
|
|
|
|
|
|
echo "${retdir}"
|
|
|
|
}
|
|
|
|
|
|
|
|
# Copy the contents of SRC into DEST, merging the contents of existing
|
|
|
|
# directories (kinda like rsync, or cpio -p).
|
|
|
|
# Creates DEST if it doesn't exist. Overwrites files with the same names.
|
|
|
|
#
|
|
|
|
# copytree SRC DEST
|
|
|
|
copytree() {
|
|
|
|
local src="$1" dest="$2"
|
|
|
|
mkdir -p "$dest"; dest=$(readlink -e -q "$dest")
|
|
|
|
( cd "$src"; cp -af . -t "$dest" )
|
|
|
|
}
|
|
|
|
|
|
|
|
# Evaluates command for UUIDs either given as arguments for this function or all
|
|
|
|
# listed in /dev/disk/by-uuid. UUIDs doesn't have to be fully specified. If
|
|
|
|
# beginning is given it is expanded to all matching UUIDs. To pass full UUID to
|
|
|
|
# your command use '$___' as a place holder. Remember to escape '$'!
|
|
|
|
#
|
|
|
|
# foreach_uuid_until [ -p prefix ] command UUIDs
|
|
|
|
#
|
|
|
|
# prefix - string to put just before $___
|
|
|
|
# command - command to be evaluated
|
|
|
|
# UUIDs - list of UUIDs separated by space
|
|
|
|
#
|
|
|
|
# The function returns after *first successful evaluation* of the given command
|
|
|
|
# with status 0. If evaluation fails for every UUID function returns with
|
|
|
|
# status 1.
|
|
|
|
#
|
|
|
|
# Example:
|
|
|
|
# foreach_uuid_until "mount -U \$___ /mnt; echo OK; umount /mnt" \
|
|
|
|
# "01234 f512 a235567f-12a3-c123-a1b1-01234567abcb"
|
|
|
|
foreach_uuid_until() (
|
|
|
|
cd /dev/disk/by-uuid
|
|
|
|
|
|
|
|
[ "$1" = -p ] && local prefix="$2" && shift 2
|
|
|
|
local cmd="$1"; shift; local uuids_list="$*"
|
|
|
|
local uuid; local full_uuid; local ___
|
|
|
|
|
|
|
|
[ -n "${cmd}" ] || return 1
|
|
|
|
|
|
|
|
for uuid in ${uuids_list:-*}; do
|
|
|
|
for full_uuid in ${uuid}*; do
|
|
|
|
[ -e "${full_uuid}" ] || continue
|
|
|
|
___="${prefix}${full_uuid}"
|
|
|
|
eval ${cmd} && return 0
|
|
|
|
done
|
|
|
|
done
|
|
|
|
|
|
|
|
return 1
|
|
|
|
)
|
|
|
|
|
|
|
|
# Get kernel name for given device. Device may be the name too (then the same
|
|
|
|
# is returned), a symlink (full path), UUID (prefixed with "UUID=") or label
|
|
|
|
# (prefixed with "LABEL="). If just a beginning of the UUID is specified or
|
|
|
|
# even an empty, function prints all device names which UUIDs match - every in
|
|
|
|
# single line.
|
|
|
|
#
|
|
|
|
# NOTICE: The name starts with "/dev/".
|
|
|
|
#
|
|
|
|
# Example:
|
|
|
|
# devnames UUID=123
|
|
|
|
# May print:
|
|
|
|
# /dev/dm-1
|
|
|
|
# /dev/sdb1
|
|
|
|
# /dev/sdf3
|
|
|
|
devnames() {
|
|
|
|
local dev="$1"; local d; local names
|
|
|
|
|
|
|
|
case "$dev" in
|
|
|
|
UUID=*)
|
|
|
|
dev="$(foreach_uuid_until '! blkid -U $___' "${dev#UUID=}")" \
|
|
|
|
&& return 255
|
|
|
|
[ -z "$dev" ] && return 255
|
|
|
|
;;
|
|
|
|
LABEL=*) dev="$(blkid -L "${dev#LABEL=}")" || return 255 ;;
|
|
|
|
/dev/?*) ;;
|
|
|
|
*) return 255 ;;
|
|
|
|
esac
|
|
|
|
|
|
|
|
for d in $dev; do
|
|
|
|
names="$names
|
|
|
|
$(readlink -e -q "$d")" || return 255
|
|
|
|
done
|
|
|
|
|
|
|
|
echo "${names#
|
|
|
|
}"
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
usable_root() {
|
|
|
|
local _i
|
|
|
|
|
|
|
|
[ -d "$1" ] || return 1
|
|
|
|
|
|
|
|
for _i in "$1"/usr/lib*/ld-*.so "$1"/lib*/ld-*.so; do
|
|
|
|
[ -e "$_i" ] && return 0
|
|
|
|
done
|
|
|
|
|
|
|
|
for _i in proc sys dev; do
|
|
|
|
[ -e "$1"/$_i ] || return 1
|
|
|
|
done
|
|
|
|
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
inst_hook() {
|
|
|
|
local _hookname _unique _name _job _exe
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
case "$1" in
|
|
|
|
--hook)
|
|
|
|
_hookname="/$2";shift;;
|
|
|
|
--unique)
|
|
|
|
_unique="yes";;
|
|
|
|
--name)
|
|
|
|
_name="$2";shift;;
|
|
|
|
*)
|
|
|
|
break;;
|
|
|
|
esac
|
|
|
|
shift
|
|
|
|
done
|
|
|
|
|
|
|
|
if [ -z "$_unique" ]; then
|
|
|
|
_job="${_name}$$"
|
|
|
|
else
|
|
|
|
_job="${_name:-$1}"
|
|
|
|
_job=${_job##*/}
|
|
|
|
fi
|
|
|
|
|
|
|
|
_exe=$1
|
|
|
|
shift
|
|
|
|
|
|
|
|
[ -x "$_exe" ] || _exe=$(command -v $_exe)
|
|
|
|
|
|
|
|
if [ -n "$onetime" ]; then
|
|
|
|
{
|
|
|
|
echo '[ -e "$_job" ] && rm -f -- "$_job"'
|
|
|
|
echo "$_exe $@"
|
|
|
|
} > "/tmp/$$-${_job}.sh"
|
|
|
|
else
|
|
|
|
echo "$_exe $@" > "/tmp/$$-${_job}.sh"
|
|
|
|
fi
|
|
|
|
|
|
|
|
mv -f "/tmp/$$-${_job}.sh" "$hookdir/${_hookname}/${_job}.sh"
|
|
|
|
}
|
|
|
|
|
|
|
|
# inst_mount_hook <mountpoint> <prio> <name> <script>
|
|
|
|
#
|
|
|
|
# Install a mount hook with priority <prio>,
|
|
|
|
# which executes <script> as soon as <mountpoint> is mounted.
|
|
|
|
inst_mount_hook() {
|
|
|
|
local _prio="$2" _jobname="$3" _script="$4"
|
|
|
|
local _hookname="mount-$(str_replace "$1" '/' '\\x2f')"
|
|
|
|
[ -d "$hookdir/${_hookname}" ] || mkdir -p "$hookdir/${_hookname}"
|
|
|
|
inst_hook --hook "$_hookname" --unique --name "${_prio}-${_jobname}" "$_script"
|
|
|
|
}
|
|
|
|
|
|
|
|
# add_mount_point <dev> <mountpoint> <filesystem> <fsopts>
|
|
|
|
#
|
|
|
|
# Mount <dev> on <mountpoint> with <filesystem> and <fsopts>
|
|
|
|
# and call any mount hooks, as soon, as it is mounted
|
|
|
|
add_mount_point() {
|
|
|
|
local _dev="$1" _mp="$2" _fs="$3" _fsopts="$4"
|
|
|
|
local _hookname="mount-$(str_replace "$2" '/' '\\x2f')"
|
|
|
|
local _devname="dev-$(str_replace "$1" '/' '\\x2f')"
|
|
|
|
echo "$_dev $_mp $_fs $_fsopts 0 0" >> /etc/fstab
|
|
|
|
|
|
|
|
exec 7>/etc/udev/rules.d/99-mount-${_devname}.rules
|
|
|
|
echo 'SUBSYSTEM!="block", GOTO="mount_end"' >&7
|
|
|
|
echo 'ACTION!="add|change", GOTO="mount_end"' >&7
|
|
|
|
if [ -n "$_dev" ]; then
|
|
|
|
udevmatch "$_dev" >&7 || {
|
|
|
|
warn "add_mount_point dev=$_dev incorrect!"
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
printf ', ' >&7
|
|
|
|
fi
|
|
|
|
|
|
|
|
{
|
|
|
|
printf -- 'RUN+="%s --unique --onetime ' $(command -v initqueue)
|
|
|
|
printf -- '--name mount-%%k '
|
|
|
|
printf -- '%s %s"\n' "$(command -v mount_hook)" "${_mp}"
|
|
|
|
} >&7
|
|
|
|
echo 'LABEL="mount_end"' >&7
|
|
|
|
exec 7>&-
|
|
|
|
}
|
|
|
|
|
|
|
|
# wait_for_mount <mountpoint>
|
|
|
|
#
|
|
|
|
# Installs a initqueue-finished script,
|
|
|
|
# which will cause the main loop only to exit,
|
|
|
|
# if <mountpoint> is mounted.
|
|
|
|
wait_for_mount()
|
|
|
|
{
|
|
|
|
local _name
|
|
|
|
_name="$(str_replace "$1" '/' '\\x2f')"
|
|
|
|
printf '. /lib/dracut-lib.sh\nismounted "%s"\n' $1 \
|
|
|
|
>> "$hookdir/initqueue/finished/ismounted-${_name}.sh"
|
|
|
|
{
|
|
|
|
printf 'ismounted "%s" || ' $1
|
|
|
|
printf 'warn "\"%s\" is not mounted"\n' $1
|
|
|
|
} >> "$hookdir/emergency/90-${_name}.sh"
|
|
|
|
}
|
|
|
|
|
|
|
|
# get a systemd-compatible unit name from a path
|
|
|
|
# (mimicks unit_name_from_path_instance())
|
|
|
|
dev_unit_name()
|
|
|
|
{
|
|
|
|
local dev="$1"
|
|
|
|
|
|
|
|
if command -v systemd-escape >/dev/null; then
|
|
|
|
systemd-escape -p -- "$dev"
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ "$dev" = "/" -o -z "$dev" ]; then
|
|
|
|
printf -- "-"
|
|
|
|
exit 0
|
|
|
|
fi
|
|
|
|
|
|
|
|
dev="${1%%/}"
|
|
|
|
dev="${dev##/}"
|
|
|
|
dev="$(str_replace "$dev" '\' '\x5c')"
|
|
|
|
dev="$(str_replace "$dev" '-' '\x2d')"
|
|
|
|
if [ "${dev##.}" != "$dev" ]; then
|
|
|
|
dev="\x2e${dev##.}"
|
|
|
|
fi
|
|
|
|
dev="$(str_replace "$dev" '/' '-')"
|
|
|
|
|
|
|
|
printf -- "%s" "$dev"
|
|
|
|
}
|
|
|
|
|
|
|
|
# set_systemd_timeout_for_dev <dev>
|
|
|
|
# Set 'rd.timeout' as the systemd timeout for <dev>
|
|
|
|
|
|
|
|
set_systemd_timeout_for_dev()
|
|
|
|
{
|
|
|
|
local _name
|
|
|
|
local _needreload
|
|
|
|
local _noreload
|
|
|
|
local _timeout
|
|
|
|
|
|
|
|
if [ "$1" = "-n" ]; then
|
|
|
|
_noreload=1
|
|
|
|
shift
|
|
|
|
fi
|
|
|
|
|
|
|
|
_timeout=$(getarg rd.timeout)
|
|
|
|
_timeout=${_timeout:-0}
|
|
|
|
|
|
|
|
if [ -n "$DRACUT_SYSTEMD" ]; then
|
|
|
|
_name=$(dev_unit_name "$1")
|
|
|
|
if ! [ -L ${PREFIX}/etc/systemd/system/initrd.target.wants/${_name}.device ]; then
|
|
|
|
[ -d ${PREFIX}/etc/systemd/system/initrd.target.wants ] || mkdir -p ${PREFIX}/etc/systemd/system/initrd.target.wants
|
|
|
|
ln -s ../${_name}.device ${PREFIX}/etc/systemd/system/initrd.target.wants/${_name}.device
|
|
|
|
type mark_hostonly >/dev/null 2>&1 && mark_hostonly /etc/systemd/system/initrd.target.wants/${_name}.device
|
|
|
|
_needreload=1
|
|
|
|
fi
|
|
|
|
|
|
|
|
if ! [ -f ${PREFIX}/etc/systemd/system/${_name}.device.d/timeout.conf ]; then
|
|
|
|
mkdir -p ${PREFIX}/etc/systemd/system/${_name}.device.d
|
|
|
|
{
|
|
|
|
echo "[Unit]"
|
|
|
|
echo "JobTimeoutSec=$_timeout"
|
|
|
|
echo "JobRunningTimeoutSec=$_timeout"
|
|
|
|
} > ${PREFIX}/etc/systemd/system/${_name}.device.d/timeout.conf
|
|
|
|
type mark_hostonly >/dev/null 2>&1 && mark_hostonly /etc/systemd/system/${_name}.device.d/timeout.conf
|
|
|
|
_needreload=1
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ -z "$PREFIX" ] && [ "$_needreload" = 1 ] && [ -z "$_noreload" ]; then
|
|
|
|
/sbin/initqueue --onetime --unique --name daemon-reload systemctl daemon-reload
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
# wait_for_dev <dev>
|
|
|
|
#
|
|
|
|
# Installs a initqueue-finished script,
|
|
|
|
# which will cause the main loop only to exit,
|
|
|
|
# if the device <dev> is recognized by the system.
|
|
|
|
wait_for_dev()
|
|
|
|
{
|
|
|
|
local _name
|
|
|
|
local _noreload
|
|
|
|
|
|
|
|
if [ "$1" = "-n" ]; then
|
|
|
|
_noreload=-n
|
|
|
|
shift
|
|
|
|
fi
|
|
|
|
|
|
|
|
_name="$(str_replace "$1" '/' '\x2f')"
|
|
|
|
|
|
|
|
type mark_hostonly >/dev/null 2>&1 && mark_hostonly "$hookdir/initqueue/finished/devexists-${_name}.sh"
|
|
|
|
|
|
|
|
[ -e "${PREFIX}$hookdir/initqueue/finished/devexists-${_name}.sh" ] && return 0
|
|
|
|
|
|
|
|
printf '[ -e "%s" ]\n' $1 \
|
|
|
|
>> "${PREFIX}$hookdir/initqueue/finished/devexists-${_name}.sh"
|
|
|
|
{
|
|
|
|
printf '[ -e "%s" ] || ' $1
|
|
|
|
printf 'warn "\"%s\" does not exist"\n' $1
|
|
|
|
} >> "${PREFIX}$hookdir/emergency/80-${_name}.sh"
|
|
|
|
|
|
|
|
set_systemd_timeout_for_dev $_noreload $1
|
|
|
|
}
|
|
|
|
|
|
|
|
cancel_wait_for_dev()
|
|
|
|
{
|
|
|
|
local _name
|
|
|
|
_name="$(str_replace "$1" '/' '\x2f')"
|
|
|
|
rm -f -- "$hookdir/initqueue/finished/devexists-${_name}.sh"
|
|
|
|
rm -f -- "$hookdir/emergency/80-${_name}.sh"
|
|
|
|
if [ -n "$DRACUT_SYSTEMD" ]; then
|
|
|
|
_name=$(dev_unit_name "$1")
|
|
|
|
rm -f -- ${PREFIX}/etc/systemd/system/initrd.target.wants/${_name}.device
|
|
|
|
rm -f -- ${PREFIX}/etc/systemd/system/${_name}.device.d/timeout.conf
|
|
|
|
/sbin/initqueue --onetime --unique --name daemon-reload systemctl daemon-reload
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
killproc() {
|
|
|
|
debug_off
|
|
|
|
local _exe="$(command -v $1)"
|
|
|
|
local _sig=$2
|
|
|
|
local _i
|
|
|
|
[ -x "$_exe" ] || return 1
|
|
|
|
for _i in /proc/[0-9]*; do
|
|
|
|
[ "$_i" = "/proc/1" ] && continue
|
|
|
|
if [ -e "$_i"/_exe ] && [ "$_i/_exe" -ef "$_exe" ] ; then
|
|
|
|
kill $_sig ${_i##*/}
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
debug_on
|
|
|
|
}
|
|
|
|
|
|
|
|
need_shutdown() {
|
|
|
|
>/run/initramfs/.need_shutdown
|
|
|
|
}
|
|
|
|
|
|
|
|
wait_for_loginit()
|
|
|
|
{
|
|
|
|
[ "$RD_DEBUG" = "yes" ] || return
|
|
|
|
[ -e /run/initramfs/loginit.pipe ] || return
|
|
|
|
debug_off
|
|
|
|
echo "DRACUT_LOG_END"
|
|
|
|
exec 0<>/dev/console 1<>/dev/console 2<>/dev/console
|
|
|
|
# wait for loginit
|
|
|
|
i=0
|
|
|
|
while [ $i -lt 10 ]; do
|
|
|
|
if [ ! -e /run/initramfs/loginit.pipe ]; then
|
|
|
|
j=$(jobs)
|
|
|
|
[ -z "$j" ] && break
|
|
|
|
[ -z "${j##*Running*}" ] || break
|
|
|
|
fi
|
|
|
|
sleep 0.1
|
|
|
|
i=$(($i+1))
|
|
|
|
done
|
|
|
|
|
|
|
|
if [ $i -eq 10 ]; then
|
|
|
|
kill %1 >/dev/null 2>&1
|
|
|
|
kill $(while read line || [ -n "$line" ];do echo $line;done</run/initramfs/loginit.pid)
|
|
|
|
fi
|
|
|
|
|
|
|
|
setdebug
|
|
|
|
rm -f -- /run/initramfs/loginit.pipe /run/initramfs/loginit.pid
|
|
|
|
}
|
|
|
|
|
|
|
|
# pidof version for root
|
|
|
|
if ! command -v pidof >/dev/null 2>/dev/null; then
|
|
|
|
pidof() {
|
|
|
|
debug_off
|
|
|
|
local _cmd
|
|
|
|
local _exe
|
|
|
|
local _rl
|
|
|
|
local _ret=1
|
|
|
|
local i
|
|
|
|
_cmd="$1"
|
|
|
|
if [ -z "$_cmd" ]; then
|
|
|
|
debug_on
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
_exe=$(command -v "$1")
|
|
|
|
for i in /proc/*/exe; do
|
|
|
|
[ -e "$i" ] || continue
|
|
|
|
if [ -n "$_exe" ]; then
|
|
|
|
[ "$i" -ef "$_exe" ] || continue
|
|
|
|
else
|
|
|
|
_rl=$(readlink -f "$i");
|
|
|
|
[ "${_rl%/$_cmd}" != "$_rl" ] || continue
|
|
|
|
fi
|
|
|
|
i=${i%/exe}
|
|
|
|
echo ${i##/proc/}
|
|
|
|
_ret=0
|
|
|
|
done
|
|
|
|
debug_on
|
|
|
|
return $_ret
|
|
|
|
}
|
|
|
|
fi
|
|
|
|
|
|
|
|
_emergency_shell()
|
|
|
|
{
|
|
|
|
local _name="$1"
|
|
|
|
if [ -n "$DRACUT_SYSTEMD" ]; then
|
|
|
|
> /.console_lock
|
|
|
|
echo "PS1=\"$_name:\\\${PWD}# \"" >/etc/profile
|
|
|
|
systemctl start dracut-emergency.service
|
|
|
|
rm -f -- /etc/profile
|
|
|
|
rm -f -- /.console_lock
|
|
|
|
else
|
|
|
|
debug_off
|
|
|
|
source_hook "$hook"
|
|
|
|
echo
|
|
|
|
/sbin/rdsosreport
|
|
|
|
echo 'You might want to save "/run/initramfs/rdsosreport.txt" to a USB stick or /boot'
|
|
|
|
echo 'after mounting them and attach it to a bug report.'
|
|
|
|
if ! RD_DEBUG= getargbool 0 rd.debug -d -y rdinitdebug -d -y rdnetdebug; then
|
|
|
|
echo
|
|
|
|
echo 'To get more debug information in the report,'
|
|
|
|
echo 'reboot with "rd.debug" added to the kernel command line.'
|
|
|
|
fi
|
|
|
|
echo
|
|
|
|
echo 'Dropping to debug shell.'
|
|
|
|
echo
|
|
|
|
export PS1="$_name:\${PWD}# "
|
|
|
|
[ -e /.profile ] || >/.profile
|
|
|
|
|
|
|
|
_ctty="$(RD_DEBUG= getarg rd.ctty=)" && _ctty="/dev/${_ctty##*/}"
|
|
|
|
if [ -z "$_ctty" ]; then
|
|
|
|
_ctty=console
|
|
|
|
while [ -f /sys/class/tty/$_ctty/active ]; do
|
|
|
|
_ctty=$(cat /sys/class/tty/$_ctty/active)
|
|
|
|
_ctty=${_ctty##* } # last one in the list
|
|
|
|
done
|
|
|
|
_ctty=/dev/$_ctty
|
|
|
|
fi
|
|
|
|
[ -c "$_ctty" ] || _ctty=/dev/tty1
|
|
|
|
case "$(/usr/bin/setsid --help 2>&1)" in *--ctty*) CTTY="--ctty";; esac
|
|
|
|
setsid $CTTY /bin/sh -i -l 0<>$_ctty 1<>$_ctty 2<>$_ctty
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
emergency_shell()
|
|
|
|
{
|
|
|
|
local _ctty
|
|
|
|
set +e
|
|
|
|
local _rdshell_name="dracut" action="Boot" hook="emergency"
|
|
|
|
local _emergency_action
|
|
|
|
|
|
|
|
if [ "$1" = "-n" ]; then
|
|
|
|
_rdshell_name=$2
|
|
|
|
shift 2
|
|
|
|
elif [ "$1" = "--shutdown" ]; then
|
|
|
|
_rdshell_name=$2; action="Shutdown"; hook="shutdown-emergency"
|
|
|
|
if type plymouth >/dev/null 2>&1; then
|
|
|
|
plymouth --hide-splash
|
|
|
|
elif [ -x /oldroot/bin/plymouth ]; then
|
|
|
|
/oldroot/bin/plymouth --hide-splash
|
|
|
|
fi
|
|
|
|
shift 2
|
|
|
|
fi
|
|
|
|
|
|
|
|
echo ; echo
|
|
|
|
warn "$*"
|
|
|
|
echo
|
|
|
|
|
|
|
|
_emergency_action=$(getarg rd.emergency)
|
|
|
|
[ -z "$_emergency_action" ] \
|
|
|
|
&& [ -e /run/initramfs/.die ] \
|
|
|
|
&& _emergency_action=halt
|
|
|
|
|
|
|
|
if getargbool 1 rd.shell -d -y rdshell || getarg rd.break -d rdbreak; then
|
|
|
|
_emergency_shell $_rdshell_name
|
|
|
|
else
|
|
|
|
source_hook "$hook"
|
|
|
|
warn "$action has failed. To debug this issue add \"rd.shell rd.debug\" to the kernel command line."
|
|
|
|
[ -z "$_emergency_action" ] && _emergency_action=halt
|
|
|
|
fi
|
|
|
|
|
|
|
|
case "$_emergency_action" in
|
|
|
|
reboot)
|
|
|
|
reboot || exit 1;;
|
|
|
|
poweroff)
|
|
|
|
poweroff || exit 1;;
|
|
|
|
halt)
|
|
|
|
halt || exit 1;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
|
|
|
# Retain the values of these variables but ensure that they are unexported
|
|
|
|
# This is a POSIX-compliant equivalent of bash's "export -n"
|
|
|
|
export_n()
|
|
|
|
{
|
|
|
|
local var
|
|
|
|
local val
|
|
|
|
for var in "$@"; do
|
|
|
|
eval val=\$$var
|
|
|
|
unset $var
|
|
|
|
[ -n "$val" ] && eval $var=\"$val\"
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
# returns OK if list1 contains all elements of list2, i.e. checks if list2 is a
|
|
|
|
# sublist of list1. An order and a duplication doesn't matter.
|
|
|
|
#
|
|
|
|
# $1 = separator
|
|
|
|
# $2 = list1
|
|
|
|
# $3 = list2
|
|
|
|
# $4 = ignore values, separated by $1
|
|
|
|
listlist() {
|
|
|
|
local _sep="$1"
|
|
|
|
local _list="${_sep}${2}${_sep}"
|
|
|
|
local _sublist="$3"
|
|
|
|
[ -n "$4" ] && local _iglist="${_sep}${4}${_sep}"
|
|
|
|
local IFS="$_sep"
|
|
|
|
local _v
|
|
|
|
|
|
|
|
[ "$_list" = "$_sublist" ] && return 0
|
|
|
|
|
|
|
|
for _v in $_sublist; do
|
|
|
|
if [ -n "$_v" ] && ! ( [ -n "$_iglist" ] && strstr "$_iglist" "$_v" )
|
|
|
|
then
|
|
|
|
strstr "$_list" "$_v" || return 1
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
# returns OK if both lists contain the same values. An order and a duplication
|
|
|
|
# doesn't matter.
|
|
|
|
#
|
|
|
|
# $1 = separator
|
|
|
|
# $2 = list1
|
|
|
|
# $3 = list2
|
|
|
|
# $4 = ignore values, separated by $1
|
|
|
|
are_lists_eq() {
|
|
|
|
listlist "$1" "$2" "$3" "$4" && listlist "$1" "$3" "$2" "$4"
|
|
|
|
}
|
|
|
|
|
|
|
|
setmemdebug() {
|
|
|
|
if [ -z "$DEBUG_MEM_LEVEL" ]; then
|
Add 99memstrack module
memstrack is a new tool to track the overall memory usage and
allocation, which can help off load the improve the builtin module
memory tracing function in dracut.
With this change, the rd.memdebug=4 behavior is similiar with before,
but the report is defered to pre-pivot, so the memory usage info
during the whole initramfs run is traced. And the ourput format is
changed a bit:
dracut-pre-pivot[519]: ======== Report format module_summary: ========
dracut-pre-pivot[519]: Module squashfs using 10.4MB (2658 pages), peak allocation 10.4MB (2671 pages)
dracut-pre-pivot[519]: Module qxl using 3.4MB (865 pages), peak allocation 3.4MB (880 pages)
dracut-pre-pivot[519]: Module crc32c_intel using 2.0MB (519 pages), peak allocation 3.0MB (769 pages)
dracut-pre-pivot[519]: Module serio_raw using 2.0MB (505 pages), peak allocation 3.6MB (918 pages)
dracut-pre-pivot[519]: Module virtio_console using 1.6MB (416 pages), peak allocation 1.6MB (419 pages)
... snip ...
dracut-pre-pivot[519]: ======== Report format module_summary END ========
It now contains more detail and also includes the peak usage which could
be more helpful.
And now it have a rd.memdebug=5, which will print more detail about
the stack trace of the top memory user, also printed on pri-pivot:
dracut-pre-pivot[519]: ======== Report format module_top: ========
dracut-pre-pivot[519]: Top stack usage of module squashfs:
dracut-pre-pivot[519]: (null) Pages: 2658 (peak: 2671)
dracut-pre-pivot[519]: (null) Pages: 2658 (peak: 2671)
dracut-pre-pivot[519]: async_page_fault (0xffffffff81a01149) Pages: 1448 (peak: 1461)
dracut-pre-pivot[519]: do_async_page_fault (0xffffffff8105c509) Pages: 1448 (peak: 1461)
dracut-pre-pivot[519]: do_page_fault (0xffffffff8106296a) Pages: 1448 (peak: 1461)
dracut-pre-pivot[519]: do_user_addr_fault (0xffffffff810626bd) Pages: 1448 (peak: 1461)
dracut-pre-pivot[519]: handle_mm_fault (0xffffffff812940c4) Pages: 1448 (peak: 1461)
dracut-pre-pivot[519]: __handle_mm_fault (0xffffffff81293627) Pages: 1195 (peak: 1208)
dracut-pre-pivot[519]: __do_fault (0xffffffff8128b07e) Pages: 1195 (peak: 1208)
dracut-pre-pivot[519]: filemap_fault (0xffffffff8124c0b9) Pages: 1195 (peak: 1208)
dracut-pre-pivot[519]: __do_page_cache_readahead (0xffffffff812585da) Pages: 1063 (peak: 1076)
dracut-pre-pivot[519]: read_pages (0xffffffff812583c2) Pages: 1063 (peak: 1076)
dracut-pre-pivot[519]: squashfs_readpage squashfs (0xffffffffc0022073) Pages: 1039 (peak: 1052)
dracut-pre-pivot[519]: squashfs_readpage_block squashfs (0xffffffffc0024334) Pages: 744 (peak: 744)
dracut-pre-pivot[519]: squashfs_copy_cache squashfs (0xffffffffc0021a3f) Pages: 744 (peak: 744)
dracut-pre-pivot[519]: pagecache_get_page (0xffffffff8124abf7) Pages: 744 (peak: 744)
dracut-pre-pivot[519]: __page_cache_alloc (0xffffffff81247df6) Pages: 744 (peak: 744)
dracut-pre-pivot[519]: alloc_pages_current (0xffffffff812cdca7) Pages: 744 (peak: 744)
dracut-pre-pivot[519]: __alloc_pages_nodemask (0xffffffff812b3107) Pages: 744 (peak: 744)
dracut-pre-pivot[519]: __alloc_pages_nodemask (0xffffffff812b3107) Pages: 1488 (peak: 1488)
dracut-pre-pivot[519]: Top stack usage of module qxl:
dracut-pre-pivot[519]: (null) Pages: 865 (peak: 880)
dracut-pre-pivot[519]: entry_SYSCALL_64_after_hwframe (0xffffffff81a0008c) Pages: 855 (peak: 858)
dracut-pre-pivot[519]: do_syscall_64 (0xffffffff81002a5a) Pages: 855 (peak: 858)
dracut-pre-pivot[519]: __x64_sys_finit_module (0xffffffff8117ccea) Pages: 811 (peak: 811)
dracut-pre-pivot[519]: __do_sys_finit_module (0xffffffff8117cc6e) Pages: 811 (peak: 811)
dracut-pre-pivot[519]: load_module (0xffffffff8117c6be) Pages: 802 (peak: 802)
dracut-pre-pivot[519]: do_init_module (0xffffffff81179e72) Pages: 802 (peak: 802)
dracut-pre-pivot[519]: do_one_initcall (0xffffffff81000d5a) Pages: 802 (peak: 802)
dracut-pre-pivot[519]: serio_raw_poll serio_raw (0xffffffffc0200054) Pages: 802 (peak: 802)
dracut-pre-pivot[519]: __pci_register_driver (0xffffffff81557804) Pages: 802 (peak: 802)
dracut-pre-pivot[519]: driver_register (0xffffffff8167ed24) Pages: 802 (peak: 802)
dracut-pre-pivot[519]: bus_add_driver (0xffffffff8167cbb2) Pages: 801 (peak: 801)
dracut-pre-pivot[519]: driver_attach (0xffffffff8167d28e) Pages: 801 (peak: 801)
dracut-pre-pivot[519]: bus_for_each_dev (0xffffffff8167b62c) Pages: 801 (peak: 801)
dracut-pre-pivot[519]: __driver_attach (0xffffffff8167e18f) Pages: 801 (peak: 801)
dracut-pre-pivot[519]: device_driver_attach (0xffffffff8167e0ed) Pages: 801 (peak: 801)
dracut-pre-pivot[519]: driver_probe_device (0xffffffff8167de6c) Pages: 801 (peak: 801)
dracut-pre-pivot[519]: really_probe (0xffffffff8167d9c9) Pages: 801 (peak: 801)
dracut-pre-pivot[519]: pci_device_probe (0xffffffff81559627) Pages: 801 (peak: 801)
dracut-pre-pivot[519]: local_pci_probe (0xffffffff81557f98) Pages: 801 (peak: 801)
dracut-pre-pivot[519]: qxl_pci_probe qxl (0xffffffffc01f0387) Pages: 773 (peak: 773)
dracut-pre-pivot[519]: drm_fbdev_generic_setup drm_kms_helper (0xffffffffc01b30c5) Pages: 773 (peak: 773)
dracut-pre-pivot[519]: drm_fbdev_client_hotplug drm_kms_helper (0xffffffffc01b2656) Pages: 773 (peak: 773)
dracut-pre-pivot[519]: __drm_fb_helper_initial_config_and_unlock drm_kms_helper (0xffffffffc01b1a28) Pages: 770 (peak: 770)
dracut-pre-pivot[519]: drm_fb_helper_generic_probe drm_kms_helper (0xffffffffc01b2fa5) Pages: 770 (peak: 770)
dracut-pre-pivot[519]: vzalloc (0xffffffff812aa39c) Pages: 770 (peak: 770)
dracut-pre-pivot[519]: __vmalloc_node_range (0xffffffff812aa200) Pages: 768 (peak: 768)
... snip ...
======== Report format module_top END ========
This could be very helpful for debuging memory usage issues.
5 years ago
|
|
|
export DEBUG_MEM_LEVEL=$(getargnum 0 0 5 rd.memdebug)
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
setmemdebug
|
|
|
|
|
|
|
|
# parameters: func log_level prefix msg [trace_level:trace]...
|
|
|
|
make_trace_mem()
|
|
|
|
{
|
|
|
|
local log_level prefix msg msg_printed
|
|
|
|
local trace trace_level trace_in_higher_levels insert_trace
|
|
|
|
|
|
|
|
msg=$1
|
|
|
|
shift
|
|
|
|
|
|
|
|
prefix='[debug_mem]'
|
|
|
|
log_level=$DEBUG_MEM_LEVEL
|
|
|
|
|
|
|
|
if [ -z "$log_level" ] || [ "$log_level" -le 0 ]; then
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
|
|
|
|
msg=$(echo $msg)
|
|
|
|
|
|
|
|
msg_printed=0
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
trace=${1%%:*}
|
|
|
|
trace_level=${trace%%+}
|
|
|
|
[ "$trace" != "$trace_level" ] && trace_in_higher_levels="yes"
|
|
|
|
trace=${1##*:}
|
|
|
|
|
|
|
|
if [ -z "$trace_level" ]; then
|
|
|
|
trace_level=0
|
|
|
|
fi
|
|
|
|
|
|
|
|
insert_trace=0
|
|
|
|
if [ -n "$trace_in_higher_levels" ]; then
|
|
|
|
if [ "$log_level" -ge "$trace_level" ]; then
|
|
|
|
insert_trace=1
|
|
|
|
fi
|
|
|
|
else
|
|
|
|
if [ "$log_level" -eq "$trace_level" ]; then
|
|
|
|
insert_trace=1
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ $insert_trace -eq 1 ]; then
|
|
|
|
if [ $msg_printed -eq 0 ]; then
|
|
|
|
echo "$prefix $msg"
|
|
|
|
msg_printed=1
|
|
|
|
fi
|
|
|
|
show_memstats $trace
|
|
|
|
fi
|
|
|
|
shift
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
# parameters: type
|
|
|
|
show_memstats()
|
|
|
|
{
|
|
|
|
case $1 in
|
|
|
|
shortmem)
|
|
|
|
cat /proc/meminfo | grep -e "^MemFree" -e "^Cached" -e "^Slab"
|
|
|
|
;;
|
|
|
|
mem)
|
|
|
|
cat /proc/meminfo
|
|
|
|
;;
|
|
|
|
slab)
|
|
|
|
cat /proc/slabinfo
|
|
|
|
;;
|
|
|
|
iomem)
|
|
|
|
cat /proc/iomem
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
|
|
|
remove_hostonly_files() {
|
|
|
|
rm -fr /etc/cmdline /etc/cmdline.d/*.conf "$hookdir/initqueue/finished"
|
|
|
|
if [ -f /lib/dracut/hostonly-files ]; then
|
|
|
|
while read -r line || [ -n "$line" ]; do
|
|
|
|
[ -e "$line" ] || [ -h "$line" ] || continue
|
|
|
|
rm -f "$line"
|
|
|
|
done < /lib/dracut/hostonly-files
|
|
|
|
fi
|
|
|
|
}
|