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