chiark / gitweb /
fs-util: add shortcut for chase_symlinks() when it is called like open(O_PATH)
[elogind.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 "process-util.h"
43 #include "stat-util.h"
44 #include "stdio-util.h"
45 #include "string-util.h"
46 #include "strv.h"
47 //#include "time-util.h"
48 #include "user-util.h"
49 #include "util.h"
50
51 /// Additional includes needed by elogind
52 #include "process-util.h"
53
54 int unlink_noerrno(const char *path) {
55         PROTECT_ERRNO;
56         int r;
57
58         r = unlink(path);
59         if (r < 0)
60                 return -errno;
61
62         return 0;
63 }
64
65 #if 0 /// UNNEEDED by elogind
66 int rmdir_parents(const char *path, const char *stop) {
67         size_t l;
68         int r = 0;
69
70         assert(path);
71         assert(stop);
72
73         l = strlen(path);
74
75         /* Skip trailing slashes */
76         while (l > 0 && path[l-1] == '/')
77                 l--;
78
79         while (l > 0) {
80                 char *t;
81
82                 /* Skip last component */
83                 while (l > 0 && path[l-1] != '/')
84                         l--;
85
86                 /* Skip trailing slashes */
87                 while (l > 0 && path[l-1] == '/')
88                         l--;
89
90                 if (l <= 0)
91                         break;
92
93                 t = strndup(path, l);
94                 if (!t)
95                         return -ENOMEM;
96
97                 if (path_startswith(stop, t)) {
98                         free(t);
99                         return 0;
100                 }
101
102                 r = rmdir(t);
103                 free(t);
104
105                 if (r < 0)
106                         if (errno != ENOENT)
107                                 return -errno;
108         }
109
110         return 0;
111 }
112
113 int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
114         struct stat buf;
115         int ret;
116
117         ret = renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE);
118         if (ret >= 0)
119                 return 0;
120
121         /* renameat2() exists since Linux 3.15, btrfs added support for it later.
122          * If it is not implemented, fallback to another method. */
123         if (!IN_SET(errno, EINVAL, ENOSYS))
124                 return -errno;
125
126         /* The link()/unlink() fallback does not work on directories. But
127          * renameat() without RENAME_NOREPLACE gives the same semantics on
128          * directories, except when newpath is an *empty* directory. This is
129          * good enough. */
130         ret = fstatat(olddirfd, oldpath, &buf, AT_SYMLINK_NOFOLLOW);
131         if (ret >= 0 && S_ISDIR(buf.st_mode)) {
132                 ret = renameat(olddirfd, oldpath, newdirfd, newpath);
133                 return ret >= 0 ? 0 : -errno;
134         }
135
136         /* If it is not a directory, use the link()/unlink() fallback. */
137         ret = linkat(olddirfd, oldpath, newdirfd, newpath, 0);
138         if (ret < 0)
139                 return -errno;
140
141         ret = unlinkat(olddirfd, oldpath, 0);
142         if (ret < 0) {
143                 /* backup errno before the following unlinkat() alters it */
144                 ret = errno;
145                 (void) unlinkat(newdirfd, newpath, 0);
146                 errno = ret;
147                 return -errno;
148         }
149
150         return 0;
151 }
152 #endif // 0
153
154 int readlinkat_malloc(int fd, const char *p, char **ret) {
155         size_t l = 100;
156         int r;
157
158         assert(p);
159         assert(ret);
160
161         for (;;) {
162                 char *c;
163                 ssize_t n;
164
165                 c = new(char, l);
166                 if (!c)
167                         return -ENOMEM;
168
169                 n = readlinkat(fd, p, c, l-1);
170                 if (n < 0) {
171                         r = -errno;
172                         free(c);
173                         return r;
174                 }
175
176                 if ((size_t) n < l-1) {
177                         c[n] = 0;
178                         *ret = c;
179                         return 0;
180                 }
181
182                 free(c);
183                 l *= 2;
184         }
185 }
186
187 int readlink_malloc(const char *p, char **ret) {
188         return readlinkat_malloc(AT_FDCWD, p, ret);
189 }
190
191 #if 0 /// UNNEEDED by elogind
192 int readlink_value(const char *p, char **ret) {
193         _cleanup_free_ char *link = NULL;
194         char *value;
195         int r;
196
197         r = readlink_malloc(p, &link);
198         if (r < 0)
199                 return r;
200
201         value = basename(link);
202         if (!value)
203                 return -ENOENT;
204
205         value = strdup(value);
206         if (!value)
207                 return -ENOMEM;
208
209         *ret = value;
210
211         return 0;
212 }
213 #endif // 0
214
215 int readlink_and_make_absolute(const char *p, char **r) {
216         _cleanup_free_ char *target = NULL;
217         char *k;
218         int j;
219
220         assert(p);
221         assert(r);
222
223         j = readlink_malloc(p, &target);
224         if (j < 0)
225                 return j;
226
227         k = file_in_same_dir(p, target);
228         if (!k)
229                 return -ENOMEM;
230
231         *r = k;
232         return 0;
233 }
234
235 #if 0 /// UNNEEDED by elogind
236 #endif // 0
237 int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
238         assert(path);
239
240         /* Under the assumption that we are running privileged we
241          * first change the access mode and only then hand out
242          * ownership to avoid a window where access is too open. */
243
244         if (mode != MODE_INVALID)
245                 if (chmod(path, mode) < 0)
246                         return -errno;
247
248         if (uid != UID_INVALID || gid != GID_INVALID)
249                 if (chown(path, uid, gid) < 0)
250                         return -errno;
251
252         return 0;
253 }
254
255 int fchmod_umask(int fd, mode_t m) {
256         mode_t u;
257         int r;
258
259         u = umask(0777);
260         r = fchmod(fd, m & (~u)) < 0 ? -errno : 0;
261         umask(u);
262
263         return r;
264 }
265
266 int fd_warn_permissions(const char *path, int fd) {
267         struct stat st;
268
269         if (fstat(fd, &st) < 0)
270                 return -errno;
271
272         if (st.st_mode & 0111)
273                 log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path);
274
275         if (st.st_mode & 0002)
276                 log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path);
277
278         if (getpid_cached() == 1 && (st.st_mode & 0044) != 0044)
279                 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);
280
281         return 0;
282 }
283
284 int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
285         char fdpath[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
286         _cleanup_close_ int fd = -1;
287         int r, ret = 0;
288
289         assert(path);
290
291         /* Note that touch_file() does not follow symlinks: if invoked on an existing symlink, then it is the symlink
292          * itself which is updated, not its target
293          *
294          * Returns the first error we encounter, but tries to apply as much as possible. */
295
296         if (parents)
297                 (void) mkdir_parents(path, 0755);
298
299         /* Initially, we try to open the node with O_PATH, so that we get a reference to the node. This is useful in
300          * case the path refers to an existing device or socket node, as we can open it successfully in all cases, and
301          * won't trigger any driver magic or so. */
302         fd = open(path, O_PATH|O_CLOEXEC|O_NOFOLLOW);
303         if (fd < 0) {
304                 if (errno != ENOENT)
305                         return -errno;
306
307                 /* if the node doesn't exist yet, we create it, but with O_EXCL, so that we only create a regular file
308                  * here, and nothing else */
309                 fd = open(path, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, IN_SET(mode, 0, MODE_INVALID) ? 0644 : mode);
310                 if (fd < 0)
311                         return -errno;
312         }
313
314         /* Let's make a path from the fd, and operate on that. With this logic, we can adjust the access mode,
315          * ownership and time of the file node in all cases, even if the fd refers to an O_PATH object â€” which is
316          * something fchown(), fchmod(), futimensat() don't allow. */
317         xsprintf(fdpath, "/proc/self/fd/%i", fd);
318
319         if (mode != MODE_INVALID)
320                 if (chmod(fdpath, mode) < 0)
321                         ret = -errno;
322
323         if (uid_is_valid(uid) || gid_is_valid(gid))
324                 if (chown(fdpath, uid, gid) < 0 && ret >= 0)
325                         ret = -errno;
326
327         if (stamp != USEC_INFINITY) {
328                 struct timespec ts[2];
329
330                 timespec_store(&ts[0], stamp);
331                 ts[1] = ts[0];
332                 r = utimensat(AT_FDCWD, fdpath, ts, 0);
333         } else
334                 r = utimensat(AT_FDCWD, fdpath, NULL, 0);
335         if (r < 0 && ret >= 0)
336                 return -errno;
337
338         return ret;
339 }
340
341 int touch(const char *path) {
342         return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
343 }
344
345 #if 0 /// UNNEEDED by elogind
346 int symlink_idempotent(const char *from, const char *to) {
347         int r;
348
349         assert(from);
350         assert(to);
351
352         if (symlink(from, to) < 0) {
353                 _cleanup_free_ char *p = NULL;
354
355                 if (errno != EEXIST)
356                         return -errno;
357
358                 r = readlink_malloc(to, &p);
359                 if (r == -EINVAL) /* Not a symlink? In that case return the original error we encountered: -EEXIST */
360                         return -EEXIST;
361                 if (r < 0) /* Any other error? In that case propagate it as is */
362                         return r;
363
364                 if (!streq(p, from)) /* Not the symlink we want it to be? In that case, propagate the original -EEXIST */
365                         return -EEXIST;
366         }
367
368         return 0;
369 }
370
371 int symlink_atomic(const char *from, const char *to) {
372         _cleanup_free_ char *t = NULL;
373         int r;
374
375         assert(from);
376         assert(to);
377
378         r = tempfn_random(to, NULL, &t);
379         if (r < 0)
380                 return r;
381
382         if (symlink(from, t) < 0)
383                 return -errno;
384
385         if (rename(t, to) < 0) {
386                 unlink_noerrno(t);
387                 return -errno;
388         }
389
390         return 0;
391 }
392
393 int mknod_atomic(const char *path, mode_t mode, dev_t dev) {
394         _cleanup_free_ char *t = NULL;
395         int r;
396
397         assert(path);
398
399         r = tempfn_random(path, NULL, &t);
400         if (r < 0)
401                 return r;
402
403         if (mknod(t, mode, dev) < 0)
404                 return -errno;
405
406         if (rename(t, path) < 0) {
407                 unlink_noerrno(t);
408                 return -errno;
409         }
410
411         return 0;
412 }
413
414 int mkfifo_atomic(const char *path, mode_t mode) {
415         _cleanup_free_ char *t = NULL;
416         int r;
417
418         assert(path);
419
420         r = tempfn_random(path, NULL, &t);
421         if (r < 0)
422                 return r;
423
424         if (mkfifo(t, mode) < 0)
425                 return -errno;
426
427         if (rename(t, path) < 0) {
428                 unlink_noerrno(t);
429                 return -errno;
430         }
431
432         return 0;
433 }
434 #endif // 0
435
436 int get_files_in_directory(const char *path, char ***list) {
437         _cleanup_closedir_ DIR *d = NULL;
438         struct dirent *de;
439         size_t bufsize = 0, n = 0;
440         _cleanup_strv_free_ char **l = NULL;
441
442         assert(path);
443
444         /* Returns all files in a directory in *list, and the number
445          * of files as return value. If list is NULL returns only the
446          * number. */
447
448         d = opendir(path);
449         if (!d)
450                 return -errno;
451
452         FOREACH_DIRENT_ALL(de, d, return -errno) {
453                 dirent_ensure_type(d, de);
454
455                 if (!dirent_is_file(de))
456                         continue;
457
458                 if (list) {
459                         /* one extra slot is needed for the terminating NULL */
460                         if (!GREEDY_REALLOC(l, bufsize, n + 2))
461                                 return -ENOMEM;
462
463                         l[n] = strdup(de->d_name);
464                         if (!l[n])
465                                 return -ENOMEM;
466
467                         l[++n] = NULL;
468                 } else
469                         n++;
470         }
471
472         if (list)
473                 *list = TAKE_PTR(l);
474
475         return n;
476 }
477
478 static int getenv_tmp_dir(const char **ret_path) {
479         const char *n;
480         int r, ret = 0;
481
482         assert(ret_path);
483
484         /* We use the same order of environment variables python uses in tempfile.gettempdir():
485          * https://docs.python.org/3/library/tempfile.html#tempfile.gettempdir */
486         FOREACH_STRING(n, "TMPDIR", "TEMP", "TMP") {
487                 const char *e;
488
489                 e = secure_getenv(n);
490                 if (!e)
491                         continue;
492                 if (!path_is_absolute(e)) {
493                         r = -ENOTDIR;
494                         goto next;
495                 }
496                 if (!path_is_normalized(e)) {
497                         r = -EPERM;
498                         goto next;
499                 }
500
501                 r = is_dir(e, true);
502                 if (r < 0)
503                         goto next;
504                 if (r == 0) {
505                         r = -ENOTDIR;
506                         goto next;
507                 }
508
509                 *ret_path = e;
510                 return 1;
511
512         next:
513                 /* Remember first error, to make this more debuggable */
514                 if (ret >= 0)
515                         ret = r;
516         }
517
518         if (ret < 0)
519                 return ret;
520
521         *ret_path = NULL;
522         return ret;
523 }
524
525 static int tmp_dir_internal(const char *def, const char **ret) {
526         const char *e;
527         int r, k;
528
529         assert(def);
530         assert(ret);
531
532         r = getenv_tmp_dir(&e);
533         if (r > 0) {
534                 *ret = e;
535                 return 0;
536         }
537
538         k = is_dir(def, true);
539         if (k == 0)
540                 k = -ENOTDIR;
541         if (k < 0)
542                 return r < 0 ? r : k;
543
544         *ret = def;
545         return 0;
546 }
547
548 #if 0 /// UNNEEDED by elogind
549 int var_tmp_dir(const char **ret) {
550
551         /* Returns the location for "larger" temporary files, that is backed by physical storage if available, and thus
552          * even might survive a boot: /var/tmp. If $TMPDIR (or related environment variables) are set, its value is
553          * returned preferably however. Note that both this function and tmp_dir() below are affected by $TMPDIR,
554          * making it a variable that overrides all temporary file storage locations. */
555
556         return tmp_dir_internal("/var/tmp", ret);
557 }
558 #endif // 0
559
560 int tmp_dir(const char **ret) {
561
562         /* Similar to var_tmp_dir() above, but returns the location for "smaller" temporary files, which is usually
563          * backed by an in-memory file system: /tmp. */
564
565         return tmp_dir_internal("/tmp", ret);
566 }
567
568 int unlink_or_warn(const char *filename) {
569         if (unlink(filename) < 0 && errno != ENOENT)
570                 /* If the file doesn't exist and the fs simply was read-only (in which
571                  * case unlink() returns EROFS even if the file doesn't exist), don't
572                  * complain */
573                 if (errno != EROFS || access(filename, F_OK) >= 0)
574                         return log_error_errno(errno, "Failed to remove \"%s\": %m", filename);
575
576         return 0;
577 }
578
579 #if 0 /// UNNEEDED by elogind
580 int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
581         char path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
582         int r;
583
584         /* This is like inotify_add_watch(), except that the file to watch is not referenced by a path, but by an fd */
585         xsprintf(path, "/proc/self/fd/%i", what);
586
587         r = inotify_add_watch(fd, path, mask);
588         if (r < 0)
589                 return -errno;
590
591         return r;
592 }
593 #endif // 0
594
595 static bool noop_root(const char *root) {
596         return isempty(root) || path_equal(root, "/");
597 }
598
599 static bool safe_transition(const struct stat *a, const struct stat *b) {
600         /* Returns true if the transition from a to b is safe, i.e. that we never transition from unprivileged to
601          * privileged files or directories. Why bother? So that unprivileged code can't symlink to privileged files
602          * making us believe we read something safe even though it isn't safe in the specific context we open it in. */
603
604         if (a->st_uid == 0) /* Transitioning from privileged to unprivileged is always fine */
605                 return true;
606
607         return a->st_uid == b->st_uid; /* Otherwise we need to stay within the same UID */
608 }
609
610 int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret) {
611         _cleanup_free_ char *buffer = NULL, *done = NULL, *root = NULL;
612         _cleanup_close_ int fd = -1;
613         unsigned max_follow = 32; /* how many symlinks to follow before giving up and returning ELOOP */
614         struct stat previous_stat;
615         bool exists = true;
616         char *todo;
617         int r;
618
619         assert(path);
620
621         /* Either the file may be missing, or we return an fd to the final object, but both make no sense */
622         if ((flags & (CHASE_NONEXISTENT|CHASE_OPEN)) == (CHASE_NONEXISTENT|CHASE_OPEN))
623                 return -EINVAL;
624
625         if (isempty(path))
626                 return -EINVAL;
627
628         /* This is a lot like canonicalize_file_name(), but takes an additional "root" parameter, that allows following
629          * symlinks relative to a root directory, instead of the root of the host.
630          *
631          * Note that "root" primarily matters if we encounter an absolute symlink. It is also used when following
632          * relative symlinks to ensure they cannot be used to "escape" the root directory. The path parameter passed is
633          * assumed to be already prefixed by it, except if the CHASE_PREFIX_ROOT flag is set, in which case it is first
634          * prefixed accordingly.
635          *
636          * Algorithmically this operates on two path buffers: "done" are the components of the path we already
637          * processed and resolved symlinks, "." and ".." of. "todo" are the components of the path we still need to
638          * process. On each iteration, we move one component from "todo" to "done", processing it's special meaning
639          * each time. The "todo" path always starts with at least one slash, the "done" path always ends in no
640          * slash. We always keep an O_PATH fd to the component we are currently processing, thus keeping lookup races
641          * at a minimum.
642          *
643          * Suggested usage: whenever you want to canonicalize a path, use this function. Pass the absolute path you got
644          * as-is: fully qualified and relative to your host's root. Optionally, specify the root parameter to tell this
645          * function what to do when encountering a symlink with an absolute path as directory: prefix it by the
646          * specified path. */
647
648         /* A root directory of "/" or "" is identical to none */
649         if (noop_root(original_root))
650                 original_root = NULL;
651
652         if (!original_root && !ret && (flags & (CHASE_NONEXISTENT|CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_OPEN)) == CHASE_OPEN) {
653                 /* Shortcut the CHASE_OPEN case if the caller isn't interested in the actual path and has no root set
654                  * and doesn't care about any of the other special features we provide either. */
655                 r = open(path, O_PATH|O_CLOEXEC);
656                 if (r < 0)
657                         return -errno;
658
659                 return r;
660         }
661
662         if (original_root) {
663                 r = path_make_absolute_cwd(original_root, &root);
664                 if (r < 0)
665                         return r;
666
667                 if (flags & CHASE_PREFIX_ROOT) {
668
669                         /* We don't support relative paths in combination with a root directory */
670                         if (!path_is_absolute(path))
671                                 return -EINVAL;
672
673                         path = prefix_roota(root, path);
674                 }
675         }
676
677         r = path_make_absolute_cwd(path, &buffer);
678         if (r < 0)
679                 return r;
680
681         fd = open("/", O_CLOEXEC|O_NOFOLLOW|O_PATH);
682         if (fd < 0)
683                 return -errno;
684
685         if (flags & CHASE_SAFE) {
686                 if (fstat(fd, &previous_stat) < 0)
687                         return -errno;
688         }
689
690         todo = buffer;
691         for (;;) {
692                 _cleanup_free_ char *first = NULL;
693                 _cleanup_close_ int child = -1;
694                 struct stat st;
695                 size_t n, m;
696
697                 /* Determine length of first component in the path */
698                 n = strspn(todo, "/");                  /* The slashes */
699                 m = n + strcspn(todo + n, "/");         /* The entire length of the component */
700
701                 /* Extract the first component. */
702                 first = strndup(todo, m);
703                 if (!first)
704                         return -ENOMEM;
705
706                 todo += m;
707
708                 /* Empty? Then we reached the end. */
709                 if (isempty(first))
710                         break;
711
712                 /* Just a single slash? Then we reached the end. */
713                 if (path_equal(first, "/")) {
714                         /* Preserve the trailing slash */
715
716                         if (flags & CHASE_TRAIL_SLASH)
717                                 if (!strextend(&done, "/", NULL))
718                                         return -ENOMEM;
719
720                         break;
721                 }
722
723                 /* Just a dot? Then let's eat this up. */
724                 if (path_equal(first, "/."))
725                         continue;
726
727                 /* Two dots? Then chop off the last bit of what we already found out. */
728                 if (path_equal(first, "/..")) {
729                         _cleanup_free_ char *parent = NULL;
730                         _cleanup_close_ int fd_parent = -1;
731
732                         /* If we already are at the top, then going up will not change anything. This is in-line with
733                          * how the kernel handles this. */
734                         if (isempty(done) || path_equal(done, "/"))
735                                 continue;
736
737                         parent = dirname_malloc(done);
738                         if (!parent)
739                                 return -ENOMEM;
740
741                         /* Don't allow this to leave the root dir.  */
742                         if (root &&
743                             path_startswith(done, root) &&
744                             !path_startswith(parent, root))
745                                 continue;
746
747                         free_and_replace(done, parent);
748
749                         fd_parent = openat(fd, "..", O_CLOEXEC|O_NOFOLLOW|O_PATH);
750                         if (fd_parent < 0)
751                                 return -errno;
752
753                         if (flags & CHASE_SAFE) {
754                                 if (fstat(fd_parent, &st) < 0)
755                                         return -errno;
756
757                                 if (!safe_transition(&previous_stat, &st))
758                                         return -EPERM;
759
760                                 previous_stat = st;
761                         }
762
763                         safe_close(fd);
764                         fd = TAKE_FD(fd_parent);
765
766                         continue;
767                 }
768
769                 /* Otherwise let's see what this is. */
770                 child = openat(fd, first + n, O_CLOEXEC|O_NOFOLLOW|O_PATH);
771                 if (child < 0) {
772
773                         if (errno == ENOENT &&
774                             (flags & CHASE_NONEXISTENT) &&
775                             (isempty(todo) || path_is_normalized(todo))) {
776
777                                 /* If CHASE_NONEXISTENT is set, and the path does not exist, then that's OK, return
778                                  * what we got so far. But don't allow this if the remaining path contains "../ or "./"
779                                  * or something else weird. */
780
781                                 /* If done is "/", as first also contains slash at the head, then remove this redundant slash. */
782                                 if (streq_ptr(done, "/"))
783                                         *done = '\0';
784
785                                 if (!strextend(&done, first, todo, NULL))
786                                         return -ENOMEM;
787
788                                 exists = false;
789                                 break;
790                         }
791
792                         return -errno;
793                 }
794
795                 if (fstat(child, &st) < 0)
796                         return -errno;
797                 if ((flags & CHASE_SAFE) &&
798                     !safe_transition(&previous_stat, &st))
799                         return -EPERM;
800
801                 previous_stat = st;
802
803                 if ((flags & CHASE_NO_AUTOFS) &&
804                     fd_is_fs_type(child, AUTOFS_SUPER_MAGIC) > 0)
805                         return -EREMOTE;
806
807                 if (S_ISLNK(st.st_mode)) {
808                         char *joined;
809
810                         _cleanup_free_ char *destination = NULL;
811
812                         /* This is a symlink, in this case read the destination. But let's make sure we don't follow
813                          * symlinks without bounds. */
814                         if (--max_follow <= 0)
815                                 return -ELOOP;
816
817                         r = readlinkat_malloc(fd, first + n, &destination);
818                         if (r < 0)
819                                 return r;
820                         if (isempty(destination))
821                                 return -EINVAL;
822
823                         if (path_is_absolute(destination)) {
824
825                                 /* An absolute destination. Start the loop from the beginning, but use the root
826                                  * directory as base. */
827
828                                 safe_close(fd);
829                                 fd = open(root ?: "/", O_CLOEXEC|O_NOFOLLOW|O_PATH);
830                                 if (fd < 0)
831                                         return -errno;
832
833                                 if (flags & CHASE_SAFE) {
834                                         if (fstat(fd, &st) < 0)
835                                                 return -errno;
836
837                                         if (!safe_transition(&previous_stat, &st))
838                                                 return -EPERM;
839
840                                         previous_stat = st;
841                                 }
842
843                                 free(done);
844
845                                 /* Note that we do not revalidate the root, we take it as is. */
846                                 if (isempty(root))
847                                         done = NULL;
848                                 else {
849                                         done = strdup(root);
850                                         if (!done)
851                                                 return -ENOMEM;
852                                 }
853
854                                 /* Prefix what's left to do with what we just read, and start the loop again, but
855                                  * remain in the current directory. */
856                                 joined = strjoin(destination, todo);
857                         } else
858                                 joined = strjoin("/", destination, todo);
859                         if (!joined)
860                                 return -ENOMEM;
861
862                         free(buffer);
863                         todo = buffer = joined;
864
865                         continue;
866                 }
867
868                 /* If this is not a symlink, then let's just add the name we read to what we already verified. */
869                 if (!done)
870                         done = TAKE_PTR(first);
871                 else {
872                         /* If done is "/", as first also contains slash at the head, then remove this redundant slash. */
873                         if (streq(done, "/"))
874                                 *done = '\0';
875
876                         if (!strextend(&done, first, NULL))
877                                 return -ENOMEM;
878                 }
879
880                 /* And iterate again, but go one directory further down. */
881                 safe_close(fd);
882                 fd = TAKE_FD(child);
883         }
884
885         if (!done) {
886                 /* Special case, turn the empty string into "/", to indicate the root directory. */
887                 done = strdup("/");
888                 if (!done)
889                         return -ENOMEM;
890         }
891
892         if (ret)
893                 *ret = TAKE_PTR(done);
894
895         if (flags & CHASE_OPEN) {
896                 /* Return the O_PATH fd we currently are looking to the caller. It can translate it to a proper fd by
897                  * opening /proc/self/fd/xyz. */
898
899                 assert(fd >= 0);
900                 return TAKE_FD(fd);
901         }
902
903         return exists;
904 }
905
906 int chase_symlinks_and_open(
907                 const char *path,
908                 const char *root,
909                 unsigned chase_flags,
910                 int open_flags,
911                 char **ret_path) {
912
913         _cleanup_close_ int path_fd = -1;
914         _cleanup_free_ char *p = NULL;
915         int r;
916
917         if (chase_flags & CHASE_NONEXISTENT)
918                 return -EINVAL;
919
920         if (noop_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) {
921                 /* Shortcut this call if none of the special features of this call are requested */
922                 r = open(path, open_flags);
923                 if (r < 0)
924                         return -errno;
925
926                 return r;
927         }
928
929         path_fd = chase_symlinks(path, root, chase_flags|CHASE_OPEN, ret_path ? &p : NULL);
930         if (path_fd < 0)
931                 return path_fd;
932
933         r = fd_reopen(path_fd, open_flags);
934         if (r < 0)
935                 return r;
936
937         if (ret_path)
938                 *ret_path = TAKE_PTR(p);
939
940         return r;
941 }
942
943 int chase_symlinks_and_opendir(
944                 const char *path,
945                 const char *root,
946                 unsigned chase_flags,
947                 char **ret_path,
948                 DIR **ret_dir) {
949
950         char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
951         _cleanup_close_ int path_fd = -1;
952         _cleanup_free_ char *p = NULL;
953         DIR *d;
954
955         if (!ret_dir)
956                 return -EINVAL;
957         if (chase_flags & CHASE_NONEXISTENT)
958                 return -EINVAL;
959
960         if (noop_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) {
961                 /* Shortcut this call if none of the special features of this call are requested */
962                 d = opendir(path);
963                 if (!d)
964                         return -errno;
965
966                 *ret_dir = d;
967                 return 0;
968         }
969
970         path_fd = chase_symlinks(path, root, chase_flags|CHASE_OPEN, ret_path ? &p : NULL);
971         if (path_fd < 0)
972                 return path_fd;
973
974         xsprintf(procfs_path, "/proc/self/fd/%i", path_fd);
975         d = opendir(procfs_path);
976         if (!d)
977                 return -errno;
978
979         if (ret_path)
980                 *ret_path = TAKE_PTR(p);
981
982         *ret_dir = d;
983         return 0;
984 }
985
986 int access_fd(int fd, int mode) {
987         char p[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
988         int r;
989
990         /* Like access() but operates on an already open fd */
991
992         xsprintf(p, "/proc/self/fd/%i", fd);
993         r = access(p, mode);
994         if (r < 0)
995                 return -errno;
996
997         return r;
998 }
999
1000 int unlinkat_deallocate(int fd, const char *name, int flags) {
1001         _cleanup_close_ int truncate_fd = -1;
1002         struct stat st;
1003         off_t l, bs;
1004
1005         /* Operates like unlinkat() but also deallocates the file contents if it is a regular file and there's no other
1006          * link to it. This is useful to ensure that other processes that might have the file open for reading won't be
1007          * able to keep the data pinned on disk forever. This call is particular useful whenever we execute clean-up
1008          * jobs ("vacuuming"), where we want to make sure the data is really gone and the disk space released and
1009          * returned to the free pool.
1010          *
1011          * Deallocation is preferably done by FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE (👊) if supported, which means
1012          * the file won't change size. That's a good thing since we shouldn't needlessly trigger SIGBUS in other
1013          * programs that have mmap()ed the file. (The assumption here is that changing file contents to all zeroes
1014          * underneath those programs is the better choice than simply triggering SIGBUS in them which truncation does.)
1015          * However if hole punching is not implemented in the kernel or file system we'll fall back to normal file
1016          * truncation (đŸ”Ē), as our goal of deallocating the data space trumps our goal of being nice to readers (💐).
1017          *
1018          * Note that we attempt deallocation, but failure to succeed with that is not considered fatal, as long as the
1019          * primary job â€“ to delete the file â€“ is accomplished. */
1020
1021         if ((flags & AT_REMOVEDIR) == 0) {
1022                 truncate_fd = openat(fd, name, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW|O_NONBLOCK);
1023                 if (truncate_fd < 0) {
1024
1025                         /* If this failed because the file doesn't exist propagate the error right-away. Also,
1026                          * AT_REMOVEDIR wasn't set, and we tried to open the file for writing, which means EISDIR is
1027                          * returned when this is a directory but we are not supposed to delete those, hence propagate
1028                          * the error right-away too. */
1029                         if (IN_SET(errno, ENOENT, EISDIR))
1030                                 return -errno;
1031
1032                         if (errno != ELOOP) /* don't complain if this is a symlink */
1033                                 log_debug_errno(errno, "Failed to open file '%s' for deallocation, ignoring: %m", name);
1034                 }
1035         }
1036
1037         if (unlinkat(fd, name, flags) < 0)
1038                 return -errno;
1039
1040         if (truncate_fd < 0) /* Don't have a file handle, can't do more â˜šī¸ */
1041                 return 0;
1042
1043         if (fstat(truncate_fd, &st) < 0) {
1044                 log_debug_errno(errno, "Failed to stat file '%s' for deallocation, ignoring.", name);
1045                 return 0;
1046         }
1047
1048         if (!S_ISREG(st.st_mode) || st.st_blocks == 0 || st.st_nlink > 0)
1049                 return 0;
1050
1051         /* If this is a regular file, it actually took up space on disk and there are no other links it's time to
1052          * punch-hole/truncate this to release the disk space. */
1053
1054         bs = MAX(st.st_blksize, 512);
1055         l = DIV_ROUND_UP(st.st_size, bs) * bs; /* Round up to next block size */
1056
1057         if (fallocate(truncate_fd, FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE, 0, l) >= 0)
1058                 return 0; /* Successfully punched a hole! đŸ˜Š */
1059
1060         /* Fall back to truncation */
1061         if (ftruncate(truncate_fd, 0) < 0) {
1062                 log_debug_errno(errno, "Failed to truncate file to 0, ignoring: %m");
1063                 return 0;
1064         }
1065
1066         return 0;
1067 }
1068
1069 int fsync_directory_of_file(int fd) {
1070         _cleanup_free_ char *path = NULL, *dn = NULL;
1071         _cleanup_close_ int dfd = -1;
1072         int r;
1073
1074         r = fd_verify_regular(fd);
1075         if (r < 0)
1076                 return r;
1077
1078         r = fd_get_path(fd, &path);
1079         if (r < 0) {
1080                 log_debug("Failed to query /proc/self/fd/%d%s: %m",
1081                           fd,
1082                           r == -EOPNOTSUPP ? ", ignoring" : "");
1083
1084                 if (r == -EOPNOTSUPP)
1085                         /* If /proc is not available, we're most likely running in some
1086                          * chroot environment, and syncing the directory is not very
1087                          * important in that case. Let's just silently do nothing. */
1088                         return 0;
1089
1090                 return r;
1091         }
1092
1093         if (!path_is_absolute(path))
1094                 return -EINVAL;
1095
1096         dn = dirname_malloc(path);
1097         if (!dn)
1098                 return -ENOMEM;
1099
1100         dfd = open(dn, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
1101         if (dfd < 0)
1102                 return -errno;
1103
1104         if (fsync(dfd) < 0)
1105                 return -errno;
1106
1107         return 0;
1108 }