]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/fileio.c
util: make use of isempty() where appropriate
[thirdparty/systemd.git] / src / shared / fileio.c
CommitLineData
a5c32cff
HH
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
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.
12
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.
17
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/>.
20***/
21
22#include <unistd.h>
e93c33d4 23#include <sys/sendfile.h>
a5c32cff
HH
24#include "fileio.h"
25#include "util.h"
26#include "strv.h"
335c46b5 27#include "utf8.h"
1e5413f7 28#include "ctype.h"
a5c32cff 29
717603e3
LP
30int write_string_stream(FILE *f, const char *line) {
31 assert(f);
32 assert(line);
33
a5c32cff 34 errno = 0;
717603e3 35
fec6fc6b 36 fputs(line, f);
a5c32cff
HH
37 if (!endswith(line, "\n"))
38 fputc('\n', f);
39
40 fflush(f);
41
42 if (ferror(f))
43 return errno ? -errno : -EIO;
44
45 return 0;
46}
47
b4bc041b
ZJS
48int write_string_file(const char *fn, const char *line) {
49 _cleanup_fclose_ FILE *f = NULL;
50
51 assert(fn);
52 assert(line);
53
54 f = fopen(fn, "we");
55 if (!f)
56 return -errno;
57
717603e3 58 return write_string_stream(f, line);
b4bc041b
ZJS
59}
60
70c949a4
LP
61int write_string_file_no_create(const char *fn, const char *line) {
62 _cleanup_fclose_ FILE *f = NULL;
63 int fd;
64
65 assert(fn);
66 assert(line);
67
68 /* We manually build our own version of fopen(..., "we") that
69 * without O_CREAT */
70 fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY);
71 if (fd < 0)
72 return -errno;
73
74 f = fdopen(fd, "we");
75 if (!f) {
76 safe_close(fd);
77 return -errno;
78 }
79
80 return write_string_stream(f, line);
81}
82
574d5f2d 83int write_string_file_atomic(const char *fn, const char *line) {
a5c32cff
HH
84 _cleanup_fclose_ FILE *f = NULL;
85 _cleanup_free_ char *p = NULL;
86 int r;
87
88 assert(fn);
89 assert(line);
90
91 r = fopen_temporary(fn, &f, &p);
92 if (r < 0)
93 return r;
94
95 fchmod_umask(fileno(f), 0644);
96
97 errno = 0;
fec6fc6b 98 fputs(line, f);
a5c32cff
HH
99 if (!endswith(line, "\n"))
100 fputc('\n', f);
101
102 fflush(f);
103
104 if (ferror(f))
105 r = errno ? -errno : -EIO;
106 else {
107 if (rename(p, fn) < 0)
108 r = -errno;
109 else
110 r = 0;
111 }
112
a5c32cff
HH
113 if (r < 0)
114 unlink(p);
115
116 return r;
117}
118
119int read_one_line_file(const char *fn, char **line) {
120 _cleanup_fclose_ FILE *f = NULL;
121 char t[LINE_MAX], *c;
122
123 assert(fn);
124 assert(line);
125
126 f = fopen(fn, "re");
127 if (!f)
128 return -errno;
129
130 if (!fgets(t, sizeof(t), f)) {
131
132 if (ferror(f))
133 return errno ? -errno : -EIO;
134
135 t[0] = 0;
136 }
137
138 c = strdup(t);
139 if (!c)
140 return -ENOMEM;
141 truncate_nl(c);
142
143 *line = c;
144 return 0;
145}
146
e93c33d4
SL
147ssize_t sendfile_full(int out_fd, const char *fn) {
148 _cleanup_fclose_ FILE *f;
149 struct stat st;
150 int r;
151 ssize_t s;
152
153 size_t n, l;
154 _cleanup_free_ char *buf = NULL;
155
156 assert(out_fd > 0);
157 assert(fn);
158
c8a202b7 159 f = fopen(fn, "re");
e93c33d4
SL
160 if (!f)
161 return -errno;
162
163 r = fstat(fileno(f), &st);
164 if (r < 0)
165 return -errno;
166
167 s = sendfile(out_fd, fileno(f), NULL, st.st_size);
168 if (s < 0)
169 if (errno == EINVAL || errno == ENOSYS) {
170 /* continue below */
171 } else
172 return -errno;
173 else
174 return s;
175
176 /* sendfile() failed, fall back to read/write */
177
178 /* Safety check */
179 if (st.st_size > 4*1024*1024)
180 return -E2BIG;
181
182 n = st.st_size > 0 ? st.st_size : LINE_MAX;
183 l = 0;
184
185 while (true) {
186 char *t;
187 size_t k;
188
189 t = realloc(buf, n);
190 if (!t)
191 return -ENOMEM;
192
193 buf = t;
194 k = fread(buf + l, 1, n - l, f);
195
196 if (k <= 0) {
197 if (ferror(f))
198 return -errno;
199
200 break;
201 }
202
203 l += k;
204 n *= 2;
205
206 /* Safety check */
207 if (n > 4*1024*1024)
208 return -E2BIG;
209 }
210
211 r = write(out_fd, buf, l);
212 if (r < 0)
213 return -errno;
214
215 return (ssize_t) l;
216}
217
717603e3 218int read_full_stream(FILE *f, char **contents, size_t *size) {
a5c32cff
HH
219 size_t n, l;
220 _cleanup_free_ char *buf = NULL;
221 struct stat st;
222
717603e3 223 assert(f);
a5c32cff
HH
224 assert(contents);
225
a5c32cff
HH
226 if (fstat(fileno(f), &st) < 0)
227 return -errno;
228
717603e3 229 n = LINE_MAX;
a5c32cff 230
717603e3
LP
231 if (S_ISREG(st.st_mode)) {
232
233 /* Safety check */
234 if (st.st_size > 4*1024*1024)
235 return -E2BIG;
236
237 /* Start with the right file size, but be prepared for
238 * files from /proc which generally report a file size
239 * of 0 */
240 if (st.st_size > 0)
241 n = st.st_size;
242 }
a5c32cff 243
717603e3 244 l = 0;
a5c32cff
HH
245 for (;;) {
246 char *t;
247 size_t k;
248
249 t = realloc(buf, n+1);
250 if (!t)
251 return -ENOMEM;
252
253 buf = t;
254 k = fread(buf + l, 1, n - l, f);
255
256 if (k <= 0) {
257 if (ferror(f))
258 return -errno;
259
260 break;
261 }
262
263 l += k;
264 n *= 2;
265
266 /* Safety check */
267 if (n > 4*1024*1024)
268 return -E2BIG;
269 }
270
271 buf[l] = 0;
272 *contents = buf;
d78a28e3 273 buf = NULL; /* do not free */
a5c32cff
HH
274
275 if (size)
276 *size = l;
277
278 return 0;
279}
280
717603e3
LP
281int read_full_file(const char *fn, char **contents, size_t *size) {
282 _cleanup_fclose_ FILE *f = NULL;
283
284 assert(fn);
285 assert(contents);
286
287 f = fopen(fn, "re");
288 if (!f)
289 return -errno;
290
291 return read_full_stream(f, contents, size);
292}
293
f73141d7 294static int parse_env_file_internal(
717603e3 295 FILE *f,
a5c32cff 296 const char *fname,
f73141d7 297 const char *newline,
335c46b5 298 int (*push) (const char *filename, unsigned line,
a5f6c30d
MS
299 const char *key, char *value, void *userdata, int *n_pushed),
300 void *userdata,
301 int *n_pushed) {
f73141d7
LP
302
303 _cleanup_free_ char *contents = NULL, *key = NULL;
2b77f67e 304 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;
f73141d7
LP
305 char *p, *value = NULL;
306 int r;
335c46b5 307 unsigned line = 1;
a5c32cff 308
f73141d7
LP
309 enum {
310 PRE_KEY,
311 KEY,
f73141d7
LP
312 PRE_VALUE,
313 VALUE,
314 VALUE_ESCAPE,
315 SINGLE_QUOTE_VALUE,
316 SINGLE_QUOTE_VALUE_ESCAPE,
317 DOUBLE_QUOTE_VALUE,
318 DOUBLE_QUOTE_VALUE_ESCAPE,
319 COMMENT,
320 COMMENT_ESCAPE
321 } state = PRE_KEY;
a5c32cff 322
f73141d7 323 assert(newline);
a5c32cff 324
717603e3
LP
325 if (f)
326 r = read_full_stream(f, &contents, NULL);
327 else
328 r = read_full_file(fname, &contents, NULL);
1c17cbed 329 if (r < 0)
a5c32cff
HH
330 return r;
331
f73141d7
LP
332 for (p = contents; *p; p++) {
333 char c = *p;
334
335 switch (state) {
336
337 case PRE_KEY:
ebc05a09 338 if (strchr(COMMENTS, c))
f73141d7
LP
339 state = COMMENT;
340 else if (!strchr(WHITESPACE, c)) {
341 state = KEY;
2b77f67e
LP
342 last_key_whitespace = (size_t) -1;
343
ca2d3784 344 if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) {
f73141d7
LP
345 r = -ENOMEM;
346 goto fail;
347 }
348
349 key[n_key++] = c;
350 }
351 break;
352
353 case KEY:
354 if (strchr(newline, c)) {
355 state = PRE_KEY;
335c46b5 356 line ++;
f73141d7 357 n_key = 0;
2b77f67e 358 } else if (c == '=') {
f73141d7 359 state = PRE_VALUE;
2b77f67e
LP
360 last_value_whitespace = (size_t) -1;
361 } else {
362 if (!strchr(WHITESPACE, c))
363 last_key_whitespace = (size_t) -1;
364 else if (last_key_whitespace == (size_t) -1)
365 last_key_whitespace = n_key;
366
ca2d3784 367 if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) {
f73141d7
LP
368 r = -ENOMEM;
369 goto fail;
370 }
371
372 key[n_key++] = c;
373 }
a5c32cff 374
f73141d7
LP
375 break;
376
f73141d7 377 case PRE_VALUE:
98f59e59 378 if (strchr(newline, c)) {
f73141d7 379 state = PRE_KEY;
335c46b5 380 line ++;
f73141d7 381 key[n_key] = 0;
a5c32cff 382
f73141d7
LP
383 if (value)
384 value[n_value] = 0;
a5c32cff 385
ebc05a09 386 /* strip trailing whitespace from key */
2b77f67e
LP
387 if (last_key_whitespace != (size_t) -1)
388 key[last_key_whitespace] = 0;
ebc05a09 389
a5f6c30d 390 r = push(fname, line, key, value, userdata, n_pushed);
f73141d7
LP
391 if (r < 0)
392 goto fail;
393
394 n_key = 0;
395 value = NULL;
396 value_alloc = n_value = 0;
2b77f67e 397
f73141d7
LP
398 } else if (c == '\'')
399 state = SINGLE_QUOTE_VALUE;
400 else if (c == '\"')
401 state = DOUBLE_QUOTE_VALUE;
402 else if (c == '\\')
403 state = VALUE_ESCAPE;
404 else if (!strchr(WHITESPACE, c)) {
405 state = VALUE;
406
ca2d3784 407 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
f73141d7
LP
408 r = -ENOMEM;
409 goto fail;
410 }
411
412 value[n_value++] = c;
413 }
414
415 break;
416
417 case VALUE:
418 if (strchr(newline, c)) {
419 state = PRE_KEY;
335c46b5 420 line ++;
98f59e59 421
f73141d7
LP
422 key[n_key] = 0;
423
424 if (value)
425 value[n_value] = 0;
426
2b77f67e
LP
427 /* Chomp off trailing whitespace from value */
428 if (last_value_whitespace != (size_t) -1)
429 value[last_value_whitespace] = 0;
f73141d7 430
ebc05a09 431 /* strip trailing whitespace from key */
2b77f67e
LP
432 if (last_key_whitespace != (size_t) -1)
433 key[last_key_whitespace] = 0;
ebc05a09 434
a5f6c30d 435 r = push(fname, line, key, value, userdata, n_pushed);
f73141d7
LP
436 if (r < 0)
437 goto fail;
438
439 n_key = 0;
440 value = NULL;
441 value_alloc = n_value = 0;
2b77f67e 442
f73141d7
LP
443 } else if (c == '\\') {
444 state = VALUE_ESCAPE;
2b77f67e 445 last_value_whitespace = (size_t) -1;
f73141d7
LP
446 } else {
447 if (!strchr(WHITESPACE, c))
2b77f67e
LP
448 last_value_whitespace = (size_t) -1;
449 else if (last_value_whitespace == (size_t) -1)
450 last_value_whitespace = n_value;
f73141d7 451
ca2d3784 452 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
f73141d7
LP
453 r = -ENOMEM;
454 goto fail;
455 }
456
457 value[n_value++] = c;
458 }
459
460 break;
461
462 case VALUE_ESCAPE:
463 state = VALUE;
464
465 if (!strchr(newline, c)) {
466 /* Escaped newlines we eat up entirely */
ca2d3784 467 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
f73141d7
LP
468 r = -ENOMEM;
469 goto fail;
470 }
471
472 value[n_value++] = c;
473 }
474 break;
475
476 case SINGLE_QUOTE_VALUE:
477 if (c == '\'')
478 state = PRE_VALUE;
479 else if (c == '\\')
480 state = SINGLE_QUOTE_VALUE_ESCAPE;
481 else {
ca2d3784 482 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
f73141d7
LP
483 r = -ENOMEM;
484 goto fail;
485 }
a5c32cff 486
f73141d7
LP
487 value[n_value++] = c;
488 }
a5c32cff 489
f73141d7 490 break;
a5c32cff 491
f73141d7
LP
492 case SINGLE_QUOTE_VALUE_ESCAPE:
493 state = SINGLE_QUOTE_VALUE;
a5c32cff 494
f73141d7 495 if (!strchr(newline, c)) {
ca2d3784 496 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
a5c32cff 497 r = -ENOMEM;
a5c32cff
HH
498 goto fail;
499 }
500
f73141d7
LP
501 value[n_value++] = c;
502 }
503 break;
504
505 case DOUBLE_QUOTE_VALUE:
506 if (c == '\"')
507 state = PRE_VALUE;
508 else if (c == '\\')
509 state = DOUBLE_QUOTE_VALUE_ESCAPE;
510 else {
ca2d3784 511 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
f73141d7
LP
512 r = -ENOMEM;
513 goto fail;
a5c32cff
HH
514 }
515
f73141d7
LP
516 value[n_value++] = c;
517 }
518
519 break;
520
521 case DOUBLE_QUOTE_VALUE_ESCAPE:
522 state = DOUBLE_QUOTE_VALUE;
a5c32cff 523
f73141d7 524 if (!strchr(newline, c)) {
ca2d3784 525 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
f73141d7
LP
526 r = -ENOMEM;
527 goto fail;
528 }
a5c32cff 529
f73141d7 530 value[n_value++] = c;
a5c32cff 531 }
f73141d7
LP
532 break;
533
534 case COMMENT:
535 if (c == '\\')
536 state = COMMENT_ESCAPE;
335c46b5 537 else if (strchr(newline, c)) {
f73141d7 538 state = PRE_KEY;
335c46b5
ZJS
539 line ++;
540 }
f73141d7
LP
541 break;
542
543 case COMMENT_ESCAPE:
544 state = COMMENT;
545 break;
a5c32cff 546 }
f73141d7
LP
547 }
548
549 if (state == PRE_VALUE ||
550 state == VALUE ||
551 state == VALUE_ESCAPE ||
552 state == SINGLE_QUOTE_VALUE ||
553 state == SINGLE_QUOTE_VALUE_ESCAPE ||
554 state == DOUBLE_QUOTE_VALUE ||
555 state == DOUBLE_QUOTE_VALUE_ESCAPE) {
a5c32cff 556
f73141d7
LP
557 key[n_key] = 0;
558
559 if (value)
560 value[n_value] = 0;
561
2b77f67e
LP
562 if (state == VALUE)
563 if (last_value_whitespace != (size_t) -1)
564 value[last_value_whitespace] = 0;
565
ebc05a09 566 /* strip trailing whitespace from key */
2b77f67e
LP
567 if (last_key_whitespace != (size_t) -1)
568 key[last_key_whitespace] = 0;
ebc05a09 569
a5f6c30d 570 r = push(fname, line, key, value, userdata, n_pushed);
f73141d7
LP
571 if (r < 0)
572 goto fail;
a5c32cff
HH
573 }
574
f73141d7
LP
575 return 0;
576
a5c32cff 577fail:
f73141d7 578 free(value);
a5c32cff
HH
579 return r;
580}
581
717603e3
LP
582static int parse_env_file_push(
583 const char *filename, unsigned line,
584 const char *key, char *value,
a5f6c30d
MS
585 void *userdata,
586 int *n_pushed) {
335c46b5 587
f27f0e21
GB
588 const char *k;
589 va_list aq, *ap = userdata;
590
591 if (!utf8_is_valid(key)) {
717603e3 592 _cleanup_free_ char *p;
550a40ec 593
717603e3
LP
594 p = utf8_escape_invalid(key);
595 log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p);
f27f0e21
GB
596 return -EINVAL;
597 }
598
599 if (value && !utf8_is_valid(value)) {
717603e3 600 _cleanup_free_ char *p;
550a40ec 601
717603e3
LP
602 p = utf8_escape_invalid(value);
603 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, p);
f27f0e21
GB
604 return -EINVAL;
605 }
a5c32cff 606
f27f0e21 607 va_copy(aq, *ap);
a5c32cff 608
f27f0e21
GB
609 while ((k = va_arg(aq, const char *))) {
610 char **v;
a5c32cff 611
f27f0e21 612 v = va_arg(aq, char **);
a5c32cff 613
f27f0e21
GB
614 if (streq(key, k)) {
615 va_end(aq);
616 free(*v);
617 *v = value;
a5f6c30d
MS
618
619 if (n_pushed)
620 (*n_pushed)++;
621
f27f0e21 622 return 1;
f73141d7 623 }
335c46b5 624 }
a5c32cff 625
f27f0e21 626 va_end(aq);
f73141d7 627 free(value);
717603e3 628
f73141d7
LP
629 return 0;
630}
a5c32cff 631
f73141d7
LP
632int parse_env_file(
633 const char *fname,
634 const char *newline, ...) {
a5c32cff 635
f73141d7 636 va_list ap;
a5f6c30d 637 int r, n_pushed = 0;
a5c32cff 638
f73141d7
LP
639 if (!newline)
640 newline = NEWLINE;
a5c32cff 641
f73141d7 642 va_start(ap, newline);
a5f6c30d 643 r = parse_env_file_internal(NULL, fname, newline, parse_env_file_push, &ap, &n_pushed);
f73141d7 644 va_end(ap);
a5c32cff 645
a5f6c30d 646 return r < 0 ? r : n_pushed;
f73141d7 647}
a5c32cff 648
717603e3
LP
649static int load_env_file_push(
650 const char *filename, unsigned line,
651 const char *key, char *value,
a5f6c30d
MS
652 void *userdata,
653 int *n_pushed) {
f27f0e21
GB
654 char ***m = userdata;
655 char *p;
656 int r;
a5c32cff 657
f27f0e21 658 if (!utf8_is_valid(key)) {
b5d74213
ZJS
659 _cleanup_free_ char *t = utf8_escape_invalid(key);
660
717603e3 661 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t);
f27f0e21
GB
662 return -EINVAL;
663 }
664
665 if (value && !utf8_is_valid(value)) {
b5d74213
ZJS
666 _cleanup_free_ char *t = utf8_escape_invalid(value);
667
717603e3 668 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t);
f27f0e21
GB
669 return -EINVAL;
670 }
a5c32cff 671
f27f0e21
GB
672 p = strjoin(key, "=", strempty(value), NULL);
673 if (!p)
674 return -ENOMEM;
335c46b5 675
6e18964d
ZJS
676 r = strv_consume(m, p);
677 if (r < 0)
f27f0e21 678 return r;
a5c32cff 679
a5f6c30d
MS
680 if (n_pushed)
681 (*n_pushed)++;
682
f73141d7
LP
683 free(value);
684 return 0;
685}
686
717603e3
LP
687int load_env_file(FILE *f, const char *fname, const char *newline, char ***rl) {
688 char **m = NULL;
689 int r;
690
691 if (!newline)
692 newline = NEWLINE;
693
a5f6c30d 694 r = parse_env_file_internal(f, fname, newline, load_env_file_push, &m, NULL);
717603e3
LP
695 if (r < 0) {
696 strv_free(m);
697 return r;
698 }
699
700 *rl = m;
701 return 0;
702}
703
704static int load_env_file_push_pairs(
705 const char *filename, unsigned line,
706 const char *key, char *value,
a5f6c30d
MS
707 void *userdata,
708 int *n_pushed) {
717603e3
LP
709 char ***m = userdata;
710 int r;
711
712 if (!utf8_is_valid(key)) {
713 _cleanup_free_ char *t = utf8_escape_invalid(key);
714
715 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t);
716 return -EINVAL;
717 }
718
719 if (value && !utf8_is_valid(value)) {
720 _cleanup_free_ char *t = utf8_escape_invalid(value);
721
722 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t);
723 return -EINVAL;
724 }
725
726 r = strv_extend(m, key);
727 if (r < 0)
728 return -ENOMEM;
729
730 if (!value) {
731 r = strv_extend(m, "");
732 if (r < 0)
733 return -ENOMEM;
734 } else {
735 r = strv_push(m, value);
736 if (r < 0)
737 return r;
738 }
739
a5f6c30d
MS
740 if (n_pushed)
741 (*n_pushed)++;
742
717603e3
LP
743 return 0;
744}
745
746int load_env_file_pairs(FILE *f, const char *fname, const char *newline, char ***rl) {
f73141d7
LP
747 char **m = NULL;
748 int r;
a5c32cff 749
f73141d7
LP
750 if (!newline)
751 newline = NEWLINE;
752
a5f6c30d 753 r = parse_env_file_internal(f, fname, newline, load_env_file_push_pairs, &m, NULL);
f73141d7
LP
754 if (r < 0) {
755 strv_free(m);
756 return r;
a5c32cff
HH
757 }
758
759 *rl = m;
a5c32cff
HH
760 return 0;
761}
762
768100ef
LP
763static void write_env_var(FILE *f, const char *v) {
764 const char *p;
765
766 p = strchr(v, '=');
767 if (!p) {
768 /* Fallback */
769 fputs(v, f);
770 fputc('\n', f);
771 return;
772 }
773
774 p++;
775 fwrite(v, 1, p-v, f);
776
0ce5a806 777 if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) {
768100ef
LP
778 fputc('\"', f);
779
780 for (; *p; p++) {
0ce5a806 781 if (strchr(SHELL_NEED_ESCAPE, *p))
768100ef
LP
782 fputc('\\', f);
783
784 fputc(*p, f);
785 }
786
787 fputc('\"', f);
788 } else
789 fputs(p, f);
790
791 fputc('\n', f);
792}
793
a5c32cff 794int write_env_file(const char *fname, char **l) {
7fd1b19b 795 _cleanup_fclose_ FILE *f = NULL;
736937e5
LP
796 _cleanup_free_ char *p = NULL;
797 char **i;
a5c32cff
HH
798 int r;
799
736937e5
LP
800 assert(fname);
801
a5c32cff
HH
802 r = fopen_temporary(fname, &f, &p);
803 if (r < 0)
804 return r;
805
806 fchmod_umask(fileno(f), 0644);
807
768100ef
LP
808 STRV_FOREACH(i, l)
809 write_env_var(f, *i);
a5c32cff 810
736937e5
LP
811 r = fflush_and_check(f);
812 if (r >= 0) {
813 if (rename(p, fname) >= 0)
814 return 0;
a5c32cff 815
736937e5 816 r = -errno;
a5c32cff
HH
817 }
818
736937e5 819 unlink(p);
a5c32cff
HH
820 return r;
821}
68fee104
ZJS
822
823int executable_is_script(const char *path, char **interpreter) {
824 int r;
c8b32e11 825 _cleanup_free_ char *line = NULL;
68fee104
ZJS
826 int len;
827 char *ans;
828
829 assert(path);
830
831 r = read_one_line_file(path, &line);
832 if (r < 0)
833 return r;
834
835 if (!startswith(line, "#!"))
836 return 0;
837
838 ans = strstrip(line + 2);
839 len = strcspn(ans, " \t");
840
841 if (len == 0)
842 return 0;
843
844 ans = strndup(ans, len);
845 if (!ans)
846 return -ENOMEM;
847
848 *interpreter = ans;
849 return 1;
850}
69ab8088
ZJS
851
852/**
0a7b53bd
ZJS
853 * Retrieve one field from a file like /proc/self/status. pattern
854 * should start with '\n' and end with a ':'. Whitespace and zeros
855 * after the ':' will be skipped. field must be freed afterwards.
69ab8088
ZJS
856 */
857int get_status_field(const char *filename, const char *pattern, char **field) {
858 _cleanup_free_ char *status = NULL;
859 char *t;
860 size_t len;
861 int r;
862
863 assert(filename);
7ff7394d 864 assert(pattern);
69ab8088
ZJS
865 assert(field);
866
867 r = read_full_file(filename, &status, NULL);
868 if (r < 0)
869 return r;
870
871 t = strstr(status, pattern);
872 if (!t)
873 return -ENOENT;
874
875 t += strlen(pattern);
4ec29144 876 if (*t) {
1e5413f7
ZJS
877 t += strspn(t, " \t");
878
879 /* Also skip zeros, because when this is used for
880 * capabilities, we don't want the zeros. This way the
881 * same capability set always maps to the same string,
882 * irrespective of the total capability set size. For
883 * other numbers it shouldn't matter. */
884 t += strspn(t, "0");
4ec29144
ZJS
885 /* Back off one char if there's nothing but whitespace
886 and zeros */
1e5413f7 887 if (!*t || isspace(*t))
4ec29144
ZJS
888 t --;
889 }
69ab8088
ZJS
890
891 len = strcspn(t, WHITESPACE);
892
893 *field = strndup(t, len);
894 if (!*field)
895 return -ENOMEM;
896
897 return 0;
898}