@@ -93,103 +93,118 @@ find_env_var_name(char *line, char **first, char **last)
93
93
return FALSE;
94
94
}
95
95
96
+ #define CONTAINER_ENV_FILE "/etc/pacemaker/pcmk-init.env"
97
+
96
98
static void
97
- load_env_vars (const char * filename )
99
+ load_env_vars (void )
98
100
{
99
101
/* We haven't forked or initialized logging yet, so don't leave any file
100
102
* descriptors open, and don't log -- silently ignore errors.
101
103
*/
102
- FILE * fp = fopen (filename , "r" );
103
- char line [LINE_MAX ] = { 0 , };
104
+ FILE * fp = fopen (CONTAINER_ENV_FILE , "r" );
105
+ char * line = NULL ;
106
+ size_t buf_size = 0 ;
104
107
105
108
if (fp == NULL ) {
106
109
return ;
107
110
}
108
111
109
- while (fgets ( line , LINE_MAX , fp ) != NULL ) {
112
+ while (getline ( & line , & buf_size , fp ) != -1 ) {
110
113
char * name = NULL ;
111
114
char * end = NULL ;
112
- char * value = NULL ;
113
115
char * quote = NULL ;
116
+ char * value = NULL ;
117
+ char * value_end = NULL ;
114
118
115
119
// Look for valid name immediately followed by equals sign
116
- if (find_env_var_name (line , & name , & end ) && (* ++ end == '=' )) {
120
+ if (!find_env_var_name (line , & name , & end ) || (* ++ end != '=' )) {
121
+ continue ;
122
+ }
117
123
118
- // Null-terminate name, and advance beyond equals sign
119
- * end ++ = '\0' ;
124
+ // Null-terminate name, and advance beyond equals sign
125
+ * end ++ = '\0' ;
126
+
127
+ // Check whether value is quoted
128
+ if ((* end == '\'' ) || (* end == '"' )) {
129
+ quote = end ++ ;
130
+ }
120
131
121
- // Check whether value is quoted
122
- if ((* end == '\'' ) || (* end == '"' )) {
123
- quote = end ++ ;
132
+ // Set beginning of value
133
+ value = end ;
134
+
135
+ // Find end of value
136
+ if (quote != NULL ) {
137
+ /* Value is remaining characters up to next non-backslashed matching
138
+ * quote character
139
+ *
140
+ * @TODO This breaks when the value ends with a literal escaped
141
+ * backslash. For example: VAR='value\\'.
142
+ */
143
+ while (((* end != * quote ) || (* (end - 1 ) == '\\' ))
144
+ && (* end != '\0' )) {
145
+ end ++ ;
124
146
}
125
- value = end ;
126
-
127
- if (quote != NULL ) {
128
- /* Value is remaining characters up to next non-backslashed
129
- * matching quote character.
130
- */
131
- while (((* end != * quote ) || (* (end - 1 ) == '\\' ))
132
- && (* end != '\0' )) {
133
- end ++ ;
134
- }
135
- if (* end == * quote ) {
136
- // Null-terminate value, and advance beyond close quote
137
- * end ++ = '\0' ;
138
- } else {
139
- // Matching closing quote wasn't found
140
- value = NULL ;
141
- }
142
-
143
- } else {
144
- /* Value is remaining characters up to next non-backslashed
145
- * whitespace.
146
- */
147
- while ((!isspace (* end ) || (* (end - 1 ) == '\\' ))
148
- && (* end != '\0' )) {
149
- end ++ ;
150
- }
151
-
152
- if (end == (line + LINE_MAX - 1 )) {
153
- // Line was too long
154
- value = NULL ;
155
- }
156
- // Do NOT null-terminate value (yet)
147
+
148
+ if (* end != * quote ) {
149
+ // Matching closing quote wasn't found
150
+ continue ;
157
151
}
158
152
159
- /* We have a valid name and value, and end is now the character
160
- * after the closing quote or the first whitespace after the
161
- * unquoted value. Make sure the rest of the line is just whitespace
162
- * or a comment.
153
+ /* Null-terminate value at the closing quote and advance the end
154
+ * pointer beyond it.
155
+ */
156
+ * end ++ = '\0' ;
157
+
158
+ } else {
159
+ /* Value is remaining characters up to next non-backslashed
160
+ * whitespace
161
+ *
162
+ * @TODO This breaks when the value ends with a literal escaped
163
+ * backslash and is followed by a space.
163
164
*/
164
- if (value != NULL ) {
165
- char * value_end = end ;
166
-
167
- while (isspace (* end ) && (* end != '\n' )) {
168
- end ++ ;
169
- }
170
- if ((* end == '\n' ) || (* end == '#' )) {
171
- if (quote == NULL ) {
172
- // Now we can null-terminate an unquoted value
173
- * value_end = '\0' ;
174
- }
175
-
176
- // Don't overwrite (bundle options take precedence)
177
- setenv (name , value , 0 );
178
-
179
- } else {
180
- value = NULL ;
181
- }
165
+ while ((!isspace (* end ) || (* (end - 1 ) == '\\' ))
166
+ && (* end != '\0' )) {
167
+ end ++ ;
182
168
}
183
- }
184
169
185
- if ((value == NULL ) && (strchr (line , '\n' ) == NULL )) {
186
- // Eat remainder of line beyond LINE_MAX
187
- if (fscanf (fp , "%*[^\n]\n" ) == EOF ) {
188
- value = NULL ; // Don't care, make compiler happy
170
+ if (* end == '\0' ) {
171
+ // Malformed line (contains null terminator before newline)
172
+ continue ;
189
173
}
190
174
}
175
+
176
+ /* We have a valid name and value, and end is now the character after
177
+ * the closing quote or the first whitespace after the unquoted value.
178
+ * Make sure the rest of the line is just whitespace or a comment.
179
+ */
180
+ value_end = end ;
181
+
182
+ while (isspace (* end ) && (* end != '\n' )) {
183
+ end ++ ;
184
+ }
185
+
186
+ if ((* end != '\n' ) && (* end != '#' )) {
187
+ // Found garbage after value
188
+ continue ;
189
+ }
190
+
191
+ // Null-terminate value (it's safe to do it again for a quoted value)
192
+ * value_end = '\0' ;
193
+
194
+ // Don't overwrite (bundle options take precedence)
195
+ setenv (name , value , 0 );
196
+ }
197
+
198
+ // getline() returns -1 on EOF or error
199
+ if (errno != 0 ) {
200
+ int rc = errno ;
201
+
202
+ crm_err ("Error while reading environment variables from "
203
+ CONTAINER_ENV_FILE ": %s" ,
204
+ pcmk_rc_str (rc ));
191
205
}
192
206
fclose (fp );
207
+ free (line );
193
208
}
194
209
195
210
void
@@ -221,7 +236,7 @@ remoted_spawn_pidone(int argc, char **argv, char **envp)
221
236
* To allow for that, look for a special file containing a shell-like syntax
222
237
* of name/value pairs, and export those into the environment.
223
238
*/
224
- load_env_vars ("/etc/pacemaker/pcmk-init.env" );
239
+ load_env_vars ();
225
240
226
241
if (strcmp (pid1 , "vars" ) == 0 ) {
227
242
return ;
0 commit comments