#!/bin/bash # mkinitcpio - modular tool for building an init ramfs cpio image # # IMPORTANT: We need to keep a common base syntax here because # some of these hooks/scripts need to run under busybox's ash - # therefore, the following constraints should be enforced: # variables should be quoted and bracketed "${SOMEVAR}" # inline execution should be done with $() instead of backticks # use -z "${var}" to test for nulls/empty strings # in case of embedded spaces, quote all path names and string comparisons # shopt -s extglob # Settings KERNELVERSION=$(uname -r) FUNCTIONS=functions CONFIG=mkinitcpio.conf HOOKDIR=hooks INSTDIR=install PRESETDIR=mkinitcpio.d COMPRESSION=gzip declare TMPDIR BASEDIR MODULE_FILE GENIMG PRESET COMPRESSION_OPTIONS BUILDROOT declare NC= BOLD= BLUE= GREEN= RED= YELLOW= declare -i QUIET=1 SHOW_AUTOMODS=0 SAVELIST=0 COLOR=1 declare -a SKIPHOOKS ADDED_MODULES MODPATHS # Add /{,usr}/sbin to path # works around undetected problems like in #8448 PATH=$PATH:/sbin:/usr/sbin # Sanitize environment further # GREP_OPTIONS="--color=always" will break everything # CDPATH can affect cd and pushd unset GREP_OPTIONS CDPATH usage() { cat </dev/null printf ' %s\n' * | column -c$(tput cols) exit 0 ;; M) SHOW_AUTOMODS=1 ;; t) TMPDIR=$OPTARG ;; z) optcompress=$OPTARG ;; :) error "option requires an argument -- '$OPTARG' (use -h for help)" exit 1 ;; \?) error "invalid option -- '$OPTARG' (use -h for help)" exit 1 ;; esac done shift $((OPTIND - 1)) if [[ -t 2 ]] && (( COLOR )); then # prefer terminal safe colored and bold text when tput is supported if tput setaf 0 &>/dev/null; then NC="$(tput sgr0)" BOLD="$(tput bold)" BLUE="$BOLD$(tput setaf 4)" GREEN="$BOLD$(tput setaf 2)" RED="$BOLD$(tput setaf 1)" YELLOW="$BOLD$(tput setaf 3)" else NC="\e[1;0m" BOLD="\e[1;1m" BLUE="$BOLD\e[1;34m" GREEN="$BOLD\e[1;32m" RED="$BOLD\e[1;31m" YELLOW="$BOLD\e[1;33m" fi fi readonly NC BOLD BLUE GREEN RED YELLOW if [[ $BASEDIR ]]; then # resolve the path. it might be a relative path and/or contain symlinks if ! pushd "$BASEDIR" &>/dev/null; then die "base directory does not exist or is not a directory: \`%s'" "$BASEDIR" fi BASEDIR=$(pwd -P) BASEDIR=${BASEDIR%/} popd &>/dev/null fi if [[ $optkver ]]; then if ! KERNELVERSION=$(get_kernver "$optkver"); then [[ ${optkver:0:1} == / ]] && optkver=$BASEDIR$optkver die "invalid kernel specifier: \`%s'" "$optkver" fi fi if [[ $TMPDIR ]]; then if [[ ! -d $TMPDIR ]]; then error "Temporary directory does not exist or is not a directory: \`%s'" "$TMPDIR" unset TMPDIR cleanup 1 fi fi TMPDIR=$(mktemp -d "${TMPDIR:-/tmp}/mkinitcpio.XXXXXX") declare BUILDROOT=$TMPDIR/root # use preset $PRESET if [[ $PRESET ]]; then # allow absolute path to preset file, else resolve it if [[ "${PRESET:0:1}" != '/' ]]; then printf -v PRESET '%s/%s.preset' "$PRESETDIR" "$PRESET" fi if [[ -f "$PRESET" ]]; then # Use -b, -m and -v options specified earlier declare -a preset_mkopts preset_cmd [[ $BASEDIR ]] && preset_mkopts+=(-b "$BASEDIR") (( QUIET )) || preset_mkopts+=(-v) # Build all images . "$PRESET" for p in "${PRESETS[@]}"; do msg "Building image from preset: '$p'" preset_cmd=("${preset_mkopts[@]}") preset_kver=${p}_kver if [[ ${!preset_kver:-$ALL_kver} ]]; then preset_cmd+=(-k "${!preset_kver:-$ALL_kver}") else warning "No kernel version specified. Skipping image \`%s'" "$p" continue fi preset_config=${p}_config if [[ ${!preset_config:-$ALL_config} ]]; then preset_cmd+=(-c "$BASEDIR${!preset_config:-$ALL_config}") else warning "No configuration file specified. Skipping image \`%s'" "$p" continue fi preset_image=${p}_image if [[ ${!preset_image} ]]; then preset_cmd+=(-g "$BASEDIR${!preset_image}") else warning "No image file specified. Skipping image \`%s'" "$p" continue fi preset_options=${p}_options if [[ ${!preset_options} ]]; then preset_cmd+=(${!preset_options}) # intentional word splitting fi msg2 "${preset_cmd[*]}" "$0" "${preset_cmd[@]}" done cleanup 0 else die "Preset not found: \`%s'" "$PRESET" fi fi if [[ $GENIMG ]]; then IMGPATH=$(readlink -f "$GENIMG") if [[ -z $IMGPATH || ! -w ${IMGPATH%/*} ]]; then die "error: unable to write to path: \`%s'" "$GENIMG" fi fi if [[ ! -f "$CONFIG" ]]; then die "Config file does not exist: \`%s'" " $CONFIG" fi . "$CONFIG" MODULEDIR=$BASEDIR/lib/modules/$KERNELVERSION if [[ ! -d $MODULEDIR ]]; then die "'$MODULEDIR' is not a valid kernel module directory" fi if (( SHOW_AUTOMODS )); then msg "Modules autodetected" . "${INSTDIR}/autodetect" build cat "${MODULE_FILE}" cleanup 0 fi if [[ -z $GENIMG ]]; then msg "Starting dry run: %s" "$KERNELVERSION" else COMPRESSION=${optcompress:-$COMPRESSION} if ! type -P "$COMPRESSION" >/dev/null; then die "Unable to locate compression method: %s" "$optcompress" fi msg "Starting build: %s" "$KERNELVERSION" fi # set errtrace and a trap to catch errors in parse_hook declare -i builderrors=0 set -E trap '[[ $FUNCNAME = parse_hook ]] && (( ++builderrors ))' ERR #parse 'global' hook, as defined in ${CONFIG} parse_hook for hook in ${HOOKS}; do in_array "$hook" "${SKIPHOOKS[@]}" && continue unset MODULES BINARIES FILES SCRIPT build () { error "$hook: no build function..."; } # A hook is considered deprecated if it is a symlink within $INSTDIR. if [[ -L "$INSTDIR/$hook" ]]; then newhook=$(readlink -e "$INSTDIR/$hook") if [[ $newhook && "$INSTDIR/${newhook##*/}" -ef "$newhook" ]]; then newhook=${newhook##*/} warning "Hook '%s' is deprecated. Replace it with '%s' in your config" "$hook" "$newhook" hook=$newhook fi fi if [[ -r "${INSTDIR}/${hook}" ]]; then . "${INSTDIR}/${hook}" msg2 "Parsing hook: [%s]" "$hook" if [[ $(type -t install) = 'function' ]]; then warning "Hook '%s' uses a deprecated 'install' function. This should be renamed 'build'" "$hook" install unset install else build fi parse_hook else die "Hook '$hook' can not be found." fi done # unset errtrace and trap set +E trap ERR if (( ${#ADDED_MODULES[*]} )); then mkdir -p "${MODPATHS[@]%/*}" pushd "${BASEDIR:-/}" >/dev/null cp --parents "${MODPATHS[@]/#$BASEDIR/.}" "$BUILDROOT" popd >/dev/null msg "Generating module dependencies" /sbin/depmod -b "${TMPDIR}/root" "${KERNELVERSION}" rm "$BUILDROOT/lib/modules/$KERNELVERSION"/modules.!(dep.bin|alias.bin|symbols.bin) fi declare -i status=0 declare -a pipesave if [[ "${GENIMG}" ]]; then msg "Creating $COMPRESSION initcpio image: %s" "$GENIMG" [[ "$COMPRESSION" = xz ]] && COMPRESSION_OPTIONS+=" --check=crc32" pushd "$BUILDROOT" >/dev/null find . -print0 | bsdcpio $( (( QUIET )) && echo '--quiet' ) -0oH newc | $COMPRESSION $COMPRESSION_OPTIONS > "$IMGPATH" pipesave=("${PIPESTATUS[@]}") # save immediately popd >/dev/null if (( pipesave[0] )); then errmsg="find reported an error" elif (( pipesave[1] )); then errmsg="bsdcpio reported an error" elif (( pipesave[2] )); then errmsg="$COMPRESSION reported an error" fi if (( builderrors )); then warning "errors were encountered during the build. The image may not be complete." status=1 fi if [[ $errmsg ]]; then error "Image generation FAILED: %s\n" "$errmsg" status=1 else msg "Image generation successful" fi else msg "Dry run complete, use -g IMAGE to generate a real image" fi cleanup $status # vim: set ft=sh ts=4 sw=4 et: