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