diff options
-rw-r--r-- | init_functions | 175 | ||||
-rwxr-xr-x | test/test_parse_cmdline | 16 |
2 files changed, 125 insertions, 66 deletions
diff --git a/init_functions b/init_functions index 05f4ab0..d5a584e 100644 --- a/init_functions +++ b/init_functions @@ -114,74 +114,133 @@ set_log_option() { done } -parse_cmdline() { - local _w _quoted _lhs _rhs _cmdline - read -r _cmdline - for _w in $_cmdline; do - if [ -z "$_quoted" ]; then - case $_w in - # ignore everything after a # in the commandline - \#*) break ;; - # special cases - rw|ro) rwopt=$_w ;; - fstype) rootfstype=$_w ;; - fsck.mode=*) - case ${_w#*=} in - force) - forcefsck=y - ;; - skip) - fastboot=y - ;; - *) - err "unknown fsck.mode parameter: '${_w#*=}'" - ;; - esac +startswith() { + local word=$1 prefix=$2 + + case $word in + $prefix*) + return 0 + ;; + esac + + return 1 +} + +endswith() { + local word=$1 suffix=$2 + + case $word in + *$suffix) + return 0 + ;; + esac + + return 1 +} + +parse_cmdline_item() { + local key=$1 value=$2 + + case $key in + rw|ro) + rwopt=$key + ;; + fstype) + # The kernel understands 'rootfstype', but mkinitcpio has (without + # documentation) supported 'fstype' instead. Ensure we support both + # for backwards compat, but make fstype legacy. + rootfstype=$value + ;; + fsck.mode) + case $value in + force) + forcefsck=y ;; - rd.*) - case ${_w#rd.} in - debug) - rd_debug=y - ;; - log) - rd_logmask=$(( _rdlog_kmsg | _rdlog_cons )) - ;; - log=*) - set_log_option "${_w#rd.log=}" - ;; - esac + skip) + fastboot=y ;; - # abide by shell variable naming rules - [[:alpha:]_]*=*) - _rhs=${_w#*=} - _lhs=${_w%%=*} - _lhs=${_lhs//[-.]/_} - if [ '"' = "${_rhs:0:1}" ]; then - if [ '"' = "${_rhs:$((${#_rhs}-1))}" ]; then - _rhs="${_rhs:1:$((${#_rhs}-2))}" - else - _rhs=${_rhs:1} - _quoted=1 - continue - fi + *) + err "unknown fsck.mode parameter: '$value'" + ;; + esac + ;; + rd.debug) + rd_debug=y + ;; + rd.log) + if [ -n "$value" ]; then + set_log_option "$value" + else + rd_logmask=$(( _rdlog_kmsg | _rdlog_cons )) + fi + ;; + [![:alpha:]_]*|[[:alpha:]_]*[![:alnum:]_]*) + # invalid shell variable, ignore it + ;; + *) + # valid shell variable + eval "$key"='${value:-y}' + ;; + esac +} + +process_cmdline_param() { + local item_callback=$1 key=$2 value=$3 + + # maybe unquote the value + if startswith "$value" "[\"']" && endswith "$value" "${value:0:1}"; then + value=${value#?} value=${value%?} + fi + + "$item_callback" "$key" "$value" +} + +parse_cmdline() { + local item_callback=${1:-parse_cmdline_item} + local cmdline word quoted key value + + set -f + read -r cmdline + set -- $cmdline + set +f + + for word; do + if [ -n "$quoted" ]; then + value="$value $word" + else + case $word in + *=*) + key=${word%%=*} + value=${word#*=} + + if startswith "$value" "[\"']"; then + quoted=${value:0:1} fi - eval $_lhs=\$_rhs ;; - [[:alpha:]_]*) - _lhs=${_w//[-.]/_} - eval $_lhs=y + '#'*) + break + ;; + *) + key=$word ;; esac - else - if [ '"' = "${_w:$((${#_w}-1))}" ]; then - _rhs="$_rhs ${_w%\"}" - unset _quoted - eval $_lhs=\$_rhs + fi + + if [ -n "$quoted" ]; then + if endswith "$value" "$quoted"; then + unset quoted else - _rhs="$_rhs $_w" + continue fi fi + + process_cmdline_param "$item_callback" "$key" "$value" + unset key value done + + if [ -n "$key" ]; then + process_cmdline_param "$item_callback" "$key" "$value" + fi } fsck_device() { diff --git a/test/test_parse_cmdline b/test/test_parse_cmdline index 9afd9cb..ff855e4 100755 --- a/test/test_parse_cmdline +++ b/test/test_parse_cmdline @@ -130,19 +130,19 @@ test_parse 'foo="bar baz"' \ 'foo' 'bar baz' # single quoting -test_parse --expect-fail "foo='bar'" \ +test_parse "foo='bar'" \ 'foo' 'bar' -test_parse --expect-parse-fail "foo='bar baz'" \ +test_parse "foo='bar baz'" \ 'foo' 'bar baz' # dangling quotes -test_parse --expect-fail 'foo="bar' \ +test_parse 'foo="bar' \ 'foo' '"bar' test_parse 'foo=bar"' \ 'foo' 'bar"' # nested quotes -test_parse --expect-parse-fail "foo='\"bar baz\"' herp='\"de\"rp'" \ +test_parse "foo='\"bar baz\"' herp='\"de\"rp'" \ 'foo' '"bar baz"' \ 'herp' '"de"rp' @@ -174,9 +174,9 @@ test_parse 'foo="bar #baz" parse=this' \ # shell metachars test_parse 'foo=*' \ 'foo' '\*' -test_parse --expect-fail 'Make*' \ +test_parse 'Make*' \ 'Makefile' '' -test_parse --expect-fail '[Makefile]*' \ +test_parse '[Makefile]*' \ 'Makefile' '' \ 'init' '' \ 'functions' '' @@ -184,7 +184,7 @@ test_parse --expect-fail '[Makefile]*' \ # invalid names test_parse 'in-valid=name' test_parse '6foo=bar' -test_parse --expect-parse-fail '"gar bage"' \ +test_parse '"gar bage"' \ 'gar' '' \ 'bage' '' @@ -197,7 +197,7 @@ test_parse 'ro' \ 'ro' '' \ 'rw' '' \ 'rwopt' 'ro' -test_parse --expect-fail 'fstype=btrfs' \ +test_parse 'fstype=btrfs' \ 'rootfstype' 'btrfs' test_parse 'fsck.mode=force' \ 'forcefsck' 'y' \ |