block: add support for generic mount options
authorJo-Philipp Wich <jow@openwrt.org>
Fri, 16 Aug 2013 10:22:34 +0000 (12:22 +0200)
committerJo-Philipp Wich <jow@openwrt.org>
Fri, 16 Aug 2013 11:12:54 +0000 (13:12 +0200)
Not all mount options are to be passed directly to the filesystem driver,
some of them are generic VFS flags that must be passed as bitfield to the
mount() syscall.

Add a new option parsing implementation that properly divides the user
sepcified mount options into flags and fs specific arguments.

block.c

diff --git a/block.c b/block.c
index 4397e1e717baeae851a2ec99985ee19e82e38dd1..ff35ba793af6624d2d7391d1ae7272073aea2d11 100644 (file)
--- a/block.c
+++ b/block.c
@@ -47,6 +47,7 @@ struct mount {
        char *target;
        char *path;
        char *options;
+       uint32_t flags;
        char *uuid;
        char *label;
        char *device;
@@ -130,6 +131,46 @@ static const struct uci_blob_param_list swap_attr_list = {
        .params = swap_policy,
 };
 
+struct mount_flag {
+       const char *name;
+       int32_t flag;
+};
+
+#ifndef MS_DIRSYNC
+#      define MS_DIRSYNC               (1 << 7)
+#endif
+
+#ifndef MS_RELATIME
+#      define MS_RELATIME              (1 << 21)
+#endif
+
+#ifndef MS_STRICTATIME
+#      define MS_STRICTATIME   (1 << 24)
+#endif
+
+static const struct mount_flag mount_flags[] = {
+       { "sync",                       MS_SYNCHRONOUS  },
+       { "async",                      ~MS_SYNCHRONOUS },
+       { "dirsync",            MS_DIRSYNC              },
+       { "mand",                       MS_MANDLOCK             },
+       { "nomand",                     ~MS_MANDLOCK    },
+       { "atime",                      ~MS_NOATIME             },
+       { "noatime",            MS_NOATIME              },
+       { "dev",                        ~MS_NODEV               },
+       { "nodev",                      MS_NODEV                },
+       { "diratime",           ~MS_NODIRATIME  },
+       { "nodiratime",         MS_NODIRATIME   },
+       { "exec",                       ~MS_NOEXEC              },
+       { "noexec",                     MS_NOEXEC               },
+       { "suid",                       ~MS_NOSUID              },
+       { "nosuid",                     MS_NOSUID               },
+       { "rw",                         ~MS_RDONLY              },
+       { "ro",                         MS_RDONLY               },
+       { "relatime",           MS_RELATIME             },
+       { "norelatime",         ~MS_RELATIME    },
+       { "strictatime",        MS_STRICTATIME  },
+};
+
 static char *blobmsg_get_strdup(struct blob_attr *attr)
 {
        if (!attr)
@@ -146,6 +187,52 @@ static char *blobmsg_get_basename(struct blob_attr *attr)
        return strdup(basename(blobmsg_get_string(attr)));
 }
 
+static void parse_mount_options(struct mount *m, char *optstr)
+{
+       int i;
+       bool is_flag;
+       char *p, *opts, *last;
+
+       m->flags = 0;
+       m->options = NULL;
+
+       if (!optstr || !*optstr)
+               return;
+
+       m->options = opts = calloc(1, strlen(optstr) + 1);
+
+       if (!m->options)
+               return;
+
+       p = last = optstr;
+
+       do {
+               p = strchr(p, ',');
+
+               if (p)
+                       *p++ = 0;
+
+               for (i = 0, is_flag = false; i < ARRAY_SIZE(mount_flags); i++) {
+                       if (!strcmp(last, mount_flags[i].name)) {
+                               if (mount_flags[i].flag < 0)
+                                       m->flags &= (uint32_t)mount_flags[i].flag;
+                               else
+                                       m->flags |= (uint32_t)mount_flags[i].flag;
+                               is_flag = true;
+                               break;
+                       }
+               }
+
+               if (!is_flag)
+                       opts += sprintf(opts, "%s%s", (opts > m->options) ? "," : "", last);
+
+               last = p;
+
+       } while (p);
+
+       free(optstr);
+}
+
 static int mount_add(struct uci_section *s)
 {
        struct blob_attr *tb[__MOUNT_MAX] = { 0 };
@@ -166,8 +253,10 @@ static int mount_add(struct uci_section *s)
        m->uuid = blobmsg_get_strdup(tb[MOUNT_UUID]);
        m->label = blobmsg_get_strdup(tb[MOUNT_LABEL]);
        m->target = blobmsg_get_strdup(tb[MOUNT_TARGET]);
-       m->options = blobmsg_get_strdup(tb[MOUNT_OPTIONS]);
        m->device = blobmsg_get_basename(tb[MOUNT_DEVICE]);
+
+       parse_mount_options(m, blobmsg_get_strdup(tb[MOUNT_OPTIONS]));
+
        m->overlay = m->extroot = 0;
        if (m->target && !strcmp(m->target, "/"))
                m->extroot = 1;
@@ -525,7 +614,8 @@ static int mount_device(struct blkid_struct_probe *pr, int hotplug)
                if (check_fs)
                        check_filesystem(pr);
 
-               err = mount(pr->dev, target, pr->id->name, 0, (m->options) ? (m->options) : (""));
+               err = mount(pr->dev, target, pr->id->name, m->flags,
+                           (m->options) ? (m->options) : (""));
                if (err)
                        fprintf(stderr, "mounting %s (%s) as %s failed (%d) - %s\n",
                                        pr->dev, pr->id->name, target, err, strerror(err));