Skip to content

Commit c94342c

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 <[email protected]>
1 parent 58e613a commit c94342c

File tree

1 file changed

+39
-37
lines changed

1 file changed

+39
-37
lines changed

daemons/execd/remoted_pidone.c

Lines changed: 39 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -61,32 +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
67-
* \param[out] first First character of valid name if found, NULL otherwise
68-
* \param[out] last Last character of valid name if found, NULL otherwise
66+
* \param[in] name String to check
6967
*
70-
* \return TRUE if valid name found, FALSE otherwise
68+
* \return \c true if \p name is a valid name, or \c false otherwise
7169
* \note It's reasonable to impose limitations on environment variable names
7270
* beyond what C or setenv() does: We only allow names that contain only
7371
* [a-zA-Z0-9_] characters and do not start with a digit.
7472
*/
7573
static bool
76-
find_env_var_name(char *line, char **first, char **last)
74+
valid_env_var_name(const gchar *name)
7775
{
78-
*first = line;
79-
80-
if (isalpha(**first) || (**first == '_')) { // Valid first character
81-
*last = *first;
82-
while (isalnum(*(*last + 1)) || (*(*last + 1) == '_')) {
83-
++*last;
84-
}
85-
return TRUE;
76+
if (!isalpha(*name) && (*name != '_')) {
77+
// Invalid first character
78+
return false;
8679
}
8780

88-
*first = *last = NULL;
89-
return FALSE;
81+
// The rest of the characters must be alphanumeric or underscores
82+
for (name++; isalnum(*name) || (*name == '_'); name++);
83+
return *name == '\0';
9084
}
9185

9286
#define CONTAINER_ENV_FILE "/etc/pacemaker/pcmk-init.env"
@@ -106,50 +100,56 @@ load_env_vars(void)
106100
}
107101

108102
while (getline(&line, &buf_size, fp) != -1) {
109-
char *name = NULL;
110-
char *end = NULL;
111-
char *value = NULL;
112-
char *comment = NULL;
103+
gchar *name = NULL;
104+
gchar *value = NULL;
105+
gchar *end = NULL;
106+
gchar *comment = NULL;
107+
bool is_quoted = false;
113108

114109
// Strip leading and trailing whitespace
115110
g_strstrip(line);
116111

117-
// Look for valid name immediately followed by equals sign
118-
if (!find_env_var_name(line, &name, &end) || (*++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);
119116
goto cleanup_loop;
120117
}
121118

122-
// Null-terminate name, and advance beyond equals sign
123-
*end++ = '\0';
119+
if (!valid_env_var_name(name)) {
120+
goto cleanup_loop;
121+
}
124122

125-
// Check whether value is quoted
126-
if ((*end == '\'') || (*end == '"')) {
127-
const char *quote = *end++;
123+
is_quoted = (*value == '\'') || (*value == '"');
124+
if (is_quoted) {
125+
char quote = *value;
128126

129-
value = end;
127+
// Strip the leading quote
128+
*value = ' ';
129+
g_strchug(value);
130130

131131
/* Value is remaining characters up to next non-backslashed matching
132132
* quote character.
133133
*/
134-
while (((*end != *quote) || (*(end - 1) == '\\'))
135-
&& (*end != '\0')) {
136-
end++;
137-
}
138-
if (*end != *quote) {
134+
for (end = value;
135+
(*end != '\0') && ((*end != quote) || (*(end - 1) == '\\'));
136+
end++);
137+
138+
if (*end != quote) {
139139
// Matching closing quote wasn't found
140140
goto cleanup_loop;
141141
}
142+
142143
// Discard closing quote and advance to check for trailing garbage
143144
*end++ = '\0';
144145

145146
} else {
146147
/* Value is remaining characters up to next non-backslashed
147148
* whitespace.
148149
*/
149-
while ((!isspace(*end) || (*(end - 1) == '\\'))
150-
&& (*end != '\0')) {
151-
end++;
152-
}
150+
for (end = value;
151+
(*end != '\0') && (!isspace(*end) || (*(end - 1) == '\\'));
152+
end++);
153153
}
154154

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

178178
cleanup_loop:
179+
g_free(name);
180+
g_free(value);
179181
errno = 0;
180182
}
181183

0 commit comments

Comments
 (0)