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