1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
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.
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.
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/>.
24 #include "alloc-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"
37 #include "umask-util.h"
41 int write_string_stream(FILE *f, const char *line, bool enforce_newline) {
47 if (enforce_newline && !endswith(line, "\n"))
50 return fflush_and_check(f);
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;
61 r = fopen_temporary(fn, &f, &p);
65 (void) fchmod_umask(fileno(f), 0644);
67 r = write_string_stream(f, line, enforce_newline);
69 if (rename(p, fn) < 0)
79 int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) {
80 _cleanup_fclose_ FILE *f = NULL;
86 if (flags & WRITE_STRING_FILE_ATOMIC) {
87 assert(flags & WRITE_STRING_FILE_CREATE);
89 r = write_string_file_atomic(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
96 if (flags & WRITE_STRING_FILE_CREATE) {
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);
113 f = fdopen(fd, "we");
121 r = write_string_stream(f, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
128 if (!(flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE))
133 /* OK, the operation failed, but let's see if the right
134 * contents in place already. If so, eat up the error. */
136 q = verify_file(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
143 int read_one_line_file(const char *fn, char **line) {
144 _cleanup_fclose_ FILE *f = NULL;
145 char t[LINE_MAX], *c;
154 if (!fgets(t, sizeof(t), f)) {
157 return errno ? -errno : -EIO;
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;
181 if (accept_extra_nl && endswith(blob, "\n"))
182 accept_extra_nl = false;
184 buf = malloc(l + accept_extra_nl + 1);
192 /* We try to read one byte more than we need, so that we know whether we hit eof */
194 k = fread(buf, 1, l + accept_extra_nl + 1, f);
196 return errno > 0 ? -errno : -EIO;
198 if (k != l && k != l + accept_extra_nl)
200 if (memcmp(buf, blob, l) != 0)
202 if (k > l && buf[l] != '\n')
208 int read_full_stream(FILE *f, char **contents, size_t *size) {
210 _cleanup_free_ char *buf = NULL;
216 if (fstat(fileno(f), &st) < 0)
221 if (S_ISREG(st.st_mode)) {
224 if (st.st_size > 4*1024*1024)
227 /* Start with the right file size, but be prepared for
228 * files from /proc which generally report a file size
239 t = realloc(buf, n+1);
244 k = fread(buf + l, 1, n - l, f);
263 buf = NULL; /* do not free */
271 int read_full_file(const char *fn, char **contents, size_t *size) {
272 _cleanup_fclose_ FILE *f = NULL;
281 return read_full_stream(f, contents, size);
284 static int parse_env_file_internal(
288 int (*push) (const char *filename, unsigned line,
289 const char *key, char *value, void *userdata, int *n_pushed),
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;
306 SINGLE_QUOTE_VALUE_ESCAPE,
308 DOUBLE_QUOTE_VALUE_ESCAPE,
316 r = read_full_stream(f, &contents, NULL);
318 r = read_full_file(fname, &contents, NULL);
322 for (p = contents; *p; p++) {
328 if (strchr(COMMENTS, c))
330 else if (!strchr(WHITESPACE, c)) {
332 last_key_whitespace = (size_t) -1;
334 if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) {
344 if (strchr(newline, c)) {
348 } else if (c == '=') {
350 last_value_whitespace = (size_t) -1;
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;
357 if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) {
368 if (strchr(newline, c)) {
376 /* strip trailing whitespace from key */
377 if (last_key_whitespace != (size_t) -1)
378 key[last_key_whitespace] = 0;
380 r = push(fname, line, key, value, userdata, n_pushed);
386 value_alloc = n_value = 0;
388 } else if (c == '\'')
389 state = SINGLE_QUOTE_VALUE;
391 state = DOUBLE_QUOTE_VALUE;
393 state = VALUE_ESCAPE;
394 else if (!strchr(WHITESPACE, c)) {
397 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
402 value[n_value++] = c;
408 if (strchr(newline, c)) {
417 /* Chomp off trailing whitespace from value */
418 if (last_value_whitespace != (size_t) -1)
419 value[last_value_whitespace] = 0;
421 /* strip trailing whitespace from key */
422 if (last_key_whitespace != (size_t) -1)
423 key[last_key_whitespace] = 0;
425 r = push(fname, line, key, value, userdata, n_pushed);
431 value_alloc = n_value = 0;
433 } else if (c == '\\') {
434 state = VALUE_ESCAPE;
435 last_value_whitespace = (size_t) -1;
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;
442 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
447 value[n_value++] = c;
455 if (!strchr(newline, c)) {
456 /* Escaped newlines we eat up entirely */
457 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
462 value[n_value++] = c;
466 case SINGLE_QUOTE_VALUE:
470 state = SINGLE_QUOTE_VALUE_ESCAPE;
472 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
477 value[n_value++] = c;
482 case SINGLE_QUOTE_VALUE_ESCAPE:
483 state = SINGLE_QUOTE_VALUE;
485 if (!strchr(newline, c)) {
486 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
491 value[n_value++] = c;
495 case DOUBLE_QUOTE_VALUE:
499 state = DOUBLE_QUOTE_VALUE_ESCAPE;
501 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
506 value[n_value++] = c;
511 case DOUBLE_QUOTE_VALUE_ESCAPE:
512 state = DOUBLE_QUOTE_VALUE;
514 if (!strchr(newline, c)) {
515 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
520 value[n_value++] = c;
526 state = COMMENT_ESCAPE;
527 else if (strchr(newline, c)) {
539 if (state == PRE_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) {
553 if (last_value_whitespace != (size_t) -1)
554 value[last_value_whitespace] = 0;
556 /* strip trailing whitespace from key */
557 if (last_key_whitespace != (size_t) -1)
558 key[last_key_whitespace] = 0;
560 r = push(fname, line, key, value, userdata, n_pushed);
572 static int parse_env_file_push(
573 const char *filename, unsigned line,
574 const char *key, char *value,
579 va_list aq, *ap = userdata;
581 if (!utf8_is_valid(key)) {
582 _cleanup_free_ char *p;
584 p = utf8_escape_invalid(key);
585 log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p);
589 if (value && !utf8_is_valid(value)) {
590 _cleanup_free_ char *p;
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);
599 while ((k = va_arg(aq, const char *))) {
602 v = va_arg(aq, char **);
624 const char *newline, ...) {
632 va_start(ap, newline);
633 r = parse_env_file_internal(NULL, fname, newline, parse_env_file_push, &ap, &n_pushed);
636 return r < 0 ? r : n_pushed;
639 static int load_env_file_push(
640 const char *filename, unsigned line,
641 const char *key, char *value,
644 char ***m = userdata;
648 if (!utf8_is_valid(key)) {
649 _cleanup_free_ char *t = utf8_escape_invalid(key);
651 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t);
655 if (value && !utf8_is_valid(value)) {
656 _cleanup_free_ char *t = utf8_escape_invalid(value);
658 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t);
662 p = strjoin(key, "=", strempty(value), NULL);
666 r = strv_consume(m, p);
677 int load_env_file(FILE *f, const char *fname, const char *newline, char ***rl) {
684 r = parse_env_file_internal(f, fname, newline, load_env_file_push, &m, NULL);
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,
700 char ***m = userdata;
703 if (!utf8_is_valid(key)) {
704 _cleanup_free_ char *t = utf8_escape_invalid(key);
706 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t);
710 if (value && !utf8_is_valid(value)) {
711 _cleanup_free_ char *t = utf8_escape_invalid(value);
713 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t);
717 r = strv_extend(m, key);
722 r = strv_extend(m, "");
726 r = strv_push(m, value);
737 int load_env_file_pairs(FILE *f, const char *fname, const char *newline, char ***rl) {
744 r = parse_env_file_internal(f, fname, newline, load_env_file_push_pairs, &m, NULL);
755 static void write_env_var(FILE *f, const char *v) {
767 fwrite(v, 1, p-v, f);
769 if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) {
773 if (strchr(SHELL_NEED_ESCAPE, *p))
786 int write_env_file(const char *fname, char **l) {
787 _cleanup_fclose_ FILE *f = NULL;
788 _cleanup_free_ char *p = NULL;
794 r = fopen_temporary(fname, &f, &p);
798 fchmod_umask(fileno(f), 0644);
801 write_env_var(f, *i);
803 r = fflush_and_check(f);
805 if (rename(p, fname) >= 0)
815 #if 0 /// UNNEEDED by elogind
816 int executable_is_script(const char *path, char **interpreter) {
818 _cleanup_free_ char *line = NULL;
824 r = read_one_line_file(path, &line);
828 if (!startswith(line, "#!"))
831 ans = strstrip(line + 2);
832 len = strcspn(ans, " \t");
837 ans = strndup(ans, len);
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).
854 int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) {
855 _cleanup_free_ char *status = NULL;
865 r = read_full_file(filename, &status, NULL);
875 t = strstr(t, pattern);
879 /* Check that pattern occurs in beginning of line. */
880 pattern_ok = (t == status || t[-1] == '\n');
882 t += strlen(pattern);
884 } while (!pattern_ok);
886 t += strspn(t, " \t");
895 t += strspn(t, " \t");
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. */
903 /* Back off one char if there's nothing but whitespace
905 if (!*t || isspace(*t))
909 len = strcspn(t, terminator);
919 DIR *xopendirat(int fd, const char *name, int flags) {
923 assert(!(flags & O_CREAT));
925 nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0);
938 #if 0 /// UNNEEDED by elogind
939 static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) {
946 if (!path_strv_resolve_uniq(search, root))
949 STRV_FOREACH(i, search) {
950 _cleanup_free_ char *p = NULL;
954 p = strjoin(root, *i, "/", path, NULL);
956 p = strjoin(*i, "/", path, NULL);
973 int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f) {
974 _cleanup_strv_free_ char **copy = NULL;
980 if (path_is_absolute(path)) {
983 f = fopen(path, mode);
992 copy = strv_copy((char**) search);
996 return search_and_fopen_internal(path, mode, root, copy, _f);
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;
1002 if (path_is_absolute(path)) {
1005 f = fopen(path, mode);
1014 s = strv_split_nulstr(search);
1018 return search_and_fopen_internal(path, mode, root, s, _f);
1022 int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
1031 r = tempfn_xxxxxx(path, NULL, &t);
1035 fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC);
1041 f = fdopen(fd, "we");
1055 int fflush_and_check(FILE *f) {
1062 return errno ? -errno : -EIO;
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;
1076 fd = mkostemp(pattern, flags);
1083 #if 0 /// UNNEEDED by elogind
1084 int open_tmpfile(const char *path, int flags) {
1091 /* Try O_TMPFILE first, if it is supported */
1092 fd = open(path, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR);
1097 /* Fall back to unguessable name + unlinking */
1098 p = strjoina(path, "/systemd-tmp-XXXXXX");
1100 fd = mkostemp_safe(p, flags);
1109 int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
1121 * /foo/bar/.#<extra>waldoXXXXXX
1125 if (!filename_is_valid(fn))
1131 t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1);
1135 strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX");
1137 *ret = path_kill_slashes(t);
1141 #if 0 /// UNNEEDED by elogind
1142 int tempfn_random(const char *p, const char *extra, char **ret) {
1156 * /foo/bar/.#<extra>waldobaa2a261115984a9
1160 if (!filename_is_valid(fn))
1166 t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1);
1170 x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn);
1173 for (i = 0; i < 16; i++) {
1174 *(x++) = hexchar(u & 0xF);
1180 *ret = path_kill_slashes(t);
1184 int tempfn_random_child(const char *p, const char *extra, char **ret) {
1195 * /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
1201 t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1);
1205 x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
1208 for (i = 0; i < 16; i++) {
1209 *(x++) = hexchar(u & 0xF);
1215 *ret = path_kill_slashes(t);
1219 int write_timestamp_file_atomic(const char *fn, usec_t n) {
1220 char ln[DECIMAL_STR_MAX(n)+2];
1222 /* Creates a "timestamp" file, that contains nothing but a
1223 * usec_t timestamp, formatted in ASCII. */
1225 if (n <= 0 || n >= USEC_INFINITY)
1228 xsprintf(ln, USEC_FMT "\n", n);
1230 return write_string_file(fn, ln, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
1233 int read_timestamp_file(const char *fn, usec_t *ret) {
1234 _cleanup_free_ char *ln = NULL;
1238 r = read_one_line_file(fn, &ln);
1242 r = safe_atou64(ln, &t);
1246 if (t <= 0 || t >= (uint64_t) USEC_INFINITY)