1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
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.
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.
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/>.
22 //#include <stdio_ext.h>
25 #include <sys/mount.h>
27 #include <sys/statvfs.h>
30 #include "alloc-util.h"
36 #include "mount-util.h"
37 #include "parse-util.h"
38 #include "path-util.h"
40 #include "stdio-util.h"
41 #include "string-util.h"
44 /* This is the original MAX_HANDLE_SZ definition from the kernel, when the API was introduced. We use that in place of
45 * any more currently defined value to future-proof things: if the size is increased in the API headers, and our code
46 * is recompiled then it would cease working on old kernels, as those refuse any sizes larger than this value with
47 * EINVAL right-away. Hence, let's disconnect ourselves from any such API changes, and stick to the original definition
48 * from when it was introduced. We use it as a start value only anyway (see below), and hence should be able to deal
49 * with large file handles anyway. */
50 #define ORIGINAL_MAX_HANDLE_SZ 128
52 int name_to_handle_at_loop(
55 struct file_handle **ret_handle,
59 _cleanup_free_ struct file_handle *h = NULL;
60 size_t n = ORIGINAL_MAX_HANDLE_SZ;
62 /* We need to invoke name_to_handle_at() in a loop, given that it might return EOVERFLOW when the specified
63 * buffer is too small. Note that in contrast to what the docs might suggest, MAX_HANDLE_SZ is only good as a
64 * start value, it is not an upper bound on the buffer size required.
66 * This improves on raw name_to_handle_at() also in one other regard: ret_handle and ret_mnt_id can be passed
67 * as NULL if there's no interest in either. */
72 h = malloc0(offsetof(struct file_handle, f_handle) + n);
78 if (name_to_handle_at(fd, path, h, &mnt_id, flags) >= 0) {
90 if (errno != EOVERFLOW)
93 if (!ret_handle && ret_mnt_id && mnt_id >= 0) {
95 /* As it appears, name_to_handle_at() fills in mnt_id even when it returns EOVERFLOW when the
96 * buffer is too small, but that's undocumented. Hence, let's make use of this if it appears to
97 * be filled in, and the caller was interested in only the mount ID an nothing else. */
103 /* If name_to_handle_at() didn't increase the byte size, then this EOVERFLOW is caused by something
104 * else (apparently EOVERFLOW is returned for untriggered nfs4 mounts sometimes), not by the too small
105 * buffer. In that case propagate EOVERFLOW */
106 if (h->handle_bytes <= n)
109 /* The buffer was too small. Size the new buffer by what name_to_handle_at() returned. */
111 if (offsetof(struct file_handle, f_handle) + n < n) /* check for addition overflow */
118 static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) {
119 char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
120 _cleanup_free_ char *fdinfo = NULL;
121 _cleanup_close_ int subfd = -1;
125 if ((flags & AT_EMPTY_PATH) && isempty(filename))
126 xsprintf(path, "/proc/self/fdinfo/%i", fd);
128 subfd = openat(fd, filename, O_CLOEXEC|O_PATH);
132 xsprintf(path, "/proc/self/fdinfo/%i", subfd);
135 r = read_full_file(path, &fdinfo, NULL);
136 if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */
141 p = startswith(fdinfo, "mnt_id:");
143 p = strstr(fdinfo, "\nmnt_id:");
144 if (!p) /* The mnt_id field is a relatively new addition */
150 p += strspn(p, WHITESPACE);
151 p[strcspn(p, WHITESPACE)] = 0;
153 return safe_atoi(p, mnt_id);
156 int fd_is_mount_point(int fd, const char *filename, int flags) {
157 _cleanup_free_ struct file_handle *h = NULL, *h_parent = NULL;
158 int mount_id = -1, mount_id_parent = -1;
159 bool nosupp = false, check_st_dev = true;
166 /* First we will try the name_to_handle_at() syscall, which
167 * tells us the mount id and an opaque file "handle". It is
168 * not supported everywhere though (kernel compile-time
169 * option, not all file systems are hooked up). If it works
170 * the mount id is usually good enough to tell us whether
171 * something is a mount point.
173 * If that didn't work we will try to read the mount id from
174 * /proc/self/fdinfo/<fd>. This is almost as good as
175 * name_to_handle_at(), however, does not return the
176 * opaque file handle. The opaque file handle is pretty useful
177 * to detect the root directory, which we should always
178 * consider a mount point. Hence we use this only as
179 * fallback. Exporting the mnt_id in fdinfo is a pretty recent
182 * As last fallback we do traditional fstat() based st_dev
183 * comparisons. This is how things were traditionally done,
184 * but unionfs breaks this since it exposes file
185 * systems with a variety of st_dev reported. Also, btrfs
186 * subvolumes have different st_dev, even though they aren't
187 * real mounts of their own. */
189 r = name_to_handle_at_loop(fd, filename, &h, &mount_id, flags);
190 if (IN_SET(r, -ENOSYS, -EACCES, -EPERM, -EOVERFLOW, -EINVAL))
191 /* This kernel does not support name_to_handle_at() at all (ENOSYS), or the syscall was blocked
192 * (EACCES/EPERM; maybe through seccomp, because we are running inside of a container?), or the mount
193 * point is not triggered yet (EOVERFLOW, think nfs4), or some general name_to_handle_at() flakiness
194 * (EINVAL): fall back to simpler logic. */
195 goto fallback_fdinfo;
196 else if (r == -EOPNOTSUPP)
197 /* This kernel or file system does not support name_to_handle_at(), hence let's see if the upper fs
198 * supports it (in which case it is a mount point), otherwise fallback to the traditional stat()
204 r = name_to_handle_at_loop(fd, "", &h_parent, &mount_id_parent, AT_EMPTY_PATH);
205 if (r == -EOPNOTSUPP) {
207 /* Neither parent nor child do name_to_handle_at()? We have no choice but to fall back. */
208 goto fallback_fdinfo;
210 /* The parent can't do name_to_handle_at() but the directory we are interested in can? If so,
211 * it must be a mount point. */
216 /* The parent can do name_to_handle_at() but the
217 * directory we are interested in can't? If so, it
218 * must be a mount point. */
222 /* If the file handle for the directory we are
223 * interested in and its parent are identical, we
224 * assume this is the root directory, which is a mount
227 if (h->handle_bytes == h_parent->handle_bytes &&
228 h->handle_type == h_parent->handle_type &&
229 memcmp(h->f_handle, h_parent->f_handle, h->handle_bytes) == 0)
232 return mount_id != mount_id_parent;
235 r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id);
236 if (IN_SET(r, -EOPNOTSUPP, -EACCES, -EPERM))
241 r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent);
245 if (mount_id != mount_id_parent)
248 /* Hmm, so, the mount ids are the same. This leaves one
249 * special case though for the root file system. For that,
250 * let's see if the parent directory has the same inode as we
251 * are interested in. Hence, let's also do fstat() checks now,
252 * too, but avoid the st_dev comparisons, since they aren't
253 * that useful on unionfs mounts. */
254 check_st_dev = false;
257 /* yay for fstatat() taking a different set of flags than the other
259 if (flags & AT_SYMLINK_FOLLOW)
260 flags &= ~AT_SYMLINK_FOLLOW;
262 flags |= AT_SYMLINK_NOFOLLOW;
263 if (fstatat(fd, filename, &a, flags) < 0)
266 if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0)
269 /* A directory with same device and inode as its parent? Must
270 * be the root directory */
271 if (a.st_dev == b.st_dev &&
272 a.st_ino == b.st_ino)
275 return check_st_dev && (a.st_dev != b.st_dev);
278 /* flags can be AT_SYMLINK_FOLLOW or 0 */
279 int path_is_mount_point(const char *t, const char *root, int flags) {
280 _cleanup_free_ char *canonical = NULL, *parent = NULL;
281 _cleanup_close_ int fd = -1;
285 assert((flags & ~AT_SYMLINK_FOLLOW) == 0);
287 if (path_equal(t, "/"))
290 /* we need to resolve symlinks manually, we can't just rely on
291 * fd_is_mount_point() to do that for us; if we have a structure like
292 * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we
293 * look at needs to be /usr, not /. */
294 if (flags & AT_SYMLINK_FOLLOW) {
295 r = chase_symlinks(t, root, 0, &canonical);
302 parent = dirname_malloc(t);
306 fd = openat(AT_FDCWD, parent, O_DIRECTORY|O_CLOEXEC|O_PATH);
310 return fd_is_mount_point(fd, last_path_component(t), flags);
313 int path_get_mnt_id(const char *path, int *ret) {
316 r = name_to_handle_at_loop(AT_FDCWD, path, NULL, ret, 0);
317 if (IN_SET(r, -EOPNOTSUPP, -ENOSYS, -EACCES, -EPERM, -EOVERFLOW, -EINVAL)) /* kernel/fs don't support this, or seccomp blocks access, or untriggered mount, or name_to_handle_at() is flaky */
318 return fd_fdinfo_mnt_id(AT_FDCWD, path, 0, ret);
323 #if 0 /// UNNEEDED by elogind
324 int umount_recursive(const char *prefix, int flags) {
328 /* Try to umount everything recursively below a
329 * directory. Also, take care of stacked mounts, and keep
330 * unmounting them until they are gone. */
333 _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
338 proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
339 if (!proc_self_mountinfo)
342 (void) __fsetlocking(proc_self_mountinfo, FSETLOCKING_BYCALLER);
345 _cleanup_free_ char *path = NULL, *p = NULL;
348 k = fscanf(proc_self_mountinfo,
349 "%*s " /* (1) mount id */
350 "%*s " /* (2) parent id */
351 "%*s " /* (3) major:minor */
352 "%*s " /* (4) root */
353 "%ms " /* (5) mount point */
354 "%*s" /* (6) mount options */
355 "%*[^-]" /* (7) optional fields */
356 "- " /* (8) separator */
357 "%*s " /* (9) file system type */
358 "%*s" /* (10) mount source */
359 "%*s" /* (11) mount options 2 */
360 "%*[^\n]", /* some rubbish at the end */
369 r = cunescape(path, UNESCAPE_RELAX, &p);
373 if (!path_startswith(p, prefix))
376 if (umount2(p, flags) < 0) {
377 r = log_debug_errno(errno, "Failed to umount %s: %m", p);
381 log_debug("Successfully unmounted %s", p);
394 static int get_mount_flags(const char *path, unsigned long *flags) {
397 if (statvfs(path, &buf) < 0)
403 /* Use this function only if do you have direct access to /proc/self/mountinfo
404 * and need the caller to open it for you. This is the case when /proc is
405 * masked or not mounted. Otherwise, use bind_remount_recursive. */
406 int bind_remount_recursive_with_mountinfo(const char *prefix, bool ro, char **blacklist, FILE *proc_self_mountinfo) {
407 _cleanup_set_free_free_ Set *done = NULL;
408 _cleanup_free_ char *cleaned = NULL;
411 assert(proc_self_mountinfo);
413 /* Recursively remount a directory (and all its submounts) read-only or read-write. If the directory is already
414 * mounted, we reuse the mount and simply mark it MS_BIND|MS_RDONLY (or remove the MS_RDONLY for read-write
415 * operation). If it isn't we first make it one. Afterwards we apply MS_BIND|MS_RDONLY (or remove MS_RDONLY) to
416 * all submounts we can access, too. When mounts are stacked on the same mount point we only care for each
417 * individual "top-level" mount on each point, as we cannot influence/access the underlying mounts anyway. We
418 * do not have any effect on future submounts that might get propagated, they migt be writable. This includes
419 * future submounts that have been triggered via autofs.
421 * If the "blacklist" parameter is specified it may contain a list of subtrees to exclude from the
422 * remount operation. Note that we'll ignore the blacklist for the top-level path. */
424 cleaned = strdup(prefix);
428 path_kill_slashes(cleaned);
430 done = set_new(&path_hash_ops);
435 _cleanup_set_free_free_ Set *todo = NULL;
436 bool top_autofs = false;
438 unsigned long orig_flags;
440 todo = set_new(&path_hash_ops);
444 rewind(proc_self_mountinfo);
447 _cleanup_free_ char *path = NULL, *p = NULL, *type = NULL;
450 k = fscanf(proc_self_mountinfo,
451 "%*s " /* (1) mount id */
452 "%*s " /* (2) parent id */
453 "%*s " /* (3) major:minor */
454 "%*s " /* (4) root */
455 "%ms " /* (5) mount point */
456 "%*s" /* (6) mount options (superblock) */
457 "%*[^-]" /* (7) optional fields */
458 "- " /* (8) separator */
459 "%ms " /* (9) file system type */
460 "%*s" /* (10) mount source */
461 "%*s" /* (11) mount options (bind mount) */
462 "%*[^\n]", /* some rubbish at the end */
472 r = cunescape(path, UNESCAPE_RELAX, &p);
476 if (!path_startswith(p, cleaned))
479 /* Ignore this mount if it is blacklisted, but only if it isn't the top-level mount we shall
481 if (!path_equal(cleaned, p)) {
482 bool blacklisted = false;
485 STRV_FOREACH(i, blacklist) {
487 if (path_equal(*i, cleaned))
490 if (!path_startswith(*i, cleaned))
493 if (path_startswith(p, *i)) {
495 log_debug("Not remounting %s, because blacklisted by %s, called for %s", p, *i, cleaned);
503 /* Let's ignore autofs mounts. If they aren't
504 * triggered yet, we want to avoid triggering
505 * them, as we don't make any guarantees for
506 * future submounts anyway. If they are
507 * already triggered, then we will find
508 * another entry for this. */
509 if (streq(type, "autofs")) {
510 top_autofs = top_autofs || path_equal(cleaned, p);
514 if (!set_contains(done, p)) {
515 r = set_consume(todo, p);
524 /* If we have no submounts to process anymore and if
525 * the root is either already done, or an autofs, we
527 if (set_isempty(todo) &&
528 (top_autofs || set_contains(done, cleaned)))
531 if (!set_contains(done, cleaned) &&
532 !set_contains(todo, cleaned)) {
533 /* The prefix directory itself is not yet a mount, make it one. */
534 if (mount(cleaned, cleaned, NULL, MS_BIND|MS_REC, NULL) < 0)
538 (void) get_mount_flags(cleaned, &orig_flags);
539 orig_flags &= ~MS_RDONLY;
541 if (mount(NULL, prefix, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0)
544 log_debug("Made top-level directory %s a mount point.", prefix);
550 r = set_consume(done, x);
555 while ((x = set_steal_first(todo))) {
557 r = set_consume(done, x);
558 if (IN_SET(r, 0, -EEXIST))
563 /* Deal with mount points that are obstructed by a later mount */
564 r = path_is_mount_point(x, NULL, 0);
565 if (IN_SET(r, 0, -ENOENT))
570 /* Try to reuse the original flag set */
572 (void) get_mount_flags(x, &orig_flags);
573 orig_flags &= ~MS_RDONLY;
575 if (mount(NULL, x, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0)
578 log_debug("Remounted %s read-only.", x);
583 int bind_remount_recursive(const char *prefix, bool ro, char **blacklist) {
584 _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
586 proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
587 if (!proc_self_mountinfo)
590 (void) __fsetlocking(proc_self_mountinfo, FSETLOCKING_BYCALLER);
592 return bind_remount_recursive_with_mountinfo(prefix, ro, blacklist, proc_self_mountinfo);
595 int mount_move_root(const char *path) {
601 if (mount(path, "/", NULL, MS_MOVE, NULL) < 0)
613 bool fstype_is_network(const char *fstype) {
616 x = startswith(fstype, "fuse.");
620 return STR_IN_SET(fstype,
632 "pvfs2", /* OrangeFS */
637 bool fstype_is_api_vfs(const char *fstype) {
638 return STR_IN_SET(fstype,
661 bool fstype_is_ro(const char *fstype) {
662 /* All Linux file systems that are necessarily read-only */
663 return STR_IN_SET(fstype,
669 bool fstype_can_discard(const char *fstype) {
670 return STR_IN_SET(fstype,
677 bool fstype_can_uid_gid(const char *fstype) {
679 /* All file systems that have a uid=/gid= mount option that fixates the owners of all files and directories,
680 * current and future. */
682 return STR_IN_SET(fstype,
693 int repeat_unmount(const char *path, int flags) {
698 /* If there are multiple mounts on a mount point, this
699 * removes them all */
702 if (umount2(path, flags) < 0) {
715 const char* mode_to_inaccessible_node(mode_t mode) {
716 /* This function maps a node type to the correspondent inaccessible node type.
717 * Character and block inaccessible devices may not be created (because major=0 and minor=0),
718 * in such case we map character and block devices to the inaccessible node type socket. */
719 switch(mode & S_IFMT) {
721 return "/run/systemd/inaccessible/reg";
723 return "/run/systemd/inaccessible/dir";
725 if (access("/run/systemd/inaccessible/chr", F_OK) == 0)
726 return "/run/systemd/inaccessible/chr";
727 return "/run/systemd/inaccessible/sock";
729 if (access("/run/systemd/inaccessible/blk", F_OK) == 0)
730 return "/run/systemd/inaccessible/blk";
731 return "/run/systemd/inaccessible/sock";
733 return "/run/systemd/inaccessible/fifo";
735 return "/run/systemd/inaccessible/sock";
740 #if 0 /// UNNEEDED by elogind
741 #define FLAG(name) (flags & name ? STRINGIFY(name) "|" : "")
742 static char* mount_flags_to_string(long unsigned flags) {
744 _cleanup_free_ char *y = NULL;
745 long unsigned overflow;
747 overflow = flags & ~(MS_RDONLY |
772 if (flags == 0 || overflow != 0)
773 if (asprintf(&y, "%lx", overflow) < 0)
776 x = strjoin(FLAG(MS_RDONLY),
780 FLAG(MS_SYNCHRONOUS),
798 FLAG(MS_STRICTATIME),
804 x[strlen(x) - 1] = '\0'; /* truncate the last | */
814 const char *options) {
816 _cleanup_free_ char *fl = NULL;
818 fl = mount_flags_to_string(flags);
820 if ((flags & MS_REMOUNT) && !what && !type)
821 log_debug("Remounting %s (%s \"%s\")...",
822 where, strnull(fl), strempty(options));
823 else if (!what && !type)
824 log_debug("Mounting %s (%s \"%s\")...",
825 where, strnull(fl), strempty(options));
826 else if ((flags & MS_BIND) && !type)
827 log_debug("Bind-mounting %s on %s (%s \"%s\")...",
828 what, where, strnull(fl), strempty(options));
829 else if (flags & MS_MOVE)
830 log_debug("Moving mount %s → %s (%s \"%s\")...",
831 what, where, strnull(fl), strempty(options));
833 log_debug("Mounting %s on %s (%s \"%s\")...",
834 strna(type), where, strnull(fl), strempty(options));
835 if (mount(what, where, type, flags, options) < 0)
836 return log_full_errno(error_log_level, errno,
837 "Failed to mount %s on %s (%s \"%s\"): %m",
838 strna(type), where, strnull(fl), strempty(options));
842 int umount_verbose(const char *what) {
843 log_debug("Umounting %s...", what);
844 if (umount(what) < 0)
845 return log_error_errno(errno, "Failed to unmount %s: %m", what);
850 const char *mount_propagation_flags_to_string(unsigned long flags) {
852 switch (flags & (MS_SHARED|MS_SLAVE|MS_PRIVATE)) {
867 int mount_propagation_flags_from_string(const char *name, unsigned long *ret) {
871 else if (streq(name, "shared"))
873 else if (streq(name, "slave"))
875 else if (streq(name, "private"))