merge latest functions from mkinitcpio git

This commit is contained in:
Tobias Powalowski 2023-02-16 21:20:32 +01:00
parent 38d9ac29e0
commit f4970abec4

View file

@ -2,11 +2,11 @@
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
parseopts() { parseopts() {
local opt= optarg= i= shortopts=$1 local opt='' optarg='' i='' shortopts="$1"
local -a longopts=() unused_argv=() local -a longopts=() unused_argv=()
shift shift
while [[ $1 && $1 != '--' ]]; do while [[ -n "$1" && "$1" != '--' ]]; do
longopts+=("$1") longopts+=("$1")
shift shift
done done
@ -15,18 +15,18 @@ parseopts() {
longoptmatch() { longoptmatch() {
local o longmatch=() local o longmatch=()
for o in "${longopts[@]}"; do for o in "${longopts[@]}"; do
if [[ ${o%:} = "$1" ]]; then if [[ "${o%:}" == "$1" ]]; then
longmatch=("$o") longmatch=("$o")
break break
fi fi
[[ ${o%:} = "$1"* ]] && longmatch+=("$o") [[ "${o%:}" == "$1"* ]] && longmatch+=("$o")
done done
case ${#longmatch[*]} in case "${#longmatch[*]}" in
1) 1)
# success, override with opt and return arg req (0 == none, 1 == required) # success, override with opt and return arg req (0 == none, 1 == required)
opt=${longmatch%:} opt="${longmatch%:}"
if [[ $longmatch = *: ]]; then if [[ "${longmatch[*]}" == *: ]]; then
return 1 return 1
else else
return 0 return 0
@ -43,7 +43,7 @@ parseopts() {
} }
while (( $# )); do while (( $# )); do
case $1 in case "$1" in
--) # explicit end of options --) # explicit end of options
shift shift
break break
@ -61,13 +61,13 @@ parseopts() {
OPTRET+=("-$opt") OPTRET+=("-$opt")
# option requires optarg # option requires optarg
if [[ $shortopts = *$opt:* ]]; then if [[ "$shortopts" == *"${opt}:"* ]]; then
# if we're not at the end of the option chunk, the rest is the optarg # if we're not at the end of the option chunk, the rest is the optarg
if (( i < ${#1} - 1 )); then if (( i < ${#1} - 1 )); then
OPTRET+=("${1:i+1}") OPTRET+=("${1:i+1}")
break break
# if we're at the end, grab the the next positional, if it exists # if we're at the end, grab the the next positional, if it exists
elif (( i == ${#1} - 1 )) && [[ $2 ]]; then elif (( i == ${#1} - 1 )) && [[ -n "$2" ]]; then
OPTRET+=("$2") OPTRET+=("$2")
shift shift
break break
@ -85,7 +85,7 @@ parseopts() {
longoptmatch "$opt" longoptmatch "$opt"
case $? in case $? in
0) 0)
if [[ $optarg ]]; then if [[ -n "$optarg" ]]; then
printf "%s: option '--%s' doesn't allow an argument\n" "${0##*/}" "$opt" printf "%s: option '--%s' doesn't allow an argument\n" "${0##*/}" "$opt"
OPTRET=(--) OPTRET=(--)
return 1 return 1
@ -95,10 +95,10 @@ parseopts() {
;; ;;
1) 1)
# --longopt=optarg # --longopt=optarg
if [[ $optarg ]]; then if [[ -n "$optarg" ]]; then
OPTRET+=("--$opt" "$optarg") OPTRET+=("--$opt" "$optarg")
# --longopt optarg # --longopt optarg
elif [[ $2 ]]; then elif [[ -n "$2" ]]; then
OPTRET+=("--$opt" "$2" ) OPTRET+=("--$opt" "$2" )
shift shift
else else
@ -135,15 +135,16 @@ parseopts() {
} }
kver_x86() { kver_x86() {
local kver
local -i offset
# scrape the version out of the kernel image. locate the offset # scrape the version out of the kernel image. locate the offset
# to the version string by reading 2 bytes out of image at at # to the version string by reading 2 bytes out of image at at
# address 0x20E. this leads us to a string of, at most, 128 bytes. # address 0x20E. this leads us to a string of, at most, 128 bytes.
# read the first word from this string as the kernel version. # read the first word from this string as the kernel version.
local kver offset=$(hexdump -s 526 -n 2 -e '"%0d"' "$1") offset="$(od -An -j0x20E -dN2 "$1")" || return
[[ $offset = +([0-9]) ]] || return 1
read kver _ < \ read -r kver _ < \
<(dd if="$1" bs=1 count=127 skip=$(( offset + 0x200 )) 2>/dev/null) <(dd if="$1" bs=1 count=127 skip=$((offset + 0x200)) 2>/dev/null)
printf '%s' "$kver" printf '%s' "$kver"
} }
@ -151,45 +152,45 @@ kver_x86() {
detect_compression() { detect_compression() {
local bytes local bytes
read -rd '' bytes < <(hexdump -n 6 -e '"%c"' "$1") bytes="$(od -An -t x1 -N6 "$1" | tr -dc '[:alnum:]')"
case $bytes in case "$bytes" in
$'\xfd7zXZ') 'fd377a585a00')
echo 'xz' echo 'xz'
return return
;; ;;
esac esac
read -rd '' bytes < <(hexdump -n 4 -e '"%c"' "$1") bytes="$(od -An -t x1 -N4 "$1" | tr -dc '[:alnum:]')"
if [[ $bytes = $'\x89LZO' ]]; then if [[ "$bytes" == '894c5a4f' ]]; then
echo 'lzop' echo 'lzop'
return return
fi fi
read -rd '' bytes < <(hexdump -n 2 -e '"%x"' "$1") bytes="$(od -An -t x2 -N2 "$1" | tr -dc '[:alnum:]')"
if [[ $bytes = '8b1f' ]]; then if [[ "$bytes" == '8b1f' ]]; then
echo 'gzip' echo 'gzip'
return return
fi fi
read -rd '' bytes < <(hexdump -n 4 -e '"%x"' "$1") bytes="$(od -An -t x4 -N4 "$1" | tr -dc '[:alnum:]')"
case $bytes in case "$bytes" in
184d2204) '184d2204')
error 'Newer lz4 stream format detected! This may not boot!' error 'Newer lz4 stream format detected! This may not boot!'
echo 'lz4' echo 'lz4'
return return
;; ;;
184c2102) '184c2102')
echo 'lz4 -l' echo 'lz4 -l'
return return
;; ;;
fd2fb528) 'fd2fb528')
echo 'zstd' echo 'zstd'
return return
;; ;;
esac esac
read -rd '' bytes < <(hexdump -n 3 -e '"%c"' "$1") bytes="$(od -An -c -N3 "$1" | tr -dc '[:alnum:]')"
if [[ $bytes == 'BZh' ]]; then if [[ "$bytes" == 'BZh' ]]; then
echo 'bzip2' echo 'bzip2'
return return
fi fi
@ -198,8 +199,8 @@ detect_compression() {
# do it without reading large portions of the stream. this # do it without reading large portions of the stream. this
# check is good enough for GNU tar, apparently, so it's good # check is good enough for GNU tar, apparently, so it's good
# enough for me. # enough for me.
read -rd '' bytes < <(hexdump -n 3 -e '"%x"' "$1") bytes="$(od -An -t x1 -N3 "$1" | tr -dc '[:alnum:]')"
if [[ $bytes = '5d' ]]; then if [[ "$bytes" == '5d0000' ]]; then
echo 'lzma' echo 'lzma'
return return
fi fi
@ -216,11 +217,11 @@ kver_generic() {
# Loosely grep for `linux_banner`: # Loosely grep for `linux_banner`:
# https://elixir.bootlin.com/linux/v5.7.2/source/init/version.c#L46 # https://elixir.bootlin.com/linux/v5.7.2/source/init/version.c#L46
local kver= reader=cat local kver='' reader='cat'
[[ $(detect_compression "$1") == 'gzip' ]] && reader=zcat [[ "$(detect_compression "$1")" == 'gzip' ]] && reader='zcat'
read _ _ kver _ < <($reader "$1" | grep -m1 -aoE 'Linux version .(\.[-[:alnum:]+]+)+') read -r _ _ kver _ < <($reader "$1" | grep -m1 -aoE 'Linux version .(\.[-[:alnum:]+]+)+')
printf '%s' "$kver" printf '%s' "$kver"
} }
@ -232,44 +233,52 @@ kver() {
# requirement for CONFIG_LOCALVERSION to be set. # requirement for CONFIG_LOCALVERSION to be set.
local kver re='^[[:digit:]]+(\.[[:digit:]]+)+' local kver re='^[[:digit:]]+(\.[[:digit:]]+)+'
local arch=$(uname -m) local arch
arch="$(uname -m)"
if [[ $arch == @(i?86|x86_64) ]]; then if [[ $arch == @(i?86|x86_64) ]]; then
kver=$(kver_x86 "$1") kver="$(kver_x86 "$1")"
else else
kver=$(kver_generic "$1") kver="$(kver_generic "$1")"
fi fi
[[ $kver =~ $re ]] || return 1 [[ "$kver" =~ $re ]] || return 1
printf '%s' "$kver" printf '%s' "$kver"
} }
plain() { plain() {
local mesg=$1; shift local mesg="$1"; shift
# shellcheck disable=SC2059
printf " $_color_bold$mesg$_color_none\n" "$@" >&1 printf " $_color_bold$mesg$_color_none\n" "$@" >&1
} }
quiet() { quiet() {
# _optquiet is assigned in mkinitcpio
# shellcheck disable=SC2154
(( _optquiet )) || plain "$@" (( _optquiet )) || plain "$@"
} }
msg() { msg() {
local mesg=$1; shift local mesg="$1"; shift
# shellcheck disable=SC2059
printf "$_color_green==>$_color_none $_color_bold$mesg$_color_none\n" "$@" >&1 printf "$_color_green==>$_color_none $_color_bold$mesg$_color_none\n" "$@" >&1
} }
msg2() { msg2() {
local mesg=$1; shift local mesg="$1"; shift
# shellcheck disable=SC2059
printf " $_color_blue->$_color_none $_color_bold$mesg$_color_none\n" "$@" >&1 printf " $_color_blue->$_color_none $_color_bold$mesg$_color_none\n" "$@" >&1
} }
warning() { warning() {
local mesg=$1; shift local mesg="$1"; shift
# shellcheck disable=SC2059
printf "$_color_yellow==> WARNING:$_color_none $_color_bold$mesg$_color_none\n" "$@" >&2 printf "$_color_yellow==> WARNING:$_color_none $_color_bold$mesg$_color_none\n" "$@" >&2
} }
error() { error() {
local mesg=$1; shift local mesg="$1"; shift
# shellcheck disable=SC2059
printf "$_color_red==> ERROR:$_color_none $_color_bold$mesg$_color_none\n" "$@" >&2 printf "$_color_red==> ERROR:$_color_none $_color_bold$mesg$_color_none\n" "$@" >&2
return 1 return 1
} }
@ -284,16 +293,16 @@ map() {
for _ in "${@:2}"; do for _ in "${@:2}"; do
"$1" "$_" || (( $# > 255 ? r=1 : ++r )) "$1" "$_" || (( $# > 255 ? r=1 : ++r ))
done done
return $r return "$r"
} }
arrayize_config() { arrayize_config() {
set -f set -f
[[ ${MODULES@a} != *a* ]] && MODULES=($MODULES) [[ ${MODULES@a} != *a* ]] && IFS=' ' read -r -a MODULES <<< "$MODULES"
[[ ${BINARIES@a} != *a* ]] && BINARIES=($BINARIES) [[ ${BINARIES@a} != *a* ]] && IFS=' ' read -r -a BINARIES <<< "$BINARIES"
[[ ${FILES@a} != *a* ]] && FILES=($FILES) [[ ${FILES@a} != *a* ]] && IFS=' ' read -r -a FILES <<< "$FILES"
[[ ${HOOKS@a} != *a* ]] && HOOKS=($HOOKS) [[ ${HOOKS@a} != *a* ]] && IFS=' ' read -r -a HOOKS <<< "$HOOKS"
[[ ${COMPRESSION_OPTIONS@a} != *a* ]] && COMPRESSION_OPTIONS=($COMPRESSION_OPTIONS) [[ ${COMPRESSION_OPTIONS@a} != *a* ]] && IFS=' ' read -r -a COMPRESSION_OPTIONS <<< "$COMPRESSION_OPTIONS"
set +f set +f
} }
@ -302,10 +311,10 @@ in_array() {
# $1: needle # $1: needle
# ${@:2}: haystack # ${@:2}: haystack
local item= needle=$1; shift local item='' needle="$1"; shift
for item in "$@"; do for item in "$@"; do
[[ $item = $needle ]] && return 0 # Found [[ "$item" == "$needle" ]] && return 0 # Found
done done
return 1 # Not Found return 1 # Not Found
} }
@ -313,10 +322,10 @@ in_array() {
index_of() { index_of() {
# get the array index of an item. sets the global var _idx with # get the array index of an item. sets the global var _idx with
# index and returns 0 if found, otherwise returns 1. # index and returns 0 if found, otherwise returns 1.
local item=$1; shift local item="$1"; shift
for (( _idx=1; _idx <= $#; _idx++ )); do for (( _idx=1; _idx <= $#; _idx++ )); do
if [[ $item = ${!_idx} ]]; then if [[ "$item" == "${!_idx}" ]]; then
(( --_idx )) (( --_idx ))
return 0 return 0
fi fi
@ -338,7 +347,9 @@ funcgrep() {
list_hookpoints() { list_hookpoints() {
local funcs script local funcs script
script=$(PATH=$_d_hooks type -P "$1") || return 0 # _d_hooks is assigned in mkinitcpio
# shellcheck disable=SC2154
script="$(PATH="$_d_hooks" type -P "$1")" || return 0
mapfile -t funcs < <(funcgrep '^run_[[:alnum:]_]+' "$script") mapfile -t funcs < <(funcgrep '^run_[[:alnum:]_]+' "$script")
@ -351,13 +362,15 @@ list_hookpoints() {
} }
modprobe() { modprobe() {
# _optmoduleroot is assigned in mkinitcpio
# shellcheck disable=SC2154
command modprobe -d "$_optmoduleroot" -S "$KERNELVERSION" "$@" command modprobe -d "$_optmoduleroot" -S "$KERNELVERSION" "$@"
} }
auto_modules() { auto_modules() {
# Perform auto detection of modules via sysfs. # Perform auto detection of modules via sysfs.
local mods= local mods=()
mapfile -t mods < <(find /sys/devices -name uevent \ mapfile -t mods < <(find /sys/devices -name uevent \
-exec sort -u {} + | awk -F= '$1 == "MODALIAS" && !_[$0]++') -exec sort -u {} + | awk -F= '$1 == "MODALIAS" && !_[$0]++')
@ -372,21 +385,23 @@ all_modules() {
# -f FILTER: ERE to filter found modules # -f FILTER: ERE to filter found modules
local -i count=0 local -i count=0
local mod= OPTIND= OPTARG= filter=() local mod='' OPTIND='' OPTARG='' modfilter=()
while getopts ':f:' flag; do while getopts ':f:' flag; do
case $flag in f) filter+=("$OPTARG") ;; esac [[ "$flag" = "f" ]] && modfilter+=("$OPTARG")
done done
shift $(( OPTIND - 1 )) shift $(( OPTIND - 1 ))
# _d_kmoduledir is assigned in mkinitcpio
# shellcheck disable=SC2154
while read -r -d '' mod; do while read -r -d '' mod; do
(( ++count )) (( ++count ))
for f in "${filter[@]}"; do for f in "${modfilter[@]}"; do
[[ $mod =~ $f ]] && continue 2 [[ "$mod" =~ $f ]] && continue 2
done done
mod=${mod##*/} mod="${mod##*/}"
mod="${mod%.ko*}" mod="${mod%.ko*}"
printf '%s\n' "${mod//-/_}" printf '%s\n' "${mod//-/_}"
done < <(find "$_d_kmoduledir" -name '*.ko*' -print0 2>/dev/null | grep -EZz "$@") done < <(find "$_d_kmoduledir" -name '*.ko*' -print0 2>/dev/null | grep -EZz "$@")
@ -398,7 +413,8 @@ add_all_modules() {
# Add modules to the initcpio. # Add modules to the initcpio.
# $@: arguments to all_modules # $@: arguments to all_modules
local mod mods local mod
local -a mods
mapfile -t mods < <(all_modules "$@") mapfile -t mods < <(all_modules "$@")
map add_module "${mods[@]}" map add_module "${mods[@]}"
@ -411,8 +427,11 @@ add_checked_modules() {
# modules. # modules.
# $@: arguments to all_modules # $@: arguments to all_modules
local mod mods local mod
local -a mods
# _autodetect_cache is declared in mkinitcpio and assigned in install/autodetect
# shellcheck disable=SC2154
if (( ${#_autodetect_cache[*]} )); then if (( ${#_autodetect_cache[*]} )); then
mapfile -t mods < <(all_modules "$@" | grep -xFf <(printf '%s\n' "${!_autodetect_cache[@]}")) mapfile -t mods < <(all_modules "$@" | grep -xFf <(printf '%s\n' "${!_autodetect_cache[@]}"))
else else
@ -431,6 +450,8 @@ add_firmware() {
local fw fwpath r=0 local fw fwpath r=0
for fw; do for fw; do
# _d_firmware is assigned in mkinitcpio
# shellcheck disable=SC2154
for fwpath in "${_d_firmware[@]}"; do for fwpath in "${_d_firmware[@]}"; do
if [[ -f $fwpath/$fw.xz ]]; then if [[ -f $fwpath/$fw.xz ]]; then
add_file "$fwpath/$fw.xz" "$fwpath/$fw.xz" && r=0 add_file "$fwpath/$fw.xz" "$fwpath/$fw.xz" && r=0
@ -445,7 +466,7 @@ add_firmware() {
done done
done done
return $r return "$r"
} }
add_module() { add_module() {
@ -453,17 +474,17 @@ add_module() {
# discovered and added. # discovered and added.
# $1: module name # $1: module name
local target= module= softdeps= deps= field= value= firmware=() local target='' module='' softdeps=() deps=() field='' value='' firmware=()
local ign_errors=0 found=0 local ign_errors=0 found=0
[[ $KERNELVERSION == none ]] && return 0 [[ "$KERNELVERSION" == 'none' ]] && return 0
if [[ $1 = *\? ]]; then if [[ "$1" == *\? ]]; then
ign_errors=1 ign_errors=1
set -- "${1%?}" set -- "${1%?}"
fi fi
target=${1%.ko*} target=${target//-/_} target="${1%.ko*}" target="${target//-/_}"
# skip expensive stuff if this module has already been added # skip expensive stuff if this module has already been added
(( _addedmodules["$target"] == 1 )) && return (( _addedmodules["$target"] == 1 )) && return
@ -475,9 +496,9 @@ add_module() {
# it might be reported as "(builtin)"). We'll defer actually # it might be reported as "(builtin)"). We'll defer actually
# checking whether or not the file exists -- any errors can be # checking whether or not the file exists -- any errors can be
# handled during module install time. # handled during module install time.
if [[ $value = /* ]]; then if [[ "$value" == /* ]]; then
found=1 found=1
module=${value##*/} module=${module%.ko*} module="${value##*/}" module="${module%.ko*}"
quiet "adding module: %s (%s)" "$module" "$value" quiet "adding module: %s (%s)" "$module" "$value"
_modpaths["$value"]=1 _modpaths["$value"]=1
_addedmodules["${module//-/_}"]=1 _addedmodules["${module//-/_}"]=1
@ -502,17 +523,17 @@ add_module() {
if (( !found )); then if (( !found )); then
(( ign_errors || _addedmodules["$target"] )) && return 0 (( ign_errors || _addedmodules["$target"] )) && return 0
error "module not found: \`%s'" "$target" error "module not found: '%s'" "$target"
return 1 return 1
fi fi
if (( ${#firmware[*]} )); then if (( ${#firmware[*]} )); then
add_firmware "${firmware[@]}" || add_firmware "${firmware[@]}" ||
warning 'Possibly missing firmware for module: %s' "$target" warning "Possibly missing firmware for module: '%s'" "$target"
fi fi
# handle module quirks # handle module quirks
case $target in case "$target" in
fat) fat)
add_module "nls_ascii?" # from CONFIG_FAT_DEFAULT_IOCHARSET add_module "nls_ascii?" # from CONFIG_FAT_DEFAULT_IOCHARSET
add_module "nls_cp437?" # from CONFIG_FAT_DEFAULT_CODEPAGE add_module "nls_cp437?" # from CONFIG_FAT_DEFAULT_CODEPAGE
@ -537,7 +558,7 @@ add_full_dir() {
# No parsing is performed and the contents of the directory is added as is. # No parsing is performed and the contents of the directory is added as is.
# $1: path to directory # $1: path to directory
if [[ -n $1 && -d $1 ]]; then if [[ -n $1 && -d $1 ]]; then
command tar -C / -cpf - ."$src" | tar -C "${BUILDROOT}" -xpf - command tar -C / -cpf - ."$1"/* | tar -C "${BUILDROOT}" -xspf -
fi fi
} }
@ -546,19 +567,20 @@ add_dir() {
# $1: pathname on initcpio # $1: pathname on initcpio
# $2: mode (optional) # $2: mode (optional)
if [[ -z $1 || $1 != /?* ]]; then if [[ -z "$1" || "$1" != /?* ]]; then
return 1 return 1
fi fi
local path=$1 mode=${2:-755} local path="$1" mode="${2:-755}"
if [[ -d $BUILDROOT$1 ]]; then # shellcheck disable=SC2153
if [[ -d "${BUILDROOT}${1}" ]]; then
# ignore dir already exists # ignore dir already exists
return 0 return 0
fi fi
quiet "adding dir: %s" "$path" quiet "adding dir: %s" "$path"
command install -dm$mode "$BUILDROOT$path" command install -dm"${mode}" "${BUILDROOT}${path}"
} }
add_symlink() { add_symlink() {
@ -585,18 +607,18 @@ add_symlink() {
target="$(realpath -eq -- "$target")" target="$(realpath -eq -- "$target")"
fi fi
if [[ -z "$target" ]]; then if [[ -z "$target" ]]; then
error 'invalid symlink: %s' "$name" error "invalid symlink: '%s'" "$name"
return 1 return 1
fi fi
add_dir "${name%/*}" add_dir "${name%/*}"
if [[ -L $BUILDROOT$1 ]]; then if [[ -L "${BUILDROOT}${1}" ]]; then
quiet "overwriting symlink %s -> %s" "$name" "$target" quiet "overwriting symlink %s -> %s" "$name" "$target"
else else
quiet "adding symlink: %s -> %s" "$name" "$target" quiet "adding symlink: %s -> %s" "$name" "$target"
fi fi
ln -sfn "$target" "$BUILDROOT$name" ln -sfn "$target" "${BUILDROOT}${name}"
} }
add_file() { add_file() {
@ -611,8 +633,8 @@ add_file() {
# determine source and destination # determine source and destination
local src="$1" dest="${2:-$1}" mode="$3" srcrealpath local src="$1" dest="${2:-$1}" mode="$3" srcrealpath
if [[ ! -f $src ]]; then if [[ ! -f "$src" ]]; then
error "file not found: \`%s'" "$src" error "file not found: '%s'" "$src"
return 1 return 1
fi fi
if [[ ! -e "${BUILDROOT}${dest}" ]]; then if [[ ! -e "${BUILDROOT}${dest}" ]]; then
@ -637,10 +659,11 @@ add_runscript() {
# Adds a runtime script to the initcpio image. The name is derived from the # Adds a runtime script to the initcpio image. The name is derived from the
# script which calls it as the basename of the caller. # script which calls it as the basename of the caller.
local funcs fn script hookname=${BASH_SOURCE[1]##*/} local fn script hookname="${BASH_SOURCE[1]##*/}"
local -a funcs
if ! script=$(PATH=$_d_hooks type -P "$hookname"); then if ! script="$(PATH="$_d_hooks" type -P "$hookname")"; then
error "runtime script for \`%s' not found" "$hookname" error "runtime script for '%s' not found" "$hookname"
return return
fi fi
@ -675,21 +698,20 @@ add_binary() {
# $1: path to binary # $1: path to binary
# $2: destination on initcpio (optional, defaults to same as source) # $2: destination on initcpio (optional, defaults to same as source)
local -a sodeps
local line='' regex='' binary='' dest='' mode='' sodep='' resolved='' shebang='' interpreter='' local line='' regex='' binary='' dest='' mode='' sodep='' resolved='' shebang='' interpreter=''
if [[ ${1:0:1} != '/' ]]; then if [[ "${1:0:1}" != '/' ]]; then
binary=$(type -P "$1") binary="$(type -P "$1")"
else else
binary=$1 binary="$1"
fi fi
if [[ ! -f $binary ]]; then if [[ ! -f "$binary" ]]; then
error "file not found: \`%s'" "$1" error "file not found: '%s'" "$1"
return 1 return 1
fi fi
dest=${2:-$binary} dest="${2:-$binary}"
add_file "$binary" "$dest" add_file "$binary" "$dest"
@ -706,7 +728,7 @@ add_binary() {
fi fi
# strip parameters # strip parameters
interpreter="${interpreter%%[[:space:]]*}" interpreter="${interpreter%%[[:space:]]*}"
# lookup the interpreter in PATH on BUILDROOT # check if the interpreter exists in BUILDROOT
if [[ "$interpreter" != '/'* ]] && PATH="${BUILDROOT}/usr/local/sbin:${BUILDROOT}/usr/local/bin:${BUILDROOT}/usr/bin" type -P "$interpreter" &>/dev/null; then if [[ "$interpreter" != '/'* ]] && PATH="${BUILDROOT}/usr/local/sbin:${BUILDROOT}/usr/local/bin:${BUILDROOT}/usr/bin" type -P "$interpreter" &>/dev/null; then
: :
elif [[ -e "${BUILDROOT}/${interpreter}" ]]; then elif [[ -e "${BUILDROOT}/${interpreter}" ]]; then
@ -721,15 +743,15 @@ add_binary() {
# resolve sodeps # resolve sodeps
regex='^(|.+ )(/.+) \(0x[a-fA-F0-9]+\)' regex='^(|.+ )(/.+) \(0x[a-fA-F0-9]+\)'
while read -r line; do while read -r line; do
if [[ $line =~ $regex ]]; then if [[ "$line" =~ $regex ]]; then
sodep=${BASH_REMATCH[2]} sodep="${BASH_REMATCH[2]}"
elif [[ $line = *'not found' ]]; then elif [[ "$line" = *'not found' ]]; then
error "binary dependency \`%s' not found for \`%s'" "${line%% *}" "$1" error "binary dependency '%s' not found for '%s'" "${line%% *}" "$1"
(( ++_builderrors )) (( ++_builderrors ))
continue continue
fi fi
if [[ -f $sodep && ! -e $BUILDROOT$sodep ]]; then if [[ -f "$sodep" && ! -e "${BUILDROOT}${sodep}" ]]; then
add_file "$sodep" "$sodep" add_file "$sodep" "$sodep"
fi fi
done <<< "$lddout" done <<< "$lddout"
@ -742,12 +764,12 @@ add_udev_rule() {
# will be discovered and added. # will be discovered and added.
# $1: path to rules file (or name of rules file) # $1: path to rules file (or name of rules file)
local rules="$1" rule= key= value= binary= local rules="$1" rule=() key='' value='' binary=''
if [[ ${rules:0:1} != '/' ]]; then if [[ "${rules:0:1}" != '/' ]]; then
rules=$(PATH=/usr/lib/udev/rules.d:/lib/udev/rules.d type -P "$rules") rules="$(PATH='/usr/lib/udev/rules.d:/lib/udev/rules.d' type -P "$rules")"
fi fi
if [[ -z $rules ]]; then if [[ -z "$rules" ]]; then
# complain about not found rules # complain about not found rules
return 1 return 1
fi fi
@ -756,19 +778,19 @@ add_udev_rule() {
while IFS=, read -ra rule; do while IFS=, read -ra rule; do
# skip empty lines, comments # skip empty lines, comments
[[ -z $rule || $rule = @(+([[:space:]])|#*) ]] && continue [[ -z "$rule" || "$rule" == @(+([[:space:]])|#*) ]] && continue
for pair in "${rule[@]}"; do for pair in "${rule[@]}"; do
IFS=' =' read -r key value <<< "$pair" IFS=' =' read -r key value <<< "$pair"
case $key in case "$key" in
RUN{program}|RUN+|IMPORT{program}|ENV{REMOVE_CMD}) 'RUN{program}'|'RUN+'|'IMPORT{program}'|'ENV{REMOVE_CMD}')
# strip quotes # strip quotes
binary=${value//[\"\']/} binary="${value//[\"\']/}"
# just take the first word as the binary name # just take the first word as the binary name
binary=${binary%% *} binary="${binary%% *}"
[[ ${binary:0:1} == '$' ]] && continue [[ "${binary:0:1}" == '$' ]] && continue
if [[ ${binary:0:1} != '/' ]]; then if [[ "${binary:0:1}" != '/' ]]; then
binary=$(PATH=/usr/lib/udev:/lib/udev type -P "$binary") binary="$(PATH='/usr/lib/udev:/lib/udev' type -P "$binary")"
fi fi
add_binary "$binary" add_binary "$binary"
;; ;;
@ -791,13 +813,14 @@ parse_config() {
# MODULES before re-sourcing the config. # MODULES before re-sourcing the config.
unset MODULES unset MODULES
# shellcheck disable=SC1091
. /dev/stdin . /dev/stdin
# arrayize MODULES if necessary. # arrayize MODULES if necessary.
[[ ${MODULES@a} != *a* ]] && read -ra MODULES <<<"${MODULES//-/_}" [[ ${MODULES@a} != *a* ]] && read -ra MODULES <<<"${MODULES//-/_}"
for mod in "${MODULES[@]%\?}"; do for mod in "${MODULES[@]%\?}"; do
mod=${mod//-/_} mod="${mod//-/_}"
# only add real modules (2 == builtin) # only add real modules (2 == builtin)
(( _addedmodules["$mod"] == 1 )) && add+=("$mod") (( _addedmodules["$mod"] == 1 )) && add+=("$mod")
done done
@ -815,15 +838,16 @@ initialize_buildroot() {
# creates a temporary directory for the buildroot and initialize it with a # creates a temporary directory for the buildroot and initialize it with a
# basic set of necessary directories and symlinks # basic set of necessary directories and symlinks
local workdir= kernver=$1 arch=$(uname -m) buildroot osreleasefile local workdir='' kernver="$1" arch buildroot osreleasefile
arch="$(uname -m)"
if ! workdir=$(mktemp -d --tmpdir mkinitcpio.XXXXXX); then if ! workdir="$(mktemp -d --tmpdir mkinitcpio.XXXXXX)"; then
error 'Failed to create temporary working directory in %s' "${TMPDIR:-/tmp}" error 'Failed to create temporary working directory in %s' "${TMPDIR:-/tmp}"
return 1 return 1
fi fi
buildroot=${2:-$workdir/root} buildroot="${2:-$workdir/root}"
if [[ ! -w ${2:-$workdir} ]]; then if [[ ! -w "${2:-$workdir}" ]]; then
error 'Unable to write to build root: %s' "$buildroot" error 'Unable to write to build root: %s' "$buildroot"
return 1 return 1
fi fi
@ -836,7 +860,7 @@ initialize_buildroot() {
ln -s "usr/bin" "$buildroot/sbin" ln -s "usr/bin" "$buildroot/sbin"
ln -s "/run" "$buildroot/var/run" ln -s "/run" "$buildroot/var/run"
case $arch in case "$arch" in
x86_64) x86_64)
ln -s "lib" "$buildroot/usr/lib64" ln -s "lib" "$buildroot/usr/lib64"
ln -s "usr/lib" "$buildroot/lib64" ln -s "usr/lib" "$buildroot/lib64"
@ -844,14 +868,15 @@ initialize_buildroot() {
esac esac
# mkinitcpio version stamp # mkinitcpio version stamp
# shellcheck disable=SC2154
printf '%s' "$version" >"$buildroot/VERSION" printf '%s' "$version" >"$buildroot/VERSION"
# kernel module dir # kernel module dir
[[ $kernver != none ]] && install -dm755 "$buildroot/usr/lib/modules/$kernver/kernel" [[ "$kernver" != 'none' ]] && install -dm755 "$buildroot/usr/lib/modules/$kernver/kernel"
# mount tables # mount tables
ln -s ../proc/self/mounts "$buildroot/etc/mtab" ln -s ../proc/self/mounts "$buildroot/etc/mtab"
>"$buildroot/etc/fstab" : >"$buildroot/etc/fstab"
# add os-release and initrd-release for systemd # add os-release and initrd-release for systemd
if [[ -e /etc/os-release ]]; then if [[ -e /etc/os-release ]]; then
@ -865,41 +890,44 @@ initialize_buildroot() {
ln -sT os-release "${buildroot}/etc/initrd-release" ln -sT os-release "${buildroot}/etc/initrd-release"
fi fi
else else
>"$buildroot/etc/initrd-release" : >"$buildroot/etc/initrd-release"
fi fi
# add a blank ld.so.conf to keep ldconfig happy # add a blank ld.so.conf to keep ldconfig happy
>"$buildroot/etc/ld.so.conf" : >"$buildroot/etc/ld.so.conf"
printf '%s' "$workdir" printf '%s' "$workdir"
} }
run_build_hook() { run_build_hook() {
local hook=$1 script= resolved= local hook="$1" script='' resolved=''
local MODULES=() BINARIES=() FILES=() SCRIPT= local MODULES=() BINARIES=() FILES=() SCRIPT=''
# find script in install dirs # find script in install dirs
if ! script=$(PATH=$_d_install type -P "$hook"); then # _d_install is assigned in mkinitcpio
# shellcheck disable=SC2154
if ! script="$(PATH="$_d_install" type -P "$hook")"; then
error "Hook '$hook' cannot be found" error "Hook '$hook' cannot be found"
return 1 return 1
fi fi
# check for deprecation # check for deprecation
if resolved=$(readlink -e "$script") && [[ ${script##*/} != "${resolved##*/}" ]]; then if resolved="$(readlink -e "$script")" && [[ "${script##*/}" != "${resolved##*/}" ]]; then
warning "Hook '%s' is deprecated. Replace it with '%s' in your config" \ warning "Hook '%s' is deprecated. Replace it with '%s' in your config" \
"${script##*/}" "${resolved##*/}" "${script##*/}" "${resolved##*/}"
script=$resolved script="$resolved"
fi fi
# source # source
unset -f build unset -f build
# shellcheck disable=SC1090
if ! . "$script"; then if ! . "$script"; then
error 'Failed to read %s' "$script" error 'Failed to read %s' "$script"
return 1 return 1
fi fi
if ! declare -f build >/dev/null; then if ! declare -f build >/dev/null; then
error 'Hook '$script' has no build function' error "Hook '%s' has no build function" "${script}"
return 1 return 1
fi fi
@ -920,18 +948,18 @@ run_build_hook() {
try_enable_color() { try_enable_color() {
local colors local colors
if ! colors=$(tput colors 2>/dev/null); then if ! colors="$(tput colors 2>/dev/null)"; then
warning "Failed to enable color. Check your TERM environment variable" warning "Failed to enable color. Check your TERM environment variable"
return return
fi fi
if (( colors > 0 )) && tput setaf 0 &>/dev/null; then if (( colors > 0 )) && tput setaf 0 &>/dev/null; then
_color_none=$(tput sgr0) _color_none="$(tput sgr0)"
_color_bold=$(tput bold) _color_bold="$(tput bold)"
_color_blue=$_color_bold$(tput setaf 4) _color_blue="$_color_bold$(tput setaf 4)"
_color_green=$_color_bold$(tput setaf 2) _color_green="$_color_bold$(tput setaf 2)"
_color_red=$_color_bold$(tput setaf 1) _color_red="$_color_bold$(tput setaf 1)"
_color_yellow=$_color_bold$(tput setaf 3) _color_yellow="$_color_bold$(tput setaf 3)"
fi fi
} }
@ -939,7 +967,7 @@ install_modules() {
local m local m
local -a xz_comp gz_comp zst_comp local -a xz_comp gz_comp zst_comp
[[ $KERNELVERSION == none ]] && return 0 [[ "$KERNELVERSION" == 'none' ]] && return 0
if (( $# == 0 )); then if (( $# == 0 )); then
warning "No modules were added to the image. This is probably not what you want." warning "No modules were added to the image. This is probably not what you want."