]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/fileio.c
path-util: introduce path_simplify()
[thirdparty/systemd.git] / src / basic / fileio.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
a5c32cff
HH
2/***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
a5c32cff
HH
6***/
7
11c3a366
TA
8#include <errno.h>
9#include <fcntl.h>
10#include <limits.h>
11#include <stdarg.h>
12#include <stdint.h>
35bbbf85 13#include <stdio_ext.h>
11c3a366
TA
14#include <stdlib.h>
15#include <string.h>
7accca23 16#include <sys/mman.h>
11c3a366
TA
17#include <sys/stat.h>
18#include <sys/types.h>
a5c32cff 19#include <unistd.h>
cda134ab 20
b5efdb8a 21#include "alloc-util.h"
4f5dd394 22#include "ctype.h"
f4b51a2d 23#include "def.h"
99003e01 24#include "env-util.h"
4f5dd394 25#include "escape.h"
3ffd4af2
LP
26#include "fd-util.h"
27#include "fileio.h"
f4f15635 28#include "fs-util.h"
0d39fa9c 29#include "hexdecoct.h"
93cc7779
TA
30#include "log.h"
31#include "macro.h"
1d9ed171 32#include "missing.h"
33d52ab9 33#include "parse-util.h"
0d39fa9c 34#include "path-util.h"
df0ff127 35#include "process-util.h"
0d39fa9c 36#include "random-util.h"
33d52ab9 37#include "stdio-util.h"
07630cea 38#include "string-util.h"
a5c32cff 39#include "strv.h"
93cc7779 40#include "time-util.h"
affb60b1 41#include "umask-util.h"
335c46b5 42#include "utf8.h"
a5c32cff 43
c2d11a63
VC
44#define READ_FULL_BYTES_MAX (4U*1024U*1024U)
45
b1837133
LP
46int write_string_stream_ts(
47 FILE *f,
48 const char *line,
49 WriteStringFileFlags flags,
50 struct timespec *ts) {
dacd6cee 51
91dc2bf7 52 bool needs_nl;
be83711c 53 int r;
91dc2bf7 54
717603e3
LP
55 assert(f);
56 assert(line);
57
ba8b8c9e
MG
58 if (ferror(f))
59 return -EIO;
60
91dc2bf7
LP
61 needs_nl = !(flags & WRITE_STRING_FILE_AVOID_NEWLINE) && !endswith(line, "\n");
62
63 if (needs_nl && (flags & WRITE_STRING_FILE_DISABLE_BUFFER)) {
64 /* If STDIO buffering was disabled, then let's append the newline character to the string itself, so
65 * that the write goes out in one go, instead of two */
66
67 line = strjoina(line, "\n");
68 needs_nl = false;
69 }
70
94d3b60f
MG
71 if (fputs(line, f) == EOF)
72 return -errno;
73
91dc2bf7 74 if (needs_nl)
94d3b60f
MG
75 if (fputc('\n', f) == EOF)
76 return -errno;
a5c32cff 77
be83711c
CL
78 if (flags & WRITE_STRING_FILE_SYNC)
79 r = fflush_sync_and_check(f);
80 else
81 r = fflush_and_check(f);
82 if (r < 0)
83 return r;
84
39c38d77
ZJS
85 if (ts) {
86 struct timespec twice[2] = {*ts, *ts};
87
88 if (futimens(fileno(f), twice) < 0)
89 return -errno;
90 }
91
be83711c 92 return 0;
a5c32cff
HH
93}
94
2eabcc77
LP
95static int write_string_file_atomic(
96 const char *fn,
97 const char *line,
b1837133 98 WriteStringFileFlags flags,
2eabcc77
LP
99 struct timespec *ts) {
100
a5c32cff
HH
101 _cleanup_fclose_ FILE *f = NULL;
102 _cleanup_free_ char *p = NULL;
103 int r;
104
105 assert(fn);
106 assert(line);
107
108 r = fopen_temporary(fn, &f, &p);
109 if (r < 0)
110 return r;
111
35bbbf85 112 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
0d39fa9c 113 (void) fchmod_umask(fileno(f), 0644);
a5c32cff 114
b1837133 115 r = write_string_stream_ts(f, line, flags, ts);
9dd1b1e8
LP
116 if (r < 0)
117 goto fail;
118
119 if (rename(p, fn) < 0) {
120 r = -errno;
121 goto fail;
a5c32cff
HH
122 }
123
9dd1b1e8 124 return 0;
a5c32cff 125
9dd1b1e8
LP
126fail:
127 (void) unlink(p);
a5c32cff
HH
128 return r;
129}
130
b1837133
LP
131int write_string_file_ts(
132 const char *fn,
133 const char *line,
134 WriteStringFileFlags flags,
135 struct timespec *ts) {
136
4c1fc3e4 137 _cleanup_fclose_ FILE *f = NULL;
eb3da901 138 int q, r;
4c1fc3e4
DM
139
140 assert(fn);
141 assert(line);
142
265710c2
AJ
143 /* We don't know how to verify whether the file contents was already on-disk. */
144 assert(!((flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE) && (flags & WRITE_STRING_FILE_SYNC)));
0675e94a 145
4c1fc3e4
DM
146 if (flags & WRITE_STRING_FILE_ATOMIC) {
147 assert(flags & WRITE_STRING_FILE_CREATE);
148
b1837133 149 r = write_string_file_atomic(fn, line, flags, ts);
eb3da901
LP
150 if (r < 0)
151 goto fail;
152
153 return r;
39c38d77 154 } else
234519ae 155 assert(!ts);
4c1fc3e4
DM
156
157 if (flags & WRITE_STRING_FILE_CREATE) {
158 f = fopen(fn, "we");
eb3da901
LP
159 if (!f) {
160 r = -errno;
161 goto fail;
162 }
4c1fc3e4
DM
163 } else {
164 int fd;
165
166 /* We manually build our own version of fopen(..., "we") that
167 * works without O_CREAT */
168 fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY);
eb3da901
LP
169 if (fd < 0) {
170 r = -errno;
171 goto fail;
172 }
4c1fc3e4
DM
173
174 f = fdopen(fd, "we");
175 if (!f) {
eb3da901 176 r = -errno;
4c1fc3e4 177 safe_close(fd);
eb3da901 178 goto fail;
4c1fc3e4
DM
179 }
180 }
181
35bbbf85
LP
182 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
183
12ec9c30
TSH
184 if (flags & WRITE_STRING_FILE_DISABLE_BUFFER)
185 setvbuf(f, NULL, _IONBF, 0);
186
b1837133 187 r = write_string_stream_ts(f, line, flags, ts);
eb3da901
LP
188 if (r < 0)
189 goto fail;
190
191 return 0;
192
193fail:
194 if (!(flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE))
195 return r;
196
197 f = safe_fclose(f);
198
199 /* OK, the operation failed, but let's see if the right
200 * contents in place already. If so, eat up the error. */
201
202 q = verify_file(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
203 if (q <= 0)
204 return r;
205
206 return 0;
4c1fc3e4
DM
207}
208
a5c32cff
HH
209int read_one_line_file(const char *fn, char **line) {
210 _cleanup_fclose_ FILE *f = NULL;
2e33df93 211 int r;
a5c32cff
HH
212
213 assert(fn);
214 assert(line);
215
216 f = fopen(fn, "re");
217 if (!f)
218 return -errno;
219
35bbbf85
LP
220 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
221
2e33df93
ZJS
222 r = read_line(f, LONG_LINE_MAX, line);
223 return r < 0 ? r : 0;
a5c32cff
HH
224}
225
eb3da901
LP
226int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
227 _cleanup_fclose_ FILE *f = NULL;
228 _cleanup_free_ char *buf = NULL;
229 size_t l, k;
15dee3f0 230
eb3da901
LP
231 assert(fn);
232 assert(blob);
233
234 l = strlen(blob);
235
236 if (accept_extra_nl && endswith(blob, "\n"))
237 accept_extra_nl = false;
238
239 buf = malloc(l + accept_extra_nl + 1);
240 if (!buf)
241 return -ENOMEM;
242
243 f = fopen(fn, "re");
244 if (!f)
245 return -errno;
246
35bbbf85
LP
247 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
248
eb3da901
LP
249 /* We try to read one byte more than we need, so that we know whether we hit eof */
250 errno = 0;
251 k = fread(buf, 1, l + accept_extra_nl + 1, f);
252 if (ferror(f))
253 return errno > 0 ? -errno : -EIO;
254
255 if (k != l && k != l + accept_extra_nl)
256 return 0;
257 if (memcmp(buf, blob, l) != 0)
258 return 0;
259 if (k > l && buf[l] != '\n')
260 return 0;
15dee3f0 261
eb3da901 262 return 1;
15dee3f0
LP
263}
264
717603e3 265int read_full_stream(FILE *f, char **contents, size_t *size) {
a5c32cff
HH
266 _cleanup_free_ char *buf = NULL;
267 struct stat st;
c4054ddf
LP
268 size_t n, l;
269 int fd;
a5c32cff 270
717603e3 271 assert(f);
a5c32cff
HH
272 assert(contents);
273
717603e3 274 n = LINE_MAX;
a5c32cff 275
c4054ddf
LP
276 fd = fileno(f);
277 if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen(), let's
278 * optimize our buffering) */
717603e3 279
c4054ddf
LP
280 if (fstat(fileno(f), &st) < 0)
281 return -errno;
282
283 if (S_ISREG(st.st_mode)) {
717603e3 284
c4054ddf
LP
285 /* Safety check */
286 if (st.st_size > READ_FULL_BYTES_MAX)
287 return -E2BIG;
288
289 /* Start with the right file size, but be prepared for files from /proc which generally report a file
290 * size of 0. Note that we increase the size to read here by one, so that the first read attempt
291 * already makes us notice the EOF. */
292 if (st.st_size > 0)
293 n = st.st_size + 1;
294 }
717603e3 295 }
a5c32cff 296
717603e3 297 l = 0;
a5c32cff
HH
298 for (;;) {
299 char *t;
300 size_t k;
301
c2d11a63 302 t = realloc(buf, n + 1);
a5c32cff
HH
303 if (!t)
304 return -ENOMEM;
305
306 buf = t;
5a89faf0 307 errno = 0;
a5c32cff 308 k = fread(buf + l, 1, n - l, f);
c2d11a63
VC
309 if (k > 0)
310 l += k;
a5c32cff 311
c2d11a63 312 if (ferror(f))
5a89faf0 313 return errno > 0 ? -errno : -EIO;
a5c32cff 314
c2d11a63 315 if (feof(f))
a5c32cff 316 break;
a5c32cff 317
c2d11a63
VC
318 /* We aren't expecting fread() to return a short read outside
319 * of (error && eof), assert buffer is full and enlarge buffer.
320 */
321 assert(l == n);
a5c32cff
HH
322
323 /* Safety check */
c2d11a63 324 if (n >= READ_FULL_BYTES_MAX)
a5c32cff 325 return -E2BIG;
c2d11a63 326
82b103a7 327 n = MIN(n * 2, READ_FULL_BYTES_MAX);
a5c32cff
HH
328 }
329
330 buf[l] = 0;
ae2a15bc 331 *contents = TAKE_PTR(buf);
a5c32cff
HH
332
333 if (size)
334 *size = l;
335
336 return 0;
337}
338
717603e3
LP
339int read_full_file(const char *fn, char **contents, size_t *size) {
340 _cleanup_fclose_ FILE *f = NULL;
341
342 assert(fn);
343 assert(contents);
344
345 f = fopen(fn, "re");
346 if (!f)
347 return -errno;
348
35bbbf85
LP
349 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
350
717603e3
LP
351 return read_full_stream(f, contents, size);
352}
353
f73141d7 354static int parse_env_file_internal(
717603e3 355 FILE *f,
a5c32cff 356 const char *fname,
f73141d7 357 const char *newline,
335c46b5 358 int (*push) (const char *filename, unsigned line,
a5f6c30d
MS
359 const char *key, char *value, void *userdata, int *n_pushed),
360 void *userdata,
361 int *n_pushed) {
f73141d7 362
2b77f67e 363 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;
d56fced9 364 _cleanup_free_ char *contents = NULL, *key = NULL, *value = NULL;
335c46b5 365 unsigned line = 1;
d56fced9
LP
366 char *p;
367 int r;
a5c32cff 368
f73141d7
LP
369 enum {
370 PRE_KEY,
371 KEY,
f73141d7
LP
372 PRE_VALUE,
373 VALUE,
374 VALUE_ESCAPE,
375 SINGLE_QUOTE_VALUE,
376 SINGLE_QUOTE_VALUE_ESCAPE,
377 DOUBLE_QUOTE_VALUE,
378 DOUBLE_QUOTE_VALUE_ESCAPE,
379 COMMENT,
380 COMMENT_ESCAPE
381 } state = PRE_KEY;
a5c32cff 382
f73141d7 383 assert(newline);
a5c32cff 384
717603e3
LP
385 if (f)
386 r = read_full_stream(f, &contents, NULL);
387 else
388 r = read_full_file(fname, &contents, NULL);
1c17cbed 389 if (r < 0)
a5c32cff
HH
390 return r;
391
f73141d7
LP
392 for (p = contents; *p; p++) {
393 char c = *p;
394
395 switch (state) {
396
397 case PRE_KEY:
ebc05a09 398 if (strchr(COMMENTS, c))
f73141d7
LP
399 state = COMMENT;
400 else if (!strchr(WHITESPACE, c)) {
401 state = KEY;
2b77f67e
LP
402 last_key_whitespace = (size_t) -1;
403
d56fced9
LP
404 if (!GREEDY_REALLOC(key, key_alloc, n_key+2))
405 return -ENOMEM;
f73141d7
LP
406
407 key[n_key++] = c;
408 }
409 break;
410
411 case KEY:
412 if (strchr(newline, c)) {
413 state = PRE_KEY;
313cefa1 414 line++;
f73141d7 415 n_key = 0;
2b77f67e 416 } else if (c == '=') {
f73141d7 417 state = PRE_VALUE;
2b77f67e
LP
418 last_value_whitespace = (size_t) -1;
419 } else {
420 if (!strchr(WHITESPACE, c))
421 last_key_whitespace = (size_t) -1;
422 else if (last_key_whitespace == (size_t) -1)
423 last_key_whitespace = n_key;
424
d56fced9
LP
425 if (!GREEDY_REALLOC(key, key_alloc, n_key+2))
426 return -ENOMEM;
f73141d7
LP
427
428 key[n_key++] = c;
429 }
a5c32cff 430
f73141d7
LP
431 break;
432
f73141d7 433 case PRE_VALUE:
98f59e59 434 if (strchr(newline, c)) {
f73141d7 435 state = PRE_KEY;
313cefa1 436 line++;
f73141d7 437 key[n_key] = 0;
a5c32cff 438
f73141d7
LP
439 if (value)
440 value[n_value] = 0;
a5c32cff 441
ebc05a09 442 /* strip trailing whitespace from key */
2b77f67e
LP
443 if (last_key_whitespace != (size_t) -1)
444 key[last_key_whitespace] = 0;
ebc05a09 445
a5f6c30d 446 r = push(fname, line, key, value, userdata, n_pushed);
f73141d7 447 if (r < 0)
d56fced9 448 return r;
f73141d7
LP
449
450 n_key = 0;
451 value = NULL;
452 value_alloc = n_value = 0;
2b77f67e 453
f73141d7
LP
454 } else if (c == '\'')
455 state = SINGLE_QUOTE_VALUE;
456 else if (c == '\"')
457 state = DOUBLE_QUOTE_VALUE;
458 else if (c == '\\')
459 state = VALUE_ESCAPE;
460 else if (!strchr(WHITESPACE, c)) {
461 state = VALUE;
462
d56fced9
LP
463 if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
464 return -ENOMEM;
f73141d7
LP
465
466 value[n_value++] = c;
467 }
468
469 break;
470
471 case VALUE:
472 if (strchr(newline, c)) {
473 state = PRE_KEY;
313cefa1 474 line++;
98f59e59 475
f73141d7
LP
476 key[n_key] = 0;
477
478 if (value)
479 value[n_value] = 0;
480
2b77f67e
LP
481 /* Chomp off trailing whitespace from value */
482 if (last_value_whitespace != (size_t) -1)
483 value[last_value_whitespace] = 0;
f73141d7 484
ebc05a09 485 /* strip trailing whitespace from key */
2b77f67e
LP
486 if (last_key_whitespace != (size_t) -1)
487 key[last_key_whitespace] = 0;
ebc05a09 488
a5f6c30d 489 r = push(fname, line, key, value, userdata, n_pushed);
f73141d7 490 if (r < 0)
d56fced9 491 return r;
f73141d7
LP
492
493 n_key = 0;
494 value = NULL;
495 value_alloc = n_value = 0;
2b77f67e 496
f73141d7
LP
497 } else if (c == '\\') {
498 state = VALUE_ESCAPE;
2b77f67e 499 last_value_whitespace = (size_t) -1;
f73141d7
LP
500 } else {
501 if (!strchr(WHITESPACE, c))
2b77f67e
LP
502 last_value_whitespace = (size_t) -1;
503 else if (last_value_whitespace == (size_t) -1)
504 last_value_whitespace = n_value;
f73141d7 505
d56fced9
LP
506 if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
507 return -ENOMEM;
f73141d7
LP
508
509 value[n_value++] = c;
510 }
511
512 break;
513
514 case VALUE_ESCAPE:
515 state = VALUE;
516
517 if (!strchr(newline, c)) {
518 /* Escaped newlines we eat up entirely */
d56fced9
LP
519 if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
520 return -ENOMEM;
f73141d7
LP
521
522 value[n_value++] = c;
523 }
524 break;
525
526 case SINGLE_QUOTE_VALUE:
527 if (c == '\'')
528 state = PRE_VALUE;
529 else if (c == '\\')
530 state = SINGLE_QUOTE_VALUE_ESCAPE;
531 else {
d56fced9
LP
532 if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
533 return -ENOMEM;
a5c32cff 534
f73141d7
LP
535 value[n_value++] = c;
536 }
a5c32cff 537
f73141d7 538 break;
a5c32cff 539
f73141d7
LP
540 case SINGLE_QUOTE_VALUE_ESCAPE:
541 state = SINGLE_QUOTE_VALUE;
a5c32cff 542
f73141d7 543 if (!strchr(newline, c)) {
d56fced9
LP
544 if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
545 return -ENOMEM;
a5c32cff 546
f73141d7
LP
547 value[n_value++] = c;
548 }
549 break;
550
551 case DOUBLE_QUOTE_VALUE:
552 if (c == '\"')
553 state = PRE_VALUE;
554 else if (c == '\\')
555 state = DOUBLE_QUOTE_VALUE_ESCAPE;
556 else {
d56fced9
LP
557 if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
558 return -ENOMEM;
a5c32cff 559
f73141d7
LP
560 value[n_value++] = c;
561 }
562
563 break;
564
565 case DOUBLE_QUOTE_VALUE_ESCAPE:
566 state = DOUBLE_QUOTE_VALUE;
a5c32cff 567
f73141d7 568 if (!strchr(newline, c)) {
d56fced9
LP
569 if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
570 return -ENOMEM;
a5c32cff 571
f73141d7 572 value[n_value++] = c;
a5c32cff 573 }
f73141d7
LP
574 break;
575
576 case COMMENT:
577 if (c == '\\')
578 state = COMMENT_ESCAPE;
335c46b5 579 else if (strchr(newline, c)) {
f73141d7 580 state = PRE_KEY;
313cefa1 581 line++;
335c46b5 582 }
f73141d7
LP
583 break;
584
585 case COMMENT_ESCAPE:
586 state = COMMENT;
587 break;
a5c32cff 588 }
f73141d7
LP
589 }
590
371328dc
ZJS
591 if (IN_SET(state,
592 PRE_VALUE,
593 VALUE,
594 VALUE_ESCAPE,
595 SINGLE_QUOTE_VALUE,
596 SINGLE_QUOTE_VALUE_ESCAPE,
597 DOUBLE_QUOTE_VALUE,
598 DOUBLE_QUOTE_VALUE_ESCAPE)) {
a5c32cff 599
f73141d7
LP
600 key[n_key] = 0;
601
602 if (value)
603 value[n_value] = 0;
604
2b77f67e
LP
605 if (state == VALUE)
606 if (last_value_whitespace != (size_t) -1)
607 value[last_value_whitespace] = 0;
608
ebc05a09 609 /* strip trailing whitespace from key */
2b77f67e
LP
610 if (last_key_whitespace != (size_t) -1)
611 key[last_key_whitespace] = 0;
ebc05a09 612
a5f6c30d 613 r = push(fname, line, key, value, userdata, n_pushed);
f73141d7 614 if (r < 0)
d56fced9
LP
615 return r;
616
617 value = NULL;
a5c32cff
HH
618 }
619
f73141d7 620 return 0;
a5c32cff
HH
621}
622
ac466818 623static int check_utf8ness_and_warn(
717603e3 624 const char *filename, unsigned line,
ac466818 625 const char *key, char *value) {
f27f0e21
GB
626
627 if (!utf8_is_valid(key)) {
3587161a 628 _cleanup_free_ char *p = NULL;
550a40ec 629
717603e3
LP
630 p = utf8_escape_invalid(key);
631 log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p);
f27f0e21
GB
632 return -EINVAL;
633 }
634
635 if (value && !utf8_is_valid(value)) {
3587161a 636 _cleanup_free_ char *p = NULL;
550a40ec 637
717603e3
LP
638 p = utf8_escape_invalid(value);
639 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, p);
f27f0e21
GB
640 return -EINVAL;
641 }
a5c32cff 642
ac466818
ZJS
643 return 0;
644}
645
646static int parse_env_file_push(
647 const char *filename, unsigned line,
648 const char *key, char *value,
649 void *userdata,
650 int *n_pushed) {
651
652 const char *k;
653 va_list aq, *ap = userdata;
654 int r;
655
656 r = check_utf8ness_and_warn(filename, line, key, value);
657 if (r < 0)
658 return r;
659
f27f0e21 660 va_copy(aq, *ap);
a5c32cff 661
f27f0e21
GB
662 while ((k = va_arg(aq, const char *))) {
663 char **v;
a5c32cff 664
f27f0e21 665 v = va_arg(aq, char **);
a5c32cff 666
f27f0e21
GB
667 if (streq(key, k)) {
668 va_end(aq);
669 free(*v);
670 *v = value;
a5f6c30d
MS
671
672 if (n_pushed)
673 (*n_pushed)++;
674
f27f0e21 675 return 1;
f73141d7 676 }
335c46b5 677 }
a5c32cff 678
f27f0e21 679 va_end(aq);
f73141d7 680 free(value);
717603e3 681
f73141d7
LP
682 return 0;
683}
a5c32cff 684
080dfda8 685int parse_env_filev(
1a5a177e 686 FILE *f,
f73141d7 687 const char *fname,
080dfda8
LP
688 const char *newline,
689 va_list ap) {
a5c32cff 690
a5f6c30d 691 int r, n_pushed = 0;
080dfda8 692 va_list aq;
a5c32cff 693
f73141d7
LP
694 if (!newline)
695 newline = NEWLINE;
a5c32cff 696
080dfda8
LP
697 va_copy(aq, ap);
698 r = parse_env_file_internal(f, fname, newline, parse_env_file_push, &aq, &n_pushed);
699 va_end(aq);
700 if (r < 0)
701 return r;
702
703 return n_pushed;
704}
705
706int parse_env_file(
707 FILE *f,
708 const char *fname,
709 const char *newline,
710 ...) {
711
712 va_list ap;
713 int r;
714
f73141d7 715 va_start(ap, newline);
080dfda8 716 r = parse_env_filev(f, fname, newline, ap);
f73141d7 717 va_end(ap);
a5c32cff 718
080dfda8 719 return r;
f73141d7 720}
a5c32cff 721
717603e3
LP
722static int load_env_file_push(
723 const char *filename, unsigned line,
724 const char *key, char *value,
a5f6c30d
MS
725 void *userdata,
726 int *n_pushed) {
f27f0e21
GB
727 char ***m = userdata;
728 char *p;
729 int r;
a5c32cff 730
ac466818
ZJS
731 r = check_utf8ness_and_warn(filename, line, key, value);
732 if (r < 0)
733 return r;
a5c32cff 734
99003e01 735 p = strjoin(key, "=", value);
f27f0e21
GB
736 if (!p)
737 return -ENOMEM;
335c46b5 738
99003e01
ZJS
739 r = strv_env_replace(m, p);
740 if (r < 0) {
741 free(p);
f27f0e21 742 return r;
99003e01 743 }
a5c32cff 744
a5f6c30d
MS
745 if (n_pushed)
746 (*n_pushed)++;
747
f73141d7
LP
748 free(value);
749 return 0;
750}
751
717603e3
LP
752int load_env_file(FILE *f, const char *fname, const char *newline, char ***rl) {
753 char **m = NULL;
754 int r;
755
756 if (!newline)
757 newline = NEWLINE;
758
a5f6c30d 759 r = parse_env_file_internal(f, fname, newline, load_env_file_push, &m, NULL);
717603e3
LP
760 if (r < 0) {
761 strv_free(m);
762 return r;
763 }
764
765 *rl = m;
766 return 0;
767}
768
769static int load_env_file_push_pairs(
770 const char *filename, unsigned line,
771 const char *key, char *value,
a5f6c30d
MS
772 void *userdata,
773 int *n_pushed) {
717603e3
LP
774 char ***m = userdata;
775 int r;
776
ac466818
ZJS
777 r = check_utf8ness_and_warn(filename, line, key, value);
778 if (r < 0)
779 return r;
717603e3
LP
780
781 r = strv_extend(m, key);
782 if (r < 0)
783 return -ENOMEM;
784
785 if (!value) {
786 r = strv_extend(m, "");
787 if (r < 0)
788 return -ENOMEM;
789 } else {
790 r = strv_push(m, value);
791 if (r < 0)
792 return r;
793 }
794
a5f6c30d
MS
795 if (n_pushed)
796 (*n_pushed)++;
797
717603e3
LP
798 return 0;
799}
800
801int load_env_file_pairs(FILE *f, const char *fname, const char *newline, char ***rl) {
f73141d7
LP
802 char **m = NULL;
803 int r;
a5c32cff 804
f73141d7
LP
805 if (!newline)
806 newline = NEWLINE;
807
a5f6c30d 808 r = parse_env_file_internal(f, fname, newline, load_env_file_push_pairs, &m, NULL);
f73141d7
LP
809 if (r < 0) {
810 strv_free(m);
811 return r;
a5c32cff
HH
812 }
813
814 *rl = m;
a5c32cff
HH
815 return 0;
816}
817
37f3ffca
RS
818static int merge_env_file_push(
819 const char *filename, unsigned line,
820 const char *key, char *value,
821 void *userdata,
822 int *n_pushed) {
823
824 char ***env = userdata;
825 char *expanded_value;
826
827 assert(env);
828
184d1904
ZJS
829 if (!value) {
830 log_error("%s:%u: invalid syntax (around \"%s\"), ignoring.", strna(filename), line, key);
831 return 0;
832 }
833
834 if (!env_name_is_valid(key)) {
835 log_error("%s:%u: invalid variable name \"%s\", ignoring.", strna(filename), line, key);
2ea8081a 836 free(value);
184d1904
ZJS
837 return 0;
838 }
839
ccad1fd0 840 expanded_value = replace_env(value, *env,
b82f58bf
RS
841 REPLACE_ENV_USE_ENVIRONMENT|
842 REPLACE_ENV_ALLOW_BRACELESS|
843 REPLACE_ENV_ALLOW_EXTENDED);
37f3ffca
RS
844 if (!expanded_value)
845 return -ENOMEM;
846
847 free_and_replace(value, expanded_value);
848
849 return load_env_file_push(filename, line, key, value, env, n_pushed);
850}
851
852int merge_env_file(
853 char ***env,
854 FILE *f,
855 const char *fname) {
856
ccad1fd0 857 /* NOTE: this function supports braceful and braceless variable expansions,
b82f58bf 858 * plus "extended" substitutions, unlike other exported parsing functions.
ccad1fd0
ZJS
859 */
860
37f3ffca
RS
861 return parse_env_file_internal(f, fname, NEWLINE, merge_env_file_push, env, NULL);
862}
863
768100ef
LP
864static void write_env_var(FILE *f, const char *v) {
865 const char *p;
866
867 p = strchr(v, '=');
868 if (!p) {
869 /* Fallback */
4b61c875
LP
870 fputs_unlocked(v, f);
871 fputc_unlocked('\n', f);
768100ef
LP
872 return;
873 }
874
875 p++;
4b61c875 876 fwrite_unlocked(v, 1, p-v, f);
768100ef 877
0ce5a806 878 if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) {
4b61c875 879 fputc_unlocked('\"', f);
768100ef
LP
880
881 for (; *p; p++) {
0ce5a806 882 if (strchr(SHELL_NEED_ESCAPE, *p))
4b61c875 883 fputc_unlocked('\\', f);
768100ef 884
4b61c875 885 fputc_unlocked(*p, f);
768100ef
LP
886 }
887
4b61c875 888 fputc_unlocked('\"', f);
768100ef 889 } else
4b61c875 890 fputs_unlocked(p, f);
768100ef 891
4b61c875 892 fputc_unlocked('\n', f);
768100ef
LP
893}
894
a5c32cff 895int write_env_file(const char *fname, char **l) {
7fd1b19b 896 _cleanup_fclose_ FILE *f = NULL;
736937e5
LP
897 _cleanup_free_ char *p = NULL;
898 char **i;
a5c32cff
HH
899 int r;
900
736937e5
LP
901 assert(fname);
902
a5c32cff
HH
903 r = fopen_temporary(fname, &f, &p);
904 if (r < 0)
905 return r;
906
35bbbf85
LP
907 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
908 (void) fchmod_umask(fileno(f), 0644);
a5c32cff 909
768100ef
LP
910 STRV_FOREACH(i, l)
911 write_env_var(f, *i);
a5c32cff 912
736937e5
LP
913 r = fflush_and_check(f);
914 if (r >= 0) {
915 if (rename(p, fname) >= 0)
916 return 0;
a5c32cff 917
736937e5 918 r = -errno;
a5c32cff
HH
919 }
920
736937e5 921 unlink(p);
a5c32cff
HH
922 return r;
923}
68fee104
ZJS
924
925int executable_is_script(const char *path, char **interpreter) {
c8b32e11 926 _cleanup_free_ char *line = NULL;
99c61f6b 927 size_t len;
68fee104 928 char *ans;
99c61f6b 929 int r;
68fee104
ZJS
930
931 assert(path);
932
933 r = read_one_line_file(path, &line);
99c61f6b
LP
934 if (r == -ENOBUFS) /* First line overly long? if so, then it's not a script */
935 return 0;
68fee104
ZJS
936 if (r < 0)
937 return r;
938
939 if (!startswith(line, "#!"))
940 return 0;
941
942 ans = strstrip(line + 2);
943 len = strcspn(ans, " \t");
944
945 if (len == 0)
946 return 0;
947
948 ans = strndup(ans, len);
949 if (!ans)
950 return -ENOMEM;
951
952 *interpreter = ans;
953 return 1;
954}
69ab8088
ZJS
955
956/**
0a7b53bd 957 * Retrieve one field from a file like /proc/self/status. pattern
c4cd1d4d
AK
958 * should not include whitespace or the delimiter (':'). pattern matches only
959 * the beginning of a line. Whitespace before ':' is skipped. Whitespace and
960 * zeros after the ':' will be skipped. field must be freed afterwards.
961 * terminator specifies the terminating characters of the field value (not
962 * included in the value).
69ab8088 963 */
c4cd1d4d 964int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) {
69ab8088 965 _cleanup_free_ char *status = NULL;
90110825 966 char *t, *f;
69ab8088
ZJS
967 size_t len;
968 int r;
969
c4cd1d4d 970 assert(terminator);
69ab8088 971 assert(filename);
7ff7394d 972 assert(pattern);
69ab8088
ZJS
973 assert(field);
974
975 r = read_full_file(filename, &status, NULL);
976 if (r < 0)
977 return r;
978
c4cd1d4d
AK
979 t = status;
980
981 do {
982 bool pattern_ok;
983
984 do {
985 t = strstr(t, pattern);
986 if (!t)
987 return -ENOENT;
988
989 /* Check that pattern occurs in beginning of line. */
990 pattern_ok = (t == status || t[-1] == '\n');
991
992 t += strlen(pattern);
993
994 } while (!pattern_ok);
995
996 t += strspn(t, " \t");
997 if (!*t)
998 return -ENOENT;
999
1000 } while (*t != ':');
1001
1002 t++;
69ab8088 1003
4ec29144 1004 if (*t) {
1e5413f7
ZJS
1005 t += strspn(t, " \t");
1006
1007 /* Also skip zeros, because when this is used for
1008 * capabilities, we don't want the zeros. This way the
1009 * same capability set always maps to the same string,
1010 * irrespective of the total capability set size. For
1011 * other numbers it shouldn't matter. */
1012 t += strspn(t, "0");
4ec29144
ZJS
1013 /* Back off one char if there's nothing but whitespace
1014 and zeros */
1e5413f7 1015 if (!*t || isspace(*t))
313cefa1 1016 t--;
4ec29144 1017 }
69ab8088 1018
c4cd1d4d 1019 len = strcspn(t, terminator);
69ab8088 1020
90110825
LP
1021 f = strndup(t, len);
1022 if (!f)
69ab8088
ZJS
1023 return -ENOMEM;
1024
90110825 1025 *field = f;
69ab8088
ZJS
1026 return 0;
1027}
0d39fa9c
LP
1028
1029DIR *xopendirat(int fd, const char *name, int flags) {
1030 int nfd;
1031 DIR *d;
1032
1033 assert(!(flags & O_CREAT));
1034
1035 nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0);
1036 if (nfd < 0)
1037 return NULL;
1038
1039 d = fdopendir(nfd);
1040 if (!d) {
1041 safe_close(nfd);
1042 return NULL;
1043 }
1044
1045 return d;
1046}
1047
1048static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) {
1049 char **i;
1050
1051 assert(path);
1052 assert(mode);
1053 assert(_f);
1054
1055 if (!path_strv_resolve_uniq(search, root))
1056 return -ENOMEM;
1057
1058 STRV_FOREACH(i, search) {
1059 _cleanup_free_ char *p = NULL;
1060 FILE *f;
1061
1062 if (root)
605405c6 1063 p = strjoin(root, *i, "/", path);
0d39fa9c 1064 else
605405c6 1065 p = strjoin(*i, "/", path);
0d39fa9c
LP
1066 if (!p)
1067 return -ENOMEM;
1068
1069 f = fopen(p, mode);
1070 if (f) {
1071 *_f = f;
1072 return 0;
1073 }
1074
1075 if (errno != ENOENT)
1076 return -errno;
1077 }
1078
1079 return -ENOENT;
1080}
1081
1082int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f) {
1083 _cleanup_strv_free_ char **copy = NULL;
1084
1085 assert(path);
1086 assert(mode);
1087 assert(_f);
1088
1089 if (path_is_absolute(path)) {
1090 FILE *f;
1091
1092 f = fopen(path, mode);
1093 if (f) {
1094 *_f = f;
1095 return 0;
1096 }
1097
1098 return -errno;
1099 }
1100
1101 copy = strv_copy((char**) search);
1102 if (!copy)
1103 return -ENOMEM;
1104
1105 return search_and_fopen_internal(path, mode, root, copy, _f);
1106}
1107
1108int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) {
1109 _cleanup_strv_free_ char **s = NULL;
1110
1111 if (path_is_absolute(path)) {
1112 FILE *f;
1113
1114 f = fopen(path, mode);
1115 if (f) {
1116 *_f = f;
1117 return 0;
1118 }
1119
1120 return -errno;
1121 }
1122
1123 s = strv_split_nulstr(search);
1124 if (!s)
1125 return -ENOMEM;
1126
1127 return search_and_fopen_internal(path, mode, root, s, _f);
1128}
1129
1130int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
1131 FILE *f;
1132 char *t;
1133 int r, fd;
1134
1135 assert(path);
1136 assert(_f);
1137 assert(_temp_path);
1138
1139 r = tempfn_xxxxxx(path, NULL, &t);
1140 if (r < 0)
1141 return r;
1142
646853bd 1143 fd = mkostemp_safe(t);
0d39fa9c
LP
1144 if (fd < 0) {
1145 free(t);
1146 return -errno;
1147 }
1148
1149 f = fdopen(fd, "we");
1150 if (!f) {
1151 unlink_noerrno(t);
1152 free(t);
1153 safe_close(fd);
1154 return -errno;
1155 }
1156
1157 *_f = f;
1158 *_temp_path = t;
1159
1160 return 0;
1161}
1162
1163int fflush_and_check(FILE *f) {
1164 assert(f);
1165
1166 errno = 0;
1167 fflush(f);
1168
1169 if (ferror(f))
f5e5c28f 1170 return errno > 0 ? -errno : -EIO;
0d39fa9c
LP
1171
1172 return 0;
1173}
1174
0675e94a
AJ
1175int fflush_sync_and_check(FILE *f) {
1176 int r;
1177
1178 assert(f);
1179
1180 r = fflush_and_check(f);
1181 if (r < 0)
1182 return r;
1183
1184 if (fsync(fileno(f)) < 0)
1185 return -errno;
1186
8ac2f74f
LP
1187 r = fsync_directory_of_file(fileno(f));
1188 if (r < 0)
1189 return r;
1190
0675e94a
AJ
1191 return 0;
1192}
1193
61233823 1194/* This is much like mkostemp() but is subject to umask(). */
646853bd 1195int mkostemp_safe(char *pattern) {
3587161a 1196 _cleanup_umask_ mode_t u = 0;
0d39fa9c
LP
1197 int fd;
1198
1199 assert(pattern);
1200
1201 u = umask(077);
1202
646853bd 1203 fd = mkostemp(pattern, O_CLOEXEC);
0d39fa9c
LP
1204 if (fd < 0)
1205 return -errno;
1206
1207 return fd;
1208}
1209
0d39fa9c
LP
1210int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
1211 const char *fn;
1212 char *t;
1213
1214 assert(p);
1215 assert(ret);
1216
1217 /*
1218 * Turns this:
1219 * /foo/bar/waldo
1220 *
1221 * Into this:
1222 * /foo/bar/.#<extra>waldoXXXXXX
1223 */
1224
1225 fn = basename(p);
1226 if (!filename_is_valid(fn))
1227 return -EINVAL;
1228
ad5d4b17 1229 extra = strempty(extra);
0d39fa9c
LP
1230
1231 t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1);
1232 if (!t)
1233 return -ENOMEM;
1234
1235 strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX");
1236
858d36c1 1237 *ret = path_simplify(t, false);
0d39fa9c
LP
1238 return 0;
1239}
1240
1241int tempfn_random(const char *p, const char *extra, char **ret) {
1242 const char *fn;
1243 char *t, *x;
1244 uint64_t u;
1245 unsigned i;
1246
1247 assert(p);
1248 assert(ret);
1249
1250 /*
1251 * Turns this:
1252 * /foo/bar/waldo
1253 *
1254 * Into this:
1255 * /foo/bar/.#<extra>waldobaa2a261115984a9
1256 */
1257
1258 fn = basename(p);
1259 if (!filename_is_valid(fn))
1260 return -EINVAL;
1261
ad5d4b17 1262 extra = strempty(extra);
0d39fa9c
LP
1263
1264 t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1);
1265 if (!t)
1266 return -ENOMEM;
1267
1268 x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn);
1269
1270 u = random_u64();
1271 for (i = 0; i < 16; i++) {
1272 *(x++) = hexchar(u & 0xF);
1273 u >>= 4;
1274 }
1275
1276 *x = 0;
1277
858d36c1 1278 *ret = path_simplify(t, false);
0d39fa9c
LP
1279 return 0;
1280}
1281
1282int tempfn_random_child(const char *p, const char *extra, char **ret) {
1283 char *t, *x;
1284 uint64_t u;
1285 unsigned i;
992e8f22 1286 int r;
0d39fa9c 1287
0d39fa9c
LP
1288 assert(ret);
1289
1290 /* Turns this:
1291 * /foo/bar/waldo
1292 * Into this:
1293 * /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
1294 */
1295
992e8f22
LP
1296 if (!p) {
1297 r = tmp_dir(&p);
1298 if (r < 0)
1299 return r;
1300 }
1301
ad5d4b17 1302 extra = strempty(extra);
0d39fa9c
LP
1303
1304 t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1);
1305 if (!t)
1306 return -ENOMEM;
1307
1308 x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
1309
1310 u = random_u64();
1311 for (i = 0; i < 16; i++) {
1312 *(x++) = hexchar(u & 0xF);
1313 u >>= 4;
1314 }
1315
1316 *x = 0;
1317
858d36c1 1318 *ret = path_simplify(t, false);
0d39fa9c
LP
1319 return 0;
1320}
33d52ab9
LP
1321
1322int write_timestamp_file_atomic(const char *fn, usec_t n) {
1323 char ln[DECIMAL_STR_MAX(n)+2];
1324
1325 /* Creates a "timestamp" file, that contains nothing but a
1326 * usec_t timestamp, formatted in ASCII. */
1327
1328 if (n <= 0 || n >= USEC_INFINITY)
1329 return -ERANGE;
1330
1331 xsprintf(ln, USEC_FMT "\n", n);
1332
1333 return write_string_file(fn, ln, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
1334}
1335
1336int read_timestamp_file(const char *fn, usec_t *ret) {
1337 _cleanup_free_ char *ln = NULL;
1338 uint64_t t;
1339 int r;
1340
1341 r = read_one_line_file(fn, &ln);
1342 if (r < 0)
1343 return r;
1344
1345 r = safe_atou64(ln, &t);
1346 if (r < 0)
1347 return r;
1348
1349 if (t <= 0 || t >= (uint64_t) USEC_INFINITY)
1350 return -ERANGE;
1351
1352 *ret = (usec_t) t;
1353 return 0;
1354}
d390f8ef
LP
1355
1356int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space) {
1357 int r;
1358
1359 assert(s);
1360
1361 /* Outputs the specified string with fputs(), but optionally prefixes it with a separator. The *space parameter
1362 * when specified shall initially point to a boolean variable initialized to false. It is set to true after the
1363 * first invocation. This call is supposed to be use in loops, where a separator shall be inserted between each
1364 * element, but not before the first one. */
1365
1366 if (!f)
1367 f = stdout;
1368
1369 if (space) {
1370 if (!separator)
1371 separator = " ";
1372
1373 if (*space) {
1374 r = fputs(separator, f);
1375 if (r < 0)
1376 return r;
1377 }
1378
1379 *space = true;
1380 }
1381
1382 return fputs(s, f);
1383}
03532f0a
LP
1384
1385int open_tmpfile_unlinkable(const char *directory, int flags) {
1386 char *p;
992e8f22 1387 int fd, r;
03532f0a 1388
992e8f22
LP
1389 if (!directory) {
1390 r = tmp_dir(&directory);
1391 if (r < 0)
1392 return r;
1393 }
03532f0a
LP
1394
1395 /* Returns an unlinked temporary file that cannot be linked into the file system anymore */
1396
03532f0a
LP
1397 /* Try O_TMPFILE first, if it is supported */
1398 fd = open(directory, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR);
1399 if (fd >= 0)
1400 return fd;
03532f0a
LP
1401
1402 /* Fall back to unguessable name + unlinking */
1403 p = strjoina(directory, "/systemd-tmp-XXXXXX");
1404
646853bd 1405 fd = mkostemp_safe(p);
03532f0a
LP
1406 if (fd < 0)
1407 return fd;
1408
1409 (void) unlink(p);
1410
1411 return fd;
1412}
1413
1414int open_tmpfile_linkable(const char *target, int flags, char **ret_path) {
1415 _cleanup_free_ char *tmp = NULL;
1416 int r, fd;
1417
1418 assert(target);
1419 assert(ret_path);
1420
1421 /* Don't allow O_EXCL, as that has a special meaning for O_TMPFILE */
1422 assert((flags & O_EXCL) == 0);
1423
1424 /* Creates a temporary file, that shall be renamed to "target" later. If possible, this uses O_TMPFILE – in
1425 * which case "ret_path" will be returned as NULL. If not possible a the tempoary path name used is returned in
1426 * "ret_path". Use link_tmpfile() below to rename the result after writing the file in full. */
1427
03532f0a
LP
1428 {
1429 _cleanup_free_ char *dn = NULL;
1430
1431 dn = dirname_malloc(target);
1432 if (!dn)
1433 return -ENOMEM;
1434
1435 fd = open(dn, O_TMPFILE|flags, 0640);
1436 if (fd >= 0) {
1437 *ret_path = NULL;
1438 return fd;
1439 }
1440
1441 log_debug_errno(errno, "Failed to use O_TMPFILE on %s: %m", dn);
1442 }
03532f0a
LP
1443
1444 r = tempfn_random(target, NULL, &tmp);
1445 if (r < 0)
1446 return r;
1447
1448 fd = open(tmp, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|flags, 0640);
1449 if (fd < 0)
1450 return -errno;
1451
ae2a15bc 1452 *ret_path = TAKE_PTR(tmp);
03532f0a
LP
1453
1454 return fd;
1455}
1456
504afd7c
ZJS
1457int open_serialization_fd(const char *ident) {
1458 int fd = -1;
1459
1460 fd = memfd_create(ident, MFD_CLOEXEC);
1461 if (fd < 0) {
1462 const char *path;
1463
df0ff127 1464 path = getpid_cached() == 1 ? "/run/systemd" : "/tmp";
504afd7c
ZJS
1465 fd = open_tmpfile_unlinkable(path, O_RDWR|O_CLOEXEC);
1466 if (fd < 0)
1467 return fd;
1468
1469 log_debug("Serializing %s to %s.", ident, path);
1470 } else
1471 log_debug("Serializing %s to memfd.", ident);
1472
1473 return fd;
1474}
1475
03532f0a
LP
1476int link_tmpfile(int fd, const char *path, const char *target) {
1477
1478 assert(fd >= 0);
1479 assert(target);
1480
1481 /* Moves a temporary file created with open_tmpfile() above into its final place. if "path" is NULL an fd
1482 * created with O_TMPFILE is assumed, and linkat() is used. Otherwise it is assumed O_TMPFILE is not supported
1483 * on the directory, and renameat2() is used instead.
1484 *
f8e2f4d6 1485 * Note that in both cases we will not replace existing files. This is because linkat() does not support this
03532f0a
LP
1486 * operation currently (renameat2() does), and there is no nice way to emulate this. */
1487
1488 if (path) {
1489 if (rename_noreplace(AT_FDCWD, path, AT_FDCWD, target) < 0)
1490 return -errno;
1491 } else {
fbd0b64f 1492 char proc_fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
03532f0a
LP
1493
1494 xsprintf(proc_fd_path, "/proc/self/fd/%i", fd);
1495
1496 if (linkat(AT_FDCWD, proc_fd_path, AT_FDCWD, target, AT_SYMLINK_FOLLOW) < 0)
1497 return -errno;
1498 }
1499
1500 return 0;
1501}
03c2b288
LP
1502
1503int read_nul_string(FILE *f, char **ret) {
1504 _cleanup_free_ char *x = NULL;
1505 size_t allocated = 0, n = 0;
1506
1507 assert(f);
1508 assert(ret);
1509
1510 /* Reads a NUL-terminated string from the specified file. */
1511
1512 for (;;) {
1513 int c;
1514
1515 if (!GREEDY_REALLOC(x, allocated, n+2))
1516 return -ENOMEM;
1517
1518 c = fgetc(f);
1519 if (c == 0) /* Terminate at NUL byte */
1520 break;
1521 if (c == EOF) {
1522 if (ferror(f))
1523 return -errno;
1524 break; /* Terminate at EOF */
1525 }
1526
1527 x[n++] = (char) c;
1528 }
1529
1530 if (x)
1531 x[n] = 0;
1532 else {
1533 x = new0(char, 1);
1534 if (!x)
1535 return -ENOMEM;
1536 }
1537
ae2a15bc 1538 *ret = TAKE_PTR(x);
03c2b288
LP
1539
1540 return 0;
1541}
676bcb0f
LP
1542
1543int mkdtemp_malloc(const char *template, char **ret) {
1544 char *p;
1545
1546 assert(template);
1547 assert(ret);
1548
1549 p = strdup(template);
1550 if (!p)
1551 return -ENOMEM;
1552
1553 if (!mkdtemp(p)) {
1554 free(p);
1555 return -errno;
1556 }
1557
1558 *ret = p;
1559 return 0;
1560}
4f9a66a3 1561
57d6f700 1562DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, funlockfile);
f858e514 1563
4f9a66a3
LP
1564int read_line(FILE *f, size_t limit, char **ret) {
1565 _cleanup_free_ char *buffer = NULL;
1566 size_t n = 0, allocated = 0, count = 0;
4f9a66a3
LP
1567
1568 assert(f);
1569
1570 /* Something like a bounded version of getline().
1571 *
1572 * Considers EOF, \n and \0 end of line delimiters, and does not include these delimiters in the string
1573 * returned.
1574 *
1575 * Returns the number of bytes read from the files (i.e. including delimiters — this hence usually differs from
1576 * the number of characters in the returned string). When EOF is hit, 0 is returned.
1577 *
1578 * The input parameter limit is the maximum numbers of characters in the returned string, i.e. excluding
1579 * delimiters. If the limit is hit we fail and return -ENOBUFS.
1580 *
1581 * If a line shall be skipped ret may be initialized as NULL. */
1582
1583 if (ret) {
1584 if (!GREEDY_REALLOC(buffer, allocated, 1))
1585 return -ENOMEM;
1586 }
1587
f858e514 1588 {
3f691417 1589 _unused_ _cleanup_(funlockfilep) FILE *flocked = f;
f858e514 1590 flockfile(f);
4f9a66a3 1591
f858e514
ZJS
1592 for (;;) {
1593 int c;
4f9a66a3 1594
f858e514
ZJS
1595 if (n >= limit)
1596 return -ENOBUFS;
4f9a66a3 1597
f858e514
ZJS
1598 errno = 0;
1599 c = fgetc_unlocked(f);
1600 if (c == EOF) {
1601 /* if we read an error, and have no data to return, then propagate the error */
1602 if (ferror_unlocked(f) && n == 0)
1603 return errno > 0 ? -errno : -EIO;
1604
1605 break;
4f9a66a3
LP
1606 }
1607
f858e514 1608 count++;
4f9a66a3 1609
f858e514
ZJS
1610 if (IN_SET(c, '\n', 0)) /* Reached a delimiter */
1611 break;
4f9a66a3 1612
f858e514
ZJS
1613 if (ret) {
1614 if (!GREEDY_REALLOC(buffer, allocated, n + 2))
1615 return -ENOMEM;
4f9a66a3 1616
f858e514 1617 buffer[n] = (char) c;
4f9a66a3
LP
1618 }
1619
f858e514 1620 n++;
4f9a66a3 1621 }
4f9a66a3
LP
1622 }
1623
4f9a66a3
LP
1624 if (ret) {
1625 buffer[n] = 0;
1626
1cc6c93a 1627 *ret = TAKE_PTR(buffer);
4f9a66a3
LP
1628 }
1629
1630 return (int) count;
1631}