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