]> git.ipfire.org Git - thirdparty/dracut.git/blame - dracut-functions
TODO: update
[thirdparty/dracut.git] / dracut-functions
CommitLineData
04b56f3a 1#!/bin/bash
cc02093d
HH
2# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
3# ex: ts=8 sw=4 sts=4 et filetype=sh
04b56f3a 4#
33ee031c 5# functions used by dracut and other tools.
04b56f3a 6#
33ee031c 7# Copyright 2005-2009 Red Hat, Inc. All rights reserved.
04b56f3a
JK
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
0f9c78c1 20# along with this program. If not, see <http://www.gnu.org/licenses/>.
04b56f3a 21#
04b56f3a 22
0874654c
HH
23if ! [[ $dracutbasedir ]]; then
24 dracutbasedir=${BASH_SOURCE[0]%/*}
25 [[ $dracutbasedir = "dracut-functions" ]] && dracutbasedir="."
26 [[ $dracutbasedir ]] || dracutbasedir="."
27 dracutbasedir="$(readlink -f $dracutbasedir)"
28fi
29
d6d53f60 30if ! type dinfo >/dev/null 2>&1; then
e103615b
31 . "$dracutbasedir/dracut-logger"
32 dlog_init
33fi
34
3198f171 35# Generic substring function. If $2 is in $1, return 0.
f76ef3aa 36strstr() { [[ $1 =~ $2 ]]; }
f04dc5f3 37
87122afc
38# Create all subdirectories for given path without creating the last element.
39# $1 = path
94f49230 40mksubdirs() { mkdir -m 0755 -p ${1%/*}; }
87122afc 41
22ecea45
42# Version comparision function. Assumes Linux style version scheme.
43# $1 = version a
44# $2 = comparision op (gt, ge, eq, le, lt, ne)
45# $3 = version b
ecf42850 46vercmp() {
22ecea45 47 local n1=(${1//./ }) op=$2 n2=(${3//./ }) i res
ecf42850 48
2c24ee9a 49 for ((i=0; ; i++))
22ecea45
50 do
51 if [[ ! ${n1[i]}${n2[i]} ]]; then res=0
52 elif ((${n1[i]:-0} > ${n2[i]:-0})); then res=1
53 elif ((${n1[i]:-0} < ${n2[i]:-0})); then res=2
54 else continue
55 fi
56 break
ecf42850 57 done
ecf42850 58
22ecea45
59 case $op in
60 gt) ((res == 1));;
61 ge) ((res != 2));;
62 eq) ((res == 0));;
63 le) ((res != 1));;
64 lt) ((res == 2));;
65 ne) ((res != 0));;
66 esac
ecf42850
67}
68
95d2dabc 69is_func() {
0b706743 70 [[ $(type -t $1) = "function" ]]
95d2dabc
HH
71}
72
87122afc
73# Function prints global variables in format name=value line by line.
74# $@ = list of global variables' name
75print_vars() {
76 local var value
77
78 for var in $@
79 do
80 value=$(eval echo \$$var)
81 [[ ${value} ]] && echo "${var}=\"${value}\""
82 done
83}
84
9ede1929 85get_fs_env() {
7c179686 86 [[ $1 ]] || return
d8b9844c
HH
87 eval $(udevadm info --query=env --name=$1|egrep 'ID_FS_(TYPE|UUID)=')
88 [[ $ID_FS_TYPE ]] && return
89
59c88f49 90 if [[ -x /lib/udev/vol_id ]]; then
cc02093d 91 eval $(/lib/udev/vol_id --export $1)
9ede1929 92 elif find_binary blkid >/dev/null; then
cc02093d 93 eval $(blkid -o udev $1)
59c88f49 94 else
cc02093d 95 return 1
59c88f49 96 fi
9ede1929
VL
97}
98
99get_fs_type() (
7c179686
HH
100 [[ $1 ]] || return
101 if [[ $1 != ${1#/dev/block/nfs:} ]] \
cc02093d
HH
102 || [[ $1 != ${1#/dev/block/nfs3:} ]] \
103 || [[ $1 != ${1#/dev/block/nfs4:} ]]; then
104 echo "nfs"
105 return
7c179686 106 fi
9ede1929
VL
107 get_fs_env $1 || return
108 echo $ID_FS_TYPE
109)
110
111get_fs_uuid() (
112 get_fs_env $1 || return
113 echo $ID_FS_UUID
59c88f49
VL
114)
115
17829e94 116# finds the major:minor of the block device backing the root filesystem.
f76ef3aa 117find_block_device() {
7c179686 118 local x mpt majmin dev fs misc maj min
0b706743 119 if [[ $use_fstab != yes ]]; then
51c977d1 120 while read x x majmin x mpt x x fs dev misc; do
7c179686
HH
121 [[ $fs = nfs ]] && { echo $dev; return 0;}
122 [[ $fs = nfs3 ]] && { echo $dev; return 0;}
123 [[ $fs = nfs4 ]] && { echo $dev; return 0;}
51c977d1 124 [[ $fs = btrfs ]] && {
0b706743
125 ls -nLl "$dev" | {
126 read x x x x maj min x
127 maj=${maj//,/}
128 echo $maj:$min
51c977d1
HH
129 } && return 0
130 }
cc02093d 131 if [[ $mpt = $1 ]] && [[ ${majmin#0:} = $majmin ]]; then
0b706743 132 echo $majmin
cc02093d
HH
133 return 0 # we have a winner!
134 fi
0b706743 135 done < /proc/self/mountinfo
7c179686 136 fi
0b706743 137 # fall back to /etc/fstab
7c179686 138 while read dev mpt fs misc; do
cc02093d 139 if [[ $mpt = $1 ]]; then
7c179686
HH
140 [[ $fs = nfs ]] && { echo $dev; return 0;}
141 [[ $fs = nfs3 ]] && { echo $dev; return 0;}
142 [[ $fs = nfs4 ]] && { echo $dev; return 0;}
143 [[ $dev != ${dev#UUID=} ]] && dev=/dev/disk/by-uuid/${dev#UUID=}
144 [[ $dev != ${dev#LABEL=} ]] && dev=/dev/disk/by-label/${dev#LABEL=}
cc02093d 145 [[ -b $dev ]] || return 1 # oops, not a block device.
0b706743
146 ls -nLl "$dev" | {
147 read x x x x maj min x
148 maj=${maj//,/}
149 echo $maj:$min
cc02093d
HH
150 } && return 0
151 fi
7c179686 152 done < /etc/fstab
0b706743
153
154 return 1
17829e94
VL
155}
156
f76ef3aa
VL
157find_root_block_device() { find_block_device /; }
158
17829e94
VL
159# Walk all the slave relationships for a given block device.
160# Stop when our helper function returns success
161# $1 = function to call on every found block device
162# $2 = block device in major:minor format
0b706743
163check_block_and_slaves() {
164 local x
17829e94
VL
165 [[ -b /dev/block/$2 ]] || return 1 # Not a block device? So sorry.
166 "$1" $2 && return
533d7dc4 167 check_vol_slaves "$@" && return 0
3478b314 168 if [[ -f /sys/dev/block/$2/../dev ]]; then
0b706743 169 check_block_and_slaves $1 $(cat "/sys/dev/block/$2/../dev") && return 0
a3afcf2a 170 fi
17829e94 171 [[ -d /sys/dev/block/$2/slaves ]] || return 1
17829e94 172 for x in /sys/dev/block/$2/slaves/*/dev; do
9defc609 173 [[ -f $x ]] || continue
0b706743 174 check_block_and_slaves $1 $(cat "$x") && return 0
17829e94
VL
175 done
176 return 1
177}
178
533d7dc4 179get_numeric_dev() {
0b706743 180 ls -lH "$1" | { read a b c d maj min rest; printf "%d:%d" ${maj%%,} $min; }
533d7dc4
HH
181}
182
183# ugly workaround for the lvm design
184# There is no volume group device,
185# so, there are no slave devices for volume groups.
186# Logical volumes only have the slave devices they really live on,
187# but you cannot create the logical volume without the volume group.
95bde758 188# And the volume group might be bigger than the devices the LV needs.
533d7dc4 189check_vol_slaves() {
0b706743 190 for i in /dev/mapper/*; do
cc02093d
HH
191 lv=$(get_numeric_dev $i)
192 if [[ $lv = $2 ]]; then
193 vg=$(lvm lvs --noheadings -o vg_name $i 2>/dev/null)
194 # strip space
195 vg=$(echo $vg)
196 if [[ $vg ]]; then
0b706743
197 for pv in $(lvm vgs --noheadings -o pv_name "$vg" 2>/dev/null)
198 do
199 check_block_and_slaves $1 $(get_numeric_dev $pv) && return 0
cc02093d
HH
200 done
201 fi
202 fi
533d7dc4
HH
203 done
204 return 1
205}
206
19612483
LA
207# Install a directory, keeping symlinks as on the original system.
208# Example: if /lib64 points to /lib on the host, "inst_dir /lib/file"
209# will create ${initdir}/lib64, ${initdir}/lib64/file,
210# and a symlink ${initdir}/lib -> lib64.
211inst_dir() {
212 local dir="$1"
3478b314 213 [[ -e ${initdir}$dir ]] && return 0
19612483
LA
214
215 # iterate over parent directories
216 local file=""
217 local IFS="/"
218 for part in $dir; do
3478b314 219 [[ $part ]] || continue
19612483 220 file="$file/$part"
3478b314 221 [[ -e ${initdir}$file ]] && continue
19612483 222
3478b314 223 if [[ -L $file ]]; then
19612483
LA
224 # create link as the original
225 local target=$(readlink "$file")
226 ln -sfn "$target" "${initdir}$file" || return 1
fe9cdf74 227 # resolve relative path and recursively install destination
0b706743 228 [[ $target == ${target#/} ]] && target="$(dirname "$file")/$target"
19612483
LA
229 inst_dir "$target"
230 else
231 # create directory
94f49230 232 mkdir -m 0755 -p "${initdir}$file" || return 1
19612483
LA
233 fi
234 done
235}
236
36b24d7c
VL
237# $1 = file to copy to ramdisk
238# $2 (optional) Name for the file on the ramdisk
239# Location of the image dir is assumed to be $initdir
3198f171 240# We never overwrite the target if it exists.
36b24d7c 241inst_simple() {
0b706743 242 local src target
54b44196 243 [[ -f $1 ]] || return 1
19612483 244 src=$1 target="${2:-$1}"
3c56f372
HH
245 if ! [[ -d ${initdir}$target ]]; then
246 [[ -e ${initdir}$target ]] && return 0
247 inst_dir "${target%/*}"
248 fi
5242d8fb 249 # install checksum files also
0b706743
250 if [[ -e "${src%/*}/.${src##*/}.hmac" ]]; then
251 inst "${src%/*}/.${src##*/}.hmac" "${target%/*}/.${target##*/}.hmac"
5242d8fb 252 fi
3b403b32 253 ddebug "Installing $src"
f6d1cb89 254 cp -pfL "$src" "${initdir}$target"
36b24d7c
VL
255}
256
a10a1416
257# find symlinks linked to given library file
258# $1 = library file
259# Function searches for symlinks by stripping version numbers appended to
260# library filename, checks if it points to the same target and finally
261# prints the list of symlinks to stdout.
262#
263# Example:
264# rev_lib_symlinks libfoo.so.8.1
265# output: libfoo.so.8 libfoo.so
266# (Only if libfoo.so.8 and libfoo.so exists on host system.)
267rev_lib_symlinks() {
268 [[ ! $1 ]] && return 0
269
270 local fn="$1" orig="$(readlink -f "$1")" links=''
271
272 [[ ${fn} =~ .*\.so\..* ]] || return 1
273
274 until [[ ${fn##*.} == so ]]; do
275 fn="${fn%.*}"
276 [[ -L ${fn} && $(readlink -f "${fn}") == ${orig} ]] && links+=" ${fn}"
277 done
278
0b706743 279 echo "${links}"
a10a1416
280}
281
95bde758 282# Same as above, but specialized to handle dynamic libraries.
3198f171
VL
283# It handles making symlinks according to how the original library
284# is referenced.
36b24d7c 285inst_library() {
a10a1416 286 local src=$1 dest=${2:-$1} lib reallib symlink
d46c2e8b 287 [[ -e $initdir$dest ]] && return 0
36b24d7c 288 if [[ -L $src ]]; then
0b706743
289 # install checksum files also
290 if [[ -e "${src%/*}/.${src##*/}.hmac" ]]; then
5242d8fb 291 inst "${src%/*}/.${src##*/}.hmac" "${dest%/*}/.${dest##*/}.hmac"
f90fd5b3 292 fi
0b706743
293 reallib=$(readlink -f "$src")
294 lib=${src##*/}
295 inst_simple "$reallib" "$reallib"
296 inst_dir "${dest%/*}"
4c2a28c6 297 (cd "${initdir}${dest%/*}" && ln -sfn "$reallib" "$lib")
36b24d7c 298 else
cc02093d 299 inst_simple "$src" "$dest"
36b24d7c 300 fi
a10a1416
301
302 # Create additional symlinks. See rev_symlinks description.
303 for symlink in $(rev_lib_symlinks $src) $(rev_lib_symlinks $reallib); do
304 [[ ! -e $initdir$symlink ]] && {
e27770e1 305 ddebug "Creating extra symlink: $symlink"
a10a1416
306 inst_symlink $symlink
307 }
308 done
36b24d7c 309}
3198f171
VL
310
311# find a binary. If we were not passed the full path directly,
312# search in the usual places to find the binary.
6b25d71a
VL
313find_binary() {
314 local binpath="/bin /sbin /usr/bin /usr/sbin" p
81c6e7fb
HH
315 if [[ -z ${1##/*} ]]; then
316 if [[ -x $1 ]] || ldd $1 &>/dev/null; then
317 echo $1
318 return 0
319 fi
320 fi
3359c8da 321 for p in $binpath; do
cc02093d 322 [[ -x $p/$1 ]] && { echo "$p/$1"; return 0; }
3359c8da
VL
323 done
324 return 1
325}
36b24d7c 326
3198f171
VL
327# Same as above, but specialized to install binary executables.
328# Install binary executable, and all shared library dependencies, if any.
36b24d7c 329inst_binary() {
09a19bb1
MS
330 local bin target f self so_regex lib_regex TLIBDIR BASE FILE
331
6b25d71a 332 bin=$(find_binary "$1") || return 1
3198f171 333 target=${2:-$bin}
d46c2e8b 334 inst_symlink $bin $target && return 0
d46c2e8b 335 [[ -e $initdir$target ]] && return 0
09a19bb1
MS
336
337 # If the binary being installed is also a library, add it to the loop.
338 so_regex='([^ ]*/lib[^/]*/[^ ]*\.so[^ ]*)'
339 [[ $bin =~ $so_regex ]] && self="\t${bin##*/} => ${bin} (0x0)\n"
340
341 lib_regex='^(/lib[^/]*).*'
8667f2b7 342 # I love bash!
09a19bb1 343 { LC_ALL=C ldd $bin 2>/dev/null; echo -en "$self"; } | while read line; do
cc02093d
HH
344 [[ $line = 'not a dynamic executable' ]] && return 1
345 if [[ $line =~ not\ found ]]; then
e27770e1
346 dfatal "Missing a shared library required by $bin."
347 dfatal "Run \"ldd $bin\" to find out what it is."
348 dfatal "dracut cannot create an initrd."
cc02093d
HH
349 exit 1
350 fi
cc02093d
HH
351 [[ $line =~ $so_regex ]] || continue
352 FILE=${BASH_REMATCH[1]}
353 [[ -e ${initdir}$FILE ]] && continue
09a19bb1
MS
354
355 # See if we are loading an optimized version of a shared lib.
cc02093d 356 if [[ $FILE =~ $lib_regex ]]; then
8667f2b7 357 TLIBDIR=${BASH_REMATCH[1]}
161efa1f 358 BASE=${FILE##*/}
09a19bb1 359 # Prefer nosegneg libs to unoptimized ones.
cc02093d
HH
360 for f in "$TLIBDIR/i686/nosegneg" "$TLIBDIR"; do
361 [[ -e $f/$BASE ]] || continue
362 FILE=$f/$BASE
363 break
364 done
365 inst_library "$FILE" "$TLIBDIR/$BASE"
09a19bb1 366 else
0b706743 367 inst_library "$FILE"
09a19bb1 368 fi
5c862533 369 done
09a19bb1
MS
370
371 # Install the binary if it wasn't handled in the above loop.
372 [[ -z $self ]] && inst_simple "$bin" "$target"
36b24d7c 373}
04b56f3a 374
36b24d7c
VL
375# same as above, except for shell scripts.
376# If your shell script does not start with shebang, it is not a shell script.
377inst_script() {
54b44196 378 [[ -f $1 ]] || return 1
c7b2624f
VL
379 local line
380 read -r -n 80 line <"$1"
00531568
AT
381 # If debug is set, clean unprintable chars to prevent messing up the term
382 [[ $debug ]] && line=$(echo -n "$line" | tr -c -d '[:print:][:space:]')
fdb3d52d
MP
383 shebang_regex='(#! *)(/[^ ]+).*'
384 [[ $line =~ $shebang_regex ]] || return 1
c7b2624f 385 inst "${BASH_REMATCH[2]}" && inst_simple "$@"
04b56f3a
JK
386}
387
36b24d7c
VL
388# same as above, but specialized for symlinks
389inst_symlink() {
390 local src=$1 target=$initdir${2:-$1} realsrc
391 [[ -L $1 ]] || return 1
392 [[ -L $target ]] && return 0
9f88fcd9 393 realsrc=$(readlink -f "$src")
161efa1f 394 [[ $realsrc = ${realsrc##*/} ]] && realsrc=${src%/*}/$realsrc
94f49230 395 inst "$realsrc" && mkdir -m 0755 -p "${target%/*}" && \
4c2a28c6 396 ln -sfn "$realsrc" "$target"
36b24d7c
VL
397}
398
f04dc5f3
VL
399# udev rules always get installed in the same place, so
400# create a function to install them to make life simpler.
0b706743 401inst_rules() {
fd2312e0
402 local target=/etc/udev/rules.d rule found
403
19612483
LA
404 inst_dir "/lib/udev/rules.d"
405 inst_dir "$target"
3b403b32 406 for rule in "$@"; do
c97e1a76
HH
407 for r in /lib/udev/rules.d /etc/udev/rules.d; do
408 if [[ -f $r/$rule ]]; then
409 found="$r/$rule"
410 inst_simple "$found"
411 fi
3b403b32 412 done
c97e1a76
HH
413 for r in '' ./ $dracutbasedir/rules.d/; do
414 if [[ -f ${r}$rule ]]; then
415 found="${r}$rule"
3b403b32 416 inst_simple "$found" "$target/${found##*/}"
c97e1a76
HH
417 fi
418 done
419 [[ $found ]] || dinfo "Skipping udev rule: $rule"
f04dc5f3
VL
420 done
421}
422
36b24d7c
VL
423# general purpose installation function
424# Same args as above.
6b24de99 425inst() {
94dcc5b8
HH
426 case $# in
427 1) ;;
3478b314 428 2) [[ ! $initdir && -d $2 ]] && export initdir=$2
cc02093d 429 [[ $initdir = $2 ]] && set $1;;
0b706743 430 3) [[ -z $initdir ]] && export initdir=$2
cc02093d 431 set $1 $3;;
e27770e1 432 *) dfatal "inst only takes 1 or 2 or 3 arguments"
cc02093d 433 exit 1;;
94dcc5b8 434 esac
8c1faa35 435 for x in inst_symlink inst_script inst_binary inst_simple; do
cc02093d 436 $x "$@" && return 0
36b24d7c
VL
437 done
438 return 1
04b56f3a
JK
439}
440
0b53ca70
HH
441[[ $hookdirs ]] || {
442 hookdirs="cmdline pre-udev pre-trigger netroot initqueue pre-mount"
443 hookdirs+=" pre-pivot mount emergency"
444 export hookdirs
445}
446
53f95456
VL
447# install function specialized for hooks
448# $1 = type of hook, $2 = hook priority (lower runs first), $3 = hook
449# All hooks should be POSIX/SuS compliant, they will be sourced by init.
450inst_hook() {
cdad82fd 451 if ! [[ -f $3 ]]; then
e27770e1
452 dfatal "Cannot install a hook ($3) that does not exist."
453 dfatal "Aborting initrd creation."
cc02093d 454 exit 1
cdad82fd 455 elif ! strstr "$hookdirs" "$1"; then
3b403b32 456 dfatal "No such hook type $1. Aborting initrd creation."
cc02093d 457 exit 1
cdad82fd 458 fi
0b53ca70 459 inst_simple "$3" "/lib/dracut/hooks/${1}/${2}${3##*/}"
53f95456
VL
460}
461
f4fff04e 462dracut_install() {
0b706743 463 if [[ $1 = '-o' ]]; then
cc02093d
HH
464 local optional=yes
465 shift
bd4c4bcb 466 fi
f4fff04e 467 while (($# > 0)); do
cc02093d
HH
468 if ! inst "$1" ; then
469 if [[ $optional = yes ]]; then
e27770e1
470 dwarn "Skipping program $1 as it cannot be found and is" \
471 "flagged to be optional"
cc02093d 472 else
e27770e1 473 dfatal "Failed to install $1"
cc02093d 474 exit 1
bd4c4bcb 475 fi
cc02093d
HH
476 fi
477 shift
f4fff04e
VL
478 done
479}
480
87122afc
481# install function decompressing the target and handling symlinks
482# $@ = list of compressed (gz or bz2) files or symlinks pointing to such files
483#
484# Function install targets in the same paths inside overlay but decompressed
485# and without extensions (.gz, .bz2).
486inst_decompress() {
487 local src dst realsrc realdst cmd
488
489 for src in $@
490 do
491 case ${src} in
492 *.gz) cmd='gzip -d' ;;
493 *.bz2) cmd='bzip2 -d' ;;
494 *) return 1 ;;
495 esac
496
497 if [[ -L ${src} ]]
498 then
499 realsrc="$(readlink -f ${src})" # symlink target with extension
500 dst="${src%.*}" # symlink without extension
501 realdst="${realsrc%.*}" # symlink target without extension
502 mksubdirs "${initdir}/${src}"
503 # Create symlink without extension to target without extension.
4c2a28c6 504 ln -sfn "${realdst}" "${initdir}/${dst}"
87122afc
505 fi
506
507 # If the source is symlink we operate on its target.
508 [[ ${realsrc} ]] && src=${realsrc}
509 inst ${src}
510 # Decompress with chosen tool. We assume that tool changes name e.g.
511 # from 'name.gz' to 'name'.
512 ${cmd} "${initdir}${src}"
513 done
514}
515
516# It's similar to above, but if file is not compressed, performs standard
517# install.
518# $@ = list of files
519inst_opt_decompress() {
520 local src
521
522 for src in $@
523 do
524 inst_decompress "${src}" || inst "${src}"
525 done
526}
527
95d2dabc
HH
528module_check() {
529 local moddir=$(echo ${dracutbasedir}/modules.d/??${1})
530 [[ -d $moddir ]] || return 1
71df3c43 531 if [[ ! -f $moddir/module-setup.sh ]]; then
95d2dabc
HH
532 # if we do not have a check script, we are unconditionally included
533 [[ -x $moddir/check ]] || return 0
534 $moddir/check $hostonly
535 return $?
536 else
537 unset check depends install installkernel
71df3c43 538 . $moddir/module-setup.sh
95d2dabc
HH
539 is_func check || return 0
540 check
4cf26268 541 ret=$?
95d2dabc
HH
542 unset check depends install installkernel
543 return $ret
0c2e3d12 544 fi
0c2e3d12
VL
545}
546
95d2dabc
HH
547module_depends() {
548 local moddir=$(echo ${dracutbasedir}/modules.d/??${1})
549 [[ -d $moddir ]] || return 1
71df3c43 550 if [[ ! -f $moddir/module-setup.sh ]]; then
95d2dabc
HH
551 # if we do not have a check script, we have no deps
552 [[ -x $moddir/check ]] || return 0
553 $moddir/check -d
554 return $?
555 else
556 unset check depends install installkernel
71df3c43 557 . $moddir/module-setup.sh
95d2dabc
HH
558 is_func depends || return 0
559 depends
560 ret=$?
561 unset check depends install installkernel
562 return $ret
33ee031c 563 fi
0c2e3d12
VL
564}
565
95d2dabc
HH
566module_install() {
567 local moddir=$(echo ${dracutbasedir}/modules.d/??${1})
568 [[ -d $moddir ]] || return 1
71df3c43 569 if [[ ! -f $moddir/module-setup.sh ]]; then
95d2dabc
HH
570 [[ -x $moddir/install ]] && . "$moddir/install"
571 return $?
572 else
573 unset check depends install installkernel
71df3c43 574 . $moddir/module-setup.sh
95d2dabc
HH
575 is_func install || return 0
576 install
577 ret=$?
578 unset check depends install installkernel
579 return $ret
580 fi
581}
582
583module_installkernel() {
584 local moddir=$(echo ${dracutbasedir}/modules.d/??${1})
585 [[ -d $moddir ]] || return 1
71df3c43 586 if [[ ! -f $moddir/module-setup.sh ]]; then
95d2dabc
HH
587 [[ -x $moddir/installkernel ]] && . "$moddir/installkernel"
588 return $?
589 else
590 unset check depends install installkernel
71df3c43 591 . $moddir/module-setup.sh
95d2dabc
HH
592 is_func installkernel || return 0
593 installkernel
594 ret=$?
595 unset check depends install installkernel
596 return $ret
597 fi
598}
599
600check_module() {
601 local mod=$1;
602 local moddir=$(echo ${dracutbasedir}/modules.d/??${1})
603 local moddep;
604 # If we are already scheduled to be loaded, no need to check again.
605 strstr " $mods_to_load " " $mod " && return 0
606 strstr " $mods_checked_as_dep " " $mod " && return 1
607
608 # This should never happen, but...
609 [[ -d $moddir ]] || return 1
610
611 [[ $2 ]] || mods_checked_as_dep+=" $mod "
612
613 strstr " $omit_dracutmodules " " $mod " && return 1
614
615 if strstr " $dracutmodules $add_dracutmodules " " $mod "; then
616 module_check $mod; ret=$?
617 # explicit module, so also accept ret=255
618 [[ $ret = 0 || $ret = 255 ]] || return 1
619 else
620 # module not in our list
621 if [[ $dracutmodules = all ]]; then
622 # check, if we can and should install this module
623 module_check $mod || return 1
cc02093d 624 else
95d2dabc
HH
625 # skip this module
626 return 1
970e646b 627 fi
95d2dabc 628 fi
bb764545 629
95d2dabc
HH
630 for moddep in $(module_depends $mod); do
631 # handle deps as if they were manually added
632 strstr " $add_dracutmodules " " $moddep " || \
633 add_dracutmodules+=" $moddep "
634 # if a module we depend on fail, fail also
635 check_module $moddep || return 1
0c2e3d12 636 done
70503db4 637
95d2dabc
HH
638 strstr " $mods_to_load " " $mod " || \
639 mods_to_load+=" $mod "
640
641 return 0
642}
643
644check_module_dir() {
645 local modcheck;
646 local mod;
647 mods_to_load=""
648 for moddir in "$dracutbasedir/modules.d"/[0-9][0-9]*; do
649 local mod=${moddir##*/}; mod=${mod#[0-9][0-9]}
650 check_module $mod 1
70503db4 651 done
724b87a6
HH
652
653 # Report any missing dracut modules, the user has specified
654 modcheck=$add_dracutmodules
655 [[ $dracutmodules != all ]] && modcheck="$m $dracutmodules"
656 for mod in $modcheck; do
657 strstr "$mods_to_load" "$mod" && continue
658 strstr "$omit_dracutmodules" "$mod" && continue
e27770e1 659 derror "Dracut module \"$mod\" cannot be found."
724b87a6 660 done
0c2e3d12
VL
661}
662
ddfd1d10
VL
663# Install a single kernel module along with any firmware it may require.
664# $1 = full path to kernel module to install
665install_kmod_with_fw() {
666 local modname=${1##*/} fwdir found
9b37edbf 667 modname=${modname%.ko*}
0b440844 668 # no need to go further if the module is already installed
0b706743
669 [[ -e "${initdir}/lib/modules/$kernel/${1##*/lib/modules/$kernel/}" ]] \
670 && return 0
671 inst_simple "$1" "/lib/modules/$kernel/${1##*/lib/modules/$kernel/}" \
672 || return $?
ddfd1d10 673 for fw in $(modinfo -k $kernel -F firmware $1 2>/dev/null); do
cc02093d
HH
674 found=''
675 for fwdir in $fw_dir; do
676 if [[ -d $fwdir && -f $fwdir/$fw ]]; then
677 inst_simple "$fwdir/$fw" "/lib/firmware/$fw"
678 found=yes
679 fi
680 done
681 if [[ $found != yes ]]; then
e2cdb570
HH
682 if ! grep -qe "\<${modname//-/_}\>" /proc/modules; then
683 dinfo "Possible missing firmware \"${fw}\" for kernel module" \
684 "\"${modname}.ko\""
685 else
686 dwarn "Possible missing firmware \"${fw}\" for kernel module" \
687 "\"${modname}.ko\""
688 fi
cc02093d 689 fi
ddfd1d10 690 done
0b440844 691 return 0
ddfd1d10
VL
692}
693
694# Do something with all the dependencies of a kernel module.
695# Note that kernel modules depend on themselves using the technique we use
0b706743
696# $1 = function to call for each dependency we find
697# It will be passed the full path to the found kernel module
ddfd1d10
VL
698# $2 = module to get dependencies for
699# rest of args = arguments to modprobe
700for_each_kmod_dep() {
0b706743 701 local func=$1 kmod=$2 cmd modpapth options
ddfd1d10 702 shift 2
0b706743
703 modprobe "$@" --ignore-install --show-depends $kmod 2>/dev/null | (
704 local found=0
705 while read cmd modpath options; do
706 [[ $cmd = insmod ]] || continue
707 $func ${modpath} || exit $?
0b440844 708 found=1
0b706743
709 done
710 [[ $found -eq 0 ]] && exit 1
711 exit 0
712 )
0b440844 713 return $?
ddfd1d10
VL
714}
715
95bde758 716# filter kernel modules to install certain modules that meet specific
240cc7c4
VL
717# requirements.
718# $1 = function to call with module name to filter.
719# This function will be passed the full path to the module to test.
720# The behaviour of this function can vary depending on whether $hostonly is set.
721# If it is, we will only look at modules that are already in memory.
722# If it is not, we will look at all kernel modules
fb8923f6 723# This function returns the full filenames of modules that match $1
240cc7c4 724filter_kernel_modules () (
ba67b923 725 if ! [[ $hostonly ]]; then
0b706743
726 filtercmd='find "$srcmods/kernel/drivers" "$srcmods/extra"'
727 filtercmd+=' "$srcmods/weak-updates" -name "*.ko" -o -name "*.ko.gz"'
728 filtercmd+=' 2>/dev/null'
240cc7c4 729 else
0b706743
730 filtercmd='cut -d " " -f 1 </proc/modules|xargs modinfo -F filename '
731 filtercmd+='-k $kernel 2>/dev/null'
240cc7c4 732 fi
fb8923f6 733 for modname in $(eval $filtercmd); do
9b37edbf 734 case $modname in
3478b314
VL
735 *.ko) "$1" "$modname" && echo "$modname";;
736 *.ko.gz) gzip -dc "$modname" > $initdir/$$.ko
cc02093d 737 $1 $initdir/$$.ko && echo "$modname"
0b706743
738 rm -f $initdir/$$.ko
739 ;;
9b37edbf 740 esac
fb8923f6 741 done
240cc7c4
VL
742)
743
ddfd1d10 744# install kernel modules along with all their dependencies.
6fa0c3d6 745instmods() {
0c1a8ebc 746 [[ $no_kernel = yes ]] && return
ecf42850 747 local mod mpargs modpath modname cmd moddirname
0b440844 748 local ret=0
6fa0c3d6 749 while (($# > 0)); do
cc02093d
HH
750 mod=${1%.ko*}
751 case $mod in
0b706743 752 =*)
cc02093d 753 # This introduces 2 incompatible meanings for =* arguments
74534e19 754 # to instmods. We need to decide which one to keep.
0b706743
755 if [[ $mod = =ata && -f $srcmods/modules.block ]]; then
756 instmods $mpargs \
757 $(egrep 'ata|ahci' "${srcmods}/modules.block")
cc02093d
HH
758 elif [ -f $srcmods/modules.${mod#=} ]; then
759 instmods $mpargs $(cat ${srcmods}/modules.${mod#=} )
760 else
761 instmods $mpargs $(find "$srcmods" -path "*/${mod#=}/*")
762 fi
763 ;;
0b706743 764 --*)
cc02093d
HH
765 mod=${mod##*/}
766 mpargs+=" $mod";;
3478b314 767 i2o_scsi) shift; continue;; # Do not load this diagnostic-only module
cc02093d 768 *) mod=${mod##*/}
6568d86a 769 # if we are already installed, skip this module and go on
cc02093d
HH
770 # to the next one.
771 [[ -f $initdir/$1 ]] && { shift; continue; }
772 # If we are building a host-specific initramfs and this
773 # module is not already loaded, move on to the next one.
0b706743
774 [[ $hostonly ]] && ! grep -qe "\<${mod//-/_}\>" /proc/modules \
775 && ! echo $add_drivers | grep -qe "\<${mod}\>" && {
776 shift; continue
777 }
04b56f3a 778
cc02093d
HH
779 # We use '-d' option in modprobe only if modules prefix path
780 # differs from default '/'. This allows us to use Dracut with
781 # old version of modprobe which doesn't have '-d' option.
782 moddirname=${srcmods%%/lib/modules/*}
783 [[ -n ${moddirname} ]] && moddirname="-d ${moddirname}/"
0b706743 784
cc02093d
HH
785 # ok, load the module, all its dependencies, and any firmware
786 # it may require
787 for_each_kmod_dep install_kmod_with_fw $mod \
788 --set-version $kernel ${moddirname}
a16ebfd5 789 ((ret+=$?))
cc02093d 790 ;;
0b706743 791 esac
0b440844 792 shift
cc02093d 793 done
0b440844 794 return $ret
0b706743 795}