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