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/>.
23 #include <sys/sendfile.h>
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_atomic(const char *fn, const char *line) {
62 _cleanup_fclose_ FILE *f = NULL;
63 _cleanup_free_ char *p = NULL;
69 r = fopen_temporary(fn, &f, &p);
73 fchmod_umask(fileno(f), 0644);
77 if (!endswith(line, "\n"))
83 r = errno ? -errno : -EIO;
85 if (rename(p, fn) < 0)
97 int read_one_line_file(const char *fn, char **line) {
98 _cleanup_fclose_ FILE *f = NULL;
108 if (!fgets(t, sizeof(t), f)) {
111 return errno ? -errno : -EIO;
125 ssize_t sendfile_full(int out_fd, const char *fn) {
126 _cleanup_fclose_ FILE *f;
132 _cleanup_free_ char *buf = NULL;
141 r = fstat(fileno(f), &st);
145 s = sendfile(out_fd, fileno(f), NULL, st.st_size);
147 if (errno == EINVAL || errno == ENOSYS) {
154 /* sendfile() failed, fall back to read/write */
157 if (st.st_size > 4*1024*1024)
160 n = st.st_size > 0 ? st.st_size : LINE_MAX;
172 k = fread(buf + l, 1, n - l, f);
189 r = write(out_fd, buf, l);
196 int read_full_stream(FILE *f, char **contents, size_t *size) {
198 _cleanup_free_ char *buf = NULL;
204 if (fstat(fileno(f), &st) < 0)
209 if (S_ISREG(st.st_mode)) {
212 if (st.st_size > 4*1024*1024)
215 /* Start with the right file size, but be prepared for
216 * files from /proc which generally report a file size
227 t = realloc(buf, n+1);
232 k = fread(buf + l, 1, n - l, f);
251 buf = NULL; /* do not free */
259 int read_full_file(const char *fn, char **contents, size_t *size) {
260 _cleanup_fclose_ FILE *f = NULL;
269 return read_full_stream(f, contents, size);
272 static int parse_env_file_internal(
276 int (*push) (const char *filename, unsigned line,
277 const char *key, char *value, void *userdata),
280 _cleanup_free_ char *contents = NULL, *key = NULL;
281 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;
282 char *p, *value = NULL;
293 SINGLE_QUOTE_VALUE_ESCAPE,
295 DOUBLE_QUOTE_VALUE_ESCAPE,
303 r = read_full_stream(f, &contents, NULL);
305 r = read_full_file(fname, &contents, NULL);
309 for (p = contents; *p; p++) {
315 if (strchr(COMMENTS, c))
317 else if (!strchr(WHITESPACE, c)) {
319 last_key_whitespace = (size_t) -1;
321 if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) {
331 if (strchr(newline, c)) {
335 } else if (c == '=') {
337 last_value_whitespace = (size_t) -1;
339 if (!strchr(WHITESPACE, c))
340 last_key_whitespace = (size_t) -1;
341 else if (last_key_whitespace == (size_t) -1)
342 last_key_whitespace = n_key;
344 if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) {
355 if (strchr(newline, c)) {
363 /* strip trailing whitespace from key */
364 if (last_key_whitespace != (size_t) -1)
365 key[last_key_whitespace] = 0;
367 r = push(fname, line, key, value, userdata);
373 value_alloc = n_value = 0;
375 } else if (c == '\'')
376 state = SINGLE_QUOTE_VALUE;
378 state = DOUBLE_QUOTE_VALUE;
380 state = VALUE_ESCAPE;
381 else if (!strchr(WHITESPACE, c)) {
384 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
389 value[n_value++] = c;
395 if (strchr(newline, c)) {
404 /* Chomp off trailing whitespace from value */
405 if (last_value_whitespace != (size_t) -1)
406 value[last_value_whitespace] = 0;
408 /* strip trailing whitespace from key */
409 if (last_key_whitespace != (size_t) -1)
410 key[last_key_whitespace] = 0;
412 r = push(fname, line, key, value, userdata);
418 value_alloc = n_value = 0;
420 } else if (c == '\\') {
421 state = VALUE_ESCAPE;
422 last_value_whitespace = (size_t) -1;
424 if (!strchr(WHITESPACE, c))
425 last_value_whitespace = (size_t) -1;
426 else if (last_value_whitespace == (size_t) -1)
427 last_value_whitespace = n_value;
429 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
434 value[n_value++] = c;
442 if (!strchr(newline, c)) {
443 /* Escaped newlines we eat up entirely */
444 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
449 value[n_value++] = c;
453 case SINGLE_QUOTE_VALUE:
457 state = SINGLE_QUOTE_VALUE_ESCAPE;
459 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
464 value[n_value++] = c;
469 case SINGLE_QUOTE_VALUE_ESCAPE:
470 state = SINGLE_QUOTE_VALUE;
472 if (!strchr(newline, c)) {
473 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
478 value[n_value++] = c;
482 case DOUBLE_QUOTE_VALUE:
486 state = DOUBLE_QUOTE_VALUE_ESCAPE;
488 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
493 value[n_value++] = c;
498 case DOUBLE_QUOTE_VALUE_ESCAPE:
499 state = DOUBLE_QUOTE_VALUE;
501 if (!strchr(newline, c)) {
502 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
507 value[n_value++] = c;
513 state = COMMENT_ESCAPE;
514 else if (strchr(newline, c)) {
526 if (state == PRE_VALUE ||
528 state == VALUE_ESCAPE ||
529 state == SINGLE_QUOTE_VALUE ||
530 state == SINGLE_QUOTE_VALUE_ESCAPE ||
531 state == DOUBLE_QUOTE_VALUE ||
532 state == DOUBLE_QUOTE_VALUE_ESCAPE) {
540 if (last_value_whitespace != (size_t) -1)
541 value[last_value_whitespace] = 0;
543 /* strip trailing whitespace from key */
544 if (last_key_whitespace != (size_t) -1)
545 key[last_key_whitespace] = 0;
547 r = push(fname, line, key, value, userdata);
559 static int parse_env_file_push(
560 const char *filename, unsigned line,
561 const char *key, char *value,
565 va_list aq, *ap = userdata;
567 if (!utf8_is_valid(key)) {
568 _cleanup_free_ char *p;
570 p = utf8_escape_invalid(key);
571 log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p);
575 if (value && !utf8_is_valid(value)) {
576 _cleanup_free_ char *p;
578 p = utf8_escape_invalid(value);
579 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, p);
585 while ((k = va_arg(aq, const char *))) {
588 v = va_arg(aq, char **);
606 const char *newline, ...) {
614 va_start(ap, newline);
615 r = parse_env_file_internal(NULL, fname, newline, parse_env_file_push, &ap);
621 static int load_env_file_push(
622 const char *filename, unsigned line,
623 const char *key, char *value,
625 char ***m = userdata;
629 if (!utf8_is_valid(key)) {
630 _cleanup_free_ char *t = utf8_escape_invalid(key);
632 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t);
636 if (value && !utf8_is_valid(value)) {
637 _cleanup_free_ char *t = utf8_escape_invalid(value);
639 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t);
643 p = strjoin(key, "=", strempty(value), NULL);
647 r = strv_consume(m, p);
655 int load_env_file(FILE *f, const char *fname, const char *newline, char ***rl) {
662 r = parse_env_file_internal(f, fname, newline, load_env_file_push, &m);
672 static int load_env_file_push_pairs(
673 const char *filename, unsigned line,
674 const char *key, char *value,
676 char ***m = userdata;
679 if (!utf8_is_valid(key)) {
680 _cleanup_free_ char *t = utf8_escape_invalid(key);
682 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t);
686 if (value && !utf8_is_valid(value)) {
687 _cleanup_free_ char *t = utf8_escape_invalid(value);
689 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t);
693 r = strv_extend(m, key);
698 r = strv_extend(m, "");
702 r = strv_push(m, value);
710 int load_env_file_pairs(FILE *f, const char *fname, const char *newline, char ***rl) {
717 r = parse_env_file_internal(f, fname, newline, load_env_file_push_pairs, &m);
727 static void write_env_var(FILE *f, const char *v) {
739 fwrite(v, 1, p-v, f);
741 if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) {
745 if (strchr(SHELL_NEED_ESCAPE, *p))
758 int write_env_file(const char *fname, char **l) {
759 _cleanup_fclose_ FILE *f = NULL;
760 _cleanup_free_ char *p = NULL;
766 r = fopen_temporary(fname, &f, &p);
770 fchmod_umask(fileno(f), 0644);
773 write_env_var(f, *i);
775 r = fflush_and_check(f);
777 if (rename(p, fname) >= 0)
787 int executable_is_script(const char *path, char **interpreter) {
789 _cleanup_free_ char *line = NULL;
795 r = read_one_line_file(path, &line);
799 if (!startswith(line, "#!"))
802 ans = strstrip(line + 2);
803 len = strcspn(ans, " \t");
808 ans = strndup(ans, len);
817 * Retrieve one field from a file like /proc/self/status. pattern
818 * should start with '\n' and end with a ':'. Whitespace and zeros
819 * after the ':' will be skipped. field must be freed afterwards.
821 int get_status_field(const char *filename, const char *pattern, char **field) {
822 _cleanup_free_ char *status = NULL;
831 r = read_full_file(filename, &status, NULL);
835 t = strstr(status, pattern);
839 t += strlen(pattern);
841 t += strspn(t, " \t");
843 /* Also skip zeros, because when this is used for
844 * capabilities, we don't want the zeros. This way the
845 * same capability set always maps to the same string,
846 * irrespective of the total capability set size. For
847 * other numbers it shouldn't matter. */
849 /* Back off one char if there's nothing but whitespace
851 if (!*t || isspace(*t))
855 len = strcspn(t, WHITESPACE);
857 *field = strndup(t, len);