From 4349cd7c1d153c4ffa23cf1cff1644e0afa9bcf0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 26 Oct 2015 18:44:13 +0100 Subject: util-lib: move mount related utility calls to mount-util.[ch] --- Makefile.am | 2 + src/basic/mount-util.c | 483 ++++++++++++++++++++++++++++ src/basic/mount-util.h | 36 +++ src/basic/path-util.c | 199 ------------ src/basic/path-util.h | 2 - src/basic/rm-rf.c | 1 + src/basic/util.c | 249 -------------- src/basic/util.h | 10 - src/core/automount.c | 1 + src/core/machine-id-setup.c | 3 +- src/core/mount-setup.c | 21 +- src/core/namespace.c | 1 + src/cryptsetup/cryptsetup.c | 1 + src/fstab-generator/fstab-generator.c | 1 + src/gpt-auto-generator/gpt-auto-generator.c | 1 + src/login/logind-user.c | 1 + src/nspawn/nspawn-mount.c | 1 + src/nspawn/nspawn.c | 1 + src/remount-fs/remount-fs.c | 7 +- src/shared/condition.c | 1 + src/shared/fstab-util.c | 1 + src/shared/generator.c | 1 + src/shared/machine-pool.c | 1 + src/test/test-path-util.c | 1 + 24 files changed, 552 insertions(+), 474 deletions(-) create mode 100644 src/basic/mount-util.c create mode 100644 src/basic/mount-util.h diff --git a/Makefile.am b/Makefile.am index 26d5587b11..275b856191 100644 --- a/Makefile.am +++ b/Makefile.am @@ -791,6 +791,8 @@ libbasic_la_SOURCES = \ src/basic/parse-util.h \ src/basic/user-util.c \ src/basic/user-util.h \ + src/basic/mount-util.c \ + src/basic/mount-util.h \ src/basic/hexdecoct.c \ src/basic/hexdecoct.h \ src/basic/extract-word.c \ diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c new file mode 100644 index 0000000000..6b33d43024 --- /dev/null +++ b/src/basic/mount-util.c @@ -0,0 +1,483 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "escape.h" +#include "fd-util.h" +#include "fileio.h" +#include "mount-util.h" +#include "parse-util.h" +#include "path-util.h" +#include "set.h" +#include "string-util.h" +#include "util.h" + +static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) { + char path[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)]; + _cleanup_free_ char *fdinfo = NULL; + _cleanup_close_ int subfd = -1; + char *p; + int r; + + if ((flags & AT_EMPTY_PATH) && isempty(filename)) + xsprintf(path, "/proc/self/fdinfo/%i", fd); + else { + subfd = openat(fd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH); + if (subfd < 0) + return -errno; + + xsprintf(path, "/proc/self/fdinfo/%i", subfd); + } + + r = read_full_file(path, &fdinfo, NULL); + if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */ + return -EOPNOTSUPP; + if (r < 0) + return -errno; + + p = startswith(fdinfo, "mnt_id:"); + if (!p) { + p = strstr(fdinfo, "\nmnt_id:"); + if (!p) /* The mnt_id field is a relatively new addition */ + return -EOPNOTSUPP; + + p += 8; + } + + p += strspn(p, WHITESPACE); + p[strcspn(p, WHITESPACE)] = 0; + + return safe_atoi(p, mnt_id); +} + + +int fd_is_mount_point(int fd, const char *filename, int flags) { + union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT; + int mount_id = -1, mount_id_parent = -1; + bool nosupp = false, check_st_dev = true; + struct stat a, b; + int r; + + assert(fd >= 0); + assert(filename); + + /* First we will try the name_to_handle_at() syscall, which + * tells us the mount id and an opaque file "handle". It is + * not supported everywhere though (kernel compile-time + * option, not all file systems are hooked up). If it works + * the mount id is usually good enough to tell us whether + * something is a mount point. + * + * If that didn't work we will try to read the mount id from + * /proc/self/fdinfo/. This is almost as good as + * name_to_handle_at(), however, does not return the + * opaque file handle. The opaque file handle is pretty useful + * to detect the root directory, which we should always + * consider a mount point. Hence we use this only as + * fallback. Exporting the mnt_id in fdinfo is a pretty recent + * kernel addition. + * + * As last fallback we do traditional fstat() based st_dev + * comparisons. This is how things were traditionally done, + * but unionfs breaks breaks this since it exposes file + * systems with a variety of st_dev reported. Also, btrfs + * subvolumes have different st_dev, even though they aren't + * real mounts of their own. */ + + r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags); + if (r < 0) { + if (errno == ENOSYS) + /* This kernel does not support name_to_handle_at() + * fall back to simpler logic. */ + goto fallback_fdinfo; + else if (errno == EOPNOTSUPP) + /* This kernel or file system does not support + * name_to_handle_at(), hence let's see if the + * upper fs supports it (in which case it is a + * mount point), otherwise fallback to the + * traditional stat() logic */ + nosupp = true; + else + return -errno; + } + + r = name_to_handle_at(fd, "", &h_parent.handle, &mount_id_parent, AT_EMPTY_PATH); + if (r < 0) { + if (errno == EOPNOTSUPP) { + if (nosupp) + /* Neither parent nor child do name_to_handle_at()? + We have no choice but to fall back. */ + goto fallback_fdinfo; + else + /* The parent can't do name_to_handle_at() but the + * directory we are interested in can? + * If so, it must be a mount point. */ + return 1; + } else + return -errno; + } + + /* The parent can do name_to_handle_at() but the + * directory we are interested in can't? If so, it + * must be a mount point. */ + if (nosupp) + return 1; + + /* If the file handle for the directory we are + * interested in and its parent are identical, we + * assume this is the root directory, which is a mount + * point. */ + + if (h.handle.handle_bytes == h_parent.handle.handle_bytes && + h.handle.handle_type == h_parent.handle.handle_type && + memcmp(h.handle.f_handle, h_parent.handle.f_handle, h.handle.handle_bytes) == 0) + return 1; + + return mount_id != mount_id_parent; + +fallback_fdinfo: + r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id); + if (r == -EOPNOTSUPP) + goto fallback_fstat; + if (r < 0) + return r; + + r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent); + if (r < 0) + return r; + + if (mount_id != mount_id_parent) + return 1; + + /* Hmm, so, the mount ids are the same. This leaves one + * special case though for the root file system. For that, + * let's see if the parent directory has the same inode as we + * are interested in. Hence, let's also do fstat() checks now, + * too, but avoid the st_dev comparisons, since they aren't + * that useful on unionfs mounts. */ + check_st_dev = false; + +fallback_fstat: + /* yay for fstatat() taking a different set of flags than the other + * _at() above */ + if (flags & AT_SYMLINK_FOLLOW) + flags &= ~AT_SYMLINK_FOLLOW; + else + flags |= AT_SYMLINK_NOFOLLOW; + if (fstatat(fd, filename, &a, flags) < 0) + return -errno; + + if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0) + return -errno; + + /* A directory with same device and inode as its parent? Must + * be the root directory */ + if (a.st_dev == b.st_dev && + a.st_ino == b.st_ino) + return 1; + + return check_st_dev && (a.st_dev != b.st_dev); +} + +/* flags can be AT_SYMLINK_FOLLOW or 0 */ +int path_is_mount_point(const char *t, int flags) { + _cleanup_close_ int fd = -1; + _cleanup_free_ char *canonical = NULL, *parent = NULL; + + assert(t); + + if (path_equal(t, "/")) + return 1; + + /* we need to resolve symlinks manually, we can't just rely on + * fd_is_mount_point() to do that for us; if we have a structure like + * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we + * look at needs to be /usr, not /. */ + if (flags & AT_SYMLINK_FOLLOW) { + canonical = canonicalize_file_name(t); + if (!canonical) + return -errno; + + t = canonical; + } + + parent = dirname_malloc(t); + if (!parent) + return -ENOMEM; + + fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH); + if (fd < 0) + return -errno; + + return fd_is_mount_point(fd, basename(t), flags); +} + +int umount_recursive(const char *prefix, int flags) { + bool again; + int n = 0, r; + + /* Try to umount everything recursively below a + * directory. Also, take care of stacked mounts, and keep + * unmounting them until they are gone. */ + + do { + _cleanup_fclose_ FILE *proc_self_mountinfo = NULL; + + again = false; + r = 0; + + proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"); + if (!proc_self_mountinfo) + return -errno; + + for (;;) { + _cleanup_free_ char *path = NULL, *p = NULL; + int k; + + k = fscanf(proc_self_mountinfo, + "%*s " /* (1) mount id */ + "%*s " /* (2) parent id */ + "%*s " /* (3) major:minor */ + "%*s " /* (4) root */ + "%ms " /* (5) mount point */ + "%*s" /* (6) mount options */ + "%*[^-]" /* (7) optional fields */ + "- " /* (8) separator */ + "%*s " /* (9) file system type */ + "%*s" /* (10) mount source */ + "%*s" /* (11) mount options 2 */ + "%*[^\n]", /* some rubbish at the end */ + &path); + if (k != 1) { + if (k == EOF) + break; + + continue; + } + + r = cunescape(path, UNESCAPE_RELAX, &p); + if (r < 0) + return r; + + if (!path_startswith(p, prefix)) + continue; + + if (umount2(p, flags) < 0) { + r = -errno; + continue; + } + + again = true; + n++; + + break; + } + + } while (again); + + return r ? r : n; +} + +static int get_mount_flags(const char *path, unsigned long *flags) { + struct statvfs buf; + + if (statvfs(path, &buf) < 0) + return -errno; + *flags = buf.f_flag; + return 0; +} + +int bind_remount_recursive(const char *prefix, bool ro) { + _cleanup_set_free_free_ Set *done = NULL; + _cleanup_free_ char *cleaned = NULL; + int r; + + /* Recursively remount a directory (and all its submounts) + * read-only or read-write. If the directory is already + * mounted, we reuse the mount and simply mark it + * MS_BIND|MS_RDONLY (or remove the MS_RDONLY for read-write + * operation). If it isn't we first make it one. Afterwards we + * apply MS_BIND|MS_RDONLY (or remove MS_RDONLY) to all + * submounts we can access, too. When mounts are stacked on + * the same mount point we only care for each individual + * "top-level" mount on each point, as we cannot + * influence/access the underlying mounts anyway. We do not + * have any effect on future submounts that might get + * propagated, they migt be writable. This includes future + * submounts that have been triggered via autofs. */ + + cleaned = strdup(prefix); + if (!cleaned) + return -ENOMEM; + + path_kill_slashes(cleaned); + + done = set_new(&string_hash_ops); + if (!done) + return -ENOMEM; + + for (;;) { + _cleanup_fclose_ FILE *proc_self_mountinfo = NULL; + _cleanup_set_free_free_ Set *todo = NULL; + bool top_autofs = false; + char *x; + unsigned long orig_flags; + + todo = set_new(&string_hash_ops); + if (!todo) + return -ENOMEM; + + proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"); + if (!proc_self_mountinfo) + return -errno; + + for (;;) { + _cleanup_free_ char *path = NULL, *p = NULL, *type = NULL; + int k; + + k = fscanf(proc_self_mountinfo, + "%*s " /* (1) mount id */ + "%*s " /* (2) parent id */ + "%*s " /* (3) major:minor */ + "%*s " /* (4) root */ + "%ms " /* (5) mount point */ + "%*s" /* (6) mount options (superblock) */ + "%*[^-]" /* (7) optional fields */ + "- " /* (8) separator */ + "%ms " /* (9) file system type */ + "%*s" /* (10) mount source */ + "%*s" /* (11) mount options (bind mount) */ + "%*[^\n]", /* some rubbish at the end */ + &path, + &type); + if (k != 2) { + if (k == EOF) + break; + + continue; + } + + r = cunescape(path, UNESCAPE_RELAX, &p); + if (r < 0) + return r; + + /* Let's ignore autofs mounts. If they aren't + * triggered yet, we want to avoid triggering + * them, as we don't make any guarantees for + * future submounts anyway. If they are + * already triggered, then we will find + * another entry for this. */ + if (streq(type, "autofs")) { + top_autofs = top_autofs || path_equal(cleaned, p); + continue; + } + + if (path_startswith(p, cleaned) && + !set_contains(done, p)) { + + r = set_consume(todo, p); + p = NULL; + + if (r == -EEXIST) + continue; + if (r < 0) + return r; + } + } + + /* If we have no submounts to process anymore and if + * the root is either already done, or an autofs, we + * are done */ + if (set_isempty(todo) && + (top_autofs || set_contains(done, cleaned))) + return 0; + + if (!set_contains(done, cleaned) && + !set_contains(todo, cleaned)) { + /* The prefix directory itself is not yet a + * mount, make it one. */ + if (mount(cleaned, cleaned, NULL, MS_BIND|MS_REC, NULL) < 0) + return -errno; + + orig_flags = 0; + (void) get_mount_flags(cleaned, &orig_flags); + orig_flags &= ~MS_RDONLY; + + if (mount(NULL, prefix, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) + return -errno; + + x = strdup(cleaned); + if (!x) + return -ENOMEM; + + r = set_consume(done, x); + if (r < 0) + return r; + } + + while ((x = set_steal_first(todo))) { + + r = set_consume(done, x); + if (r == -EEXIST || r == 0) + continue; + if (r < 0) + return r; + + /* Try to reuse the original flag set, but + * don't care for errors, in case of + * obstructed mounts */ + orig_flags = 0; + (void) get_mount_flags(x, &orig_flags); + orig_flags &= ~MS_RDONLY; + + if (mount(NULL, x, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) { + + /* Deal with mount points that are + * obstructed by a later mount */ + + if (errno != ENOENT) + return -errno; + } + + } + } +} + +int mount_move_root(const char *path) { + assert(path); + + if (chdir(path) < 0) + return -errno; + + if (mount(path, "/", NULL, MS_MOVE, NULL) < 0) + return -errno; + + if (chroot(".") < 0) + return -errno; + + if (chdir("/") < 0) + return -errno; + + return 0; +} diff --git a/src/basic/mount-util.h b/src/basic/mount-util.h new file mode 100644 index 0000000000..b415d00e2f --- /dev/null +++ b/src/basic/mount-util.h @@ -0,0 +1,36 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +int fd_is_mount_point(int fd, const char *filename, int flags); +int path_is_mount_point(const char *path, int flags); + +int umount_recursive(const char *target, int flags); +int bind_remount_recursive(const char *prefix, bool ro); + +int mount_move_root(const char *path); + +DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent); +#define _cleanup_endmntent_ _cleanup_(endmntentp) diff --git a/src/basic/path-util.c b/src/basic/path-util.c index 7abb3a7b9e..b1cab7356c 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -454,205 +454,6 @@ char* path_join(const char *root, const char *path, const char *rest) { NULL); } -static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) { - char path[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)]; - _cleanup_free_ char *fdinfo = NULL; - _cleanup_close_ int subfd = -1; - char *p; - int r; - - if ((flags & AT_EMPTY_PATH) && isempty(filename)) - xsprintf(path, "/proc/self/fdinfo/%i", fd); - else { - subfd = openat(fd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH); - if (subfd < 0) - return -errno; - - xsprintf(path, "/proc/self/fdinfo/%i", subfd); - } - - r = read_full_file(path, &fdinfo, NULL); - if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */ - return -EOPNOTSUPP; - if (r < 0) - return -errno; - - p = startswith(fdinfo, "mnt_id:"); - if (!p) { - p = strstr(fdinfo, "\nmnt_id:"); - if (!p) /* The mnt_id field is a relatively new addition */ - return -EOPNOTSUPP; - - p += 8; - } - - p += strspn(p, WHITESPACE); - p[strcspn(p, WHITESPACE)] = 0; - - return safe_atoi(p, mnt_id); -} - -int fd_is_mount_point(int fd, const char *filename, int flags) { - union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT; - int mount_id = -1, mount_id_parent = -1; - bool nosupp = false, check_st_dev = true; - struct stat a, b; - int r; - - assert(fd >= 0); - assert(filename); - - /* First we will try the name_to_handle_at() syscall, which - * tells us the mount id and an opaque file "handle". It is - * not supported everywhere though (kernel compile-time - * option, not all file systems are hooked up). If it works - * the mount id is usually good enough to tell us whether - * something is a mount point. - * - * If that didn't work we will try to read the mount id from - * /proc/self/fdinfo/. This is almost as good as - * name_to_handle_at(), however, does not return the - * opaque file handle. The opaque file handle is pretty useful - * to detect the root directory, which we should always - * consider a mount point. Hence we use this only as - * fallback. Exporting the mnt_id in fdinfo is a pretty recent - * kernel addition. - * - * As last fallback we do traditional fstat() based st_dev - * comparisons. This is how things were traditionally done, - * but unionfs breaks breaks this since it exposes file - * systems with a variety of st_dev reported. Also, btrfs - * subvolumes have different st_dev, even though they aren't - * real mounts of their own. */ - - r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags); - if (r < 0) { - if (errno == ENOSYS) - /* This kernel does not support name_to_handle_at() - * fall back to simpler logic. */ - goto fallback_fdinfo; - else if (errno == EOPNOTSUPP) - /* This kernel or file system does not support - * name_to_handle_at(), hence let's see if the - * upper fs supports it (in which case it is a - * mount point), otherwise fallback to the - * traditional stat() logic */ - nosupp = true; - else - return -errno; - } - - r = name_to_handle_at(fd, "", &h_parent.handle, &mount_id_parent, AT_EMPTY_PATH); - if (r < 0) { - if (errno == EOPNOTSUPP) { - if (nosupp) - /* Neither parent nor child do name_to_handle_at()? - We have no choice but to fall back. */ - goto fallback_fdinfo; - else - /* The parent can't do name_to_handle_at() but the - * directory we are interested in can? - * If so, it must be a mount point. */ - return 1; - } else - return -errno; - } - - /* The parent can do name_to_handle_at() but the - * directory we are interested in can't? If so, it - * must be a mount point. */ - if (nosupp) - return 1; - - /* If the file handle for the directory we are - * interested in and its parent are identical, we - * assume this is the root directory, which is a mount - * point. */ - - if (h.handle.handle_bytes == h_parent.handle.handle_bytes && - h.handle.handle_type == h_parent.handle.handle_type && - memcmp(h.handle.f_handle, h_parent.handle.f_handle, h.handle.handle_bytes) == 0) - return 1; - - return mount_id != mount_id_parent; - -fallback_fdinfo: - r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id); - if (r == -EOPNOTSUPP) - goto fallback_fstat; - if (r < 0) - return r; - - r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent); - if (r < 0) - return r; - - if (mount_id != mount_id_parent) - return 1; - - /* Hmm, so, the mount ids are the same. This leaves one - * special case though for the root file system. For that, - * let's see if the parent directory has the same inode as we - * are interested in. Hence, let's also do fstat() checks now, - * too, but avoid the st_dev comparisons, since they aren't - * that useful on unionfs mounts. */ - check_st_dev = false; - -fallback_fstat: - /* yay for fstatat() taking a different set of flags than the other - * _at() above */ - if (flags & AT_SYMLINK_FOLLOW) - flags &= ~AT_SYMLINK_FOLLOW; - else - flags |= AT_SYMLINK_NOFOLLOW; - if (fstatat(fd, filename, &a, flags) < 0) - return -errno; - - if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0) - return -errno; - - /* A directory with same device and inode as its parent? Must - * be the root directory */ - if (a.st_dev == b.st_dev && - a.st_ino == b.st_ino) - return 1; - - return check_st_dev && (a.st_dev != b.st_dev); -} - -/* flags can be AT_SYMLINK_FOLLOW or 0 */ -int path_is_mount_point(const char *t, int flags) { - _cleanup_close_ int fd = -1; - _cleanup_free_ char *canonical = NULL, *parent = NULL; - - assert(t); - - if (path_equal(t, "/")) - return 1; - - /* we need to resolve symlinks manually, we can't just rely on - * fd_is_mount_point() to do that for us; if we have a structure like - * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we - * look at needs to be /usr, not /. */ - if (flags & AT_SYMLINK_FOLLOW) { - canonical = canonicalize_file_name(t); - if (!canonical) - return -errno; - - t = canonical; - } - - parent = dirname_malloc(t); - if (!parent) - return -ENOMEM; - - fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH); - if (fd < 0) - return -errno; - - return fd_is_mount_point(fd, basename(t), flags); -} - int path_is_read_only_fs(const char *path) { struct statvfs st; diff --git a/src/basic/path-util.h b/src/basic/path-util.h index 708cdc1707..1ff47ab193 100644 --- a/src/basic/path-util.h +++ b/src/basic/path-util.h @@ -52,8 +52,6 @@ int path_strv_make_absolute_cwd(char **l); char** path_strv_resolve(char **l, const char *prefix); char** path_strv_resolve_uniq(char **l, const char *prefix); -int fd_is_mount_point(int fd, const char *filename, int flags); -int path_is_mount_point(const char *path, int flags); int path_is_read_only_fs(const char *path); int path_is_os_tree(const char *path); diff --git a/src/basic/rm-rf.c b/src/basic/rm-rf.c index a5daa23f86..f1850ea8a3 100644 --- a/src/basic/rm-rf.c +++ b/src/basic/rm-rf.c @@ -21,6 +21,7 @@ #include "btrfs-util.h" #include "fd-util.h" +#include "mount-util.h" #include "path-util.h" #include "rm-rf.h" #include "string-util.h" diff --git a/src/basic/util.c b/src/basic/util.c index 607d9cd933..06fe307ba0 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -2137,237 +2137,6 @@ int update_reboot_param_file(const char *param) { return 0; } -int umount_recursive(const char *prefix, int flags) { - bool again; - int n = 0, r; - - /* Try to umount everything recursively below a - * directory. Also, take care of stacked mounts, and keep - * unmounting them until they are gone. */ - - do { - _cleanup_fclose_ FILE *proc_self_mountinfo = NULL; - - again = false; - r = 0; - - proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"); - if (!proc_self_mountinfo) - return -errno; - - for (;;) { - _cleanup_free_ char *path = NULL, *p = NULL; - int k; - - k = fscanf(proc_self_mountinfo, - "%*s " /* (1) mount id */ - "%*s " /* (2) parent id */ - "%*s " /* (3) major:minor */ - "%*s " /* (4) root */ - "%ms " /* (5) mount point */ - "%*s" /* (6) mount options */ - "%*[^-]" /* (7) optional fields */ - "- " /* (8) separator */ - "%*s " /* (9) file system type */ - "%*s" /* (10) mount source */ - "%*s" /* (11) mount options 2 */ - "%*[^\n]", /* some rubbish at the end */ - &path); - if (k != 1) { - if (k == EOF) - break; - - continue; - } - - r = cunescape(path, UNESCAPE_RELAX, &p); - if (r < 0) - return r; - - if (!path_startswith(p, prefix)) - continue; - - if (umount2(p, flags) < 0) { - r = -errno; - continue; - } - - again = true; - n++; - - break; - } - - } while (again); - - return r ? r : n; -} - -static int get_mount_flags(const char *path, unsigned long *flags) { - struct statvfs buf; - - if (statvfs(path, &buf) < 0) - return -errno; - *flags = buf.f_flag; - return 0; -} - -int bind_remount_recursive(const char *prefix, bool ro) { - _cleanup_set_free_free_ Set *done = NULL; - _cleanup_free_ char *cleaned = NULL; - int r; - - /* Recursively remount a directory (and all its submounts) - * read-only or read-write. If the directory is already - * mounted, we reuse the mount and simply mark it - * MS_BIND|MS_RDONLY (or remove the MS_RDONLY for read-write - * operation). If it isn't we first make it one. Afterwards we - * apply MS_BIND|MS_RDONLY (or remove MS_RDONLY) to all - * submounts we can access, too. When mounts are stacked on - * the same mount point we only care for each individual - * "top-level" mount on each point, as we cannot - * influence/access the underlying mounts anyway. We do not - * have any effect on future submounts that might get - * propagated, they migt be writable. This includes future - * submounts that have been triggered via autofs. */ - - cleaned = strdup(prefix); - if (!cleaned) - return -ENOMEM; - - path_kill_slashes(cleaned); - - done = set_new(&string_hash_ops); - if (!done) - return -ENOMEM; - - for (;;) { - _cleanup_fclose_ FILE *proc_self_mountinfo = NULL; - _cleanup_set_free_free_ Set *todo = NULL; - bool top_autofs = false; - char *x; - unsigned long orig_flags; - - todo = set_new(&string_hash_ops); - if (!todo) - return -ENOMEM; - - proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"); - if (!proc_self_mountinfo) - return -errno; - - for (;;) { - _cleanup_free_ char *path = NULL, *p = NULL, *type = NULL; - int k; - - k = fscanf(proc_self_mountinfo, - "%*s " /* (1) mount id */ - "%*s " /* (2) parent id */ - "%*s " /* (3) major:minor */ - "%*s " /* (4) root */ - "%ms " /* (5) mount point */ - "%*s" /* (6) mount options (superblock) */ - "%*[^-]" /* (7) optional fields */ - "- " /* (8) separator */ - "%ms " /* (9) file system type */ - "%*s" /* (10) mount source */ - "%*s" /* (11) mount options (bind mount) */ - "%*[^\n]", /* some rubbish at the end */ - &path, - &type); - if (k != 2) { - if (k == EOF) - break; - - continue; - } - - r = cunescape(path, UNESCAPE_RELAX, &p); - if (r < 0) - return r; - - /* Let's ignore autofs mounts. If they aren't - * triggered yet, we want to avoid triggering - * them, as we don't make any guarantees for - * future submounts anyway. If they are - * already triggered, then we will find - * another entry for this. */ - if (streq(type, "autofs")) { - top_autofs = top_autofs || path_equal(cleaned, p); - continue; - } - - if (path_startswith(p, cleaned) && - !set_contains(done, p)) { - - r = set_consume(todo, p); - p = NULL; - - if (r == -EEXIST) - continue; - if (r < 0) - return r; - } - } - - /* If we have no submounts to process anymore and if - * the root is either already done, or an autofs, we - * are done */ - if (set_isempty(todo) && - (top_autofs || set_contains(done, cleaned))) - return 0; - - if (!set_contains(done, cleaned) && - !set_contains(todo, cleaned)) { - /* The prefix directory itself is not yet a - * mount, make it one. */ - if (mount(cleaned, cleaned, NULL, MS_BIND|MS_REC, NULL) < 0) - return -errno; - - orig_flags = 0; - (void) get_mount_flags(cleaned, &orig_flags); - orig_flags &= ~MS_RDONLY; - - if (mount(NULL, prefix, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) - return -errno; - - x = strdup(cleaned); - if (!x) - return -ENOMEM; - - r = set_consume(done, x); - if (r < 0) - return r; - } - - while ((x = set_steal_first(todo))) { - - r = set_consume(done, x); - if (r == -EEXIST || r == 0) - continue; - if (r < 0) - return r; - - /* Try to reuse the original flag set, but - * don't care for errors, in case of - * obstructed mounts */ - orig_flags = 0; - (void) get_mount_flags(x, &orig_flags); - orig_flags &= ~MS_RDONLY; - - if (mount(NULL, x, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) { - - /* Deal with mount points that are - * obstructed by a later mount */ - - if (errno != ENOENT) - return -errno; - } - - } - } -} - int take_password_lock(const char *root) { struct flock flock = { @@ -2710,24 +2479,6 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char return 0; } -int mount_move_root(const char *path) { - assert(path); - - if (chdir(path) < 0) - return -errno; - - if (mount(path, "/", NULL, MS_MOVE, NULL) < 0) - return -errno; - - if (chroot(".") < 0) - return -errno; - - if (chdir("/") < 0) - return -errno; - - return 0; -} - int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink) { char *v; size_t l; diff --git a/src/basic/util.h b/src/basic/util.h index c6c3ba99f2..9388ba7d74 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -279,12 +278,9 @@ static inline void umaskp(mode_t *u) { umask(*u); } -DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent); - #define _cleanup_free_ _cleanup_(freep) #define _cleanup_umask_ _cleanup_(umaskp) #define _cleanup_globfree_ _cleanup_(globfree) -#define _cleanup_endmntent_ _cleanup_(endmntentp) _malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) { if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) @@ -525,10 +521,6 @@ union file_handle_union { int update_reboot_param_file(const char *param); -int umount_recursive(const char *target, int flags); - -int bind_remount_recursive(const char *prefix, bool ro); - int take_password_lock(const char *root); int is_symlink(const char *path); @@ -568,8 +560,6 @@ int syslog_parse_priority(const char **p, int *priority, bool with_facility); int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath); -int mount_move_root(const char *path); - int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink); int fgetxattr_malloc(int fd, const char *name, char **value); diff --git a/src/core/automount.c b/src/core/automount.c index df98711d96..00911118e6 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -39,6 +39,7 @@ #include "io-util.h" #include "label.h" #include "mkdir.h" +#include "mount-util.h" #include "mount.h" #include "parse-util.h" #include "path-util.h" diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c index ea4bdc5414..764728c804 100644 --- a/src/core/machine-id-setup.c +++ b/src/core/machine-id-setup.c @@ -31,12 +31,13 @@ #include "fd-util.h" #include "fileio.h" +#include "hexdecoct.h" #include "io-util.h" #include "log.h" #include "machine-id-setup.h" #include "macro.h" #include "mkdir.h" -#include "hexdecoct.h" +#include "mount-util.h" #include "path-util.h" #include "process-util.h" #include "string-util.h" diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c index 9b16eaa0e2..7486ec3985 100644 --- a/src/core/mount-setup.c +++ b/src/core/mount-setup.c @@ -25,22 +25,23 @@ #include #include -#include "mount-setup.h" -#include "dev-setup.h" #include "bus-util.h" +#include "cgroup-util.h" +#include "dev-setup.h" +#include "efivars.h" +#include "label.h" #include "log.h" #include "macro.h" -#include "util.h" -#include "label.h" -#include "set.h" -#include "strv.h" +#include "missing.h" #include "mkdir.h" +#include "mount-setup.h" +#include "mount-util.h" #include "path-util.h" -#include "missing.h" -#include "virt.h" -#include "efivars.h" +#include "set.h" #include "smack-util.h" -#include "cgroup-util.h" +#include "strv.h" +#include "util.h" +#include "virt.h" typedef enum MountMode { MNT_NONE = 0, diff --git a/src/core/namespace.c b/src/core/namespace.c index 4d11d54bfe..e6c381800b 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -33,6 +33,7 @@ #include "loopback-setup.h" #include "missing.h" #include "mkdir.h" +#include "mount-util.h" #include "namespace.h" #include "path-util.h" #include "selinux-util.h" diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 4c1d8a8e74..8531b6b125 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -32,6 +32,7 @@ #include "escape.h" #include "fileio.h" #include "log.h" +#include "mount-util.h" #include "parse-util.h" #include "path-util.h" #include "string-util.h" diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 732b3d1704..fd0d01153a 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -32,6 +32,7 @@ #include "log.h" #include "mkdir.h" #include "mount-setup.h" +#include "mount-util.h" #include "parse-util.h" #include "path-util.h" #include "special.h" diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index ac6d731753..6440fd654e 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -37,6 +37,7 @@ #include "gpt.h" #include "missing.h" #include "mkdir.h" +#include "mount-util.h" #include "parse-util.h" #include "path-util.h" #include "special.h" diff --git a/src/login/logind-user.c b/src/login/logind-user.c index 9f3af59b54..5a7ae11ec1 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -36,6 +36,7 @@ #include "label.h" #include "logind-user.h" #include "mkdir.h" +#include "mount-util.h" #include "parse-util.h" #include "path-util.h" #include "rm-rf.h" diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c index 5d8172092a..ac9c31b931 100644 --- a/src/nspawn/nspawn-mount.c +++ b/src/nspawn/nspawn-mount.c @@ -26,6 +26,7 @@ #include "escape.h" #include "label.h" #include "mkdir.h" +#include "mount-util.h" #include "nspawn-mount.h" #include "parse-util.h" #include "path-util.h" diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index a4eefe5eb8..c34d52293d 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -69,6 +69,7 @@ #include "macro.h" #include "missing.h" #include "mkdir.h" +#include "mount-util.h" #include "netlink-util.h" #include "nspawn-cgroup.h" #include "nspawn-expose-ports.h" diff --git a/src/remount-fs/remount-fs.c b/src/remount-fs/remount-fs.c index f904e48e75..57f99c9ef0 100644 --- a/src/remount-fs/remount-fs.c +++ b/src/remount-fs/remount-fs.c @@ -26,12 +26,13 @@ #include #include +#include "exit-status.h" #include "log.h" -#include "util.h" +#include "mount-setup.h" +#include "mount-util.h" #include "path-util.h" #include "signal-util.h" -#include "mount-setup.h" -#include "exit-status.h" +#include "util.h" /* Goes through /etc/fstab and remounts all API file systems, applying * options that are in /etc/fstab that systemd might not have diff --git a/src/shared/condition.c b/src/shared/condition.c index 145ea41095..700bc92438 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -36,6 +36,7 @@ #include "fd-util.h" #include "hostname-util.h" #include "ima-util.h" +#include "mount-util.h" #include "parse-util.h" #include "path-util.h" #include "selinux-util.h" diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c index 77faa7bc35..1ea11ea5a4 100644 --- a/src/shared/fstab-util.c +++ b/src/shared/fstab-util.c @@ -21,6 +21,7 @@ #include "device-nodes.h" #include "fstab-util.h" +#include "mount-util.h" #include "parse-util.h" #include "path-util.h" #include "string-util.h" diff --git a/src/shared/generator.c b/src/shared/generator.c index 0a8e282949..203e01318b 100644 --- a/src/shared/generator.c +++ b/src/shared/generator.c @@ -28,6 +28,7 @@ #include "fstab-util.h" #include "generator.h" #include "mkdir.h" +#include "mount-util.h" #include "path-util.h" #include "special.h" #include "string-util.h" diff --git a/src/shared/machine-pool.c b/src/shared/machine-pool.c index 6d726a687a..9270f22479 100644 --- a/src/shared/machine-pool.c +++ b/src/shared/machine-pool.c @@ -36,6 +36,7 @@ #include "signal-util.h" #include "string-util.h" #include "util.h" +#include "mount-util.h" #define VAR_LIB_MACHINES_SIZE_START (1024UL*1024UL*500UL) #define VAR_LIB_MACHINES_FREE_MIN (1024UL*1024UL*750UL) diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index 86d61b2efb..e2979a8710 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -25,6 +25,7 @@ #include "fd-util.h" #include "macro.h" +#include "mount-util.h" #include "path-util.h" #include "rm-rf.h" #include "string-util.h" -- cgit v1.2.3-54-g00ecf