]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/fs-util.c
tree-wide: codespell fixes
[thirdparty/systemd.git] / src / basic / fs-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <errno.h>
4 #include <stddef.h>
5 #include <stdlib.h>
6 #include <linux/falloc.h>
7 #include <linux/magic.h>
8 #include <unistd.h>
9
10 #include "alloc-util.h"
11 #include "blockdev-util.h"
12 #include "dirent-util.h"
13 #include "fd-util.h"
14 #include "fileio.h"
15 #include "fs-util.h"
16 #include "locale-util.h"
17 #include "log.h"
18 #include "macro.h"
19 #include "missing_fcntl.h"
20 #include "missing_fs.h"
21 #include "missing_syscall.h"
22 #include "mkdir.h"
23 #include "parse-util.h"
24 #include "path-util.h"
25 #include "process-util.h"
26 #include "random-util.h"
27 #include "stat-util.h"
28 #include "stdio-util.h"
29 #include "string-util.h"
30 #include "strv.h"
31 #include "time-util.h"
32 #include "tmpfile-util.h"
33 #include "user-util.h"
34 #include "util.h"
35
36 int unlink_noerrno(const char *path) {
37 PROTECT_ERRNO;
38 int r;
39
40 r = unlink(path);
41 if (r < 0)
42 return -errno;
43
44 return 0;
45 }
46
47 int rmdir_parents(const char *path, const char *stop) {
48 size_t l;
49 int r = 0;
50
51 assert(path);
52 assert(stop);
53
54 l = strlen(path);
55
56 /* Skip trailing slashes */
57 while (l > 0 && path[l-1] == '/')
58 l--;
59
60 while (l > 0) {
61 char *t;
62
63 /* Skip last component */
64 while (l > 0 && path[l-1] != '/')
65 l--;
66
67 /* Skip trailing slashes */
68 while (l > 0 && path[l-1] == '/')
69 l--;
70
71 if (l <= 0)
72 break;
73
74 t = strndup(path, l);
75 if (!t)
76 return -ENOMEM;
77
78 if (path_startswith(stop, t)) {
79 free(t);
80 return 0;
81 }
82
83 r = rmdir(t);
84 free(t);
85
86 if (r < 0)
87 if (errno != ENOENT)
88 return -errno;
89 }
90
91 return 0;
92 }
93
94 int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
95 int r;
96
97 /* Try the ideal approach first */
98 if (renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE) >= 0)
99 return 0;
100
101 /* renameat2() exists since Linux 3.15, btrfs and FAT added support for it later. If it is not implemented,
102 * fall back to a different method. */
103 if (!IN_SET(errno, EINVAL, ENOSYS, ENOTTY))
104 return -errno;
105
106 /* Let's try to use linkat()+unlinkat() as fallback. This doesn't work on directories and on some file systems
107 * that do not support hard links (such as FAT, most prominently), but for files it's pretty close to what we
108 * want — though not atomic (i.e. for a short period both the new and the old filename will exist). */
109 if (linkat(olddirfd, oldpath, newdirfd, newpath, 0) >= 0) {
110
111 if (unlinkat(olddirfd, oldpath, 0) < 0) {
112 r = -errno; /* Backup errno before the following unlinkat() alters it */
113 (void) unlinkat(newdirfd, newpath, 0);
114 return r;
115 }
116
117 return 0;
118 }
119
120 if (!IN_SET(errno, EINVAL, ENOSYS, ENOTTY, EPERM)) /* FAT returns EPERM on link()… */
121 return -errno;
122
123 /* OK, neither RENAME_NOREPLACE nor linkat()+unlinkat() worked. Let's then fallback to the racy TOCTOU
124 * vulnerable accessat(F_OK) check followed by classic, replacing renameat(), we have nothing better. */
125
126 if (faccessat(newdirfd, newpath, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
127 return -EEXIST;
128 if (errno != ENOENT)
129 return -errno;
130
131 if (renameat(olddirfd, oldpath, newdirfd, newpath) < 0)
132 return -errno;
133
134 return 0;
135 }
136
137 int readlinkat_malloc(int fd, const char *p, char **ret) {
138 size_t l = FILENAME_MAX+1;
139 int r;
140
141 assert(p);
142 assert(ret);
143
144 for (;;) {
145 char *c;
146 ssize_t n;
147
148 c = new(char, l);
149 if (!c)
150 return -ENOMEM;
151
152 n = readlinkat(fd, p, c, l-1);
153 if (n < 0) {
154 r = -errno;
155 free(c);
156 return r;
157 }
158
159 if ((size_t) n < l-1) {
160 c[n] = 0;
161 *ret = c;
162 return 0;
163 }
164
165 free(c);
166 l *= 2;
167 }
168 }
169
170 int readlink_malloc(const char *p, char **ret) {
171 return readlinkat_malloc(AT_FDCWD, p, ret);
172 }
173
174 int readlink_value(const char *p, char **ret) {
175 _cleanup_free_ char *link = NULL;
176 char *value;
177 int r;
178
179 r = readlink_malloc(p, &link);
180 if (r < 0)
181 return r;
182
183 value = basename(link);
184 if (!value)
185 return -ENOENT;
186
187 value = strdup(value);
188 if (!value)
189 return -ENOMEM;
190
191 *ret = value;
192
193 return 0;
194 }
195
196 int readlink_and_make_absolute(const char *p, char **r) {
197 _cleanup_free_ char *target = NULL;
198 char *k;
199 int j;
200
201 assert(p);
202 assert(r);
203
204 j = readlink_malloc(p, &target);
205 if (j < 0)
206 return j;
207
208 k = file_in_same_dir(p, target);
209 if (!k)
210 return -ENOMEM;
211
212 *r = k;
213 return 0;
214 }
215
216 int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
217 _cleanup_close_ int fd = -1;
218
219 assert(path);
220
221 fd = open(path, O_PATH|O_CLOEXEC|O_NOFOLLOW); /* Let's acquire an O_PATH fd, as precaution to change
222 * mode/owner on the same file */
223 if (fd < 0)
224 return -errno;
225
226 return fchmod_and_chown(fd, mode, uid, gid);
227 }
228
229 int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) {
230 bool do_chown, do_chmod;
231 struct stat st;
232
233 /* Change ownership and access mode of the specified fd. Tries to do so safely, ensuring that at no
234 * point in time the access mode is above the old access mode under the old ownership or the new
235 * access mode under the new ownership. Note: this call tries hard to leave the access mode
236 * unaffected if the uid/gid is changed, i.e. it undoes implicit suid/sgid dropping the kernel does
237 * on chown().
238 *
239 * This call is happy with O_PATH fds. */
240
241 if (fstat(fd, &st) < 0)
242 return -errno;
243
244 do_chown =
245 (uid != UID_INVALID && st.st_uid != uid) ||
246 (gid != GID_INVALID && st.st_gid != gid);
247
248 do_chmod =
249 !S_ISLNK(st.st_mode) && /* chmod is not defined on symlinks */
250 ((mode != MODE_INVALID && ((st.st_mode ^ mode) & 07777) != 0) ||
251 do_chown); /* If we change ownership, make sure we reset the mode afterwards, since chown()
252 * modifies the access mode too */
253
254 if (mode == MODE_INVALID)
255 mode = st.st_mode; /* If we only shall do a chown(), save original mode, since chown() might break it. */
256 else if ((mode & S_IFMT) != 0 && ((mode ^ st.st_mode) & S_IFMT) != 0)
257 return -EINVAL; /* insist on the right file type if it was specified */
258
259 if (do_chown && do_chmod) {
260 mode_t minimal = st.st_mode & mode; /* the subset of the old and the new mask */
261
262 if (((minimal ^ st.st_mode) & 07777) != 0)
263 if (fchmod_opath(fd, minimal & 07777) < 0)
264 return -errno;
265 }
266
267 if (do_chown)
268 if (fchownat(fd, "", uid, gid, AT_EMPTY_PATH) < 0)
269 return -errno;
270
271 if (do_chmod)
272 if (fchmod_opath(fd, mode & 07777) < 0)
273 return -errno;
274
275 return do_chown || do_chmod;
276 }
277
278 int chmod_and_chown_unsafe(const char *path, mode_t mode, uid_t uid, gid_t gid) {
279 bool do_chown, do_chmod;
280 struct stat st;
281
282 assert(path);
283
284 /* Change ownership and access mode of the specified path, see description of fchmod_and_chown().
285 * Should only be used on trusted paths. */
286
287 if (lstat(path, &st) < 0)
288 return -errno;
289
290 do_chown =
291 (uid != UID_INVALID && st.st_uid != uid) ||
292 (gid != GID_INVALID && st.st_gid != gid);
293
294 do_chmod =
295 !S_ISLNK(st.st_mode) && /* chmod is not defined on symlinks */
296 ((mode != MODE_INVALID && ((st.st_mode ^ mode) & 07777) != 0) ||
297 do_chown); /* If we change ownership, make sure we reset the mode afterwards, since chown()
298 * modifies the access mode too */
299
300 if (mode == MODE_INVALID)
301 mode = st.st_mode; /* If we only shall do a chown(), save original mode, since chown() might break it. */
302 else if ((mode & S_IFMT) != 0 && ((mode ^ st.st_mode) & S_IFMT) != 0)
303 return -EINVAL; /* insist on the right file type if it was specified */
304
305 if (do_chown && do_chmod) {
306 mode_t minimal = st.st_mode & mode; /* the subset of the old and the new mask */
307
308 if (((minimal ^ st.st_mode) & 07777) != 0)
309 if (chmod(path, minimal & 07777) < 0)
310 return -errno;
311 }
312
313 if (do_chown)
314 if (lchown(path, uid, gid) < 0)
315 return -errno;
316
317 if (do_chmod)
318 if (chmod(path, mode & 07777) < 0)
319 return -errno;
320
321 return do_chown || do_chmod;
322 }
323
324 int fchmod_umask(int fd, mode_t m) {
325 mode_t u;
326 int r;
327
328 u = umask(0777);
329 r = fchmod(fd, m & (~u)) < 0 ? -errno : 0;
330 umask(u);
331
332 return r;
333 }
334
335 int fchmod_opath(int fd, mode_t m) {
336 char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
337
338 /* This function operates also on fd that might have been opened with
339 * O_PATH. Indeed fchmodat() doesn't have the AT_EMPTY_PATH flag like
340 * fchownat() does. */
341
342 xsprintf(procfs_path, "/proc/self/fd/%i", fd);
343 if (chmod(procfs_path, m) < 0) {
344 if (errno != ENOENT)
345 return -errno;
346
347 if (proc_mounted() == 0)
348 return -ENOSYS; /* if we have no /proc/, the concept is not implementable */
349
350 return -ENOENT;
351 }
352
353 return 0;
354 }
355
356 int fd_warn_permissions(const char *path, int fd) {
357 struct stat st;
358
359 if (fstat(fd, &st) < 0)
360 return -errno;
361
362 /* Don't complain if we are reading something that is not a file, for example /dev/null */
363 if (!S_ISREG(st.st_mode))
364 return 0;
365
366 if (st.st_mode & 0111)
367 log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path);
368
369 if (st.st_mode & 0002)
370 log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path);
371
372 if (getpid_cached() == 1 && (st.st_mode & 0044) != 0044)
373 log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path);
374
375 return 0;
376 }
377
378 int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
379 char fdpath[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
380 _cleanup_close_ int fd = -1;
381 int r, ret = 0;
382
383 assert(path);
384
385 /* Note that touch_file() does not follow symlinks: if invoked on an existing symlink, then it is the symlink
386 * itself which is updated, not its target
387 *
388 * Returns the first error we encounter, but tries to apply as much as possible. */
389
390 if (parents)
391 (void) mkdir_parents(path, 0755);
392
393 /* Initially, we try to open the node with O_PATH, so that we get a reference to the node. This is useful in
394 * case the path refers to an existing device or socket node, as we can open it successfully in all cases, and
395 * won't trigger any driver magic or so. */
396 fd = open(path, O_PATH|O_CLOEXEC|O_NOFOLLOW);
397 if (fd < 0) {
398 if (errno != ENOENT)
399 return -errno;
400
401 /* if the node doesn't exist yet, we create it, but with O_EXCL, so that we only create a regular file
402 * here, and nothing else */
403 fd = open(path, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, IN_SET(mode, 0, MODE_INVALID) ? 0644 : mode);
404 if (fd < 0)
405 return -errno;
406 }
407
408 /* Let's make a path from the fd, and operate on that. With this logic, we can adjust the access mode,
409 * ownership and time of the file node in all cases, even if the fd refers to an O_PATH object — which is
410 * something fchown(), fchmod(), futimensat() don't allow. */
411 xsprintf(fdpath, "/proc/self/fd/%i", fd);
412
413 ret = fchmod_and_chown(fd, mode, uid, gid);
414
415 if (stamp != USEC_INFINITY) {
416 struct timespec ts[2];
417
418 timespec_store(&ts[0], stamp);
419 ts[1] = ts[0];
420 r = utimensat(AT_FDCWD, fdpath, ts, 0);
421 } else
422 r = utimensat(AT_FDCWD, fdpath, NULL, 0);
423 if (r < 0 && ret >= 0)
424 return -errno;
425
426 return ret;
427 }
428
429 int touch(const char *path) {
430 return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
431 }
432
433 int symlink_idempotent(const char *from, const char *to, bool make_relative) {
434 _cleanup_free_ char *relpath = NULL;
435 int r;
436
437 assert(from);
438 assert(to);
439
440 if (make_relative) {
441 _cleanup_free_ char *parent = NULL;
442
443 parent = dirname_malloc(to);
444 if (!parent)
445 return -ENOMEM;
446
447 r = path_make_relative(parent, from, &relpath);
448 if (r < 0)
449 return r;
450
451 from = relpath;
452 }
453
454 if (symlink(from, to) < 0) {
455 _cleanup_free_ char *p = NULL;
456
457 if (errno != EEXIST)
458 return -errno;
459
460 r = readlink_malloc(to, &p);
461 if (r == -EINVAL) /* Not a symlink? In that case return the original error we encountered: -EEXIST */
462 return -EEXIST;
463 if (r < 0) /* Any other error? In that case propagate it as is */
464 return r;
465
466 if (!streq(p, from)) /* Not the symlink we want it to be? In that case, propagate the original -EEXIST */
467 return -EEXIST;
468 }
469
470 return 0;
471 }
472
473 int symlink_atomic(const char *from, const char *to) {
474 _cleanup_free_ char *t = NULL;
475 int r;
476
477 assert(from);
478 assert(to);
479
480 r = tempfn_random(to, NULL, &t);
481 if (r < 0)
482 return r;
483
484 if (symlink(from, t) < 0)
485 return -errno;
486
487 if (rename(t, to) < 0) {
488 unlink_noerrno(t);
489 return -errno;
490 }
491
492 return 0;
493 }
494
495 int mknod_atomic(const char *path, mode_t mode, dev_t dev) {
496 _cleanup_free_ char *t = NULL;
497 int r;
498
499 assert(path);
500
501 r = tempfn_random(path, NULL, &t);
502 if (r < 0)
503 return r;
504
505 if (mknod(t, mode, dev) < 0)
506 return -errno;
507
508 if (rename(t, path) < 0) {
509 unlink_noerrno(t);
510 return -errno;
511 }
512
513 return 0;
514 }
515
516 int mkfifo_atomic(const char *path, mode_t mode) {
517 _cleanup_free_ char *t = NULL;
518 int r;
519
520 assert(path);
521
522 r = tempfn_random(path, NULL, &t);
523 if (r < 0)
524 return r;
525
526 if (mkfifo(t, mode) < 0)
527 return -errno;
528
529 if (rename(t, path) < 0) {
530 unlink_noerrno(t);
531 return -errno;
532 }
533
534 return 0;
535 }
536
537 int mkfifoat_atomic(int dirfd, const char *path, mode_t mode) {
538 _cleanup_free_ char *t = NULL;
539 int r;
540
541 assert(path);
542
543 if (path_is_absolute(path))
544 return mkfifo_atomic(path, mode);
545
546 /* We're only interested in the (random) filename. */
547 r = tempfn_random_child("", NULL, &t);
548 if (r < 0)
549 return r;
550
551 if (mkfifoat(dirfd, t, mode) < 0)
552 return -errno;
553
554 if (renameat(dirfd, t, dirfd, path) < 0) {
555 unlink_noerrno(t);
556 return -errno;
557 }
558
559 return 0;
560 }
561
562 int get_files_in_directory(const char *path, char ***list) {
563 _cleanup_closedir_ DIR *d = NULL;
564 struct dirent *de;
565 size_t bufsize = 0, n = 0;
566 _cleanup_strv_free_ char **l = NULL;
567
568 assert(path);
569
570 /* Returns all files in a directory in *list, and the number
571 * of files as return value. If list is NULL returns only the
572 * number. */
573
574 d = opendir(path);
575 if (!d)
576 return -errno;
577
578 FOREACH_DIRENT_ALL(de, d, return -errno) {
579 dirent_ensure_type(d, de);
580
581 if (!dirent_is_file(de))
582 continue;
583
584 if (list) {
585 /* one extra slot is needed for the terminating NULL */
586 if (!GREEDY_REALLOC(l, bufsize, n + 2))
587 return -ENOMEM;
588
589 l[n] = strdup(de->d_name);
590 if (!l[n])
591 return -ENOMEM;
592
593 l[++n] = NULL;
594 } else
595 n++;
596 }
597
598 if (list)
599 *list = TAKE_PTR(l);
600
601 return n;
602 }
603
604 static int getenv_tmp_dir(const char **ret_path) {
605 const char *n;
606 int r, ret = 0;
607
608 assert(ret_path);
609
610 /* We use the same order of environment variables python uses in tempfile.gettempdir():
611 * https://docs.python.org/3/library/tempfile.html#tempfile.gettempdir */
612 FOREACH_STRING(n, "TMPDIR", "TEMP", "TMP") {
613 const char *e;
614
615 e = secure_getenv(n);
616 if (!e)
617 continue;
618 if (!path_is_absolute(e)) {
619 r = -ENOTDIR;
620 goto next;
621 }
622 if (!path_is_normalized(e)) {
623 r = -EPERM;
624 goto next;
625 }
626
627 r = is_dir(e, true);
628 if (r < 0)
629 goto next;
630 if (r == 0) {
631 r = -ENOTDIR;
632 goto next;
633 }
634
635 *ret_path = e;
636 return 1;
637
638 next:
639 /* Remember first error, to make this more debuggable */
640 if (ret >= 0)
641 ret = r;
642 }
643
644 if (ret < 0)
645 return ret;
646
647 *ret_path = NULL;
648 return ret;
649 }
650
651 static int tmp_dir_internal(const char *def, const char **ret) {
652 const char *e;
653 int r, k;
654
655 assert(def);
656 assert(ret);
657
658 r = getenv_tmp_dir(&e);
659 if (r > 0) {
660 *ret = e;
661 return 0;
662 }
663
664 k = is_dir(def, true);
665 if (k == 0)
666 k = -ENOTDIR;
667 if (k < 0)
668 return r < 0 ? r : k;
669
670 *ret = def;
671 return 0;
672 }
673
674 int var_tmp_dir(const char **ret) {
675
676 /* Returns the location for "larger" temporary files, that is backed by physical storage if available, and thus
677 * even might survive a boot: /var/tmp. If $TMPDIR (or related environment variables) are set, its value is
678 * returned preferably however. Note that both this function and tmp_dir() below are affected by $TMPDIR,
679 * making it a variable that overrides all temporary file storage locations. */
680
681 return tmp_dir_internal("/var/tmp", ret);
682 }
683
684 int tmp_dir(const char **ret) {
685
686 /* Similar to var_tmp_dir() above, but returns the location for "smaller" temporary files, which is usually
687 * backed by an in-memory file system: /tmp. */
688
689 return tmp_dir_internal("/tmp", ret);
690 }
691
692 int unlink_or_warn(const char *filename) {
693 if (unlink(filename) < 0 && errno != ENOENT)
694 /* If the file doesn't exist and the fs simply was read-only (in which
695 * case unlink() returns EROFS even if the file doesn't exist), don't
696 * complain */
697 if (errno != EROFS || access(filename, F_OK) >= 0)
698 return log_error_errno(errno, "Failed to remove \"%s\": %m", filename);
699
700 return 0;
701 }
702
703 int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
704 char path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
705 int wd;
706
707 /* This is like inotify_add_watch(), except that the file to watch is not referenced by a path, but by an fd */
708 xsprintf(path, "/proc/self/fd/%i", what);
709
710 wd = inotify_add_watch(fd, path, mask);
711 if (wd < 0)
712 return -errno;
713
714 return wd;
715 }
716
717 int inotify_add_watch_and_warn(int fd, const char *pathname, uint32_t mask) {
718 int wd;
719
720 wd = inotify_add_watch(fd, pathname, mask);
721 if (wd < 0) {
722 if (errno == ENOSPC)
723 return log_error_errno(errno, "Failed to add a watch for %s: inotify watch limit reached", pathname);
724
725 return log_error_errno(errno, "Failed to add a watch for %s: %m", pathname);
726 }
727
728 return wd;
729 }
730
731 static bool unsafe_transition(const struct stat *a, const struct stat *b) {
732 /* Returns true if the transition from a to b is safe, i.e. that we never transition from unprivileged to
733 * privileged files or directories. Why bother? So that unprivileged code can't symlink to privileged files
734 * making us believe we read something safe even though it isn't safe in the specific context we open it in. */
735
736 if (a->st_uid == 0) /* Transitioning from privileged to unprivileged is always fine */
737 return false;
738
739 return a->st_uid != b->st_uid; /* Otherwise we need to stay within the same UID */
740 }
741
742 static int log_unsafe_transition(int a, int b, const char *path, unsigned flags) {
743 _cleanup_free_ char *n1 = NULL, *n2 = NULL;
744
745 if (!FLAGS_SET(flags, CHASE_WARN))
746 return -ENOLINK;
747
748 (void) fd_get_path(a, &n1);
749 (void) fd_get_path(b, &n2);
750
751 return log_warning_errno(SYNTHETIC_ERRNO(ENOLINK),
752 "Detected unsafe path transition %s %s %s during canonicalization of %s.",
753 n1, special_glyph(SPECIAL_GLYPH_ARROW), n2, path);
754 }
755
756 static int log_autofs_mount_point(int fd, const char *path, unsigned flags) {
757 _cleanup_free_ char *n1 = NULL;
758
759 if (!FLAGS_SET(flags, CHASE_WARN))
760 return -EREMOTE;
761
762 (void) fd_get_path(fd, &n1);
763
764 return log_warning_errno(SYNTHETIC_ERRNO(EREMOTE),
765 "Detected autofs mount point %s during canonicalization of %s.",
766 n1, path);
767 }
768
769 int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret_path, int *ret_fd) {
770 _cleanup_free_ char *buffer = NULL, *done = NULL, *root = NULL;
771 _cleanup_close_ int fd = -1;
772 unsigned max_follow = CHASE_SYMLINKS_MAX; /* how many symlinks to follow before giving up and returning ELOOP */
773 struct stat previous_stat;
774 bool exists = true;
775 char *todo;
776 int r;
777
778 assert(path);
779
780 /* Either the file may be missing, or we return an fd to the final object, but both make no sense */
781 if ((flags & CHASE_NONEXISTENT) && ret_fd)
782 return -EINVAL;
783
784 if ((flags & CHASE_STEP) && ret_fd)
785 return -EINVAL;
786
787 if (isempty(path))
788 return -EINVAL;
789
790 /* This is a lot like canonicalize_file_name(), but takes an additional "root" parameter, that allows following
791 * symlinks relative to a root directory, instead of the root of the host.
792 *
793 * Note that "root" primarily matters if we encounter an absolute symlink. It is also used when following
794 * relative symlinks to ensure they cannot be used to "escape" the root directory. The path parameter passed is
795 * assumed to be already prefixed by it, except if the CHASE_PREFIX_ROOT flag is set, in which case it is first
796 * prefixed accordingly.
797 *
798 * Algorithmically this operates on two path buffers: "done" are the components of the path we already
799 * processed and resolved symlinks, "." and ".." of. "todo" are the components of the path we still need to
800 * process. On each iteration, we move one component from "todo" to "done", processing it's special meaning
801 * each time. The "todo" path always starts with at least one slash, the "done" path always ends in no
802 * slash. We always keep an O_PATH fd to the component we are currently processing, thus keeping lookup races
803 * to a minimum.
804 *
805 * Suggested usage: whenever you want to canonicalize a path, use this function. Pass the absolute path you got
806 * as-is: fully qualified and relative to your host's root. Optionally, specify the root parameter to tell this
807 * function what to do when encountering a symlink with an absolute path as directory: prefix it by the
808 * specified path.
809 *
810 * There are five ways to invoke this function:
811 *
812 * 1. Without CHASE_STEP or ret_fd: in this case the path is resolved and the normalized path is
813 * returned in `ret_path`. The return value is < 0 on error. If CHASE_NONEXISTENT is also set, 0
814 * is returned if the file doesn't exist, > 0 otherwise. If CHASE_NONEXISTENT is not set, >= 0 is
815 * returned if the destination was found, -ENOENT if it wasn't.
816 *
817 * 2. With ret_fd: in this case the destination is opened after chasing it as O_PATH and this file
818 * descriptor is returned as return value. This is useful to open files relative to some root
819 * directory. Note that the returned O_PATH file descriptors must be converted into a regular one (using
820 * fd_reopen() or such) before it can be used for reading/writing. ret_fd may not be combined with
821 * CHASE_NONEXISTENT.
822 *
823 * 3. With CHASE_STEP: in this case only a single step of the normalization is executed, i.e. only the first
824 * symlink or ".." component of the path is resolved, and the resulting path is returned. This is useful if
825 * a caller wants to trace the a path through the file system verbosely. Returns < 0 on error, > 0 if the
826 * path is fully normalized, and == 0 for each normalization step. This may be combined with
827 * CHASE_NONEXISTENT, in which case 1 is returned when a component is not found.
828 *
829 * 4. With CHASE_SAFE: in this case the path must not contain unsafe transitions, i.e. transitions from
830 * unprivileged to privileged files or directories. In such cases the return value is -ENOLINK. If
831 * CHASE_WARN is also set, a warning describing the unsafe transition is emitted.
832 *
833 * 5. With CHASE_NO_AUTOFS: in this case if an autofs mount point is encountered, path normalization
834 * is aborted and -EREMOTE is returned. If CHASE_WARN is also set, a warning showing the path of
835 * the mount point is emitted.
836 */
837
838 /* A root directory of "/" or "" is identical to none */
839 if (empty_or_root(original_root))
840 original_root = NULL;
841
842 if (!original_root && !ret_path && !(flags & (CHASE_NONEXISTENT|CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_STEP)) && ret_fd) {
843 /* Shortcut the ret_fd case if the caller isn't interested in the actual path and has no root set
844 * and doesn't care about any of the other special features we provide either. */
845 r = open(path, O_PATH|O_CLOEXEC|((flags & CHASE_NOFOLLOW) ? O_NOFOLLOW : 0));
846 if (r < 0)
847 return -errno;
848
849 *ret_fd = r;
850 return 0;
851 }
852
853 if (original_root) {
854 r = path_make_absolute_cwd(original_root, &root);
855 if (r < 0)
856 return r;
857
858 /* Simplify the root directory, so that it has no duplicate slashes and nothing at the
859 * end. While we won't resolve the root path we still simplify it. Note that dropping the
860 * trailing slash should not change behaviour, since when opening it we specify O_DIRECTORY
861 * anyway. Moreover at the end of this function after processing everything we'll always turn
862 * the empty string back to "/". */
863 delete_trailing_chars(root, "/");
864 path_simplify(root, true);
865
866 if (flags & CHASE_PREFIX_ROOT) {
867 /* We don't support relative paths in combination with a root directory */
868 if (!path_is_absolute(path))
869 return -EINVAL;
870
871 path = prefix_roota(root, path);
872 }
873 }
874
875 r = path_make_absolute_cwd(path, &buffer);
876 if (r < 0)
877 return r;
878
879 fd = open(root ?: "/", O_CLOEXEC|O_DIRECTORY|O_PATH);
880 if (fd < 0)
881 return -errno;
882
883 if (flags & CHASE_SAFE) {
884 if (fstat(fd, &previous_stat) < 0)
885 return -errno;
886 }
887
888 if (root) {
889 _cleanup_free_ char *absolute = NULL;
890 const char *e;
891
892 /* If we are operating on a root directory, let's take the root directory as it is. */
893
894 e = path_startswith(buffer, root);
895 if (!e)
896 return log_full_errno(flags & CHASE_WARN ? LOG_WARNING : LOG_DEBUG,
897 SYNTHETIC_ERRNO(ECHRNG),
898 "Specified path '%s' is outside of specified root directory '%s', refusing to resolve.",
899 path, root);
900
901 done = strdup(root);
902 if (!done)
903 return -ENOMEM;
904
905 /* Make sure "todo" starts with a slash */
906 absolute = strjoin("/", e);
907 if (!absolute)
908 return -ENOMEM;
909
910 free_and_replace(buffer, absolute);
911 }
912
913 todo = buffer;
914 for (;;) {
915 _cleanup_free_ char *first = NULL;
916 _cleanup_close_ int child = -1;
917 struct stat st;
918 size_t n, m;
919
920 /* Determine length of first component in the path */
921 n = strspn(todo, "/"); /* The slashes */
922
923 if (n > 1) {
924 /* If we are looking at more than a single slash then skip all but one, so that when
925 * we are done with everything we have a normalized path with only single slashes
926 * separating the path components. */
927 todo += n - 1;
928 n = 1;
929 }
930
931 m = n + strcspn(todo + n, "/"); /* The entire length of the component */
932
933 /* Extract the first component. */
934 first = strndup(todo, m);
935 if (!first)
936 return -ENOMEM;
937
938 todo += m;
939
940 /* Empty? Then we reached the end. */
941 if (isempty(first))
942 break;
943
944 /* Just a single slash? Then we reached the end. */
945 if (path_equal(first, "/")) {
946 /* Preserve the trailing slash */
947
948 if (flags & CHASE_TRAIL_SLASH)
949 if (!strextend(&done, "/", NULL))
950 return -ENOMEM;
951
952 break;
953 }
954
955 /* Just a dot? Then let's eat this up. */
956 if (path_equal(first, "/."))
957 continue;
958
959 /* Two dots? Then chop off the last bit of what we already found out. */
960 if (path_equal(first, "/..")) {
961 _cleanup_free_ char *parent = NULL;
962 _cleanup_close_ int fd_parent = -1;
963
964 /* If we already are at the top, then going up will not change anything. This is in-line with
965 * how the kernel handles this. */
966 if (empty_or_root(done))
967 continue;
968
969 parent = dirname_malloc(done);
970 if (!parent)
971 return -ENOMEM;
972
973 /* Don't allow this to leave the root dir. */
974 if (root &&
975 path_startswith(done, root) &&
976 !path_startswith(parent, root))
977 continue;
978
979 free_and_replace(done, parent);
980
981 if (flags & CHASE_STEP)
982 goto chased_one;
983
984 fd_parent = openat(fd, "..", O_CLOEXEC|O_NOFOLLOW|O_PATH);
985 if (fd_parent < 0)
986 return -errno;
987
988 if (flags & CHASE_SAFE) {
989 if (fstat(fd_parent, &st) < 0)
990 return -errno;
991
992 if (unsafe_transition(&previous_stat, &st))
993 return log_unsafe_transition(fd, fd_parent, path, flags);
994
995 previous_stat = st;
996 }
997
998 safe_close(fd);
999 fd = TAKE_FD(fd_parent);
1000
1001 continue;
1002 }
1003
1004 /* Otherwise let's see what this is. */
1005 child = openat(fd, first + n, O_CLOEXEC|O_NOFOLLOW|O_PATH);
1006 if (child < 0) {
1007
1008 if (errno == ENOENT &&
1009 (flags & CHASE_NONEXISTENT) &&
1010 (isempty(todo) || path_is_normalized(todo))) {
1011
1012 /* If CHASE_NONEXISTENT is set, and the path does not exist, then that's OK, return
1013 * what we got so far. But don't allow this if the remaining path contains "../ or "./"
1014 * or something else weird. */
1015
1016 /* If done is "/", as first also contains slash at the head, then remove this redundant slash. */
1017 if (streq_ptr(done, "/"))
1018 *done = '\0';
1019
1020 if (!strextend(&done, first, todo, NULL))
1021 return -ENOMEM;
1022
1023 exists = false;
1024 break;
1025 }
1026
1027 return -errno;
1028 }
1029
1030 if (fstat(child, &st) < 0)
1031 return -errno;
1032 if ((flags & CHASE_SAFE) &&
1033 unsafe_transition(&previous_stat, &st))
1034 return log_unsafe_transition(fd, child, path, flags);
1035
1036 previous_stat = st;
1037
1038 if ((flags & CHASE_NO_AUTOFS) &&
1039 fd_is_fs_type(child, AUTOFS_SUPER_MAGIC) > 0)
1040 return log_autofs_mount_point(child, path, flags);
1041
1042 if (S_ISLNK(st.st_mode) && !((flags & CHASE_NOFOLLOW) && isempty(todo))) {
1043 char *joined;
1044 _cleanup_free_ char *destination = NULL;
1045
1046 /* This is a symlink, in this case read the destination. But let's make sure we don't follow
1047 * symlinks without bounds. */
1048 if (--max_follow <= 0)
1049 return -ELOOP;
1050
1051 r = readlinkat_malloc(fd, first + n, &destination);
1052 if (r < 0)
1053 return r;
1054 if (isempty(destination))
1055 return -EINVAL;
1056
1057 if (path_is_absolute(destination)) {
1058
1059 /* An absolute destination. Start the loop from the beginning, but use the root
1060 * directory as base. */
1061
1062 safe_close(fd);
1063 fd = open(root ?: "/", O_CLOEXEC|O_DIRECTORY|O_PATH);
1064 if (fd < 0)
1065 return -errno;
1066
1067 if (flags & CHASE_SAFE) {
1068 if (fstat(fd, &st) < 0)
1069 return -errno;
1070
1071 if (unsafe_transition(&previous_stat, &st))
1072 return log_unsafe_transition(child, fd, path, flags);
1073
1074 previous_stat = st;
1075 }
1076
1077 free(done);
1078
1079 /* Note that we do not revalidate the root, we take it as is. */
1080 if (isempty(root))
1081 done = NULL;
1082 else {
1083 done = strdup(root);
1084 if (!done)
1085 return -ENOMEM;
1086 }
1087
1088 /* Prefix what's left to do with what we just read, and start the loop again, but
1089 * remain in the current directory. */
1090 joined = path_join(destination, todo);
1091 } else
1092 joined = path_join("/", destination, todo);
1093 if (!joined)
1094 return -ENOMEM;
1095
1096 free(buffer);
1097 todo = buffer = joined;
1098
1099 if (flags & CHASE_STEP)
1100 goto chased_one;
1101
1102 continue;
1103 }
1104
1105 /* If this is not a symlink, then let's just add the name we read to what we already verified. */
1106 if (!done)
1107 done = TAKE_PTR(first);
1108 else {
1109 /* If done is "/", as first also contains slash at the head, then remove this redundant slash. */
1110 if (streq(done, "/"))
1111 *done = '\0';
1112
1113 if (!strextend(&done, first, NULL))
1114 return -ENOMEM;
1115 }
1116
1117 /* And iterate again, but go one directory further down. */
1118 safe_close(fd);
1119 fd = TAKE_FD(child);
1120 }
1121
1122 if (!done) {
1123 /* Special case, turn the empty string into "/", to indicate the root directory. */
1124 done = strdup("/");
1125 if (!done)
1126 return -ENOMEM;
1127 }
1128
1129 if (ret_path)
1130 *ret_path = TAKE_PTR(done);
1131
1132 if (ret_fd) {
1133 /* Return the O_PATH fd we currently are looking to the caller. It can translate it to a
1134 * proper fd by opening /proc/self/fd/xyz. */
1135
1136 assert(fd >= 0);
1137 *ret_fd = TAKE_FD(fd);
1138 }
1139
1140 if (flags & CHASE_STEP)
1141 return 1;
1142
1143 return exists;
1144
1145 chased_one:
1146 if (ret_path) {
1147 char *c;
1148
1149 c = strjoin(strempty(done), todo);
1150 if (!c)
1151 return -ENOMEM;
1152
1153 *ret_path = c;
1154 }
1155
1156 return 0;
1157 }
1158
1159 int chase_symlinks_and_open(
1160 const char *path,
1161 const char *root,
1162 unsigned chase_flags,
1163 int open_flags,
1164 char **ret_path) {
1165
1166 _cleanup_close_ int path_fd = -1;
1167 _cleanup_free_ char *p = NULL;
1168 int r;
1169
1170 if (chase_flags & CHASE_NONEXISTENT)
1171 return -EINVAL;
1172
1173 if (empty_or_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) {
1174 /* Shortcut this call if none of the special features of this call are requested */
1175 r = open(path, open_flags);
1176 if (r < 0)
1177 return -errno;
1178
1179 return r;
1180 }
1181
1182 r = chase_symlinks(path, root, chase_flags, ret_path ? &p : NULL, &path_fd);
1183 if (r < 0)
1184 return r;
1185 assert(path_fd >= 0);
1186
1187 r = fd_reopen(path_fd, open_flags);
1188 if (r < 0)
1189 return r;
1190
1191 if (ret_path)
1192 *ret_path = TAKE_PTR(p);
1193
1194 return r;
1195 }
1196
1197 int chase_symlinks_and_opendir(
1198 const char *path,
1199 const char *root,
1200 unsigned chase_flags,
1201 char **ret_path,
1202 DIR **ret_dir) {
1203
1204 char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
1205 _cleanup_close_ int path_fd = -1;
1206 _cleanup_free_ char *p = NULL;
1207 DIR *d;
1208 int r;
1209
1210 if (!ret_dir)
1211 return -EINVAL;
1212 if (chase_flags & CHASE_NONEXISTENT)
1213 return -EINVAL;
1214
1215 if (empty_or_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) {
1216 /* Shortcut this call if none of the special features of this call are requested */
1217 d = opendir(path);
1218 if (!d)
1219 return -errno;
1220
1221 *ret_dir = d;
1222 return 0;
1223 }
1224
1225 r = chase_symlinks(path, root, chase_flags, ret_path ? &p : NULL, &path_fd);
1226 if (r < 0)
1227 return r;
1228 assert(path_fd >= 0);
1229
1230 xsprintf(procfs_path, "/proc/self/fd/%i", path_fd);
1231 d = opendir(procfs_path);
1232 if (!d)
1233 return -errno;
1234
1235 if (ret_path)
1236 *ret_path = TAKE_PTR(p);
1237
1238 *ret_dir = d;
1239 return 0;
1240 }
1241
1242 int chase_symlinks_and_stat(
1243 const char *path,
1244 const char *root,
1245 unsigned chase_flags,
1246 char **ret_path,
1247 struct stat *ret_stat,
1248 int *ret_fd) {
1249
1250 _cleanup_close_ int path_fd = -1;
1251 _cleanup_free_ char *p = NULL;
1252 int r;
1253
1254 assert(path);
1255 assert(ret_stat);
1256
1257 if (chase_flags & CHASE_NONEXISTENT)
1258 return -EINVAL;
1259
1260 if (empty_or_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) {
1261 /* Shortcut this call if none of the special features of this call are requested */
1262 if (stat(path, ret_stat) < 0)
1263 return -errno;
1264
1265 return 1;
1266 }
1267
1268 r = chase_symlinks(path, root, chase_flags, ret_path ? &p : NULL, &path_fd);
1269 if (r < 0)
1270 return r;
1271 assert(path_fd >= 0);
1272
1273 if (fstat(path_fd, ret_stat) < 0)
1274 return -errno;
1275
1276 if (ret_path)
1277 *ret_path = TAKE_PTR(p);
1278 if (ret_fd)
1279 *ret_fd = TAKE_FD(path_fd);
1280
1281 return 1;
1282 }
1283
1284 int access_fd(int fd, int mode) {
1285 char p[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
1286 int r;
1287
1288 /* Like access() but operates on an already open fd */
1289
1290 xsprintf(p, "/proc/self/fd/%i", fd);
1291 r = access(p, mode);
1292 if (r < 0)
1293 return -errno;
1294
1295 return r;
1296 }
1297
1298 void unlink_tempfilep(char (*p)[]) {
1299 /* If the file is created with mkstemp(), it will (almost always)
1300 * change the suffix. Treat this as a sign that the file was
1301 * successfully created. We ignore both the rare case where the
1302 * original suffix is used and unlink failures. */
1303 if (!endswith(*p, ".XXXXXX"))
1304 (void) unlink_noerrno(*p);
1305 }
1306
1307 int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags) {
1308 _cleanup_close_ int truncate_fd = -1;
1309 struct stat st;
1310 off_t l, bs;
1311
1312 assert((flags & ~(UNLINK_REMOVEDIR|UNLINK_ERASE)) == 0);
1313
1314 /* Operates like unlinkat() but also deallocates the file contents if it is a regular file and there's no other
1315 * link to it. This is useful to ensure that other processes that might have the file open for reading won't be
1316 * able to keep the data pinned on disk forever. This call is particular useful whenever we execute clean-up
1317 * jobs ("vacuuming"), where we want to make sure the data is really gone and the disk space released and
1318 * returned to the free pool.
1319 *
1320 * Deallocation is preferably done by FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE (👊) if supported, which means
1321 * the file won't change size. That's a good thing since we shouldn't needlessly trigger SIGBUS in other
1322 * programs that have mmap()ed the file. (The assumption here is that changing file contents to all zeroes
1323 * underneath those programs is the better choice than simply triggering SIGBUS in them which truncation does.)
1324 * However if hole punching is not implemented in the kernel or file system we'll fall back to normal file
1325 * truncation (🔪), as our goal of deallocating the data space trumps our goal of being nice to readers (💐).
1326 *
1327 * Note that we attempt deallocation, but failure to succeed with that is not considered fatal, as long as the
1328 * primary job – to delete the file – is accomplished. */
1329
1330 if (!FLAGS_SET(flags, UNLINK_REMOVEDIR)) {
1331 truncate_fd = openat(fd, name, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW|O_NONBLOCK);
1332 if (truncate_fd < 0) {
1333
1334 /* If this failed because the file doesn't exist propagate the error right-away. Also,
1335 * AT_REMOVEDIR wasn't set, and we tried to open the file for writing, which means EISDIR is
1336 * returned when this is a directory but we are not supposed to delete those, hence propagate
1337 * the error right-away too. */
1338 if (IN_SET(errno, ENOENT, EISDIR))
1339 return -errno;
1340
1341 if (errno != ELOOP) /* don't complain if this is a symlink */
1342 log_debug_errno(errno, "Failed to open file '%s' for deallocation, ignoring: %m", name);
1343 }
1344 }
1345
1346 if (unlinkat(fd, name, FLAGS_SET(flags, UNLINK_REMOVEDIR) ? AT_REMOVEDIR : 0) < 0)
1347 return -errno;
1348
1349 if (truncate_fd < 0) /* Don't have a file handle, can't do more ☹️ */
1350 return 0;
1351
1352 if (fstat(truncate_fd, &st) < 0) {
1353 log_debug_errno(errno, "Failed to stat file '%s' for deallocation, ignoring: %m", name);
1354 return 0;
1355 }
1356
1357 if (!S_ISREG(st.st_mode))
1358 return 0;
1359
1360 if (FLAGS_SET(flags, UNLINK_ERASE) && st.st_size > 0 && st.st_nlink == 0) {
1361 uint64_t left = st.st_size;
1362 char buffer[64 * 1024];
1363
1364 /* If erasing is requested, let's overwrite the file with random data once before deleting
1365 * it. This isn't going to give you shred(1) semantics, but hopefully should be good enough
1366 * for stuff backed by tmpfs at least.
1367 *
1368 * Note that we only erase like this if the link count of the file is zero. If it is higher it
1369 * is still linked by someone else and we'll leave it to them to remove it securely
1370 * eventually! */
1371
1372 random_bytes(buffer, sizeof(buffer));
1373
1374 while (left > 0) {
1375 ssize_t n;
1376
1377 n = write(truncate_fd, buffer, MIN(sizeof(buffer), left));
1378 if (n < 0) {
1379 log_debug_errno(errno, "Failed to erase data in file '%s', ignoring.", name);
1380 break;
1381 }
1382
1383 assert(left >= (size_t) n);
1384 left -= n;
1385 }
1386
1387 /* Let's refresh metadata */
1388 if (fstat(truncate_fd, &st) < 0) {
1389 log_debug_errno(errno, "Failed to stat file '%s' for deallocation, ignoring: %m", name);
1390 return 0;
1391 }
1392 }
1393
1394 /* Don't dallocate if there's nothing to deallocate or if the file is linked elsewhere */
1395 if (st.st_blocks == 0 || st.st_nlink > 0)
1396 return 0;
1397
1398 /* If this is a regular file, it actually took up space on disk and there are no other links it's time to
1399 * punch-hole/truncate this to release the disk space. */
1400
1401 bs = MAX(st.st_blksize, 512);
1402 l = DIV_ROUND_UP(st.st_size, bs) * bs; /* Round up to next block size */
1403
1404 if (fallocate(truncate_fd, FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE, 0, l) >= 0)
1405 return 0; /* Successfully punched a hole! 😊 */
1406
1407 /* Fall back to truncation */
1408 if (ftruncate(truncate_fd, 0) < 0) {
1409 log_debug_errno(errno, "Failed to truncate file to 0, ignoring: %m");
1410 return 0;
1411 }
1412
1413 return 0;
1414 }
1415
1416 int fsync_directory_of_file(int fd) {
1417 _cleanup_free_ char *path = NULL;
1418 _cleanup_close_ int dfd = -1;
1419 int r;
1420
1421 r = fd_verify_regular(fd);
1422 if (r < 0)
1423 return r;
1424
1425 r = fd_get_path(fd, &path);
1426 if (r < 0) {
1427 log_debug_errno(r, "Failed to query /proc/self/fd/%d%s: %m",
1428 fd,
1429 r == -EOPNOTSUPP ? ", ignoring" : "");
1430
1431 if (r == -EOPNOTSUPP)
1432 /* If /proc is not available, we're most likely running in some
1433 * chroot environment, and syncing the directory is not very
1434 * important in that case. Let's just silently do nothing. */
1435 return 0;
1436
1437 return r;
1438 }
1439
1440 if (!path_is_absolute(path))
1441 return -EINVAL;
1442
1443 dfd = open_parent(path, O_CLOEXEC, 0);
1444 if (dfd < 0)
1445 return dfd;
1446
1447 if (fsync(dfd) < 0)
1448 return -errno;
1449
1450 return 0;
1451 }
1452
1453 int fsync_full(int fd) {
1454 int r, q;
1455
1456 /* Sync both the file and the directory */
1457
1458 r = fsync(fd) < 0 ? -errno : 0;
1459 q = fsync_directory_of_file(fd);
1460
1461 return r < 0 ? r : q;
1462 }
1463
1464 int fsync_path_at(int at_fd, const char *path) {
1465 _cleanup_close_ int opened_fd = -1;
1466 int fd;
1467
1468 if (isempty(path)) {
1469 if (at_fd == AT_FDCWD) {
1470 opened_fd = open(".", O_RDONLY|O_DIRECTORY|O_CLOEXEC);
1471 if (opened_fd < 0)
1472 return -errno;
1473
1474 fd = opened_fd;
1475 } else
1476 fd = at_fd;
1477 } else {
1478
1479 opened_fd = openat(at_fd, path, O_RDONLY|O_CLOEXEC);
1480 if (opened_fd < 0)
1481 return -errno;
1482
1483 fd = opened_fd;
1484 }
1485
1486 if (fsync(fd) < 0)
1487 return -errno;
1488
1489 return 0;
1490 }
1491
1492 int syncfs_path(int atfd, const char *path) {
1493 _cleanup_close_ int fd = -1;
1494
1495 assert(path);
1496
1497 fd = openat(atfd, path, O_CLOEXEC|O_RDONLY|O_NONBLOCK);
1498 if (fd < 0)
1499 return -errno;
1500
1501 if (syncfs(fd) < 0)
1502 return -errno;
1503
1504 return 0;
1505 }
1506
1507 int open_parent(const char *path, int flags, mode_t mode) {
1508 _cleanup_free_ char *parent = NULL;
1509 int fd;
1510
1511 if (isempty(path))
1512 return -EINVAL;
1513 if (path_equal(path, "/")) /* requesting the parent of the root dir is fishy, let's prohibit that */
1514 return -EINVAL;
1515
1516 parent = dirname_malloc(path);
1517 if (!parent)
1518 return -ENOMEM;
1519
1520 /* Let's insist on O_DIRECTORY since the parent of a file or directory is a directory. Except if we open an
1521 * O_TMPFILE file, because in that case we are actually create a regular file below the parent directory. */
1522
1523 if (FLAGS_SET(flags, O_PATH))
1524 flags |= O_DIRECTORY;
1525 else if (!FLAGS_SET(flags, O_TMPFILE))
1526 flags |= O_DIRECTORY|O_RDONLY;
1527
1528 fd = open(parent, flags, mode);
1529 if (fd < 0)
1530 return -errno;
1531
1532 return fd;
1533 }
1534
1535 static int blockdev_is_encrypted(const char *sysfs_path, unsigned depth_left) {
1536 _cleanup_free_ char *p = NULL, *uuids = NULL;
1537 _cleanup_closedir_ DIR *d = NULL;
1538 int r, found_encrypted = false;
1539
1540 assert(sysfs_path);
1541
1542 if (depth_left == 0)
1543 return -EINVAL;
1544
1545 p = path_join(sysfs_path, "dm/uuid");
1546 if (!p)
1547 return -ENOMEM;
1548
1549 r = read_one_line_file(p, &uuids);
1550 if (r != -ENOENT) {
1551 if (r < 0)
1552 return r;
1553
1554 /* The DM device's uuid attribute is prefixed with "CRYPT-" if this is a dm-crypt device. */
1555 if (startswith(uuids, "CRYPT-"))
1556 return true;
1557 }
1558
1559 /* Not a dm-crypt device itself. But maybe it is on top of one? Follow the links in the "slaves/"
1560 * subdir. */
1561
1562 p = mfree(p);
1563 p = path_join(sysfs_path, "slaves");
1564 if (!p)
1565 return -ENOMEM;
1566
1567 d = opendir(p);
1568 if (!d) {
1569 if (errno == ENOENT) /* Doesn't have slaves */
1570 return false;
1571
1572 return -errno;
1573 }
1574
1575 for (;;) {
1576 _cleanup_free_ char *q = NULL;
1577 struct dirent *de;
1578
1579 errno = 0;
1580 de = readdir_no_dot(d);
1581 if (!de) {
1582 if (errno != 0)
1583 return -errno;
1584
1585 break; /* No more slaves */
1586 }
1587
1588 q = path_join(p, de->d_name);
1589 if (!q)
1590 return -ENOMEM;
1591
1592 r = blockdev_is_encrypted(q, depth_left - 1);
1593 if (r < 0)
1594 return r;
1595 if (r == 0) /* we found one that is not encrypted? then propagate that immediately */
1596 return false;
1597
1598 found_encrypted = true;
1599 }
1600
1601 return found_encrypted;
1602 }
1603
1604 int path_is_encrypted(const char *path) {
1605 char p[SYS_BLOCK_PATH_MAX(NULL)];
1606 dev_t devt;
1607 int r;
1608
1609 r = get_block_device(path, &devt);
1610 if (r < 0)
1611 return r;
1612 if (r == 0) /* doesn't have a block device */
1613 return false;
1614
1615 xsprintf_sys_block_path(p, NULL, devt);
1616
1617 return blockdev_is_encrypted(p, 10 /* safety net: maximum recursion depth */);
1618 }