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