#!/bin/bash # -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- # ex: ts=8 sw=4 sts=4 et filetype=sh # # Generator script for a dracut initramfs # Tries to retain some degree of compatibility with the command line # of the various mkinitrd implementations out there # # Copyright 2005-2010 Red Hat, Inc. All rights reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # store for logging dracut_args="$@" usage() { # 80x25 linebreak here ^ cat << EOF Usage: $0 [OPTION]... Creates initial ramdisk images for preloading modules -f, --force Overwrite existing initramfs file. -m, --modules [LIST] Specify a space-separated list of dracut modules to call when building the initramfs. Modules are located in /usr/share/dracut/modules.d. -o, --omit [LIST] Omit a space-separated list of dracut modules. -a, --add [LIST] Add a space-separated list of dracut modules. -d, --drivers [LIST] Specify a space-separated list of kernel modules to exclusively include in the initramfs. --add-drivers [LIST] Specify a space-separated list of kernel modules to add to the initramfs. --filesystems [LIST] Specify a space-separated list of kernel filesystem modules to exclusively include in the generic initramfs. -k, --kmoddir [DIR] Specify the directory, where to look for kernel modules --fwdir [DIR] Specify additional directories, where to look for firmwares, separated by : --kernel-only Only install kernel drivers and firmware files --no-kernel Do not install kernel drivers and firmware files --strip Strip binaries in the initramfs --nostrip Do not strip binaries in the initramfs (default) --mdadmconf Include local /etc/mdadm.conf --nomdadmconf Do not include local /etc/mdadm.conf --lvmconf Include local /etc/lvm/lvm.conf --nolvmconf Do not include local /etc/lvm/lvm.conf -h, --help This message --debug Output debug information of the build process -L, --stdlog [0-6] Specify logging level (to standard error) 0 - suppress any messages 1 - only fatal errors 2 - all errors 3 - warnings 4 - info (default) 5 - debug info (here starts lots of output) 6 - trace info (and even more) -v, --verbose Increase verbosity level (default is info(4)) -q, --quiet Decrease verbosity level (default is info(4)) -c, --conf [FILE] Specify configuration file to use. Default: /etc/dracut.conf --confdir [DIR] Specify configuration directory to use *.conf files from. Default: /etc/dracut.conf.d -l, --local Local mode. Use modules from the current working directory instead of the system-wide installed in /usr/share/dracut/modules.d. Useful when running dracut from a git checkout. -H, --hostonly Host-Only mode: Install only what is needed for booting the local host instead of a generic host. --fstab Use /etc/fstab to determine the root device. -i, --include [SOURCE] [TARGET] Include the files in the SOURCE directory into the Target directory in the final initramfs. If SOURCE is a file, it will be installed to TARGET in the final initramfs. -I, --install [LIST] Install the space separated list of files into the initramfs. --gzip Compress the generated initramfs using gzip. This will be done by default, unless another compression option or --no-compress is passed. --bzip2 Compress the generated initramfs using bzip2. Make sure your kernel has bzip2 decompression support compiled in, otherwise you will not be able to boot. --lzma Compress the generated initramfs using lzma. Make sure your kernel has lzma support compiled in, otherwise you will not be able to boot. --xz Compress the generated initramfs using xz. Make sure that your kernel has xz support compiled in, otherwise you will not be able to boot. --compress [COMPRESSION] Compress the generated initramfs with the passed compression program. Make sure your kernel knows how to decompress the generated initramfs, otherwise you will not be able to boot. --no-compress Do not compress the generated initramfs. This will override any other compression options. --list-modules List all available dracut modules. -M, --show-modules Print included module's name to standard output during build. EOF } # function push() # push values to a stack # $1 = stack variable # $2.. values # example: # push stack 1 2 "3 4" push() { local __stack=$1; shift for i in "$@"; do eval ${__stack}'[${#'${__stack}'[@]}]="$i"' done } # function pop() # pops the last value from a stack # assigns value to second argument variable # or echo to stdout, if no second argument # $1 = stack variable # $2 = optional variable to store the value # example: # pop stack val # val=$(pop stack) pop() { local __stack=$1; shift local __resultvar=$1 local myresult; # check for empty stack eval '[[ ${#'${__stack}'[@]} -eq 0 ]] && return 1' eval myresult='${'${__stack}'[${#'${__stack}'[@]}-1]}' if [[ "$__resultvar" ]]; then eval $__resultvar="'$myresult'" else echo "$myresult" fi eval unset ${__stack}'[${#'${__stack}'[@]}-1]' return 0 } # Little helper function for reading args from the commandline. # it automatically handles -a b and -a=b variants, and returns 1 if # we need to shift $3. read_arg() { # $1 = arg name # $2 = arg value # $3 = arg parameter local rematch='^[^=]*=(.*)$' if [[ $2 =~ $rematch ]]; then read "$1" <<< "${BASH_REMATCH[1]}" else read "$1" <<< "$3" # There is no way to shift our callers args, so # return 1 to indicate they should do it instead. return 1 fi } # Little helper function for reading args from the commandline to a stack. # it automatically handles -a b and -a=b variants, and returns 1 if # we need to shift $3. push_arg() { # $1 = arg name # $2 = arg value # $3 = arg parameter local rematch='^[^=]*=(.*)$' if [[ $2 =~ $rematch ]]; then push "$1" "${BASH_REMATCH[1]}" else push "$1" "$3" # There is no way to shift our callers args, so # return 1 to indicate they should do it instead. return 1 fi } verbosity_mod_l=0 while (($# > 0)); do case ${1%%=*} in -a|--add) push_arg add_dracutmodules_l "$@" || shift;; --add-drivers) push_arg add_drivers_l "$@" || shift;; -m|--modules) push_arg dracutmodules_l "$@" || shift;; -o|--omit) push_arg omit_dracutmodules_l "$@" || shift;; -d|--drivers) push_arg drivers_l "$@" || shift;; --filesystems) push_arg filesystems_l "$@" || shift;; -I|--install) push_arg install_items "$@" || shift;; --fwdir) push_arg fw_dir_l "$@" || shift;; -k|--kmoddir) read_arg drivers_dir_l "$@" || shift;; -c|--conf) read_arg conffile "$@" || shift;; --confdir) read_arg confdir "$@" || shift;; -L|--stdlog) read_arg stdloglvl_l "$@" || shift;; -I|--install) read_arg install_items "$@" || shift;; --fwdir) read_arg fw_dir_l "$@" || shift;; --compress) read_arg compress_l "$@" || shift;; -f|--force) force=yes;; --kernel-only) kernel_only="yes"; no_kernel="no";; --no-kernel) kernel_only="no"; no_kernel="yes";; --strip) do_strip_l="yes";; --nostrip) do_strip_l="no";; --mdadmconf) mdadmconf_l="yes";; --nomdadmconf) mdadmconf_l="no";; --lvmconf) lvmconf_l="yes";; --nolvmconf) lvmconf_l="no";; --debug) debug="yes";; -v|--verbose) ((verbosity_mod_l++));; -q|--quiet) ((verbosity_mod_l--));; -l|--local) allowlocal="yes" ;; -H|--hostonly) hostonly_l="yes" ;; --fstab) use_fstab_l="yes" ;; -h|--help) usage; exit 1 ;; -i|--include) push include_src "$2" push include_target "$3" shift 2;; --bzip2) compress_l="bzip2";; --lzma) compress_l="lzma";; --xz) compress_l="xz";; --no-compress) _no_compress_l="cat";; --gzip) compress_l="gzip";; --list-modules) do_list="yes"; ;; -M|--show-modules) show_modules_l="yes" ;; -*) printf "\nUnknown option: %s\n\n" "$1" >&2; usage; exit 1;; *) if ! [[ ${outfile+x} ]]; then outfile=$1 elif ! [[ ${kernel+x} ]]; then kernel=$1 else usage; exit 1; fi ;; esac shift done if ! [[ $kernel ]]; then kernel=$(uname -r) fi [[ $outfile ]] || outfile="/boot/initramfs-$kernel.img" PATH=/sbin:/bin:/usr/sbin:/usr/bin export PATH [[ $debug ]] && { export PS4='${BASH_SOURCE}@${LINENO}(${FUNCNAME[0]}): '; set -x } [[ $dracutbasedir ]] || dracutbasedir=/usr/share/dracut [[ $allowlocal && -f "$(readlink -f ${0%/*})/dracut-functions" ]] && \ dracutbasedir="$(readlink -f ${0%/*})" # if we were not passed a config file, try the default one if [[ ! -f $conffile ]]; then [[ $allowlocal ]] && conffile="$dracutbasedir/dracut.conf" || \ conffile="/etc/dracut.conf" fi if [[ ! -d $confdir ]]; then [[ $allowlocal ]] && confdir="$dracutbasedir/dracut.conf.d" || \ confdir="/etc/dracut.conf.d" fi # source our config file [[ -f $conffile ]] && . "$conffile" # source our config dir if [[ $confdir && -d $confdir ]]; then for f in "$confdir"/*.conf; do [[ -e $f ]] && . "$f" done fi # these optins add to the stuff in the config file if (( ${#add_dracutmodules_l[@]} )); then while pop add_dracutmodules_l val; do add_dracutmodules+=" $val " done fi if (( ${#add_drivers_l[@]} )); then while pop add_drivers_l val; do add_drivers+=" $val " done fi # these options override the stuff in the config file if (( ${#dracutmodules_l[@]} )); then dracutmodules='' while pop dracutmodules_l val; do dracutmodules+="$val " done fi if (( ${#omit_dracutmodules_l[@]} )); then omit_dracutmodules='' while pop omit_dracutmodules_l val; do omit_dracutmodules+="$val " done fi if (( ${#drivers_l[@]} )); then drivers='' while pop drivers_l val; do drivers+="$val " done fi if (( ${#filesystems_l[@]} )); then filesystems='' while pop filesystems_l val; do filesystems+="$val " done fi if (( ${#fw_dir_l[@]} )); then fw_dir='' while pop fw_dir_l val; do fw_dir+="$val " done fi [[ $stdloglvl_l ]] && stdloglvl=$stdloglvl_l [[ ! $stdloglvl ]] && stdloglvl=4 stdloglvl=$((stdloglvl + verbosity_mod_l)) ((stdloglvl > 6)) && stdloglvl=6 ((stdloglvl < 0)) && stdloglvl=0 [[ $drivers_dir_l ]] && drivers_dir=$drivers_dir_l [[ $do_strip_l ]] && do_strip=$do_strip_l [[ $hostonly_l ]] && hostonly=$hostonly_l [[ $use_fstab_l ]] && use_fstab=$use_fstab_l [[ $mdadmconf_l ]] && mdadmconf=$mdadmconf_l [[ $lvmconf_l ]] && lvmconf=$lvmconf_l [[ $dracutbasedir ]] || dracutbasedir=/usr/share/dracut [[ $fw_dir ]] || fw_dir="/lib/firmware/updates /lib/firmware" [[ $do_strip ]] || do_strip=no [[ $compress_l ]] && compress=$compress_l [[ $show_modules_l ]] && show_modules=$show_modules_l # eliminate IFS hackery when messing with fw_dir fw_dir=${fw_dir//:/ } # handle compression options. case $compress in bzip2) compress="bzip -9";; lzma) compress="lzma -9";; xz) compress="xz --check=crc32 --lzma2=dict=1MiB";; gzip) type pigz > /dev/null 2>&1 && compress="pigz -9" || \ compress="gzip -9";; esac if [[ $_no_compress_l = "cat" ]]; then compress="cat" fi [[ $hostonly = yes ]] && hostonly="-h" [[ $hostonly != "-h" ]] && unset hostonly [[ $compress ]] || compress="gzip -9" if [[ -f $dracutbasedir/dracut-functions ]]; then . $dracutbasedir/dracut-functions else echo "Cannot find $dracutbasedir/dracut-functions." >&2 echo "Are you running from a git checkout?" >&2 echo "Try passing -l as an argument to $0" >&2 exit 1 fi dracutfunctions=$dracutbasedir/dracut-functions export dracutfunctions ddebug "Executing $0 $dracut_args" [[ $do_list = yes ]] && { for mod in $dracutbasedir/modules.d/*; do [[ -d $mod ]] || continue; [[ -e $mod/install || -e $mod/installkernel || \ -e $mod/module-setup.sh ]] || continue echo ${mod##*/??} done exit 0 } # Detect lib paths [[ $libdir ]] || for libdir in /lib64 /lib; do [[ -d $libdir ]] && break done || { dfatal 'No lib directory?!!!' exit 1 } [[ $usrlibdir ]] || for usrlibdir in /usr/lib64 /usr/lib; do [[ -d $usrlibdir ]] && break done || dwarn 'No usr/lib directory!' # This is kinda legacy -- eventually it should go away. case $dracutmodules in ""|auto) dracutmodules="all" ;; esac abs_outfile=$(readlink -f "$outfile") && outfile="$abs_outfile" srcmods="/lib/modules/$kernel/" [[ $drivers_dir ]] && { if vercmp $(modprobe --version | cut -d' ' -f3) lt 3.7; then dfatal 'To use --kmoddir option module-init-tools >= 3.7 is required.' exit 1 fi srcmods="$drivers_dir" } export srcmods if [[ -f $outfile && ! $force ]]; then dfatal "Will not override existing initramfs ($outfile) without --force" exit 1 fi outdir=${outfile%/*} [[ $outdir ]] || outdir="/" if [[ ! -d "$outdir" ]]; then dfatal "Can't write $outfile: Directory $outdir does not exist." exit 1 elif [[ ! -w "$outdir" ]]; then dfatal "No permission to write $outdir." exit 1 elif [[ -f "$outfile" && ! -w "$outfile" ]]; then dfatal "No permission to write $outfile." exit 1 fi [[ $TMPDIR && ! -w $TMPDIR ]] && unset TMPDIR readonly initdir=$(mktemp -d -t initramfs.XXXXXX) # clean up after ourselves no matter how we die. trap 'ret=$?;rm -rf "$initdir";exit $ret;' EXIT # clean up after ourselves no matter how we die. trap 'exit 1;' SIGINT # Need to be able to have non-root users read stuff (rpcbind etc) chmod 755 "$initdir" export initdir dracutbasedir dracutmodules drivers \ fw_dir drivers_dir debug no_kernel kernel_only \ add_drivers mdadmconf lvmconf filesystems \ use_fstab libdir usrlibdir \ stdloglvl sysloglvl fileloglvl kmsgloglvl logfile \ debug if [[ $kernel_only != yes ]]; then # Create some directory structure first for d in bin sbin usr/bin usr/sbin usr/lib etc \ proc sys sysroot tmp dev/pts var/run; do inst_dir "/$d"; done fi # check all our modules to see if they should be sourced. # This builds a list of modules that we will install next. check_module_dir # source our modules. for moddir in "$dracutbasedir/modules.d"/[0-9][0-9]*; do mod=${moddir##*/}; mod=${mod#[0-9][0-9]} if strstr "$mods_to_load" " $mod "; then [[ $show_modules = yes ]] && echo "$mod" || \ dinfo "*** Including module: $mod ***" if [[ $kernel_only = yes ]]; then module_installkernel $mod else module_install $mod if [[ $no_kernel != yes ]]; then module_installkernel $mod fi fi mods_to_load=${mods_to_load// $mod /} fi done unset moddir dinfo "*** Including modules done ***" ## final stuff that has to happen # generate module dependencies for the initrd if [[ -d $initdir/lib/modules/$kernel ]] && \ ! depmod -a -b "$initdir" $kernel; then dfatal "\"depmod -a $kernel\" failed." exit 1 fi while pop include_src src && pop include_target tgt; do if [[ $src && $tgt ]]; then if [[ -f $src ]]; then inst $src $tgt else ddebug "Including directory: $src" mkdir -p "${initdir}/${tgt}" cp -a -t "${initdir}/${tgt}" "$src"/* fi fi done while pop install_items items; do for item in $items; do dracut_install "$item" done done unset item # make sure that library links are correct and up to date dracut_install /etc/ld.so.conf /etc/ld.so.conf.d/* if ! ldconfig -r "$initdir"; then if [[ $UID = 0 ]]; then derror "ldconfig exited ungracefully" else derror "ldconfig might need uid=0 (root) for chroot()" fi fi if (($maxloglvl >= 5)); then ddebug "Listing sizes of included files:" du -c "$initdir" | sort -n | ddebug fi # strip binaries if [[ $do_strip = yes ]] ; then for p in strip grep find; do if ! type -P $p >/dev/null; then derror "Could not find '$p'. You should run $0 with '--nostrip'." do_strip=no fi done fi if [[ $do_strip = yes ]] ; then for f in $(find "$initdir" -type f \ \( -perm -0100 -or -perm -0010 -or -perm -0001 \ -or -path '*/lib/modules/*.ko' \) ); do dinfo "Stripping $f" strip -g "$f" 2>/dev/null|| : done fi type hardlink &>/dev/null && { hardlink "$initdir" 2>&1 } if ! ( cd "$initdir"; find . |cpio -R 0:0 -H newc -o --quiet | \ $compress > "$outfile"; ); then dfatal "dracut: creation of $outfile failed" exit 1 fi dinfo "Wrote $outfile:" dinfo "$(ls -l "$outfile")" exit 0