]>
Commit | Line | Data |
---|---|---|
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 |
23 | if ! [[ $dracutbasedir ]]; then |
24 | dracutbasedir=${BASH_SOURCE[0]%/*} | |
25 | [[ $dracutbasedir = "dracut-functions" ]] && dracutbasedir="." | |
26 | [[ $dracutbasedir ]] || dracutbasedir="." | |
27 | dracutbasedir="$(readlink -f $dracutbasedir)" | |
28 | fi | |
29 | ||
d6d53f60 | 30 | if ! type dinfo >/dev/null 2>&1; then |
e103615b AŻ |
31 | . "$dracutbasedir/dracut-logger" |
32 | dlog_init | |
33 | fi | |
34 | ||
3198f171 | 35 | # Generic substring function. If $2 is in $1, return 0. |
f76ef3aa | 36 | strstr() { [[ $1 =~ $2 ]]; } |
f04dc5f3 | 37 | |
87122afc AŻ |
38 | # Create all subdirectories for given path without creating the last element. |
39 | # $1 = path | |
94f49230 | 40 | mksubdirs() { mkdir -m 0755 -p ${1%/*}; } |
87122afc | 41 | |
22ecea45 AŻ |
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 | 46 | vercmp() { |
22ecea45 | 47 | local n1=(${1//./ }) op=$2 n2=(${3//./ }) i res |
ecf42850 | 48 | |
2c24ee9a | 49 | for ((i=0; ; i++)) |
22ecea45 AŻ |
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 AŻ |
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 AŻ |
67 | } |
68 | ||
95d2dabc | 69 | is_func() { |
0b706743 | 70 | [[ $(type -t $1) = "function" ]] |
95d2dabc HH |
71 | } |
72 | ||
87122afc AŻ |
73 | # Function prints global variables in format name=value line by line. |
74 | # $@ = list of global variables' name | |
75 | print_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 | 85 | get_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 | ||
99 | get_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 | ||
111 | get_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 | 117 | find_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 AŻ |
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 AŻ |
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 AŻ |
153 | |
154 | return 1 | |
17829e94 VL |
155 | } |
156 | ||
f76ef3aa VL |
157 | find_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 AŻ |
163 | check_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 | 179 | get_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 | 189 | check_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 AŻ |
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. | |
211 | inst_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 | 241 | inst_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 AŻ |
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 AŻ |
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.) | |
267 | rev_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 AŻ |
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 | 285 | inst_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 AŻ |
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 AŻ |
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 AŻ |
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 AŻ |
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 |
313 | find_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 | 329 | inst_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 AŻ |
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. | |
377 | inst_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 |
389 | inst_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 | 401 | inst_rules() { |
fd2312e0 AŻ |
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 | 425 | inst() { |
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. | |
450 | inst_hook() { | |
cdad82fd | 451 | if ! [[ -f $3 ]]; then |
e27770e1 AŻ |
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 | 462 | dracut_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 AŻ |
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 AŻ |
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). | |
486 | inst_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 AŻ |
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 | |
519 | inst_opt_decompress() { | |
520 | local src | |
521 | ||
522 | for src in $@ | |
523 | do | |
524 | inst_decompress "${src}" || inst "${src}" | |
525 | done | |
526 | } | |
527 | ||
95d2dabc HH |
528 | module_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 |
547 | module_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 |
566 | module_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 | ||
583 | module_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 | ||
600 | check_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 | ||
644 | check_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 | |
665 | install_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 AŻ |
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 AŻ |
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 | |
700 | for_each_kmod_dep() { | |
0b706743 | 701 | local func=$1 kmod=$2 cmd modpapth options |
ddfd1d10 | 702 | shift 2 |
0b706743 AŻ |
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 AŻ |
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 | 724 | filter_kernel_modules () ( |
ba67b923 | 725 | if ! [[ $hostonly ]]; then |
0b706743 AŻ |
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 AŻ |
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 AŻ |
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 | 745 | instmods() { |
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 AŻ |
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 AŻ |
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 | } |