]> git.ipfire.org Git - thirdparty/dracut.git/blame - dracut-functions.sh
fix(test): only use QEMU machine q35 on x86
[thirdparty/dracut.git] / dracut-functions.sh
CommitLineData
04b56f3a
JK
1#!/bin/bash
2#
33ee031c 3# functions used by dracut and other tools.
04b56f3a 4#
33ee031c 5# Copyright 2005-2009 Red Hat, Inc. All rights reserved.
04b56f3a
JK
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
0f9c78c1 18# along with this program. If not, see <http://www.gnu.org/licenses/>.
04b56f3a 19#
258de828 20export LC_MESSAGES=C
f4031e8a 21
561eb42f
HH
22# is_func <command>
23# Check whether $1 is a function.
24is_func() {
75d758e8 25 [[ "$(type -t "$1")" == "function" ]]
561eb42f
HH
26}
27
8d95b8b3 28# Generic substring function. If $2 is in $1, return 0.
75d758e8 29strstr() { [[ $1 == *"$2"* ]]; }
2c19a5fa 30# Generic glob matching function. If glob pattern $2 matches anywhere in $1, OK
75d758e8 31strglobin() { [[ $1 == *$2* ]]; }
2c19a5fa 32# Generic glob matching function. If glob pattern $2 matches all of $1, OK
3483509e 33# shellcheck disable=SC2053
75d758e8 34strglob() { [[ $1 == $2 ]]; }
1cadc26f
HH
35# returns OK if $1 contains literal string $2 at the beginning, and isn't empty
36str_starts() { [ "${1#"$2"*}" != "$1" ]; }
37# returns OK if $1 contains literal string $2 at the end, and isn't empty
38str_ends() { [ "${1%*"$2"}" != "$1" ]; }
8d95b8b3 39
b4de9ee1
AAF
40trim() {
41 local var="$*"
42 var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters
43 var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters
44 printf "%s" "$var"
45}
46
f4031e8a
HH
47# find a binary. If we were not passed the full path directly,
48# search in the usual places to find the binary.
49find_binary() {
a0120420 50 local _delim
f769154b 51 local _path
a0120420
BZ
52 local l
53 local p
54 [[ -z ${1##/*} ]] || _delim="/"
55
75d758e8 56 if [[ $1 == *.so* ]]; then
3483509e 57 # shellcheck disable=SC2154
9a52c3fd 58 for l in $libdirs; do
f769154b 59 _path="${l}${_delim}${1}"
9a52c3fd 60 if { $DRACUT_LDD "${dracutsysrootdir}${_path}" &> /dev/null; }; then
f769154b 61 printf "%s\n" "${_path}"
a0120420
BZ
62 return 0
63 fi
64 done
f769154b 65 _path="${_delim}${1}"
9a52c3fd 66 if { $DRACUT_LDD "${dracutsysrootdir}${_path}" &> /dev/null; }; then
f769154b 67 printf "%s\n" "${_path}"
f4031e8a
HH
68 return 0
69 fi
70 fi
75d758e8 71 if [[ $1 == */* ]]; then
f769154b
AT
72 _path="${_delim}${1}"
73 if [[ -L ${dracutsysrootdir}${_path} ]] || [[ -x ${dracutsysrootdir}${_path} ]]; then
74 printf "%s\n" "${_path}"
a0120420
BZ
75 return 0
76 fi
77 fi
9a52c3fd 78 for p in $DRACUT_PATH; do
f769154b 79 _path="${p}${_delim}${1}"
9a52c3fd 80 if [[ -L ${dracutsysrootdir}${_path} ]] || [[ -x ${dracutsysrootdir}${_path} ]]; then
f769154b 81 printf "%s\n" "${_path}"
a0120420
BZ
82 return 0
83 fi
84 done
f4031e8a 85
75d758e8 86 [[ -n $dracutsysrootdir ]] && return 1
b093aa2d 87 type -P "${1##*/}"
f4031e8a
HH
88}
89
9a52c3fd
HH
90ldconfig_paths() {
91 $DRACUT_LDCONFIG ${dracutsysrootdir:+-r ${dracutsysrootdir} -f /etc/ld.so.conf} -pN 2> /dev/null | grep -E -v '/(lib|lib64|usr/lib|usr/lib64)/[^/]*$' | sed -n 's,.* => \(.*\)/.*,\1,p' | sort | uniq
4fe1bdd4
HH
92}
93
ddf63231 94# Version comparison function. Assumes Linux style version scheme.
f06c2b58 95# $1 = version a
ddf63231 96# $2 = comparison op (gt, ge, eq, le, lt, ne)
f06c2b58
HH
97# $3 = version b
98vercmp() {
3483509e 99 local _n1
2b5ddc77 100 read -r -a _n1 <<< "${1//./ }"
3483509e
HH
101 local _op=$2
102 local _n2
2b5ddc77 103 read -r -a _n2 <<< "${3//./ }"
3483509e 104 local _i _res
f06c2b58 105
9a52c3fd
HH
106 for ((_i = 0; ; _i++)); do
107 if [[ ! ${_n1[_i]}${_n2[_i]} ]]; then
108 _res=0
109 elif ((${_n1[_i]:-0} > ${_n2[_i]:-0})); then
110 _res=1
111 elif ((${_n1[_i]:-0} < ${_n2[_i]:-0})); then
112 _res=2
113 else
114 continue
f06c2b58
HH
115 fi
116 break
117 done
118
119 case $_op in
9a52c3fd
HH
120 gt) ((_res == 1)) ;;
121 ge) ((_res != 2)) ;;
122 eq) ((_res == 0)) ;;
123 le) ((_res != 1)) ;;
124 lt) ((_res == 2)) ;;
125 ne) ((_res != 0)) ;;
f06c2b58
HH
126 esac
127}
128
87122afc
129# Create all subdirectories for given path without creating the last element.
130# $1 = path
b093aa2d 131mksubdirs() {
3483509e 132 # shellcheck disable=SC2174
b093aa2d
HH
133 [[ -e ${1%/*} ]] || mkdir -m 0755 -p -- "${1%/*}"
134}
87122afc 135
87122afc
136# Function prints global variables in format name=value line by line.
137# $@ = list of global variables' name
138print_vars() {
29b10e65 139 local _var _value
87122afc 140
9a52c3fd 141 for _var in "$@"; do
7a94a432 142 eval printf -v _value "%s" \""\$$_var"\"
b093aa2d 143 [[ ${_value} ]] && printf '%s="%s"\n' "$_var" "$_value"
87122afc
144 done
145}
146
7e2bca48
HH
147# normalize_path <path>
148# Prints the normalized path, where it removes any duplicated
149# and trailing slashes.
150# Example:
151# $ normalize_path ///test/test//
152# /test/test
626d9eba 153normalize_path() {
2b5ddc77
HH
154 # shellcheck disable=SC2064
155 trap "$(shopt -p extglob)" RETURN
c44e3cb4 156 shopt -q -s extglob
2b5ddc77
HH
157 local p=${1//+(\/)//}
158 printf "%s\n" "${p%/}"
626d9eba 159}
d4bb4316 160
7e2bca48
HH
161# convert_abs_rel <from> <to>
162# Prints the relative path, when creating a symlink to <to> from <from>.
163# Example:
164# $ convert_abs_rel /usr/bin/test /bin/test-2
165# ../../bin/test-2
166# $ ln -s $(convert_abs_rel /usr/bin/test /bin/test-2) /usr/bin/test
d4bb4316 167convert_abs_rel() {
6d2a7942 168 local __current __absolute __abssize __cursize __newpath
c44e3cb4 169 local -i __i __level
d4bb4316 170
c44e3cb4
MS
171 set -- "$(normalize_path "$1")" "$(normalize_path "$2")"
172
c1609dd4 173 # corner case #1 - self looping link
75d758e8 174 [[ $1 == "$2" ]] && {
9a52c3fd
HH
175 printf "%s\n" "${1##*/}"
176 return
177 }
c1609dd4
MS
178
179 # corner case #2 - own dir link
75d758e8 180 [[ ${1%/*} == "$2" ]] && {
9a52c3fd
HH
181 printf ".\n"
182 return
183 }
c1609dd4 184
2b5ddc77
HH
185 IFS=/ read -r -a __current <<< "$1"
186 IFS=/ read -r -a __absolute <<< "$2"
d4bb4316
HH
187
188 __abssize=${#__absolute[@]}
189 __cursize=${#__current[@]}
190
75d758e8 191 while [[ ${__absolute[__level]} == "${__current[__level]}" ]]; do
9a52c3fd
HH
192 ((__level++))
193 if ((__level > __abssize || __level > __cursize)); then
d4bb4316
HH
194 break
195 fi
196 done
197
9a52c3fd
HH
198 for ((__i = __level; __i < __cursize - 1; __i++)); do
199 if ((__i > __level)); then
d4bb4316
HH
200 __newpath=$__newpath"/"
201 fi
202 __newpath=$__newpath".."
203 done
204
9a52c3fd
HH
205 for ((__i = __level; __i < __abssize; __i++)); do
206 if [[ -n $__newpath ]]; then
d4bb4316
HH
207 __newpath=$__newpath"/"
208 fi
209 __newpath=$__newpath${__absolute[__i]}
210 done
211
3483509e 212 printf -- "%s\n" "$__newpath"
d4bb4316
HH
213}
214
7e2bca48 215# get_fs_env <device>
97af51db 216# Get and the ID_FS_TYPE variable from udev for a device.
7e2bca48 217# Example:
97af51db 218# $ get_fs_env /dev/sda2
7e2bca48 219# ext4
9ede1929 220get_fs_env() {
7c179686 221 [[ $1 ]] || return
29b10e65 222 unset ID_FS_TYPE
69f7ed96 223 ID_FS_TYPE=$(blkid -u filesystem -o export -- "$1" \
2b5ddc77
HH
224 | while read -r line || [ -n "$line" ]; do
225 if [[ $line == "TYPE="* ]]; then
9a52c3fd
HH
226 printf "%s" "${line#TYPE=}"
227 exit 0
69f7ed96 228 fi
9a52c3fd 229 done)
69f7ed96
HH
230 if [[ $ID_FS_TYPE ]]; then
231 printf "%s" "$ID_FS_TYPE"
232 return 0
7c179686 233 fi
a5cde2dd
HH
234 return 1
235}
9ede1929 236
7e2bca48
HH
237# get_maj_min <device>
238# Prints the major and minor of a device node.
239# Example:
240# $ get_maj_min /dev/sda2
241# 8:2
480d772f 242get_maj_min() {
224175d8 243 local _majmin
a277a5fc
HH
244 local _out
245
246 if [[ $get_maj_min_cache_file ]]; then
67591e88 247 _out="$(grep -m1 -oE "^$1 \S+$" "$get_maj_min_cache_file" | awk '{print $NF}')"
a277a5fc
HH
248 fi
249
250 if ! [[ "$_out" ]]; then
c3bb9d18 251 _majmin="$(stat -L -c '%t:%T' "$1" 2> /dev/null)"
a277a5fc
HH
252 _out="$(printf "%s" "$((0x${_majmin%:*})):$((0x${_majmin#*:}))")"
253 if [[ $get_maj_min_cache_file ]]; then
254 echo "$1 $_out" >> "$get_maj_min_cache_file"
255 fi
c3bb9d18 256 fi
a277a5fc 257 echo -n "$_out"
480d772f
HH
258}
259
281327f7
HH
260# get_devpath_block <device>
261# get the DEVPATH in /sys of a block device
262get_devpath_block() {
8552a327 263 local _majmin _i
281327f7
HH
264 _majmin=$(get_maj_min "$1")
265
266 for _i in /sys/block/*/dev /sys/block/*/*/dev; do
75d758e8
HH
267 [[ -e $_i ]] || continue
268 if [[ $_majmin == "$(< "$_i")" ]]; then
281327f7
HH
269 printf "%s" "${_i%/dev}"
270 return 0
271 fi
272 done
273 return 1
274}
275
69f7ed96
HH
276# get a persistent path from a device
277get_persistent_dev() {
b6054b5d 278 local i _tmp _dev _pol
69f7ed96
HH
279
280 _dev=$(get_maj_min "$1")
281 [ -z "$_dev" ] && return
282
75d758e8 283 if [[ -n $persistent_policy ]]; then
9a52c3fd 284 _pol="/dev/disk/${persistent_policy}/*"
b6054b5d 285 else
9a52c3fd 286 _pol=
b6054b5d
MW
287 fi
288
324ea606 289 for i in \
b6054b5d 290 $_pol \
324ea606 291 /dev/mapper/* \
324ea606
HH
292 /dev/disk/by-uuid/* \
293 /dev/disk/by-label/* \
294 /dev/disk/by-partuuid/* \
295 /dev/disk/by-partlabel/* \
296 /dev/disk/by-id/* \
9a52c3fd 297 /dev/disk/by-path/*; do
75d758e8 298 [[ -e $i ]] || continue
1743473b 299 [[ $i == /dev/mapper/control ]] && continue
69f7ed96
HH
300 [[ $i == /dev/mapper/mpath* ]] && continue
301 _tmp=$(get_maj_min "$i")
302 if [ "$_tmp" = "$_dev" ]; then
303 printf -- "%s" "$i"
304 return
305 fi
306 done
9efb74a3 307 printf -- "%s" "$1"
69f7ed96
HH
308}
309
c82a1133
HH
310expand_persistent_dev() {
311 local _dev=$1
312
313 case "$_dev" in
314 LABEL=*)
315 _dev="/dev/disk/by-label/${_dev#LABEL=}"
316 ;;
317 UUID=*)
318 _dev="${_dev#UUID=}"
93b02f50 319 _dev="${_dev,,}"
c82a1133
HH
320 _dev="/dev/disk/by-uuid/${_dev}"
321 ;;
322 PARTUUID=*)
323 _dev="${_dev#PARTUUID=}"
93b02f50 324 _dev="${_dev,,}"
c82a1133
HH
325 _dev="/dev/disk/by-partuuid/${_dev}"
326 ;;
327 PARTLABEL=*)
328 _dev="/dev/disk/by-partlabel/${_dev#PARTLABEL=}"
329 ;;
330 esac
331 printf "%s" "$_dev"
332}
333
324ea606 334shorten_persistent_dev() {
c82a1133
HH
335 local _dev="$1"
336 case "$_dev" in
324ea606 337 /dev/disk/by-uuid/*)
9a52c3fd
HH
338 printf "%s" "UUID=${_dev##*/}"
339 ;;
324ea606 340 /dev/disk/by-label/*)
9a52c3fd
HH
341 printf "%s" "LABEL=${_dev##*/}"
342 ;;
324ea606 343 /dev/disk/by-partuuid/*)
9a52c3fd
HH
344 printf "%s" "PARTUUID=${_dev##*/}"
345 ;;
324ea606 346 /dev/disk/by-partlabel/*)
9a52c3fd
HH
347 printf "%s" "PARTLABEL=${_dev##*/}"
348 ;;
324ea606 349 *)
9a52c3fd
HH
350 printf "%s" "$_dev"
351 ;;
324ea606
HH
352 esac
353}
354
7e2bca48
HH
355# find_block_device <mountpoint>
356# Prints the major and minor number of the block device
357# for a given mountpoint.
358# Unless $use_fstab is set to "yes" the functions
359# uses /proc/self/mountinfo as the primary source of the
360# information and only falls back to /etc/fstab, if the mountpoint
361# is not found there.
362# Example:
363# $ find_block_device /usr
364# 8:4
f76ef3aa 365find_block_device() {
9918afd2 366 local _dev _majmin _find_mpt
c8d685c9 367 _find_mpt="$1"
3483509e 368
0b706743 369 if [[ $use_fstab != yes ]]; then
9d36d4fb 370 [[ -d $_find_mpt/. ]]
9a52c3fd 371 findmnt -e -v -n -o 'MAJ:MIN,SOURCE' --target "$_find_mpt" | {
2b5ddc77 372 while read -r _majmin _dev || [ -n "$_dev" ]; do
dba20559
HH
373 if [[ -b $_dev ]]; then
374 if ! [[ $_majmin ]] || [[ $_majmin == 0:* ]]; then
2b5ddc77 375 _majmin=$(get_maj_min "$_dev")
dba20559
HH
376 fi
377 if [[ $_majmin ]]; then
466a5998 378 printf "%s\n" "$_majmin"
dba20559 379 else
466a5998 380 printf "%s\n" "$_dev"
dba20559
HH
381 fi
382 return 0
383 fi
75d758e8 384 if [[ $_dev == *:* ]]; then
466a5998 385 printf "%s\n" "$_dev"
dba20559
HH
386 return 0
387 fi
9a52c3fd
HH
388 done
389 return 1
390 } && return 0
dba20559
HH
391 fi
392 # fall back to /etc/fstab
e9ed44c8 393 [[ ! -f "$dracutsysrootdir"/etc/fstab ]] && return 1
dba20559 394
9a52c3fd 395 findmnt -e --fstab -v -n -o 'MAJ:MIN,SOURCE' --target "$_find_mpt" | {
2b5ddc77 396 while read -r _majmin _dev || [ -n "$_dev" ]; do
dba20559
HH
397 if ! [[ $_dev ]]; then
398 _dev="$_majmin"
399 unset _majmin
400 fi
9d36d4fb 401 if [[ -b $_dev ]]; then
2b5ddc77 402 [[ $_majmin ]] || _majmin=$(get_maj_min "$_dev")
9d36d4fb 403 if [[ $_majmin ]]; then
466a5998 404 printf "%s\n" "$_majmin"
9d36d4fb 405 else
466a5998 406 printf "%s\n" "$_dev"
9d36d4fb
HH
407 fi
408 return 0
409 fi
75d758e8 410 if [[ $_dev == *:* ]]; then
466a5998 411 printf "%s\n" "$_dev"
9d36d4fb 412 return 0
cc02093d 413 fi
9a52c3fd
HH
414 done
415 return 1
416 } && return 0
0b706743
417
418 return 1
17829e94
VL
419}
420
9d36d4fb
HH
421# find_mp_fstype <mountpoint>
422# Echo the filesystem type for a given mountpoint.
7e2bca48
HH
423# /proc/self/mountinfo is taken as the primary source of information
424# and /etc/fstab is used as a fallback.
425# No newline is appended!
426# Example:
9d36d4fb 427# $ find_mp_fstype /;echo
7e2bca48 428# ext4
9d36d4fb
HH
429find_mp_fstype() {
430 local _fs
7ae5d9d1 431
9d36d4fb 432 if [[ $use_fstab != yes ]]; then
9a52c3fd 433 findmnt -e -v -n -o 'FSTYPE' --target "$1" | {
2b5ddc77 434 while read -r _fs || [ -n "$_fs" ]; do
dba20559 435 [[ $_fs ]] || continue
75d758e8 436 [[ $_fs == "autofs" ]] && continue
466a5998 437 printf "%s" "$_fs"
dba20559 438 return 0
9a52c3fd
HH
439 done
440 return 1
441 } && return 0
dba20559
HH
442 fi
443
e9ed44c8
TL
444 [[ ! -f "$dracutsysrootdir"/etc/fstab ]] && return 1
445
9a52c3fd 446 findmnt --fstab -e -v -n -o 'FSTYPE' --target "$1" | {
2b5ddc77 447 while read -r _fs || [ -n "$_fs" ]; do
9d36d4fb 448 [[ $_fs ]] || continue
75d758e8 449 [[ $_fs == "autofs" ]] && continue
466a5998 450 printf "%s" "$_fs"
9d36d4fb 451 return 0
9a52c3fd
HH
452 done
453 return 1
454 } && return 0
7ae5d9d1
HH
455
456 return 1
457}
458
9d36d4fb
HH
459# find_dev_fstype <device>
460# Echo the filesystem type for a given device.
81672479
HH
461# /proc/self/mountinfo is taken as the primary source of information
462# and /etc/fstab is used as a fallback.
463# No newline is appended!
464# Example:
9d36d4fb 465# $ find_dev_fstype /dev/sda2;echo
81672479 466# ext4
9d36d4fb 467find_dev_fstype() {
5e601454 468 local _find_dev _fs
9d36d4fb 469 _find_dev="$1"
75d758e8 470 if ! [[ $_find_dev == /dev* ]]; then
a4f7b504
HH
471 [[ -b "/dev/block/$_find_dev" ]] && _find_dev="/dev/block/$_find_dev"
472 fi
5e601454
HH
473
474 if [[ $use_fstab != yes ]]; then
9a52c3fd 475 findmnt -e -v -n -o 'FSTYPE' --source "$_find_dev" | {
2b5ddc77 476 while read -r _fs || [ -n "$_fs" ]; do
dba20559 477 [[ $_fs ]] || continue
75d758e8 478 [[ $_fs == "autofs" ]] && continue
466a5998 479 printf "%s" "$_fs"
dba20559 480 return 0
9a52c3fd
HH
481 done
482 return 1
483 } && return 0
dba20559
HH
484 fi
485
e9ed44c8
TL
486 [[ ! -f "$dracutsysrootdir"/etc/fstab ]] && return 1
487
9a52c3fd 488 findmnt --fstab -e -v -n -o 'FSTYPE' --source "$_find_dev" | {
2b5ddc77 489 while read -r _fs || [ -n "$_fs" ]; do
5e601454 490 [[ $_fs ]] || continue
75d758e8 491 [[ $_fs == "autofs" ]] && continue
466a5998 492 printf "%s" "$_fs"
5e601454 493 return 0
9a52c3fd
HH
494 done
495 return 1
496 } && return 0
5e601454
HH
497
498 return 1
97af51db 499}
5e601454 500
bbc9bfe1
HH
501# find_mp_fsopts <mountpoint>
502# Echo the filesystem options for a given mountpoint.
503# /proc/self/mountinfo is taken as the primary source of information
504# and /etc/fstab is used as a fallback.
505# No newline is appended!
506# Example:
507# $ find_mp_fsopts /;echo
508# rw,relatime,discard,data=ordered
509find_mp_fsopts() {
510 if [[ $use_fstab != yes ]]; then
9a52c3fd 511 findmnt -e -v -n -o 'OPTIONS' --target "$1" 2> /dev/null && return 0
bbc9bfe1
HH
512 fi
513
e9ed44c8
TL
514 [[ ! -f "$dracutsysrootdir"/etc/fstab ]] && return 1
515
bbc9bfe1
HH
516 findmnt --fstab -e -v -n -o 'OPTIONS' --target "$1"
517}
518
97af51db
HH
519# find_dev_fsopts <device>
520# Echo the filesystem options for a given device.
521# /proc/self/mountinfo is taken as the primary source of information
522# and /etc/fstab is used as a fallback.
3483509e
HH
523# if `use_fstab == yes`, then only `/etc/fstab` is used.
524#
97af51db
HH
525# Example:
526# $ find_dev_fsopts /dev/sda2
527# rw,relatime,discard,data=ordered
528find_dev_fsopts() {
3483509e 529 local _find_dev
97af51db 530 _find_dev="$1"
75d758e8 531 if ! [[ $_find_dev == /dev* ]]; then
97af51db
HH
532 [[ -b "/dev/block/$_find_dev" ]] && _find_dev="/dev/block/$_find_dev"
533 fi
534
535 if [[ $use_fstab != yes ]]; then
9a52c3fd 536 findmnt -e -v -n -o 'OPTIONS' --source "$_find_dev" 2> /dev/null && return 0
97af51db
HH
537 fi
538
e9ed44c8
TL
539 [[ ! -f "$dracutsysrootdir"/etc/fstab ]] && return 1
540
97af51db 541 findmnt --fstab -e -v -n -o 'OPTIONS' --source "$_find_dev"
81672479
HH
542}
543
7ae5d9d1 544# finds the major:minor of the block device backing the root filesystem.
f76ef3aa
VL
545find_root_block_device() { find_block_device /; }
546
7e2bca48 547# for_each_host_dev_fs <func>
d351541e 548# Execute "<func> <dev> <filesystem>" for every "<dev> <fs>" pair found
7e2bca48 549# in ${host_fs_types[@]}
9a52c3fd 550for_each_host_dev_fs() {
480d772f 551 local _func="$1"
d0096de7 552 local _dev
2efa546f 553 local _ret=1
fd191a7b 554
e6199960
PL
555 [[ "${#host_fs_types[@]}" ]] || return 2
556
d351541e
HH
557 for _dev in "${!host_fs_types[@]}"; do
558 $_func "$_dev" "${host_fs_types[$_dev]}" && _ret=0
480d772f 559 done
2efa546f 560 return $_ret
480d772f
HH
561}
562
9a52c3fd 563host_fs_all() {
466a5998 564 printf "%s\n" "${host_fs_types[@]}"
fd191a7b
HH
565}
566
17829e94
VL
567# Walk all the slave relationships for a given block device.
568# Stop when our helper function returns success
569# $1 = function to call on every found block device
570# $2 = block device in major:minor format
0b706743 571check_block_and_slaves() {
29b10e65 572 local _x
17829e94 573 [[ -b /dev/block/$2 ]] || return 1 # Not a block device? So sorry.
2b5ddc77 574 if ! lvm_internal_dev "$2"; then "$1" "$2" && return; fi
533d7dc4 575 check_vol_slaves "$@" && return 0
e64dafd1 576 if [[ -f /sys/dev/block/$2/../dev ]] && [[ /sys/dev/block/$2/../subsystem -ef /sys/class/block ]]; then
2b5ddc77 577 check_block_and_slaves "$1" "$(< "/sys/dev/block/$2/../dev")" && return 0
a3afcf2a 578 fi
2b5ddc77 579 for _x in /sys/dev/block/"$2"/slaves/*; do
e64dafd1
HH
580 [[ -f $_x/dev ]] || continue
581 [[ $_x/subsystem -ef /sys/class/block ]] || continue
2b5ddc77 582 check_block_and_slaves "$1" "$(< "$_x/dev")" && return 0
17829e94
VL
583 done
584 return 1
585}
586
83e0dc7a
DY
587check_block_and_slaves_all() {
588 local _x _ret=1
589 [[ -b /dev/block/$2 ]] || return 1 # Not a block device? So sorry.
2b5ddc77 590 if ! lvm_internal_dev "$2" && "$1" "$2"; then
dba20559 591 _ret=0
83e0dc7a 592 fi
c7c8c498 593 check_vol_slaves_all "$@" && return 0
e64dafd1 594 if [[ -f /sys/dev/block/$2/../dev ]] && [[ /sys/dev/block/$2/../subsystem -ef /sys/class/block ]]; then
2b5ddc77 595 check_block_and_slaves_all "$1" "$(< "/sys/dev/block/$2/../dev")" && _ret=0
83e0dc7a 596 fi
2b5ddc77 597 for _x in /sys/dev/block/"$2"/slaves/*; do
e64dafd1
HH
598 [[ -f $_x/dev ]] || continue
599 [[ $_x/subsystem -ef /sys/class/block ]] || continue
2b5ddc77 600 check_block_and_slaves_all "$1" "$(< "$_x/dev")" && _ret=0
83e0dc7a
DY
601 done
602 return $_ret
603}
604# for_each_host_dev_and_slaves <func>
605# Execute "<func> <dev>" for every "<dev>" found
606# in ${host_devs[@]} and their slaves
9a52c3fd 607for_each_host_dev_and_slaves_all() {
83e0dc7a
DY
608 local _func="$1"
609 local _dev
610 local _ret=1
fd191a7b 611
3483509e 612 [[ "${host_devs[*]}" ]] || return 2
fd191a7b 613
3721635b 614 for _dev in "${host_devs[@]}"; do
75d758e8 615 [[ -b $_dev ]] || continue
2b5ddc77 616 if check_block_and_slaves_all "$_func" "$(get_maj_min "$_dev")"; then
dba20559 617 _ret=0
83e0dc7a
DY
618 fi
619 done
620 return $_ret
621}
622
9a52c3fd 623for_each_host_dev_and_slaves() {
83e0dc7a
DY
624 local _func="$1"
625 local _dev
fd191a7b 626
3483509e 627 [[ "${host_devs[*]}" ]] || return 2
fd191a7b 628
3721635b 629 for _dev in "${host_devs[@]}"; do
75d758e8 630 [[ -b $_dev ]] || continue
2b5ddc77 631 check_block_and_slaves "$_func" "$(get_maj_min "$_dev")" && return 0
83e0dc7a
DY
632 done
633 return 1
634}
635
c86f4d28
PL
636# /sys/dev/block/major:minor is symbol link to real hardware device
637# go downstream $(realpath /sys/dev/block/major:minor) to detect driver
638get_blockdev_drv_through_sys() {
639 local _block_mods=""
640 local _path
641
642 _path=$(realpath "$1")
643 while true; do
644 if [[ -L "$_path"/driver/module ]]; then
645 _mod=$(realpath "$_path"/driver/module)
646 _mod=$(basename "$_mod")
647 _block_mods="$_block_mods $_mod"
648 fi
649 _path=$(dirname "$_path")
650 if [[ $_path == '/sys/devices' ]] || [[ $_path == '/' ]]; then
651 break
652 fi
653 done
654 echo "$_block_mods"
655}
656
533d7dc4
HH
657# ugly workaround for the lvm design
658# There is no volume group device,
659# so, there are no slave devices for volume groups.
660# Logical volumes only have the slave devices they really live on,
661# but you cannot create the logical volume without the volume group.
95bde758 662# And the volume group might be bigger than the devices the LV needs.
533d7dc4 663check_vol_slaves() {
2b5ddc77 664 local _vg _pv _dm _majmin
9ed6eb74 665 _majmin="$2"
9ed6eb74 666 _dm=/sys/dev/block/$_majmin/dm
2b5ddc77
HH
667 [[ -f $_dm/uuid && $(< "$_dm"/uuid) =~ LVM-* ]] || return 1
668 _vg=$(dmsetup splitname --noheadings -o vg_name "$(< "$_dm/name")")
9ed6eb74
HH
669 # strip space
670 _vg="${_vg//[[:space:]]/}"
671 if [[ $_vg ]]; then
9a52c3fd 672 for _pv in $(lvm vgs --noheadings -o pv_name "$_vg" 2> /dev/null); do
2b5ddc77 673 check_block_and_slaves "$1" "$(get_maj_min "$_pv")" && return 0
9ed6eb74
HH
674 done
675 fi
533d7dc4
HH
676 return 1
677}
678
c7c8c498 679check_vol_slaves_all() {
2b5ddc77 680 local _vg _pv _majmin
9ed6eb74 681 _majmin="$2"
9ed6eb74 682 _dm="/sys/dev/block/$_majmin/dm"
2b5ddc77
HH
683 [[ -f $_dm/uuid && $(< "$_dm"/uuid) =~ LVM-* ]] || return 1
684 _vg=$(dmsetup splitname --noheadings -o vg_name "$(< "$_dm/name")")
9ed6eb74
HH
685 # strip space
686 _vg="${_vg//[[:space:]]/}"
687 if [[ $_vg ]]; then
da36b76a 688 # when filter/global_filter is set, lvm may be failed
2b5ddc77 689 if ! lvm lvs --noheadings -o vg_name "$_vg" 2> /dev/null 1> /dev/null; then
9a52c3fd 690 return 1
da36b76a 691 fi
692
9a52c3fd 693 for _pv in $(lvm vgs --noheadings -o pv_name "$_vg" 2> /dev/null); do
2b5ddc77 694 check_block_and_slaves_all "$1" "$(get_maj_min "$_pv")"
9ed6eb74
HH
695 done
696 return 0
697 fi
c7c8c498
HH
698 return 1
699}
700
8aa99268
HH
701# fs_get_option <filesystem options> <search for option>
702# search for a specific option in a bunch of filesystem options
703# and return the value
704fs_get_option() {
705 local _fsopts=$1
706 local _option=$2
707 local OLDIFS="$IFS"
708 IFS=,
2b5ddc77 709 # shellcheck disable=SC2086
8aa99268
HH
710 set -- $_fsopts
711 IFS="$OLDIFS"
712 while [ $# -gt 0 ]; do
713 case $1 in
714 $_option=*)
08b63a25 715 echo "${1#"${_option}"=}"
8aa99268 716 break
9a52c3fd 717 ;;
8aa99268
HH
718 esac
719 shift
720 done
721}
722
9a52c3fd 723check_kernel_config() {
8e3f6537
HH
724 local _config_opt="$1"
725 local _config_file
a0120420 726 [[ -f $dracutsysrootdir/boot/config-$kernel ]] \
8e3f6537 727 && _config_file="/boot/config-$kernel"
a0120420 728 [[ -f $dracutsysrootdir/lib/modules/$kernel/config ]] \
8e3f6537
HH
729 && _config_file="/lib/modules/$kernel/config"
730
731 # no kernel config file, so return true
732 [[ $_config_file ]] || return 0
733
560f45b1 734 grep -q -F "${_config_opt}=" "$dracutsysrootdir$_config_file" && return 0
8e3f6537
HH
735 return 1
736}
737
c050190f
KS
738# 0 if the kernel module is either built-in or available
739# 1 if the kernel module is not enabled
740check_kernel_module() {
6c42d378 741 modprobe -d "$dracutsysrootdir" -S "$kernel" --dry-run "$1" &> /dev/null || return 1
c050190f 742}
8e3f6537 743
5f2c30d9
KRW
744# get_cpu_vendor
745# Only two values are returned: AMD or Intel
9a52c3fd 746get_cpu_vendor() {
5f2c30d9
KRW
747 if grep -qE AMD /proc/cpuinfo; then
748 printf "AMD"
749 fi
750 if grep -qE Intel /proc/cpuinfo; then
751 printf "Intel"
752 fi
753}
754
755# get_host_ucode
756# Get the hosts' ucode file based on the /proc/cpuinfo
9a52c3fd 757get_ucode_file() {
2b5ddc77
HH
758 local family
759 local model
760 local stepping
122657b2
KS
761 family=$(grep -E "cpu family" /proc/cpuinfo | head -1 | sed "s/.*:\ //")
762 model=$(grep -E "model" /proc/cpuinfo | grep -v name | head -1 | sed "s/.*:\ //")
763 stepping=$(grep -E "stepping" /proc/cpuinfo | head -1 | sed "s/.*:\ //")
5f2c30d9
KRW
764
765 if [[ "$(get_cpu_vendor)" == "AMD" ]]; then
19453dc8 766 if [[ $family -ge 21 ]]; then
2b5ddc77 767 printf "microcode_amd_fam%xh.bin" "$family"
5f2c30d9
KRW
768 else
769 printf "microcode_amd.bin"
770 fi
771 fi
772 if [[ "$(get_cpu_vendor)" == "Intel" ]]; then
773 # The /proc/cpuinfo are in decimal.
2b5ddc77 774 printf "%02x-%02x-%02x" "${family}" "${model}" "${stepping}"
5f2c30d9
KRW
775 fi
776}
96c6f6f3
MC
777
778# Not every device in /dev/mapper should be examined.
779# If it is an LVM device, touch only devices which have /dev/VG/LV symlink.
780lvm_internal_dev() {
781 local dev_dm_dir=/sys/dev/block/$1/dm
2b5ddc77 782 [[ ! -f $dev_dm_dir/uuid || $(< "$dev_dm_dir"/uuid) != LVM-* ]] && return 1 # Not an LVM device
96c6f6f3 783 local DM_VG_NAME DM_LV_NAME DM_LV_LAYER
2b5ddc77 784 eval "$(dmsetup splitname --nameprefixes --noheadings --rows "$(< "$dev_dm_dir"/name)" 2> /dev/null)"
96c6f6f3
MC
785 [[ ${DM_VG_NAME} ]] && [[ ${DM_LV_NAME} ]] || return 0 # Better skip this!
786 [[ ${DM_LV_LAYER} ]] || [[ ! -L /dev/${DM_VG_NAME}/${DM_LV_NAME} ]]
787}
788
1cadc26f
HH
789btrfs_devs() {
790 local _mp="$1"
791 btrfs device usage "$_mp" \
2b5ddc77 792 | while read -r _dev _; do
9a52c3fd
HH
793 str_starts "$_dev" "/" || continue
794 _dev=${_dev%,}
795 printf -- "%s\n" "$_dev"
1cadc26f
HH
796 done
797}
ceca74cc 798
9582f027
SJ
799zfs_devs() {
800 local _mp="$1"
801 zpool list -H -v -P "${_mp%%/*}" | awk -F$'\t' '$2 ~ /^\// {print $2}' \
802 | while read -r _dev; do
803 realpath "${_dev}"
804 done
805}
806
ceca74cc 807iface_for_remote_addr() {
2b5ddc77 808 # shellcheck disable=SC2046
ceca74cc 809 set -- $(ip -o route get to "$1")
d754e1c6
MW
810 while [ $# -gt 0 ]; do
811 case $1 in
812 dev)
813 echo "$2"
814 return
815 ;;
816 esac
817 shift
818 done
ceca74cc
MW
819}
820
821local_addr_for_remote_addr() {
2b5ddc77 822 # shellcheck disable=SC2046
ceca74cc 823 set -- $(ip -o route get to "$1")
d754e1c6
MW
824 while [ $# -gt 0 ]; do
825 case $1 in
826 src)
827 echo "$2"
828 return
829 ;;
830 esac
831 shift
832 done
ceca74cc
MW
833}
834
835peer_for_addr() {
836 local addr=$1
837 local qtd
838
839 # quote periods in IPv4 address
840 qtd=${addr//./\\.}
9a52c3fd
HH
841 ip -o addr show \
842 | sed -n 's%^.* '"$qtd"' peer \([0-9a-f.:]\{1,\}\(/[0-9]*\)\?\).*$%\1%p'
ceca74cc
MW
843}
844
845netmask_for_addr() {
846 local addr=$1
847 local qtd
848
849 # quote periods in IPv4 address
850 qtd=${addr//./\\.}
851 ip -o addr show | sed -n 's,^.* '"$qtd"'/\([0-9]*\) .*$,\1,p'
852}
853
854gateway_for_iface() {
855 local ifname=$1 addr=$2
856
857 case $addr in
9a52c3fd
HH
858 *.*) proto=4 ;;
859 *:*) proto=6 ;;
860 *) return ;;
ceca74cc 861 esac
9a52c3fd
HH
862 ip -o -$proto route show \
863 | sed -n "s/^default via \([0-9a-z.:]\{1,\}\) dev $ifname .*\$/\1/p"
ceca74cc
MW
864}
865
866# This works only for ifcfg-style network configuration!
867bootproto_for_iface() {
868 local ifname=$1
869 local dir
870
871 # follow ifcfg settings for boot protocol
872 for dir in network-scripts network; do
873 [ -f "/etc/sysconfig/$dir/ifcfg-$ifname" ] && {
874 sed -n "s/BOOTPROTO=[\"']\?\([[:alnum:]]\{1,\}\)[\"']\?.*\$/\1/p" \
875 "/etc/sysconfig/$dir/ifcfg-$ifname"
876 return
877 }
878 done
879}
880
881is_unbracketed_ipv6_address() {
882 strglob "$1" '*:*' && ! strglob "$1" '\[*:*\]'
883}
884
885# Create an ip= string to set up networking such that the given
886# remote address can be reached
887ip_params_for_remote_addr() {
888 local remote_addr=$1
2b5ddc77 889 local ifname local_addr peer netmask gateway ifmac
ceca74cc
MW
890
891 [[ $remote_addr ]] || return 1
892 ifname=$(iface_for_remote_addr "$remote_addr")
893 [[ $ifname ]] || {
894 berror "failed to determine interface to connect to $remote_addr"
895 return 1
896 }
897
898 # ifname clause to bind the interface name to a MAC address
899 if [ -d "/sys/class/net/$ifname/bonding" ]; then
900 dinfo "Found bonded interface '${ifname}'. Make sure to provide an appropriate 'bond=' cmdline."
9a52c3fd 901 elif [ -e "/sys/class/net/$ifname/address" ]; then
ceca74cc
MW
902 ifmac=$(cat "/sys/class/net/$ifname/address")
903 [[ $ifmac ]] && printf 'ifname=%s:%s ' "${ifname}" "${ifmac}"
904 fi
905
906 bootproto=$(bootproto_for_iface "$ifname")
907 case $bootproto in
9a52c3fd 908 dhcp | dhcp6 | auto6) ;;
ceca74cc 909 dhcp4)
9a52c3fd
HH
910 bootproto=dhcp
911 ;;
912 static* | "")
913 bootproto=
914 ;;
ceca74cc
MW
915 *)
916 derror "bootproto \"$bootproto\" is unsupported by dracut, trying static configuration"
9a52c3fd
HH
917 bootproto=
918 ;;
ceca74cc
MW
919 esac
920 if [[ $bootproto ]]; then
921 printf 'ip=%s:%s ' "${ifname}" "${bootproto}"
922 else
923 local_addr=$(local_addr_for_remote_addr "$remote_addr")
924 [[ $local_addr ]] || {
925 berror "failed to determine local address to connect to $remote_addr"
926 return 1
927 }
928 peer=$(peer_for_addr "$local_addr")
929 # Set peer or netmask, but not both
930 [[ $peer ]] || netmask=$(netmask_for_addr "$local_addr")
931 gateway=$(gateway_for_iface "$ifname" "$local_addr")
932 # Quote IPv6 addresses with brackets
933 is_unbracketed_ipv6_address "$local_addr" && local_addr="[$local_addr]"
934 is_unbracketed_ipv6_address "$peer" && peer="[$peer]"
935 is_unbracketed_ipv6_address "$gateway" && gateway="[$gateway]"
936 printf 'ip=%s:%s:%s:%s::%s:none ' \
9a52c3fd 937 "${local_addr}" "${peer}" "${gateway}" "${netmask}" "${ifname}"
ceca74cc
MW
938 fi
939
940}
480aa969
DM
941
942# block_is_nbd <maj:min>
943# Check whether $1 is an nbd device
944block_is_nbd() {
945 [[ -b /dev/block/$1 && $1 == 43:* ]]
946}
947
948# block_is_iscsi <maj:min>
0afa840e 949# Check whether $1 is an iSCSI device
480aa969
DM
950block_is_iscsi() {
951 local _dir
952 local _dev=$1
953 [[ -L "/sys/dev/block/$_dev" ]] || return
954 _dir="$(readlink -f "/sys/dev/block/$_dev")" || return
955 until [[ -d "$_dir/sys" || -d "$_dir/iscsi_session" ]]; do
956 _dir="$_dir/.."
957 done
958 [[ -d "$_dir/iscsi_session" ]]
959}
960
961# block_is_fcoe <maj:min>
962# Check whether $1 is an FCoE device
963# Will not work for HBAs that hide the ethernet aspect
964# completely and present a pure FC device
965block_is_fcoe() {
966 local _dir
967 local _dev=$1
968 [[ -L "/sys/dev/block/$_dev" ]] || return
969 _dir="$(readlink -f "/sys/dev/block/$_dev")"
970 until [[ -d "$_dir/sys" ]]; do
971 _dir="$_dir/.."
972 if [[ -d "$_dir/subsystem" ]]; then
2b5ddc77 973 subsystem=$(basename "$(readlink "$_dir"/subsystem)")
480aa969
DM
974 [[ $subsystem == "fcoe" ]] && return 0
975 fi
976 done
977 return 1
978}
979
980# block_is_netdevice <maj:min>
981# Check whether $1 is a net device
982block_is_netdevice() {
983 block_is_nbd "$1" || block_is_iscsi "$1" || block_is_fcoe "$1"
984}
cbafcd0f 985
a62e895d
TL
986# convert the driver name given by udevadm to the corresponding kernel module name
987get_module_name() {
988 local dev_driver
989 while read -r dev_driver; do
990 case "$dev_driver" in
991 mmcblk)
992 echo "mmc_block"
993 ;;
994 *)
995 echo "$dev_driver"
996 ;;
997 esac
998 done
999}
1000
cbafcd0f
KS
1001# get the corresponding kernel modules of a /sys/class/*/* or/dev/* device
1002get_dev_module() {
dc3b976f
AAF
1003 local dev_attr_walk
1004 local dev_drivers
87a76dbb 1005 local dev_paths
dc3b976f 1006 dev_attr_walk=$(udevadm info -a "$1")
a62e895d
TL
1007 dev_drivers=$(echo "$dev_attr_walk" \
1008 | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' \
1009 | get_module_name)
87a76dbb
AT
1010
1011 # also return modalias info from sysfs paths parsed by udevadm
1012 dev_paths=$(echo "$dev_attr_walk" | sed -n 's/.*\(\/devices\/.*\)'\'':/\1/p')
1013 local dev_path
1014 for dev_path in $dev_paths; do
1015 local modalias_file="/sys$dev_path/modalias"
1016 if [ -e "$modalias_file" ]; then
1017 dev_drivers="$(printf "%s\n%s" "$dev_drivers" "$(cat "$modalias_file")")"
1018 fi
1019 done
1020
dc3b976f
AAF
1021 # if no kernel modules found and device is in a virtual subsystem, follow symlinks
1022 if [[ -z $dev_drivers && $(udevadm info -q path "$1") == "/devices/virtual"* ]]; then
1023 local dev_vkernel
1024 local dev_vsubsystem
1025 local dev_vpath
1026 dev_vkernel=$(echo "$dev_attr_walk" | sed -n 's/\s*KERNELS=="\(\S\+\)"/\1/p' | tail -1)
1027 dev_vsubsystem=$(echo "$dev_attr_walk" | sed -n 's/\s*SUBSYSTEMS=="\(\S\+\)"/\1/p' | tail -1)
1028 dev_vpath="/sys/devices/virtual/$dev_vsubsystem/$dev_vkernel"
1029 if [[ -n $dev_vkernel && -n $dev_vsubsystem && -d $dev_vpath ]]; then
1030 local dev_links
1031 local dev_link
1032 dev_links=$(find "$dev_vpath" -maxdepth 1 -type l ! -name "subsystem" -exec readlink {} \;)
1033 for dev_link in $dev_links; do
1034 [[ -n $dev_drivers && ${dev_drivers: -1} != $'\n' ]] && dev_drivers+=$'\n'
1035 dev_drivers+=$(udevadm info -a "$dev_vpath/$dev_link" \
1036 | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' \
a62e895d 1037 | get_module_name \
dc3b976f
AAF
1038 | grep -v -e pcieport)
1039 done
1040 fi
1041 fi
1042 echo "$dev_drivers"
cbafcd0f 1043}
f32e95bc
VL
1044
1045# Check if file is in PE format
1046pe_file_format() {
1047 if [[ $# -eq 1 ]]; then
1048 local magic
1049 magic=$(objdump -p "$1" \
33a66ed0 1050 | gawk '{if ($1 == "Magic"){print strtonum("0x"$2)}}')
f32e95bc
VL
1051 magic=$(printf "0x%x" "$magic")
1052 # 0x10b (PE32), 0x20b (PE32+)
1053 [[ $magic == 0x20b || $magic == 0x10b ]] && return 0
1054 fi
1055 return 1
1056}
1057
6178a9d8 1058# Get specific data from the PE header
1059pe_get_header_data() {
1060 local data_header
1061 [[ $# -ne "2" ]] && return 1
1062 [[ $(pe_file_format "$1") -eq 1 ]] && return 1
1063 data_header=$(objdump -p "$1" \
1064 | awk -v data="$2" '{if ($1 == data){print $2}}')
1065 echo "$data_header"
1066}
1067
1068# Get the SectionAlignment data from the PE header
f32e95bc
VL
1069pe_get_section_align() {
1070 local align_hex
1071 [[ $# -ne "1" ]] && return 1
6178a9d8 1072 align_hex=$(pe_get_header_data "$1" "SectionAlignment")
1073 [[ $? -eq 1 ]] && return 1
f32e95bc
VL
1074 echo "$((16#$align_hex))"
1075}
6178a9d8 1076
1077# Get the ImageBase data from the PE header
1078pe_get_image_base() {
1079 local base_image
1080 [[ $# -ne "1" ]] && return 1
1081 base_image=$(pe_get_header_data "$1" "ImageBase")
1082 [[ $? -eq 1 ]] && return 1
1083 echo "$((16#$base_image))"
1084}