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