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