#!/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 # # Settings TMPDIR="$(mktemp -d /tmp/mkinitcpio.XXXXXX)" BASEDIR="" FILELIST="${TMPDIR}/filelist" MESSAGEFILE="${TMPDIR}/message" KERNELVERSION="$(uname -r)" FUNCTIONS="functions" CONFIG="mkinitcpio.conf" HOOKDIR="hooks" INSTDIR="install" MODULE_FILE="" SAVELIST="" GENIMG="" APPEND="" PRESET="" MESSAGE="" SKIPHOOKS=() PRESETDIR="mkinitcpio.d" QUIET="y" SHOW_AUTOMODS="n" COMPRESSION="gzip" COMPRESSION_OPTIONS="" if [ ! $UID ]; then UID=$(id -u) fi # Add /{,usr}/sbin to path # works around undetected problems like in #8448 PATH="${PATH}:/sbin:/usr/sbin" APPNAME=$(basename "${0}") usage () { echo "${APPNAME}: usage" echo " -c CONFIG Use CONFIG file. default: /etc/mkinitcpio.conf" echo " -k KERNELVERSION Use KERNELVERSION. default: $(uname -r)" echo " -s NAME Save filelist. default: no" echo " -b BASEDIR Use BASEDIR. default: /" echo " -g IMAGE Generate a cpio image as IMAGE. default: no" echo " -a NAME Append to an existing filelist. default: no" echo " -p PRESET Build specified preset." echo " -m MESSAGE Print MESSAGE before passing control to init." echo " -S SKIPHOOKS Skip SKIPHOOKS (comma-separated) when building the image." echo " -v Verbose output. Default: no" echo " -M Display modules found via autodetection." echo " -L List all available hooks." echo " -H HOOKNAME Output help for hook 'HOOKNAME'." echo " -h This message." cleanup exit 1 } cleanup () { [ -n "${TMPDIR}" -a -d "${TMPDIR}" ] && rm -rf ${TMPDIR} } sighandler() { cleanup exit 1 } trap sighandler TERM INT while getopts ':c:k:s:b:g:a:p:m:vH:LMhS:' arg; do if [ "${OPTARG#-}" != "${OPTARG}" ]; then echo "error: optional argument to '-${arg}' begins with a '-'" echo " you probably don't want this....aborting." usage fi case "${arg}" in c) CONFIG="${OPTARG}" ;; k) KERNELVERSION="${OPTARG}" ;; s) SAVELIST="y"; FILELIST="${OPTARG}" ;; b) BASEDIR="${OPTARG}" ;; g) GENIMG="${OPTARG}" ;; a) APPEND="y"; SAVELIST="y"; FILELIST="${OPTARG}" ;; p) PRESET="${OPTARG}" ;; m) MESSAGE="${OPTARG}" ;; v) QUIET="n" ;; S) OLDIFS=${IFS} IFS=, SKIPHOOKS=(${OPTARG}) IFS=${OLDIFS} unset OLDIFS ;; H) . "${INSTDIR}/${OPTARG}"; echo "Help for hook '${OPTARG}':" help cleanup exit 0 ;; L) echo "Available hooks: " for h in ${INSTDIR}/*; do echo " $(basename ${h})" done cleanup exit 0 ;; M) SHOW_AUTOMODS="y" ;; h|?) usage ;; :) echo "${OPTARG} requires a value..."; usage ;; *) echo "invalid argument '${arg}'"; usage ;; esac done shift $((${OPTIND} - 1)) # use preset $PRESET if [ -n "${PRESET}" ]; then if [ -f "${PRESETDIR}/${PRESET}.preset" ]; then # Use -b, -m and -v options specified earlier PRESET_MKOPTS="${0}" [ -n "${BASEDIR}" ] && PRESET_MKOPTS="${PRESET_MKOPTS} -b ${BASEDIR}" [ -n "${MESSAGE}" ] && PRESET_MKOPTS="${PRESET_MKOPTS} -m \"${MESSAGE}\"" [ "${QUIET}" = "n" ] && PRESET_MKOPTS="${PRESET_MKOPTS} -v" # Build all images . ${PRESETDIR}/${PRESET}.preset for p in ${PRESETS[@]}; do echo "==> Building image \"${p}\"" PRESET_CMD="${PRESET_MKOPTS}" eval "PRESET_KVER=\"\${${p}_kver}\"" [ -z "${PRESET_KVER}" ] && PRESET_KVER="${ALL_kver}" eval "PRESET_CONFIG=\"\${${p}_config}\"" [ -z "${PRESET_CONFIG}" ] && PRESET_CONFIG="${ALL_config}" eval "PRESET_IMAGE=\"\${${p}_image}\"" eval "PRESET_OPTIONS=\"\${${p}_options}\"" if [ -n "${PRESET_KVER}" ]; then PRESET_CMD="${PRESET_CMD} -k ${PRESET_KVER}" else echo "==> No kernel version specified. Skipping image \"${p}\"." continue fi if [ -n "${PRESET_CONFIG}" ]; then PRESET_CMD="${PRESET_CMD} -c ${PRESET_CONFIG}" else echo "==> No configuration file specified. Skipping image \"${p}\"." continue fi if [ -n "${PRESET_IMAGE}" ]; then PRESET_CMD="${PRESET_CMD} -g ${PRESET_IMAGE}" else echo "==> No image file specified. Skipping image \"${p}\"." continue fi if [ -n "${PRESET_OPTIONS}" ]; then PRESET_CMD="${PRESET_CMD} ${PRESET_OPTIONS}" fi echo "==> Running command: ${PRESET_CMD}" if eval ${PRESET_CMD}; then echo "==> SUCCESS" else echo "==> FAIL" fi done cleanup exit 0 else echo "Preset ${PRESET} does not exist. Exiting." cleanup exit 1 fi fi # remove trailing / from BASEDIR BASEDIR="${BASEDIR%/}" MODULEDIR="${BASEDIR}/lib/modules/${KERNELVERSION}" if [ -n "${BASEDIR}" ]; then if [ "${BASEDIR}" = "${BASEDIR#/}" ]; then BASEDIR="$(pwd)/${BASEDIR}" elif [ ! -d "${BASEDIR}" ]; then echo "base directory '${BASEDIR}' does not exist or is not a directory" cleanup exit 1 fi fi if [ ! -f "${CONFIG}" ]; then echo "config file '${CONFIG}' cannot be found, aborting..." cleanup exit 1 fi . "${CONFIG}" if [ -f "${FILELIST}" -a -z "${APPEND}" ]; then if [ -z "${SAVELIST}" ]; then rm ${FILELIST} touch "${FILELIST}" else echo "destination file list '${FILELIST}' exists - remove before running" cleanup exit 1 fi else touch "${FILELIST}" fi BASEDIR=$(echo ${BASEDIR} | tr -s /) MODULEDIR=$(echo ${MODULEDIR} | tr -s /) . "${FUNCTIONS}" if [ "${SHOW_AUTOMODS}" = "y" ]; then echo "Modules autodetected:" . "${INSTDIR}/autodetect" install cat "${MODULE_FILE}" cleanup exit 0 fi if [ -z "${GENIMG}" ]; then echo ":: Begin dry run" else echo ":: Begin build" fi #parse 'global' hook, as defined in ${CONFIG} parse_hook for hook in ${HOOKS}; do in_array ${hook} ${SKIPHOOKS[@]} && continue unset MODULES unset BINARIES unset FILES install () { msg "${hook}: no install function..."; } # Deprecation check # A hook is considered deprecated if it is a symlink # within $INSTDIR. if [ -h "${INSTDIR}/${hook}" ]; then newhook="$(readlink -ne "${INSTDIR}/${hook}")" if [ -n "${newhook}" -a "${INSTDIR}/$(get_basename ${newhook})" -ef "${newhook}" ]; then newhook="$(get_basename ${newhook})" echo " -------------------------------------------------------------------" echo " WARNING: Hook \"${hook}\" is deprecated." echo " Replace it with \"${newhook}\" in your configuration file." echo " -------------------------------------------------------------------" hook="${newhook}" fi fi if grep -q "install" "${INSTDIR}/${hook}"; then . "${INSTDIR}/${hook}" echo ":: Parsing hook [${hook}]" install parse_hook else die "Hook '${hook}' can not be found." fi done if [ "${HAS_MODULES}" = "y" ]; then echo ":: Generating module dependencies" # unfortuate name collision between a function and utility program unset install for mod in $(grep "file /lib/modules/${KERNELVERSION}" ${FILELIST} | cut -d' ' -f2); do install -m 644 -D "${BASEDIR}${mod}" "${TMPDIR}${mod}" done /sbin/depmod -b ${TMPDIR} ${KERNELVERSION} add_file "${TMPDIR}/lib/modules/${KERNELVERSION}/modules.dep" "/lib/modules/${KERNELVERSION}/modules.dep" add_file "${TMPDIR}/lib/modules/${KERNELVERSION}/modules.alias" "/lib/modules/${KERNELVERSION}/modules.alias" add_file "${TMPDIR}/lib/modules/${KERNELVERSION}/modules.symbols" "/lib/modules/${KERNELVERSION}/modules.symbols" fi status=0 if [ -n "${GENIMG}" ]; then echo -n ":: Generating image '${GENIMG}'..." shopt -s -o pipefail [ ${COMPRESSION} = "xz" ] && COMPRESSION_OPTIONS="${COMPRESSION_OPTIONS} --check=crc32" if ! /sbin/gen_init_cpio ${FILELIST} | ${COMPRESSION} ${COMPRESSION_OPTIONS} > "${GENIMG}"; then echo "FAILED" status=1 else echo "SUCCESS" status=0 fi if [ -z "${SAVELIST}" ]; then rm ${FILELIST} fi else echo ":: Dry run complete, use -g IMAGE to generate a real image" fi cleanup exit ${status} #vim:set ft=sh ts=4 sw=4 noet: