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