Skip to content

Commit f71ef81

Browse files
committed
Refactor: remoted: Clean up load_env_vars()
The changes in this commit involve using (gchar *) strings and some dynamic allocation to make load_env_vars() easier to reason about. Previously, we tried to be as efficient as possible by reading a line into a buffer, iterating over it with multiple pointers, dividing it into name and value by insertion of a null terminator, etc. This is premature optimization. This function is not called along a path of execution where performance is so critical as to require this. In my opinion, clarity is more important. * Use pcmk__scan_nvpair() to separate the line on the equal sign. * Simplify name validation since we now have name as a separate string (before the equal sign) and don't need to return first and last pointers. * Use an is_quoted boolean variable, so that we can limit the quote character to the inner block and compare to the value instead of maintaining a pointer to the quote character. * Skip the leading quote by converting it to a space and calling g_strchug() to memmove() value up by one position. This ensures that value still points to the beginning of the buffer, which simplifies freeing it later. Signed-off-by: Reid Wahl <nrwahl@protonmail.com>
1 parent 2df15f3 commit f71ef81

File tree

1 file changed

+41
-33
lines changed

1 file changed

+41
-33
lines changed

daemons/execd/remoted_pidone.c

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -61,24 +61,26 @@ static struct {
6161

6262
/*!
6363
* \internal
64-
* \brief Check a line of text for a valid environment variable name
64+
* \brief Check whether a string is a valid environment variable name
6565
*
66-
* \param[in] line Text to check
66+
* \param[in] name String to check
6767
*
68-
* \return Last character of valid name if found, or \c NULL otherwise
68+
* \return \c true if \p name is a valid name, or \c false otherwise
6969
* \note It's reasonable to impose limitations on environment variable names
7070
* beyond what C or setenv() does: We only allow names that contain only
7171
* [a-zA-Z0-9_] characters and do not start with a digit.
7272
*/
73-
static char *
74-
find_env_var_name(char *line)
73+
static bool
74+
valid_env_var_name(const gchar *name)
7575
{
76-
if (!isalpha(*line) && (*line != '_')) {
76+
if (!isalpha(*name) && (*name != '_')) {
7777
// Invalid first character
78-
return NULL;
78+
return false;
7979
}
80-
for (line++; isalnum(*line) || (*line == '_'); line++);
81-
return line;
80+
81+
// The rest of the characters must be alphanumeric or underscores
82+
for (name++; isalnum(*name) || (*name == '_'); name++);
83+
return *name == '\0';
8284
}
8385

8486
#define CONTAINER_ENV_FILE "/etc/pacemaker/pcmk-init.env"
@@ -98,52 +100,56 @@ load_env_vars(void)
98100
}
99101

100102
while (getline(&line, &buf_size, fp) != -1) {
101-
char *name = NULL;
102-
char *end = NULL;
103-
char *value = NULL;
104-
char *comment = NULL;
103+
gchar *name = NULL;
104+
gchar *value = NULL;
105+
gchar *end = NULL;
106+
gchar *comment = NULL;
107+
bool is_quoted = false;
105108

106109
// Strip leading and trailing whitespace
107110
g_strstrip(line);
108111

109-
// Look for valid name immediately followed by equals sign
110-
end = find_env_var_name(line);
111-
if (*++end != '=') {
112+
if (pcmk__scan_nvpair(line, &name, &value) != pcmk_rc_ok) {
113+
crm_warn("Ignoring malformed line while reading environment "
114+
"variables from " CONTAINER_ENV_FILE ": '%s'",
115+
line);
116+
goto cleanup_loop;
117+
}
118+
119+
if (!valid_env_var_name(name)) {
112120
goto cleanup_loop;
113121
}
114-
name = line;
115122

116-
// Null-terminate name, and advance beyond equals sign
117-
*end++ = '\0';
123+
is_quoted = (*value == '\'') || (*value == '"');
124+
if (is_quoted) {
125+
char quote = *value;
118126

119-
// Check whether value is quoted
120-
if ((*end == '\'') || (*end == '"')) {
121-
const char *quote = *end++;
127+
// Strip the leading quote
128+
*value = ' ';
129+
g_strchug(value);
122130

123131
/* Value is remaining characters up to next non-backslashed matching
124132
* quote character.
125133
*/
126-
value = end;
127-
while (((*end != *quote) || (*(end - 1) == '\\'))
128-
&& (*end != '\0')) {
129-
end++;
130-
}
131-
if (*end != *quote) {
134+
for (end = value;
135+
(*end != '\0') && ((*end != quote) || (*(end - 1) == '\\'));
136+
end++);
137+
138+
if (*end != quote) {
132139
// Matching closing quote wasn't found
133140
goto cleanup_loop;
134141
}
142+
135143
// Discard closing quote and advance to check for trailing garbage
136144
*end++ = '\0';
137145

138146
} else {
139147
/* Value is remaining characters up to next non-backslashed
140148
* whitespace.
141149
*/
142-
value = end;
143-
while ((!isspace(*end) || (*(end - 1) == '\\'))
144-
&& (*end != '\0')) {
145-
end++;
146-
}
150+
for (end = value;
151+
(*end != '\0') && (!isspace(*end) || (*(end - 1) == '\\'));
152+
end++);
147153
}
148154

149155
/* We have a valid name and value, and end is now the character after
@@ -170,6 +176,8 @@ load_env_vars(void)
170176
setenv(name, value, 0);
171177

172178
cleanup_loop:
179+
g_free(name);
180+
g_free(value);
173181
errno = 0;
174182
}
175183

0 commit comments

Comments
 (0)