Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include <ctype.h>
4 : #include <errno.h>
5 : #include <fcntl.h>
6 : #include <limits.h>
7 : #include <stdarg.h>
8 : #include <stdint.h>
9 : #include <stdio_ext.h>
10 : #include <stdlib.h>
11 : #include <string.h>
12 : #include <sys/stat.h>
13 : #include <sys/types.h>
14 : #include <unistd.h>
15 :
16 : #include "alloc-util.h"
17 : #include "fd-util.h"
18 : #include "fileio.h"
19 : #include "fs-util.h"
20 : #include "hexdecoct.h"
21 : #include "log.h"
22 : #include "macro.h"
23 : #include "missing.h"
24 : #include "mkdir.h"
25 : #include "parse-util.h"
26 : #include "path-util.h"
27 : #include "stdio-util.h"
28 : #include "string-util.h"
29 : #include "tmpfile-util.h"
30 :
31 : #define READ_FULL_BYTES_MAX (4U*1024U*1024U)
32 :
33 20594 : int fopen_unlocked(const char *path, const char *options, FILE **ret) {
34 20594 : assert(ret);
35 :
36 20594 : FILE *f = fopen(path, options);
37 20594 : if (!f)
38 7470 : return -errno;
39 :
40 13124 : (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
41 :
42 13124 : *ret = f;
43 13124 : return 0;
44 : }
45 :
46 6 : int fdopen_unlocked(int fd, const char *options, FILE **ret) {
47 6 : assert(ret);
48 :
49 6 : FILE *f = fdopen(fd, options);
50 6 : if (!f)
51 0 : return -errno;
52 :
53 6 : (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
54 :
55 6 : *ret = f;
56 6 : return 0;
57 : }
58 :
59 546 : FILE* open_memstream_unlocked(char **ptr, size_t *sizeloc) {
60 546 : FILE *f = open_memstream(ptr, sizeloc);
61 546 : if (!f)
62 0 : return NULL;
63 :
64 546 : (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
65 :
66 546 : return f;
67 : }
68 :
69 14 : FILE* fmemopen_unlocked(void *buf, size_t size, const char *mode) {
70 14 : FILE *f = fmemopen(buf, size, mode);
71 14 : if (!f)
72 0 : return NULL;
73 :
74 14 : (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
75 :
76 14 : return f;
77 : }
78 :
79 118 : int write_string_stream_ts(
80 : FILE *f,
81 : const char *line,
82 : WriteStringFileFlags flags,
83 : struct timespec *ts) {
84 :
85 : bool needs_nl;
86 : int r;
87 :
88 118 : assert(f);
89 118 : assert(line);
90 :
91 118 : if (ferror(f))
92 0 : return -EIO;
93 :
94 118 : needs_nl = !(flags & WRITE_STRING_FILE_AVOID_NEWLINE) && !endswith(line, "\n");
95 :
96 118 : if (needs_nl && (flags & WRITE_STRING_FILE_DISABLE_BUFFER)) {
97 : /* If STDIO buffering was disabled, then let's append the newline character to the string itself, so
98 : * that the write goes out in one go, instead of two */
99 :
100 0 : line = strjoina(line, "\n");
101 0 : needs_nl = false;
102 : }
103 :
104 118 : if (fputs(line, f) == EOF)
105 1 : return -errno;
106 :
107 117 : if (needs_nl)
108 62 : if (fputc('\n', f) == EOF)
109 0 : return -errno;
110 :
111 117 : if (flags & WRITE_STRING_FILE_SYNC)
112 0 : r = fflush_sync_and_check(f);
113 : else
114 117 : r = fflush_and_check(f);
115 117 : if (r < 0)
116 0 : return r;
117 :
118 117 : if (ts) {
119 0 : struct timespec twice[2] = {*ts, *ts};
120 :
121 0 : if (futimens(fileno(f), twice) < 0)
122 0 : return -errno;
123 : }
124 :
125 117 : return 0;
126 : }
127 :
128 0 : static int write_string_file_atomic(
129 : const char *fn,
130 : const char *line,
131 : WriteStringFileFlags flags,
132 : struct timespec *ts) {
133 :
134 0 : _cleanup_fclose_ FILE *f = NULL;
135 0 : _cleanup_free_ char *p = NULL;
136 : int r;
137 :
138 0 : assert(fn);
139 0 : assert(line);
140 :
141 0 : r = fopen_temporary(fn, &f, &p);
142 0 : if (r < 0)
143 0 : return r;
144 :
145 0 : (void) fchmod_umask(fileno(f), 0644);
146 :
147 0 : r = write_string_stream_ts(f, line, flags, ts);
148 0 : if (r < 0)
149 0 : goto fail;
150 :
151 0 : if (rename(p, fn) < 0) {
152 0 : r = -errno;
153 0 : goto fail;
154 : }
155 :
156 0 : return 0;
157 :
158 0 : fail:
159 0 : (void) unlink(p);
160 0 : return r;
161 : }
162 :
163 106 : int write_string_file_ts(
164 : const char *fn,
165 : const char *line,
166 : WriteStringFileFlags flags,
167 : struct timespec *ts) {
168 :
169 106 : _cleanup_fclose_ FILE *f = NULL;
170 : int q, r;
171 :
172 106 : assert(fn);
173 106 : assert(line);
174 :
175 : /* We don't know how to verify whether the file contents was already on-disk. */
176 106 : assert(!((flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE) && (flags & WRITE_STRING_FILE_SYNC)));
177 :
178 106 : if (flags & WRITE_STRING_FILE_MKDIR_0755) {
179 0 : r = mkdir_parents(fn, 0755);
180 0 : if (r < 0)
181 0 : return r;
182 : }
183 :
184 106 : if (flags & WRITE_STRING_FILE_ATOMIC) {
185 0 : assert(flags & WRITE_STRING_FILE_CREATE);
186 :
187 0 : r = write_string_file_atomic(fn, line, flags, ts);
188 0 : if (r < 0)
189 0 : goto fail;
190 :
191 0 : return r;
192 : } else
193 106 : assert(!ts);
194 :
195 106 : if (flags & WRITE_STRING_FILE_CREATE) {
196 89 : r = fopen_unlocked(fn, "we", &f);
197 89 : if (r < 0)
198 0 : goto fail;
199 : } else {
200 : int fd;
201 :
202 : /* We manually build our own version of fopen(..., "we") that
203 : * works without O_CREAT */
204 17 : fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY | ((flags & WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0));
205 17 : if (fd < 0) {
206 16 : r = -errno;
207 16 : goto fail;
208 : }
209 :
210 1 : r = fdopen_unlocked(fd, "w", &f);
211 1 : if (r < 0) {
212 0 : safe_close(fd);
213 0 : goto fail;
214 : }
215 : }
216 :
217 90 : if (flags & WRITE_STRING_FILE_DISABLE_BUFFER)
218 0 : setvbuf(f, NULL, _IONBF, 0);
219 :
220 90 : r = write_string_stream_ts(f, line, flags, ts);
221 90 : if (r < 0)
222 0 : goto fail;
223 :
224 90 : return 0;
225 :
226 16 : fail:
227 16 : if (!(flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE))
228 12 : return r;
229 :
230 4 : f = safe_fclose(f);
231 :
232 : /* OK, the operation failed, but let's see if the right
233 : * contents in place already. If so, eat up the error. */
234 :
235 4 : q = verify_file(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
236 4 : if (q <= 0)
237 1 : return r;
238 :
239 3 : return 0;
240 : }
241 :
242 0 : int write_string_filef(
243 : const char *fn,
244 : WriteStringFileFlags flags,
245 : const char *format, ...) {
246 :
247 0 : _cleanup_free_ char *p = NULL;
248 : va_list ap;
249 : int r;
250 :
251 0 : va_start(ap, format);
252 0 : r = vasprintf(&p, format, ap);
253 0 : va_end(ap);
254 :
255 0 : if (r < 0)
256 0 : return -ENOMEM;
257 :
258 0 : return write_string_file(fn, p, flags);
259 : }
260 :
261 2426 : int read_one_line_file(const char *fn, char **line) {
262 2426 : _cleanup_fclose_ FILE *f = NULL;
263 : int r;
264 :
265 2426 : assert(fn);
266 2426 : assert(line);
267 :
268 2426 : r = fopen_unlocked(fn, "re", &f);
269 2426 : if (r < 0)
270 414 : return r;
271 :
272 2012 : return read_line(f, LONG_LINE_MAX, line);
273 : }
274 :
275 4 : int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
276 4 : _cleanup_fclose_ FILE *f = NULL;
277 4 : _cleanup_free_ char *buf = NULL;
278 : size_t l, k;
279 : int r;
280 :
281 4 : assert(fn);
282 4 : assert(blob);
283 :
284 4 : l = strlen(blob);
285 :
286 4 : if (accept_extra_nl && endswith(blob, "\n"))
287 1 : accept_extra_nl = false;
288 :
289 4 : buf = malloc(l + accept_extra_nl + 1);
290 4 : if (!buf)
291 0 : return -ENOMEM;
292 :
293 4 : r = fopen_unlocked(fn, "re", &f);
294 4 : if (r < 0)
295 0 : return r;
296 :
297 : /* We try to read one byte more than we need, so that we know whether we hit eof */
298 4 : errno = 0;
299 4 : k = fread(buf, 1, l + accept_extra_nl + 1, f);
300 4 : if (ferror(f))
301 0 : return errno_or_else(EIO);
302 :
303 4 : if (k != l && k != l + accept_extra_nl)
304 1 : return 0;
305 3 : if (memcmp(buf, blob, l) != 0)
306 0 : return 0;
307 3 : if (k > l && buf[l] != '\n')
308 0 : return 0;
309 :
310 3 : return 1;
311 : }
312 :
313 8332 : int read_full_stream_full(
314 : FILE *f,
315 : const char *filename,
316 : ReadFullFileFlags flags,
317 : char **ret_contents,
318 : size_t *ret_size) {
319 :
320 8332 : _cleanup_free_ char *buf = NULL;
321 : struct stat st;
322 : size_t n, n_next, l;
323 : int fd, r;
324 :
325 8332 : assert(f);
326 8332 : assert(ret_contents);
327 8332 : assert(!FLAGS_SET(flags, READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX));
328 8332 : assert(!(flags & (READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)) || ret_size);
329 :
330 8332 : n_next = LINE_MAX; /* Start size */
331 :
332 8332 : fd = fileno(f);
333 8332 : if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen(), let's
334 : * optimize our buffering) */
335 :
336 8331 : if (fstat(fd, &st) < 0)
337 0 : return -errno;
338 :
339 8331 : if (S_ISREG(st.st_mode)) {
340 :
341 : /* Safety check */
342 8331 : if (st.st_size > READ_FULL_BYTES_MAX)
343 0 : return -E2BIG;
344 :
345 : /* Start with the right file size, but be prepared for files from /proc which generally report a file
346 : * size of 0. Note that we increase the size to read here by one, so that the first read attempt
347 : * already makes us notice the EOF. */
348 8331 : if (st.st_size > 0)
349 7783 : n_next = st.st_size + 1;
350 :
351 8331 : if (flags & READ_FULL_FILE_SECURE)
352 0 : (void) warn_file_is_world_accessible(filename, &st, NULL, 0);
353 : }
354 : }
355 :
356 8332 : n = l = 0;
357 0 : for (;;) {
358 : char *t;
359 : size_t k;
360 :
361 8332 : if (flags & READ_FULL_FILE_SECURE) {
362 0 : t = malloc(n_next + 1);
363 0 : if (!t) {
364 0 : r = -ENOMEM;
365 0 : goto finalize;
366 : }
367 0 : memcpy_safe(t, buf, n);
368 0 : explicit_bzero_safe(buf, n);
369 0 : buf = mfree(buf);
370 : } else {
371 8332 : t = realloc(buf, n_next + 1);
372 8332 : if (!t)
373 0 : return -ENOMEM;
374 : }
375 :
376 8332 : buf = t;
377 8332 : n = n_next;
378 :
379 8332 : errno = 0;
380 8332 : k = fread(buf + l, 1, n - l, f);
381 8332 : if (k > 0)
382 6040 : l += k;
383 :
384 8332 : if (ferror(f)) {
385 3 : r = errno_or_else(EIO);
386 3 : goto finalize;
387 : }
388 :
389 8329 : if (feof(f))
390 8329 : break;
391 :
392 : /* We aren't expecting fread() to return a short read outside
393 : * of (error && eof), assert buffer is full and enlarge buffer.
394 : */
395 0 : assert(l == n);
396 :
397 : /* Safety check */
398 0 : if (n >= READ_FULL_BYTES_MAX) {
399 0 : r = -E2BIG;
400 0 : goto finalize;
401 : }
402 :
403 0 : n_next = MIN(n * 2, READ_FULL_BYTES_MAX);
404 : }
405 :
406 8329 : if (flags & (READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)) {
407 0 : buf[l++] = 0;
408 0 : if (flags & READ_FULL_FILE_UNBASE64)
409 0 : r = unbase64mem_full(buf, l, flags & READ_FULL_FILE_SECURE, (void **) ret_contents, ret_size);
410 : else
411 0 : r = unhexmem_full(buf, l, flags & READ_FULL_FILE_SECURE, (void **) ret_contents, ret_size);
412 0 : goto finalize;
413 : }
414 :
415 8329 : if (!ret_size) {
416 : /* Safety check: if the caller doesn't want to know the size of what we just read it will rely on the
417 : * trailing NUL byte. But if there's an embedded NUL byte, then we should refuse operation as otherwise
418 : * there'd be ambiguity about what we just read. */
419 :
420 92 : if (memchr(buf, 0, l)) {
421 0 : r = -EBADMSG;
422 0 : goto finalize;
423 : }
424 : }
425 :
426 8329 : buf[l] = 0;
427 8329 : *ret_contents = TAKE_PTR(buf);
428 :
429 8329 : if (ret_size)
430 8237 : *ret_size = l;
431 :
432 8329 : return 0;
433 :
434 3 : finalize:
435 3 : if (flags & READ_FULL_FILE_SECURE)
436 0 : explicit_bzero_safe(buf, n);
437 :
438 3 : return r;
439 : }
440 :
441 14987 : int read_full_file_full(const char *filename, ReadFullFileFlags flags, char **contents, size_t *size) {
442 14987 : _cleanup_fclose_ FILE *f = NULL;
443 : int r;
444 :
445 14987 : assert(filename);
446 14987 : assert(contents);
447 :
448 14987 : r = fopen_unlocked(filename, "re", &f);
449 14987 : if (r < 0)
450 6661 : return r;
451 :
452 8326 : return read_full_stream_full(f, filename, flags, contents, size);
453 : }
454 :
455 3 : int executable_is_script(const char *path, char **interpreter) {
456 3 : _cleanup_free_ char *line = NULL;
457 : size_t len;
458 : char *ans;
459 : int r;
460 :
461 3 : assert(path);
462 :
463 3 : r = read_one_line_file(path, &line);
464 3 : if (r == -ENOBUFS) /* First line overly long? if so, then it's not a script */
465 0 : return 0;
466 3 : if (r < 0)
467 0 : return r;
468 :
469 3 : if (!startswith(line, "#!"))
470 1 : return 0;
471 :
472 2 : ans = strstrip(line + 2);
473 2 : len = strcspn(ans, " \t");
474 :
475 2 : if (len == 0)
476 0 : return 0;
477 :
478 2 : ans = strndup(ans, len);
479 2 : if (!ans)
480 0 : return -ENOMEM;
481 :
482 2 : *interpreter = ans;
483 2 : return 1;
484 : }
485 :
486 : /**
487 : * Retrieve one field from a file like /proc/self/status. pattern
488 : * should not include whitespace or the delimiter (':'). pattern matches only
489 : * the beginning of a line. Whitespace before ':' is skipped. Whitespace and
490 : * zeros after the ':' will be skipped. field must be freed afterwards.
491 : * terminator specifies the terminating characters of the field value (not
492 : * included in the value).
493 : */
494 6 : int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) {
495 6 : _cleanup_free_ char *status = NULL;
496 : char *t, *f;
497 : size_t len;
498 : int r;
499 :
500 6 : assert(terminator);
501 6 : assert(filename);
502 6 : assert(pattern);
503 6 : assert(field);
504 :
505 6 : r = read_full_file(filename, &status, NULL);
506 6 : if (r < 0)
507 0 : return r;
508 :
509 6 : t = status;
510 :
511 : do {
512 : bool pattern_ok;
513 :
514 : do {
515 6 : t = strstr(t, pattern);
516 6 : if (!t)
517 1 : return -ENOENT;
518 :
519 : /* Check that pattern occurs in beginning of line. */
520 5 : pattern_ok = (t == status || t[-1] == '\n');
521 :
522 5 : t += strlen(pattern);
523 :
524 5 : } while (!pattern_ok);
525 :
526 5 : t += strspn(t, " \t");
527 5 : if (!*t)
528 0 : return -ENOENT;
529 :
530 5 : } while (*t != ':');
531 :
532 5 : t++;
533 :
534 5 : if (*t) {
535 5 : t += strspn(t, " \t");
536 :
537 : /* Also skip zeros, because when this is used for
538 : * capabilities, we don't want the zeros. This way the
539 : * same capability set always maps to the same string,
540 : * irrespective of the total capability set size. For
541 : * other numbers it shouldn't matter. */
542 5 : t += strspn(t, "0");
543 : /* Back off one char if there's nothing but whitespace
544 : and zeros */
545 5 : if (!*t || isspace(*t))
546 2 : t--;
547 : }
548 :
549 5 : len = strcspn(t, terminator);
550 :
551 5 : f = strndup(t, len);
552 5 : if (!f)
553 0 : return -ENOMEM;
554 :
555 5 : *field = f;
556 5 : return 0;
557 : }
558 :
559 0 : DIR *xopendirat(int fd, const char *name, int flags) {
560 : int nfd;
561 : DIR *d;
562 :
563 0 : assert(!(flags & O_CREAT));
564 :
565 0 : nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0);
566 0 : if (nfd < 0)
567 0 : return NULL;
568 :
569 0 : d = fdopendir(nfd);
570 0 : if (!d) {
571 0 : safe_close(nfd);
572 0 : return NULL;
573 : }
574 :
575 0 : return d;
576 : }
577 :
578 7 : static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) {
579 : char **i;
580 :
581 7 : assert(path);
582 7 : assert(mode);
583 7 : assert(_f);
584 :
585 7 : if (!path_strv_resolve_uniq(search, root))
586 0 : return -ENOMEM;
587 :
588 18 : STRV_FOREACH(i, search) {
589 14 : _cleanup_free_ char *p = NULL;
590 : FILE *f;
591 :
592 14 : p = path_join(root, *i, path);
593 14 : if (!p)
594 0 : return -ENOMEM;
595 :
596 14 : f = fopen(p, mode);
597 14 : if (f) {
598 3 : *_f = f;
599 3 : return 0;
600 : }
601 :
602 11 : if (errno != ENOENT)
603 0 : return -errno;
604 : }
605 :
606 4 : return -ENOENT;
607 : }
608 :
609 6 : int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f) {
610 6 : _cleanup_strv_free_ char **copy = NULL;
611 :
612 6 : assert(path);
613 6 : assert(mode);
614 6 : assert(_f);
615 :
616 6 : if (path_is_absolute(path)) {
617 : FILE *f;
618 :
619 2 : f = fopen(path, mode);
620 2 : if (f) {
621 1 : *_f = f;
622 1 : return 0;
623 : }
624 :
625 1 : return -errno;
626 : }
627 :
628 4 : copy = strv_copy((char**) search);
629 4 : if (!copy)
630 0 : return -ENOMEM;
631 :
632 4 : return search_and_fopen_internal(path, mode, root, copy, _f);
633 : }
634 :
635 5 : int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) {
636 5 : _cleanup_strv_free_ char **s = NULL;
637 :
638 5 : if (path_is_absolute(path)) {
639 : FILE *f;
640 :
641 2 : f = fopen(path, mode);
642 2 : if (f) {
643 1 : *_f = f;
644 1 : return 0;
645 : }
646 :
647 1 : return -errno;
648 : }
649 :
650 3 : s = strv_split_nulstr(search);
651 3 : if (!s)
652 0 : return -ENOMEM;
653 :
654 3 : return search_and_fopen_internal(path, mode, root, s, _f);
655 : }
656 :
657 696 : int fflush_and_check(FILE *f) {
658 696 : assert(f);
659 :
660 696 : errno = 0;
661 696 : fflush(f);
662 :
663 696 : if (ferror(f))
664 0 : return errno_or_else(EIO);
665 :
666 696 : return 0;
667 : }
668 :
669 0 : int fflush_sync_and_check(FILE *f) {
670 : int r;
671 :
672 0 : assert(f);
673 :
674 0 : r = fflush_and_check(f);
675 0 : if (r < 0)
676 0 : return r;
677 :
678 0 : if (fsync(fileno(f)) < 0)
679 0 : return -errno;
680 :
681 0 : r = fsync_directory_of_file(fileno(f));
682 0 : if (r < 0)
683 0 : return r;
684 :
685 0 : return 0;
686 : }
687 :
688 0 : int write_timestamp_file_atomic(const char *fn, usec_t n) {
689 : char ln[DECIMAL_STR_MAX(n)+2];
690 :
691 : /* Creates a "timestamp" file, that contains nothing but a
692 : * usec_t timestamp, formatted in ASCII. */
693 :
694 0 : if (n <= 0 || n >= USEC_INFINITY)
695 0 : return -ERANGE;
696 :
697 0 : xsprintf(ln, USEC_FMT "\n", n);
698 :
699 0 : return write_string_file(fn, ln, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
700 : }
701 :
702 0 : int read_timestamp_file(const char *fn, usec_t *ret) {
703 0 : _cleanup_free_ char *ln = NULL;
704 : uint64_t t;
705 : int r;
706 :
707 0 : r = read_one_line_file(fn, &ln);
708 0 : if (r < 0)
709 0 : return r;
710 :
711 0 : r = safe_atou64(ln, &t);
712 0 : if (r < 0)
713 0 : return r;
714 :
715 0 : if (t <= 0 || t >= (uint64_t) USEC_INFINITY)
716 0 : return -ERANGE;
717 :
718 0 : *ret = (usec_t) t;
719 0 : return 0;
720 : }
721 :
722 11 : int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space) {
723 : int r;
724 :
725 11 : assert(s);
726 :
727 : /* Outputs the specified string with fputs(), but optionally prefixes it with a separator. The *space parameter
728 : * when specified shall initially point to a boolean variable initialized to false. It is set to true after the
729 : * first invocation. This call is supposed to be use in loops, where a separator shall be inserted between each
730 : * element, but not before the first one. */
731 :
732 11 : if (!f)
733 0 : f = stdout;
734 :
735 11 : if (space) {
736 11 : if (!separator)
737 11 : separator = " ";
738 :
739 11 : if (*space) {
740 8 : r = fputs(separator, f);
741 8 : if (r < 0)
742 0 : return r;
743 : }
744 :
745 11 : *space = true;
746 : }
747 :
748 11 : return fputs(s, f);
749 : }
750 :
751 : /* A bitmask of the EOL markers we know */
752 : typedef enum EndOfLineMarker {
753 : EOL_NONE = 0,
754 : EOL_ZERO = 1 << 0, /* \0 (aka NUL) */
755 : EOL_TEN = 1 << 1, /* \n (aka NL, aka LF) */
756 : EOL_THIRTEEN = 1 << 2, /* \r (aka CR) */
757 : } EndOfLineMarker;
758 :
759 10642503 : static EndOfLineMarker categorize_eol(char c, ReadLineFlags flags) {
760 :
761 10642503 : if (!IN_SET(flags, READ_LINE_ONLY_NUL)) {
762 10642424 : if (c == '\n')
763 410279 : return EOL_TEN;
764 10232145 : if (c == '\r')
765 16 : return EOL_THIRTEEN;
766 : }
767 :
768 10232208 : if (c == '\0')
769 29 : return EOL_ZERO;
770 :
771 10232179 : return EOL_NONE;
772 : }
773 :
774 320714 : DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, funlockfile);
775 :
776 320714 : int read_line_full(FILE *f, size_t limit, ReadLineFlags flags, char **ret) {
777 320714 : size_t n = 0, allocated = 0, count = 0;
778 320714 : _cleanup_free_ char *buffer = NULL;
779 320714 : int r, tty = -1;
780 :
781 320714 : assert(f);
782 :
783 : /* Something like a bounded version of getline().
784 : *
785 : * Considers EOF, \n, \r and \0 end of line delimiters (or combinations of these), and does not include these
786 : * delimiters in the string returned. Specifically, recognizes the following combinations of markers as line
787 : * endings:
788 : *
789 : * • \n (UNIX)
790 : * • \r (old MacOS)
791 : * • \0 (C strings)
792 : * • \n\0
793 : * • \r\0
794 : * • \r\n (Windows)
795 : * • \n\r
796 : * • \r\n\0
797 : * • \n\r\0
798 : *
799 : * Returns the number of bytes read from the files (i.e. including delimiters — this hence usually differs from
800 : * the number of characters in the returned string). When EOF is hit, 0 is returned.
801 : *
802 : * The input parameter limit is the maximum numbers of characters in the returned string, i.e. excluding
803 : * delimiters. If the limit is hit we fail and return -ENOBUFS.
804 : *
805 : * If a line shall be skipped ret may be initialized as NULL. */
806 :
807 320714 : if (ret) {
808 320681 : if (!GREEDY_REALLOC(buffer, allocated, 1))
809 0 : return -ENOMEM;
810 : }
811 :
812 : {
813 320714 : _unused_ _cleanup_(funlockfilep) FILE *flocked = f;
814 320714 : EndOfLineMarker previous_eol = EOL_NONE;
815 320714 : flockfile(f);
816 :
817 10328181 : for (;;) {
818 : EndOfLineMarker eol;
819 : char c;
820 :
821 10648895 : if (n >= limit)
822 3 : return -ENOBUFS;
823 :
824 10648892 : if (count >= INT_MAX) /* We couldn't return the counter anymore as "int", hence refuse this */
825 0 : return -ENOBUFS;
826 :
827 10648892 : r = safe_fgetc(f, &c);
828 10648892 : if (r < 0)
829 0 : return r;
830 10648892 : if (r == 0) /* EOF is definitely EOL */
831 320711 : break;
832 :
833 10642503 : eol = categorize_eol(c, flags);
834 :
835 10642503 : if (FLAGS_SET(previous_eol, EOL_ZERO) ||
836 10642487 : (eol == EOL_NONE && previous_eol != EOL_NONE) ||
837 410319 : (eol != EOL_NONE && (previous_eol & eol) != 0)) {
838 : /* Previous char was a NUL? This is not an EOL, but the previous char was? This type of
839 : * EOL marker has been seen right before? In either of these three cases we are
840 : * done. But first, let's put this character back in the queue. (Note that we have to
841 : * cast this to (unsigned char) here as ungetc() expects a positive 'int', and if we
842 : * are on an architecture where 'char' equals 'signed char' we need to ensure we don't
843 : * pass a negative value here. That said, to complicate things further ungetc() is
844 : * actually happy with most negative characters and implicitly casts them back to
845 : * positive ones as needed, except for \xff (aka -1, aka EOF), which it refuses. What a
846 : * godawful API!) */
847 314322 : assert_se(ungetc((unsigned char) c, f) != EOF);
848 314322 : break;
849 : }
850 :
851 10328181 : count++;
852 :
853 10328181 : if (eol != EOL_NONE) {
854 : /* If we are on a tty, we can't wait for more input. But we expect only
855 : * \n as the single EOL marker, so there is no need to wait. We check
856 : * this condition last to avoid isatty() check if not necessary. */
857 :
858 319602 : if (tty < 0)
859 319576 : tty = isatty(fileno(f));
860 319602 : if (tty > 0)
861 0 : break;
862 : }
863 :
864 10328181 : if (eol != EOL_NONE) {
865 319602 : previous_eol |= eol;
866 319602 : continue;
867 : }
868 :
869 10008579 : if (ret) {
870 10008469 : if (!GREEDY_REALLOC(buffer, allocated, n + 2))
871 0 : return -ENOMEM;
872 :
873 10008469 : buffer[n] = c;
874 : }
875 :
876 10008579 : n++;
877 : }
878 : }
879 :
880 320711 : if (ret) {
881 320678 : buffer[n] = 0;
882 :
883 320678 : *ret = TAKE_PTR(buffer);
884 : }
885 :
886 320711 : return (int) count;
887 : }
888 :
889 10656188 : int safe_fgetc(FILE *f, char *ret) {
890 : int k;
891 :
892 10656188 : assert(f);
893 :
894 : /* A safer version of plain fgetc(): let's propagate the error that happened while reading as such, and
895 : * separate the EOF condition from the byte read, to avoid those confusion signed/unsigned issues fgetc()
896 : * has. */
897 :
898 10656188 : errno = 0;
899 10656188 : k = fgetc(f);
900 10656188 : if (k == EOF) {
901 6391 : if (ferror(f))
902 0 : return errno_or_else(EIO);
903 :
904 6391 : if (ret)
905 6391 : *ret = 0;
906 :
907 6391 : return 0;
908 : }
909 :
910 10649797 : if (ret)
911 10649797 : *ret = k;
912 :
913 10649797 : return 1;
914 : }
915 :
916 0 : int warn_file_is_world_accessible(const char *filename, struct stat *st, const char *unit, unsigned line) {
917 : struct stat _st;
918 :
919 0 : if (!filename)
920 0 : return 0;
921 :
922 0 : if (!st) {
923 0 : if (stat(filename, &_st) < 0)
924 0 : return -errno;
925 0 : st = &_st;
926 : }
927 :
928 0 : if ((st->st_mode & S_IRWXO) == 0)
929 0 : return 0;
930 :
931 0 : if (unit)
932 0 : log_syntax(unit, LOG_WARNING, filename, line, 0,
933 : "%s has %04o mode that is too permissive, please adjust the access mode.",
934 : filename, st->st_mode & 07777);
935 : else
936 0 : log_warning("%s has %04o mode that is too permissive, please adjust the access mode.",
937 : filename, st->st_mode & 07777);
938 0 : return 0;
939 : }
|