#!/bin/bash plain() { local mesg=$1; shift printf "$BOLD $mesg$NC\n" "$@" >&1 } msg() { local mesg=$1; shift printf "$GREEN==>$NC$BOLD $mesg$NC\n" "$@" >&1 } msg2() { local mesg=$1; shift printf "$BLUE ->$NC$BOLD $mesg$NC\n" "$@" >&1 } warning() { local mesg=$1; shift printf "$YELLOW==> WARNING:$NC$BOLD $mesg$NC\n" "$@" >&2 } error() { local mesg=$1; shift printf "$RED==> ERROR:$NC$BOLD $mesg$NC\n" "$@" >&2 } die() { error "$@" cleanup exit 1 } get_dirname() { # strip any trailing slash first... local dir="${1%/}" # then get the directory portion echo "${dir%/*}" } get_basename() { echo "${1##*/}" } in_array() { # Search for an element in an array. # $1: needle # ${@:2}: haystack local needle=$1; shift [[ -z $1 ]] && return 1 # Not Found local item for item in "$@"; do [[ $item = $needle ]] && return 0 # Found done return 1 # Not Found } kmodinfo() { # A wrapper around modinfo, which is aware of our $BASEDIR and # $KERNELVERSION # $@: args to modinfo modinfo -b "$BASEDIR" -k "$KERNELVERSION" "$@" 2>/dev/null } auto_modules() { # Perform auto detection of modules via sysfs. IFS=$'\n' read -rd '' -a mods < \ <(find /sys/devices -name modalias -exec sort -zu {} + | xargs -0 modprobe -aRS "$KERNELVERSION" | sort -u) printf "%s\n" "${mods[@]//-/_}" (( ${#mods[*]} )) } all_modules() { # Add modules to the initcpio, filtered by grep. # $@: filter arguments to grep local -i count=0 while read -r -d '' mod; do (( ++count )) mod=${mod##*/} mod="${mod%.ko*}" printf '%s\n' "${mod//-/_}" done < <(find "$MODULEDIR" -name '*.ko*' -print0 2>/dev/null | grep -Zz "$@") (( count )) } checked_modules() { # Add modules to the initcpio, filtered by the list of autodetected # modules. # $@: arguments to all_modules if [[ -s "$MODULE_FILE" ]]; then grep -xFf "$MODULE_FILE" <(all_modules "$@") return 1 else all_modules "$@" fi } add_full_dir() { # Add a directory and all its contents, recursively, to the initcpio image. # No parsing is performed and the contents of the directory is added as is. # $1: path to directory if [[ -n $1 && -d $1 ]]; then for f in "$1"/*; do if [[ -d "$f" ]]; then add_full_dir "$f" else add_file "$f" fi done fi } add_dir() { # Add a directory to the initcpio image. # $1: absolute path of directory on image if [[ ! -e "$BUILDROOT/$1" ]]; then (( QUIET )) || plain "adding dir: %s" "$1" command install -dm755 "$BUILDROOT/$1" fi } add_symlink() { # Add a symlink to the initcpio image. # $1: pathname of symlink on image # $2: absolute path to target of symlink local file=$1 dest=$2 add_dir $(get_dirname "$file") if [[ ! -e "$TMPDIR/root/$dest" ]]; then (( QUIET )) || plain "adding symlink: $file -> $dest" ln -s "$dest" "$BUILDROOT/$file" fi } add_file() { # Add a plain file to the initcpio image. No parsing is performed and only # the singular file is added. # $1: path to file # $2: destination on initcpio (optional, defaults to same as source) local file dest file=$1 dest=${2:-${file##$BASEDIR}} if [[ -f "$file" ]]; then if [[ -L "$file" ]]; then add_symlink "$file" "$(readlink -f "$file")" add_file "$(readlink -f "$file")" return fi if [[ ! -e "$BUILDROOT/$dest" ]]; then (( QUIET )) || plain "adding file: %s" "$dest" command install -Dm$(stat -c '%a' "$file") "$file" "$BUILDROOT/$dest" fi else error "file '$file' does not exist" return 1 fi } add_module() { # Add a kernel module to the initcpio image. Dependencies will be # discovered and added. # $1: module name local module path fw dep deps module=${1%.ko*} # skip expensive stuff if this module has already been added in_array "${module//-/_}" "${ADDED_MODULES[@]}" && return path=$(kmodinfo -0F filename "$module") if [[ $path ]]; then # get module firmware while read -r -d '' fw; do if [[ -e "$BASEDIR/lib/firmware/$fw" ]]; then add_file "$BASEDIR/lib/firmware/$fw" fi done < <(kmodinfo -0F firmware "$module") # get module depends IFS=',' read -r -d '' -a deps < <(kmodinfo -0F depends "$module") for dep in "${deps[@]}"; do add_module "$dep" done ADDED_MODULES+=("${module//-/_}") add_file "$path" || return else error "module '$module' not found" return fi # explicit module depends case "$module" in fat) add_module "nls_cp437" ;; ocfs2) add_module "configfs" ;; libcrc32c) add_module "crc32c"; add_module "crc32c_intel" ;; esac } add_binary() { # add a binary file to the initcpio image. library dependencies will # be discovered and added. # $1: path to binary # $2: destination on initcpio (optional, defaults to same as source) local bin dest lib bin=$(type -P "$1") dest=$2 if [[ ! -f "$bin" ]]; then error "'$1' is not a file" return 1 fi case "$(file -b "$bin")" in *script*) plain "adding '$type' script, ensure proper interp exists..." add_file "$bin" ${dest+"$dest"} ;; *executable*|*shared\ object*|*symbolic\ link*) add_file "$bin" ${dest+"$dest"} # note, this will also handle 'not a dynamic executable' spit out # by static binaries... the deps will produce nothing while read -r lib; do [[ -f "$lib" ]] && add_file "$lib" done < <(ldd "$bin" 2>/dev/null | sed '1d;s|.*=>\(.*\)|\1|;s/(0x[0-9a-f]\+)//') ;; *) error "unknown type '$type' for binary '$bin'" return 1 ;; esac } parse_hook() { # parse key global variables set by install hooks. This function is called # prior to the start of hook processing, and after each hook's build # function is run. local item for item in $MODULES; do add_module "$item" done for item in $BINARIES; do add_binary "$item" done for item in $FILES; do add_file "$item" done [[ $SCRIPT ]] && add_file "$HOOKDIR/$SCRIPT" "/hooks/$SCRIPT" } # vim: set ft=sh ts=4 sw=4 et: