summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Reisner <dreisner@archlinux.org>2016-07-06 13:22:16 +0200
committerDave Reisner <dreisner@archlinux.org>2016-07-07 14:30:59 +0200
commitb9308a5296fc0dc8da78cd6f02a5af9c38f0a044 (patch)
treeecfa5b08409b65424cdcf4a063bc0d33fecbd5c2
parenta089c8622708d5249aa7830590464fb29dc799a4 (diff)
downloadmkinitcpio-b9308a5296fc0dc8da78cd6f02a5af9c38f0a044.tar.gz
mkinitcpio-b9308a5296fc0dc8da78cd6f02a5af9c38f0a044.tar.xz
refactor parse_cmdline into something more readable
This refactors parse_cmdline into a few chunks of code, mainly to separate the work of parsing from the handling of the actual parsed parameters. By default, parse_cmdline_item is used as the callback for handling the parameters, but this could be overriden by other code sourcing init_functions if desirable. Our test harness passes more tests, but we leave behind some expected failures to describe the cases where it still fails. Fortunately I've not yet been able to find any cases which warrant --expect-parse-fail.
-rw-r--r--init_functions175
-rwxr-xr-xtest/test_parse_cmdline16
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' \