diff options
Diffstat (limited to 'hook-functions')
-rw-r--r-- | hook-functions | 797 |
1 files changed, 797 insertions, 0 deletions
diff --git a/hook-functions b/hook-functions new file mode 100644 index 0000000..151a84e --- /dev/null +++ b/hook-functions @@ -0,0 +1,797 @@ +# -*- shell-script -*- + +catenate_cpiogz() { + # Sanity check + if [ ! -e "${1}" ]; then + echo "W: catenate_cpiogz: arg1='${1}' does not exist." >&2 + return + fi + + cat "${1}" >>"${__TMPCPIOGZ}" +} + +prepend_earlyinitramfs() { + # Sanity check + if [ ! -e "${1}" ]; then + echo "W: prepend_earlyinitramfs: arg1='${1}' does not exist." >&2 + return + fi + + cat "${1}" >>"${__TMPEARLYCPIO}" +} + +# force_load module [args...] +force_load() +{ + manual_add_modules "$1" + echo "${@}" >>"${DESTDIR}/conf/modules" +} + +# Takes a file containing a list of modules to be added as an +# argument, figures out dependancies, and adds them. +# +# Input file syntax: +# +# # comment +# modprobe_module_name [args ...] +# [...] +# +add_modules_from_file() +{ + # Sanity check + if [ ! -e "${1}" ]; then + echo "W: add_modules_from_file: arg1='${1}' does not exist." >&2 + return + fi + + grep '^[^#]' "${1}" | while read -r module args; do + [ -n "$module" ] || continue + force_load "${module}" "${args}" + done +} + +# Add dependent modules + eventual firmware +manual_add_modules() +{ + local prefix kmod options firmware + + if [ $# -eq 0 ]; then + return + fi + + # modprobe --ignore-install inhibits processing of 'install' + # configuration lines, so that instead we will see 'insmod + # module.ko' as we want. However it also means that 'softdep' + # configuration lines and embedded softdep information is not + # processed. So we run twice, with and without this option. + # shellcheck disable=SC2034 + { modprobe --all --set-version="${version?}" --ignore-install --quiet --show-depends "$@"; + modprobe --all --set-version="${version}" --quiet --show-depends "$@"; } | + while read -r prefix kmod options ; do + if [ "${prefix}" != "insmod" ]; then + continue + fi + + copy_file module "${kmod}" || continue + + # Add required firmware + for firmware in $(modinfo -k "${version}" -F firmware "${kmod}"); do + if [ -e "${DESTDIR}/lib/firmware/${firmware}" ] \ + || [ -e "${DESTDIR}/lib/firmware/${version}/${firmware}" ]; then + continue + fi + + # Only print warning for missing fw of loaded module + # or forced loaded module + if [ ! -e "/lib/firmware/${firmware}" ] \ + && [ ! -e "/lib/firmware/${version}/${firmware}" ] ; then + # Only warn about missing firmware if + # /proc/modules exists + if [ ! -e /proc/modules ] ; then + continue + fi + + kmod_modname="${kmod##*/}" + kmod_modname="${kmod_modname%%.*}" + if grep -q "^$kmod_modname\\>" /proc/modules "${CONFDIR}/modules"; then + echo "W: Possible missing firmware /lib/firmware/${firmware} for module ${kmod_modname}" >&2 + fi + continue + fi + + if [ -e "/lib/firmware/${version}/${firmware}" ]; then + copy_file firmware \ + "/lib/firmware/${version}/${firmware}" + else + copy_file firmware "/lib/firmware/${firmware}" + fi + done + done +} + +# $1 = file type (for logging) +# $2 = file to copy to initramfs +# $3 (optional) Name for the file on the initramfs +# Location of the image dir is assumed to be $DESTDIR +# If the target exists, we leave it and return 1. +# On any other error, we return >1. +copy_file() { + local type src target link_target + + type="${1}" + src="${2}" + target="${3:-$2}" + + [ -f "${src}" ] || return 2 + + if [ -d "${DESTDIR}/${target}" ]; then + target="${target}/${src##*/}" + fi + + # Canonicalise usr-merged target directories + case "${target}" in + /bin/* | /lib* | /sbin/*) target="/usr${target}" ;; + esac + + # check if already copied + [ -e "${DESTDIR}/${target}" ] && return 1 + + mkdir -p "${DESTDIR}/${target%/*}" + + if [ -h "${src}" ]; then + # We don't need to replicate a chain of links completely; + # just link directly to the ultimate target + link_target="$(readlink -f "${src}")" || return $(($? + 1)) + + # Update source for the copy + src="${link_target}" + + # Canonicalise usr-merged target directories + case "${link_target}" in + /bin/* | /lib* | /sbin/*) link_target="/usr${link_target}" ;; + esac + + if [ "${link_target}" != "${target}" ]; then + [ "${verbose?}" = "y" ] && echo "Adding ${type}-link ${src}" + + # Create a relative link so it always points + # to the right place + ln -rs "${DESTDIR}/${link_target}" "${DESTDIR}/${target}" + fi + + # Copy the link target if it doesn't already exist + target="${link_target}" + [ -e "${DESTDIR}/${target}" ] && return 0 + mkdir -p "${DESTDIR}/${target%/*}" + fi + + [ "${verbose}" = "y" ] && echo "Adding ${type} ${src}" + + cp -pP "${src}" "${DESTDIR}/${target}" || return $(($? + 1)) +} + +# $1 = executable to copy to initramfs, with library dependencies +# $2 (optional) Name for the file on the initramfs +# Location of the image dir is assumed to be $DESTDIR +# We never overwrite the target if it exists. +copy_exec() { + local src target x nonoptlib ret + + src="${1}" + target="${2:-$1}" + + copy_file binary "${src}" "${target}" || return $(($? - 1)) + + # Copy the dependant libraries + for x in $(ldd "${src}" 2>/dev/null | sed -e ' + /\//!d; + /linux-gate/d; + /=>/ {s/.*=>[[:blank:]]*\([^[:blank:]]*\).*/\1/}; + s/[[:blank:]]*\([^[:blank:]]*\) (.*)/\1/' 2>/dev/null); do + + # Try to use non-optimised libraries where possible. + # We assume that all HWCAP libraries will be in tls, + # sse2, vfp or neon. + nonoptlib=$(echo "${x}" | sed -e 's#/lib/\([^/]*/\)\?\(tls\|i686\|sse2\|neon\|vfp\).*/\(lib.*\)#/lib/\1\3#') + nonoptlib=$(echo "${nonoptlib}" | sed -e 's#-linux-gnu/\(tls\|i686\|sse2\|neon\|vfp\).*/\(lib.*\)#-linux-gnu/\2#') + + if [ -e "${nonoptlib}" ]; then + x="${nonoptlib}" + fi + + copy_file library "${x}" || { + ret=$? + [ ${ret} = 1 ] || return $((ret - 1)) + } + done +} + +# Copy entire subtrees to the initramfs +copy_modules_dir() +{ + local kmod first exclude + local modules= + local dir="$1" + shift + + if ! [ -d "${MODULESDIR}/${dir}" ]; then + return; + fi + if [ "${verbose}" = "y" ]; then + echo "Copying module directory ${dir}" + if [ $# -ge 1 ]; then + echo "(excluding $*)" + fi + fi + + # Build up an expression for find + first=true + for exclude in "$@"; do + # Change .ko suffix in exclusion to .ko* + if [ "${exclude%.ko}" != "${exclude}" ]; then + exclude="${exclude}*" + fi + $first && set -- + set -- "$@" -name "${exclude}" -prune -o + first=false + done + + # shellcheck disable=SC2044 + for kmod in $(find "${MODULESDIR}/${dir}" "$@" -name '*.ko*' -printf '%f\n'); do + modules="$modules ${kmod%%.*}" + done + # shellcheck disable=SC2086 + manual_add_modules $modules +} + +# walk /sys for relevant modules +sys_walk_mod_add() +{ + local driver_path module device_path modalias + device_path="$1" + + while [ "${device_path}" != "/sys" ]; do + # device modalias + if [ -e "${device_path}/modalias" ]; then + modalias=$(cat "${device_path}/modalias") + if [ -n "${modalias}" ]; then + manual_add_modules "${modalias}" + fi + fi + + # current driver module + driver_path="$(readlink -f "${device_path}/driver/module")" + if [ -e "$driver_path" ]; then + module="$(basename "$(readlink -f "$driver_path")")" + if [ -n "${module}" ]; then + manual_add_modules "${module}" + fi + fi + + device_path="$(dirname "${device_path}")" + done +} + +block_dev_sys_walk_mod_add() +{ + local dev_sys_path disk_sys_path component + + # Resolve symlink so sys_walk_mod_add can walk up the hierarchy + dev_sys_path="$(readlink -f "$1")" + + # Find whole disk from partition + if grep -q "^DEVTYPE=partition$" "$dev_sys_path/uevent"; then + disk_sys_path="$dev_sys_path/.." + else + disk_sys_path="$dev_sys_path" + fi + + # Iterate over component of a layered device + find "$disk_sys_path/slaves" -mindepth 1 -maxdepth 1 | while read -r component; do + block_dev_sys_walk_mod_add "$component" + done + + sys_walk_mod_add "${dev_sys_path}" +} + +block_dev_mod_add() +{ + local dev_node dev_num dev_sys_path + dev_node="$1" + + # Look up device number and convert to decimal as it appears in sysfs + dev_num="$(stat -L -c %t:%T "$dev_node")" + dev_num="$((0x${dev_num%:*})):$((0x${dev_num#*:}))" + + # Look up device in sysfs + dev_sys_path="/sys/dev/block/$dev_num" + if [ ! -d "$dev_sys_path" ]; then + echo "mkinitramfs: for device ${dev_node} missing ${dev_sys_path}" >&2 + echo "mkinitramfs: workaround is MODULES=most" >&2 + echo "mkinitramfs: Error please report the bug" >&2 + exit 1 + fi + + block_dev_sys_walk_mod_add "$dev_sys_path" +} + +# Copy all loaded or built-in modules matching the given pattern. +# Pattern mustn't include directory or '.ko' suffix but should use +# '[-_]' to allow for differences in naming between /sys/module and +# modules.builtin. +add_loaded_modules() +{ + local pattern="$1" + local module builtin + builtin="/lib/modules/$(uname -r)/modules.builtin" + + for module in /sys/module/$pattern; do + if [ -d "$module" ]; then + manual_add_modules "$(basename "$module")" + fi + done + if [ -f "$builtin" ]; then + while read -r module; do + case "$module" in + */$pattern.ko) + manual_add_modules "$(basename "$module" .ko)" + ;; + esac + done < "$builtin" + fi +} + +# find and only copy modules relevant to a mountpoint +dep_add_modules_mount() +{ + local dir dev_node FSTYPE + + dir="$1" + + # require mounted sysfs + if [ ! -d /sys/devices/ ]; then + echo "mkinitramfs: MODULES dep requires mounted sysfs on /sys" >&2 + exit 1 + fi + + # find out block device + fstype + # shellcheck disable=SC2034 + eval "$(while read -r dev mp fs opts rest ; do \ + [ "$mp" = "$dir" ] && [ "$fs" != "rootfs" ] \ + && printf "dev_node=%s\\nFSTYPE=%s" "$dev" "$fs"\ + && break; done < /proc/mounts)" + + # Only the root mountpoint has to exist; do nothing if any other + # directory is not a mountpoint. + if [ "$dir" != / ] && [ -z "$dev_node" ]; then + return + fi + + # handle ubifs and return since ubifs is mounted on char devices + # but most of the commands below only work with block devices. + if [ "${FSTYPE}" = "ubifs" ]; then + manual_add_modules "${FSTYPE}" + return + fi + + if [ "$dir" = / ] && [ "${dev_node}" = "/dev/root" ] ; then + if [ -b "${dev_node}" ]; then + # Match it to the canonical device name by UUID + dev_node="/dev/disk/by-uuid/"$(blkid -o value -s UUID "${dev_node}") 2>/dev/null + else + # Does not exist in our namespace, so look at the + # kernel command line + dev_node= + # shellcheck disable=SC2013 + for arg in $(cat /proc/cmdline); do + case "$arg" in + root=*) + dev_node="${arg#root=}" + if [ "${dev_node#/dev/}" = "$dev_node" ]; then + dev_node="/dev/$dev_node" + fi + ;; + --) + break + ;; + *) + ;; + esac + done + fi + fi + + # recheck device + if [ -z "$dev_node" ] || ! dev_node="$(readlink -f "${dev_node}")" \ + || ! [ -b "$dev_node" ]; then + echo "mkinitramfs: failed to determine device for $dir" >&2 + echo "mkinitramfs: workaround is MODULES=most, check:" >&2 + echo "grep -r MODULES ${CONFDIR}" >&2 + echo "" >&2 + echo "Error please report bug on initramfs-tools" >&2 + echo "Include the output of 'mount' and 'cat /proc/mounts'" >&2 + exit 1 + fi + + # do not trust mount, check superblock + eval "$(/usr/lib/klibc/bin/fstype "${dev_node}")" + + # check that fstype fs recognition + if [ "${FSTYPE}" = "unknown" ]; then + FSTYPE=$(blkid -o value -s TYPE "${dev_node}") + if [ -z "${FSTYPE}" ]; then + echo "mkinitramfs: unknown fstype on device ${dev_node}" >&2 + echo "mkinitramfs: workaround is MODULES=most" >&2 + echo "Error please report bug on initramfs-tools" >&2 + exit 1 + fi + fi + + # Add filesystem + manual_add_modules "${FSTYPE}" + + block_dev_mod_add "$dev_node" +} + +dep_add_modules() +{ + local device dev_node + local modules= + + dep_add_modules_mount / + dep_add_modules_mount /usr + + if [ -n "${RESUME}" ]; then + dev_node="$(resolve_device "${RESUME}")" + if [ -n "${dev_node}" ]; then + block_dev_mod_add "${dev_node}" + fi + fi + + # sys walk some important device classes + for class in extcon gpio phy regulator rtc; do + for device in "/sys/class/$class"/*; do + device="$(readlink -f "$device")" \ + && sys_walk_mod_add "$device" + done + done + + # clk, USB-PHY and pinctrl devices are outside the device model (!) so + # match loaded modules by name + add_loaded_modules 'clk[-_]*' + add_loaded_modules 'phy[-_]*' + add_loaded_modules 'pinctrl[-_]*' + + # Sys walk keyboards. We identify keyboards as input devices + # that can generate at least key events 1-31; udev has the + # same heuristic. Note that the format of the bitmap + # properties depends on the word size of the process reading + # the uevent file! + for device in /sys/class/input/input*; do + if grep -qs "^KEY=.*fffffff[ef]$" "${device}/uevent"; then + sys_walk_mod_add "$(readlink -f "$device")" + fi + done + + # catch old-style IDE + if [ -e /sys/bus/ide/devices/ ]; then + modules="$modules ide-gd_mod ide-cd" + fi + + if [ -e /sys/bus/scsi/devices/ ]; then + modules="$modules sd_mod" + fi + + if [ -e /sys/bus/mmc/devices/ ]; then + modules="$modules mmc_block" + fi + + if [ -e /sys/bus/virtio ] ; then + modules="$modules virtio_pci virtio_mmio" + fi + + if [ -e /sys/bus/i2o/devices/ ]; then + force_load i2o_block + force_load i2o_config + fi + + if [ -e /sys/bus/ps3_system_bus/ ]; then + modules="$modules ps3disk ps3rom ps3-gelic ps3_sys_manager" + fi + + if [ -e /sys/bus/vio/ ]; then + modules="$modules sunvnet sunvdc" + fi + + # shellcheck disable=SC2086 + manual_add_modules $modules +} + +# The modules "most" classes added per default to the initramfs +auto_add_modules() +{ + local arg + local modules= + + if [ "$#" -eq 0 ] ; then + set -- base net ide scsi block ata i2o dasd ieee1394 firewire mmc usb_storage + fi + + for arg in "$@" ; do + case "$arg" in + base) + modules="$modules btrfs ext2 ext3 ext4 ext4dev " + modules="$modules isofs jfs reiserfs udf xfs" + modules="$modules nfs nfsv2 nfsv3 nfsv4" + modules="$modules af_packet atkbd i8042 psmouse" + modules="$modules virtio_pci virtio_mmio" + + # Include most USB host and dual-role drivers + copy_modules_dir kernel/drivers/usb/host \ + hwa-hc.ko sl811_cs.ko sl811-hcd.ko \ + u132-hcd.ko whci-hcd.ko + copy_modules_dir kernel/drivers/usb/c67x00 + copy_modules_dir kernel/drivers/usb/chipidea + copy_modules_dir kernel/drivers/usb/dwc2 + copy_modules_dir kernel/drivers/usb/dwc3 + copy_modules_dir kernel/drivers/usb/isp1760 + copy_modules_dir kernel/drivers/usb/musb + copy_modules_dir kernel/drivers/usb/renesas_usbhs + # and any extcon drivers for USB + modules="$modules extcon-usb-gpio extcon-usbc-cros-ec" + # Add the axp20x_usb_power power supply driver, + # required to initialize the USB host controllers + # on a number of armhf systems + modules="$modules axp20x_usb_power" + + # Include all keyboard drivers and all HID drivers + # unless we're sure they don't support keyboards. + # hid-*ff covers various game controllers with + # force feedback. + copy_modules_dir kernel/drivers/input/keyboard + copy_modules_dir kernel/drivers/hid \ + 'hid-*ff.ko' hid-a4tech.ko hid-cypress.ko \ + hid-dr.ko hid-elecom.ko hid-gyration.ko \ + hid-icade.ko hid-kensington.ko hid-kye.ko \ + hid-lcpower.ko hid-magicmouse.ko \ + hid-multitouch.ko hid-ntrig.ko \ + hid-petalynx.ko hid-picolcd.ko hid-pl.ko \ + hid-ps3remote.ko hid-quanta.ko \ + 'hid-roccat-ko*.ko' hid-roccat-pyra.ko \ + hid-saitek.ko hid-sensor-hub.ko hid-sony.ko \ + hid-speedlink.ko hid-tivo.ko hid-twinhan.ko \ + hid-uclogic.ko hid-wacom.ko hid-waltop.ko \ + hid-wiimote.ko hid-zydacron.ko + # needed to access keyboard on some ChromeOS devices + modules="$modules cros_ec_spi" + + # Any of these might be needed by other drivers + copy_modules_dir kernel/drivers/bus + copy_modules_dir kernel/drivers/clk + copy_modules_dir kernel/drivers/gpio + copy_modules_dir kernel/drivers/i2c/busses + copy_modules_dir kernel/drivers/i2c/muxes + copy_modules_dir kernel/drivers/mfd + copy_modules_dir kernel/drivers/phy + copy_modules_dir kernel/drivers/pinctrl + copy_modules_dir kernel/drivers/regulator + copy_modules_dir kernel/drivers/spi + copy_modules_dir kernel/drivers/usb/phy + + # Needed for periodic fsck + copy_modules_dir kernel/drivers/rtc + ;; + net) + copy_modules_dir kernel/drivers/net \ + appletalk arcnet bonding can dummy.ko \ + hamradio hippi ifb.ko irda macvlan.ko \ + macvtap.ko pcmcia sb1000.ko team tokenring \ + tun.ko usb veth.ko wan wimax wireless \ + xen-netback.ko + ;; + ide) + copy_modules_dir kernel/drivers/ide + ;; + mmc) + copy_modules_dir kernel/drivers/mmc + ;; + scsi) + copy_modules_dir kernel/drivers/scsi + modules="$modules mptfc mptsas mptscsih mptspi zfcp" + ;; + ata) + copy_modules_dir kernel/drivers/ata + ;; + block) + copy_modules_dir kernel/drivers/block + copy_modules_dir kernel/drivers/nvme + modules="$modules vmd" + ;; + ubi) + modules="$modules deflate zlib lzo ubi ubifs" + ;; + ieee1394) + modules="$modules ohci1394 sbp2" + ;; + firewire) + modules="$modules firewire-ohci firewire-sbp2" + ;; + i2o) + modules="$modules i2o_block" + ;; + dasd) + modules="$modules dasd_diag_mod dasd_eckd_mod dasd_fba_mod" + ;; + usb_storage) + copy_modules_dir kernel/drivers/usb/storage + ;; + esac + done + + # shellcheck disable=SC2086 + manual_add_modules $modules +} + +# 'depmod' only looks at symbol dependencies and the 'softdep' module +# information field; there is no way for modules to declare weaker +# dependencies (modules that *might* be needed at run-time) through +# module information, Until this is fixed, we need to handle those +# hidden dependencies. +hidden_dep_add_modules() +{ + # shellcheck disable=SC2046 + manual_add_modules $( + { + cat "${DESTDIR}/lib/modules/${version}/modules.builtin" + find "${DESTDIR}/lib/modules/${version}/kernel" -name '*.ko*' + } | + while read -r module; do + module="${module##*/}" + module="${module%%.*}" + case "$module" in + libcrc32c) + echo crc32c + ;; + ubifs) + echo deflate zlib lzo + ;; + btrfs) + echo crc32c + ;; + mlx4_core) + echo mlx4_ib + ;; + mlx5_core) + echo mlx5_ib + ;; + i8042) + echo psmouse + ;; + nvme) + echo vmd + ;; + esac + done + ) +} + +# Find the source for a script file. This is needed to work around +# temporary directories mounted with the noexec option. The source +# will be on / or /usr which must be executable. +get_source() +{ + if [ -z "$scriptdir" ]; then + echo "${initdir}/$1" + elif [ -f "${CONFDIR}${scriptdir}/$1" ]; then + echo "${CONFDIR}${scriptdir}/$1" + else + echo "/usr/share/initramfs-tools${scriptdir}/$1" + fi +} + +set_initlist() +{ + unset initlist + for si_x in "${initdir}"/*; do + # skip empty dirs without warning + [ "${si_x}" = "${initdir}/*" ] && return + + # only allow variable name chars + case ${si_x#${initdir}/} in + *[![:alnum:]\._-]*) + [ "${verbose}" = "y" ] \ + && echo "$si_x ignored: not alphanumeric or '_' file" >&2 + continue + ;; + esac + + # skip directories + if [ -d "${si_x}" ]; then + [ "${verbose}" = "y" ] \ + && echo "$si_x ignored: a directory" >&2 + continue + fi + + si_x="$(get_source "${si_x#${initdir}/}")" + + # skip non executable scripts + if [ ! -x "${si_x}" ]; then + [ "${verbose}" = "y" ] \ + && echo "$si_x ignored: not executable" >&2 + continue + fi + + # skip bad syntax + if ! sh -n "${si_x}" ; then + [ "${verbose}" = "y" ] \ + && echo "$si_x ignored: bad syntax" >&2 + continue + fi + + initlist="${initlist:-} ${si_x##*/}" + done +} + +get_prereq_pairs() +{ + set_initlist + for gp_x in ${initlist:-}; do + echo "${gp_x} ${gp_x}" + gp_src="$(get_source "$gp_x")" + prereqs=$("${gp_src}" prereqs) + for prereq in ${prereqs}; do + echo "${prereq} ${gp_x}" + done + done +} + +# cache boot scripts order +cache_run_scripts() +{ + DESTDIR=${1} + scriptdir=${2} + initdir=${DESTDIR}${scriptdir} + [ ! -d "${initdir}" ] && return + + true > "${initdir}/ORDER" + runlist=$(get_prereq_pairs | tsort) + for crs_x in ${runlist}; do + [ -f "${initdir}/${crs_x}" ] || continue + echo "${scriptdir}/${crs_x} \"\$@\"" >> "${initdir}/ORDER" + echo "[ -e /conf/param.conf ] && . /conf/param.conf" >> "${initdir}/ORDER" + done +} + +call_scripts() +{ + set -e + for cs_x in ${runlist}; do + [ -f "${initdir}/${cs_x}" ] || continue + # mkinitramfs verbose output + if [ "${verbose}" = "y" ]; then + echo "Calling hook ${cs_x}" + fi + "${initdir}/${cs_x}" && ec=$? || ec=$? + # allow hooks to abort build: + if [ "$ec" -ne 0 ]; then + echo "E: ${initdir}/${cs_x} failed with return $ec." >&2 + # only errexit on mkinitramfs + [ -n "${version}" ] && exit $ec + fi + # allow boot scripts to modify exported boot parameters + if [ -e /conf/param.conf ]; then + . /conf/param.conf + fi + done + set +e +} + +run_scripts() +{ + scriptdir=${2:-} + initdir=${1} + [ ! -d "${initdir}" ] && return + + runlist=$(get_prereq_pairs | tsort) + call_scripts "$scriptdir" +} |