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/>.
28 int write_string_to_file(FILE *f
, const char *line
) {
31 if (!endswith(line
, "\n"))
37 return errno
? -errno
: -EIO
;
42 int write_string_file(const char *fn
, const char *line
) {
43 _cleanup_fclose_
FILE *f
= NULL
;
52 return write_string_to_file(f
, line
);
55 int write_string_file_atomic(const char *fn
, const char *line
) {
56 _cleanup_fclose_
FILE *f
= NULL
;
57 _cleanup_free_
char *p
= NULL
;
63 r
= fopen_temporary(fn
, &f
, &p
);
67 fchmod_umask(fileno(f
), 0644);
71 if (!endswith(line
, "\n"))
77 r
= errno
? -errno
: -EIO
;
79 if (rename(p
, fn
) < 0)
91 int read_one_line_file(const char *fn
, char **line
) {
92 _cleanup_fclose_
FILE *f
= NULL
;
102 if (!fgets(t
, sizeof(t
), f
)) {
105 return errno
? -errno
: -EIO
;
119 int read_full_file(const char *fn
, char **contents
, size_t *size
) {
120 _cleanup_fclose_
FILE *f
= NULL
;
122 _cleanup_free_
char *buf
= NULL
;
132 if (fstat(fileno(f
), &st
) < 0)
136 if (st
.st_size
> 4*1024*1024)
139 n
= st
.st_size
> 0 ? st
.st_size
: LINE_MAX
;
146 t
= realloc(buf
, n
+1);
151 k
= fread(buf
+ l
, 1, n
- l
, f
);
178 static int parse_env_file_internal(
181 int (*push
) (const char *filename
, unsigned line
,
182 const char *key
, char *value
, void *userdata
),
185 _cleanup_free_
char *contents
= NULL
, *key
= NULL
;
186 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;
187 char *p
, *value
= NULL
;
198 SINGLE_QUOTE_VALUE_ESCAPE
,
200 DOUBLE_QUOTE_VALUE_ESCAPE
,
208 r
= read_full_file(fname
, &contents
, NULL
);
212 for (p
= contents
; *p
; p
++) {
218 if (strchr(COMMENTS
, c
))
220 else if (!strchr(WHITESPACE
, c
)) {
222 last_key_whitespace
= (size_t) -1;
224 if (!greedy_realloc((void**) &key
, &key_alloc
, n_key
+2)) {
234 if (strchr(newline
, c
)) {
238 } else if (c
== '=') {
240 last_value_whitespace
= (size_t) -1;
242 if (!strchr(WHITESPACE
, c
))
243 last_key_whitespace
= (size_t) -1;
244 else if (last_key_whitespace
== (size_t) -1)
245 last_key_whitespace
= n_key
;
247 if (!greedy_realloc((void**) &key
, &key_alloc
, n_key
+2)) {
258 if (strchr(newline
, c
)) {
266 /* strip trailing whitespace from key */
267 if (last_key_whitespace
!= (size_t) -1)
268 key
[last_key_whitespace
] = 0;
270 r
= push(fname
, line
, key
, value
, userdata
);
276 value_alloc
= n_value
= 0;
278 } else if (c
== '\'')
279 state
= SINGLE_QUOTE_VALUE
;
281 state
= DOUBLE_QUOTE_VALUE
;
283 state
= VALUE_ESCAPE
;
284 else if (!strchr(WHITESPACE
, c
)) {
287 if (!greedy_realloc((void**) &value
, &value_alloc
, n_value
+2)) {
292 value
[n_value
++] = c
;
298 if (strchr(newline
, c
)) {
307 /* Chomp off trailing whitespace from value */
308 if (last_value_whitespace
!= (size_t) -1)
309 value
[last_value_whitespace
] = 0;
311 /* strip trailing whitespace from key */
312 if (last_key_whitespace
!= (size_t) -1)
313 key
[last_key_whitespace
] = 0;
315 r
= push(fname
, line
, key
, value
, userdata
);
321 value_alloc
= n_value
= 0;
323 } else if (c
== '\\') {
324 state
= VALUE_ESCAPE
;
325 last_value_whitespace
= (size_t) -1;
327 if (!strchr(WHITESPACE
, c
))
328 last_value_whitespace
= (size_t) -1;
329 else if (last_value_whitespace
== (size_t) -1)
330 last_value_whitespace
= n_value
;
332 if (!greedy_realloc((void**) &value
, &value_alloc
, n_value
+2)) {
337 value
[n_value
++] = c
;
345 if (!strchr(newline
, c
)) {
346 /* Escaped newlines we eat up entirely */
347 if (!greedy_realloc((void**) &value
, &value_alloc
, n_value
+2)) {
352 value
[n_value
++] = c
;
356 case SINGLE_QUOTE_VALUE
:
360 state
= SINGLE_QUOTE_VALUE_ESCAPE
;
362 if (!greedy_realloc((void**) &value
, &value_alloc
, n_value
+2)) {
367 value
[n_value
++] = c
;
372 case SINGLE_QUOTE_VALUE_ESCAPE
:
373 state
= SINGLE_QUOTE_VALUE
;
375 if (!strchr(newline
, c
)) {
376 if (!greedy_realloc((void**) &value
, &value_alloc
, n_value
+2)) {
381 value
[n_value
++] = c
;
385 case DOUBLE_QUOTE_VALUE
:
389 state
= DOUBLE_QUOTE_VALUE_ESCAPE
;
391 if (!greedy_realloc((void**) &value
, &value_alloc
, n_value
+2)) {
396 value
[n_value
++] = c
;
401 case DOUBLE_QUOTE_VALUE_ESCAPE
:
402 state
= DOUBLE_QUOTE_VALUE
;
404 if (!strchr(newline
, c
)) {
405 if (!greedy_realloc((void**) &value
, &value_alloc
, n_value
+2)) {
410 value
[n_value
++] = c
;
416 state
= COMMENT_ESCAPE
;
417 else if (strchr(newline
, c
)) {
429 if (state
== PRE_VALUE
||
431 state
== VALUE_ESCAPE
||
432 state
== SINGLE_QUOTE_VALUE
||
433 state
== SINGLE_QUOTE_VALUE_ESCAPE
||
434 state
== DOUBLE_QUOTE_VALUE
||
435 state
== DOUBLE_QUOTE_VALUE_ESCAPE
) {
443 if (last_value_whitespace
!= (size_t) -1)
444 value
[last_value_whitespace
] = 0;
446 /* strip trailing whitespace from key */
447 if (last_key_whitespace
!= (size_t) -1)
448 key
[last_key_whitespace
] = 0;
450 r
= push(fname
, line
, key
, value
, userdata
);
462 static int parse_env_file_push(const char *filename
, unsigned line
,
463 const char *key
, char *value
, void *userdata
) {
464 assert(utf8_is_valid(key
));
466 if (value
&& !utf8_is_valid(value
))
467 /* FIXME: filter UTF-8 */
468 log_error("%s:%u: invalid UTF-8 for key %s: '%s', ignoring.",
469 filename
, line
, key
, value
);
472 va_list* ap
= (va_list*) userdata
;
477 while ((k
= va_arg(aq
, const char *))) {
480 v
= va_arg(aq
, char **);
499 const char *newline
, ...) {
507 va_start(ap
, newline
);
508 r
= parse_env_file_internal(fname
, newline
, parse_env_file_push
, &ap
);
514 static int load_env_file_push(const char *filename
, unsigned line
,
515 const char *key
, char *value
, void *userdata
) {
516 assert(utf8_is_valid(key
));
518 if (value
&& !utf8_is_valid(value
))
519 /* FIXME: filter UTF-8 */
520 log_error("%s:%u: invalid UTF-8 for key %s: '%s', ignoring.",
521 filename
, line
, key
, value
);
523 char ***m
= userdata
;
527 p
= strjoin(key
, "=", strempty(value
), NULL
);
542 int load_env_file(const char *fname
, const char *newline
, char ***rl
) {
549 r
= parse_env_file_internal(fname
, newline
, load_env_file_push
, &m
);
559 static void write_env_var(FILE *f
, const char *v
) {
571 fwrite(v
, 1, p
-v
, f
);
573 if (string_has_cc(p
) || chars_intersect(p
, WHITESPACE
"\'\"\\`$")) {
577 if (strchr("\'\"\\`$", *p
))
590 int write_env_file(const char *fname
, char **l
) {
592 _cleanup_free_
char *p
= NULL
;
593 _cleanup_fclose_
FILE *f
= NULL
;
596 r
= fopen_temporary(fname
, &f
, &p
);
600 fchmod_umask(fileno(f
), 0644);
604 write_env_var(f
, *i
);
609 r
= errno
? -errno
: -EIO
;
611 if (rename(p
, fname
) < 0)
623 int executable_is_script(const char *path
, char **interpreter
) {
625 char _cleanup_free_
*line
= NULL
;
631 r
= read_one_line_file(path
, &line
);
635 if (!startswith(line
, "#!"))
638 ans
= strstrip(line
+ 2);
639 len
= strcspn(ans
, " \t");
644 ans
= strndup(ans
, len
);
653 * Retrieve one field from a file like /proc/self/status. pattern
654 * should start with '\n' and end with a ':'. Whitespace and zeros
655 * after the ':' will be skipped. field must be freed afterwards.
657 int get_status_field(const char *filename
, const char *pattern
, char **field
) {
658 _cleanup_free_
char *status
= NULL
;
666 r
= read_full_file(filename
, &status
, NULL
);
670 t
= strstr(status
, pattern
);
674 t
+= strlen(pattern
);
675 /* Also skip zeros, because when this is used for capabilities,
676 * we don't want the zeros. This way the same capability set
677 * always maps to the same string, irrespective of the total
678 * capability set size. For other numbers it shouldn't matter.
681 t
+= strspn(t
, WHITESPACE
"0");
682 /* Back off one char if there's nothing but whitespace
688 len
= strcspn(t
, WHITESPACE
);
690 *field
= strndup(t
, len
);