]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/fileio.c
networkd: optinally use DHCP lease domain info for routing only
[thirdparty/systemd.git] / src / basic / fileio.c
CommitLineData
a5c32cff
HH
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
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 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
11c3a366
TA
22#include <errno.h>
23#include <fcntl.h>
24#include <limits.h>
25#include <stdarg.h>
26#include <stdint.h>
27#include <stdlib.h>
28#include <string.h>
29#include <sys/stat.h>
30#include <sys/types.h>
a5c32cff 31#include <unistd.h>
cda134ab 32
b5efdb8a 33#include "alloc-util.h"
4f5dd394
LP
34#include "ctype.h"
35#include "escape.h"
3ffd4af2
LP
36#include "fd-util.h"
37#include "fileio.h"
f4f15635 38#include "fs-util.h"
0d39fa9c 39#include "hexdecoct.h"
93cc7779
TA
40#include "log.h"
41#include "macro.h"
33d52ab9 42#include "parse-util.h"
0d39fa9c
LP
43#include "path-util.h"
44#include "random-util.h"
33d52ab9 45#include "stdio-util.h"
07630cea 46#include "string-util.h"
a5c32cff 47#include "strv.h"
93cc7779 48#include "time-util.h"
affb60b1 49#include "umask-util.h"
335c46b5 50#include "utf8.h"
a5c32cff 51
40beecdb 52int write_string_stream(FILE *f, const char *line, bool enforce_newline) {
dacd6cee 53
717603e3
LP
54 assert(f);
55 assert(line);
56
fec6fc6b 57 fputs(line, f);
40beecdb 58 if (enforce_newline && !endswith(line, "\n"))
a5c32cff
HH
59 fputc('\n', f);
60
dacd6cee 61 return fflush_and_check(f);
a5c32cff
HH
62}
63
4c1fc3e4 64static int write_string_file_atomic(const char *fn, const char *line, bool enforce_newline) {
a5c32cff
HH
65 _cleanup_fclose_ FILE *f = NULL;
66 _cleanup_free_ char *p = NULL;
67 int r;
68
69 assert(fn);
70 assert(line);
71
72 r = fopen_temporary(fn, &f, &p);
73 if (r < 0)
74 return r;
75
0d39fa9c 76 (void) fchmod_umask(fileno(f), 0644);
a5c32cff 77
4c1fc3e4 78 r = write_string_stream(f, line, enforce_newline);
f2997962 79 if (r >= 0) {
a5c32cff
HH
80 if (rename(p, fn) < 0)
81 r = -errno;
a5c32cff
HH
82 }
83
a5c32cff 84 if (r < 0)
0d39fa9c 85 (void) unlink(p);
a5c32cff
HH
86
87 return r;
88}
89
4c1fc3e4
DM
90int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) {
91 _cleanup_fclose_ FILE *f = NULL;
eb3da901 92 int q, r;
4c1fc3e4
DM
93
94 assert(fn);
95 assert(line);
96
97 if (flags & WRITE_STRING_FILE_ATOMIC) {
98 assert(flags & WRITE_STRING_FILE_CREATE);
99
eb3da901
LP
100 r = write_string_file_atomic(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
101 if (r < 0)
102 goto fail;
103
104 return r;
4c1fc3e4
DM
105 }
106
107 if (flags & WRITE_STRING_FILE_CREATE) {
108 f = fopen(fn, "we");
eb3da901
LP
109 if (!f) {
110 r = -errno;
111 goto fail;
112 }
4c1fc3e4
DM
113 } else {
114 int fd;
115
116 /* We manually build our own version of fopen(..., "we") that
117 * works without O_CREAT */
118 fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY);
eb3da901
LP
119 if (fd < 0) {
120 r = -errno;
121 goto fail;
122 }
4c1fc3e4
DM
123
124 f = fdopen(fd, "we");
125 if (!f) {
eb3da901 126 r = -errno;
4c1fc3e4 127 safe_close(fd);
eb3da901 128 goto fail;
4c1fc3e4
DM
129 }
130 }
131
eb3da901
LP
132 r = write_string_stream(f, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
133 if (r < 0)
134 goto fail;
135
136 return 0;
137
138fail:
139 if (!(flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE))
140 return r;
141
142 f = safe_fclose(f);
143
144 /* OK, the operation failed, but let's see if the right
145 * contents in place already. If so, eat up the error. */
146
147 q = verify_file(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
148 if (q <= 0)
149 return r;
150
151 return 0;
4c1fc3e4
DM
152}
153
a5c32cff
HH
154int read_one_line_file(const char *fn, char **line) {
155 _cleanup_fclose_ FILE *f = NULL;
156 char t[LINE_MAX], *c;
157
158 assert(fn);
159 assert(line);
160
161 f = fopen(fn, "re");
162 if (!f)
163 return -errno;
164
165 if (!fgets(t, sizeof(t), f)) {
166
167 if (ferror(f))
f5e5c28f 168 return errno > 0 ? -errno : -EIO;
a5c32cff
HH
169
170 t[0] = 0;
171 }
172
173 c = strdup(t);
174 if (!c)
175 return -ENOMEM;
176 truncate_nl(c);
177
178 *line = c;
179 return 0;
180}
181
eb3da901
LP
182int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
183 _cleanup_fclose_ FILE *f = NULL;
184 _cleanup_free_ char *buf = NULL;
185 size_t l, k;
15dee3f0 186
eb3da901
LP
187 assert(fn);
188 assert(blob);
189
190 l = strlen(blob);
191
192 if (accept_extra_nl && endswith(blob, "\n"))
193 accept_extra_nl = false;
194
195 buf = malloc(l + accept_extra_nl + 1);
196 if (!buf)
197 return -ENOMEM;
198
199 f = fopen(fn, "re");
200 if (!f)
201 return -errno;
202
203 /* We try to read one byte more than we need, so that we know whether we hit eof */
204 errno = 0;
205 k = fread(buf, 1, l + accept_extra_nl + 1, f);
206 if (ferror(f))
207 return errno > 0 ? -errno : -EIO;
208
209 if (k != l && k != l + accept_extra_nl)
210 return 0;
211 if (memcmp(buf, blob, l) != 0)
212 return 0;
213 if (k > l && buf[l] != '\n')
214 return 0;
15dee3f0 215
eb3da901 216 return 1;
15dee3f0
LP
217}
218
717603e3 219int read_full_stream(FILE *f, char **contents, size_t *size) {
a5c32cff
HH
220 size_t n, l;
221 _cleanup_free_ char *buf = NULL;
222 struct stat st;
223
717603e3 224 assert(f);
a5c32cff
HH
225 assert(contents);
226
a5c32cff
HH
227 if (fstat(fileno(f), &st) < 0)
228 return -errno;
229
717603e3 230 n = LINE_MAX;
a5c32cff 231
717603e3
LP
232 if (S_ISREG(st.st_mode)) {
233
234 /* Safety check */
235 if (st.st_size > 4*1024*1024)
236 return -E2BIG;
237
238 /* Start with the right file size, but be prepared for
239 * files from /proc which generally report a file size
240 * of 0 */
241 if (st.st_size > 0)
242 n = st.st_size;
243 }
a5c32cff 244
717603e3 245 l = 0;
a5c32cff
HH
246 for (;;) {
247 char *t;
248 size_t k;
249
250 t = realloc(buf, n+1);
251 if (!t)
252 return -ENOMEM;
253
254 buf = t;
255 k = fread(buf + l, 1, n - l, f);
256
257 if (k <= 0) {
258 if (ferror(f))
259 return -errno;
260
261 break;
262 }
263
264 l += k;
265 n *= 2;
266
267 /* Safety check */
268 if (n > 4*1024*1024)
269 return -E2BIG;
270 }
271
272 buf[l] = 0;
273 *contents = buf;
d78a28e3 274 buf = NULL; /* do not free */
a5c32cff
HH
275
276 if (size)
277 *size = l;
278
279 return 0;
280}
281
717603e3
LP
282int read_full_file(const char *fn, char **contents, size_t *size) {
283 _cleanup_fclose_ FILE *f = NULL;
284
285 assert(fn);
286 assert(contents);
287
288 f = fopen(fn, "re");
289 if (!f)
290 return -errno;
291
292 return read_full_stream(f, contents, size);
293}
294
f73141d7 295static int parse_env_file_internal(
717603e3 296 FILE *f,
a5c32cff 297 const char *fname,
f73141d7 298 const char *newline,
335c46b5 299 int (*push) (const char *filename, unsigned line,
a5f6c30d
MS
300 const char *key, char *value, void *userdata, int *n_pushed),
301 void *userdata,
302 int *n_pushed) {
f73141d7
LP
303
304 _cleanup_free_ char *contents = NULL, *key = NULL;
2b77f67e 305 size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = (size_t) -1, last_key_whitespace = (size_t) -1;
f73141d7
LP
306 char *p, *value = NULL;
307 int r;
335c46b5 308 unsigned line = 1;
a5c32cff 309
f73141d7
LP
310 enum {
311 PRE_KEY,
312 KEY,
f73141d7
LP
313 PRE_VALUE,
314 VALUE,
315 VALUE_ESCAPE,
316 SINGLE_QUOTE_VALUE,
317 SINGLE_QUOTE_VALUE_ESCAPE,
318 DOUBLE_QUOTE_VALUE,
319 DOUBLE_QUOTE_VALUE_ESCAPE,
320 COMMENT,
321 COMMENT_ESCAPE
322 } state = PRE_KEY;
a5c32cff 323
f73141d7 324 assert(newline);
a5c32cff 325
717603e3
LP
326 if (f)
327 r = read_full_stream(f, &contents, NULL);
328 else
329 r = read_full_file(fname, &contents, NULL);
1c17cbed 330 if (r < 0)
a5c32cff
HH
331 return r;
332
f73141d7
LP
333 for (p = contents; *p; p++) {
334 char c = *p;
335
336 switch (state) {
337
338 case PRE_KEY:
ebc05a09 339 if (strchr(COMMENTS, c))
f73141d7
LP
340 state = COMMENT;
341 else if (!strchr(WHITESPACE, c)) {
342 state = KEY;
2b77f67e
LP
343 last_key_whitespace = (size_t) -1;
344
ca2d3784 345 if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) {
f73141d7
LP
346 r = -ENOMEM;
347 goto fail;
348 }
349
350 key[n_key++] = c;
351 }
352 break;
353
354 case KEY:
355 if (strchr(newline, c)) {
356 state = PRE_KEY;
335c46b5 357 line ++;
f73141d7 358 n_key = 0;
2b77f67e 359 } else if (c == '=') {
f73141d7 360 state = PRE_VALUE;
2b77f67e
LP
361 last_value_whitespace = (size_t) -1;
362 } else {
363 if (!strchr(WHITESPACE, c))
364 last_key_whitespace = (size_t) -1;
365 else if (last_key_whitespace == (size_t) -1)
366 last_key_whitespace = n_key;
367
ca2d3784 368 if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) {
f73141d7
LP
369 r = -ENOMEM;
370 goto fail;
371 }
372
373 key[n_key++] = c;
374 }
a5c32cff 375
f73141d7
LP
376 break;
377
f73141d7 378 case PRE_VALUE:
98f59e59 379 if (strchr(newline, c)) {
f73141d7 380 state = PRE_KEY;
335c46b5 381 line ++;
f73141d7 382 key[n_key] = 0;
a5c32cff 383
f73141d7
LP
384 if (value)
385 value[n_value] = 0;
a5c32cff 386
ebc05a09 387 /* strip trailing whitespace from key */
2b77f67e
LP
388 if (last_key_whitespace != (size_t) -1)
389 key[last_key_whitespace] = 0;
ebc05a09 390
a5f6c30d 391 r = push(fname, line, key, value, userdata, n_pushed);
f73141d7
LP
392 if (r < 0)
393 goto fail;
394
395 n_key = 0;
396 value = NULL;
397 value_alloc = n_value = 0;
2b77f67e 398
f73141d7
LP
399 } else if (c == '\'')
400 state = SINGLE_QUOTE_VALUE;
401 else if (c == '\"')
402 state = DOUBLE_QUOTE_VALUE;
403 else if (c == '\\')
404 state = VALUE_ESCAPE;
405 else if (!strchr(WHITESPACE, c)) {
406 state = VALUE;
407
ca2d3784 408 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
f73141d7
LP
409 r = -ENOMEM;
410 goto fail;
411 }
412
413 value[n_value++] = c;
414 }
415
416 break;
417
418 case VALUE:
419 if (strchr(newline, c)) {
420 state = PRE_KEY;
335c46b5 421 line ++;
98f59e59 422
f73141d7
LP
423 key[n_key] = 0;
424
425 if (value)
426 value[n_value] = 0;
427
2b77f67e
LP
428 /* Chomp off trailing whitespace from value */
429 if (last_value_whitespace != (size_t) -1)
430 value[last_value_whitespace] = 0;
f73141d7 431
ebc05a09 432 /* strip trailing whitespace from key */
2b77f67e
LP
433 if (last_key_whitespace != (size_t) -1)
434 key[last_key_whitespace] = 0;
ebc05a09 435
a5f6c30d 436 r = push(fname, line, key, value, userdata, n_pushed);
f73141d7
LP
437 if (r < 0)
438 goto fail;
439
440 n_key = 0;
441 value = NULL;
442 value_alloc = n_value = 0;
2b77f67e 443
f73141d7
LP
444 } else if (c == '\\') {
445 state = VALUE_ESCAPE;
2b77f67e 446 last_value_whitespace = (size_t) -1;
f73141d7
LP
447 } else {
448 if (!strchr(WHITESPACE, c))
2b77f67e
LP
449 last_value_whitespace = (size_t) -1;
450 else if (last_value_whitespace == (size_t) -1)
451 last_value_whitespace = n_value;
f73141d7 452
ca2d3784 453 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
f73141d7
LP
454 r = -ENOMEM;
455 goto fail;
456 }
457
458 value[n_value++] = c;
459 }
460
461 break;
462
463 case VALUE_ESCAPE:
464 state = VALUE;
465
466 if (!strchr(newline, c)) {
467 /* Escaped newlines we eat up entirely */
ca2d3784 468 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
f73141d7
LP
469 r = -ENOMEM;
470 goto fail;
471 }
472
473 value[n_value++] = c;
474 }
475 break;
476
477 case SINGLE_QUOTE_VALUE:
478 if (c == '\'')
479 state = PRE_VALUE;
480 else if (c == '\\')
481 state = SINGLE_QUOTE_VALUE_ESCAPE;
482 else {
ca2d3784 483 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
f73141d7
LP
484 r = -ENOMEM;
485 goto fail;
486 }
a5c32cff 487
f73141d7
LP
488 value[n_value++] = c;
489 }
a5c32cff 490
f73141d7 491 break;
a5c32cff 492
f73141d7
LP
493 case SINGLE_QUOTE_VALUE_ESCAPE:
494 state = SINGLE_QUOTE_VALUE;
a5c32cff 495
f73141d7 496 if (!strchr(newline, c)) {
ca2d3784 497 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
a5c32cff 498 r = -ENOMEM;
a5c32cff
HH
499 goto fail;
500 }
501
f73141d7
LP
502 value[n_value++] = c;
503 }
504 break;
505
506 case DOUBLE_QUOTE_VALUE:
507 if (c == '\"')
508 state = PRE_VALUE;
509 else if (c == '\\')
510 state = DOUBLE_QUOTE_VALUE_ESCAPE;
511 else {
ca2d3784 512 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
f73141d7
LP
513 r = -ENOMEM;
514 goto fail;
a5c32cff
HH
515 }
516
f73141d7
LP
517 value[n_value++] = c;
518 }
519
520 break;
521
522 case DOUBLE_QUOTE_VALUE_ESCAPE:
523 state = DOUBLE_QUOTE_VALUE;
a5c32cff 524
f73141d7 525 if (!strchr(newline, c)) {
ca2d3784 526 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
f73141d7
LP
527 r = -ENOMEM;
528 goto fail;
529 }
a5c32cff 530
f73141d7 531 value[n_value++] = c;
a5c32cff 532 }
f73141d7
LP
533 break;
534
535 case COMMENT:
536 if (c == '\\')
537 state = COMMENT_ESCAPE;
335c46b5 538 else if (strchr(newline, c)) {
f73141d7 539 state = PRE_KEY;
335c46b5
ZJS
540 line ++;
541 }
f73141d7
LP
542 break;
543
544 case COMMENT_ESCAPE:
545 state = COMMENT;
546 break;
a5c32cff 547 }
f73141d7
LP
548 }
549
550 if (state == PRE_VALUE ||
551 state == VALUE ||
552 state == VALUE_ESCAPE ||
553 state == SINGLE_QUOTE_VALUE ||
554 state == SINGLE_QUOTE_VALUE_ESCAPE ||
555 state == DOUBLE_QUOTE_VALUE ||
556 state == DOUBLE_QUOTE_VALUE_ESCAPE) {
a5c32cff 557
f73141d7
LP
558 key[n_key] = 0;
559
560 if (value)
561 value[n_value] = 0;
562
2b77f67e
LP
563 if (state == VALUE)
564 if (last_value_whitespace != (size_t) -1)
565 value[last_value_whitespace] = 0;
566
ebc05a09 567 /* strip trailing whitespace from key */
2b77f67e
LP
568 if (last_key_whitespace != (size_t) -1)
569 key[last_key_whitespace] = 0;
ebc05a09 570
a5f6c30d 571 r = push(fname, line, key, value, userdata, n_pushed);
f73141d7
LP
572 if (r < 0)
573 goto fail;
a5c32cff
HH
574 }
575
f73141d7
LP
576 return 0;
577
a5c32cff 578fail:
f73141d7 579 free(value);
a5c32cff
HH
580 return r;
581}
582
717603e3
LP
583static int parse_env_file_push(
584 const char *filename, unsigned line,
585 const char *key, char *value,
a5f6c30d
MS
586 void *userdata,
587 int *n_pushed) {
335c46b5 588
f27f0e21
GB
589 const char *k;
590 va_list aq, *ap = userdata;
591
592 if (!utf8_is_valid(key)) {
717603e3 593 _cleanup_free_ char *p;
550a40ec 594
717603e3
LP
595 p = utf8_escape_invalid(key);
596 log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p);
f27f0e21
GB
597 return -EINVAL;
598 }
599
600 if (value && !utf8_is_valid(value)) {
717603e3 601 _cleanup_free_ char *p;
550a40ec 602
717603e3
LP
603 p = utf8_escape_invalid(value);
604 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, p);
f27f0e21
GB
605 return -EINVAL;
606 }
a5c32cff 607
f27f0e21 608 va_copy(aq, *ap);
a5c32cff 609
f27f0e21
GB
610 while ((k = va_arg(aq, const char *))) {
611 char **v;
a5c32cff 612
f27f0e21 613 v = va_arg(aq, char **);
a5c32cff 614
f27f0e21
GB
615 if (streq(key, k)) {
616 va_end(aq);
617 free(*v);
618 *v = value;
a5f6c30d
MS
619
620 if (n_pushed)
621 (*n_pushed)++;
622
f27f0e21 623 return 1;
f73141d7 624 }
335c46b5 625 }
a5c32cff 626
f27f0e21 627 va_end(aq);
f73141d7 628 free(value);
717603e3 629
f73141d7
LP
630 return 0;
631}
a5c32cff 632
f73141d7
LP
633int parse_env_file(
634 const char *fname,
635 const char *newline, ...) {
a5c32cff 636
f73141d7 637 va_list ap;
a5f6c30d 638 int r, n_pushed = 0;
a5c32cff 639
f73141d7
LP
640 if (!newline)
641 newline = NEWLINE;
a5c32cff 642
f73141d7 643 va_start(ap, newline);
a5f6c30d 644 r = parse_env_file_internal(NULL, fname, newline, parse_env_file_push, &ap, &n_pushed);
f73141d7 645 va_end(ap);
a5c32cff 646
a5f6c30d 647 return r < 0 ? r : n_pushed;
f73141d7 648}
a5c32cff 649
717603e3
LP
650static int load_env_file_push(
651 const char *filename, unsigned line,
652 const char *key, char *value,
a5f6c30d
MS
653 void *userdata,
654 int *n_pushed) {
f27f0e21
GB
655 char ***m = userdata;
656 char *p;
657 int r;
a5c32cff 658
f27f0e21 659 if (!utf8_is_valid(key)) {
b5d74213
ZJS
660 _cleanup_free_ char *t = utf8_escape_invalid(key);
661
717603e3 662 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t);
f27f0e21
GB
663 return -EINVAL;
664 }
665
666 if (value && !utf8_is_valid(value)) {
b5d74213
ZJS
667 _cleanup_free_ char *t = utf8_escape_invalid(value);
668
717603e3 669 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t);
f27f0e21
GB
670 return -EINVAL;
671 }
a5c32cff 672
f27f0e21
GB
673 p = strjoin(key, "=", strempty(value), NULL);
674 if (!p)
675 return -ENOMEM;
335c46b5 676
6e18964d
ZJS
677 r = strv_consume(m, p);
678 if (r < 0)
f27f0e21 679 return r;
a5c32cff 680
a5f6c30d
MS
681 if (n_pushed)
682 (*n_pushed)++;
683
f73141d7
LP
684 free(value);
685 return 0;
686}
687
717603e3
LP
688int load_env_file(FILE *f, const char *fname, const char *newline, char ***rl) {
689 char **m = NULL;
690 int r;
691
692 if (!newline)
693 newline = NEWLINE;
694
a5f6c30d 695 r = parse_env_file_internal(f, fname, newline, load_env_file_push, &m, NULL);
717603e3
LP
696 if (r < 0) {
697 strv_free(m);
698 return r;
699 }
700
701 *rl = m;
702 return 0;
703}
704
705static int load_env_file_push_pairs(
706 const char *filename, unsigned line,
707 const char *key, char *value,
a5f6c30d
MS
708 void *userdata,
709 int *n_pushed) {
717603e3
LP
710 char ***m = userdata;
711 int r;
712
713 if (!utf8_is_valid(key)) {
714 _cleanup_free_ char *t = utf8_escape_invalid(key);
715
716 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t);
717 return -EINVAL;
718 }
719
720 if (value && !utf8_is_valid(value)) {
721 _cleanup_free_ char *t = utf8_escape_invalid(value);
722
723 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t);
724 return -EINVAL;
725 }
726
727 r = strv_extend(m, key);
728 if (r < 0)
729 return -ENOMEM;
730
731 if (!value) {
732 r = strv_extend(m, "");
733 if (r < 0)
734 return -ENOMEM;
735 } else {
736 r = strv_push(m, value);
737 if (r < 0)
738 return r;
739 }
740
a5f6c30d
MS
741 if (n_pushed)
742 (*n_pushed)++;
743
717603e3
LP
744 return 0;
745}
746
747int load_env_file_pairs(FILE *f, const char *fname, const char *newline, char ***rl) {
f73141d7
LP
748 char **m = NULL;
749 int r;
a5c32cff 750
f73141d7
LP
751 if (!newline)
752 newline = NEWLINE;
753
a5f6c30d 754 r = parse_env_file_internal(f, fname, newline, load_env_file_push_pairs, &m, NULL);
f73141d7
LP
755 if (r < 0) {
756 strv_free(m);
757 return r;
a5c32cff
HH
758 }
759
760 *rl = m;
a5c32cff
HH
761 return 0;
762}
763
768100ef
LP
764static void write_env_var(FILE *f, const char *v) {
765 const char *p;
766
767 p = strchr(v, '=');
768 if (!p) {
769 /* Fallback */
770 fputs(v, f);
771 fputc('\n', f);
772 return;
773 }
774
775 p++;
776 fwrite(v, 1, p-v, f);
777
0ce5a806 778 if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) {
768100ef
LP
779 fputc('\"', f);
780
781 for (; *p; p++) {
0ce5a806 782 if (strchr(SHELL_NEED_ESCAPE, *p))
768100ef
LP
783 fputc('\\', f);
784
785 fputc(*p, f);
786 }
787
788 fputc('\"', f);
789 } else
790 fputs(p, f);
791
792 fputc('\n', f);
793}
794
a5c32cff 795int write_env_file(const char *fname, char **l) {
7fd1b19b 796 _cleanup_fclose_ FILE *f = NULL;
736937e5
LP
797 _cleanup_free_ char *p = NULL;
798 char **i;
a5c32cff
HH
799 int r;
800
736937e5
LP
801 assert(fname);
802
a5c32cff
HH
803 r = fopen_temporary(fname, &f, &p);
804 if (r < 0)
805 return r;
806
807 fchmod_umask(fileno(f), 0644);
808
768100ef
LP
809 STRV_FOREACH(i, l)
810 write_env_var(f, *i);
a5c32cff 811
736937e5
LP
812 r = fflush_and_check(f);
813 if (r >= 0) {
814 if (rename(p, fname) >= 0)
815 return 0;
a5c32cff 816
736937e5 817 r = -errno;
a5c32cff
HH
818 }
819
736937e5 820 unlink(p);
a5c32cff
HH
821 return r;
822}
68fee104
ZJS
823
824int executable_is_script(const char *path, char **interpreter) {
825 int r;
c8b32e11 826 _cleanup_free_ char *line = NULL;
68fee104
ZJS
827 int len;
828 char *ans;
829
830 assert(path);
831
832 r = read_one_line_file(path, &line);
833 if (r < 0)
834 return r;
835
836 if (!startswith(line, "#!"))
837 return 0;
838
839 ans = strstrip(line + 2);
840 len = strcspn(ans, " \t");
841
842 if (len == 0)
843 return 0;
844
845 ans = strndup(ans, len);
846 if (!ans)
847 return -ENOMEM;
848
849 *interpreter = ans;
850 return 1;
851}
69ab8088
ZJS
852
853/**
0a7b53bd 854 * Retrieve one field from a file like /proc/self/status. pattern
c4cd1d4d
AK
855 * should not include whitespace or the delimiter (':'). pattern matches only
856 * the beginning of a line. Whitespace before ':' is skipped. Whitespace and
857 * zeros after the ':' will be skipped. field must be freed afterwards.
858 * terminator specifies the terminating characters of the field value (not
859 * included in the value).
69ab8088 860 */
c4cd1d4d 861int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) {
69ab8088 862 _cleanup_free_ char *status = NULL;
90110825 863 char *t, *f;
69ab8088
ZJS
864 size_t len;
865 int r;
866
c4cd1d4d 867 assert(terminator);
69ab8088 868 assert(filename);
7ff7394d 869 assert(pattern);
69ab8088
ZJS
870 assert(field);
871
872 r = read_full_file(filename, &status, NULL);
873 if (r < 0)
874 return r;
875
c4cd1d4d
AK
876 t = status;
877
878 do {
879 bool pattern_ok;
880
881 do {
882 t = strstr(t, pattern);
883 if (!t)
884 return -ENOENT;
885
886 /* Check that pattern occurs in beginning of line. */
887 pattern_ok = (t == status || t[-1] == '\n');
888
889 t += strlen(pattern);
890
891 } while (!pattern_ok);
892
893 t += strspn(t, " \t");
894 if (!*t)
895 return -ENOENT;
896
897 } while (*t != ':');
898
899 t++;
69ab8088 900
4ec29144 901 if (*t) {
1e5413f7
ZJS
902 t += strspn(t, " \t");
903
904 /* Also skip zeros, because when this is used for
905 * capabilities, we don't want the zeros. This way the
906 * same capability set always maps to the same string,
907 * irrespective of the total capability set size. For
908 * other numbers it shouldn't matter. */
909 t += strspn(t, "0");
4ec29144
ZJS
910 /* Back off one char if there's nothing but whitespace
911 and zeros */
1e5413f7 912 if (!*t || isspace(*t))
4ec29144
ZJS
913 t --;
914 }
69ab8088 915
c4cd1d4d 916 len = strcspn(t, terminator);
69ab8088 917
90110825
LP
918 f = strndup(t, len);
919 if (!f)
69ab8088
ZJS
920 return -ENOMEM;
921
90110825 922 *field = f;
69ab8088
ZJS
923 return 0;
924}
0d39fa9c
LP
925
926DIR *xopendirat(int fd, const char *name, int flags) {
927 int nfd;
928 DIR *d;
929
930 assert(!(flags & O_CREAT));
931
932 nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0);
933 if (nfd < 0)
934 return NULL;
935
936 d = fdopendir(nfd);
937 if (!d) {
938 safe_close(nfd);
939 return NULL;
940 }
941
942 return d;
943}
944
945static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) {
946 char **i;
947
948 assert(path);
949 assert(mode);
950 assert(_f);
951
952 if (!path_strv_resolve_uniq(search, root))
953 return -ENOMEM;
954
955 STRV_FOREACH(i, search) {
956 _cleanup_free_ char *p = NULL;
957 FILE *f;
958
959 if (root)
960 p = strjoin(root, *i, "/", path, NULL);
961 else
962 p = strjoin(*i, "/", path, NULL);
963 if (!p)
964 return -ENOMEM;
965
966 f = fopen(p, mode);
967 if (f) {
968 *_f = f;
969 return 0;
970 }
971
972 if (errno != ENOENT)
973 return -errno;
974 }
975
976 return -ENOENT;
977}
978
979int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f) {
980 _cleanup_strv_free_ char **copy = NULL;
981
982 assert(path);
983 assert(mode);
984 assert(_f);
985
986 if (path_is_absolute(path)) {
987 FILE *f;
988
989 f = fopen(path, mode);
990 if (f) {
991 *_f = f;
992 return 0;
993 }
994
995 return -errno;
996 }
997
998 copy = strv_copy((char**) search);
999 if (!copy)
1000 return -ENOMEM;
1001
1002 return search_and_fopen_internal(path, mode, root, copy, _f);
1003}
1004
1005int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) {
1006 _cleanup_strv_free_ char **s = NULL;
1007
1008 if (path_is_absolute(path)) {
1009 FILE *f;
1010
1011 f = fopen(path, mode);
1012 if (f) {
1013 *_f = f;
1014 return 0;
1015 }
1016
1017 return -errno;
1018 }
1019
1020 s = strv_split_nulstr(search);
1021 if (!s)
1022 return -ENOMEM;
1023
1024 return search_and_fopen_internal(path, mode, root, s, _f);
1025}
1026
1027int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
1028 FILE *f;
1029 char *t;
1030 int r, fd;
1031
1032 assert(path);
1033 assert(_f);
1034 assert(_temp_path);
1035
1036 r = tempfn_xxxxxx(path, NULL, &t);
1037 if (r < 0)
1038 return r;
1039
1040 fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC);
1041 if (fd < 0) {
1042 free(t);
1043 return -errno;
1044 }
1045
1046 f = fdopen(fd, "we");
1047 if (!f) {
1048 unlink_noerrno(t);
1049 free(t);
1050 safe_close(fd);
1051 return -errno;
1052 }
1053
1054 *_f = f;
1055 *_temp_path = t;
1056
1057 return 0;
1058}
1059
1060int fflush_and_check(FILE *f) {
1061 assert(f);
1062
1063 errno = 0;
1064 fflush(f);
1065
1066 if (ferror(f))
f5e5c28f 1067 return errno > 0 ? -errno : -EIO;
0d39fa9c
LP
1068
1069 return 0;
1070}
1071
1072/* This is much like like mkostemp() but is subject to umask(). */
1073int mkostemp_safe(char *pattern, int flags) {
1074 _cleanup_umask_ mode_t u;
1075 int fd;
1076
1077 assert(pattern);
1078
1079 u = umask(077);
1080
1081 fd = mkostemp(pattern, flags);
1082 if (fd < 0)
1083 return -errno;
1084
1085 return fd;
1086}
1087
1088int open_tmpfile(const char *path, int flags) {
1089 char *p;
1090 int fd;
1091
1092 assert(path);
1093
1094#ifdef O_TMPFILE
1095 /* Try O_TMPFILE first, if it is supported */
1096 fd = open(path, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR);
1097 if (fd >= 0)
1098 return fd;
1099#endif
1100
1101 /* Fall back to unguessable name + unlinking */
1102 p = strjoina(path, "/systemd-tmp-XXXXXX");
1103
1104 fd = mkostemp_safe(p, flags);
1105 if (fd < 0)
1106 return fd;
1107
1108 unlink(p);
1109 return fd;
1110}
1111
1112int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
1113 const char *fn;
1114 char *t;
1115
1116 assert(p);
1117 assert(ret);
1118
1119 /*
1120 * Turns this:
1121 * /foo/bar/waldo
1122 *
1123 * Into this:
1124 * /foo/bar/.#<extra>waldoXXXXXX
1125 */
1126
1127 fn = basename(p);
1128 if (!filename_is_valid(fn))
1129 return -EINVAL;
1130
1131 if (extra == NULL)
1132 extra = "";
1133
1134 t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1);
1135 if (!t)
1136 return -ENOMEM;
1137
1138 strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX");
1139
1140 *ret = path_kill_slashes(t);
1141 return 0;
1142}
1143
1144int tempfn_random(const char *p, const char *extra, char **ret) {
1145 const char *fn;
1146 char *t, *x;
1147 uint64_t u;
1148 unsigned i;
1149
1150 assert(p);
1151 assert(ret);
1152
1153 /*
1154 * Turns this:
1155 * /foo/bar/waldo
1156 *
1157 * Into this:
1158 * /foo/bar/.#<extra>waldobaa2a261115984a9
1159 */
1160
1161 fn = basename(p);
1162 if (!filename_is_valid(fn))
1163 return -EINVAL;
1164
1165 if (!extra)
1166 extra = "";
1167
1168 t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1);
1169 if (!t)
1170 return -ENOMEM;
1171
1172 x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn);
1173
1174 u = random_u64();
1175 for (i = 0; i < 16; i++) {
1176 *(x++) = hexchar(u & 0xF);
1177 u >>= 4;
1178 }
1179
1180 *x = 0;
1181
1182 *ret = path_kill_slashes(t);
1183 return 0;
1184}
1185
1186int tempfn_random_child(const char *p, const char *extra, char **ret) {
1187 char *t, *x;
1188 uint64_t u;
1189 unsigned i;
1190
1191 assert(p);
1192 assert(ret);
1193
1194 /* Turns this:
1195 * /foo/bar/waldo
1196 * Into this:
1197 * /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
1198 */
1199
1200 if (!extra)
1201 extra = "";
1202
1203 t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1);
1204 if (!t)
1205 return -ENOMEM;
1206
1207 x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
1208
1209 u = random_u64();
1210 for (i = 0; i < 16; i++) {
1211 *(x++) = hexchar(u & 0xF);
1212 u >>= 4;
1213 }
1214
1215 *x = 0;
1216
1217 *ret = path_kill_slashes(t);
1218 return 0;
1219}
33d52ab9
LP
1220
1221int write_timestamp_file_atomic(const char *fn, usec_t n) {
1222 char ln[DECIMAL_STR_MAX(n)+2];
1223
1224 /* Creates a "timestamp" file, that contains nothing but a
1225 * usec_t timestamp, formatted in ASCII. */
1226
1227 if (n <= 0 || n >= USEC_INFINITY)
1228 return -ERANGE;
1229
1230 xsprintf(ln, USEC_FMT "\n", n);
1231
1232 return write_string_file(fn, ln, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
1233}
1234
1235int read_timestamp_file(const char *fn, usec_t *ret) {
1236 _cleanup_free_ char *ln = NULL;
1237 uint64_t t;
1238 int r;
1239
1240 r = read_one_line_file(fn, &ln);
1241 if (r < 0)
1242 return r;
1243
1244 r = safe_atou64(ln, &t);
1245 if (r < 0)
1246 return r;
1247
1248 if (t <= 0 || t >= (uint64_t) USEC_INFINITY)
1249 return -ERANGE;
1250
1251 *ret = (usec_t) t;
1252 return 0;
1253}