]> git.ipfire.org Git - thirdparty/dracut.git/blame - modules.d/99base/dracut-lib.sh
Add memory usage trace to diffrent hook points
[thirdparty/dracut.git] / modules.d / 99base / dracut-lib.sh
CommitLineData
8ce58f1f 1#!/bin/sh
cc02093d
HH
2# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
3# ex: ts=8 sw=4 sts=4 et filetype=sh
c98bcec8 4
c32908ce
HH
5debug_off() {
6 set +x
7}
8
9debug_on() {
10 [ "$RD_DEBUG" = "yes" ] && set -x
11}
12
c98bcec8
HH
13# returns OK if $1 contains $2
14strstr() {
cc02093d 15 [ "${1#*$2*}" != "$1" ]
c98bcec8
HH
16}
17
ccb0ab73
18# returns OK if $1 contains $2 at the beginning
19str_starts() {
20 [ "${1#$2*}" != "$1" ]
21}
22
d8f0e320
WW
23# returns OK if $1 contains $2 at the end
24str_ends() {
25 [ "${1%*$2}" != "$1" ]
26}
27
ccb0ab73
28# replaces all occurrences of 'search' in 'str' with 'replacement'
29#
30# str_replace str search replacement
31#
32# example:
33# str_replace ' one two three ' ' ' '_'
34str_replace() {
35 local in="$1"; local s="$2"; local r="$3"
36 local out=''
37
38 while strstr "${in}" "$s"; do
39 chop="${in%%$s*}"
cb288154 40 out="${out}${chop}$r"
ccb0ab73
41 in="${in#*$s}"
42 done
43 echo "${out}${in}"
44}
45
551c2dd7
HH
46killall_proc_mountpoint() {
47 local _pid
48 local _t
49 for _pid in /proc/*; do
50 _pid=${_pid##/proc/}
51 case $_pid in
52 *[!0-9]*) continue;;
53 esac
54 [ -e /proc/$_pid/exe ] || continue
55 [ -e /proc/$_pid/root ] || continue
56 strstr "$(ls -l /proc/$_pid /proc/$_pid/fd 2>/dev/null)" "$1" && kill -9 $_pid
57 done
58}
59
fa7ada31
HH
60_getcmdline() {
61 local _line
c2801d09 62 local _i
fa7ada31 63 unset _line
c1a37d92 64 if [ -z "$CMDLINE" ]; then
982161e0 65 unset CMDLINE_ETC CMDLINE_ETC_D
2dfdcbf4 66 if [ -e /etc/cmdline ]; then
2cd4a806 67 while read -r _line; do
fa7ada31 68 CMDLINE_ETC="$CMDLINE_ETC $_line";
2dfdcbf4
HH
69 done </etc/cmdline;
70 fi
c2801d09
HH
71 for _i in /etc/cmdline.d/*.conf; do
72 [ -e "$_i" ] || continue
73 while read -r _line; do
74 CMDLINE_ETC_D="$CMDLINE_ETC_D $_line";
75 done <"$_i";
76 done
2cd4a806 77 read -r CMDLINE </proc/cmdline;
c2801d09 78 CMDLINE="$CMDLINE_ETC_D $CMDLINE_ETC $CMDLINE"
c1a37d92 79 fi
fa7ada31
HH
80}
81
82_dogetarg() {
9e7f4955 83 local _o _val _doecho
fa7ada31
HH
84 unset _val
85 unset _o
9e7f4955 86 unset _doecho
fa7ada31
HH
87 _getcmdline
88
89 for _o in $CMDLINE; do
b1b67842 90 if [ "${_o%%=*}" = "${1%%=*}" ]; then
9e7f4955
HH
91 if [ -n "${1#*=}" -a "${1#*=*}" != "${1}" ]; then
92 # if $1 has a "=<value>", we want the exact match
93 if [ "$_o" = "$1" ]; then
94 _val="1";
95 unset _doecho
96 fi
97 continue
98 fi
99
100 if [ "${_o#*=}" = "$_o" ]; then
101 # if cmdline argument has no "=<value>", we assume "=1"
102 _val="1";
103 unset _doecho
104 continue
105 fi
106
107 _val=${_o#*=};
108 _doecho=1
3a4d0c9c 109 fi
df44688f 110 done
fa7ada31 111 if [ -n "$_val" ]; then
d765a3e7 112 [ "x$_doecho" != "x" ] && echo "$_val";
cc02093d 113 return 0;
3a4d0c9c 114 fi
fa7ada31
HH
115 return 1;
116}
117
118getarg() {
c32908ce 119 debug_off
68e7661c 120 local _deprecated _newoption
fa7ada31
HH
121 while [ $# -gt 0 ]; do
122 case $1 in
68e7661c 123 -d) _deprecated=1; shift;;
9e7f4955 124 -y) if _dogetarg $2 >/dev/null; then
68e7661c 125 if [ "$_deprecated" = "1" ]; then
8ea8d6de 126 [ -n "$_newoption" ] && warn "Kernel command line option '$2' is deprecated, use '$_newoption' instead." || warn "Option '$2' is deprecated."
68e7661c 127 fi
fa7ada31 128 echo 1
c32908ce 129 debug_on
fa7ada31
HH
130 return 0
131 fi
68e7661c 132 _deprecated=0
fa7ada31 133 shift 2;;
9e7f4955 134 -n) if _dogetarg $2 >/dev/null; then
fa7ada31 135 echo 0;
68e7661c 136 if [ "$_deprecated" = "1" ]; then
8ea8d6de 137 [ -n "$_newoption" ] && warn "Kernel command line option '$2' is deprecated, use '$_newoption=0' instead." || warn "Option '$2' is deprecated."
68e7661c 138 fi
c32908ce 139 debug_on
fa7ada31
HH
140 return 1
141 fi
68e7661c 142 _deprecated=0
fa7ada31 143 shift 2;;
68e7661c
HH
144 *) if [ -z "$_newoption" ]; then
145 _newoption=$1
146 fi
147 if _dogetarg $1; then
148 if [ "$_deprecated" = "1" ]; then
8ea8d6de 149 [ -n "$_newoption" ] && warn "Kernel command line option '$1' is deprecated, use '$_newoption' instead." || warn "Option '$1' is deprecated."
68e7661c 150 fi
c32908ce 151 debug_on
fa7ada31
HH
152 return 0;
153 fi
68e7661c 154 _deprecated=0
fa7ada31
HH
155 shift;;
156 esac
157 done
c32908ce 158 debug_on
df44688f
DD
159 return 1
160}
ae5bc1fd 161
7e2285a4
WW
162# getargbool <defaultval> <args...>
163# False if "getarg <args...>" returns "0", "no", or "off".
164# True if getarg returns any other non-empty string.
165# If not found, assumes <defaultval> - usually 0 for false, 1 for true.
166# example: getargbool 0 rd.info
167# true: rd.info, rd.info=1, rd.info=xxx
168# false: rd.info=0, rd.info=off, rd.info not present (default val is 0)
fa7ada31
HH
169getargbool() {
170 local _b
171 unset _b
172 local _default
173 _default=$1; shift
174 _b=$(getarg "$@")
175 [ $? -ne 0 -a -z "$_b" ] && _b=$_default
176 if [ -n "$_b" ]; then
4ad45344 177 [ $_b = "0" ] && return 1
fa7ada31 178 [ $_b = "no" ] && return 1
1cc57eda 179 [ $_b = "off" ] && return 1
c1a37d92 180 fi
fa7ada31
HH
181 return 0
182}
183
a08ea34a
DY
184isdigit() {
185 case "$1" in
186 *[!0-9]*|"") return 1;;
187 esac
188
189 return 0
190}
191
192# getargnum <defaultval> <minval> <maxval> <arg>
193# Will echo the arg if it's in range [minval - maxval].
194# If it's not set or it's not valid, will set it <defaultval>.
195# Note all values are required to be >= 0 here.
196# <defaultval> should be with [minval -maxval].
197getargnum() {
198 local _b
199 unset _b
200 local _default _min _max
201 _default=$1; shift
202 _min=$1; shift
203 _max=$1; shift
204 _b=$(getarg "$1")
205 [ $? -ne 0 -a -z "$_b" ] && _b=$_default
206 if [ -n "$_b" ]; then
207 isdigit "$_b" && _b=$(($_b)) && \
208 [ $_b -ge $_min ] && [ $_b -le $_max ] && echo $_b && return
209 fi
210 echo $_default
211}
212
fa7ada31 213_dogetargs() {
c32908ce 214 debug_off
a9fa6d26 215 local _o _found _key
fa7ada31
HH
216 unset _o
217 unset _found
218 _getcmdline
a9fa6d26
HH
219 _key=$1
220 set --
fa7ada31 221 for _o in $CMDLINE; do
a9fa6d26
HH
222 if [ "$_o" = "$_key" ]; then
223 _found=1;
224 elif [ "${_o%%=*}" = "${_key%=}" ]; then
225 [ -n "${_o%%=*}" ] && set -- "$@" "${_o#*=}";
fa7ada31 226 _found=1;
cc02093d 227 fi
da1c03c8 228 done
a9fa6d26
HH
229 if [ -n "$_found" ]; then
230 [ $# -gt 0 ] && echo -n "$@"
231 return 0
232 fi
fa7ada31
HH
233 return 1;
234}
235
236getargs() {
c32908ce 237 debug_off
68e7661c 238 local _val _i _args _gfound _deprecated
a9fa6d26
HH
239 unset _val
240 unset _gfound
68e7661c 241 _newoption="$1"
a9fa6d26
HH
242 _args="$@"
243 set --
244 for _i in $_args; do
68e7661c
HH
245 if [ "$i" = "-d" ]; then
246 _deprecated=1
247 continue
248 fi
a9fa6d26 249 _val="$(_dogetargs $_i)"
68e7661c
HH
250 if [ $? -eq 0 ]; then
251 if [ "$_deprecated" = "1" ]; then
252 [ -n "$_newoption" ] && warn "Option '$_i' is deprecated, use '$_newoption' instead." || warn "Option $_i is deprecated!"
253 fi
254 _gfound=1
255 fi
a9fa6d26 256 [ -n "$_val" ] && set -- "$@" "$_val"
68e7661c 257 _deprecated=0
fa7ada31 258 done
a9fa6d26
HH
259 if [ -n "$_gfound" ]; then
260 if [ $# -gt 0 ]; then
261 echo -n "$@"
262 else
263 echo -n 1
264 fi
c32908ce 265 debug_on
fa7ada31 266 return 0
3a4d0c9c 267 fi
c32908ce 268 debug_on
4bb570c9 269 return 1;
da1c03c8
HH
270}
271
fa7ada31 272
2926b5b3
273# Prints value of given option. If option is a flag and it's present,
274# it just returns 0. Otherwise 1 is returned.
275# $1 = options separated by commas
276# $2 = option we are interested in
3b403b32 277#
2926b5b3
278# Example:
279# $1 = cipher=aes-cbc-essiv:sha256,hash=sha256,verify
280# $2 = hash
281# Output:
282# sha256
283getoptcomma() {
284 local line=",$1,"; local opt="$2"; local tmp
285
286 case "${line}" in
287 *,${opt}=*,*)
288 tmp="${line#*,${opt}=}"
289 echo "${tmp%%,*}"
290 return 0
cc02093d
HH
291 ;;
292 *,${opt},*) return 0;;
2926b5b3 293 esac
2926b5b3
294 return 1
295}
296
ccb0ab73
297# Splits given string 'str' with separator 'sep' into variables 'var1', 'var2',
298# 'varN'. If number of fields is less than number of variables, remaining are
299# not set. If number of fields is greater than number of variables, the last
300# variable takes remaining fields. In short - it acts similary to 'read'.
301#
302# splitsep sep str var1 var2 varN
303#
304# example:
305# splitsep ':' 'foo:bar:baz' v1 v2
306# in result:
307# v1='foo', v2='bar:baz'
308#
309# TODO: ':' inside fields.
310splitsep() {
c32908ce 311 debug_off
ccb0ab73
312 local sep="$1"; local str="$2"; shift 2
313 local tmp
314
f7cadaa8 315 while [ -n "$str" -a "$#" -gt 1 ]; do
7a8a33b6 316 tmp="${str%%$sep*}"
32b2fb8a
WW
317 eval "$1='${tmp}'"
318 str="${str#"$tmp"}"
7a8a33b6 319 str="${str#$sep}"
ccb0ab73
320 shift
321 done
32b2fb8a 322 [ -n "$str" -a -n "$1" ] && eval "$1='$str'"
c32908ce 323 debug_on
ccb0ab73
324 return 0
325}
326
4bb570c9 327setdebug() {
9e7a3bf2 328 if [ -z "$RD_DEBUG" ]; then
4bb570c9 329 if [ -e /proc/cmdline ]; then
9e7a3bf2 330 RD_DEBUG=no
68e7661c 331 if getargbool 0 rd.debug -d -y rdinitdebug -d -y rdnetdebug; then
3b403b32 332 RD_DEBUG=yes
0d837ebf
HH
333 [ -n "$BASH" ] && \
334 export PS4='${BASH_SOURCE}@${LINENO}(${FUNCNAME[0]}): ';
335 fi
4bb570c9 336 fi
9e7a3bf2 337 export RD_DEBUG
4bb570c9 338 fi
c32908ce 339 debug_on
4bb570c9
HH
340}
341
c98bcec8 342setdebug
4bb570c9 343
ae5bc1fd
DD
344source_all() {
345 local f
f8d50f60
HH
346 local _dir
347 _dir=$1; shift
348 [ "$_dir" ] && [ -d "/$_dir" ] || return
349 for f in "/$_dir"/*.sh; do [ -e "$f" ] && . "$f" "$@"; done
ae5bc1fd 350}
51031303 351
0b53ca70
HH
352hookdir=/lib/dracut/hooks
353export hookdir
354
355source_hook() {
f8d50f60
HH
356 local _dir
357 _dir=$1; shift
358 source_all "/lib/dracut/hooks/$_dir" "$@"
0b53ca70
HH
359}
360
8238850c
HH
361check_finished() {
362 local f
b0692d03
HH
363 for f in $hookdir/initqueue/finished/*.sh; do
364 [ "$f" = "$hookdir/initqueue/finished/*.sh" ] && return 0
365 { [ -e "$f" ] && ( . "$f" ) ; } || return 1
366 done
8238850c
HH
367 return 0
368}
369
0375106c
HH
370source_conf() {
371 local f
372 [ "$1" ] && [ -d "/$1" ] || return
54a73cbb 373 for f in "/$1"/*.conf; do [ -e "$f" ] && . "$f"; done
0375106c
HH
374}
375
311a2769 376die() {
449adc61 377 {
84a12fbc 378 echo "<24>dracut: FATAL: $*";
79471f36 379 echo "<24>dracut: Refusing to continue";
449adc61
HH
380 } > /dev/kmsg
381
3b403b32 382 {
84a12fbc 383 echo "warn dracut: FATAL: \"$*\"";
535ad9d1 384 echo "warn dracut: Refusing to continue";
0b53ca70 385 } >> $hookdir/emergency/01-die.sh
535ad9d1 386
03f405bc 387 > /run/initramfs/.die
78274fe2 388 emergency_shell
311a2769
PS
389 exit 1
390}
391
695de849
HH
392check_quiet() {
393 if [ -z "$DRACUT_QUIET" ]; then
cc02093d 394 DRACUT_QUIET="yes"
68e7661c
HH
395 getargbool 0 rd.info -d -y rdinfo && DRACUT_QUIET="no"
396 getargbool 0 rd.debug -d -y rdinitdebug && DRACUT_QUIET="no"
cc02093d 397 getarg quiet || DRACUT_QUIET="yes"
cad10a7f
HH
398 a=$(getarg loglevel=)
399 [ -n "$a" ] && [ $a -ge 28 ] && DRACUT_QUIET="yes"
400 export DRACUT_QUIET
695de849
HH
401 fi
402}
403
aefea76c 404if [ -z "$DRACUT_SYSTEMD" ]; then
449adc61 405
d9087a2d
HH
406 warn() {
407 check_quiet
84a12fbc
408 echo "<28>dracut Warning: $*" > /dev/kmsg
409 echo "dracut Warning: $*" >&2
d9087a2d
HH
410 }
411
412 info() {
413 check_quiet
84a12fbc 414 echo "<30>dracut: $*" > /dev/kmsg
d9087a2d 415 [ "$DRACUT_QUIET" != "yes" ] && \
84a12fbc 416 echo "dracut: $*"
d9087a2d
HH
417 }
418
419else
420
421 warn() {
84a12fbc 422 echo "Warning: $*" >&2
d9087a2d
HH
423 }
424
425 info() {
84a12fbc 426 echo "$*"
d9087a2d
HH
427 }
428
429fi
449adc61 430
e639630d
MS
431vwarn() {
432 while read line; do
433 warn $line;
434 done
435}
436
449adc61 437vinfo() {
3b403b32 438 while read line; do
449adc61
HH
439 info $line;
440 done
9f10836d
PS
441}
442
51031303
DD
443check_occurances() {
444 # Count the number of times the character $ch occurs in $str
445 # Return 0 if the count matches the expected number, 1 otherwise
446 local str="$1"
447 local ch="$2"
448 local expected="$3"
449 local count=0
450
451 while [ "${str#*$ch}" != "${str}" ]; do
cc02093d
HH
452 str="${str#*$ch}"
453 count=$(( $count + 1 ))
51031303
DD
454 done
455
456 [ $count -eq $expected ]
457}
07b2fbb1
PS
458
459incol2() {
c32908ce 460 debug_off
07b2fbb1
PS
461 local dummy check;
462 local file="$1";
463 local str="$2";
464
a2cb4dbc
HH
465 [ -z "$file" ] && return 1;
466 [ -z "$str" ] && return 1;
07b2fbb1
PS
467
468 while read dummy check restofline; do
c32908ce
HH
469 if [ "$check" = "$str" ]; then
470 debug_on
471 return 0
472 fi
07b2fbb1 473 done < $file
c32908ce 474 debug_on
07b2fbb1
PS
475 return 1
476}
5c6a593f
HH
477
478udevsettle() {
fe98cfee 479 [ -z "$UDEVVERSION" ] && export UDEVVERSION=$(udevadm --version)
8ef0be56 480
5c6a593f 481 if [ $UDEVVERSION -ge 143 ]; then
0b53ca70 482 udevadm settle --exit-if-exists=$hookdir/initqueue/work $settle_exit_if_exists
5c6a593f
HH
483 else
484 udevadm settle --timeout=30
485 fi
486}
273b197d 487
1dd5bc3f 488udevproperty() {
fe98cfee 489 [ -z "$UDEVVERSION" ] && export UDEVVERSION=$(udevadm --version)
1dd5bc3f
HH
490
491 if [ $UDEVVERSION -ge 143 ]; then
cc02093d 492 for i in "$@"; do udevadm control --property=$i; done
1dd5bc3f 493 else
cc02093d 494 for i in "$@"; do udevadm control --env=$i; done
1dd5bc3f
HH
495 fi
496}
497
42116050
HH
498find_mount() {
499 local dev mnt etc wanted_dev
500 wanted_dev="$(readlink -e -q $1)"
501 while read dev mnt etc; do
502 [ "$dev" = "$wanted_dev" ] && echo "$dev" && return 0
503 done < /proc/mounts
504 return 1
505}
506
27790828
HH
507# usage: ismounted <mountpoint>
508# usage: ismounted /dev/<device>
42116050
HH
509if command -v findmnt >/dev/null; then
510 ismounted() {
511 findmnt "$1" > /dev/null 2>&1
512 }
513else
514 ismounted() {
515 if [ -b "$1" ]; then
516 find_mount "$1" > /dev/null && return 0
517 return 1
518 fi
519
520 while read a m a; do
521 [ "$m" = "$1" ] && return 0
522 done < /proc/mounts
523 return 1
524 }
525fi
a5f01bbf 526
3b403b32 527# root=nfs:[<server-ip>:]<root-dir>[:<nfs-options>]
c98bcec8
HH
528# root=nfs4:[<server-ip>:]<root-dir>[:<nfs-options>]
529nfsroot_to_var() {
530 # strip nfs[4]:
531 local arg="$@:"
532 nfs="${arg%%:*}"
533 arg="${arg##$nfs:}"
c98bcec8
HH
534
535 # check if we have a server
536 if strstr "$arg" ':/*' ; then
cc02093d
HH
537 server="${arg%%:/*}"
538 arg="/${arg##*:/}"
c98bcec8
HH
539 fi
540
541 path="${arg%%:*}"
542
543 # rest are options
544 options="${arg##$path}"
545 # strip leading ":"
546 options="${options##:}"
547 # strip ":"
548 options="${options%%:}"
3b403b32 549
c98bcec8
HH
550 # Does it really start with '/'?
551 [ -n "${path%%/*}" ] && path="error";
3b403b32 552
c98bcec8
HH
553 #Fix kernel legacy style separating path and options with ','
554 if [ "$path" != "${path#*,}" ] ; then
cc02093d
HH
555 options=${path#*,}
556 path=${path%%,*}
c98bcec8
HH
557 fi
558}
559
ccb0ab73
560# Create udev rule match for a device with its device name, or the udev property
561# ID_FS_UUID or ID_FS_LABEL
562#
563# example:
564# udevmatch LABEL=boot
565# prints:
566# ENV{ID_FS_LABEL}="boot"
567#
568# TOOD: symlinks
569udevmatch() {
570 case "$1" in
571 UUID=????????-????-????-????-????????????|LABEL=*)
572 printf 'ENV{ID_FS_%s}=="%s"' "${1%%=*}" "${1#*=}"
573 ;;
574 UUID=*)
575 printf 'ENV{ID_FS_UUID}=="%s*"' "${1#*=}"
576 ;;
577 /dev/?*) printf 'KERNEL=="%s"' "${1#/dev/}" ;;
578 *) return 255 ;;
579 esac
580}
581
582# Prints unique path for potential file inside specified directory. It consists
583# of specified directory, prefix and number at the end which is incremented
584# until non-existing file is found.
585#
586# funiq dir prefix
587#
588# example:
589# # ls /mnt
590# cdrom0 cdrom1
591#
592# # funiq /mnt cdrom
593# /mnt/cdrom2
594funiq() {
595 local dir="$1"; local prefix="$2"
596 local i=0
597
598 [ -d "${dir}" ] || return 1
599
600 while [ -e "${dir}/${prefix}$i" ]; do
601 i=$(($i+1)) || return 1
602 done
603
604 echo "${dir}/${prefix}$i"
605}
606
607# Creates unique directory and prints its path. It's using funiq to generate
608# path.
609#
610# mkuniqdir subdir new_dir_name
611mkuniqdir() {
612 local dir="$1"; local prefix="$2"
613 local retdir; local retdir_new
614
d125a470 615 [ -d "${dir}" ] || mkdir -m 0755 -p "${dir}" || return 1
ccb0ab73
616
617 retdir=$(funiq "${dir}" "${prefix}") || return 1
d125a470 618 until mkdir -m 0755 "${retdir}" 2>/dev/null; do
ccb0ab73
619 retdir_new=$(funiq "${dir}" "${prefix}") || return 1
620 [ "$retdir_new" = "$retdir" ] && return 1
621 retdir="$retdir_new"
622 done
623
624 echo "${retdir}"
625}
626
31cfc9aa
WW
627# Copy the contents of SRC into DEST, merging the contents of existing
628# directories (kinda like rsync, or cpio -p).
629# Creates DEST if it doesn't exist. Overwrites files with the same names.
630#
631# copytree SRC DEST
632copytree() {
633 local src="$1" dest="$2"
634 mkdir -p "$dest"; dest=$(readlink -e -q "$dest")
635 ( cd "$src"; cp -af . -t "$dest" )
636}
637
ccb0ab73 638# Evaluates command for UUIDs either given as arguments for this function or all
2926b5b3 639# listed in /dev/disk/by-uuid. UUIDs doesn't have to be fully specified. If
ccb0ab73
640# beginning is given it is expanded to all matching UUIDs. To pass full UUID to
641# your command use '$___' as a place holder. Remember to escape '$'!
642#
643# foreach_uuid_until [ -p prefix ] command UUIDs
2926b5b3 644#
ccb0ab73
645# prefix - string to put just before $___
646# command - command to be evaluated
647# UUIDs - list of UUIDs separated by space
2926b5b3
648#
649# The function returns after *first successful evaluation* of the given command
650# with status 0. If evaluation fails for every UUID function returns with
651# status 1.
652#
653# Example:
ccb0ab73 654# foreach_uuid_until "mount -U \$___ /mnt; echo OK; umount /mnt" \
2926b5b3
655# "01234 f512 a235567f-12a3-c123-a1b1-01234567abcb"
656foreach_uuid_until() (
657 cd /dev/disk/by-uuid
658
ccb0ab73 659 [ "$1" = -p ] && local prefix="$2" && shift 2
2926b5b3 660 local cmd="$1"; shift; local uuids_list="$*"
ccb0ab73 661 local uuid; local full_uuid; local ___
2926b5b3
662
663 [ -n "${cmd}" ] || return 1
664
665 for uuid in ${uuids_list:-*}; do
666 for full_uuid in ${uuid}*; do
667 [ -e "${full_uuid}" ] || continue
ccb0ab73 668 ___="${prefix}${full_uuid}"
2926b5b3
669 eval ${cmd} && return 0
670 done
671 done
672
673 return 1
674)
f8342dd5 675
1939a4f9
HH
676# Get kernel name for given device. Device may be the name too (then the same
677# is returned), a symlink (full path), UUID (prefixed with "UUID=") or label
678# (prefixed with "LABEL="). If just a beginning of the UUID is specified or
679# even an empty, function prints all device names which UUIDs match - every in
680# single line.
681#
682# NOTICE: The name starts with "/dev/".
683#
684# Example:
685# devnames UUID=123
686# May print:
687# /dev/dm-1
688# /dev/sdb1
689# /dev/sdf3
690devnames() {
691 local dev="$1"; local d; local names
692
693 case "$dev" in
694 UUID=*)
695 dev="$(foreach_uuid_until '! blkid -U $___' "${dev#UUID=}")" \
696 && return 255
697 [ -z "$dev" ] && return 255
698 ;;
699 LABEL=*) dev="$(blkid -L "${dev#LABEL=}")" || return 255 ;;
700 /dev/?*) ;;
701 *) return 255 ;;
702 esac
703
704 for d in $dev; do
705 names="$names
706$(readlink -e -q "$d")" || return 255
707 done
708
709 echo "${names#
710}"
711}
712
713
f8342dd5
MS
714usable_root() {
715 local _d
716 [ -d $1 ] || return 1
717 for _d in proc sys dev; do
718 [ -e "$1"/$_d ] || return 1
719 done
720 return 0
721}
b0692d03 722
bb61d657
HH
723inst_hook() {
724 local _hookname _unique _name _job _exe
725 while [ $# -gt 0 ]; do
726 case "$1" in
727 --hook)
728 _hookname="/$2";shift;;
729 --unique)
730 _unique="yes";;
731 --name)
732 _name="$2";shift;;
733 *)
734 break;;
735 esac
736 shift
737 done
738
739 if [ -z "$_unique" ]; then
740 _job="${_name}$$"
741 else
742 _job="${_name:-$1}"
743 _job=${_job##*/}
744 fi
745
746 _exe=$1
747 shift
748
749 [ -x "$_exe" ] || _exe=$(command -v $_exe)
750
751 if [ -n "$onetime" ]; then
752 {
753 echo '[ -e "$_job" ] && rm "$_job"'
754 echo "$_exe $@"
755 } > "/tmp/$$-${_job}.sh"
756 else
757 echo "$_exe $@" > "/tmp/$$-${_job}.sh"
758 fi
759
760 mv -f "/tmp/$$-${_job}.sh" "$hookdir/${_hookname}/${_job}.sh"
761}
762
763# inst_mount_hook <mountpoint> <prio> <name> <script>
764#
765# Install a mount hook with priority <prio>,
766# which executes <script> as soon as <mountpoint> is mounted.
767inst_mount_hook() {
768 local _prio="$2" _jobname="$3" _script="$4"
769 local _hookname="mount-$(str_replace "$1" '/' '\\x2f')"
770 [ -d "$hookdir/${_hookname}" ] || mkdir -p "$hookdir/${_hookname}"
771 inst_hook --hook "$_hookname" --unique --name "${_prio}-${_jobname}" "$_script"
772}
773
774# add_mount_point <dev> <mountpoint> <filesystem> <fsopts>
775#
776# Mount <dev> on <mountpoint> with <filesystem> and <fsopts>
777# and call any mount hooks, as soon, as it is mounted
778add_mount_point() {
779 local _dev="$1" _mp="$2" _fs="$3" _fsopts="$4"
780 local _hookname="mount-$(str_replace "$2" '/' '\\x2f')"
781 local _devname="dev-$(str_replace "$1" '/' '\\x2f')"
782 echo "$_dev $_mp $_fs $_fsopts 0 0" >> /etc/fstab
783
784 exec 7>/etc/udev/rules.d/99-mount-${_devname}.rules
785 echo 'SUBSYSTEM!="block", GOTO="mount_end"' >&7
786 echo 'ACTION!="add|change", GOTO="mount_end"' >&7
787 if [ -n "$_dev" ]; then
788 udevmatch "$_dev" >&7 || {
789 warn "add_mount_point dev=$_dev incorrect!"
790 continue
791 }
792 printf ', ' >&7
793 fi
794
795 {
796 printf -- 'RUN+="%s --unique --onetime ' $(command -v initqueue)
797 printf -- '--name mount-%%k '
798 printf -- '%s %s"\n' "$(command -v mount_hook)" "${_mp}"
799 } >&7
800 echo 'LABEL="mount_end"' >&7
801 exec 7>&-
802}
803
804# wait_for_mount <mountpoint>
805#
806# Installs a initqueue-finished script,
807# which will cause the main loop only to exit,
808# if <mountpoint> is mounted.
b0692d03
HH
809wait_for_mount()
810{
811 local _name
812 _name="$(str_replace "$1" '/' '\\x2f')"
813 printf '. /lib/dracut-lib.sh\nismounted "%s"\n' $1 \
814 >> "$hookdir/initqueue/finished/ismounted-${_name}.sh"
815 {
816 printf 'ismounted "%s" || ' $1
817 printf 'warn "\"%s\" is not mounted"\n' $1
818 } >> "$hookdir/emergency/90-${_name}.sh"
819}
820
bb61d657
HH
821# wait_for_dev <dev>
822#
823# Installs a initqueue-finished script,
824# which will cause the main loop only to exit,
825# if the device <dev> is recognized by the system.
b0692d03
HH
826wait_for_dev()
827{
828 local _name
829 _name="$(str_replace "$1" '/' '\\x2f')"
830 printf '[ -e "%s" ]\n' $1 \
831 >> "$hookdir/initqueue/finished/devexists-${_name}.sh"
832 {
833 printf '[ -e "%s" ] || ' $1
834 printf 'warn "\"%s\" does not exist"\n' $1
835 } >> "$hookdir/emergency/80-${_name}.sh"
836}
745af916 837
f65b874b
CG
838cancel_wait_for_dev()
839{
840 local _name
841 _name="$(str_replace "$1" '/' '\\x2f')"
842 rm -f "$hookdir/initqueue/finished/devexists-${_name}.sh"
843 rm -f "$hookdir/emergency/80-${_name}.sh"
844}
845
745af916 846killproc() {
c32908ce 847 debug_off
4d638826
HH
848 local _exe="$(command -v $1)"
849 local _sig=$2
850 local _i
851 [ -x "$_exe" ] || return 1
852 for _i in /proc/[0-9]*; do
853 [ "$_i" = "/proc/1" ] && continue
854 if [ -e "$_i"/_exe ] && [ "$_i/_exe" -ef "$_exe" ] ; then
855 kill $_sig ${_i##*/}
745af916
HH
856 fi
857 done
c32908ce 858 debug_on
745af916 859}
fb67e4aa
HH
860
861need_shutdown() {
862 >/run/initramfs/.need_shutdown
863}
ffcc64bd 864
4d518aec
HH
865wait_for_loginit()
866{
4d518aec
HH
867 [ "$RD_DEBUG" = "yes" ] || return
868 [ -e /run/initramfs/loginit.pipe ] || return
c32908ce 869 debug_off
4d518aec
HH
870 echo "DRACUT_LOG_END"
871 exec 0<>/dev/console 1<>/dev/console 2<>/dev/console
872 # wait for loginit
873 i=0
874 while [ $i -lt 10 ]; do
875 if [ ! -e /run/initramfs/loginit.pipe ]; then
876 j=$(jobs)
877 [ -z "$j" ] && break
878 [ -z "${j##*Running*}" ] || break
879 fi
880 sleep 0.1
881 i=$(($i+1))
882 done
883
884 if [ $i -eq 10 ]; then
885 kill %1 >/dev/null 2>&1
886 kill $(while read line;do echo $line;done</run/initramfs/loginit.pid)
887 fi
888
478314a9 889 setdebug
4d518aec
HH
890 rm -f /run/initramfs/loginit.pipe /run/initramfs/loginit.pid
891}
892
126732bc
DY
893_emergency_shell()
894{
895 local _name="$1"
7dd7ff0f 896 if [ -n "$DRACUT_SYSTEMD" ]; then
126732bc
DY
897 > /.console_lock
898 echo "PS1=\"$_name:\${PWD}# \"" >/etc/profile
2242cd92 899 systemctl start dracut-emergency.service
a6c718ce 900 rm -f /.console_lock
126732bc 901 else
64d144ae
HH
902 debug_off
903 echo
904 /sbin/sosreport
905 echo 'You might want to save "/run/initramfs/sosreport.txt" to a USB stick or /boot'
906 echo 'after mounting them and attach it to a bug report.'
907 if ! RD_DEBUG= getargbool 0 rd.debug -d -y rdinitdebug -d -y rdnetdebug; then
908 echo
909 echo 'To get more debug information in the report,'
910 echo 'reboot with "rd.debug" added to the kernel command line.'
911 fi
912 echo
913 echo 'Dropping to debug shell.'
126732bc
DY
914 echo
915 export PS1="$_name:\${PWD}# "
916 [ -e /.profile ] || >/.profile
917
64d144ae 918 _ctty="$(RD_DEBUG= getarg rd.ctty=)" && _ctty="/dev/${_ctty##*/}"
126732bc
DY
919 if [ -z "$_ctty" ]; then
920 _ctty=console
921 while [ -f /sys/class/tty/$_ctty/active ]; do
922 _ctty=$(cat /sys/class/tty/$_ctty/active)
923 _ctty=${_ctty##* } # last one in the list
924 done
925 _ctty=/dev/$_ctty
926 fi
927 [ -c "$_ctty" ] || _ctty=/dev/tty1
3bff70ef 928 case "$(/usr/bin/setsid --help 2>&1)" in *--ctty*) CTTY="--ctty";; esac
a6c718ce 929 setsid $CTTY /bin/sh -i -l 0<>$_ctty 1<>$_ctty 2<>$_ctty
126732bc
DY
930 fi
931}
932
ffcc64bd
WW
933emergency_shell()
934{
935 local _ctty
936 set +e
bd3bf2ce 937 local _rdshell_name="dracut" action="Boot" hook="emergency"
ffcc64bd
WW
938 if [ "$1" = "-n" ]; then
939 _rdshell_name=$2
940 shift 2
bd3bf2ce
WW
941 elif [ "$1" = "--shutdown" ]; then
942 _rdshell_name=$2; action="Shutdown"; hook="shutdown-emergency"
5b683008
HH
943 if [ -x /bin/plymouth ]; then
944 /bin/plymouth --hide-splash
945 elif [ -x /oldroot/bin/plymouth ]; then
946 /oldroot/bin/plymouth --hide-splash
947 fi
bd3bf2ce 948 shift 2
ffcc64bd 949 fi
1e570bf8 950
ffcc64bd 951 echo ; echo
84a12fbc 952 warn "$*"
bd3bf2ce 953 source_hook "$hook"
ffcc64bd 954 echo
1e570bf8 955
68e7661c 956 if getargbool 1 rd.shell -d -y rdshell || getarg rd.break -d rdbreak; then
126732bc 957 _emergency_shell $_rdshell_name
ffcc64bd 958 else
64d144ae 959 warn "$action has failed. To debug this issue add \"rd.shell rd.debug\" to the kernel command line."
ffcc64bd
WW
960 # cause a kernel panic
961 exit 1
962 fi
78274fe2 963 [ -e /run/initramfs/.die ] && exit 1
ffcc64bd 964}
476eb1b3
HH
965
966# Retain the values of these variables but ensure that they are unexported
967# This is a POSIX-compliant equivalent of bash's "export -n"
968export_n()
969{
970 local var
971 local val
972 for var in "$@"; do
973 eval val=\$$var
974 unset $var
975 [ -n "$val" ] && eval $var=\"$val\"
976 done
977}
5767201e
978
979# returns OK if list1 contains all elements of list2, i.e. checks if list2 is a
980# sublist of list1. An order and a duplication doesn't matter.
981#
982# $1 = separator
983# $2 = list1
984# $3 = list2
985# $4 = ignore values, separated by $1
986listlist() {
987 local _sep="$1"
988 local _list="${_sep}${2}${_sep}"
989 local _sublist="$3"
990 [ -n "$4" ] && local _iglist="${_sep}${4}${_sep}"
991 local IFS="$_sep"
992 local _v
993
994 [ "$_list" = "$_sublist" ] && return 0
995
996 for _v in $_sublist; do
997 if [ -n "$_v" ] && ! ( [ -n "$_iglist" ] && strstr "$_iglist" "$_v" )
998 then
999 strstr "$_list" "$_v" || return 1
1000 fi
1001 done
1002
1003 return 0
1004}
1005
1006# returns OK if both lists contain the same values. An order and a duplication
1007# doesn't matter.
1008#
1009# $1 = separator
1010# $2 = list1
1011# $3 = list2
1012# $4 = ignore values, separated by $1
1013are_lists_eq() {
1014 listlist "$1" "$2" "$3" "$4" && listlist "$1" "$3" "$2" "$4"
1015}
7bd8f233
DY
1016
1017setmemdebug() {
1018 if [ -z "$DEBUG_MEM_LEVEL" ]; then
1019 export DEBUG_MEM_LEVEL=$(getargnum 0 0 3 rd.memdebug)
1020 fi
1021}
1022
1023setmemdebug
1024
1025# parameters: msg [trace_level:trace]...
1026make_trace_mem()
1027{
1028 local msg
1029 msg="$1"
1030 shift
1031 if [ -n "$DEBUG_MEM_LEVEL" ] && [ "$DEBUG_MEM_LEVEL" -gt 0 ]; then
1032 make_trace show_memstats $DEBUG_MEM_LEVEL "[debug_mem]" "$msg" "$@"
1033 fi
1034}
1035
1036# parameters: func log_level prefix msg [trace_level:trace]...
1037make_trace()
1038{
1039 local func log_level prefix msg msg_printed
1040 local trace trace_level trace_in_higher_levels insert_trace
1041
1042 func=$1
1043 shift
1044
1045 log_level=$1
1046 shift
1047
1048 prefix=$1
1049 shift
1050
1051 msg=$1
1052 shift
1053
1054 if [ -z "$log_level" ]; then
1055 return
1056 fi
1057
1058 msg=$(echo $msg)
1059
1060 msg_printed=0
1061 while [ $# -gt 0 ]; do
1062 trace=${1%%:*}
1063 trace_level=${trace%%+}
1064 [ "$trace" != "$trace_level" ] && trace_in_higher_levels="yes"
1065 trace=${1##*:}
1066
1067 if [ -z "$trace_level" ]; then
1068 trace_level=0
1069 fi
1070
1071 insert_trace=0
1072 if [ -n "$trace_in_higher_levels" ]; then
1073 if [ "$log_level" -ge "$trace_level" ]; then
1074 insert_trace=1
1075 fi
1076 else
1077 if [ "$log_level" -eq "$trace_level" ]; then
1078 insert_trace=1
1079 fi
1080 fi
1081
1082 if [ $insert_trace -eq 1 ]; then
1083 if [ $msg_printed -eq 0 ]; then
1084 echo "$prefix $msg"
1085 msg_printed=1
1086 fi
1087 $func $trace
1088 fi
1089 shift
1090 done
1091}
1092
1093# parameters: type
1094show_memstats()
1095{
1096 case $1 in
1097 shortmem)
1098 cat /proc/meminfo | grep -e "^MemFree" -e "^Cached" -e "^Slab"
1099 ;;
1100 mem)
1101 cat /proc/meminfo
1102 ;;
1103 slab)
1104 cat /proc/slabinfo
1105 ;;
1106 iomem)
1107 cat /proc/iomem
1108 ;;
1109 esac
1110}