#!/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 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 item= needle=$1; shift for item in "$@"; do [[ $item = $needle ]] && return 0 # Found done return 1 # Not Found } _add_file() { # add a file to $BUILDROOT # $1: pathname on initcpio # $2: source on disk # $3: mode (( $# == 3 )) || return $EINVAL [[ -e "$BUILDROOT$1" ]] && return $EEXIST (( QUIET )) || plain "adding file: %s" "$1" command install -Dm$3 "$2" "$BUILDROOT$1" } _add_dir() { # add a directory (with parents) to $BUILDROOT # $1: pathname on initcpio # $2: mode (( $# == 2 )) || [[ "$1" == /?* ]] || return 1 # bad args [[ -e "$BUILDROOT$1" ]] && return 0 # file exists (( QUIET )) || plain "adding dir: %s" "$1" command install -dm$2 "$BUILDROOT$1" } _add_symlink() { # add a symlink to $buildroot # $1: name on initcpio # $2: target of $1 (( $# == 2 )) || return $EINVAL [[ -L "$BUILDROOT$1" ]] && return $EEXIST (( QUIET )) || plain "adding symlink: %s -> %s" "$2" "$1" ln -s "$2" "$BUILDROOT$1" } auto_modules() { # Perform auto detection of modules via sysfs. IFS=$'\n' read -rd '' -a mods < \ <(find /sys/devices -name modalias -exec sort -u {} + | xargs modprobe -d "$BASEDIR" -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_module() { # Add a kernel module to the initcpio image. Dependencies will be # discovered and added. # $1: module name local module path dep deps field value module=${1%.ko*} # skip expensive stuff if this module has already been added in_array "${module//-/_}" "${ADDED_MODULES[@]}" && return while IFS=':= ' read -r -d '' field value; do case "$field" in filename) path=$value ;; depends) IFS=',' read -r -a deps <<< "$value" for dep in "${deps[@]}"; do add_module "$dep" done ;; firmware) if [[ -e "$BASEDIR/lib/firmware/$value" ]]; then _add_file "/lib/firmware/$value" "$BASEDIR/lib/firmware/$value" 644 fi ;; esac done < <(modinfo -b "$BASEDIR" -k "$KERNELVERSION" -0 "$module" 2>/dev/null) if [[ -z $path ]]; then error "module not found: \`%s'" "$module" return 1 fi # aggregate modules and add them all at once to save some forks MODPATHS+=("$path") ADDED_MODULES+=("${module//-/_}") # 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_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 (( ! $# )) && return 1 local path=$1 mode=${2:-755} _add_dir "$path" "$mode" } add_symlink() { # Add a symlink to the initcpio image. # $1: pathname of symlink on image # $2: absolute path to target of symlink (( $# == 2 )) || return 1 _add_dir "$(get_dirname "$1")" _add_symlink "$2" "$1" } 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) (( $# )) || return 1 # determine source and destination local src= dest=${2:-$1} mode= src=$BASEDIR$1 [[ -f "$src" ]] || { error "file not found: \`%s'" "$src"; return 1; } mode=$(stat -c %a "$src") if [[ -z "$mode" ]]; then error "failed to stat file: \`%s'." "$src" return 1 fi _add_file "${dest#$BASEDIR}" "$src" "$mode" } 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 -a sodeps local regex binary dest mode sodep resolved dirname binary=$BASEDIR$1 [[ -f "$binary" ]] || { error "file not found: \`%s'" "$binary"; return 1; } dest=${2:-$binary} mode=$(stat -c %a "$binary") # always add the binary itself _add_file "${dest#$BASEDIR}" "$binary" "$mode" lddout=$(ldd "$binary" 2>/dev/null) || return 1 # not a binary! # resolve sodeps regex='(/.+) \(0x[a-fA-F0-9]+\)' while read line; do [[ "$line" =~ $regex ]] && sodep=${BASH_REMATCH[1]} || continue if [[ -f "$sodep" ]]; then # -f follows symlinks, don't believe it! if [[ ! -L $sodep ]]; then _add_file "$sodep" "$BASEDIR$sodep" "$(stat -c %a "$sodep")" else resolved=$(readlink -e "$BASEDIR$sodep") dirname=${resolved%/*} _add_dir "${dirname#$BASEDIR}" 755 _add_symlink "$sodep" "${resolved#$BASEDIR}" _add_file "${resolved#$BASEDIR}" "$resolved" 755 fi fi done <<< "$lddout" return 0 } 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: