#!/bin/sh # 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 # the klibc shell or even 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 "x${var}" = "x" to test for nulls/empty strings # incase of embedded spaces, quote all path names and string comaprissons # # TODO # sudo cp img /boot HOOKDIR="hooks" # Settings BASEDIR="" KERNELVERSION="$(uname -r)" CONFIG="mkinitcpio.conf" SAVELIST="" GENIMG="" APPEND="" usage () { echo "TODO usage..." exit 1 } while getopts 'c:k:sb:g:a' arg; do case "$arg" in c) CONFIG="$OPTARG" ;; k) KERNELVERSION="$OPTARG" ;; s) SAVELIST="y" ;; b) BASEDIR="$OPTARG" ;; g) GENIMG="$OPTARG" ;; a) APPEND="y" ;; ?) usage ;; *) echo "invalid argument '$arg'"; usage ;; esac done shift $(($OPTIND - 1)) # append a trailing / if needed if [ "${BASEDIR:${#BASEDIR}}" == "/" ]; then BASEDIR="${BASEDIR:0:${#BASEDIR}-1}" fi MODULEDIR="${BASEDIR}/lib/modules/${KERNELVERSION}" FILELIST=${1:-"initcpio.filelist"} if [ "x${BASEDIR}" != "x" ]; then if [ "${BASEDIR:0:1}" != "/" ]; then echo "base directory '${BASEDIR}' must be an absolute path" exit 1 elif [ ! -d "${BASEDIR}" ]; then echo "base directory '${BASEDIR}' does not exist or is not a directory" exit 1 fi fi if [ ! -f "${CONFIG}" ]; then echo "config file '${CONFIG}' cannot be found, aborting..." exit 1 fi source "${CONFIG}" if [ -f "${FILELIST}" -a "x${APPEND}" == "x" ]; then echo "destination file list '${FILELIST}' exists - remove before running" exit 1 elif [ -f "${DESTIMG}" ]; then echo "destination image '${DESTIMG}' exists - remove before running" exit 1 else touch "${FILELIST}" fi # this function is a helper for the *-auto install functions auto_modules () { aliases=$(find /sys/devices/ -name modalias -exec cat {} \;) modprobe --show-depends -a $aliases 2>/dev/null |\ sed "s|insmod \(.*\)|\1|" | sort -u } add_dir() { local dir dir="${1}" if [ "x${dir}" != "x" -a "${dir}" != "/" ]; then dir="${dir}" #this got stripped off above... put it back if ! grep "dir ${dir} " "${FILELIST}" 2>&1 > /dev/null; then add_dir $(dirname ${dir}) echo " adding dir ${dir}" echo "dir ${dir} 755 0 0" >> "${FILELIST}" fi fi } add_symlink () { local fil dest dir if [ -L ${1} ]; then fil="${1}" dest="${fil##$BASEDIR}" dir=$(dirname "${dest}") add_dir "${dir}" if ! grep "slink ${fil} " "${FILELIST}" 2>&1 > /dev/null; then echo " adding symlink ${dest}" echo "slink ${dest} ${fil} $(stat -c '%a %u %g' ${fil})" >> "${FILELIST}" fi fi } add_file () { local fil lnk dir dest if [ -e "${1}" ]; then fil="${1}" lnk=$(readlink -f "${fil}") if [ -n "${lnk}" ]; then add_symlink "${fil}" fil="${lnk}" fi if [ $# -eq 2 ]; then dest="${2}" else dest="${fil##$BASEDIR}" fi dir=$(dirname "${dest}") add_dir "${dir}" if ! grep "file ${fil} " "${FILELIST}" 2>&1 > /dev/null; then echo " adding file ${dest}" echo "file ${dest} ${fil} $(stat -c '%a %u %g' ${fil})" >> "${FILELIST}" fi fi } HAS_MODULES="n" add_module() { local fil path mod deps #cleanup - remove .ko, replace - and _ with [-_] to match either fil=$(basename "${1}" | sed -e "s|[-_]|\[-_\]|g" -e "s|\.ko$||g") for path in $(find "${MODULEDIR}" -type f -name "${fil}.ko"); do for mod in $(modinfo -F depends "${path}" | tr ',' ' '); do if [ "x${mod}" != "x" ]; then add_module "${mod}" HAS_MODULES="y" fi done add_file "${path}" done } add_binary() { local bin type lib bin=$(which "${1}") if [ $? -ne 0 ]; then bin="${1}" fi if [ ! -f "${bin}" ]; then echo "add_binary: '${bin}' is not a file" return 1 fi if [ $? -eq 0 ]; then type=$(file -b "${bin}") case "${type}" in *script*) msg " adding '${type}' script, ensure proper interp exists..." add_file "${bin}" ;; *executable*) add_file "${bin}" #note, this will also handle 'not a dynamic executable' spit out by # static binaries... the deps will produce nothing for lib in $(ldd ${bin} 2>/dev/null | sed "s|.*=>\(.*\)|\1|"); do if [ "x${lib}" != "x" ]; then #remove TLS libraries notls=$(echo ${lib} | sed 's|/lib/tls.*/\(lib.*\)|/lib/\1|') [ -e "${notls}" ] && lib="${notls}" [ -f "${lib}" ] && add_file "${lib}" fi done ;; *) echo "add_binary: unknown type '${type}' for binary '${bin}'" return 1 ;; esac fi } function parse_hook() { local mod bin fil for mod in $MODULES; do if [ "x${mod}" != "x" ]; then add_module "${mod}" fi done for bin in $BINARIES; do if [ "x${bin}" != "x" ]; then add_binary "${bin}" fi done for fil in $FILES; do if [ "x${fil}" != "x" ]; then add_file "${fil}" fi done } #parse 'global' hook, as defined in ${CONFIG} parse_hook for hook in $HOOKS; do unset MODULES unset BINARIES unset FILES install () { msg "$hook: no install function..."; } source "${HOOKDIR}/${hook}" install parse_hook #quick test to check for existance... need a better way... if grep "run_hook" "${HOOKDIR}/${hook}" 2>&1>/dev/null; then add_file "${HOOKDIR}/${hook}" "/hooks/${hook}" fi done if [ "${HAS_MODULES}" == "y" ]; then add_file "${MODULEDIR}/modules.dep" add_file "${MODULEDIR}/modules.alias" add_file "${MODULEDIR}/modules.symbols" fi if [ "x$GENIMG" != "x" ]; then gen_init_cpio ${FILELIST} | gzip -9 > "${GENIMG}" if [ "x${SAVELIST}" == "x" ]; then rm ${FILELIST} fi fi