summaryrefslogtreecommitdiffstats
path: root/scripts/functions
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 15:45:07 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 15:45:07 +0000
commit3b043b08c9b52424072db56be6636ff44c737e83 (patch)
treed64185acc33a046c8bb297641a16b01ec167eaa5 /scripts/functions
parentInitial commit. (diff)
downloadinitramfs-tools-upstream.tar.xz
initramfs-tools-upstream.zip
Adding upstream version 0.142.upstream/0.142upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'scripts/functions')
-rw-r--r--scripts/functions581
1 files changed, 581 insertions, 0 deletions
diff --git a/scripts/functions b/scripts/functions
new file mode 100644
index 0000000..ae11b96
--- /dev/null
+++ b/scripts/functions
@@ -0,0 +1,581 @@
+# -*- shell-script -*-
+
+_log_msg()
+{
+ if [ "${quiet?}" = "y" ]; then return; fi
+ # shellcheck disable=SC2059
+ printf "$@"
+ return 0 # Prevents error carry over in case of unavailable console
+}
+
+log_success_msg()
+{
+ _log_msg "Success: %s\\n" "$*"
+}
+
+log_failure_msg()
+{
+ _log_msg "Failure: %s\\n" "$*"
+}
+
+log_warning_msg()
+{
+ _log_msg "Warning: %s\\n" "$*"
+}
+
+log_begin_msg()
+{
+ _log_msg "Begin: %s ... " "$*"
+}
+
+log_end_msg()
+{
+ _log_msg "done.\\n"
+}
+
+panic()
+{
+ local console rest IFS
+
+ if command -v chvt >/dev/null 2>&1; then
+ chvt 1
+ fi
+
+ echo "$@"
+
+ # The panic= parameter implies we should disallow console access
+ if [ -n "${panic?}" ]; then
+ delay=
+ case "${panic?}" in
+ -*[![:digit:].]*) # invalid: wait forever
+ ;;
+ -*) # timeout < 0: reboot immediately
+ delay=0
+ ;;
+ 0 | *[![:digit:].]*) # timeout = 0 or invalid: wait forever
+ ;;
+ *) # timeout > 0: seconds before rebooting
+ delay="${panic}"
+ ;;
+ esac
+ if [ -n "${delay}" ]; then
+ echo "Rebooting automatically due to panic= boot argument"
+ sleep "${delay}"
+ reboot -f
+ else
+ echo "Halting automatically due to panic= boot argument"
+ halt -f
+ fi
+ exit # in case reboot fails, force kernel panic
+ fi
+
+ run_scripts /scripts/panic
+
+ # Try to use setsid, which will enable job control in the shell
+ # and paging in more
+ if command -v setsid >/dev/null 2>&1; then
+ unset IFS
+ read -r console rest </proc/consoles
+ if [ "${console}" = "tty0" ]; then
+ # Need to choose a specific VT
+ console="tty1"
+ fi
+ # We don't have 'setsid -c' so we need to setsid, open
+ # the tty, and finally exec an interactive shell
+ REASON="$*" PS1='(initramfs) ' setsid sh -c "exec sh -i <>/dev/${console} 1>&0 2>&1"
+ else
+ REASON="$*" PS1='(initramfs) ' sh -i </dev/console >/dev/console 2>&1
+ fi
+}
+
+maybe_break()
+{
+ case ",${break?}," in
+ *,$1,*)
+ if [ "$1" = "top" ]; then
+ # udev is not yet running, so load keyboard drivers
+ if [ "${quiet}" = "y" ]; then
+ opts="-q"
+ else
+ opts="-v"
+ fi
+ /sbin/modprobe ${opts} -a i8042 atkbd ehci-pci ehci-orion \
+ ehci-hcd ohci-hcd ohci-pci uhci-hcd usbhid xhci \
+ xhci-pci xhci-hcd
+ sleep 2
+ for modalias in /sys/bus/hid/devices/*/modalias; do
+ if [ -f "${modalias}" ]; then
+ /sbin/modprobe ${opts} -b "$(cat "${modalias}")"
+ fi
+ done
+ fi
+ panic "Spawning shell within the initramfs"
+ ;;
+ esac
+}
+
+# For boot time only; this is overridden at build time in hook-functions
+run_scripts()
+{
+ initdir=${1}
+ [ ! -d "${initdir}" ] && return
+
+ shift
+ . "${initdir}/ORDER"
+}
+
+# Load custom modules first
+load_modules()
+{
+ if [ -e /conf/modules ]; then
+ while read -r m; do
+ # Skip empty lines
+ if [ -z "$m" ]; then
+ continue
+ fi
+ # Skip comments - d?ash removes whitespace prefix
+ com=$(printf "%.1s" "${m}")
+ if [ "$com" = "#" ]; then
+ continue
+ fi
+ # shellcheck disable=SC2086
+ /sbin/modprobe $m
+ done < /conf/modules
+ fi
+}
+
+_uptime() {
+ local uptime
+ uptime="$(cat /proc/uptime)"
+ uptime="${uptime%%[. ]*}"
+ echo "$uptime"
+}
+
+time_elapsed() {
+ # shellcheck disable=SC2154
+ if [ -z "$starttime" ]; then
+ log_failure_msg "time_elapsed() called before \$starttime initialized"
+ echo 0
+ fi
+ local delta
+ delta="$(_uptime)"
+ delta=$((delta - starttime))
+ echo "$delta"
+}
+
+# lilo compatibility
+parse_numeric() {
+ case $1 in
+ *:*)
+ # Does it match /[0-9]*:[0-9]*/?
+ minor=${1#*:}
+ major=${1%:*}
+ case $major$minor in
+ *[!0-9]*)
+ # No.
+ return
+ ;;
+ esac
+ ;;
+ "" | *[!A-Fa-f0-9]*)
+ # "", "/*", etc.
+ return
+ ;;
+ *)
+ # [A-Fa-f0-9]*
+ value=$(( 0x${1} ))
+ minor=$(( (value & 0xff) | (value >> 12) & 0xfff00 ))
+ major=$(( (value >> 8) & 0xfff ))
+ ;;
+ esac
+
+ # shellcheck disable=SC2034
+ ROOT="/dev/block/${major}:${minor}"
+}
+
+# Parameter: device node to check
+# Echos fstype to stdout
+# Return value: indicates if an fs could be recognized
+get_fstype ()
+{
+ local FS FSTYPE
+ FS="${1}"
+
+ # blkid has a more complete list of file systems,
+ # but fstype is more robust
+ FSTYPE="unknown"
+ eval "$(fstype "${FS}" 2> /dev/null)"
+ if [ "$FSTYPE" = "unknown" ]; then
+ FSTYPE=$(blkid -o value -s TYPE "${FS}") || return
+ fi
+ echo "${FSTYPE}"
+ return 0
+}
+
+_set_netdev_from_ip_param()
+{
+ # If the ip= parameter is present and specifies a device, use
+ # that in preference to any device name we already have
+ local IFS=:
+ set -f
+ # shellcheck disable=SC2086
+ set -- ${IP}
+ set +f
+ if [ -n "$6" ]; then
+ DEVICE="$6"
+ return 0
+ fi
+ return 1
+}
+
+_set_netdev_from_hw_address()
+{
+ local want_address="$1"
+ local device
+ for device in /sys/class/net/*; do
+ if [ -f "$device/address" ] &&
+ [ "$(cat "$device/address")" = "$want_address" ]; then
+ DEVICE="${device##*/}"
+ return 0
+ fi
+ done
+ return 1
+}
+
+_usable_netdev_exists()
+{
+ # Look for a device with IFF_LOOPBACK clear and (IFF_BROADCAST
+ # or IFF_POINTTOPOINT) set. This is the same test the kernel
+ # and ipconfig apply to find a device.
+ local device
+ local flags
+ for device in /sys/class/net/*; do
+ if [ -f "${device}/flags" ]; then
+ flags="$(cat "${device}/flags")"
+ if [ "$((flags & 8))" -eq 0 ] &&
+ [ "$((flags & 0x12))" -ne 0 ]; then
+ return 0
+ fi
+ fi
+ done
+ return 1
+}
+
+_update_ip_param()
+{
+ # If the ip= parameter is present, and is a colon-separated list,
+ # but does not specify a device, substitute in the device name
+ # we have
+ local IFS=:
+ set -f
+ # shellcheck disable=SC2086
+ set -- ${IP}
+ set +f
+ if [ -z "$6" ] && [ $# -ge 2 ] && [ -n "${DEVICE}" ]; then
+ IP="$1:$2:$3:$4:$5:${DEVICE}"
+ shift 6 || shift $#
+ IP="${IP}:$*"
+ fi
+}
+
+configure_networking()
+{
+ local netdev_desc
+
+ # The order of precedence here is:
+ # 1. Device specified by ip= kernel parameter
+ # 2. Device matching MAC specified by BOOTIF= kernel parameter
+ # 3. Build-time DEVICE variable
+ # In case 2 we only discover the device name while waiting
+ # for a device.
+ if _set_netdev_from_ip_param; then
+ netdev_desc="${DEVICE}"
+ elif [ -n "${BOOTIF}" ]; then
+ # pxelinux sets BOOTIF to a value based on the mac address of the
+ # network card used to PXE boot
+ # pxelinux sets BOOTIF to 01-$mac_address
+
+ # strip off the leading "01-", which isn't part of the mac
+ # address
+ temp_mac=${BOOTIF#*-}
+
+ # convert to typical mac address format by replacing "-" with ":"
+ bootif_mac=""
+ IFS='-'
+ for x in $temp_mac ; do
+ if [ -z "$bootif_mac" ]; then
+ bootif_mac="$x"
+ else
+ bootif_mac="$bootif_mac:$x"
+ fi
+ done
+ unset IFS
+
+ _set_netdev_from_hw_address "${bootif_mac}"
+ netdev_desc="device with address ${bootif_mac}"
+ elif [ -n "${DEVICE}" ]; then
+ netdev_desc="${DEVICE}"
+ else
+ netdev_desc="any network device"
+ fi
+
+ # networking already configured thus bail out
+ [ -n "${DEVICE}" ] && [ -e /run/net-"${DEVICE}".conf ] && return 0
+
+ local netdevwait=180
+ log_begin_msg "Waiting up to ${netdevwait} secs for ${netdev_desc} to become available"
+ while true; do
+ if [ "$(time_elapsed)" -ge "$netdevwait" ]; then
+ log_failure_msg "Network device did not appear in time"
+ break
+ fi
+ if [ -n "${DEVICE}" ]; then
+ [ -e "/sys/class/net/${DEVICE}" ] && break
+ elif [ -n "${bootif_mac}" ]; then
+ _set_netdev_from_hw_address "${bootif_mac}" && break
+ else
+ _usable_netdev_exists && break
+ fi
+ sleep 1
+ done
+ log_end_msg
+
+ _update_ip_param
+
+ wait_for_udev 10
+
+ # support ip options see linux sources
+ # Documentation/filesystems/nfs/nfsroot.txt
+ # Documentation/frv/booting.txt
+
+ for ROUNDTTT in 2 3 4 6 9 16 25 36 64 100; do
+
+ # The NIC is to be configured if this file does not exist.
+ # Ip-Config tries to create this file and when it succeds
+ # creating the file, ipconfig is not run again.
+ for x in /run/net-"${DEVICE}".conf /run/net-*.conf ; do
+ [ -e "$x" ] && break 2
+ done
+
+ case ${IP} in
+ none|off)
+ # Do nothing
+ ;;
+ ""|on|any)
+ # Bring up device
+ ipconfig -t ${ROUNDTTT} "${DEVICE}"
+ ;;
+ dhcp|bootp|rarp|both)
+ ipconfig -t ${ROUNDTTT} -c "${IP}" -d "${DEVICE}"
+ ;;
+ *)
+ ipconfig -t ${ROUNDTTT} -d "$IP"
+ ;;
+ esac
+ done
+
+ # source ipconfig output
+ if [ -n "${DEVICE}" ]; then
+ # source specific bootdevice
+ . "/run/net-${DEVICE}.conf"
+ else
+ # source any interface...
+ # ipconfig should have quit after first response
+ . /run/net-*.conf
+ fi
+}
+
+# Wait for queued kernel/udev events
+wait_for_udev()
+{
+ command -v udevadm >/dev/null 2>&1 || return 0
+ udevadm settle ${1:+--timeout=$1}
+}
+
+# Find a specific fstab entry
+# $1=mountpoint
+# $2=fstype (optional)
+# returns 0 on success, 1 on failure (not found or no fstab)
+read_fstab_entry() {
+ # Not found by default.
+ found=1
+
+ for file in ${rootmnt?}/etc/fstab; do
+ if [ -f "$file" ]; then
+ # shellcheck disable=SC2034
+ while read -r MNT_FSNAME MNT_DIR MNT_TYPE MNT_OPTS MNT_FREQ MNT_PASS MNT_JUNK; do
+ case "$MNT_FSNAME" in
+ ""|\#*)
+ continue;
+ ;;
+ esac
+ if [ "$MNT_DIR" = "$1" ]; then
+ if [ -n "$2" ]; then
+ [ "$MNT_TYPE" = "$2" ] || continue;
+ fi
+ found=0
+ break 2
+ fi
+ done < "$file"
+ fi
+ done
+
+ return $found
+}
+
+# Resolve device node from a name. This expands any LABEL or UUID.
+# $1=name
+# Resolved name is echoed.
+resolve_device() {
+ DEV="$1"
+
+ case "$DEV" in
+ LABEL=* | UUID=* | PARTLABEL=* | PARTUUID=*)
+ DEV="$(blkid -l -t "$DEV" -o device)" || return 1
+ ;;
+ esac
+ [ -e "$DEV" ] && echo "$DEV"
+}
+
+# Check a file system.
+# $1=device
+# $2=mountpoint (for diagnostics only)
+# $3=type (may be "auto")
+_checkfs_once()
+{
+ DEV="$1"
+ NAME="$2"
+ TYPE="$3"
+ if [ "$NAME" = "/" ] ; then
+ NAME="root"
+ fi
+ FSCK_LOGFILE=/run/initramfs/fsck.log
+ FSCK_STAMPFILE=/run/initramfs/fsck-${NAME#/}
+
+ if [ "${TYPE}" = "auto" ]; then
+ TYPE="$(get_fstype "${DEV}")"
+ fi
+
+ FSCKCODE=0
+ if [ -z "${TYPE}" ]; then
+ log_warning_msg "Type of $NAME file system is unknown, so skipping check."
+ return
+ fi
+ if ! command -v fsck >/dev/null 2>&1; then
+ log_warning_msg "fsck not present, so skipping $NAME file system"
+ return
+ fi
+ if [ "${fastboot?}" = "y" ] ; then
+ log_warning_msg "Fast boot enabled, so skipping $NAME file system check."
+ return
+ fi
+
+ if [ "${forcefsck?}" = "y" ]
+ then
+ force="-f"
+ else
+ force=""
+ fi
+
+ if [ "${fsckfix?}" = "y" ]
+ then
+ fix="-y"
+ elif [ "${fsckfix?}" = "n" ]
+ then
+ fix="-n"
+ else
+ fix="-a"
+ fi
+
+ spinner=""
+ if [ -z "${debug?}" ]; then
+ spinner="-C"
+ fi
+
+ if [ "${quiet}" = n ]
+ then
+ log_begin_msg "Will now check $NAME file system"
+ # shellcheck disable=SC2086
+ logsave -a -s $FSCK_LOGFILE fsck $spinner $force $fix -V -t "$TYPE" "$DEV"
+ FSCKCODE=$?
+ log_end_msg
+ else
+ log_begin_msg "Checking $NAME file system"
+ # shellcheck disable=SC2086
+ logsave -a -s $FSCK_LOGFILE fsck $spinner $force $fix -T -t "$TYPE" "$DEV"
+ FSCKCODE=$?
+ log_end_msg
+ fi
+
+ # NOTE: "failure" is defined as exiting with a return code of
+ # 4, possibly or-ed with other flags. A return code of 1
+ # indicates that file system errors were corrected but that
+ # the boot may proceed.
+ #
+ if [ "$FSCKCODE" -eq 32 ]
+ then
+ log_warning_msg "File system check was interrupted by user"
+ elif [ $((FSCKCODE & 4)) -eq 4 ]
+ then
+ log_failure_msg "File system check of the $NAME filesystem failed"
+ return 1
+ elif [ "$FSCKCODE" -gt 1 ]
+ then
+ log_warning_msg "File system check failed but did not detect errors"
+ sleep 5
+ else
+ true > $FSCK_STAMPFILE
+ fi
+ return 0
+}
+
+checkfs()
+{
+ while ! _checkfs_once "$@"; do
+ panic "The $2 filesystem on $1 requires a manual fsck"
+ done
+}
+
+# Mount a file system. We parse the information from the fstab. This
+# should be overridden by any boot script which can mount arbitrary
+# filesystems such as /usr. This default implementation delegates to
+# local or nfs based upon the filesystem type.
+# $1=mountpoint mount location
+mountfs()
+{
+ type=local
+ read_fstab_entry "$1"
+ if [ "${MNT_TYPE}" = "nfs" ] || [ "${MNT_TYPE}" = "nfs4" ]; then
+ type=nfs
+ fi
+
+ ${type}_mount_fs "$1"
+}
+
+# Mount the root file system. It should be overridden by all
+# boot scripts.
+mountroot()
+{
+ :
+}
+
+# Run /scripts/${boot}-top. This should be overridden by all boot
+# scripts.
+mount_top()
+{
+ :
+}
+
+# Run /scripts/${boot}-premount. This should be overridden by all boot
+# scripts.
+mount_premount()
+{
+ :
+}
+
+# Run /scripts/${boot}-bottom. This should be overridden by all boot
+# scripts.
+mount_bottom()
+{
+ :
+}