diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-03 05:42:59 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-03 05:42:59 +0000 |
commit | c45bd7dca7394d3a25f5bbf416f3b75c50759190 (patch) | |
tree | f7dbbfcc2f6b787eea456d1f1e28525ca2ceb9ba | |
parent | Initial commit. (diff) | |
download | initramfs-tools-c45bd7dca7394d3a25f5bbf416f3b75c50759190.tar.xz initramfs-tools-c45bd7dca7394d3a25f5bbf416f3b75c50759190.zip |
Adding upstream version 0.143.upstream/0.143upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
38 files changed, 5933 insertions, 0 deletions
diff --git a/.dir-locals.el b/.dir-locals.el new file mode 100644 index 0000000..e91b46a --- /dev/null +++ b/.dir-locals.el @@ -0,0 +1,8 @@ +;;; Directory Local Variables +;;; For more information see (info "(emacs) Directory Variables") + +((sh-mode + (sh-basic-offset . 8) + (sh-indentation . 8) + (sh-indent-for-case-label . 0) + (sh-indent-for-case-alt . +))) diff --git a/bash_completion.d/update-initramfs b/bash_completion.d/update-initramfs new file mode 100644 index 0000000..bf822cd --- /dev/null +++ b/bash_completion.d/update-initramfs @@ -0,0 +1,23 @@ +# update-initramfs(8) completion + +_update_initramfs() +{ + local cur prev valid_options + + _get_comp_words_by_ref cur prev + + # The only option that takes an argument is -k + if [[ "$prev" == '-k' ]]; then + # Complete with kernel versions + _kernel_versions + COMPREPLY=( $( compgen -W '${COMPREPLY[@]} all' -- "$cur" ) ) + return; + fi + + # Complete with available options (obtained from -h) + valid_options=$( update-initramfs -h 2>&1 | \ + sed -e '/^ -/!d;s/^ \(-\w\+\).*/\1/' ) + COMPREPLY=( $( compgen -W "$valid_options" -- $cur ) ) +} + +complete -F _update_initramfs update-initramfs diff --git a/conf/initramfs.conf b/conf/initramfs.conf new file mode 100644 index 0000000..aa561bd --- /dev/null +++ b/conf/initramfs.conf @@ -0,0 +1,90 @@ +# +# initramfs.conf +# Configuration file for mkinitramfs(8). See initramfs.conf(5). +# +# Note that configuration options from this file can be overridden +# by config files in the /etc/initramfs-tools/conf.d directory. + +# +# MODULES: [ most | netboot | dep | list ] +# +# most - Add most filesystem and all harddrive drivers. +# +# dep - Try and guess which modules to load. +# +# netboot - Add the base modules, network modules, but skip block devices. +# +# list - Only include modules from the 'additional modules' list +# + +MODULES=most + +# +# BUSYBOX: [ y | n | auto ] +# +# Use busybox shell and utilities. If set to n, klibc utilities will be used. +# If set to auto (or unset), busybox will be used if installed and klibc will +# be used otherwise. +# + +BUSYBOX=auto + +# +# KEYMAP: [ y | n ] +# +# Load a keymap during the initramfs stage. +# + +KEYMAP=n + +# +# COMPRESS: [ gzip | bzip2 | lz4 | lzma | lzop | xz | zstd ] +# + +COMPRESS=zstd + +# +# COMPRESSLEVEL: ... +# +# Set a compression level for the compressor. +# Defaults vary by compressor. +# +# Valid values are: +# 1 - 9 for gzip|bzip2|lzma|lzop +# 0 - 9 for lz4|xz +# 0 - 19 for zstd +# +# COMPRESSLEVEL=3 + +# +# DEVICE: ... +# +# Specify a specific network interface, like eth0 +# Overridden by optional ip= or BOOTIF= bootarg +# + +DEVICE= + +# +# NFSROOT: [ auto | HOST:MOUNT ] +# + +NFSROOT=auto + +# +# RUNSIZE: ... +# +# The size of the /run tmpfs mount point, like 256M or 10% +# Overridden by optional initramfs.runsize= bootarg +# + +RUNSIZE=10% + +# +# FSTYPE: ... +# +# The filesystem type(s) to support, or "auto" to use the current root +# filesystem type +# + +FSTYPE=auto diff --git a/conf/modules b/conf/modules new file mode 100644 index 0000000..a229e4d --- /dev/null +++ b/conf/modules @@ -0,0 +1,14 @@ +### This file is the template for /etc/initramfs-tools/modules. +### It is not a configuration file itself. +### +# List of modules that you want to include in your initramfs. +# They will be loaded at boot time in the order below. +# +# Syntax: module_name [args ...] +# +# You must run update-initramfs(8) to effect this change. +# +# Examples: +# +# raid1 +# sd_mod diff --git a/conf/update-initramfs.conf b/conf/update-initramfs.conf new file mode 100644 index 0000000..31823e2 --- /dev/null +++ b/conf/update-initramfs.conf @@ -0,0 +1,20 @@ +# +# Configuration file for update-initramfs(8) +# + +# +# update_initramfs [ yes | all | no ] +# +# Default is yes +# If set to all update-initramfs will update all initramfs +# If set to no disables any update to initramfs beside kernel upgrade + +update_initramfs=yes + +# +# backup_initramfs [ yes | no ] +# +# Default is no +# If set to no leaves no .bak backup files. + +backup_initramfs=no diff --git a/docs/example_hook b/docs/example_hook new file mode 100644 index 0000000..85ff6c6 --- /dev/null +++ b/docs/example_hook @@ -0,0 +1,68 @@ +#!/bin/sh +# +# +# This is an example hook script. It will be run by 'mkinitramfs' +# when it creates the image. It's job is to decide which files to +# install, then install them into the staging area, where the +# initramfs is being created. This happens when a new 'linux-image' +# package is installed, or when the administrator runs 'mkinitramfs' +# by hand to update an initramfs image. +# +# CONFDIR -- usually /etc/initramfs-tools, can be set on mkinitramfs +# command line. +# +# DESTDIR -- The staging directory where we are building the image. +# +# see initramfs-tools(7) + +# +# List the soft prerequisites here. This is a space separated list of +# names, of scripts that are in the same directory as this one, that +# must be run before this one can be. +# +PREREQ="" + +prereqs() +{ + echo "$PREREQ" +} + +case $1 in +# get pre-requisites +prereqs) + prereqs + exit 0 + ;; +esac + + +# You can do anything you need to from here on. +# + +# Source the optional 'hook-functions' scriptlet, if you need the +# functions defined within it. Read it to see what is available to +# you. It contains functions for copying dynamically linked program +# binaries, and kernel modules into the DESTDIR. +# +. /usr/share/initramfs-tools/hook-functions + + +# If this hook script is a conffile (and thus stored in +# /etc/mkinitramfs/hooks), it must take care to do the right thing +# when the package containing it is removed but not purged. There of +# course may be other reasons to have custom logic deciding what to +# install. The version variable may be useful for this. +# +if command -v myprog >/dev/null 2>&1; then + copy_exec /usr/bin/myprog usr/bin +fi + +# To accompany this, there should usually be a script for inside the +# initramfs named something like: +# +# "/etc/mkinitramfs/local-premount/myprog" +# +# ... and it should do what is necessary to have 'myprog' get run +# inside the early runtime environment. + +exit 0 diff --git a/docs/example_script b/docs/example_script new file mode 100644 index 0000000..accab37 --- /dev/null +++ b/docs/example_script @@ -0,0 +1,35 @@ +#!/bin/sh + +# +# This script is run inside of the initramfs environment during the +# system boot process. It is installed there by 'update-initramfs'. +# The # package that owns it may opt to install it in an appropriate +# location under "/usr/share/initramfs-tools/scripts/". +# +# see initramfs-tools(7) for more details. + +# +# List the soft prerequisites here. This is a space separated list of +# names, of scripts that are in the same directory as this one, that +# must be run before this one can be. +# +PREREQ="" + +prereqs() +{ + echo "$PREREQ" +} + +case $1 in +# get pre-requisites +prereqs) + prereqs + exit 0 + ;; +esac + +# Do the work here. + +echo "Got here!" + +exit 0 diff --git a/docs/framebuffer b/docs/framebuffer new file mode 100644 index 0000000..453ac8f --- /dev/null +++ b/docs/framebuffer @@ -0,0 +1,116 @@ +#!/bin/sh + +PREREQ="" +prereqs() +{ + echo "$PREREQ" +} +case $1 in +# get pre-requisites +prereqs) + prereqs + exit 0 + ;; +esac + + +# The options part of the kernel "video=" argument (i.e. everyting +# after "video=<fbdriver>:") has very inconsistent rules. +# +# Generally the following applies: +# 1) options are comma-separated +# 2) options can be in either of these three forms: +# <arg>=<value>, <arg>:<value>, <boolean-arg>. +# 3) the "mode" or "mode_option" option (name depends on the framebuffer driver) +# has the form <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m] +# and may or may not start with "mode=" or "mode_option=" +# -> please adjust as necessary in the parse_video_opts() function +# +# When the options are used with modules, they need to be space-separated +# and the following conversions are needed: +# <arg>:<value> -> <arg>=<value> +# <boolean-arg> -> <boolean-arg>=1 +# <modevalue> -> mode=<modevalue> or mode_option=<modevalue> +parse_video_opts() +{ + local OPTS="$1" + local IFS="," + + # Must be a line like video=<fbdriver>:<opt1>,[opt2]... + if [ "${OPTS}" = "${OPTS%%:*}" ]; then + return + fi + OPTS="${OPTS#*:}" + for opt in ${OPTS}; do + # Already in the "<arg>=<value>" form + if [ "${opt}" != "${opt#*=}" ]; then + printf "%s" "$opt " + # In the "<arg>:<value>" form + elif [ "${opt}" != "${opt#*:}" ]; then + printf "%s" "${opt%:*}=${opt#*:} " + # Presumably a modevalue without the "mode=" prefix + elif [ "${opt}" != "${opt#[0-9]*x[0-9]}" ]; then + # Adjust: mode= option? + printf "%s" "mode=$opt " + # ... or mode_option= option? + # printf "%s" "mode_option=$opt " + # Presumably a boolean + else + printf "%s" "${opt}=1 " + fi + done +} + +FB="" +OPTS="" + +# shellcheck disable=SC2013 +for x in $(cat /proc/cmdline); do + case ${x} in + vga=*) + FB="vesafb"; + OPTS=""; + ;; + video=*) + FB=${x#*=} + FB="${FB%%:*}" + OPTS="$(parse_video_opts "${x}")" + esac +done + +# Module-specific workarounds +case ${FB} in +matroxfb) + # Map command line name to module name + FB=matroxfb_base + ;; +intelfb|i810fb|i915) + # Needs AGP driver loaded + /sbin/modprobe intel-agp + ;; +uvesafb) + # v86d requires /dev/zero and dev/mem, but udev haven't been started yet + [ -e /dev/zero ] || mknod -m 0666 /dev/zero c 1 5 + [ -e /dev/mem ] || mknod -m 0640 /dev/mem c 1 1 + ;; +*) + ;; +esac + +if [ -n "${FB}" ]; then + unset MODPROBE_OPTIONS + /sbin/modprobe -q fbcon + # shellcheck disable=SC2086 + /sbin/modprobe -q ${FB} ${OPTS} +fi + +if [ -e /proc/fb ]; then + # shellcheck disable=SC2034 + while read -r fbno desc; do + if [ $((fbno < 32)) ]; then + mknod -m 0640 "/dev/fb${fbno}" c 29 "${fbno}" + fi + done < /proc/fb +else + mknod -m 0640 /dev/fb0 c 29 0 +fi diff --git a/docs/maintainer-notes.md b/docs/maintainer-notes.md new file mode 100644 index 0000000..3b51046 --- /dev/null +++ b/docs/maintainer-notes.md @@ -0,0 +1,193 @@ +# Maintainer documentation for initramfs-tools + +[[_TOC_]] + +**NOTE:** The most recent version of this document is available at +docs/maintainer-notes.md in the [the git repository](#checkout) +or online at [salsa.debian.org](https://salsa.debian.org/kernel-team/initramfs-tools/blob/master/docs/maintainer-notes.md). + +## <a name="definitions">1. Definitions</a> + +| Name | Meaning | +| --- | --- | +| **`$mailaddress`** | mailaddress of the user | +| **`$username`** | name of the Salsa account | +| **`$version`** | version string | +| **`$yourname`** | your fullname | + +## <a name="preparations">2. Preparations</a> + +1. Install required software: + + # apt-get install git git-buildpackage dpkg-dev + +1. Set environment variables (e.g. through your ~/.bashrc or ~/.zshrc) for devscripts (gbp dch): + + export DEBEMAIL=$mailaddress + export DEBFULLNAME=$yourname + +1. Set user name and email address for git (drop the --global option to use configuration per-repo basis): + + % git config --global user.name "$yourname" + % git config --global user.email "$mailaddress" + +1. <a name="checkout">Checkout repository (anonymous):</a> + + % git clone https://salsa.debian.org/kernel-team/initramfs-tools.git + % cd initramfs-tools + +1. Checkout repository (with developer access): + + % git clone ssh://git@salsa.debian.org/kernel-team/initramfs-tools.git + % cd initramfs-tools + +## <a name="workflow">3. Workflow for daily work</a> + +### <a name="newfeature">3.1 Implement new features</a> + +1. Checkout new branch and switch to it: + + % git checkout -b $username/short-descr-of-new-feature + +1. Hack and commit work: + + % $EDITOR $somefile + % git add $somefile + % git commit -s + + **NOTE:** Use 'Closes: #BUGID' for closing a bugreport and 'Thanks: Fullname + <mailaddress>' for giving credits in your commit message. gbp dch will use + this information for generating the changelog using the --meta option later + on. + +1. Finally push your branch to Salsa: + + % git push origin $username/short-descr-of-new-feature + +### <a name="merge">3.2 Merge branches</a> + +1. Switch to the branch you want to merge: + + % git checkout $username/new-feature + +1. Rebase to master: + + % git rebase master + +1. Switch to master branch and merge: + + % git checkout master + % git merge $username/new-feature + +1. Push: + + % git push + +1. After branch is merged delete branch on server and locally: + + % git push origin :$username/short-descr-of-new-feature + % git branch -d $username/short-descr-of-new-feature + +1. If a branch is removed from the server it will stay locally. You can get of +any stale remote branches locally by executing: + + % git remote prune origin + +### <a name="test">3.3 Test specific branch</a> + +1. Checkout a specific branch iff branch is not already present locally: + + % git checkout -b somename/short-descr-of-new-feature origin/somename/short-descr-of-new-feature + +1. Checkout a specific branch iff branch is already present locally: + + % git checkout -b somename/short-descr-of-new-feature + +1. Adjust debian/changelog accordingly: + + % gbp dch --debian-branch="$(git branch | awk -F\*\ '/^* / { print $2}' )" \ + --since="v$(dpkg-parsechangelog | awk '/^Version:/ {print $2}')" -S --id-length=7 --meta --multimaint-merge + +1. Build package: + + % gbp buildpackage --git-ignore-new --git-debian-branch="$(git branch | awk -F\*\ '/^* / { print $2}' )" --post-clean + +### <a name="snapshot">3.4 Build snapshot version</a> + +1. Adjust debian/changelog accordingly: + + % gbp dch --debian-branch="$(git branch | awk -F\*\ '/^* / { print $2}' )" \ + --since="v$(dpkg-parsechangelog | awk '/^Version:/ {print $2}')" -S --id-length=7 --meta --multimaint-merge + +1. Build package: + + % gbp buildpackage --git-debian-branch="$(git branch | awk -F\*\ '/^* / { print $2}' )" --post-clean [-us -uc] + +## <a name="contribute">4. Contribute</a> + +1. Create patch: + + % git format-patch -s -p origin/master + +1. Send patch file(s) to maintainers via mail (requires Debian package git-email): + + % git send-email --to=initramfs-tools@packages.debian.org $PATCHFILE[S] + +1. The development mailinglists are [debian-kernel@lists.debian.org](mailto:debian-kernel@lists.debian.org) + and [initramfs@vger.kernel.org](mailto:initramfs@vger.kernel.org). + Discussion of features, bugs and patches are more than welcome on one + of these lists. + +## <a name="release">5. Release new version</a> + +1. Creating changelog: + + % gbp dch --debian-branch master --release --since HASH + + or more dynamically: + + % gbp dch --meta --release --since v$(dpkg-parsechangelog | awk '/^Version:/ {print $2}') --debian-branch="$(git branch | awk -F\*\ '/^* / { print $2}' )" --id-length=7 --meta --multimaint-merge + + **NOTE:** we do not use history based sorting for the changelog entries but + sort them by author. + +1. Releasing: + + % git commit -a -s -m "Releasing version $version." + +1. Tagging: + + % git tag -s v"$version" -m "release $version" + +1. Pushing: + + % git push + % git push --tags + +1. Build in chroot and upload to ftp-master. + +1. Send mail announcing the new initramfs-tools version with subject + "initramfs-tools $VERSION release" to initramfs@vger.kernel.org, + debian-kernel@lists.debian.org + kernel-team@lists.ubuntu.com - including a + shortlog (generated through "git shortlog $TAG.."). + +## <a name="resources">6. Resources</a> + +* [initramfs-tools git web interface](https://salsa.debian.org/kernel-team/initramfs-tools) +* [initramfs @ debian-wiki](https://wiki.debian.org/initramfs) +* [bugreports](https://bugs.debian.org/cgi-bin/pkgreport.cgi?src=initramfs-tools;dist=unstable) +* [initramfs-tools @ tracker](https://tracker.debian.org/pkg/initramfs-tools) +* [popcon graph](https://qa.debian.org/popcon.php?package=initramfs-tools) +* [bugreports @ ubuntu](https://bugs.launchpad.net/ubuntu/+source/initramfs-tools) +* [qa page @ ubuntu](http://status.qa.ubuntu.com/qapkgstatus/initramfs-tools) + +## <a name="credits">7. Credits</a> + +* Thanks to Daniel Baumann for his "[Debian Packaging with Git](https://web.archive.org/web/20110528125600/http://documentation.debian-projects.org/other/debian-packaging-git/)" which inspired this document. + +## <a name="license">8. License</a> + +* This document is licensed under GPL v2 or any later version. + +*-- Michael Prokop <[mika@debian.org](mailto:mika@debian.org)>, +Ben Hutchings <[benh@debian.org](mailto:benh@debian.org)>* diff --git a/hook-functions b/hook-functions new file mode 100644 index 0000000..7fccf0e --- /dev/null +++ b/hook-functions @@ -0,0 +1,983 @@ +# -*- 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 dependencies, 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 +} + +# Locate a firmware file with the given name and copy it into DESTDIR, unless +# DESTDIR already contains such a file. +# Returns an error if no such firmware file can be located and DESTDIR doesn't +# already contain any matching file. (It is up to the caller to figure out +# whether a warning should be printed in that case.) +add_firmware() +{ + local firmware found_fwloc fwloc fw_path_para path suffix + + firmware="${1}" + + read -r fw_path_para < /sys/module/firmware_class/parameters/path + + for suffix in "" ".zst" ".xz"; do + for path in ${fw_path_para:+"$fw_path_para"} \ + "/lib/firmware/updates/${version?}" \ + "/lib/firmware/updates" \ + "/lib/firmware/${version}" \ + "/lib/firmware"; do + fwloc="${path}/${firmware}${suffix}" + if [ -e "${DESTDIR}${fwloc}" ]; then + # DESTDIR already contains a matching firmware file. + return 0 + fi + if [ -z "${found_fwloc}" ] && [ -e "${fwloc}" ]; then + found_fwloc="$fwloc" + fi + done + done + + if [ -z "${found_fwloc}" ]; then + # We can't figure out where to get that firmware from. + return 1 + fi + + copy_file firmware "${found_fwloc}" +} + +# Add dependent modules + eventual firmware +# This function was changed to only collect the wanted kernel modules. +# Call apply_add_modules to copy the kernel modules. +manual_add_modules() +{ + for module in "$@"; do + echo "$module" >> "$__MODULES_TO_ADD" + done +} + +# Copy the kernel modules that were marked in manual_add_modules +apply_add_modules() +{ + # shellcheck disable=SC2046 + _call_dracut_install $(sort -u "$__MODULES_TO_ADD") + true > "$__MODULES_TO_ADD" +} + +_call_dracut_install() +{ + local dracut_verbose fw_path_para + + if [ $# -eq 0 ]; then + return + fi + + if [ "${verbose?}" = "y" ]; then + dracut_verbose=-v + fi + + read -r fw_path_para < /sys/module/firmware_class/parameters/path + /usr/lib/dracut/dracut-install -D "$DESTDIR" --kerneldir "/lib/modules/${version?}" \ + --firmwaredirs "${fw_path_para:+${fw_path_para}:}/lib/firmware/updates/${version?}:/lib/firmware/updates:/lib/firmware/${version?}:/lib/firmware" \ + ${dracut_verbose-} -o -m "$@" +} + +# manual_add_modules() takes care of adding firmware for things that were built +# as modules; but drivers can also be built into the kernel itself. To cover +# that case, we have to look at modules.builtin.modinfo instead. +# This file is generated by the kernel's build process since commit 898490c010b5 +# ("moduleparam: Save information about built-in modules in separate file"), +# which was added in Linux 5.2. +add_builtin_firmware() +{ + local builtin_modinfo_path builtin_modname firmware + + builtin_modinfo_path="/lib/modules/${version?}/modules.builtin.modinfo" + if [ ! -e "$builtin_modinfo_path" ]; then + if linux-version compare "${version}" ge 5.2; then + echo "W: Can't find modules.builtin.modinfo (for locating built-in drivers' firmware, supported in Linux >=5.2)" >&2 + fi + return + fi + + tr '\0' '\n' < "$builtin_modinfo_path" | grep -E '^[^=]*\.firmware=' | sed -n 's/\.firmware=/\t/p' | while read -r builtin_modname firmware; do + if ! add_firmware "$firmware"; then + echo "W: Possible missing firmware /lib/firmware/${firmware} for built-in driver ${builtin_modname}" >&2 + fi + 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 ${target}" + + # 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/shared library to copy to initramfs, with 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 $(env --unset=LD_PRELOAD ldd "${src}" 2>/dev/null | sed -e ' + /^[^\t]/d; + /\//!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 + + # Handle common dlopen() dependency (Debian bug #950254) + case "${x}" in + */libpthread.so.*) + copy_libgcc "${x%/*}" || return + ;; + esac + + copy_file binary "${x}" || { + ret=$? + [ ${ret} = 1 ] || return $((ret - 1)) + } + done +} + +copy_libgcc() { + local libdir library + + libdir="$1" + for library in "${libdir}"/libgcc_s.so.[1-9]; do + copy_exec "${library}" || return + 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 devlink + + # This is a crude way of storing two stacks in "$@" by using + # "--" as a separator between them, to implement iterative + # graph traversal over parent/supplier dependencies. The first + # part is device paths to traverse, the other is visited ones. + set -- "$1" "--" + while [ "$1" != "--" ]; do + device_path="$(readlink -f "$1")" + shift + + # Don't walk into same path twice, avoid infinite recursion + case "$*" in + "${device_path}") continue ;; + "${device_path} "*) continue ;; + *" ${device_path} "*) continue ;; + *" ${device_path}") continue ;; + esac + + if [ "$device_path" = "/sys" ]; then + continue + fi + + # Keep current path to add module/modalias for + set -- "$@" "$device_path" + + # Walk into suppliers in next iteration + for devlink in "${device_path}/supplier:"*; do + if [ -d "$devlink" ]; then + set -- "${devlink}/supplier/" "$@" + fi + done + + # Walk into parent in next iteration + set -- "$(dirname "$device_path")" "$@" + done + shift + + for device_path in "$@"; 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 + 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 + + # Return upon finding a zfs because when used as rootfs it is + # not presented as a typical mount point like other fs, so that + # can not be handled with commands below. Since zfs has its own + # addons in the zfs-initramfs package, do nothing here. + if [ "${FSTYPE}" = "zfs" ]; then + 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" +} + +class_add_modules() +{ + local device + + for device in "/sys/class/$1"/*; do + device="$(readlink -f "$device")" \ + && sys_walk_mod_add "$device" + done +} + +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 pwm regulator rtc; do + class_add_modules "$class" + 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 + + # Sys walk graphics for machines that don't have a generic framebuffer + # device and wouldn't have a working video console otherwise. + walk_graphics=yes + for device in /sys/bus/platform/drivers/efi-framebuffer/* \ + /sys/bus/platform/drivers/platform-framebuffer/* \ + /sys/bus/platform/drivers/simple-framebuffer/* \ + /sys/bus/platform/drivers/vesa-framebuffer/* \ + /sys/bus/coreboot/drivers/framebuffer/*; do + if [ -d "$device" ]; then + walk_graphics=no + break + fi + done + + # It's possible that a generic framebuffer device works, but is taken + # over by a more capable driver and no longer available in /sys. We + # have no reliable consistent way to detect that, so apply heuristics. + case "$(uname -m)" in + i386|i686|x86_64) walk_graphics=no ;; + esac + + if [ -d "/sys/firmware/efi/efivars" ]; then + walk_graphics=no + fi + + for node in /sys/firmware/devicetree/base/chosen/framebuffer@*; do + if [ -d "$node" ] && grep -qz '^simple-framebuffer$' "$node/compatible"; then + if [ ! -f "$node/status" ] || grep -qz '^\(okay\|ok\)$' "$node/status"; then + walk_graphics=no + fi + fi + done + + if [ "$walk_graphics" = "yes" ]; then + class_add_modules backlight + class_add_modules graphics + fi + + # 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/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 + + for device in /sys/bus/*/drivers/*panel*/*; do + if [ -d "$device" ] && [ "$(basename "$device")" != "module" ]; then + sys_walk_mod_add "$device" + fi + done + + # 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 dasd firewire mmc usb_storage fb + fi + + for arg in "$@" ; do + case "$arg" in + base) + modules="$modules btrfs ext2 ext3 ext4 f2fs" + 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/mtu3 + copy_modules_dir kernel/drivers/usb/musb + copy_modules_dir kernel/drivers/usb/renesas_usbhs + copy_modules_dir kernel/drivers/usb/typec/tcpm + # 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" + # needed to access keyboard in Gen2 Hyper-V virtual + # machines (e.g. full disk encryption scenarios) + modules="$modules hyperv-keyboard" + + # 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/pci/controller + copy_modules_dir kernel/drivers/phy + copy_modules_dir kernel/drivers/pinctrl + copy_modules_dir kernel/drivers/regulator + copy_modules_dir kernel/drivers/reset + 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 cdc-phonet.ko \ + cdc_mbim.ko cdc_subset.ko cx82310_eth.ko \ + dummy.ko gl620a.ko hamradio hippi hso.ko \ + huawei_cdc_ncm.ko ifb.ko ipheth.ko irda \ + kalmia.ko lg-vl600.ko macvlan.ko macvtap.ko \ + net1080.ko pcmcia plusb.ko qmi_wwan.ko \ + sb1000.ko sierra_net.ko team tokenring tun.ko \ + veth.ko wan wimax wireless xen-netback.ko \ + zaurus.ko + + # Required to initialize Ethernet (FEC) on ARM64 iMX8M + # devices. + modules="$modules nvmem-imx-ocotp" + ;; + ide) + copy_modules_dir kernel/drivers/ide + ;; + mmc) + copy_modules_dir kernel/drivers/mmc + ;; + scsi) + copy_modules_dir kernel/drivers/scsi + copy_modules_dir kernel/drivers/ufs + 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" + ;; + firewire) + modules="$modules firewire-ohci firewire-sbp2" + ;; + dasd) + modules="$modules dasd_diag_mod dasd_eckd_mod dasd_fba_mod" + ;; + usb_storage) + copy_modules_dir kernel/drivers/usb/storage + ;; + fb) + # For machines that don't have a generic framebuffer device. + modules="$modules rockchipdrm pwm-cros-ec pwm_bl pwm-rockchip panel-simple" + modules="$modules analogix-anx6345 pwm-sun4i sun4i-drm sun8i-mixer panel-edp" + modules="$modules mediatek-drm pwm-mtk-disp anx7625 parade_ps8640" + # For panel/backlight on MNT Reform 2 + modules="$modules pwm_imx27 nwl-dsi ti-sn65dsi86 imx-dcss" + modules="$modules mux-mmio mxsfb imx8mq-interconnect" + ;; + 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 + _call_dracut_install $( + { + cat "${DESTDIR}/lib/modules/${version}/modules.builtin" + if [ -d "${DESTDIR}/lib/modules/${version}/kernel" ]; then + find "${DESTDIR}/lib/modules/${version}/kernel" -name '*.ko*' + fi + } | + while read -r module; do + module="${module##*/}" + module="${module%%.*}" + case "$module" in + libcrc32c) + echo crc32c + ;; + ubifs) + echo deflate zlib lzo + ;; + btrfs) + echo crc32c + ;; + f2fs) + echo crc32 + ;; + mlx4_core) + echo mlx4_ib + ;; + mlx5_core) + echo mlx5_ib + ;; + i8042) + echo psmouse + ;; + nvme) + echo vmd + ;; + spi-rockchip) + echo pl330 + ;; + dw_mmc-rockchip) + echo rockchip-io-domain io-domain + ;; + mediatek-drm) + echo mediatek-drm-hdmi mtk_iommu mtk-smi + ;; + mtk_iommu) + echo mtk-smi + ;; + phy-mtk-mipi-dsi-drv) + echo nvmem_mtk-efuse + ;; + mt6397) + echo mtk-pmic-wrap + ;; + 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" +} diff --git a/hooks/fsck b/hooks/fsck new file mode 100755 index 0000000..9e84a5b --- /dev/null +++ b/hooks/fsck @@ -0,0 +1,111 @@ +#!/bin/sh + +PREREQ="" + +prereqs() +{ + echo "$PREREQ" +} + +# Find a specific fstab entry +# $1=mountpoint +# $2=fstype (optional) +_read_fstab_entry () { + # Not found by default. + echo "MNT_FSNAME=" + echo "MNT_DIR=" + echo "MNT_TYPE=" + + for file in /etc/fstab /etc/fstab.d/*.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 + echo "MNT_FSNAME=$MNT_FSNAME" + echo "MNT_DIR=$MNT_DIR" + echo "MNT_TYPE=$MNT_TYPE" + echo "MNT_PASS=$MNT_PASS" + break 2 + fi + MNT_DIR="" + done < "$file" + fi + done +} + +# Find a specific fstab entry and print its type (if found, and pass != 0) +# $1=mountpoint +get_fsck_type_fstab () { + eval "$(_read_fstab_entry "$1")" + + # Not found by default. + if [ "$1" = "$MNT_DIR" ]; then + # Ignore filesystem type for /, as it is not available and + # therefore never used at boot time + if [ "${MNT_DIR}" = "/" ] || [ "${MNT_TYPE}" = "auto" ]; then + MNT_FSNAME="$(resolve_device "${MNT_FSNAME}")" + # shellcheck disable=SC2317 + fstype() { "/usr/lib/klibc/bin/fstype" "$@"; } + if ! get_fstype "${MNT_FSNAME}"; then + echo "W: Couldn't identify type of $2 file system for fsck hook" >&2 + fi + unset -f fstype + else + echo "${MNT_TYPE}" + fi + fi +} + +get_fsck_types() { + if [ "${FSTYPE:-auto}" = auto ]; then + get_fsck_type_fstab / root + get_fsck_type_fstab /usr usr + else + local IFS=, + local fstype + set -f + for fstype in $FSTYPE; do + echo "$fstype" + done + set +f + fi +} + +case $1 in +prereqs) + prereqs + exit 0 + ;; +esac + +if [ ! -x /sbin/fsck ]; then + exit 0 +fi + +. /usr/share/initramfs-tools/scripts/functions +. /usr/share/initramfs-tools/hook-functions + +fsck_types="$(get_fsck_types | sort | uniq)" + +if [ -z "$fsck_types" ]; then + exit 0 +fi + +copy_exec /sbin/fsck +copy_exec /sbin/logsave + +for type in $fsck_types; do + if prog="$(command -v "fsck.${type}")"; then + copy_exec "$prog" + else + echo "W: /sbin/fsck.${type} doesn't exist, can't install to initramfs" >&2 + fi +done diff --git a/hooks/keymap b/hooks/keymap new file mode 100755 index 0000000..64f8e6d --- /dev/null +++ b/hooks/keymap @@ -0,0 +1,40 @@ +#!/bin/sh + +PREREQ="" + +prereqs() +{ + echo "$PREREQ" +} + +case $1 in +# get pre-requisites +prereqs) + prereqs + exit 0 + ;; +esac + +# Hook to load keymaps into the initramfs if requested by KEYMAP="y" +if [ "$KEYMAP" != "y" ] && [ "$KEYMAP" != "Y" ]; then + exit 0 +fi + +if [ ! -x /bin/setupcon ]; then + echo "setupcon is missing. Please install the 'console-setup' package." + exit 0 +fi + +. /usr/share/initramfs-tools/hook-functions + +# Tell setupcon to copy/create the files it needs. +setupcon --setup-dir "$DESTDIR" + +# Copy additional files that setupcon needs. We assume they are +# executables. +while read -r file; do + copy_exec "$file" +done < "$DESTDIR/morefiles" +rm -f "$DESTDIR/morefiles" + +exit 0 diff --git a/hooks/resume b/hooks/resume new file mode 100755 index 0000000..8ff84dd --- /dev/null +++ b/hooks/resume @@ -0,0 +1,117 @@ +#!/bin/sh + +PREREQ="" + +prereqs() +{ + echo "$PREREQ" +} + +case $1 in +# get pre-requisites +prereqs) + prereqs + exit 0 + ;; +esac + +. /usr/share/initramfs-tools/scripts/functions + +# First check if a location is set and is a valid swap partition. +# If so, the config file will be copied in and there is nothing to do. +if [ -n "$RESUME" ] && [ "$RESUME" != auto ]; then + if [ "$RESUME" = none ]; then + exit 0 + fi + if resume_dev_node="$(resolve_device "$RESUME")" && \ + blkid -p -n swap "$resume_dev_node" >/dev/null 2>&1; then + exit 0 + fi + + echo >&2 "W: initramfs-tools configuration sets RESUME=$RESUME" + echo >&2 "W: but no matching swap device is available." +fi + +# If we were not explicitly requested to select a device, or the -v +# option is used, report that we are doing so +report_auto() +{ + test "${verbose?}" != y && test "$RESUME" = auto || echo "I: $*" +} + +# Report in excruciating detail if the -v option is used +report_verbose() +{ + test "${verbose?}" != y || echo "I: $*" +} + +report_verbose "Configuration sets RESUME=$RESUME" + +# Try to autodetect the RESUME partition, using biggest swap device that +# is not ephemeral. We need to be able to read the listed swap partitions. +resume_auto= +if ! ischroot && [ -r /proc/swaps ]; then + # shellcheck disable=SC2013 + for resume_auto in $(grep ^/dev/ /proc/swaps | sort -rnk3 | cut -d " " -f 1); do + report_verbose "Checking swap device $resume_auto" + ephemeral=false + dm_name="$(dmsetup info -c --noheadings -o name "$resume_auto" 2>/dev/null)" + + # dm-crypt is ephemeral if the key file is /dev/urandom + if [ -n "$dm_name" ] && [ -e /etc/crypttab ]; then + report_verbose "$resume_auto has device-mapper name $dm_name; checking crypttab" + # shellcheck disable=SC2034 + while read -r cryptdev srcdev keyfile junk; do + report_verbose "Found cryptdev=$cryptdev keyfile=$keyfile" + if [ "$cryptdev" = "$dm_name" ] && [ "$keyfile" = /dev/urandom ]; then + report_verbose "Rejecting $resume_auto since it has no permanent key" + ephemeral=true + fi + done < /etc/crypttab + fi + + # zram is ephemeral + case "$resume_auto" in + /dev/zram*) + report_verbose "Rejecting $resume_auto since it is zram" + ephemeral=true + ;; + + /dev/zd[0-9]*) + report_verbose "Rejecting $resume_auto since it is zvol" + ephemeral=true + ;; + esac + + $ephemeral || break + done + + if $ephemeral; then + resume_auto= + fi + if [ -n "$resume_auto" ]; then + if [ -n "$dm_name" ]; then + resume_auto_canon="/dev/mapper/$dm_name" + elif UUID=$(blkid -s UUID -o value "$resume_auto"); then + resume_auto_canon="UUID=$UUID" + else + resume_auto_canon= + fi + report_auto "The initramfs will attempt to resume from $resume_auto" + if [ -n "$resume_auto_canon" ]; then + report_auto "($resume_auto_canon)" + resume_auto="$resume_auto_canon" + fi + report_auto "Set the RESUME variable to override this." + fi +fi + +# Write selected resume device to intramfs conf.d +if [ "$RESUME" = auto ] || [ -n "$resume_auto" ]; then + # If we were explicitly requested to select a device, and we failed, + # report that + if [ -z "$resume_auto" ]; then + echo >&2 "W: initramfs-tools failed to select a resume device" + fi + echo "RESUME=${resume_auto}" > "${DESTDIR}/conf/conf.d/zz-resume-auto" +fi diff --git a/hooks/thermal b/hooks/thermal new file mode 100755 index 0000000..37eae63 --- /dev/null +++ b/hooks/thermal @@ -0,0 +1,65 @@ +#!/bin/sh + +PREREQ="" + +prereqs() +{ + echo "$PREREQ" +} + +case $1 in +# get pre-requisites +prereqs) + prereqs + exit 0 + ;; +esac + +# Hooks for loading thermal bits into the initramfs + +. /usr/share/initramfs-tools/hook-functions + +case "$DPKG_ARCH" in +# copy the right modules +powerpc|ppc64) + + # Only G5 Mac machines need to load + # windfarm_core or one of the windfarm_pm* modules. + + [ -r /proc/cpuinfo ] || exit 0 + + MODEL="$(grep model /proc/cpuinfo)" + MODEL="${MODEL##*: }" + + case "$MODEL" in + RackMac3,1) + force_load windfarm_rm31 + ;; + PowerMac7,2|PowerMac7,3) + force_load windfarm_pm72 + ;; + PowerMac8,1|PowerMac8,2) + force_load windfarm_pm81 + ;; + PowerMac9,1) + force_load windfarm_pm91 + ;; + PowerMac11,2) + force_load windfarm_pm112 + ;; + PowerMac12,1) + force_load windfarm_pm121 + ;; + *) + # No other machine needs windfarm_* modules on initrd. + exit 0 + ;; + esac + manual_add_modules windfarm_core windfarm_cpufreq_clamp \ + windfarm_lm75_sensor windfarm_max6690_sensor windfarm_pid \ + windfarm_smu_controls windfarm_smu_sat windfarm_smu_sensors + ;; +i386|amd64|ia64) + manual_add_modules fan thermal + ;; +esac @@ -0,0 +1,339 @@ +#!/bin/sh + +# Default PATH differs between shells, and is not automatically exported +# by klibc dash. Make it consistent. +export PATH=/sbin:/usr/sbin:/bin:/usr/bin + +[ -d /dev ] || mkdir -m 0755 /dev +[ -d /root ] || mkdir -m 0700 /root +[ -d /sys ] || mkdir /sys +[ -d /proc ] || mkdir /proc +[ -d /tmp ] || mkdir /tmp +mkdir -p /var/lock +mount -t sysfs -o nodev,noexec,nosuid sysfs /sys +mount -t proc -o nodev,noexec,nosuid proc /proc + +# shellcheck disable=SC2013 +for x in $(cat /proc/cmdline); do + case $x in + initramfs.clear) + clear + ;; + quiet) + quiet=y + ;; + esac +done + +if [ "$quiet" != "y" ]; then + quiet=n + echo "Loading, please wait..." +fi +export quiet + +# Note that this only becomes /dev on the real filesystem if udev's scripts +# are used; which they will be, but it's worth pointing out +mount -t devtmpfs -o nosuid,mode=0755 udev /dev + +# Prepare the /dev directory +[ ! -h /dev/fd ] && ln -s /proc/self/fd /dev/fd +[ ! -h /dev/stdin ] && ln -s /proc/self/fd/0 /dev/stdin +[ ! -h /dev/stdout ] && ln -s /proc/self/fd/1 /dev/stdout +[ ! -h /dev/stderr ] && ln -s /proc/self/fd/2 /dev/stderr + +mkdir /dev/pts +mount -t devpts -o noexec,nosuid,gid=5,mode=0620 devpts /dev/pts || true + +# Export the dpkg architecture +export DPKG_ARCH= +. /conf/arch.conf + +# Set modprobe env +export MODPROBE_OPTIONS="-qb" + +# Export relevant variables +export ROOT= +export ROOTDELAY= +export ROOTFLAGS= +export ROOTFSTYPE= +export IP= +export DEVICE= +export BOOT= +export BOOTIF= +export UBIMTD= +export break= +export init=/sbin/init +export readonly=y +export rootmnt=/root +export debug= +export panic= +export blacklist= +export resume= +export resume_offset= +export noresume= +export drop_caps= +export fastboot=n +export forcefsck=n +export fsckfix= + + +# Bring in the main config +. /conf/initramfs.conf +for conf in conf/conf.d/*; do + [ -f "${conf}" ] && . "${conf}" +done +. /scripts/functions + +# Parse command line options +# shellcheck disable=SC2013 +for x in $(cat /proc/cmdline); do + case $x in + init=*) + init=${x#init=} + ;; + root=*) + ROOT=${x#root=} + if [ -z "${BOOT}" ] && [ "$ROOT" = "/dev/nfs" ]; then + BOOT=nfs + fi + ;; + rootflags=*) + ROOTFLAGS="-o ${x#rootflags=}" + ;; + rootfstype=*) + ROOTFSTYPE="${x#rootfstype=}" + ;; + rootdelay=*) + ROOTDELAY="${x#rootdelay=}" + case ${ROOTDELAY} in + *[![:digit:].]*) + ROOTDELAY= + ;; + esac + ;; + nfsroot=*) + # shellcheck disable=SC2034 + NFSROOT="${x#nfsroot=}" + ;; + initramfs.runsize=*) + RUNSIZE="${x#initramfs.runsize=}" + ;; + ip=*) + IP="${x#ip=}" + ;; + boot=*) + BOOT=${x#boot=} + ;; + ubi.mtd=*) + UBIMTD=${x#ubi.mtd=} + ;; + resume=*) + RESUME="${x#resume=}" + ;; + resume_offset=*) + resume_offset="${x#resume_offset=}" + ;; + noresume) + noresume=y + ;; + drop_capabilities=*) + drop_caps="-d ${x#drop_capabilities=}" + ;; + panic=*) + panic="${x#panic=}" + ;; + ro) + readonly=y + ;; + rw) + readonly=n + ;; + debug) + debug=y + quiet=n + if [ -n "${netconsole}" ]; then + log_output=/dev/kmsg + else + log_output=/run/initramfs/initramfs.debug + fi + set -x + ;; + debug=*) + debug=y + quiet=n + set -x + ;; + break=*) + break=${x#break=} + ;; + break) + break=premount + ;; + blacklist=*) + blacklist=${x#blacklist=} + ;; + netconsole=*) + netconsole=${x#netconsole=} + [ "$debug" = "y" ] && log_output=/dev/kmsg + ;; + BOOTIF=*) + BOOTIF=${x#BOOTIF=} + ;; + fastboot|fsck.mode=skip) + fastboot=y + ;; + forcefsck|fsck.mode=force) + forcefsck=y + ;; + fsckfix|fsck.repair=yes) + fsckfix=y + ;; + fsck.repair=no) + fsckfix=n + ;; + esac +done + +# Default to BOOT=local if no boot script defined. +if [ -z "${BOOT}" ]; then + BOOT=local +fi + +if [ -n "${noresume}" ] || [ "$RESUME" = none ]; then + noresume=y +else + resume=${RESUME:-} +fi + +mount -t tmpfs -o "nodev,noexec,nosuid,size=${RUNSIZE:-10%},mode=0755" tmpfs /run +mkdir -m 0700 /run/initramfs + +if [ -n "$log_output" ]; then + exec >"$log_output" 2>&1 + unset log_output +fi + +maybe_break top + +# Don't do log messages here to avoid confusing graphical boots +run_scripts /scripts/init-top + +maybe_break modules +[ "$quiet" != "y" ] && log_begin_msg "Loading essential drivers" +[ -n "${netconsole}" ] && /sbin/modprobe netconsole netconsole="${netconsole}" +load_modules +[ "$quiet" != "y" ] && log_end_msg + +starttime="$(_uptime)" +starttime=$((starttime + 1)) # round up +export starttime + +if [ "$ROOTDELAY" ]; then + sleep "$ROOTDELAY" +fi + +maybe_break premount +[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/init-premount" +run_scripts /scripts/init-premount +[ "$quiet" != "y" ] && log_end_msg + +maybe_break mount +log_begin_msg "Mounting root file system" +# Always load local and nfs (since these might be needed for /etc or +# /usr, irrespective of the boot script used to mount the rootfs). +. /scripts/local +. /scripts/nfs +. "/scripts/${BOOT}" +parse_numeric "${ROOT}" +maybe_break mountroot +mount_top +mount_premount +mountroot +log_end_msg + +if read_fstab_entry /usr; then + log_begin_msg "Mounting /usr file system" + mountfs /usr + log_end_msg +fi + +# Mount cleanup +mount_bottom +nfs_bottom +local_bottom + +case "$IP" in +""|none|off) ;; # Do nothing +*) + configure_networking +esac + +maybe_break bottom +[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/init-bottom" +# We expect udev's init-bottom script to move /dev to ${rootmnt}/dev +run_scripts /scripts/init-bottom +[ "$quiet" != "y" ] && log_end_msg + +# Move /run to the root +mount -n -o move /run ${rootmnt}/run + +validate_init() { + run-init -n "${rootmnt}" "${1}" +} + +# Check init is really there +if ! validate_init "$init"; then + echo "Target filesystem doesn't have requested ${init}." + init= + for inittest in /sbin/init /etc/init /bin/init /bin/sh; do + if validate_init "${inittest}"; then + init="$inittest" + break + fi + done +fi + +# No init on rootmount +if ! validate_init "${init}" ; then + panic "No init found. Try passing init= bootarg." +fi + +maybe_break init + +# don't leak too much of env - some init(8) don't clear it +# (keep init, rootmnt, drop_caps) +unset debug +unset MODPROBE_OPTIONS +unset DPKG_ARCH +unset ROOTFLAGS +unset ROOTFSTYPE +unset ROOTDELAY +unset ROOT +unset IP +unset BOOT +unset BOOTIF +unset DEVICE +unset UBIMTD +unset blacklist +unset break +unset noresume +unset panic +unset quiet +unset readonly +unset resume +unset resume_offset +unset noresume +unset fastboot +unset forcefsck +unset fsckfix +unset starttime + +# Move virtual filesystems over to the real filesystem +mount -n -o move /sys ${rootmnt}/sys +mount -n -o move /proc ${rootmnt}/proc + +# Chain to real filesystem +# shellcheck disable=SC2086,SC2094 +exec run-init ${drop_caps} "${rootmnt}" "${init}" "$@" <"${rootmnt}/dev/console" >"${rootmnt}/dev/console" 2>&1 +echo "Something went badly wrong in the initramfs." +panic "Please file a bug on initramfs-tools." diff --git a/initramfs-tools.7 b/initramfs-tools.7 new file mode 100644 index 0000000..2d5d2d2 --- /dev/null +++ b/initramfs-tools.7 @@ -0,0 +1,671 @@ +.TH INITRAMFS-TOOLS 7 "2018/07/18" "initramfs\-tools" "Linux Programmer's Manual" + +.SH NAME +initramfs-tools \- an introduction to writing scripts for mkinitramfs + +.SH DESCRIPTION +initramfs-tools has one main script and two different sets of subscripts which +will be used during different phases of execution. Each of these will be +discussed separately below with the help of an imaginary tool which performs a +frobnication of a lvm partition prior to mounting the root partition. + +.SH Kernel Command Line +The root filesystem used by the kernel is specified by the boot loader as +always. The traditional \fBroot=/dev/sda1\fR style device specification is +allowed. If a label is used, as in \fBroot=LABEL=rootPart\fR the initrd will +search all available devices for a filesystem with the appropriate label, and +mount that device as the root filesystem. \fBroot=UUID=uuidnumber\fR will +mount the partition with that UUID as the root filesystem. + +.SS Standard + +.TP +\fB\fI init= "<path to real init>" +the binary to hand over execution to on the root fs after the initramfs scripts are done. + +.TP +\fB\fI initramfs.clear +clear screen at the beginning + +.TP +\fB\fI initramfs.runsize +The size of the \fI/run\fP tmpfs mount point in bytes (suffixes are supported) +or as percentage of your physical RAM. This parameter is used as the value of +the size mount option to tmpfs. See +\fBhttps://www.kernel.org/doc/Documentation/filesystems/tmpfs.txt\fR for +details. The default is 10%. + +.TP +\fB\fI root= "<path to blockdevice>" +the device node to mount as the root file system. +The recommended usage is to specify the UUID as followed "root=UUID=xxx". + +.TP +\fB\fI rootfstype +set the root file system type. + +.TP +\fB\fI rootdelay +set delay in seconds. Determines how long mountroot waits for root to appear. +The default is 180 seconds. + +.TP +\fB\fI rootflags +set the file system mount option string. + +.TP +\fB\fI nfsroot +can be either "auto" to try to get the relevant information from DHCP or a +string of the form NFSSERVER:NFSPATH or NFSSERVER:NFSPATH:NFSOPTS. +Use root=/dev/nfs for NFS to kick to in. NFSOPTS can be looked up in +\fInfs(5)\fP. + +.TP +\fB\fI ip +tells how to configure the ip address. Allows one to specify an different +NFS server than the DHCP server. See Documentation/filesystems/nfsroot.txt +in any recent Linux source for details. Optional parameter for NFS root. + +.TP +\fB\fI BOOTIF +is a mac address in pxelinux format with leading "01-" and "-" as separations. +pxelinux passes mac address of network card used to PXE boot on with this +bootarg. + +.TP +\fB\fI boot +either local or NFS (affects which initramfs scripts are run, see the "Subdirectories" section under boot scripts). + +.TP +\fB\fI resume +The resume hook tries to autodetect the resume partition and uses the first +swap partition as valid guess. It is possible to set the RESUME variable in +/etc/initramfs-tools/conf.d/resume. +The boot variable noresume overrides it. + +.TP +\fB\fI resume_offset +Specify the offset from the partition given by "resume=" at which the swap +header of the swap file is located. + +.TP +\fB\fI quiet +reduces the amount of text output to the console during boot. + +.TP +\fB\fI ro +mounts the rootfs read-only. + +.TP +\fB\fI rw +mounts the rootfs read-write. + +.TP +\fB\fI blacklist +disables load of specific modules. +Use blacklist=module1,module2,module3 bootparameter. + +.SS Debug +.TP +\fB\fI panic +sets an timeout on panic. +panic=<sec> is a documented security feature: it disables the debug shell. + +.TP +\fB\fI debug +generates lots of output. It writes a log to /run/initramfs/initramfs.debug. +Instead when invoked with an arbitrary argument output is written to console. +Use for example "debug=vc". + +.TP +\fB\fI break +spawns a shell in the initramfs image at the chosen phase +(top, modules, premount, mount, mountroot, bottom, init) +before actually executing the corresponding scripts +(see the "Boot scripts" section) or action. Multiple +phases may be specified, delimited by commas. +The default, if no phase is specified, is "premount". +Beware that if both "panic" and "break" are present, +initramfs will not spawn any shells but reboot instead. + +.TP +\fB\fI netconsole +loads netconsole linux modules with the chosen args. + +.TP +\fB\fI all_generic_ide +loads generic IDE/ATA chipset support on boot. + + +.SH SCRIPTS + +Valid boot and hook scripts names consist solely of alphabetics, numerics, +dashes and underscores. Other scripts are discarded. + +.SS Configuration hook scripts +These are used to override the user configuration where necessary, for +example to force use of busybox instead of klibc utilities. + +.SS Hook scripts +These are used when an initramfs image is created and not included in the +image itself. They can however cause files to be included in the image. +Hook scripts are executed under errexit. Thus a hook script can abort the +mkinitramfs build on possible errors (exitcode != 0). + +.SS Boot scripts +These are included in the initramfs image and normally executed during +kernel boot in the early user-space before the root partition has been +mounted. + + +.SH CONFIGURATION HOOK SCRIPTS + +Configuration hook scripts can be found in +/usr/share/initramfs-tools/conf-hooks.d. They are sourced by +mkinitramfs after the configuration files in /etc and before running +any hook scripts. They can override any of the variables documented +in \fIinitramfs.conf\fR(5), but this should be done only if absolutely +necessary. For example, if a package's boot script requires commands +not provided by klibc-utils, it should also install a configuration +hook that sets \fBBUSYBOX=y\fR. + + +.SH HOOK SCRIPTS + +Hooks can be found in two places: /usr/share/initramfs-tools/hooks and +/etc/initramfs-tools/hooks. They are executed during generation of the +initramfs-image and are responsible for including all the necessary components +in the image itself. No guarantees are made as to the order in which the +different scripts are executed unless the prereqs are setup in the script. +Please notice that PREREQ is only honored inside a single directory. So first +the scripts in /usr/share/initramfs-tools are ordered according to their PREREQ +values and executed. Then all scripts in /etc/initramfs-tools are ordered +according to \fBtheir\fR PREREQ values and executed. This mean that currently +there is no possibility to have a local script (/etc/initramfs-tools) get +executed before one from the package (/usr/share/initramfs-tools). + +If a hook script requires configuration beyond the exported variables +listed below, it should read a private configuration file that is +separate from the /etc/initramfs-tools directory. It \fImust not\fR +read initramfs-tools configuration files directly. + +.SS Header +In order to support prereqs, each script should begin with the following lines: + +.RS +.nf +#!/bin/sh +PREREQ="" +prereqs() +{ + echo "$PREREQ" +} + +case $1 in +prereqs) + prereqs + exit 0 + ;; +esac + +\fR. /usr/share/initramfs-tools/hook-functions +# Begin real processing below this line +.fi +.RE + +For example, if you are writing a new hook script which relies on lvm, the line +starting with PREREQ should be changed to PREREQ="lvm" which will ensure that +the lvm hook script is run before your custom script. + +.SS Help functions +/usr/share/initramfs-tools/hook-functions contains a number of functions which +deal with some common tasks in a hook script: +.TP +\fB\fI +manual_add_modules +adds a module (and any modules which it depends on) to the initramfs image. +.RS +.PP +.B Example: +manual_add_modules isofs +.RE + +.TP +\fB\fI +add_modules_from_file +reads a file containing a list of modules (one per line) to be added to the +initramfs image. The file can contain comments (lines starting with #) and +arguments to the modules by writing the arguments on the same line as the name +of the module. +.RS +.PP +.B Example: +add_modules_from_file /tmp/modlist +.RE + +.TP +\fB\fI +force_load +adds a module (and its dependencies) to the initramfs image and also +unconditionally loads the module during boot. Also supports passing arguments +to the module by listing them after the module name. +.RS +.PP +.B Example: +force_load cdrom debug=1 +.RE + +.TP +\fB\fI +copy_modules_dir +copies an entire module directory from /lib/modules/KERNELVERSION/ into the +initramfs image. +.RS +.PP +.B Example: +copy_modules_dir kernel/drivers/ata +.RE + +.SS Including binaries +If you need to copy an executable or shared library to the initramfs +module, use a command like this: +.PP +.RS +copy_exec /sbin/mdadm /sbin +.RE + +mkinitramfs will automatically detect which libraries it depends on +and copy them to the initramfs. This means that most executables, unless +compiled with klibc, will automatically include glibc in the image which will +increase its size by several hundred kilobytes. + +.SS Including a system firmware preimage (early initramfs) +If you need to prepend data to the initramfs image, you need to prepare it +in a file, and call the \fB\fIprepend_earlyinitramfs\fR function. The file +can be disposed of as soon as the function returns. + +.B Example: +.nf +TEMP_FILE=$(mktemp ...) + ... +prepend_earlyinitramfs ${TEMP_FILE} +rm -f ${TEMP_FILE} + +.RE + +.SS Exported variables +mkinitramfs sets several variables for the hook scripts environment. + +.TP +\fB\fI MODULESDIR +corresponds to the linux modules dir. +.TP +\fB\fI version +is the $(uname \-r) linux version against mkinitramfs is run. +.TP +\fB\fI CONFDIR +is the path of the used initramfs-tools configurations. +.TP +\fB\fI DESTDIR +is the root path of the newly build initramfs. +.TP +\fB\fI DPKG_ARCH +allows arch specific hook additions. +.TP +\fB\fI verbose +corresponds to the verbosity of the update-initramfs run. +.TP +\fB\fI BUSYBOX, KEYMAP, MODULES +are as described in \fIinitramfs.conf\fR(5). +.TP +\fB\fI BUSYBOXDIR +is the directory where busybox utilities should be installed from, or +empty if busybox is not being used. + + +.SH BOOT SCRIPTS + +Similarly to hook scripts, boot scripts can be found in two places +/usr/share/initramfs-tools/scripts/ and /etc/initramfs-tools/scripts/. There +are a number of subdirectories to these two directories which control the boot +stage at which the scripts are executed. + +.SS Header +Like for hook scripts, there are no guarantees as to the order in which the +different scripts in one subdirectory (see "Subdirectories" below) are +executed. In order to define a certain order, a similar header as for hook +scripts should be used: + +.RS +.nf +#!/bin/sh +PREREQ="" +prereqs() +{ + echo "$PREREQ" +} + +case $1 in +prereqs) + prereqs + exit 0 + ;; +esac +.fi +.RE + +Where PREREQ is modified to list other scripts in the same subdirectory if necessary. + +.SS Help functions +A number of functions (mostly dealing with output) are provided to boot scripts in +.I /scripts/functions +: + +.TP +\fB\fI +log_success_msg +Logs a success message +.RS +.PP +.B Example: +log_success_msg "Frobnication successful" +.RE + +.TP +\fB\fI +log_failure_msg +Logs a failure message +.RS +.PP +.B Example: +log_failure_msg "Frobnication component froobz missing" +.RE + +.TP +\fB\fI +log_warning_msg +Logs a warning message +.RS +.PP +.B Example: +log_warning_msg "Only partial frobnication possible" +.RE + +.TP +\fB\fI +log_begin_msg +Logs a message that some processing step has begun + +.TP +\fB\fI +log_end_msg +Logs a message that some processing step is finished +.RS +.PP +.B Example: +.PP +.RS +.nf +log_begin_msg "Frobnication begun" +# Do something +log_end_msg +.fi +.RE +.RE + +.TP +\fB\fI +panic +Logs an error message and executes a shell in the initramfs image to allow the +user to investigate the situation. +.RS +.PP +.B Example: +panic "Frobnication failed" +.RE + +.SS Subdirectories +Both /usr/share/initramfs-tools/scripts and /etc/initramfs-tools/scripts +contains the following subdirectories. + +.TP +\fB\fI +init-top +the scripts in this directory are the first scripts to be executed after sysfs +and procfs have been mounted. +It also runs the udev hook for populating the /dev tree (udev will keep +running until init-bottom). + +.TP +\fB\fI +init-premount +happens after modules specified by hooks and /etc/initramfs-tools/modules +have been loaded. + +.TP +\fB\fI +local-top OR nfs-top +After these scripts have been executed, the root device node is expected to be +present (local) or the network interface is expected to be usable (NFS). + +.TP +\fB\fI +local-block +These scripts are called with the name of a local block device. After +these scripts have been executed, that device node should be present. +If the local-top or local-block scripts fail to create the wanted +device node, the local-block scripts will be called periodically to +try again. + +.TP +\fB\fI +local-premount OR nfs-premount +are run after the sanity of the root device has been verified (local) or the +network interface has been brought up (NFS), but before the actual root fs has +been mounted. + +.TP +\fB\fI +local-bottom OR nfs-bottom +are run after the rootfs has been mounted (local) or the NFS root share has +been mounted. + +.TP +\fB\fI +init-bottom +are the last scripts to be executed before procfs and sysfs are moved to the +real rootfs and execution is turned over to the init binary which should now be +found in the mounted rootfs. udev is stopped. + +.SS Boot parameters +.TP +\fB\fI +/conf/param.conf +allows boot scripts to change exported variables that are listed on top of init. Write the new values to it. It will be sourced after an boot script run if it exists. + + +.SH EXAMPLES + +.SS Hook script +An example hook script would look something like this (and would usually be +placed in /etc/initramfs-tools/hooks/frobnicate): + +.RS +.nf +#!/bin/sh +# Example frobnication hook script + +PREREQ="lvm" +prereqs() +{ + echo "$PREREQ" +} + +case $1 in +prereqs) + prereqs + exit 0 + ;; +esac + +\fR. /usr/share/initramfs-tools/hook-functions +# Begin real processing below this line + +if [ ! \-x "/sbin/frobnicate" ]; then + exit 0 +fi + +force_load frobnicator interval=10 +copy_exec /sbin/frobnicate /sbin +exit 0 +.fi +.RE + +.SS Boot script +An example boot script would look something like this (and would usually be placed in /etc/initramfs-tools/scripts/local-top/frobnicate): + +.RS +.nf +#!/bin/sh +# Example frobnication boot script + +PREREQ="lvm" +prereqs() +{ + echo "$PREREQ" +} + +case $1 in +prereqs) + prereqs + exit 0 + ;; +esac + +\fR. /scripts/functions +# Begin real processing below this line +if [ ! \-x "/sbin/frobnicate" ]; then + panic "Frobnication executable not found" +fi + +if [ ! \-e "/dev/mapper/frobb" ]; then + panic "Frobnication device not found" +fi + +log_begin_msg "Starting frobnication" +/sbin/frobnicate "/dev/mapper/frobb" || panic "Frobnication failed" +log_end_msg + +exit 0 +.fi +.RE + +.SS Exported variables +init sets several variables for the boot scripts environment. + +.TP +\fB\fI ROOT +corresponds to the root boot option. +Advanced boot scripts like cryptsetup or live-initramfs need to play tricks. +Otherwise keep it alone. +.TP +\fB\fI ROOTDELAY, ROOTFLAGS, ROOTFSTYPE, IP +corresponds to the rootdelay, rootflags, rootfstype or ip boot option. +Use of ROOTDELAY is deprecated; you should implement a \fIlocal-block\fR +boot script rather than delaying or polling. +.TP +\fB\fI DPKG_ARCH +allows arch specific boot actions. +.TP +\fB\fI blacklist, panic, quiet, resume, noresume, resume_offset +set according relevant boot option. +.TP +\fB\fI break +Useful for manual intervention during setup and coding an boot script. +.TP +\fB\fI REASON +Argument passed to the \fIpanic\fP helper function. Use to find out why +you landed in the initramfs shell. +.TP +\fB\fI init +passes the path to init(8) usually /sbin/init. +.TP +\fB\fI readonly +is the default for mounting the root corresponds to the ro bootarg. +Overridden by rw bootarg. +.TP +\fB\fI rootmnt +is the path where root gets mounted usually /root. +.TP +\fB\fI debug +indicates that a debug log is captured for further investigation. + + +.SH UPDATING THE INITRAMFS FROM ANOTHER PACKAGE +Package maintainer scripts should not run \fBupdate-initramfs\fR +directly. A package that installs hooks for initramfs-tools should +include a triggers file containing: +.RS +.nf +activate\-noawait update\-initramfs +.fi +.RE + +Kernel packages must call the kernel hooks as documented in the +Debian Kernel Handbook. + +A package that requires an initramfs to function, but is not a kernel +package, should include a triggers file containing: +.RS +.nf +activate\-await update\-initramfs +.fi +.RE + + +.SH KERNEL HOOKS +initramfs-tools includes hook scripts that are called by kernel +packages on installation and removal, so that an initramfs is +automatically created, updated or deleted as necessary. The hook +scripts do nothing if the environment variable \fBINITRD\fR is +set to \fBNo\fR. This will be the case for kernel packages +built with \fBmake deb-pkg\fR and with \fBCONFIG_BLK_DEV_INITRD\fR +not set in the kernel config, or built with \fBmake-kpkg\fR and not +using the \fB--initrd\fR option. + + +.SH DEBUG +It is easy to check the generated initramfs for its content. One may need +to double-check if it contains the relevant binaries, libs or modules: +.RS +.nf +lsinitramfs /boot/initrd.img\-3.16\-3\-amd64 +.fi +.RE + + +.SH FILES +.TP +.I /run/initramfs/fsck.log +Log of fsck commands run within the initramfs, with their output. +.TP +.I /run/initramfs/fsck-root +Exists only if fsck ran successfully for the root filesystem. +.TP +.I /run/initramfs/fsck-usr +Exists only if fsck ran successfully for the \fI/usr\fR filesystem. + + +.SH AUTHOR +The initramfs-tools are written by Maximilian Attems <maks@debian.org>, +Jeff Bailey <jbailey@raspberryginger.com> and numerous others. +.PP +This manual was written by David H\[:a]rdeman <david@hardeman.nu>, +updated by Maximilian Attems <maks@debian.org>. + +.SH SEE ALSO +.BR +.IR initramfs.conf (5), +.IR mkinitramfs (8), +.IR update-initramfs (8), +.IR lsinitramfs (8). diff --git a/initramfs.conf.5 b/initramfs.conf.5 new file mode 100644 index 0000000..76e4010 --- /dev/null +++ b/initramfs.conf.5 @@ -0,0 +1,138 @@ +.TH INITRAMFS.CONF 5 "2018/07/18" "initramfs\-tools" "File Formats Manual" + +.SH NAME +initramfs.conf \- configuration file for mkinitramfs + +.SH DESCRIPTION +The behaviour of +.B mkinitramfs +can be modified by its configuration file. + +Each line in the file can be a configuration variable, a blank line, +or a comment. The value of an variable is assigned by an statement +of the form: \fIname\fP=[\fIvalue\fP] + +Configuration options can be broken out into configuration snippets and +placed in individual files in the /etc/initramfs-tools/conf.d directory. Files +in this directory are always read \fBafter\fP the main configuration file, +so you can override the settings in the main config file without editing it +directly. + +.SH GENERAL VARIABLES +.TP +\fB MODULES +Specifies the modules for the initramfs image. + +Modules listed in \fI/etc/initramfs-tools/modules\fP and +\fI/usr/share/initramfs-tools/modules.d/*\fP are always included in the +initramfs, and are loaded early in the boot process. + + +\fIlist\fP doesn't load any additional modules at boot time, other than those +listed in the above files. + +\fImost\fP adds most file system, all ata, sata, scsi and usb drivers. + +\fIdep\fP tries to guess which modules are necessary for the running box and +only adds those modules. + +\fInetboot\fP adds the base and network modules, but skips block devices. + + +The default setting is \fImost\fP. + +.TP +\fB BUSYBOX +Include busybox utilities for the boot scripts. +If set to 'n' +.B mkinitramfs +will build an initramfs without busybox. +Beware that many boot scripts need busybox utilities. + +.TP +\fB KEYMAP +If set to 'y', the console keymap will be loaded during the initramfs stage. +The keymap will anyway be loaded by the initscripts later, and the packages +that might need input will normally set this variable automatically, so there +should normally be no need to set this. + +.TP +\fB COMPRESS +Specifies the compression method used for the initramfs image. +.B mkinitramfs +will default to gzip if the kernel lacks support (CONFIG_RD) or the +corresponding userspace utility is not present. + +.TP +\fB COMPRESSLEVEL +Specifies the compression level used for the initramfs image. +.B mkinitramfs +will default to 9 for lz4, 9 for zstd, and the builtin defaults for all +others. + +.TP +\fB UMASK +Set the umask value of the generated initramfs file. +Useful to not disclose eventual keys. + +.TP +\fB BOOT +Allows one to use an nfs drive as the root of the drive. +The default is to boot from \fIlocal\fP media (hard drive, USB stick). +Set to \fInfs\fP for an NFS root share. + +.TP +\fB RUNSIZE +The size of the \fI/run\fP tmpfs mount point in bytes (suffixes are supported) +or as percentage of your physical RAM. This parameter is used as the value of +the size mount option to tmpfs. See +\fBhttps://www.kernel.org/doc/Documentation/filesystems/tmpfs.txt\fR for +details. Can be overridden by an optional \fBinitramfs.runsize=\fR bootarg. +The default is 10%. + +.SH VARIABLES FOR LOCAL BOOT +.TP +\fB RESUME +Specifies the device used for suspend-to-disk (hibernation), which the +initramfs code should attempt to resume from. If this is not defined +or is set to \fIauto\fP, +.B mkinitramfs +will automatically select the largest available swap partition. +Set it to \fInone\fP to disable resume from disk. + +.TP +\fB FSTYPE +Specifies the filesystem type(s) to support, separated by commas. If +this is not defined or is set to \fIauto\fP, \fBmkinitramfs\fP will +automatically detect the current root and \fI/usr\fP filesystem types. + +.SH VARIABLES FOR NFS BOOT +.TP +\fB DEVICE +Specifies the default network interface to use, like eth0. The \fIip\fP or +\fIBOOTIF\fP bootargs may override this. + +.TP +\fB ROOT +Allows optional root bootarg hardcoding, when no root bootarg can be passed. +A root bootarg overrides that special setting. + +.TP +\fB NFSROOT +Defaults to \fIauto\fP in order to pick up value from DHCP server. +Otherwise you need to specify \fIHOST:MOUNT\fP. + +.SH FILES +.TP +.I /etc/initramfs-tools/initramfs.conf + +.SH AUTHOR +The initramfs-tools are written by Maximilian Attems <maks@debian.org>, +Jeff Bailey <jbailey@raspberryginger.com> and numerous others. +Loosely based on mkinitrd.conf by Herbert Xu. + +.SH SEE ALSO +.BR +.IR initramfs-tools (7), +.IR mkinitramfs (8), +.IR update-initramfs (8). diff --git a/kernel/postinst.d/initramfs-tools b/kernel/postinst.d/initramfs-tools new file mode 100755 index 0000000..6b6fef3 --- /dev/null +++ b/kernel/postinst.d/initramfs-tools @@ -0,0 +1,36 @@ +#!/bin/sh -e + +version="$1" +bootopt="" + +command -v update-initramfs >/dev/null 2>&1 || exit 0 + +# passing the kernel version is required +if [ -z "${version}" ]; then + echo >&2 "W: initramfs-tools: ${DPKG_MAINTSCRIPT_PACKAGE:-kernel package} did not pass a version number" + exit 2 +fi + +# exit if kernel does not need an initramfs +if [ "$INITRD" = 'No' ]; then + exit 0 +fi + +# absolute file name of kernel image may be passed as a second argument; +# create the initrd in the same directory +if [ -n "$2" ]; then + bootdir=$(dirname "$2") + bootopt="-b ${bootdir}" +fi + +# avoid running multiple times +if [ -n "$DEB_MAINT_PARAMS" ]; then + eval set -- "$DEB_MAINT_PARAMS" + if [ -z "$1" ] || [ "$1" != "configure" ]; then + exit 0 + fi +fi + +# we're good - create initramfs. update runs do_bootloader +# shellcheck disable=SC2086 +update-initramfs -c -k "${version}" ${bootopt} >&2 diff --git a/kernel/postrm.d/initramfs-tools b/kernel/postrm.d/initramfs-tools new file mode 100755 index 0000000..c340beb --- /dev/null +++ b/kernel/postrm.d/initramfs-tools @@ -0,0 +1,36 @@ +#!/bin/sh -e + +version="$1" +bootopt="" + +[ -x /usr/sbin/update-initramfs ] || exit 0 + +# passing the kernel version is required +if [ -z "${version}" ]; then + echo >&2 "W: initramfs-tools: ${DPKG_MAINTSCRIPT_PACKAGE:-kernel package} did not pass a version number" + exit 0 +fi + +# exit if custom kernel does not need an initramfs +if [ "$INITRD" = 'No' ]; then + exit 0 +fi + +# absolute file name of kernel image may be passed as a second argument; +# create the initrd in the same directory +if [ -n "$2" ]; then + bootdir=$(dirname "$2") + bootopt="-b ${bootdir}" +fi + +# avoid running multiple times +if [ -n "$DEB_MAINT_PARAMS" ]; then + eval set -- "$DEB_MAINT_PARAMS" + if [ -z "$1" ] || [ "$1" != "remove" ]; then + exit 0 + fi +fi + +# delete initramfs +# shellcheck disable=SC2086 +update-initramfs -d -k "${version}" ${bootopt} >&2 diff --git a/lsinitramfs b/lsinitramfs new file mode 100755 index 0000000..8d2a967 --- /dev/null +++ b/lsinitramfs @@ -0,0 +1,58 @@ +#!/bin/sh + +set -eu + +usage() +{ + cat << EOF + +Usage: lsinitramfs [-l] initramfs-file... + +Options: + -l Display long and more verbose listing of initramfs content + +See lsinitramfs(8) for further details. + +EOF +} + +usage_error() +{ + usage >&2 + exit 2 +} + +umi_opts="--list" + +OPTIONS=$(getopt -o hl --long help,long -n "$0" -- "$@") || usage_error + +eval set -- "$OPTIONS" + +while true; do + case "$1" in + -h|--help) + usage + exit 0 + ;; + -l|--long) + umi_opts="${umi_opts:+${umi_opts} --verbose}" + shift + ;; + --) + shift + break + ;; + *) + echo "Internal error!" >&2 + exit 1 + esac +done + +if [ "$#" -eq 0 ] ; then + usage_error +fi + +for initramfs in "$@" ; do + # shellcheck disable=SC2086 + unmkinitramfs $umi_opts -- "$initramfs" +done diff --git a/lsinitramfs.8 b/lsinitramfs.8 new file mode 100644 index 0000000..c571552 --- /dev/null +++ b/lsinitramfs.8 @@ -0,0 +1,56 @@ +.TH LSINITRAMFS 8 "2015/12/09" "initramfs\-tools" "System Administration" + +.SH NAME +lsinitramfs \- list content of an initramfs image + +.SH SYNOPSIS +.B lsinitramfs +.RB [ -l ] +.IR initramfs-file ... +.br +.BR lsinitramfs " " -h + +.SH DESCRIPTION +The +.B lsinitramfs +command lists the content of given initramfs images. It allows one to quickly check +the content of one (or multiple) specified initramfs files. + +.SH OPTIONS + +.TP +.B -h +Display usage information and exit. + +.TP +.B -l +Display long and more verbose listing of initramfs content. + +.SH USAGE EXAMPLES + +List initramfs content of current running kernel: + +.PP +.B lsinitramfs /boot/initrd.img-$(uname -r) + +List content of two initramfs files in verbose mode: + +.PP +.B lsinitramfs -l /boot/vmlinuz-2.6.31-grml64 /boot/vmlinuz-2.6.33-grml64 + +.SH BUGS +.BR lsinitramfs +cannot deal with multiple-segmented initramfs images, except where an +early (uncompressed) initramfs with system firmware is prepended to +the regular compressed initramfs. + +.SH AUTHOR +The initramfs-tools are written by Maximilian Attems <maks@debian.org> +and numerous others. + +.SH SEE ALSO +.BR +.IR initramfs-tools (7), +.IR mkinitramfs (8), +.IR unmkinitramfs (8), +.IR update-initramfs (8). diff --git a/mkinitramfs b/mkinitramfs new file mode 100755 index 0000000..40e0fd1 --- /dev/null +++ b/mkinitramfs @@ -0,0 +1,523 @@ +#!/bin/sh + +umask 0022 +export PATH='/usr/bin:/sbin:/bin' + +# Defaults +keep="n" +CONFDIR="/etc/initramfs-tools" +verbose="n" +# Will be updated by busybox's conf hook, if present +BUSYBOXDIR= +export BUSYBOXDIR + +usage() +{ + cat << EOF + +Usage: mkinitramfs [option]... -o outfile [version] + +Options: + -c compress Override COMPRESS setting in initramfs.conf. + -d confdir Specify an alternative configuration directory. + -l level Override COMPRESSLEVEL setting in initramfs.conf. + -k Keep temporary directory used to make the image. + -o outfile Write to outfile. + -r root Override ROOT setting in initramfs.conf. + +See mkinitramfs(8) for further details. + +EOF +} + +usage_error() +{ + usage >&2 + exit 2 +} + +OPTIONS=$(getopt -o c:d:hl:ko:r:v --long help -n "$0" -- "$@") || usage_error + +eval set -- "$OPTIONS" + +while true; do + case "$1" in + -c) + compress="$2" + shift 2 + ;; + -d) + CONFDIR="$2" + shift 2 + if [ ! -d "${CONFDIR}" ]; then + echo "${0}: ${CONFDIR}: Not a directory" >&2 + exit 1 + fi + ;; + -h|--help) + usage + exit 0 + ;; + -l) + compresslevel="$2" + shift 2 + ;; + -o) + outfile="$2" + shift 2 + ;; + -k) + keep="y" + shift + ;; + -r) + ROOT="$2" + shift 2 + ;; + -v) + verbose="y" + shift + ;; + --) + shift + break + ;; + *) + echo "Internal error!" >&2 + exit 1 + ;; + esac +done + +# For dependency ordered mkinitramfs hook scripts. +. /usr/share/initramfs-tools/scripts/functions +. /usr/share/initramfs-tools/hook-functions + +. "${CONFDIR}/initramfs.conf" + +EXTRA_CONF='' +maybe_add_conf() { + if [ -e "$1" ] && \ + basename "$1" \ + | grep '^[[:alnum:]][[:alnum:]\._-]*$' \ + | grep -qv '\.dpkg-.*$'; then + if [ -d "$1" ]; then + echo "W: $1 is a directory instead of file" >&2 + else + EXTRA_CONF="${EXTRA_CONF} $1" + . "$1" + fi + fi +} +for i in /usr/share/initramfs-tools/conf.d/*; do + # Configuration files in /etc mask those in /usr/share + if ! [ -e "${CONFDIR}"/conf.d/"$(basename "${i}")" ]; then + maybe_add_conf "${i}" + fi +done +for i in "${CONFDIR}"/conf.d/*; do + maybe_add_conf "${i}" +done + +# source package confs +for i in /usr/share/initramfs-tools/conf-hooks.d/*; do + if [ -d "${i}" ]; then + echo "W: ${i} is a directory instead of file." >&2 + elif [ -e "${i}" ]; then + . "${i}" + fi +done + +# Check busybox dependency +if [ "${BUSYBOX}" = "y" ] && [ -z "${BUSYBOXDIR}" ]; then + echo >&2 "E: @BUSYBOX_PACKAGES@ is required but not installed" + exit 1 +fi + +if [ -n "${UMASK:-}" ]; then + umask "${UMASK}" +fi + +if [ -z "${outfile}" ]; then + usage_error +fi + +touch "$outfile" +outfile="$(readlink -f "$outfile")" + +# And by "version" we really mean path to kernel modules +# This is braindead, and exists to preserve the interface with mkinitrd +if [ ${#} -ne 1 ]; then + version="$(uname -r)" +else + version="${1}" +fi + +case "${version}" in +/lib/modules/*/[!/]*) + ;; +/lib/modules/[!/]*) + version="${version#/lib/modules/}" + version="${version%%/*}" + ;; +esac + +case "${version}" in +*/*) + echo "$PROG: ${version} is not a valid kernel version" >&2 + exit 2 + ;; +esac + +if [ -z "${compress:-}" ]; then + compress=${COMPRESS?} +fi +unset COMPRESS + +if ! command -v "${compress}" >/dev/null 2>&1; then + echo "W: No ${compress} in ${PATH}, using gzip" >&2 + compress=gzip +fi + +# Support packages installing in /lib/ rather than /boot/ +kconfig="/lib/modules/${version}/config-${version}" +if [ ! -f "$kconfig" ]; then + kconfig="/boot/config-${version}" +fi + +# Check that kernel supports selected compressor, and fall back to gzip. +# Exit if even gzip is not supported. +case "${compress}" in +gzip) kconfig_sym=CONFIG_RD_GZIP ;; +bzip2) kconfig_sym=CONFIG_RD_BZIP2 ;; +lzma) kconfig_sym=CONFIG_RD_LZMA ;; +xz) kconfig_sym=CONFIG_RD_XZ ;; +lzop) kconfig_sym=CONFIG_RD_LZO ;; +lz4) kconfig_sym=CONFIG_RD_LZ4 ;; +zstd) kconfig_sym=CONFIG_RD_ZSTD ;; +esac +if [ -e "${kconfig}" ]; then + while ! grep -q "^$kconfig_sym=y" "${kconfig}"; do + if [ "${compress}" = gzip ]; then + echo "E: gzip compression ($kconfig_sym) not supported by kernel" >&2 + exit 1 + fi + echo "W: ${compress} compression ($kconfig_sym) not supported by kernel, using gzip" >&2 + compress=gzip + kconfig_sym=CONFIG_RD_GZIP + done +else + echo "W: Kernel configuration ${kconfig} is missing, ${compress} compression" \ + "support ($kconfig_sym) cannot be checked and is assumed to be available" >&2 +fi + +if [ -z "${compresslevel:-}" ]; then + compresslevel=${COMPRESSLEVEL:-} +fi +case "${compress}" in +lz4) compresslevel="-${compresslevel:-9}" ;; +zstd) compresslevel="-${compresslevel:-9}" ;; +#gzip|xz|bzip2|lzma|lzop included +*) + # We're not using a compression level by default + compresslevel="${compresslevel:+-${compresslevel}}" + ;; +esac +unset COMPRESSLEVEL + +case "${compress}" in +gzip) # If we're doing a reproducible build, use gzip -n + if [ -n "${SOURCE_DATE_EPOCH}" ]; then + compress="gzip -n" + # Otherwise, substitute pigz if it's available + elif command -v pigz >/dev/null; then + compress=pigz + fi + if [ -n "${compresslevel}" ]; then + compress="${compress} ${compresslevel}" + fi + ;; +lz4) compress="lz4 ${compresslevel} -l" ;; +zstd) compress="zstd -q ${compresslevel}" + # If we're not doing a reproducible build, enable multithreading + test -z "${SOURCE_DATE_EPOCH}" && compress="$compress -T0" + ;; +xz) compress="xz ${compresslevel} --check=crc32" + # If we're not doing a reproducible build, enable multithreading + test -z "${SOURCE_DATE_EPOCH}" && compress="$compress --threads=0" + ;; +bzip2|lzma|lzop) + compress="${compress} ${compresslevel}" + ;; +*) echo "W: Unknown compression command ${compress}" >&2 ;; +esac + +if [ -d "${outfile}" ]; then + echo "${outfile} is a directory" >&2 + exit 1 +fi + +MODULESDIR="/lib/modules/${version}" + +if [ ! -e "${MODULESDIR}" ]; then + echo "W: missing ${MODULESDIR}" >&2 + echo "W: Ensure all necessary drivers are built into the linux image!" >&2 +fi +if [ ! -e "${MODULESDIR}/modules.dep" ]; then + depmod "${version}" +fi + +# Prepare to clean up temporary files on exit +DESTDIR= +__TMPCPIOGZ= +__TMPMAINCPIO= +__TMPEARLYCPIO= +__MODULES_TO_ADD= +# shellcheck disable=SC2317 +clean_on_exit() { + if [ "${keep}" = "y" ]; then + echo "Working files in ${DESTDIR:-<not yet created>}," \ + "early initramfs in ${__TMPEARLYCPIO:-<not yet created>}," \ + "main initramfs in ${__TMPMAINCPIO:-<not yet created>} and" \ + "overlay in ${__TMPCPIOGZ:-<not yet created>}" + else + for path in "${DESTDIR}" "${__TMPCPIOGZ}" "${__TMPMAINCPIO}" "${__TMPEARLYCPIO}" "${__MODULES_TO_ADD}"; do + test -z "${path}" || rm -rf "${path}" + done + fi +} +trap clean_on_exit EXIT +trap "exit 1" INT TERM # makes the EXIT trap effective even when killed + +# Create temporary directory and files for initramfs contents +[ -n "${TMPDIR}" ] && [ ! -w "${TMPDIR}" ] && unset TMPDIR +DESTDIR="$(mktemp -d "${TMPDIR:-/var/tmp}/mkinitramfs_XXXXXX")" || exit 1 +chmod 755 "${DESTDIR}" +__TMPCPIOGZ="$(mktemp "${TMPDIR:-/var/tmp}/mkinitramfs-OL_XXXXXX")" || exit 1 +__TMPMAINCPIO="$(mktemp "${TMPDIR:-/var/tmp}/mkinitramfs-MAIN_XXXXXX")" || exit 1 +__TMPEARLYCPIO="$(mktemp "${TMPDIR:-/var/tmp}/mkinitramfs-FW_XXXXXX")" || exit 1 +__MODULES_TO_ADD="$(mktemp "${TMPDIR:-/var/tmp}/modules_XXXXXX")" || exit 1 + +DPKG_ARCH=$(dpkg --print-architecture) + +# Export environment for hook scripts. +# +export MODULESDIR +export version +export CONFDIR +export DESTDIR +export DPKG_ARCH +export verbose +export KEYMAP +export MODULES +export BUSYBOX +export RESUME +export FSTYPE + +# Private, used by 'catenate_cpiogz'. +export __TMPCPIOGZ + +# Private, used by 'prepend_earlyinitramfs'. +export __TMPEARLYCPIO + +# Private, used by 'manual_add_modules'. +export __MODULES_TO_ADD + +# Create usr-merged filesystem layout, to avoid duplicates if the host +# filesystem is usr-merged. +for d in /bin /lib* /sbin; do + mkdir -p "${DESTDIR}/usr${d}" + ln -s "usr${d}" "${DESTDIR}${d}" +done +for d in conf/conf.d etc run scripts ${MODULESDIR}; do + mkdir -p "${DESTDIR}/${d}" +done + +# Copy in modules.builtin, modules.builtin.modinfo and modules.order (not generated by depmod) +# and modules.builtin.bin (generated by depmod, but too late to avoid +# error messages as in #948257) +for x in modules.builtin modules.builtin.bin modules.builtin.modinfo modules.order; do + if [ -f "${MODULESDIR}/${x}" ]; then + cp -p "${MODULESDIR}/${x}" "${DESTDIR}${MODULESDIR}/${x}" + fi +done + +# MODULES=list case. Always honour. +for x in "${CONFDIR}/modules" /usr/share/initramfs-tools/modules.d/*; do + if [ -f "${x}" ]; then + add_modules_from_file "${x}" + fi +done + +# MODULES=most is default +case "${MODULES}" in +dep) + dep_add_modules + ;; +most) + auto_add_modules + ;; +netboot) + auto_add_modules base + auto_add_modules net + ;; +list) + # nothing to add + ;; +*) + echo "W: mkinitramfs: unsupported MODULES setting: ${MODULES}." >&2 + echo "W: mkinitramfs: Falling back to MODULES=most." >&2 + auto_add_modules + ;; +esac + +# Add firmware for built-in code +add_builtin_firmware + +# First file executed by linux +cp -p /usr/share/initramfs-tools/init "${DESTDIR}/init" + +# add existant boot scripts +for b in $(cd /usr/share/initramfs-tools/scripts/ && find . \ + -regextype posix-extended -regex '.*/[[:alnum:]\._-]+$' -type f); do + [ -d "${DESTDIR}/scripts/$(dirname "${b}")" ] \ + || mkdir -p "${DESTDIR}/scripts/$(dirname "${b}")" + cp -p "/usr/share/initramfs-tools/scripts/${b}" \ + "${DESTDIR}/scripts/$(dirname "${b}")/" +done +# Prune dot-files/directories and limit depth to exclude VCS files +for b in $(cd "${CONFDIR}/scripts" && find . -maxdepth 2 -name '.?*' -prune -o \ + -regextype posix-extended -regex '.*/[[:alnum:]\._-]+$' -type f -print); do + [ -d "${DESTDIR}/scripts/$(dirname "${b}")" ] \ + || mkdir -p "${DESTDIR}/scripts/$(dirname "${b}")" + cp -p "${CONFDIR}/scripts/${b}" "${DESTDIR}/scripts/$(dirname "${b}")/" +done + +echo "DPKG_ARCH=${DPKG_ARCH}" > "${DESTDIR}/conf/arch.conf" +cp -p "${CONFDIR}/initramfs.conf" "${DESTDIR}/conf" +for i in ${EXTRA_CONF}; do + copy_file config "${i}" /conf/conf.d +done + +# ROOT hardcoding +if [ -n "${ROOT:-}" ]; then + echo "ROOT=${ROOT}" > "${DESTDIR}/conf/conf.d/root" +fi + +if ! command -v ldd >/dev/null 2>&1 ; then + echo "E: no ldd around - install libc-bin" >&2 + exit 1 +fi + +# fstab and mtab +touch "${DESTDIR}/etc/fstab" +ln -s /proc/mounts "${DESTDIR}/etc/mtab" + +# module-init-tools +copy_exec /sbin/modprobe /sbin +copy_exec /sbin/rmmod /sbin +mkdir -p "${DESTDIR}/etc/modprobe.d" "${DESTDIR}/lib/modprobe.d" +for file in /etc/modprobe.d/*.conf /lib/modprobe.d/*.conf ; do + if test -e "$file" || test -L "$file" ; then + copy_file config "$file" + fi +done + +# Copy kernel modules here, because some hooks rely on them being copied +apply_add_modules +run_scripts /usr/share/initramfs-tools/hooks +run_scripts "${CONFDIR}"/hooks + +# cache boot run order +for b in $(cd "${DESTDIR}/scripts" && find . -mindepth 1 -type d); do + cache_run_scripts "${DESTDIR}" "/scripts/${b#./}" +done + +apply_add_modules +# Resolve hidden dependencies +hidden_dep_add_modules + +# decompress modules for boot speed, if possible +find "${DESTDIR}/${MODULESDIR}" -name '*.ko.*' | while read -r ko; do + case "$ko" in + *.xz) + if ! command -v xz >/dev/null 2>&1; then + break + fi + xz -d "${ko}" + ;; + *.zst) + if ! command -v zstd >/dev/null 2>&1; then + break + fi + zstd -q -d --rm "${ko}" + ;; + esac +done + +# generate module deps +depmod -a -b "${DESTDIR}" "${version}" +rm -f "${DESTDIR}/lib/modules/${version}"/modules.*map + +# make sure that library search path is up to date +cp -pPr /etc/ld.so.conf* "$DESTDIR"/etc/ +if ! ldconfig -r "$DESTDIR" ; then + [ "$(id -u)" != "0" ] \ + && echo "ldconfig might need uid=0 (root) for chroot()" >&2 +fi +# The auxiliary cache is not reproducible and is always invalid at boot +# (see #845034) +if [ -d "${DESTDIR}"/var/cache/ldconfig ]; then + rm -f "${DESTDIR}"/var/cache/ldconfig/aux-cache + rmdir --ignore-fail-on-non-empty "${DESTDIR}"/var/cache/ldconfig +fi + +# Apply DSDT to initramfs +if [ -e "${CONFDIR}/DSDT.aml" ]; then + copy_file DSDT "${CONFDIR}/DSDT.aml" +fi + +[ "${verbose}" = y ] && echo "Building cpio ${outfile} initramfs" + +# preserve permissions if root builds the image, see #633582 +[ "$(id -ru)" != 0 ] && cpio_owner_root="-R 0:0" + +# if SOURCE_DATE_EPOCH is set, try and create a reproducible image +if [ -n "${SOURCE_DATE_EPOCH}" ]; then + # ensure that no timestamps are newer than $SOURCE_DATE_EPOCH + find "${DESTDIR}" -newermt "@${SOURCE_DATE_EPOCH}" -print0 | \ + xargs -0r touch --no-dereference --date="@${SOURCE_DATE_EPOCH}" + + # --reproducible requires cpio >= 2.12 + cpio_reproducible="--reproducible" +fi + +# work around lack of "set -o pipefail" for pipes. +# Write exit code to FD 3 in case of a failure to pass it through the pipes. +{ + cd "${DESTDIR}" + { + find . || { echo "E: mkinitramfs failure find $?" >&2; echo 1 >&3; exit; } + } | { + LC_ALL=C sort || { echo "E: mkinitramfs failure sort $?" >&2; echo 1 >&3; exit; } + } | { + # shellcheck disable=SC2086 + cpio --quiet $cpio_owner_root $cpio_reproducible -o -H newc >"${__TMPMAINCPIO}" || + { echo "E: mkinitramfs failure cpio $?" >&2; echo 1 >&3; exit; } + } +} 3>&1 | { read -r exit_code; exit "${exit_code:-0}"; } || exit $? + +{ + if [ -s "${__TMPEARLYCPIO}" ]; then + cat "${__TMPEARLYCPIO}" || exit 1 + fi + + $compress -c "${__TMPMAINCPIO}" || + { echo "E: mkinitramfs failure $compress $?" >&2; exit 1; } + + if [ -s "${__TMPCPIOGZ}" ]; then + cat "${__TMPCPIOGZ}" || exit 1 + fi +} >"${outfile}" || exit 1 + +exit 0 diff --git a/mkinitramfs.8 b/mkinitramfs.8 new file mode 100644 index 0000000..9a3ddc1 --- /dev/null +++ b/mkinitramfs.8 @@ -0,0 +1,153 @@ +.TH MKINITRAMFS 8 "2018/07/18" "initramfs\-tools" "System Administration" + +.SH NAME +mkinitramfs \- low-level tool for generating an initramfs image + +.SH SYNOPSIS +.B mkinitramfs +.RI [ option ]... +.B \-o +.IR outfile +.RI [ version ] +.br +.BR mkinitramfs " " -h + +.SH DESCRIPTION +The +.B mkinitramfs +script generates an initramfs image. +The initramfs is a compressed cpio archive. The archive can be used on a +different box of the same arch with the corresponding Linux kernel. +.B mkinitramfs +is meant for advanced usage. On your local box +.B update-initramfs +calls +.B mkinitramfs +with the relevant parameters. +.B update-initramfs +keeps sha1sum of generated initramfs. It takes care to generate backups +and eventually runs the bootloader. + +At boot time, the kernel unpacks that archive into RAM disk, mounts and +uses it as initial root file system. All finding of the root device +happens in this early userspace. + +.SH OPTIONS +.TP +\fB\-c \fI compress +Override the +.B COMPRESS +setting in +.IR initramfs.conf . + +.TP +\fB\-d \fI confdir +Set an alternate configuration directory. + +.TP +\fB\-k +Keep the temporary directory used to make the image. + +.TP +\fB\-l \fI compresslevel +Override the +.B COMPRESSLEVEL +setting in +.IR initramfs.conf . + +.TP +\fB\-o \fI outfile +Write the image to +.IR outfile . + +.TP +\fB\-r \fI root +Override the +.B ROOT +setting in +.IR initramfs.conf . + +.TP +\fB\-v +Set the verbose mode output. + +.TP +\fIversion +Set the kernel version of the initramfs image +(defaults to the running kernel). + +.TP +\fB\-h\fR, \fB\-\-help\fR +Display usage information and exit. + +.SH ENVIRONMENT +.B mkinitramfs +honours the +.B TMPDIR +environment variable. If set, it uses subdirectories in the given +directory to create its temporary working directories. Else it uses +.I /var/tmp +as default value for that purpose. The given directory should be on a +filesystem which allows the execution of files stored there, i.e. +should not be mounted with the +.B noexec +mount option. + +If +.B SOURCE_DATE_EPOCH +is set, +.B mkinitramfs +attempts to generate a reproducible initramfs image. + +.SH FILES +.TP +.I /etc/initramfs-tools/initramfs.conf +The default configuration file for the script. See +.BR initramfs.conf (5) +for a description of the available configuration parameter. + +.TP +.I /etc/initramfs-tools/modules +Specified modules will be put in the generated image and loaded when the system boots. The format - one per line - is identical to that of +.I /etc/modules, +which is described in +.BR modules (5). + +.TP +.I /etc/initramfs-tools/conf.d +The conf.d directory allows one to hardcode bootargs at initramfs build time +via config snippets. This allows one to set ROOT or RESUME. +This is especially useful for bootloaders, which do not pass an root bootarg. + +.TP +.I /etc/initramfs-tools/DSDT.aml +If this file exists, it will be appended to the initramfs in a way that causes +it to be loaded by ACPI. + +.SH EXAMPLES + +Create an initramfs for current running kernel: + +.PP +.B mkinitramfs -o ~/tmp/initramfs-$(uname -r) + +Create an initramfs for specific kernel and keep builddirs: + +.PP +.B mkinitramfs -k -o ~/tmp/initramfs-2.6.21-686 2.6.21-686 + +Debug initramfs creation (check out written logfile) +.PP +.B sh -x mkinitramfs -o ~/tmp/initramfs-$(uname -r) 2> ~/tmp/log + +.SH AUTHOR +The initramfs-tools are written by Maximilian Attems <maks@debian.org>, +Jeff Bailey <jbailey@raspberryginger.com> and numerous others. + +.SH SEE ALSO +.BR +.IR initramfs.conf (5), +.IR initramfs-tools (7), +.IR update-initramfs (8), +.IR lsinitramfs (8), +.IR unmkinitramfs (8). diff --git a/scripts/functions b/scripts/functions new file mode 100644 index 0000000..60f9195 --- /dev/null +++ b/scripts/functions @@ -0,0 +1,688 @@ +# -*- 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() { + 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 (first try specific bootdevice, then any + # interface...). ipconfig should have quit after first response + local file + for file in "/run/net-${DEVICE-}.conf" /run/net-*.conf; do + if [ -e "$file" ]; then + . "$file" + break + fi + done + + netinfo_to_resolv_conf /etc/resolv.conf "/run/net-${DEVICE-}.conf" /run/net-*.conf + + # shellcheck disable=SC2169 + if test -n "${HOSTNAME-}"; then + # shellcheck disable=SC2169 + persist_hostname "${HOSTNAME}" "${DNSDOMAIN-}" + fi +} + +# Write resolv.conf from /run/net-<device> style files. +# $1=resolv.conf path (print to stdout if "-" is specified) +# remaining parameters: /run/net-<device> style files +netinfo_to_resolv_conf() +{ + local domain="" n="" nameservers="" resolv_conf="" search="" output="$1" CR=" +" + shift + + for net_file in "$@"; do + # Define sourced variables as local to avoid causing side effects. + # shellcheck disable=SC2034 + local DEVICE PROTO IPV4ADDR IPV4BROADCAST IPV4NETMASK IPV4ROUTE0SUBNET \ + IPV4ROUTE0GATEWAY IPV4ROUTE1SUBNET IPV4ROUTE1GATEWAY IPV4GATEWAY \ + IPV4DNS0 IPV4DNS1 HOSTNAME DNSDOMAIN NISDOMAIN ROOTSERVER ROOTPATH \ + filename UPTIME DHCPLEASETIME DOMAINSEARCH + [ -e "$net_file" ] || continue + . "$net_file" || { echo "Error: Failed to source $net_file" >&2; return 1; } + if test -n "${DNSDOMAIN}"; then + domain="${DNSDOMAIN}" + fi + for n in "${IPV4DNS0}" "${IPV4DNS1}"; do + if test -z "$n" -o "$n" = 0.0.0.0; then + continue + fi + # Remove duplicates + case " ${nameservers} " in + *\ $n\ *) + continue ;; + esac + nameservers="${nameservers} ${n}" + done + for n in ${DOMAINSEARCH}; do + [ -n "$n" ] || continue + # Remove duplicates + case " ${search} " in + *\ $n\ *) + continue ;; + esac + search="${search} ${n}" + done + done + + # Construct content for resolv.conf + if test -n "${domain}"; then + resolv_conf="${resolv_conf}domain ${domain}${CR}" + fi + for n in ${nameservers}; do + resolv_conf="${resolv_conf}nameserver $n${CR}" + done + if test -n "${search}"; then + resolv_conf="${resolv_conf}search ${search# }${CR}" + fi + + if test -z "$resolv_conf"; then + echo "no search or nameservers found in $*" 1>&2 + return + fi + if test "$output" = "-"; then + printf "%s" "$resolv_conf" + else + printf "%s" "$resolv_conf" > "$output" + fi +} + +_generate_hosts_content() +{ + local hostname="$1" + local domain="$2" + local fqdn + + if test -n "${domain}"; then + fqdn="${hostname}.${domain} " + else + fqdn="" + fi + cat <<EOF +127.0.0.1 localhost +127.0.1.1 ${fqdn}${hostname} + +# The following lines are desirable for IPv6 capable hosts +::1 localhost ip6-localhost ip6-loopback +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters +EOF +} + +# Write hostname into /etc/hostname and /etc/hosts +# $1=hostname +# $2=domain (optional) +persist_hostname() +{ + local hostname="$1" + local domain="${2-}" + + echo "$hostname" > /etc/hostname + echo "$hostname" > /proc/sys/kernel/hostname + _generate_hosts_content "$hostname" "$domain" > /etc/hosts +} + +# 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() +{ + : +} diff --git a/scripts/init-top/all_generic_ide b/scripts/init-top/all_generic_ide new file mode 100755 index 0000000..cdf69cc --- /dev/null +++ b/scripts/init-top/all_generic_ide @@ -0,0 +1,28 @@ +#!/bin/sh + +PREREQ="" +prereqs() +{ + echo "$PREREQ" +} +case $1 in +# get pre-requisites +prereqs) + prereqs + exit 0 + ;; +esac + +# shellcheck disable=SC2013 +for x in $(cat /proc/cmdline); do + case ${x} in + all_generic_ide) + /sbin/modprobe ata_generic all_generic_ide=1 + ;; + all_generic_ide=*) + if [ -n "${x#all_generic_ide=}" ]; then + /sbin/modprobe ata_generic all_generic_ide=1 + fi + ;; + esac +done diff --git a/scripts/init-top/blacklist b/scripts/init-top/blacklist new file mode 100755 index 0000000..d860603 --- /dev/null +++ b/scripts/init-top/blacklist @@ -0,0 +1,25 @@ +#!/bin/sh + +PREREQ="" + +prereqs() +{ + echo "$PREREQ" +} + +case $1 in +# get pre-requisites +prereqs) + prereqs + exit 0 + ;; +esac + +# sanity check +[ -z "${blacklist?}" ] && exit 0 + +# write blacklist to modprobe.d +IFS=',' +for b in ${blacklist}; do + echo "blacklist $b" >> /etc/modprobe.d/initramfs.conf +done diff --git a/scripts/init-top/keymap b/scripts/init-top/keymap new file mode 100755 index 0000000..1c6b2dc --- /dev/null +++ b/scripts/init-top/keymap @@ -0,0 +1,18 @@ +#!/bin/sh + +PREREQ="" +prereqs() +{ + echo "$PREREQ" +} +case $1 in +# get pre-requisites +prereqs) + prereqs + exit 0 + ;; +esac + +if [ -x /bin/setupcon ]; then + /bin/setupcon +fi diff --git a/scripts/local b/scripts/local new file mode 100644 index 0000000..8f9597f --- /dev/null +++ b/scripts/local @@ -0,0 +1,223 @@ +# Local filesystem mounting -*- shell-script -*- + +local_top() +{ + if [ "${local_top_used}" != "yes" ]; then + [ "${quiet?}" != "y" ] && log_begin_msg "Running /scripts/local-top" + run_scripts /scripts/local-top + [ "$quiet" != "y" ] && log_end_msg + fi + local_top_used=yes +} + +local_block() +{ + [ "${quiet?}" != "y" ] && log_begin_msg "Running /scripts/local-block" + run_scripts /scripts/local-block "$@" + [ "$quiet" != "y" ] && log_end_msg +} + +local_premount() +{ + if [ "${local_premount_used}" != "yes" ]; then + [ "${quiet?}" != "y" ] && log_begin_msg "Running /scripts/local-premount" + run_scripts /scripts/local-premount + [ "$quiet" != "y" ] && log_end_msg + fi + local_premount_used=yes +} + +local_bottom() +{ + if [ "${local_premount_used}" = "yes" ] || [ "${local_top_used}" = "yes" ]; then + [ "${quiet?}" != "y" ] && log_begin_msg "Running /scripts/local-bottom" + run_scripts /scripts/local-bottom + [ "$quiet" != "y" ] && log_end_msg + fi + local_premount_used=no + local_top_used=no +} + +# $1=device ID to mount +# $2=optionname (for root and etc) +# $3=panic if device is missing (true or false, default: true) +# Sets $DEV to the resolved device node +local_device_setup() +{ + local dev_id="$1" + local name="$2" + local may_panic="${3:-true}" + local real_dev + local time_elapsed + local count + + wait_for_udev 10 + + # Load ubi with the correct MTD partition and return since fstype + # doesn't work with a char device like ubi. + if [ -n "$UBIMTD" ]; then + /sbin/modprobe ubi "mtd=$UBIMTD" + DEV="${dev_id}" + return + fi + + # Don't wait for a device that doesn't have a corresponding + # device in /dev and isn't resolvable by blkid (e.g. mtd0) + if [ "${dev_id#/dev}" = "${dev_id}" ] && + [ "${dev_id#*=}" = "${dev_id}" ]; then + DEV="${dev_id}" + return + fi + + # If the root device hasn't shown up yet, give it a little while + # to allow for asynchronous device discovery (e.g. USB). We + # also need to keep invoking the local-block scripts in case + # there are devices stacked on top of those. + if ! real_dev=$(resolve_device "${dev_id}") || + ! get_fstype "${real_dev}" >/dev/null; then + log_begin_msg "Waiting for ${name}" + + # Timeout is max(30, rootdelay) seconds (approximately) + slumber=30 + if [ "${ROOTDELAY:-0}" -gt $slumber ]; then + slumber=$ROOTDELAY + fi + + while true; do + sleep 1 + time_elapsed="$(time_elapsed)" + + local_block "${dev_id}" + + # If mdadm's local-block script counts the + # number of times it is run, make sure to + # run it the expected number of times. + while true; do + if [ -f /run/count.mdadm.initrd ]; then + count="$(cat /run/count.mdadm.initrd)" + elif [ -n "${count}" ]; then + # mdadm script deleted it; put it back + count=$((count + 1)) + echo "${count}" >/run/count.mdadm.initrd + else + break + fi + if [ "${count}" -ge "${time_elapsed}" ]; then + break; + fi + /scripts/local-block/mdadm "${dev_id}" + done + + if real_dev=$(resolve_device "${dev_id}") && + get_fstype "${real_dev}" >/dev/null; then + wait_for_udev 10 + log_end_msg 0 + break + fi + if [ "${time_elapsed}" -ge "${slumber}" ]; then + log_end_msg 1 || true + break + fi + done + fi + + # We've given up, but we'll let the user fix matters if they can + while ! real_dev=$(resolve_device "${dev_id}") || + ! get_fstype "${real_dev}" >/dev/null; do + if ! $may_panic; then + echo "Gave up waiting for ${name}" + return 1 + fi + echo "Gave up waiting for ${name} device. Common problems:" + echo " - Boot args (cat /proc/cmdline)" + echo " - Check rootdelay= (did the system wait long enough?)" + if [ "${name}" = root ]; then + echo " - Check root= (did the system wait for the right device?)" + fi + echo " - Missing modules (cat /proc/modules; ls /dev)" + panic "ALERT! ${dev_id} does not exist. Dropping to a shell!" + done + + DEV="${real_dev}" +} + +local_mount_root() +{ + local_top + if [ -z "${ROOT}" ]; then + panic "No root device specified. Boot arguments must include a root= parameter." + fi + local_device_setup "${ROOT}" "root file system" + ROOT="${DEV}" + + # Get the root filesystem type if not set + if [ -z "${ROOTFSTYPE}" ] || [ "${ROOTFSTYPE}" = auto ]; then + FSTYPE=$(get_fstype "${ROOT}") + else + FSTYPE=${ROOTFSTYPE} + fi + + local_premount + + if [ "${readonly?}" = "y" ]; then + roflag=-r + else + roflag=-w + fi + + checkfs "${ROOT}" root "${FSTYPE}" + + # Mount root + # shellcheck disable=SC2086 + if ! mount ${roflag} ${FSTYPE:+-t "${FSTYPE}"} ${ROOTFLAGS} "${ROOT}" "${rootmnt?}"; then + panic "Failed to mount ${ROOT} as root file system." + fi +} + +local_mount_fs() +{ + read_fstab_entry "$1" + + local_device_setup "$MNT_FSNAME" "$1 file system" + MNT_FSNAME="${DEV}" + + local_premount + + if [ "${readonly}" = "y" ]; then + roflag=-r + else + roflag=-w + fi + + if [ "$MNT_PASS" != 0 ]; then + checkfs "$MNT_FSNAME" "$MNT_DIR" "${MNT_TYPE}" + fi + + # Mount filesystem + if ! mount ${roflag} -t "${MNT_TYPE}" -o "${MNT_OPTS}" "$MNT_FSNAME" "${rootmnt}${MNT_DIR}"; then + panic "Failed to mount ${MNT_FSNAME} as $MNT_DIR file system." + fi +} + +mountroot() +{ + local_mount_root +} + +mount_top() +{ + # Note, also called directly in case it's overridden. + local_top +} + +mount_premount() +{ + # Note, also called directly in case it's overridden. + local_premount +} + +mount_bottom() +{ + # Note, also called directly in case it's overridden. + local_bottom +} diff --git a/scripts/local-premount/resume b/scripts/local-premount/resume new file mode 100755 index 0000000..63dcc49 --- /dev/null +++ b/scripts/local-premount/resume @@ -0,0 +1,46 @@ +#!/bin/sh + +PREREQ="" + +prereqs() +{ + echo "$PREREQ" +} + +case $1 in +# get pre-requisites +prereqs) + prereqs + exit 0 + ;; +esac + +if [ -z "${resume?}" ] || [ ! -e /sys/power/resume ]; then + exit 0 +fi + +. /scripts/functions +. /scripts/local + +if ! local_device_setup "${resume}" "suspend/resume device" false; then + exit 0 +fi + +if [ "$(get_fstype "${DEV}")" = suspend ] && + command -v plymouth >/dev/null && + plymouth --ping; then + plymouth display-message --text="Resuming from hibernation" + + # The above command does not wait for a framebuffer update to + # complete, so the kernel can freeze the framebuffer before + # the message is even visible. Wait just a moment to make + # that less likely. + sleep 0.1 +fi + +# hardcode path, uswsusp ships an resume binary too +if [ -n "${resume_offset?}" ]; then + /bin/resume "${DEV}" "${resume_offset}" +else + /bin/resume "${DEV}" +fi diff --git a/scripts/nfs b/scripts/nfs new file mode 100644 index 0000000..26a969b --- /dev/null +++ b/scripts/nfs @@ -0,0 +1,166 @@ +# NFS filesystem mounting -*- shell-script -*- + +# FIXME This needs error checking + +nfs_top() +{ + if [ "${nfs_top_used}" != "yes" ]; then + [ "${quiet?}" != "y" ] && log_begin_msg "Running /scripts/nfs-top" + run_scripts /scripts/nfs-top + [ "$quiet" != "y" ] && log_end_msg + fi + nfs_top_used=yes +} + +nfs_premount() +{ + if [ "${nfs_premount_used}" != "yes" ]; then + [ "${quiet?}" != "y" ] && log_begin_msg "Running /scripts/nfs-premount" + run_scripts /scripts/nfs-premount + [ "$quiet" != "y" ] && log_end_msg + fi + nfs_premount_used=yes +} + +nfs_bottom() +{ + if [ "${nfs_premount_used}" = "yes" ] || [ "${nfs_top_used}" = "yes" ]; then + [ "${quiet?}" != "y" ] && log_begin_msg "Running /scripts/nfs-bottom" + run_scripts /scripts/nfs-bottom + [ "$quiet" != "y" ] && log_end_msg + fi + nfs_premount_used=no + nfs_top_used=no +} + +# parse nfs bootargs and mount nfs +nfs_mount_root_impl() +{ + configure_networking + + # get nfs root from dhcp + if [ "${NFSROOT}" = "auto" ]; then + # check if server ip is part of dhcp root-path + if [ "${ROOTPATH#*:}" = "${ROOTPATH}" ]; then + NFSROOT=${ROOTSERVER}:${ROOTPATH} + else + NFSROOT=${ROOTPATH} + fi + + # nfsroot=[<server-ip>:]<root-dir>[,<nfs-options>] + elif [ -n "${NFSROOT}" ]; then + # nfs options are an optional arg + if [ "${NFSROOT#*,}" != "${NFSROOT}" ]; then + NFSOPTS="-o ${NFSROOT#*,}" + fi + NFSROOT=${NFSROOT%%,*} + if [ "${NFSROOT#*:}" = "$NFSROOT" ]; then + NFSROOT=${ROOTSERVER}:${NFSROOT} + fi + fi + + if [ -z "${NFSOPTS}" ]; then + NFSOPTS="-o retrans=10" + fi + + nfs_premount + + if [ "${readonly?}" = y ]; then + roflag="-o ro" + else + roflag="-o rw" + fi + + # shellcheck disable=SC2086 + nfsmount -o nolock ${roflag} ${NFSOPTS} "${NFSROOT}" "${rootmnt?}" +} + +# NFS root mounting +nfs_mount_root() +{ + nfs_top + + # For DHCP + /sbin/modprobe af_packet + + wait_for_udev 10 + + # Default delay is around 180s + delay=${ROOTDELAY:-180} + + # loop until nfsmount succeeds + nfs_mount_root_impl + ret=$? + nfs_retry_count=0 + while [ ${nfs_retry_count} -lt "${delay}" ] \ + && [ $ret -ne 0 ] ; do + [ "$quiet" != "y" ] && log_begin_msg "Retrying nfs mount" + sleep 1 + nfs_mount_root_impl + ret=$? + nfs_retry_count=$(( nfs_retry_count + 1 )) + [ "$quiet" != "y" ] && log_end_msg + done +} + +nfs_mount_fs_impl() +{ + configure_networking + + if [ -z "${NFSOPTS}" ]; then + NFSOPTS="-o retrans=10" + fi + + nfs_premount + + if [ "${readonly}" = y ]; then + roflag="-o ro" + else + roflag="-o rw" + fi + + read_fstab_entry "$1" + + # shellcheck disable=SC2086 + nfsmount ${roflag} ${NFSOPTS} -o "${MNT_OPTS}" "$MNT_FSNAME" "${rootmnt}${MNT_DIR}" +} + +nfs_mount_fs() +{ + nfs_top + + # For DHCP + /sbin/modprobe af_packet + + wait_for_udev 10 + + # Default delay is around 180s + delay=${ROOTDELAY:-180} + + # Don't loop here; we can't sanely check if it worked like for + # the rootfs or /etc. + nfs_mount_fs_impl "$1" +} + +mountroot() +{ + nfs_mount_root +} + +mount_top() +{ + # Note, also called directly in case it's overridden. + nfs_top +} + +mount_premount() +{ + # Note, also called directly in case it's overridden. + nfs_premount +} + +mount_bottom() +{ + # Note, also called directly in case it's overridden. + nfs_bottom +} diff --git a/tests/functions_test b/tests/functions_test new file mode 100755 index 0000000..c5db566 --- /dev/null +++ b/tests/functions_test @@ -0,0 +1,54 @@ +#!/bin/sh +set -u + +# Unit tests for scripts/functions + +TEST_DIR="${0%/*}" +ROOT_DIR="$TEST_DIR/.." +CR=" +" + +oneTimeSetUp() { + . "$ROOT_DIR/scripts/functions" +} + +HOSTS_FOOTER=" +# The following lines are desirable for IPv6 capable hosts +::1 localhost ip6-localhost ip6-loopback +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters" + +test_generate_hosts_content_with_domain() { + hosts_content=$(_generate_hosts_content example com) + assertEquals "127.0.0.1 localhost${CR}127.0.1.1 example.com example${CR}${HOSTS_FOOTER}" "$hosts_content" +} + +test_generate_hosts_content_without_domain() { + hosts_content=$(_generate_hosts_content example "") + assertEquals "127.0.0.1 localhost${CR}127.0.1.1 example${CR}${HOSTS_FOOTER}" "$hosts_content" +} + +test_netinfo_to_resolv_conf_IPv4() { + resolv_conf=$(netinfo_to_resolv_conf - "$TEST_DIR/netinfo/net-eth0.conf") + assertEquals "domain example.net${CR}nameserver 192.0.2.42${CR}search example.net. example.com." "$resolv_conf" +} + +test_netinfo_to_resolv_conf_duplicates() { + resolv_conf=$(netinfo_to_resolv_conf - "$TEST_DIR/netinfo/net-eth0.conf" "$TEST_DIR/netinfo/net-eth0.conf") + assertEquals "domain example.net${CR}nameserver 192.0.2.42${CR}search example.net. example.com." "$resolv_conf" +} + +test_netinfo_to_resolv_conf_mutliple() { + resolv_conf=$(netinfo_to_resolv_conf - "$TEST_DIR/netinfo/net-eth0.conf" "$TEST_DIR/netinfo/net-eth1.conf") + assertEquals "domain example.org${CR}nameserver 192.0.2.42${CR}nameserver 192.0.2.84${CR}search example.net. example.com. example.org." "$resolv_conf" +} + +test_netinfo_to_resolv_conf_write_output() { + tmpfile=$(mktemp -t initramfs-tools.XXXXXXXXXX) + netinfo_to_resolv_conf "$tmpfile" "$TEST_DIR/netinfo/net-eth0.conf" + assertEquals "domain example.net${CR}nameserver 192.0.2.42${CR}search example.net. example.com." "$(cat "$tmpfile")" + rm -f "$tmpfile" +} + +# Load shUnit2. +. shunit2 diff --git a/tests/netinfo/net-eth0.conf b/tests/netinfo/net-eth0.conf new file mode 100644 index 0000000..3c79b6d --- /dev/null +++ b/tests/netinfo/net-eth0.conf @@ -0,0 +1,17 @@ +DEVICE='eth0' +PROTO='dhcp' +IPV4ADDR='192.0.2.101' +IPV4BROADCAST='192.0.2.255' +IPV4NETMASK='255.255.255.0' +IPV4GATEWAY='192.0.2.1' +IPV4DNS0='192.0.2.42' +IPV4DNS1='0.0.0.0' +HOSTNAME='example-host' +DNSDOMAIN='example.net' +NISDOMAIN='' +ROOTSERVER='192.0.2.1' +ROOTPATH='' +filename='' +UPTIME='4' +DHCPLEASETIME='86400' +DOMAINSEARCH='example.net. example.com.' diff --git a/tests/netinfo/net-eth1.conf b/tests/netinfo/net-eth1.conf new file mode 100644 index 0000000..fb3fb27 --- /dev/null +++ b/tests/netinfo/net-eth1.conf @@ -0,0 +1,17 @@ +DEVICE='eth1' +PROTO='dhcp' +IPV4ADDR='192.0.2.150' +IPV4BROADCAST='192.0.2.255' +IPV4NETMASK='255.255.255.0' +IPV4GATEWAY='192.0.2.254' +IPV4DNS0='192.0.2.84' +IPV4DNS1='0.0.0.0' +HOSTNAME='example-host' +DNSDOMAIN='example.org' +NISDOMAIN='' +ROOTSERVER='192.0.2.254' +ROOTPATH='' +filename='' +UPTIME='4' +DHCPLEASETIME='86400' +DOMAINSEARCH='example.org.' diff --git a/unmkinitramfs b/unmkinitramfs new file mode 100755 index 0000000..a296029 --- /dev/null +++ b/unmkinitramfs @@ -0,0 +1,174 @@ +#!/bin/sh + +set -eu + +usage() +{ + cat << EOF + +Usage: unmkinitramfs [-v] initramfs-file directory + +Options: + -v Display verbose messages about extraction + +See unmkinitramfs(8) for further details. + +EOF +} + +usage_error() +{ + usage >&2 + exit 2 +} + +# Extract a compressed cpio archive +xcpio() +{ + archive="$1" + dir="$2" + shift 2 + + if gzip -t "$archive" >/dev/null 2>&1 ; then + gzip -c -d "$archive" + elif zstd -q -c -t "$archive" >/dev/null 2>&1 ; then + zstd -q -c -d "$archive" + elif xzcat -t "$archive" >/dev/null 2>&1 ; then + xzcat "$archive" + elif lz4cat -t < "$archive" >/dev/null 2>&1 ; then + lz4cat "$archive" + elif bzip2 -t "$archive" >/dev/null 2>&1 ; then + bzip2 -c -d "$archive" + elif lzop -t "$archive" >/dev/null 2>&1 ; then + lzop -c -d "$archive" + # Ignoring other data, which may be garbage at the end of the file + fi | ( + if [ -n "$dir" ]; then + mkdir -p -- "$dir" + cd -- "$dir" + fi + cpio "$@" + ) +} + +# Read bytes out of a file, checking that they are valid hex digits +readhex() +{ + dd < "$1" bs=1 skip="$2" count="$3" 2> /dev/null | \ + LANG=C grep -E "^[0-9A-Fa-f]{$3}\$" +} + +# Check for a zero byte in a file +checkzero() +{ + dd < "$1" bs=1 skip="$2" count=1 2> /dev/null | \ + LANG=C grep -q -z '^$' +} + +# Split an initramfs into archives and call xcpio on each +splitinitramfs() +{ + initramfs="$1" + dir="$2" + shift 2 + + count=0 + start=0 + while true; do + # There may be prepended uncompressed archives. cpio + # won't tell us the true size of these so we have to + # parse the headers and padding ourselves. This is + # very roughly based on linux/lib/earlycpio.c + end=$start + while true; do + if checkzero "$initramfs" $end; then + # This is the EOF marker. There might + # be more zero padding before the next + # archive, so read through all of it. + end=$((end + 4)) + while checkzero "$initramfs" $end; do + end=$((end + 4)) + done + break + fi + magic="$(readhex "$initramfs" $end 6)" || break + test "$magic" = 070701 || test "$magic" = 070702 || break + namesize=0x$(readhex "$initramfs" $((end + 94)) 8) + filesize=0x$(readhex "$initramfs" $((end + 54)) 8) + end=$((end + 110)) + end=$(((end + namesize + 3) & ~3)) + end=$(((end + filesize + 3) & ~3)) + done + if [ $end -eq $start ]; then + break + fi + + # Extract to early, early2, ... subdirectories + count=$((count + 1)) + if [ $count -eq 1 ]; then + subdir=early + else + subdir=early$count + fi + dd < "$initramfs" skip=$start count=$((end - start)) iflag=skip_bytes,count_bytes 2> /dev/null | + ( + if [ -n "$dir" ]; then + mkdir -p -- "$dir/$subdir" + cd -- "$dir/$subdir" + fi + cpio -i "$@" + ) + start=$end + done + + if [ "$end" -gt 0 ]; then + # Extract to main subdirectory + subarchive=$(mktemp "${TMPDIR:-/var/tmp}/unmkinitramfs_XXXXXX") + trap 'rm -f "$subarchive"' EXIT + dd < "$initramfs" skip="$end" iflag=skip_bytes 2> /dev/null \ + > "$subarchive" + xcpio "$subarchive" "${dir:+$dir/main}" -i "$@" + else + # Don't use subdirectories (for backward compatibility) + xcpio "$initramfs" "$dir" -i "$@" + fi +} + +OPTIONS=$(getopt -o hv --long help,list,verbose -n "$0" -- "$@") || usage_error + +cpio_opts="--preserve-modification-time --no-absolute-filenames --quiet" +expected_args=2 +eval set -- "$OPTIONS" + +while true; do + case "$1" in + -h|--help) + usage + exit 0 + ;; + --list) + # For lsinitramfs + cpio_opts="${cpio_opts:+${cpio_opts} --list}" + expected_args=1 + shift + ;; + -v|--verbose) + cpio_opts="${cpio_opts:+${cpio_opts} --verbose}" + shift + ;; + --) + shift + break + ;; + *) + echo "Internal error!" >&2 + exit 1 + esac +done + +if [ $# -ne $expected_args ]; then + usage_error +fi + +# shellcheck disable=SC2086 +splitinitramfs "$1" "${2:-}" $cpio_opts diff --git a/unmkinitramfs.8 b/unmkinitramfs.8 new file mode 100644 index 0000000..ae9252d --- /dev/null +++ b/unmkinitramfs.8 @@ -0,0 +1,56 @@ +.TH UNMKINITRAMFS 8 "2016/12/15" "initramfs\-tools" "System Administration" + +.SH NAME +unmkinitramfs \- extract content from an initramfs image + +.SH SYNOPSIS +.B unmkinitramfs +.RB [ -v ] +.IR initramfs-file " " directory +.br +.BR unmkinitramfs " " -h + +.SH DESCRIPTION +The +.B unmkinitramfs +command extracts the content of a given initramfs image using +.BR cpio . +If the image contains multiple segments, each are passed to +.B cpio +in order. + +.SH OPTIONS + +.TP +.B -h +Display usage information and exit. + +.TP +.B -v +Display verbose messages about extraction. + + +.SH USAGE EXAMPLES + +Extract initramfs content of current running kernel: + +.PP +.B unmkinitramfs /boot/initrd.img-$(uname -r) initramfs/ + + +.SH BUGS +.BR unmkinitramfs +cannot deal with multiple-segmented initramfs images, except where an +early (uncompressed) initramfs with system firmware is prepended to +the regular compressed initramfs. + +.SH AUTHOR +The initramfs-tools are written by Maximilian Attems <maks@debian.org> +and numerous others. + +.SH SEE ALSO +.BR +.IR initramfs-tools (7), +.IR lsinitramfs (8), +.IR mkinitramfs (8), +.IR update-initramfs (8). diff --git a/update-initramfs b/update-initramfs new file mode 100755 index 0000000..4bb8d8a --- /dev/null +++ b/update-initramfs @@ -0,0 +1,398 @@ +#!/bin/sh + +BOOTDIR=/boot +CONF=/etc/initramfs-tools/update-initramfs.conf +mode="" +version="" +update_initramfs=yes +backup_initramfs=no + +set -e + +[ -r ${CONF} ] && . ${CONF} + +if [ -n "$DPKG_MAINTSCRIPT_PACKAGE" ] && [ $# = 1 ] && [ "$1" = -u ]; then + if dpkg-trigger --no-await update-initramfs; then + echo "update-initramfs: deferring update (trigger activated)" + exit 0 + fi +fi + +usage() +{ + cat << EOF + +Usage: update-initramfs {-c|-d|-u} [-k version] [-v] [-b directory] + +Options: + -k version Specify kernel version or 'all' + -c Create a new initramfs + -u Update an existing initramfs + -d Remove an existing initramfs + -b directory Set alternate boot directory + -v Be verbose + +See update-initramfs(8) for further details. + +EOF +} + +usage_error() +{ + if [ -n "${1:-}" ]; then + printf "%s\\n\\n" "${*}" >&2 + fi + usage >&2 + exit 2 +} + +mild_panic() +{ + if [ -n "${1:-}" ]; then + printf "%s\\n" "${*}" >&2 + fi + exit 0 +} + +panic() +{ + if [ -n "${1:-}" ]; then + printf "%s\\n" "${*}" >&2 + fi + exit 1 +} + +verbose() +{ + if [ "${verbose}" = 1 ]; then + printf "%s\\n" "${*}" + fi +} + +set_initramfs() +{ + initramfs="${BOOTDIR}/initrd.img-${version}" +} + + +# backup initramfs while running +backup_initramfs() +{ + [ ! -r "${initramfs}" ] && return 0 + initramfs_bak="${initramfs}.dpkg-bak" + [ -r "${initramfs_bak}" ] && rm -f "${initramfs_bak}" + ln -f "${initramfs}" "${initramfs_bak}" 2>/dev/null \ + || cp -a "${initramfs}" "${initramfs_bak}" + verbose "Keeping ${initramfs_bak}" +} + +# keep booted initramfs +backup_booted_initramfs() +{ + initramfs_bak="${initramfs}.dpkg-bak" + + # first time run thus no backup + [ ! -r "${initramfs_bak}" ] && return 0 + + # chroot with no /proc + [ ! -r /proc/uptime ] && rm -f "${initramfs_bak}" && return 0 + + # no kept backup wanted + [ "${backup_initramfs}" = "no" ] && rm -f "${initramfs_bak}" && return 0 + + # no backup yet + if [ ! -r "${initramfs}.bak" ]; then + mv -f "${initramfs_bak}" "${initramfs}.bak" + verbose "Backup ${initramfs}.bak" + return 0 + fi + + # keep booted initramfs + boot_initramfs= + uptime_days=$(awk '{printf "%d", $1 / 3600 / 24}' /proc/uptime) + if [ -n "$uptime_days" ]; then + boot_initramfs=$(find "${initramfs}.bak" -mtime "+${uptime_days}") + fi + if [ -n "${boot_initramfs}" ]; then + mv -f "${initramfs_bak}" "${initramfs}.bak" + verbose "Backup ${initramfs}.bak" + return 0 + fi + verbose "Removing current backup ${initramfs_bak}" + rm -f "${initramfs_bak}" +} + +# nuke generated copy +remove_initramfs_bak() +{ + [ -z "${initramfs_bak:-}" ] && return 0 + rm -f "${initramfs_bak}" + verbose "Removing ${initramfs_bak}" +} + + +generate_initramfs() +{ + echo "update-initramfs: Generating ${initramfs}" + OPTS="-o" + if [ "${verbose}" = 1 ]; then + OPTS="-v ${OPTS}" + fi + # shellcheck disable=SC2086 + if mkinitramfs ${OPTS} "${initramfs}.new" "${version}"; then + mv -f "${initramfs}.new" "${initramfs}" + # Guard against an unclean shutdown + sync -f "${initramfs}" + else + mkinitramfs_return="$?" + remove_initramfs_bak + rm -f "${initramfs}.new" + echo "update-initramfs: failed for ${initramfs} with $mkinitramfs_return." >&2 + exit $mkinitramfs_return + fi +} + +# Invoke bootloader +run_bootloader() +{ + # invoke policy conformant bootloader hooks + if [ -d /etc/initramfs/post-update.d/ ]; then + run-parts --arg="${version}" --arg="${initramfs}" \ + /etc/initramfs/post-update.d/ + return 0 + fi +} + +# ro /boot is not modified +ro_boot_check() +{ + # check irrelevant inside of a chroot + if [ ! -r /proc/mounts ] || ischroot; then + return 0 + fi + + # shellcheck disable=SC1004 + boot_opts=$(awk '/boot/{if ((match($4, /^ro/) || match($4, /,ro/)) \ + && $2 == "/boot") print "ro"}' /proc/mounts) + if [ -n "${boot_opts}" ]; then + echo "W: /boot is ro mounted." >&2 + echo "W: update-initramfs: Not updating ${initramfs}" >&2 + exit 0 + fi +} + +get_sorted_versions() +{ + version_list="$( + linux-version list | + while read -r version; do + test -e "${BOOTDIR}/initrd.img-$version" && echo "$version" + done | + linux-version sort --reverse + )" + verbose "Available versions: ${version_list}" +} + +set_current_version() +{ + if [ -f "/boot/initrd.img-$(uname -r)" ]; then + version=$(uname -r) + fi +} + +set_linked_version() +{ + linktarget= + if [ -e /initrd.img ] && [ -L /initrd.img ]; then + linktarget="$(basename "$(readlink /initrd.img)")" + fi + + if [ -e /boot/initrd.img ] && [ -L /boot/initrd.img ]; then + linktarget="$(basename "$(readlink /boot/initrd.img)")" + fi + + if [ -z "${linktarget}" ]; then + return + fi + + version="${linktarget##initrd.img-}" +} + +set_highest_version() +{ + get_sorted_versions + if [ -z "${version_list}" ]; then + version= + return + fi + # shellcheck disable=SC2086 + set -- ${version_list} + version=${1} +} + +create() +{ + if [ -z "${version}" ]; then + usage_error "Create mode requires a version argument" + fi + + set_initramfs + + generate_initramfs + + run_bootloader +} + +update() +{ + if [ "${update_initramfs}" = "no" ]; then + echo "update-initramfs: Not updating initramfs." + exit 0 + fi + + if [ -z "${version}" ]; then + set_highest_version + fi + + if [ -z "${version}" ]; then + set_linked_version + fi + + if [ -z "${version}" ]; then + set_current_version + fi + + if [ -z "${version}" ]; then + verbose "Nothing to do, exiting." + exit 0 + fi + + set_initramfs + + ro_boot_check + + backup_initramfs + + generate_initramfs + + run_bootloader + + backup_booted_initramfs +} + +delete() +{ + if [ -z "${version}" ]; then + usage_error "Delete mode requires a version argument" + fi + + set_initramfs + + echo "update-initramfs: Deleting ${initramfs}" + + rm -f "${initramfs}" "${initramfs}.bak" +} + +# Defaults +verbose=0 + +## + +OPTIONS=$(getopt -o "k:cudvtb:h?" --long help -n "$0" -- "$@") || usage_error + +eval set -- "$OPTIONS" + +while true; do + case "$1" in + -k) + version="$2" + shift 2 + ;; + -c) + mode="c" + shift + ;; + -d) + mode="d" + shift + ;; + -u) + mode="u" + shift + ;; + -v) + verbose="1" + shift + ;; + -t) + # accepted for compatibility, but ignored + shift + ;; + -b) + BOOTDIR="$2" + if [ ! -d "${BOOTDIR}" ]; then + echo "E: ${BOOTDIR} is not a directory." >&2 + exit 1 + fi + shift 2 + ;; + -h|-\?|--help) + usage + exit 0 + ;; + --) + shift + break + ;; + esac +done + +if [ $# -ne 0 ]; then + printf "Extra argument '%s'\\n\\n" "$1" >&2 + usage_error +fi + +# Validate arguments +if [ -z "${mode}" ]; then + usage_error "You must specify at least one of -c, -u, or -d." +fi + +if [ "${version}" = "all" ] \ + || { [ "${update_initramfs}" = "all" ] && [ -z "${version}" ]; }; then + case "${mode}" in + c) + version_list="$(linux-version list)" + ;; + d | u) + get_sorted_versions + ;; + esac + if [ -z "${version_list}" ]; then + verbose "Nothing to do, exiting." + exit 0 + fi + + OPTS="-b ${BOOTDIR}" + if [ "${verbose}" = "1" ]; then + OPTS="${OPTS} -v" + fi + for u_version in ${version_list}; do + verbose "Execute: ${0} -${mode} -k \"${u_version}\" ${OPTS}" + # shellcheck disable=SC2086 + "${0}" -${mode} -k "${u_version}" ${OPTS} + done + exit 0 +fi + + +case "${mode}" in + c) + create + ;; + d) + delete + ;; + u) + update + ;; +esac diff --git a/update-initramfs.8 b/update-initramfs.8 new file mode 100644 index 0000000..b36fc57 --- /dev/null +++ b/update-initramfs.8 @@ -0,0 +1,95 @@ +.TH UPDATE-INITRAMFS 8 "2014/10/16" "initramfs\-tools" "System Administration" + +.SH NAME +update\-initramfs \- generate an initramfs image + +.SH SYNOPSIS +.B update\-initramfs +.RB { \-c | \-d | \-u } +.RB [ \-k +.IR version ] +.RB [ \-v ] +.RB [ \-b +.IR directory ] +.br +.BR update\-initramfs " " \-h +.SH DESCRIPTION +The +.B update\-initramfs +script manages your initramfs images on your local box. +It keeps track of the existing initramfs archives in /boot. +There are three modes of operation create, update or delete. +You must at least specify one of those modes. + +The initramfs is a gzipped cpio archive. +At boot time, the kernel unpacks that archive into RAM disk, mounts and +uses it as initial root file system. All finding of the root device +happens in this early userspace. + +.SH OPTIONS +.TP +\fB\-k \fI version +Set the specific kernel version for whom the initramfs will be generated. +For example the output of uname \-r for your currently running kernel. +This argument is optional for update. The default is the latest kernel version. + +The use of "all" for the +.I version +string specifies that +.B update\-initramfs +should operate on all installed kernel versions (with \fB\-c\fR), or +on all installed kernel versions that already have an initramfs +(with \fB\-d\fR or \fB\-u\fR). + +.TP +\fB\-c +This mode creates a new initramfs. + +.TP +\fB\-u +This mode updates an existing initramfs. + +.TP +\fB\-d +This mode deletes an existing initramfs. + +.TP +\fB\-v +This option increases the amount of information you are given during +the chosen action. + +.TP +\fB\-b \fI directory +Set an different bootdir for the image creation. + +.TP +\fB\-h\fR, \fB--help\fR +Print a short help page describing the available options in +.B update\-initramfs. + +.SH EXAMPLES + +Update the initramfs of the newest kernel: + +.PP +.B update\-initramfs -u + + +Create the initramfs for a specific kernel: + +.PP +.B update\-initramfs -c -k 2.6.18-1-686 + +.SH FILES +/etc/initramfs-tools/update-initramfs.conf + +.SH AUTHOR +The initramfs-tools are written by Maximilian Attems <maks@debian.org>, +Jeff Bailey <jbailey@raspberryginger.com> and numerous others. + +.SH SEE ALSO +.BR +.IR initramfs.conf (5), +.IR initramfs-tools (7), +.IR mkinitramfs (8), +.IR lsinitramfs (8). diff --git a/update-initramfs.conf.5 b/update-initramfs.conf.5 new file mode 100644 index 0000000..cd1f4ea --- /dev/null +++ b/update-initramfs.conf.5 @@ -0,0 +1,35 @@ +.TH UPDATE-INITRAMFS.CONF 5 "2010/04/05" "initramfs\-tools" "File Formats Manual" + +.SH NAME +update-initramfs.conf \- configuration file for update-initramfs + +.SH DESCRIPTION +The configuration file allows one to disable the update action from +.B update-initramfs. + +.SH GENERAL VARIABLES +.TP +\fB update_initramfs +Default is \fIyes\fP for running the latest initramfs-tools hooks in the +newest Linux image. +Setting it to \fIall\fP updates any known initramfs. +It is possible to set it to \fIno\fP for remote servers or boxes where +conservative manners needs to be applied. This disables +the \fBupdate_initramfs \-u\fP call. +.TP +\fB backup_initramfs +If set \fBupdate_initramfs\fP keeps an .bak file of the previous initramfs. If unset the backup initramfs will not be kept. + +.SH FILES +.TP +.I /etc/initramfs-tools/update-initramfs.conf + +.SH AUTHOR +The initramfs-tools are written by Maximilian Attems <maks@debian.org>, +Jeff Bailey <jbailey@raspberryginger.com> and numerous others. +.SH SEE ALSO +.BR +.IR initramfs.conf (5), +.IR initramfs-tools (7), +.IR mkinitramfs (8), +.IR update-initramfs (8). |