Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 29 Jan 2021 05:26:55 GMT
From:      Kyle Evans <kevans@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 633f82126b28 - stable/13 - lualoader: improve loader.conf var processing
Message-ID:  <202101290526.10T5QtlU085225@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by kevans:

URL: https://cgit.FreeBSD.org/src/commit/?id=633f82126b28d6c44beae579a7f71eb85ca1453c

commit 633f82126b28d6c44beae579a7f71eb85ca1453c
Author:     Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2021-01-24 19:25:34 +0000
Commit:     Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2021-01-29 05:26:30 +0000

    lualoader: improve loader.conf var processing
    
    lualoader was previously not processing \ as escapes; this commit fixes
    that and does better error checking on the value as well.
    
    Additionally, loader.conf had some odd restrictions on values that make
    little sense. Previously, lines like:
    
    kernel=foo
    
    Would simply be discarded with a malformed line complaint you might not
    see unless you disable beastie.
    
    lualoader tries to process these as well as it can and manipulates the
    environment, while forthloader did minimal processing and constructed a
    `set` command to do the heavy lifting instead. The lua approach was
    re-envisioned from building a `set` command so that we can appropriately
    reset the environment when, for example, boot environments change.
    
    Lift the previous restrictions to allow unquoted values on the right hand
    side of an expression.  Note that an unquoted value is effectively:
    
    [A-Za-z0-9-][A-Za-z0-9-_.]*
    
    This commit also stops trying to weirdly limit what it can handle in a
    quoted value. Previously it only allowed spaces, alphanumeric, and
    punctuation, which is kind of weird. Change it here to grab as much as it
    can between two sets of quotes, then let processEnvVar() do the needful and
    complain if it finds something malformed looking.
    
    My extremely sophisticated test suite is as follows:
    
    <<EOF
    X_01_simple_string="simple"
    X_02_escaped_string="s\imple"
    
    X_03_unquoted_val=3
    X_04_unquoted_strval=simple_test
    
    X_05_subval="${X_03_unquoted_val}"
    X_06_escaped_subval="\${X_03_unquoted_val}"
    
    X_07_embedded="truth${X_03_unquoted_val}"
    X_08_escaped_embedded="truth\${X_03_unquoted_val}"
    
    X_09_unknown="${unknown_val}"
    X_10_unknown_embedded="truth${unknown_val}"
    
    X_11_crunchy="crunch$unknown_val crunch"
    X_12_crunchy="crunch${unknown_val}crunch"
    
    Y_01_badquote="te"lol"
    Y_02_eolesc="lol\"
    Y_02_noteolesc="lol\\"
    Y_03_eolvar="lol$"
    Y_03_noteolvar="lol\$"
    Y_04_badvar="lol${"
    
    exec="echo Done!"
    EOF
    
    Future work may provide a stub loader module in userland so that we can
    formally test the loader scripts rather than sketchy setups like the above
    in conjunction with the lua-* tools in ^/tools/boot.
    
    (cherry picked from commit 576562856efbec31520aca6a1f72f2b11298e9a7)
---
 stand/lua/config.lua | 90 +++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 68 insertions(+), 22 deletions(-)

diff --git a/stand/lua/config.lua b/stand/lua/config.lua
index 095d354c637b..f569b2e00b76 100644
--- a/stand/lua/config.lua
+++ b/stand/lua/config.lua
@@ -45,6 +45,7 @@ local MSG_FAILSETENV = "Failed to '%s' with value: %s"
 local MSG_FAILOPENCFG = "Failed to open config: '%s'"
 local MSG_FAILREADCFG = "Failed to read config: '%s'"
 local MSG_FAILPARSECFG = "Failed to parse config: '%s'"
+local MSG_FAILPARSEVAR = "Failed to parse variable '%s': %s"
 local MSG_FAILEXBEF = "Failed to execute '%s' before loading '%s'"
 local MSG_FAILEXAF = "Failed to execute '%s' after loading '%s'"
 local MSG_MALFORMED = "Malformed line (%d):\n\t'%s'"
@@ -56,10 +57,15 @@ local MSG_KERNLOADING = "Loading kernel..."
 local MSG_MODLOADING = "Loading configured modules..."
 local MSG_MODBLACKLIST = "Not loading blacklisted module '%s'"
 
+local MSG_FAILSYN_QUOTE = "Stray quote at position '%d'"
+local MSG_FAILSYN_EOLESC = "Stray escape at end of line"
+local MSG_FAILSYN_EOLVAR = "Unescaped $ at end of line"
+local MSG_FAILSYN_BADVAR = "Malformed variable expression at position '%d'"
+
 local MODULEEXPR = '([%w-_]+)'
-local QVALEXPR = "\"([%w%s%p]-)\""
+local QVALEXPR = '"(.*)"'
 local QVALREPL = QVALEXPR:gsub('%%', '%%%%')
-local WORDEXPR = "([%w]+)"
+local WORDEXPR = "([%w%d-][%w%d-_.]*)"
 local WORDREPL = WORDEXPR:gsub('%%', '%%%%')
 
 -- Entries that should never make it into the environment; each one should have
@@ -146,15 +152,59 @@ local function escapeName(name)
 end
 
 local function processEnvVar(value)
-	for name in value:gmatch("${([^}]+)}") do
-		local replacement = loader.getenv(name) or ""
-		value = value:gsub("${" .. escapeName(name) .. "}", replacement)
-	end
-	for name in value:gmatch("$([%w%p]+)%s*") do
-		local replacement = loader.getenv(name) or ""
-		value = value:gsub("$" .. escapeName(name), replacement)
+	local pval, vlen = '', #value
+	local nextpos, vdelim, vinit = 1
+	local vpat
+	for i = 1, vlen do
+		if i < nextpos then
+			goto nextc
+		end
+
+		local c = value:sub(i, i)
+		if c == '\\' then
+			if i == vlen then
+				return nil, MSG_FAILSYN_EOLESC
+			end
+			nextpos = i + 2
+			pval = pval .. value:sub(i + 1, i + 1)
+		elseif c == '"' then
+			return nil, MSG_FAILSYN_QUOTE:format(i)
+		elseif c == "$" then
+			if i == vlen then
+				return nil, MSG_FAILSYN_EOLVAR
+			else
+				if value:sub(i + 1, i + 1) == "{" then
+					-- Skip ${
+					vinit = i + 2
+					vdelim = '}'
+					vpat = "^([^}]+)}"
+				else
+					-- Skip the $
+					vinit = i + 1
+					vdelim = nil
+					vpat = "^([%w][%w%d-_.]*)"
+				end
+
+				local name = value:match(vpat, vinit)
+				if not name then
+					return nil, MSG_FAILSYN_BADVAR:format(i)
+				else
+					nextpos = vinit + #name
+					if vdelim then
+						nextpos = nextpos + 1
+					end
+
+					local repl = loader.getenv(name) or ""
+					pval = pval .. repl
+				end
+			end
+		else
+			pval = pval .. c
+		end
+		::nextc::
 	end
-	return value
+
+	return pval
 end
 
 local function checkPattern(line, pattern)
@@ -260,21 +310,17 @@ local pattern_table = {
 		end,
 		groups = 1,
 	},
-	--  env_var="value"
+	--  env_var="value" or env_var=[word|num]
 	{
-		str = "([%w%p]+)%s*=%s*$VALUE",
+		str = "([%w][%w%d-_.]*)%s*=%s*$VALUE",
 		process = function(k, v)
-			if setEnv(k, processEnvVar(v)) ~= 0 then
-				print(MSG_FAILSETENV:format(k, v))
+			local pv, msg = processEnvVar(v)
+			if not pv then
+				print(MSG_FAILPARSEVAR:format(k, msg))
+				return
 			end
-		end,
-	},
-	--  env_var=num
-	{
-		str = "([%w%p]+)%s*=%s*(-?%d+)",
-		process = function(k, v)
-			if setEnv(k, processEnvVar(v)) ~= 0 then
-				print(MSG_FAILSETENV:format(k, tostring(v)))
+			if setEnv(k, pv) ~= 0 then
+				print(MSG_FAILSETENV:format(k, v))
 			end
 		end,
 	},



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202101290526.10T5QtlU085225>