]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/file_utils.c
tree-wide: use lxc_drop_groups() instead of lxc_setgroups(0, NULL)
[mirror_lxc.git] / src / lxc / file_utils.c
CommitLineData
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
24int 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
29int 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
45int 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
61int 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
73int 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
99int 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
125ssize_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
151ssize_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
162ssize_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
173ssize_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
184ssize_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
195ssize_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
206ssize_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
222ssize_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
240ssize_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
252bool file_exists(const char *f)
253{
254 struct stat statbuf;
255
256 return stat(f, &statbuf) == 0;
257}
258
259int 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
274int 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 */
289int 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
306int 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
331bool 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
336bool 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
348bool 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
360FILE *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
399ssize_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 410ssize_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 443int 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
472char *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
490FILE *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
511FILE *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
545int 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
567static 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
581FILE *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
604int 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
631bool 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
643bool 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
650int 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
670int 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
683static 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
692static 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
702char *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}