[arch-projects] [initscripts][PATCH 6/7] functions: implement a environment file parser

Dave Reisner d at falconindy.com
Sun Nov 6 19:27:40 EST 2011


This adds a 'parse_envfile' function that reads files such as
/etc/locale.conf and /etc/vconsole.conf without sourcing them as bash
logic. Several benefits are realized from this:

- Impossible to execute arbitrary code
- Bad syntax won't prevent the entire file from being read
- Possible to limit what variables are allowed

Signed-off-by: Dave Reisner <dreisner at archlinux.org>
---
 functions  |   50 ++++++++++++++++++++++++++++++++++++++++++++++++--
 rc.sysinit |    4 ++--
 2 files changed, 50 insertions(+), 4 deletions(-)

diff --git a/functions b/functions
index ce664ed..387f2af 100644
--- a/functions
+++ b/functions
@@ -9,6 +9,8 @@ localevars=(LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY
             LC_MESSAGES LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE
             LC_MEASUREMENT LC_IDENTIFICATION LC_ALL)
 
+vconsolevars=(KEYMAP KEYMAP_TOGGLE FONT FONT_MAP FONT_UNIMAP)
+
 if [[ $1 == "start" ]]; then
 	if [[ $STARTING ]]; then
 		echo "A daemon is starting another daemon, this is unlikely to work as intended."
@@ -70,12 +72,56 @@ unset TZ
 # sanitize the locale settins
 unset "${localevars[@]}"
 
+parse_envfile() {
+	local file=$1 validkeys=${@:2} ret=0 lineno=0 key= val=
+
+	if [[ -z $file ]]; then
+		printf "error: no environment file specified\n"
+		return 1
+	fi
+
+	if [[ ! -f $file ]]; then
+		printf "error: cannot parse \`%s': No such file or directory\n" "$file"
+		return 1
+	fi
+
+	if [[ ! -r $file ]]; then
+		printf "error: cannot read \`%s': Permission denied\n" "$file"
+		return 1
+	fi
+
+	while IFS='=' read -r key val; do
+		(( ++lineno ))
+
+		# trim whitespace, avoiding usage of a tempfile
+		key=$(echo "$1" | { read -r val; echo "$val"; })
+		val=$(echo "$1" | { read -r val; echo "$val"; })
+
+		[[ $key ]] || continue
+
+		if [[ -z $val ]]; then
+			printf "error: found key \`%s' without value on line %s of %s\n" \
+					"$key" "$lineno" "$file"
+			(( ++ret ))
+			continue
+		fi
+
+		# ignore invalid keys if we have a list of valid ones
+		if (( ${#validkeys[*]} )); then
+			in_array "$key" "${validkeys[@]}" || continue
+		fi
+
+		export "$key=$val" || (( ++ret ))
+	done <"$file"
+
+	return $ret
+}
+
 if [[ $DAEMON_LOCALE = [yY][eE][sS] ]]; then
 	LANG=${LOCALE:-C}
 	if [[ -r /etc/locale.conf ]]; then
-		. /etc/locale.conf
+		parse_envfile /etc/locale.conf "${localevars[@]}"
 	fi
-	export "${localevars[@]}"
 else
 	export LANG=C
 fi
diff --git a/rc.sysinit b/rc.sysinit
index eb66935..654a409 100755
--- a/rc.sysinit
+++ b/rc.sysinit
@@ -237,7 +237,7 @@ if [[ $HOSTNAME ]]; then
 fi
 
 if [[ -s /etc/locale.conf ]]; then
-	. /etc/locale.conf
+	parse_envfile /etc/locale.conf "LANG"
 	[[ $LANG ]] && LOCALE=$LANG
 fi
 if [[ ${LOCALE,,} =~ utf ]]; then
@@ -263,7 +263,7 @@ else
 fi
 
 if [[ -s /etc/vconsole.conf ]]; then
-	. /etc/vconsole.conf
+	parse_envfile /etc/vconsole.conf "${vconsolevars[@]}"
 	[[ $FONT ]] && CONSOLEFONT=$FONT
 	[[ $FONT_MAP ]] && CONSOLEMAP=$FONT_MAP
 fi
-- 
1.7.7.2



More information about the arch-projects mailing list