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