chiark / gitweb /
Prep v228: Add remaining updates from upstream (2/3)
[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 /// UNNEEDED by elogind
817 #if 0
818 int executable_is_script(const char *path, char **interpreter) {
819         int r;
820         _cleanup_free_ char *line = NULL;
821         int len;
822         char *ans;
823
824         assert(path);
825
826         r = read_one_line_file(path, &line);
827         if (r < 0)
828                 return r;
829
830         if (!startswith(line, "#!"))
831                 return 0;
832
833         ans = strstrip(line + 2);
834         len = strcspn(ans, " \t");
835
836         if (len == 0)
837                 return 0;
838
839         ans = strndup(ans, len);
840         if (!ans)
841                 return -ENOMEM;
842
843         *interpreter = ans;
844         return 1;
845 }
846 #endif // 0
847
848 /**
849  * Retrieve one field from a file like /proc/self/status.  pattern
850  * should not include whitespace or the delimiter (':'). pattern matches only
851  * the beginning of a line. Whitespace before ':' is skipped. Whitespace and
852  * zeros after the ':' will be skipped. field must be freed afterwards.
853  * terminator specifies the terminating characters of the field value (not
854  * included in the value).
855  */
856 int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) {
857         _cleanup_free_ char *status = NULL;
858         char *t, *f;
859         size_t len;
860         int r;
861
862         assert(terminator);
863         assert(filename);
864         assert(pattern);
865         assert(field);
866
867         r = read_full_file(filename, &status, NULL);
868         if (r < 0)
869                 return r;
870
871         t = status;
872
873         do {
874                 bool pattern_ok;
875
876                 do {
877                         t = strstr(t, pattern);
878         if (!t)
879                 return -ENOENT;
880
881                         /* Check that pattern occurs in beginning of line. */
882                         pattern_ok = (t == status || t[-1] == '\n');
883
884         t += strlen(pattern);
885
886                 } while (!pattern_ok);
887
888                 t += strspn(t, " \t");
889                 if (!*t)
890                         return -ENOENT;
891
892         } while (*t != ':');
893
894         t++;
895
896         if (*t) {
897                 t += strspn(t, " \t");
898
899                 /* Also skip zeros, because when this is used for
900                  * capabilities, we don't want the zeros. This way the
901                  * same capability set always maps to the same string,
902                  * irrespective of the total capability set size. For
903                  * other numbers it shouldn't matter. */
904                 t += strspn(t, "0");
905                 /* Back off one char if there's nothing but whitespace
906                    and zeros */
907                 if (!*t || isspace(*t))
908                         t --;
909         }
910
911         len = strcspn(t, terminator);
912
913         f = strndup(t, len);
914         if (!f)
915                 return -ENOMEM;
916
917         *field = f;
918         return 0;
919 }
920
921 DIR *xopendirat(int fd, const char *name, int flags) {
922         int nfd;
923         DIR *d;
924
925         assert(!(flags & O_CREAT));
926
927         nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0);
928         if (nfd < 0)
929                 return NULL;
930
931         d = fdopendir(nfd);
932         if (!d) {
933                 safe_close(nfd);
934                 return NULL;
935         }
936
937         return d;
938 }
939
940 static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) {
941         char **i;
942
943         assert(path);
944         assert(mode);
945         assert(_f);
946
947         if (!path_strv_resolve_uniq(search, root))
948                 return -ENOMEM;
949
950         STRV_FOREACH(i, search) {
951                 _cleanup_free_ char *p = NULL;
952                 FILE *f;
953
954                 if (root)
955                         p = strjoin(root, *i, "/", path, NULL);
956                 else
957                         p = strjoin(*i, "/", path, NULL);
958                 if (!p)
959                         return -ENOMEM;
960
961                 f = fopen(p, mode);
962                 if (f) {
963                         *_f = f;
964                         return 0;
965                 }
966
967                 if (errno != ENOENT)
968                         return -errno;
969         }
970
971         return -ENOENT;
972 }
973
974 int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f) {
975         _cleanup_strv_free_ char **copy = NULL;
976
977         assert(path);
978         assert(mode);
979         assert(_f);
980
981         if (path_is_absolute(path)) {
982                 FILE *f;
983
984                 f = fopen(path, mode);
985                 if (f) {
986                         *_f = f;
987                         return 0;
988                 }
989
990                 return -errno;
991         }
992
993         copy = strv_copy((char**) search);
994         if (!copy)
995                 return -ENOMEM;
996
997         return search_and_fopen_internal(path, mode, root, copy, _f);
998 }
999
1000 /// UNNEEDED by elogind
1001 #if 0
1002 int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) {
1003         _cleanup_strv_free_ char **s = NULL;
1004
1005         if (path_is_absolute(path)) {
1006                 FILE *f;
1007
1008                 f = fopen(path, mode);
1009                 if (f) {
1010                         *_f = f;
1011                         return 0;
1012                 }
1013
1014                 return -errno;
1015         }
1016
1017         s = strv_split_nulstr(search);
1018         if (!s)
1019                 return -ENOMEM;
1020
1021         return search_and_fopen_internal(path, mode, root, s, _f);
1022 }
1023 #endif // 0
1024
1025 int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
1026         FILE *f;
1027         char *t;
1028         int r, fd;
1029
1030         assert(path);
1031         assert(_f);
1032         assert(_temp_path);
1033
1034         r = tempfn_xxxxxx(path, NULL, &t);
1035         if (r < 0)
1036                 return r;
1037
1038         fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC);
1039         if (fd < 0) {
1040                 free(t);
1041                 return -errno;
1042         }
1043
1044         f = fdopen(fd, "we");
1045         if (!f) {
1046                 unlink_noerrno(t);
1047                 free(t);
1048                 safe_close(fd);
1049                 return -errno;
1050         }
1051
1052         *_f = f;
1053         *_temp_path = t;
1054
1055         return 0;
1056 }
1057
1058 int fflush_and_check(FILE *f) {
1059         assert(f);
1060
1061         errno = 0;
1062         fflush(f);
1063
1064         if (ferror(f))
1065                 return errno ? -errno : -EIO;
1066
1067         return 0;
1068 }
1069
1070 /* This is much like like mkostemp() but is subject to umask(). */
1071 int mkostemp_safe(char *pattern, int flags) {
1072         _cleanup_umask_ mode_t u;
1073         int fd;
1074
1075         assert(pattern);
1076
1077         u = umask(077);
1078
1079         fd = mkostemp(pattern, flags);
1080         if (fd < 0)
1081                 return -errno;
1082
1083         return fd;
1084 }
1085
1086 /// UNNEEDED by elogind
1087 #if 0
1088 int open_tmpfile(const char *path, int flags) {
1089         char *p;
1090         int fd;
1091
1092         assert(path);
1093
1094 #ifdef O_TMPFILE
1095         /* Try O_TMPFILE first, if it is supported */
1096         fd = open(path, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR);
1097         if (fd >= 0)
1098                 return fd;
1099 #endif
1100
1101         /* Fall back to unguessable name + unlinking */
1102         p = strjoina(path, "/systemd-tmp-XXXXXX");
1103
1104         fd = mkostemp_safe(p, flags);
1105         if (fd < 0)
1106                 return fd;
1107
1108         unlink(p);
1109         return fd;
1110 }
1111 #endif // 0
1112
1113 int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
1114         const char *fn;
1115         char *t;
1116
1117         assert(p);
1118         assert(ret);
1119
1120         /*
1121          * Turns this:
1122          *         /foo/bar/waldo
1123          *
1124          * Into this:
1125          *         /foo/bar/.#<extra>waldoXXXXXX
1126          */
1127
1128         fn = basename(p);
1129         if (!filename_is_valid(fn))
1130                 return -EINVAL;
1131
1132         if (extra == NULL)
1133                 extra = "";
1134
1135         t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1);
1136         if (!t)
1137                 return -ENOMEM;
1138
1139         strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX");
1140
1141         *ret = path_kill_slashes(t);
1142         return 0;
1143 }
1144
1145 int tempfn_random(const char *p, const char *extra, char **ret) {
1146         const char *fn;
1147         char *t, *x;
1148         uint64_t u;
1149         unsigned i;
1150
1151         assert(p);
1152         assert(ret);
1153
1154         /*
1155          * Turns this:
1156          *         /foo/bar/waldo
1157          *
1158          * Into this:
1159          *         /foo/bar/.#<extra>waldobaa2a261115984a9
1160          */
1161
1162         fn = basename(p);
1163         if (!filename_is_valid(fn))
1164                 return -EINVAL;
1165
1166         if (!extra)
1167                 extra = "";
1168
1169         t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1);
1170         if (!t)
1171                 return -ENOMEM;
1172
1173         x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn);
1174
1175         u = random_u64();
1176         for (i = 0; i < 16; i++) {
1177                 *(x++) = hexchar(u & 0xF);
1178                 u >>= 4;
1179         }
1180
1181         *x = 0;
1182
1183         *ret = path_kill_slashes(t);
1184         return 0;
1185 }
1186
1187 /// UNNEEDED by elogind
1188 #if 0
1189 int tempfn_random_child(const char *p, const char *extra, char **ret) {
1190         char *t, *x;
1191         uint64_t u;
1192         unsigned i;
1193
1194         assert(p);
1195         assert(ret);
1196
1197         /* Turns this:
1198          *         /foo/bar/waldo
1199          * Into this:
1200          *         /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
1201          */
1202
1203         if (!extra)
1204                 extra = "";
1205
1206         t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1);
1207         if (!t)
1208                 return -ENOMEM;
1209
1210         x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
1211
1212         u = random_u64();
1213         for (i = 0; i < 16; i++) {
1214                 *(x++) = hexchar(u & 0xF);
1215                 u >>= 4;
1216         }
1217
1218         *x = 0;
1219
1220         *ret = path_kill_slashes(t);
1221         return 0;
1222 }
1223
1224 int write_timestamp_file_atomic(const char *fn, usec_t n) {
1225         char ln[DECIMAL_STR_MAX(n)+2];
1226
1227         /* Creates a "timestamp" file, that contains nothing but a
1228          * usec_t timestamp, formatted in ASCII. */
1229
1230         if (n <= 0 || n >= USEC_INFINITY)
1231                 return -ERANGE;
1232
1233         xsprintf(ln, USEC_FMT "\n", n);
1234
1235         return write_string_file(fn, ln, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
1236 }
1237
1238 int read_timestamp_file(const char *fn, usec_t *ret) {
1239         _cleanup_free_ char *ln = NULL;
1240         uint64_t t;
1241         int r;
1242
1243         r = read_one_line_file(fn, &ln);
1244         if (r < 0)
1245                 return r;
1246
1247         r = safe_atou64(ln, &t);
1248         if (r < 0)
1249                 return r;
1250
1251         if (t <= 0 || t >= (uint64_t) USEC_INFINITY)
1252                 return -ERANGE;
1253
1254         *ret = (usec_t) t;
1255         return 0;
1256 }
1257 #endif // 0