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_to_file(FILE *f, const char *line) {
33 if (!endswith(line, "\n"))
39 return errno ? -errno : -EIO;
44 int write_string_file(const char *fn, const char *line) {
45 _cleanup_fclose_ FILE *f = NULL;
54 return write_string_to_file(f, line);
57 int write_string_file_atomic(const char *fn, const char *line) {
58 _cleanup_fclose_ FILE *f = NULL;
59 _cleanup_free_ char *p = NULL;
65 r = fopen_temporary(fn, &f, &p);
69 fchmod_umask(fileno(f), 0644);
73 if (!endswith(line, "\n"))
79 r = errno ? -errno : -EIO;
81 if (rename(p, fn) < 0)
93 int read_one_line_file(const char *fn, char **line) {
94 _cleanup_fclose_ FILE *f = NULL;
104 if (!fgets(t, sizeof(t), f)) {
107 return errno ? -errno : -EIO;
121 ssize_t sendfile_full(int out_fd, const char *fn) {
122 _cleanup_fclose_ FILE *f;
128 _cleanup_free_ char *buf = NULL;
137 r = fstat(fileno(f), &st);
141 s = sendfile(out_fd, fileno(f), NULL, st.st_size);
143 if (errno == EINVAL || errno == ENOSYS) {
150 /* sendfile() failed, fall back to read/write */
153 if (st.st_size > 4*1024*1024)
156 n = st.st_size > 0 ? st.st_size : LINE_MAX;
168 k = fread(buf + l, 1, n - l, f);
185 r = write(out_fd, buf, l);
192 int read_full_file(const char *fn, char **contents, size_t *size) {
193 _cleanup_fclose_ FILE *f = NULL;
195 _cleanup_free_ char *buf = NULL;
205 if (fstat(fileno(f), &st) < 0)
209 if (st.st_size > 4*1024*1024)
212 n = st.st_size > 0 ? st.st_size : LINE_MAX;
219 t = realloc(buf, n+1);
224 k = fread(buf + l, 1, n - l, f);
243 buf = NULL; /* do not free */
251 static int parse_env_file_internal(
254 int (*push) (const char *filename, unsigned line,
255 const char *key, char *value, void *userdata),
258 _cleanup_free_ char *contents = NULL, *key = NULL;
259 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;
260 char *p, *value = NULL;
271 SINGLE_QUOTE_VALUE_ESCAPE,
273 DOUBLE_QUOTE_VALUE_ESCAPE,
281 r = read_full_file(fname, &contents, NULL);
285 for (p = contents; *p; p++) {
291 if (strchr(COMMENTS, c))
293 else if (!strchr(WHITESPACE, c)) {
295 last_key_whitespace = (size_t) -1;
297 if (!greedy_realloc((void**) &key, &key_alloc, n_key+2)) {
307 if (strchr(newline, c)) {
311 } else if (c == '=') {
313 last_value_whitespace = (size_t) -1;
315 if (!strchr(WHITESPACE, c))
316 last_key_whitespace = (size_t) -1;
317 else if (last_key_whitespace == (size_t) -1)
318 last_key_whitespace = n_key;
320 if (!greedy_realloc((void**) &key, &key_alloc, n_key+2)) {
331 if (strchr(newline, c)) {
339 /* strip trailing whitespace from key */
340 if (last_key_whitespace != (size_t) -1)
341 key[last_key_whitespace] = 0;
343 r = push(fname, line, key, value, userdata);
349 value_alloc = n_value = 0;
351 } else if (c == '\'')
352 state = SINGLE_QUOTE_VALUE;
354 state = DOUBLE_QUOTE_VALUE;
356 state = VALUE_ESCAPE;
357 else if (!strchr(WHITESPACE, c)) {
360 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
365 value[n_value++] = c;
371 if (strchr(newline, c)) {
380 /* Chomp off trailing whitespace from value */
381 if (last_value_whitespace != (size_t) -1)
382 value[last_value_whitespace] = 0;
384 /* strip trailing whitespace from key */
385 if (last_key_whitespace != (size_t) -1)
386 key[last_key_whitespace] = 0;
388 r = push(fname, line, key, value, userdata);
394 value_alloc = n_value = 0;
396 } else if (c == '\\') {
397 state = VALUE_ESCAPE;
398 last_value_whitespace = (size_t) -1;
400 if (!strchr(WHITESPACE, c))
401 last_value_whitespace = (size_t) -1;
402 else if (last_value_whitespace == (size_t) -1)
403 last_value_whitespace = n_value;
405 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
410 value[n_value++] = c;
418 if (!strchr(newline, c)) {
419 /* Escaped newlines we eat up entirely */
420 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
425 value[n_value++] = c;
429 case SINGLE_QUOTE_VALUE:
433 state = SINGLE_QUOTE_VALUE_ESCAPE;
435 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
440 value[n_value++] = c;
445 case SINGLE_QUOTE_VALUE_ESCAPE:
446 state = SINGLE_QUOTE_VALUE;
448 if (!strchr(newline, c)) {
449 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
454 value[n_value++] = c;
458 case DOUBLE_QUOTE_VALUE:
462 state = DOUBLE_QUOTE_VALUE_ESCAPE;
464 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
469 value[n_value++] = c;
474 case DOUBLE_QUOTE_VALUE_ESCAPE:
475 state = DOUBLE_QUOTE_VALUE;
477 if (!strchr(newline, c)) {
478 if (!greedy_realloc((void**) &value, &value_alloc, n_value+2)) {
483 value[n_value++] = c;
489 state = COMMENT_ESCAPE;
490 else if (strchr(newline, c)) {
502 if (state == PRE_VALUE ||
504 state == VALUE_ESCAPE ||
505 state == SINGLE_QUOTE_VALUE ||
506 state == SINGLE_QUOTE_VALUE_ESCAPE ||
507 state == DOUBLE_QUOTE_VALUE ||
508 state == DOUBLE_QUOTE_VALUE_ESCAPE) {
516 if (last_value_whitespace != (size_t) -1)
517 value[last_value_whitespace] = 0;
519 /* strip trailing whitespace from key */
520 if (last_key_whitespace != (size_t) -1)
521 key[last_key_whitespace] = 0;
523 r = push(fname, line, key, value, userdata);
535 static int parse_env_file_push(const char *filename, unsigned line,
536 const char *key, char *value, void *userdata) {
539 va_list aq, *ap = userdata;
541 if (!utf8_is_valid(key)) {
542 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.",
543 filename, line, key);
547 if (value && !utf8_is_valid(value)) {
548 /* FIXME: filter UTF-8 */
549 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.",
550 filename, line, key, value);
556 while ((k = va_arg(aq, const char *))) {
559 v = va_arg(aq, char **);
576 const char *newline, ...) {
584 va_start(ap, newline);
585 r = parse_env_file_internal(fname, newline, parse_env_file_push, &ap);
591 static int load_env_file_push(const char *filename, unsigned line,
592 const char *key, char *value, void *userdata) {
593 char ***m = userdata;
597 if (!utf8_is_valid(key)) {
598 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.",
599 filename, line, key);
603 if (value && !utf8_is_valid(value)) {
604 /* FIXME: filter UTF-8 */
605 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.",
606 filename, line, key, value);
610 p = strjoin(key, "=", strempty(value), NULL);
624 int load_env_file(const char *fname, const char *newline, char ***rl) {
631 r = parse_env_file_internal(fname, newline, load_env_file_push, &m);
641 static void write_env_var(FILE *f, const char *v) {
653 fwrite(v, 1, p-v, f);
655 if (string_has_cc(p) || chars_intersect(p, WHITESPACE "\'\"\\`$")) {
659 if (strchr("\'\"\\`$", *p))
672 int write_env_file(const char *fname, char **l) {
674 _cleanup_free_ char *p = NULL;
675 _cleanup_fclose_ FILE *f = NULL;
678 r = fopen_temporary(fname, &f, &p);
682 fchmod_umask(fileno(f), 0644);
686 write_env_var(f, *i);
691 r = errno ? -errno : -EIO;
693 if (rename(p, fname) < 0)
705 int executable_is_script(const char *path, char **interpreter) {
707 char _cleanup_free_ *line = NULL;
713 r = read_one_line_file(path, &line);
717 if (!startswith(line, "#!"))
720 ans = strstrip(line + 2);
721 len = strcspn(ans, " \t");
726 ans = strndup(ans, len);
735 * Retrieve one field from a file like /proc/self/status. pattern
736 * should start with '\n' and end with a ':'. Whitespace and zeros
737 * after the ':' will be skipped. field must be freed afterwards.
739 int get_status_field(const char *filename, const char *pattern, char **field) {
740 _cleanup_free_ char *status = NULL;
749 r = read_full_file(filename, &status, NULL);
753 t = strstr(status, pattern);
757 t += strlen(pattern);
759 t += strspn(t, " \t");
761 /* Also skip zeros, because when this is used for
762 * capabilities, we don't want the zeros. This way the
763 * same capability set always maps to the same string,
764 * irrespective of the total capability set size. For
765 * other numbers it shouldn't matter. */
767 /* Back off one char if there's nothing but whitespace
769 if (!*t || isspace(*t))
773 len = strcspn(t, WHITESPACE);
775 *field = strndup(t, len);