]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/env-util.c
transaction.c: do not point users to logs when unit not found
[thirdparty/systemd.git] / src / shared / env-util.c
CommitLineData
4d1a6904
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2012 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <limits.h>
23#include <sys/param.h>
24#include <unistd.h>
25
26#include "strv.h"
27#include "utf8.h"
28#include "util.h"
29#include "env-util.h"
30
31#define VALID_CHARS_ENV_NAME \
32 "0123456789" \
33 "abcdefghijklmnopqrstuvwxyz" \
34 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
35 "_"
36
37#ifndef ARG_MAX
38#define ARG_MAX ((size_t) sysconf(_SC_ARG_MAX))
39#endif
40
41static bool env_name_is_valid_n(const char *e, size_t n) {
42 const char *p;
43
44 if (!e)
45 return false;
46
47 if (n <= 0)
48 return false;
49
50 if (e[0] >= '0' && e[0] <= '9')
51 return false;
52
53 /* POSIX says the overall size of the environment block cannot
54 * be > ARG_MAX, an individual assignment hence cannot be
55 * either. Discounting the equal sign and trailing NUL this
56 * hence leaves ARG_MAX-2 as longest possible variable
57 * name. */
58 if (n > ARG_MAX - 2)
59 return false;
60
61 for (p = e; p < e + n; p++)
62 if (!strchr(VALID_CHARS_ENV_NAME, *p))
63 return false;
64
65 return true;
66}
67
68bool env_name_is_valid(const char *e) {
69 if (!e)
70 return false;
71
72 return env_name_is_valid_n(e, strlen(e));
73}
74
75bool env_value_is_valid(const char *e) {
76 if (!e)
77 return false;
78
79 if (!utf8_is_valid(e))
80 return false;
81
82 if (string_has_cc(e))
83 return false;
84
85 /* POSIX says the overall size of the environment block cannot
86 * be > ARG_MAX, an individual assignment hence cannot be
87 * either. Discounting the shortest possible variable name of
88 * length 1, the equal sign and trailing NUL this hence leaves
89 * ARG_MAX-3 as longest possible variable value. */
90 if (strlen(e) > ARG_MAX - 3)
91 return false;
92
93 return true;
94}
95
96bool env_assignment_is_valid(const char *e) {
97 const char *eq;
98
99 eq = strchr(e, '=');
100 if (!eq)
101 return false;
102
103 if (!env_name_is_valid_n(e, eq - e))
104 return false;
105
106 if (!env_value_is_valid(eq + 1))
107 return false;
108
109 /* POSIX says the overall size of the environment block cannot
110 * be > ARG_MAX, hence the individual variable assignments
5f9cfd4c 111 * cannot be either, but let's leave room for one trailing NUL
4d1a6904
LP
112 * byte. */
113 if (strlen(e) > ARG_MAX - 1)
114 return false;
115
116 return true;
117}
118
119bool strv_env_is_valid(char **e) {
120 char **p, **q;
121
122 STRV_FOREACH(p, e) {
123 size_t k;
124
125 if (!env_assignment_is_valid(*p))
126 return false;
127
128 /* Check if there are duplicate assginments */
129 k = strcspn(*p, "=");
130 STRV_FOREACH(q, p + 1)
641906e9 131 if (strneq(*p, *q, k) && (*q)[k] == '=')
4d1a6904
LP
132 return false;
133 }
134
135 return true;
136}
137
123b964a
LP
138bool strv_env_name_or_assignment_is_valid(char **l) {
139 char **p, **q;
140
141 STRV_FOREACH(p, l) {
142 if (!env_assignment_is_valid(*p) && !env_name_is_valid(*p))
143 return false;
144
145 STRV_FOREACH(q, p + 1)
146 if (streq(*p, *q))
147 return false;
148 }
149
150 return true;
151}
152
4d1a6904
LP
153static int env_append(char **r, char ***k, char **a) {
154 assert(r);
155 assert(k);
156
157 if (!a)
158 return 0;
159
160 /* Add the entries of a to *k unless they already exist in *r
161 * in which case they are overridden instead. This assumes
162 * there is enough space in the r array. */
163
164 for (; *a; a++) {
165 char **j;
166 size_t n;
167
168 n = strcspn(*a, "=");
169
170 if ((*a)[n] == '=')
171 n++;
172
173 for (j = r; j < *k; j++)
641906e9 174 if (strneq(*j, *a, n))
4d1a6904
LP
175 break;
176
177 if (j >= *k)
178 (*k)++;
179 else
180 free(*j);
181
182 *j = strdup(*a);
183 if (!*j)
184 return -ENOMEM;
185 }
186
187 return 0;
188}
189
190char **strv_env_merge(unsigned n_lists, ...) {
191 size_t n = 0;
192 char **l, **k, **r;
193 va_list ap;
194 unsigned i;
195
196 /* Merges an arbitrary number of environment sets */
197
198 va_start(ap, n_lists);
199 for (i = 0; i < n_lists; i++) {
200 l = va_arg(ap, char**);
201 n += strv_length(l);
202 }
203 va_end(ap);
204
205 r = new(char*, n+1);
206 if (!r)
207 return NULL;
208
209 k = r;
210
211 va_start(ap, n_lists);
212 for (i = 0; i < n_lists; i++) {
213 l = va_arg(ap, char**);
214 if (env_append(r, &k, l) < 0)
215 goto fail;
216 }
217 va_end(ap);
218
219 *k = NULL;
220
221 return r;
222
223fail:
224 va_end(ap);
225 strv_free(r);
226
227 return NULL;
228}
229
44a6b1b6 230_pure_ static bool env_match(const char *t, const char *pattern) {
4d1a6904
LP
231 assert(t);
232 assert(pattern);
233
234 /* pattern a matches string a
235 * a matches a=
236 * a matches a=b
237 * a= matches a=
238 * a=b matches a=b
239 * a= does not match a
240 * a=b does not match a=
241 * a=b does not match a
242 * a=b does not match a=c */
243
244 if (streq(t, pattern))
245 return true;
246
247 if (!strchr(pattern, '=')) {
248 size_t l = strlen(pattern);
249
641906e9 250 return strneq(t, pattern, l) && t[l] == '=';
4d1a6904
LP
251 }
252
253 return false;
254}
255
256char **strv_env_delete(char **x, unsigned n_lists, ...) {
257 size_t n, i = 0;
258 char **k, **r;
259 va_list ap;
260
261 /* Deletes every entry from x that is mentioned in the other
262 * string lists */
263
264 n = strv_length(x);
265
266 r = new(char*, n+1);
267 if (!r)
268 return NULL;
269
270 STRV_FOREACH(k, x) {
271 unsigned v;
272
273 va_start(ap, n_lists);
274 for (v = 0; v < n_lists; v++) {
275 char **l, **j;
276
277 l = va_arg(ap, char**);
278 STRV_FOREACH(j, l)
279 if (env_match(*k, *j))
280 goto skip;
281 }
282 va_end(ap);
283
284 r[i] = strdup(*k);
285 if (!r[i]) {
286 strv_free(r);
287 return NULL;
288 }
289
290 i++;
291 continue;
292
293 skip:
294 va_end(ap);
295 }
296
297 r[i] = NULL;
298
299 assert(i <= n);
300
301 return r;
302}
303
304char **strv_env_unset(char **l, const char *p) {
305
306 char **f, **t;
307
308 if (!l)
309 return NULL;
310
311 assert(p);
312
313 /* Drops every occurrence of the env var setting p in the
314 * string list. edits in-place. */
315
316 for (f = t = l; *f; f++) {
317
318 if (env_match(*f, p)) {
319 free(*f);
320 continue;
321 }
322
323 *(t++) = *f;
324 }
325
326 *t = NULL;
327 return l;
328}
329
330char **strv_env_set(char **x, const char *p) {
331
332 char **k, **r;
333 char* m[2] = { (char*) p, NULL };
334
335 /* Overrides the env var setting of p, returns a new copy */
336
337 r = new(char*, strv_length(x)+2);
338 if (!r)
339 return NULL;
340
341 k = r;
342 if (env_append(r, &k, x) < 0)
343 goto fail;
344
345 if (env_append(r, &k, m) < 0)
346 goto fail;
347
348 *k = NULL;
349
350 return r;
351
352fail:
353 strv_free(r);
354 return NULL;
355}
356
357char *strv_env_get_n(char **l, const char *name, size_t k) {
358 char **i;
359
360 assert(name);
361
362 if (k <= 0)
363 return NULL;
364
365 STRV_FOREACH(i, l)
641906e9 366 if (strneq(*i, name, k) &&
4d1a6904
LP
367 (*i)[k] == '=')
368 return *i + k + 1;
369
370 return NULL;
371}
372
373char *strv_env_get(char **l, const char *name) {
374 assert(name);
375
376 return strv_env_get_n(l, name, strlen(name));
377}
378
ebc05a09 379char **strv_env_clean_log(char **e, const char *message) {
4d1a6904
LP
380 char **p, **q;
381 int k = 0;
382
383 STRV_FOREACH(p, e) {
384 size_t n;
385 bool duplicate = false;
386
387 if (!env_assignment_is_valid(*p)) {
ebc05a09
HH
388 if (message)
389 log_error("Ignoring invalid environment '%s': %s", *p, message);
4d1a6904
LP
390 free(*p);
391 continue;
392 }
393
394 n = strcspn(*p, "=");
395 STRV_FOREACH(q, p + 1)
641906e9 396 if (strneq(*p, *q, n) && (*q)[n] == '=') {
4d1a6904
LP
397 duplicate = true;
398 break;
399 }
400
401 if (duplicate) {
402 free(*p);
403 continue;
404 }
405
406 e[k++] = *p;
407 }
408
409 e[k] = NULL;
410 return e;
411}
ebc05a09
HH
412
413char **strv_env_clean(char **e) {
414 return strv_env_clean_log(e, NULL);
415}