chiark / gitweb /
mount-setup: automatically mount binfmt_misc
[elogind.git] / mount-setup.c
index 4a5e2cc760abcc363bc78f0c1c4761c294869f66..b80289466200e7c9be97f7511f99f2278041572f 100644 (file)
 
 #include "mount-setup.h"
 #include "log.h"
-
-enum {
-        MOUNT_WHAT,
-        MOUNT_WHERE,
-        MOUNT_TYPE,
-        MOUNT_OPTIONS,
-        MOUNT_SKIP
+#include "macro.h"
+#include "util.h"
+
+typedef struct MountPoint {
+        const char *what;
+        const char *where;
+        const char *type;
+        const char *options;
+        unsigned long flags;
+        bool fatal;
+} MountPoint;
+
+static const MountPoint mount_table[] = {
+        { "proc",        "/proc",                    "proc",        NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
+        { "sysfs",       "/sys",                     "sysfs",       NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
+        { "devtmps",     "/dev",                     "devtmpfs",    "mode=755",  MS_NOSUID,                    true },
+        { "tmpfs",       "/dev/shm",                 "tmpfs",       "mode=1777", MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
+        { "devpts",      "/dev/pts",                 "devpts",      NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV, false },
+        { "cgroup",      "/cgroup/debug",            "cgroup",      "debug",     MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
+        { "debugfs",     "/sys/kernel/debug",        "debugfs",     NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV, false },
+        { "binfmt_misc", "/proc/sys/fs/binfmt_misc", "binfmt_misc", NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV, false },
 };
 
-static const char *table[] = {
-        "/proc",  "/proc",         "proc",   "rw",
-        "/sys",   "/sys",          "sysfs",  "rw",
-        "cgroup", "/cgroup/debug", "cgroup", "debug",
-        NULL
-};
+bool mount_point_is_api(const char *path) {
+        unsigned i;
 
-static int is_mount_point(const char *t) {
-        struct stat a, b;
-        char *copy;
+        /* Checks if this mount point is considered "API", and hence
+         * should be ignored */
 
-        if (lstat(t, &a) < 0) {
+        for (i = 0; i < ELEMENTSOF(mount_table); i ++)
+                if (path_startswith(path, mount_table[i].where))
+                        return true;
 
-                if (errno == ENOENT)
-                        return 0;
+        return false;
+}
 
-                return -errno;
-        }
+static int mount_one(const MountPoint *p) {
+        int r;
 
-        if (!(copy = strdup(t)))
-                return -ENOMEM;
+        assert(p);
 
-        if (lstat(dirname(copy), &b) < 0) {
-                free(copy);
-                return -errno;
-        }
+        if ((r = path_is_mount_point(p->where)) < 0)
+                return r;
 
-        free(copy);
+        if (r > 0)
+                return 0;
 
-        return a.st_dev != b.st_dev;
+        /* The access mode here doesn't really matter too much, since
+         * the mounted file system will take precedence anyway. */
+        mkdir_p(p->where, 0755);
 
+        log_debug("Mounting %s to %s of type %s with options %s.",
+                  p->what,
+                  p->where,
+                  p->type,
+                  strna(p->options));
+
+        if (mount(p->what,
+                  p->where,
+                  p->type,
+                  p->flags,
+                  p->options) < 0) {
+                log_error("Failed to mount %s: %s", p->where, strerror(errno));
+                return p->fatal ? -errno : 0;
+        }
+
+        return 0;
 }
 
-static int mount_one(const char *t[]) {
+static int mount_cgroup_controllers(void) {
         int r;
+        FILE *f;
+        char buf [256];
 
-        assert(t);
+        /* Mount all available cgroup controllers. */
 
-        if ((r = is_mount_point(t[MOUNT_WHERE])) < 0)
-                return r;
+        if (!(f = fopen("/proc/cgroups", "re")))
+                return -ENOENT;
 
-        if (r > 0)
-                return 0;
+        /* Ignore the header line */
+        fgets(buf, sizeof(buf), f);
 
-        log_debug("Mounting %s to %s of type %s with options %s.",
-                  t[MOUNT_WHAT],
-                  t[MOUNT_WHERE],
-                  t[MOUNT_TYPE],
-                  t[MOUNT_OPTIONS]);
-
-        if (mount(t[MOUNT_WHAT],
-                  t[MOUNT_WHERE],
-                  t[MOUNT_TYPE],
-                  0,
-                  t[MOUNT_OPTIONS]) < 0) {
-                log_error("Failed to mount %s: %s", t[MOUNT_WHERE], strerror(errno));
-                return -errno;
+        for (;;) {
+                MountPoint p;
+                char *controller, *where;
+
+                if (fscanf(f, "%ms %*i %*i %*i", &controller) != 1) {
+
+                        if (feof(f))
+                                break;
+
+                        log_error("Failed to parse /proc/cgroups.");
+                        r = -EIO;
+                        goto finish;
+                }
+
+                if (asprintf(&where, "/cgroup/%s", controller) < 0) {
+                        free(controller);
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                zero(p);
+                p.what = "cgroup";
+                p.where = where;
+                p.type = "cgroup";
+                p.options = controller;
+                p.flags = MS_NOSUID|MS_NOEXEC|MS_NODEV;
+                p.fatal = false;
+
+                r = mount_one(&p);
+                free(controller);
+                free(where);
+
+                if (r < 0)
+                        goto finish;
         }
 
-        return 0;
+        r = 0;
+
+finish:
+        fclose(f);
+
+        return r;
 }
 
 int mount_setup(void) {
         int r;
-        const char **t;
+        unsigned i;
 
-        for (t = table; *t; t += MOUNT_SKIP)
-                if ((r = mount_one(t)) < 0)
+        for (i = 0; i < ELEMENTSOF(mount_table); i ++)
+                if ((r = mount_one(mount_table+i)) < 0)
                         return r;
 
-        return 0;
+        return mount_cgroup_controllers();
 }