]> git.ipfire.org Git - thirdparty/dracut.git/blob - dracut-functions.sh
dracut-functions.sh: degrade info about missing binaries to info
[thirdparty/dracut.git] / dracut-functions.sh
1 #!/bin/bash
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 # functions used by dracut and other tools.
6 #
7 # Copyright 2005-2009 Red Hat, Inc. All rights reserved.
8 #
9 # This program is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 2 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #
22 export LC_MESSAGES=C
23
24 if [[ $DRACUT_KERNEL_LAZY ]] && ! [[ $DRACUT_KERNEL_LAZY_HASHDIR ]]; then
25 if ! [[ -d "$initdir/.kernelmodseen" ]]; then
26 mkdir -p "$initdir/.kernelmodseen"
27 fi
28 DRACUT_KERNEL_LAZY_HASHDIR="$initdir/.kernelmodseen"
29 fi
30
31 if [[ $initdir ]] && ! [[ -d $initdir ]]; then
32 mkdir -p "$initdir"
33 fi
34
35 # Generic substring function. If $2 is in $1, return 0.
36 strstr() { [[ $1 = *$2* ]]; }
37
38 # helper function for check() in module-setup.sh
39 # to check for required installed binaries
40 # issues a standardized warning message
41 require_binaries() {
42 local _module_name="${moddir##*/}"
43 local _ret=0
44
45 if [[ "$1" = "-m" ]]; then
46 _module_name="$2"
47 shift 2
48 fi
49
50 for cmd in "$@"; do
51 if ! find_binary "$cmd" &>/dev/null; then
52 dinfo "$_module_name: Could not find command '$cmd'!"
53 ((_ret++))
54 fi
55 done
56 return $_ret
57 }
58
59 require_any_binary() {
60 local _module_name="${moddir##*/}"
61 local _ret=1
62
63 if [[ "$1" = "-m" ]]; then
64 _module_name="$2"
65 shift 2
66 fi
67
68 for cmd in "$@"; do
69 if find_binary "$cmd" &>/dev/null; then
70 _ret=0
71 break
72 fi
73 done
74
75 if (( $_ret != 0 )); then
76 dinfo "$_module_name: Could not find any command of '$@'!"
77 return 1
78 fi
79
80 return 0
81 }
82
83 # find a binary. If we were not passed the full path directly,
84 # search in the usual places to find the binary.
85 find_binary() {
86 if [[ -z ${1##/*} ]]; then
87 if [[ -x $1 ]] || { [[ "$1" == *.so* ]] && ldd "$1" &>/dev/null; }; then
88 printf "%s\n" "$1"
89 return 0
90 fi
91 fi
92
93 type -P "${1##*/}"
94 }
95
96 if ! [[ $dracutbasedir ]]; then
97 dracutbasedir=${BASH_SOURCE[0]%/*}
98 [[ $dracutbasedir = "dracut-functions" ]] && dracutbasedir="."
99 [[ $dracutbasedir ]] || dracutbasedir="."
100 dracutbasedir="$(readlink -f $dracutbasedir)"
101 fi
102
103 ldconfig_paths()
104 {
105 local a i
106 declare -A a
107 for i in $(
108 ldconfig -pN 2>/dev/null | while read a b c d; do
109 [[ "$c" != "=>" ]] && continue
110 printf "%s\n" ${d%/*};
111 done
112 ); do
113 [[ "$i" = "/lib" || "$i" = "/usr/lib" || "$i" = "/lib64" || "$i" = "/usr/lib64" ]] && continue
114 a["$i"]=1;
115 done;
116 printf "%s\n" ${!a[@]}
117 }
118
119 # Detect lib paths
120 if ! [[ $libdirs ]] ; then
121 if [[ "$(ldd /bin/sh)" == */lib64/* ]] &>/dev/null \
122 && [[ -d /lib64 ]]; then
123 libdirs+=" /lib64"
124 [[ -d /usr/lib64 ]] && libdirs+=" /usr/lib64"
125 else
126 libdirs+=" /lib"
127 [[ -d /usr/lib ]] && libdirs+=" /usr/lib"
128 fi
129
130 libdirs+=" $(ldconfig_paths)"
131
132 export libdirs
133 fi
134
135 if ! [[ $kernel ]]; then
136 kernel=$(uname -r)
137 export kernel
138 fi
139
140 # Version comparision function. Assumes Linux style version scheme.
141 # $1 = version a
142 # $2 = comparision op (gt, ge, eq, le, lt, ne)
143 # $3 = version b
144 vercmp() {
145 local _n1=(${1//./ }) _op=$2 _n2=(${3//./ }) _i _res
146
147 for ((_i=0; ; _i++))
148 do
149 if [[ ! ${_n1[_i]}${_n2[_i]} ]]; then _res=0
150 elif ((${_n1[_i]:-0} > ${_n2[_i]:-0})); then _res=1
151 elif ((${_n1[_i]:-0} < ${_n2[_i]:-0})); then _res=2
152 else continue
153 fi
154 break
155 done
156
157 case $_op in
158 gt) ((_res == 1));;
159 ge) ((_res != 2));;
160 eq) ((_res == 0));;
161 le) ((_res != 1));;
162 lt) ((_res == 2));;
163 ne) ((_res != 0));;
164 esac
165 }
166
167 srcmods="/lib/modules/$kernel/"
168
169 [[ $drivers_dir ]] && {
170 if ! command -v kmod &>/dev/null && vercmp "$(modprobe --version | cut -d' ' -f3)" lt 3.7; then
171 dfatal 'To use --kmoddir option module-init-tools >= 3.7 is required.'
172 exit 1
173 fi
174 srcmods="$drivers_dir"
175 }
176 export srcmods
177
178 if ! type dinfo >/dev/null 2>&1; then
179 . "$dracutbasedir/dracut-logger.sh"
180 dlog_init
181 fi
182
183 if ! [[ $initdir ]]; then
184 dfatal "initdir not set"
185 exit 1
186 fi
187
188 # export standard hookdirs
189 [[ $hookdirs ]] || {
190 hookdirs="cmdline pre-udev pre-trigger netroot "
191 hookdirs+="initqueue initqueue/settled initqueue/online initqueue/finished initqueue/timeout "
192 hookdirs+="pre-mount pre-pivot cleanup mount "
193 hookdirs+="emergency shutdown-emergency pre-shutdown shutdown "
194 export hookdirs
195 }
196
197 dracut_need_initqueue() {
198 >"$initdir/lib/dracut/need-initqueue"
199 }
200
201 dracut_module_included() {
202 [[ " $mods_to_load $modules_loaded " == *\ $*\ * ]]
203 }
204
205 # Create all subdirectories for given path without creating the last element.
206 # $1 = path
207 mksubdirs() {
208 [[ -e ${1%/*} ]] || mkdir -m 0755 -p -- "${1%/*}"
209 }
210
211 # is_func <command>
212 # Check whether $1 is a function.
213 is_func() {
214 [[ "$(type -t "$1")" = "function" ]]
215 }
216
217 # Function prints global variables in format name=value line by line.
218 # $@ = list of global variables' name
219 print_vars() {
220 local _var _value
221
222 for _var in "$@"
223 do
224 eval printf -v _value "%s" "\$$_var"
225 [[ ${_value} ]] && printf '%s="%s"\n' "$_var" "$_value"
226 done
227 }
228
229 # normalize_path <path>
230 # Prints the normalized path, where it removes any duplicated
231 # and trailing slashes.
232 # Example:
233 # $ normalize_path ///test/test//
234 # /test/test
235 normalize_path() {
236 shopt -q -s extglob
237 set -- "${1//+(\/)//}"
238 shopt -q -u extglob
239 printf "%s\n" "${1%/}"
240 }
241
242 # convert_abs_rel <from> <to>
243 # Prints the relative path, when creating a symlink to <to> from <from>.
244 # Example:
245 # $ convert_abs_rel /usr/bin/test /bin/test-2
246 # ../../bin/test-2
247 # $ ln -s $(convert_abs_rel /usr/bin/test /bin/test-2) /usr/bin/test
248 convert_abs_rel() {
249 local __current __absolute __abssize __cursize __newpath
250 local -i __i __level
251
252 set -- "$(normalize_path "$1")" "$(normalize_path "$2")"
253
254 # corner case #1 - self looping link
255 [[ "$1" == "$2" ]] && { printf "%s\n" "${1##*/}"; return; }
256
257 # corner case #2 - own dir link
258 [[ "${1%/*}" == "$2" ]] && { printf ".\n"; return; }
259
260 IFS="/" __current=($1)
261 IFS="/" __absolute=($2)
262
263 __abssize=${#__absolute[@]}
264 __cursize=${#__current[@]}
265
266 while [[ "${__absolute[__level]}" == "${__current[__level]}" ]]
267 do
268 (( __level++ ))
269 if (( __level > __abssize || __level > __cursize ))
270 then
271 break
272 fi
273 done
274
275 for ((__i = __level; __i < __cursize-1; __i++))
276 do
277 if ((__i > __level))
278 then
279 __newpath=$__newpath"/"
280 fi
281 __newpath=$__newpath".."
282 done
283
284 for ((__i = __level; __i < __abssize; __i++))
285 do
286 if [[ -n $__newpath ]]
287 then
288 __newpath=$__newpath"/"
289 fi
290 __newpath=$__newpath${__absolute[__i]}
291 done
292
293 printf "%s\n" "$__newpath"
294 }
295
296 if [[ "$(ln --help)" == *--relative* ]]; then
297 ln_r() {
298 ln -sfnr "${initdir}/$1" "${initdir}/$2"
299 }
300 else
301 ln_r() {
302 local _source=$1
303 local _dest=$2
304 [[ -d "${_dest%/*}" ]] && _dest=$(readlink -f "${_dest%/*}")/${_dest##*/}
305 ln -sfn -- "$(convert_abs_rel "${_dest}" "${_source}")" "${initdir}/${_dest}"
306 }
307 fi
308
309 # get_fs_env <device>
310 # Get and the ID_FS_TYPE variable from udev for a device.
311 # Example:
312 # $ get_fs_env /dev/sda2
313 # ext4
314 get_fs_env() {
315 local evalstr
316 local found
317
318 [[ $1 ]] || return
319 unset ID_FS_TYPE
320 ID_FS_TYPE=$(blkid -u filesystem -o export -- "$1" \
321 | while read line; do
322 if [[ "$line" == TYPE\=* ]]; then
323 printf "%s" "${line#TYPE=}";
324 exit 0;
325 fi
326 done)
327 if [[ $ID_FS_TYPE ]]; then
328 printf "%s" "$ID_FS_TYPE"
329 return 0
330 fi
331 return 1
332 }
333
334 # get_maj_min <device>
335 # Prints the major and minor of a device node.
336 # Example:
337 # $ get_maj_min /dev/sda2
338 # 8:2
339 get_maj_min() {
340 local _maj _min _majmin
341 _majmin="$(stat -L -c '%t:%T' "$1" 2>/dev/null)"
342 printf "%s" "$((0x${_majmin%:*})):$((0x${_majmin#*:}))"
343 }
344
345
346 # get_devpath_block <device>
347 # get the DEVPATH in /sys of a block device
348 get_devpath_block() {
349 local _majmin _i
350 _majmin=$(get_maj_min "$1")
351
352 for _i in /sys/block/*/dev /sys/block/*/*/dev; do
353 [[ -e "$_i" ]] || continue
354 if [[ "$_majmin" == "$(<"$_i")" ]]; then
355 printf "%s" "${_i%/dev}"
356 return 0
357 fi
358 done
359 return 1
360 }
361
362 # get a persistent path from a device
363 get_persistent_dev() {
364 local i _tmp _dev
365
366 _dev=$(get_maj_min "$1")
367 [ -z "$_dev" ] && return
368
369 for i in \
370 /dev/mapper/* \
371 /dev/disk/${persistent_policy:-by-uuid}/* \
372 /dev/disk/by-uuid/* \
373 /dev/disk/by-label/* \
374 /dev/disk/by-partuuid/* \
375 /dev/disk/by-partlabel/* \
376 /dev/disk/by-id/* \
377 /dev/disk/by-path/* \
378 ; do
379 [[ -e "$i" ]] || continue
380 [[ $i == /dev/mapper/control ]] && continue
381 [[ $i == /dev/mapper/mpath* ]] && continue
382 _tmp=$(get_maj_min "$i")
383 if [ "$_tmp" = "$_dev" ]; then
384 printf -- "%s" "$i"
385 return
386 fi
387 done
388 }
389
390 expand_persistent_dev() {
391 local _dev=$1
392
393 case "$_dev" in
394 LABEL=*)
395 _dev="/dev/disk/by-label/${_dev#LABEL=}"
396 ;;
397 UUID=*)
398 _dev="${_dev#UUID=}"
399 _dev="${_dev,,}"
400 _dev="/dev/disk/by-uuid/${_dev}"
401 ;;
402 PARTUUID=*)
403 _dev="${_dev#PARTUUID=}"
404 _dev="${_dev,,}"
405 _dev="/dev/disk/by-partuuid/${_dev}"
406 ;;
407 PARTLABEL=*)
408 _dev="/dev/disk/by-partlabel/${_dev#PARTLABEL=}"
409 ;;
410 esac
411 printf "%s" "$_dev"
412 }
413
414 shorten_persistent_dev() {
415 local _dev="$1"
416 case "$_dev" in
417 /dev/disk/by-uuid/*)
418 printf "%s" "UUID=${_dev##*/}";;
419 /dev/disk/by-label/*)
420 printf "%s" "LABEL=${_dev##*/}";;
421 /dev/disk/by-partuuid/*)
422 printf "%s" "PARTUUID=${_dev##*/}";;
423 /dev/disk/by-partlabel/*)
424 printf "%s" "PARTLABEL=${_dev##*/}";;
425 *)
426 printf "%s" "$_dev";;
427 esac
428 }
429
430 # find_block_device <mountpoint>
431 # Prints the major and minor number of the block device
432 # for a given mountpoint.
433 # Unless $use_fstab is set to "yes" the functions
434 # uses /proc/self/mountinfo as the primary source of the
435 # information and only falls back to /etc/fstab, if the mountpoint
436 # is not found there.
437 # Example:
438 # $ find_block_device /usr
439 # 8:4
440 find_block_device() {
441 local _majmin _dev _majmin _find_mpt
442 _find_mpt="$1"
443 if [[ $use_fstab != yes ]]; then
444 [[ -d $_find_mpt/. ]]
445 findmnt -e -v -n -o 'MAJ:MIN,SOURCE' --target "$_find_mpt" | { \
446 while read _majmin _dev; do
447 if [[ -b $_dev ]]; then
448 if ! [[ $_majmin ]] || [[ $_majmin == 0:* ]]; then
449 _majmin=$(get_maj_min $_dev)
450 fi
451 if [[ $_majmin ]]; then
452 printf "%s\n" "$_majmin"
453 else
454 printf "%s\n" "$_dev"
455 fi
456 return 0
457 fi
458 if [[ $_dev = *:* ]]; then
459 printf "%s\n" "$_dev"
460 return 0
461 fi
462 done; return 1; } && return 0
463 fi
464 # fall back to /etc/fstab
465
466 findmnt -e --fstab -v -n -o 'MAJ:MIN,SOURCE' --target "$_find_mpt" | { \
467 while read _majmin _dev; do
468 if ! [[ $_dev ]]; then
469 _dev="$_majmin"
470 unset _majmin
471 fi
472 if [[ -b $_dev ]]; then
473 [[ $_majmin ]] || _majmin=$(get_maj_min $_dev)
474 if [[ $_majmin ]]; then
475 printf "%s\n" "$_majmin"
476 else
477 printf "%s\n" "$_dev"
478 fi
479 return 0
480 fi
481 if [[ $_dev = *:* ]]; then
482 printf "%s\n" "$_dev"
483 return 0
484 fi
485 done; return 1; } && return 0
486
487 return 1
488 }
489
490 # find_mp_fstype <mountpoint>
491 # Echo the filesystem type for a given mountpoint.
492 # /proc/self/mountinfo is taken as the primary source of information
493 # and /etc/fstab is used as a fallback.
494 # No newline is appended!
495 # Example:
496 # $ find_mp_fstype /;echo
497 # ext4
498 find_mp_fstype() {
499 local _fs
500
501 if [[ $use_fstab != yes ]]; then
502 findmnt -e -v -n -o 'FSTYPE' --target "$1" | { \
503 while read _fs; do
504 [[ $_fs ]] || continue
505 [[ $_fs = "autofs" ]] && continue
506 printf "%s" "$_fs"
507 return 0
508 done; return 1; } && return 0
509 fi
510
511 findmnt --fstab -e -v -n -o 'FSTYPE' --target "$1" | { \
512 while read _fs; do
513 [[ $_fs ]] || continue
514 [[ $_fs = "autofs" ]] && continue
515 printf "%s" "$_fs"
516 return 0
517 done; return 1; } && return 0
518
519 return 1
520 }
521
522 # find_dev_fstype <device>
523 # Echo the filesystem type for a given device.
524 # /proc/self/mountinfo is taken as the primary source of information
525 # and /etc/fstab is used as a fallback.
526 # No newline is appended!
527 # Example:
528 # $ find_dev_fstype /dev/sda2;echo
529 # ext4
530 find_dev_fstype() {
531 local _find_dev _fs
532 _find_dev="$1"
533 if ! [[ "$_find_dev" = /dev* ]]; then
534 [[ -b "/dev/block/$_find_dev" ]] && _find_dev="/dev/block/$_find_dev"
535 fi
536
537 if [[ $use_fstab != yes ]]; then
538 findmnt -e -v -n -o 'FSTYPE' --source "$_find_dev" | { \
539 while read _fs; do
540 [[ $_fs ]] || continue
541 [[ $_fs = "autofs" ]] && continue
542 printf "%s" "$_fs"
543 return 0
544 done; return 1; } && return 0
545 fi
546
547 findmnt --fstab -e -v -n -o 'FSTYPE' --source "$_find_dev" | { \
548 while read _fs; do
549 [[ $_fs ]] || continue
550 [[ $_fs = "autofs" ]] && continue
551 printf "%s" "$_fs"
552 return 0
553 done; return 1; } && return 0
554
555 return 1
556 }
557
558 # find_mp_fsopts <mountpoint>
559 # Echo the filesystem options for a given mountpoint.
560 # /proc/self/mountinfo is taken as the primary source of information
561 # and /etc/fstab is used as a fallback.
562 # No newline is appended!
563 # Example:
564 # $ find_mp_fsopts /;echo
565 # rw,relatime,discard,data=ordered
566 find_mp_fsopts() {
567 if [[ $use_fstab != yes ]]; then
568 findmnt -e -v -n -o 'OPTIONS' --target "$1" 2>/dev/null && return 0
569 fi
570
571 findmnt --fstab -e -v -n -o 'OPTIONS' --target "$1"
572 }
573
574 # find_dev_fsopts <device>
575 # Echo the filesystem options for a given device.
576 # /proc/self/mountinfo is taken as the primary source of information
577 # and /etc/fstab is used as a fallback.
578 # Example:
579 # $ find_dev_fsopts /dev/sda2
580 # rw,relatime,discard,data=ordered
581 find_dev_fsopts() {
582 local _find_dev _opts
583 _find_dev="$1"
584 if ! [[ "$_find_dev" = /dev* ]]; then
585 [[ -b "/dev/block/$_find_dev" ]] && _find_dev="/dev/block/$_find_dev"
586 fi
587
588 if [[ $use_fstab != yes ]]; then
589 findmnt -e -v -n -o 'OPTIONS' --source "$_find_dev" 2>/dev/null && return 0
590 fi
591
592 findmnt --fstab -e -v -n -o 'OPTIONS' --source "$_find_dev"
593 }
594
595
596 # finds the major:minor of the block device backing the root filesystem.
597 find_root_block_device() { find_block_device /; }
598
599 # for_each_host_dev_fs <func>
600 # Execute "<func> <dev> <filesystem>" for every "<dev> <fs>" pair found
601 # in ${host_fs_types[@]}
602 for_each_host_dev_fs()
603 {
604 local _func="$1"
605 local _dev
606 local _ret=1
607
608 [[ "${!host_fs_types[@]}" ]] || return 0
609
610 for _dev in "${!host_fs_types[@]}"; do
611 $_func "$_dev" "${host_fs_types[$_dev]}" && _ret=0
612 done
613 return $_ret
614 }
615
616 host_fs_all()
617 {
618 printf "%s\n" "${host_fs_types[@]}"
619 }
620
621 # Walk all the slave relationships for a given block device.
622 # Stop when our helper function returns success
623 # $1 = function to call on every found block device
624 # $2 = block device in major:minor format
625 check_block_and_slaves() {
626 local _x
627 [[ -b /dev/block/$2 ]] || return 1 # Not a block device? So sorry.
628 if ! lvm_internal_dev $2; then "$1" $2 && return; fi
629 check_vol_slaves "$@" && return 0
630 if [[ -f /sys/dev/block/$2/../dev ]]; then
631 check_block_and_slaves $1 $(<"/sys/dev/block/$2/../dev") && return 0
632 fi
633 [[ -d /sys/dev/block/$2/slaves ]] || return 1
634 for _x in /sys/dev/block/$2/slaves/*/dev; do
635 [[ -f $_x ]] || continue
636 check_block_and_slaves $1 $(<"$_x") && return 0
637 done
638 return 1
639 }
640
641 check_block_and_slaves_all() {
642 local _x _ret=1
643 [[ -b /dev/block/$2 ]] || return 1 # Not a block device? So sorry.
644 if ! lvm_internal_dev $2 && "$1" $2; then
645 _ret=0
646 fi
647 check_vol_slaves "$@" && return 0
648 if [[ -f /sys/dev/block/$2/../dev ]]; then
649 check_block_and_slaves_all $1 $(<"/sys/dev/block/$2/../dev") && _ret=0
650 fi
651 [[ -d /sys/dev/block/$2/slaves ]] || return 1
652 for _x in /sys/dev/block/$2/slaves/*/dev; do
653 [[ -f $_x ]] || continue
654 check_block_and_slaves_all $1 $(<"$_x") && _ret=0
655 done
656 return $_ret
657 }
658 # for_each_host_dev_and_slaves <func>
659 # Execute "<func> <dev>" for every "<dev>" found
660 # in ${host_devs[@]} and their slaves
661 for_each_host_dev_and_slaves_all()
662 {
663 local _func="$1"
664 local _dev
665 local _ret=1
666
667 [[ "${host_devs[@]}" ]] || return 0
668
669 for _dev in ${host_devs[@]}; do
670 [[ -b "$_dev" ]] || continue
671 if check_block_and_slaves_all $_func $(get_maj_min $_dev); then
672 _ret=0
673 fi
674 done
675 return $_ret
676 }
677
678 for_each_host_dev_and_slaves()
679 {
680 local _func="$1"
681 local _dev
682
683 [[ "${host_devs[@]}" ]] || return 0
684
685 for _dev in ${host_devs[@]}; do
686 [[ -b "$_dev" ]] || continue
687 check_block_and_slaves $_func $(get_maj_min $_dev) && return 0
688 done
689 return 1
690 }
691
692 # ugly workaround for the lvm design
693 # There is no volume group device,
694 # so, there are no slave devices for volume groups.
695 # Logical volumes only have the slave devices they really live on,
696 # but you cannot create the logical volume without the volume group.
697 # And the volume group might be bigger than the devices the LV needs.
698 check_vol_slaves() {
699 local _lv _vg _pv
700 for i in /dev/mapper/*; do
701 [[ $i == /dev/mapper/control ]] && continue
702 _lv=$(get_maj_min $i)
703 if [[ $_lv = $2 ]]; then
704 _vg=$(lvm lvs --noheadings -o vg_name $i 2>/dev/null)
705 # strip space
706 _vg=$(printf "%s\n" "$_vg")
707 if [[ $_vg ]]; then
708 for _pv in $(lvm vgs --noheadings -o pv_name "$_vg" 2>/dev/null)
709 do
710 check_block_and_slaves $1 $(get_maj_min $_pv) && return 0
711 done
712 fi
713 fi
714 done
715 return 1
716 }
717
718 # fs_get_option <filesystem options> <search for option>
719 # search for a specific option in a bunch of filesystem options
720 # and return the value
721 fs_get_option() {
722 local _fsopts=$1
723 local _option=$2
724 local OLDIFS="$IFS"
725 IFS=,
726 set -- $_fsopts
727 IFS="$OLDIFS"
728 while [ $# -gt 0 ]; do
729 case $1 in
730 $_option=*)
731 echo ${1#${_option}=}
732 break
733 esac
734 shift
735 done
736 }
737
738
739 if ! [[ $DRACUT_INSTALL ]]; then
740 DRACUT_INSTALL=$(find_binary dracut-install)
741 fi
742
743 if ! [[ $DRACUT_INSTALL ]] && [[ -x $dracutbasedir/dracut-install ]]; then
744 DRACUT_INSTALL=$dracutbasedir/dracut-install
745 fi
746
747 if ! [[ -x $DRACUT_INSTALL ]]; then
748 dfatal "dracut-install not found!"
749 exit 10
750 fi
751
752 [[ $DRACUT_RESOLVE_LAZY ]] || export DRACUT_RESOLVE_DEPS=1
753 inst_dir() {
754 [[ -e ${initdir}/"$1" ]] && return 0 # already there
755 $DRACUT_INSTALL ${initdir:+-D "$initdir"} -d "$@"
756 (($? != 0)) && derror $DRACUT_INSTALL ${initdir:+-D "$initdir"} -d "$@" || :
757 }
758
759 inst() {
760 [[ -e ${initdir}/"${2:-$1}" ]] && return 0 # already there
761 #dinfo "$DRACUT_INSTALL -l $@"
762 $DRACUT_INSTALL ${initdir:+-D "$initdir"} ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-H} "$@"
763 (($? != 0)) && derror $DRACUT_INSTALL ${initdir:+-D "$initdir"} ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-H} "$@" || :
764 }
765
766 inst_simple() {
767 [[ -e ${initdir}/"${2:-$1}" ]] && return 0 # already there
768 [[ -e $1 ]] || return 1 # no source
769 $DRACUT_INSTALL ${initdir:+-D "$initdir"} "$@"
770 (($? != 0)) && derror $DRACUT_INSTALL ${initdir:+-D "$initdir"} "$@" || :
771 }
772
773 inst_symlink() {
774 [[ -e ${initdir}/"${2:-$1}" ]] && return 0 # already there
775 [[ -L $1 ]] || return 1
776 $DRACUT_INSTALL ${initdir:+-D "$initdir"} ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-H} "$@"
777 (($? != 0)) && derror $DRACUT_INSTALL ${initdir:+-D "$initdir"} ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-H} "$@" || :
778 }
779
780 inst_multiple() {
781 local ret
782 #dinfo "initdir=$initdir $DRACUT_INSTALL -l $@"
783 $DRACUT_INSTALL ${initdir:+-D "$initdir"} -a ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-H} "$@"
784 ret=$?
785 (($ret != 0)) && derror $DRACUT_INSTALL ${initdir:+-D "$initdir"} -a ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-H} "$@" || :
786 return $ret
787 }
788
789 dracut_install() {
790 inst_multiple "$@"
791 }
792
793 inst_library() {
794 [[ -e ${initdir}/"${2:-$1}" ]] && return 0 # already there
795 [[ -e $1 ]] || return 1 # no source
796 $DRACUT_INSTALL ${initdir:+-D "$initdir"} ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-H} "$@"
797 (($? != 0)) && derror $DRACUT_INSTALL ${initdir:+-D "$initdir"} ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-H} "$@" || :
798 }
799
800 inst_binary() {
801 $DRACUT_INSTALL ${initdir:+-D "$initdir"} ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-H} "$@"
802 (($? != 0)) && derror $DRACUT_INSTALL ${initdir:+-D "$initdir"} ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-H} "$@" || :
803 }
804
805 inst_script() {
806 $DRACUT_INSTALL ${initdir:+-D "$initdir"} ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-H} "$@"
807 (($? != 0)) && derror $DRACUT_INSTALL ${initdir:+-D "$initdir"} ${DRACUT_RESOLVE_DEPS:+-l} ${DRACUT_FIPS_MODE:+-H} "$@" || :
808 }
809
810 # find symlinks linked to given library file
811 # $1 = library file
812 # Function searches for symlinks by stripping version numbers appended to
813 # library filename, checks if it points to the same target and finally
814 # prints the list of symlinks to stdout.
815 #
816 # Example:
817 # rev_lib_symlinks libfoo.so.8.1
818 # output: libfoo.so.8 libfoo.so
819 # (Only if libfoo.so.8 and libfoo.so exists on host system.)
820 rev_lib_symlinks() {
821 [[ ! $1 ]] && return 0
822
823 local fn="$1" orig="$(readlink -f "$1")" links=''
824
825 [[ ${fn} == *.so.* ]] || return 1
826
827 until [[ ${fn##*.} == so ]]; do
828 fn="${fn%.*}"
829 [[ -L ${fn} && $(readlink -f "${fn}") == ${orig} ]] && links+=" ${fn}"
830 done
831
832 echo "${links}"
833 }
834
835 # attempt to install any programs specified in a udev rule
836 inst_rule_programs() {
837 local _prog _bin
838
839 if grep -qE 'PROGRAM==?"[^ "]+' "$1"; then
840 for _prog in $(grep -E 'PROGRAM==?"[^ "]+' "$1" | sed -r 's/.*PROGRAM==?"([^ "]+).*/\1/'); do
841 _bin=""
842 if [ -x ${udevdir}/$_prog ]; then
843 _bin=${udevdir}/$_prog
844 elif [[ "${_prog/\$env\{/}" == "$_prog" ]]; then
845 _bin=$(find_binary "$_prog") || {
846 dinfo "Skipping program $_prog using in udev rule ${1##*/} as it cannot be found"
847 continue;
848 }
849 fi
850
851 [[ $_bin ]] && inst_binary "$_bin"
852 done
853 fi
854 if grep -qE 'RUN[+=]=?"[^ "]+' "$1"; then
855 for _prog in $(grep -E 'RUN[+=]=?"[^ "]+' "$1" | sed -r 's/.*RUN[+=]=?"([^ "]+).*/\1/'); do
856 _bin=""
857 if [ -x ${udevdir}/$_prog ]; then
858 _bin=${udevdir}/$_prog
859 elif [[ "${_prog/\$env\{/}" == "$_prog" ]] && [[ "${_prog}" != "/sbin/initqueue" ]]; then
860 _bin=$(find_binary "$_prog") || {
861 dinfo "Skipping program $_prog using in udev rule ${1##*/} as it cannot be found"
862 continue;
863 }
864 fi
865
866 [[ $_bin ]] && inst_binary "$_bin"
867 done
868 fi
869 if grep -qE 'IMPORT\{program\}==?"[^ "]+' "$1"; then
870 for _prog in $(grep -E 'IMPORT\{program\}==?"[^ "]+' "$1" | sed -r 's/.*IMPORT\{program\}==?"([^ "]+).*/\1/'); do
871 _bin=""
872 if [ -x ${udevdir}/$_prog ]; then
873 _bin=${udevdir}/$_prog
874 elif [[ "${_prog/\$env\{/}" == "$_prog" ]]; then
875 _bin=$(find_binary "$_prog") || {
876 dinfo "Skipping program $_prog using in udev rule ${1##*/} as it cannot be found"
877 continue;
878 }
879 fi
880
881 [[ $_bin ]] && dracut_install "$_bin"
882 done
883 fi
884 }
885
886 # attempt to install any programs specified in a udev rule
887 inst_rule_group_owner() {
888 local i
889
890 if grep -qE 'OWNER=?"[^ "]+' "$1"; then
891 for i in $(grep -E 'OWNER=?"[^ "]+' "$1" | sed -r 's/.*OWNER=?"([^ "]+).*/\1/'); do
892 if ! egrep -q "^$i:" "$initdir/etc/passwd" 2>/dev/null; then
893 egrep "^$i:" /etc/passwd 2>/dev/null >> "$initdir/etc/passwd"
894 fi
895 done
896 fi
897 if grep -qE 'GROUP=?"[^ "]+' "$1"; then
898 for i in $(grep -E 'GROUP=?"[^ "]+' "$1" | sed -r 's/.*GROUP=?"([^ "]+).*/\1/'); do
899 if ! egrep -q "^$i:" "$initdir/etc/group" 2>/dev/null; then
900 egrep "^$i:" /etc/group 2>/dev/null >> "$initdir/etc/group"
901 fi
902 done
903 fi
904 }
905
906 inst_rule_initqueue() {
907 if grep -q -F initqueue "$1"; then
908 dracut_need_initqueue
909 fi
910 }
911
912 # udev rules always get installed in the same place, so
913 # create a function to install them to make life simpler.
914 inst_rules() {
915 local _target=/etc/udev/rules.d _rule _found
916
917 inst_dir "${udevdir}/rules.d"
918 inst_dir "$_target"
919 for _rule in "$@"; do
920 if [ "${_rule#/}" = "$_rule" ]; then
921 for r in ${udevdir}/rules.d ${hostonly:+/etc/udev/rules.d}; do
922 if [[ -e $r/$_rule ]]; then
923 _found="$r/$_rule"
924 inst_rule_programs "$_found"
925 inst_rule_group_owner "$_found"
926 inst_rule_initqueue "$_found"
927 inst_simple "$_found"
928 fi
929 done
930 fi
931 for r in '' $dracutbasedir/rules.d/; do
932 # skip rules without an absolute path
933 [[ "${r}$_rule" != /* ]] && continue
934
935 if [[ -f ${r}$_rule ]]; then
936 _found="${r}$_rule"
937 inst_rule_programs "$_found"
938 inst_rule_group_owner "$_found"
939 inst_rule_initqueue "$_found"
940 inst_simple "$_found" "$_target/${_found##*/}"
941 fi
942 done
943 [[ $_found ]] || dinfo "Skipping udev rule: $_rule"
944 done
945 }
946
947 inst_rules_wildcard() {
948 local _target=/etc/udev/rules.d _rule _found
949
950 inst_dir "${udevdir}/rules.d"
951 inst_dir "$_target"
952 for _rule in ${udevdir}/rules.d/$1 ${dracutbasedir}/rules.d/$1 ; do
953 if [[ -e $_rule ]]; then
954 inst_rule_programs "$_rule"
955 inst_rule_group_owner "$_rule"
956 inst_rule_initqueue "$_rule"
957 inst_simple "$_rule"
958 _found=$_rule
959 fi
960 done
961 if [ -n ${hostonly} ] ; then
962 for _rule in ${_target}/$1 ; do
963 if [[ -f $_rule ]]; then
964 inst_rule_programs "$_rule"
965 inst_rule_group_owner "$_rule"
966 inst_rule_initqueue "$_rule"
967 inst_simple "$_rule"
968 _found=$_rule
969 fi
970 done
971 fi
972 [[ $_found ]] || dinfo "Skipping udev rule: $_rule"
973 }
974
975 prepare_udev_rules() {
976 [ -z "$UDEVVERSION" ] && export UDEVVERSION=$(udevadm --version)
977
978 for f in "$@"; do
979 f="${initdir}/etc/udev/rules.d/$f"
980 [ -e "$f" ] || continue
981 while read line; do
982 if [ "${line%%IMPORT PATH_ID}" != "$line" ]; then
983 if [ $UDEVVERSION -ge 174 ]; then
984 printf '%sIMPORT{builtin}="path_id"\n' "${line%%IMPORT PATH_ID}"
985 else
986 printf '%sIMPORT{program}="path_id %%p"\n' "${line%%IMPORT PATH_ID}"
987 fi
988 elif [ "${line%%IMPORT BLKID}" != "$line" ]; then
989 if [ $UDEVVERSION -ge 176 ]; then
990 printf '%sIMPORT{builtin}="blkid"\n' "${line%%IMPORT BLKID}"
991 else
992 printf '%sIMPORT{program}="/sbin/blkid -o udev -p $tempnode"\n' "${line%%IMPORT BLKID}"
993 fi
994 else
995 echo "$line"
996 fi
997 done < "${f}" > "${f}.new"
998 mv "${f}.new" "$f"
999 done
1000 }
1001
1002 # install function specialized for hooks
1003 # $1 = type of hook, $2 = hook priority (lower runs first), $3 = hook
1004 # All hooks should be POSIX/SuS compliant, they will be sourced by init.
1005 inst_hook() {
1006 if ! [[ -f $3 ]]; then
1007 dfatal "Cannot install a hook ($3) that does not exist."
1008 dfatal "Aborting initrd creation."
1009 exit 1
1010 elif ! [[ "$hookdirs" == *$1* ]]; then
1011 dfatal "No such hook type $1. Aborting initrd creation."
1012 exit 1
1013 fi
1014 inst_simple "$3" "/lib/dracut/hooks/${1}/${2}-${3##*/}"
1015 }
1016
1017 # install any of listed files
1018 #
1019 # If first argument is '-d' and second some destination path, first accessible
1020 # source is installed into this path, otherwise it will installed in the same
1021 # path as source. If none of listed files was installed, function return 1.
1022 # On first successful installation it returns with 0 status.
1023 #
1024 # Example:
1025 #
1026 # inst_any -d /bin/foo /bin/bar /bin/baz
1027 #
1028 # Lets assume that /bin/baz exists, so it will be installed as /bin/foo in
1029 # initramfs.
1030 inst_any() {
1031 local to f
1032
1033 [[ $1 = '-d' ]] && to="$2" && shift 2
1034
1035 for f in "$@"; do
1036 if [[ -e $f ]]; then
1037 [[ $to ]] && inst "$f" "$to" && return 0
1038 inst "$f" && return 0
1039 fi
1040 done
1041
1042 return 1
1043 }
1044
1045
1046 # inst_libdir_file [-n <pattern>] <file> [<file>...]
1047 # Install a <file> located on a lib directory to the initramfs image
1048 # -n <pattern> install matching files
1049 inst_libdir_file() {
1050 local _files
1051 if [[ "$1" == "-n" ]]; then
1052 local _pattern=$2
1053 shift 2
1054 for _dir in $libdirs; do
1055 for _i in "$@"; do
1056 for _f in "$_dir"/$_i; do
1057 [[ "$_f" =~ $_pattern ]] || continue
1058 [[ -e "$_f" ]] && _files+="$_f "
1059 done
1060 done
1061 done
1062 else
1063 for _dir in $libdirs; do
1064 for _i in "$@"; do
1065 for _f in "$_dir"/$_i; do
1066 [[ -e "$_f" ]] && _files+="$_f "
1067 done
1068 done
1069 done
1070 fi
1071 [[ $_files ]] && inst_multiple $_files
1072 }
1073
1074
1075 # install function decompressing the target and handling symlinks
1076 # $@ = list of compressed (gz or bz2) files or symlinks pointing to such files
1077 #
1078 # Function install targets in the same paths inside overlay but decompressed
1079 # and without extensions (.gz, .bz2).
1080 inst_decompress() {
1081 local _src _cmd
1082
1083 for _src in $@
1084 do
1085 case ${_src} in
1086 *.gz) _cmd='gzip -f -d' ;;
1087 *.bz2) _cmd='bzip2 -d' ;;
1088 *) return 1 ;;
1089 esac
1090 inst_simple ${_src}
1091 # Decompress with chosen tool. We assume that tool changes name e.g.
1092 # from 'name.gz' to 'name'.
1093 ${_cmd} "${initdir}${_src}"
1094 done
1095 }
1096
1097 # It's similar to above, but if file is not compressed, performs standard
1098 # install.
1099 # $@ = list of files
1100 inst_opt_decompress() {
1101 local _src
1102
1103 for _src in $@
1104 do
1105 inst_decompress "${_src}" || inst "${_src}"
1106 done
1107 }
1108
1109 # module_check <dracut module>
1110 # execute the check() function of module-setup.sh of <dracut module>
1111 # or the "check" script, if module-setup.sh is not found
1112 # "check $hostonly" is called
1113 module_check() {
1114 local _moddir=$(echo ${dracutbasedir}/modules.d/??${1})
1115 local _ret
1116 local _forced=0
1117 local _hostonly=$hostonly
1118 [ $# -eq 2 ] && _forced=$2
1119 [[ -d $_moddir ]] || return 1
1120 if [[ ! -f $_moddir/module-setup.sh ]]; then
1121 # if we do not have a check script, we are unconditionally included
1122 [[ -x $_moddir/check ]] || return 0
1123 [ $_forced -ne 0 ] && unset hostonly
1124 $_moddir/check $hostonly
1125 _ret=$?
1126 else
1127 unset check depends cmdline install installkernel
1128 check() { true; }
1129 . $_moddir/module-setup.sh
1130 is_func check || return 0
1131 [ $_forced -ne 0 ] && unset hostonly
1132 moddir=$_moddir check $hostonly
1133 _ret=$?
1134 unset check depends cmdline install installkernel
1135 fi
1136 hostonly=$_hostonly
1137 return $_ret
1138 }
1139
1140 # module_check_mount <dracut module>
1141 # execute the check() function of module-setup.sh of <dracut module>
1142 # or the "check" script, if module-setup.sh is not found
1143 # "mount_needs=1 check 0" is called
1144 module_check_mount() {
1145 local _moddir=$(echo ${dracutbasedir}/modules.d/??${1})
1146 local _ret
1147 mount_needs=1
1148 [[ -d $_moddir ]] || return 1
1149 if [[ ! -f $_moddir/module-setup.sh ]]; then
1150 # if we do not have a check script, we are unconditionally included
1151 [[ -x $_moddir/check ]] || return 0
1152 mount_needs=1 $_moddir/check 0
1153 _ret=$?
1154 else
1155 unset check depends cmdline install installkernel
1156 check() { false; }
1157 . $_moddir/module-setup.sh
1158 moddir=$_moddir check 0
1159 _ret=$?
1160 unset check depends cmdline install installkernel
1161 fi
1162 unset mount_needs
1163 return $_ret
1164 }
1165
1166 # module_depends <dracut module>
1167 # execute the depends() function of module-setup.sh of <dracut module>
1168 # or the "depends" script, if module-setup.sh is not found
1169 module_depends() {
1170 local _moddir=$(echo ${dracutbasedir}/modules.d/??${1})
1171 local _ret
1172 [[ -d $_moddir ]] || return 1
1173 if [[ ! -f $_moddir/module-setup.sh ]]; then
1174 # if we do not have a check script, we have no deps
1175 [[ -x $_moddir/check ]] || return 0
1176 $_moddir/check -d
1177 return $?
1178 else
1179 unset check depends cmdline install installkernel
1180 depends() { true; }
1181 . $_moddir/module-setup.sh
1182 moddir=$_moddir depends
1183 _ret=$?
1184 unset check depends cmdline install installkernel
1185 return $_ret
1186 fi
1187 }
1188
1189 # module_cmdline <dracut module>
1190 # execute the cmdline() function of module-setup.sh of <dracut module>
1191 # or the "cmdline" script, if module-setup.sh is not found
1192 module_cmdline() {
1193 local _moddir=$(echo ${dracutbasedir}/modules.d/??${1})
1194 local _ret
1195 [[ -d $_moddir ]] || return 1
1196 if [[ ! -f $_moddir/module-setup.sh ]]; then
1197 [[ -x $_moddir/cmdline ]] && . "$_moddir/cmdline"
1198 return $?
1199 else
1200 unset check depends cmdline install installkernel
1201 cmdline() { true; }
1202 . $_moddir/module-setup.sh
1203 moddir=$_moddir cmdline
1204 _ret=$?
1205 unset check depends cmdline install installkernel
1206 return $_ret
1207 fi
1208 }
1209
1210 # module_install <dracut module>
1211 # execute the install() function of module-setup.sh of <dracut module>
1212 # or the "install" script, if module-setup.sh is not found
1213 module_install() {
1214 local _moddir=$(echo ${dracutbasedir}/modules.d/??${1})
1215 local _ret
1216 [[ -d $_moddir ]] || return 1
1217 if [[ ! -f $_moddir/module-setup.sh ]]; then
1218 [[ -x $_moddir/install ]] && . "$_moddir/install"
1219 return $?
1220 else
1221 unset check depends cmdline install installkernel
1222 install() { true; }
1223 . $_moddir/module-setup.sh
1224 moddir=$_moddir install
1225 _ret=$?
1226 unset check depends cmdline install installkernel
1227 return $_ret
1228 fi
1229 }
1230
1231 # module_installkernel <dracut module>
1232 # execute the installkernel() function of module-setup.sh of <dracut module>
1233 # or the "installkernel" script, if module-setup.sh is not found
1234 module_installkernel() {
1235 local _moddir=$(echo ${dracutbasedir}/modules.d/??${1})
1236 local _ret
1237 [[ -d $_moddir ]] || return 1
1238 if [[ ! -f $_moddir/module-setup.sh ]]; then
1239 [[ -x $_moddir/installkernel ]] && . "$_moddir/installkernel"
1240 return $?
1241 else
1242 unset check depends cmdline install installkernel
1243 installkernel() { true; }
1244 . $_moddir/module-setup.sh
1245 moddir=$_moddir installkernel
1246 _ret=$?
1247 unset check depends cmdline install installkernel
1248 return $_ret
1249 fi
1250 }
1251
1252 # check_mount <dracut module>
1253 # check_mount checks, if a dracut module is needed for the given
1254 # device and filesystem types in "${host_fs_types[@]}"
1255 check_mount() {
1256 local _mod=$1
1257 local _moddir=$(echo ${dracutbasedir}/modules.d/??${1})
1258 local _ret
1259 local _moddep
1260
1261 [ "${#host_fs_types[*]}" -le 0 ] && return 1
1262
1263 # If we are already scheduled to be loaded, no need to check again.
1264 [[ " $mods_to_load " == *\ $_mod\ * ]] && return 0
1265 [[ " $mods_checked_as_dep " == *\ $_mod\ * ]] && return 1
1266
1267 # This should never happen, but...
1268 [[ -d $_moddir ]] || return 1
1269
1270 [[ $2 ]] || mods_checked_as_dep+=" $_mod "
1271
1272 if [[ " $omit_dracutmodules " == *\ $_mod\ * ]]; then
1273 return 1
1274 fi
1275
1276 if [[ " $dracutmodules $add_dracutmodules $force_add_dracutmodules" == *\ $_mod\ * ]]; then
1277 module_check_mount $_mod; ret=$?
1278
1279 # explicit module, so also accept ret=255
1280 [[ $ret = 0 || $ret = 255 ]] || return 1
1281 else
1282 # module not in our list
1283 if [[ $dracutmodules = all ]]; then
1284 # check, if we can and should install this module
1285 module_check_mount $_mod || return 1
1286 else
1287 # skip this module
1288 return 1
1289 fi
1290 fi
1291
1292
1293 for _moddep in $(module_depends $_mod); do
1294 # handle deps as if they were manually added
1295 [[ " $add_dracutmodules " == *\ $_moddep\ * ]] || \
1296 add_dracutmodules+=" $_moddep "
1297 [[ " $force_add_dracutmodules " == *\ $_moddep\ * ]] || \
1298 force_add_dracutmodules+=" $_moddep "
1299 # if a module we depend on fail, fail also
1300 if ! check_module $_moddep; then
1301 derror "dracut module '$_mod' depends on '$_moddep', which can't be installed"
1302 return 1
1303 fi
1304 done
1305
1306 [[ " $mods_to_load " == *\ $_mod\ * ]] || \
1307 mods_to_load+=" $_mod "
1308
1309 return 0
1310 }
1311
1312 # check_module <dracut module> [<use_as_dep>]
1313 # check if a dracut module is to be used in the initramfs process
1314 # if <use_as_dep> is set, then the process also keeps track
1315 # that the modules were checked for the dependency tracking process
1316 check_module() {
1317 local _mod=$1
1318 local _moddir=$(echo ${dracutbasedir}/modules.d/??${1})
1319 local _ret
1320 local _moddep
1321 # If we are already scheduled to be loaded, no need to check again.
1322 [[ " $mods_to_load " == *\ $_mod\ * ]] && return 0
1323 [[ " $mods_checked_as_dep " == *\ $_mod\ * ]] && return 1
1324
1325 # This should never happen, but...
1326 [[ -d $_moddir ]] || return 1
1327
1328 [[ $2 ]] || mods_checked_as_dep+=" $_mod "
1329
1330 if [[ " $omit_dracutmodules " == *\ $_mod\ * ]]; then
1331 dinfo "dracut module '$_mod' will not be installed, because it's in the list to be omitted!"
1332 return 1
1333 fi
1334
1335 if [[ " $dracutmodules $add_dracutmodules $force_add_dracutmodules" == *\ $_mod\ * ]]; then
1336 if [[ " $force_add_dracutmodules " == *\ $_mod\ * ]]; then
1337 module_check $_mod 1; ret=$?
1338 else
1339 module_check $_mod 0; ret=$?
1340 fi
1341 # explicit module, so also accept ret=255
1342 [[ $ret = 0 || $ret = 255 ]] || return 1
1343 else
1344 # module not in our list
1345 if [[ $dracutmodules = all ]]; then
1346 # check, if we can and should install this module
1347 module_check $_mod || return 1
1348 else
1349 # skip this module
1350 return 1
1351 fi
1352 fi
1353
1354 for _moddep in $(module_depends $_mod); do
1355 # handle deps as if they were manually added
1356 [[ " $add_dracutmodules " == *\ $_moddep\ * ]] || \
1357 add_dracutmodules+=" $_moddep "
1358 [[ " $force_add_dracutmodules " == *\ $_moddep\ * ]] || \
1359 force_add_dracutmodules+=" $_moddep "
1360 # if a module we depend on fail, fail also
1361 if ! check_module $_moddep; then
1362 derror "dracut module '$_mod' depends on '$_moddep', which can't be installed"
1363 return 1
1364 fi
1365 done
1366
1367 [[ " $mods_to_load " == *\ $_mod\ * ]] || \
1368 mods_to_load+=" $_mod "
1369
1370 return 0
1371 }
1372
1373 # for_each_module_dir <func>
1374 # execute "<func> <dracut module> 1"
1375 for_each_module_dir() {
1376 local _modcheck
1377 local _mod
1378 local _moddir
1379 local _func
1380 _func=$1
1381 for _moddir in "$dracutbasedir/modules.d"/[0-9][0-9]*; do
1382 [[ -d $_moddir ]] || continue;
1383 [[ -e $_moddir/install || -e $_moddir/installkernel || \
1384 -e $_moddir/module-setup.sh ]] || continue
1385 _mod=${_moddir##*/}; _mod=${_mod#[0-9][0-9]}
1386 $_func $_mod 1
1387 done
1388
1389 # Report any missing dracut modules, the user has specified
1390 _modcheck="$add_dracutmodules $force_add_dracutmodules"
1391 [[ $dracutmodules != all ]] && _modcheck="$m $dracutmodules"
1392 for _mod in $_modcheck; do
1393 [[ " $mods_to_load " == *\ $_mod\ * ]] && continue
1394 [[ " $omit_dracutmodules " == *\ $_mod\ * ]] && continue
1395 derror "dracut module '$_mod' cannot be found or installed."
1396 done
1397 }
1398
1399 # Install a single kernel module along with any firmware it may require.
1400 # $1 = full path to kernel module to install
1401 install_kmod_with_fw() {
1402 # no need to go further if the module is already installed
1403
1404 [[ -e "${initdir}/lib/modules/$kernel/${1##*/lib/modules/$kernel/}" ]] \
1405 && return 0
1406
1407 if [[ $DRACUT_KERNEL_LAZY_HASHDIR ]] && [[ -e "$DRACUT_KERNEL_LAZY_HASHDIR/${1##*/}" ]]; then
1408 read ret < "$DRACUT_KERNEL_LAZY_HASHDIR/${1##*/}"
1409 return $ret
1410 fi
1411
1412 if [[ $omit_drivers ]]; then
1413 local _kmod=${1##*/}
1414 _kmod=${_kmod%.ko}
1415 _kmod=${_kmod/-/_}
1416 if [[ "$_kmod" =~ $omit_drivers ]]; then
1417 dinfo "Omitting driver $_kmod"
1418 return 0
1419 fi
1420 if [[ "${1##*/lib/modules/$kernel/}" =~ $omit_drivers ]]; then
1421 dinfo "Omitting driver $_kmod"
1422 return 0
1423 fi
1424 fi
1425
1426 if [[ $silent_omit_drivers ]]; then
1427 local _kmod=${1##*/}
1428 _kmod=${_kmod%.ko}
1429 _kmod=${_kmod/-/_}
1430 [[ "$_kmod" =~ $silent_omit_drivers ]] && return 0
1431 [[ "${1##*/lib/modules/$kernel/}" =~ $silent_omit_drivers ]] && return 0
1432 fi
1433
1434 inst_simple "$1" "/lib/modules/$kernel/${1##*/lib/modules/$kernel/}"
1435 ret=$?
1436 [[ $DRACUT_KERNEL_LAZY_HASHDIR ]] && \
1437 [[ -d "$DRACUT_KERNEL_LAZY_HASHDIR" ]] && \
1438 echo $ret > "$DRACUT_KERNEL_LAZY_HASHDIR/${1##*/}"
1439 (($ret != 0)) && return $ret
1440
1441 local _modname=${1##*/} _fwdir _found _fw
1442 _modname=${_modname%.ko*}
1443 for _fw in $(modinfo -k $kernel -F firmware $1 2>/dev/null); do
1444 _found=''
1445 for _fwdir in $fw_dir; do
1446 if [[ -d $_fwdir && -f $_fwdir/$_fw ]]; then
1447 inst_simple "$_fwdir/$_fw" "/lib/firmware/$_fw"
1448 _found=yes
1449 fi
1450 done
1451 if [[ $_found != yes ]]; then
1452 if ! [[ -d $(echo /sys/module/${_modname//-/_}|{ read a b; echo $a; }) ]]; then
1453 dinfo "Possible missing firmware \"${_fw}\" for kernel module" \
1454 "\"${_modname}.ko\""
1455 else
1456 dwarn "Possible missing firmware \"${_fw}\" for kernel module" \
1457 "\"${_modname}.ko\""
1458 fi
1459 fi
1460 done
1461 return 0
1462 }
1463
1464 # Do something with all the dependencies of a kernel module.
1465 # Note that kernel modules depend on themselves using the technique we use
1466 # $1 = function to call for each dependency we find
1467 # It will be passed the full path to the found kernel module
1468 # $2 = module to get dependencies for
1469 # rest of args = arguments to modprobe
1470 # _fderr specifies FD passed from surrounding scope
1471 for_each_kmod_dep() {
1472 local _func=$1 _kmod=$2 _cmd _modpath _options
1473 shift 2
1474 modprobe "$@" --ignore-install --show-depends $_kmod 2>&${_fderr} | (
1475 while read _cmd _modpath _options; do
1476 [[ $_cmd = insmod ]] || continue
1477 $_func ${_modpath} || exit $?
1478 done
1479 )
1480 }
1481
1482 dracut_kernel_post() {
1483 local _moddirname=${srcmods%%/lib/modules/*}
1484 local _pid
1485
1486 if [[ $DRACUT_KERNEL_LAZY_HASHDIR ]] && [[ -f "$DRACUT_KERNEL_LAZY_HASHDIR/lazylist" ]]; then
1487 xargs -r modprobe -a ${_moddirname:+-d ${_moddirname}/} \
1488 --ignore-install --show-depends --set-version $kernel \
1489 < "$DRACUT_KERNEL_LAZY_HASHDIR/lazylist" 2>/dev/null \
1490 | sort -u \
1491 | while read _cmd _modpath _options; do
1492 [[ $_cmd = insmod ]] || continue
1493 echo "$_modpath"
1494 done > "$DRACUT_KERNEL_LAZY_HASHDIR/lazylist.dep"
1495
1496 (
1497 if [[ $DRACUT_INSTALL ]] && [[ -z $_moddirname ]]; then
1498 xargs -r $DRACUT_INSTALL ${initdir:+-D "$initdir"} -a < "$DRACUT_KERNEL_LAZY_HASHDIR/lazylist.dep"
1499 else
1500 while read _modpath; do
1501 local _destpath=$_modpath
1502 [[ $_moddirname ]] && _destpath=${_destpath##$_moddirname/}
1503 _destpath=${_destpath##*/lib/modules/$kernel/}
1504 inst_simple "$_modpath" "/lib/modules/$kernel/${_destpath}" || exit $?
1505 done < "$DRACUT_KERNEL_LAZY_HASHDIR/lazylist.dep"
1506 fi
1507 ) &
1508 _pid=$(jobs -p | while read a ; do printf ":$a";done)
1509 _pid=${_pid##*:}
1510
1511 if [[ $DRACUT_INSTALL ]]; then
1512 xargs -r modinfo -k $kernel -F firmware < "$DRACUT_KERNEL_LAZY_HASHDIR/lazylist.dep" \
1513 | while read line; do
1514 for _fwdir in $fw_dir; do
1515 echo $_fwdir/$line;
1516 done;
1517 done | xargs -r $DRACUT_INSTALL ${initdir:+-D "$initdir"} -a -o
1518 else
1519 for _fw in $(xargs -r modinfo -k $kernel -F firmware < "$DRACUT_KERNEL_LAZY_HASHDIR/lazylist.dep"); do
1520 for _fwdir in $fw_dir; do
1521 if [[ -d $_fwdir && -f $_fwdir/$_fw ]]; then
1522 inst_simple "$_fwdir/$_fw" "/lib/firmware/$_fw"
1523 break
1524 fi
1525 done
1526 done
1527 fi
1528
1529 wait $_pid
1530 fi
1531
1532 for _f in modules.builtin.bin modules.builtin modules.order; do
1533 [[ $srcmods/$_f ]] && inst_simple "$srcmods/$_f" "/lib/modules/$kernel/$_f"
1534 done
1535
1536 # generate module dependencies for the initrd
1537 if [[ -d $initdir/lib/modules/$kernel ]] && \
1538 ! depmod -a -b "$initdir" $kernel; then
1539 dfatal "\"depmod -a $kernel\" failed."
1540 exit 1
1541 fi
1542
1543 [[ $DRACUT_KERNEL_LAZY_HASHDIR ]] && rm -fr -- "$DRACUT_KERNEL_LAZY_HASHDIR"
1544 }
1545
1546 [[ "$kernel_current" ]] || export kernel_current=$(uname -r)
1547
1548 module_is_host_only() {
1549 local _mod=$1
1550 local _modenc a i _k _s _v _aliases
1551 _mod=${_mod##*/}
1552 _mod=${_mod%.ko}
1553 _modenc=${_mod//-/_}
1554
1555 [[ " $add_drivers " == *\ ${_mod}\ * ]] && return 0
1556
1557 # check if module is loaded
1558 [[ ${host_modules["$_modenc"]} ]] && return 0
1559
1560 [[ "$kernel_current" ]] || export kernel_current=$(uname -r)
1561
1562 if [[ "$kernel_current" != "$kernel" ]]; then
1563 # check if module is loadable on the current kernel
1564 # this covers the case, where a new module is introduced
1565 # or a module was renamed
1566 # or a module changed from builtin to a module
1567
1568 if [[ -d /lib/modules/$kernel_current ]]; then
1569 # if the modinfo can be parsed, but the module
1570 # is not loaded, then we can safely return 1
1571 modinfo -F filename "$_mod" &>/dev/null && return 1
1572 fi
1573
1574 _aliases=$(modinfo -k $kernel -F alias $_mod 2>/dev/null)
1575
1576 # if the module has no aliases, install it
1577 [[ $_aliases ]] || return 0
1578
1579 # finally check all modalias
1580 for a in $_aliases; do
1581 for i in "${!host_modalias[@]}"; do
1582 [[ $i == $a ]] && return 0
1583 done
1584 done
1585
1586 fi
1587
1588 return 1
1589 }
1590
1591 find_kernel_modules_by_path () {
1592 local _OLDIFS
1593
1594 [[ -f "$srcmods/modules.dep" ]] || return 0
1595
1596 _OLDIFS=$IFS
1597 IFS=:
1598 while read a rest; do
1599 [[ $a = */$1/* ]] || [[ $a = updates/* ]] || continue
1600 printf "%s\n" "$srcmods/$a"
1601 done < "$srcmods/modules.dep"
1602 IFS=$_OLDIFS
1603 return 0
1604 }
1605
1606 find_kernel_modules () {
1607 find_kernel_modules_by_path drivers
1608 }
1609
1610 # instmods [-c [-s]] <kernel module> [<kernel module> ... ]
1611 # instmods [-c [-s]] <kernel subsystem>
1612 # install kernel modules along with all their dependencies.
1613 # <kernel subsystem> can be e.g. "=block" or "=drivers/usb/storage"
1614 instmods() {
1615 [[ $no_kernel = yes ]] && return
1616 # called [sub]functions inherit _fderr
1617 local _fderr=9
1618 local _check=no
1619 local _silent=no
1620 if [[ $1 = '-c' ]]; then
1621 _check=yes
1622 shift
1623 fi
1624
1625 if [[ $1 = '-s' ]]; then
1626 _silent=yes
1627 shift
1628 fi
1629
1630 function inst1mod() {
1631 local _ret=0 _mod="$1"
1632 case $_mod in
1633 =*)
1634 ( [[ "$_mpargs" ]] && echo $_mpargs
1635 find_kernel_modules_by_path "${_mod#=}" ) \
1636 | instmods
1637 ((_ret+=$?))
1638 ;;
1639 --*) _mpargs+=" $_mod" ;;
1640 *)
1641 _mod=${_mod##*/}
1642 # if we are already installed, skip this module and go on
1643 # to the next one.
1644 if [[ $DRACUT_KERNEL_LAZY_HASHDIR ]] && \
1645 [[ -f "$DRACUT_KERNEL_LAZY_HASHDIR/${_mod%.ko}.ko" ]]; then
1646 read _ret <"$DRACUT_KERNEL_LAZY_HASHDIR/${_mod%.ko}.ko"
1647 return $_ret
1648 fi
1649
1650 _mod=${_mod/-/_}
1651 if [[ $omit_drivers ]] && [[ "$_mod" =~ $omit_drivers ]]; then
1652 dinfo "Omitting driver ${_mod##$srcmods}"
1653 return 0
1654 fi
1655
1656 # If we are building a host-specific initramfs and this
1657 # module is not already loaded, move on to the next one.
1658 [[ $hostonly ]] \
1659 && ! module_is_host_only "$_mod" \
1660 && return 0
1661
1662 if [[ "$_check" = "yes" ]] || ! [[ $DRACUT_KERNEL_LAZY_HASHDIR ]]; then
1663 # We use '-d' option in modprobe only if modules prefix path
1664 # differs from default '/'. This allows us to use dracut with
1665 # old version of modprobe which doesn't have '-d' option.
1666 local _moddirname=${srcmods%%/lib/modules/*}
1667 [[ -n ${_moddirname} ]] && _moddirname="-d ${_moddirname}/"
1668
1669 # ok, load the module, all its dependencies, and any firmware
1670 # it may require
1671 for_each_kmod_dep install_kmod_with_fw $_mod \
1672 --set-version $kernel ${_moddirname} $_mpargs
1673 ((_ret+=$?))
1674 else
1675 [[ $DRACUT_KERNEL_LAZY_HASHDIR ]] && \
1676 echo $_mod >> "$DRACUT_KERNEL_LAZY_HASHDIR/lazylist"
1677 fi
1678 ;;
1679 esac
1680 return $_ret
1681 }
1682
1683 function instmods_1() {
1684 local _mod _mpargs
1685 if (($# == 0)); then # filenames from stdin
1686 while read _mod; do
1687 inst1mod "${_mod%.ko*}" || {
1688 if [[ "$_check" == "yes" ]]; then
1689 [[ "$_silent" == "no" ]] && dfatal "Failed to install module $_mod"
1690 return 1
1691 fi
1692 }
1693 done
1694 fi
1695 while (($# > 0)); do # filenames as arguments
1696 inst1mod ${1%.ko*} || {
1697 if [[ "$_check" == "yes" ]]; then
1698 [[ "$_silent" == "no" ]] && dfatal "Failed to install module $1"
1699 return 1
1700 fi
1701 }
1702 shift
1703 done
1704 return 0
1705 }
1706
1707 local _ret _filter_not_found='FATAL: Module .* not found.'
1708 # Capture all stderr from modprobe to _fderr. We could use {var}>...
1709 # redirections, but that would make dracut require bash4 at least.
1710 eval "( instmods_1 \"\$@\" ) ${_fderr}>&1" \
1711 | while read line; do [[ "$line" =~ $_filter_not_found ]] || echo $line;done | derror
1712 _ret=$?
1713 return $_ret
1714 }
1715 # get_cpu_vendor
1716 # Only two values are returned: AMD or Intel
1717 get_cpu_vendor ()
1718 {
1719 if grep -qE AMD /proc/cpuinfo; then
1720 printf "AMD"
1721 fi
1722 if grep -qE Intel /proc/cpuinfo; then
1723 printf "Intel"
1724 fi
1725 }
1726
1727 # get_host_ucode
1728 # Get the hosts' ucode file based on the /proc/cpuinfo
1729 get_ucode_file ()
1730 {
1731 local family=`grep -E "cpu family" /proc/cpuinfo | head -1 | sed s/.*:\ //`
1732 local model=`grep -E "model" /proc/cpuinfo |grep -v name | head -1 | sed s/.*:\ //`
1733 local stepping=`grep -E "stepping" /proc/cpuinfo | head -1 | sed s/.*:\ //`
1734
1735 if [[ "$(get_cpu_vendor)" == "AMD" ]]; then
1736 # If family greater or equal than 0x15
1737 if [[ $family -ge 21 ]]; then
1738 printf "microcode_amd_fam15h.bin"
1739 else
1740 printf "microcode_amd.bin"
1741 fi
1742 fi
1743 if [[ "$(get_cpu_vendor)" == "Intel" ]]; then
1744 # The /proc/cpuinfo are in decimal.
1745 printf "%02x-%02x-%02x" ${family} ${model} ${stepping}
1746 fi
1747 }
1748
1749 # Not every device in /dev/mapper should be examined.
1750 # If it is an LVM device, touch only devices which have /dev/VG/LV symlink.
1751 lvm_internal_dev() {
1752 local dev_dm_dir=/sys/dev/block/$1/dm
1753 [[ ! -f $dev_dm_dir/uuid || $(<$dev_dm_dir/uuid) != LVM-* ]] && return 1 # Not an LVM device
1754 local DM_VG_NAME DM_LV_NAME DM_LV_LAYER
1755 eval $(dmsetup splitname --nameprefixes --noheadings --rows "$(<$dev_dm_dir/name)" 2>/dev/null)
1756 [[ ${DM_VG_NAME} ]] && [[ ${DM_LV_NAME} ]] || return 0 # Better skip this!
1757 [[ ${DM_LV_LAYER} ]] || [[ ! -L /dev/${DM_VG_NAME}/${DM_LV_NAME} ]]
1758 }
1759