~ubuntu-branches/ubuntu/trusty/systemd/trusty

« back to all changes in this revision

Viewing changes to src/shared/env-util.c

  • Committer: Package Import Robot
  • Author(s): Michael Biebl, Michael Biebl, Michael Stapelberg, Daniel Schaal, Ondrej Balaz
  • Date: 2013-09-12 00:13:11 UTC
  • mfrom: (1.1.11) (9.1.2 experimental)
  • mto: This revision was merged to the branch mainline in revision 53.
  • Revision ID: package-import@ubuntu.com-20130912001311-dz35it34wr2lbday
Tags: 204-3
[ Michael Biebl ]
* Upload to unstable.
* Use /bin/bash in debug-shell.service as Debian doesn't have /sbin/sushell.
* Only import net.ifaces cmdline property for network devices.
* Generate strict dependencies between the binary packages using a
  shlibs.local file and add an explicit versioned dependency on
  libsystemd-login0 to systemd to ensure packages are upgraded in sync.
  Closes: #719444
* Drop obsolete Replaces: libudev0 from udev package.
* Use correct paths for various binaries, like /sbin/quotaon, which are
  installed in / and not /usr in Debian.  Closes: #721347
* Don't install kernel-install(8) man page since we don't install the
  corresponding binary either.  Closes: #722180
* Cherry-pick upstream fixes to make switching runlevels and starting
  reboot via ctrl-alt-del more robust.
* Cherry-pick upstream fix to properly apply ACLs to Journal files.

[ Michael Stapelberg ]
* Make systemctl enable|disable call update-rc.d for SysV init scripts.
  Closes: #709780
* Don't mount /tmp as tmpfs by default and make it possible to enable this
  feature via "systemctl enable tmp.mount".

[ Daniel Schaal ]
* Add bug-script to systemd and udev.  Closes: #711245

[ Ondrej Balaz ]
* Recognize discard option in /etc/crypttab.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
41
static 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
 
 
68
bool 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
 
 
75
bool 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
 
 
96
bool 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
 
111
         * cannot be either, but let's leave room for one trailing NUL
 
112
         * byte. */
 
113
        if (strlen(e) > ARG_MAX - 1)
 
114
                return false;
 
115
 
 
116
        return true;
 
117
}
 
118
 
 
119
bool 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)
 
131
                        if (strneq(*p, *q, k) && (*q)[k] == '=')
 
132
                                return false;
 
133
        }
 
134
 
 
135
        return true;
 
136
}
 
137
 
 
138
bool 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
 
 
153
static 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++)
 
174
                        if (strneq(*j, *a, n))
 
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
 
 
190
char **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
 
 
223
fail:
 
224
        va_end(ap);
 
225
        strv_free(r);
 
226
 
 
227
        return NULL;
 
228
}
 
229
 
 
230
_pure_ static bool env_match(const char *t, const char *pattern) {
 
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
 
 
250
                return strneq(t, pattern, l) && t[l] == '=';
 
251
        }
 
252
 
 
253
        return false;
 
254
}
 
255
 
 
256
char **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
 
 
304
char **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
 
 
330
char **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
 
 
352
fail:
 
353
        strv_free(r);
 
354
        return NULL;
 
355
}
 
356
 
 
357
char *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)
 
366
                if (strneq(*i, name, k) &&
 
367
                    (*i)[k] == '=')
 
368
                        return *i + k + 1;
 
369
 
 
370
        return NULL;
 
371
}
 
372
 
 
373
char *strv_env_get(char **l, const char *name) {
 
374
        assert(name);
 
375
 
 
376
        return strv_env_get_n(l, name, strlen(name));
 
377
}
 
378
 
 
379
char **strv_env_clean_log(char **e, const char *message) {
 
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)) {
 
388
                        if (message)
 
389
                                log_error("Ignoring invalid environment '%s': %s", *p, message);
 
390
                        free(*p);
 
391
                        continue;
 
392
                }
 
393
 
 
394
                n = strcspn(*p, "=");
 
395
                STRV_FOREACH(q, p + 1)
 
396
                        if (strneq(*p, *q, n) && (*q)[n] == '=') {
 
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
}
 
412
 
 
413
char **strv_env_clean(char **e) {
 
414
        return strv_env_clean_log(e, NULL);
 
415
}