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