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