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