Branch data 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 : 81854 : int fopen_unlocked(const char *path, const char *options, FILE **ret) {
34 [ - + ]: 81854 : assert(ret);
35 : :
36 : 81854 : FILE *f = fopen(path, options);
37 [ + + ]: 81854 : if (!f)
38 : 29556 : return -errno;
39 : :
40 : 52298 : (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
41 : :
42 : 52298 : *ret = f;
43 : 52298 : return 0;
44 : : }
45 : :
46 : 24 : int fdopen_unlocked(int fd, const char *options, FILE **ret) {
47 [ - + ]: 24 : assert(ret);
48 : :
49 : 24 : FILE *f = fdopen(fd, options);
50 [ - + ]: 24 : if (!f)
51 : 0 : return -errno;
52 : :
53 : 24 : (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
54 : :
55 : 24 : *ret = f;
56 : 24 : return 0;
57 : : }
58 : :
59 : 2184 : FILE* open_memstream_unlocked(char **ptr, size_t *sizeloc) {
60 : 2184 : FILE *f = open_memstream(ptr, sizeloc);
61 [ - + ]: 2184 : if (!f)
62 : 0 : return NULL;
63 : :
64 : 2184 : (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
65 : :
66 : 2184 : return f;
67 : : }
68 : :
69 : 56 : FILE* fmemopen_unlocked(void *buf, size_t size, const char *mode) {
70 : 56 : FILE *f = fmemopen(buf, size, mode);
71 [ - + ]: 56 : if (!f)
72 : 0 : return NULL;
73 : :
74 : 56 : (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
75 : :
76 : 56 : return f;
77 : : }
78 : :
79 : 472 : 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 [ - + ]: 472 : assert(f);
89 [ - + ]: 472 : assert(line);
90 : :
91 [ - + ]: 472 : if (ferror(f))
92 : 0 : return -EIO;
93 : :
94 [ + + + + ]: 472 : needs_nl = !(flags & WRITE_STRING_FILE_AVOID_NEWLINE) && !endswith(line, "\n");
95 : :
96 [ + + - + ]: 472 : 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 [ + + ]: 472 : if (fputs(line, f) == EOF)
105 : 4 : return -errno;
106 : :
107 [ + + ]: 468 : if (needs_nl)
108 [ - + ]: 248 : if (fputc('\n', f) == EOF)
109 : 0 : return -errno;
110 : :
111 [ - + ]: 468 : if (flags & WRITE_STRING_FILE_SYNC)
112 : 0 : r = fflush_sync_and_check(f);
113 : : else
114 : 468 : r = fflush_and_check(f);
115 [ - + ]: 468 : if (r < 0)
116 : 0 : return r;
117 : :
118 [ - + ]: 468 : 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 : 468 : 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 : 424 : int write_string_file_ts(
164 : : const char *fn,
165 : : const char *line,
166 : : WriteStringFileFlags flags,
167 : : struct timespec *ts) {
168 : :
169 : 424 : _cleanup_fclose_ FILE *f = NULL;
170 : : int q, r;
171 : :
172 [ - + ]: 424 : assert(fn);
173 [ - + ]: 424 : assert(line);
174 : :
175 : : /* We don't know how to verify whether the file contents was already on-disk. */
176 [ + + - + ]: 424 : assert(!((flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE) && (flags & WRITE_STRING_FILE_SYNC)));
177 : :
178 [ - + ]: 424 : 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 [ - + ]: 424 : 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 [ - + ]: 424 : assert(!ts);
194 : :
195 [ + + ]: 424 : if (flags & WRITE_STRING_FILE_CREATE) {
196 : 356 : r = fopen_unlocked(fn, "we", &f);
197 [ - + ]: 356 : 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 : 68 : fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY | ((flags & WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0));
205 [ + + ]: 68 : if (fd < 0) {
206 : 64 : r = -errno;
207 : 64 : goto fail;
208 : : }
209 : :
210 : 4 : r = fdopen_unlocked(fd, "w", &f);
211 [ - + ]: 4 : if (r < 0) {
212 : 0 : safe_close(fd);
213 : 0 : goto fail;
214 : : }
215 : : }
216 : :
217 [ - + ]: 360 : if (flags & WRITE_STRING_FILE_DISABLE_BUFFER)
218 : 0 : setvbuf(f, NULL, _IONBF, 0);
219 : :
220 : 360 : r = write_string_stream_ts(f, line, flags, ts);
221 [ - + ]: 360 : if (r < 0)
222 : 0 : goto fail;
223 : :
224 : 360 : return 0;
225 : :
226 : 64 : fail:
227 [ + + ]: 64 : if (!(flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE))
228 : 48 : return r;
229 : :
230 : 16 : 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 : 16 : q = verify_file(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
236 [ + + ]: 16 : if (q <= 0)
237 : 4 : return r;
238 : :
239 : 12 : 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 : 9756 : int read_one_line_file(const char *fn, char **line) {
262 : 9756 : _cleanup_fclose_ FILE *f = NULL;
263 : : int r;
264 : :
265 [ - + ]: 9756 : assert(fn);
266 [ - + ]: 9756 : assert(line);
267 : :
268 : 9756 : r = fopen_unlocked(fn, "re", &f);
269 [ + + ]: 9756 : if (r < 0)
270 : 1658 : return r;
271 : :
272 : 8098 : return read_line(f, LONG_LINE_MAX, line);
273 : : }
274 : :
275 : 16 : int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
276 : 16 : _cleanup_fclose_ FILE *f = NULL;
277 : 16 : _cleanup_free_ char *buf = NULL;
278 : : size_t l, k;
279 : : int r;
280 : :
281 [ - + ]: 16 : assert(fn);
282 [ - + ]: 16 : assert(blob);
283 : :
284 : 16 : l = strlen(blob);
285 : :
286 [ + + + + ]: 16 : if (accept_extra_nl && endswith(blob, "\n"))
287 : 4 : accept_extra_nl = false;
288 : :
289 : 16 : buf = malloc(l + accept_extra_nl + 1);
290 [ - + ]: 16 : if (!buf)
291 : 0 : return -ENOMEM;
292 : :
293 : 16 : r = fopen_unlocked(fn, "re", &f);
294 [ - + ]: 16 : 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 : 16 : errno = 0;
299 : 16 : k = fread(buf, 1, l + accept_extra_nl + 1, f);
300 [ - + ]: 16 : if (ferror(f))
301 : 0 : return errno_or_else(EIO);
302 : :
303 [ + + + + ]: 16 : if (k != l && k != l + accept_extra_nl)
304 : 4 : return 0;
305 [ - + ]: 12 : if (memcmp(buf, blob, l) != 0)
306 : 0 : return 0;
307 [ + + - + ]: 12 : if (k > l && buf[l] != '\n')
308 : 0 : return 0;
309 : :
310 : 12 : return 1;
311 : : }
312 : :
313 : 32772 : 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 : 32772 : _cleanup_free_ char *buf = NULL;
321 : : struct stat st;
322 : : size_t n, n_next, l;
323 : : int fd, r;
324 : :
325 [ - + ]: 32772 : assert(f);
326 [ - + ]: 32772 : assert(ret_contents);
327 [ - + ]: 32772 : assert(!FLAGS_SET(flags, READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX));
328 [ - + # # ]: 32772 : assert(!(flags & (READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)) || ret_size);
329 : :
330 : 32772 : n_next = LINE_MAX; /* Start size */
331 : :
332 : 32772 : fd = fileno(f);
333 [ + + ]: 32772 : 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 [ - + ]: 32768 : if (fstat(fd, &st) < 0)
337 : 0 : return -errno;
338 : :
339 [ + - ]: 32768 : if (S_ISREG(st.st_mode)) {
340 : :
341 : : /* Safety check */
342 [ - + ]: 32768 : 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 [ + + ]: 32768 : if (st.st_size > 0)
349 : 30648 : n_next = st.st_size + 1;
350 : :
351 [ - + ]: 32768 : if (flags & READ_FULL_FILE_SECURE)
352 : 0 : (void) warn_file_is_world_accessible(filename, &st, NULL, 0);
353 : : }
354 : : }
355 : :
356 : 32772 : n = l = 0;
357 : 0 : for (;;) {
358 : : char *t;
359 : : size_t k;
360 : :
361 [ - + ]: 32772 : 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 : 32772 : t = realloc(buf, n_next + 1);
372 [ - + ]: 32772 : if (!t)
373 : 0 : return -ENOMEM;
374 : : }
375 : :
376 : 32772 : buf = t;
377 : 32772 : n = n_next;
378 : :
379 : 32772 : errno = 0;
380 : 32772 : k = fread(buf + l, 1, n - l, f);
381 [ + + ]: 32772 : if (k > 0)
382 : 23808 : l += k;
383 : :
384 [ + + ]: 32772 : if (ferror(f)) {
385 : 16 : r = errno_or_else(EIO);
386 : 16 : goto finalize;
387 : : }
388 : :
389 [ + - ]: 32756 : if (feof(f))
390 : 32756 : 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 [ - + ]: 32756 : 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 [ + + ]: 32756 : 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 [ - + ]: 368 : if (memchr(buf, 0, l)) {
421 : 0 : r = -EBADMSG;
422 : 0 : goto finalize;
423 : : }
424 : : }
425 : :
426 : 32756 : buf[l] = 0;
427 : 32756 : *ret_contents = TAKE_PTR(buf);
428 : :
429 [ + + ]: 32756 : if (ret_size)
430 : 32388 : *ret_size = l;
431 : :
432 : 32756 : return 0;
433 : :
434 : 16 : finalize:
435 [ - + ]: 16 : if (flags & READ_FULL_FILE_SECURE)
436 : 0 : explicit_bzero_safe(buf, n);
437 : :
438 : 16 : return r;
439 : : }
440 : :
441 : 59068 : int read_full_file_full(const char *filename, ReadFullFileFlags flags, char **contents, size_t *size) {
442 : 59068 : _cleanup_fclose_ FILE *f = NULL;
443 : : int r;
444 : :
445 [ - + ]: 59068 : assert(filename);
446 [ - + ]: 59068 : assert(contents);
447 : :
448 : 59068 : r = fopen_unlocked(filename, "re", &f);
449 [ + + ]: 59068 : if (r < 0)
450 : 26320 : return r;
451 : :
452 : 32748 : return read_full_stream_full(f, filename, flags, contents, size);
453 : : }
454 : :
455 : 12 : int executable_is_script(const char *path, char **interpreter) {
456 : 12 : _cleanup_free_ char *line = NULL;
457 : : size_t len;
458 : : char *ans;
459 : : int r;
460 : :
461 [ - + ]: 12 : assert(path);
462 : :
463 : 12 : r = read_one_line_file(path, &line);
464 [ - + ]: 12 : if (r == -ENOBUFS) /* First line overly long? if so, then it's not a script */
465 : 0 : return 0;
466 [ - + ]: 12 : if (r < 0)
467 : 0 : return r;
468 : :
469 [ + + ]: 12 : if (!startswith(line, "#!"))
470 : 4 : return 0;
471 : :
472 : 8 : ans = strstrip(line + 2);
473 : 8 : len = strcspn(ans, " \t");
474 : :
475 [ - + ]: 8 : if (len == 0)
476 : 0 : return 0;
477 : :
478 : 8 : ans = strndup(ans, len);
479 [ - + ]: 8 : if (!ans)
480 : 0 : return -ENOMEM;
481 : :
482 : 8 : *interpreter = ans;
483 : 8 : 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 : 24 : int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) {
495 : 24 : _cleanup_free_ char *status = NULL;
496 : : char *t, *f;
497 : : size_t len;
498 : : int r;
499 : :
500 [ - + ]: 24 : assert(terminator);
501 [ - + ]: 24 : assert(filename);
502 [ - + ]: 24 : assert(pattern);
503 [ - + ]: 24 : assert(field);
504 : :
505 : 24 : r = read_full_file(filename, &status, NULL);
506 [ - + ]: 24 : if (r < 0)
507 : 0 : return r;
508 : :
509 : 24 : t = status;
510 : :
511 : : do {
512 : : bool pattern_ok;
513 : :
514 : : do {
515 : 24 : t = strstr(t, pattern);
516 [ + + ]: 24 : if (!t)
517 : 4 : return -ENOENT;
518 : :
519 : : /* Check that pattern occurs in beginning of line. */
520 [ + + + - ]: 20 : pattern_ok = (t == status || t[-1] == '\n');
521 : :
522 : 20 : t += strlen(pattern);
523 : :
524 [ - + ]: 20 : } while (!pattern_ok);
525 : :
526 : 20 : t += strspn(t, " \t");
527 [ - + ]: 20 : if (!*t)
528 : 0 : return -ENOENT;
529 : :
530 [ - + ]: 20 : } while (*t != ':');
531 : :
532 : 20 : t++;
533 : :
534 [ + - ]: 20 : if (*t) {
535 : 20 : 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 : 20 : t += strspn(t, "0");
543 : : /* Back off one char if there's nothing but whitespace
544 : : and zeros */
545 [ + - + + ]: 20 : if (!*t || isspace(*t))
546 : 8 : t--;
547 : : }
548 : :
549 : 20 : len = strcspn(t, terminator);
550 : :
551 : 20 : f = strndup(t, len);
552 [ - + ]: 20 : if (!f)
553 : 0 : return -ENOMEM;
554 : :
555 : 20 : *field = f;
556 : 20 : 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 : 28 : static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) {
579 : : char **i;
580 : :
581 [ - + ]: 28 : assert(path);
582 [ - + ]: 28 : assert(mode);
583 [ - + ]: 28 : assert(_f);
584 : :
585 [ - + ]: 28 : if (!path_strv_resolve_uniq(search, root))
586 : 0 : return -ENOMEM;
587 : :
588 [ + - + + ]: 72 : STRV_FOREACH(i, search) {
589 [ + + ]: 56 : _cleanup_free_ char *p = NULL;
590 : : FILE *f;
591 : :
592 : 56 : p = path_join(root, *i, path);
593 [ - + ]: 56 : if (!p)
594 : 0 : return -ENOMEM;
595 : :
596 : 56 : f = fopen(p, mode);
597 [ + + ]: 56 : if (f) {
598 : 12 : *_f = f;
599 : 12 : return 0;
600 : : }
601 : :
602 [ - + ]: 44 : if (errno != ENOENT)
603 : 0 : return -errno;
604 : : }
605 : :
606 : 16 : return -ENOENT;
607 : : }
608 : :
609 : 24 : int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f) {
610 : 24 : _cleanup_strv_free_ char **copy = NULL;
611 : :
612 [ - + ]: 24 : assert(path);
613 [ - + ]: 24 : assert(mode);
614 [ - + ]: 24 : assert(_f);
615 : :
616 [ + + ]: 24 : if (path_is_absolute(path)) {
617 : : FILE *f;
618 : :
619 : 8 : f = fopen(path, mode);
620 [ + + ]: 8 : if (f) {
621 : 4 : *_f = f;
622 : 4 : return 0;
623 : : }
624 : :
625 : 4 : return -errno;
626 : : }
627 : :
628 : 16 : copy = strv_copy((char**) search);
629 [ - + ]: 16 : if (!copy)
630 : 0 : return -ENOMEM;
631 : :
632 : 16 : return search_and_fopen_internal(path, mode, root, copy, _f);
633 : : }
634 : :
635 : 20 : int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) {
636 : 20 : _cleanup_strv_free_ char **s = NULL;
637 : :
638 [ + + ]: 20 : if (path_is_absolute(path)) {
639 : : FILE *f;
640 : :
641 : 8 : f = fopen(path, mode);
642 [ + + ]: 8 : if (f) {
643 : 4 : *_f = f;
644 : 4 : return 0;
645 : : }
646 : :
647 : 4 : return -errno;
648 : : }
649 : :
650 : 12 : s = strv_split_nulstr(search);
651 [ - + ]: 12 : if (!s)
652 : 0 : return -ENOMEM;
653 : :
654 : 12 : return search_and_fopen_internal(path, mode, root, s, _f);
655 : : }
656 : :
657 : 2784 : int fflush_and_check(FILE *f) {
658 [ - + ]: 2784 : assert(f);
659 : :
660 : 2784 : errno = 0;
661 : 2784 : fflush(f);
662 : :
663 [ - + ]: 2784 : if (ferror(f))
664 : 0 : return errno_or_else(EIO);
665 : :
666 : 2784 : 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 : 44 : int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space) {
723 : : int r;
724 : :
725 [ - + ]: 44 : 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 [ - + ]: 44 : if (!f)
733 : 0 : f = stdout;
734 : :
735 [ + - ]: 44 : if (space) {
736 [ + - ]: 44 : if (!separator)
737 : 44 : separator = " ";
738 : :
739 [ + + ]: 44 : if (*space) {
740 : 32 : r = fputs(separator, f);
741 [ - + ]: 32 : if (r < 0)
742 : 0 : return r;
743 : : }
744 : :
745 : 44 : *space = true;
746 : : }
747 : :
748 : 44 : 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 : 42666611 : static EndOfLineMarker categorize_eol(char c, ReadLineFlags flags) {
760 : :
761 [ + + + + ]: 42666611 : if (!IN_SET(flags, READ_LINE_ONLY_NUL)) {
762 [ + + ]: 42666295 : if (c == '\n')
763 : 1644870 : return EOL_TEN;
764 [ + + ]: 41021425 : if (c == '\r')
765 : 64 : return EOL_THIRTEEN;
766 : : }
767 : :
768 [ + + ]: 41021677 : if (c == '\0')
769 : 116 : return EOL_ZERO;
770 : :
771 : 41021561 : return EOL_NONE;
772 : : }
773 : :
774 [ + - ]: 1286610 : DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, funlockfile);
775 : :
776 : 1286610 : int read_line_full(FILE *f, size_t limit, ReadLineFlags flags, char **ret) {
777 : 1286610 : size_t n = 0, allocated = 0, count = 0;
778 : 1286610 : _cleanup_free_ char *buffer = NULL;
779 : 1286610 : int r, tty = -1;
780 : :
781 [ - + ]: 1286610 : 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 [ + + ]: 1286610 : if (ret) {
808 [ - + ]: 1286478 : if (!GREEDY_REALLOC(buffer, allocated, 1))
809 : 0 : return -ENOMEM;
810 : : }
811 : :
812 : : {
813 [ + + ]: 1286610 : _unused_ _cleanup_(funlockfilep) FILE *flocked = f;
814 : 1286610 : EndOfLineMarker previous_eol = EOL_NONE;
815 : 1286610 : flockfile(f);
816 : :
817 : 41405929 : for (;;) {
818 : : EndOfLineMarker eol;
819 : : char c;
820 : :
821 [ + + ]: 42692539 : if (n >= limit)
822 : 12 : return -ENOBUFS;
823 : :
824 [ - + ]: 42692527 : if (count >= INT_MAX) /* We couldn't return the counter anymore as "int", hence refuse this */
825 : 0 : return -ENOBUFS;
826 : :
827 : 42692527 : r = safe_fgetc(f, &c);
828 [ - + ]: 42692527 : if (r < 0)
829 : 0 : return r;
830 [ + + ]: 42692527 : if (r == 0) /* EOF is definitely EOL */
831 : 1286598 : break;
832 : :
833 : 42666611 : eol = categorize_eol(c, flags);
834 : :
835 [ + + + + ]: 42666611 : if (FLAGS_SET(previous_eol, EOL_ZERO) ||
836 [ + + + + ]: 42666547 : (eol == EOL_NONE && previous_eol != EOL_NONE) ||
837 [ + + ]: 1645030 : (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 [ - + ]: 1260682 : assert_se(ungetc((unsigned char) c, f) != EOF);
848 : 1260682 : break;
849 : : }
850 : :
851 : 41405929 : count++;
852 : :
853 [ + + ]: 41405929 : 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 [ + + ]: 1282162 : if (tty < 0)
859 : 1282058 : tty = isatty(fileno(f));
860 [ - + ]: 1282162 : if (tty > 0)
861 : 0 : break;
862 : : }
863 : :
864 [ + + ]: 41405929 : if (eol != EOL_NONE) {
865 : 1282162 : previous_eol |= eol;
866 : 1282162 : continue;
867 : : }
868 : :
869 [ + + ]: 40123767 : if (ret) {
870 [ - + ]: 40123327 : if (!GREEDY_REALLOC(buffer, allocated, n + 2))
871 : 0 : return -ENOMEM;
872 : :
873 : 40123327 : buffer[n] = c;
874 : : }
875 : :
876 : 40123767 : n++;
877 : : }
878 : : }
879 : :
880 [ + + ]: 1286598 : if (ret) {
881 : 1286466 : buffer[n] = 0;
882 : :
883 : 1286466 : *ret = TAKE_PTR(buffer);
884 : : }
885 : :
886 : 1286598 : return (int) count;
887 : : }
888 : :
889 : 42721709 : int safe_fgetc(FILE *f, char *ret) {
890 : : int k;
891 : :
892 [ - + ]: 42721709 : 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 : 42721709 : errno = 0;
899 : 42721709 : k = fgetc(f);
900 [ + + ]: 42721709 : if (k == EOF) {
901 [ - + ]: 25924 : if (ferror(f))
902 : 0 : return errno_or_else(EIO);
903 : :
904 [ + - ]: 25924 : if (ret)
905 : 25924 : *ret = 0;
906 : :
907 : 25924 : return 0;
908 : : }
909 : :
910 [ + - ]: 42695785 : if (ret)
911 : 42695785 : *ret = k;
912 : :
913 : 42695785 : 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 : : }
|