]>
Commit | Line | Data |
---|---|---|
cc73685d | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
37ef15bb | 2 | |
d38dd64a CB |
3 | #ifndef _GNU_SOURCE |
4 | #define _GNU_SOURCE 1 | |
5 | #endif | |
37ef15bb CB |
6 | #include <errno.h> |
7 | #include <fcntl.h> | |
8 | #include <linux/magic.h> | |
e1e08f39 | 9 | #include <stdio.h> |
37ef15bb | 10 | #include <stdlib.h> |
7c4d9466 | 11 | #include <sys/sendfile.h> |
07d1f84a | 12 | #include <sys/stat.h> |
37ef15bb | 13 | #include <sys/types.h> |
07d1f84a | 14 | #include <time.h> |
37ef15bb | 15 | |
d38dd64a | 16 | #include "config.h" |
37ef15bb | 17 | #include "file_utils.h" |
37ef15bb | 18 | #include "macro.h" |
4aa90f60 | 19 | #include "memory_utils.h" |
6400238d | 20 | #include "string_utils.h" |
8ea93a0f | 21 | #include "syscall_wrappers.h" |
4aa90f60 | 22 | #include "utils.h" |
37ef15bb | 23 | |
c04a6d4e CB |
24 | int lxc_open_dirfd(const char *dir) |
25 | { | |
1973b62a | 26 | return open(dir, O_DIRECTORY | O_RDONLY | O_CLOEXEC | O_NOFOLLOW); |
c04a6d4e CB |
27 | } |
28 | ||
29 | int lxc_readat(int dirfd, const char *filename, void *buf, size_t count) | |
30 | { | |
f62cf1d4 | 31 | __do_close int fd = -EBADF; |
c04a6d4e CB |
32 | ssize_t ret; |
33 | ||
34 | fd = openat(dirfd, filename, O_RDONLY | O_CLOEXEC); | |
35 | if (fd < 0) | |
36 | return -1; | |
37 | ||
38 | ret = lxc_read_nointr(fd, buf, count); | |
39 | if (ret < 0 || (size_t)ret != count) | |
40 | return -1; | |
41 | ||
42 | return 0; | |
43 | } | |
44 | ||
bad788b0 CB |
45 | int lxc_writeat(int dirfd, const char *filename, const void *buf, size_t count) |
46 | { | |
f62cf1d4 | 47 | __do_close int fd = -EBADF; |
bad788b0 CB |
48 | ssize_t ret; |
49 | ||
ef6d231f CB |
50 | fd = openat(dirfd, filename, |
51 | O_WRONLY | O_CLOEXEC | O_NOCTTY | O_NOFOLLOW); | |
bad788b0 CB |
52 | if (fd < 0) |
53 | return -1; | |
54 | ||
55 | ret = lxc_write_nointr(fd, buf, count); | |
56 | if (ret < 0 || (size_t)ret != count) | |
57 | return -1; | |
58 | ||
59 | return 0; | |
60 | } | |
61 | ||
c04a6d4e CB |
62 | int lxc_write_openat(const char *dir, const char *filename, const void *buf, |
63 | size_t count) | |
64 | { | |
f62cf1d4 | 65 | __do_close int dirfd = -EBADF; |
c04a6d4e | 66 | |
ef6d231f | 67 | dirfd = open(dir, O_DIRECTORY | O_RDONLY | O_CLOEXEC | O_NOCTTY | O_NOFOLLOW); |
c04a6d4e CB |
68 | if (dirfd < 0) |
69 | return -1; | |
70 | ||
71 | return lxc_writeat(dirfd, filename, buf, count); | |
72 | } | |
73 | ||
37ef15bb CB |
74 | int lxc_write_to_file(const char *filename, const void *buf, size_t count, |
75 | bool add_newline, mode_t mode) | |
76 | { | |
f62cf1d4 | 77 | __do_close int fd = -EBADF; |
37ef15bb CB |
78 | ssize_t ret; |
79 | ||
80 | fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode); | |
81 | if (fd < 0) | |
82 | return -1; | |
83 | ||
84 | ret = lxc_write_nointr(fd, buf, count); | |
85 | if (ret < 0) | |
1dc51604 | 86 | return -1; |
37ef15bb CB |
87 | |
88 | if ((size_t)ret != count) | |
1dc51604 | 89 | return -1; |
37ef15bb CB |
90 | |
91 | if (add_newline) { | |
92 | ret = lxc_write_nointr(fd, "\n", 1); | |
93 | if (ret != 1) | |
1dc51604 | 94 | return -1; |
37ef15bb CB |
95 | } |
96 | ||
37ef15bb | 97 | return 0; |
37ef15bb CB |
98 | } |
99 | ||
100 | int lxc_read_from_file(const char *filename, void *buf, size_t count) | |
101 | { | |
f62cf1d4 | 102 | __do_close int fd = -EBADF; |
37ef15bb CB |
103 | ssize_t ret; |
104 | ||
105 | fd = open(filename, O_RDONLY | O_CLOEXEC); | |
106 | if (fd < 0) | |
107 | return -1; | |
108 | ||
109 | if (!buf || !count) { | |
110 | char buf2[100]; | |
111 | size_t count2 = 0; | |
112 | ||
113 | while ((ret = lxc_read_nointr(fd, buf2, 100)) > 0) | |
114 | count2 += ret; | |
115 | ||
116 | if (ret >= 0) | |
117 | ret = count2; | |
118 | } else { | |
119 | memset(buf, 0, count); | |
120 | ret = lxc_read_nointr(fd, buf, count); | |
121 | } | |
122 | ||
37ef15bb CB |
123 | return ret; |
124 | } | |
125 | ||
126 | ssize_t lxc_write_nointr(int fd, const void *buf, size_t count) | |
127 | { | |
128 | ssize_t ret; | |
1dc51604 CB |
129 | |
130 | do { | |
131 | ret = write(fd, buf, count); | |
132 | } while (ret < 0 && errno == EINTR); | |
37ef15bb CB |
133 | |
134 | return ret; | |
135 | } | |
136 | ||
2120b89b CB |
137 | ssize_t lxc_pwrite_nointr(int fd, const void *buf, size_t count, off_t offset) |
138 | { | |
139 | ssize_t ret; | |
140 | ||
141 | do { | |
142 | ret = pwrite(fd, buf, count, offset); | |
143 | } while (ret < 0 && errno == EINTR); | |
144 | ||
145 | return ret; | |
146 | } | |
147 | ||
28143f88 CB |
148 | ssize_t lxc_send_nointr(int sockfd, void *buf, size_t len, int flags) |
149 | { | |
150 | ssize_t ret; | |
1dc51604 CB |
151 | |
152 | do { | |
153 | ret = send(sockfd, buf, len, flags); | |
154 | } while (ret < 0 && errno == EINTR); | |
28143f88 CB |
155 | |
156 | return ret; | |
157 | } | |
158 | ||
37ef15bb CB |
159 | ssize_t lxc_read_nointr(int fd, void *buf, size_t count) |
160 | { | |
161 | ssize_t ret; | |
1dc51604 CB |
162 | |
163 | do { | |
164 | ret = read(fd, buf, count); | |
165 | } while (ret < 0 && errno == EINTR); | |
37ef15bb CB |
166 | |
167 | return ret; | |
168 | } | |
169 | ||
de69edd1 CB |
170 | ssize_t lxc_recv_nointr(int sockfd, void *buf, size_t len, int flags) |
171 | { | |
172 | ssize_t ret; | |
1dc51604 CB |
173 | |
174 | do { | |
175 | ret = recv(sockfd, buf, len, flags); | |
176 | } while (ret < 0 && errno == EINTR); | |
de69edd1 CB |
177 | |
178 | return ret; | |
179 | } | |
180 | ||
99d03dec WB |
181 | ssize_t lxc_recvmsg_nointr_iov(int sockfd, struct iovec *iov, size_t iovlen, |
182 | int flags) | |
183 | { | |
184 | ssize_t ret; | |
1dc51604 CB |
185 | struct msghdr msg = { |
186 | .msg_iov = iov, | |
187 | .msg_iovlen = iovlen, | |
188 | }; | |
99d03dec | 189 | |
1dc51604 CB |
190 | do { |
191 | ret = recvmsg(sockfd, &msg, flags); | |
192 | } while (ret < 0 && errno == EINTR); | |
99d03dec WB |
193 | |
194 | return ret; | |
195 | } | |
196 | ||
1dc51604 CB |
197 | ssize_t lxc_read_nointr_expect(int fd, void *buf, size_t count, |
198 | const void *expected_buf) | |
37ef15bb CB |
199 | { |
200 | ssize_t ret; | |
201 | ||
202 | ret = lxc_read_nointr(fd, buf, count); | |
6509154d | 203 | if (ret < 0) |
37ef15bb CB |
204 | return ret; |
205 | ||
206 | if ((size_t)ret != count) | |
207 | return -1; | |
208 | ||
1dc51604 CB |
209 | if (expected_buf && memcmp(buf, expected_buf, count) != 0) |
210 | return ret_set_errno(-1, EINVAL); | |
37ef15bb | 211 | |
6509154d | 212 | return 0; |
213 | } | |
214 | ||
1dc51604 CB |
215 | ssize_t lxc_read_file_expect(const char *path, void *buf, size_t count, |
216 | const void *expected_buf) | |
6509154d | 217 | { |
f62cf1d4 | 218 | __do_close int fd = -EBADF; |
6509154d | 219 | |
220 | fd = open(path, O_RDONLY | O_CLOEXEC); | |
221 | if (fd < 0) | |
222 | return -1; | |
223 | ||
224 | return lxc_read_nointr_expect(fd, buf, count, expected_buf); | |
37ef15bb CB |
225 | } |
226 | ||
227 | bool file_exists(const char *f) | |
228 | { | |
229 | struct stat statbuf; | |
230 | ||
231 | return stat(f, &statbuf) == 0; | |
232 | } | |
233 | ||
234 | int print_to_file(const char *file, const char *content) | |
235 | { | |
1dc51604 | 236 | __do_fclose FILE *f = NULL; |
37ef15bb CB |
237 | int ret = 0; |
238 | ||
4110345b | 239 | f = fopen(file, "we"); |
37ef15bb CB |
240 | if (!f) |
241 | return -1; | |
242 | ||
243 | if (fprintf(f, "%s", content) != strlen(content)) | |
244 | ret = -1; | |
245 | ||
37ef15bb CB |
246 | return ret; |
247 | } | |
248 | ||
249 | int is_dir(const char *path) | |
250 | { | |
37ef15bb | 251 | int ret; |
1dc51604 | 252 | struct stat statbuf; |
37ef15bb CB |
253 | |
254 | ret = stat(path, &statbuf); | |
255 | if (ret == 0 && S_ISDIR(statbuf.st_mode)) | |
256 | return 1; | |
257 | ||
258 | return 0; | |
259 | } | |
260 | ||
261 | /* | |
262 | * Return the number of lines in file @fn, or -1 on error | |
263 | */ | |
264 | int lxc_count_file_lines(const char *fn) | |
265 | { | |
1dc51604 CB |
266 | __do_free char *line = NULL; |
267 | __do_fclose FILE *f = NULL; | |
37ef15bb CB |
268 | size_t sz = 0; |
269 | int n = 0; | |
270 | ||
271 | f = fopen_cloexec(fn, "r"); | |
272 | if (!f) | |
273 | return -1; | |
274 | ||
1dc51604 | 275 | while (getline(&line, &sz, f) != -1) |
37ef15bb | 276 | n++; |
37ef15bb | 277 | |
37ef15bb CB |
278 | return n; |
279 | } | |
280 | ||
281 | int lxc_make_tmpfile(char *template, bool rm) | |
282 | { | |
f62cf1d4 | 283 | __do_close int fd = -EBADF; |
4aa90f60 | 284 | int ret; |
37ef15bb CB |
285 | mode_t msk; |
286 | ||
287 | msk = umask(0022); | |
288 | fd = mkstemp(template); | |
289 | umask(msk); | |
290 | if (fd < 0) | |
291 | return -1; | |
292 | ||
4aa90f60 CB |
293 | if (lxc_set_cloexec(fd)) |
294 | return -1; | |
295 | ||
37ef15bb | 296 | if (!rm) |
240fecd0 | 297 | return move_fd(fd); |
37ef15bb CB |
298 | |
299 | ret = unlink(template); | |
4aa90f60 | 300 | if (ret < 0) |
37ef15bb | 301 | return -1; |
37ef15bb | 302 | |
240fecd0 | 303 | return move_fd(fd); |
37ef15bb CB |
304 | } |
305 | ||
37ef15bb CB |
306 | bool is_fs_type(const struct statfs *fs, fs_type_magic magic_val) |
307 | { | |
308 | return (fs->f_type == (fs_type_magic)magic_val); | |
309 | } | |
310 | ||
311 | bool has_fs_type(const char *path, fs_type_magic magic_val) | |
312 | { | |
37ef15bb CB |
313 | int ret; |
314 | struct statfs sb; | |
315 | ||
316 | ret = statfs(path, &sb); | |
317 | if (ret < 0) | |
318 | return false; | |
319 | ||
320 | return is_fs_type(&sb, magic_val); | |
321 | } | |
322 | ||
323 | bool fhas_fs_type(int fd, fs_type_magic magic_val) | |
324 | { | |
325 | int ret; | |
326 | struct statfs sb; | |
327 | ||
328 | ret = fstatfs(fd, &sb); | |
329 | if (ret < 0) | |
330 | return false; | |
331 | ||
332 | return is_fs_type(&sb, magic_val); | |
333 | } | |
334 | ||
335 | FILE *fopen_cloexec(const char *path, const char *mode) | |
336 | { | |
f62cf1d4 | 337 | __do_close int fd = -EBADF; |
1dc51604 CB |
338 | int open_mode = 0, step = 0; |
339 | FILE *f; | |
37ef15bb CB |
340 | |
341 | if (!strncmp(mode, "r+", 2)) { | |
342 | open_mode = O_RDWR; | |
343 | step = 2; | |
344 | } else if (!strncmp(mode, "r", 1)) { | |
345 | open_mode = O_RDONLY; | |
346 | step = 1; | |
347 | } else if (!strncmp(mode, "w+", 2)) { | |
348 | open_mode = O_RDWR | O_TRUNC | O_CREAT; | |
349 | step = 2; | |
350 | } else if (!strncmp(mode, "w", 1)) { | |
351 | open_mode = O_WRONLY | O_TRUNC | O_CREAT; | |
352 | step = 1; | |
353 | } else if (!strncmp(mode, "a+", 2)) { | |
354 | open_mode = O_RDWR | O_CREAT | O_APPEND; | |
355 | step = 2; | |
356 | } else if (!strncmp(mode, "a", 1)) { | |
357 | open_mode = O_WRONLY | O_CREAT | O_APPEND; | |
358 | step = 1; | |
359 | } | |
360 | for (; mode[step]; step++) | |
361 | if (mode[step] == 'x') | |
362 | open_mode |= O_EXCL; | |
37ef15bb | 363 | |
1dc51604 | 364 | fd = open(path, open_mode | O_CLOEXEC, 0660); |
37ef15bb CB |
365 | if (fd < 0) |
366 | return NULL; | |
367 | ||
1dc51604 CB |
368 | f = fdopen(fd, mode); |
369 | if (f) | |
370 | move_fd(fd); | |
371 | return f; | |
37ef15bb | 372 | } |
7c4d9466 CB |
373 | |
374 | ssize_t lxc_sendfile_nointr(int out_fd, int in_fd, off_t *offset, size_t count) | |
375 | { | |
376 | ssize_t ret; | |
377 | ||
1dc51604 CB |
378 | do { |
379 | ret = sendfile(out_fd, in_fd, offset, count); | |
380 | } while (ret < 0 && errno == EINTR); | |
7c4d9466 CB |
381 | |
382 | return ret; | |
383 | } | |
6400238d | 384 | |
26dffd82 | 385 | ssize_t __fd_to_fd(int from, int to) |
4aa90f60 | 386 | { |
26dffd82 CB |
387 | ssize_t total_bytes = 0; |
388 | ||
4aa90f60 CB |
389 | for (;;) { |
390 | uint8_t buf[PATH_MAX]; | |
391 | uint8_t *p = buf; | |
392 | ssize_t bytes_to_write; | |
393 | ssize_t bytes_read; | |
394 | ||
395 | bytes_read = lxc_read_nointr(from, buf, sizeof buf); | |
396 | if (bytes_read < 0) | |
397 | return -1; | |
398 | if (bytes_read == 0) | |
399 | break; | |
400 | ||
401 | bytes_to_write = (size_t)bytes_read; | |
7d84e2cd | 402 | total_bytes += bytes_read; |
4aa90f60 CB |
403 | do { |
404 | ssize_t bytes_written; | |
405 | ||
406 | bytes_written = lxc_write_nointr(to, p, bytes_to_write); | |
407 | if (bytes_written < 0) | |
408 | return -1; | |
409 | ||
410 | bytes_to_write -= bytes_written; | |
411 | p += bytes_written; | |
412 | } while (bytes_to_write > 0); | |
413 | } | |
414 | ||
26dffd82 | 415 | return total_bytes; |
4aa90f60 | 416 | } |
4110345b | 417 | |
2120b89b | 418 | int fd_to_buf(int fd, char **buf, size_t *length) |
4110345b CB |
419 | { |
420 | __do_free char *copy = NULL; | |
421 | ||
422 | if (!length) | |
2120b89b | 423 | return 0; |
4110345b CB |
424 | |
425 | *length = 0; | |
426 | for (;;) { | |
427 | ssize_t bytes_read; | |
2120b89b | 428 | char chunk[4096]; |
4110345b CB |
429 | char *old = copy; |
430 | ||
2120b89b | 431 | bytes_read = lxc_read_nointr(fd, chunk, sizeof(chunk)); |
4110345b | 432 | if (bytes_read < 0) |
2120b89b | 433 | return 0; |
4110345b CB |
434 | |
435 | if (!bytes_read) | |
436 | break; | |
437 | ||
438 | copy = must_realloc(old, (*length + bytes_read) * sizeof(*old)); | |
2120b89b | 439 | memcpy(copy + *length, chunk, bytes_read); |
4110345b CB |
440 | *length += bytes_read; |
441 | } | |
442 | ||
2120b89b CB |
443 | *buf = move_ptr(copy); |
444 | return 0; | |
4110345b CB |
445 | } |
446 | ||
447 | char *file_to_buf(const char *path, size_t *length) | |
448 | { | |
f62cf1d4 | 449 | __do_close int fd = -EBADF; |
2120b89b | 450 | char *buf = NULL; |
4110345b CB |
451 | |
452 | if (!length) | |
453 | return NULL; | |
454 | ||
455 | fd = open(path, O_RDONLY | O_CLOEXEC); | |
456 | if (fd < 0) | |
457 | return NULL; | |
458 | ||
2120b89b CB |
459 | if (fd_to_buf(fd, &buf, length) < 0) |
460 | return NULL; | |
461 | ||
462 | return buf; | |
4110345b CB |
463 | } |
464 | ||
465 | FILE *fopen_cached(const char *path, const char *mode, void **caller_freed_buffer) | |
466 | { | |
7fa90630 | 467 | #ifdef HAVE_FMEMOPEN |
4110345b CB |
468 | __do_free char *buf = NULL; |
469 | size_t len = 0; | |
470 | FILE *f; | |
471 | ||
472 | buf = file_to_buf(path, &len); | |
473 | if (!buf) | |
474 | return NULL; | |
475 | ||
476 | f = fmemopen(buf, len, mode); | |
477 | if (!f) | |
478 | return NULL; | |
479 | *caller_freed_buffer = move_ptr(buf); | |
480 | return f; | |
7fa90630 CB |
481 | #else |
482 | return fopen(path, mode); | |
483 | #endif | |
4110345b CB |
484 | } |
485 | ||
486 | FILE *fdopen_cached(int fd, const char *mode, void **caller_freed_buffer) | |
487 | { | |
7fa90630 CB |
488 | FILE *f; |
489 | #ifdef HAVE_FMEMOPEN | |
4110345b CB |
490 | __do_free char *buf = NULL; |
491 | size_t len = 0; | |
4110345b | 492 | |
2120b89b | 493 | if (fd_to_buf(fd, &buf, &len) < 0) |
4110345b CB |
494 | return NULL; |
495 | ||
496 | f = fmemopen(buf, len, mode); | |
497 | if (!f) | |
498 | return NULL; | |
499 | ||
500 | *caller_freed_buffer = move_ptr(buf); | |
7fa90630 CB |
501 | |
502 | #else | |
503 | ||
f62cf1d4 | 504 | __do_close int dupfd = -EBADF; |
7fa90630 CB |
505 | |
506 | dupfd = dup(fd); | |
507 | if (dupfd < 0) | |
508 | return NULL; | |
509 | ||
510 | f = fdopen(dupfd, "re"); | |
511 | if (!f) | |
512 | return NULL; | |
513 | ||
514 | /* Transfer ownership of fd. */ | |
515 | move_fd(dupfd); | |
516 | #endif | |
4110345b CB |
517 | return f; |
518 | } | |
70fd7fc9 | 519 | |
a60d8c4e CB |
520 | int fd_cloexec(int fd, bool cloexec) |
521 | { | |
522 | int oflags, nflags; | |
523 | ||
524 | oflags = fcntl(fd, F_GETFD, 0); | |
525 | if (oflags < 0) | |
526 | return -errno; | |
527 | ||
528 | if (cloexec) | |
529 | nflags = oflags | FD_CLOEXEC; | |
530 | else | |
531 | nflags = oflags & ~FD_CLOEXEC; | |
532 | ||
533 | if (nflags == oflags) | |
534 | return 0; | |
535 | ||
536 | if (fcntl(fd, F_SETFD, nflags) < 0) | |
537 | return -errno; | |
538 | ||
539 | return 0; | |
540 | } | |
541 | ||
542 | static inline int dup_cloexec(int fd) | |
543 | { | |
544 | __do_close int fd_dup = -EBADF; | |
545 | ||
546 | fd_dup = dup(fd); | |
547 | if (fd_dup < 0) | |
548 | return -errno; | |
549 | ||
550 | if (fd_cloexec(fd_dup, true)) | |
551 | return -errno; | |
552 | ||
553 | return move_fd(fd_dup); | |
554 | } | |
555 | ||
556 | FILE *fdopenat(int dfd, const char *path, const char *mode) | |
557 | { | |
558 | __do_close int fd = -EBADF; | |
559 | __do_fclose FILE *f = NULL; | |
560 | ||
561 | if (is_empty_string(path)) | |
562 | fd = dup_cloexec(dfd); | |
563 | else | |
564 | fd = openat(dfd, path, O_CLOEXEC | O_NOCTTY | O_NOFOLLOW); | |
565 | if (fd < 0) | |
566 | return NULL; | |
567 | ||
568 | f = fdopen(fd, "re"); | |
569 | if (!f) | |
570 | return NULL; | |
571 | ||
572 | /* Transfer ownership of fd. */ | |
573 | move_fd(fd); | |
574 | ||
575 | return move_ptr(f); | |
576 | } | |
577 | ||
70fd7fc9 CB |
578 | int timens_offset_write(clockid_t clk_id, int64_t s_offset, int64_t ns_offset) |
579 | { | |
580 | __do_close int fd = -EBADF; | |
581 | int ret; | |
582 | ssize_t len; | |
583 | char buf[INTTYPE_TO_STRLEN(int) + | |
584 | STRLITERALLEN(" ") + INTTYPE_TO_STRLEN(int64_t) + | |
585 | STRLITERALLEN(" ") + INTTYPE_TO_STRLEN(int64_t) + 1]; | |
586 | ||
587 | if (clk_id == CLOCK_MONOTONIC_COARSE || clk_id == CLOCK_MONOTONIC_RAW) | |
588 | clk_id = CLOCK_MONOTONIC; | |
589 | ||
590 | fd = open("/proc/self/timens_offsets", O_WRONLY | O_CLOEXEC); | |
591 | if (fd < 0) | |
592 | return -errno; | |
593 | ||
594 | len = snprintf(buf, sizeof(buf), "%d %" PRId64 " %" PRId64, clk_id, s_offset, ns_offset); | |
595 | if (len < 0 || len >= sizeof(buf)) | |
596 | return ret_errno(EFBIG); | |
597 | ||
598 | ret = lxc_write_nointr(fd, buf, len); | |
599 | if (ret < 0 || (size_t)ret != len) | |
600 | return -EIO; | |
601 | ||
602 | return 0; | |
603 | } | |
6f61472b CB |
604 | |
605 | bool exists_dir_at(int dir_fd, const char *path) | |
606 | { | |
607 | struct stat sb; | |
608 | int ret; | |
609 | ||
610 | ret = fstatat(dir_fd, path, &sb, 0); | |
611 | if (ret < 0) | |
612 | return false; | |
613 | ||
614 | return S_ISDIR(sb.st_mode); | |
615 | } | |
953db219 CB |
616 | |
617 | bool exists_file_at(int dir_fd, const char *path) | |
618 | { | |
619 | struct stat sb; | |
620 | ||
621 | return fstatat(dir_fd, path, &sb, 0) == 0; | |
622 | } | |
8ea93a0f | 623 | |
7166ab75 CB |
624 | int open_at(int dfd, const char *path, mode_t mode, unsigned int o_flags, |
625 | unsigned int resolve_flags) | |
8ea93a0f CB |
626 | { |
627 | __do_close int fd = -EBADF; | |
628 | struct lxc_open_how how = { | |
7166ab75 CB |
629 | .flags = o_flags, |
630 | .mode = mode, | |
631 | .resolve = resolve_flags, | |
8ea93a0f CB |
632 | }; |
633 | ||
7166ab75 | 634 | fd = openat2(dfd, path, &how, sizeof(how)); |
8ea93a0f CB |
635 | if (fd >= 0) |
636 | return move_fd(fd); | |
637 | ||
638 | if (errno != ENOSYS) | |
639 | return -errno; | |
640 | ||
7166ab75 | 641 | return openat(dfd, path, O_NOFOLLOW | o_flags); |
8ea93a0f | 642 | } |
a60c98aa CB |
643 | |
644 | int fd_make_nonblocking(int fd) | |
645 | { | |
646 | int flags; | |
647 | ||
648 | flags = fcntl(fd, F_GETFL); | |
649 | if (flags < 0) | |
650 | return -1; | |
651 | ||
652 | flags &= ~O_NONBLOCK; | |
653 | return fcntl(fd, F_SETFL, flags); | |
654 | } | |
d23cb29e CB |
655 | |
656 | #define BATCH_SIZE 50 | |
657 | static void batch_realloc(char **mem, size_t oldlen, size_t newlen) | |
658 | { | |
659 | int newbatches = (newlen / BATCH_SIZE) + 1; | |
660 | int oldbatches = (oldlen / BATCH_SIZE) + 1; | |
661 | ||
662 | if (!*mem || newbatches > oldbatches) | |
663 | *mem = must_realloc(*mem, newbatches * BATCH_SIZE); | |
664 | } | |
665 | ||
666 | static void append_line(char **dest, size_t oldlen, char *new, size_t newlen) | |
667 | { | |
668 | size_t full = oldlen + newlen; | |
669 | ||
670 | batch_realloc(dest, oldlen, full + 1); | |
671 | ||
672 | memcpy(*dest + oldlen, new, newlen + 1); | |
673 | } | |
674 | ||
675 | /* Slurp in a whole file */ | |
676 | char *read_file_at(int dfd, const char *fnam) | |
677 | { | |
678 | __do_close int fd = -EBADF; | |
679 | __do_free char *buf = NULL, *line = NULL; | |
680 | __do_fclose FILE *f = NULL; | |
681 | size_t len = 0, fulllen = 0; | |
682 | int linelen; | |
683 | ||
684 | fd = openat(dfd, fnam, O_NOCTTY | O_CLOEXEC | O_NOFOLLOW | O_RDONLY); | |
685 | if (fd < 0) | |
686 | return NULL; | |
687 | ||
688 | f = fdopen(fd, "re"); | |
689 | if (!f) | |
690 | return NULL; | |
691 | /* Transfer ownership to fdopen(). */ | |
692 | move_fd(fd); | |
693 | ||
694 | while ((linelen = getline(&line, &len, f)) != -1) { | |
695 | append_line(&buf, fulllen, line, linelen); | |
696 | fulllen += linelen; | |
697 | } | |
698 | ||
699 | return move_ptr(buf); | |
700 | } |