]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/fileio.c
bus-policy: split API for bus-proxyd
[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
ZJS
298 int (*push) (const char *filename, unsigned line,
299 const char *key, char *value, void *userdata),
f73141d7
LP
300 void *userdata) {
301
302 _cleanup_free_ char *contents = NULL, *key = NULL;
2b77f67e 303 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
304 char *p, *value = NULL;
305 int r;
335c46b5 306 unsigned line = 1;
a5c32cff 307
f73141d7
LP
308 enum {
309 PRE_KEY,
310 KEY,
f73141d7
LP
311 PRE_VALUE,
312 VALUE,
313 VALUE_ESCAPE,
314 SINGLE_QUOTE_VALUE,
315 SINGLE_QUOTE_VALUE_ESCAPE,
316 DOUBLE_QUOTE_VALUE,
317 DOUBLE_QUOTE_VALUE_ESCAPE,
318 COMMENT,
319 COMMENT_ESCAPE
320 } state = PRE_KEY;
a5c32cff 321
f73141d7 322 assert(newline);
a5c32cff 323
717603e3
LP
324 if (f)
325 r = read_full_stream(f, &contents, NULL);
326 else
327 r = read_full_file(fname, &contents, NULL);
1c17cbed 328 if (r < 0)
a5c32cff
HH
329 return r;
330
f73141d7
LP
331 for (p = contents; *p; p++) {
332 char c = *p;
333
334 switch (state) {
335
336 case PRE_KEY:
ebc05a09 337 if (strchr(COMMENTS, c))
f73141d7
LP
338 state = COMMENT;
339 else if (!strchr(WHITESPACE, c)) {
340 state = KEY;
2b77f67e
LP
341 last_key_whitespace = (size_t) -1;
342
ca2d3784 343 if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) {
f73141d7
LP
344 r = -ENOMEM;
345 goto fail;
346 }
347
348 key[n_key++] = c;
349 }
350 break;
351
352 case KEY:
353 if (strchr(newline, c)) {
354 state = PRE_KEY;
335c46b5 355 line ++;
f73141d7 356 n_key = 0;
2b77f67e 357 } else if (c == '=') {
f73141d7 358 state = PRE_VALUE;
2b77f67e
LP
359 last_value_whitespace = (size_t) -1;
360 } else {
361 if (!strchr(WHITESPACE, c))
362 last_key_whitespace = (size_t) -1;
363 else if (last_key_whitespace == (size_t) -1)
364 last_key_whitespace = n_key;
365
ca2d3784 366 if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) {
f73141d7
LP
367 r = -ENOMEM;
368 goto fail;
369 }
370
371 key[n_key++] = c;
372 }
a5c32cff 373
f73141d7
LP
374 break;
375
f73141d7 376 case PRE_VALUE:
98f59e59 377 if (strchr(newline, c)) {
f73141d7 378 state = PRE_KEY;
335c46b5 379 line ++;
f73141d7 380 key[n_key] = 0;
a5c32cff 381
f73141d7
LP
382 if (value)
383 value[n_value] = 0;
a5c32cff 384
ebc05a09 385 /* strip trailing whitespace from key */
2b77f67e
LP
386 if (last_key_whitespace != (size_t) -1)
387 key[last_key_whitespace] = 0;
ebc05a09 388
335c46b5 389 r = push(fname, line, key, value, userdata);
f73141d7
LP
390 if (r < 0)
391 goto fail;
392
393 n_key = 0;
394 value = NULL;
395 value_alloc = n_value = 0;
2b77f67e 396
f73141d7
LP
397 } else if (c == '\'')
398 state = SINGLE_QUOTE_VALUE;
399 else if (c == '\"')
400 state = DOUBLE_QUOTE_VALUE;
401 else if (c == '\\')
402 state = VALUE_ESCAPE;
403 else if (!strchr(WHITESPACE, c)) {
404 state = VALUE;
405
ca2d3784 406 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
f73141d7
LP
407 r = -ENOMEM;
408 goto fail;
409 }
410
411 value[n_value++] = c;
412 }
413
414 break;
415
416 case VALUE:
417 if (strchr(newline, c)) {
418 state = PRE_KEY;
335c46b5 419 line ++;
98f59e59 420
f73141d7
LP
421 key[n_key] = 0;
422
423 if (value)
424 value[n_value] = 0;
425
2b77f67e
LP
426 /* Chomp off trailing whitespace from value */
427 if (last_value_whitespace != (size_t) -1)
428 value[last_value_whitespace] = 0;
f73141d7 429
ebc05a09 430 /* strip trailing whitespace from key */
2b77f67e
LP
431 if (last_key_whitespace != (size_t) -1)
432 key[last_key_whitespace] = 0;
ebc05a09 433
335c46b5 434 r = push(fname, line, key, value, userdata);
f73141d7
LP
435 if (r < 0)
436 goto fail;
437
438 n_key = 0;
439 value = NULL;
440 value_alloc = n_value = 0;
2b77f67e 441
f73141d7
LP
442 } else if (c == '\\') {
443 state = VALUE_ESCAPE;
2b77f67e 444 last_value_whitespace = (size_t) -1;
f73141d7
LP
445 } else {
446 if (!strchr(WHITESPACE, c))
2b77f67e
LP
447 last_value_whitespace = (size_t) -1;
448 else if (last_value_whitespace == (size_t) -1)
449 last_value_whitespace = n_value;
f73141d7 450
ca2d3784 451 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
f73141d7
LP
452 r = -ENOMEM;
453 goto fail;
454 }
455
456 value[n_value++] = c;
457 }
458
459 break;
460
461 case VALUE_ESCAPE:
462 state = VALUE;
463
464 if (!strchr(newline, c)) {
465 /* Escaped newlines we eat up entirely */
ca2d3784 466 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
f73141d7
LP
467 r = -ENOMEM;
468 goto fail;
469 }
470
471 value[n_value++] = c;
472 }
473 break;
474
475 case SINGLE_QUOTE_VALUE:
476 if (c == '\'')
477 state = PRE_VALUE;
478 else if (c == '\\')
479 state = SINGLE_QUOTE_VALUE_ESCAPE;
480 else {
ca2d3784 481 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
f73141d7
LP
482 r = -ENOMEM;
483 goto fail;
484 }
a5c32cff 485
f73141d7
LP
486 value[n_value++] = c;
487 }
a5c32cff 488
f73141d7 489 break;
a5c32cff 490
f73141d7
LP
491 case SINGLE_QUOTE_VALUE_ESCAPE:
492 state = SINGLE_QUOTE_VALUE;
a5c32cff 493
f73141d7 494 if (!strchr(newline, c)) {
ca2d3784 495 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
a5c32cff 496 r = -ENOMEM;
a5c32cff
HH
497 goto fail;
498 }
499
f73141d7
LP
500 value[n_value++] = c;
501 }
502 break;
503
504 case DOUBLE_QUOTE_VALUE:
505 if (c == '\"')
506 state = PRE_VALUE;
507 else if (c == '\\')
508 state = DOUBLE_QUOTE_VALUE_ESCAPE;
509 else {
ca2d3784 510 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
f73141d7
LP
511 r = -ENOMEM;
512 goto fail;
a5c32cff
HH
513 }
514
f73141d7
LP
515 value[n_value++] = c;
516 }
517
518 break;
519
520 case DOUBLE_QUOTE_VALUE_ESCAPE:
521 state = DOUBLE_QUOTE_VALUE;
a5c32cff 522
f73141d7 523 if (!strchr(newline, c)) {
ca2d3784 524 if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) {
f73141d7
LP
525 r = -ENOMEM;
526 goto fail;
527 }
a5c32cff 528
f73141d7 529 value[n_value++] = c;
a5c32cff 530 }
f73141d7
LP
531 break;
532
533 case COMMENT:
534 if (c == '\\')
535 state = COMMENT_ESCAPE;
335c46b5 536 else if (strchr(newline, c)) {
f73141d7 537 state = PRE_KEY;
335c46b5
ZJS
538 line ++;
539 }
f73141d7
LP
540 break;
541
542 case COMMENT_ESCAPE:
543 state = COMMENT;
544 break;
a5c32cff 545 }
f73141d7
LP
546 }
547
548 if (state == PRE_VALUE ||
549 state == VALUE ||
550 state == VALUE_ESCAPE ||
551 state == SINGLE_QUOTE_VALUE ||
552 state == SINGLE_QUOTE_VALUE_ESCAPE ||
553 state == DOUBLE_QUOTE_VALUE ||
554 state == DOUBLE_QUOTE_VALUE_ESCAPE) {
a5c32cff 555
f73141d7
LP
556 key[n_key] = 0;
557
558 if (value)
559 value[n_value] = 0;
560
2b77f67e
LP
561 if (state == VALUE)
562 if (last_value_whitespace != (size_t) -1)
563 value[last_value_whitespace] = 0;
564
ebc05a09 565 /* strip trailing whitespace from key */
2b77f67e
LP
566 if (last_key_whitespace != (size_t) -1)
567 key[last_key_whitespace] = 0;
ebc05a09 568
335c46b5 569 r = push(fname, line, key, value, userdata);
f73141d7
LP
570 if (r < 0)
571 goto fail;
a5c32cff
HH
572 }
573
f73141d7
LP
574 return 0;
575
a5c32cff 576fail:
f73141d7 577 free(value);
a5c32cff
HH
578 return r;
579}
580
717603e3
LP
581static int parse_env_file_push(
582 const char *filename, unsigned line,
583 const char *key, char *value,
584 void *userdata) {
335c46b5 585
f27f0e21
GB
586 const char *k;
587 va_list aq, *ap = userdata;
588
589 if (!utf8_is_valid(key)) {
717603e3 590 _cleanup_free_ char *p;
550a40ec 591
717603e3
LP
592 p = utf8_escape_invalid(key);
593 log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p);
f27f0e21
GB
594 return -EINVAL;
595 }
596
597 if (value && !utf8_is_valid(value)) {
717603e3 598 _cleanup_free_ char *p;
550a40ec 599
717603e3
LP
600 p = utf8_escape_invalid(value);
601 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, p);
f27f0e21
GB
602 return -EINVAL;
603 }
a5c32cff 604
f27f0e21 605 va_copy(aq, *ap);
a5c32cff 606
f27f0e21
GB
607 while ((k = va_arg(aq, const char *))) {
608 char **v;
a5c32cff 609
f27f0e21 610 v = va_arg(aq, char **);
a5c32cff 611
f27f0e21
GB
612 if (streq(key, k)) {
613 va_end(aq);
614 free(*v);
615 *v = value;
616 return 1;
f73141d7 617 }
335c46b5 618 }
a5c32cff 619
f27f0e21 620 va_end(aq);
f73141d7 621 free(value);
717603e3 622
f73141d7
LP
623 return 0;
624}
a5c32cff 625
f73141d7
LP
626int parse_env_file(
627 const char *fname,
628 const char *newline, ...) {
a5c32cff 629
f73141d7
LP
630 va_list ap;
631 int r;
a5c32cff 632
f73141d7
LP
633 if (!newline)
634 newline = NEWLINE;
a5c32cff 635
f73141d7 636 va_start(ap, newline);
717603e3 637 r = parse_env_file_internal(NULL, fname, newline, parse_env_file_push, &ap);
f73141d7 638 va_end(ap);
a5c32cff 639
f73141d7
LP
640 return r;
641}
a5c32cff 642
717603e3
LP
643static int load_env_file_push(
644 const char *filename, unsigned line,
645 const char *key, char *value,
646 void *userdata) {
f27f0e21
GB
647 char ***m = userdata;
648 char *p;
649 int r;
a5c32cff 650
f27f0e21 651 if (!utf8_is_valid(key)) {
b5d74213
ZJS
652 _cleanup_free_ char *t = utf8_escape_invalid(key);
653
717603e3 654 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t);
f27f0e21
GB
655 return -EINVAL;
656 }
657
658 if (value && !utf8_is_valid(value)) {
b5d74213
ZJS
659 _cleanup_free_ char *t = utf8_escape_invalid(value);
660
717603e3 661 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t);
f27f0e21
GB
662 return -EINVAL;
663 }
a5c32cff 664
f27f0e21
GB
665 p = strjoin(key, "=", strempty(value), NULL);
666 if (!p)
667 return -ENOMEM;
335c46b5 668
6e18964d
ZJS
669 r = strv_consume(m, p);
670 if (r < 0)
f27f0e21 671 return r;
a5c32cff 672
f73141d7
LP
673 free(value);
674 return 0;
675}
676
717603e3
LP
677int load_env_file(FILE *f, const char *fname, const char *newline, char ***rl) {
678 char **m = NULL;
679 int r;
680
681 if (!newline)
682 newline = NEWLINE;
683
684 r = parse_env_file_internal(f, fname, newline, load_env_file_push, &m);
685 if (r < 0) {
686 strv_free(m);
687 return r;
688 }
689
690 *rl = m;
691 return 0;
692}
693
694static int load_env_file_push_pairs(
695 const char *filename, unsigned line,
696 const char *key, char *value,
697 void *userdata) {
698 char ***m = userdata;
699 int r;
700
701 if (!utf8_is_valid(key)) {
702 _cleanup_free_ char *t = utf8_escape_invalid(key);
703
704 log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t);
705 return -EINVAL;
706 }
707
708 if (value && !utf8_is_valid(value)) {
709 _cleanup_free_ char *t = utf8_escape_invalid(value);
710
711 log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t);
712 return -EINVAL;
713 }
714
715 r = strv_extend(m, key);
716 if (r < 0)
717 return -ENOMEM;
718
719 if (!value) {
720 r = strv_extend(m, "");
721 if (r < 0)
722 return -ENOMEM;
723 } else {
724 r = strv_push(m, value);
725 if (r < 0)
726 return r;
727 }
728
729 return 0;
730}
731
732int load_env_file_pairs(FILE *f, const char *fname, const char *newline, char ***rl) {
f73141d7
LP
733 char **m = NULL;
734 int r;
a5c32cff 735
f73141d7
LP
736 if (!newline)
737 newline = NEWLINE;
738
717603e3 739 r = parse_env_file_internal(f, fname, newline, load_env_file_push_pairs, &m);
f73141d7
LP
740 if (r < 0) {
741 strv_free(m);
742 return r;
a5c32cff
HH
743 }
744
745 *rl = m;
a5c32cff
HH
746 return 0;
747}
748
768100ef
LP
749static void write_env_var(FILE *f, const char *v) {
750 const char *p;
751
752 p = strchr(v, '=');
753 if (!p) {
754 /* Fallback */
755 fputs(v, f);
756 fputc('\n', f);
757 return;
758 }
759
760 p++;
761 fwrite(v, 1, p-v, f);
762
0ce5a806 763 if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) {
768100ef
LP
764 fputc('\"', f);
765
766 for (; *p; p++) {
0ce5a806 767 if (strchr(SHELL_NEED_ESCAPE, *p))
768100ef
LP
768 fputc('\\', f);
769
770 fputc(*p, f);
771 }
772
773 fputc('\"', f);
774 } else
775 fputs(p, f);
776
777 fputc('\n', f);
778}
779
a5c32cff 780int write_env_file(const char *fname, char **l) {
7fd1b19b 781 _cleanup_fclose_ FILE *f = NULL;
736937e5
LP
782 _cleanup_free_ char *p = NULL;
783 char **i;
a5c32cff
HH
784 int r;
785
736937e5
LP
786 assert(fname);
787
a5c32cff
HH
788 r = fopen_temporary(fname, &f, &p);
789 if (r < 0)
790 return r;
791
792 fchmod_umask(fileno(f), 0644);
793
768100ef
LP
794 STRV_FOREACH(i, l)
795 write_env_var(f, *i);
a5c32cff 796
736937e5
LP
797 r = fflush_and_check(f);
798 if (r >= 0) {
799 if (rename(p, fname) >= 0)
800 return 0;
a5c32cff 801
736937e5 802 r = -errno;
a5c32cff
HH
803 }
804
736937e5 805 unlink(p);
a5c32cff
HH
806 return r;
807}
68fee104
ZJS
808
809int executable_is_script(const char *path, char **interpreter) {
810 int r;
c8b32e11 811 _cleanup_free_ char *line = NULL;
68fee104
ZJS
812 int len;
813 char *ans;
814
815 assert(path);
816
817 r = read_one_line_file(path, &line);
818 if (r < 0)
819 return r;
820
821 if (!startswith(line, "#!"))
822 return 0;
823
824 ans = strstrip(line + 2);
825 len = strcspn(ans, " \t");
826
827 if (len == 0)
828 return 0;
829
830 ans = strndup(ans, len);
831 if (!ans)
832 return -ENOMEM;
833
834 *interpreter = ans;
835 return 1;
836}
69ab8088
ZJS
837
838/**
0a7b53bd
ZJS
839 * Retrieve one field from a file like /proc/self/status. pattern
840 * should start with '\n' and end with a ':'. Whitespace and zeros
841 * after the ':' will be skipped. field must be freed afterwards.
69ab8088
ZJS
842 */
843int get_status_field(const char *filename, const char *pattern, char **field) {
844 _cleanup_free_ char *status = NULL;
845 char *t;
846 size_t len;
847 int r;
848
849 assert(filename);
7ff7394d 850 assert(pattern);
69ab8088
ZJS
851 assert(field);
852
853 r = read_full_file(filename, &status, NULL);
854 if (r < 0)
855 return r;
856
857 t = strstr(status, pattern);
858 if (!t)
859 return -ENOENT;
860
861 t += strlen(pattern);
4ec29144 862 if (*t) {
1e5413f7
ZJS
863 t += strspn(t, " \t");
864
865 /* Also skip zeros, because when this is used for
866 * capabilities, we don't want the zeros. This way the
867 * same capability set always maps to the same string,
868 * irrespective of the total capability set size. For
869 * other numbers it shouldn't matter. */
870 t += strspn(t, "0");
4ec29144
ZJS
871 /* Back off one char if there's nothing but whitespace
872 and zeros */
1e5413f7 873 if (!*t || isspace(*t))
4ec29144
ZJS
874 t --;
875 }
69ab8088
ZJS
876
877 len = strcspn(t, WHITESPACE);
878
879 *field = strndup(t, len);
880 if (!*field)
881 return -ENOMEM;
882
883 return 0;
884}