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