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