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) {
37 if (!endswith(line, "\n"))
43 return errno ? -errno : -EIO;
48 int write_string_file(const char *fn, const char *line) {
49 _cleanup_fclose_ FILE *f = NULL;
58 return write_string_stream(f, line);
61 int write_string_file_no_create(const char *fn, const char *line) {
62 _cleanup_fclose_ FILE *f = NULL;
68 /* We manually build our own version of fopen(..., "we") that
70 fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY);
80 return write_string_stream(f, line);
83 int write_string_file_atomic(const char *fn, const char *line) {
84 _cleanup_fclose_ FILE *f = NULL;
85 _cleanup_free_ char *p = NULL;
91 r = fopen_temporary(fn, &f, &p);
95 fchmod_umask(fileno(f), 0644);
99 if (!endswith(line, "\n"))
105 r = errno ? -errno : -EIO;
107 if (rename(p, fn) < 0)
119 int read_one_line_file(const char *fn, char **line) {
120 _cleanup_fclose_ FILE *f = NULL;
121 char t[LINE_MAX], *c;
130 if (!fgets(t, sizeof(t), f)) {
133 return errno ? -errno : -EIO;
147 int read_full_stream(FILE *f, char **contents, size_t *size) {
149 _cleanup_free_ char *buf = NULL;
155 if (fstat(fileno(f), &st) < 0)
160 if (S_ISREG(st.st_mode)) {
163 if (st.st_size > 4*1024*1024)
166 /* Start with the right file size, but be prepared for
167 * files from /proc which generally report a file size
178 t = realloc(buf, n+1);
183 k = fread(buf + l, 1, n - l, f);
202 buf = NULL; /* do not free */
210 int read_full_file(const char *fn, char **contents, size_t *size) {
211 _cleanup_fclose_ FILE *f = NULL;
220 return read_full_stream(f, contents, size);
223 static int parse_env_file_internal(
227 int (*push) (const char *filename, unsigned line,
228 const char *key, char *value, void *userdata, int *n_pushed),
232 _cleanup_free_ char *contents = NULL, *key = NULL;
233 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;
234 char *p, *value = NULL;
245 SINGLE_QUOTE_VALUE_ESCAPE,
247 DOUBLE_QUOTE_VALUE_ESCAPE,
255 r = read_full_stream(f, &contents, NULL);
257 r = read_full_file(fname, &contents, NULL);
261 for (p = contents; *p; p++) {
267 if (strchr(COMMENTS, c))
269 else if (!strchr(WHITESPACE, c)) {
271 last_key_whitespace = (size_t) -1;
273 if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) {
283 if (strchr(newline, c)) {
287 } else if (c == '=') {
289 last_value_whitespace = (size_t) -1;
291 if (!strchr(WHITESPACE, c))
292 last_key_whitespace = (size_t) -1;
293 else if (last_key_whitespace == (size_t) -1)
294 last_key_whitespace = n_key;
296 if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) {
307 if (strchr(newline, c)) {
315 /* strip trailing whitespace from key */
316 if (last_key_whitespace != (size_t) -1)
317 key[last_key_whitespace] = 0;
319 r = push(fname, line, key, value, userdata, n_pushed);
325 value_alloc = n_value = 0;
327 } else if (c == '\'')
328 state = SINGLE_QUOTE_VALUE;
330 state = DOUBLE_QUOTE_VALUE;
332 state = VALUE_ESCAPE;
333 else if (!strchr(WHITESPACE, c)) {
336 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
341 value[n_value++] = c;
347 if (strchr(newline, c)) {
356 /* Chomp off trailing whitespace from value */
357 if (last_value_whitespace != (size_t) -1)
358 value[last_value_whitespace] = 0;
360 /* strip trailing whitespace from key */
361 if (last_key_whitespace != (size_t) -1)
362 key[last_key_whitespace] = 0;
364 r = push(fname, line, key, value, userdata, n_pushed);
370 value_alloc = n_value = 0;
372 } else if (c == '\\') {
373 state = VALUE_ESCAPE;
374 last_value_whitespace = (size_t) -1;
376 if (!strchr(WHITESPACE, c))
377 last_value_whitespace = (size_t) -1;
378 else if (last_value_whitespace == (size_t) -1)
379 last_value_whitespace = n_value;
381 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
386 value[n_value++] = c;
394 if (!strchr(newline, c)) {
395 /* Escaped newlines we eat up entirely */
396 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
401 value[n_value++] = c;
405 case SINGLE_QUOTE_VALUE:
409 state = SINGLE_QUOTE_VALUE_ESCAPE;
411 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
416 value[n_value++] = c;
421 case SINGLE_QUOTE_VALUE_ESCAPE:
422 state = SINGLE_QUOTE_VALUE;
424 if (!strchr(newline, c)) {
425 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
430 value[n_value++] = c;
434 case DOUBLE_QUOTE_VALUE:
438 state = DOUBLE_QUOTE_VALUE_ESCAPE;
440 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
445 value[n_value++] = c;
450 case DOUBLE_QUOTE_VALUE_ESCAPE:
451 state = DOUBLE_QUOTE_VALUE;
453 if (!strchr(newline, c)) {
454 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
459 value[n_value++] = c;
465 state = COMMENT_ESCAPE;
466 else if (strchr(newline, c)) {
478 if (state == PRE_VALUE ||
480 state == VALUE_ESCAPE ||
481 state == SINGLE_QUOTE_VALUE ||
482 state == SINGLE_QUOTE_VALUE_ESCAPE ||
483 state == DOUBLE_QUOTE_VALUE ||
484 state == DOUBLE_QUOTE_VALUE_ESCAPE) {
492 if (last_value_whitespace != (size_t) -1)
493 value[last_value_whitespace] = 0;
495 /* strip trailing whitespace from key */
496 if (last_key_whitespace != (size_t) -1)
497 key[last_key_whitespace] = 0;
499 r = push(fname, line, key, value, userdata, n_pushed);
511 static int parse_env_file_push(
512 const char *filename, unsigned line,
513 const char *key, char *value,
518 va_list aq, *ap = userdata;
520 if (!utf8_is_valid(key)) {
521 _cleanup_free_ char *p;
523 p = utf8_escape_invalid(key);
524 log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p);
528 if (value && !utf8_is_valid(value)) {
529 _cleanup_free_ char *p;
531 p = utf8_escape_invalid(value);
532 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, p);
538 while ((k = va_arg(aq, const char *))) {
541 v = va_arg(aq, char **);
563 const char *newline, ...) {
571 va_start(ap, newline);
572 r = parse_env_file_internal(NULL, fname, newline, parse_env_file_push, &ap, &n_pushed);
575 return r < 0 ? r : n_pushed;
578 static int load_env_file_push(
579 const char *filename, unsigned line,
580 const char *key, char *value,
583 char ***m = userdata;
587 if (!utf8_is_valid(key)) {
588 _cleanup_free_ char *t = utf8_escape_invalid(key);
590 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t);
594 if (value && !utf8_is_valid(value)) {
595 _cleanup_free_ char *t = utf8_escape_invalid(value);
597 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t);
601 p = strjoin(key, "=", strempty(value), NULL);
605 r = strv_consume(m, p);
616 int load_env_file(FILE *f, const char *fname, const char *newline, char ***rl) {
623 r = parse_env_file_internal(f, fname, newline, load_env_file_push, &m, NULL);
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);
692 static void write_env_var(FILE *f, const char *v) {
704 fwrite(v, 1, p-v, f);
706 if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) {
710 if (strchr(SHELL_NEED_ESCAPE, *p))
723 int write_env_file(const char *fname, char **l) {
724 _cleanup_fclose_ FILE *f = NULL;
725 _cleanup_free_ char *p = NULL;
731 r = fopen_temporary(fname, &f, &p);
735 fchmod_umask(fileno(f), 0644);
738 write_env_var(f, *i);
740 r = fflush_and_check(f);
742 if (rename(p, fname) >= 0)
752 int executable_is_script(const char *path, char **interpreter) {
754 _cleanup_free_ char *line = NULL;
760 r = read_one_line_file(path, &line);
764 if (!startswith(line, "#!"))
767 ans = strstrip(line + 2);
768 len = strcspn(ans, " \t");
773 ans = strndup(ans, len);
782 * Retrieve one field from a file like /proc/self/status. pattern
783 * should start with '\n' and end with a ':'. Whitespace and zeros
784 * after the ':' will be skipped. field must be freed afterwards.
786 int get_status_field(const char *filename, const char *pattern, char **field) {
787 _cleanup_free_ char *status = NULL;
796 r = read_full_file(filename, &status, NULL);
800 t = strstr(status, pattern);
804 t += strlen(pattern);
806 t += strspn(t, " \t");
808 /* Also skip zeros, because when this is used for
809 * capabilities, we don't want the zeros. This way the
810 * same capability set always maps to the same string,
811 * irrespective of the total capability set size. For
812 * other numbers it shouldn't matter. */
814 /* Back off one char if there's nothing but whitespace
816 if (!*t || isspace(*t))
820 len = strcspn(t, WHITESPACE);
822 *field = strndup(t, len);