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