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