Blob Blame History Raw
From ffa71b4afa3e8865ab4f068f908ff8e05744a6ee Mon Sep 17 00:00:00 2001
From: Harald Hoyer <harald@redhat.com>
Date: Tue, 3 Jul 2012 14:20:51 +0200
Subject: [PATCH] dracut.sh: use getopt to parse arguments

now we can put options and arguments anywhere we like.

e.g.
$ dracut test.img --force
---
 dracut.sh |  233 ++++++++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 169 insertions(+), 64 deletions(-)

diff --git a/dracut.sh b/dracut.sh
index 4a6d5c7..c1be619 100755
--- a/dracut.sh
+++ b/dracut.sh
@@ -24,7 +24,7 @@
 #
 
 # store for logging
-dracut_args="$@"
+dracut_args=( "$@" )
 
 set -o pipefail
 
@@ -36,7 +36,32 @@ usage() {
 
 #                                                       80x25 linebreak here ^
     cat << EOF
-Usage: $0 [OPTION]... <initramfs> <kernel-version>
+Usage: $0 [OPTION]... [<initramfs> [<kernel-version>]]
+
+Version: $DRACUT_VERSION
+
+Creates initial ramdisk images for preloading modules
+
+  -h, --help  Display all options
+
+If a [LIST] has multiple arguments, then you have to put these in quotes.
+
+For example:
+
+    # dracut --add-drivers "module1 module2"  ...
+
+EOF
+}
+
+long_usage() {
+    [[ $dracutbasedir ]] || dracutbasedir=/usr/lib/dracut
+    if [[ -f $dracutbasedir/dracut-version.sh ]]; then
+        . $dracutbasedir/dracut-version.sh
+    fi
+
+#                                                       80x25 linebreak here ^
+    cat << EOF
+Usage: $0 [OPTION]... [<initramfs> [<kernel-version>]]
 
 Version: $DRACUT_VERSION
 
@@ -139,8 +164,11 @@ Creates initial ramdisk images for preloading modules
   --sshkey [SSHKEY]     Add ssh key to initramfs (use with ssh-client module)
 
 If [LIST] has multiple arguments, then you have to put these in quotes.
+
 For example:
-# dracut --add-drivers "module1 module2"  ...
+
+    # dracut --add-drivers "module1 module2"  ...
+
 EOF
 }
 
@@ -151,9 +179,10 @@ EOF
 # example:
 # push stack 1 2 "3 4"
 push() {
+    local _i
     local __stack=$1; shift
-    for i in "$@"; do
-        eval ${__stack}'[${#'${__stack}'[@]}]="$i"'
+    for _i in "$@"; do
+        eval ${__stack}'[${#'${__stack}'[@]}]="$_i"'
     done
 }
 
@@ -169,16 +198,16 @@ push() {
 pop() {
     local __stack=$1; shift
     local __resultvar=$1
-    local myresult;
+    local _value;
     # check for empty stack
     eval '[[ ${#'${__stack}'[@]} -eq 0 ]] && return 1'
 
-    eval myresult='${'${__stack}'[${#'${__stack}'[@]}-1]}'
+    eval _value='${'${__stack}'[${#'${__stack}'[@]}-1]}'
 
     if [[ "$__resultvar" ]]; then
-        eval $__resultvar="'$myresult'"
+        eval $__resultvar="'$_value'"
     else
-        echo "$myresult"
+        echo "$_value"
     fi
     eval unset ${__stack}'[${#'${__stack}'[@]}-1]'
     return 0
@@ -202,52 +231,105 @@ read_arg() {
     fi
 }
 
-# Little helper function for reading args from the commandline to a stack.
-# it automatically handles -a b and -a=b variants, and returns 1 if
-# we need to shift $3.
-push_arg() {
-    # $1 = arg name
-    # $2 = arg value
-    # $3 = arg parameter
-    local rematch='^[^=]*=(.*)$'
-    if [[ $2 =~ $rematch ]]; then
-        push "$1" "${BASH_REMATCH[1]}"
-    else
-        push "$1" "$3"
-        # There is no way to shift our callers args, so
-        # return 1 to indicate they should do it instead.
-        return 1
-    fi
-}
-
 verbosity_mod_l=0
 unset kernel
 unset outfile
 
-while (($# > 0)); do
-    case ${1%%=*} in
-        -a|--add)      push_arg add_dracutmodules_l  "$@" || shift;;
-        --force-add)   push_arg force_add_dracutmodules_l  "$@" || shift;;
-        --add-drivers) push_arg add_drivers_l        "$@" || shift;;
-        --omit-drivers) push_arg omit_drivers_l      "$@" || shift;;
-        -m|--modules)  push_arg dracutmodules_l      "$@" || shift;;
-        -o|--omit)     push_arg omit_dracutmodules_l "$@" || shift;;
-        -d|--drivers)  push_arg drivers_l            "$@" || shift;;
-        --filesystems) push_arg filesystems_l        "$@" || shift;;
-        -I|--install)  push_arg install_items_l      "$@" || shift;;
-        --fwdir)       push_arg fw_dir_l             "$@" || shift;;
-        --libdirs)     push_arg libdirs_l            "$@" || shift;;
-        --fscks)       push_arg fscks_l              "$@" || shift;;
-        --add-fstab)   push_arg add_fstab_l          "$@" || shift;;
-        --mount)       push_arg fstab_lines          "$@" || shift;;
+# Workaround -i, --include taking 2 arguments
+set -- "${@/--include/++include}"
+
+# This prevents any long argument ending with "-i"
+# -i, like --opt-i but I think we can just prevent that
+set -- "${@/%-i/++include}"
+
+TEMP=$(unset POSIXLY_CORRECT; getopt \
+    -o "a:m:o:d:I:k:c:L:fvqlHhM" \
+    --long add: \
+    --long force-add: \
+    --long add-drivers: \
+    --long omit-drivers: \
+    --long modules: \
+    --long omit: \
+    --long drivers: \
+    --long filesystems: \
+    --long install: \
+    --long fwdir: \
+    --long libdirs: \
+    --long fscks: \
+    --long add-fstab: \
+    --long mount: \
+    --long nofscks: \
+    --long kmoddir: \
+    --long conf: \
+    --long confdir: \
+    --long tmpdir: \
+    --long stdlog: \
+    --long compress: \
+    --long prefix: \
+    --long force \
+    --long kernel-only \
+    --long no-kernel \
+    --long strip \
+    --long nostrip \
+    --long hardlink \
+    --long nohardlink \
+    --long noprefix \
+    --long mdadmconf \
+    --long nomdadmconf \
+    --long lvmconf \
+    --long nolvmconf \
+    --long debug \
+    --long profile \
+    --long sshkey: \
+    --long verbose \
+    --long quiet \
+    --long local \
+    --long hostonly \
+    --long no-hostonly \
+    --long fstab \
+    --long help \
+    --long bzip2 \
+    --long lzma \
+    --long xz \
+    --long no-compress \
+    --long gzip \
+    --long list-modules \
+    --long show-modules \
+    --long keep \
+    --long printsize \
+    -- "$@")
+
+if (( $? != 0 )); then
+    usage
+    exit 1
+fi
+
+eval set -- "$TEMP"
+
+while :; do
+    case $1 in
+        -a|--add)      push add_dracutmodules_l  "$2"; shift;;
+        --force-add)   push force_add_dracutmodules_l  "$2"; shift;;
+        --add-drivers) push add_drivers_l        "$2"; shift;;
+        --omit-drivers) push omit_drivers_l      "$2"; shift;;
+        -m|--modules)  push dracutmodules_l      "$2"; shift;;
+        -o|--omit)     push omit_dracutmodules_l "$2"; shift;;
+        -d|--drivers)  push drivers_l            "$2"; shift;;
+        --filesystems) push filesystems_l        "$2"; shift;;
+        -I|--install)  push install_items_l      "$2"; shift;;
+        --fwdir)       push fw_dir_l             "$2"; shift;;
+        --libdirs)     push libdirs_l            "$2"; shift;;
+        --fscks)       push fscks_l              "$2"; shift;;
+        --add-fstab)   push add_fstab_l          "$2"; shift;;
+        --mount)       push fstab_lines          "$2"; shift;;
         --nofscks)     nofscks_l="yes";;
-        -k|--kmoddir)  read_arg drivers_dir_l        "$@" || shift;;
-        -c|--conf)     read_arg conffile             "$@" || shift;;
-        --confdir)     read_arg confdir              "$@" || shift;;
-        --tmpdir)      read_arg tmpdir_l             "$@" || shift;;
-        -L|--stdlog)   read_arg stdloglvl_l          "$@" || shift;;
-        --compress)    read_arg compress_l           "$@" || shift;;
-        --prefix)      read_arg prefix_l             "$@" || shift;;
+        -k|--kmoddir)  drivers_dir_l="$2"; shift;;
+        -c|--conf)     conffile="$2"; shift;;
+        --confdir)     confdir="$2"; shift;;
+        --tmpdir)      tmpdir_l="$2"; shift;;
+        -L|--stdlog)   stdloglvl_l="$2"; shift;;
+        --compress)    compress_l="$2"; shift;;
+        --prefix)      prefix_l="$2"; shift;;
         -f|--force)    force=yes;;
         --kernel-only) kernel_only="yes"; no_kernel="no";;
         --no-kernel)   kernel_only="no"; no_kernel="yes";;
@@ -262,7 +344,7 @@ while (($# > 0)); do
         --nolvmconf)   lvmconf_l="no";;
         --debug)       debug="yes";;
         --profile)     profile="yes";;
-        --sshkey)      read_arg sshkey   "$@" || shift;;
+        --sshkey)      sshkey="$2"; shift;;
         -v|--verbose)  ((verbosity_mod_l++));;
         -q|--quiet)    ((verbosity_mod_l--));;
         -l|--local)
@@ -273,48 +355,67 @@ while (($# > 0)); do
         -H|--hostonly) hostonly_l="yes" ;;
         --no-hostonly) hostonly_l="no" ;;
         --fstab)       use_fstab_l="yes" ;;
-        -h|--help)     usage; exit 1 ;;
+        -h|--help)     long_usage; exit 1 ;;
         -i|--include)  push include_src "$2"
-                       push include_target "$3"
-                       shift 2;;
+                       shift;;
         --bzip2)       compress_l="bzip2";;
         --lzma)        compress_l="lzma";;
         --xz)          compress_l="xz";;
         --no-compress) _no_compress_l="cat";;
         --gzip)        compress_l="gzip";;
-        --list-modules)
-            do_list="yes";
-            ;;
+        --list-modules) do_list="yes";;
         -M|--show-modules)
                        show_modules_l="yes"
                        ;;
         --keep)        keep="yes";;
         --printsize)   printsize="yes";;
-        -*) printf "\nUnknown option: %s\n\n" "$1" >&2; usage; exit 1;;
+
+        --) shift; break;;
+
+        *)  # should not even reach this point
+            printf "\n!Unknown option: '%s'\n\n" "$1" >&2; usage; exit 1;;
+    esac
+    shift
+done
+
+# getopt cannot handle multiple arguments, so just handle "-I,--include"
+# the old fashioned way
+
+while (($# > 0)); do
+    case ${1%%=*} in
+        ++include) push include_src "$2"
+                       push include_target "$3"
+                       shift 2;;
         *)
             if ! [[ ${outfile+x} ]]; then
                 outfile=$1
             elif ! [[ ${kernel+x} ]]; then
                 kernel=$1
             else
-                echo "Unknown argument: $1"
+                printf "\nUnknown arguments: %s\n\n" "$*" >&2
                 usage; exit 1;
             fi
             ;;
     esac
     shift
 done
+
 if ! [[ $kernel ]]; then
     kernel=$(uname -r)
 fi
-[[ $outfile ]] || outfile="/boot/initramfs-$kernel.img"
+
+if ! [[ $outfile ]]; then
+    outfile="/boot/initramfs-$kernel.img"
+fi
 
 for i in /usr/sbin /sbin /usr/bin /bin; do
     rl=$i
     if [ -L "$i" ]; then
         rl=$(readlink -f $i)
     fi
-    NPATH+=":$rl"
+    if [[ "$NPATH" != "*:$rl*" ]] ; then
+        NPATH+=":$rl"
+    fi
 done
 export PATH="${NPATH#:}"
 unset NPATH
@@ -536,8 +637,12 @@ done
 omit_drivers="${omit_drivers_corrected%|}"
 unset omit_drivers_corrected
 
-
-ddebug "Executing $0 $dracut_args"
+# prepare args for logging
+for ((i=0; i < ${#dracut_args[@]}; i++)); do
+    strstr "${dracut_args[$i]}" " " && \
+        dracut_args[$i]="\"${dracut_args[$i]}\""
+done
+ddebug "Executing: $0 ${dracut_args[@]}"
 
 [[ $do_list = yes ]] && {
     for mod in $dracutbasedir/modules.d/*; do
@@ -573,7 +678,7 @@ if [[ ! -d "$outdir" ]]; then
     dfatal "Can't write $outfile: Directory $outdir does not exist."
     exit 1
 elif [[ ! -w "$outdir" ]]; then
-    dfatal "No permission to write $outdir."
+    dfatal "No permission to write to $outdir."
     exit 1
 elif [[ -f "$outfile" && ! -w "$outfile" ]]; then
     dfatal "No permission to write $outfile."