From bc5cc2dcc6edf70fd0bbe0f7c9f4adbcb6b0b442 Mon Sep 17 00:00:00 2001 From: "Kang.Yihang" Date: Wed, 1 Nov 2023 17:59:30 +0800 Subject: [PATCH 1/8] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=BA=86055=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E5=AF=B9=E8=99=9A=E6=8B=9F=E5=9D=97=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E7=9A=84=E9=81=8D=E5=8E=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dracut.spec | 4 ++++ fix-virture.patch | 49 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 fix-virture.patch diff --git a/dracut.spec b/dracut.spec index 6cf4784..74c2109 100644 --- a/dracut.spec +++ b/dracut.spec @@ -40,6 +40,7 @@ Patch13: backport-feat-lvm-only-run-lvchange-for-LV-that-is-seen-on-de.patch Patch14: backport-fix-lvm-restore-setting-LVM_MD_PV_ACTIVATED.patch Patch15: backport-Bring-back-51-dracut-rescue-postinst.sh.patch Patch16: backport-fix-dracut-shutdown-add-cleanup-handler-on-failure.patch +Patch17: fix-virture.patch Patch9000: remove-iscsi-related-code-since-it-is-no-longer-main.patch @@ -516,6 +517,9 @@ install -m 0755 51-dracut-rescue-postinst.sh $RPM_BUILD_ROOT%{_sysconfdir}/kerne %endif %changelog +* Wed Nov 1 2023 kangyihang - 055-8 +- fix(dracut-functions.sh): get block device driver if in a virtual subsystem + * Wed Mar 22 2023 wangyuhang - 055-7 - fix(dracut-shutdown): add cleanup handler on failure diff --git a/fix-virture.patch b/fix-virture.patch new file mode 100644 index 0000000..3d8a25d --- /dev/null +++ b/fix-virture.patch @@ -0,0 +1,49 @@ +--- ./dracut-functions.sh 2023-11-01 17:21:34.776084229 +0800 ++++ ./dracut-functions-fix.sh 2023-11-01 17:24:45.146084561 +0800 +@@ -924,5 +924,45 @@ block_is_netdevice() { + + # get the corresponding kernel modules of a /sys/class/*/* or/dev/* device + get_dev_module() { +- udevadm info -a "$1" | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' ++ #udevadm info -a "$1" | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' ++ local dev_attr_walk ++ local dev_drivers ++ local dev_paths ++ dev_attr_walk=$(udevadm info -a "$1") ++ dev_drivers=$(echo "$dev_attr_walk" \ ++ | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' \ ++ | get_module_name) ++ ++ # also return modalias info from sysfs paths parsed by udevadm ++ dev_paths=$(echo "$dev_attr_walk" | sed -n 's/.*\(\/devices\/.*\)'\'':/\1/p') ++ local dev_path ++ for dev_path in $dev_paths; do ++ local modalias_file="/sys$dev_path/modalias" ++ if [ -e "$modalias_file" ]; then ++ dev_drivers="$(printf "%s\n%s" "$dev_drivers" "$(cat "$modalias_file")")" ++ fi ++ done ++ ++ # if no kernel modules found and device is in a virtual subsystem, follow symlinks ++ if [[ -z $dev_drivers && $(udevadm info -q path "$1") == "/devices/virtual"* ]]; then ++ local dev_vkernel ++ local dev_vsubsystem ++ local dev_vpath ++ dev_vkernel=$(echo "$dev_attr_walk" | sed -n 's/\s*KERNELS=="\(\S\+\)"/\1/p' | tail -1) ++ dev_vsubsystem=$(echo "$dev_attr_walk" | sed -n 's/\s*SUBSYSTEMS=="\(\S\+\)"/\1/p' | tail -1) ++ dev_vpath="/sys/devices/virtual/$dev_vsubsystem/$dev_vkernel" ++ if [[ -n $dev_vkernel && -n $dev_vsubsystem && -d $dev_vpath ]]; then ++ local dev_links ++ local dev_link ++ dev_links=$(find "$dev_vpath" -maxdepth 1 -type l ! -name "subsystem" -exec readlink {} \;) ++ for dev_link in $dev_links; do ++ [[ -n $dev_drivers && ${dev_drivers: -1} != $'\n' ]] && dev_drivers+=$'\n' ++ dev_drivers+=$(udevadm info -a "$dev_vpath/$dev_link" \ ++ | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' \ ++ | get_module_name \ ++ | grep -v -e pcieport) ++ done ++ fi ++ fi ++ echo "$dev_drivers" + } -- Gitee From 583816f1d63e881e31ae1ff30133dd1850d23c15 Mon Sep 17 00:00:00 2001 From: "Kang.Yihang" Date: Thu, 2 Nov 2023 10:34:24 +0800 Subject: [PATCH 2/8] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fix-virture.patch | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/fix-virture.patch b/fix-virture.patch index 3d8a25d..ef3fd64 100644 --- a/fix-virture.patch +++ b/fix-virture.patch @@ -1,7 +1,24 @@ ---- ./dracut-functions.sh 2023-11-01 17:21:34.776084229 +0800 -+++ ./dracut-functions-fix.sh 2023-11-01 17:24:45.146084561 +0800 -@@ -924,5 +924,45 @@ block_is_netdevice() { +--- a/dracut-functions.sh 2023-11-01 17:21:34.776084229 +0800 ++++ b/dracut-functions-fix.sh 2023-11-02 10:32:28.810495055 +0800 +@@ -922,7 +922,62 @@ block_is_netdevice() { + block_is_nbd "$1" || block_is_iscsi "$1" || block_is_fcoe "$1" + } ++# convert the driver name given by udevadm to the corresponding kernel module name ++get_module_name() { ++ local dev_driver ++ while read -r dev_driver; do ++ case "$dev_driver" in ++ mmcblk) ++ echo "mmc_block" ++ ;; ++ *) ++ echo "$dev_driver" ++ ;; ++ esac ++ done ++} ++ # get the corresponding kernel modules of a /sys/class/*/* or/dev/* device get_dev_module() { - udevadm info -a "$1" | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' -- Gitee From ae3de677e320a804e349017627847541063a22ff Mon Sep 17 00:00:00 2001 From: "Kang.Yihang" Date: Thu, 2 Nov 2023 14:16:00 +0800 Subject: [PATCH 3/8] =?UTF-8?q?=E4=BF=AE=E6=AD=A3patch=E7=9A=84=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fix-virture.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fix-virture.patch b/fix-virture.patch index ef3fd64..366136f 100644 --- a/fix-virture.patch +++ b/fix-virture.patch @@ -1,5 +1,5 @@ --- a/dracut-functions.sh 2023-11-01 17:21:34.776084229 +0800 -+++ b/dracut-functions-fix.sh 2023-11-02 10:32:28.810495055 +0800 ++++ b/dracut-functions.sh 2023-11-02 10:32:28.810495055 +0800 @@ -922,7 +922,62 @@ block_is_netdevice() { block_is_nbd "$1" || block_is_iscsi "$1" || block_is_fcoe "$1" } -- Gitee From e5f2bf724d58ce60c0b9fa52d072c8023acf60f5 Mon Sep 17 00:00:00 2001 From: "Kang.Yihang" Date: Thu, 2 Nov 2023 14:44:55 +0800 Subject: [PATCH 4/8] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E5=88=B0=E6=9C=AC?= =?UTF-8?q?=E5=9C=B0=E7=9A=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- a/dracut-functions.sh | 928 +++++++++++++++++++++++++++++++++++++++ b/dracut-functions.sh | 983 ++++++++++++++++++++++++++++++++++++++++++ dracut-functions.sh | 928 +++++++++++++++++++++++++++++++++++++++ fix-virture.patch | 66 --- 4 files changed, 2839 insertions(+), 66 deletions(-) create mode 100644 a/dracut-functions.sh create mode 100644 b/dracut-functions.sh create mode 100644 dracut-functions.sh delete mode 100644 fix-virture.patch diff --git a/a/dracut-functions.sh b/a/dracut-functions.sh new file mode 100644 index 0000000..5206bd2 --- /dev/null +++ b/a/dracut-functions.sh @@ -0,0 +1,928 @@ +#!/bin/bash +# +# functions used by dracut and other tools. +# +# Copyright 2005-2009 Red Hat, Inc. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +export LC_MESSAGES=C + +# is_func +# Check whether $1 is a function. +is_func() { + [[ "$(type -t "$1")" == "function" ]] +} + +# Generic substring function. If $2 is in $1, return 0. +strstr() { [[ $1 == *"$2"* ]]; } +# Generic glob matching function. If glob pattern $2 matches anywhere in $1, OK +strglobin() { [[ $1 == *$2* ]]; } +# Generic glob matching function. If glob pattern $2 matches all of $1, OK +# shellcheck disable=SC2053 +strglob() { [[ $1 == $2 ]]; } +# returns OK if $1 contains literal string $2 at the beginning, and isn't empty +str_starts() { [ "${1#"$2"*}" != "$1" ]; } +# returns OK if $1 contains literal string $2 at the end, and isn't empty +str_ends() { [ "${1%*"$2"}" != "$1" ]; } + +# find a binary. If we were not passed the full path directly, +# search in the usual places to find the binary. +find_binary() { + local _delim + local _path + local l + local p + [[ -z ${1##/*} ]] || _delim="/" + + if [[ $1 == *.so* ]]; then + # shellcheck disable=SC2154 + for l in $libdirs; do + _path="${l}${_delim}${1}" + if { $DRACUT_LDD "${dracutsysrootdir}${_path}" &> /dev/null; }; then + printf "%s\n" "${_path}" + return 0 + fi + done + _path="${_delim}${1}" + if { $DRACUT_LDD "${dracutsysrootdir}${_path}" &> /dev/null; }; then + printf "%s\n" "${_path}" + return 0 + fi + fi + if [[ $1 == */* ]]; then + _path="${_delim}${1}" + if [[ -L ${dracutsysrootdir}${_path} ]] || [[ -x ${dracutsysrootdir}${_path} ]]; then + printf "%s\n" "${_path}" + return 0 + fi + fi + for p in $DRACUT_PATH; do + _path="${p}${_delim}${1}" + if [[ -L ${dracutsysrootdir}${_path} ]] || [[ -x ${dracutsysrootdir}${_path} ]]; then + printf "%s\n" "${_path}" + return 0 + fi + done + + [[ -n $dracutsysrootdir ]] && return 1 + type -P "${1##*/}" +} + +ldconfig_paths() { + $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 +} + +# Version comparision function. Assumes Linux style version scheme. +# $1 = version a +# $2 = comparision op (gt, ge, eq, le, lt, ne) +# $3 = version b +vercmp() { + local _n1 + read -r -a _n1 <<< "${1//./ }" + local _op=$2 + local _n2 + read -r -a _n2 <<< "${3//./ }" + local _i _res + + for ((_i = 0; ; _i++)); do + if [[ ! ${_n1[_i]}${_n2[_i]} ]]; then + _res=0 + elif ((${_n1[_i]:-0} > ${_n2[_i]:-0})); then + _res=1 + elif ((${_n1[_i]:-0} < ${_n2[_i]:-0})); then + _res=2 + else + continue + fi + break + done + + case $_op in + gt) ((_res == 1)) ;; + ge) ((_res != 2)) ;; + eq) ((_res == 0)) ;; + le) ((_res != 1)) ;; + lt) ((_res == 2)) ;; + ne) ((_res != 0)) ;; + esac +} + +# Create all subdirectories for given path without creating the last element. +# $1 = path +mksubdirs() { + # shellcheck disable=SC2174 + [[ -e ${1%/*} ]] || mkdir -m 0755 -p -- "${1%/*}" +} + +# Function prints global variables in format name=value line by line. +# $@ = list of global variables' name +print_vars() { + local _var _value + + for _var in "$@"; do + eval printf -v _value "%s" \""\$$_var"\" + [[ ${_value} ]] && printf '%s="%s"\n' "$_var" "$_value" + done +} + +# normalize_path +# Prints the normalized path, where it removes any duplicated +# and trailing slashes. +# Example: +# $ normalize_path ///test/test// +# /test/test +normalize_path() { + # shellcheck disable=SC2064 + trap "$(shopt -p extglob)" RETURN + shopt -q -s extglob + local p=${1//+(\/)//} + printf "%s\n" "${p%/}" +} + +# convert_abs_rel +# Prints the relative path, when creating a symlink to from . +# Example: +# $ convert_abs_rel /usr/bin/test /bin/test-2 +# ../../bin/test-2 +# $ ln -s $(convert_abs_rel /usr/bin/test /bin/test-2) /usr/bin/test +convert_abs_rel() { + local __current __absolute __abssize __cursize __newpath + local -i __i __level + + set -- "$(normalize_path "$1")" "$(normalize_path "$2")" + + # corner case #1 - self looping link + [[ $1 == "$2" ]] && { + printf "%s\n" "${1##*/}" + return + } + + # corner case #2 - own dir link + [[ ${1%/*} == "$2" ]] && { + printf ".\n" + return + } + + IFS=/ read -r -a __current <<< "$1" + IFS=/ read -r -a __absolute <<< "$2" + + __abssize=${#__absolute[@]} + __cursize=${#__current[@]} + + while [[ ${__absolute[__level]} == "${__current[__level]}" ]]; do + ((__level++)) + if ((__level > __abssize || __level > __cursize)); then + break + fi + done + + for ((__i = __level; __i < __cursize - 1; __i++)); do + if ((__i > __level)); then + __newpath=$__newpath"/" + fi + __newpath=$__newpath".." + done + + for ((__i = __level; __i < __abssize; __i++)); do + if [[ -n $__newpath ]]; then + __newpath=$__newpath"/" + fi + __newpath=$__newpath${__absolute[__i]} + done + + printf -- "%s\n" "$__newpath" +} + +# get_fs_env +# Get and the ID_FS_TYPE variable from udev for a device. +# Example: +# $ get_fs_env /dev/sda2 +# ext4 +get_fs_env() { + [[ $1 ]] || return + unset ID_FS_TYPE + ID_FS_TYPE=$(blkid -u filesystem -o export -- "$1" \ + | while read -r line || [ -n "$line" ]; do + if [[ $line == "TYPE="* ]]; then + printf "%s" "${line#TYPE=}" + exit 0 + fi + done) + if [[ $ID_FS_TYPE ]]; then + printf "%s" "$ID_FS_TYPE" + return 0 + fi + return 1 +} + +# get_maj_min +# Prints the major and minor of a device node. +# Example: +# $ get_maj_min /dev/sda2 +# 8:2 +get_maj_min() { + local _majmin + local _out + + if [[ $get_maj_min_cache_file ]]; then + _out="$(grep -m1 -oP "^$1 \K\S+$" "$get_maj_min_cache_file")" + fi + + if ! [[ "$_out" ]]; then + _majmin="$(stat -L -c '%t:%T' "$1" 2> /dev/null)" + _out="$(printf "%s" "$((0x${_majmin%:*})):$((0x${_majmin#*:}))")" + if [[ $get_maj_min_cache_file ]]; then + echo "$1 $_out" >> "$get_maj_min_cache_file" + fi + fi + echo -n "$_out" +} + +# get_devpath_block +# get the DEVPATH in /sys of a block device +get_devpath_block() { + local _majmin _i + _majmin=$(get_maj_min "$1") + + for _i in /sys/block/*/dev /sys/block/*/*/dev; do + [[ -e $_i ]] || continue + if [[ $_majmin == "$(< "$_i")" ]]; then + printf "%s" "${_i%/dev}" + return 0 + fi + done + return 1 +} + +# get a persistent path from a device +get_persistent_dev() { + local i _tmp _dev _pol + + _dev=$(get_maj_min "$1") + [ -z "$_dev" ] && return + + if [[ -n $persistent_policy ]]; then + _pol="/dev/disk/${persistent_policy}/*" + else + _pol= + fi + + for i in \ + $_pol \ + /dev/mapper/* \ + /dev/disk/by-uuid/* \ + /dev/disk/by-label/* \ + /dev/disk/by-partuuid/* \ + /dev/disk/by-partlabel/* \ + /dev/disk/by-id/* \ + /dev/disk/by-path/*; do + [[ -e $i ]] || continue + [[ $i == /dev/mapper/control ]] && continue + [[ $i == /dev/mapper/mpath* ]] && continue + _tmp=$(get_maj_min "$i") + if [ "$_tmp" = "$_dev" ]; then + printf -- "%s" "$i" + return + fi + done + printf -- "%s" "$1" +} + +expand_persistent_dev() { + local _dev=$1 + + case "$_dev" in + LABEL=*) + _dev="/dev/disk/by-label/${_dev#LABEL=}" + ;; + UUID=*) + _dev="${_dev#UUID=}" + _dev="${_dev,,}" + _dev="/dev/disk/by-uuid/${_dev}" + ;; + PARTUUID=*) + _dev="${_dev#PARTUUID=}" + _dev="${_dev,,}" + _dev="/dev/disk/by-partuuid/${_dev}" + ;; + PARTLABEL=*) + _dev="/dev/disk/by-partlabel/${_dev#PARTLABEL=}" + ;; + esac + printf "%s" "$_dev" +} + +shorten_persistent_dev() { + local _dev="$1" + case "$_dev" in + /dev/disk/by-uuid/*) + printf "%s" "UUID=${_dev##*/}" + ;; + /dev/disk/by-label/*) + printf "%s" "LABEL=${_dev##*/}" + ;; + /dev/disk/by-partuuid/*) + printf "%s" "PARTUUID=${_dev##*/}" + ;; + /dev/disk/by-partlabel/*) + printf "%s" "PARTLABEL=${_dev##*/}" + ;; + *) + printf "%s" "$_dev" + ;; + esac +} + +# find_block_device +# Prints the major and minor number of the block device +# for a given mountpoint. +# Unless $use_fstab is set to "yes" the functions +# uses /proc/self/mountinfo as the primary source of the +# information and only falls back to /etc/fstab, if the mountpoint +# is not found there. +# Example: +# $ find_block_device /usr +# 8:4 +find_block_device() { + local _dev _majmin _find_mpt + _find_mpt="$1" + + if [[ $use_fstab != yes ]]; then + [[ -d $_find_mpt/. ]] + findmnt -e -v -n -o 'MAJ:MIN,SOURCE' --target "$_find_mpt" | { + while read -r _majmin _dev || [ -n "$_dev" ]; do + if [[ -b $_dev ]]; then + if ! [[ $_majmin ]] || [[ $_majmin == 0:* ]]; then + _majmin=$(get_maj_min "$_dev") + fi + if [[ $_majmin ]]; then + printf "%s\n" "$_majmin" + else + printf "%s\n" "$_dev" + fi + return 0 + fi + if [[ $_dev == *:* ]]; then + printf "%s\n" "$_dev" + return 0 + fi + done + return 1 + } && return 0 + fi + # fall back to /etc/fstab + + findmnt -e --fstab -v -n -o 'MAJ:MIN,SOURCE' --target "$_find_mpt" | { + while read -r _majmin _dev || [ -n "$_dev" ]; do + if ! [[ $_dev ]]; then + _dev="$_majmin" + unset _majmin + fi + if [[ -b $_dev ]]; then + [[ $_majmin ]] || _majmin=$(get_maj_min "$_dev") + if [[ $_majmin ]]; then + printf "%s\n" "$_majmin" + else + printf "%s\n" "$_dev" + fi + return 0 + fi + if [[ $_dev == *:* ]]; then + printf "%s\n" "$_dev" + return 0 + fi + done + return 1 + } && return 0 + + return 1 +} + +# find_mp_fstype +# Echo the filesystem type for a given mountpoint. +# /proc/self/mountinfo is taken as the primary source of information +# and /etc/fstab is used as a fallback. +# No newline is appended! +# Example: +# $ find_mp_fstype /;echo +# ext4 +find_mp_fstype() { + local _fs + + if [[ $use_fstab != yes ]]; then + findmnt -e -v -n -o 'FSTYPE' --target "$1" | { + while read -r _fs || [ -n "$_fs" ]; do + [[ $_fs ]] || continue + [[ $_fs == "autofs" ]] && continue + printf "%s" "$_fs" + return 0 + done + return 1 + } && return 0 + fi + + findmnt --fstab -e -v -n -o 'FSTYPE' --target "$1" | { + while read -r _fs || [ -n "$_fs" ]; do + [[ $_fs ]] || continue + [[ $_fs == "autofs" ]] && continue + printf "%s" "$_fs" + return 0 + done + return 1 + } && return 0 + + return 1 +} + +# find_dev_fstype +# Echo the filesystem type for a given device. +# /proc/self/mountinfo is taken as the primary source of information +# and /etc/fstab is used as a fallback. +# No newline is appended! +# Example: +# $ find_dev_fstype /dev/sda2;echo +# ext4 +find_dev_fstype() { + local _find_dev _fs + _find_dev="$1" + if ! [[ $_find_dev == /dev* ]]; then + [[ -b "/dev/block/$_find_dev" ]] && _find_dev="/dev/block/$_find_dev" + fi + + if [[ $use_fstab != yes ]]; then + findmnt -e -v -n -o 'FSTYPE' --source "$_find_dev" | { + while read -r _fs || [ -n "$_fs" ]; do + [[ $_fs ]] || continue + [[ $_fs == "autofs" ]] && continue + printf "%s" "$_fs" + return 0 + done + return 1 + } && return 0 + fi + + findmnt --fstab -e -v -n -o 'FSTYPE' --source "$_find_dev" | { + while read -r _fs || [ -n "$_fs" ]; do + [[ $_fs ]] || continue + [[ $_fs == "autofs" ]] && continue + printf "%s" "$_fs" + return 0 + done + return 1 + } && return 0 + + return 1 +} + +# find_mp_fsopts +# Echo the filesystem options for a given mountpoint. +# /proc/self/mountinfo is taken as the primary source of information +# and /etc/fstab is used as a fallback. +# No newline is appended! +# Example: +# $ find_mp_fsopts /;echo +# rw,relatime,discard,data=ordered +find_mp_fsopts() { + if [[ $use_fstab != yes ]]; then + findmnt -e -v -n -o 'OPTIONS' --target "$1" 2> /dev/null && return 0 + fi + + findmnt --fstab -e -v -n -o 'OPTIONS' --target "$1" +} + +# find_dev_fsopts +# Echo the filesystem options for a given device. +# /proc/self/mountinfo is taken as the primary source of information +# and /etc/fstab is used as a fallback. +# if `use_fstab == yes`, then only `/etc/fstab` is used. +# +# Example: +# $ find_dev_fsopts /dev/sda2 +# rw,relatime,discard,data=ordered +find_dev_fsopts() { + local _find_dev + _find_dev="$1" + if ! [[ $_find_dev == /dev* ]]; then + [[ -b "/dev/block/$_find_dev" ]] && _find_dev="/dev/block/$_find_dev" + fi + + if [[ $use_fstab != yes ]]; then + findmnt -e -v -n -o 'OPTIONS' --source "$_find_dev" 2> /dev/null && return 0 + fi + + findmnt --fstab -e -v -n -o 'OPTIONS' --source "$_find_dev" +} + +# finds the major:minor of the block device backing the root filesystem. +find_root_block_device() { find_block_device /; } + +# for_each_host_dev_fs +# Execute " " for every " " pair found +# in ${host_fs_types[@]} +for_each_host_dev_fs() { + local _func="$1" + local _dev + local _ret=1 + + [[ "${#host_fs_types[@]}" ]] || return 2 + + for _dev in "${!host_fs_types[@]}"; do + $_func "$_dev" "${host_fs_types[$_dev]}" && _ret=0 + done + return $_ret +} + +host_fs_all() { + printf "%s\n" "${host_fs_types[@]}" +} + +# Walk all the slave relationships for a given block device. +# Stop when our helper function returns success +# $1 = function to call on every found block device +# $2 = block device in major:minor format +check_block_and_slaves() { + local _x + [[ -b /dev/block/$2 ]] || return 1 # Not a block device? So sorry. + if ! lvm_internal_dev "$2"; then "$1" "$2" && return; fi + check_vol_slaves "$@" && return 0 + if [[ -f /sys/dev/block/$2/../dev ]] && [[ /sys/dev/block/$2/../subsystem -ef /sys/class/block ]]; then + check_block_and_slaves "$1" "$(< "/sys/dev/block/$2/../dev")" && return 0 + fi + for _x in /sys/dev/block/"$2"/slaves/*; do + [[ -f $_x/dev ]] || continue + [[ $_x/subsystem -ef /sys/class/block ]] || continue + check_block_and_slaves "$1" "$(< "$_x/dev")" && return 0 + done + return 1 +} + +check_block_and_slaves_all() { + local _x _ret=1 + [[ -b /dev/block/$2 ]] || return 1 # Not a block device? So sorry. + if ! lvm_internal_dev "$2" && "$1" "$2"; then + _ret=0 + fi + check_vol_slaves_all "$@" && return 0 + if [[ -f /sys/dev/block/$2/../dev ]] && [[ /sys/dev/block/$2/../subsystem -ef /sys/class/block ]]; then + check_block_and_slaves_all "$1" "$(< "/sys/dev/block/$2/../dev")" && _ret=0 + fi + for _x in /sys/dev/block/"$2"/slaves/*; do + [[ -f $_x/dev ]] || continue + [[ $_x/subsystem -ef /sys/class/block ]] || continue + check_block_and_slaves_all "$1" "$(< "$_x/dev")" && _ret=0 + done + return $_ret +} +# for_each_host_dev_and_slaves +# Execute " " for every "" found +# in ${host_devs[@]} and their slaves +for_each_host_dev_and_slaves_all() { + local _func="$1" + local _dev + local _ret=1 + + [[ "${host_devs[*]}" ]] || return 2 + + for _dev in "${host_devs[@]}"; do + [[ -b $_dev ]] || continue + if check_block_and_slaves_all "$_func" "$(get_maj_min "$_dev")"; then + _ret=0 + fi + done + return $_ret +} + +for_each_host_dev_and_slaves() { + local _func="$1" + local _dev + + [[ "${host_devs[*]}" ]] || return 2 + + for _dev in "${host_devs[@]}"; do + [[ -b $_dev ]] || continue + check_block_and_slaves "$_func" "$(get_maj_min "$_dev")" && return 0 + done + return 1 +} + +# ugly workaround for the lvm design +# There is no volume group device, +# so, there are no slave devices for volume groups. +# Logical volumes only have the slave devices they really live on, +# but you cannot create the logical volume without the volume group. +# And the volume group might be bigger than the devices the LV needs. +check_vol_slaves() { + local _vg _pv _dm _majmin + _majmin="$2" + _dm=/sys/dev/block/$_majmin/dm + [[ -f $_dm/uuid && $(< "$_dm"/uuid) =~ LVM-* ]] || return 1 + _vg=$(dmsetup splitname --noheadings -o vg_name "$(< "$_dm/name")") + # strip space + _vg="${_vg//[[:space:]]/}" + if [[ $_vg ]]; then + for _pv in $(lvm vgs --noheadings -o pv_name "$_vg" 2> /dev/null); do + check_block_and_slaves "$1" "$(get_maj_min "$_pv")" && return 0 + done + fi + return 1 +} + +check_vol_slaves_all() { + local _vg _pv _majmin + _majmin="$2" + _dm="/sys/dev/block/$_majmin/dm" + [[ -f $_dm/uuid && $(< "$_dm"/uuid) =~ LVM-* ]] || return 1 + _vg=$(dmsetup splitname --noheadings -o vg_name "$(< "$_dm/name")") + # strip space + _vg="${_vg//[[:space:]]/}" + if [[ $_vg ]]; then + # when filter/global_filter is set, lvm may be failed + if ! lvm lvs --noheadings -o vg_name "$_vg" 2> /dev/null 1> /dev/null; then + return 1 + fi + + for _pv in $(lvm vgs --noheadings -o pv_name "$_vg" 2> /dev/null); do + check_block_and_slaves_all "$1" "$(get_maj_min "$_pv")" + done + return 0 + fi + return 1 +} + +# fs_get_option +# search for a specific option in a bunch of filesystem options +# and return the value +fs_get_option() { + local _fsopts=$1 + local _option=$2 + local OLDIFS="$IFS" + IFS=, + # shellcheck disable=SC2086 + set -- $_fsopts + IFS="$OLDIFS" + while [ $# -gt 0 ]; do + case $1 in + $_option=*) + echo "${1#${_option}=}" + break + ;; + esac + shift + done +} + +check_kernel_config() { + local _config_opt="$1" + local _config_file + [[ -f $dracutsysrootdir/boot/config-$kernel ]] \ + && _config_file="/boot/config-$kernel" + [[ -f $dracutsysrootdir/lib/modules/$kernel/config ]] \ + && _config_file="/lib/modules/$kernel/config" + + # no kernel config file, so return true + [[ $_config_file ]] || return 0 + + grep -q -F "${_config_opt}=" "$dracutsysrootdir$_config_file" && return 0 + return 1 +} + +# 0 if the kernel module is either built-in or available +# 1 if the kernel module is not enabled +check_kernel_module() { + modprobe -S "$kernel" --dry-run "$1" &> /dev/null || return 1 +} + +# get_cpu_vendor +# Only two values are returned: AMD or Intel +get_cpu_vendor() { + if grep -qE AMD /proc/cpuinfo; then + printf "AMD" + fi + if grep -qE Intel /proc/cpuinfo; then + printf "Intel" + fi +} + +# get_host_ucode +# Get the hosts' ucode file based on the /proc/cpuinfo +get_ucode_file() { + local family + local model + local stepping + family=$(grep -E "cpu family" /proc/cpuinfo | head -1 | sed "s/.*:\ //") + model=$(grep -E "model" /proc/cpuinfo | grep -v name | head -1 | sed "s/.*:\ //") + stepping=$(grep -E "stepping" /proc/cpuinfo | head -1 | sed "s/.*:\ //") + + if [[ "$(get_cpu_vendor)" == "AMD" ]]; then + if [[ $family -ge 21 ]]; then + printf "microcode_amd_fam%xh.bin" "$family" + else + printf "microcode_amd.bin" + fi + fi + if [[ "$(get_cpu_vendor)" == "Intel" ]]; then + # The /proc/cpuinfo are in decimal. + printf "%02x-%02x-%02x" "${family}" "${model}" "${stepping}" + fi +} + +# Not every device in /dev/mapper should be examined. +# If it is an LVM device, touch only devices which have /dev/VG/LV symlink. +lvm_internal_dev() { + local dev_dm_dir=/sys/dev/block/$1/dm + [[ ! -f $dev_dm_dir/uuid || $(< "$dev_dm_dir"/uuid) != LVM-* ]] && return 1 # Not an LVM device + local DM_VG_NAME DM_LV_NAME DM_LV_LAYER + eval "$(dmsetup splitname --nameprefixes --noheadings --rows "$(< "$dev_dm_dir"/name)" 2> /dev/null)" + [[ ${DM_VG_NAME} ]] && [[ ${DM_LV_NAME} ]] || return 0 # Better skip this! + [[ ${DM_LV_LAYER} ]] || [[ ! -L /dev/${DM_VG_NAME}/${DM_LV_NAME} ]] +} + +btrfs_devs() { + local _mp="$1" + btrfs device usage "$_mp" \ + | while read -r _dev _; do + str_starts "$_dev" "/" || continue + _dev=${_dev%,} + printf -- "%s\n" "$_dev" + done +} + +iface_for_remote_addr() { + # shellcheck disable=SC2046 + set -- $(ip -o route get to "$1") + echo "$3" +} + +local_addr_for_remote_addr() { + # shellcheck disable=SC2046 + set -- $(ip -o route get to "$1") + echo "$5" +} + +peer_for_addr() { + local addr=$1 + local qtd + + # quote periods in IPv4 address + qtd=${addr//./\\.} + ip -o addr show \ + | sed -n 's%^.* '"$qtd"' peer \([0-9a-f.:]\{1,\}\(/[0-9]*\)\?\).*$%\1%p' +} + +netmask_for_addr() { + local addr=$1 + local qtd + + # quote periods in IPv4 address + qtd=${addr//./\\.} + ip -o addr show | sed -n 's,^.* '"$qtd"'/\([0-9]*\) .*$,\1,p' +} + +gateway_for_iface() { + local ifname=$1 addr=$2 + + case $addr in + *.*) proto=4 ;; + *:*) proto=6 ;; + *) return ;; + esac + ip -o -$proto route show \ + | sed -n "s/^default via \([0-9a-z.:]\{1,\}\) dev $ifname .*\$/\1/p" +} + +# This works only for ifcfg-style network configuration! +bootproto_for_iface() { + local ifname=$1 + local dir + + # follow ifcfg settings for boot protocol + for dir in network-scripts network; do + [ -f "/etc/sysconfig/$dir/ifcfg-$ifname" ] && { + sed -n "s/BOOTPROTO=[\"']\?\([[:alnum:]]\{1,\}\)[\"']\?.*\$/\1/p" \ + "/etc/sysconfig/$dir/ifcfg-$ifname" + return + } + done +} + +is_unbracketed_ipv6_address() { + strglob "$1" '*:*' && ! strglob "$1" '\[*:*\]' +} + +# Create an ip= string to set up networking such that the given +# remote address can be reached +ip_params_for_remote_addr() { + local remote_addr=$1 + local ifname local_addr peer netmask gateway ifmac + + [[ $remote_addr ]] || return 1 + ifname=$(iface_for_remote_addr "$remote_addr") + [[ $ifname ]] || { + berror "failed to determine interface to connect to $remote_addr" + return 1 + } + + # ifname clause to bind the interface name to a MAC address + if [ -d "/sys/class/net/$ifname/bonding" ]; then + dinfo "Found bonded interface '${ifname}'. Make sure to provide an appropriate 'bond=' cmdline." + elif [ -e "/sys/class/net/$ifname/address" ]; then + ifmac=$(cat "/sys/class/net/$ifname/address") + [[ $ifmac ]] && printf 'ifname=%s:%s ' "${ifname}" "${ifmac}" + fi + + bootproto=$(bootproto_for_iface "$ifname") + case $bootproto in + dhcp | dhcp6 | auto6) ;; + dhcp4) + bootproto=dhcp + ;; + static* | "") + bootproto= + ;; + *) + derror "bootproto \"$bootproto\" is unsupported by dracut, trying static configuration" + bootproto= + ;; + esac + if [[ $bootproto ]]; then + printf 'ip=%s:%s ' "${ifname}" "${bootproto}" + else + local_addr=$(local_addr_for_remote_addr "$remote_addr") + [[ $local_addr ]] || { + berror "failed to determine local address to connect to $remote_addr" + return 1 + } + peer=$(peer_for_addr "$local_addr") + # Set peer or netmask, but not both + [[ $peer ]] || netmask=$(netmask_for_addr "$local_addr") + gateway=$(gateway_for_iface "$ifname" "$local_addr") + # Quote IPv6 addresses with brackets + is_unbracketed_ipv6_address "$local_addr" && local_addr="[$local_addr]" + is_unbracketed_ipv6_address "$peer" && peer="[$peer]" + is_unbracketed_ipv6_address "$gateway" && gateway="[$gateway]" + printf 'ip=%s:%s:%s:%s::%s:none ' \ + "${local_addr}" "${peer}" "${gateway}" "${netmask}" "${ifname}" + fi + +} + +# block_is_nbd +# Check whether $1 is an nbd device +block_is_nbd() { + [[ -b /dev/block/$1 && $1 == 43:* ]] +} + +# block_is_iscsi +# Check whether $1 is an nbd device +block_is_iscsi() { + local _dir + local _dev=$1 + [[ -L "/sys/dev/block/$_dev" ]] || return + _dir="$(readlink -f "/sys/dev/block/$_dev")" || return + until [[ -d "$_dir/sys" || -d "$_dir/iscsi_session" ]]; do + _dir="$_dir/.." + done + [[ -d "$_dir/iscsi_session" ]] +} + +# block_is_fcoe +# Check whether $1 is an FCoE device +# Will not work for HBAs that hide the ethernet aspect +# completely and present a pure FC device +block_is_fcoe() { + local _dir + local _dev=$1 + [[ -L "/sys/dev/block/$_dev" ]] || return + _dir="$(readlink -f "/sys/dev/block/$_dev")" + until [[ -d "$_dir/sys" ]]; do + _dir="$_dir/.." + if [[ -d "$_dir/subsystem" ]]; then + subsystem=$(basename "$(readlink "$_dir"/subsystem)") + [[ $subsystem == "fcoe" ]] && return 0 + fi + done + return 1 +} + +# block_is_netdevice +# Check whether $1 is a net device +block_is_netdevice() { + block_is_nbd "$1" || block_is_iscsi "$1" || block_is_fcoe "$1" +} + +# get the corresponding kernel modules of a /sys/class/*/* or/dev/* device +get_dev_module() { + udevadm info -a "$1" | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' +} diff --git a/b/dracut-functions.sh b/b/dracut-functions.sh new file mode 100644 index 0000000..1efad3b --- /dev/null +++ b/b/dracut-functions.sh @@ -0,0 +1,983 @@ +#!/bin/bash +# +# functions used by dracut and other tools. +# +# Copyright 2005-2009 Red Hat, Inc. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +export LC_MESSAGES=C + +# is_func +# Check whether $1 is a function. +is_func() { + [[ "$(type -t "$1")" == "function" ]] +} + +# Generic substring function. If $2 is in $1, return 0. +strstr() { [[ $1 == *"$2"* ]]; } +# Generic glob matching function. If glob pattern $2 matches anywhere in $1, OK +strglobin() { [[ $1 == *$2* ]]; } +# Generic glob matching function. If glob pattern $2 matches all of $1, OK +# shellcheck disable=SC2053 +strglob() { [[ $1 == $2 ]]; } +# returns OK if $1 contains literal string $2 at the beginning, and isn't empty +str_starts() { [ "${1#"$2"*}" != "$1" ]; } +# returns OK if $1 contains literal string $2 at the end, and isn't empty +str_ends() { [ "${1%*"$2"}" != "$1" ]; } + +# find a binary. If we were not passed the full path directly, +# search in the usual places to find the binary. +find_binary() { + local _delim + local _path + local l + local p + [[ -z ${1##/*} ]] || _delim="/" + + if [[ $1 == *.so* ]]; then + # shellcheck disable=SC2154 + for l in $libdirs; do + _path="${l}${_delim}${1}" + if { $DRACUT_LDD "${dracutsysrootdir}${_path}" &> /dev/null; }; then + printf "%s\n" "${_path}" + return 0 + fi + done + _path="${_delim}${1}" + if { $DRACUT_LDD "${dracutsysrootdir}${_path}" &> /dev/null; }; then + printf "%s\n" "${_path}" + return 0 + fi + fi + if [[ $1 == */* ]]; then + _path="${_delim}${1}" + if [[ -L ${dracutsysrootdir}${_path} ]] || [[ -x ${dracutsysrootdir}${_path} ]]; then + printf "%s\n" "${_path}" + return 0 + fi + fi + for p in $DRACUT_PATH; do + _path="${p}${_delim}${1}" + if [[ -L ${dracutsysrootdir}${_path} ]] || [[ -x ${dracutsysrootdir}${_path} ]]; then + printf "%s\n" "${_path}" + return 0 + fi + done + + [[ -n $dracutsysrootdir ]] && return 1 + type -P "${1##*/}" +} + +ldconfig_paths() { + $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 +} + +# Version comparision function. Assumes Linux style version scheme. +# $1 = version a +# $2 = comparision op (gt, ge, eq, le, lt, ne) +# $3 = version b +vercmp() { + local _n1 + read -r -a _n1 <<< "${1//./ }" + local _op=$2 + local _n2 + read -r -a _n2 <<< "${3//./ }" + local _i _res + + for ((_i = 0; ; _i++)); do + if [[ ! ${_n1[_i]}${_n2[_i]} ]]; then + _res=0 + elif ((${_n1[_i]:-0} > ${_n2[_i]:-0})); then + _res=1 + elif ((${_n1[_i]:-0} < ${_n2[_i]:-0})); then + _res=2 + else + continue + fi + break + done + + case $_op in + gt) ((_res == 1)) ;; + ge) ((_res != 2)) ;; + eq) ((_res == 0)) ;; + le) ((_res != 1)) ;; + lt) ((_res == 2)) ;; + ne) ((_res != 0)) ;; + esac +} + +# Create all subdirectories for given path without creating the last element. +# $1 = path +mksubdirs() { + # shellcheck disable=SC2174 + [[ -e ${1%/*} ]] || mkdir -m 0755 -p -- "${1%/*}" +} + +# Function prints global variables in format name=value line by line. +# $@ = list of global variables' name +print_vars() { + local _var _value + + for _var in "$@"; do + eval printf -v _value "%s" \""\$$_var"\" + [[ ${_value} ]] && printf '%s="%s"\n' "$_var" "$_value" + done +} + +# normalize_path +# Prints the normalized path, where it removes any duplicated +# and trailing slashes. +# Example: +# $ normalize_path ///test/test// +# /test/test +normalize_path() { + # shellcheck disable=SC2064 + trap "$(shopt -p extglob)" RETURN + shopt -q -s extglob + local p=${1//+(\/)//} + printf "%s\n" "${p%/}" +} + +# convert_abs_rel +# Prints the relative path, when creating a symlink to from . +# Example: +# $ convert_abs_rel /usr/bin/test /bin/test-2 +# ../../bin/test-2 +# $ ln -s $(convert_abs_rel /usr/bin/test /bin/test-2) /usr/bin/test +convert_abs_rel() { + local __current __absolute __abssize __cursize __newpath + local -i __i __level + + set -- "$(normalize_path "$1")" "$(normalize_path "$2")" + + # corner case #1 - self looping link + [[ $1 == "$2" ]] && { + printf "%s\n" "${1##*/}" + return + } + + # corner case #2 - own dir link + [[ ${1%/*} == "$2" ]] && { + printf ".\n" + return + } + + IFS=/ read -r -a __current <<< "$1" + IFS=/ read -r -a __absolute <<< "$2" + + __abssize=${#__absolute[@]} + __cursize=${#__current[@]} + + while [[ ${__absolute[__level]} == "${__current[__level]}" ]]; do + ((__level++)) + if ((__level > __abssize || __level > __cursize)); then + break + fi + done + + for ((__i = __level; __i < __cursize - 1; __i++)); do + if ((__i > __level)); then + __newpath=$__newpath"/" + fi + __newpath=$__newpath".." + done + + for ((__i = __level; __i < __abssize; __i++)); do + if [[ -n $__newpath ]]; then + __newpath=$__newpath"/" + fi + __newpath=$__newpath${__absolute[__i]} + done + + printf -- "%s\n" "$__newpath" +} + +# get_fs_env +# Get and the ID_FS_TYPE variable from udev for a device. +# Example: +# $ get_fs_env /dev/sda2 +# ext4 +get_fs_env() { + [[ $1 ]] || return + unset ID_FS_TYPE + ID_FS_TYPE=$(blkid -u filesystem -o export -- "$1" \ + | while read -r line || [ -n "$line" ]; do + if [[ $line == "TYPE="* ]]; then + printf "%s" "${line#TYPE=}" + exit 0 + fi + done) + if [[ $ID_FS_TYPE ]]; then + printf "%s" "$ID_FS_TYPE" + return 0 + fi + return 1 +} + +# get_maj_min +# Prints the major and minor of a device node. +# Example: +# $ get_maj_min /dev/sda2 +# 8:2 +get_maj_min() { + local _majmin + local _out + + if [[ $get_maj_min_cache_file ]]; then + _out="$(grep -m1 -oP "^$1 \K\S+$" "$get_maj_min_cache_file")" + fi + + if ! [[ "$_out" ]]; then + _majmin="$(stat -L -c '%t:%T' "$1" 2> /dev/null)" + _out="$(printf "%s" "$((0x${_majmin%:*})):$((0x${_majmin#*:}))")" + if [[ $get_maj_min_cache_file ]]; then + echo "$1 $_out" >> "$get_maj_min_cache_file" + fi + fi + echo -n "$_out" +} + +# get_devpath_block +# get the DEVPATH in /sys of a block device +get_devpath_block() { + local _majmin _i + _majmin=$(get_maj_min "$1") + + for _i in /sys/block/*/dev /sys/block/*/*/dev; do + [[ -e $_i ]] || continue + if [[ $_majmin == "$(< "$_i")" ]]; then + printf "%s" "${_i%/dev}" + return 0 + fi + done + return 1 +} + +# get a persistent path from a device +get_persistent_dev() { + local i _tmp _dev _pol + + _dev=$(get_maj_min "$1") + [ -z "$_dev" ] && return + + if [[ -n $persistent_policy ]]; then + _pol="/dev/disk/${persistent_policy}/*" + else + _pol= + fi + + for i in \ + $_pol \ + /dev/mapper/* \ + /dev/disk/by-uuid/* \ + /dev/disk/by-label/* \ + /dev/disk/by-partuuid/* \ + /dev/disk/by-partlabel/* \ + /dev/disk/by-id/* \ + /dev/disk/by-path/*; do + [[ -e $i ]] || continue + [[ $i == /dev/mapper/control ]] && continue + [[ $i == /dev/mapper/mpath* ]] && continue + _tmp=$(get_maj_min "$i") + if [ "$_tmp" = "$_dev" ]; then + printf -- "%s" "$i" + return + fi + done + printf -- "%s" "$1" +} + +expand_persistent_dev() { + local _dev=$1 + + case "$_dev" in + LABEL=*) + _dev="/dev/disk/by-label/${_dev#LABEL=}" + ;; + UUID=*) + _dev="${_dev#UUID=}" + _dev="${_dev,,}" + _dev="/dev/disk/by-uuid/${_dev}" + ;; + PARTUUID=*) + _dev="${_dev#PARTUUID=}" + _dev="${_dev,,}" + _dev="/dev/disk/by-partuuid/${_dev}" + ;; + PARTLABEL=*) + _dev="/dev/disk/by-partlabel/${_dev#PARTLABEL=}" + ;; + esac + printf "%s" "$_dev" +} + +shorten_persistent_dev() { + local _dev="$1" + case "$_dev" in + /dev/disk/by-uuid/*) + printf "%s" "UUID=${_dev##*/}" + ;; + /dev/disk/by-label/*) + printf "%s" "LABEL=${_dev##*/}" + ;; + /dev/disk/by-partuuid/*) + printf "%s" "PARTUUID=${_dev##*/}" + ;; + /dev/disk/by-partlabel/*) + printf "%s" "PARTLABEL=${_dev##*/}" + ;; + *) + printf "%s" "$_dev" + ;; + esac +} + +# find_block_device +# Prints the major and minor number of the block device +# for a given mountpoint. +# Unless $use_fstab is set to "yes" the functions +# uses /proc/self/mountinfo as the primary source of the +# information and only falls back to /etc/fstab, if the mountpoint +# is not found there. +# Example: +# $ find_block_device /usr +# 8:4 +find_block_device() { + local _dev _majmin _find_mpt + _find_mpt="$1" + + if [[ $use_fstab != yes ]]; then + [[ -d $_find_mpt/. ]] + findmnt -e -v -n -o 'MAJ:MIN,SOURCE' --target "$_find_mpt" | { + while read -r _majmin _dev || [ -n "$_dev" ]; do + if [[ -b $_dev ]]; then + if ! [[ $_majmin ]] || [[ $_majmin == 0:* ]]; then + _majmin=$(get_maj_min "$_dev") + fi + if [[ $_majmin ]]; then + printf "%s\n" "$_majmin" + else + printf "%s\n" "$_dev" + fi + return 0 + fi + if [[ $_dev == *:* ]]; then + printf "%s\n" "$_dev" + return 0 + fi + done + return 1 + } && return 0 + fi + # fall back to /etc/fstab + + findmnt -e --fstab -v -n -o 'MAJ:MIN,SOURCE' --target "$_find_mpt" | { + while read -r _majmin _dev || [ -n "$_dev" ]; do + if ! [[ $_dev ]]; then + _dev="$_majmin" + unset _majmin + fi + if [[ -b $_dev ]]; then + [[ $_majmin ]] || _majmin=$(get_maj_min "$_dev") + if [[ $_majmin ]]; then + printf "%s\n" "$_majmin" + else + printf "%s\n" "$_dev" + fi + return 0 + fi + if [[ $_dev == *:* ]]; then + printf "%s\n" "$_dev" + return 0 + fi + done + return 1 + } && return 0 + + return 1 +} + +# find_mp_fstype +# Echo the filesystem type for a given mountpoint. +# /proc/self/mountinfo is taken as the primary source of information +# and /etc/fstab is used as a fallback. +# No newline is appended! +# Example: +# $ find_mp_fstype /;echo +# ext4 +find_mp_fstype() { + local _fs + + if [[ $use_fstab != yes ]]; then + findmnt -e -v -n -o 'FSTYPE' --target "$1" | { + while read -r _fs || [ -n "$_fs" ]; do + [[ $_fs ]] || continue + [[ $_fs == "autofs" ]] && continue + printf "%s" "$_fs" + return 0 + done + return 1 + } && return 0 + fi + + findmnt --fstab -e -v -n -o 'FSTYPE' --target "$1" | { + while read -r _fs || [ -n "$_fs" ]; do + [[ $_fs ]] || continue + [[ $_fs == "autofs" ]] && continue + printf "%s" "$_fs" + return 0 + done + return 1 + } && return 0 + + return 1 +} + +# find_dev_fstype +# Echo the filesystem type for a given device. +# /proc/self/mountinfo is taken as the primary source of information +# and /etc/fstab is used as a fallback. +# No newline is appended! +# Example: +# $ find_dev_fstype /dev/sda2;echo +# ext4 +find_dev_fstype() { + local _find_dev _fs + _find_dev="$1" + if ! [[ $_find_dev == /dev* ]]; then + [[ -b "/dev/block/$_find_dev" ]] && _find_dev="/dev/block/$_find_dev" + fi + + if [[ $use_fstab != yes ]]; then + findmnt -e -v -n -o 'FSTYPE' --source "$_find_dev" | { + while read -r _fs || [ -n "$_fs" ]; do + [[ $_fs ]] || continue + [[ $_fs == "autofs" ]] && continue + printf "%s" "$_fs" + return 0 + done + return 1 + } && return 0 + fi + + findmnt --fstab -e -v -n -o 'FSTYPE' --source "$_find_dev" | { + while read -r _fs || [ -n "$_fs" ]; do + [[ $_fs ]] || continue + [[ $_fs == "autofs" ]] && continue + printf "%s" "$_fs" + return 0 + done + return 1 + } && return 0 + + return 1 +} + +# find_mp_fsopts +# Echo the filesystem options for a given mountpoint. +# /proc/self/mountinfo is taken as the primary source of information +# and /etc/fstab is used as a fallback. +# No newline is appended! +# Example: +# $ find_mp_fsopts /;echo +# rw,relatime,discard,data=ordered +find_mp_fsopts() { + if [[ $use_fstab != yes ]]; then + findmnt -e -v -n -o 'OPTIONS' --target "$1" 2> /dev/null && return 0 + fi + + findmnt --fstab -e -v -n -o 'OPTIONS' --target "$1" +} + +# find_dev_fsopts +# Echo the filesystem options for a given device. +# /proc/self/mountinfo is taken as the primary source of information +# and /etc/fstab is used as a fallback. +# if `use_fstab == yes`, then only `/etc/fstab` is used. +# +# Example: +# $ find_dev_fsopts /dev/sda2 +# rw,relatime,discard,data=ordered +find_dev_fsopts() { + local _find_dev + _find_dev="$1" + if ! [[ $_find_dev == /dev* ]]; then + [[ -b "/dev/block/$_find_dev" ]] && _find_dev="/dev/block/$_find_dev" + fi + + if [[ $use_fstab != yes ]]; then + findmnt -e -v -n -o 'OPTIONS' --source "$_find_dev" 2> /dev/null && return 0 + fi + + findmnt --fstab -e -v -n -o 'OPTIONS' --source "$_find_dev" +} + +# finds the major:minor of the block device backing the root filesystem. +find_root_block_device() { find_block_device /; } + +# for_each_host_dev_fs +# Execute " " for every " " pair found +# in ${host_fs_types[@]} +for_each_host_dev_fs() { + local _func="$1" + local _dev + local _ret=1 + + [[ "${#host_fs_types[@]}" ]] || return 2 + + for _dev in "${!host_fs_types[@]}"; do + $_func "$_dev" "${host_fs_types[$_dev]}" && _ret=0 + done + return $_ret +} + +host_fs_all() { + printf "%s\n" "${host_fs_types[@]}" +} + +# Walk all the slave relationships for a given block device. +# Stop when our helper function returns success +# $1 = function to call on every found block device +# $2 = block device in major:minor format +check_block_and_slaves() { + local _x + [[ -b /dev/block/$2 ]] || return 1 # Not a block device? So sorry. + if ! lvm_internal_dev "$2"; then "$1" "$2" && return; fi + check_vol_slaves "$@" && return 0 + if [[ -f /sys/dev/block/$2/../dev ]] && [[ /sys/dev/block/$2/../subsystem -ef /sys/class/block ]]; then + check_block_and_slaves "$1" "$(< "/sys/dev/block/$2/../dev")" && return 0 + fi + for _x in /sys/dev/block/"$2"/slaves/*; do + [[ -f $_x/dev ]] || continue + [[ $_x/subsystem -ef /sys/class/block ]] || continue + check_block_and_slaves "$1" "$(< "$_x/dev")" && return 0 + done + return 1 +} + +check_block_and_slaves_all() { + local _x _ret=1 + [[ -b /dev/block/$2 ]] || return 1 # Not a block device? So sorry. + if ! lvm_internal_dev "$2" && "$1" "$2"; then + _ret=0 + fi + check_vol_slaves_all "$@" && return 0 + if [[ -f /sys/dev/block/$2/../dev ]] && [[ /sys/dev/block/$2/../subsystem -ef /sys/class/block ]]; then + check_block_and_slaves_all "$1" "$(< "/sys/dev/block/$2/../dev")" && _ret=0 + fi + for _x in /sys/dev/block/"$2"/slaves/*; do + [[ -f $_x/dev ]] || continue + [[ $_x/subsystem -ef /sys/class/block ]] || continue + check_block_and_slaves_all "$1" "$(< "$_x/dev")" && _ret=0 + done + return $_ret +} +# for_each_host_dev_and_slaves +# Execute " " for every "" found +# in ${host_devs[@]} and their slaves +for_each_host_dev_and_slaves_all() { + local _func="$1" + local _dev + local _ret=1 + + [[ "${host_devs[*]}" ]] || return 2 + + for _dev in "${host_devs[@]}"; do + [[ -b $_dev ]] || continue + if check_block_and_slaves_all "$_func" "$(get_maj_min "$_dev")"; then + _ret=0 + fi + done + return $_ret +} + +for_each_host_dev_and_slaves() { + local _func="$1" + local _dev + + [[ "${host_devs[*]}" ]] || return 2 + + for _dev in "${host_devs[@]}"; do + [[ -b $_dev ]] || continue + check_block_and_slaves "$_func" "$(get_maj_min "$_dev")" && return 0 + done + return 1 +} + +# ugly workaround for the lvm design +# There is no volume group device, +# so, there are no slave devices for volume groups. +# Logical volumes only have the slave devices they really live on, +# but you cannot create the logical volume without the volume group. +# And the volume group might be bigger than the devices the LV needs. +check_vol_slaves() { + local _vg _pv _dm _majmin + _majmin="$2" + _dm=/sys/dev/block/$_majmin/dm + [[ -f $_dm/uuid && $(< "$_dm"/uuid) =~ LVM-* ]] || return 1 + _vg=$(dmsetup splitname --noheadings -o vg_name "$(< "$_dm/name")") + # strip space + _vg="${_vg//[[:space:]]/}" + if [[ $_vg ]]; then + for _pv in $(lvm vgs --noheadings -o pv_name "$_vg" 2> /dev/null); do + check_block_and_slaves "$1" "$(get_maj_min "$_pv")" && return 0 + done + fi + return 1 +} + +check_vol_slaves_all() { + local _vg _pv _majmin + _majmin="$2" + _dm="/sys/dev/block/$_majmin/dm" + [[ -f $_dm/uuid && $(< "$_dm"/uuid) =~ LVM-* ]] || return 1 + _vg=$(dmsetup splitname --noheadings -o vg_name "$(< "$_dm/name")") + # strip space + _vg="${_vg//[[:space:]]/}" + if [[ $_vg ]]; then + # when filter/global_filter is set, lvm may be failed + if ! lvm lvs --noheadings -o vg_name "$_vg" 2> /dev/null 1> /dev/null; then + return 1 + fi + + for _pv in $(lvm vgs --noheadings -o pv_name "$_vg" 2> /dev/null); do + check_block_and_slaves_all "$1" "$(get_maj_min "$_pv")" + done + return 0 + fi + return 1 +} + +# fs_get_option +# search for a specific option in a bunch of filesystem options +# and return the value +fs_get_option() { + local _fsopts=$1 + local _option=$2 + local OLDIFS="$IFS" + IFS=, + # shellcheck disable=SC2086 + set -- $_fsopts + IFS="$OLDIFS" + while [ $# -gt 0 ]; do + case $1 in + $_option=*) + echo "${1#${_option}=}" + break + ;; + esac + shift + done +} + +check_kernel_config() { + local _config_opt="$1" + local _config_file + [[ -f $dracutsysrootdir/boot/config-$kernel ]] \ + && _config_file="/boot/config-$kernel" + [[ -f $dracutsysrootdir/lib/modules/$kernel/config ]] \ + && _config_file="/lib/modules/$kernel/config" + + # no kernel config file, so return true + [[ $_config_file ]] || return 0 + + grep -q -F "${_config_opt}=" "$dracutsysrootdir$_config_file" && return 0 + return 1 +} + +# 0 if the kernel module is either built-in or available +# 1 if the kernel module is not enabled +check_kernel_module() { + modprobe -S "$kernel" --dry-run "$1" &> /dev/null || return 1 +} + +# get_cpu_vendor +# Only two values are returned: AMD or Intel +get_cpu_vendor() { + if grep -qE AMD /proc/cpuinfo; then + printf "AMD" + fi + if grep -qE Intel /proc/cpuinfo; then + printf "Intel" + fi +} + +# get_host_ucode +# Get the hosts' ucode file based on the /proc/cpuinfo +get_ucode_file() { + local family + local model + local stepping + family=$(grep -E "cpu family" /proc/cpuinfo | head -1 | sed "s/.*:\ //") + model=$(grep -E "model" /proc/cpuinfo | grep -v name | head -1 | sed "s/.*:\ //") + stepping=$(grep -E "stepping" /proc/cpuinfo | head -1 | sed "s/.*:\ //") + + if [[ "$(get_cpu_vendor)" == "AMD" ]]; then + if [[ $family -ge 21 ]]; then + printf "microcode_amd_fam%xh.bin" "$family" + else + printf "microcode_amd.bin" + fi + fi + if [[ "$(get_cpu_vendor)" == "Intel" ]]; then + # The /proc/cpuinfo are in decimal. + printf "%02x-%02x-%02x" "${family}" "${model}" "${stepping}" + fi +} + +# Not every device in /dev/mapper should be examined. +# If it is an LVM device, touch only devices which have /dev/VG/LV symlink. +lvm_internal_dev() { + local dev_dm_dir=/sys/dev/block/$1/dm + [[ ! -f $dev_dm_dir/uuid || $(< "$dev_dm_dir"/uuid) != LVM-* ]] && return 1 # Not an LVM device + local DM_VG_NAME DM_LV_NAME DM_LV_LAYER + eval "$(dmsetup splitname --nameprefixes --noheadings --rows "$(< "$dev_dm_dir"/name)" 2> /dev/null)" + [[ ${DM_VG_NAME} ]] && [[ ${DM_LV_NAME} ]] || return 0 # Better skip this! + [[ ${DM_LV_LAYER} ]] || [[ ! -L /dev/${DM_VG_NAME}/${DM_LV_NAME} ]] +} + +btrfs_devs() { + local _mp="$1" + btrfs device usage "$_mp" \ + | while read -r _dev _; do + str_starts "$_dev" "/" || continue + _dev=${_dev%,} + printf -- "%s\n" "$_dev" + done +} + +iface_for_remote_addr() { + # shellcheck disable=SC2046 + set -- $(ip -o route get to "$1") + echo "$3" +} + +local_addr_for_remote_addr() { + # shellcheck disable=SC2046 + set -- $(ip -o route get to "$1") + echo "$5" +} + +peer_for_addr() { + local addr=$1 + local qtd + + # quote periods in IPv4 address + qtd=${addr//./\\.} + ip -o addr show \ + | sed -n 's%^.* '"$qtd"' peer \([0-9a-f.:]\{1,\}\(/[0-9]*\)\?\).*$%\1%p' +} + +netmask_for_addr() { + local addr=$1 + local qtd + + # quote periods in IPv4 address + qtd=${addr//./\\.} + ip -o addr show | sed -n 's,^.* '"$qtd"'/\([0-9]*\) .*$,\1,p' +} + +gateway_for_iface() { + local ifname=$1 addr=$2 + + case $addr in + *.*) proto=4 ;; + *:*) proto=6 ;; + *) return ;; + esac + ip -o -$proto route show \ + | sed -n "s/^default via \([0-9a-z.:]\{1,\}\) dev $ifname .*\$/\1/p" +} + +# This works only for ifcfg-style network configuration! +bootproto_for_iface() { + local ifname=$1 + local dir + + # follow ifcfg settings for boot protocol + for dir in network-scripts network; do + [ -f "/etc/sysconfig/$dir/ifcfg-$ifname" ] && { + sed -n "s/BOOTPROTO=[\"']\?\([[:alnum:]]\{1,\}\)[\"']\?.*\$/\1/p" \ + "/etc/sysconfig/$dir/ifcfg-$ifname" + return + } + done +} + +is_unbracketed_ipv6_address() { + strglob "$1" '*:*' && ! strglob "$1" '\[*:*\]' +} + +# Create an ip= string to set up networking such that the given +# remote address can be reached +ip_params_for_remote_addr() { + local remote_addr=$1 + local ifname local_addr peer netmask gateway ifmac + + [[ $remote_addr ]] || return 1 + ifname=$(iface_for_remote_addr "$remote_addr") + [[ $ifname ]] || { + berror "failed to determine interface to connect to $remote_addr" + return 1 + } + + # ifname clause to bind the interface name to a MAC address + if [ -d "/sys/class/net/$ifname/bonding" ]; then + dinfo "Found bonded interface '${ifname}'. Make sure to provide an appropriate 'bond=' cmdline." + elif [ -e "/sys/class/net/$ifname/address" ]; then + ifmac=$(cat "/sys/class/net/$ifname/address") + [[ $ifmac ]] && printf 'ifname=%s:%s ' "${ifname}" "${ifmac}" + fi + + bootproto=$(bootproto_for_iface "$ifname") + case $bootproto in + dhcp | dhcp6 | auto6) ;; + dhcp4) + bootproto=dhcp + ;; + static* | "") + bootproto= + ;; + *) + derror "bootproto \"$bootproto\" is unsupported by dracut, trying static configuration" + bootproto= + ;; + esac + if [[ $bootproto ]]; then + printf 'ip=%s:%s ' "${ifname}" "${bootproto}" + else + local_addr=$(local_addr_for_remote_addr "$remote_addr") + [[ $local_addr ]] || { + berror "failed to determine local address to connect to $remote_addr" + return 1 + } + peer=$(peer_for_addr "$local_addr") + # Set peer or netmask, but not both + [[ $peer ]] || netmask=$(netmask_for_addr "$local_addr") + gateway=$(gateway_for_iface "$ifname" "$local_addr") + # Quote IPv6 addresses with brackets + is_unbracketed_ipv6_address "$local_addr" && local_addr="[$local_addr]" + is_unbracketed_ipv6_address "$peer" && peer="[$peer]" + is_unbracketed_ipv6_address "$gateway" && gateway="[$gateway]" + printf 'ip=%s:%s:%s:%s::%s:none ' \ + "${local_addr}" "${peer}" "${gateway}" "${netmask}" "${ifname}" + fi + +} + +# block_is_nbd +# Check whether $1 is an nbd device +block_is_nbd() { + [[ -b /dev/block/$1 && $1 == 43:* ]] +} + +# block_is_iscsi +# Check whether $1 is an nbd device +block_is_iscsi() { + local _dir + local _dev=$1 + [[ -L "/sys/dev/block/$_dev" ]] || return + _dir="$(readlink -f "/sys/dev/block/$_dev")" || return + until [[ -d "$_dir/sys" || -d "$_dir/iscsi_session" ]]; do + _dir="$_dir/.." + done + [[ -d "$_dir/iscsi_session" ]] +} + +# block_is_fcoe +# Check whether $1 is an FCoE device +# Will not work for HBAs that hide the ethernet aspect +# completely and present a pure FC device +block_is_fcoe() { + local _dir + local _dev=$1 + [[ -L "/sys/dev/block/$_dev" ]] || return + _dir="$(readlink -f "/sys/dev/block/$_dev")" + until [[ -d "$_dir/sys" ]]; do + _dir="$_dir/.." + if [[ -d "$_dir/subsystem" ]]; then + subsystem=$(basename "$(readlink "$_dir"/subsystem)") + [[ $subsystem == "fcoe" ]] && return 0 + fi + done + return 1 +} + +# block_is_netdevice +# Check whether $1 is a net device +block_is_netdevice() { + block_is_nbd "$1" || block_is_iscsi "$1" || block_is_fcoe "$1" +} + +# convert the driver name given by udevadm to the corresponding kernel module name +get_module_name() { + local dev_driver + while read -r dev_driver; do + case "$dev_driver" in + mmcblk) + echo "mmc_block" + ;; + *) + echo "$dev_driver" + ;; + esac + done +} + +# get the corresponding kernel modules of a /sys/class/*/* or/dev/* device +get_dev_module() { + #udevadm info -a "$1" | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' + local dev_attr_walk + local dev_drivers + local dev_paths + dev_attr_walk=$(udevadm info -a "$1") + dev_drivers=$(echo "$dev_attr_walk" \ + | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' \ + | get_module_name) + + # also return modalias info from sysfs paths parsed by udevadm + dev_paths=$(echo "$dev_attr_walk" | sed -n 's/.*\(\/devices\/.*\)'\'':/\1/p') + local dev_path + for dev_path in $dev_paths; do + local modalias_file="/sys$dev_path/modalias" + if [ -e "$modalias_file" ]; then + dev_drivers="$(printf "%s\n%s" "$dev_drivers" "$(cat "$modalias_file")")" + fi + done + + # if no kernel modules found and device is in a virtual subsystem, follow symlinks + if [[ -z $dev_drivers && $(udevadm info -q path "$1") == "/devices/virtual"* ]]; then + local dev_vkernel + local dev_vsubsystem + local dev_vpath + dev_vkernel=$(echo "$dev_attr_walk" | sed -n 's/\s*KERNELS=="\(\S\+\)"/\1/p' | tail -1) + dev_vsubsystem=$(echo "$dev_attr_walk" | sed -n 's/\s*SUBSYSTEMS=="\(\S\+\)"/\1/p' | tail -1) + dev_vpath="/sys/devices/virtual/$dev_vsubsystem/$dev_vkernel" + if [[ -n $dev_vkernel && -n $dev_vsubsystem && -d $dev_vpath ]]; then + local dev_links + local dev_link + dev_links=$(find "$dev_vpath" -maxdepth 1 -type l ! -name "subsystem" -exec readlink {} \;) + for dev_link in $dev_links; do + [[ -n $dev_drivers && ${dev_drivers: -1} != $'\n' ]] && dev_drivers+=$'\n' + dev_drivers+=$(udevadm info -a "$dev_vpath/$dev_link" \ + | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' \ + | get_module_name \ + | grep -v -e pcieport) + done + fi + fi + echo "$dev_drivers" +} diff --git a/dracut-functions.sh b/dracut-functions.sh new file mode 100644 index 0000000..5206bd2 --- /dev/null +++ b/dracut-functions.sh @@ -0,0 +1,928 @@ +#!/bin/bash +# +# functions used by dracut and other tools. +# +# Copyright 2005-2009 Red Hat, Inc. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +export LC_MESSAGES=C + +# is_func +# Check whether $1 is a function. +is_func() { + [[ "$(type -t "$1")" == "function" ]] +} + +# Generic substring function. If $2 is in $1, return 0. +strstr() { [[ $1 == *"$2"* ]]; } +# Generic glob matching function. If glob pattern $2 matches anywhere in $1, OK +strglobin() { [[ $1 == *$2* ]]; } +# Generic glob matching function. If glob pattern $2 matches all of $1, OK +# shellcheck disable=SC2053 +strglob() { [[ $1 == $2 ]]; } +# returns OK if $1 contains literal string $2 at the beginning, and isn't empty +str_starts() { [ "${1#"$2"*}" != "$1" ]; } +# returns OK if $1 contains literal string $2 at the end, and isn't empty +str_ends() { [ "${1%*"$2"}" != "$1" ]; } + +# find a binary. If we were not passed the full path directly, +# search in the usual places to find the binary. +find_binary() { + local _delim + local _path + local l + local p + [[ -z ${1##/*} ]] || _delim="/" + + if [[ $1 == *.so* ]]; then + # shellcheck disable=SC2154 + for l in $libdirs; do + _path="${l}${_delim}${1}" + if { $DRACUT_LDD "${dracutsysrootdir}${_path}" &> /dev/null; }; then + printf "%s\n" "${_path}" + return 0 + fi + done + _path="${_delim}${1}" + if { $DRACUT_LDD "${dracutsysrootdir}${_path}" &> /dev/null; }; then + printf "%s\n" "${_path}" + return 0 + fi + fi + if [[ $1 == */* ]]; then + _path="${_delim}${1}" + if [[ -L ${dracutsysrootdir}${_path} ]] || [[ -x ${dracutsysrootdir}${_path} ]]; then + printf "%s\n" "${_path}" + return 0 + fi + fi + for p in $DRACUT_PATH; do + _path="${p}${_delim}${1}" + if [[ -L ${dracutsysrootdir}${_path} ]] || [[ -x ${dracutsysrootdir}${_path} ]]; then + printf "%s\n" "${_path}" + return 0 + fi + done + + [[ -n $dracutsysrootdir ]] && return 1 + type -P "${1##*/}" +} + +ldconfig_paths() { + $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 +} + +# Version comparision function. Assumes Linux style version scheme. +# $1 = version a +# $2 = comparision op (gt, ge, eq, le, lt, ne) +# $3 = version b +vercmp() { + local _n1 + read -r -a _n1 <<< "${1//./ }" + local _op=$2 + local _n2 + read -r -a _n2 <<< "${3//./ }" + local _i _res + + for ((_i = 0; ; _i++)); do + if [[ ! ${_n1[_i]}${_n2[_i]} ]]; then + _res=0 + elif ((${_n1[_i]:-0} > ${_n2[_i]:-0})); then + _res=1 + elif ((${_n1[_i]:-0} < ${_n2[_i]:-0})); then + _res=2 + else + continue + fi + break + done + + case $_op in + gt) ((_res == 1)) ;; + ge) ((_res != 2)) ;; + eq) ((_res == 0)) ;; + le) ((_res != 1)) ;; + lt) ((_res == 2)) ;; + ne) ((_res != 0)) ;; + esac +} + +# Create all subdirectories for given path without creating the last element. +# $1 = path +mksubdirs() { + # shellcheck disable=SC2174 + [[ -e ${1%/*} ]] || mkdir -m 0755 -p -- "${1%/*}" +} + +# Function prints global variables in format name=value line by line. +# $@ = list of global variables' name +print_vars() { + local _var _value + + for _var in "$@"; do + eval printf -v _value "%s" \""\$$_var"\" + [[ ${_value} ]] && printf '%s="%s"\n' "$_var" "$_value" + done +} + +# normalize_path +# Prints the normalized path, where it removes any duplicated +# and trailing slashes. +# Example: +# $ normalize_path ///test/test// +# /test/test +normalize_path() { + # shellcheck disable=SC2064 + trap "$(shopt -p extglob)" RETURN + shopt -q -s extglob + local p=${1//+(\/)//} + printf "%s\n" "${p%/}" +} + +# convert_abs_rel +# Prints the relative path, when creating a symlink to from . +# Example: +# $ convert_abs_rel /usr/bin/test /bin/test-2 +# ../../bin/test-2 +# $ ln -s $(convert_abs_rel /usr/bin/test /bin/test-2) /usr/bin/test +convert_abs_rel() { + local __current __absolute __abssize __cursize __newpath + local -i __i __level + + set -- "$(normalize_path "$1")" "$(normalize_path "$2")" + + # corner case #1 - self looping link + [[ $1 == "$2" ]] && { + printf "%s\n" "${1##*/}" + return + } + + # corner case #2 - own dir link + [[ ${1%/*} == "$2" ]] && { + printf ".\n" + return + } + + IFS=/ read -r -a __current <<< "$1" + IFS=/ read -r -a __absolute <<< "$2" + + __abssize=${#__absolute[@]} + __cursize=${#__current[@]} + + while [[ ${__absolute[__level]} == "${__current[__level]}" ]]; do + ((__level++)) + if ((__level > __abssize || __level > __cursize)); then + break + fi + done + + for ((__i = __level; __i < __cursize - 1; __i++)); do + if ((__i > __level)); then + __newpath=$__newpath"/" + fi + __newpath=$__newpath".." + done + + for ((__i = __level; __i < __abssize; __i++)); do + if [[ -n $__newpath ]]; then + __newpath=$__newpath"/" + fi + __newpath=$__newpath${__absolute[__i]} + done + + printf -- "%s\n" "$__newpath" +} + +# get_fs_env +# Get and the ID_FS_TYPE variable from udev for a device. +# Example: +# $ get_fs_env /dev/sda2 +# ext4 +get_fs_env() { + [[ $1 ]] || return + unset ID_FS_TYPE + ID_FS_TYPE=$(blkid -u filesystem -o export -- "$1" \ + | while read -r line || [ -n "$line" ]; do + if [[ $line == "TYPE="* ]]; then + printf "%s" "${line#TYPE=}" + exit 0 + fi + done) + if [[ $ID_FS_TYPE ]]; then + printf "%s" "$ID_FS_TYPE" + return 0 + fi + return 1 +} + +# get_maj_min +# Prints the major and minor of a device node. +# Example: +# $ get_maj_min /dev/sda2 +# 8:2 +get_maj_min() { + local _majmin + local _out + + if [[ $get_maj_min_cache_file ]]; then + _out="$(grep -m1 -oP "^$1 \K\S+$" "$get_maj_min_cache_file")" + fi + + if ! [[ "$_out" ]]; then + _majmin="$(stat -L -c '%t:%T' "$1" 2> /dev/null)" + _out="$(printf "%s" "$((0x${_majmin%:*})):$((0x${_majmin#*:}))")" + if [[ $get_maj_min_cache_file ]]; then + echo "$1 $_out" >> "$get_maj_min_cache_file" + fi + fi + echo -n "$_out" +} + +# get_devpath_block +# get the DEVPATH in /sys of a block device +get_devpath_block() { + local _majmin _i + _majmin=$(get_maj_min "$1") + + for _i in /sys/block/*/dev /sys/block/*/*/dev; do + [[ -e $_i ]] || continue + if [[ $_majmin == "$(< "$_i")" ]]; then + printf "%s" "${_i%/dev}" + return 0 + fi + done + return 1 +} + +# get a persistent path from a device +get_persistent_dev() { + local i _tmp _dev _pol + + _dev=$(get_maj_min "$1") + [ -z "$_dev" ] && return + + if [[ -n $persistent_policy ]]; then + _pol="/dev/disk/${persistent_policy}/*" + else + _pol= + fi + + for i in \ + $_pol \ + /dev/mapper/* \ + /dev/disk/by-uuid/* \ + /dev/disk/by-label/* \ + /dev/disk/by-partuuid/* \ + /dev/disk/by-partlabel/* \ + /dev/disk/by-id/* \ + /dev/disk/by-path/*; do + [[ -e $i ]] || continue + [[ $i == /dev/mapper/control ]] && continue + [[ $i == /dev/mapper/mpath* ]] && continue + _tmp=$(get_maj_min "$i") + if [ "$_tmp" = "$_dev" ]; then + printf -- "%s" "$i" + return + fi + done + printf -- "%s" "$1" +} + +expand_persistent_dev() { + local _dev=$1 + + case "$_dev" in + LABEL=*) + _dev="/dev/disk/by-label/${_dev#LABEL=}" + ;; + UUID=*) + _dev="${_dev#UUID=}" + _dev="${_dev,,}" + _dev="/dev/disk/by-uuid/${_dev}" + ;; + PARTUUID=*) + _dev="${_dev#PARTUUID=}" + _dev="${_dev,,}" + _dev="/dev/disk/by-partuuid/${_dev}" + ;; + PARTLABEL=*) + _dev="/dev/disk/by-partlabel/${_dev#PARTLABEL=}" + ;; + esac + printf "%s" "$_dev" +} + +shorten_persistent_dev() { + local _dev="$1" + case "$_dev" in + /dev/disk/by-uuid/*) + printf "%s" "UUID=${_dev##*/}" + ;; + /dev/disk/by-label/*) + printf "%s" "LABEL=${_dev##*/}" + ;; + /dev/disk/by-partuuid/*) + printf "%s" "PARTUUID=${_dev##*/}" + ;; + /dev/disk/by-partlabel/*) + printf "%s" "PARTLABEL=${_dev##*/}" + ;; + *) + printf "%s" "$_dev" + ;; + esac +} + +# find_block_device +# Prints the major and minor number of the block device +# for a given mountpoint. +# Unless $use_fstab is set to "yes" the functions +# uses /proc/self/mountinfo as the primary source of the +# information and only falls back to /etc/fstab, if the mountpoint +# is not found there. +# Example: +# $ find_block_device /usr +# 8:4 +find_block_device() { + local _dev _majmin _find_mpt + _find_mpt="$1" + + if [[ $use_fstab != yes ]]; then + [[ -d $_find_mpt/. ]] + findmnt -e -v -n -o 'MAJ:MIN,SOURCE' --target "$_find_mpt" | { + while read -r _majmin _dev || [ -n "$_dev" ]; do + if [[ -b $_dev ]]; then + if ! [[ $_majmin ]] || [[ $_majmin == 0:* ]]; then + _majmin=$(get_maj_min "$_dev") + fi + if [[ $_majmin ]]; then + printf "%s\n" "$_majmin" + else + printf "%s\n" "$_dev" + fi + return 0 + fi + if [[ $_dev == *:* ]]; then + printf "%s\n" "$_dev" + return 0 + fi + done + return 1 + } && return 0 + fi + # fall back to /etc/fstab + + findmnt -e --fstab -v -n -o 'MAJ:MIN,SOURCE' --target "$_find_mpt" | { + while read -r _majmin _dev || [ -n "$_dev" ]; do + if ! [[ $_dev ]]; then + _dev="$_majmin" + unset _majmin + fi + if [[ -b $_dev ]]; then + [[ $_majmin ]] || _majmin=$(get_maj_min "$_dev") + if [[ $_majmin ]]; then + printf "%s\n" "$_majmin" + else + printf "%s\n" "$_dev" + fi + return 0 + fi + if [[ $_dev == *:* ]]; then + printf "%s\n" "$_dev" + return 0 + fi + done + return 1 + } && return 0 + + return 1 +} + +# find_mp_fstype +# Echo the filesystem type for a given mountpoint. +# /proc/self/mountinfo is taken as the primary source of information +# and /etc/fstab is used as a fallback. +# No newline is appended! +# Example: +# $ find_mp_fstype /;echo +# ext4 +find_mp_fstype() { + local _fs + + if [[ $use_fstab != yes ]]; then + findmnt -e -v -n -o 'FSTYPE' --target "$1" | { + while read -r _fs || [ -n "$_fs" ]; do + [[ $_fs ]] || continue + [[ $_fs == "autofs" ]] && continue + printf "%s" "$_fs" + return 0 + done + return 1 + } && return 0 + fi + + findmnt --fstab -e -v -n -o 'FSTYPE' --target "$1" | { + while read -r _fs || [ -n "$_fs" ]; do + [[ $_fs ]] || continue + [[ $_fs == "autofs" ]] && continue + printf "%s" "$_fs" + return 0 + done + return 1 + } && return 0 + + return 1 +} + +# find_dev_fstype +# Echo the filesystem type for a given device. +# /proc/self/mountinfo is taken as the primary source of information +# and /etc/fstab is used as a fallback. +# No newline is appended! +# Example: +# $ find_dev_fstype /dev/sda2;echo +# ext4 +find_dev_fstype() { + local _find_dev _fs + _find_dev="$1" + if ! [[ $_find_dev == /dev* ]]; then + [[ -b "/dev/block/$_find_dev" ]] && _find_dev="/dev/block/$_find_dev" + fi + + if [[ $use_fstab != yes ]]; then + findmnt -e -v -n -o 'FSTYPE' --source "$_find_dev" | { + while read -r _fs || [ -n "$_fs" ]; do + [[ $_fs ]] || continue + [[ $_fs == "autofs" ]] && continue + printf "%s" "$_fs" + return 0 + done + return 1 + } && return 0 + fi + + findmnt --fstab -e -v -n -o 'FSTYPE' --source "$_find_dev" | { + while read -r _fs || [ -n "$_fs" ]; do + [[ $_fs ]] || continue + [[ $_fs == "autofs" ]] && continue + printf "%s" "$_fs" + return 0 + done + return 1 + } && return 0 + + return 1 +} + +# find_mp_fsopts +# Echo the filesystem options for a given mountpoint. +# /proc/self/mountinfo is taken as the primary source of information +# and /etc/fstab is used as a fallback. +# No newline is appended! +# Example: +# $ find_mp_fsopts /;echo +# rw,relatime,discard,data=ordered +find_mp_fsopts() { + if [[ $use_fstab != yes ]]; then + findmnt -e -v -n -o 'OPTIONS' --target "$1" 2> /dev/null && return 0 + fi + + findmnt --fstab -e -v -n -o 'OPTIONS' --target "$1" +} + +# find_dev_fsopts +# Echo the filesystem options for a given device. +# /proc/self/mountinfo is taken as the primary source of information +# and /etc/fstab is used as a fallback. +# if `use_fstab == yes`, then only `/etc/fstab` is used. +# +# Example: +# $ find_dev_fsopts /dev/sda2 +# rw,relatime,discard,data=ordered +find_dev_fsopts() { + local _find_dev + _find_dev="$1" + if ! [[ $_find_dev == /dev* ]]; then + [[ -b "/dev/block/$_find_dev" ]] && _find_dev="/dev/block/$_find_dev" + fi + + if [[ $use_fstab != yes ]]; then + findmnt -e -v -n -o 'OPTIONS' --source "$_find_dev" 2> /dev/null && return 0 + fi + + findmnt --fstab -e -v -n -o 'OPTIONS' --source "$_find_dev" +} + +# finds the major:minor of the block device backing the root filesystem. +find_root_block_device() { find_block_device /; } + +# for_each_host_dev_fs +# Execute " " for every " " pair found +# in ${host_fs_types[@]} +for_each_host_dev_fs() { + local _func="$1" + local _dev + local _ret=1 + + [[ "${#host_fs_types[@]}" ]] || return 2 + + for _dev in "${!host_fs_types[@]}"; do + $_func "$_dev" "${host_fs_types[$_dev]}" && _ret=0 + done + return $_ret +} + +host_fs_all() { + printf "%s\n" "${host_fs_types[@]}" +} + +# Walk all the slave relationships for a given block device. +# Stop when our helper function returns success +# $1 = function to call on every found block device +# $2 = block device in major:minor format +check_block_and_slaves() { + local _x + [[ -b /dev/block/$2 ]] || return 1 # Not a block device? So sorry. + if ! lvm_internal_dev "$2"; then "$1" "$2" && return; fi + check_vol_slaves "$@" && return 0 + if [[ -f /sys/dev/block/$2/../dev ]] && [[ /sys/dev/block/$2/../subsystem -ef /sys/class/block ]]; then + check_block_and_slaves "$1" "$(< "/sys/dev/block/$2/../dev")" && return 0 + fi + for _x in /sys/dev/block/"$2"/slaves/*; do + [[ -f $_x/dev ]] || continue + [[ $_x/subsystem -ef /sys/class/block ]] || continue + check_block_and_slaves "$1" "$(< "$_x/dev")" && return 0 + done + return 1 +} + +check_block_and_slaves_all() { + local _x _ret=1 + [[ -b /dev/block/$2 ]] || return 1 # Not a block device? So sorry. + if ! lvm_internal_dev "$2" && "$1" "$2"; then + _ret=0 + fi + check_vol_slaves_all "$@" && return 0 + if [[ -f /sys/dev/block/$2/../dev ]] && [[ /sys/dev/block/$2/../subsystem -ef /sys/class/block ]]; then + check_block_and_slaves_all "$1" "$(< "/sys/dev/block/$2/../dev")" && _ret=0 + fi + for _x in /sys/dev/block/"$2"/slaves/*; do + [[ -f $_x/dev ]] || continue + [[ $_x/subsystem -ef /sys/class/block ]] || continue + check_block_and_slaves_all "$1" "$(< "$_x/dev")" && _ret=0 + done + return $_ret +} +# for_each_host_dev_and_slaves +# Execute " " for every "" found +# in ${host_devs[@]} and their slaves +for_each_host_dev_and_slaves_all() { + local _func="$1" + local _dev + local _ret=1 + + [[ "${host_devs[*]}" ]] || return 2 + + for _dev in "${host_devs[@]}"; do + [[ -b $_dev ]] || continue + if check_block_and_slaves_all "$_func" "$(get_maj_min "$_dev")"; then + _ret=0 + fi + done + return $_ret +} + +for_each_host_dev_and_slaves() { + local _func="$1" + local _dev + + [[ "${host_devs[*]}" ]] || return 2 + + for _dev in "${host_devs[@]}"; do + [[ -b $_dev ]] || continue + check_block_and_slaves "$_func" "$(get_maj_min "$_dev")" && return 0 + done + return 1 +} + +# ugly workaround for the lvm design +# There is no volume group device, +# so, there are no slave devices for volume groups. +# Logical volumes only have the slave devices they really live on, +# but you cannot create the logical volume without the volume group. +# And the volume group might be bigger than the devices the LV needs. +check_vol_slaves() { + local _vg _pv _dm _majmin + _majmin="$2" + _dm=/sys/dev/block/$_majmin/dm + [[ -f $_dm/uuid && $(< "$_dm"/uuid) =~ LVM-* ]] || return 1 + _vg=$(dmsetup splitname --noheadings -o vg_name "$(< "$_dm/name")") + # strip space + _vg="${_vg//[[:space:]]/}" + if [[ $_vg ]]; then + for _pv in $(lvm vgs --noheadings -o pv_name "$_vg" 2> /dev/null); do + check_block_and_slaves "$1" "$(get_maj_min "$_pv")" && return 0 + done + fi + return 1 +} + +check_vol_slaves_all() { + local _vg _pv _majmin + _majmin="$2" + _dm="/sys/dev/block/$_majmin/dm" + [[ -f $_dm/uuid && $(< "$_dm"/uuid) =~ LVM-* ]] || return 1 + _vg=$(dmsetup splitname --noheadings -o vg_name "$(< "$_dm/name")") + # strip space + _vg="${_vg//[[:space:]]/}" + if [[ $_vg ]]; then + # when filter/global_filter is set, lvm may be failed + if ! lvm lvs --noheadings -o vg_name "$_vg" 2> /dev/null 1> /dev/null; then + return 1 + fi + + for _pv in $(lvm vgs --noheadings -o pv_name "$_vg" 2> /dev/null); do + check_block_and_slaves_all "$1" "$(get_maj_min "$_pv")" + done + return 0 + fi + return 1 +} + +# fs_get_option +# search for a specific option in a bunch of filesystem options +# and return the value +fs_get_option() { + local _fsopts=$1 + local _option=$2 + local OLDIFS="$IFS" + IFS=, + # shellcheck disable=SC2086 + set -- $_fsopts + IFS="$OLDIFS" + while [ $# -gt 0 ]; do + case $1 in + $_option=*) + echo "${1#${_option}=}" + break + ;; + esac + shift + done +} + +check_kernel_config() { + local _config_opt="$1" + local _config_file + [[ -f $dracutsysrootdir/boot/config-$kernel ]] \ + && _config_file="/boot/config-$kernel" + [[ -f $dracutsysrootdir/lib/modules/$kernel/config ]] \ + && _config_file="/lib/modules/$kernel/config" + + # no kernel config file, so return true + [[ $_config_file ]] || return 0 + + grep -q -F "${_config_opt}=" "$dracutsysrootdir$_config_file" && return 0 + return 1 +} + +# 0 if the kernel module is either built-in or available +# 1 if the kernel module is not enabled +check_kernel_module() { + modprobe -S "$kernel" --dry-run "$1" &> /dev/null || return 1 +} + +# get_cpu_vendor +# Only two values are returned: AMD or Intel +get_cpu_vendor() { + if grep -qE AMD /proc/cpuinfo; then + printf "AMD" + fi + if grep -qE Intel /proc/cpuinfo; then + printf "Intel" + fi +} + +# get_host_ucode +# Get the hosts' ucode file based on the /proc/cpuinfo +get_ucode_file() { + local family + local model + local stepping + family=$(grep -E "cpu family" /proc/cpuinfo | head -1 | sed "s/.*:\ //") + model=$(grep -E "model" /proc/cpuinfo | grep -v name | head -1 | sed "s/.*:\ //") + stepping=$(grep -E "stepping" /proc/cpuinfo | head -1 | sed "s/.*:\ //") + + if [[ "$(get_cpu_vendor)" == "AMD" ]]; then + if [[ $family -ge 21 ]]; then + printf "microcode_amd_fam%xh.bin" "$family" + else + printf "microcode_amd.bin" + fi + fi + if [[ "$(get_cpu_vendor)" == "Intel" ]]; then + # The /proc/cpuinfo are in decimal. + printf "%02x-%02x-%02x" "${family}" "${model}" "${stepping}" + fi +} + +# Not every device in /dev/mapper should be examined. +# If it is an LVM device, touch only devices which have /dev/VG/LV symlink. +lvm_internal_dev() { + local dev_dm_dir=/sys/dev/block/$1/dm + [[ ! -f $dev_dm_dir/uuid || $(< "$dev_dm_dir"/uuid) != LVM-* ]] && return 1 # Not an LVM device + local DM_VG_NAME DM_LV_NAME DM_LV_LAYER + eval "$(dmsetup splitname --nameprefixes --noheadings --rows "$(< "$dev_dm_dir"/name)" 2> /dev/null)" + [[ ${DM_VG_NAME} ]] && [[ ${DM_LV_NAME} ]] || return 0 # Better skip this! + [[ ${DM_LV_LAYER} ]] || [[ ! -L /dev/${DM_VG_NAME}/${DM_LV_NAME} ]] +} + +btrfs_devs() { + local _mp="$1" + btrfs device usage "$_mp" \ + | while read -r _dev _; do + str_starts "$_dev" "/" || continue + _dev=${_dev%,} + printf -- "%s\n" "$_dev" + done +} + +iface_for_remote_addr() { + # shellcheck disable=SC2046 + set -- $(ip -o route get to "$1") + echo "$3" +} + +local_addr_for_remote_addr() { + # shellcheck disable=SC2046 + set -- $(ip -o route get to "$1") + echo "$5" +} + +peer_for_addr() { + local addr=$1 + local qtd + + # quote periods in IPv4 address + qtd=${addr//./\\.} + ip -o addr show \ + | sed -n 's%^.* '"$qtd"' peer \([0-9a-f.:]\{1,\}\(/[0-9]*\)\?\).*$%\1%p' +} + +netmask_for_addr() { + local addr=$1 + local qtd + + # quote periods in IPv4 address + qtd=${addr//./\\.} + ip -o addr show | sed -n 's,^.* '"$qtd"'/\([0-9]*\) .*$,\1,p' +} + +gateway_for_iface() { + local ifname=$1 addr=$2 + + case $addr in + *.*) proto=4 ;; + *:*) proto=6 ;; + *) return ;; + esac + ip -o -$proto route show \ + | sed -n "s/^default via \([0-9a-z.:]\{1,\}\) dev $ifname .*\$/\1/p" +} + +# This works only for ifcfg-style network configuration! +bootproto_for_iface() { + local ifname=$1 + local dir + + # follow ifcfg settings for boot protocol + for dir in network-scripts network; do + [ -f "/etc/sysconfig/$dir/ifcfg-$ifname" ] && { + sed -n "s/BOOTPROTO=[\"']\?\([[:alnum:]]\{1,\}\)[\"']\?.*\$/\1/p" \ + "/etc/sysconfig/$dir/ifcfg-$ifname" + return + } + done +} + +is_unbracketed_ipv6_address() { + strglob "$1" '*:*' && ! strglob "$1" '\[*:*\]' +} + +# Create an ip= string to set up networking such that the given +# remote address can be reached +ip_params_for_remote_addr() { + local remote_addr=$1 + local ifname local_addr peer netmask gateway ifmac + + [[ $remote_addr ]] || return 1 + ifname=$(iface_for_remote_addr "$remote_addr") + [[ $ifname ]] || { + berror "failed to determine interface to connect to $remote_addr" + return 1 + } + + # ifname clause to bind the interface name to a MAC address + if [ -d "/sys/class/net/$ifname/bonding" ]; then + dinfo "Found bonded interface '${ifname}'. Make sure to provide an appropriate 'bond=' cmdline." + elif [ -e "/sys/class/net/$ifname/address" ]; then + ifmac=$(cat "/sys/class/net/$ifname/address") + [[ $ifmac ]] && printf 'ifname=%s:%s ' "${ifname}" "${ifmac}" + fi + + bootproto=$(bootproto_for_iface "$ifname") + case $bootproto in + dhcp | dhcp6 | auto6) ;; + dhcp4) + bootproto=dhcp + ;; + static* | "") + bootproto= + ;; + *) + derror "bootproto \"$bootproto\" is unsupported by dracut, trying static configuration" + bootproto= + ;; + esac + if [[ $bootproto ]]; then + printf 'ip=%s:%s ' "${ifname}" "${bootproto}" + else + local_addr=$(local_addr_for_remote_addr "$remote_addr") + [[ $local_addr ]] || { + berror "failed to determine local address to connect to $remote_addr" + return 1 + } + peer=$(peer_for_addr "$local_addr") + # Set peer or netmask, but not both + [[ $peer ]] || netmask=$(netmask_for_addr "$local_addr") + gateway=$(gateway_for_iface "$ifname" "$local_addr") + # Quote IPv6 addresses with brackets + is_unbracketed_ipv6_address "$local_addr" && local_addr="[$local_addr]" + is_unbracketed_ipv6_address "$peer" && peer="[$peer]" + is_unbracketed_ipv6_address "$gateway" && gateway="[$gateway]" + printf 'ip=%s:%s:%s:%s::%s:none ' \ + "${local_addr}" "${peer}" "${gateway}" "${netmask}" "${ifname}" + fi + +} + +# block_is_nbd +# Check whether $1 is an nbd device +block_is_nbd() { + [[ -b /dev/block/$1 && $1 == 43:* ]] +} + +# block_is_iscsi +# Check whether $1 is an nbd device +block_is_iscsi() { + local _dir + local _dev=$1 + [[ -L "/sys/dev/block/$_dev" ]] || return + _dir="$(readlink -f "/sys/dev/block/$_dev")" || return + until [[ -d "$_dir/sys" || -d "$_dir/iscsi_session" ]]; do + _dir="$_dir/.." + done + [[ -d "$_dir/iscsi_session" ]] +} + +# block_is_fcoe +# Check whether $1 is an FCoE device +# Will not work for HBAs that hide the ethernet aspect +# completely and present a pure FC device +block_is_fcoe() { + local _dir + local _dev=$1 + [[ -L "/sys/dev/block/$_dev" ]] || return + _dir="$(readlink -f "/sys/dev/block/$_dev")" + until [[ -d "$_dir/sys" ]]; do + _dir="$_dir/.." + if [[ -d "$_dir/subsystem" ]]; then + subsystem=$(basename "$(readlink "$_dir"/subsystem)") + [[ $subsystem == "fcoe" ]] && return 0 + fi + done + return 1 +} + +# block_is_netdevice +# Check whether $1 is a net device +block_is_netdevice() { + block_is_nbd "$1" || block_is_iscsi "$1" || block_is_fcoe "$1" +} + +# get the corresponding kernel modules of a /sys/class/*/* or/dev/* device +get_dev_module() { + udevadm info -a "$1" | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' +} diff --git a/fix-virture.patch b/fix-virture.patch deleted file mode 100644 index 366136f..0000000 --- a/fix-virture.patch +++ /dev/null @@ -1,66 +0,0 @@ ---- a/dracut-functions.sh 2023-11-01 17:21:34.776084229 +0800 -+++ b/dracut-functions.sh 2023-11-02 10:32:28.810495055 +0800 -@@ -922,7 +922,62 @@ block_is_netdevice() { - block_is_nbd "$1" || block_is_iscsi "$1" || block_is_fcoe "$1" - } - -+# convert the driver name given by udevadm to the corresponding kernel module name -+get_module_name() { -+ local dev_driver -+ while read -r dev_driver; do -+ case "$dev_driver" in -+ mmcblk) -+ echo "mmc_block" -+ ;; -+ *) -+ echo "$dev_driver" -+ ;; -+ esac -+ done -+} -+ - # get the corresponding kernel modules of a /sys/class/*/* or/dev/* device - get_dev_module() { -- udevadm info -a "$1" | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' -+ #udevadm info -a "$1" | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' -+ local dev_attr_walk -+ local dev_drivers -+ local dev_paths -+ dev_attr_walk=$(udevadm info -a "$1") -+ dev_drivers=$(echo "$dev_attr_walk" \ -+ | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' \ -+ | get_module_name) -+ -+ # also return modalias info from sysfs paths parsed by udevadm -+ dev_paths=$(echo "$dev_attr_walk" | sed -n 's/.*\(\/devices\/.*\)'\'':/\1/p') -+ local dev_path -+ for dev_path in $dev_paths; do -+ local modalias_file="/sys$dev_path/modalias" -+ if [ -e "$modalias_file" ]; then -+ dev_drivers="$(printf "%s\n%s" "$dev_drivers" "$(cat "$modalias_file")")" -+ fi -+ done -+ -+ # if no kernel modules found and device is in a virtual subsystem, follow symlinks -+ if [[ -z $dev_drivers && $(udevadm info -q path "$1") == "/devices/virtual"* ]]; then -+ local dev_vkernel -+ local dev_vsubsystem -+ local dev_vpath -+ dev_vkernel=$(echo "$dev_attr_walk" | sed -n 's/\s*KERNELS=="\(\S\+\)"/\1/p' | tail -1) -+ dev_vsubsystem=$(echo "$dev_attr_walk" | sed -n 's/\s*SUBSYSTEMS=="\(\S\+\)"/\1/p' | tail -1) -+ dev_vpath="/sys/devices/virtual/$dev_vsubsystem/$dev_vkernel" -+ if [[ -n $dev_vkernel && -n $dev_vsubsystem && -d $dev_vpath ]]; then -+ local dev_links -+ local dev_link -+ dev_links=$(find "$dev_vpath" -maxdepth 1 -type l ! -name "subsystem" -exec readlink {} \;) -+ for dev_link in $dev_links; do -+ [[ -n $dev_drivers && ${dev_drivers: -1} != $'\n' ]] && dev_drivers+=$'\n' -+ dev_drivers+=$(udevadm info -a "$dev_vpath/$dev_link" \ -+ | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' \ -+ | get_module_name \ -+ | grep -v -e pcieport) -+ done -+ fi -+ fi -+ echo "$dev_drivers" - } -- Gitee From 326e29ffd44eef2f0dc67f16b4075cc8efe23f70 Mon Sep 17 00:00:00 2001 From: "Kang.Yihang" Date: Thu, 2 Nov 2023 14:45:35 +0800 Subject: [PATCH 5/8] =?UTF-8?q?=E6=9A=82=E5=AD=98=E5=88=B0=E6=9C=AC?= =?UTF-8?q?=E5=9C=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dracut-functions.sh | 57 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/dracut-functions.sh b/dracut-functions.sh index 5206bd2..1efad3b 100644 --- a/dracut-functions.sh +++ b/dracut-functions.sh @@ -922,7 +922,62 @@ block_is_netdevice() { block_is_nbd "$1" || block_is_iscsi "$1" || block_is_fcoe "$1" } +# convert the driver name given by udevadm to the corresponding kernel module name +get_module_name() { + local dev_driver + while read -r dev_driver; do + case "$dev_driver" in + mmcblk) + echo "mmc_block" + ;; + *) + echo "$dev_driver" + ;; + esac + done +} + # get the corresponding kernel modules of a /sys/class/*/* or/dev/* device get_dev_module() { - udevadm info -a "$1" | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' + #udevadm info -a "$1" | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' + local dev_attr_walk + local dev_drivers + local dev_paths + dev_attr_walk=$(udevadm info -a "$1") + dev_drivers=$(echo "$dev_attr_walk" \ + | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' \ + | get_module_name) + + # also return modalias info from sysfs paths parsed by udevadm + dev_paths=$(echo "$dev_attr_walk" | sed -n 's/.*\(\/devices\/.*\)'\'':/\1/p') + local dev_path + for dev_path in $dev_paths; do + local modalias_file="/sys$dev_path/modalias" + if [ -e "$modalias_file" ]; then + dev_drivers="$(printf "%s\n%s" "$dev_drivers" "$(cat "$modalias_file")")" + fi + done + + # if no kernel modules found and device is in a virtual subsystem, follow symlinks + if [[ -z $dev_drivers && $(udevadm info -q path "$1") == "/devices/virtual"* ]]; then + local dev_vkernel + local dev_vsubsystem + local dev_vpath + dev_vkernel=$(echo "$dev_attr_walk" | sed -n 's/\s*KERNELS=="\(\S\+\)"/\1/p' | tail -1) + dev_vsubsystem=$(echo "$dev_attr_walk" | sed -n 's/\s*SUBSYSTEMS=="\(\S\+\)"/\1/p' | tail -1) + dev_vpath="/sys/devices/virtual/$dev_vsubsystem/$dev_vkernel" + if [[ -n $dev_vkernel && -n $dev_vsubsystem && -d $dev_vpath ]]; then + local dev_links + local dev_link + dev_links=$(find "$dev_vpath" -maxdepth 1 -type l ! -name "subsystem" -exec readlink {} \;) + for dev_link in $dev_links; do + [[ -n $dev_drivers && ${dev_drivers: -1} != $'\n' ]] && dev_drivers+=$'\n' + dev_drivers+=$(udevadm info -a "$dev_vpath/$dev_link" \ + | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' \ + | get_module_name \ + | grep -v -e pcieport) + done + fi + fi + echo "$dev_drivers" } -- Gitee From 33de215d633517c27909834bbbf766f4988ffff3 Mon Sep 17 00:00:00 2001 From: "Kang.Yihang" Date: Thu, 2 Nov 2023 14:48:22 +0800 Subject: [PATCH 6/8] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E5=88=B0=E6=9C=AC?= =?UTF-8?q?=E5=9C=B0=EF=BC=8C=E6=A0=B9=E6=8D=AEgit=20format-patch=E8=BF=9B?= =?UTF-8?q?=E8=A1=8C=E7=94=9F=E6=88=90patch=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fix-virture.patch | 83 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 fix-virture.patch diff --git a/fix-virture.patch b/fix-virture.patch new file mode 100644 index 0000000..a37e4e2 --- /dev/null +++ b/fix-virture.patch @@ -0,0 +1,83 @@ +From 326e29ffd44eef2f0dc67f16b4075cc8efe23f70 Mon Sep 17 00:00:00 2001 +From: "Kang.Yihang" +Date: Thu, 2 Nov 2023 14:45:35 +0800 +Subject: [PATCH] =?UTF-8?q?=E6=9A=82=E5=AD=98=E5=88=B0=E6=9C=AC=E5=9C=B0?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--- + dracut-functions.sh | 57 ++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 56 insertions(+), 1 deletion(-) + +diff --git a/dracut-functions.sh b/dracut-functions.sh +index 5206bd2..1efad3b 100644 +--- a/dracut-functions.sh ++++ b/dracut-functions.sh +@@ -922,7 +922,62 @@ block_is_netdevice() { + block_is_nbd "$1" || block_is_iscsi "$1" || block_is_fcoe "$1" + } + ++# convert the driver name given by udevadm to the corresponding kernel module name ++get_module_name() { ++ local dev_driver ++ while read -r dev_driver; do ++ case "$dev_driver" in ++ mmcblk) ++ echo "mmc_block" ++ ;; ++ *) ++ echo "$dev_driver" ++ ;; ++ esac ++ done ++} ++ + # get the corresponding kernel modules of a /sys/class/*/* or/dev/* device + get_dev_module() { +- udevadm info -a "$1" | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' ++ #udevadm info -a "$1" | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' ++ local dev_attr_walk ++ local dev_drivers ++ local dev_paths ++ dev_attr_walk=$(udevadm info -a "$1") ++ dev_drivers=$(echo "$dev_attr_walk" \ ++ | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' \ ++ | get_module_name) ++ ++ # also return modalias info from sysfs paths parsed by udevadm ++ dev_paths=$(echo "$dev_attr_walk" | sed -n 's/.*\(\/devices\/.*\)'\'':/\1/p') ++ local dev_path ++ for dev_path in $dev_paths; do ++ local modalias_file="/sys$dev_path/modalias" ++ if [ -e "$modalias_file" ]; then ++ dev_drivers="$(printf "%s\n%s" "$dev_drivers" "$(cat "$modalias_file")")" ++ fi ++ done ++ ++ # if no kernel modules found and device is in a virtual subsystem, follow symlinks ++ if [[ -z $dev_drivers && $(udevadm info -q path "$1") == "/devices/virtual"* ]]; then ++ local dev_vkernel ++ local dev_vsubsystem ++ local dev_vpath ++ dev_vkernel=$(echo "$dev_attr_walk" | sed -n 's/\s*KERNELS=="\(\S\+\)"/\1/p' | tail -1) ++ dev_vsubsystem=$(echo "$dev_attr_walk" | sed -n 's/\s*SUBSYSTEMS=="\(\S\+\)"/\1/p' | tail -1) ++ dev_vpath="/sys/devices/virtual/$dev_vsubsystem/$dev_vkernel" ++ if [[ -n $dev_vkernel && -n $dev_vsubsystem && -d $dev_vpath ]]; then ++ local dev_links ++ local dev_link ++ dev_links=$(find "$dev_vpath" -maxdepth 1 -type l ! -name "subsystem" -exec readlink {} \;) ++ for dev_link in $dev_links; do ++ [[ -n $dev_drivers && ${dev_drivers: -1} != $'\n' ]] && dev_drivers+=$'\n' ++ dev_drivers+=$(udevadm info -a "$dev_vpath/$dev_link" \ ++ | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' \ ++ | get_module_name \ ++ | grep -v -e pcieport) ++ done ++ fi ++ fi ++ echo "$dev_drivers" + } +-- +2.36.1 + -- Gitee From a4f2889e28615a8ae45d6492e5953b6a1f61a363 Mon Sep 17 00:00:00 2001 From: "Kang.Yihang" Date: Thu, 2 Nov 2023 14:49:00 +0800 Subject: [PATCH 7/8] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=9A=82=E6=97=B6?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- a/dracut-functions.sh | 928 --------------------------------------- b/dracut-functions.sh | 983 ------------------------------------------ 2 files changed, 1911 deletions(-) delete mode 100644 a/dracut-functions.sh delete mode 100644 b/dracut-functions.sh diff --git a/a/dracut-functions.sh b/a/dracut-functions.sh deleted file mode 100644 index 5206bd2..0000000 --- a/a/dracut-functions.sh +++ /dev/null @@ -1,928 +0,0 @@ -#!/bin/bash -# -# functions used by dracut and other tools. -# -# Copyright 2005-2009 Red Hat, Inc. All rights reserved. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -export LC_MESSAGES=C - -# is_func -# Check whether $1 is a function. -is_func() { - [[ "$(type -t "$1")" == "function" ]] -} - -# Generic substring function. If $2 is in $1, return 0. -strstr() { [[ $1 == *"$2"* ]]; } -# Generic glob matching function. If glob pattern $2 matches anywhere in $1, OK -strglobin() { [[ $1 == *$2* ]]; } -# Generic glob matching function. If glob pattern $2 matches all of $1, OK -# shellcheck disable=SC2053 -strglob() { [[ $1 == $2 ]]; } -# returns OK if $1 contains literal string $2 at the beginning, and isn't empty -str_starts() { [ "${1#"$2"*}" != "$1" ]; } -# returns OK if $1 contains literal string $2 at the end, and isn't empty -str_ends() { [ "${1%*"$2"}" != "$1" ]; } - -# find a binary. If we were not passed the full path directly, -# search in the usual places to find the binary. -find_binary() { - local _delim - local _path - local l - local p - [[ -z ${1##/*} ]] || _delim="/" - - if [[ $1 == *.so* ]]; then - # shellcheck disable=SC2154 - for l in $libdirs; do - _path="${l}${_delim}${1}" - if { $DRACUT_LDD "${dracutsysrootdir}${_path}" &> /dev/null; }; then - printf "%s\n" "${_path}" - return 0 - fi - done - _path="${_delim}${1}" - if { $DRACUT_LDD "${dracutsysrootdir}${_path}" &> /dev/null; }; then - printf "%s\n" "${_path}" - return 0 - fi - fi - if [[ $1 == */* ]]; then - _path="${_delim}${1}" - if [[ -L ${dracutsysrootdir}${_path} ]] || [[ -x ${dracutsysrootdir}${_path} ]]; then - printf "%s\n" "${_path}" - return 0 - fi - fi - for p in $DRACUT_PATH; do - _path="${p}${_delim}${1}" - if [[ -L ${dracutsysrootdir}${_path} ]] || [[ -x ${dracutsysrootdir}${_path} ]]; then - printf "%s\n" "${_path}" - return 0 - fi - done - - [[ -n $dracutsysrootdir ]] && return 1 - type -P "${1##*/}" -} - -ldconfig_paths() { - $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 -} - -# Version comparision function. Assumes Linux style version scheme. -# $1 = version a -# $2 = comparision op (gt, ge, eq, le, lt, ne) -# $3 = version b -vercmp() { - local _n1 - read -r -a _n1 <<< "${1//./ }" - local _op=$2 - local _n2 - read -r -a _n2 <<< "${3//./ }" - local _i _res - - for ((_i = 0; ; _i++)); do - if [[ ! ${_n1[_i]}${_n2[_i]} ]]; then - _res=0 - elif ((${_n1[_i]:-0} > ${_n2[_i]:-0})); then - _res=1 - elif ((${_n1[_i]:-0} < ${_n2[_i]:-0})); then - _res=2 - else - continue - fi - break - done - - case $_op in - gt) ((_res == 1)) ;; - ge) ((_res != 2)) ;; - eq) ((_res == 0)) ;; - le) ((_res != 1)) ;; - lt) ((_res == 2)) ;; - ne) ((_res != 0)) ;; - esac -} - -# Create all subdirectories for given path without creating the last element. -# $1 = path -mksubdirs() { - # shellcheck disable=SC2174 - [[ -e ${1%/*} ]] || mkdir -m 0755 -p -- "${1%/*}" -} - -# Function prints global variables in format name=value line by line. -# $@ = list of global variables' name -print_vars() { - local _var _value - - for _var in "$@"; do - eval printf -v _value "%s" \""\$$_var"\" - [[ ${_value} ]] && printf '%s="%s"\n' "$_var" "$_value" - done -} - -# normalize_path -# Prints the normalized path, where it removes any duplicated -# and trailing slashes. -# Example: -# $ normalize_path ///test/test// -# /test/test -normalize_path() { - # shellcheck disable=SC2064 - trap "$(shopt -p extglob)" RETURN - shopt -q -s extglob - local p=${1//+(\/)//} - printf "%s\n" "${p%/}" -} - -# convert_abs_rel -# Prints the relative path, when creating a symlink to from . -# Example: -# $ convert_abs_rel /usr/bin/test /bin/test-2 -# ../../bin/test-2 -# $ ln -s $(convert_abs_rel /usr/bin/test /bin/test-2) /usr/bin/test -convert_abs_rel() { - local __current __absolute __abssize __cursize __newpath - local -i __i __level - - set -- "$(normalize_path "$1")" "$(normalize_path "$2")" - - # corner case #1 - self looping link - [[ $1 == "$2" ]] && { - printf "%s\n" "${1##*/}" - return - } - - # corner case #2 - own dir link - [[ ${1%/*} == "$2" ]] && { - printf ".\n" - return - } - - IFS=/ read -r -a __current <<< "$1" - IFS=/ read -r -a __absolute <<< "$2" - - __abssize=${#__absolute[@]} - __cursize=${#__current[@]} - - while [[ ${__absolute[__level]} == "${__current[__level]}" ]]; do - ((__level++)) - if ((__level > __abssize || __level > __cursize)); then - break - fi - done - - for ((__i = __level; __i < __cursize - 1; __i++)); do - if ((__i > __level)); then - __newpath=$__newpath"/" - fi - __newpath=$__newpath".." - done - - for ((__i = __level; __i < __abssize; __i++)); do - if [[ -n $__newpath ]]; then - __newpath=$__newpath"/" - fi - __newpath=$__newpath${__absolute[__i]} - done - - printf -- "%s\n" "$__newpath" -} - -# get_fs_env -# Get and the ID_FS_TYPE variable from udev for a device. -# Example: -# $ get_fs_env /dev/sda2 -# ext4 -get_fs_env() { - [[ $1 ]] || return - unset ID_FS_TYPE - ID_FS_TYPE=$(blkid -u filesystem -o export -- "$1" \ - | while read -r line || [ -n "$line" ]; do - if [[ $line == "TYPE="* ]]; then - printf "%s" "${line#TYPE=}" - exit 0 - fi - done) - if [[ $ID_FS_TYPE ]]; then - printf "%s" "$ID_FS_TYPE" - return 0 - fi - return 1 -} - -# get_maj_min -# Prints the major and minor of a device node. -# Example: -# $ get_maj_min /dev/sda2 -# 8:2 -get_maj_min() { - local _majmin - local _out - - if [[ $get_maj_min_cache_file ]]; then - _out="$(grep -m1 -oP "^$1 \K\S+$" "$get_maj_min_cache_file")" - fi - - if ! [[ "$_out" ]]; then - _majmin="$(stat -L -c '%t:%T' "$1" 2> /dev/null)" - _out="$(printf "%s" "$((0x${_majmin%:*})):$((0x${_majmin#*:}))")" - if [[ $get_maj_min_cache_file ]]; then - echo "$1 $_out" >> "$get_maj_min_cache_file" - fi - fi - echo -n "$_out" -} - -# get_devpath_block -# get the DEVPATH in /sys of a block device -get_devpath_block() { - local _majmin _i - _majmin=$(get_maj_min "$1") - - for _i in /sys/block/*/dev /sys/block/*/*/dev; do - [[ -e $_i ]] || continue - if [[ $_majmin == "$(< "$_i")" ]]; then - printf "%s" "${_i%/dev}" - return 0 - fi - done - return 1 -} - -# get a persistent path from a device -get_persistent_dev() { - local i _tmp _dev _pol - - _dev=$(get_maj_min "$1") - [ -z "$_dev" ] && return - - if [[ -n $persistent_policy ]]; then - _pol="/dev/disk/${persistent_policy}/*" - else - _pol= - fi - - for i in \ - $_pol \ - /dev/mapper/* \ - /dev/disk/by-uuid/* \ - /dev/disk/by-label/* \ - /dev/disk/by-partuuid/* \ - /dev/disk/by-partlabel/* \ - /dev/disk/by-id/* \ - /dev/disk/by-path/*; do - [[ -e $i ]] || continue - [[ $i == /dev/mapper/control ]] && continue - [[ $i == /dev/mapper/mpath* ]] && continue - _tmp=$(get_maj_min "$i") - if [ "$_tmp" = "$_dev" ]; then - printf -- "%s" "$i" - return - fi - done - printf -- "%s" "$1" -} - -expand_persistent_dev() { - local _dev=$1 - - case "$_dev" in - LABEL=*) - _dev="/dev/disk/by-label/${_dev#LABEL=}" - ;; - UUID=*) - _dev="${_dev#UUID=}" - _dev="${_dev,,}" - _dev="/dev/disk/by-uuid/${_dev}" - ;; - PARTUUID=*) - _dev="${_dev#PARTUUID=}" - _dev="${_dev,,}" - _dev="/dev/disk/by-partuuid/${_dev}" - ;; - PARTLABEL=*) - _dev="/dev/disk/by-partlabel/${_dev#PARTLABEL=}" - ;; - esac - printf "%s" "$_dev" -} - -shorten_persistent_dev() { - local _dev="$1" - case "$_dev" in - /dev/disk/by-uuid/*) - printf "%s" "UUID=${_dev##*/}" - ;; - /dev/disk/by-label/*) - printf "%s" "LABEL=${_dev##*/}" - ;; - /dev/disk/by-partuuid/*) - printf "%s" "PARTUUID=${_dev##*/}" - ;; - /dev/disk/by-partlabel/*) - printf "%s" "PARTLABEL=${_dev##*/}" - ;; - *) - printf "%s" "$_dev" - ;; - esac -} - -# find_block_device -# Prints the major and minor number of the block device -# for a given mountpoint. -# Unless $use_fstab is set to "yes" the functions -# uses /proc/self/mountinfo as the primary source of the -# information and only falls back to /etc/fstab, if the mountpoint -# is not found there. -# Example: -# $ find_block_device /usr -# 8:4 -find_block_device() { - local _dev _majmin _find_mpt - _find_mpt="$1" - - if [[ $use_fstab != yes ]]; then - [[ -d $_find_mpt/. ]] - findmnt -e -v -n -o 'MAJ:MIN,SOURCE' --target "$_find_mpt" | { - while read -r _majmin _dev || [ -n "$_dev" ]; do - if [[ -b $_dev ]]; then - if ! [[ $_majmin ]] || [[ $_majmin == 0:* ]]; then - _majmin=$(get_maj_min "$_dev") - fi - if [[ $_majmin ]]; then - printf "%s\n" "$_majmin" - else - printf "%s\n" "$_dev" - fi - return 0 - fi - if [[ $_dev == *:* ]]; then - printf "%s\n" "$_dev" - return 0 - fi - done - return 1 - } && return 0 - fi - # fall back to /etc/fstab - - findmnt -e --fstab -v -n -o 'MAJ:MIN,SOURCE' --target "$_find_mpt" | { - while read -r _majmin _dev || [ -n "$_dev" ]; do - if ! [[ $_dev ]]; then - _dev="$_majmin" - unset _majmin - fi - if [[ -b $_dev ]]; then - [[ $_majmin ]] || _majmin=$(get_maj_min "$_dev") - if [[ $_majmin ]]; then - printf "%s\n" "$_majmin" - else - printf "%s\n" "$_dev" - fi - return 0 - fi - if [[ $_dev == *:* ]]; then - printf "%s\n" "$_dev" - return 0 - fi - done - return 1 - } && return 0 - - return 1 -} - -# find_mp_fstype -# Echo the filesystem type for a given mountpoint. -# /proc/self/mountinfo is taken as the primary source of information -# and /etc/fstab is used as a fallback. -# No newline is appended! -# Example: -# $ find_mp_fstype /;echo -# ext4 -find_mp_fstype() { - local _fs - - if [[ $use_fstab != yes ]]; then - findmnt -e -v -n -o 'FSTYPE' --target "$1" | { - while read -r _fs || [ -n "$_fs" ]; do - [[ $_fs ]] || continue - [[ $_fs == "autofs" ]] && continue - printf "%s" "$_fs" - return 0 - done - return 1 - } && return 0 - fi - - findmnt --fstab -e -v -n -o 'FSTYPE' --target "$1" | { - while read -r _fs || [ -n "$_fs" ]; do - [[ $_fs ]] || continue - [[ $_fs == "autofs" ]] && continue - printf "%s" "$_fs" - return 0 - done - return 1 - } && return 0 - - return 1 -} - -# find_dev_fstype -# Echo the filesystem type for a given device. -# /proc/self/mountinfo is taken as the primary source of information -# and /etc/fstab is used as a fallback. -# No newline is appended! -# Example: -# $ find_dev_fstype /dev/sda2;echo -# ext4 -find_dev_fstype() { - local _find_dev _fs - _find_dev="$1" - if ! [[ $_find_dev == /dev* ]]; then - [[ -b "/dev/block/$_find_dev" ]] && _find_dev="/dev/block/$_find_dev" - fi - - if [[ $use_fstab != yes ]]; then - findmnt -e -v -n -o 'FSTYPE' --source "$_find_dev" | { - while read -r _fs || [ -n "$_fs" ]; do - [[ $_fs ]] || continue - [[ $_fs == "autofs" ]] && continue - printf "%s" "$_fs" - return 0 - done - return 1 - } && return 0 - fi - - findmnt --fstab -e -v -n -o 'FSTYPE' --source "$_find_dev" | { - while read -r _fs || [ -n "$_fs" ]; do - [[ $_fs ]] || continue - [[ $_fs == "autofs" ]] && continue - printf "%s" "$_fs" - return 0 - done - return 1 - } && return 0 - - return 1 -} - -# find_mp_fsopts -# Echo the filesystem options for a given mountpoint. -# /proc/self/mountinfo is taken as the primary source of information -# and /etc/fstab is used as a fallback. -# No newline is appended! -# Example: -# $ find_mp_fsopts /;echo -# rw,relatime,discard,data=ordered -find_mp_fsopts() { - if [[ $use_fstab != yes ]]; then - findmnt -e -v -n -o 'OPTIONS' --target "$1" 2> /dev/null && return 0 - fi - - findmnt --fstab -e -v -n -o 'OPTIONS' --target "$1" -} - -# find_dev_fsopts -# Echo the filesystem options for a given device. -# /proc/self/mountinfo is taken as the primary source of information -# and /etc/fstab is used as a fallback. -# if `use_fstab == yes`, then only `/etc/fstab` is used. -# -# Example: -# $ find_dev_fsopts /dev/sda2 -# rw,relatime,discard,data=ordered -find_dev_fsopts() { - local _find_dev - _find_dev="$1" - if ! [[ $_find_dev == /dev* ]]; then - [[ -b "/dev/block/$_find_dev" ]] && _find_dev="/dev/block/$_find_dev" - fi - - if [[ $use_fstab != yes ]]; then - findmnt -e -v -n -o 'OPTIONS' --source "$_find_dev" 2> /dev/null && return 0 - fi - - findmnt --fstab -e -v -n -o 'OPTIONS' --source "$_find_dev" -} - -# finds the major:minor of the block device backing the root filesystem. -find_root_block_device() { find_block_device /; } - -# for_each_host_dev_fs -# Execute " " for every " " pair found -# in ${host_fs_types[@]} -for_each_host_dev_fs() { - local _func="$1" - local _dev - local _ret=1 - - [[ "${#host_fs_types[@]}" ]] || return 2 - - for _dev in "${!host_fs_types[@]}"; do - $_func "$_dev" "${host_fs_types[$_dev]}" && _ret=0 - done - return $_ret -} - -host_fs_all() { - printf "%s\n" "${host_fs_types[@]}" -} - -# Walk all the slave relationships for a given block device. -# Stop when our helper function returns success -# $1 = function to call on every found block device -# $2 = block device in major:minor format -check_block_and_slaves() { - local _x - [[ -b /dev/block/$2 ]] || return 1 # Not a block device? So sorry. - if ! lvm_internal_dev "$2"; then "$1" "$2" && return; fi - check_vol_slaves "$@" && return 0 - if [[ -f /sys/dev/block/$2/../dev ]] && [[ /sys/dev/block/$2/../subsystem -ef /sys/class/block ]]; then - check_block_and_slaves "$1" "$(< "/sys/dev/block/$2/../dev")" && return 0 - fi - for _x in /sys/dev/block/"$2"/slaves/*; do - [[ -f $_x/dev ]] || continue - [[ $_x/subsystem -ef /sys/class/block ]] || continue - check_block_and_slaves "$1" "$(< "$_x/dev")" && return 0 - done - return 1 -} - -check_block_and_slaves_all() { - local _x _ret=1 - [[ -b /dev/block/$2 ]] || return 1 # Not a block device? So sorry. - if ! lvm_internal_dev "$2" && "$1" "$2"; then - _ret=0 - fi - check_vol_slaves_all "$@" && return 0 - if [[ -f /sys/dev/block/$2/../dev ]] && [[ /sys/dev/block/$2/../subsystem -ef /sys/class/block ]]; then - check_block_and_slaves_all "$1" "$(< "/sys/dev/block/$2/../dev")" && _ret=0 - fi - for _x in /sys/dev/block/"$2"/slaves/*; do - [[ -f $_x/dev ]] || continue - [[ $_x/subsystem -ef /sys/class/block ]] || continue - check_block_and_slaves_all "$1" "$(< "$_x/dev")" && _ret=0 - done - return $_ret -} -# for_each_host_dev_and_slaves -# Execute " " for every "" found -# in ${host_devs[@]} and their slaves -for_each_host_dev_and_slaves_all() { - local _func="$1" - local _dev - local _ret=1 - - [[ "${host_devs[*]}" ]] || return 2 - - for _dev in "${host_devs[@]}"; do - [[ -b $_dev ]] || continue - if check_block_and_slaves_all "$_func" "$(get_maj_min "$_dev")"; then - _ret=0 - fi - done - return $_ret -} - -for_each_host_dev_and_slaves() { - local _func="$1" - local _dev - - [[ "${host_devs[*]}" ]] || return 2 - - for _dev in "${host_devs[@]}"; do - [[ -b $_dev ]] || continue - check_block_and_slaves "$_func" "$(get_maj_min "$_dev")" && return 0 - done - return 1 -} - -# ugly workaround for the lvm design -# There is no volume group device, -# so, there are no slave devices for volume groups. -# Logical volumes only have the slave devices they really live on, -# but you cannot create the logical volume without the volume group. -# And the volume group might be bigger than the devices the LV needs. -check_vol_slaves() { - local _vg _pv _dm _majmin - _majmin="$2" - _dm=/sys/dev/block/$_majmin/dm - [[ -f $_dm/uuid && $(< "$_dm"/uuid) =~ LVM-* ]] || return 1 - _vg=$(dmsetup splitname --noheadings -o vg_name "$(< "$_dm/name")") - # strip space - _vg="${_vg//[[:space:]]/}" - if [[ $_vg ]]; then - for _pv in $(lvm vgs --noheadings -o pv_name "$_vg" 2> /dev/null); do - check_block_and_slaves "$1" "$(get_maj_min "$_pv")" && return 0 - done - fi - return 1 -} - -check_vol_slaves_all() { - local _vg _pv _majmin - _majmin="$2" - _dm="/sys/dev/block/$_majmin/dm" - [[ -f $_dm/uuid && $(< "$_dm"/uuid) =~ LVM-* ]] || return 1 - _vg=$(dmsetup splitname --noheadings -o vg_name "$(< "$_dm/name")") - # strip space - _vg="${_vg//[[:space:]]/}" - if [[ $_vg ]]; then - # when filter/global_filter is set, lvm may be failed - if ! lvm lvs --noheadings -o vg_name "$_vg" 2> /dev/null 1> /dev/null; then - return 1 - fi - - for _pv in $(lvm vgs --noheadings -o pv_name "$_vg" 2> /dev/null); do - check_block_and_slaves_all "$1" "$(get_maj_min "$_pv")" - done - return 0 - fi - return 1 -} - -# fs_get_option -# search for a specific option in a bunch of filesystem options -# and return the value -fs_get_option() { - local _fsopts=$1 - local _option=$2 - local OLDIFS="$IFS" - IFS=, - # shellcheck disable=SC2086 - set -- $_fsopts - IFS="$OLDIFS" - while [ $# -gt 0 ]; do - case $1 in - $_option=*) - echo "${1#${_option}=}" - break - ;; - esac - shift - done -} - -check_kernel_config() { - local _config_opt="$1" - local _config_file - [[ -f $dracutsysrootdir/boot/config-$kernel ]] \ - && _config_file="/boot/config-$kernel" - [[ -f $dracutsysrootdir/lib/modules/$kernel/config ]] \ - && _config_file="/lib/modules/$kernel/config" - - # no kernel config file, so return true - [[ $_config_file ]] || return 0 - - grep -q -F "${_config_opt}=" "$dracutsysrootdir$_config_file" && return 0 - return 1 -} - -# 0 if the kernel module is either built-in or available -# 1 if the kernel module is not enabled -check_kernel_module() { - modprobe -S "$kernel" --dry-run "$1" &> /dev/null || return 1 -} - -# get_cpu_vendor -# Only two values are returned: AMD or Intel -get_cpu_vendor() { - if grep -qE AMD /proc/cpuinfo; then - printf "AMD" - fi - if grep -qE Intel /proc/cpuinfo; then - printf "Intel" - fi -} - -# get_host_ucode -# Get the hosts' ucode file based on the /proc/cpuinfo -get_ucode_file() { - local family - local model - local stepping - family=$(grep -E "cpu family" /proc/cpuinfo | head -1 | sed "s/.*:\ //") - model=$(grep -E "model" /proc/cpuinfo | grep -v name | head -1 | sed "s/.*:\ //") - stepping=$(grep -E "stepping" /proc/cpuinfo | head -1 | sed "s/.*:\ //") - - if [[ "$(get_cpu_vendor)" == "AMD" ]]; then - if [[ $family -ge 21 ]]; then - printf "microcode_amd_fam%xh.bin" "$family" - else - printf "microcode_amd.bin" - fi - fi - if [[ "$(get_cpu_vendor)" == "Intel" ]]; then - # The /proc/cpuinfo are in decimal. - printf "%02x-%02x-%02x" "${family}" "${model}" "${stepping}" - fi -} - -# Not every device in /dev/mapper should be examined. -# If it is an LVM device, touch only devices which have /dev/VG/LV symlink. -lvm_internal_dev() { - local dev_dm_dir=/sys/dev/block/$1/dm - [[ ! -f $dev_dm_dir/uuid || $(< "$dev_dm_dir"/uuid) != LVM-* ]] && return 1 # Not an LVM device - local DM_VG_NAME DM_LV_NAME DM_LV_LAYER - eval "$(dmsetup splitname --nameprefixes --noheadings --rows "$(< "$dev_dm_dir"/name)" 2> /dev/null)" - [[ ${DM_VG_NAME} ]] && [[ ${DM_LV_NAME} ]] || return 0 # Better skip this! - [[ ${DM_LV_LAYER} ]] || [[ ! -L /dev/${DM_VG_NAME}/${DM_LV_NAME} ]] -} - -btrfs_devs() { - local _mp="$1" - btrfs device usage "$_mp" \ - | while read -r _dev _; do - str_starts "$_dev" "/" || continue - _dev=${_dev%,} - printf -- "%s\n" "$_dev" - done -} - -iface_for_remote_addr() { - # shellcheck disable=SC2046 - set -- $(ip -o route get to "$1") - echo "$3" -} - -local_addr_for_remote_addr() { - # shellcheck disable=SC2046 - set -- $(ip -o route get to "$1") - echo "$5" -} - -peer_for_addr() { - local addr=$1 - local qtd - - # quote periods in IPv4 address - qtd=${addr//./\\.} - ip -o addr show \ - | sed -n 's%^.* '"$qtd"' peer \([0-9a-f.:]\{1,\}\(/[0-9]*\)\?\).*$%\1%p' -} - -netmask_for_addr() { - local addr=$1 - local qtd - - # quote periods in IPv4 address - qtd=${addr//./\\.} - ip -o addr show | sed -n 's,^.* '"$qtd"'/\([0-9]*\) .*$,\1,p' -} - -gateway_for_iface() { - local ifname=$1 addr=$2 - - case $addr in - *.*) proto=4 ;; - *:*) proto=6 ;; - *) return ;; - esac - ip -o -$proto route show \ - | sed -n "s/^default via \([0-9a-z.:]\{1,\}\) dev $ifname .*\$/\1/p" -} - -# This works only for ifcfg-style network configuration! -bootproto_for_iface() { - local ifname=$1 - local dir - - # follow ifcfg settings for boot protocol - for dir in network-scripts network; do - [ -f "/etc/sysconfig/$dir/ifcfg-$ifname" ] && { - sed -n "s/BOOTPROTO=[\"']\?\([[:alnum:]]\{1,\}\)[\"']\?.*\$/\1/p" \ - "/etc/sysconfig/$dir/ifcfg-$ifname" - return - } - done -} - -is_unbracketed_ipv6_address() { - strglob "$1" '*:*' && ! strglob "$1" '\[*:*\]' -} - -# Create an ip= string to set up networking such that the given -# remote address can be reached -ip_params_for_remote_addr() { - local remote_addr=$1 - local ifname local_addr peer netmask gateway ifmac - - [[ $remote_addr ]] || return 1 - ifname=$(iface_for_remote_addr "$remote_addr") - [[ $ifname ]] || { - berror "failed to determine interface to connect to $remote_addr" - return 1 - } - - # ifname clause to bind the interface name to a MAC address - if [ -d "/sys/class/net/$ifname/bonding" ]; then - dinfo "Found bonded interface '${ifname}'. Make sure to provide an appropriate 'bond=' cmdline." - elif [ -e "/sys/class/net/$ifname/address" ]; then - ifmac=$(cat "/sys/class/net/$ifname/address") - [[ $ifmac ]] && printf 'ifname=%s:%s ' "${ifname}" "${ifmac}" - fi - - bootproto=$(bootproto_for_iface "$ifname") - case $bootproto in - dhcp | dhcp6 | auto6) ;; - dhcp4) - bootproto=dhcp - ;; - static* | "") - bootproto= - ;; - *) - derror "bootproto \"$bootproto\" is unsupported by dracut, trying static configuration" - bootproto= - ;; - esac - if [[ $bootproto ]]; then - printf 'ip=%s:%s ' "${ifname}" "${bootproto}" - else - local_addr=$(local_addr_for_remote_addr "$remote_addr") - [[ $local_addr ]] || { - berror "failed to determine local address to connect to $remote_addr" - return 1 - } - peer=$(peer_for_addr "$local_addr") - # Set peer or netmask, but not both - [[ $peer ]] || netmask=$(netmask_for_addr "$local_addr") - gateway=$(gateway_for_iface "$ifname" "$local_addr") - # Quote IPv6 addresses with brackets - is_unbracketed_ipv6_address "$local_addr" && local_addr="[$local_addr]" - is_unbracketed_ipv6_address "$peer" && peer="[$peer]" - is_unbracketed_ipv6_address "$gateway" && gateway="[$gateway]" - printf 'ip=%s:%s:%s:%s::%s:none ' \ - "${local_addr}" "${peer}" "${gateway}" "${netmask}" "${ifname}" - fi - -} - -# block_is_nbd -# Check whether $1 is an nbd device -block_is_nbd() { - [[ -b /dev/block/$1 && $1 == 43:* ]] -} - -# block_is_iscsi -# Check whether $1 is an nbd device -block_is_iscsi() { - local _dir - local _dev=$1 - [[ -L "/sys/dev/block/$_dev" ]] || return - _dir="$(readlink -f "/sys/dev/block/$_dev")" || return - until [[ -d "$_dir/sys" || -d "$_dir/iscsi_session" ]]; do - _dir="$_dir/.." - done - [[ -d "$_dir/iscsi_session" ]] -} - -# block_is_fcoe -# Check whether $1 is an FCoE device -# Will not work for HBAs that hide the ethernet aspect -# completely and present a pure FC device -block_is_fcoe() { - local _dir - local _dev=$1 - [[ -L "/sys/dev/block/$_dev" ]] || return - _dir="$(readlink -f "/sys/dev/block/$_dev")" - until [[ -d "$_dir/sys" ]]; do - _dir="$_dir/.." - if [[ -d "$_dir/subsystem" ]]; then - subsystem=$(basename "$(readlink "$_dir"/subsystem)") - [[ $subsystem == "fcoe" ]] && return 0 - fi - done - return 1 -} - -# block_is_netdevice -# Check whether $1 is a net device -block_is_netdevice() { - block_is_nbd "$1" || block_is_iscsi "$1" || block_is_fcoe "$1" -} - -# get the corresponding kernel modules of a /sys/class/*/* or/dev/* device -get_dev_module() { - udevadm info -a "$1" | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' -} diff --git a/b/dracut-functions.sh b/b/dracut-functions.sh deleted file mode 100644 index 1efad3b..0000000 --- a/b/dracut-functions.sh +++ /dev/null @@ -1,983 +0,0 @@ -#!/bin/bash -# -# functions used by dracut and other tools. -# -# Copyright 2005-2009 Red Hat, Inc. All rights reserved. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -export LC_MESSAGES=C - -# is_func -# Check whether $1 is a function. -is_func() { - [[ "$(type -t "$1")" == "function" ]] -} - -# Generic substring function. If $2 is in $1, return 0. -strstr() { [[ $1 == *"$2"* ]]; } -# Generic glob matching function. If glob pattern $2 matches anywhere in $1, OK -strglobin() { [[ $1 == *$2* ]]; } -# Generic glob matching function. If glob pattern $2 matches all of $1, OK -# shellcheck disable=SC2053 -strglob() { [[ $1 == $2 ]]; } -# returns OK if $1 contains literal string $2 at the beginning, and isn't empty -str_starts() { [ "${1#"$2"*}" != "$1" ]; } -# returns OK if $1 contains literal string $2 at the end, and isn't empty -str_ends() { [ "${1%*"$2"}" != "$1" ]; } - -# find a binary. If we were not passed the full path directly, -# search in the usual places to find the binary. -find_binary() { - local _delim - local _path - local l - local p - [[ -z ${1##/*} ]] || _delim="/" - - if [[ $1 == *.so* ]]; then - # shellcheck disable=SC2154 - for l in $libdirs; do - _path="${l}${_delim}${1}" - if { $DRACUT_LDD "${dracutsysrootdir}${_path}" &> /dev/null; }; then - printf "%s\n" "${_path}" - return 0 - fi - done - _path="${_delim}${1}" - if { $DRACUT_LDD "${dracutsysrootdir}${_path}" &> /dev/null; }; then - printf "%s\n" "${_path}" - return 0 - fi - fi - if [[ $1 == */* ]]; then - _path="${_delim}${1}" - if [[ -L ${dracutsysrootdir}${_path} ]] || [[ -x ${dracutsysrootdir}${_path} ]]; then - printf "%s\n" "${_path}" - return 0 - fi - fi - for p in $DRACUT_PATH; do - _path="${p}${_delim}${1}" - if [[ -L ${dracutsysrootdir}${_path} ]] || [[ -x ${dracutsysrootdir}${_path} ]]; then - printf "%s\n" "${_path}" - return 0 - fi - done - - [[ -n $dracutsysrootdir ]] && return 1 - type -P "${1##*/}" -} - -ldconfig_paths() { - $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 -} - -# Version comparision function. Assumes Linux style version scheme. -# $1 = version a -# $2 = comparision op (gt, ge, eq, le, lt, ne) -# $3 = version b -vercmp() { - local _n1 - read -r -a _n1 <<< "${1//./ }" - local _op=$2 - local _n2 - read -r -a _n2 <<< "${3//./ }" - local _i _res - - for ((_i = 0; ; _i++)); do - if [[ ! ${_n1[_i]}${_n2[_i]} ]]; then - _res=0 - elif ((${_n1[_i]:-0} > ${_n2[_i]:-0})); then - _res=1 - elif ((${_n1[_i]:-0} < ${_n2[_i]:-0})); then - _res=2 - else - continue - fi - break - done - - case $_op in - gt) ((_res == 1)) ;; - ge) ((_res != 2)) ;; - eq) ((_res == 0)) ;; - le) ((_res != 1)) ;; - lt) ((_res == 2)) ;; - ne) ((_res != 0)) ;; - esac -} - -# Create all subdirectories for given path without creating the last element. -# $1 = path -mksubdirs() { - # shellcheck disable=SC2174 - [[ -e ${1%/*} ]] || mkdir -m 0755 -p -- "${1%/*}" -} - -# Function prints global variables in format name=value line by line. -# $@ = list of global variables' name -print_vars() { - local _var _value - - for _var in "$@"; do - eval printf -v _value "%s" \""\$$_var"\" - [[ ${_value} ]] && printf '%s="%s"\n' "$_var" "$_value" - done -} - -# normalize_path -# Prints the normalized path, where it removes any duplicated -# and trailing slashes. -# Example: -# $ normalize_path ///test/test// -# /test/test -normalize_path() { - # shellcheck disable=SC2064 - trap "$(shopt -p extglob)" RETURN - shopt -q -s extglob - local p=${1//+(\/)//} - printf "%s\n" "${p%/}" -} - -# convert_abs_rel -# Prints the relative path, when creating a symlink to from . -# Example: -# $ convert_abs_rel /usr/bin/test /bin/test-2 -# ../../bin/test-2 -# $ ln -s $(convert_abs_rel /usr/bin/test /bin/test-2) /usr/bin/test -convert_abs_rel() { - local __current __absolute __abssize __cursize __newpath - local -i __i __level - - set -- "$(normalize_path "$1")" "$(normalize_path "$2")" - - # corner case #1 - self looping link - [[ $1 == "$2" ]] && { - printf "%s\n" "${1##*/}" - return - } - - # corner case #2 - own dir link - [[ ${1%/*} == "$2" ]] && { - printf ".\n" - return - } - - IFS=/ read -r -a __current <<< "$1" - IFS=/ read -r -a __absolute <<< "$2" - - __abssize=${#__absolute[@]} - __cursize=${#__current[@]} - - while [[ ${__absolute[__level]} == "${__current[__level]}" ]]; do - ((__level++)) - if ((__level > __abssize || __level > __cursize)); then - break - fi - done - - for ((__i = __level; __i < __cursize - 1; __i++)); do - if ((__i > __level)); then - __newpath=$__newpath"/" - fi - __newpath=$__newpath".." - done - - for ((__i = __level; __i < __abssize; __i++)); do - if [[ -n $__newpath ]]; then - __newpath=$__newpath"/" - fi - __newpath=$__newpath${__absolute[__i]} - done - - printf -- "%s\n" "$__newpath" -} - -# get_fs_env -# Get and the ID_FS_TYPE variable from udev for a device. -# Example: -# $ get_fs_env /dev/sda2 -# ext4 -get_fs_env() { - [[ $1 ]] || return - unset ID_FS_TYPE - ID_FS_TYPE=$(blkid -u filesystem -o export -- "$1" \ - | while read -r line || [ -n "$line" ]; do - if [[ $line == "TYPE="* ]]; then - printf "%s" "${line#TYPE=}" - exit 0 - fi - done) - if [[ $ID_FS_TYPE ]]; then - printf "%s" "$ID_FS_TYPE" - return 0 - fi - return 1 -} - -# get_maj_min -# Prints the major and minor of a device node. -# Example: -# $ get_maj_min /dev/sda2 -# 8:2 -get_maj_min() { - local _majmin - local _out - - if [[ $get_maj_min_cache_file ]]; then - _out="$(grep -m1 -oP "^$1 \K\S+$" "$get_maj_min_cache_file")" - fi - - if ! [[ "$_out" ]]; then - _majmin="$(stat -L -c '%t:%T' "$1" 2> /dev/null)" - _out="$(printf "%s" "$((0x${_majmin%:*})):$((0x${_majmin#*:}))")" - if [[ $get_maj_min_cache_file ]]; then - echo "$1 $_out" >> "$get_maj_min_cache_file" - fi - fi - echo -n "$_out" -} - -# get_devpath_block -# get the DEVPATH in /sys of a block device -get_devpath_block() { - local _majmin _i - _majmin=$(get_maj_min "$1") - - for _i in /sys/block/*/dev /sys/block/*/*/dev; do - [[ -e $_i ]] || continue - if [[ $_majmin == "$(< "$_i")" ]]; then - printf "%s" "${_i%/dev}" - return 0 - fi - done - return 1 -} - -# get a persistent path from a device -get_persistent_dev() { - local i _tmp _dev _pol - - _dev=$(get_maj_min "$1") - [ -z "$_dev" ] && return - - if [[ -n $persistent_policy ]]; then - _pol="/dev/disk/${persistent_policy}/*" - else - _pol= - fi - - for i in \ - $_pol \ - /dev/mapper/* \ - /dev/disk/by-uuid/* \ - /dev/disk/by-label/* \ - /dev/disk/by-partuuid/* \ - /dev/disk/by-partlabel/* \ - /dev/disk/by-id/* \ - /dev/disk/by-path/*; do - [[ -e $i ]] || continue - [[ $i == /dev/mapper/control ]] && continue - [[ $i == /dev/mapper/mpath* ]] && continue - _tmp=$(get_maj_min "$i") - if [ "$_tmp" = "$_dev" ]; then - printf -- "%s" "$i" - return - fi - done - printf -- "%s" "$1" -} - -expand_persistent_dev() { - local _dev=$1 - - case "$_dev" in - LABEL=*) - _dev="/dev/disk/by-label/${_dev#LABEL=}" - ;; - UUID=*) - _dev="${_dev#UUID=}" - _dev="${_dev,,}" - _dev="/dev/disk/by-uuid/${_dev}" - ;; - PARTUUID=*) - _dev="${_dev#PARTUUID=}" - _dev="${_dev,,}" - _dev="/dev/disk/by-partuuid/${_dev}" - ;; - PARTLABEL=*) - _dev="/dev/disk/by-partlabel/${_dev#PARTLABEL=}" - ;; - esac - printf "%s" "$_dev" -} - -shorten_persistent_dev() { - local _dev="$1" - case "$_dev" in - /dev/disk/by-uuid/*) - printf "%s" "UUID=${_dev##*/}" - ;; - /dev/disk/by-label/*) - printf "%s" "LABEL=${_dev##*/}" - ;; - /dev/disk/by-partuuid/*) - printf "%s" "PARTUUID=${_dev##*/}" - ;; - /dev/disk/by-partlabel/*) - printf "%s" "PARTLABEL=${_dev##*/}" - ;; - *) - printf "%s" "$_dev" - ;; - esac -} - -# find_block_device -# Prints the major and minor number of the block device -# for a given mountpoint. -# Unless $use_fstab is set to "yes" the functions -# uses /proc/self/mountinfo as the primary source of the -# information and only falls back to /etc/fstab, if the mountpoint -# is not found there. -# Example: -# $ find_block_device /usr -# 8:4 -find_block_device() { - local _dev _majmin _find_mpt - _find_mpt="$1" - - if [[ $use_fstab != yes ]]; then - [[ -d $_find_mpt/. ]] - findmnt -e -v -n -o 'MAJ:MIN,SOURCE' --target "$_find_mpt" | { - while read -r _majmin _dev || [ -n "$_dev" ]; do - if [[ -b $_dev ]]; then - if ! [[ $_majmin ]] || [[ $_majmin == 0:* ]]; then - _majmin=$(get_maj_min "$_dev") - fi - if [[ $_majmin ]]; then - printf "%s\n" "$_majmin" - else - printf "%s\n" "$_dev" - fi - return 0 - fi - if [[ $_dev == *:* ]]; then - printf "%s\n" "$_dev" - return 0 - fi - done - return 1 - } && return 0 - fi - # fall back to /etc/fstab - - findmnt -e --fstab -v -n -o 'MAJ:MIN,SOURCE' --target "$_find_mpt" | { - while read -r _majmin _dev || [ -n "$_dev" ]; do - if ! [[ $_dev ]]; then - _dev="$_majmin" - unset _majmin - fi - if [[ -b $_dev ]]; then - [[ $_majmin ]] || _majmin=$(get_maj_min "$_dev") - if [[ $_majmin ]]; then - printf "%s\n" "$_majmin" - else - printf "%s\n" "$_dev" - fi - return 0 - fi - if [[ $_dev == *:* ]]; then - printf "%s\n" "$_dev" - return 0 - fi - done - return 1 - } && return 0 - - return 1 -} - -# find_mp_fstype -# Echo the filesystem type for a given mountpoint. -# /proc/self/mountinfo is taken as the primary source of information -# and /etc/fstab is used as a fallback. -# No newline is appended! -# Example: -# $ find_mp_fstype /;echo -# ext4 -find_mp_fstype() { - local _fs - - if [[ $use_fstab != yes ]]; then - findmnt -e -v -n -o 'FSTYPE' --target "$1" | { - while read -r _fs || [ -n "$_fs" ]; do - [[ $_fs ]] || continue - [[ $_fs == "autofs" ]] && continue - printf "%s" "$_fs" - return 0 - done - return 1 - } && return 0 - fi - - findmnt --fstab -e -v -n -o 'FSTYPE' --target "$1" | { - while read -r _fs || [ -n "$_fs" ]; do - [[ $_fs ]] || continue - [[ $_fs == "autofs" ]] && continue - printf "%s" "$_fs" - return 0 - done - return 1 - } && return 0 - - return 1 -} - -# find_dev_fstype -# Echo the filesystem type for a given device. -# /proc/self/mountinfo is taken as the primary source of information -# and /etc/fstab is used as a fallback. -# No newline is appended! -# Example: -# $ find_dev_fstype /dev/sda2;echo -# ext4 -find_dev_fstype() { - local _find_dev _fs - _find_dev="$1" - if ! [[ $_find_dev == /dev* ]]; then - [[ -b "/dev/block/$_find_dev" ]] && _find_dev="/dev/block/$_find_dev" - fi - - if [[ $use_fstab != yes ]]; then - findmnt -e -v -n -o 'FSTYPE' --source "$_find_dev" | { - while read -r _fs || [ -n "$_fs" ]; do - [[ $_fs ]] || continue - [[ $_fs == "autofs" ]] && continue - printf "%s" "$_fs" - return 0 - done - return 1 - } && return 0 - fi - - findmnt --fstab -e -v -n -o 'FSTYPE' --source "$_find_dev" | { - while read -r _fs || [ -n "$_fs" ]; do - [[ $_fs ]] || continue - [[ $_fs == "autofs" ]] && continue - printf "%s" "$_fs" - return 0 - done - return 1 - } && return 0 - - return 1 -} - -# find_mp_fsopts -# Echo the filesystem options for a given mountpoint. -# /proc/self/mountinfo is taken as the primary source of information -# and /etc/fstab is used as a fallback. -# No newline is appended! -# Example: -# $ find_mp_fsopts /;echo -# rw,relatime,discard,data=ordered -find_mp_fsopts() { - if [[ $use_fstab != yes ]]; then - findmnt -e -v -n -o 'OPTIONS' --target "$1" 2> /dev/null && return 0 - fi - - findmnt --fstab -e -v -n -o 'OPTIONS' --target "$1" -} - -# find_dev_fsopts -# Echo the filesystem options for a given device. -# /proc/self/mountinfo is taken as the primary source of information -# and /etc/fstab is used as a fallback. -# if `use_fstab == yes`, then only `/etc/fstab` is used. -# -# Example: -# $ find_dev_fsopts /dev/sda2 -# rw,relatime,discard,data=ordered -find_dev_fsopts() { - local _find_dev - _find_dev="$1" - if ! [[ $_find_dev == /dev* ]]; then - [[ -b "/dev/block/$_find_dev" ]] && _find_dev="/dev/block/$_find_dev" - fi - - if [[ $use_fstab != yes ]]; then - findmnt -e -v -n -o 'OPTIONS' --source "$_find_dev" 2> /dev/null && return 0 - fi - - findmnt --fstab -e -v -n -o 'OPTIONS' --source "$_find_dev" -} - -# finds the major:minor of the block device backing the root filesystem. -find_root_block_device() { find_block_device /; } - -# for_each_host_dev_fs -# Execute " " for every " " pair found -# in ${host_fs_types[@]} -for_each_host_dev_fs() { - local _func="$1" - local _dev - local _ret=1 - - [[ "${#host_fs_types[@]}" ]] || return 2 - - for _dev in "${!host_fs_types[@]}"; do - $_func "$_dev" "${host_fs_types[$_dev]}" && _ret=0 - done - return $_ret -} - -host_fs_all() { - printf "%s\n" "${host_fs_types[@]}" -} - -# Walk all the slave relationships for a given block device. -# Stop when our helper function returns success -# $1 = function to call on every found block device -# $2 = block device in major:minor format -check_block_and_slaves() { - local _x - [[ -b /dev/block/$2 ]] || return 1 # Not a block device? So sorry. - if ! lvm_internal_dev "$2"; then "$1" "$2" && return; fi - check_vol_slaves "$@" && return 0 - if [[ -f /sys/dev/block/$2/../dev ]] && [[ /sys/dev/block/$2/../subsystem -ef /sys/class/block ]]; then - check_block_and_slaves "$1" "$(< "/sys/dev/block/$2/../dev")" && return 0 - fi - for _x in /sys/dev/block/"$2"/slaves/*; do - [[ -f $_x/dev ]] || continue - [[ $_x/subsystem -ef /sys/class/block ]] || continue - check_block_and_slaves "$1" "$(< "$_x/dev")" && return 0 - done - return 1 -} - -check_block_and_slaves_all() { - local _x _ret=1 - [[ -b /dev/block/$2 ]] || return 1 # Not a block device? So sorry. - if ! lvm_internal_dev "$2" && "$1" "$2"; then - _ret=0 - fi - check_vol_slaves_all "$@" && return 0 - if [[ -f /sys/dev/block/$2/../dev ]] && [[ /sys/dev/block/$2/../subsystem -ef /sys/class/block ]]; then - check_block_and_slaves_all "$1" "$(< "/sys/dev/block/$2/../dev")" && _ret=0 - fi - for _x in /sys/dev/block/"$2"/slaves/*; do - [[ -f $_x/dev ]] || continue - [[ $_x/subsystem -ef /sys/class/block ]] || continue - check_block_and_slaves_all "$1" "$(< "$_x/dev")" && _ret=0 - done - return $_ret -} -# for_each_host_dev_and_slaves -# Execute " " for every "" found -# in ${host_devs[@]} and their slaves -for_each_host_dev_and_slaves_all() { - local _func="$1" - local _dev - local _ret=1 - - [[ "${host_devs[*]}" ]] || return 2 - - for _dev in "${host_devs[@]}"; do - [[ -b $_dev ]] || continue - if check_block_and_slaves_all "$_func" "$(get_maj_min "$_dev")"; then - _ret=0 - fi - done - return $_ret -} - -for_each_host_dev_and_slaves() { - local _func="$1" - local _dev - - [[ "${host_devs[*]}" ]] || return 2 - - for _dev in "${host_devs[@]}"; do - [[ -b $_dev ]] || continue - check_block_and_slaves "$_func" "$(get_maj_min "$_dev")" && return 0 - done - return 1 -} - -# ugly workaround for the lvm design -# There is no volume group device, -# so, there are no slave devices for volume groups. -# Logical volumes only have the slave devices they really live on, -# but you cannot create the logical volume without the volume group. -# And the volume group might be bigger than the devices the LV needs. -check_vol_slaves() { - local _vg _pv _dm _majmin - _majmin="$2" - _dm=/sys/dev/block/$_majmin/dm - [[ -f $_dm/uuid && $(< "$_dm"/uuid) =~ LVM-* ]] || return 1 - _vg=$(dmsetup splitname --noheadings -o vg_name "$(< "$_dm/name")") - # strip space - _vg="${_vg//[[:space:]]/}" - if [[ $_vg ]]; then - for _pv in $(lvm vgs --noheadings -o pv_name "$_vg" 2> /dev/null); do - check_block_and_slaves "$1" "$(get_maj_min "$_pv")" && return 0 - done - fi - return 1 -} - -check_vol_slaves_all() { - local _vg _pv _majmin - _majmin="$2" - _dm="/sys/dev/block/$_majmin/dm" - [[ -f $_dm/uuid && $(< "$_dm"/uuid) =~ LVM-* ]] || return 1 - _vg=$(dmsetup splitname --noheadings -o vg_name "$(< "$_dm/name")") - # strip space - _vg="${_vg//[[:space:]]/}" - if [[ $_vg ]]; then - # when filter/global_filter is set, lvm may be failed - if ! lvm lvs --noheadings -o vg_name "$_vg" 2> /dev/null 1> /dev/null; then - return 1 - fi - - for _pv in $(lvm vgs --noheadings -o pv_name "$_vg" 2> /dev/null); do - check_block_and_slaves_all "$1" "$(get_maj_min "$_pv")" - done - return 0 - fi - return 1 -} - -# fs_get_option -# search for a specific option in a bunch of filesystem options -# and return the value -fs_get_option() { - local _fsopts=$1 - local _option=$2 - local OLDIFS="$IFS" - IFS=, - # shellcheck disable=SC2086 - set -- $_fsopts - IFS="$OLDIFS" - while [ $# -gt 0 ]; do - case $1 in - $_option=*) - echo "${1#${_option}=}" - break - ;; - esac - shift - done -} - -check_kernel_config() { - local _config_opt="$1" - local _config_file - [[ -f $dracutsysrootdir/boot/config-$kernel ]] \ - && _config_file="/boot/config-$kernel" - [[ -f $dracutsysrootdir/lib/modules/$kernel/config ]] \ - && _config_file="/lib/modules/$kernel/config" - - # no kernel config file, so return true - [[ $_config_file ]] || return 0 - - grep -q -F "${_config_opt}=" "$dracutsysrootdir$_config_file" && return 0 - return 1 -} - -# 0 if the kernel module is either built-in or available -# 1 if the kernel module is not enabled -check_kernel_module() { - modprobe -S "$kernel" --dry-run "$1" &> /dev/null || return 1 -} - -# get_cpu_vendor -# Only two values are returned: AMD or Intel -get_cpu_vendor() { - if grep -qE AMD /proc/cpuinfo; then - printf "AMD" - fi - if grep -qE Intel /proc/cpuinfo; then - printf "Intel" - fi -} - -# get_host_ucode -# Get the hosts' ucode file based on the /proc/cpuinfo -get_ucode_file() { - local family - local model - local stepping - family=$(grep -E "cpu family" /proc/cpuinfo | head -1 | sed "s/.*:\ //") - model=$(grep -E "model" /proc/cpuinfo | grep -v name | head -1 | sed "s/.*:\ //") - stepping=$(grep -E "stepping" /proc/cpuinfo | head -1 | sed "s/.*:\ //") - - if [[ "$(get_cpu_vendor)" == "AMD" ]]; then - if [[ $family -ge 21 ]]; then - printf "microcode_amd_fam%xh.bin" "$family" - else - printf "microcode_amd.bin" - fi - fi - if [[ "$(get_cpu_vendor)" == "Intel" ]]; then - # The /proc/cpuinfo are in decimal. - printf "%02x-%02x-%02x" "${family}" "${model}" "${stepping}" - fi -} - -# Not every device in /dev/mapper should be examined. -# If it is an LVM device, touch only devices which have /dev/VG/LV symlink. -lvm_internal_dev() { - local dev_dm_dir=/sys/dev/block/$1/dm - [[ ! -f $dev_dm_dir/uuid || $(< "$dev_dm_dir"/uuid) != LVM-* ]] && return 1 # Not an LVM device - local DM_VG_NAME DM_LV_NAME DM_LV_LAYER - eval "$(dmsetup splitname --nameprefixes --noheadings --rows "$(< "$dev_dm_dir"/name)" 2> /dev/null)" - [[ ${DM_VG_NAME} ]] && [[ ${DM_LV_NAME} ]] || return 0 # Better skip this! - [[ ${DM_LV_LAYER} ]] || [[ ! -L /dev/${DM_VG_NAME}/${DM_LV_NAME} ]] -} - -btrfs_devs() { - local _mp="$1" - btrfs device usage "$_mp" \ - | while read -r _dev _; do - str_starts "$_dev" "/" || continue - _dev=${_dev%,} - printf -- "%s\n" "$_dev" - done -} - -iface_for_remote_addr() { - # shellcheck disable=SC2046 - set -- $(ip -o route get to "$1") - echo "$3" -} - -local_addr_for_remote_addr() { - # shellcheck disable=SC2046 - set -- $(ip -o route get to "$1") - echo "$5" -} - -peer_for_addr() { - local addr=$1 - local qtd - - # quote periods in IPv4 address - qtd=${addr//./\\.} - ip -o addr show \ - | sed -n 's%^.* '"$qtd"' peer \([0-9a-f.:]\{1,\}\(/[0-9]*\)\?\).*$%\1%p' -} - -netmask_for_addr() { - local addr=$1 - local qtd - - # quote periods in IPv4 address - qtd=${addr//./\\.} - ip -o addr show | sed -n 's,^.* '"$qtd"'/\([0-9]*\) .*$,\1,p' -} - -gateway_for_iface() { - local ifname=$1 addr=$2 - - case $addr in - *.*) proto=4 ;; - *:*) proto=6 ;; - *) return ;; - esac - ip -o -$proto route show \ - | sed -n "s/^default via \([0-9a-z.:]\{1,\}\) dev $ifname .*\$/\1/p" -} - -# This works only for ifcfg-style network configuration! -bootproto_for_iface() { - local ifname=$1 - local dir - - # follow ifcfg settings for boot protocol - for dir in network-scripts network; do - [ -f "/etc/sysconfig/$dir/ifcfg-$ifname" ] && { - sed -n "s/BOOTPROTO=[\"']\?\([[:alnum:]]\{1,\}\)[\"']\?.*\$/\1/p" \ - "/etc/sysconfig/$dir/ifcfg-$ifname" - return - } - done -} - -is_unbracketed_ipv6_address() { - strglob "$1" '*:*' && ! strglob "$1" '\[*:*\]' -} - -# Create an ip= string to set up networking such that the given -# remote address can be reached -ip_params_for_remote_addr() { - local remote_addr=$1 - local ifname local_addr peer netmask gateway ifmac - - [[ $remote_addr ]] || return 1 - ifname=$(iface_for_remote_addr "$remote_addr") - [[ $ifname ]] || { - berror "failed to determine interface to connect to $remote_addr" - return 1 - } - - # ifname clause to bind the interface name to a MAC address - if [ -d "/sys/class/net/$ifname/bonding" ]; then - dinfo "Found bonded interface '${ifname}'. Make sure to provide an appropriate 'bond=' cmdline." - elif [ -e "/sys/class/net/$ifname/address" ]; then - ifmac=$(cat "/sys/class/net/$ifname/address") - [[ $ifmac ]] && printf 'ifname=%s:%s ' "${ifname}" "${ifmac}" - fi - - bootproto=$(bootproto_for_iface "$ifname") - case $bootproto in - dhcp | dhcp6 | auto6) ;; - dhcp4) - bootproto=dhcp - ;; - static* | "") - bootproto= - ;; - *) - derror "bootproto \"$bootproto\" is unsupported by dracut, trying static configuration" - bootproto= - ;; - esac - if [[ $bootproto ]]; then - printf 'ip=%s:%s ' "${ifname}" "${bootproto}" - else - local_addr=$(local_addr_for_remote_addr "$remote_addr") - [[ $local_addr ]] || { - berror "failed to determine local address to connect to $remote_addr" - return 1 - } - peer=$(peer_for_addr "$local_addr") - # Set peer or netmask, but not both - [[ $peer ]] || netmask=$(netmask_for_addr "$local_addr") - gateway=$(gateway_for_iface "$ifname" "$local_addr") - # Quote IPv6 addresses with brackets - is_unbracketed_ipv6_address "$local_addr" && local_addr="[$local_addr]" - is_unbracketed_ipv6_address "$peer" && peer="[$peer]" - is_unbracketed_ipv6_address "$gateway" && gateway="[$gateway]" - printf 'ip=%s:%s:%s:%s::%s:none ' \ - "${local_addr}" "${peer}" "${gateway}" "${netmask}" "${ifname}" - fi - -} - -# block_is_nbd -# Check whether $1 is an nbd device -block_is_nbd() { - [[ -b /dev/block/$1 && $1 == 43:* ]] -} - -# block_is_iscsi -# Check whether $1 is an nbd device -block_is_iscsi() { - local _dir - local _dev=$1 - [[ -L "/sys/dev/block/$_dev" ]] || return - _dir="$(readlink -f "/sys/dev/block/$_dev")" || return - until [[ -d "$_dir/sys" || -d "$_dir/iscsi_session" ]]; do - _dir="$_dir/.." - done - [[ -d "$_dir/iscsi_session" ]] -} - -# block_is_fcoe -# Check whether $1 is an FCoE device -# Will not work for HBAs that hide the ethernet aspect -# completely and present a pure FC device -block_is_fcoe() { - local _dir - local _dev=$1 - [[ -L "/sys/dev/block/$_dev" ]] || return - _dir="$(readlink -f "/sys/dev/block/$_dev")" - until [[ -d "$_dir/sys" ]]; do - _dir="$_dir/.." - if [[ -d "$_dir/subsystem" ]]; then - subsystem=$(basename "$(readlink "$_dir"/subsystem)") - [[ $subsystem == "fcoe" ]] && return 0 - fi - done - return 1 -} - -# block_is_netdevice -# Check whether $1 is a net device -block_is_netdevice() { - block_is_nbd "$1" || block_is_iscsi "$1" || block_is_fcoe "$1" -} - -# convert the driver name given by udevadm to the corresponding kernel module name -get_module_name() { - local dev_driver - while read -r dev_driver; do - case "$dev_driver" in - mmcblk) - echo "mmc_block" - ;; - *) - echo "$dev_driver" - ;; - esac - done -} - -# get the corresponding kernel modules of a /sys/class/*/* or/dev/* device -get_dev_module() { - #udevadm info -a "$1" | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' - local dev_attr_walk - local dev_drivers - local dev_paths - dev_attr_walk=$(udevadm info -a "$1") - dev_drivers=$(echo "$dev_attr_walk" \ - | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' \ - | get_module_name) - - # also return modalias info from sysfs paths parsed by udevadm - dev_paths=$(echo "$dev_attr_walk" | sed -n 's/.*\(\/devices\/.*\)'\'':/\1/p') - local dev_path - for dev_path in $dev_paths; do - local modalias_file="/sys$dev_path/modalias" - if [ -e "$modalias_file" ]; then - dev_drivers="$(printf "%s\n%s" "$dev_drivers" "$(cat "$modalias_file")")" - fi - done - - # if no kernel modules found and device is in a virtual subsystem, follow symlinks - if [[ -z $dev_drivers && $(udevadm info -q path "$1") == "/devices/virtual"* ]]; then - local dev_vkernel - local dev_vsubsystem - local dev_vpath - dev_vkernel=$(echo "$dev_attr_walk" | sed -n 's/\s*KERNELS=="\(\S\+\)"/\1/p' | tail -1) - dev_vsubsystem=$(echo "$dev_attr_walk" | sed -n 's/\s*SUBSYSTEMS=="\(\S\+\)"/\1/p' | tail -1) - dev_vpath="/sys/devices/virtual/$dev_vsubsystem/$dev_vkernel" - if [[ -n $dev_vkernel && -n $dev_vsubsystem && -d $dev_vpath ]]; then - local dev_links - local dev_link - dev_links=$(find "$dev_vpath" -maxdepth 1 -type l ! -name "subsystem" -exec readlink {} \;) - for dev_link in $dev_links; do - [[ -n $dev_drivers && ${dev_drivers: -1} != $'\n' ]] && dev_drivers+=$'\n' - dev_drivers+=$(udevadm info -a "$dev_vpath/$dev_link" \ - | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' \ - | get_module_name \ - | grep -v -e pcieport) - done - fi - fi - echo "$dev_drivers" -} -- Gitee From c7de98aa37309e7670043ea47a904fdb1695657b Mon Sep 17 00:00:00 2001 From: "Kang.Yihang" Date: Thu, 2 Nov 2023 17:32:40 +0800 Subject: [PATCH 8/8] =?UTF-8?q?=E5=88=A0=E9=99=A4=E4=B8=B4=E6=97=B6?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dracut-functions.sh | 983 -------------------------------------------- 1 file changed, 983 deletions(-) delete mode 100644 dracut-functions.sh diff --git a/dracut-functions.sh b/dracut-functions.sh deleted file mode 100644 index 1efad3b..0000000 --- a/dracut-functions.sh +++ /dev/null @@ -1,983 +0,0 @@ -#!/bin/bash -# -# functions used by dracut and other tools. -# -# Copyright 2005-2009 Red Hat, Inc. All rights reserved. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -export LC_MESSAGES=C - -# is_func -# Check whether $1 is a function. -is_func() { - [[ "$(type -t "$1")" == "function" ]] -} - -# Generic substring function. If $2 is in $1, return 0. -strstr() { [[ $1 == *"$2"* ]]; } -# Generic glob matching function. If glob pattern $2 matches anywhere in $1, OK -strglobin() { [[ $1 == *$2* ]]; } -# Generic glob matching function. If glob pattern $2 matches all of $1, OK -# shellcheck disable=SC2053 -strglob() { [[ $1 == $2 ]]; } -# returns OK if $1 contains literal string $2 at the beginning, and isn't empty -str_starts() { [ "${1#"$2"*}" != "$1" ]; } -# returns OK if $1 contains literal string $2 at the end, and isn't empty -str_ends() { [ "${1%*"$2"}" != "$1" ]; } - -# find a binary. If we were not passed the full path directly, -# search in the usual places to find the binary. -find_binary() { - local _delim - local _path - local l - local p - [[ -z ${1##/*} ]] || _delim="/" - - if [[ $1 == *.so* ]]; then - # shellcheck disable=SC2154 - for l in $libdirs; do - _path="${l}${_delim}${1}" - if { $DRACUT_LDD "${dracutsysrootdir}${_path}" &> /dev/null; }; then - printf "%s\n" "${_path}" - return 0 - fi - done - _path="${_delim}${1}" - if { $DRACUT_LDD "${dracutsysrootdir}${_path}" &> /dev/null; }; then - printf "%s\n" "${_path}" - return 0 - fi - fi - if [[ $1 == */* ]]; then - _path="${_delim}${1}" - if [[ -L ${dracutsysrootdir}${_path} ]] || [[ -x ${dracutsysrootdir}${_path} ]]; then - printf "%s\n" "${_path}" - return 0 - fi - fi - for p in $DRACUT_PATH; do - _path="${p}${_delim}${1}" - if [[ -L ${dracutsysrootdir}${_path} ]] || [[ -x ${dracutsysrootdir}${_path} ]]; then - printf "%s\n" "${_path}" - return 0 - fi - done - - [[ -n $dracutsysrootdir ]] && return 1 - type -P "${1##*/}" -} - -ldconfig_paths() { - $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 -} - -# Version comparision function. Assumes Linux style version scheme. -# $1 = version a -# $2 = comparision op (gt, ge, eq, le, lt, ne) -# $3 = version b -vercmp() { - local _n1 - read -r -a _n1 <<< "${1//./ }" - local _op=$2 - local _n2 - read -r -a _n2 <<< "${3//./ }" - local _i _res - - for ((_i = 0; ; _i++)); do - if [[ ! ${_n1[_i]}${_n2[_i]} ]]; then - _res=0 - elif ((${_n1[_i]:-0} > ${_n2[_i]:-0})); then - _res=1 - elif ((${_n1[_i]:-0} < ${_n2[_i]:-0})); then - _res=2 - else - continue - fi - break - done - - case $_op in - gt) ((_res == 1)) ;; - ge) ((_res != 2)) ;; - eq) ((_res == 0)) ;; - le) ((_res != 1)) ;; - lt) ((_res == 2)) ;; - ne) ((_res != 0)) ;; - esac -} - -# Create all subdirectories for given path without creating the last element. -# $1 = path -mksubdirs() { - # shellcheck disable=SC2174 - [[ -e ${1%/*} ]] || mkdir -m 0755 -p -- "${1%/*}" -} - -# Function prints global variables in format name=value line by line. -# $@ = list of global variables' name -print_vars() { - local _var _value - - for _var in "$@"; do - eval printf -v _value "%s" \""\$$_var"\" - [[ ${_value} ]] && printf '%s="%s"\n' "$_var" "$_value" - done -} - -# normalize_path -# Prints the normalized path, where it removes any duplicated -# and trailing slashes. -# Example: -# $ normalize_path ///test/test// -# /test/test -normalize_path() { - # shellcheck disable=SC2064 - trap "$(shopt -p extglob)" RETURN - shopt -q -s extglob - local p=${1//+(\/)//} - printf "%s\n" "${p%/}" -} - -# convert_abs_rel -# Prints the relative path, when creating a symlink to from . -# Example: -# $ convert_abs_rel /usr/bin/test /bin/test-2 -# ../../bin/test-2 -# $ ln -s $(convert_abs_rel /usr/bin/test /bin/test-2) /usr/bin/test -convert_abs_rel() { - local __current __absolute __abssize __cursize __newpath - local -i __i __level - - set -- "$(normalize_path "$1")" "$(normalize_path "$2")" - - # corner case #1 - self looping link - [[ $1 == "$2" ]] && { - printf "%s\n" "${1##*/}" - return - } - - # corner case #2 - own dir link - [[ ${1%/*} == "$2" ]] && { - printf ".\n" - return - } - - IFS=/ read -r -a __current <<< "$1" - IFS=/ read -r -a __absolute <<< "$2" - - __abssize=${#__absolute[@]} - __cursize=${#__current[@]} - - while [[ ${__absolute[__level]} == "${__current[__level]}" ]]; do - ((__level++)) - if ((__level > __abssize || __level > __cursize)); then - break - fi - done - - for ((__i = __level; __i < __cursize - 1; __i++)); do - if ((__i > __level)); then - __newpath=$__newpath"/" - fi - __newpath=$__newpath".." - done - - for ((__i = __level; __i < __abssize; __i++)); do - if [[ -n $__newpath ]]; then - __newpath=$__newpath"/" - fi - __newpath=$__newpath${__absolute[__i]} - done - - printf -- "%s\n" "$__newpath" -} - -# get_fs_env -# Get and the ID_FS_TYPE variable from udev for a device. -# Example: -# $ get_fs_env /dev/sda2 -# ext4 -get_fs_env() { - [[ $1 ]] || return - unset ID_FS_TYPE - ID_FS_TYPE=$(blkid -u filesystem -o export -- "$1" \ - | while read -r line || [ -n "$line" ]; do - if [[ $line == "TYPE="* ]]; then - printf "%s" "${line#TYPE=}" - exit 0 - fi - done) - if [[ $ID_FS_TYPE ]]; then - printf "%s" "$ID_FS_TYPE" - return 0 - fi - return 1 -} - -# get_maj_min -# Prints the major and minor of a device node. -# Example: -# $ get_maj_min /dev/sda2 -# 8:2 -get_maj_min() { - local _majmin - local _out - - if [[ $get_maj_min_cache_file ]]; then - _out="$(grep -m1 -oP "^$1 \K\S+$" "$get_maj_min_cache_file")" - fi - - if ! [[ "$_out" ]]; then - _majmin="$(stat -L -c '%t:%T' "$1" 2> /dev/null)" - _out="$(printf "%s" "$((0x${_majmin%:*})):$((0x${_majmin#*:}))")" - if [[ $get_maj_min_cache_file ]]; then - echo "$1 $_out" >> "$get_maj_min_cache_file" - fi - fi - echo -n "$_out" -} - -# get_devpath_block -# get the DEVPATH in /sys of a block device -get_devpath_block() { - local _majmin _i - _majmin=$(get_maj_min "$1") - - for _i in /sys/block/*/dev /sys/block/*/*/dev; do - [[ -e $_i ]] || continue - if [[ $_majmin == "$(< "$_i")" ]]; then - printf "%s" "${_i%/dev}" - return 0 - fi - done - return 1 -} - -# get a persistent path from a device -get_persistent_dev() { - local i _tmp _dev _pol - - _dev=$(get_maj_min "$1") - [ -z "$_dev" ] && return - - if [[ -n $persistent_policy ]]; then - _pol="/dev/disk/${persistent_policy}/*" - else - _pol= - fi - - for i in \ - $_pol \ - /dev/mapper/* \ - /dev/disk/by-uuid/* \ - /dev/disk/by-label/* \ - /dev/disk/by-partuuid/* \ - /dev/disk/by-partlabel/* \ - /dev/disk/by-id/* \ - /dev/disk/by-path/*; do - [[ -e $i ]] || continue - [[ $i == /dev/mapper/control ]] && continue - [[ $i == /dev/mapper/mpath* ]] && continue - _tmp=$(get_maj_min "$i") - if [ "$_tmp" = "$_dev" ]; then - printf -- "%s" "$i" - return - fi - done - printf -- "%s" "$1" -} - -expand_persistent_dev() { - local _dev=$1 - - case "$_dev" in - LABEL=*) - _dev="/dev/disk/by-label/${_dev#LABEL=}" - ;; - UUID=*) - _dev="${_dev#UUID=}" - _dev="${_dev,,}" - _dev="/dev/disk/by-uuid/${_dev}" - ;; - PARTUUID=*) - _dev="${_dev#PARTUUID=}" - _dev="${_dev,,}" - _dev="/dev/disk/by-partuuid/${_dev}" - ;; - PARTLABEL=*) - _dev="/dev/disk/by-partlabel/${_dev#PARTLABEL=}" - ;; - esac - printf "%s" "$_dev" -} - -shorten_persistent_dev() { - local _dev="$1" - case "$_dev" in - /dev/disk/by-uuid/*) - printf "%s" "UUID=${_dev##*/}" - ;; - /dev/disk/by-label/*) - printf "%s" "LABEL=${_dev##*/}" - ;; - /dev/disk/by-partuuid/*) - printf "%s" "PARTUUID=${_dev##*/}" - ;; - /dev/disk/by-partlabel/*) - printf "%s" "PARTLABEL=${_dev##*/}" - ;; - *) - printf "%s" "$_dev" - ;; - esac -} - -# find_block_device -# Prints the major and minor number of the block device -# for a given mountpoint. -# Unless $use_fstab is set to "yes" the functions -# uses /proc/self/mountinfo as the primary source of the -# information and only falls back to /etc/fstab, if the mountpoint -# is not found there. -# Example: -# $ find_block_device /usr -# 8:4 -find_block_device() { - local _dev _majmin _find_mpt - _find_mpt="$1" - - if [[ $use_fstab != yes ]]; then - [[ -d $_find_mpt/. ]] - findmnt -e -v -n -o 'MAJ:MIN,SOURCE' --target "$_find_mpt" | { - while read -r _majmin _dev || [ -n "$_dev" ]; do - if [[ -b $_dev ]]; then - if ! [[ $_majmin ]] || [[ $_majmin == 0:* ]]; then - _majmin=$(get_maj_min "$_dev") - fi - if [[ $_majmin ]]; then - printf "%s\n" "$_majmin" - else - printf "%s\n" "$_dev" - fi - return 0 - fi - if [[ $_dev == *:* ]]; then - printf "%s\n" "$_dev" - return 0 - fi - done - return 1 - } && return 0 - fi - # fall back to /etc/fstab - - findmnt -e --fstab -v -n -o 'MAJ:MIN,SOURCE' --target "$_find_mpt" | { - while read -r _majmin _dev || [ -n "$_dev" ]; do - if ! [[ $_dev ]]; then - _dev="$_majmin" - unset _majmin - fi - if [[ -b $_dev ]]; then - [[ $_majmin ]] || _majmin=$(get_maj_min "$_dev") - if [[ $_majmin ]]; then - printf "%s\n" "$_majmin" - else - printf "%s\n" "$_dev" - fi - return 0 - fi - if [[ $_dev == *:* ]]; then - printf "%s\n" "$_dev" - return 0 - fi - done - return 1 - } && return 0 - - return 1 -} - -# find_mp_fstype -# Echo the filesystem type for a given mountpoint. -# /proc/self/mountinfo is taken as the primary source of information -# and /etc/fstab is used as a fallback. -# No newline is appended! -# Example: -# $ find_mp_fstype /;echo -# ext4 -find_mp_fstype() { - local _fs - - if [[ $use_fstab != yes ]]; then - findmnt -e -v -n -o 'FSTYPE' --target "$1" | { - while read -r _fs || [ -n "$_fs" ]; do - [[ $_fs ]] || continue - [[ $_fs == "autofs" ]] && continue - printf "%s" "$_fs" - return 0 - done - return 1 - } && return 0 - fi - - findmnt --fstab -e -v -n -o 'FSTYPE' --target "$1" | { - while read -r _fs || [ -n "$_fs" ]; do - [[ $_fs ]] || continue - [[ $_fs == "autofs" ]] && continue - printf "%s" "$_fs" - return 0 - done - return 1 - } && return 0 - - return 1 -} - -# find_dev_fstype -# Echo the filesystem type for a given device. -# /proc/self/mountinfo is taken as the primary source of information -# and /etc/fstab is used as a fallback. -# No newline is appended! -# Example: -# $ find_dev_fstype /dev/sda2;echo -# ext4 -find_dev_fstype() { - local _find_dev _fs - _find_dev="$1" - if ! [[ $_find_dev == /dev* ]]; then - [[ -b "/dev/block/$_find_dev" ]] && _find_dev="/dev/block/$_find_dev" - fi - - if [[ $use_fstab != yes ]]; then - findmnt -e -v -n -o 'FSTYPE' --source "$_find_dev" | { - while read -r _fs || [ -n "$_fs" ]; do - [[ $_fs ]] || continue - [[ $_fs == "autofs" ]] && continue - printf "%s" "$_fs" - return 0 - done - return 1 - } && return 0 - fi - - findmnt --fstab -e -v -n -o 'FSTYPE' --source "$_find_dev" | { - while read -r _fs || [ -n "$_fs" ]; do - [[ $_fs ]] || continue - [[ $_fs == "autofs" ]] && continue - printf "%s" "$_fs" - return 0 - done - return 1 - } && return 0 - - return 1 -} - -# find_mp_fsopts -# Echo the filesystem options for a given mountpoint. -# /proc/self/mountinfo is taken as the primary source of information -# and /etc/fstab is used as a fallback. -# No newline is appended! -# Example: -# $ find_mp_fsopts /;echo -# rw,relatime,discard,data=ordered -find_mp_fsopts() { - if [[ $use_fstab != yes ]]; then - findmnt -e -v -n -o 'OPTIONS' --target "$1" 2> /dev/null && return 0 - fi - - findmnt --fstab -e -v -n -o 'OPTIONS' --target "$1" -} - -# find_dev_fsopts -# Echo the filesystem options for a given device. -# /proc/self/mountinfo is taken as the primary source of information -# and /etc/fstab is used as a fallback. -# if `use_fstab == yes`, then only `/etc/fstab` is used. -# -# Example: -# $ find_dev_fsopts /dev/sda2 -# rw,relatime,discard,data=ordered -find_dev_fsopts() { - local _find_dev - _find_dev="$1" - if ! [[ $_find_dev == /dev* ]]; then - [[ -b "/dev/block/$_find_dev" ]] && _find_dev="/dev/block/$_find_dev" - fi - - if [[ $use_fstab != yes ]]; then - findmnt -e -v -n -o 'OPTIONS' --source "$_find_dev" 2> /dev/null && return 0 - fi - - findmnt --fstab -e -v -n -o 'OPTIONS' --source "$_find_dev" -} - -# finds the major:minor of the block device backing the root filesystem. -find_root_block_device() { find_block_device /; } - -# for_each_host_dev_fs -# Execute " " for every " " pair found -# in ${host_fs_types[@]} -for_each_host_dev_fs() { - local _func="$1" - local _dev - local _ret=1 - - [[ "${#host_fs_types[@]}" ]] || return 2 - - for _dev in "${!host_fs_types[@]}"; do - $_func "$_dev" "${host_fs_types[$_dev]}" && _ret=0 - done - return $_ret -} - -host_fs_all() { - printf "%s\n" "${host_fs_types[@]}" -} - -# Walk all the slave relationships for a given block device. -# Stop when our helper function returns success -# $1 = function to call on every found block device -# $2 = block device in major:minor format -check_block_and_slaves() { - local _x - [[ -b /dev/block/$2 ]] || return 1 # Not a block device? So sorry. - if ! lvm_internal_dev "$2"; then "$1" "$2" && return; fi - check_vol_slaves "$@" && return 0 - if [[ -f /sys/dev/block/$2/../dev ]] && [[ /sys/dev/block/$2/../subsystem -ef /sys/class/block ]]; then - check_block_and_slaves "$1" "$(< "/sys/dev/block/$2/../dev")" && return 0 - fi - for _x in /sys/dev/block/"$2"/slaves/*; do - [[ -f $_x/dev ]] || continue - [[ $_x/subsystem -ef /sys/class/block ]] || continue - check_block_and_slaves "$1" "$(< "$_x/dev")" && return 0 - done - return 1 -} - -check_block_and_slaves_all() { - local _x _ret=1 - [[ -b /dev/block/$2 ]] || return 1 # Not a block device? So sorry. - if ! lvm_internal_dev "$2" && "$1" "$2"; then - _ret=0 - fi - check_vol_slaves_all "$@" && return 0 - if [[ -f /sys/dev/block/$2/../dev ]] && [[ /sys/dev/block/$2/../subsystem -ef /sys/class/block ]]; then - check_block_and_slaves_all "$1" "$(< "/sys/dev/block/$2/../dev")" && _ret=0 - fi - for _x in /sys/dev/block/"$2"/slaves/*; do - [[ -f $_x/dev ]] || continue - [[ $_x/subsystem -ef /sys/class/block ]] || continue - check_block_and_slaves_all "$1" "$(< "$_x/dev")" && _ret=0 - done - return $_ret -} -# for_each_host_dev_and_slaves -# Execute " " for every "" found -# in ${host_devs[@]} and their slaves -for_each_host_dev_and_slaves_all() { - local _func="$1" - local _dev - local _ret=1 - - [[ "${host_devs[*]}" ]] || return 2 - - for _dev in "${host_devs[@]}"; do - [[ -b $_dev ]] || continue - if check_block_and_slaves_all "$_func" "$(get_maj_min "$_dev")"; then - _ret=0 - fi - done - return $_ret -} - -for_each_host_dev_and_slaves() { - local _func="$1" - local _dev - - [[ "${host_devs[*]}" ]] || return 2 - - for _dev in "${host_devs[@]}"; do - [[ -b $_dev ]] || continue - check_block_and_slaves "$_func" "$(get_maj_min "$_dev")" && return 0 - done - return 1 -} - -# ugly workaround for the lvm design -# There is no volume group device, -# so, there are no slave devices for volume groups. -# Logical volumes only have the slave devices they really live on, -# but you cannot create the logical volume without the volume group. -# And the volume group might be bigger than the devices the LV needs. -check_vol_slaves() { - local _vg _pv _dm _majmin - _majmin="$2" - _dm=/sys/dev/block/$_majmin/dm - [[ -f $_dm/uuid && $(< "$_dm"/uuid) =~ LVM-* ]] || return 1 - _vg=$(dmsetup splitname --noheadings -o vg_name "$(< "$_dm/name")") - # strip space - _vg="${_vg//[[:space:]]/}" - if [[ $_vg ]]; then - for _pv in $(lvm vgs --noheadings -o pv_name "$_vg" 2> /dev/null); do - check_block_and_slaves "$1" "$(get_maj_min "$_pv")" && return 0 - done - fi - return 1 -} - -check_vol_slaves_all() { - local _vg _pv _majmin - _majmin="$2" - _dm="/sys/dev/block/$_majmin/dm" - [[ -f $_dm/uuid && $(< "$_dm"/uuid) =~ LVM-* ]] || return 1 - _vg=$(dmsetup splitname --noheadings -o vg_name "$(< "$_dm/name")") - # strip space - _vg="${_vg//[[:space:]]/}" - if [[ $_vg ]]; then - # when filter/global_filter is set, lvm may be failed - if ! lvm lvs --noheadings -o vg_name "$_vg" 2> /dev/null 1> /dev/null; then - return 1 - fi - - for _pv in $(lvm vgs --noheadings -o pv_name "$_vg" 2> /dev/null); do - check_block_and_slaves_all "$1" "$(get_maj_min "$_pv")" - done - return 0 - fi - return 1 -} - -# fs_get_option -# search for a specific option in a bunch of filesystem options -# and return the value -fs_get_option() { - local _fsopts=$1 - local _option=$2 - local OLDIFS="$IFS" - IFS=, - # shellcheck disable=SC2086 - set -- $_fsopts - IFS="$OLDIFS" - while [ $# -gt 0 ]; do - case $1 in - $_option=*) - echo "${1#${_option}=}" - break - ;; - esac - shift - done -} - -check_kernel_config() { - local _config_opt="$1" - local _config_file - [[ -f $dracutsysrootdir/boot/config-$kernel ]] \ - && _config_file="/boot/config-$kernel" - [[ -f $dracutsysrootdir/lib/modules/$kernel/config ]] \ - && _config_file="/lib/modules/$kernel/config" - - # no kernel config file, so return true - [[ $_config_file ]] || return 0 - - grep -q -F "${_config_opt}=" "$dracutsysrootdir$_config_file" && return 0 - return 1 -} - -# 0 if the kernel module is either built-in or available -# 1 if the kernel module is not enabled -check_kernel_module() { - modprobe -S "$kernel" --dry-run "$1" &> /dev/null || return 1 -} - -# get_cpu_vendor -# Only two values are returned: AMD or Intel -get_cpu_vendor() { - if grep -qE AMD /proc/cpuinfo; then - printf "AMD" - fi - if grep -qE Intel /proc/cpuinfo; then - printf "Intel" - fi -} - -# get_host_ucode -# Get the hosts' ucode file based on the /proc/cpuinfo -get_ucode_file() { - local family - local model - local stepping - family=$(grep -E "cpu family" /proc/cpuinfo | head -1 | sed "s/.*:\ //") - model=$(grep -E "model" /proc/cpuinfo | grep -v name | head -1 | sed "s/.*:\ //") - stepping=$(grep -E "stepping" /proc/cpuinfo | head -1 | sed "s/.*:\ //") - - if [[ "$(get_cpu_vendor)" == "AMD" ]]; then - if [[ $family -ge 21 ]]; then - printf "microcode_amd_fam%xh.bin" "$family" - else - printf "microcode_amd.bin" - fi - fi - if [[ "$(get_cpu_vendor)" == "Intel" ]]; then - # The /proc/cpuinfo are in decimal. - printf "%02x-%02x-%02x" "${family}" "${model}" "${stepping}" - fi -} - -# Not every device in /dev/mapper should be examined. -# If it is an LVM device, touch only devices which have /dev/VG/LV symlink. -lvm_internal_dev() { - local dev_dm_dir=/sys/dev/block/$1/dm - [[ ! -f $dev_dm_dir/uuid || $(< "$dev_dm_dir"/uuid) != LVM-* ]] && return 1 # Not an LVM device - local DM_VG_NAME DM_LV_NAME DM_LV_LAYER - eval "$(dmsetup splitname --nameprefixes --noheadings --rows "$(< "$dev_dm_dir"/name)" 2> /dev/null)" - [[ ${DM_VG_NAME} ]] && [[ ${DM_LV_NAME} ]] || return 0 # Better skip this! - [[ ${DM_LV_LAYER} ]] || [[ ! -L /dev/${DM_VG_NAME}/${DM_LV_NAME} ]] -} - -btrfs_devs() { - local _mp="$1" - btrfs device usage "$_mp" \ - | while read -r _dev _; do - str_starts "$_dev" "/" || continue - _dev=${_dev%,} - printf -- "%s\n" "$_dev" - done -} - -iface_for_remote_addr() { - # shellcheck disable=SC2046 - set -- $(ip -o route get to "$1") - echo "$3" -} - -local_addr_for_remote_addr() { - # shellcheck disable=SC2046 - set -- $(ip -o route get to "$1") - echo "$5" -} - -peer_for_addr() { - local addr=$1 - local qtd - - # quote periods in IPv4 address - qtd=${addr//./\\.} - ip -o addr show \ - | sed -n 's%^.* '"$qtd"' peer \([0-9a-f.:]\{1,\}\(/[0-9]*\)\?\).*$%\1%p' -} - -netmask_for_addr() { - local addr=$1 - local qtd - - # quote periods in IPv4 address - qtd=${addr//./\\.} - ip -o addr show | sed -n 's,^.* '"$qtd"'/\([0-9]*\) .*$,\1,p' -} - -gateway_for_iface() { - local ifname=$1 addr=$2 - - case $addr in - *.*) proto=4 ;; - *:*) proto=6 ;; - *) return ;; - esac - ip -o -$proto route show \ - | sed -n "s/^default via \([0-9a-z.:]\{1,\}\) dev $ifname .*\$/\1/p" -} - -# This works only for ifcfg-style network configuration! -bootproto_for_iface() { - local ifname=$1 - local dir - - # follow ifcfg settings for boot protocol - for dir in network-scripts network; do - [ -f "/etc/sysconfig/$dir/ifcfg-$ifname" ] && { - sed -n "s/BOOTPROTO=[\"']\?\([[:alnum:]]\{1,\}\)[\"']\?.*\$/\1/p" \ - "/etc/sysconfig/$dir/ifcfg-$ifname" - return - } - done -} - -is_unbracketed_ipv6_address() { - strglob "$1" '*:*' && ! strglob "$1" '\[*:*\]' -} - -# Create an ip= string to set up networking such that the given -# remote address can be reached -ip_params_for_remote_addr() { - local remote_addr=$1 - local ifname local_addr peer netmask gateway ifmac - - [[ $remote_addr ]] || return 1 - ifname=$(iface_for_remote_addr "$remote_addr") - [[ $ifname ]] || { - berror "failed to determine interface to connect to $remote_addr" - return 1 - } - - # ifname clause to bind the interface name to a MAC address - if [ -d "/sys/class/net/$ifname/bonding" ]; then - dinfo "Found bonded interface '${ifname}'. Make sure to provide an appropriate 'bond=' cmdline." - elif [ -e "/sys/class/net/$ifname/address" ]; then - ifmac=$(cat "/sys/class/net/$ifname/address") - [[ $ifmac ]] && printf 'ifname=%s:%s ' "${ifname}" "${ifmac}" - fi - - bootproto=$(bootproto_for_iface "$ifname") - case $bootproto in - dhcp | dhcp6 | auto6) ;; - dhcp4) - bootproto=dhcp - ;; - static* | "") - bootproto= - ;; - *) - derror "bootproto \"$bootproto\" is unsupported by dracut, trying static configuration" - bootproto= - ;; - esac - if [[ $bootproto ]]; then - printf 'ip=%s:%s ' "${ifname}" "${bootproto}" - else - local_addr=$(local_addr_for_remote_addr "$remote_addr") - [[ $local_addr ]] || { - berror "failed to determine local address to connect to $remote_addr" - return 1 - } - peer=$(peer_for_addr "$local_addr") - # Set peer or netmask, but not both - [[ $peer ]] || netmask=$(netmask_for_addr "$local_addr") - gateway=$(gateway_for_iface "$ifname" "$local_addr") - # Quote IPv6 addresses with brackets - is_unbracketed_ipv6_address "$local_addr" && local_addr="[$local_addr]" - is_unbracketed_ipv6_address "$peer" && peer="[$peer]" - is_unbracketed_ipv6_address "$gateway" && gateway="[$gateway]" - printf 'ip=%s:%s:%s:%s::%s:none ' \ - "${local_addr}" "${peer}" "${gateway}" "${netmask}" "${ifname}" - fi - -} - -# block_is_nbd -# Check whether $1 is an nbd device -block_is_nbd() { - [[ -b /dev/block/$1 && $1 == 43:* ]] -} - -# block_is_iscsi -# Check whether $1 is an nbd device -block_is_iscsi() { - local _dir - local _dev=$1 - [[ -L "/sys/dev/block/$_dev" ]] || return - _dir="$(readlink -f "/sys/dev/block/$_dev")" || return - until [[ -d "$_dir/sys" || -d "$_dir/iscsi_session" ]]; do - _dir="$_dir/.." - done - [[ -d "$_dir/iscsi_session" ]] -} - -# block_is_fcoe -# Check whether $1 is an FCoE device -# Will not work for HBAs that hide the ethernet aspect -# completely and present a pure FC device -block_is_fcoe() { - local _dir - local _dev=$1 - [[ -L "/sys/dev/block/$_dev" ]] || return - _dir="$(readlink -f "/sys/dev/block/$_dev")" - until [[ -d "$_dir/sys" ]]; do - _dir="$_dir/.." - if [[ -d "$_dir/subsystem" ]]; then - subsystem=$(basename "$(readlink "$_dir"/subsystem)") - [[ $subsystem == "fcoe" ]] && return 0 - fi - done - return 1 -} - -# block_is_netdevice -# Check whether $1 is a net device -block_is_netdevice() { - block_is_nbd "$1" || block_is_iscsi "$1" || block_is_fcoe "$1" -} - -# convert the driver name given by udevadm to the corresponding kernel module name -get_module_name() { - local dev_driver - while read -r dev_driver; do - case "$dev_driver" in - mmcblk) - echo "mmc_block" - ;; - *) - echo "$dev_driver" - ;; - esac - done -} - -# get the corresponding kernel modules of a /sys/class/*/* or/dev/* device -get_dev_module() { - #udevadm info -a "$1" | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' - local dev_attr_walk - local dev_drivers - local dev_paths - dev_attr_walk=$(udevadm info -a "$1") - dev_drivers=$(echo "$dev_attr_walk" \ - | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' \ - | get_module_name) - - # also return modalias info from sysfs paths parsed by udevadm - dev_paths=$(echo "$dev_attr_walk" | sed -n 's/.*\(\/devices\/.*\)'\'':/\1/p') - local dev_path - for dev_path in $dev_paths; do - local modalias_file="/sys$dev_path/modalias" - if [ -e "$modalias_file" ]; then - dev_drivers="$(printf "%s\n%s" "$dev_drivers" "$(cat "$modalias_file")")" - fi - done - - # if no kernel modules found and device is in a virtual subsystem, follow symlinks - if [[ -z $dev_drivers && $(udevadm info -q path "$1") == "/devices/virtual"* ]]; then - local dev_vkernel - local dev_vsubsystem - local dev_vpath - dev_vkernel=$(echo "$dev_attr_walk" | sed -n 's/\s*KERNELS=="\(\S\+\)"/\1/p' | tail -1) - dev_vsubsystem=$(echo "$dev_attr_walk" | sed -n 's/\s*SUBSYSTEMS=="\(\S\+\)"/\1/p' | tail -1) - dev_vpath="/sys/devices/virtual/$dev_vsubsystem/$dev_vkernel" - if [[ -n $dev_vkernel && -n $dev_vsubsystem && -d $dev_vpath ]]; then - local dev_links - local dev_link - dev_links=$(find "$dev_vpath" -maxdepth 1 -type l ! -name "subsystem" -exec readlink {} \;) - for dev_link in $dev_links; do - [[ -n $dev_drivers && ${dev_drivers: -1} != $'\n' ]] && dev_drivers+=$'\n' - dev_drivers+=$(udevadm info -a "$dev_vpath/$dev_link" \ - | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' \ - | get_module_name \ - | grep -v -e pcieport) - done - fi - fi - echo "$dev_drivers" -} -- Gitee