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

This has the benefit of not triggering any autofs mount points
unnecessarily.

---
 src/core/namespace.c |    6 ++++
 src/shared/util.c    |   68 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/shared/util.h    |    2 +
 3 files changed, 76 insertions(+)

--- src/core/namespace.c
+++ src/core/namespace.c	2014-06-11 00:00:00.000000000 +0000
@@ -220,6 +220,12 @@ static int apply_mount(
                 return mount_dev(m);
 
         case INACCESSIBLE:
+
+                /* First, get rid of everything that is below if there
+                 * is anything... Then, overmount it with an
+                 * inaccessible directory. */
+                umount_recursive(m->path, 0);
+
                 what = "/run/systemd/inaccessible";
                 break;
 
--- src/shared/util.c
+++ src/shared/util.c	2014-06-11 00:00:00.000000000 +0000
@@ -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>
@@ -4635,6 +4636,73 @@ char *strjoin(const char *x, ...) {
         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;
+}
+
 bool is_main_thread(void) {
         static thread_local int cached = 0;
 
--- src/shared/util.h
+++ src/shared/util.h	2014-06-11 10:10:08.000000000 +0000
@@ -890,3 +890,5 @@ union file_handle_union {
   struct file_handle handle;
   char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ];
 };
+
+int umount_recursive(const char *target, int flags);
