]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/fs-util.c
fs-util: add new chase_symlinks() flag CHASE_OPEN
[thirdparty/systemd.git] / src / basic / fs-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <errno.h>
22 #include <stddef.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/stat.h>
27 #include <linux/magic.h>
28 #include <time.h>
29 #include <unistd.h>
30
31 #include "alloc-util.h"
32 #include "dirent-util.h"
33 #include "fd-util.h"
34 #include "fileio.h"
35 #include "fs-util.h"
36 #include "log.h"
37 #include "macro.h"
38 #include "missing.h"
39 #include "mkdir.h"
40 #include "parse-util.h"
41 #include "path-util.h"
42 #include "stat-util.h"
43 #include "stdio-util.h"
44 #include "string-util.h"
45 #include "strv.h"
46 #include "time-util.h"
47 #include "user-util.h"
48 #include "util.h"
49
50 int unlink_noerrno(const char *path) {
51 PROTECT_ERRNO;
52 int r;
53
54 r = unlink(path);
55 if (r < 0)
56 return -errno;
57
58 return 0;
59 }
60
61 int rmdir_parents(const char *path, const char *stop) {
62 size_t l;
63 int r = 0;
64
65 assert(path);
66 assert(stop);
67
68 l = strlen(path);
69
70 /* Skip trailing slashes */
71 while (l > 0 && path[l-1] == '/')
72 l--;
73
74 while (l > 0) {
75 char *t;
76
77 /* Skip last component */
78 while (l > 0 && path[l-1] != '/')
79 l--;
80
81 /* Skip trailing slashes */
82 while (l > 0 && path[l-1] == '/')
83 l--;
84
85 if (l <= 0)
86 break;
87
88 t = strndup(path, l);
89 if (!t)
90 return -ENOMEM;
91
92 if (path_startswith(stop, t)) {
93 free(t);
94 return 0;
95 }
96
97 r = rmdir(t);
98 free(t);
99
100 if (r < 0)
101 if (errno != ENOENT)
102 return -errno;
103 }
104
105 return 0;
106 }
107
108 int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
109 struct stat buf;
110 int ret;
111
112 ret = renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE);
113 if (ret >= 0)
114 return 0;
115
116 /* renameat2() exists since Linux 3.15, btrfs added support for it later.
117 * If it is not implemented, fallback to another method. */
118 if (!IN_SET(errno, EINVAL, ENOSYS))
119 return -errno;
120
121 /* The link()/unlink() fallback does not work on directories. But
122 * renameat() without RENAME_NOREPLACE gives the same semantics on
123 * directories, except when newpath is an *empty* directory. This is
124 * good enough. */
125 ret = fstatat(olddirfd, oldpath, &buf, AT_SYMLINK_NOFOLLOW);
126 if (ret >= 0 && S_ISDIR(buf.st_mode)) {
127 ret = renameat(olddirfd, oldpath, newdirfd, newpath);
128 return ret >= 0 ? 0 : -errno;
129 }
130
131 /* If it is not a directory, use the link()/unlink() fallback. */
132 ret = linkat(olddirfd, oldpath, newdirfd, newpath, 0);
133 if (ret < 0)
134 return -errno;
135
136 ret = unlinkat(olddirfd, oldpath, 0);
137 if (ret < 0) {
138 /* backup errno before the following unlinkat() alters it */
139 ret = errno;
140 (void) unlinkat(newdirfd, newpath, 0);
141 errno = ret;
142 return -errno;
143 }
144
145 return 0;
146 }
147
148 int readlinkat_malloc(int fd, const char *p, char **ret) {
149 size_t l = 100;
150 int r;
151
152 assert(p);
153 assert(ret);
154
155 for (;;) {
156 char *c;
157 ssize_t n;
158
159 c = new(char, l);
160 if (!c)
161 return -ENOMEM;
162
163 n = readlinkat(fd, p, c, l-1);
164 if (n < 0) {
165 r = -errno;
166 free(c);
167 return r;
168 }
169
170 if ((size_t) n < l-1) {
171 c[n] = 0;
172 *ret = c;
173 return 0;
174 }
175
176 free(c);
177 l *= 2;
178 }
179 }
180
181 int readlink_malloc(const char *p, char **ret) {
182 return readlinkat_malloc(AT_FDCWD, p, ret);
183 }
184
185 int readlink_value(const char *p, char **ret) {
186 _cleanup_free_ char *link = NULL;
187 char *value;
188 int r;
189
190 r = readlink_malloc(p, &link);
191 if (r < 0)
192 return r;
193
194 value = basename(link);
195 if (!value)
196 return -ENOENT;
197
198 value = strdup(value);
199 if (!value)
200 return -ENOMEM;
201
202 *ret = value;
203
204 return 0;
205 }
206
207 int readlink_and_make_absolute(const char *p, char **r) {
208 _cleanup_free_ char *target = NULL;
209 char *k;
210 int j;
211
212 assert(p);
213 assert(r);
214
215 j = readlink_malloc(p, &target);
216 if (j < 0)
217 return j;
218
219 k = file_in_same_dir(p, target);
220 if (!k)
221 return -ENOMEM;
222
223 *r = k;
224 return 0;
225 }
226
227 int readlink_and_canonicalize(const char *p, const char *root, char **ret) {
228 char *t, *s;
229 int r;
230
231 assert(p);
232 assert(ret);
233
234 r = readlink_and_make_absolute(p, &t);
235 if (r < 0)
236 return r;
237
238 r = chase_symlinks(t, root, 0, &s);
239 if (r < 0)
240 /* If we can't follow up, then let's return the original string, slightly cleaned up. */
241 *ret = path_kill_slashes(t);
242 else {
243 *ret = s;
244 free(t);
245 }
246
247 return 0;
248 }
249
250 int readlink_and_make_absolute_root(const char *root, const char *path, char **ret) {
251 _cleanup_free_ char *target = NULL, *t = NULL;
252 const char *full;
253 int r;
254
255 full = prefix_roota(root, path);
256 r = readlink_malloc(full, &target);
257 if (r < 0)
258 return r;
259
260 t = file_in_same_dir(path, target);
261 if (!t)
262 return -ENOMEM;
263
264 *ret = t;
265 t = NULL;
266
267 return 0;
268 }
269
270 int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
271 assert(path);
272
273 /* Under the assumption that we are running privileged we
274 * first change the access mode and only then hand out
275 * ownership to avoid a window where access is too open. */
276
277 if (mode != MODE_INVALID)
278 if (chmod(path, mode) < 0)
279 return -errno;
280
281 if (uid != UID_INVALID || gid != GID_INVALID)
282 if (chown(path, uid, gid) < 0)
283 return -errno;
284
285 return 0;
286 }
287
288 int fchmod_umask(int fd, mode_t m) {
289 mode_t u;
290 int r;
291
292 u = umask(0777);
293 r = fchmod(fd, m & (~u)) < 0 ? -errno : 0;
294 umask(u);
295
296 return r;
297 }
298
299 int fd_warn_permissions(const char *path, int fd) {
300 struct stat st;
301
302 if (fstat(fd, &st) < 0)
303 return -errno;
304
305 if (st.st_mode & 0111)
306 log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path);
307
308 if (st.st_mode & 0002)
309 log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path);
310
311 if (getpid_cached() == 1 && (st.st_mode & 0044) != 0044)
312 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);
313
314 return 0;
315 }
316
317 int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
318 char fdpath[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
319 _cleanup_close_ int fd = -1;
320 int r, ret = 0;
321
322 assert(path);
323
324 /* Note that touch_file() does not follow symlinks: if invoked on an existing symlink, then it is the symlink
325 * itself which is updated, not its target
326 *
327 * Returns the first error we encounter, but tries to apply as much as possible. */
328
329 if (parents)
330 (void) mkdir_parents(path, 0755);
331
332 /* Initially, we try to open the node with O_PATH, so that we get a reference to the node. This is useful in
333 * case the path refers to an existing device or socket node, as we can open it successfully in all cases, and
334 * won't trigger any driver magic or so. */
335 fd = open(path, O_PATH|O_CLOEXEC|O_NOFOLLOW);
336 if (fd < 0) {
337 if (errno != ENOENT)
338 return -errno;
339
340 /* if the node doesn't exist yet, we create it, but with O_EXCL, so that we only create a regular file
341 * here, and nothing else */
342 fd = open(path, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, IN_SET(mode, 0, MODE_INVALID) ? 0644 : mode);
343 if (fd < 0)
344 return -errno;
345 }
346
347 /* Let's make a path from the fd, and operate on that. With this logic, we can adjust the access mode,
348 * ownership and time of the file node in all cases, even if the fd refers to an O_PATH object — which is
349 * something fchown(), fchmod(), futimensat() don't allow. */
350 xsprintf(fdpath, "/proc/self/fd/%i", fd);
351
352 if (mode != MODE_INVALID)
353 if (chmod(fdpath, mode) < 0)
354 ret = -errno;
355
356 if (uid_is_valid(uid) || gid_is_valid(gid))
357 if (chown(fdpath, uid, gid) < 0 && ret >= 0)
358 ret = -errno;
359
360 if (stamp != USEC_INFINITY) {
361 struct timespec ts[2];
362
363 timespec_store(&ts[0], stamp);
364 ts[1] = ts[0];
365 r = utimensat(AT_FDCWD, fdpath, ts, 0);
366 } else
367 r = utimensat(AT_FDCWD, fdpath, NULL, 0);
368 if (r < 0 && ret >= 0)
369 return -errno;
370
371 return ret;
372 }
373
374 int touch(const char *path) {
375 return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
376 }
377
378 int symlink_idempotent(const char *from, const char *to) {
379 int r;
380
381 assert(from);
382 assert(to);
383
384 if (symlink(from, to) < 0) {
385 _cleanup_free_ char *p = NULL;
386
387 if (errno != EEXIST)
388 return -errno;
389
390 r = readlink_malloc(to, &p);
391 if (r == -EINVAL) /* Not a symlink? In that case return the original error we encountered: -EEXIST */
392 return -EEXIST;
393 if (r < 0) /* Any other error? In that case propagate it as is */
394 return r;
395
396 if (!streq(p, from)) /* Not the symlink we want it to be? In that case, propagate the original -EEXIST */
397 return -EEXIST;
398 }
399
400 return 0;
401 }
402
403 int symlink_atomic(const char *from, const char *to) {
404 _cleanup_free_ char *t = NULL;
405 int r;
406
407 assert(from);
408 assert(to);
409
410 r = tempfn_random(to, NULL, &t);
411 if (r < 0)
412 return r;
413
414 if (symlink(from, t) < 0)
415 return -errno;
416
417 if (rename(t, to) < 0) {
418 unlink_noerrno(t);
419 return -errno;
420 }
421
422 return 0;
423 }
424
425 int mknod_atomic(const char *path, mode_t mode, dev_t dev) {
426 _cleanup_free_ char *t = NULL;
427 int r;
428
429 assert(path);
430
431 r = tempfn_random(path, NULL, &t);
432 if (r < 0)
433 return r;
434
435 if (mknod(t, mode, dev) < 0)
436 return -errno;
437
438 if (rename(t, path) < 0) {
439 unlink_noerrno(t);
440 return -errno;
441 }
442
443 return 0;
444 }
445
446 int mkfifo_atomic(const char *path, mode_t mode) {
447 _cleanup_free_ char *t = NULL;
448 int r;
449
450 assert(path);
451
452 r = tempfn_random(path, NULL, &t);
453 if (r < 0)
454 return r;
455
456 if (mkfifo(t, mode) < 0)
457 return -errno;
458
459 if (rename(t, path) < 0) {
460 unlink_noerrno(t);
461 return -errno;
462 }
463
464 return 0;
465 }
466
467 int get_files_in_directory(const char *path, char ***list) {
468 _cleanup_closedir_ DIR *d = NULL;
469 struct dirent *de;
470 size_t bufsize = 0, n = 0;
471 _cleanup_strv_free_ char **l = NULL;
472
473 assert(path);
474
475 /* Returns all files in a directory in *list, and the number
476 * of files as return value. If list is NULL returns only the
477 * number. */
478
479 d = opendir(path);
480 if (!d)
481 return -errno;
482
483 FOREACH_DIRENT_ALL(de, d, return -errno) {
484 dirent_ensure_type(d, de);
485
486 if (!dirent_is_file(de))
487 continue;
488
489 if (list) {
490 /* one extra slot is needed for the terminating NULL */
491 if (!GREEDY_REALLOC(l, bufsize, n + 2))
492 return -ENOMEM;
493
494 l[n] = strdup(de->d_name);
495 if (!l[n])
496 return -ENOMEM;
497
498 l[++n] = NULL;
499 } else
500 n++;
501 }
502
503 if (list) {
504 *list = l;
505 l = NULL; /* avoid freeing */
506 }
507
508 return n;
509 }
510
511 static int getenv_tmp_dir(const char **ret_path) {
512 const char *n;
513 int r, ret = 0;
514
515 assert(ret_path);
516
517 /* We use the same order of environment variables python uses in tempfile.gettempdir():
518 * https://docs.python.org/3/library/tempfile.html#tempfile.gettempdir */
519 FOREACH_STRING(n, "TMPDIR", "TEMP", "TMP") {
520 const char *e;
521
522 e = secure_getenv(n);
523 if (!e)
524 continue;
525 if (!path_is_absolute(e)) {
526 r = -ENOTDIR;
527 goto next;
528 }
529 if (!path_is_normalized(e)) {
530 r = -EPERM;
531 goto next;
532 }
533
534 r = is_dir(e, true);
535 if (r < 0)
536 goto next;
537 if (r == 0) {
538 r = -ENOTDIR;
539 goto next;
540 }
541
542 *ret_path = e;
543 return 1;
544
545 next:
546 /* Remember first error, to make this more debuggable */
547 if (ret >= 0)
548 ret = r;
549 }
550
551 if (ret < 0)
552 return ret;
553
554 *ret_path = NULL;
555 return ret;
556 }
557
558 static int tmp_dir_internal(const char *def, const char **ret) {
559 const char *e;
560 int r, k;
561
562 assert(def);
563 assert(ret);
564
565 r = getenv_tmp_dir(&e);
566 if (r > 0) {
567 *ret = e;
568 return 0;
569 }
570
571 k = is_dir(def, true);
572 if (k == 0)
573 k = -ENOTDIR;
574 if (k < 0)
575 return r < 0 ? r : k;
576
577 *ret = def;
578 return 0;
579 }
580
581 int var_tmp_dir(const char **ret) {
582
583 /* Returns the location for "larger" temporary files, that is backed by physical storage if available, and thus
584 * even might survive a boot: /var/tmp. If $TMPDIR (or related environment variables) are set, its value is
585 * returned preferably however. Note that both this function and tmp_dir() below are affected by $TMPDIR,
586 * making it a variable that overrides all temporary file storage locations. */
587
588 return tmp_dir_internal("/var/tmp", ret);
589 }
590
591 int tmp_dir(const char **ret) {
592
593 /* Similar to var_tmp_dir() above, but returns the location for "smaller" temporary files, which is usually
594 * backed by an in-memory file system: /tmp. */
595
596 return tmp_dir_internal("/tmp", ret);
597 }
598
599 int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
600 char path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
601 int r;
602
603 /* This is like inotify_add_watch(), except that the file to watch is not referenced by a path, but by an fd */
604 xsprintf(path, "/proc/self/fd/%i", what);
605
606 r = inotify_add_watch(fd, path, mask);
607 if (r < 0)
608 return -errno;
609
610 return r;
611 }
612
613 static bool safe_transition(const struct stat *a, const struct stat *b) {
614 /* Returns true if the transition from a to b is safe, i.e. that we never transition from unprivileged to
615 * privileged files or directories. Why bother? So that unprivileged code can't symlink to privileged files
616 * making us believe we read something safe even though it isn't safe in the specific context we open it in. */
617
618 if (a->st_uid == 0) /* Transitioning from privileged to unprivileged is always fine */
619 return true;
620
621 return a->st_uid == b->st_uid; /* Otherwise we need to stay within the same UID */
622 }
623
624 int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret) {
625 _cleanup_free_ char *buffer = NULL, *done = NULL, *root = NULL;
626 _cleanup_close_ int fd = -1;
627 unsigned max_follow = 32; /* how many symlinks to follow before giving up and returning ELOOP */
628 struct stat previous_stat;
629 bool exists = true;
630 char *todo;
631 int r;
632
633 assert(path);
634
635 /* Either the file may be missing, or we return an fd to the final object, but both make no sense */
636 if ((flags & (CHASE_NONEXISTENT|CHASE_OPEN)) == (CHASE_NONEXISTENT|CHASE_OPEN))
637 return -EINVAL;
638
639 /* This is a lot like canonicalize_file_name(), but takes an additional "root" parameter, that allows following
640 * symlinks relative to a root directory, instead of the root of the host.
641 *
642 * Note that "root" primarily matters if we encounter an absolute symlink. It is also used when following
643 * relative symlinks to ensure they cannot be used to "escape" the root directory. The path parameter passed is
644 * assumed to be already prefixed by it, except if the CHASE_PREFIX_ROOT flag is set, in which case it is first
645 * prefixed accordingly.
646 *
647 * Algorithmically this operates on two path buffers: "done" are the components of the path we already
648 * processed and resolved symlinks, "." and ".." of. "todo" are the components of the path we still need to
649 * process. On each iteration, we move one component from "todo" to "done", processing it's special meaning
650 * each time. The "todo" path always starts with at least one slash, the "done" path always ends in no
651 * slash. We always keep an O_PATH fd to the component we are currently processing, thus keeping lookup races
652 * at a minimum.
653 *
654 * Suggested usage: whenever you want to canonicalize a path, use this function. Pass the absolute path you got
655 * as-is: fully qualified and relative to your host's root. Optionally, specify the root parameter to tell this
656 * function what to do when encountering a symlink with an absolute path as directory: prefix it by the
657 * specified path. */
658
659 if (original_root) {
660 r = path_make_absolute_cwd(original_root, &root);
661 if (r < 0)
662 return r;
663
664 if (flags & CHASE_PREFIX_ROOT)
665 path = prefix_roota(root, path);
666 }
667
668 r = path_make_absolute_cwd(path, &buffer);
669 if (r < 0)
670 return r;
671
672 fd = open("/", O_CLOEXEC|O_NOFOLLOW|O_PATH);
673 if (fd < 0)
674 return -errno;
675
676 if (flags & CHASE_SAFE) {
677 if (fstat(fd, &previous_stat) < 0)
678 return -errno;
679 }
680
681 todo = buffer;
682 for (;;) {
683 _cleanup_free_ char *first = NULL;
684 _cleanup_close_ int child = -1;
685 struct stat st;
686 size_t n, m;
687
688 /* Determine length of first component in the path */
689 n = strspn(todo, "/"); /* The slashes */
690 m = n + strcspn(todo + n, "/"); /* The entire length of the component */
691
692 /* Extract the first component. */
693 first = strndup(todo, m);
694 if (!first)
695 return -ENOMEM;
696
697 todo += m;
698
699 /* Empty? Then we reached the end. */
700 if (isempty(first))
701 break;
702
703 /* Just a single slash? Then we reached the end. */
704 if (path_equal(first, "/")) {
705 /* Preserve the trailing slash */
706 if (!strextend(&done, "/", NULL))
707 return -ENOMEM;
708
709 break;
710 }
711
712 /* Just a dot? Then let's eat this up. */
713 if (path_equal(first, "/."))
714 continue;
715
716 /* Two dots? Then chop off the last bit of what we already found out. */
717 if (path_equal(first, "/..")) {
718 _cleanup_free_ char *parent = NULL;
719 int fd_parent = -1;
720
721 /* If we already are at the top, then going up will not change anything. This is in-line with
722 * how the kernel handles this. */
723 if (isempty(done) || path_equal(done, "/"))
724 continue;
725
726 parent = dirname_malloc(done);
727 if (!parent)
728 return -ENOMEM;
729
730 /* Don't allow this to leave the root dir. */
731 if (root &&
732 path_startswith(done, root) &&
733 !path_startswith(parent, root))
734 continue;
735
736 free_and_replace(done, parent);
737
738 fd_parent = openat(fd, "..", O_CLOEXEC|O_NOFOLLOW|O_PATH);
739 if (fd_parent < 0)
740 return -errno;
741
742 if (flags & CHASE_SAFE) {
743 if (fstat(fd_parent, &st) < 0)
744 return -errno;
745
746 if (!safe_transition(&previous_stat, &st))
747 return -EPERM;
748
749 previous_stat = st;
750 }
751
752 safe_close(fd);
753 fd = fd_parent;
754
755 continue;
756 }
757
758 /* Otherwise let's see what this is. */
759 child = openat(fd, first + n, O_CLOEXEC|O_NOFOLLOW|O_PATH);
760 if (child < 0) {
761
762 if (errno == ENOENT &&
763 (flags & CHASE_NONEXISTENT) &&
764 (isempty(todo) || path_is_normalized(todo))) {
765
766 /* If CHASE_NONEXISTENT is set, and the path does not exist, then that's OK, return
767 * what we got so far. But don't allow this if the remaining path contains "../ or "./"
768 * or something else weird. */
769
770 /* If done is "/", as first also contains slash at the head, then remove this redundant slash. */
771 if (streq_ptr(done, "/"))
772 *done = '\0';
773
774 if (!strextend(&done, first, todo, NULL))
775 return -ENOMEM;
776
777 exists = false;
778 break;
779 }
780
781 return -errno;
782 }
783
784 if (fstat(child, &st) < 0)
785 return -errno;
786 if ((flags & CHASE_SAFE) &&
787 !safe_transition(&previous_stat, &st))
788 return -EPERM;
789
790 previous_stat = st;
791
792 if ((flags & CHASE_NO_AUTOFS) &&
793 fd_is_fs_type(child, AUTOFS_SUPER_MAGIC) > 0)
794 return -EREMOTE;
795
796 if (S_ISLNK(st.st_mode)) {
797 char *joined;
798
799 _cleanup_free_ char *destination = NULL;
800
801 /* This is a symlink, in this case read the destination. But let's make sure we don't follow
802 * symlinks without bounds. */
803 if (--max_follow <= 0)
804 return -ELOOP;
805
806 r = readlinkat_malloc(fd, first + n, &destination);
807 if (r < 0)
808 return r;
809 if (isempty(destination))
810 return -EINVAL;
811
812 if (path_is_absolute(destination)) {
813
814 /* An absolute destination. Start the loop from the beginning, but use the root
815 * directory as base. */
816
817 safe_close(fd);
818 fd = open(root ?: "/", O_CLOEXEC|O_NOFOLLOW|O_PATH);
819 if (fd < 0)
820 return -errno;
821
822 free(done);
823
824 if (flags & CHASE_SAFE) {
825 if (fstat(fd, &st) < 0)
826 return -errno;
827
828 if (!safe_transition(&previous_stat, &st))
829 return -EPERM;
830
831 previous_stat = st;
832 }
833
834 /* Note that we do not revalidate the root, we take it as is. */
835 if (isempty(root))
836 done = NULL;
837 else {
838 done = strdup(root);
839 if (!done)
840 return -ENOMEM;
841 }
842
843 /* Prefix what's left to do with what we just read, and start the loop again, but
844 * remain in the current directory. */
845 joined = strjoin(destination, todo);
846 } else
847 joined = strjoin("/", destination, todo);
848 if (!joined)
849 return -ENOMEM;
850
851 free(buffer);
852 todo = buffer = joined;
853
854 continue;
855 }
856
857 /* If this is not a symlink, then let's just add the name we read to what we already verified. */
858 if (!done) {
859 done = first;
860 first = NULL;
861 } else {
862 /* If done is "/", as first also contains slash at the head, then remove this redundant slash. */
863 if (streq(done, "/"))
864 *done = '\0';
865
866 if (!strextend(&done, first, NULL))
867 return -ENOMEM;
868 }
869
870 /* And iterate again, but go one directory further down. */
871 safe_close(fd);
872 fd = child;
873 child = -1;
874 }
875
876 if (!done) {
877 /* Special case, turn the empty string into "/", to indicate the root directory. */
878 done = strdup("/");
879 if (!done)
880 return -ENOMEM;
881 }
882
883 if (ret) {
884 *ret = done;
885 done = NULL;
886 }
887
888 if (flags & CHASE_OPEN) {
889 int q;
890
891 /* Return the O_PATH fd we currently are looking to the caller. It can translate it to a proper fd by
892 * opening /proc/self/fd/xyz. */
893
894 assert(fd >= 0);
895 q = fd;
896 fd = -1;
897
898 return q;
899 }
900
901 return exists;
902 }
903
904 int access_fd(int fd, int mode) {
905 char p[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
906 int r;
907
908 /* Like access() but operates on an already open fd */
909
910 xsprintf(p, "/proc/self/fd/%i", fd);
911
912 r = access(p, mode);
913 if (r < 0)
914 r = -errno;
915
916 return r;
917 }