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