chiark / gitweb /
Prep v228: Condense elogind source masks (1/5)
[elogind.git] / src / basic / fileio.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <unistd.h>
23
24 #include "alloc-util.h"
25 #include "ctype.h"
26 #include "escape.h"
27 #include "fd-util.h"
28 #include "fileio.h"
29 #include "fs-util.h"
30 #include "hexdecoct.h"
31 #include "parse-util.h"
32 #include "path-util.h"
33 #include "random-util.h"
34 #include "stdio-util.h"
35 #include "string-util.h"
36 #include "strv.h"
37 #include "umask-util.h"
38 #include "utf8.h"
39 #include "util.h"
40
41 int write_string_stream(FILE *f, const char *line, bool enforce_newline) {
42
43         assert(f);
44         assert(line);
45
46         fputs(line, f);
47         if (enforce_newline && !endswith(line, "\n"))
48                 fputc('\n', f);
49
50         return fflush_and_check(f);
51 }
52
53 static int write_string_file_atomic(const char *fn, const char *line, bool enforce_newline) {
54         _cleanup_fclose_ FILE *f = NULL;
55         _cleanup_free_ char *p = NULL;
56         int r;
57
58         assert(fn);
59         assert(line);
60
61         r = fopen_temporary(fn, &f, &p);
62         if (r < 0)
63                 return r;
64
65         (void) fchmod_umask(fileno(f), 0644);
66
67         r = write_string_stream(f, line, enforce_newline);
68         if (r >= 0) {
69                 if (rename(p, fn) < 0)
70                         r = -errno;
71         }
72
73         if (r < 0)
74                 (void) unlink(p);
75
76         return r;
77 }
78
79 int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) {
80         _cleanup_fclose_ FILE *f = NULL;
81         int q, r;
82
83         assert(fn);
84         assert(line);
85
86         if (flags & WRITE_STRING_FILE_ATOMIC) {
87                 assert(flags & WRITE_STRING_FILE_CREATE);
88
89                 r = write_string_file_atomic(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
90                 if (r < 0)
91                         goto fail;
92
93                 return r;
94         }
95
96         if (flags & WRITE_STRING_FILE_CREATE) {
97                 f = fopen(fn, "we");
98                 if (!f) {
99                         r = -errno;
100                         goto fail;
101                 }
102         } else {
103                 int fd;
104
105                 /* We manually build our own version of fopen(..., "we") that
106                  * works without O_CREAT */
107                 fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY);
108                 if (fd < 0) {
109                         r = -errno;
110                         goto fail;
111                 }
112
113                 f = fdopen(fd, "we");
114                 if (!f) {
115                         r = -errno;
116                         safe_close(fd);
117                         goto fail;
118                 }
119         }
120
121         r = write_string_stream(f, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
122         if (r < 0)
123                 goto fail;
124
125         return 0;
126
127 fail:
128         if (!(flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE))
129                 return r;
130
131         f = safe_fclose(f);
132
133         /* OK, the operation failed, but let's see if the right
134          * contents in place already. If so, eat up the error. */
135
136         q = verify_file(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
137         if (q <= 0)
138                 return r;
139
140         return 0;
141 }
142
143 int read_one_line_file(const char *fn, char **line) {
144         _cleanup_fclose_ FILE *f = NULL;
145         char t[LINE_MAX], *c;
146
147         assert(fn);
148         assert(line);
149
150         f = fopen(fn, "re");
151         if (!f)
152                 return -errno;
153
154         if (!fgets(t, sizeof(t), f)) {
155
156                 if (ferror(f))
157                         return errno ? -errno : -EIO;
158
159                 t[0] = 0;
160         }
161
162         c = strdup(t);
163         if (!c)
164                 return -ENOMEM;
165         truncate_nl(c);
166
167         *line = c;
168         return 0;
169 }
170
171 int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
172         _cleanup_fclose_ FILE *f = NULL;
173         _cleanup_free_ char *buf = NULL;
174         size_t l, k;
175
176         assert(fn);
177         assert(blob);
178
179         l = strlen(blob);
180
181         if (accept_extra_nl && endswith(blob, "\n"))
182                 accept_extra_nl = false;
183
184         buf = malloc(l + accept_extra_nl + 1);
185         if (!buf)
186                 return -ENOMEM;
187
188         f = fopen(fn, "re");
189         if (!f)
190                 return -errno;
191
192         /* We try to read one byte more than we need, so that we know whether we hit eof */
193         errno = 0;
194         k = fread(buf, 1, l + accept_extra_nl + 1, f);
195         if (ferror(f))
196                 return errno > 0 ? -errno : -EIO;
197
198         if (k != l && k != l + accept_extra_nl)
199                 return 0;
200         if (memcmp(buf, blob, l) != 0)
201                 return 0;
202         if (k > l && buf[l] != '\n')
203                 return 0;
204
205         return 1;
206 }
207
208 int read_full_stream(FILE *f, char **contents, size_t *size) {
209         size_t n, l;
210         _cleanup_free_ char *buf = NULL;
211         struct stat st;
212
213         assert(f);
214         assert(contents);
215
216         if (fstat(fileno(f), &st) < 0)
217                 return -errno;
218
219         n = LINE_MAX;
220
221         if (S_ISREG(st.st_mode)) {
222
223                 /* Safety check */
224                 if (st.st_size > 4*1024*1024)
225                         return -E2BIG;
226
227                 /* Start with the right file size, but be prepared for
228                  * files from /proc which generally report a file size
229                  * of 0 */
230                 if (st.st_size > 0)
231                         n = st.st_size;
232         }
233
234         l = 0;
235         for (;;) {
236                 char *t;
237                 size_t k;
238
239                 t = realloc(buf, n+1);
240                 if (!t)
241                         return -ENOMEM;
242
243                 buf = t;
244                 k = fread(buf + l, 1, n - l, f);
245
246                 if (k <= 0) {
247                         if (ferror(f))
248                                 return -errno;
249
250                         break;
251                 }
252
253                 l += k;
254                 n *= 2;
255
256                 /* Safety check */
257                 if (n > 4*1024*1024)
258                         return -E2BIG;
259         }
260
261         buf[l] = 0;
262         *contents = buf;
263         buf = NULL; /* do not free */
264
265         if (size)
266                 *size = l;
267
268         return 0;
269 }
270
271 int read_full_file(const char *fn, char **contents, size_t *size) {
272         _cleanup_fclose_ FILE *f = NULL;
273
274         assert(fn);
275         assert(contents);
276
277         f = fopen(fn, "re");
278         if (!f)
279                 return -errno;
280
281         return read_full_stream(f, contents, size);
282 }
283
284 static int parse_env_file_internal(
285                 FILE *f,
286                 const char *fname,
287                 const char *newline,
288                 int (*push) (const char *filename, unsigned line,
289                              const char *key, char *value, void *userdata, int *n_pushed),
290                 void *userdata,
291                 int *n_pushed) {
292
293         _cleanup_free_ char *contents = NULL, *key = NULL;
294         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;
295         char *p, *value = NULL;
296         int r;
297         unsigned line = 1;
298
299         enum {
300                 PRE_KEY,
301                 KEY,
302                 PRE_VALUE,
303                 VALUE,
304                 VALUE_ESCAPE,
305                 SINGLE_QUOTE_VALUE,
306                 SINGLE_QUOTE_VALUE_ESCAPE,
307                 DOUBLE_QUOTE_VALUE,
308                 DOUBLE_QUOTE_VALUE_ESCAPE,
309                 COMMENT,
310                 COMMENT_ESCAPE
311         } state = PRE_KEY;
312
313         assert(newline);
314
315         if (f)
316                 r = read_full_stream(f, &contents, NULL);
317         else
318                 r = read_full_file(fname, &contents, NULL);
319         if (r < 0)
320                 return r;
321
322         for (p = contents; *p; p++) {
323                 char c = *p;
324
325                 switch (state) {
326
327                 case PRE_KEY:
328                         if (strchr(COMMENTS, c))
329                                 state = COMMENT;
330                         else if (!strchr(WHITESPACE, c)) {
331                                 state = KEY;
332                                 last_key_whitespace = (size_t) -1;
333
334                                 if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) {
335                                         r = -ENOMEM;
336                                         goto fail;
337                                 }
338
339                                 key[n_key++] = c;
340                         }
341                         break;
342
343                 case KEY:
344                         if (strchr(newline, c)) {
345                                 state = PRE_KEY;
346                                 line ++;
347                                 n_key = 0;
348                         } else if (c == '=') {
349                                 state = PRE_VALUE;
350                                 last_value_whitespace = (size_t) -1;
351                         } else {
352                                 if (!strchr(WHITESPACE, c))
353                                         last_key_whitespace = (size_t) -1;
354                                 else if (last_key_whitespace == (size_t) -1)
355                                          last_key_whitespace = n_key;
356
357                                 if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) {
358                                         r = -ENOMEM;
359                                         goto fail;
360                                 }
361
362                                 key[n_key++] = c;
363                         }
364
365                         break;
366
367                 case PRE_VALUE:
368                         if (strchr(newline, c)) {
369                                 state = PRE_KEY;
370                                 line ++;
371                                 key[n_key] = 0;
372
373                                 if (value)
374                                         value[n_value] = 0;
375
376                                 /* strip trailing whitespace from key */
377                                 if (last_key_whitespace != (size_t) -1)
378                                         key[last_key_whitespace] = 0;
379
380                                 r = push(fname, line, key, value, userdata, n_pushed);
381                                 if (r < 0)
382                                         goto fail;
383
384                                 n_key = 0;
385                                 value = NULL;
386                                 value_alloc = n_value = 0;
387
388                         } else if (c == '\'')
389                                 state = SINGLE_QUOTE_VALUE;
390                         else if (c == '\"')
391                                 state = DOUBLE_QUOTE_VALUE;
392                         else if (c == '\\')
393                                 state = VALUE_ESCAPE;
394                         else if (!strchr(WHITESPACE, c)) {
395                                 state = VALUE;
396
397                                 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
398                                         r = -ENOMEM;
399                                         goto fail;
400                                 }
401
402                                 value[n_value++] = c;
403                         }
404
405                         break;
406
407                 case VALUE:
408                         if (strchr(newline, c)) {
409                                 state = PRE_KEY;
410                                 line ++;
411
412                                 key[n_key] = 0;
413
414                                 if (value)
415                                         value[n_value] = 0;
416
417                                 /* Chomp off trailing whitespace from value */
418                                 if (last_value_whitespace != (size_t) -1)
419                                         value[last_value_whitespace] = 0;
420
421                                 /* strip trailing whitespace from key */
422                                 if (last_key_whitespace != (size_t) -1)
423                                         key[last_key_whitespace] = 0;
424
425                                 r = push(fname, line, key, value, userdata, n_pushed);
426                                 if (r < 0)
427                                         goto fail;
428
429                                 n_key = 0;
430                                 value = NULL;
431                                 value_alloc = n_value = 0;
432
433                         } else if (c == '\\') {
434                                 state = VALUE_ESCAPE;
435                                 last_value_whitespace = (size_t) -1;
436                         } else {
437                                 if (!strchr(WHITESPACE, c))
438                                         last_value_whitespace = (size_t) -1;
439                                 else if (last_value_whitespace == (size_t) -1)
440                                         last_value_whitespace = n_value;
441
442                                 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
443                                         r = -ENOMEM;
444                                         goto fail;
445                                 }
446
447                                 value[n_value++] = c;
448                         }
449
450                         break;
451
452                 case VALUE_ESCAPE:
453                         state = VALUE;
454
455                         if (!strchr(newline, c)) {
456                                 /* Escaped newlines we eat up entirely */
457                                 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
458                                         r = -ENOMEM;
459                                         goto fail;
460                                 }
461
462                                 value[n_value++] = c;
463                         }
464                         break;
465
466                 case SINGLE_QUOTE_VALUE:
467                         if (c == '\'')
468                                 state = PRE_VALUE;
469                         else if (c == '\\')
470                                 state = SINGLE_QUOTE_VALUE_ESCAPE;
471                         else {
472                                 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
473                                         r = -ENOMEM;
474                                         goto fail;
475                                 }
476
477                                 value[n_value++] = c;
478                         }
479
480                         break;
481
482                 case SINGLE_QUOTE_VALUE_ESCAPE:
483                         state = SINGLE_QUOTE_VALUE;
484
485                         if (!strchr(newline, c)) {
486                                 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
487                                         r = -ENOMEM;
488                                         goto fail;
489                                 }
490
491                                 value[n_value++] = c;
492                         }
493                         break;
494
495                 case DOUBLE_QUOTE_VALUE:
496                         if (c == '\"')
497                                 state = PRE_VALUE;
498                         else if (c == '\\')
499                                 state = DOUBLE_QUOTE_VALUE_ESCAPE;
500                         else {
501                                 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
502                                         r = -ENOMEM;
503                                         goto fail;
504                                 }
505
506                                 value[n_value++] = c;
507                         }
508
509                         break;
510
511                 case DOUBLE_QUOTE_VALUE_ESCAPE:
512                         state = DOUBLE_QUOTE_VALUE;
513
514                         if (!strchr(newline, c)) {
515                                 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
516                                         r = -ENOMEM;
517                                         goto fail;
518                                 }
519
520                                 value[n_value++] = c;
521                         }
522                         break;
523
524                 case COMMENT:
525                         if (c == '\\')
526                                 state = COMMENT_ESCAPE;
527                         else if (strchr(newline, c)) {
528                                 state = PRE_KEY;
529                                 line ++;
530                         }
531                         break;
532
533                 case COMMENT_ESCAPE:
534                         state = COMMENT;
535                         break;
536                 }
537         }
538
539         if (state == PRE_VALUE ||
540             state == VALUE ||
541             state == VALUE_ESCAPE ||
542             state == SINGLE_QUOTE_VALUE ||
543             state == SINGLE_QUOTE_VALUE_ESCAPE ||
544             state == DOUBLE_QUOTE_VALUE ||
545             state == DOUBLE_QUOTE_VALUE_ESCAPE) {
546
547                 key[n_key] = 0;
548
549                 if (value)
550                         value[n_value] = 0;
551
552                 if (state == VALUE)
553                         if (last_value_whitespace != (size_t) -1)
554                                 value[last_value_whitespace] = 0;
555
556                 /* strip trailing whitespace from key */
557                 if (last_key_whitespace != (size_t) -1)
558                         key[last_key_whitespace] = 0;
559
560                 r = push(fname, line, key, value, userdata, n_pushed);
561                 if (r < 0)
562                         goto fail;
563         }
564
565         return 0;
566
567 fail:
568         free(value);
569         return r;
570 }
571
572 static int parse_env_file_push(
573                 const char *filename, unsigned line,
574                 const char *key, char *value,
575                 void *userdata,
576                 int *n_pushed) {
577
578         const char *k;
579         va_list aq, *ap = userdata;
580
581         if (!utf8_is_valid(key)) {
582                 _cleanup_free_ char *p;
583
584                 p = utf8_escape_invalid(key);
585                 log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p);
586                 return -EINVAL;
587         }
588
589         if (value && !utf8_is_valid(value)) {
590                 _cleanup_free_ char *p;
591
592                 p = utf8_escape_invalid(value);
593                 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, p);
594                 return -EINVAL;
595         }
596
597         va_copy(aq, *ap);
598
599         while ((k = va_arg(aq, const char *))) {
600                 char **v;
601
602                 v = va_arg(aq, char **);
603
604                 if (streq(key, k)) {
605                         va_end(aq);
606                         free(*v);
607                         *v = value;
608
609                         if (n_pushed)
610                                 (*n_pushed)++;
611
612                         return 1;
613                 }
614         }
615
616         va_end(aq);
617         free(value);
618
619         return 0;
620 }
621
622 int parse_env_file(
623                 const char *fname,
624                 const char *newline, ...) {
625
626         va_list ap;
627         int r, n_pushed = 0;
628
629         if (!newline)
630                 newline = NEWLINE;
631
632         va_start(ap, newline);
633         r = parse_env_file_internal(NULL, fname, newline, parse_env_file_push, &ap, &n_pushed);
634         va_end(ap);
635
636         return r < 0 ? r : n_pushed;
637 }
638
639 static int load_env_file_push(
640                 const char *filename, unsigned line,
641                 const char *key, char *value,
642                 void *userdata,
643                 int *n_pushed) {
644         char ***m = userdata;
645         char *p;
646         int r;
647
648         if (!utf8_is_valid(key)) {
649                 _cleanup_free_ char *t = utf8_escape_invalid(key);
650
651                 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t);
652                 return -EINVAL;
653         }
654
655         if (value && !utf8_is_valid(value)) {
656                 _cleanup_free_ char *t = utf8_escape_invalid(value);
657
658                 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t);
659                 return -EINVAL;
660         }
661
662         p = strjoin(key, "=", strempty(value), NULL);
663         if (!p)
664                 return -ENOMEM;
665
666         r = strv_consume(m, p);
667         if (r < 0)
668                 return r;
669
670         if (n_pushed)
671                 (*n_pushed)++;
672
673         free(value);
674         return 0;
675 }
676
677 int load_env_file(FILE *f, const char *fname, const char *newline, char ***rl) {
678         char **m = NULL;
679         int r;
680
681         if (!newline)
682                 newline = NEWLINE;
683
684         r = parse_env_file_internal(f, fname, newline, load_env_file_push, &m, NULL);
685         if (r < 0) {
686                 strv_free(m);
687                 return r;
688         }
689
690         *rl = m;
691         return 0;
692 }
693
694 /// UNNEDED by elogind
695 #if 0
696 static int load_env_file_push_pairs(
697                 const char *filename, unsigned line,
698                 const char *key, char *value,
699                 void *userdata,
700                 int *n_pushed) {
701         char ***m = userdata;
702         int r;
703
704         if (!utf8_is_valid(key)) {
705                 _cleanup_free_ char *t = utf8_escape_invalid(key);
706
707                 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t);
708                 return -EINVAL;
709         }
710
711         if (value && !utf8_is_valid(value)) {
712                 _cleanup_free_ char *t = utf8_escape_invalid(value);
713
714                 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t);
715                 return -EINVAL;
716         }
717
718         r = strv_extend(m, key);
719         if (r < 0)
720                 return -ENOMEM;
721
722         if (!value) {
723                 r = strv_extend(m, "");
724                 if (r < 0)
725                         return -ENOMEM;
726         } else {
727                 r = strv_push(m, value);
728                 if (r < 0)
729                         return r;
730         }
731
732         if (n_pushed)
733                 (*n_pushed)++;
734
735         return 0;
736 }
737
738 int load_env_file_pairs(FILE *f, const char *fname, const char *newline, char ***rl) {
739         char **m = NULL;
740         int r;
741
742         if (!newline)
743                 newline = NEWLINE;
744
745         r = parse_env_file_internal(f, fname, newline, load_env_file_push_pairs, &m, NULL);
746         if (r < 0) {
747                 strv_free(m);
748                 return r;
749         }
750
751         *rl = m;
752         return 0;
753 }
754 #endif // 0
755
756 static void write_env_var(FILE *f, const char *v) {
757         const char *p;
758
759         p = strchr(v, '=');
760         if (!p) {
761                 /* Fallback */
762                 fputs(v, f);
763                 fputc('\n', f);
764                 return;
765         }
766
767         p++;
768         fwrite(v, 1, p-v, f);
769
770         if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) {
771                 fputc('\"', f);
772
773                 for (; *p; p++) {
774                         if (strchr(SHELL_NEED_ESCAPE, *p))
775                                 fputc('\\', f);
776
777                         fputc(*p, f);
778                 }
779
780                 fputc('\"', f);
781         } else
782                 fputs(p, f);
783
784         fputc('\n', f);
785 }
786
787 int write_env_file(const char *fname, char **l) {
788         _cleanup_fclose_ FILE *f = NULL;
789         _cleanup_free_ char *p = NULL;
790         char **i;
791         int r;
792
793         assert(fname);
794
795         r = fopen_temporary(fname, &f, &p);
796         if (r < 0)
797                 return r;
798
799         fchmod_umask(fileno(f), 0644);
800
801         STRV_FOREACH(i, l)
802                 write_env_var(f, *i);
803
804         r = fflush_and_check(f);
805         if (r >= 0) {
806                 if (rename(p, fname) >= 0)
807                         return 0;
808
809                 r = -errno;
810         }
811
812         unlink(p);
813         return r;
814 }
815
816 #if 0 /// UNNEEDED by elogind
817 int executable_is_script(const char *path, char **interpreter) {
818         int r;
819         _cleanup_free_ char *line = NULL;
820         int len;
821         char *ans;
822
823         assert(path);
824
825         r = read_one_line_file(path, &line);
826         if (r < 0)
827                 return r;
828
829         if (!startswith(line, "#!"))
830                 return 0;
831
832         ans = strstrip(line + 2);
833         len = strcspn(ans, " \t");
834
835         if (len == 0)
836                 return 0;
837
838         ans = strndup(ans, len);
839         if (!ans)
840                 return -ENOMEM;
841
842         *interpreter = ans;
843         return 1;
844 }
845 #endif // 0
846
847 /**
848  * Retrieve one field from a file like /proc/self/status.  pattern
849  * should not include whitespace or the delimiter (':'). pattern matches only
850  * the beginning of a line. Whitespace before ':' is skipped. Whitespace and
851  * zeros after the ':' will be skipped. field must be freed afterwards.
852  * terminator specifies the terminating characters of the field value (not
853  * included in the value).
854  */
855 int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) {
856         _cleanup_free_ char *status = NULL;
857         char *t, *f;
858         size_t len;
859         int r;
860
861         assert(terminator);
862         assert(filename);
863         assert(pattern);
864         assert(field);
865
866         r = read_full_file(filename, &status, NULL);
867         if (r < 0)
868                 return r;
869
870         t = status;
871
872         do {
873                 bool pattern_ok;
874
875                 do {
876                         t = strstr(t, pattern);
877         if (!t)
878                 return -ENOENT;
879
880                         /* Check that pattern occurs in beginning of line. */
881                         pattern_ok = (t == status || t[-1] == '\n');
882
883         t += strlen(pattern);
884
885                 } while (!pattern_ok);
886
887                 t += strspn(t, " \t");
888                 if (!*t)
889                         return -ENOENT;
890
891         } while (*t != ':');
892
893         t++;
894
895         if (*t) {
896                 t += strspn(t, " \t");
897
898                 /* Also skip zeros, because when this is used for
899                  * capabilities, we don't want the zeros. This way the
900                  * same capability set always maps to the same string,
901                  * irrespective of the total capability set size. For
902                  * other numbers it shouldn't matter. */
903                 t += strspn(t, "0");
904                 /* Back off one char if there's nothing but whitespace
905                    and zeros */
906                 if (!*t || isspace(*t))
907                         t --;
908         }
909
910         len = strcspn(t, terminator);
911
912         f = strndup(t, len);
913         if (!f)
914                 return -ENOMEM;
915
916         *field = f;
917         return 0;
918 }
919
920 DIR *xopendirat(int fd, const char *name, int flags) {
921         int nfd;
922         DIR *d;
923
924         assert(!(flags & O_CREAT));
925
926         nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0);
927         if (nfd < 0)
928                 return NULL;
929
930         d = fdopendir(nfd);
931         if (!d) {
932                 safe_close(nfd);
933                 return NULL;
934         }
935
936         return d;
937 }
938
939 static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) {
940         char **i;
941
942         assert(path);
943         assert(mode);
944         assert(_f);
945
946         if (!path_strv_resolve_uniq(search, root))
947                 return -ENOMEM;
948
949         STRV_FOREACH(i, search) {
950                 _cleanup_free_ char *p = NULL;
951                 FILE *f;
952
953                 if (root)
954                         p = strjoin(root, *i, "/", path, NULL);
955                 else
956                         p = strjoin(*i, "/", path, NULL);
957                 if (!p)
958                         return -ENOMEM;
959
960                 f = fopen(p, mode);
961                 if (f) {
962                         *_f = f;
963                         return 0;
964                 }
965
966                 if (errno != ENOENT)
967                         return -errno;
968         }
969
970         return -ENOENT;
971 }
972
973 int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f) {
974         _cleanup_strv_free_ char **copy = NULL;
975
976         assert(path);
977         assert(mode);
978         assert(_f);
979
980         if (path_is_absolute(path)) {
981                 FILE *f;
982
983                 f = fopen(path, mode);
984                 if (f) {
985                         *_f = f;
986                         return 0;
987                 }
988
989                 return -errno;
990         }
991
992         copy = strv_copy((char**) search);
993         if (!copy)
994                 return -ENOMEM;
995
996         return search_and_fopen_internal(path, mode, root, copy, _f);
997 }
998
999 #if 0 /// UNNEEDED by elogind
1000 int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) {
1001         _cleanup_strv_free_ char **s = NULL;
1002
1003         if (path_is_absolute(path)) {
1004                 FILE *f;
1005
1006                 f = fopen(path, mode);
1007                 if (f) {
1008                         *_f = f;
1009                         return 0;
1010                 }
1011
1012                 return -errno;
1013         }
1014
1015         s = strv_split_nulstr(search);
1016         if (!s)
1017                 return -ENOMEM;
1018
1019         return search_and_fopen_internal(path, mode, root, s, _f);
1020 }
1021 #endif // 0
1022
1023 int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
1024         FILE *f;
1025         char *t;
1026         int r, fd;
1027
1028         assert(path);
1029         assert(_f);
1030         assert(_temp_path);
1031
1032         r = tempfn_xxxxxx(path, NULL, &t);
1033         if (r < 0)
1034                 return r;
1035
1036         fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC);
1037         if (fd < 0) {
1038                 free(t);
1039                 return -errno;
1040         }
1041
1042         f = fdopen(fd, "we");
1043         if (!f) {
1044                 unlink_noerrno(t);
1045                 free(t);
1046                 safe_close(fd);
1047                 return -errno;
1048         }
1049
1050         *_f = f;
1051         *_temp_path = t;
1052
1053         return 0;
1054 }
1055
1056 int fflush_and_check(FILE *f) {
1057         assert(f);
1058
1059         errno = 0;
1060         fflush(f);
1061
1062         if (ferror(f))
1063                 return errno ? -errno : -EIO;
1064
1065         return 0;
1066 }
1067
1068 /* This is much like like mkostemp() but is subject to umask(). */
1069 int mkostemp_safe(char *pattern, int flags) {
1070         _cleanup_umask_ mode_t u;
1071         int fd;
1072
1073         assert(pattern);
1074
1075         u = umask(077);
1076
1077         fd = mkostemp(pattern, flags);
1078         if (fd < 0)
1079                 return -errno;
1080
1081         return fd;
1082 }
1083
1084 #if 0 /// UNNEEDED by elogind
1085 int open_tmpfile(const char *path, int flags) {
1086         char *p;
1087         int fd;
1088
1089         assert(path);
1090
1091 #ifdef O_TMPFILE
1092         /* Try O_TMPFILE first, if it is supported */
1093         fd = open(path, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR);
1094         if (fd >= 0)
1095                 return fd;
1096 #endif
1097
1098         /* Fall back to unguessable name + unlinking */
1099         p = strjoina(path, "/systemd-tmp-XXXXXX");
1100
1101         fd = mkostemp_safe(p, flags);
1102         if (fd < 0)
1103                 return fd;
1104
1105         unlink(p);
1106         return fd;
1107 }
1108 #endif // 0
1109
1110 int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
1111         const char *fn;
1112         char *t;
1113
1114         assert(p);
1115         assert(ret);
1116
1117         /*
1118          * Turns this:
1119          *         /foo/bar/waldo
1120          *
1121          * Into this:
1122          *         /foo/bar/.#<extra>waldoXXXXXX
1123          */
1124
1125         fn = basename(p);
1126         if (!filename_is_valid(fn))
1127                 return -EINVAL;
1128
1129         if (extra == NULL)
1130                 extra = "";
1131
1132         t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1);
1133         if (!t)
1134                 return -ENOMEM;
1135
1136         strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX");
1137
1138         *ret = path_kill_slashes(t);
1139         return 0;
1140 }
1141
1142 int tempfn_random(const char *p, const char *extra, char **ret) {
1143         const char *fn;
1144         char *t, *x;
1145         uint64_t u;
1146         unsigned i;
1147
1148         assert(p);
1149         assert(ret);
1150
1151         /*
1152          * Turns this:
1153          *         /foo/bar/waldo
1154          *
1155          * Into this:
1156          *         /foo/bar/.#<extra>waldobaa2a261115984a9
1157          */
1158
1159         fn = basename(p);
1160         if (!filename_is_valid(fn))
1161                 return -EINVAL;
1162
1163         if (!extra)
1164                 extra = "";
1165
1166         t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1);
1167         if (!t)
1168                 return -ENOMEM;
1169
1170         x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn);
1171
1172         u = random_u64();
1173         for (i = 0; i < 16; i++) {
1174                 *(x++) = hexchar(u & 0xF);
1175                 u >>= 4;
1176         }
1177
1178         *x = 0;
1179
1180         *ret = path_kill_slashes(t);
1181         return 0;
1182 }
1183
1184 #if 0 /// UNNEEDED by elogind
1185 int tempfn_random_child(const char *p, const char *extra, char **ret) {
1186         char *t, *x;
1187         uint64_t u;
1188         unsigned i;
1189
1190         assert(p);
1191         assert(ret);
1192
1193         /* Turns this:
1194          *         /foo/bar/waldo
1195          * Into this:
1196          *         /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
1197          */
1198
1199         if (!extra)
1200                 extra = "";
1201
1202         t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1);
1203         if (!t)
1204                 return -ENOMEM;
1205
1206         x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
1207
1208         u = random_u64();
1209         for (i = 0; i < 16; i++) {
1210                 *(x++) = hexchar(u & 0xF);
1211                 u >>= 4;
1212         }
1213
1214         *x = 0;
1215
1216         *ret = path_kill_slashes(t);
1217         return 0;
1218 }
1219
1220 int write_timestamp_file_atomic(const char *fn, usec_t n) {
1221         char ln[DECIMAL_STR_MAX(n)+2];
1222
1223         /* Creates a "timestamp" file, that contains nothing but a
1224          * usec_t timestamp, formatted in ASCII. */
1225
1226         if (n <= 0 || n >= USEC_INFINITY)
1227                 return -ERANGE;
1228
1229         xsprintf(ln, USEC_FMT "\n", n);
1230
1231         return write_string_file(fn, ln, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
1232 }
1233
1234 int read_timestamp_file(const char *fn, usec_t *ret) {
1235         _cleanup_free_ char *ln = NULL;
1236         uint64_t t;
1237         int r;
1238
1239         r = read_one_line_file(fn, &ln);
1240         if (r < 0)
1241                 return r;
1242
1243         r = safe_atou64(ln, &t);
1244         if (r < 0)
1245                 return r;
1246
1247         if (t <= 0 || t >= (uint64_t) USEC_INFINITY)
1248                 return -ERANGE;
1249
1250         *ret = (usec_t) t;
1251         return 0;
1252 }
1253 #endif // 0