]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/strv.c
main: print warning if /usr is on a seperate partition
[thirdparty/systemd.git] / src / strv.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
60918275 2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 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 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
60918275
LP
22#include <assert.h>
23#include <stdlib.h>
24#include <stdarg.h>
25#include <string.h>
2e6c9e6b 26#include <errno.h>
60918275
LP
27
28#include "util.h"
29#include "strv.h"
30
31char *strv_find(char **l, const char *name) {
5f9a22c3
LP
32 char **i;
33
60918275
LP
34 assert(name);
35
5f9a22c3
LP
36 STRV_FOREACH(i, l)
37 if (streq(*i, name))
38 return *i;
60918275
LP
39
40 return NULL;
41}
42
a4bfb399
LP
43char *strv_find_prefix(char **l, const char *name) {
44 char **i;
45
46 assert(name);
47
48 STRV_FOREACH(i, l)
49 if (startswith(*i, name))
50 return *i;
51
52 return NULL;
53}
54
60918275
LP
55void strv_free(char **l) {
56 char **k;
57
58 if (!l)
59 return;
60
61 for (k = l; *k; k++)
62 free(*k);
63
64 free(l);
65}
66
67char **strv_copy(char **l) {
68 char **r, **k;
69
70 if (!(r = new(char*, strv_length(l)+1)))
71 return NULL;
72
73 for (k = r; *l; k++, l++)
74 if (!(*k = strdup(*l)))
75 goto fail;
76
77 *k = NULL;
78 return r;
79
80fail:
81 for (k--, l--; k >= r; k--, l--)
82 free(*k);
83
84 return NULL;
85}
86
87unsigned strv_length(char **l) {
88 unsigned n = 0;
89
90 if (!l)
91 return 0;
92
93 for (; *l; l++)
94 n++;
95
96 return n;
97}
98
257eca1a 99char **strv_new_ap(const char *x, va_list ap) {
60918275
LP
100 const char *s;
101 char **a;
102 unsigned n = 0, i = 0;
257eca1a
LP
103 va_list aq;
104
60918275
LP
105
106 if (x) {
107 n = 1;
108
257eca1a
LP
109 va_copy(aq, ap);
110 while (va_arg(aq, const char*))
60918275 111 n++;
257eca1a 112 va_end(aq);
60918275
LP
113 }
114
115 if (!(a = new(char*, n+1)))
116 return NULL;
117
118 if (x) {
119 if (!(a[i] = strdup(x))) {
120 free(a);
121 return NULL;
122 }
123
124 i++;
125
60918275
LP
126 while ((s = va_arg(ap, const char*))) {
127 if (!(a[i] = strdup(s)))
128 goto fail;
129
130 i++;
131 }
60918275
LP
132 }
133
134 a[i] = NULL;
257eca1a 135
60918275
LP
136 return a;
137
138fail:
139
140 for (; i > 0; i--)
141 if (a[i-1])
142 free(a[i-1]);
143
144 free(a);
257eca1a 145
60918275
LP
146 return NULL;
147}
034c6ed7 148
257eca1a
LP
149char **strv_new(const char *x, ...) {
150 char **r;
151 va_list ap;
152
153 va_start(ap, x);
154 r = strv_new_ap(x, ap);
155 va_end(ap);
156
157 return r;
158}
159
034c6ed7
LP
160char **strv_merge(char **a, char **b) {
161 char **r, **k;
162
163 if (!a)
164 return strv_copy(b);
165
166 if (!b)
167 return strv_copy(a);
168
169 if (!(r = new(char*, strv_length(a)+strv_length(b)+1)))
170 return NULL;
171
172 for (k = r; *a; k++, a++)
173 if (!(*k = strdup(*a)))
174 goto fail;
175 for (; *b; k++, b++)
176 if (!(*k = strdup(*b)))
177 goto fail;
178
179 *k = NULL;
180 return r;
181
182fail:
183 for (k--; k >= r; k--)
184 free(*k);
185
100a76ee
LP
186 free(r);
187
034c6ed7 188 return NULL;
5f9a22c3
LP
189}
190
191char **strv_merge_concat(char **a, char **b, const char *suffix) {
192 char **r, **k;
193
194 /* Like strv_merge(), but appends suffix to all strings in b, before adding */
195
196 if (!b)
197 return strv_copy(a);
198
199 if (!(r = new(char*, strv_length(a)+strv_length(b)+1)))
200 return NULL;
201
202 for (k = r; *a; k++, a++)
203 if (!(*k = strdup(*a)))
204 goto fail;
205 for (; *b; k++, b++)
206 if (!(*k = strappend(*b, suffix)))
207 goto fail;
208
209 *k = NULL;
210 return r;
211
212fail:
213 for (k--; k >= r; k--)
214 free(*k);
215
100a76ee
LP
216 free(r);
217
5f9a22c3
LP
218 return NULL;
219
220}
221
222char **strv_split(const char *s, const char *separator) {
223 char *state;
224 char *w;
225 size_t l;
226 unsigned n, i;
227 char **r;
228
229 assert(s);
230
231 n = 0;
232 FOREACH_WORD_SEPARATOR(w, l, s, separator, state)
233 n++;
234
235 if (!(r = new(char*, n+1)))
236 return NULL;
237
238 i = 0;
239 FOREACH_WORD_SEPARATOR(w, l, s, separator, state)
240 if (!(r[i++] = strndup(w, l))) {
241 strv_free(r);
242 return NULL;
243 }
244
245 r[i] = NULL;
246 return r;
247}
248
249char **strv_split_quoted(const char *s) {
250 char *state;
251 char *w;
252 size_t l;
253 unsigned n, i;
254 char **r;
255
256 assert(s);
257
258 n = 0;
259 FOREACH_WORD_QUOTED(w, l, s, state)
260 n++;
261
262 if (!(r = new(char*, n+1)))
263 return NULL;
264
265 i = 0;
266 FOREACH_WORD_QUOTED(w, l, s, state)
f60f22df 267 if (!(r[i++] = cunescape_length(w, l))) {
5f9a22c3
LP
268 strv_free(r);
269 return NULL;
270 }
271
272 r[i] = NULL;
273 return r;
274}
275
276char *strv_join(char **l, const char *separator) {
277 char *r, *e;
278 char **s;
279 size_t n, k;
280
281 if (!separator)
282 separator = " ";
283
284 k = strlen(separator);
285
286 n = 0;
287 STRV_FOREACH(s, l) {
288 if (n != 0)
289 n += k;
290 n += strlen(*s);
291 }
292
293 if (!(r = new(char, n+1)))
294 return NULL;
295
296 e = r;
297 STRV_FOREACH(s, l) {
298 if (e != r)
299 e = stpcpy(e, separator);
300
301 e = stpcpy(e, *s);
302 }
303
8d49745c
LP
304 *e = 0;
305
5f9a22c3
LP
306 return r;
307}
308
309char **strv_append(char **l, const char *s) {
310 char **r, **k;
311
312 if (!l)
313 return strv_new(s, NULL);
314
315 if (!s)
316 return strv_copy(l);
317
318 if (!(r = new(char*, strv_length(l)+2)))
319 return NULL;
034c6ed7 320
5f9a22c3
LP
321 for (k = r; *l; k++, l++)
322 if (!(*k = strdup(*l)))
323 goto fail;
2e6c9e6b 324
5f9a22c3
LP
325 if (!(*(k++) = strdup(s)))
326 goto fail;
327
328 *k = NULL;
329 return r;
330
331fail:
332 for (k--; k >= r; k--)
333 free(*k);
334
100a76ee
LP
335 free(r);
336
5f9a22c3 337 return NULL;
034c6ed7 338}
cba8922f 339
5f9a22c3 340char **strv_uniq(char **l) {
cba8922f
LP
341 char **i;
342
5f9a22c3
LP
343 /* Drops duplicate entries. The first identical string will be
344 * kept, the others dropped */
345
cba8922f 346 STRV_FOREACH(i, l)
5f9a22c3
LP
347 strv_remove(i+1, *i);
348
349 return l;
350}
351
352char **strv_remove(char **l, const char *s) {
353 char **f, **t;
354
355 if (!l)
356 return NULL;
357
358 /* Drops every occurence of s in the string list */
359
360 for (f = t = l; *f; f++) {
361
362 if (streq(*f, s)) {
363 free(*f);
364 continue;
365 }
366
367 *(t++) = *f;
368 }
cba8922f 369
5f9a22c3
LP
370 *t = NULL;
371 return l;
cba8922f 372}
2e6c9e6b
LP
373
374static int env_append(char **r, char ***k, char **a) {
375 assert(r);
376 assert(k);
5b6319dc
LP
377
378 if (!a)
379 return 0;
2e6c9e6b
LP
380
381 /* Add the entries of a to *k unless they already exist in *r
382 * in which case they are overriden instead. This assumes
a6ff950e 383 * there is enough space in the r array. */
2e6c9e6b
LP
384
385 for (; *a; a++) {
386 char **j;
387 size_t n = strcspn(*a, "=") + 1;
388
389 for (j = r; j < *k; j++)
390 if (strncmp(*j, *a, n) == 0)
391 break;
392
393 if (j >= *k)
394 (*k)++;
395 else
396 free(*j);
397
398 if (!(*j = strdup(*a)))
399 return -ENOMEM;
400 }
401
402 return 0;
403}
404
5b6319dc 405char **strv_env_merge(unsigned n_lists, ...) {
2e6c9e6b
LP
406 size_t n = 0;
407 char **l, **k, **r;
408 va_list ap;
5b6319dc 409 unsigned i;
2e6c9e6b
LP
410
411 /* Merges an arbitrary number of environment sets */
412
5b6319dc
LP
413 va_start(ap, n_lists);
414 for (i = 0; i < n_lists; i++) {
415 l = va_arg(ap, char**);
416 n += strv_length(l);
2e6c9e6b 417 }
5b6319dc 418 va_end(ap);
2e6c9e6b
LP
419
420 if (!(r = new(char*, n+1)))
421 return NULL;
422
423 k = r;
424
5b6319dc
LP
425 va_start(ap, n_lists);
426 for (i = 0; i < n_lists; i++) {
427 l = va_arg(ap, char**);
428 if (env_append(r, &k, l) < 0)
2e6c9e6b 429 goto fail;
2e6c9e6b 430 }
5b6319dc 431 va_end(ap);
2e6c9e6b
LP
432
433 *k = NULL;
434
435 return r;
436
437fail:
438 for (k--; k >= r; k--)
439 free(*k);
440
441 free(r);
442
443 return NULL;
444}
1137a57c
LP
445
446static bool env_match(const char *t, const char *pattern) {
447 assert(t);
448 assert(pattern);
449
450 /* pattern a matches string a
451 * a matches a=
452 * a matches a=b
453 * a= matches a=
454 * a=b matches a=b
455 * a= does not match a
456 * a=b does not match a=
457 * a=b does not match a
458 * a=b does not match a=c */
459
460 if (streq(t, pattern))
461 return true;
462
463 if (!strchr(pattern, '=')) {
464 size_t l = strlen(pattern);
465
466 return strncmp(t, pattern, l) == 0 && t[l] == '=';
467 }
468
469 return false;
470}
471
5b6319dc 472char **strv_env_delete(char **x, unsigned n_lists, ...) {
1137a57c
LP
473 size_t n = 0, i = 0;
474 char **l, **k, **r, **j;
475 va_list ap;
476
477 /* Deletes every entry fromx that is mentioned in the other
478 * string lists */
479
480 n = strv_length(x);
481
482 if (!(r = new(char*, n+1)))
483 return NULL;
484
485 STRV_FOREACH(k, x) {
5b6319dc 486 va_start(ap, n_lists);
1137a57c 487
5b6319dc
LP
488 for (i = 0; i < n_lists; i++) {
489 l = va_arg(ap, char**);
1137a57c
LP
490 STRV_FOREACH(j, l)
491 if (env_match(*k, *j))
492 goto delete;
5b6319dc 493 }
1137a57c
LP
494
495 va_end(ap);
496
497 if (!(r[i++] = strdup(*k))) {
498 strv_free(r);
499 return NULL;
500 }
501
502 continue;
503
504 delete:
505 va_end(ap);
506 }
507
508 r[i] = NULL;
509
510 assert(i <= n);
511
512 return r;
513}
ddb26e18
LP
514
515char **strv_env_set(char **x, const char *p) {
516
517 char **k, **r;
518
519 if (!(r = new(char*, strv_length(x)+2)))
520 return NULL;
521
522 k = r;
523 if (env_append(r, &k, x) < 0)
524 goto fail;
525
526 if (!(*(k++) = strdup(p)))
527 goto fail;
528
529 *k = NULL;
530
531 return r;
532
533fail:
534 for (k--; k >= r; k--)
535 free(*k);
536
537 free(r);
538
539 return NULL;
540
541}
fab56fc5
LP
542
543char *strv_env_get_with_length(char **l, const char *name, size_t k) {
544 char **i;
545
546 assert(name);
547
548 STRV_FOREACH(i, l)
549 if (strncmp(*i, name, k) == 0 &&
550 (*i)[k] == '=')
551 return *i + k + 1;
552
553 return NULL;
554}
555
556char *strv_env_get(char **l, const char *name) {
557 return strv_env_get_with_length(l, name, strlen(name));
558}
a6ff950e
LP
559
560char **strv_env_clean(char **l) {
561 char **r, **ret;
562
563 for (r = ret = l; *l; l++) {
564 const char *equal;
565
566 equal = strchr(*l, '=');
567
568 if (equal && equal[1] == 0) {
569 free(*l);
570 continue;
571 }
572
573 *(r++) = *l;
574 }
575
576 *r = NULL;
577
578 return ret;
579}