]> git.ipfire.org Git - thirdparty/dracut.git/blob - dracut-init.sh
fix(zfcp_rules): correct shellcheck regression when parsing ccw args
[thirdparty/dracut.git] / dracut-init.sh
1 #!/bin/bash
2 #
3 # functions used only by dracut and dracut modules
4 #
5 # Copyright 2005-2009 Red Hat, Inc. All rights reserved.
6 #
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #
20 export LC_MESSAGES=C
21
22 if [[ $EUID == "0" ]] && ! [[ $DRACUT_NO_XATTR ]]; then
23 export DRACUT_CP="cp --reflink=auto --sparse=auto --preserve=mode,timestamps,xattr,links -dfr"
24 else
25 export DRACUT_CP="cp --reflink=auto --sparse=auto --preserve=mode,timestamps,links -dfr"
26 fi
27
28 # is_func <command>
29 # Check whether $1 is a function.
30 is_func() {
31 [[ "$(type -t "$1")" == "function" ]]
32 }
33
34 if ! [[ $dracutbasedir ]]; then
35 dracutbasedir=${BASH_SOURCE[0]%/*}
36 [[ $dracutbasedir == dracut-functions* ]] && dracutbasedir="."
37 [[ $dracutbasedir ]] || dracutbasedir="."
38 dracutbasedir="$(readlink -f $dracutbasedir)"
39 fi
40
41 if ! is_func dinfo > /dev/null 2>&1; then
42 # shellcheck source=./dracut-logger.sh
43 . "$dracutbasedir/dracut-logger.sh"
44 dlog_init
45 fi
46
47 if ! [[ $initdir ]]; then
48 dfatal "initdir not set"
49 exit 1
50 fi
51
52 if ! [[ -d $initdir ]]; then
53 mkdir -p "$initdir"
54 fi
55
56 if ! [[ $kernel ]]; then
57 kernel=$(uname -r)
58 export kernel
59 fi
60
61 srcmods="$dracutsysrootdir/lib/modules/$kernel/"
62
63 [[ $drivers_dir ]] && {
64 if ! command -v kmod &> /dev/null && vercmp "$(modprobe --version | cut -d' ' -f3)" lt 3.7; then
65 dfatal 'To use --kmoddir option module-init-tools >= 3.7 is required.'
66 exit 1
67 fi
68 srcmods="$drivers_dir"
69 }
70 export srcmods
71
72 # export standard hookdirs
73 [[ $hookdirs ]] || {
74 hookdirs="cmdline pre-udev pre-trigger netroot "
75 hookdirs+="initqueue initqueue/settled initqueue/online initqueue/finished initqueue/timeout "
76 hookdirs+="pre-mount pre-pivot cleanup mount "
77 hookdirs+="emergency shutdown-emergency pre-shutdown shutdown "
78 export hookdirs
79 }
80
81 DRACUT_LDD=${DRACUT_LDD:-ldd}
82 DRACUT_TESTBIN=${DRACUT_TESTBIN:-/bin/sh}
83 DRACUT_LDCONFIG=${DRACUT_LDCONFIG:-ldconfig}
84
85 # shellcheck source=./dracut-functions.sh
86 . "$dracutbasedir"/dracut-functions.sh
87
88 # Detect lib paths
89 if ! [[ $libdirs ]]; then
90 if [[ $("$DRACUT_LDD" "$dracutsysrootdir$DRACUT_TESTBIN") == */lib64/* ]] &> /dev/null \
91 && [[ -d $dracutsysrootdir/lib64 ]]; then
92 libdirs+=" /lib64"
93 [[ -d $dracutsysrootdir/usr/lib64 ]] && libdirs+=" /usr/lib64"
94 else
95 libdirs+=" /lib"
96 [[ -d $dracutsysrootdir/usr/lib ]] && libdirs+=" /usr/lib"
97 fi
98
99 libdirs+=" $(ldconfig_paths)"
100
101 export libdirs
102 fi
103
104 # helper function for check() in module-setup.sh
105 # to check for required installed binaries
106 # issues a standardized warning message
107 require_binaries() {
108 local _module_name="${moddir##*/}"
109 local _ret=0
110
111 if [[ $1 == "-m" ]]; then
112 _module_name="$2"
113 shift 2
114 fi
115
116 for cmd in "$@"; do
117 if ! find_binary "$cmd" &> /dev/null; then
118 dinfo "Module '${_module_name#[0-9][0-9]}' will not be installed, because command '$cmd' could not be found!"
119 ((_ret++))
120 fi
121 done
122 return "$_ret"
123 }
124
125 require_any_binary() {
126 local _module_name="${moddir##*/}"
127 local _ret=1
128
129 if [[ $1 == "-m" ]]; then
130 _module_name="$2"
131 shift 2
132 fi
133
134 for cmd in "$@"; do
135 if find_binary "$cmd" &> /dev/null; then
136 _ret=0
137 break
138 fi
139 done
140
141 if ((_ret != 0)); then
142 dinfo "$_module_name: Could not find any command of '$*'!"
143 return 1
144 fi
145
146 return 0
147 }
148
149 # helper function for check() in module-setup.sh
150 # to check for required kernel modules
151 # issues a standardized warning message
152 require_kernel_modules() {
153 local _module_name="${moddir##*/}"
154 local _ret=0
155
156 # Ignore kernel module requirement for no-kernel build
157 [[ $no_kernel == yes ]] && return 0
158
159 if [[ $1 == "-m" ]]; then
160 _module_name="$2"
161 shift 2
162 fi
163
164 for mod in "$@"; do
165 if ! check_kernel_module "$mod" &> /dev/null; then
166 dinfo "Module '${_module_name#[0-9][0-9]}' will not be installed, because kernel module '$mod' is not available!"
167 ((_ret++))
168 fi
169 done
170 return "$_ret"
171 }
172
173 dracut_need_initqueue() {
174 : > "$initdir/lib/dracut/need-initqueue"
175 }
176
177 dracut_module_included() {
178 [[ " $mods_to_load $modules_loaded " == *\ $*\ * ]]
179 }
180
181 dracut_no_switch_root() {
182 : > "$initdir/lib/dracut/no-switch-root"
183 }
184
185 dracut_module_path() {
186 local _dir
187
188 # shellcheck disable=SC2231
189 for _dir in "${dracutbasedir}"/modules.d/??${1}; do
190 echo "$_dir"
191 return 0
192 done
193 return 1
194 }
195
196 if ! [[ $DRACUT_INSTALL ]]; then
197 DRACUT_INSTALL=$(find_binary dracut-install)
198 fi
199
200 if ! [[ $DRACUT_INSTALL ]] && [[ -x $dracutbasedir/dracut-install ]]; then
201 DRACUT_INSTALL=$dracutbasedir/dracut-install
202 elif ! [[ $DRACUT_INSTALL ]] && [[ -x $dracutbasedir/src/install/dracut-install ]]; then
203 DRACUT_INSTALL=$dracutbasedir/src/install/dracut-install
204 fi
205
206 # Test if dracut-install is a standalone executable with no options.
207 # E.g. DRACUT_INSTALL may be set externally as:
208 # DRACUT_INSTALL="valgrind dracut-install"
209 # or
210 # DRACUT_INSTALL="dracut-install --debug"
211 # in which case the string cannot be tested for being executable.
212 DRINSTALLPARTS=0
213 for i in $DRACUT_INSTALL; do
214 DRINSTALLPARTS=$((DRINSTALLPARTS + 1))
215 done
216
217 if [[ $DRINSTALLPARTS == 1 ]] && ! command -v "$DRACUT_INSTALL" > /dev/null 2>&1; then
218 dfatal "dracut-install not found!"
219 exit 10
220 fi
221
222 if [[ $hostonly == "-h" ]]; then
223 if ! [[ $DRACUT_KERNEL_MODALIASES ]] || ! [[ -f $DRACUT_KERNEL_MODALIASES ]]; then
224 export DRACUT_KERNEL_MODALIASES="${DRACUT_TMPDIR}/modaliases"
225 $DRACUT_INSTALL ${dracutsysrootdir:+-r "$dracutsysrootdir"} ${srcmods:+--kerneldir "$srcmods"} --modalias > "$DRACUT_KERNEL_MODALIASES"
226 fi
227 fi
228
229 [[ $DRACUT_RESOLVE_LAZY ]] || export DRACUT_RESOLVE_DEPS=1
230 inst_dir() {
231 local _ret
232 [[ -e ${initdir}/"$1" ]] && return 0 # already there
233 if $DRACUT_INSTALL ${dracutsysrootdir:+-r "$dracutsysrootdir"} ${initdir:+-D "$initdir"} -d "$@"; then
234 return 0
235 else
236 _ret=$?
237 derror FAILED: "$DRACUT_INSTALL" ${dracutsysrootdir:+-r "$dracutsysrootdir"} ${initdir:+-D "$initdir"} -d "$@"
238 return $_ret
239 fi
240 }
241
242 inst() {
243 local _ret _hostonly_install
244 if [[ $1 == "-H" ]]; then
245 _hostonly_install="-H"
246 shift
247 fi
248 [[ -e ${initdir}/"${2:-$1}" ]] && return 0 # already there
249 if $DRACUT_INSTALL ${dracutsysrootdir:+-r "$dracutsysrootdir"} ${initdir:+-D "$initdir"} ${loginstall:+-L "$loginstall"} ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-f} ${_hostonly_install:+-H} "$@"; then
250 return 0
251 else
252 _ret=$?
253 derror FAILED: "$DRACUT_INSTALL" ${dracutsysrootdir:+-r "$dracutsysrootdir"} ${initdir:+-D "$initdir"} ${loginstall:+-L "$loginstall"} ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-f} ${_hostonly_install:+-H} "$@"
254 return $_ret
255 fi
256 }
257
258 inst_simple() {
259 local _ret _hostonly_install
260 if [[ $1 == "-H" ]]; then
261 _hostonly_install="-H"
262 shift
263 fi
264 [[ -e ${initdir}/"${2:-$1}" ]] && return 0 # already there
265 [[ -e $1 ]] || return 1 # no source
266 if $DRACUT_INSTALL ${dracutsysrootdir:+-r "$dracutsysrootdir"} ${initdir:+-D "$initdir"} ${loginstall:+-L "$loginstall"} ${_hostonly_install:+-H} "$@"; then
267 return 0
268 else
269 _ret=$?
270 derror FAILED: "$DRACUT_INSTALL" ${dracutsysrootdir:+-r "$dracutsysrootdir"} ${initdir:+-D "$initdir"} ${loginstall:+-L "$loginstall"} ${_hostonly_install:+-H} "$@"
271 return $_ret
272 fi
273 }
274
275 inst_symlink() {
276 local _ret _hostonly_install
277 if [[ $1 == "-H" ]]; then
278 _hostonly_install="-H"
279 shift
280 fi
281 [[ -e ${initdir}/"${2:-$1}" ]] && return 0 # already there
282 [[ -L $1 ]] || return 1
283 if $DRACUT_INSTALL ${dracutsysrootdir:+-r "$dracutsysrootdir"} ${initdir:+-D "$initdir"} ${loginstall:+-L "$loginstall"} ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-f} ${_hostonly_install:+-H} "$@"; then
284 return 0
285 else
286 _ret=$?
287 derror FAILED: "$DRACUT_INSTALL" ${dracutsysrootdir:+-r "$dracutsysrootdir"} ${initdir:+-D "$initdir"} ${loginstall:+-L "$loginstall"} ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-f} ${_hostonly_install:+-H} "$@"
288 return $_ret
289 fi
290 }
291
292 inst_multiple() {
293 local _ret _hostonly_install
294 if [[ $1 == "-H" ]]; then
295 _hostonly_install="-H"
296 shift
297 fi
298 if $DRACUT_INSTALL ${dracutsysrootdir:+-r "$dracutsysrootdir"} ${initdir:+-D "$initdir"} -a ${loginstall:+-L "$loginstall"} ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-f} ${_hostonly_install:+-H} "$@"; then
299 return 0
300 else
301 _ret=$?
302 derror FAILED: "$DRACUT_INSTALL" ${dracutsysrootdir:+-r "$dracutsysrootdir"} ${initdir:+-D "$initdir"} -a ${loginstall:+-L "$loginstall"} ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-f} ${_hostonly_install:+-H} "$@"
303 return $_ret
304 fi
305 }
306
307 dracut_install() {
308 inst_multiple "$@"
309 }
310
311 dracut_instmods() {
312 local _ret _silent=0
313 local i
314 [[ $no_kernel == yes ]] && return
315 for i in "$@"; do
316 [[ $i == "--silent" ]] && _silent=1
317 done
318
319 if $DRACUT_INSTALL \
320 ${dracutsysrootdir:+-r "$dracutsysrootdir"} \
321 ${initdir:+-D "$initdir"} ${loginstall:+-L "$loginstall"} ${hostonly:+-H} ${omit_drivers:+-N "$omit_drivers"} ${srcmods:+--kerneldir "$srcmods"} -m "$@"; then
322 return 0
323 else
324 _ret=$?
325 if ((_silent == 0)); then
326 derror FAILED: "$DRACUT_INSTALL" ${dracutsysrootdir:+-r "$dracutsysrootdir"} ${initdir:+-D "$initdir"} ${loginstall:+-L "$loginstall"} ${hostonly:+-H} ${omit_drivers:+-N "$omit_drivers"} ${srcmods:+--kerneldir "$srcmods"} -m "$@"
327 fi
328 return $_ret
329 fi
330 }
331
332 inst_library() {
333 local _ret _hostonly_install
334 if [[ $1 == "-H" ]]; then
335 _hostonly_install="-H"
336 shift
337 fi
338 [[ -e ${initdir}/"${2:-$1}" ]] && return 0 # already there
339 [[ -e $1 ]] || return 1 # no source
340 if $DRACUT_INSTALL ${dracutsysrootdir:+-r "$dracutsysrootdir"} ${initdir:+-D "$initdir"} ${loginstall:+-L "$loginstall"} ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-f} ${_hostonly_install:+-H} "$@"; then
341 return 0
342 else
343 _ret=$?
344 derror FAILED: "$DRACUT_INSTALL" ${dracutsysrootdir:+-r "$dracutsysrootdir"} ${initdir:+-D "$initdir"} ${loginstall:+-L "$loginstall"} ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-f} ${_hostonly_install:+-H} "$@"
345 return $_ret
346 fi
347 }
348
349 inst_binary() {
350 local _ret
351 if $DRACUT_INSTALL ${dracutsysrootdir:+-r "$dracutsysrootdir"} ${initdir:+-D "$initdir"} ${loginstall:+-L "$loginstall"} ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-f} "$@"; then
352 return 0
353 else
354 _ret=$?
355 derror FAILED: "$DRACUT_INSTALL" ${dracutsysrootdir:+-r "$dracutsysrootdir"} ${initdir:+-D "$initdir"} ${loginstall:+-L "$loginstall"} ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-f} "$@"
356 return $_ret
357 fi
358 }
359
360 inst_script() {
361 local _ret
362 if $DRACUT_INSTALL ${dracutsysrootdir:+-r "$dracutsysrootdir"} ${initdir:+-D "$initdir"} ${loginstall:+-L "$loginstall"} ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-f} "$@"; then
363 return 0
364 else
365 _ret=$?
366 derror FAILED: "$DRACUT_INSTALL" ${dracutsysrootdir:+-r "$dracutsysrootdir"} ${initdir:+-D "$initdir"} ${loginstall:+-L "$loginstall"} ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-f} "$@"
367 return $_ret
368 fi
369 }
370
371 inst_fsck_help() {
372 local _ret _helper="/run/dracut/fsck/fsck_help_$1.txt"
373 if $DRACUT_INSTALL ${dracutsysrootdir:+-r "$dracutsysrootdir"} ${initdir:+-D "$initdir"} ${loginstall:+-L "$loginstall"} ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-f} "$2" "$_helper"; then
374 return 0
375 else
376 _ret=$?
377 derror "$DRACUT_INSTALL" ${dracutsysrootdir:+-r "$dracutsysrootdir"} ${initdir:+-D "$initdir"} ${loginstall:+-L "$loginstall"} ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-f} "$2" "$_helper"
378 return $_ret
379 fi
380 }
381
382 # Use with form hostonly="$(optional_hostonly)" inst_xxxx <args>
383 # If hostonly mode is set to "strict", hostonly restrictions will still
384 # be applied, else will ignore hostonly mode and try to install all
385 # given modules.
386 optional_hostonly() {
387 if [[ $hostonly_mode == "strict" ]]; then
388 printf -- "%s" "$hostonly"
389 else
390 printf ""
391 fi
392 }
393
394 mark_hostonly() {
395 for i in "$@"; do
396 echo "$i" >> "$initdir/lib/dracut/hostonly-files"
397 done
398 }
399
400 # find symlinks linked to given library file
401 # $1 = library file
402 # Function searches for symlinks by stripping version numbers appended to
403 # library filename, checks if it points to the same target and finally
404 # prints the list of symlinks to stdout.
405 #
406 # Example:
407 # rev_lib_symlinks libfoo.so.8.1
408 # output: libfoo.so.8 libfoo.so
409 # (Only if libfoo.so.8 and libfoo.so exists on host system.)
410 rev_lib_symlinks() {
411 local _fn
412 local _orig
413 local _links
414
415 [[ ! $1 ]] && return 0
416
417 _fn="$1"
418 _orig="$(readlink -f "$1")"
419 _links=()
420
421 [[ ${_fn} == *.so.* ]] || return 1
422
423 until [[ ${_fn##*.} == so ]]; do
424 _fn="${_fn%.*}"
425 [[ -L ${_fn} ]] && [[ $(readlink -f "${_fn}") == "${_orig}" ]] && _links+=("${_fn}")
426 done
427
428 echo "${_links[*]}}"
429 }
430
431 # attempt to install any programs specified in a udev rule
432 inst_rule_programs() {
433 local _prog _bin
434
435 # shellcheck disable=SC2013
436 for _prog in $(sed -nr 's/.*PROGRAM==?"([^ "]+).*/\1/p' "$1"); do
437 _bin=""
438 if [[ -x ${udevdir}/$_prog ]]; then
439 _bin="${udevdir}"/$_prog
440 elif [[ ${_prog/\$env\{/} == "$_prog" ]]; then
441 _bin=$(find_binary "$_prog") || {
442 dinfo "Skipping program $_prog using in udev rule ${1##*/} as it cannot be found"
443 continue
444 }
445 fi
446
447 [[ $_bin ]] && inst_binary "$_bin"
448 done
449
450 # shellcheck disable=SC2013
451 for _prog in $(sed -nr 's/.*RUN[+=]=?"([^ "]+).*/\1/p' "$1"); do
452 _bin=""
453 if [[ -x ${udevdir}/$_prog ]]; then
454 _bin=${udevdir}/$_prog
455 elif [[ ${_prog/\$env\{/} == "$_prog" ]] && [[ ${_prog} != "/sbin/initqueue" ]]; then
456 _bin=$(find_binary "$_prog") || {
457 dinfo "Skipping program $_prog using in udev rule ${1##*/} as it cannot be found"
458 continue
459 }
460 fi
461
462 [[ $_bin ]] && inst_binary "$_bin"
463 done
464
465 # shellcheck disable=SC2013
466 for _prog in $(sed -nr 's/.*IMPORT\{program\}==?"([^ "]+).*/\1/p' "$1"); do
467 _bin=""
468 if [[ -x ${udevdir}/$_prog ]]; then
469 _bin=${udevdir}/$_prog
470 elif [[ ${_prog/\$env\{/} == "$_prog" ]]; then
471 _bin=$(find_binary "$_prog") || {
472 dinfo "Skipping program $_prog using in udev rule ${1##*/} as it cannot be found"
473 continue
474 }
475 fi
476
477 [[ $_bin ]] && dracut_install "$_bin"
478 done
479 }
480
481 # attempt to create any groups and users specified in a udev rule
482 inst_rule_group_owner() {
483 local i
484
485 # shellcheck disable=SC2013
486 for i in $(sed -nr 's/.*OWNER=?"([^ "]+).*/\1/p' "$1"); do
487 if ! grep -Eq "^$i:" "$initdir/etc/passwd" 2> /dev/null; then
488 grep -E "^$i:" "$dracutsysrootdir"/etc/passwd 2> /dev/null >> "$initdir/etc/passwd"
489 fi
490 done
491
492 # shellcheck disable=SC2013
493 for i in $(sed -nr 's/.*GROUP=?"([^ "]+).*/\1/p' "$1"); do
494 if ! grep -Eq "^$i:" "$initdir/etc/group" 2> /dev/null; then
495 grep -E "^$i:" "$dracutsysrootdir"/etc/group 2> /dev/null >> "$initdir/etc/group"
496 fi
497 done
498 }
499
500 inst_rule_initqueue() {
501 if grep -q -F initqueue "$1"; then
502 dracut_need_initqueue
503 fi
504 }
505
506 # udev rules always get installed in the same place, so
507 # create a function to install them to make life simpler.
508 inst_rules() {
509 local _target=/etc/udev/rules.d _rule _found
510
511 inst_dir "${udevdir}/rules.d"
512 inst_dir "$_target"
513 for _rule in "$@"; do
514 if [ "${_rule#/}" = "$_rule" ]; then
515 for r in "$dracutsysrootdir${udevdir}/rules.d" ${hostonly:+"$dracutsysrootdir"/etc/udev/rules.d}; do
516 [[ -e $r/$_rule ]] || continue
517 _found="$r/$_rule"
518 inst_rule_programs "$_found"
519 inst_rule_group_owner "$_found"
520 inst_rule_initqueue "$_found"
521 inst_simple "$_found"
522 done
523 fi
524 for r in '' "$dracutsysrootdir$dracutbasedir/rules.d/"; do
525 # skip rules without an absolute path
526 [[ "${r}$_rule" != /* ]] && continue
527 [[ -f ${r}$_rule ]] || continue
528 _found="${r}$_rule"
529 inst_rule_programs "$_found"
530 inst_rule_group_owner "$_found"
531 inst_rule_initqueue "$_found"
532 inst_simple "$_found" "$_target/${_found##*/}"
533 done
534 [[ $_found ]] || ddebug "Skipping udev rule: $_rule"
535 done
536 }
537
538 inst_rules_wildcard() {
539 local _target=/etc/udev/rules.d _rule _found
540
541 inst_dir "${udevdir}/rules.d"
542 inst_dir "$_target"
543 for _rule in ${udevdir}/rules.d/$1 ${dracutbasedir}/rules.d/$1; do
544 [[ -e $_rule ]] || continue
545 inst_rule_programs "$_rule"
546 inst_rule_group_owner "$_rule"
547 inst_rule_initqueue "$_rule"
548 inst_simple "$_rule"
549 _found=$_rule
550 done
551 if [[ -n ${hostonly} ]]; then
552 for _rule in ${_target}/$1; do
553 [[ -f $_rule ]] || continue
554 inst_rule_programs "$_rule"
555 inst_rule_group_owner "$_rule"
556 inst_rule_initqueue "$_rule"
557 inst_simple "$_rule"
558 _found=$_rule
559 done
560 fi
561 [[ $_found ]] || ddebug "Skipping udev rule: $_rule"
562 }
563
564 # make sure that library links are correct and up to date
565 build_ld_cache() {
566 for f in "$dracutsysrootdir"/etc/ld.so.conf "$dracutsysrootdir"/etc/ld.so.conf.d/*; do
567 [[ -f $f ]] && inst_simple "${f#"$dracutsysrootdir"}"
568 done
569 if ! $DRACUT_LDCONFIG -r "$initdir" -f /etc/ld.so.conf; then
570 if [[ $EUID == 0 ]]; then
571 derror "ldconfig exited ungracefully"
572 else
573 derror "ldconfig might need uid=0 (root) for chroot()"
574 fi
575 fi
576 }
577
578 prepare_udev_rules() {
579 dwarn "prepare_udev_rules: deprecated and will be removed"
580
581 if [ -z "$UDEVVERSION" ]; then
582 UDEVVERSION=$(udevadm --version)
583 export UDEVVERSION
584 fi
585
586 if [ -z "$UDEVVERSION" ]; then
587 derror "Failed to detect udev version!"
588 return 1
589 fi
590 if [ -z "${UDEVVERSION##*[!0-9]*}" ]; then
591 derror "udevadm --version did not report an integer, udev version cannot be determined!"
592 return 1
593 fi
594
595 for f in "$@"; do
596 f="${initdir}/etc/udev/rules.d/$f"
597 [ -e "$f" ] || continue
598 while read -r line || [ -n "$line" ]; do
599 if [ "${line%%IMPORT PATH_ID}" != "$line" ]; then
600 if ((UDEVVERSION >= 174)); then
601 printf '%sIMPORT{builtin}="path_id"\n' "${line%%IMPORT PATH_ID}"
602 else
603 printf '%sIMPORT{program}="path_id %%p"\n' "${line%%IMPORT PATH_ID}"
604 fi
605 elif [ "${line%%IMPORT BLKID}" != "$line" ]; then
606 if ((UDEVVERSION >= 176)); then
607 printf '%sIMPORT{builtin}="blkid"\n' "${line%%IMPORT BLKID}"
608 else
609 # shellcheck disable=SC2016
610 printf '%sIMPORT{program}="/sbin/blkid -o udev -p $tempnode"\n' "${line%%IMPORT BLKID}"
611 fi
612 else
613 echo "$line"
614 fi
615 done < "${f}" > "${f}.new"
616 mv "${f}.new" "$f"
617 done
618 }
619
620 # install function specialized for hooks
621 # $1 = type of hook, $2 = hook priority (lower runs first), $3 = hook
622 # All hooks should be POSIX/SuS compliant, they will be sourced by init.
623 inst_hook() {
624 local hook
625 if ! [[ -f $3 ]]; then
626 dfatal "Cannot install a hook ($3) that does not exist."
627 dfatal "Aborting initrd creation."
628 exit 1
629 elif ! [[ $hookdirs == *$1* ]]; then
630 dfatal "No such hook type $1. Aborting initrd creation."
631 exit 1
632 fi
633 hook="/lib/dracut/hooks/${1}/${2}-${3##*/}"
634 inst_simple "$3" "$hook"
635 chmod u+x "$initdir/$hook"
636 }
637
638 # install any of listed files
639 #
640 # If first argument is '-d' and second some destination path, first accessible
641 # source is installed into this path, otherwise it will installed in the same
642 # path as source. If none of listed files was installed, function return 1.
643 # On first successful installation it returns with 0 status.
644 #
645 # Example:
646 #
647 # inst_any -d /bin/foo /bin/bar /bin/baz
648 #
649 # Lets assume that /bin/baz exists, so it will be installed as /bin/foo in
650 # initramfs.
651 inst_any() {
652 local to f
653
654 [[ $1 == '-d' ]] && to="$2" && shift 2
655
656 for f in "$@"; do
657 [[ -e $f ]] || continue
658 [[ $to ]] && inst "$f" "$to" && return 0
659 inst "$f" && return 0
660 done
661
662 return 1
663 }
664
665 # inst_libdir_dir <dir> [<dir>...]
666 # Install a <dir> located on a lib directory to the initramfs image
667 inst_libdir_dir() {
668 local -a _dirs
669 for _dir in $libdirs; do
670 for _i in "$@"; do
671 for _d in "$dracutsysrootdir$_dir"/$_i; do
672 [[ -d $_d ]] && _dirs+=("${_d#"$dracutsysrootdir"}")
673 done
674 done
675 done
676 for _dir in "${_dirs[@]}"; do
677 inst_dir "$_dir"
678 done
679 }
680
681 # inst_libdir_file [-n <pattern>] <file> [<file>...]
682 # Install a <file> located on a lib directory to the initramfs image
683 # -n <pattern> install matching files
684 inst_libdir_file() {
685 local -a _files
686 if [[ $1 == "-n" ]]; then
687 local _pattern=$2
688 shift 2
689 for _dir in $libdirs; do
690 for _i in "$@"; do
691 for _f in "$dracutsysrootdir$_dir"/$_i; do
692 [[ ${_f#"$dracutsysrootdir"} =~ $_pattern ]] || continue
693 [[ -e $_f ]] && _files+=("${_f#"$dracutsysrootdir"}")
694 done
695 done
696 done
697 else
698 for _dir in $libdirs; do
699 for _i in "$@"; do
700 for _f in "$dracutsysrootdir$_dir"/$_i; do
701 [[ -e $_f ]] && _files+=("${_f#"$dracutsysrootdir"}")
702 done
703 done
704 done
705 fi
706 [[ ${#_files[@]} -gt 0 ]] && inst_multiple "${_files[@]}"
707 }
708
709 # get a command to decompress the given file
710 get_decompress_cmd() {
711 case "$1" in
712 *.gz) echo 'gzip -f -d' ;;
713 *.bz2) echo 'bzip2 -d' ;;
714 *.xz) echo 'xz -f -d' ;;
715 *.zst) echo 'zstd -f -d ' ;;
716 esac
717 }
718
719 # install function decompressing the target and handling symlinks
720 # $@ = list of compressed (gz or bz2) files or symlinks pointing to such files
721 #
722 # Function install targets in the same paths inside overlay but decompressed
723 # and without extensions (.gz, .bz2).
724 inst_decompress() {
725 local _src _cmd
726
727 for _src in "$@"; do
728 _cmd=$(get_decompress_cmd "${_src}")
729 [[ -z ${_cmd} ]] && return 1
730 inst_simple "${_src}"
731 # Decompress with chosen tool. We assume that tool changes name e.g.
732 # from 'name.gz' to 'name'.
733 ${_cmd} "${initdir}${_src}"
734 done
735 }
736
737 # It's similar to above, but if file is not compressed, performs standard
738 # install.
739 # $@ = list of files
740 inst_opt_decompress() {
741 local _src
742
743 for _src in "$@"; do
744 inst_decompress "${_src}" || inst "${_src}"
745 done
746 }
747
748 # module_check <dracut module> [<forced>] [<module path>]
749 # execute the check() function of module-setup.sh of <dracut module>
750 # or the "check" script, if module-setup.sh is not found
751 # "check $hostonly" is called
752 module_check() {
753 local _moddir=$3
754 local _ret
755 local _forced=0
756 local _hostonly=$hostonly
757 [[ -z $_moddir ]] && _moddir=$(dracut_module_path "$1")
758 [ $# -ge 2 ] && _forced=$2
759 [[ -f $_moddir/module-setup.sh ]] || return 1
760 unset check depends cmdline install installkernel
761 check() { true; }
762 # shellcheck disable=SC1090
763 . "$_moddir"/module-setup.sh
764 is_func check || return 0
765 [[ $_forced != 0 ]] && unset hostonly
766 # don't quote $hostonly to leave argument empty
767 # shellcheck disable=SC2086
768 moddir="$_moddir" check $hostonly
769 _ret=$?
770 unset check depends cmdline install installkernel
771 hostonly=$_hostonly
772 return $_ret
773 }
774
775 # module_check_mount <dracut module> [<module path>]
776 # execute the check() function of module-setup.sh of <dracut module>
777 # or the "check" script, if module-setup.sh is not found
778 # "mount_needs=1 check 0" is called
779 module_check_mount() {
780 local _moddir=$2
781 local _ret
782 export mount_needs=1
783 [[ -z $_moddir ]] && _moddir=$(dracut_module_path "$1")
784 [[ -f $_moddir/module-setup.sh ]] || return 1
785 unset check depends cmdline install installkernel
786 check() { false; }
787 # shellcheck disable=SC1090
788 . "$_moddir"/module-setup.sh
789 moddir=$_moddir check 0
790 _ret=$?
791 unset check depends cmdline install installkernel
792 unset mount_needs
793 return "$_ret"
794 }
795
796 # module_depends <dracut module> [<module path>]
797 # execute the depends() function of module-setup.sh of <dracut module>
798 # or the "depends" script, if module-setup.sh is not found
799 module_depends() {
800 local _moddir=$2
801 local _ret
802 [[ -z $_moddir ]] && _moddir=$(dracut_module_path "$1")
803 [[ -f $_moddir/module-setup.sh ]] || return 1
804 unset check depends cmdline install installkernel
805 depends() { true; }
806 # shellcheck disable=SC1090
807 . "$_moddir"/module-setup.sh
808 moddir=$_moddir depends
809 _ret=$?
810 unset check depends cmdline install installkernel
811 return $_ret
812 }
813
814 # module_cmdline <dracut module> [<module path>]
815 # execute the cmdline() function of module-setup.sh of <dracut module>
816 # or the "cmdline" script, if module-setup.sh is not found
817 module_cmdline() {
818 local _moddir=$2
819 local _ret
820 [[ -z $_moddir ]] && _moddir=$(dracut_module_path "$1")
821 [[ -f $_moddir/module-setup.sh ]] || return 1
822 unset check depends cmdline install installkernel
823 cmdline() { true; }
824 # shellcheck disable=SC1090
825 . "$_moddir"/module-setup.sh
826 moddir="$_moddir" cmdline
827 _ret=$?
828 unset check depends cmdline install installkernel
829 return $_ret
830 }
831
832 # module_install <dracut module> [<module path>]
833 # execute the install() function of module-setup.sh of <dracut module>
834 # or the "install" script, if module-setup.sh is not found
835 module_install() {
836 local _moddir=$2
837 local _ret
838 [[ -z $_moddir ]] && _moddir=$(dracut_module_path "$1")
839 [[ -f $_moddir/module-setup.sh ]] || return 1
840 unset check depends cmdline install installkernel
841 install() { true; }
842 # shellcheck disable=SC1090
843 . "$_moddir"/module-setup.sh
844 moddir="$_moddir" install
845 _ret=$?
846 unset check depends cmdline install installkernel
847 return $_ret
848 }
849
850 # module_installkernel <dracut module> [<module path>]
851 # execute the installkernel() function of module-setup.sh of <dracut module>
852 # or the "installkernel" script, if module-setup.sh is not found
853 module_installkernel() {
854 local _moddir=$2
855 local _ret
856 [[ -z $_moddir ]] && _moddir=$(dracut_module_path "$1")
857 [[ -f $_moddir/module-setup.sh ]] || return 1
858 unset check depends cmdline install installkernel
859 installkernel() { true; }
860 # shellcheck disable=SC1090
861 . "$_moddir"/module-setup.sh
862 moddir="$_moddir" installkernel
863 _ret=$?
864 unset check depends cmdline install installkernel
865 return $_ret
866 }
867
868 # check_mount <dracut module> [<use_as_dep>] [<module path>]
869 # check_mount checks, if a dracut module is needed for the given
870 # device and filesystem types in "${host_fs_types[@]}"
871 check_mount() {
872 local _mod=$1
873 local _moddir=$3
874 local _ret
875 local _moddep
876
877 [[ -z $_moddir ]] && _moddir=$(dracut_module_path "$1")
878 [ "${#host_fs_types[@]}" -le 0 ] && return 1
879
880 # If we are already scheduled to be loaded, no need to check again.
881 [[ " $mods_to_load " == *\ $_mod\ * ]] && return 0
882 [[ " $mods_checked_as_dep " == *\ $_mod\ * ]] && return 1
883
884 # This should never happen, but...
885 [[ -d $_moddir ]] || return 1
886
887 [[ $2 ]] || mods_checked_as_dep+=" $_mod "
888
889 if [[ " $omit_dracutmodules " == *\ $_mod\ * ]]; then
890 return 1
891 fi
892
893 if [[ " $dracutmodules $add_dracutmodules $force_add_dracutmodules" == *\ $_mod\ * ]]; then
894 module_check_mount "$_mod" "$_moddir"
895 _ret=$?
896
897 # explicit module, so also accept _ret=255
898 [[ $_ret == 0 || $_ret == 255 ]] || return 1
899 else
900 # module not in our list
901 if [[ $dracutmodules == all ]]; then
902 # check, if we can and should install this module
903 module_check_mount "$_mod" "$_moddir" || return 1
904 else
905 # skip this module
906 return 1
907 fi
908 fi
909
910 for _moddep in $(module_depends "$_mod" "$_moddir"); do
911 # handle deps as if they were manually added
912 [[ " $dracutmodules " == *\ $_mod\ * ]] \
913 && [[ " $dracutmodules " != *\ $_moddep\ * ]] \
914 && dracutmodules+=" $_moddep "
915 [[ " $add_dracutmodules " == *\ $_mod\ * ]] \
916 && [[ " $add_dracutmodules " != *\ $_moddep\ * ]] \
917 && add_dracutmodules+=" $_moddep "
918 [[ " $force_add_dracutmodules " == *\ $_mod\ * ]] \
919 && [[ " $force_add_dracutmodules " != *\ $_moddep\ * ]] \
920 && force_add_dracutmodules+=" $_moddep "
921 # if a module we depend on fail, fail also
922 if ! check_module "$_moddep"; then
923 derror "Module '$_mod' depends on '$_moddep', which can't be installed"
924 return 1
925 fi
926 done
927
928 [[ " $mods_to_load " == *\ $_mod\ * ]] \
929 || mods_to_load+=" $_mod "
930
931 return 0
932 }
933
934 # check_module <dracut module> [<use_as_dep>] [<module path>]
935 # check if a dracut module is to be used in the initramfs process
936 # if <use_as_dep> is set, then the process also keeps track
937 # that the modules were checked for the dependency tracking process
938 check_module() {
939 local _mod=$1
940 local _moddir=$3
941 local _ret
942 local _moddep
943
944 [[ -z $_moddir ]] && _moddir=$(dracut_module_path "$1")
945 # If we are already scheduled to be loaded, no need to check again.
946 [[ " $mods_to_load " == *\ $_mod\ * ]] && return 0
947 [[ " $mods_checked_as_dep " == *\ $_mod\ * ]] && return 1
948
949 # This should never happen, but...
950 [[ -d $_moddir ]] || return 1
951
952 [[ $2 ]] || mods_checked_as_dep+=" $_mod "
953
954 if [[ " $omit_dracutmodules " == *\ $_mod\ * ]]; then
955 ddebug "Module '$_mod' will not be installed, because it's in the list to be omitted!"
956 return 1
957 fi
958
959 if [[ " $dracutmodules $add_dracutmodules $force_add_dracutmodules" == *\ $_mod\ * ]]; then
960 if [[ " $dracutmodules $force_add_dracutmodules " == *\ $_mod\ * ]]; then
961 module_check "$_mod" 1 "$_moddir"
962 _ret=$?
963 else
964 module_check "$_mod" 0 "$_moddir"
965 _ret=$?
966 fi
967 # explicit module, so also accept _ret=255
968 [[ $_ret == 0 || $_ret == 255 ]] || return 1
969 else
970 # module not in our list
971 if [[ $dracutmodules == all ]]; then
972 # check, if we can and should install this module
973 module_check "$_mod" 0 "$_moddir"
974 _ret=$?
975 if [[ $_ret != 0 ]]; then
976 [[ $2 ]] && return 1
977 [[ $_ret != 255 ]] && return 1
978 fi
979 else
980 # skip this module
981 return 1
982 fi
983 fi
984
985 for _moddep in $(module_depends "$_mod" "$_moddir"); do
986 # handle deps as if they were manually added
987 [[ " $dracutmodules " == *\ $_mod\ * ]] \
988 && [[ " $dracutmodules " != *\ $_moddep\ * ]] \
989 && dracutmodules+=" $_moddep "
990 [[ " $add_dracutmodules " == *\ $_mod\ * ]] \
991 && [[ " $add_dracutmodules " != *\ $_moddep\ * ]] \
992 && add_dracutmodules+=" $_moddep "
993 [[ " $force_add_dracutmodules " == *\ $_mod\ * ]] \
994 && [[ " $force_add_dracutmodules " != *\ $_moddep\ * ]] \
995 && force_add_dracutmodules+=" $_moddep "
996 # if a module we depend on fail, fail also
997 if ! check_module "$_moddep"; then
998 derror "Module '$_mod' depends on '$_moddep', which can't be installed"
999 return 1
1000 fi
1001 done
1002
1003 [[ " $mods_to_load " == *\ $_mod\ * ]] \
1004 || mods_to_load+=" $_mod "
1005
1006 return 0
1007 }
1008
1009 # for_each_module_dir <func>
1010 # execute "<func> <dracut module> 1 <module path>"
1011 for_each_module_dir() {
1012 local _modcheck
1013 local _mod
1014 local _moddir
1015 local _func
1016 local _reason
1017 _func=$1
1018 for _moddir in "$dracutbasedir/modules.d"/[0-9][0-9]*; do
1019 [[ -e $_moddir/module-setup.sh ]] || continue
1020 _mod=${_moddir##*/}
1021 _mod=${_mod#[0-9][0-9]}
1022 $_func "$_mod" 1 "$_moddir"
1023 done
1024
1025 # Report any missing dracut modules, the user has specified
1026 _modcheck="$add_dracutmodules $force_add_dracutmodules"
1027 [[ $dracutmodules != all ]] && _modcheck="$_modcheck $dracutmodules"
1028 for _mod in $_modcheck; do
1029 [[ " $mods_to_load " == *\ $_mod\ * ]] && continue
1030
1031 [[ " $force_add_dracutmodules " != *\ $_mod\ * ]] \
1032 && [[ " $dracutmodules " != *\ $_mod\ * ]] \
1033 && [[ " $omit_dracutmodules " == *\ $_mod\ * ]] \
1034 && continue
1035
1036 [[ -d $(echo "$dracutbasedir/modules.d"/[0-9][0-9]"$_mod") ]] \
1037 && _reason="installed" \
1038 || _reason="found"
1039 derror "Module '$_mod' cannot be $_reason."
1040 [[ " $force_add_dracutmodules " == *\ $_mod\ * ]] && exit 1
1041 [[ " $dracutmodules " == *\ $_mod\ * ]] && exit 1
1042 [[ " $add_dracutmodules " == *\ $_mod\ * ]] && exit 1
1043 done
1044 }
1045
1046 dracut_kernel_post() {
1047 for _f in modules.builtin modules.builtin.alias modules.builtin.modinfo modules.order; do
1048 [[ -e $srcmods/$_f ]] && inst_simple "$srcmods/$_f" "/lib/modules/$kernel/$_f"
1049 done
1050
1051 # generate module dependencies for the initrd
1052 if [[ -d $initdir/lib/modules/$kernel ]] \
1053 && ! depmod -a -b "$initdir" "$kernel"; then
1054 dfatal "\"depmod -a $kernel\" failed."
1055 exit 1
1056 fi
1057
1058 }
1059
1060 instmods() {
1061 # instmods [-c [-s]] <kernel module> [<kernel module> ... ]
1062 # instmods [-c [-s]] <kernel subsystem>
1063 # install kernel modules along with all their dependencies.
1064 # <kernel subsystem> can be e.g. "=block" or "=drivers/usb/storage"
1065 # -c check
1066 # -s silent
1067 local _optional="-o"
1068 local _silent
1069 local _ret
1070
1071 [[ $no_kernel == yes ]] && return
1072
1073 if [[ $1 == '-c' ]]; then
1074 unset _optional
1075 shift
1076 fi
1077 if [[ $1 == '-s' ]]; then
1078 _silent=1
1079 shift
1080 fi
1081
1082 if (($# == 0)); then
1083 read -r -d '' -a args
1084 set -- "${args[@]}"
1085 fi
1086
1087 if (($# == 0)); then
1088 return 0
1089 fi
1090
1091 $DRACUT_INSTALL \
1092 ${initdir:+-D "$initdir"} \
1093 ${dracutsysrootdir:+-r "$dracutsysrootdir"} \
1094 ${loginstall:+-L "$loginstall"} \
1095 ${hostonly:+-H} \
1096 ${omit_drivers:+-N "$omit_drivers"} \
1097 ${srcmods:+--kerneldir "$srcmods"} \
1098 ${_optional:+-o} \
1099 ${_silent:+--silent} \
1100 -m "$@"
1101 _ret=$?
1102
1103 if ((_ret != 0)) && [[ -z $_silent ]]; then
1104 derror "FAILED: " \
1105 "$DRACUT_INSTALL" \
1106 ${initdir:+-D "$initdir"} \
1107 ${dracutsysrootdir:+-r "$dracutsysrootdir"} \
1108 ${loginstall:+-L "$loginstall"} \
1109 ${hostonly:+-H} \
1110 ${omit_drivers:+-N "$omit_drivers"} \
1111 ${srcmods:+--kerneldir "$srcmods"} \
1112 ${_optional:+-o} \
1113 ${_silent:+--silent} \
1114 -m "$@"
1115 fi
1116
1117 [[ "$_optional" ]] && return 0
1118 return $_ret
1119 }
1120
1121 if [[ "$(ln --help)" == *--relative* ]]; then
1122 ln_r() {
1123 ln -sfnr "${initdir}/$1" "${initdir}/$2"
1124 }
1125 else
1126 ln_r() {
1127 local _source=$1
1128 local _dest=$2
1129 [[ -d ${_dest%/*} ]] && _dest=$(readlink -f "${_dest%/*}")/${_dest##*/}
1130 ln -sfn -- "$(convert_abs_rel "${_dest}" "${_source}")" "${initdir}/${_dest}"
1131 }
1132 fi
1133
1134 is_qemu_virtualized() {
1135 # 0 if a virt environment was detected
1136 # 1 if a virt environment could not be detected
1137 # 255 if any error was encountered
1138 if type -P systemd-detect-virt > /dev/null 2>&1; then
1139 if ! vm=$(systemd-detect-virt --vm 2> /dev/null); then
1140 return 255
1141 fi
1142 [[ $vm == "qemu" ]] && return 0
1143 [[ $vm == "kvm" ]] && return 0
1144 [[ $vm == "bochs" ]] && return 0
1145 fi
1146
1147 for i in /sys/class/dmi/id/*_vendor; do
1148 [[ -f $i ]] || continue
1149 read -r vendor < "$i"
1150 [[ $vendor == "QEMU" ]] && return 0
1151 [[ $vendor == "Red Hat" ]] && return 0
1152 [[ $vendor == "Bochs" ]] && return 0
1153 done
1154 return 1
1155 }