From 6d313367d9ef780560e117e886502a99fa220eac Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Thu, 5 Jun 2014 21:35:35 +0200
Subject: namespace: when setting up an inaccessible mount point, unmounting
 everything below

This has the benefit of not triggering any autofs mount points
unnecessarily.
---
 src/shared/util.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/shared/util.h |  2 ++
 2 files changed, 70 insertions(+)

(limited to 'src/shared')

diff --git a/src/shared/util.c b/src/shared/util.c
index 49185a99a9..011fb36f49 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -54,6 +54,7 @@
 #include <grp.h>
 #include <sys/mman.h>
 #include <sys/vfs.h>
+#include <sys/mount.h>
 #include <linux/magic.h>
 #include <limits.h>
 #include <langinfo.h>
@@ -6502,3 +6503,70 @@ int update_reboot_param_file(const char *param) {
 
         return r;
 }
+
+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;
+                        }
+
+                        p = cunescape(path);
+                        if (!p)
+                                return -ENOMEM;
+
+                        if (!path_startswith(p, prefix))
+                                continue;
+
+                        if (umount2(p, flags) < 0) {
+                                r = -errno;
+                                continue;
+                        }
+
+                        again = true;
+                        n++;
+
+                        break;
+                }
+
+        } while (again);
+
+        return r ? r : n;
+}
diff --git a/src/shared/util.h b/src/shared/util.h
index 62eb60402d..ac851fa4d6 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -942,3 +942,5 @@ union file_handle_union {
 };
 
 int update_reboot_param_file(const char *param);
+
+int umount_recursive(const char *target, int flags);
-- 
cgit v1.2.3-54-g00ecf