+int add_mount_bind(const char *path, int readonly, int error)
+{
+ unsigned long mountflags = MS_BIND;
+
+ if (readonly)
+ mountflags |= MS_RDONLY;
+
+ return add_mount(path, path, NULL, mountflags, NULL, error);
+}
+
+
+enum {
+ OCI_MOUNT_SOURCE,
+ OCI_MOUNT_DESTINATION,
+ OCI_MOUNT_TYPE,
+ OCI_MOUNT_OPTIONS,
+ __OCI_MOUNT_MAX,
+};
+
+static const struct blobmsg_policy oci_mount_policy[] = {
+ [OCI_MOUNT_SOURCE] = { "source", BLOBMSG_TYPE_STRING },
+ [OCI_MOUNT_DESTINATION] = { "destination", BLOBMSG_TYPE_STRING },
+ [OCI_MOUNT_TYPE] = { "type", BLOBMSG_TYPE_STRING },
+ [OCI_MOUNT_OPTIONS] = { "options", BLOBMSG_TYPE_ARRAY },
+};
+
+struct mount_opt {
+ struct list_head list;
+ char *optstr;
+};
+
+static int parseOCImountopts(struct blob_attr *msg, unsigned long *mount_flags, char **mount_data, int *error)
+{
+ struct blob_attr *cur;
+ int rem;
+ unsigned long mf = 0;
+ char *tmp;
+ struct list_head fsopts = LIST_HEAD_INIT(fsopts);
+ size_t len = 0;
+ struct mount_opt *opt;
+
+ blobmsg_for_each_attr(cur, msg, rem) {
+ tmp = blobmsg_get_string(cur);
+ if (!strcmp("ro", tmp))
+ mf |= MS_RDONLY;
+ else if (!strcmp("rw", tmp))
+ mf &= ~MS_RDONLY;
+ else if (!strcmp("bind", tmp))
+ mf = MS_BIND;
+ else if (!strcmp("rbind", tmp))
+ mf |= MS_BIND | MS_REC;
+ else if (!strcmp("sync", tmp))
+ mf |= MS_SYNCHRONOUS;
+ else if (!strcmp("async", tmp))
+ mf &= ~MS_SYNCHRONOUS;
+ else if (!strcmp("atime", tmp))
+ mf &= ~MS_NOATIME;
+ else if (!strcmp("noatime", tmp))
+ mf |= MS_NOATIME;
+ else if (!strcmp("defaults", tmp))
+ mf = 0; /* rw, suid, dev, exec, auto, nouser, and async */
+ else if (!strcmp("dev", tmp))
+ mf &= ~MS_NODEV;
+ else if (!strcmp("nodev", tmp))
+ mf |= MS_NODEV;
+ else if (!strcmp("diratime", tmp))
+ mf &= ~MS_NODIRATIME;
+ else if (!strcmp("nodiratime", tmp))
+ mf |= MS_NODIRATIME;
+ else if (!strcmp("dirsync", tmp))
+ mf |= MS_DIRSYNC;
+ else if (!strcmp("exec", tmp))
+ mf &= ~MS_NOEXEC;
+ else if (!strcmp("noexec", tmp))
+ mf |= MS_NOEXEC;
+ else if (!strcmp("mand", tmp))
+ mf |= MS_MANDLOCK;
+ else if (!strcmp("nomand", tmp))
+ mf &= ~MS_MANDLOCK;
+ else if (!strcmp("relatime", tmp))
+ mf |= MS_RELATIME;
+ else if (!strcmp("norelatime", tmp))
+ mf &= ~MS_RELATIME;
+ else if (!strcmp("strictatime", tmp))
+ mf |= MS_STRICTATIME;
+ else if (!strcmp("nostrictatime", tmp))
+ mf &= ~MS_STRICTATIME;
+ else if (!strcmp("lazytime", tmp))
+ mf |= MS_LAZYTIME;
+ else if (!strcmp("nostrictatime", tmp))
+ mf &= ~MS_LAZYTIME;
+ else if (!strcmp("suid", tmp))
+ mf &= ~MS_NOSUID;
+ else if (!strcmp("nosuid", tmp))
+ mf |= MS_NOSUID;
+ else if (!strcmp("remount", tmp))
+ mf |= MS_REMOUNT;
+ else if(!strcmp("nofail", tmp))
+ *error = 0;
+ else if (!strcmp("auto", tmp) ||
+ !strcmp("noauto", tmp) ||
+ !strcmp("user", tmp) ||
+ !strcmp("group", tmp) ||
+ !strcmp("_netdev", tmp))
+ DEBUG("ignoring built-in mount option %s\n", tmp);
+ else {
+ /* filesystem-specific free-form option */
+ opt = calloc(1, sizeof(*opt));
+ opt->optstr = tmp;
+ list_add_tail(&opt->list, &fsopts);
+ }
+ };
+
+ *mount_flags = mf;
+
+ list_for_each_entry(opt, &fsopts, list) {
+ if (len)
+ ++len;
+
+ len += strlen(opt->optstr);
+ };
+
+ if (!len)
+ return 0;
+
+ *mount_data = calloc(len + 1, sizeof(char));
+ if (!mount_data)
+ return ENOMEM;
+
+ len = 0;
+ list_for_each_entry(opt, &fsopts, list) {
+ if (len)
+ strcat(*mount_data, ",");
+
+ strcat(*mount_data, opt->optstr);
+ ++len;
+ };
+
+ list_del(&fsopts);
+
+ DEBUG("mount flags(%08lx) fsopts(\"%s\")\n", mf, *mount_data?:"");
+
+ return 0;
+};
+
+int parseOCImount(struct blob_attr *msg)
+{
+ struct blob_attr *tb[__OCI_MOUNT_MAX];
+ unsigned long mount_flags = 0;
+ char *mount_data = NULL;
+ int ret, err = -1;
+
+ blobmsg_parse(oci_mount_policy, __OCI_MOUNT_MAX, tb, blobmsg_data(msg), blobmsg_len(msg));
+
+ if (!tb[OCI_MOUNT_DESTINATION])
+ return EINVAL;
+
+ if (tb[OCI_MOUNT_OPTIONS]) {
+ ret = parseOCImountopts(tb[OCI_MOUNT_OPTIONS], &mount_flags, &mount_data, &err);
+ if (ret)
+ return ret;
+ }
+
+ add_mount(tb[OCI_MOUNT_SOURCE] ? blobmsg_get_string(tb[OCI_MOUNT_SOURCE]) : NULL,
+ blobmsg_get_string(tb[OCI_MOUNT_DESTINATION]),
+ tb[OCI_MOUNT_TYPE] ? blobmsg_get_string(tb[OCI_MOUNT_TYPE]) : NULL,
+ mount_flags, mount_data, err);
+
+ return 0;
+};
+
+