#!/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 comarpisons
#
#TODO trap and remove FILELIST


# Settings
BASEDIR=""
FILELIST="$(mktemp /tmp/.tmpfilelist.XXXX)"
KERNELVERSION="$(uname -r)"
FUNCTIONS="functions"
CONFIG="mkinitcpio.conf"
HOOKDIR="hooks"
INSTDIR="install"
MODULE_FILE=""
SAVELIST=""
GENIMG=""
APPEND=""
QUIET="y"
SHOW_AUTOMODS="n"

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 "  -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."
    exit 1
}

while getopts ':c:k:s:b:g:a:vH:LMh' arg; do
    if [ "${OPTARG:0:1}" = "-" ]; 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" ;;
        v) QUIET="n" ;;
        H) source "${INSTDIR}/${OPTARG}";
           echo "Help for hook '${OPTARG}':"
           help
           exit 0 ;;
        L) echo "Available hooks: " 
           for h in ${INSTDIR}/*; do
               echo "   $(basename ${h})"
           done
           exit 0 ;;
        M) SHOW_AUTOMODS="y" ;;
        h|?) usage ;;
        :) echo "${OPTARG} requires a value..."; 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}"

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
    if [ "x${SAVELIST}" == "x" ]; then
        rm ${FILELIST}
        touch "${FILELIST}"
    else
        echo "destination file list '${FILELIST}' exists - remove before running"
        exit 1
    fi
elif [ -f "${DESTIMG}" ]; then
    echo "destination image '${DESTIMG}' exists - remove before running"
    exit 1
else
    touch "${FILELIST}"
fi

source "${FUNCTIONS}"

if [ "${SHOW_AUTOMODS}" = "y" ]; then
    echo "Modules autodetected:"
    source "${INSTDIR}/autodetect"
    install
    cat "${MODULE_FILE}"
    exit 0
fi

echo ":: Begin build"
#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..."; }
    if grep "install" "${INSTDIR}/${hook}" >/dev/null 2>&1; then
        source "${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 dependancies"
    for mod in $(grep "file /lib/modules/${KERNELVERSION}" ${FILELIST} | cut -d' ' -f2); do
        dir=$(dirname "${mod}")
        mkdir -p "/tmp/${dir}"
        cp "${BASEDIR}${mod}" "/tmp/${dir}/"
    done
    depmod -b /tmp ${KERNELVERSION}
    add_file "/tmp/lib/modules/${KERNELVERSION}/modules.dep"     "/lib/modules/${KERNELVERSION}/modules.dep"
    add_file "/tmp/lib/modules/${KERNELVERSION}/modules.alias"   "/lib/modules/${KERNELVERSION}/modules.alias"
    add_file "/tmp/lib/modules/${KERNELVERSION}/modules.symbols" "/lib/modules/${KERNELVERSION}/modules.symbols"
fi

status=0
if [ "x$GENIMG" != "x" ]; then
    echo -n ":: Generating image '${GENIMG}'..."
    if ! gen_init_cpio ${FILELIST} | gzip -9 > "${GENIMG}"; then
        echo "FAILED"
        status=1
    else
        echo "SUCCESS"
        status=0
    fi

    if [ "x${SAVELIST}" == "x" ]; then
        rm ${FILELIST}
    fi
else
    echo ":: Dry run complete, use -g IMAGE to generate a real image"
fi

#cleanup - we should probably trap this...
isempty () { [ $(ls -1 "${1}" | wc -l) -eq 0 ]; }
[ -e "${MODULE_FILE}" ] && rm "${MODULE_FILE}"
if [ -d /tmp/lib/modules/${KERNELVERSION} ]; then
    rm -rf /tmp/lib/modules/${KERNELVERSION}
    isempty /tmp/lib/modules && rm -rf /tmp/lib/modules
    isempty /tmp/lib && rm -rf /tmp/lib
fi
exit $status
#vim:set ft=sh ts=4 sw=4 noet:
