INITRAMFS-TOOLS(7)

๐Ÿ“ฆ
version 0.151ubuntu3 ยท 2 versions
, in ubuntu jammy, ubuntu noble, ubuntu questing, ubuntu resolute, ubuntu stonking

๐ŸŽ€ initramfs-tools ๐ŸŽ€

okay bestie, this is the manual section 7 page from the Linux Programmer's Manual, and it's all about initramfs-tools ๐Ÿงš let's get into it ๐Ÿ’…

โœจ NAME โœจ

initramfs-tools is an intro to writing scripts for mkinitramfs ๐Ÿ’–

โœจ DESCRIPTION โœจ

okay so initramfs-tools has one main script and two different sets of subscripts ๐Ÿซถ they run during different phases of execution. we'll go through each one separately, using an imaginary tool that frobnicates an lvm partition before the root partition gets mounted ๐Ÿ”ฅ

Kernel Command Line

the boot loader picks the root filesystem for the kernel, same as always ๐Ÿ‘‘ the old-school root=/dev/sda1 style device spec still works โœจ if you use a label like root=LABEL=rootPart, the initrd will search every available device for a filesystem with that label and mount it as root ๐ŸŒธ and root=UUID=uuidnumber mounts the partition with that UUID as root ๐Ÿ’œ

Standard

  • init= "<path to real init>" โ€” the binary that takes over on the root fs once the initramfs scripts are finished ๐Ÿฆ‹
  • initramfs.clear โ€” clears the screen at the very beginning ๐Ÿงน
  • initramfs.runsize โ€” sets the size of the /run tmpfs mount point. you can give it in bytes (suffixes work too) or as a percentage of your physical RAM ๐Ÿง  it gets passed as the size mount option to tmpfs. check https://www.kernel.org/doc/Documentation/filesystems/tmpfs.txt for the full details ๐Ÿ“š the default is 10% ๐Ÿ’…
  • root= "<path to blockdevice>" โ€” the device node to mount as the root file system ๐ŸŒˆ the recommended move is to use the UUID, like root=UUID=xxx ๐Ÿซถ
  • rootfstype โ€” sets the root file system type ๐Ÿ“
  • roottimeout โ€” sets a timeout in seconds for how long mountroot waits for root to show up โฐ the default is 30 seconds ๐Ÿ™ˆ
  • rootdelay โ€” an alias for roottimeout ๐Ÿ”
  • rootflags โ€” sets the file system mount option string ๐ŸŽ€
  • loop= "<path to image>" โ€” a path inside the original root file system that gets loop-mounted and used as the real root file system ๐Ÿ”„
  • loopfstype โ€” sets the loop file system type, if that applies ๐ŸŒธ
  • loopflags โ€” sets the loop file system mount option string, if that applies ๐Ÿฆ‹
  • nfsroot โ€” can be either auto, which tries to grab the info from DHCP, or a string shaped like NFSSERVER:NFSPATH or NFSSERVER:NFSPATH:NFSOPTS ๐ŸŒ use root=/dev/nfs so NFS kicks in ๐Ÿ’œ you can look up NFSOPTS in nfs(5) โœจ
  • ip โ€” tells it how to configure the IP address ๐Ÿงš this lets you name a different NFS server than the DHCP server. check Documentation/filesystems/nfsroot.txt in any recent Linux source for the deets ๐Ÿ“– it's an optional parameter for NFS root ๐Ÿซถ
  • vlan โ€” tells it to create a VLAN tagged device ๐Ÿท๏ธ you can set up one or multiple VLAN tagged devices with the vlan=$name.$id:$parent syntax, e.g. vlan=eth0.1:eth0 โœจ also optional for NFS root ๐Ÿ’–
  • BOOTIF โ€” a MAC address in pxelinux format, with leading 01- and - as separators ๐Ÿ”ฅ pxelinux passes along the MAC address of the network card it PXE booted with using this bootarg ๐ŸŽ€
  • boot โ€” either local or NFS ๐Ÿ‘‘ this decides which initramfs scripts run, so check the "Subdirectories" section under boot scripts ๐Ÿง 
  • resume โ€” the resume hook tries to autodetect the resume partition and uses the first swap partition as its best guess ๐Ÿ” you can set the RESUME variable in /etc/initramfs-tools/conf.d/resume ๐ŸŒธ the boot variable noresume overrides all of this ๐Ÿ™…โ€โ™€๏ธ
  • resume_offset โ€” the offset from the partition given by resume= where the swap header of the swap file lives ๐Ÿฆ‹
  • quiet โ€” cuts down the amount of text printed to the console during boot ๐Ÿคซ
  • ro โ€” mounts the rootfs read-only ๐Ÿ”’
  • rw โ€” mounts the rootfs read-write ๐Ÿ”“
  • blacklist โ€” stops specific modules from loading ๐Ÿšซ use the boot parameter blacklist=module1,module2,module3 ๐Ÿ’…

Debug

  • panic โ€” sets a timeout on panic ๐Ÿ˜ญ panic=<sec> is a documented security feature, since it disables the debug shell ๐Ÿ”
  • debug โ€” generates LOTS of output ๐Ÿ“œ it writes a log to /run/initramfs/initramfs.debug. but if you pass it an arbitrary argument, the output goes to the console instead ๐Ÿ–ฅ๏ธ for example, debug=vc ๐Ÿ’œ
  • break โ€” spawns a shell in the initramfs image at the phase you pick (top, modules, premount, mount, mountroot, bottom, init) ๐Ÿš this happens before the matching scripts (see the "Boot scripts" section) or action actually run ๐ŸŽฌ you can list several phases separated by commas ๐Ÿซถ if you don't pick one, the default is premount ๐ŸŒท
โš ๏ธ beware: if both panic and break are present, initramfs won't spawn any shells and will reboot instead ๐Ÿ’€
  • netconsole โ€” loads the netconsole linux modules with the args you choose ๐Ÿ“ก
  • all_generic_ide โ€” loads generic IDE/ATA chipset support on boot ๐Ÿ’ฟ

โœจ SCRIPTS โœจ

okay so valid boot and hook script names are made up only of alphabetics, numerics, dashes and underscores ๐Ÿ”ค anything else gets discarded ๐Ÿ—‘๏ธ bye bye ๐Ÿ‘‹

Configuration hook scripts

these let you override the user configuration when you really need to ๐Ÿ› ๏ธ for example, forcing busybox to be used instead of klibc utilities ๐Ÿงฐ

Hook scripts

these run when an initramfs image gets created, and they are not part of the image itself ๐Ÿ—๏ธ they can still cause files to be included in the image though ๐Ÿ“ฆ hook scripts run under errexit, so a hook script can abort the mkinitramfs build on errors (anything with exitcode != 0) ๐Ÿšจ

Boot scripts

these are included in the initramfs image and usually run during kernel boot in early user-space, before the root partition gets mounted ๐ŸŒ…


โœจ CONFIGURATION HOOK SCRIPTS โœจ

config hook scripts live in /usr/share/initramfs-tools/conf-hooks.d ๐Ÿ“‚ mkinitramfs sources them after the config files in /etc and before it runs any hook scripts ๐Ÿงฉ they can override any of the variables documented in initramfs.conf(5), but only do this if it's absolutely necessary ๐Ÿ™ for example, if a package's boot script needs commands that klibc-utils doesn't provide, it should also install a configuration hook that sets BUSYBOX=y ๐Ÿ’œ


โœจ HOOK SCRIPTS โœจ

hooks can live in two places: /usr/share/initramfs-tools/hooks and /etc/initramfs-tools/hooks ๐Ÿ  they run while the initramfs image is being generated, and they're responsible for pulling in every component the image needs ๐Ÿ“ฆ there are no guarantees about the order the scripts run in, unless you set up the prereqs in your script ๐Ÿคทโ€โ™€๏ธ

๐Ÿšจ heads up: PREREQ is only honored inside a single directory ๐Ÿซฃ so the scripts in /usr/share/initramfs-tools get ordered by their PREREQ values and run first ๐Ÿฅ‡ then all the scripts in /etc/initramfs-tools get ordered by their PREREQ values and run ๐Ÿฅˆ which means a local script in /etc/initramfs-tools can never run before one from the package in /usr/share/initramfs-tools ๐Ÿ˜ญ

if a hook script needs config beyond the exported variables listed further down, it should read its own private config file that lives separately from the /etc/initramfs-tools directory ๐Ÿ” it must not read initramfs-tools config files directly ๐Ÿ™…โ€โ™€๏ธ

to support prereqs, every script should start with these lines ๐Ÿ’…

#!/bin/sh
PREREQ=""
prereqs()
{
     echo "$PREREQ"
}

case $1 in
prereqs)
     prereqs
     exit 0
     ;;
esac

. /usr/share/initramfs-tools/hook-functions
# Begin real processing below this line

for example, if you're writing a new hook script that relies on lvm, change the PREREQ line to PREREQ="lvm" โœจ that way the lvm hook script is guaranteed to run before yours ๐Ÿซถ

Help functions

/usr/share/initramfs-tools/hook-functions has a bunch of functions that handle common hook script tasks ๐Ÿงฐ slay ๐Ÿ’…

  • manual_add_modules โ€” adds a module (plus any modules it depends on) to the initramfs image ๐Ÿงฉ
    • example: manual_add_modules isofs
  • add_modules_from_file โ€” reads a file with a list of modules (one per line) and adds them to the initramfs image ๐Ÿ“ƒ the file can have comments (lines starting with #), and you can pass arguments to a module by writing them on the same line as the module name ๐ŸŽ€
    • example: add_modules_from_file /tmp/modlist
  • force_load โ€” adds a module (and its dependencies) to the initramfs image AND unconditionally loads it during boot ๐Ÿ’ช you can pass arguments to the module by listing them after the module name ๐Ÿ”ฅ
    • example: force_load cdrom debug=1
  • copy_modules_dir โ€” copies an entire module directory from /lib/modules/KERNELVERSION/ into the initramfs image ๐Ÿ“
    • example: copy_modules_dir kernel/drivers/ata

Including binaries

if you need to copy an executable or shared library into the initramfs, use something like this ๐Ÿฆ‹

copy_exec /sbin/mdadm /sbin

mkinitramfs automatically detects which libraries your stuff depends on and copies them in for you ๐Ÿค– this means most executables, unless they were compiled with klibc, will pull glibc into the image too ๐Ÿ˜ฉ which can bloat it by several hundred kilobytes ๐Ÿ’€

โœจ BOOT SCRIPTS โœจ

okay so boot scripts are basically hook scripts' hype cousin ๐Ÿ’– they live in two places too: /usr/share/initramfs-tools/scripts/ and /etc/initramfs-tools/scripts/. Inside those are a bunch of subdirectories, and each one decides when during boot the scripts get run ๐ŸŽ€

Header

same deal as hook scripts: there's no promise about what order the scripts in one subdirectory (see "Subdirectories" below) run in ๐Ÿ™ˆ if you want to set an order, you use a similar header as hook scripts:

#!/bin/sh
PREREQ=""
prereqs()
{
     echo "$PREREQ"
}

case $1 in
prereqs)
     prereqs
     exit 0
     ;;
esac

and yes, you tweak PREREQ to list any other scripts in the same subdirectory that need to go first if you need that ๐Ÿซถ

Help functions

there's a bunch of helper functions (mostly for output stuff) that boot scripts get for free, living in /scripts/functions โœจ these are giving toolkit energy:

  • log_success_msg โ€” logs a success message ๐ŸŽ‰ Example: log_success_msg "Frobnication successful"
  • log_failure_msg โ€” logs a failure message ๐Ÿ’€ Example: log_failure_msg "Frobnication component froobz missing"
  • log_warning_msg โ€” logs a warning message โš ๏ธ Example: log_warning_msg "Only partial frobnication possible"
  • log_begin_msg โ€” logs a message that some processing step has begun ๐ŸŒธ
  • log_end_msg โ€” logs a message that some processing step is finished ๐Ÿฆ‹

Example:

log_begin_msg "Frobnication begun"
# Do something
log_end_msg
  • panic โ€” logs an error message and drops you into a shell inside the initramfs image so you can poke around and figure out what went wrong ๐Ÿ™ˆ Example: panic "Frobnication failed"
  • add_mountroot_fail_hook NN-name โ€” Deprecated! this one is now a stub that basically does nothing ๐Ÿ’€ it's going to be removed in a future version, so please go remove mountroot failure hooks from your existing packages accordingly ๐Ÿฅบ

Subdirectories

both /usr/share/initramfs-tools/scripts and /etc/initramfs-tools/scripts have the following subdirectories, and the name of each one tells you its boot stage ๐Ÿ‘‘

  • init-top โ€” the first scripts to run after sysfs and procfs get mounted ๐ŸŒˆ this one also runs the udev hook that fills up the /dev tree (udev keeps running until init-bottom).
  • init-premount โ€” runs after the modules from hooks and /etc/initramfs-tools/modules have been loaded ๐Ÿงš
  • local-top OR nfs-top โ€” once these have run, the root device node is expected to be there (local) or the network interface is expected to be usable (NFS) ๐Ÿ”ฅ
  • local-block โ€” these scripts get called with the name of a local block device ๐Ÿ’œ after they've run, that device node should exist. if the local-top or local-block scripts fail to make the device node you wanted, the local-block scripts will keep getting called periodically to try again, so they're basically persistent ๐Ÿฅน
  • local-premount OR nfs-premount โ€” these run after the root device's sanity has been checked (local) or the network interface has been brought up (NFS), but before the actual root fs gets mounted ๐ŸŒธ
  • local-bottom OR nfs-bottom โ€” these run after the rootfs has been mounted (local) or the NFS root share has been mounted ๐Ÿฆ‹
  • init-bottom โ€” the very last scripts before procfs and sysfs get moved over to the real rootfs and control gets handed to the init binary (which should now be in the mounted rootfs). udev gets stopped here ๐Ÿซถ

Boot parameters

/conf/param.conf lets boot scripts change the exported variables that are listed at the top of init. just write the new values into it! it gets sourced after a boot script run if it exists โœจ

โœจ EXAMPLES โœจ

Hook script

an example hook script would look something like this (and it would usually go in /etc/initramfs-tools/hooks/frobnicate) ๐Ÿ’…

#!/bin/sh
# Example frobnication hook script

PREREQ="lvm"
prereqs()
{
     echo "$PREREQ"
}

case $1 in
prereqs)
     prereqs
     exit 0
     ;;
esac

. /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

Boot script

an example boot script would look something like this (and it would usually go in /etc/initramfs-tools/scripts/local-top/frobnicate) ๐Ÿงš

#!/bin/sh
# Example frobnication boot script

PREREQ="lvm"
prereqs()
{
     echo "$PREREQ"
}

case $1 in
prereqs)
     prereqs
     exit 0
     ;;
esac

. /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

Exported variables

init sets a bunch of variables for the boot scripts environment ๐Ÿ’œ

  • ROOT โ€” matches the root boot option ๐Ÿ‘‘ advanced boot scripts like cryptsetup or live-initramfs need to play tricks with it. otherwise, leave it alone!
  • ROOTDELAY, ROOTFLAGS, ROOTFSTYPE, IP โ€” match the rootdelay, rootflags, rootfstype or ip boot options. Use of ROOTDELAY is deprecated ๐Ÿ’€ instead of delaying or polling, you should write a local-block boot script.
  • DPKG_ARCH โ€” lets you do arch-specific boot actions ๐ŸŒˆ
  • blacklist, panic, quiet, resume, noresume, resume_offset โ€” set according to their relevant boot options ๐ŸŽ€
  • break โ€” super useful for manual intervention during setup and when you're coding a boot script ๐Ÿ› ๏ธ
  • REASON โ€” the argument passed to the panic helper function. use it to figure out why you ended up in the initramfs shell ๐Ÿ™ˆ
  • init โ€” passes the path to init(8), usually /sbin/init โœจ
  • readonly โ€” the default for mounting root, and it matches the ro bootarg. it gets overridden by the rw bootarg ๐Ÿ“
  • rootmnt โ€” the path where root gets mounted, usually /root ๐Ÿฆ‹
  • debug โ€” indicates that a debug log is captured for further investigation ๐Ÿ”

โœจ UPDATING THE INITRAMFS FROM ANOTHER PACKAGE โœจ

okay this part is important, bestie ๐Ÿšจ package maintainer scripts should not run update-initramfs directly ๐Ÿ™…โ€โ™€๏ธ instead, a package that installs hooks for initramfs-tools should ship a triggers file containing:

activate-noawait update-initramfs

kernel packages have their own rules: they must call the kernel hooks as documented in the Debian Kernel Handbook ๐Ÿ“–

and a package that needs an initramfs to function, but isn't a kernel package, should ship a triggers file containing:

activate-await update-initramfs

โœจ KERNEL HOOKS โœจ

initramfs-tools comes with hook scripts that kernel packages call on installation and removal, so the initramfs gets created, updated or deleted automatically when needed ๐Ÿค– the hook scripts do nothing if the environment variable INITRD is set to No. that happens for kernel packages built with make deb-pkg (with CONFIG_BLK_DEV_INITRD not set in the kernel config), or built with make-kpkg without using the --initrd option ๐Ÿ™ˆ

โœจ DEBUG โœจ

it's super easy to peek inside the generated initramfs and check what's in it ๐Ÿ‘€ you might want to double-check that it has the binaries, libs or modules you need:

lsinitramfs /boot/initrd.img-3.16-3-amd64

โœจ FILES โœจ

  • /run/initramfs/fsck.log โ€” log of the fsck commands run inside the initramfs, with their output ๐Ÿ“œ
  • /run/initramfs/fsck-root โ€” only exists if fsck ran successfully on the root filesystem โœ…
  • /run/initramfs/fsck-usr โ€” only exists if fsck ran successfully on the /usr filesystem โœ…

โœจ AUTHOR โœจ

the initramfs-tools were written by Maximilian Attems <maks@debian.org>, Jeff Bailey <jbailey@raspberryginger.com> and numerous others ๐Ÿซถ

this manual was written by David Hรคrdeman <david@hardeman.nu>, and updated by Maximilian Attems <maks@debian.org> ๐Ÿ’œ

โœจ SEE ALSO โœจ

go check out these bestie-approved references ๐Ÿ‘‘ initramfs.conf(5), mkinitramfs(8), update-initramfs(8), lsinitramfs(8) ๐ŸŒˆ


๐Ÿ“œ that's a wrap! this page comes from initramfs-tools, dated 2018/07/18, and it's INITRAMFS-TOOLS(7) ๐Ÿ’– go forth and frobnicate responsibly, periodt ๐Ÿ’…โœจ