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