]>
Commit | Line | Data |
---|---|---|
a032b68d | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
663996b3 | 2 | |
6e866b33 | 3 | #include <ctype.h> |
4c89c718 MP |
4 | #include <errno.h> |
5 | #include <fcntl.h> | |
6 | #include <limits.h> | |
7 | #include <stdarg.h> | |
8 | #include <stdint.h> | |
52ad194e | 9 | #include <stdio_ext.h> |
4c89c718 | 10 | #include <stdlib.h> |
4c89c718 MP |
11 | #include <sys/stat.h> |
12 | #include <sys/types.h> | |
663996b3 | 13 | #include <unistd.h> |
f47781d8 | 14 | |
db2df898 | 15 | #include "alloc-util.h" |
db2df898 | 16 | #include "fd-util.h" |
f47781d8 | 17 | #include "fileio.h" |
db2df898 | 18 | #include "fs-util.h" |
bb4f798a | 19 | #include "hexdecoct.h" |
4c89c718 MP |
20 | #include "log.h" |
21 | #include "macro.h" | |
f2dec872 | 22 | #include "mkdir.h" |
db2df898 MP |
23 | #include "parse-util.h" |
24 | #include "path-util.h" | |
a10f5d05 | 25 | #include "socket-util.h" |
db2df898 MP |
26 | #include "stdio-util.h" |
27 | #include "string-util.h" | |
6e866b33 | 28 | #include "tmpfile-util.h" |
663996b3 | 29 | |
8b3d4ff0 MB |
30 | /* The maximum size of the file we'll read in one go in read_full_file() (64M). */ |
31 | #define READ_FULL_BYTES_MAX (64U*1024U*1024U - 1U) | |
32 | ||
33 | /* The maximum size of virtual files we'll read in one go in read_virtual_file() (4M). Note that this limit | |
34 | * is different (and much lower) than the READ_FULL_BYTES_MAX limit. This reflects the fact that we use | |
35 | * different strategies for reading virtual and regular files: virtual files are generally size constrained: | |
36 | * there we allocate the full buffer size in advance. Regular files OTOH can be much larger, and here we grow | |
37 | * the allocations exponentially in a loop. In glibc large allocations are immediately backed by mmap() | |
38 | * making them relatively slow (measurably so). Thus, when allocating the full buffer in advance the large | |
39 | * limit is a problem. When allocating piecemeal it's not. Hence pick two distinct limits. */ | |
40 | #define READ_VIRTUAL_BYTES_MAX (4U*1024U*1024U - 1U) | |
8a584da2 | 41 | |
f2dec872 BR |
42 | int fopen_unlocked(const char *path, const char *options, FILE **ret) { |
43 | assert(ret); | |
44 | ||
45 | FILE *f = fopen(path, options); | |
46 | if (!f) | |
47 | return -errno; | |
48 | ||
49 | (void) __fsetlocking(f, FSETLOCKING_BYCALLER); | |
50 | ||
51 | *ret = f; | |
52 | return 0; | |
53 | } | |
54 | ||
55 | int fdopen_unlocked(int fd, const char *options, FILE **ret) { | |
56 | assert(ret); | |
57 | ||
58 | FILE *f = fdopen(fd, options); | |
59 | if (!f) | |
60 | return -errno; | |
61 | ||
62 | (void) __fsetlocking(f, FSETLOCKING_BYCALLER); | |
63 | ||
64 | *ret = f; | |
65 | return 0; | |
66 | } | |
67 | ||
a10f5d05 | 68 | int take_fdopen_unlocked(int *fd, const char *options, FILE **ret) { |
5b5a102a | 69 | int r; |
a10f5d05 MB |
70 | |
71 | assert(fd); | |
72 | ||
73 | r = fdopen_unlocked(*fd, options, ret); | |
74 | if (r < 0) | |
75 | return r; | |
76 | ||
77 | *fd = -1; | |
78 | ||
79 | return 0; | |
80 | } | |
81 | ||
82 | FILE* take_fdopen(int *fd, const char *options) { | |
83 | assert(fd); | |
84 | ||
85 | FILE *f = fdopen(*fd, options); | |
86 | if (!f) | |
87 | return NULL; | |
88 | ||
89 | *fd = -1; | |
90 | ||
91 | return f; | |
92 | } | |
93 | ||
94 | DIR* take_fdopendir(int *dfd) { | |
95 | assert(dfd); | |
96 | ||
97 | DIR *d = fdopendir(*dfd); | |
98 | if (!d) | |
99 | return NULL; | |
100 | ||
101 | *dfd = -1; | |
102 | ||
103 | return d; | |
104 | } | |
105 | ||
f2dec872 BR |
106 | FILE* open_memstream_unlocked(char **ptr, size_t *sizeloc) { |
107 | FILE *f = open_memstream(ptr, sizeloc); | |
108 | if (!f) | |
109 | return NULL; | |
110 | ||
111 | (void) __fsetlocking(f, FSETLOCKING_BYCALLER); | |
112 | ||
113 | return f; | |
114 | } | |
115 | ||
116 | FILE* fmemopen_unlocked(void *buf, size_t size, const char *mode) { | |
117 | FILE *f = fmemopen(buf, size, mode); | |
118 | if (!f) | |
119 | return NULL; | |
120 | ||
121 | (void) __fsetlocking(f, FSETLOCKING_BYCALLER); | |
122 | ||
123 | return f; | |
124 | } | |
125 | ||
f5e65279 MB |
126 | int write_string_stream_ts( |
127 | FILE *f, | |
128 | const char *line, | |
129 | WriteStringFileFlags flags, | |
a032b68d | 130 | const struct timespec *ts) { |
5fd56512 | 131 | |
1d42b86d | 132 | bool needs_nl; |
8b3d4ff0 | 133 | int r, fd = -1; |
1d42b86d | 134 | |
e842803a MB |
135 | assert(f); |
136 | assert(line); | |
137 | ||
1d42b86d MB |
138 | if (ferror(f)) |
139 | return -EIO; | |
140 | ||
d0648cfe MB |
141 | if (ts) { |
142 | /* If we shall set the timestamp we need the fd. But fmemopen() streams generally don't have | |
143 | * an fd. Let's fail early in that case. */ | |
144 | fd = fileno(f); | |
145 | if (fd < 0) | |
146 | return -EBADF; | |
147 | } | |
148 | ||
1d42b86d MB |
149 | needs_nl = !(flags & WRITE_STRING_FILE_AVOID_NEWLINE) && !endswith(line, "\n"); |
150 | ||
151 | if (needs_nl && (flags & WRITE_STRING_FILE_DISABLE_BUFFER)) { | |
8b3d4ff0 MB |
152 | /* If STDIO buffering was disabled, then let's append the newline character to the string |
153 | * itself, so that the write goes out in one go, instead of two */ | |
1d42b86d MB |
154 | |
155 | line = strjoina(line, "\n"); | |
156 | needs_nl = false; | |
157 | } | |
158 | ||
159 | if (fputs(line, f) == EOF) | |
160 | return -errno; | |
161 | ||
162 | if (needs_nl) | |
163 | if (fputc('\n', f) == EOF) | |
164 | return -errno; | |
663996b3 | 165 | |
b012e921 MB |
166 | if (flags & WRITE_STRING_FILE_SYNC) |
167 | r = fflush_sync_and_check(f); | |
168 | else | |
169 | r = fflush_and_check(f); | |
170 | if (r < 0) | |
171 | return r; | |
172 | ||
81c58355 | 173 | if (ts) { |
a032b68d | 174 | const struct timespec twice[2] = {*ts, *ts}; |
81c58355 | 175 | |
8b3d4ff0 | 176 | assert(fd >= 0); |
d0648cfe | 177 | if (futimens(fd, twice) < 0) |
81c58355 MB |
178 | return -errno; |
179 | } | |
180 | ||
b012e921 | 181 | return 0; |
663996b3 MS |
182 | } |
183 | ||
f5e65279 MB |
184 | static int write_string_file_atomic( |
185 | const char *fn, | |
186 | const char *line, | |
187 | WriteStringFileFlags flags, | |
a032b68d | 188 | const struct timespec *ts) { |
f5e65279 | 189 | |
663996b3 MS |
190 | _cleanup_fclose_ FILE *f = NULL; |
191 | _cleanup_free_ char *p = NULL; | |
192 | int r; | |
193 | ||
194 | assert(fn); | |
195 | assert(line); | |
196 | ||
46cdbd49 BR |
197 | /* Note that we'd really like to use O_TMPFILE here, but can't really, since we want replacement |
198 | * semantics here, and O_TMPFILE can't offer that. i.e. rename() replaces but linkat() doesn't. */ | |
199 | ||
663996b3 MS |
200 | r = fopen_temporary(fn, &f, &p); |
201 | if (r < 0) | |
202 | return r; | |
203 | ||
f5e65279 MB |
204 | r = write_string_stream_ts(f, line, flags, ts); |
205 | if (r < 0) | |
206 | goto fail; | |
207 | ||
46cdbd49 BR |
208 | r = fchmod_umask(fileno(f), FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0600) ? 0600 : 0644); |
209 | if (r < 0) | |
210 | goto fail; | |
211 | ||
f5e65279 MB |
212 | if (rename(p, fn) < 0) { |
213 | r = -errno; | |
214 | goto fail; | |
663996b3 MS |
215 | } |
216 | ||
a10f5d05 MB |
217 | if (FLAGS_SET(flags, WRITE_STRING_FILE_SYNC)) { |
218 | /* Sync the rename, too */ | |
219 | r = fsync_directory_of_file(fileno(f)); | |
220 | if (r < 0) | |
221 | return r; | |
222 | } | |
223 | ||
f5e65279 | 224 | return 0; |
663996b3 | 225 | |
f5e65279 MB |
226 | fail: |
227 | (void) unlink(p); | |
663996b3 MS |
228 | return r; |
229 | } | |
230 | ||
f5e65279 MB |
231 | int write_string_file_ts( |
232 | const char *fn, | |
233 | const char *line, | |
234 | WriteStringFileFlags flags, | |
a032b68d | 235 | const struct timespec *ts) { |
f5e65279 | 236 | |
7035cd9e | 237 | _cleanup_fclose_ FILE *f = NULL; |
46cdbd49 | 238 | int q, r, fd; |
7035cd9e MP |
239 | |
240 | assert(fn); | |
241 | assert(line); | |
242 | ||
f5e65279 MB |
243 | /* We don't know how to verify whether the file contents was already on-disk. */ |
244 | assert(!((flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE) && (flags & WRITE_STRING_FILE_SYNC))); | |
245 | ||
f2dec872 BR |
246 | if (flags & WRITE_STRING_FILE_MKDIR_0755) { |
247 | r = mkdir_parents(fn, 0755); | |
248 | if (r < 0) | |
249 | return r; | |
250 | } | |
251 | ||
7035cd9e MP |
252 | if (flags & WRITE_STRING_FILE_ATOMIC) { |
253 | assert(flags & WRITE_STRING_FILE_CREATE); | |
254 | ||
f5e65279 | 255 | r = write_string_file_atomic(fn, line, flags, ts); |
db2df898 MP |
256 | if (r < 0) |
257 | goto fail; | |
258 | ||
259 | return r; | |
81c58355 | 260 | } else |
52ad194e | 261 | assert(!ts); |
7035cd9e | 262 | |
46cdbd49 BR |
263 | /* We manually build our own version of fopen(..., "we") that works without O_CREAT and with O_NOFOLLOW if needed. */ |
264 | fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY | | |
265 | (FLAGS_SET(flags, WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0) | | |
a032b68d MB |
266 | (FLAGS_SET(flags, WRITE_STRING_FILE_CREATE) ? O_CREAT : 0) | |
267 | (FLAGS_SET(flags, WRITE_STRING_FILE_TRUNCATE) ? O_TRUNC : 0), | |
46cdbd49 BR |
268 | (FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0600) ? 0600 : 0666)); |
269 | if (fd < 0) { | |
270 | r = -errno; | |
271 | goto fail; | |
272 | } | |
7035cd9e | 273 | |
46cdbd49 BR |
274 | r = fdopen_unlocked(fd, "w", &f); |
275 | if (r < 0) { | |
276 | safe_close(fd); | |
277 | goto fail; | |
7035cd9e MP |
278 | } |
279 | ||
52ad194e MB |
280 | if (flags & WRITE_STRING_FILE_DISABLE_BUFFER) |
281 | setvbuf(f, NULL, _IONBF, 0); | |
282 | ||
f5e65279 | 283 | r = write_string_stream_ts(f, line, flags, ts); |
db2df898 MP |
284 | if (r < 0) |
285 | goto fail; | |
286 | ||
287 | return 0; | |
288 | ||
289 | fail: | |
290 | if (!(flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE)) | |
291 | return r; | |
292 | ||
293 | f = safe_fclose(f); | |
294 | ||
295 | /* OK, the operation failed, but let's see if the right | |
296 | * contents in place already. If so, eat up the error. */ | |
297 | ||
8b3d4ff0 | 298 | q = verify_file(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE) || (flags & WRITE_STRING_FILE_VERIFY_IGNORE_NEWLINE)); |
db2df898 MP |
299 | if (q <= 0) |
300 | return r; | |
301 | ||
302 | return 0; | |
7035cd9e MP |
303 | } |
304 | ||
b012e921 MB |
305 | int write_string_filef( |
306 | const char *fn, | |
307 | WriteStringFileFlags flags, | |
308 | const char *format, ...) { | |
309 | ||
310 | _cleanup_free_ char *p = NULL; | |
311 | va_list ap; | |
312 | int r; | |
313 | ||
314 | va_start(ap, format); | |
315 | r = vasprintf(&p, format, ap); | |
316 | va_end(ap); | |
317 | ||
318 | if (r < 0) | |
319 | return -ENOMEM; | |
320 | ||
321 | return write_string_file(fn, p, flags); | |
322 | } | |
323 | ||
663996b3 MS |
324 | int read_one_line_file(const char *fn, char **line) { |
325 | _cleanup_fclose_ FILE *f = NULL; | |
f2dec872 | 326 | int r; |
663996b3 MS |
327 | |
328 | assert(fn); | |
329 | assert(line); | |
330 | ||
f2dec872 BR |
331 | r = fopen_unlocked(fn, "re", &f); |
332 | if (r < 0) | |
333 | return r; | |
52ad194e | 334 | |
bb4f798a | 335 | return read_line(f, LONG_LINE_MAX, line); |
663996b3 MS |
336 | } |
337 | ||
db2df898 MP |
338 | int verify_file(const char *fn, const char *blob, bool accept_extra_nl) { |
339 | _cleanup_fclose_ FILE *f = NULL; | |
340 | _cleanup_free_ char *buf = NULL; | |
341 | size_t l, k; | |
f2dec872 | 342 | int r; |
fb183854 | 343 | |
db2df898 MP |
344 | assert(fn); |
345 | assert(blob); | |
346 | ||
347 | l = strlen(blob); | |
348 | ||
349 | if (accept_extra_nl && endswith(blob, "\n")) | |
350 | accept_extra_nl = false; | |
351 | ||
352 | buf = malloc(l + accept_extra_nl + 1); | |
353 | if (!buf) | |
354 | return -ENOMEM; | |
fb183854 | 355 | |
f2dec872 BR |
356 | r = fopen_unlocked(fn, "re", &f); |
357 | if (r < 0) | |
358 | return r; | |
52ad194e | 359 | |
db2df898 MP |
360 | /* We try to read one byte more than we need, so that we know whether we hit eof */ |
361 | errno = 0; | |
362 | k = fread(buf, 1, l + accept_extra_nl + 1, f); | |
363 | if (ferror(f)) | |
f2dec872 | 364 | return errno_or_else(EIO); |
db2df898 MP |
365 | |
366 | if (k != l && k != l + accept_extra_nl) | |
367 | return 0; | |
368 | if (memcmp(buf, blob, l) != 0) | |
369 | return 0; | |
370 | if (k > l && buf[l] != '\n') | |
371 | return 0; | |
372 | ||
373 | return 1; | |
fb183854 MP |
374 | } |
375 | ||
8b3d4ff0 | 376 | int read_virtual_file(const char *filename, size_t max_size, char **ret_contents, size_t *ret_size) { |
e1f67bc7 MB |
377 | _cleanup_free_ char *buf = NULL; |
378 | _cleanup_close_ int fd = -1; | |
e1f67bc7 MB |
379 | size_t n, size; |
380 | int n_retries; | |
8b3d4ff0 MB |
381 | bool truncated = false; |
382 | ||
383 | /* Virtual filesystems such as sysfs or procfs use kernfs, and kernfs can work with two sorts of | |
384 | * virtual files. One sort uses "seq_file", and the results of the first read are buffered for the | |
385 | * second read. The other sort uses "raw" reads which always go direct to the device. In the latter | |
386 | * case, the content of the virtual file must be retrieved with a single read otherwise a second read | |
387 | * might get the new value instead of finding EOF immediately. That's the reason why the usage of | |
388 | * fread(3) is prohibited in this case as it always performs a second call to read(2) looking for | |
389 | * EOF. See issue #13585. | |
390 | * | |
391 | * max_size specifies a limit on the bytes read. If max_size is SIZE_MAX, the full file is read. If | |
392 | * the full file is too large to read, an error is returned. For other values of max_size, *partial | |
393 | * contents* may be returned. (Though the read is still done using one syscall.) Returns 0 on | |
394 | * partial success, 1 if untruncated contents were read. */ | |
e1f67bc7 MB |
395 | |
396 | fd = open(filename, O_RDONLY|O_CLOEXEC); | |
397 | if (fd < 0) | |
398 | return -errno; | |
399 | ||
8b3d4ff0 MB |
400 | assert(max_size <= READ_VIRTUAL_BYTES_MAX || max_size == SIZE_MAX); |
401 | ||
e1f67bc7 MB |
402 | /* Limit the number of attempts to read the number of bytes returned by fstat(). */ |
403 | n_retries = 3; | |
404 | ||
405 | for (;;) { | |
8b3d4ff0 MB |
406 | struct stat st; |
407 | ||
e1f67bc7 MB |
408 | if (fstat(fd, &st) < 0) |
409 | return -errno; | |
410 | ||
411 | if (!S_ISREG(st.st_mode)) | |
412 | return -EBADF; | |
413 | ||
414 | /* Be prepared for files from /proc which generally report a file size of 0. */ | |
8b3d4ff0 MB |
415 | assert_cc(READ_VIRTUAL_BYTES_MAX < SSIZE_MAX); |
416 | if (st.st_size > 0 && n_retries > 1) { | |
417 | /* Let's use the file size if we have more than 1 attempt left. On the last attempt | |
418 | * we'll ignore the file size */ | |
419 | ||
420 | if (st.st_size > SSIZE_MAX) { /* Avoid overflow with 32-bit size_t and 64-bit off_t. */ | |
421 | ||
422 | if (max_size == SIZE_MAX) | |
423 | return -EFBIG; | |
424 | ||
425 | size = max_size; | |
426 | } else { | |
427 | size = MIN((size_t) st.st_size, max_size); | |
428 | ||
429 | if (size > READ_VIRTUAL_BYTES_MAX) | |
430 | return -EFBIG; | |
431 | } | |
3a6ce677 | 432 | |
e1f67bc7 | 433 | n_retries--; |
3a6ce677 | 434 | } else { |
8b3d4ff0 | 435 | size = MIN(READ_VIRTUAL_BYTES_MAX, max_size); |
3a6ce677 BR |
436 | n_retries = 0; |
437 | } | |
e1f67bc7 | 438 | |
3a6ce677 BR |
439 | buf = malloc(size + 1); |
440 | if (!buf) | |
e1f67bc7 | 441 | return -ENOMEM; |
8b3d4ff0 | 442 | |
3a6ce677 | 443 | /* Use a bigger allocation if we got it anyway, but not more than the limit. */ |
8b3d4ff0 | 444 | size = MIN3(MALLOC_SIZEOF_SAFE(buf) - 1, max_size, READ_VIRTUAL_BYTES_MAX); |
e1f67bc7 MB |
445 | |
446 | for (;;) { | |
447 | ssize_t k; | |
448 | ||
449 | /* Read one more byte so we can detect whether the content of the | |
450 | * file has already changed or the guessed size for files from /proc | |
451 | * wasn't large enough . */ | |
452 | k = read(fd, buf, size + 1); | |
453 | if (k >= 0) { | |
454 | n = k; | |
455 | break; | |
456 | } | |
457 | ||
20a6e51f | 458 | if (errno != EINTR) |
e1f67bc7 MB |
459 | return -errno; |
460 | } | |
461 | ||
462 | /* Consider a short read as EOF */ | |
463 | if (n <= size) | |
464 | break; | |
465 | ||
8b3d4ff0 MB |
466 | /* If a maximum size is specified and we already read as much, no need to try again */ |
467 | if (max_size != SIZE_MAX && n >= max_size) { | |
468 | n = max_size; | |
469 | truncated = true; | |
470 | break; | |
471 | } | |
e1f67bc7 | 472 | |
8b3d4ff0 | 473 | /* We have no further attempts left? Then the file is apparently larger than our limits. Give up. */ |
3a6ce677 | 474 | if (n_retries <= 0) |
8b3d4ff0 MB |
475 | return -EFBIG; |
476 | ||
477 | /* Hmm... either we read too few bytes from /proc or less likely the content of the file | |
478 | * might have been changed (and is now bigger) while we were processing, let's try again | |
479 | * either with the new file size. */ | |
3a6ce677 | 480 | |
e1f67bc7 MB |
481 | if (lseek(fd, 0, SEEK_SET) < 0) |
482 | return -errno; | |
3a6ce677 BR |
483 | |
484 | buf = mfree(buf); | |
e1f67bc7 MB |
485 | } |
486 | ||
8b3d4ff0 | 487 | if (ret_contents) { |
3a6ce677 | 488 | |
3a6ce677 BR |
489 | /* Safety check: if the caller doesn't want to know the size of what we just read it will |
490 | * rely on the trailing NUL byte. But if there's an embedded NUL byte, then we should refuse | |
491 | * operation as otherwise there'd be ambiguity about what we just read. */ | |
8b3d4ff0 MB |
492 | if (!ret_size && memchr(buf, 0, n)) |
493 | return -EBADMSG; | |
e1f67bc7 | 494 | |
8b3d4ff0 MB |
495 | if (n < size) { |
496 | char *p; | |
e1f67bc7 | 497 | |
8b3d4ff0 MB |
498 | /* Return rest of the buffer to libc */ |
499 | p = realloc(buf, n + 1); | |
500 | if (!p) | |
501 | return -ENOMEM; | |
502 | buf = p; | |
503 | } | |
504 | ||
505 | buf[n] = 0; | |
506 | *ret_contents = TAKE_PTR(buf); | |
507 | } | |
508 | ||
509 | if (ret_size) | |
510 | *ret_size = n; | |
511 | ||
512 | return !truncated; | |
e1f67bc7 MB |
513 | } |
514 | ||
bb4f798a | 515 | int read_full_stream_full( |
6e866b33 | 516 | FILE *f, |
bb4f798a | 517 | const char *filename, |
3a6ce677 BR |
518 | uint64_t offset, |
519 | size_t size, | |
bb4f798a | 520 | ReadFullFileFlags flags, |
6e866b33 MB |
521 | char **ret_contents, |
522 | size_t *ret_size) { | |
523 | ||
663996b3 | 524 | _cleanup_free_ char *buf = NULL; |
bb4f798a MB |
525 | size_t n, n_next, l; |
526 | int fd, r; | |
663996b3 | 527 | |
e842803a | 528 | assert(f); |
6e866b33 | 529 | assert(ret_contents); |
f2dec872 | 530 | assert(!FLAGS_SET(flags, READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)); |
663996b3 | 531 | |
3a6ce677 BR |
532 | if (offset != UINT64_MAX && offset > LONG_MAX) |
533 | return -ERANGE; | |
534 | ||
535 | n_next = size != SIZE_MAX ? size : LINE_MAX; /* Start size */ | |
663996b3 | 536 | |
b012e921 | 537 | fd = fileno(f); |
3a6ce677 BR |
538 | if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see |
539 | * fmemopen()), let's optimize our buffering */ | |
540 | struct stat st; | |
e842803a | 541 | |
bb4f798a | 542 | if (fstat(fd, &st) < 0) |
b012e921 MB |
543 | return -errno; |
544 | ||
545 | if (S_ISREG(st.st_mode)) { | |
3a6ce677 BR |
546 | if (size == SIZE_MAX) { |
547 | uint64_t rsize = | |
548 | LESS_BY((uint64_t) st.st_size, offset == UINT64_MAX ? 0 : offset); | |
549 | ||
550 | /* Safety check */ | |
551 | if (rsize > READ_FULL_BYTES_MAX) | |
552 | return -E2BIG; | |
553 | ||
554 | /* Start with the right file size. Note that we increase the size to read | |
555 | * here by one, so that the first read attempt already makes us notice the | |
556 | * EOF. If the reported size of the file is zero, we avoid this logic | |
557 | * however, since quite likely it might be a virtual file in procfs that all | |
558 | * report a zero file size. */ | |
559 | if (st.st_size > 0) | |
560 | n_next = rsize + 1; | |
561 | } | |
bb4f798a | 562 | |
a10f5d05 | 563 | if (flags & READ_FULL_FILE_WARN_WORLD_READABLE) |
bb4f798a | 564 | (void) warn_file_is_world_accessible(filename, &st, NULL, 0); |
b012e921 | 565 | } |
e842803a | 566 | } |
663996b3 | 567 | |
3a6ce677 BR |
568 | if (offset != UINT64_MAX && fseek(f, offset, SEEK_SET) < 0) |
569 | return -errno; | |
570 | ||
bb4f798a | 571 | n = l = 0; |
663996b3 MS |
572 | for (;;) { |
573 | char *t; | |
574 | size_t k; | |
575 | ||
bb4f798a MB |
576 | if (flags & READ_FULL_FILE_SECURE) { |
577 | t = malloc(n_next + 1); | |
578 | if (!t) { | |
579 | r = -ENOMEM; | |
580 | goto finalize; | |
581 | } | |
582 | memcpy_safe(t, buf, n); | |
583 | explicit_bzero_safe(buf, n); | |
8b3d4ff0 | 584 | free(buf); |
bb4f798a MB |
585 | } else { |
586 | t = realloc(buf, n_next + 1); | |
587 | if (!t) | |
588 | return -ENOMEM; | |
589 | } | |
663996b3 MS |
590 | |
591 | buf = t; | |
3a6ce677 BR |
592 | /* Unless a size has been explicitly specified, try to read as much as fits into the memory |
593 | * we allocated (minus 1, to leave one byte for the safety NUL byte) */ | |
8b3d4ff0 | 594 | n = size == SIZE_MAX ? MALLOC_SIZEOF_SAFE(buf) - 1 : n_next; |
bb4f798a | 595 | |
f5e65279 | 596 | errno = 0; |
663996b3 | 597 | k = fread(buf + l, 1, n - l, f); |
a10f5d05 MB |
598 | |
599 | assert(k <= n - l); | |
600 | l += k; | |
663996b3 | 601 | |
bb4f798a | 602 | if (ferror(f)) { |
f2dec872 | 603 | r = errno_or_else(EIO); |
bb4f798a MB |
604 | goto finalize; |
605 | } | |
8a584da2 | 606 | if (feof(f)) |
663996b3 | 607 | break; |
663996b3 | 608 | |
3a6ce677 BR |
609 | if (size != SIZE_MAX) { /* If we got asked to read some specific size, we already sized the buffer right, hence leave */ |
610 | assert(l == size); | |
611 | break; | |
612 | } | |
613 | ||
a10f5d05 | 614 | assert(k > 0); /* we can't have read zero bytes because that would have been EOF */ |
663996b3 MS |
615 | |
616 | /* Safety check */ | |
bb4f798a MB |
617 | if (n >= READ_FULL_BYTES_MAX) { |
618 | r = -E2BIG; | |
619 | goto finalize; | |
620 | } | |
621 | ||
622 | n_next = MIN(n * 2, READ_FULL_BYTES_MAX); | |
623 | } | |
8a584da2 | 624 | |
f2dec872 | 625 | if (flags & (READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)) { |
a10f5d05 MB |
626 | _cleanup_free_ void *decoded = NULL; |
627 | size_t decoded_size; | |
628 | ||
bb4f798a | 629 | buf[l++] = 0; |
f2dec872 | 630 | if (flags & READ_FULL_FILE_UNBASE64) |
a10f5d05 | 631 | r = unbase64mem_full(buf, l, flags & READ_FULL_FILE_SECURE, &decoded, &decoded_size); |
f2dec872 | 632 | else |
a10f5d05 MB |
633 | r = unhexmem_full(buf, l, flags & READ_FULL_FILE_SECURE, &decoded, &decoded_size); |
634 | if (r < 0) | |
635 | goto finalize; | |
636 | ||
637 | if (flags & READ_FULL_FILE_SECURE) | |
638 | explicit_bzero_safe(buf, n); | |
639 | free_and_replace(buf, decoded); | |
640 | n = l = decoded_size; | |
663996b3 MS |
641 | } |
642 | ||
6e866b33 MB |
643 | if (!ret_size) { |
644 | /* Safety check: if the caller doesn't want to know the size of what we just read it will rely on the | |
645 | * trailing NUL byte. But if there's an embedded NUL byte, then we should refuse operation as otherwise | |
646 | * there'd be ambiguity about what we just read. */ | |
647 | ||
bb4f798a MB |
648 | if (memchr(buf, 0, l)) { |
649 | r = -EBADMSG; | |
650 | goto finalize; | |
651 | } | |
6e866b33 MB |
652 | } |
653 | ||
663996b3 | 654 | buf[l] = 0; |
6e866b33 | 655 | *ret_contents = TAKE_PTR(buf); |
663996b3 | 656 | |
6e866b33 MB |
657 | if (ret_size) |
658 | *ret_size = l; | |
663996b3 MS |
659 | |
660 | return 0; | |
bb4f798a MB |
661 | |
662 | finalize: | |
663 | if (flags & READ_FULL_FILE_SECURE) | |
664 | explicit_bzero_safe(buf, n); | |
665 | ||
666 | return r; | |
663996b3 MS |
667 | } |
668 | ||
a032b68d MB |
669 | int read_full_file_full( |
670 | int dir_fd, | |
671 | const char *filename, | |
3a6ce677 BR |
672 | uint64_t offset, |
673 | size_t size, | |
a032b68d MB |
674 | ReadFullFileFlags flags, |
675 | const char *bind_name, | |
3a6ce677 BR |
676 | char **ret_contents, |
677 | size_t *ret_size) { | |
a032b68d | 678 | |
e842803a | 679 | _cleanup_fclose_ FILE *f = NULL; |
f2dec872 | 680 | int r; |
e842803a | 681 | |
bb4f798a | 682 | assert(filename); |
3a6ce677 | 683 | assert(ret_contents); |
e842803a | 684 | |
46cdbd49 | 685 | r = xfopenat(dir_fd, filename, "re", 0, &f); |
a10f5d05 MB |
686 | if (r < 0) { |
687 | _cleanup_close_ int dfd = -1, sk = -1; | |
688 | union sockaddr_union sa; | |
689 | ||
690 | /* ENXIO is what Linux returns if we open a node that is an AF_UNIX socket */ | |
691 | if (r != -ENXIO) | |
692 | return r; | |
693 | ||
694 | /* If this is enabled, let's try to connect to it */ | |
695 | if (!FLAGS_SET(flags, READ_FULL_FILE_CONNECT_SOCKET)) | |
696 | return -ENXIO; | |
697 | ||
3a6ce677 BR |
698 | /* Seeking is not supported on AF_UNIX sockets */ |
699 | if (offset != UINT64_MAX) | |
700 | return -ESPIPE; | |
701 | ||
a10f5d05 MB |
702 | if (dir_fd == AT_FDCWD) |
703 | r = sockaddr_un_set_path(&sa.un, filename); | |
704 | else { | |
705 | char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; | |
706 | ||
707 | /* If we shall operate relative to some directory, then let's use O_PATH first to | |
708 | * open the socket inode, and then connect to it via /proc/self/fd/. We have to do | |
709 | * this since there's not connectat() that takes a directory fd as first arg. */ | |
710 | ||
711 | dfd = openat(dir_fd, filename, O_PATH|O_CLOEXEC); | |
712 | if (dfd < 0) | |
713 | return -errno; | |
714 | ||
715 | xsprintf(procfs_path, "/proc/self/fd/%i", dfd); | |
716 | r = sockaddr_un_set_path(&sa.un, procfs_path); | |
717 | } | |
718 | if (r < 0) | |
719 | return r; | |
720 | ||
721 | sk = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); | |
722 | if (sk < 0) | |
723 | return -errno; | |
724 | ||
a032b68d MB |
725 | if (bind_name) { |
726 | /* If the caller specified a socket name to bind to, do so before connecting. This is | |
727 | * useful to communicate some minor, short meta-information token from the client to | |
728 | * the server. */ | |
729 | union sockaddr_union bsa; | |
730 | ||
731 | r = sockaddr_un_set_path(&bsa.un, bind_name); | |
732 | if (r < 0) | |
733 | return r; | |
734 | ||
735 | if (bind(sk, &bsa.sa, r) < 0) | |
736 | return r; | |
737 | } | |
738 | ||
a10f5d05 MB |
739 | if (connect(sk, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) |
740 | return errno == ENOTSOCK ? -ENXIO : -errno; /* propagate original error if this is | |
741 | * not a socket after all */ | |
742 | ||
743 | if (shutdown(sk, SHUT_WR) < 0) | |
744 | return -errno; | |
745 | ||
746 | f = fdopen(sk, "r"); | |
747 | if (!f) | |
748 | return -errno; | |
749 | ||
750 | TAKE_FD(sk); | |
751 | } | |
52ad194e | 752 | |
46cdbd49 BR |
753 | (void) __fsetlocking(f, FSETLOCKING_BYCALLER); |
754 | ||
3a6ce677 | 755 | return read_full_stream_full(f, filename, offset, size, flags, ret_contents, ret_size); |
e842803a MB |
756 | } |
757 | ||
14228c0d | 758 | int executable_is_script(const char *path, char **interpreter) { |
e842803a | 759 | _cleanup_free_ char *line = NULL; |
1d42b86d | 760 | size_t len; |
14228c0d | 761 | char *ans; |
1d42b86d | 762 | int r; |
14228c0d MB |
763 | |
764 | assert(path); | |
765 | ||
766 | r = read_one_line_file(path, &line); | |
1d42b86d MB |
767 | if (r == -ENOBUFS) /* First line overly long? if so, then it's not a script */ |
768 | return 0; | |
14228c0d MB |
769 | if (r < 0) |
770 | return r; | |
771 | ||
772 | if (!startswith(line, "#!")) | |
773 | return 0; | |
774 | ||
775 | ans = strstrip(line + 2); | |
776 | len = strcspn(ans, " \t"); | |
777 | ||
778 | if (len == 0) | |
779 | return 0; | |
780 | ||
781 | ans = strndup(ans, len); | |
782 | if (!ans) | |
783 | return -ENOMEM; | |
784 | ||
785 | *interpreter = ans; | |
786 | return 1; | |
787 | } | |
788 | ||
789 | /** | |
790 | * Retrieve one field from a file like /proc/self/status. pattern | |
6300502b MP |
791 | * should not include whitespace or the delimiter (':'). pattern matches only |
792 | * the beginning of a line. Whitespace before ':' is skipped. Whitespace and | |
793 | * zeros after the ':' will be skipped. field must be freed afterwards. | |
794 | * terminator specifies the terminating characters of the field value (not | |
795 | * included in the value). | |
14228c0d | 796 | */ |
6300502b | 797 | int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) { |
14228c0d | 798 | _cleanup_free_ char *status = NULL; |
7035cd9e | 799 | char *t, *f; |
14228c0d MB |
800 | size_t len; |
801 | int r; | |
802 | ||
6300502b | 803 | assert(terminator); |
14228c0d | 804 | assert(filename); |
60f067b4 | 805 | assert(pattern); |
14228c0d MB |
806 | assert(field); |
807 | ||
e1f67bc7 | 808 | r = read_full_virtual_file(filename, &status, NULL); |
14228c0d MB |
809 | if (r < 0) |
810 | return r; | |
811 | ||
6300502b MP |
812 | t = status; |
813 | ||
814 | do { | |
815 | bool pattern_ok; | |
816 | ||
817 | do { | |
818 | t = strstr(t, pattern); | |
819 | if (!t) | |
820 | return -ENOENT; | |
821 | ||
822 | /* Check that pattern occurs in beginning of line. */ | |
823 | pattern_ok = (t == status || t[-1] == '\n'); | |
824 | ||
825 | t += strlen(pattern); | |
826 | ||
827 | } while (!pattern_ok); | |
828 | ||
829 | t += strspn(t, " \t"); | |
830 | if (!*t) | |
831 | return -ENOENT; | |
832 | ||
833 | } while (*t != ':'); | |
834 | ||
835 | t++; | |
14228c0d | 836 | |
14228c0d MB |
837 | if (*t) { |
838 | t += strspn(t, " \t"); | |
839 | ||
840 | /* Also skip zeros, because when this is used for | |
841 | * capabilities, we don't want the zeros. This way the | |
842 | * same capability set always maps to the same string, | |
843 | * irrespective of the total capability set size. For | |
844 | * other numbers it shouldn't matter. */ | |
845 | t += strspn(t, "0"); | |
846 | /* Back off one char if there's nothing but whitespace | |
847 | and zeros */ | |
848 | if (!*t || isspace(*t)) | |
aa27b158 | 849 | t--; |
14228c0d MB |
850 | } |
851 | ||
6300502b | 852 | len = strcspn(t, terminator); |
14228c0d | 853 | |
7035cd9e MP |
854 | f = strndup(t, len); |
855 | if (!f) | |
14228c0d MB |
856 | return -ENOMEM; |
857 | ||
7035cd9e | 858 | *field = f; |
14228c0d MB |
859 | return 0; |
860 | } | |
db2df898 MP |
861 | |
862 | DIR *xopendirat(int fd, const char *name, int flags) { | |
863 | int nfd; | |
864 | DIR *d; | |
865 | ||
866 | assert(!(flags & O_CREAT)); | |
867 | ||
868 | nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0); | |
869 | if (nfd < 0) | |
870 | return NULL; | |
871 | ||
872 | d = fdopendir(nfd); | |
873 | if (!d) { | |
874 | safe_close(nfd); | |
875 | return NULL; | |
876 | } | |
877 | ||
878 | return d; | |
879 | } | |
880 | ||
46cdbd49 BR |
881 | static int mode_to_flags(const char *mode) { |
882 | const char *p; | |
883 | int flags; | |
884 | ||
885 | if ((p = startswith(mode, "r+"))) | |
886 | flags = O_RDWR; | |
887 | else if ((p = startswith(mode, "r"))) | |
888 | flags = O_RDONLY; | |
889 | else if ((p = startswith(mode, "w+"))) | |
890 | flags = O_RDWR|O_CREAT|O_TRUNC; | |
891 | else if ((p = startswith(mode, "w"))) | |
892 | flags = O_WRONLY|O_CREAT|O_TRUNC; | |
893 | else if ((p = startswith(mode, "a+"))) | |
894 | flags = O_RDWR|O_CREAT|O_APPEND; | |
895 | else if ((p = startswith(mode, "a"))) | |
896 | flags = O_WRONLY|O_CREAT|O_APPEND; | |
897 | else | |
898 | return -EINVAL; | |
899 | ||
900 | for (; *p != 0; p++) { | |
901 | ||
902 | switch (*p) { | |
903 | ||
904 | case 'e': | |
905 | flags |= O_CLOEXEC; | |
906 | break; | |
907 | ||
908 | case 'x': | |
909 | flags |= O_EXCL; | |
910 | break; | |
911 | ||
912 | case 'm': | |
913 | /* ignore this here, fdopen() might care later though */ | |
914 | break; | |
915 | ||
916 | case 'c': /* not sure what to do about this one */ | |
917 | default: | |
918 | return -EINVAL; | |
919 | } | |
920 | } | |
921 | ||
922 | return flags; | |
923 | } | |
924 | ||
925 | int xfopenat(int dir_fd, const char *path, const char *mode, int flags, FILE **ret) { | |
926 | FILE *f; | |
927 | ||
928 | /* A combination of fopen() with openat() */ | |
929 | ||
930 | if (dir_fd == AT_FDCWD && flags == 0) { | |
931 | f = fopen(path, mode); | |
932 | if (!f) | |
933 | return -errno; | |
934 | } else { | |
935 | int fd, mode_flags; | |
936 | ||
937 | mode_flags = mode_to_flags(mode); | |
938 | if (mode_flags < 0) | |
939 | return mode_flags; | |
940 | ||
941 | fd = openat(dir_fd, path, mode_flags | flags); | |
942 | if (fd < 0) | |
943 | return -errno; | |
944 | ||
945 | f = fdopen(fd, mode); | |
946 | if (!f) { | |
947 | safe_close(fd); | |
948 | return -errno; | |
949 | } | |
950 | } | |
951 | ||
952 | *ret = f; | |
953 | return 0; | |
954 | } | |
955 | ||
8b3d4ff0 MB |
956 | static int search_and_fopen_internal( |
957 | const char *path, | |
958 | const char *mode, | |
959 | const char *root, | |
960 | char **search, | |
961 | FILE **ret, | |
962 | char **ret_path) { | |
963 | ||
db2df898 MP |
964 | char **i; |
965 | ||
966 | assert(path); | |
967 | assert(mode); | |
8b3d4ff0 | 968 | assert(ret); |
db2df898 MP |
969 | |
970 | if (!path_strv_resolve_uniq(search, root)) | |
971 | return -ENOMEM; | |
972 | ||
973 | STRV_FOREACH(i, search) { | |
974 | _cleanup_free_ char *p = NULL; | |
975 | FILE *f; | |
976 | ||
f2dec872 | 977 | p = path_join(root, *i, path); |
db2df898 MP |
978 | if (!p) |
979 | return -ENOMEM; | |
980 | ||
981 | f = fopen(p, mode); | |
982 | if (f) { | |
8b3d4ff0 MB |
983 | if (ret_path) |
984 | *ret_path = path_simplify(TAKE_PTR(p)); | |
985 | ||
986 | *ret = f; | |
db2df898 MP |
987 | return 0; |
988 | } | |
989 | ||
990 | if (errno != ENOENT) | |
991 | return -errno; | |
992 | } | |
993 | ||
994 | return -ENOENT; | |
995 | } | |
996 | ||
8b3d4ff0 MB |
997 | int search_and_fopen( |
998 | const char *filename, | |
999 | const char *mode, | |
1000 | const char *root, | |
1001 | const char **search, | |
1002 | FILE **ret, | |
1003 | char **ret_path) { | |
1004 | ||
db2df898 MP |
1005 | _cleanup_strv_free_ char **copy = NULL; |
1006 | ||
8b3d4ff0 | 1007 | assert(filename); |
db2df898 | 1008 | assert(mode); |
8b3d4ff0 | 1009 | assert(ret); |
db2df898 | 1010 | |
8b3d4ff0 MB |
1011 | if (path_is_absolute(filename)) { |
1012 | _cleanup_fclose_ FILE *f = NULL; | |
db2df898 | 1013 | |
8b3d4ff0 MB |
1014 | f = fopen(filename, mode); |
1015 | if (!f) | |
1016 | return -errno; | |
1017 | ||
1018 | if (ret_path) { | |
1019 | char *p; | |
1020 | ||
1021 | p = strdup(filename); | |
1022 | if (!p) | |
1023 | return -ENOMEM; | |
1024 | ||
1025 | *ret_path = path_simplify(p); | |
db2df898 MP |
1026 | } |
1027 | ||
8b3d4ff0 MB |
1028 | *ret = TAKE_PTR(f); |
1029 | return 0; | |
db2df898 MP |
1030 | } |
1031 | ||
1032 | copy = strv_copy((char**) search); | |
1033 | if (!copy) | |
1034 | return -ENOMEM; | |
1035 | ||
8b3d4ff0 | 1036 | return search_and_fopen_internal(filename, mode, root, copy, ret, ret_path); |
db2df898 MP |
1037 | } |
1038 | ||
8b3d4ff0 MB |
1039 | int search_and_fopen_nulstr( |
1040 | const char *filename, | |
1041 | const char *mode, | |
1042 | const char *root, | |
1043 | const char *search, | |
1044 | FILE **ret, | |
1045 | char **ret_path) { | |
1046 | ||
db2df898 MP |
1047 | _cleanup_strv_free_ char **s = NULL; |
1048 | ||
8b3d4ff0 MB |
1049 | if (path_is_absolute(filename)) { |
1050 | _cleanup_fclose_ FILE *f = NULL; | |
db2df898 | 1051 | |
8b3d4ff0 MB |
1052 | f = fopen(filename, mode); |
1053 | if (!f) | |
1054 | return -errno; | |
1055 | ||
1056 | if (ret_path) { | |
1057 | char *p; | |
1058 | ||
1059 | p = strdup(filename); | |
1060 | if (!p) | |
1061 | return -ENOMEM; | |
1062 | ||
1063 | *ret_path = path_simplify(p); | |
db2df898 MP |
1064 | } |
1065 | ||
8b3d4ff0 MB |
1066 | *ret = TAKE_PTR(f); |
1067 | return 0; | |
db2df898 MP |
1068 | } |
1069 | ||
1070 | s = strv_split_nulstr(search); | |
1071 | if (!s) | |
1072 | return -ENOMEM; | |
1073 | ||
8b3d4ff0 | 1074 | return search_and_fopen_internal(filename, mode, root, s, ret, ret_path); |
db2df898 MP |
1075 | } |
1076 | ||
a032b68d MB |
1077 | int chase_symlinks_and_fopen_unlocked( |
1078 | const char *path, | |
1079 | const char *root, | |
1080 | unsigned chase_flags, | |
1081 | const char *open_flags, | |
1082 | FILE **ret_file, | |
1083 | char **ret_path) { | |
1084 | ||
1085 | _cleanup_close_ int fd = -1; | |
1086 | _cleanup_free_ char *final_path = NULL; | |
1087 | int mode_flags, r; | |
a032b68d MB |
1088 | |
1089 | assert(path); | |
1090 | assert(open_flags); | |
1091 | assert(ret_file); | |
1092 | ||
1093 | mode_flags = mode_to_flags(open_flags); | |
1094 | if (mode_flags < 0) | |
1095 | return mode_flags; | |
1096 | ||
1097 | fd = chase_symlinks_and_open(path, root, chase_flags, mode_flags, ret_path ? &final_path : NULL); | |
1098 | if (fd < 0) | |
1099 | return fd; | |
1100 | ||
5b5a102a | 1101 | r = take_fdopen_unlocked(&fd, open_flags, ret_file); |
a032b68d MB |
1102 | if (r < 0) |
1103 | return r; | |
a032b68d | 1104 | |
a032b68d MB |
1105 | if (ret_path) |
1106 | *ret_path = TAKE_PTR(final_path); | |
1107 | return 0; | |
1108 | } | |
1109 | ||
db2df898 MP |
1110 | int fflush_and_check(FILE *f) { |
1111 | assert(f); | |
1112 | ||
1113 | errno = 0; | |
1114 | fflush(f); | |
1115 | ||
1116 | if (ferror(f)) | |
f2dec872 | 1117 | return errno_or_else(EIO); |
db2df898 MP |
1118 | |
1119 | return 0; | |
1120 | } | |
1121 | ||
f5e65279 | 1122 | int fflush_sync_and_check(FILE *f) { |
d0648cfe | 1123 | int r, fd; |
f5e65279 MB |
1124 | |
1125 | assert(f); | |
1126 | ||
1127 | r = fflush_and_check(f); | |
1128 | if (r < 0) | |
1129 | return r; | |
1130 | ||
d0648cfe MB |
1131 | /* Not all file streams have an fd associated (think: fmemopen()), let's handle this gracefully and |
1132 | * assume that in that case we need no explicit syncing */ | |
1133 | fd = fileno(f); | |
1134 | if (fd < 0) | |
1135 | return 0; | |
1136 | ||
1137 | if (fsync(fd) < 0) | |
f5e65279 MB |
1138 | return -errno; |
1139 | ||
d0648cfe | 1140 | r = fsync_directory_of_file(fd); |
98393f85 MB |
1141 | if (r < 0) |
1142 | return r; | |
1143 | ||
f5e65279 MB |
1144 | return 0; |
1145 | } | |
1146 | ||
db2df898 MP |
1147 | int write_timestamp_file_atomic(const char *fn, usec_t n) { |
1148 | char ln[DECIMAL_STR_MAX(n)+2]; | |
1149 | ||
1150 | /* Creates a "timestamp" file, that contains nothing but a | |
1151 | * usec_t timestamp, formatted in ASCII. */ | |
1152 | ||
1153 | if (n <= 0 || n >= USEC_INFINITY) | |
1154 | return -ERANGE; | |
1155 | ||
1156 | xsprintf(ln, USEC_FMT "\n", n); | |
1157 | ||
1158 | return write_string_file(fn, ln, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC); | |
1159 | } | |
1160 | ||
1161 | int read_timestamp_file(const char *fn, usec_t *ret) { | |
1162 | _cleanup_free_ char *ln = NULL; | |
1163 | uint64_t t; | |
1164 | int r; | |
1165 | ||
1166 | r = read_one_line_file(fn, &ln); | |
1167 | if (r < 0) | |
1168 | return r; | |
1169 | ||
1170 | r = safe_atou64(ln, &t); | |
1171 | if (r < 0) | |
1172 | return r; | |
1173 | ||
1174 | if (t <= 0 || t >= (uint64_t) USEC_INFINITY) | |
1175 | return -ERANGE; | |
1176 | ||
1177 | *ret = (usec_t) t; | |
1178 | return 0; | |
1179 | } | |
4c89c718 MP |
1180 | |
1181 | int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space) { | |
1182 | int r; | |
1183 | ||
1184 | assert(s); | |
1185 | ||
1186 | /* Outputs the specified string with fputs(), but optionally prefixes it with a separator. The *space parameter | |
1187 | * when specified shall initially point to a boolean variable initialized to false. It is set to true after the | |
1188 | * first invocation. This call is supposed to be use in loops, where a separator shall be inserted between each | |
1189 | * element, but not before the first one. */ | |
1190 | ||
1191 | if (!f) | |
1192 | f = stdout; | |
1193 | ||
1194 | if (space) { | |
1195 | if (!separator) | |
1196 | separator = " "; | |
1197 | ||
1198 | if (*space) { | |
1199 | r = fputs(separator, f); | |
1200 | if (r < 0) | |
1201 | return r; | |
1202 | } | |
1203 | ||
1204 | *space = true; | |
1205 | } | |
1206 | ||
1207 | return fputs(s, f); | |
1208 | } | |
aa27b158 | 1209 | |
6e866b33 MB |
1210 | /* A bitmask of the EOL markers we know */ |
1211 | typedef enum EndOfLineMarker { | |
1212 | EOL_NONE = 0, | |
1213 | EOL_ZERO = 1 << 0, /* \0 (aka NUL) */ | |
1214 | EOL_TEN = 1 << 1, /* \n (aka NL, aka LF) */ | |
1215 | EOL_THIRTEEN = 1 << 2, /* \r (aka CR) */ | |
1216 | } EndOfLineMarker; | |
aa27b158 | 1217 | |
6e866b33 | 1218 | static EndOfLineMarker categorize_eol(char c, ReadLineFlags flags) { |
aa27b158 | 1219 | |
6e866b33 MB |
1220 | if (!IN_SET(flags, READ_LINE_ONLY_NUL)) { |
1221 | if (c == '\n') | |
1222 | return EOL_TEN; | |
1223 | if (c == '\r') | |
1224 | return EOL_THIRTEEN; | |
aa27b158 | 1225 | } |
aa27b158 | 1226 | |
6e866b33 MB |
1227 | if (c == '\0') |
1228 | return EOL_ZERO; | |
2897b343 | 1229 | |
6e866b33 | 1230 | return EOL_NONE; |
2897b343 | 1231 | } |
f5e65279 | 1232 | |
3a6ce677 | 1233 | DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(FILE*, funlockfile, NULL); |
f5e65279 | 1234 | |
6e866b33 | 1235 | int read_line_full(FILE *f, size_t limit, ReadLineFlags flags, char **ret) { |
6e866b33 | 1236 | _cleanup_free_ char *buffer = NULL; |
8b3d4ff0 | 1237 | size_t n = 0, count = 0; |
d0648cfe | 1238 | int r; |
f5e65279 MB |
1239 | |
1240 | assert(f); | |
1241 | ||
1242 | /* Something like a bounded version of getline(). | |
1243 | * | |
6e866b33 MB |
1244 | * Considers EOF, \n, \r and \0 end of line delimiters (or combinations of these), and does not include these |
1245 | * delimiters in the string returned. Specifically, recognizes the following combinations of markers as line | |
1246 | * endings: | |
1247 | * | |
1248 | * • \n (UNIX) | |
1249 | * • \r (old MacOS) | |
1250 | * • \0 (C strings) | |
1251 | * • \n\0 | |
1252 | * • \r\0 | |
1253 | * • \r\n (Windows) | |
1254 | * • \n\r | |
1255 | * • \r\n\0 | |
1256 | * • \n\r\0 | |
f5e65279 MB |
1257 | * |
1258 | * Returns the number of bytes read from the files (i.e. including delimiters — this hence usually differs from | |
1259 | * the number of characters in the returned string). When EOF is hit, 0 is returned. | |
1260 | * | |
1261 | * The input parameter limit is the maximum numbers of characters in the returned string, i.e. excluding | |
1262 | * delimiters. If the limit is hit we fail and return -ENOBUFS. | |
1263 | * | |
1264 | * If a line shall be skipped ret may be initialized as NULL. */ | |
1265 | ||
1266 | if (ret) { | |
8b3d4ff0 | 1267 | if (!GREEDY_REALLOC(buffer, 1)) |
f5e65279 MB |
1268 | return -ENOMEM; |
1269 | } | |
1270 | ||
1271 | { | |
52ad194e | 1272 | _unused_ _cleanup_(funlockfilep) FILE *flocked = f; |
6e866b33 | 1273 | EndOfLineMarker previous_eol = EOL_NONE; |
f5e65279 MB |
1274 | flockfile(f); |
1275 | ||
1276 | for (;;) { | |
6e866b33 MB |
1277 | EndOfLineMarker eol; |
1278 | char c; | |
f5e65279 MB |
1279 | |
1280 | if (n >= limit) | |
1281 | return -ENOBUFS; | |
1282 | ||
6e866b33 MB |
1283 | if (count >= INT_MAX) /* We couldn't return the counter anymore as "int", hence refuse this */ |
1284 | return -ENOBUFS; | |
f5e65279 | 1285 | |
6e866b33 MB |
1286 | r = safe_fgetc(f, &c); |
1287 | if (r < 0) | |
1288 | return r; | |
1289 | if (r == 0) /* EOF is definitely EOL */ | |
1290 | break; | |
1291 | ||
1292 | eol = categorize_eol(c, flags); | |
1293 | ||
1294 | if (FLAGS_SET(previous_eol, EOL_ZERO) || | |
1295 | (eol == EOL_NONE && previous_eol != EOL_NONE) || | |
1296 | (eol != EOL_NONE && (previous_eol & eol) != 0)) { | |
1297 | /* Previous char was a NUL? This is not an EOL, but the previous char was? This type of | |
1298 | * EOL marker has been seen right before? In either of these three cases we are | |
1299 | * done. But first, let's put this character back in the queue. (Note that we have to | |
1300 | * cast this to (unsigned char) here as ungetc() expects a positive 'int', and if we | |
1301 | * are on an architecture where 'char' equals 'signed char' we need to ensure we don't | |
1302 | * pass a negative value here. That said, to complicate things further ungetc() is | |
1303 | * actually happy with most negative characters and implicitly casts them back to | |
1304 | * positive ones as needed, except for \xff (aka -1, aka EOF), which it refuses. What a | |
1305 | * godawful API!) */ | |
1306 | assert_se(ungetc((unsigned char) c, f) != EOF); | |
f5e65279 MB |
1307 | break; |
1308 | } | |
1309 | ||
1310 | count++; | |
1311 | ||
f2dec872 | 1312 | if (eol != EOL_NONE) { |
d0648cfe MB |
1313 | /* If we are on a tty, we can't shouldn't wait for more input, because that |
1314 | * generally means waiting for the user, interactively. In the case of a TTY | |
1315 | * we expect only \n as the single EOL marker, so we are in the lucky | |
1316 | * position that there is no need to wait. We check this condition last, to | |
1317 | * avoid isatty() check if not necessary. */ | |
1318 | ||
1319 | if ((flags & (READ_LINE_IS_A_TTY|READ_LINE_NOT_A_TTY)) == 0) { | |
1320 | int fd; | |
1321 | ||
1322 | fd = fileno(f); | |
1323 | if (fd < 0) /* Maybe an fmemopen() stream? Handle this gracefully, | |
1324 | * and don't call isatty() on an invalid fd */ | |
1325 | flags |= READ_LINE_NOT_A_TTY; | |
1326 | else | |
1327 | flags |= isatty(fd) ? READ_LINE_IS_A_TTY : READ_LINE_NOT_A_TTY; | |
1328 | } | |
1329 | if (FLAGS_SET(flags, READ_LINE_IS_A_TTY)) | |
f2dec872 BR |
1330 | break; |
1331 | } | |
1332 | ||
6e866b33 MB |
1333 | if (eol != EOL_NONE) { |
1334 | previous_eol |= eol; | |
1335 | continue; | |
1336 | } | |
f5e65279 MB |
1337 | |
1338 | if (ret) { | |
8b3d4ff0 | 1339 | if (!GREEDY_REALLOC(buffer, n + 2)) |
f5e65279 MB |
1340 | return -ENOMEM; |
1341 | ||
6e866b33 | 1342 | buffer[n] = c; |
f5e65279 MB |
1343 | } |
1344 | ||
1345 | n++; | |
1346 | } | |
1347 | } | |
1348 | ||
1349 | if (ret) { | |
1350 | buffer[n] = 0; | |
1351 | ||
b012e921 | 1352 | *ret = TAKE_PTR(buffer); |
f5e65279 MB |
1353 | } |
1354 | ||
1355 | return (int) count; | |
1356 | } | |
6e866b33 MB |
1357 | |
1358 | int safe_fgetc(FILE *f, char *ret) { | |
1359 | int k; | |
1360 | ||
1361 | assert(f); | |
1362 | ||
1363 | /* A safer version of plain fgetc(): let's propagate the error that happened while reading as such, and | |
1364 | * separate the EOF condition from the byte read, to avoid those confusion signed/unsigned issues fgetc() | |
1365 | * has. */ | |
1366 | ||
1367 | errno = 0; | |
1368 | k = fgetc(f); | |
1369 | if (k == EOF) { | |
1370 | if (ferror(f)) | |
f2dec872 | 1371 | return errno_or_else(EIO); |
6e866b33 MB |
1372 | |
1373 | if (ret) | |
1374 | *ret = 0; | |
1375 | ||
1376 | return 0; | |
1377 | } | |
1378 | ||
1379 | if (ret) | |
1380 | *ret = k; | |
1381 | ||
1382 | return 1; | |
1383 | } | |
bb4f798a MB |
1384 | |
1385 | int warn_file_is_world_accessible(const char *filename, struct stat *st, const char *unit, unsigned line) { | |
1386 | struct stat _st; | |
1387 | ||
1388 | if (!filename) | |
1389 | return 0; | |
1390 | ||
1391 | if (!st) { | |
1392 | if (stat(filename, &_st) < 0) | |
1393 | return -errno; | |
1394 | st = &_st; | |
1395 | } | |
1396 | ||
1397 | if ((st->st_mode & S_IRWXO) == 0) | |
1398 | return 0; | |
1399 | ||
1400 | if (unit) | |
1401 | log_syntax(unit, LOG_WARNING, filename, line, 0, | |
e1f67bc7 | 1402 | "%s has %04o mode that is too permissive, please adjust the ownership and access mode.", |
bb4f798a MB |
1403 | filename, st->st_mode & 07777); |
1404 | else | |
e1f67bc7 | 1405 | log_warning("%s has %04o mode that is too permissive, please adjust the ownership and access mode.", |
bb4f798a MB |
1406 | filename, st->st_mode & 07777); |
1407 | return 0; | |
1408 | } | |
a10f5d05 | 1409 | |
a10f5d05 MB |
1410 | int rename_and_apply_smack_floor_label(const char *from, const char *to) { |
1411 | int r = 0; | |
1412 | if (rename(from, to) < 0) | |
1413 | return -errno; | |
1414 | ||
8b3d4ff0 | 1415 | #if HAVE_SMACK_RUN_LABEL |
a10f5d05 MB |
1416 | r = mac_smack_apply(to, SMACK_ATTR_ACCESS, SMACK_FLOOR_LABEL); |
1417 | if (r < 0) | |
1418 | return r; | |
1419 | #endif | |
1420 | return r; | |
1421 | } |