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/>.
30 int write_string_stream(FILE *f, const char *line, bool enforce_newline) {
36 if (enforce_newline && !endswith(line, "\n"))
39 return fflush_and_check(f);
42 static int write_string_file_atomic(const char *fn, const char *line, bool enforce_newline) {
43 _cleanup_fclose_ FILE *f = NULL;
44 _cleanup_free_ char *p = NULL;
50 r = fopen_temporary(fn, &f, &p);
54 fchmod_umask(fileno(f), 0644);
56 r = write_string_stream(f, line, enforce_newline);
58 if (rename(p, fn) < 0)
68 int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) {
69 _cleanup_fclose_ FILE *f = NULL;
74 if (flags & WRITE_STRING_FILE_ATOMIC) {
75 assert(flags & WRITE_STRING_FILE_CREATE);
77 return write_string_file_atomic(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
80 if (flags & WRITE_STRING_FILE_CREATE) {
87 /* We manually build our own version of fopen(..., "we") that
88 * works without O_CREAT */
89 fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY);
100 return write_string_stream(f, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
103 int read_one_line_file(const char *fn, char **line) {
104 _cleanup_fclose_ FILE *f = NULL;
105 char t[LINE_MAX], *c;
114 if (!fgets(t, sizeof(t), f)) {
117 return errno ? -errno : -EIO;
131 /// UNNEEDED by elogind
133 int verify_one_line_file(const char *fn, const char *line) {
134 _cleanup_free_ char *value = NULL;
137 r = read_one_line_file(fn, &value);
141 return streq(value, line);
145 int read_full_stream(FILE *f, char **contents, size_t *size) {
147 _cleanup_free_ char *buf = NULL;
153 if (fstat(fileno(f), &st) < 0)
158 if (S_ISREG(st.st_mode)) {
161 if (st.st_size > 4*1024*1024)
164 /* Start with the right file size, but be prepared for
165 * files from /proc which generally report a file size
176 t = realloc(buf, n+1);
181 k = fread(buf + l, 1, n - l, f);
200 buf = NULL; /* do not free */
208 int read_full_file(const char *fn, char **contents, size_t *size) {
209 _cleanup_fclose_ FILE *f = NULL;
218 return read_full_stream(f, contents, size);
221 static int parse_env_file_internal(
225 int (*push) (const char *filename, unsigned line,
226 const char *key, char *value, void *userdata, int *n_pushed),
230 _cleanup_free_ char *contents = NULL, *key = NULL;
231 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;
232 char *p, *value = NULL;
243 SINGLE_QUOTE_VALUE_ESCAPE,
245 DOUBLE_QUOTE_VALUE_ESCAPE,
253 r = read_full_stream(f, &contents, NULL);
255 r = read_full_file(fname, &contents, NULL);
259 for (p = contents; *p; p++) {
265 if (strchr(COMMENTS, c))
267 else if (!strchr(WHITESPACE, c)) {
269 last_key_whitespace = (size_t) -1;
271 if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) {
281 if (strchr(newline, c)) {
285 } else if (c == '=') {
287 last_value_whitespace = (size_t) -1;
289 if (!strchr(WHITESPACE, c))
290 last_key_whitespace = (size_t) -1;
291 else if (last_key_whitespace == (size_t) -1)
292 last_key_whitespace = n_key;
294 if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) {
305 if (strchr(newline, c)) {
313 /* strip trailing whitespace from key */
314 if (last_key_whitespace != (size_t) -1)
315 key[last_key_whitespace] = 0;
317 r = push(fname, line, key, value, userdata, n_pushed);
323 value_alloc = n_value = 0;
325 } else if (c == '\'')
326 state = SINGLE_QUOTE_VALUE;
328 state = DOUBLE_QUOTE_VALUE;
330 state = VALUE_ESCAPE;
331 else if (!strchr(WHITESPACE, c)) {
334 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
339 value[n_value++] = c;
345 if (strchr(newline, c)) {
354 /* Chomp off trailing whitespace from value */
355 if (last_value_whitespace != (size_t) -1)
356 value[last_value_whitespace] = 0;
358 /* strip trailing whitespace from key */
359 if (last_key_whitespace != (size_t) -1)
360 key[last_key_whitespace] = 0;
362 r = push(fname, line, key, value, userdata, n_pushed);
368 value_alloc = n_value = 0;
370 } else if (c == '\\') {
371 state = VALUE_ESCAPE;
372 last_value_whitespace = (size_t) -1;
374 if (!strchr(WHITESPACE, c))
375 last_value_whitespace = (size_t) -1;
376 else if (last_value_whitespace == (size_t) -1)
377 last_value_whitespace = n_value;
379 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
384 value[n_value++] = c;
392 if (!strchr(newline, c)) {
393 /* Escaped newlines we eat up entirely */
394 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
399 value[n_value++] = c;
403 case SINGLE_QUOTE_VALUE:
407 state = SINGLE_QUOTE_VALUE_ESCAPE;
409 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
414 value[n_value++] = c;
419 case SINGLE_QUOTE_VALUE_ESCAPE:
420 state = SINGLE_QUOTE_VALUE;
422 if (!strchr(newline, c)) {
423 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
428 value[n_value++] = c;
432 case DOUBLE_QUOTE_VALUE:
436 state = DOUBLE_QUOTE_VALUE_ESCAPE;
438 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
443 value[n_value++] = c;
448 case DOUBLE_QUOTE_VALUE_ESCAPE:
449 state = DOUBLE_QUOTE_VALUE;
451 if (!strchr(newline, c)) {
452 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
457 value[n_value++] = c;
463 state = COMMENT_ESCAPE;
464 else if (strchr(newline, c)) {
476 if (state == PRE_VALUE ||
478 state == VALUE_ESCAPE ||
479 state == SINGLE_QUOTE_VALUE ||
480 state == SINGLE_QUOTE_VALUE_ESCAPE ||
481 state == DOUBLE_QUOTE_VALUE ||
482 state == DOUBLE_QUOTE_VALUE_ESCAPE) {
490 if (last_value_whitespace != (size_t) -1)
491 value[last_value_whitespace] = 0;
493 /* strip trailing whitespace from key */
494 if (last_key_whitespace != (size_t) -1)
495 key[last_key_whitespace] = 0;
497 r = push(fname, line, key, value, userdata, n_pushed);
509 static int parse_env_file_push(
510 const char *filename, unsigned line,
511 const char *key, char *value,
516 va_list aq, *ap = userdata;
518 if (!utf8_is_valid(key)) {
519 _cleanup_free_ char *p;
521 p = utf8_escape_invalid(key);
522 log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p);
526 if (value && !utf8_is_valid(value)) {
527 _cleanup_free_ char *p;
529 p = utf8_escape_invalid(value);
530 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, p);
536 while ((k = va_arg(aq, const char *))) {
539 v = va_arg(aq, char **);
561 const char *newline, ...) {
569 va_start(ap, newline);
570 r = parse_env_file_internal(NULL, fname, newline, parse_env_file_push, &ap, &n_pushed);
573 return r < 0 ? r : n_pushed;
576 static int load_env_file_push(
577 const char *filename, unsigned line,
578 const char *key, char *value,
581 char ***m = userdata;
585 if (!utf8_is_valid(key)) {
586 _cleanup_free_ char *t = utf8_escape_invalid(key);
588 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t);
592 if (value && !utf8_is_valid(value)) {
593 _cleanup_free_ char *t = utf8_escape_invalid(value);
595 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t);
599 p = strjoin(key, "=", strempty(value), NULL);
603 r = strv_consume(m, p);
614 int load_env_file(FILE *f, const char *fname, const char *newline, char ***rl) {
621 r = parse_env_file_internal(f, fname, newline, load_env_file_push, &m, NULL);
631 /// UNNEDED by elogind
633 static int load_env_file_push_pairs(
634 const char *filename, unsigned line,
635 const char *key, char *value,
638 char ***m = userdata;
641 if (!utf8_is_valid(key)) {
642 _cleanup_free_ char *t = utf8_escape_invalid(key);
644 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t);
648 if (value && !utf8_is_valid(value)) {
649 _cleanup_free_ char *t = utf8_escape_invalid(value);
651 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t);
655 r = strv_extend(m, key);
660 r = strv_extend(m, "");
664 r = strv_push(m, value);
675 int load_env_file_pairs(FILE *f, const char *fname, const char *newline, char ***rl) {
682 r = parse_env_file_internal(f, fname, newline, load_env_file_push_pairs, &m, NULL);
693 static void write_env_var(FILE *f, const char *v) {
705 fwrite(v, 1, p-v, f);
707 if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) {
711 if (strchr(SHELL_NEED_ESCAPE, *p))
724 int write_env_file(const char *fname, char **l) {
725 _cleanup_fclose_ FILE *f = NULL;
726 _cleanup_free_ char *p = NULL;
732 r = fopen_temporary(fname, &f, &p);
736 fchmod_umask(fileno(f), 0644);
739 write_env_var(f, *i);
741 r = fflush_and_check(f);
743 if (rename(p, fname) >= 0)
753 /// UNNEEDED by elogind
755 int executable_is_script(const char *path, char **interpreter) {
757 _cleanup_free_ char *line = NULL;
763 r = read_one_line_file(path, &line);
767 if (!startswith(line, "#!"))
770 ans = strstrip(line + 2);
771 len = strcspn(ans, " \t");
776 ans = strndup(ans, len);
786 * Retrieve one field from a file like /proc/self/status. pattern
787 * should start with '\n' and end with a ':'. Whitespace and zeros
788 * after the ':' will be skipped. field must be freed afterwards.
790 int get_status_field(const char *filename, const char *pattern, char **field) {
791 _cleanup_free_ char *status = NULL;
800 r = read_full_file(filename, &status, NULL);
804 t = strstr(status, pattern);
808 t += strlen(pattern);
810 t += strspn(t, " \t");
812 /* Also skip zeros, because when this is used for
813 * capabilities, we don't want the zeros. This way the
814 * same capability set always maps to the same string,
815 * irrespective of the total capability set size. For
816 * other numbers it shouldn't matter. */
818 /* Back off one char if there's nothing but whitespace
820 if (!*t || isspace(*t))
824 len = strcspn(t, WHITESPACE);