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