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) {
37 if (enforce_newline && !endswith(line, "\n"))
43 return errno ? -errno : -EIO;
48 static int write_string_file_atomic(const char *fn, const char *line, bool enforce_newline) {
49 _cleanup_fclose_ FILE *f = NULL;
50 _cleanup_free_ char *p = NULL;
56 r = fopen_temporary(fn, &f, &p);
60 fchmod_umask(fileno(f), 0644);
62 r = write_string_stream(f, line, enforce_newline);
64 if (rename(p, fn) < 0)
74 int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) {
75 _cleanup_fclose_ FILE *f = NULL;
80 if (flags & WRITE_STRING_FILE_ATOMIC) {
81 assert(flags & WRITE_STRING_FILE_CREATE);
83 return write_string_file_atomic(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
86 if (flags & WRITE_STRING_FILE_CREATE) {
93 /* We manually build our own version of fopen(..., "we") that
94 * works without O_CREAT */
95 fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY);
106 return write_string_stream(f, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
109 int read_one_line_file(const char *fn, char **line) {
110 _cleanup_fclose_ FILE *f = NULL;
111 char t[LINE_MAX], *c;
120 if (!fgets(t, sizeof(t), f)) {
123 return errno ? -errno : -EIO;
137 /// UNNEEDED by elogind
139 int verify_one_line_file(const char *fn, const char *line) {
140 _cleanup_free_ char *value = NULL;
143 r = read_one_line_file(fn, &value);
147 return streq(value, line);
151 int read_full_stream(FILE *f, char **contents, size_t *size) {
153 _cleanup_free_ char *buf = NULL;
159 if (fstat(fileno(f), &st) < 0)
164 if (S_ISREG(st.st_mode)) {
167 if (st.st_size > 4*1024*1024)
170 /* Start with the right file size, but be prepared for
171 * files from /proc which generally report a file size
182 t = realloc(buf, n+1);
187 k = fread(buf + l, 1, n - l, f);
206 buf = NULL; /* do not free */
214 int read_full_file(const char *fn, char **contents, size_t *size) {
215 _cleanup_fclose_ FILE *f = NULL;
224 return read_full_stream(f, contents, size);
227 static int parse_env_file_internal(
231 int (*push) (const char *filename, unsigned line,
232 const char *key, char *value, void *userdata, int *n_pushed),
236 _cleanup_free_ char *contents = NULL, *key = NULL;
237 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;
238 char *p, *value = NULL;
249 SINGLE_QUOTE_VALUE_ESCAPE,
251 DOUBLE_QUOTE_VALUE_ESCAPE,
259 r = read_full_stream(f, &contents, NULL);
261 r = read_full_file(fname, &contents, NULL);
265 for (p = contents; *p; p++) {
271 if (strchr(COMMENTS, c))
273 else if (!strchr(WHITESPACE, c)) {
275 last_key_whitespace = (size_t) -1;
277 if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) {
287 if (strchr(newline, c)) {
291 } else if (c == '=') {
293 last_value_whitespace = (size_t) -1;
295 if (!strchr(WHITESPACE, c))
296 last_key_whitespace = (size_t) -1;
297 else if (last_key_whitespace == (size_t) -1)
298 last_key_whitespace = n_key;
300 if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) {
311 if (strchr(newline, c)) {
319 /* strip trailing whitespace from key */
320 if (last_key_whitespace != (size_t) -1)
321 key[last_key_whitespace] = 0;
323 r = push(fname, line, key, value, userdata, n_pushed);
329 value_alloc = n_value = 0;
331 } else if (c == '\'')
332 state = SINGLE_QUOTE_VALUE;
334 state = DOUBLE_QUOTE_VALUE;
336 state = VALUE_ESCAPE;
337 else if (!strchr(WHITESPACE, c)) {
340 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
345 value[n_value++] = c;
351 if (strchr(newline, c)) {
360 /* Chomp off trailing whitespace from value */
361 if (last_value_whitespace != (size_t) -1)
362 value[last_value_whitespace] = 0;
364 /* strip trailing whitespace from key */
365 if (last_key_whitespace != (size_t) -1)
366 key[last_key_whitespace] = 0;
368 r = push(fname, line, key, value, userdata, n_pushed);
374 value_alloc = n_value = 0;
376 } else if (c == '\\') {
377 state = VALUE_ESCAPE;
378 last_value_whitespace = (size_t) -1;
380 if (!strchr(WHITESPACE, c))
381 last_value_whitespace = (size_t) -1;
382 else if (last_value_whitespace == (size_t) -1)
383 last_value_whitespace = n_value;
385 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
390 value[n_value++] = c;
398 if (!strchr(newline, c)) {
399 /* Escaped newlines we eat up entirely */
400 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
405 value[n_value++] = c;
409 case SINGLE_QUOTE_VALUE:
413 state = SINGLE_QUOTE_VALUE_ESCAPE;
415 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
420 value[n_value++] = c;
425 case SINGLE_QUOTE_VALUE_ESCAPE:
426 state = SINGLE_QUOTE_VALUE;
428 if (!strchr(newline, c)) {
429 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
434 value[n_value++] = c;
438 case DOUBLE_QUOTE_VALUE:
442 state = DOUBLE_QUOTE_VALUE_ESCAPE;
444 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
449 value[n_value++] = c;
454 case DOUBLE_QUOTE_VALUE_ESCAPE:
455 state = DOUBLE_QUOTE_VALUE;
457 if (!strchr(newline, c)) {
458 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
463 value[n_value++] = c;
469 state = COMMENT_ESCAPE;
470 else if (strchr(newline, c)) {
482 if (state == PRE_VALUE ||
484 state == VALUE_ESCAPE ||
485 state == SINGLE_QUOTE_VALUE ||
486 state == SINGLE_QUOTE_VALUE_ESCAPE ||
487 state == DOUBLE_QUOTE_VALUE ||
488 state == DOUBLE_QUOTE_VALUE_ESCAPE) {
496 if (last_value_whitespace != (size_t) -1)
497 value[last_value_whitespace] = 0;
499 /* strip trailing whitespace from key */
500 if (last_key_whitespace != (size_t) -1)
501 key[last_key_whitespace] = 0;
503 r = push(fname, line, key, value, userdata, n_pushed);
515 static int parse_env_file_push(
516 const char *filename, unsigned line,
517 const char *key, char *value,
522 va_list aq, *ap = userdata;
524 if (!utf8_is_valid(key)) {
525 _cleanup_free_ char *p;
527 p = utf8_escape_invalid(key);
528 log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p);
532 if (value && !utf8_is_valid(value)) {
533 _cleanup_free_ char *p;
535 p = utf8_escape_invalid(value);
536 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, p);
542 while ((k = va_arg(aq, const char *))) {
545 v = va_arg(aq, char **);
567 const char *newline, ...) {
575 va_start(ap, newline);
576 r = parse_env_file_internal(NULL, fname, newline, parse_env_file_push, &ap, &n_pushed);
579 return r < 0 ? r : n_pushed;
582 static int load_env_file_push(
583 const char *filename, unsigned line,
584 const char *key, char *value,
587 char ***m = userdata;
591 if (!utf8_is_valid(key)) {
592 _cleanup_free_ char *t = utf8_escape_invalid(key);
594 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t);
598 if (value && !utf8_is_valid(value)) {
599 _cleanup_free_ char *t = utf8_escape_invalid(value);
601 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t);
605 p = strjoin(key, "=", strempty(value), NULL);
609 r = strv_consume(m, p);
620 int load_env_file(FILE *f, const char *fname, const char *newline, char ***rl) {
627 r = parse_env_file_internal(f, fname, newline, load_env_file_push, &m, NULL);
637 /// UNNEDED by elogind
639 static int load_env_file_push_pairs(
640 const char *filename, unsigned line,
641 const char *key, char *value,
644 char ***m = userdata;
647 if (!utf8_is_valid(key)) {
648 _cleanup_free_ char *t = utf8_escape_invalid(key);
650 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t);
654 if (value && !utf8_is_valid(value)) {
655 _cleanup_free_ char *t = utf8_escape_invalid(value);
657 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t);
661 r = strv_extend(m, key);
666 r = strv_extend(m, "");
670 r = strv_push(m, value);
681 int load_env_file_pairs(FILE *f, const char *fname, const char *newline, char ***rl) {
688 r = parse_env_file_internal(f, fname, newline, load_env_file_push_pairs, &m, NULL);
699 static void write_env_var(FILE *f, const char *v) {
711 fwrite(v, 1, p-v, f);
713 if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) {
717 if (strchr(SHELL_NEED_ESCAPE, *p))
730 int write_env_file(const char *fname, char **l) {
731 _cleanup_fclose_ FILE *f = NULL;
732 _cleanup_free_ char *p = NULL;
738 r = fopen_temporary(fname, &f, &p);
742 fchmod_umask(fileno(f), 0644);
745 write_env_var(f, *i);
747 r = fflush_and_check(f);
749 if (rename(p, fname) >= 0)
759 /// UNNEEDED by elogind
761 int executable_is_script(const char *path, char **interpreter) {
763 _cleanup_free_ char *line = NULL;
769 r = read_one_line_file(path, &line);
773 if (!startswith(line, "#!"))
776 ans = strstrip(line + 2);
777 len = strcspn(ans, " \t");
782 ans = strndup(ans, len);
792 * Retrieve one field from a file like /proc/self/status. pattern
793 * should start with '\n' and end with a ':'. Whitespace and zeros
794 * after the ':' will be skipped. field must be freed afterwards.
796 int get_status_field(const char *filename, const char *pattern, char **field) {
797 _cleanup_free_ char *status = NULL;
806 r = read_full_file(filename, &status, NULL);
810 t = strstr(status, pattern);
814 t += strlen(pattern);
816 t += strspn(t, " \t");
818 /* Also skip zeros, because when this is used for
819 * capabilities, we don't want the zeros. This way the
820 * same capability set always maps to the same string,
821 * irrespective of the total capability set size. For
822 * other numbers it shouldn't matter. */
824 /* Back off one char if there's nothing but whitespace
826 if (!*t || isspace(*t))
830 len = strcspn(t, WHITESPACE);
832 *field = strndup(t, len);