[arch-projects] [mkinitcpio][PATCH 08/12] use bsdcpio to create images

Dave Reisner d at falconindy.com
Thu Jun 9 16:10:02 EDT 2011


This is a departure from using gen_init_cpio, which proved to be a huge
bottleneck in performance. Tests for existance change from being a call
to grep, to a simple shell test.

In the process, we have to modify the behavior of the -s option, and we
lose the -a option.

Signed-off-by: Dave Reisner <d at falconindy.com>
---
 functions        |   41 +++++++++++++----------------
 mkinitcpio       |   74 +++++++++++++++++++++++++++--------------------------
 mkinitcpio.5.txt |    7 +---
 3 files changed, 58 insertions(+), 64 deletions(-)

diff --git a/functions b/functions
index 03be8cc..666aeec 100644
--- a/functions
+++ b/functions
@@ -79,12 +79,12 @@ checked_modules ()
 
 add_full_dir ()
 {
-    if [ -n "${1}" -a -d "${1}" ]; then
-        for f in ${1}/*; do
-            if [ -d "${f}" ]; then
-                add_full_dir "${f}"
+    if [[ -n $1 && -d $1 ]]; then
+        for f in "$1"/*; do
+            if [[ -d "$f" ]]; then
+                add_full_dir "$f"
             else
-                add_file "${f}"
+                add_file "$f"
             fi
         done
     fi
@@ -92,28 +92,23 @@ add_full_dir ()
 
 add_dir ()
 {
-    #skip root directory and "." for relative directories... i.e. /foo/bar/./blah
-    if [ -n "${1}" -a "${1}" != "/" -a "${1}" != "." ]; then
-        if ! grep -q "dir ${1} " "${FILELIST}"; then
-            add_dir $(get_dirname "${1}")
-            msg "  adding  dir ${1}"
-            echo "dir ${1} 755 0 0" >> "${FILELIST}"
-        fi
+    if [[ ! -e "$TMPDIR/root/$1" ]]; then
+        msg "  adding  dir ${1}"
+        command install -dm755 "$TMPDIR/root/$1"
     fi
 }
 
-# what the hell does this do?
 add_symlink ()
 {
     local fil dest dir
-    if [ -h ${1} ]; then
+    if [[ -h $1 ]]; then
         fil="${1##$BASEDIR}"
         dest="${2##$BASEDIR}"
         add_dir $(get_dirname "${dest}")
         add_dir $(get_dirname "${fil}")
-        if ! grep -q "slink ${fil} " "${FILELIST}"; then
+        if [[ ! -e "$TMPDIR/root/$dest" ]]; then
             msg "  adding link ${fil} -> ${dest}"
-            echo "slink ${fil} ${dest} $(stat -c '%a' ${1}) 0 0" >> "${FILELIST}"
+            ln -s "$dest" "$TMPDIR/root/$fil"
         fi
     fi
     #fail quietly
@@ -122,27 +117,27 @@ add_symlink ()
 add_file ()
 {
     local fil lnk dir dest
-    if [ -f "${1}" ]; then
-        fil="${1}"
+    if [[ -f "$1" ]]; then
+        fil=$1
         lnk=$(readlink -f "${fil}")
-        if [ -n "${lnk}" ]; then
+        if [[ ${lnk} ]]; then
             add_symlink "${fil}" "${lnk}"
             fil="${lnk}"
         fi
         if [[ $2 ]]; then
-            dest="${2}"
+            dest=$2
         else
             dest="${fil##$BASEDIR}"
-            if [ "${dest}" = "${dest#/}" ]; then
+            if [[ "${dest}" = "${dest#/}" ]]; then
                 dest="/${dest}"
             fi
         fi
 
         add_dir $(get_dirname "${dest}")
 
-        if ! grep -q "file ${dest} " "${FILELIST}"; then
+        if [[ ! -e $TMPDIR/root/$dest ]]; then
             msg "  adding file ${dest}"
-            echo "file ${dest} ${fil} $(stat -c '%a' ${fil}) 0 0" >> "${FILELIST}"
+            command install -Dm$(stat -c '%a' "$fil") "$fil" "$TMPDIR/root/$dest"
         fi
     else
         err "file '${1}' does not exist"
diff --git a/mkinitcpio b/mkinitcpio
index ac9522b..c40fb2d 100755
--- a/mkinitcpio
+++ b/mkinitcpio
@@ -10,11 +10,11 @@
 #   in case of embedded spaces, quote all path names and string comparisons
 #
 
+shopt -s extglob
 
 # Settings
 TMPDIR="$(mktemp -d /tmp/mkinitcpio.XXXXXX)"
 BASEDIR=""
-FILELIST="${TMPDIR}/filelist"
 MESSAGEFILE="${TMPDIR}/message"
 KERNELVERSION="$(uname -r)"
 FUNCTIONS="functions"
@@ -24,7 +24,6 @@ INSTDIR="install"
 MODULE_FILE=""
 SAVELIST=""
 GENIMG=""
-APPEND=""
 PRESET=""
 MESSAGE=""
 SKIPHOOKS=()
@@ -49,10 +48,9 @@ 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 "  -s               Save build directory. 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."
@@ -67,7 +65,11 @@ usage ()
 
 cleanup ()
 {
-    [ -n "${TMPDIR}" -a -d "${TMPDIR}" ] && rm -rf ${TMPDIR}
+    if [[ $SAVELIST ]]; then
+        echo ":: build directory saved in $TMPDIR"
+    else
+        rm -rf ${TMPDIR}
+    fi
 }
 
 sighandler() {
@@ -77,7 +79,7 @@ sighandler() {
 
 trap sighandler TERM INT
 
-while getopts ':c:k:s:b:g:a:p:m:vH:LMhS:' arg; do
+while getopts ':c:k:sb:g: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."
@@ -86,10 +88,9 @@ while getopts ':c:k:s:b:g:a:p:m:vH:LMhS:' arg; do
     case "${arg}" in
         c) CONFIG="${OPTARG}" ;;
         k) KERNELVERSION="${OPTARG}" ;;
-        s) SAVELIST="y"; FILELIST="${OPTARG}" ;;
+        s) SAVELIST="y"; ;;
         b) BASEDIR="${OPTARG}" ;;
         g) GENIMG="${OPTARG}" ;;
-        a) APPEND="y"; SAVELIST="y"; FILELIST="${OPTARG}" ;;
         p) PRESET="${OPTARG}" ;;
         m) MESSAGE="${OPTARG}" ;;
         v) QUIET="n" ;;
@@ -185,6 +186,15 @@ BASEDIR="${BASEDIR%/}"
 
 MODULEDIR="${BASEDIR}/lib/modules/${KERNELVERSION}"
 
+if [[ $GENIMG ]]; then
+  IMGPATH=$(readlink -f "$GENIMG")
+  if [[ -z $IMGPATH || ! -w ${IMGPATH%/*} ]]; then
+    echo "error: unable to write to path: '$GENIMG'"
+    cleanup
+    exit 1
+  fi
+fi
+
 if [ -n "${BASEDIR}" ]; then
     if [ "${BASEDIR}" = "${BASEDIR#/}" ]; then
         BASEDIR="$(pwd)/${BASEDIR}"
@@ -202,19 +212,6 @@ if [ ! -f "${CONFIG}" ]; then
 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 /)
 
@@ -276,31 +273,36 @@ done
 
 if (( ${#ADDED_MODULES[*]} )); then
     echo ":: Generating module dependencies"
-    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}
-    for dmfile in modules.{dep,alias,symbols}.bin; do
-        add_file "${TMPDIR}/lib/modules/${KERNELVERSION}/$dmfile" "/lib/modules/${KERNELVERSION}/$dmfile"
-    done
+    /sbin/depmod -b "${TMPDIR}/root" "${KERNELVERSION}"
+    rm "$TMPDIR/root/lib/modules/$KERNELVERSION"/modules.!(dep.bin|alias.bin|symbols.bin)
 fi
 
-status=0
+declare -i status=0
+declare -a pipesave
 if [ -n "${GENIMG}" ]; then
     echo ":: 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 ":: Image generation FAILED"
+
+    pushd "$TMPDIR/root" >/dev/null
+    find . -print0 | bsdcpio -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 [[ $errmsg ]]; then
+        echo ":: Image generation FAILED ($errmsg)"
         status=1
     else
         echo ":: Image generation successful"
-        status=0
     fi
 
-    if [ -z "${SAVELIST}" ]; then
-        rm ${FILELIST}
-    fi
 else
     echo ":: Dry run complete, use -g IMAGE to generate a real image"
 fi
diff --git a/mkinitcpio.5.txt b/mkinitcpio.5.txt
index 1c095dc..3d0fdc9 100644
--- a/mkinitcpio.5.txt
+++ b/mkinitcpio.5.txt
@@ -21,8 +21,8 @@ Options
 *-k* 'kernelversion'::
 	Use 'kernelversion'. Default is the current running kernel.
 
-*-s* 'filelist'::
-	Saves a list of all the files in the initial ramdisk in 'filelist'. Default: no; This means the filelist will not be retained if this option isn't specified. Useful for debugging purposes.
+*-s*::
+	Saves the build directory for the initial ramdisk. Default: no; This means the directory will not be retained if this option isn't specified. Useful for debugging purposes.
 
 *-b* 'basedir'::
 	Use 'basedir' as a starting point for gathering information about the currently running system. Default: /.
@@ -30,9 +30,6 @@ Options
 *-g* 'filename'::
 	Generate a CPIO image as 'filename'. Default: no; this means nothing will be written to the filesystem unless this option is specified.
 
-*-a* 'filelist'::
-	Append to an existing 'filelist'. Default no.
-
 *-p* 'preset'::
 	Build initial ramdisk according to specified 'preset'. Presets are found in /etc/mkinitcpio.d
 
-- 
1.7.5.4



More information about the arch-projects mailing list