2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
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.
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.
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/>.
28 #include <sys/types.h>
31 #include "alloc-util.h"
37 #include "hexdecoct.h"
40 #include "parse-util.h"
41 #include "path-util.h"
42 #include "random-util.h"
43 #include "stdio-util.h"
44 #include "string-util.h"
46 //#include "time-util.h"
47 #include "umask-util.h"
50 int write_string_stream(FILE *f, const char *line, bool enforce_newline) {
56 if (enforce_newline && !endswith(line, "\n"))
59 return fflush_and_check(f);
62 static int write_string_file_atomic(const char *fn, const char *line, bool enforce_newline) {
63 _cleanup_fclose_ FILE *f = NULL;
64 _cleanup_free_ char *p = NULL;
70 r = fopen_temporary(fn, &f, &p);
74 (void) fchmod_umask(fileno(f), 0644);
76 r = write_string_stream(f, line, enforce_newline);
78 if (rename(p, fn) < 0)
88 int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) {
89 _cleanup_fclose_ FILE *f = NULL;
95 if (flags & WRITE_STRING_FILE_ATOMIC) {
96 assert(flags & WRITE_STRING_FILE_CREATE);
98 r = write_string_file_atomic(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
105 if (flags & WRITE_STRING_FILE_CREATE) {
114 /* We manually build our own version of fopen(..., "we") that
115 * works without O_CREAT */
116 fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY);
122 f = fdopen(fd, "we");
130 r = write_string_stream(f, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
137 if (!(flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE))
142 /* OK, the operation failed, but let's see if the right
143 * contents in place already. If so, eat up the error. */
145 q = verify_file(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
152 int read_one_line_file(const char *fn, char **line) {
153 _cleanup_fclose_ FILE *f = NULL;
154 char t[LINE_MAX], *c;
163 if (!fgets(t, sizeof(t), f)) {
166 return errno > 0 ? -errno : -EIO;
180 int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
181 _cleanup_fclose_ FILE *f = NULL;
182 _cleanup_free_ char *buf = NULL;
190 if (accept_extra_nl && endswith(blob, "\n"))
191 accept_extra_nl = false;
193 buf = malloc(l + accept_extra_nl + 1);
201 /* We try to read one byte more than we need, so that we know whether we hit eof */
203 k = fread(buf, 1, l + accept_extra_nl + 1, f);
205 return errno > 0 ? -errno : -EIO;
207 if (k != l && k != l + accept_extra_nl)
209 if (memcmp(buf, blob, l) != 0)
211 if (k > l && buf[l] != '\n')
217 int read_full_stream(FILE *f, char **contents, size_t *size) {
219 _cleanup_free_ char *buf = NULL;
225 if (fstat(fileno(f), &st) < 0)
230 if (S_ISREG(st.st_mode)) {
233 if (st.st_size > 4*1024*1024)
236 /* Start with the right file size, but be prepared for
237 * files from /proc which generally report a file size
248 t = realloc(buf, n+1);
253 k = fread(buf + l, 1, n - l, f);
272 buf = NULL; /* do not free */
280 int read_full_file(const char *fn, char **contents, size_t *size) {
281 _cleanup_fclose_ FILE *f = NULL;
290 return read_full_stream(f, contents, size);
293 static int parse_env_file_internal(
297 int (*push) (const char *filename, unsigned line,
298 const char *key, char *value, void *userdata, int *n_pushed),
302 _cleanup_free_ char *contents = NULL, *key = NULL;
303 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;
304 char *p, *value = NULL;
315 SINGLE_QUOTE_VALUE_ESCAPE,
317 DOUBLE_QUOTE_VALUE_ESCAPE,
325 r = read_full_stream(f, &contents, NULL);
327 r = read_full_file(fname, &contents, NULL);
331 for (p = contents; *p; p++) {
337 if (strchr(COMMENTS, c))
339 else if (!strchr(WHITESPACE, c)) {
341 last_key_whitespace = (size_t) -1;
343 if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) {
353 if (strchr(newline, c)) {
357 } else if (c == '=') {
359 last_value_whitespace = (size_t) -1;
361 if (!strchr(WHITESPACE, c))
362 last_key_whitespace = (size_t) -1;
363 else if (last_key_whitespace == (size_t) -1)
364 last_key_whitespace = n_key;
366 if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) {
377 if (strchr(newline, c)) {
385 /* strip trailing whitespace from key */
386 if (last_key_whitespace != (size_t) -1)
387 key[last_key_whitespace] = 0;
389 r = push(fname, line, key, value, userdata, n_pushed);
395 value_alloc = n_value = 0;
397 } else if (c == '\'')
398 state = SINGLE_QUOTE_VALUE;
400 state = DOUBLE_QUOTE_VALUE;
402 state = VALUE_ESCAPE;
403 else if (!strchr(WHITESPACE, c)) {
406 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
411 value[n_value++] = c;
417 if (strchr(newline, c)) {
426 /* Chomp off trailing whitespace from value */
427 if (last_value_whitespace != (size_t) -1)
428 value[last_value_whitespace] = 0;
430 /* strip trailing whitespace from key */
431 if (last_key_whitespace != (size_t) -1)
432 key[last_key_whitespace] = 0;
434 r = push(fname, line, key, value, userdata, n_pushed);
440 value_alloc = n_value = 0;
442 } else if (c == '\\') {
443 state = VALUE_ESCAPE;
444 last_value_whitespace = (size_t) -1;
446 if (!strchr(WHITESPACE, c))
447 last_value_whitespace = (size_t) -1;
448 else if (last_value_whitespace == (size_t) -1)
449 last_value_whitespace = n_value;
451 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
456 value[n_value++] = c;
464 if (!strchr(newline, c)) {
465 /* Escaped newlines we eat up entirely */
466 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
471 value[n_value++] = c;
475 case SINGLE_QUOTE_VALUE:
479 state = SINGLE_QUOTE_VALUE_ESCAPE;
481 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
486 value[n_value++] = c;
491 case SINGLE_QUOTE_VALUE_ESCAPE:
492 state = SINGLE_QUOTE_VALUE;
494 if (!strchr(newline, c)) {
495 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
500 value[n_value++] = c;
504 case DOUBLE_QUOTE_VALUE:
508 state = DOUBLE_QUOTE_VALUE_ESCAPE;
510 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
515 value[n_value++] = c;
520 case DOUBLE_QUOTE_VALUE_ESCAPE:
521 state = DOUBLE_QUOTE_VALUE;
523 if (!strchr(newline, c)) {
524 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
529 value[n_value++] = c;
535 state = COMMENT_ESCAPE;
536 else if (strchr(newline, c)) {
548 if (state == PRE_VALUE ||
550 state == VALUE_ESCAPE ||
551 state == SINGLE_QUOTE_VALUE ||
552 state == SINGLE_QUOTE_VALUE_ESCAPE ||
553 state == DOUBLE_QUOTE_VALUE ||
554 state == DOUBLE_QUOTE_VALUE_ESCAPE) {
562 if (last_value_whitespace != (size_t) -1)
563 value[last_value_whitespace] = 0;
565 /* strip trailing whitespace from key */
566 if (last_key_whitespace != (size_t) -1)
567 key[last_key_whitespace] = 0;
569 r = push(fname, line, key, value, userdata, n_pushed);
581 static int parse_env_file_push(
582 const char *filename, unsigned line,
583 const char *key, char *value,
588 va_list aq, *ap = userdata;
590 if (!utf8_is_valid(key)) {
591 _cleanup_free_ char *p;
593 p = utf8_escape_invalid(key);
594 log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p);
598 if (value && !utf8_is_valid(value)) {
599 _cleanup_free_ char *p;
601 p = utf8_escape_invalid(value);
602 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, p);
608 while ((k = va_arg(aq, const char *))) {
611 v = va_arg(aq, char **);
633 const char *newline, ...) {
641 va_start(ap, newline);
642 r = parse_env_file_internal(NULL, fname, newline, parse_env_file_push, &ap, &n_pushed);
645 return r < 0 ? r : n_pushed;
648 static int load_env_file_push(
649 const char *filename, unsigned line,
650 const char *key, char *value,
653 char ***m = userdata;
657 if (!utf8_is_valid(key)) {
658 _cleanup_free_ char *t = utf8_escape_invalid(key);
660 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t);
664 if (value && !utf8_is_valid(value)) {
665 _cleanup_free_ char *t = utf8_escape_invalid(value);
667 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t);
671 p = strjoin(key, "=", strempty(value), NULL);
675 r = strv_consume(m, p);
686 int load_env_file(FILE *f, const char *fname, const char *newline, char ***rl) {
693 r = parse_env_file_internal(f, fname, newline, load_env_file_push, &m, NULL);
703 #if 0 /// UNNEDED by elogind
704 static int load_env_file_push_pairs(
705 const char *filename, unsigned line,
706 const char *key, char *value,
709 char ***m = userdata;
712 if (!utf8_is_valid(key)) {
713 _cleanup_free_ char *t = utf8_escape_invalid(key);
715 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t);
719 if (value && !utf8_is_valid(value)) {
720 _cleanup_free_ char *t = utf8_escape_invalid(value);
722 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t);
726 r = strv_extend(m, key);
731 r = strv_extend(m, "");
735 r = strv_push(m, value);
746 int load_env_file_pairs(FILE *f, const char *fname, const char *newline, char ***rl) {
753 r = parse_env_file_internal(f, fname, newline, load_env_file_push_pairs, &m, NULL);
764 static void write_env_var(FILE *f, const char *v) {
776 fwrite(v, 1, p-v, f);
778 if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) {
782 if (strchr(SHELL_NEED_ESCAPE, *p))
795 int write_env_file(const char *fname, char **l) {
796 _cleanup_fclose_ FILE *f = NULL;
797 _cleanup_free_ char *p = NULL;
803 r = fopen_temporary(fname, &f, &p);
807 fchmod_umask(fileno(f), 0644);
810 write_env_var(f, *i);
812 r = fflush_and_check(f);
814 if (rename(p, fname) >= 0)
824 #if 0 /// UNNEEDED by elogind
825 int executable_is_script(const char *path, char **interpreter) {
827 _cleanup_free_ char *line = NULL;
833 r = read_one_line_file(path, &line);
837 if (!startswith(line, "#!"))
840 ans = strstrip(line + 2);
841 len = strcspn(ans, " \t");
846 ans = strndup(ans, len);
856 * Retrieve one field from a file like /proc/self/status. pattern
857 * should not include whitespace or the delimiter (':'). pattern matches only
858 * the beginning of a line. Whitespace before ':' is skipped. Whitespace and
859 * zeros after the ':' will be skipped. field must be freed afterwards.
860 * terminator specifies the terminating characters of the field value (not
861 * included in the value).
863 int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) {
864 _cleanup_free_ char *status = NULL;
874 r = read_full_file(filename, &status, NULL);
884 t = strstr(t, pattern);
888 /* Check that pattern occurs in beginning of line. */
889 pattern_ok = (t == status || t[-1] == '\n');
891 t += strlen(pattern);
893 } while (!pattern_ok);
895 t += strspn(t, " \t");
904 t += strspn(t, " \t");
906 /* Also skip zeros, because when this is used for
907 * capabilities, we don't want the zeros. This way the
908 * same capability set always maps to the same string,
909 * irrespective of the total capability set size. For
910 * other numbers it shouldn't matter. */
912 /* Back off one char if there's nothing but whitespace
914 if (!*t || isspace(*t))
918 len = strcspn(t, terminator);
928 DIR *xopendirat(int fd, const char *name, int flags) {
932 assert(!(flags & O_CREAT));
934 nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0);
947 #if 0 /// UNNEEDED by elogind
948 static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) {
955 if (!path_strv_resolve_uniq(search, root))
958 STRV_FOREACH(i, search) {
959 _cleanup_free_ char *p = NULL;
963 p = strjoin(root, *i, "/", path, NULL);
965 p = strjoin(*i, "/", path, NULL);
982 int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f) {
983 _cleanup_strv_free_ char **copy = NULL;
989 if (path_is_absolute(path)) {
992 f = fopen(path, mode);
1001 copy = strv_copy((char**) search);
1005 return search_and_fopen_internal(path, mode, root, copy, _f);
1008 int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) {
1009 _cleanup_strv_free_ char **s = NULL;
1011 if (path_is_absolute(path)) {
1014 f = fopen(path, mode);
1023 s = strv_split_nulstr(search);
1027 return search_and_fopen_internal(path, mode, root, s, _f);
1031 int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
1040 r = tempfn_xxxxxx(path, NULL, &t);
1044 fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC);
1050 f = fdopen(fd, "we");
1064 int fflush_and_check(FILE *f) {
1071 return errno > 0 ? -errno : -EIO;
1076 /* This is much like like mkostemp() but is subject to umask(). */
1077 int mkostemp_safe(char *pattern, int flags) {
1078 _cleanup_umask_ mode_t u;
1085 fd = mkostemp(pattern, flags);
1092 #if 0 /// UNNEEDED by elogind
1093 int open_tmpfile(const char *path, int flags) {
1100 /* Try O_TMPFILE first, if it is supported */
1101 fd = open(path, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR);
1106 /* Fall back to unguessable name + unlinking */
1107 p = strjoina(path, "/systemd-tmp-XXXXXX");
1109 fd = mkostemp_safe(p, flags);
1118 int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
1130 * /foo/bar/.#<extra>waldoXXXXXX
1134 if (!filename_is_valid(fn))
1140 t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1);
1144 strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX");
1146 *ret = path_kill_slashes(t);
1150 #if 0 /// UNNEEDED by elogind
1151 int tempfn_random(const char *p, const char *extra, char **ret) {
1165 * /foo/bar/.#<extra>waldobaa2a261115984a9
1169 if (!filename_is_valid(fn))
1175 t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1);
1179 x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn);
1182 for (i = 0; i < 16; i++) {
1183 *(x++) = hexchar(u & 0xF);
1189 *ret = path_kill_slashes(t);
1193 int tempfn_random_child(const char *p, const char *extra, char **ret) {
1204 * /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
1210 t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1);
1214 x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
1217 for (i = 0; i < 16; i++) {
1218 *(x++) = hexchar(u & 0xF);
1224 *ret = path_kill_slashes(t);
1228 int write_timestamp_file_atomic(const char *fn, usec_t n) {
1229 char ln[DECIMAL_STR_MAX(n)+2];
1231 /* Creates a "timestamp" file, that contains nothing but a
1232 * usec_t timestamp, formatted in ASCII. */
1234 if (n <= 0 || n >= USEC_INFINITY)
1237 xsprintf(ln, USEC_FMT "\n", n);
1239 return write_string_file(fn, ln, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
1242 int read_timestamp_file(const char *fn, usec_t *ret) {
1243 _cleanup_free_ char *ln = NULL;
1247 r = read_one_line_file(fn, &ln);
1251 r = safe_atou64(ln, &t);
1255 if (t <= 0 || t >= (uint64_t) USEC_INFINITY)
1262 int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space) {
1267 /* Outputs the specified string with fputs(), but optionally prefixes it with a separator. The *space parameter
1268 * when specified shall initially point to a boolean variable initialized to false. It is set to true after the
1269 * first invocation. This call is supposed to be use in loops, where a separator shall be inserted between each
1270 * element, but not before the first one. */
1280 r = fputs(separator, f);