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