]> git.hungrycats.org Git - linux/commitdiff
[PATCH] table-driven filesystems option parsing
authorAndrew Morton <akpm@osdl.org>
Wed, 1 Oct 2003 17:58:08 +0000 (10:58 -0700)
committerLinus Torvalds <torvalds@home.osdl.org>
Wed, 1 Oct 2003 17:58:08 +0000 (10:58 -0700)
From: "Randy.Dunlap" <rddunlap@osdl.org>, Will Dyson <will_dyson@pobox.com>, me

Add generic filesystem options parser (infrastructure) and use it to parse
mount options in several filesystems (adfs, affs, autofs, autofs4, ext2,
ext3, fat, hfs, hpfs, isofs, jfs, procfs, udf, and ufs).

It saves between 128 and 512 bytes per filesystem.

18 files changed:
fs/adfs/super.c
fs/affs/super.c
fs/autofs/inode.c
fs/autofs4/inode.c
fs/befs/linuxvfs.c
fs/ext2/super.c
fs/ext3/super.c
fs/fat/inode.c
fs/hfs/super.c
fs/hpfs/super.c
fs/isofs/inode.c
fs/jfs/super.c
fs/proc/inode.c
fs/udf/super.c
fs/ufs/super.c
include/linux/parser.h [new file with mode: 0644]
lib/Makefile
lib/parser.c [new file with mode: 0644]

index 13737397d24bca311f1dfc8eb71c98159a725694..add13abbc08760c965d1106714fb7c8623d02b5c 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/buffer_head.h>
 #include <linux/vfs.h>
+#include <linux/parser.h>
 
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
@@ -133,50 +134,56 @@ static void adfs_put_super(struct super_block *sb)
        sb->s_fs_info = NULL;
 }
 
+enum {Opt_uid, Opt_gid, Opt_ownmask, Opt_othmask, Opt_err};
+
+static match_table_t tokens = {
+       {Opt_uid, "uid=%u"},
+       {Opt_gid, "gid=%u"},
+       {Opt_ownmask, "ownmask=%o"},
+       {Opt_othmask, "othmask=%o"},
+       {Opt_err, NULL}
+};
+
 static int parse_options(struct super_block *sb, char *options)
 {
-       char *value, *opt;
+       char *p;
        struct adfs_sb_info *asb = ADFS_SB(sb);
+       int option;
 
        if (!options)
                return 0;
 
-       while ((opt = strsep(&options, ",")) != NULL) {
-               if (!*opt)
+       while ((p = strsep(&options, ",")) != NULL) {
+               substring_t args[MAX_OPT_ARGS];
+               int token;
+               if (!*p)
                        continue;
-               value = strchr(opt, '=');
-               if (value)
-                       *value++ = '\0';
 
-               if (!strcmp(opt, "uid")) {      /* owner of all files */
-                       if (!value || !*value)
-                               return -EINVAL;
-                       asb->s_uid = simple_strtoul(value, &value, 0);
-                       if (*value)
-                               return -EINVAL;
-               } else
-               if (!strcmp(opt, "gid")) {      /* group owner of all files */
-                       if (!value || !*value)
-                               return -EINVAL;
-                       asb->s_gid = simple_strtoul(value, &value, 0);
-                       if (*value)
-                               return -EINVAL;
-               } else
-               if (!strcmp(opt, "ownmask")) {  /* owner permission mask */
-                       if (!value || !*value)
+               token = match_token(p, tokens, args);
+               switch (token) {
+               case Opt_uid:
+                       if (match_int(args, &option))
                                return -EINVAL;
-                       asb->s_owner_mask = simple_strtoul(value, &value, 8);
-                       if (*value)
+                       asb->s_uid = option;
+                       break;
+               case Opt_gid:
+                       if (match_int(args, &option))
                                return -EINVAL;
-               } else
-               if (!strcmp(opt, "othmask")) {  /* others permission mask */
-                       if (!value || !*value)
+                       asb->s_gid = option;
+                       break;
+               case Opt_ownmask:
+                       if (match_octal(args, &option))
                                return -EINVAL;
-                       asb->s_other_mask = simple_strtoul(value, &value, 8);
-                       if (*value)
+                       asb->s_owner_mask = option;
+                       break;
+               case Opt_othmask:
+                       if (match_octal(args, &option))
                                return -EINVAL;
-               } else {                        /* eh? say again. */
-                       printk("ADFS-fs: unrecognised mount option %s\n", opt);
+                       asb->s_other_mask = option;
+                       break;
+               default:
+                       printk("ADFS-fs: unrecognised mount option \"%s\" "
+                                       "or missing value\n", p);
                        return -EINVAL;
                }
        }
index 5a07bcd17f606b0e2f9d87342da57a62766f1250..ef5537a03a31cc367960a6b5a34cd9c41b2eb2c1 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/vfs.h>
+#include <linux/parser.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
@@ -142,12 +143,37 @@ static struct super_operations affs_sops = {
        .remount_fs     = affs_remount,
 };
 
+enum {
+       Opt_bs, Opt_mode, Opt_mufs, Opt_prefix, Opt_protect,
+       Opt_reserved, Opt_root, Opt_setgid, Opt_setuid,
+       Opt_verbose, Opt_volume, Opt_ignore, Opt_err,
+};
+
+static match_table_t tokens = {
+       {Opt_bs, "bs=%d"},
+       {Opt_mode, "mode=%o"},
+       {Opt_mufs, "mufs"},
+       {Opt_prefix, "prefix=%s"},
+       {Opt_protect, "protect"},
+       {Opt_reserved, "reserved=%d"},
+       {Opt_root, "root=%d"},
+       {Opt_setgid, "setgid=%d"},
+       {Opt_setuid, "setuid=%d"},
+       {Opt_verbose, "verbose"},
+       {Opt_volume, "volume=%s"},
+       {Opt_ignore, "grpquota"},
+       {Opt_ignore, "noquota"},
+       {Opt_ignore, "quota"},
+       {Opt_ignore, "usrquota"},
+       {Opt_err, NULL},
+};
+
 static int
 parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s32 *root,
                int *blocksize, char **prefix, char *volume, unsigned long *mount_opts)
 {
-       char    *this_char, *value, *optn;
-       int      f;
+       char *p;
+       substring_t args[MAX_OPT_ARGS];
 
        /* Fill in defaults */
 
@@ -161,109 +187,85 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s
        *mount_opts = 0;
        if (!options)
                return 1;
-       while ((this_char = strsep(&options, ",")) != NULL) {
-               if (!*this_char)
+
+       while ((p = strsep(&options, ",")) != NULL) {
+               int token, n, option;
+               if (!*p)
                        continue;
-               f = 0;
-               if ((value = strchr(this_char,'=')) != NULL)
-                       *value++ = 0;
-               if ((optn = "protect") && !strcmp(this_char, optn)) {
-                       if (value)
-                               goto out_inv_arg;
-                       *mount_opts |= SF_IMMUTABLE;
-               } else if ((optn = "verbose") && !strcmp(this_char, optn)) {
-                       if (value)
-                               goto out_inv_arg;
-                       *mount_opts |= SF_VERBOSE;
-               } else if ((optn = "mufs") && !strcmp(this_char, optn)) {
-                       if (value)
-                               goto out_inv_arg;
-                       *mount_opts |= SF_MUFS;
-               } else if ((f = !strcmp(this_char,"setuid")) || !strcmp(this_char,"setgid")) {
-                       if (value) {
-                               if (!*value) {
-                                       printk("AFFS: Argument for set[ug]id option missing\n");
-                                       return 0;
-                               } else {
-                                       (f ? *uid : *gid) = simple_strtoul(value,&value,0);
-                                       if (*value) {
-                                               printk("AFFS: Bad set[ug]id argument\n");
-                                               return 0;
-                                       }
-                                       *mount_opts |= f ? SF_SETUID : SF_SETGID;
-                               }
+
+               token = match_token(p, tokens, args);
+               switch (token) {
+               case Opt_bs:
+                       if (match_int(&args[0], &n))
+                               return -EINVAL;
+                       if (n != 512 && n != 1024 && n != 2048
+                           && n != 4096) {
+                               printk ("AFFS: Invalid blocksize (512, 1024, 2048, 4096 allowed)\n");
+                               return 0;
                        }
-               } else if (!strcmp(this_char,"prefix")) {
-                       optn = "prefix";
-                       if (!value || !*value)
-                               goto out_no_arg;
+                       *blocksize = n;
+                       break;
+               case Opt_mode:
+                       if (match_octal(&args[0], &option))
+                               return 1;
+                       *mode = option & 0777;
+                       *mount_opts |= SF_SETMODE;
+                       break;
+               case Opt_mufs:
+                       *mount_opts |= SF_MUFS;
+                       break;
+               case Opt_prefix:
                        if (*prefix) {          /* Free any previous prefix */
                                kfree(*prefix);
                                *prefix = NULL;
                        }
-                       *prefix = kmalloc(strlen(value) + 1,GFP_KERNEL);
+                       *prefix = match_strdup(&args[0]);
                        if (!*prefix)
                                return 0;
-                       strcpy(*prefix,value);
                        *mount_opts |= SF_PREFIX;
-               } else if (!strcmp(this_char,"volume")) {
-                       optn = "volume";
-                       if (!value || !*value)
-                               goto out_no_arg;
-                       strlcpy(volume,value,31);
-               } else if (!strcmp(this_char,"mode")) {
-                       optn = "mode";
-                       if (!value || !*value)
-                               goto out_no_arg;
-                       *mode = simple_strtoul(value,&value,8) & 0777;
-                       if (*value)
-                               return 0;
-                       *mount_opts |= SF_SETMODE;
-               } else if (!strcmp(this_char,"reserved")) {
-                       optn = "reserved";
-                       if (!value || !*value)
-                               goto out_no_arg;
-                       *reserved = simple_strtoul(value,&value,0);
-                       if (*value)
-                               return 0;
-               } else if (!strcmp(this_char,"root")) {
-                       optn = "root";
-                       if (!value || !*value)
-                               goto out_no_arg;
-                       *root = simple_strtoul(value,&value,0);
-                       if (*value)
-                               return 0;
-               } else if (!strcmp(this_char,"bs")) {
-                       optn = "bs";
-                       if (!value || !*value)
-                               goto out_no_arg;
-                       *blocksize = simple_strtoul(value,&value,0);
-                       if (*value)
-                               return 0;
-                       if (*blocksize != 512 && *blocksize != 1024 && *blocksize != 2048
-                           && *blocksize != 4096) {
-                               printk ("AFFS: Invalid blocksize (512, 1024, 2048, 4096 allowed)\n");
-                               return 0;
-                       }
-               } else if (!strcmp (this_char, "grpquota")
-                        || !strcmp (this_char, "noquota")
-                        || !strcmp (this_char, "quota")
-                        || !strcmp (this_char, "usrquota"))
-                        /* Silently ignore the quota options */
-                       ;
-               else {
-                       printk("AFFS: Unrecognized mount option %s\n", this_char);
+                       break;
+               case Opt_protect:
+                       *mount_opts |= SF_IMMUTABLE;
+                       break;
+               case Opt_reserved:
+                       if (match_int(&args[0], reserved))
+                               return 1;
+                       break;
+               case Opt_root:
+                       if (match_int(&args[0], root))
+                               return 1;
+                       break;
+               case Opt_setgid:
+                       if (match_int(&args[0], &option))
+                               return 1;
+                       *gid = option;
+                       *mount_opts |= SF_SETGID;
+                       break;
+               case Opt_setuid:
+                       if (match_int(&args[0], &option))
+                               return -EINVAL;
+                       *uid = option;
+                       *mount_opts |= SF_SETUID;
+                       break;
+               case Opt_verbose:
+                       *mount_opts |= SF_VERBOSE;
+                       break;
+               case Opt_volume: {
+                       char *vol = match_strdup(&args[0]);
+                       strlcpy(volume, vol, 32);
+                       kfree(vol);
+                       break;
+               }
+               case Opt_ignore:
+                       /* Silently ignore the quota options */
+                       break;
+               default:
+                       printk("AFFS: Unrecognized mount option \"%s\" "
+                                       "or missing value\n", p);
                        return 0;
                }
        }
        return 1;
-
-out_no_arg:
-       printk("AFFS: The %s option requires an argument\n", optn);
-       return 0;
-out_inv_arg:
-       printk("AFFS: Option %s does not take an argument\n", optn);
-       return 0;
 }
 
 /* This function definitely needs to be split up. Some fine day I'll
index 398cade9442d0a9b9f5a7a5c160044b399889f57..f901bba0994662c8a90b137ae3dad046b9321e45 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/file.h>
+#include <linux/parser.h>
 #include <asm/bitops.h>
 #include "autofs_i.h"
 #include <linux/module.h>
@@ -45,10 +46,24 @@ static struct super_operations autofs_sops = {
        .statfs         = simple_statfs,
 };
 
+enum {Opt_err, Opt_fd, Opt_uid, Opt_gid, Opt_pgrp, Opt_minproto, Opt_maxproto};
+
+static match_table_t autofs_tokens = {
+       {Opt_fd, "fd=%d"},
+       {Opt_uid, "uid=%d"},
+       {Opt_gid, "gid=%d"},
+       {Opt_pgrp, "pgrp=%d"},
+       {Opt_minproto, "minproto=%d"},
+       {Opt_maxproto, "maxproto=%d"},
+       {Opt_err, NULL}
+};
+
 static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, pid_t *pgrp, int *minproto, int *maxproto)
 {
-       char *this_char, *value;
-       
+       char *p;
+       substring_t args[MAX_OPT_ARGS];
+       int option;
+
        *uid = current->uid;
        *gid = current->gid;
        *pgrp = process_group(current);
@@ -57,55 +72,49 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, pid
 
        *pipefd = -1;
 
-       if ( !options ) return 1;
-       while ((this_char = strsep(&options,",")) != NULL) {
-               if (!*this_char)
+       if (!options)
+               return 1;
+
+       while ((p = strsep(&options, ",")) != NULL) {
+               int token;
+               if (!*p)
                        continue;
-               if ((value = strchr(this_char,'=')) != NULL)
-                       *value++ = 0;
-               if (!strcmp(this_char,"fd")) {
-                       if (!value || !*value)
-                               return 1;
-                       *pipefd = simple_strtoul(value,&value,0);
-                       if (*value)
-                               return 1;
-               }
-               else if (!strcmp(this_char,"uid")) {
-                       if (!value || !*value)
-                               return 1;
-                       *uid = simple_strtoul(value,&value,0);
-                       if (*value)
-                               return 1;
-               }
-               else if (!strcmp(this_char,"gid")) {
-                       if (!value || !*value)
-                               return 1;
-                       *gid = simple_strtoul(value,&value,0);
-                       if (*value)
-                               return 1;
-               }
-               else if (!strcmp(this_char,"pgrp")) {
-                       if (!value || !*value)
+
+               token = match_token(p, autofs_tokens, args);
+               switch (token) {
+               case Opt_fd:
+                       if (match_int(&args[0], &option))
                                return 1;
-                       *pgrp = simple_strtoul(value,&value,0);
-                       if (*value)
+                       *pipefd = option;
+                       break;
+               case Opt_uid:
+                       if (match_int(&args[0], &option))
                                return 1;
-               }
-               else if (!strcmp(this_char,"minproto")) {
-                       if (!value || !*value)
+                       *uid = option;
+                       break;
+               case Opt_gid:
+                       if (match_int(&args[0], &option))
                                return 1;
-                       *minproto = simple_strtoul(value,&value,0);
-                       if (*value)
+                       *gid = option;
+                       break;
+               case Opt_pgrp:
+                       if (match_int(&args[0], &option))
                                return 1;
-               }
-               else if (!strcmp(this_char,"maxproto")) {
-                       if (!value || !*value)
+                       *pgrp = option;
+                       break;
+               case Opt_minproto:
+                       if (match_int(&args[0], &option))
                                return 1;
-                       *maxproto = simple_strtoul(value,&value,0);
-                       if (*value)
+                       *minproto = option;
+                       break;
+               case Opt_maxproto:
+                       if (match_int(&args[0], &option))
                                return 1;
+                       *maxproto = option;
+                       break;
+               default:
+                       return 1;
                }
-               else break;
        }
        return (*pipefd < 0);
 }
index f7cb9de42d9513ef7822aab0992011053e774562..8c9d598937b470ec8f6fc18c395d7b1e85703fed 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/file.h>
 #include <linux/pagemap.h>
+#include <linux/parser.h>
 #include <asm/bitops.h>
 #include "autofs_i.h"
 #include <linux/module.h>
@@ -94,11 +95,25 @@ static struct super_operations autofs4_sops = {
        .statfs         = simple_statfs,
 };
 
+enum {Opt_err, Opt_fd, Opt_uid, Opt_gid, Opt_pgrp, Opt_minproto, Opt_maxproto};
+
+static match_table_t tokens = {
+       {Opt_fd, "fd=%d"},
+       {Opt_uid, "uid=%d"},
+       {Opt_gid, "gid=%d"},
+       {Opt_pgrp, "pgrp=%d"},
+       {Opt_minproto, "minproto=%d"},
+       {Opt_maxproto, "maxproto=%d"},
+       {Opt_err, NULL}
+};
+
 static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
                         pid_t *pgrp, int *minproto, int *maxproto)
 {
-       char *this_char, *value;
-       
+       char *p;
+       substring_t args[MAX_OPT_ARGS];
+       int option;
+
        *uid = current->uid;
        *gid = current->gid;
        *pgrp = process_group(current);
@@ -108,55 +123,48 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
 
        *pipefd = -1;
 
-       if ( !options ) return 1;
-       while ((this_char = strsep(&options,",")) != NULL) {
-               if (!*this_char)
+       if (!options)
+               return 1;
+
+       while ((p = strsep(&options, ",")) != NULL) {
+               int token;
+               if (!*p)
                        continue;
-               if ((value = strchr(this_char,'=')) != NULL)
-                       *value++ = 0;
-               if (!strcmp(this_char,"fd")) {
-                       if (!value || !*value)
-                               return 1;
-                       *pipefd = simple_strtoul(value,&value,0);
-                       if (*value)
-                               return 1;
-               }
-               else if (!strcmp(this_char,"uid")) {
-                       if (!value || !*value)
-                               return 1;
-                       *uid = simple_strtoul(value,&value,0);
-                       if (*value)
-                               return 1;
-               }
-               else if (!strcmp(this_char,"gid")) {
-                       if (!value || !*value)
-                               return 1;
-                       *gid = simple_strtoul(value,&value,0);
-                       if (*value)
-                               return 1;
-               }
-               else if (!strcmp(this_char,"pgrp")) {
-                       if (!value || !*value)
+
+               token = match_token(p, tokens, args);
+               switch (token) {
+               case Opt_fd:
+                       if (match_int(args, pipefd))
                                return 1;
-                       *pgrp = simple_strtoul(value,&value,0);
-                       if (*value)
+                       break;
+               case Opt_uid:
+                       if (match_int(args, &option))
                                return 1;
-               }
-               else if (!strcmp(this_char,"minproto")) {
-                       if (!value || !*value)
+                       *uid = option;
+                       break;
+               case Opt_gid:
+                       if (match_int(args, &option))
                                return 1;
-                       *minproto = simple_strtoul(value,&value,0);
-                       if (*value)
+                       *gid = option;
+                       break;
+               case Opt_pgrp:
+                       if (match_int(args, &option))
                                return 1;
-               }
-               else if (!strcmp(this_char,"maxproto")) {
-                       if (!value || !*value)
+                       *pgrp = option;
+                       break;
+               case Opt_minproto:
+                       if (match_int(args, &option))
                                return 1;
-                       *maxproto = simple_strtoul(value,&value,0);
-                       if (*value)
+                       *minproto = option;
+                       break;
+               case Opt_maxproto:
+                       if (match_int(args, &option))
                                return 1;
+                       *maxproto = option;
+                       break;
+               default:
+                       return 1;
                }
-               else break;
        }
        return (*pipefd < 0);
 }
index 494c5569a5371c99422d8703879f0468bc326051..88812263284612ef529d6db04c911f168eeeae4a 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/nls.h>
 #include <linux/buffer_head.h>
 #include <linux/vfs.h>
+#include <linux/parser.h>
 
 #include "befs.h"
 #include "btree.h"
@@ -667,12 +668,27 @@ befs_nls2utf(struct super_block *sb, const char *in,
        return -EILSEQ;
 }
 
+/**
+ * Use the
+ *
+ */
+enum {
+       Opt_uid, Opt_gid, Opt_charset, Opt_debug,
+};
+
+static match_table_t befs_tokens = {
+       {Opt_uid, "uid=%d"},
+       {Opt_gid, "gid=%d"},
+       {Opt_charset, "iocharset=%s"},
+       {Opt_debug, "debug"}
+};
+
 static int
 parse_options(char *options, befs_mount_options * opts)
 {
-       char *this_char;
-       char *value;
-       int ret = 1;
+       char *p;
+       substring_t args[MAX_OPT_ARGS];
+       int option;
 
        /* Initialize options */
        opts->uid = 0;
@@ -683,64 +699,56 @@ parse_options(char *options, befs_mount_options * opts)
        opts->debug = 0;
 
        if (!options)
-               return ret;
-
-       while ((this_char = strsep(&options, ",")) != NULL) {
-
-               if ((value = strchr(this_char, '=')) != NULL)
-                       *value++ = 0;
-
-               if (!strcmp(this_char, "uid")) {
-                       if (!value || !*value) {
-                               ret = 0;
-                       } else {
-                               opts->uid = simple_strtoul(value, &value, 0);
-                               opts->use_uid = 1;
-                               if (*value) {
-                                       printk(KERN_ERR "BEFS: Invalid uid "
-                                              "option: %s\n", value);
-                                       ret = 0;
-                               }
+               return 1;
+
+       while ((p = strsep(&options, ",")) != NULL) {
+               int token;
+               if (!*p)
+                       continue;
+
+               token = match_token(p, befs_tokens, args);
+               switch (token) {
+               case Opt_uid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       if (option < 0) {
+                               printk(KERN_ERR "BeFS: Invalid uid %d, "
+                                               "using default\n", option);
+                               break;
                        }
-               } else if (!strcmp(this_char, "gid")) {
-                       if (!value || !*value)
-                               ret = 0;
-                       else {
-                               opts->gid = simple_strtoul(value, &value, 0);
-                               opts->use_gid = 1;
-                               if (*value) {
-                                       printk(KERN_ERR
-                                              "BEFS: Invalid gid option: "
-                                              "%s\n", value);
-                                       ret = 0;
-                               }
+                       opts->uid = option;
+                       opts->use_uid = 1;
+                       break;
+               case Opt_gid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       if (option < 0) {
+                               printk(KERN_ERR "BeFS: Invalid gid %d, "
+                                               "using default\n", option);
+                               break;
                        }
-               } else if (!strcmp(this_char, "iocharset") && value) {
-                       char *p = value;
-                       int len;
-
-                       while (*value && *value != ',')
-                               value++;
-                       len = value - p;
-                       if (len) {
-                               char *buffer = kmalloc(len + 1, GFP_NOFS);
-                               if (buffer) {
-                                       opts->iocharset = buffer;
-                                       memcpy(buffer, p, len);
-                                       buffer[len] = 0;
-
-                               } else {
-                                       printk(KERN_ERR "BEFS: "
-                                              "cannot allocate memory\n");
-                                       ret = 0;
-                               }
+                       opts->gid = option;
+                       opts->use_gid = 1;
+                       break;
+               case Opt_charset:
+                       kfree(opts->iocharset);
+                       opts->iocharset = match_strdup(&args[0]);
+                       if (!opts->iocharset) {
+                               printk(KERN_ERR "BeFS: allocation failure for "
+                                               "iocharset string\n");
+                               return 0;
                        }
-               } else if (!strcmp(this_char, "debug")) {
+                       break;
+               case Opt_debug:
                        opts->debug = 1;
+                       break;
+               default:
+                       printk(KERN_ERR "BeFS: Unrecognized mount option \"%s\" "
+                                       "or missing value\n", p);
+                       return 0;
                }
        }
-
-       return ret;
+       return 1;
 }
 
 /* This function has the responsibiltiy of getting the
index 14b8cca47277ce51e98da8f237f7449013621e19..4ecbd5ac548d0655e5951bfcb8a06523f150998e 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/blkdev.h>
+#include <linux/parser.h>
 #include <linux/random.h>
 #include <linux/buffer_head.h>
 #include <linux/smp_lock.h>
@@ -265,149 +266,157 @@ static unsigned long get_sb_block(void **data)
        return sb_block;
 }
 
-static int want_value(char *value, char *option)
-{
-       if (!value || !*value) {
-               printk(KERN_NOTICE "EXT2-fs: the %s option needs an argument\n",
-                      option);
-               return -1;
-       }
-       return 0;
-}
-
-static int want_null_value(char *value, char *option)
-{
-       if (*value) {
-               printk(KERN_NOTICE "EXT2-fs: Invalid %s argument: %s\n",
-                      option, value);
-               return -1;
-       }
-       return 0;
-}
+enum {
+       Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
+       Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
+       Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_nobh,
+       Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
+       Opt_ignore, Opt_err,
+};
 
-static int want_numeric(char *value, char *option, unsigned long *number)
-{
-       if (want_value(value, option))
-               return -1;
-       *number = simple_strtoul(value, &value, 0);
-       if (want_null_value(value, option))
-               return -1;
-       return 0;
-}
+static match_table_t tokens = {
+       {Opt_bsd_df, "bsddf"},
+       {Opt_minix_df, "minixdf"},
+       {Opt_grpid, "grpid"},
+       {Opt_grpid, "bsdgroups"},
+       {Opt_nogrpid, "nogrpid"},
+       {Opt_nogrpid, "sysvgroups"},
+       {Opt_resgid, "resgid=%d"},
+       {Opt_resuid, "resuid=%d"},
+       {Opt_sb, "sb=%d"},
+       {Opt_err_cont, "errors=continue"},
+       {Opt_err_panic, "errors=panic"},
+       {Opt_err_ro, "errors=remount-ro"},
+       {Opt_nouid32, "nouid32"},
+       {Opt_nocheck, "check=none"},
+       {Opt_nocheck, "nocheck"},
+       {Opt_check, "check"},
+       {Opt_debug, "debug"},
+       {Opt_oldalloc, "oldalloc"},
+       {Opt_orlov, "orlov"},
+       {Opt_nobh, "nobh"},
+       {Opt_user_xattr, "user_xattr"},
+       {Opt_nouser_xattr, "nouser_xattr"},
+       {Opt_acl, "acl"},
+       {Opt_noacl, "noacl"},
+       {Opt_ignore, "grpquota"},
+       {Opt_ignore, "noquota"},
+       {Opt_ignore, "quota"},
+       {Opt_ignore, "usrquota"},
+       {Opt_err, NULL}
+};
 
-/*
- * This function has been shamelessly adapted from the msdos fs
- */
 static int parse_options (char * options,
                          struct ext2_sb_info *sbi)
 {
-       char * this_char;
-       char * value;
+       char * p;
+       substring_t args[MAX_OPT_ARGS];
+       unsigned long kind = EXT2_MOUNT_ERRORS_CONT;
+       int option;
 
        if (!options)
                return 1;
-       while ((this_char = strsep (&options, ",")) != NULL) {
-               if (!*this_char)
+
+       while ((p = strsep (&options, ",")) != NULL) {
+               int token;
+               if (!*p)
                        continue;
-               if ((value = strchr (this_char, '=')) != NULL)
-                       *value++ = 0;
+
+               token = match_token(p, tokens, args);
+               switch (token) {
+               case Opt_bsd_df:
+                       clear_opt (sbi->s_mount_opt, MINIX_DF);
+                       break;
+               case Opt_minix_df:
+                       set_opt (sbi->s_mount_opt, MINIX_DF);
+                       break;
+               case Opt_grpid:
+                       set_opt (sbi->s_mount_opt, GRPID);
+                       break;
+               case Opt_nogrpid:
+                       clear_opt (sbi->s_mount_opt, GRPID);
+                       break;
+               case Opt_resuid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       sbi->s_resuid = option;
+                       break;
+               case Opt_resgid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       sbi->s_resgid = option;
+                       break;
+               case Opt_sb:
+                       /* handled by get_sb_block() instead of here */
+                       /* *sb_block = match_int(&args[0]); */
+                       break;
+               case Opt_err_panic:
+                       kind = EXT2_MOUNT_ERRORS_PANIC;
+                       break;
+               case Opt_err_ro:
+                       kind = EXT2_MOUNT_ERRORS_RO;
+                       break;
+               case Opt_err_cont:
+                       kind = EXT2_MOUNT_ERRORS_CONT;
+                       break;
+               case Opt_nouid32:
+                       set_opt (sbi->s_mount_opt, NO_UID32);
+                       break;
+               case Opt_check:
+#ifdef CONFIG_EXT2_CHECK
+                       set_opt (sbi->s_mount_opt, CHECK);
+#else
+                       printk("EXT2 Check option not supported\n");
+#endif
+                       break;
+               case Opt_nocheck:
+                       clear_opt (sbi->s_mount_opt, CHECK);
+                       break;
+               case Opt_debug:
+                       set_opt (sbi->s_mount_opt, DEBUG);
+                       break;
+               case Opt_oldalloc:
+                       set_opt (sbi->s_mount_opt, OLDALLOC);
+                       break;
+               case Opt_orlov:
+                       clear_opt (sbi->s_mount_opt, OLDALLOC);
+                       break;
+               case Opt_nobh:
+                       set_opt (sbi->s_mount_opt, NOBH);
+                       break;
 #ifdef CONFIG_EXT2_FS_XATTR
-               if (!strcmp (this_char, "user_xattr"))
+               case Opt_user_xattr:
                        set_opt (sbi->s_mount_opt, XATTR_USER);
-               else if (!strcmp (this_char, "nouser_xattr"))
+                       break;
+               case Opt_nouser_xattr:
                        clear_opt (sbi->s_mount_opt, XATTR_USER);
-               else
+                       break;
+#else
+               case Opt_user_xattr:
+               case Opt_nouser_xattr:
+                       printk("EXT2 (no)user_xattr options not supported\n");
+                       break;
 #endif
 #ifdef CONFIG_EXT2_FS_POSIX_ACL
-               if (!strcmp(this_char, "acl"))
+               case Opt_acl:
                        set_opt(sbi->s_mount_opt, POSIX_ACL);
-               else if (!strcmp(this_char, "noacl"))
+                       break;
+               case Opt_noacl:
                        clear_opt(sbi->s_mount_opt, POSIX_ACL);
-               else
-#endif
-               if (!strcmp (this_char, "bsddf"))
-                       clear_opt (sbi->s_mount_opt, MINIX_DF);
-               else if (!strcmp (this_char, "nouid32")) {
-                       set_opt (sbi->s_mount_opt, NO_UID32);
-               }
-               else if (!strcmp (this_char, "check")) {
-                       if (!value || !*value || !strcmp (value, "none"))
-                               clear_opt (sbi->s_mount_opt, CHECK);
-                       else
-#ifdef CONFIG_EXT2_CHECK
-                               set_opt (sbi->s_mount_opt, CHECK);
+                       break;
 #else
-                               printk("EXT2 Check option not supported\n");
+               case Opt_acl:
+               case Opt_noacl:
+                       printk("EXT2 (no)acl options not supported\n");
+                       break;
 #endif
-               }
-               else if (!strcmp (this_char, "debug"))
-                       set_opt (sbi->s_mount_opt, DEBUG);
-               else if (!strcmp (this_char, "errors")) {
-                       if (!value || !*value) {
-                               printk ("EXT2-fs: the errors option requires "
-                                       "an argument\n");
-                               return 0;
-                       }
-                       if (!strcmp (value, "continue")) {
-                               clear_opt (sbi->s_mount_opt, ERRORS_RO);
-                               clear_opt (sbi->s_mount_opt, ERRORS_PANIC);
-                               set_opt (sbi->s_mount_opt, ERRORS_CONT);
-                       }
-                       else if (!strcmp (value, "remount-ro")) {
-                               clear_opt (sbi->s_mount_opt, ERRORS_CONT);
-                               clear_opt (sbi->s_mount_opt, ERRORS_PANIC);
-                               set_opt (sbi->s_mount_opt, ERRORS_RO);
-                       }
-                       else if (!strcmp (value, "panic")) {
-                               clear_opt (sbi->s_mount_opt, ERRORS_CONT);
-                               clear_opt (sbi->s_mount_opt, ERRORS_RO);
-                               set_opt (sbi->s_mount_opt, ERRORS_PANIC);
-                       }
-                       else {
-                               printk ("EXT2-fs: Invalid errors option: %s\n",
-                                       value);
-                               return 0;
-                       }
-               }
-               else if (!strcmp (this_char, "grpid") ||
-                        !strcmp (this_char, "bsdgroups"))
-                       set_opt (sbi->s_mount_opt, GRPID);
-               else if (!strcmp (this_char, "minixdf"))
-                       set_opt (sbi->s_mount_opt, MINIX_DF);
-               else if (!strcmp (this_char, "nocheck"))
-                       clear_opt (sbi->s_mount_opt, CHECK);
-               else if (!strcmp (this_char, "nogrpid") ||
-                        !strcmp (this_char, "sysvgroups"))
-                       clear_opt (sbi->s_mount_opt, GRPID);
-               else if (!strcmp (this_char, "resgid")) {
-                       unsigned long v;
-                       if (want_numeric(value, "resgid", &v))
-                               return 0;
-                       sbi->s_resgid = v;
-               }
-               else if (!strcmp (this_char, "resuid")) {
-                       unsigned long v;
-                       if (want_numeric(value, "resuid", &v))
-                               return 0;
-                       sbi->s_resuid = v;
-               }
-               else if (!strcmp (this_char, "oldalloc"))
-                       set_opt (sbi->s_mount_opt, OLDALLOC);
-               else if (!strcmp (this_char, "orlov"))
-                       clear_opt (sbi->s_mount_opt, OLDALLOC);
-               else if (!strcmp (this_char, "nobh"))
-                       set_opt(sbi->s_mount_opt, NOBH);
-               /* Silently ignore the quota options */
-               else if (!strcmp (this_char, "grpquota")
-                        || !strcmp (this_char, "noquota")
-                        || !strcmp (this_char, "quota")
-                        || !strcmp (this_char, "usrquota"))
-                       /* Don't do anything ;-) */ ;
-               else {
-                       printk ("EXT2-fs: Unrecognized mount option %s\n", this_char);
+               case Opt_ignore:
+                       break;
+               default:
                        return 0;
                }
        }
+       sbi->s_mount_opt |= kind;
        return 1;
 }
 
index c0b2aea90a9028c123d83caf2a04d78f07453749..cb753bcdaabf4063eec314e21d1c70f0f0f161ae 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/blkdev.h>
+#include <linux/parser.h>
 #include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/vfs.h>
@@ -526,36 +527,54 @@ static struct export_operations ext3_export_ops = {
        .get_parent = ext3_get_parent,
 };
 
+enum {
+       Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
+       Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
+       Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov,
+       Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_noload,
+       Opt_commit, Opt_journal_update, Opt_journal_inum,
+       Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
+       Opt_ignore, Opt_err,
+};
 
-static int want_value(char *value, char *option)
-{
-       if (!value || !*value) {
-               printk(KERN_NOTICE "EXT3-fs: the %s option needs an argument\n",
-                      option);
-               return -1;
-       }
-       return 0;
-}
-
-static int want_null_value(char *value, char *option)
-{
-       if (*value) {
-               printk(KERN_NOTICE "EXT3-fs: Invalid %s argument: %s\n",
-                      option, value);
-               return -1;
-       }
-       return 0;
-}
-
-static int want_numeric(char *value, char *option, unsigned long *number)
-{
-       if (want_value(value, option))
-               return -1;
-       *number = simple_strtoul(value, &value, 0);
-       if (want_null_value(value, option))
-               return -1;
-       return 0;
-}
+static match_table_t tokens = {
+       {Opt_bsd_df, "bsddf"},
+       {Opt_minix_df, "minixdf"},
+       {Opt_grpid, "grpid"},
+       {Opt_grpid, "bsdgroups"},
+       {Opt_nogrpid, "nogrpid"},
+       {Opt_nogrpid, "sysvgroups"},
+       {Opt_resgid, "resgid=%d"},
+       {Opt_resuid, "resuid=%d"},
+       {Opt_sb, "sb=%d"},
+       {Opt_err_cont, "errors=continue"},
+       {Opt_err_panic, "errors=panic"},
+       {Opt_err_ro, "errors=remount-ro"},
+       {Opt_nouid32, "nouid32"},
+       {Opt_nocheck, "nocheck"},
+       {Opt_nocheck, "check=none"},
+       {Opt_check, "check"},
+       {Opt_debug, "debug"},
+       {Opt_oldalloc, "oldalloc"},
+       {Opt_orlov, "orlov"},
+       {Opt_user_xattr, "user_xattr"},
+       {Opt_nouser_xattr, "nouser_xattr"},
+       {Opt_acl, "acl"},
+       {Opt_noacl, "noacl"},
+       {Opt_noload, "noload"},
+       {Opt_commit, "commit=%u"},
+       {Opt_journal_update, "journal=update"},
+       {Opt_journal_inum, "journal=%u"},
+       {Opt_abort, "abort"},
+       {Opt_data_journal, "data=journal"},
+       {Opt_data_ordered, "data=ordered"},
+       {Opt_data_writeback, "data=writeback"},
+       {Opt_ignore, "grpquota"},
+       {Opt_ignore, "noquota"},
+       {Opt_ignore, "quota"},
+       {Opt_ignore, "usrquota"},
+       {Opt_err, NULL}
+};
 
 static unsigned long get_sb_block(void **data)
 {
@@ -577,175 +596,180 @@ static unsigned long get_sb_block(void **data)
        return sb_block;
 }
 
-/*
- * This function has been shamelessly adapted from the msdos fs
- */
 static int parse_options (char * options, struct ext3_sb_info *sbi,
                          unsigned long * inum, int is_remount)
 {
-       char * this_char;
-       char * value;
+       char * p;
+       substring_t args[MAX_OPT_ARGS];
+       int data_opt = 0;
+       int option;
 
        if (!options)
                return 1;
-       while ((this_char = strsep (&options, ",")) != NULL) {
-               if (!*this_char)
+
+       while ((p = strsep (&options, ",")) != NULL) {
+               int token;
+               if (!*p)
                        continue;
-               if ((value = strchr (this_char, '=')) != NULL)
-                       *value++ = 0;
-#ifdef CONFIG_EXT3_FS_XATTR
-               if (!strcmp (this_char, "user_xattr"))
-                       set_opt (sbi->s_mount_opt, XATTR_USER);
-               else if (!strcmp (this_char, "nouser_xattr"))
-                       clear_opt (sbi->s_mount_opt, XATTR_USER);
-               else
-#endif
-#ifdef CONFIG_EXT3_FS_POSIX_ACL
-               if (!strcmp(this_char, "acl"))
-                       set_opt (sbi->s_mount_opt, POSIX_ACL);
-               else if (!strcmp(this_char, "noacl"))
-                       clear_opt (sbi->s_mount_opt, POSIX_ACL);
-               else
-#endif
-               if (!strcmp (this_char, "bsddf"))
+
+               token = match_token(p, tokens, args);
+               switch (token) {
+               case Opt_bsd_df:
                        clear_opt (sbi->s_mount_opt, MINIX_DF);
-               else if (!strcmp (this_char, "nouid32")) {
+                       break;
+               case Opt_minix_df:
+                       set_opt (sbi->s_mount_opt, MINIX_DF);
+                       break;
+               case Opt_grpid:
+                       set_opt (sbi->s_mount_opt, GRPID);
+                       break;
+               case Opt_nogrpid:
+                       clear_opt (sbi->s_mount_opt, GRPID);
+                       break;
+               case Opt_resuid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       sbi->s_resuid = option;
+                       break;
+               case Opt_resgid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       sbi->s_resgid = option;
+                       break;
+               case Opt_sb:
+                       /* handled by get_sb_block() instead of here */
+                       /* *sb_block = match_int(&args[0]); */
+                       break;
+               case Opt_err_panic:
+                       clear_opt (sbi->s_mount_opt, ERRORS_CONT);
+                       clear_opt (sbi->s_mount_opt, ERRORS_RO);
+                       set_opt (sbi->s_mount_opt, ERRORS_PANIC);
+                       break;
+               case Opt_err_ro:
+                       clear_opt (sbi->s_mount_opt, ERRORS_CONT);
+                       clear_opt (sbi->s_mount_opt, ERRORS_PANIC);
+                       set_opt (sbi->s_mount_opt, ERRORS_RO);
+                       break;
+               case Opt_err_cont:
+                       clear_opt (sbi->s_mount_opt, ERRORS_RO);
+                       clear_opt (sbi->s_mount_opt, ERRORS_PANIC);
+                       set_opt (sbi->s_mount_opt, ERRORS_CONT);
+                       break;
+               case Opt_nouid32:
                        set_opt (sbi->s_mount_opt, NO_UID32);
-               }
-               else if (!strcmp (this_char, "abort"))
-                       set_opt (sbi->s_mount_opt, ABORT);
-               else if (!strcmp (this_char, "check")) {
-                       if (!value || !*value || !strcmp (value, "none"))
-                               clear_opt (sbi->s_mount_opt, CHECK);
-                       else
+                       break;
+               case Opt_check:
 #ifdef CONFIG_EXT3_CHECK
-                               set_opt (sbi->s_mount_opt, CHECK);
+                       set_opt (sbi->s_mount_opt, CHECK);
 #else
-                               printk(KERN_ERR 
-                                      "EXT3 Check option not supported\n");
+                       printk(KERN_ERR
+                              "EXT3 Check option not supported\n");
 #endif
-               }
-               else if (!strcmp (this_char, "debug"))
-                       set_opt (sbi->s_mount_opt, DEBUG);
-               else if (!strcmp (this_char, "errors")) {
-                       if (want_value(value, "errors"))
-                               return 0;
-                       if (!strcmp (value, "continue")) {
-                               clear_opt (sbi->s_mount_opt, ERRORS_RO);
-                               clear_opt (sbi->s_mount_opt, ERRORS_PANIC);
-                               set_opt (sbi->s_mount_opt, ERRORS_CONT);
-                       }
-                       else if (!strcmp (value, "remount-ro")) {
-                               clear_opt (sbi->s_mount_opt, ERRORS_CONT);
-                               clear_opt (sbi->s_mount_opt, ERRORS_PANIC);
-                               set_opt (sbi->s_mount_opt, ERRORS_RO);
-                       }
-                       else if (!strcmp (value, "panic")) {
-                               clear_opt (sbi->s_mount_opt, ERRORS_CONT);
-                               clear_opt (sbi->s_mount_opt, ERRORS_RO);
-                               set_opt (sbi->s_mount_opt, ERRORS_PANIC);
-                       }
-                       else {
-                               printk (KERN_ERR
-                                       "EXT3-fs: Invalid errors option: %s\n",
-                                       value);
-                               return 0;
-                       }
-               }
-               else if (!strcmp (this_char, "grpid") ||
-                        !strcmp (this_char, "bsdgroups"))
-                       set_opt (sbi->s_mount_opt, GRPID);
-               else if (!strcmp (this_char, "minixdf"))
-                       set_opt (sbi->s_mount_opt, MINIX_DF);
-               else if (!strcmp (this_char, "nocheck"))
+                       break;
+               case Opt_nocheck:
                        clear_opt (sbi->s_mount_opt, CHECK);
-               else if (!strcmp (this_char, "nogrpid") ||
-                        !strcmp (this_char, "sysvgroups"))
-                       clear_opt (sbi->s_mount_opt, GRPID);
-               else if (!strcmp (this_char, "resgid")) {
-                       unsigned long v;
-                       if (want_numeric(value, "resgid", &v))
-                               return 0;
-                       sbi->s_resgid = v;
-               }
-               else if (!strcmp (this_char, "resuid")) {
-                       unsigned long v;
-                       if (want_numeric(value, "resuid", &v))
-                               return 0;
-                       sbi->s_resuid = v;
-               }
-               else if (!strcmp (this_char, "oldalloc"))
+                       break;
+               case Opt_debug:
+                       set_opt (sbi->s_mount_opt, DEBUG);
+                       break;
+               case Opt_oldalloc:
                        set_opt (sbi->s_mount_opt, OLDALLOC);
-               else if (!strcmp (this_char, "orlov"))
+                       break;
+               case Opt_orlov:
                        clear_opt (sbi->s_mount_opt, OLDALLOC);
-               /* Silently ignore the quota options */
-               else if (!strcmp (this_char, "grpquota")
-                        || !strcmp (this_char, "noquota")
-                        || !strcmp (this_char, "quota")
-                        || !strcmp (this_char, "usrquota"))
-                       /* Don't do anything ;-) */ ;
-               else if (!strcmp (this_char, "journal")) {
+                       break;
+#ifdef CONFIG_EXT3_FS_XATTR
+               case Opt_user_xattr:
+                       set_opt (sbi->s_mount_opt, XATTR_USER);
+                       break;
+               case Opt_nouser_xattr:
+                       clear_opt (sbi->s_mount_opt, XATTR_USER);
+                       break;
+#else
+               case Opt_user_xattr:
+               case Opt_nouser_xattr:
+                       printk("EXT3 (no)user_xattr options not supported\n");
+                       break;
+#endif
+#ifdef CONFIG_EXT3_FS_POSIX_ACL
+               case Opt_acl:
+                       set_opt(sbi->s_mount_opt, POSIX_ACL);
+                       break;
+               case Opt_noacl:
+                       clear_opt(sbi->s_mount_opt, POSIX_ACL);
+                       break;
+#else
+               case Opt_acl:
+               case Opt_noacl:
+                       printk("EXT3 (no)acl options not supported\n");
+                       break;
+#endif
+               case Opt_journal_update:
                        /* @@@ FIXME */
                        /* Eventually we will want to be able to create
-                           a journal file here.  For now, only allow the
-                           user to specify an existing inode to be the
-                           journal file. */
+                          a journal file here.  For now, only allow the
+                          user to specify an existing inode to be the
+                          journal file. */
                        if (is_remount) {
                                printk(KERN_ERR "EXT3-fs: cannot specify "
                                       "journal on remount\n");
                                return 0;
                        }
-
-                       if (want_value(value, "journal"))
+                       set_opt (sbi->s_mount_opt, UPDATE_JOURNAL);
+                       break;
+               case Opt_journal_inum:
+                       if (is_remount) {
+                               printk(KERN_ERR "EXT3-fs: cannot specify "
+                                      "journal on remount\n");
                                return 0;
-                       if (!strcmp (value, "update"))
-                               set_opt (sbi->s_mount_opt, UPDATE_JOURNAL);
-                       else if (want_numeric(value, "journal", inum))
+                       }
+                       if (match_int(&args[0], &option))
                                return 0;
-               }
-               else if (!strcmp (this_char, "noload"))
+                       *inum = option;
+                       break;
+               case Opt_noload:
                        set_opt (sbi->s_mount_opt, NOLOAD);
-               else if (!strcmp (this_char, "data")) {
-                       int data_opt = 0;
-
-                       if (want_value(value, "data"))
-                               return 0;
-                       if (!strcmp (value, "journal"))
-                               data_opt = EXT3_MOUNT_JOURNAL_DATA;
-                       else if (!strcmp (value, "ordered"))
-                               data_opt = EXT3_MOUNT_ORDERED_DATA;
-                       else if (!strcmp (value, "writeback"))
-                               data_opt = EXT3_MOUNT_WRITEBACK_DATA;
-                       else {
-                               printk (KERN_ERR 
-                                       "EXT3-fs: Invalid data option: %s\n",
-                                       value);
+                       break;
+               case Opt_commit:
+                       if (match_int(&args[0], &option))
                                return 0;
-                       }
+                       sbi->s_commit_interval = HZ * option;
+                       break;
+               case Opt_data_journal:
+                       data_opt = EXT3_MOUNT_JOURNAL_DATA;
+                       goto datacheck;
+               case Opt_data_ordered:
+                       data_opt = EXT3_MOUNT_ORDERED_DATA;
+                       goto datacheck;
+               case Opt_data_writeback:
+                       data_opt = EXT3_MOUNT_WRITEBACK_DATA;
+               datacheck:
                        if (is_remount) {
-                               if ((sbi->s_mount_opt & EXT3_MOUNT_DATA_FLAGS) !=
-                                                       data_opt) {
+                               if ((sbi->s_mount_opt & EXT3_MOUNT_DATA_FLAGS)
+                                               != data_opt) {
                                        printk(KERN_ERR
-                                              "EXT3-fs: cannot change data "
-                                              "mode on remount\n");
+                                               "EXT3-fs: cannot change data "
+                                               "mode on remount\n");
                                        return 0;
                                }
                        } else {
                                sbi->s_mount_opt &= ~EXT3_MOUNT_DATA_FLAGS;
                                sbi->s_mount_opt |= data_opt;
                        }
-               } else if (!strcmp (this_char, "commit")) {
-                       unsigned long v;
-                       if (want_numeric(value, "commit", &v))
-                               return 0;
-                       sbi->s_commit_interval = (HZ * v);
-               } else {
-                       printk (KERN_ERR 
-                               "EXT3-fs: Unrecognized mount option %s\n",
-                               this_char);
+                       break;
+               case Opt_abort:
+                       set_opt(sbi->s_mount_opt, ABORT);
+                       break;
+               case Opt_ignore:
+                       break;
+               default:
+                       printk (KERN_ERR
+                               "EXT3-fs: Unrecognized mount option \"%s\" "
+                               "or missing value\n", p);
                        return 0;
                }
        }
+
        return 1;
 }
 
index f214dc6b611899c856daa661ac49704dfd4d2c1a..5a60ca977f339c8a81a901cbf466cbe70bd3aeb0 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/buffer_head.h>
 #include <linux/mount.h>
 #include <linux/vfs.h>
+#include <linux/parser.h>
 #include <asm/unaligned.h>
 
 /*
@@ -183,20 +184,6 @@ void fat_put_super(struct super_block *sb)
        kfree(sbi);
 }
 
-static int simple_getbool(char *s, int *setval)
-{
-       if (s) {
-               if (!strcmp(s,"1") || !strcmp(s,"yes") || !strcmp(s,"true"))
-                       *setval = 1;
-               else if (!strcmp(s,"0") || !strcmp(s,"no") || !strcmp(s,"false"))
-                       *setval = 0;
-               else
-                       return 0;
-       } else
-               *setval = 1;
-       return 1;
-}
-
 static int fat_show_options(struct seq_file *m, struct vfsmount *mnt)
 {
        struct msdos_sb_info *sbi = MSDOS_SB(mnt->mnt_sb);
@@ -259,11 +246,95 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt)
        return 0;
 }
 
+static void print_obsolete_option(char *optname)
+{
+       printk(KERN_INFO "FAT: %s option is obsolete, "
+                       "not supported now\n", optname);
+}
+
+enum {
+       Opt_blocksize, Opt_charset, Opt_check_n, Opt_check_r, Opt_check_s,
+       Opt_fat, Opt_codepage, Opt_conv_a, Opt_conv_b, Opt_conv_t,
+       Opt_debug, Opt_dots, Opt_err, Opt_gid, Opt_immutable,
+       Opt_nocase, Opt_nodots, Opt_quiet, Opt_showexec, Opt_uid,
+       Opt_shortname_lower, Opt_shortname_win95, Opt_shortname_winnt, Opt_shortname_mixed,
+       Opt_umask, Opt_dmask, Opt_fmask, Opt_posix, Opt_cvf_format, Opt_cvf_options,
+       Opt_utf8_off, Opt_utf8_no, Opt_utf8_false,
+       Opt_utf8_on, Opt_utf8_yes, Opt_utf8_true, Opt_utf8_opt,
+       Opt_uni_xl_off, Opt_uni_xl_no, Opt_uni_xl_false,
+       Opt_uni_xl_on, Opt_uni_xl_yes, Opt_uni_xl_true, Opt_uni_xl_opt,
+       Opt_nonumtail_off, Opt_nonumtail_no, Opt_nonumtail_false,
+       Opt_nonumtail_on, Opt_nonumtail_yes, Opt_nonumtail_true, Opt_nonumtail_opt,
+};
+
+static match_table_t FAT_tokens = {
+       {Opt_check_r, "check=relaxed"},
+       {Opt_check_s, "check=strict"},
+       {Opt_check_n, "check=normal"},
+       {Opt_check_r, "check=r"},
+       {Opt_check_s, "check=s"},
+       {Opt_check_n, "check=n"},
+       {Opt_conv_b, "conv=binary"},
+       {Opt_conv_t, "conv=text"},
+       {Opt_conv_a, "conv=auto"},
+       {Opt_conv_b, "conv=b"},
+       {Opt_conv_t, "conv=t"},
+       {Opt_conv_a, "conv=a"},
+       {Opt_nodots, "nodots"},
+       {Opt_nodots, "dotsOK=no"},
+       {Opt_dots, "dotsOK=yes"},
+       {Opt_dots, "dots"},
+       {Opt_uid, "uid=%d"},
+       {Opt_gid, "gid=%d"},
+       {Opt_umask, "umask=%o"},
+       {Opt_dmask, "dmask=%o"},
+       {Opt_fmask, "fmask=%o"},
+       {Opt_fat, "fat=%d"},
+       {Opt_codepage, "codepage=%d"},
+       {Opt_charset, "iocharset=%s"},
+       {Opt_blocksize, "blocksize=%d"},
+       {Opt_nocase, "nocase"},
+       {Opt_cvf_format, "cvf_format=%20s"},
+       {Opt_cvf_options, "cvf_options=%100s"},
+       {Opt_shortname_lower, "shortname=lower"},
+       {Opt_shortname_win95, "shortname=win95"},
+       {Opt_shortname_winnt, "shortname=winnt"},
+       {Opt_shortname_mixed, "shortname=mixed"},
+       {Opt_utf8_off, "utf8=0"},       /* 0 or no or false */
+       {Opt_utf8_no, "utf8=no"},
+       {Opt_utf8_false, "utf8=false"},
+       {Opt_utf8_on, "utf8=1"},        /* empty or 1 or yes or true */
+       {Opt_utf8_yes, "utf8=yes"},
+       {Opt_utf8_true, "utf8=true"},
+       {Opt_utf8_opt, "utf8"},
+       {Opt_uni_xl_off, "uni_xlate=0"},        /* 0 or no or false */
+       {Opt_uni_xl_no, "uni_xlate=no"},
+       {Opt_uni_xl_false, "uni_xlate=false"},
+       {Opt_uni_xl_on, "uni_xlate=1"},         /* empty or 1 or yes or true */
+       {Opt_uni_xl_yes, "uni_xlate=yes"},
+       {Opt_uni_xl_true, "uni_xlate=true"},
+       {Opt_uni_xl_opt, "uni_xlate"},
+       {Opt_nonumtail_off, "nonumtail=0"},     /* 0 or no or false */
+       {Opt_nonumtail_no, "nonumtail=no"},
+       {Opt_nonumtail_false, "nonumtail=false"},
+       {Opt_nonumtail_on, "nonumtail=1"},      /* empty or 1 or yes or true */
+       {Opt_nonumtail_yes, "nonumtail=yes"},
+       {Opt_nonumtail_true, "nonumtail=true"},
+       {Opt_nonumtail_opt, "nonumtail"},
+       {Opt_quiet, "quiet"},
+       {Opt_showexec, "showexec"},
+       {Opt_debug, "debug"},
+       {Opt_immutable, "sys_immutable"},
+       {Opt_posix, "posix"},
+       {Opt_err, NULL}
+};
+
 static int parse_options(char *options, int is_vfat, int *debug,
                         struct fat_mount_options *opts)
 {
-       char *this_char, *value, *p;
-       int ret = 1, val, len;
+       char *p;
+       substring_t args[MAX_OPT_ARGS];
+       int option;
 
        opts->isvfat = is_vfat;
 
@@ -284,183 +355,198 @@ static int parse_options(char *options, int is_vfat, int *debug,
        *debug = 0;
 
        if (!options)
-               goto out;
-       while ((this_char = strsep(&options,",")) != NULL) {
-               if (!*this_char)
+               return 1;
+
+       while ((p = strsep(&options, ",")) != NULL) {
+               int token;
+               if (!*p)
                        continue;
-               if ((value = strchr(this_char,'=')) != NULL)
-                       *value++ = 0;
-
-               if (!strcmp(this_char,"check") && value) {
-                       if (value[0] && !value[1] && strchr("rns",*value))
-                               opts->name_check = *value;
-                       else if (!strcmp(value,"relaxed"))
-                               opts->name_check = 'r';
-                       else if (!strcmp(value,"normal"))
-                               opts->name_check = 'n';
-                       else if (!strcmp(value,"strict"))
-                               opts->name_check = 's';
-                       else ret = 0;
-               }
-               else if (!strcmp(this_char,"conv") && value) {
-                       printk(KERN_INFO "FAT: conv option is obsolete, "
-                              "not supported now\n");
-               }
-               else if (!strcmp(this_char,"nocase")) {
+
+               token = match_token(p, FAT_tokens, args);
+               switch (token) {
+               case Opt_check_s:
+                       opts->name_check = 's';
+                       break;
+               case Opt_check_r:
+                               opts->name_check = 'r';
+                       break;
+               case Opt_check_n:
+                               opts->name_check = 'n';
+                       break;
+               case Opt_dots:          /* msdos specific */
+                       if (!is_vfat)
+                               opts->dotsOK = 1;
+                       break;
+               case Opt_nodots:        /* msdos specific */
+                       if (!is_vfat)
+                               opts->dotsOK = 0;
+                       break;
+               case Opt_nocase:
                        if (!is_vfat)
                                opts->nocase = 1;
                        else {
-                               /* for backward compatible */
+                               /* for backward compatibility */
                                opts->shortname = VFAT_SFN_DISPLAY_WIN95
                                        | VFAT_SFN_CREATE_WIN95;
                        }
-               }
-               else if (!strcmp(this_char,"showexec")) {
+                       break;
+               case Opt_quiet:
+                       opts->quiet = 1;
+                       break;
+               case Opt_showexec:
                        opts->showexec = 1;
-               }
-               else if (!strcmp(this_char,"uid")) {
-                       if (!value || !*value) ret = 0;
-                       else {
-                               opts->fs_uid = simple_strtoul(value,&value,0);
-                               if (*value) ret = 0;
-                       }
-               }
-               else if (!strcmp(this_char,"gid")) {
-                       if (!value || !*value) ret= 0;
-                       else {
-                               opts->fs_gid = simple_strtoul(value,&value,0);
-                               if (*value) ret = 0;
-                       }
-               }
-               else if (!strcmp(this_char,"umask")) {
-                       if (!value || !*value) ret = 0;
-                       else {
-                               opts->fs_fmask = opts->fs_dmask =
-                                       simple_strtoul(value,&value,8);
-                               if (*value) ret = 0;
-                       }
-               }
-               else if (!strcmp(this_char,"fmask")) {
-                       if (!value || !*value) ret = 0;
-                       else {
-                               opts->fs_fmask = simple_strtoul(value,&value,8);
-                               if (*value) ret = 0;
-                       }
-               }
-               else if (!strcmp(this_char,"dmask")) {
-                       if (!value || !*value) ret = 0;
-                       else {
-                               opts->fs_dmask = simple_strtoul(value,&value,8);
-                               if (*value) ret = 0;
-                       }
-               }
-               else if (!strcmp(this_char,"debug")) {
-                       if (value) ret = 0;
-                       else *debug = 1;
-               }
-               else if (!strcmp(this_char,"fat")) {
-                       printk(KERN_INFO "FAT: fat option is obsolete, "
-                              "not supported now\n");
-               }
-               else if (!strcmp(this_char,"quiet")) {
-                       if (value) ret = 0;
-                       else opts->quiet = 1;
-               }
-               else if (!strcmp(this_char,"blocksize")) {
-                       printk(KERN_INFO "FAT: blocksize option is obsolete, "
-                              "not supported now\n");
-               }
-               else if (!strcmp(this_char,"sys_immutable")) {
-                       if (value) ret = 0;
-                       else opts->sys_immutable = 1;
-               }
-               else if (!strcmp(this_char,"codepage") && value) {
-                       opts->codepage = simple_strtoul(value,&value,0);
-                       if (*value) ret = 0;
-               }
-
-               /* msdos specific */
-               else if (!is_vfat && !strcmp(this_char,"dots")) {
-                       opts->dotsOK = 1;
-               }
-               else if (!is_vfat && !strcmp(this_char,"nodots")) {
-                       opts->dotsOK = 0;
-               }
-               else if (!is_vfat && !strcmp(this_char,"dotsOK") && value) {
-                       if (!strcmp(value,"yes")) opts->dotsOK = 1;
-                       else if (!strcmp(value,"no")) opts->dotsOK = 0;
-                       else ret = 0;
-               }
+                       break;
+               case Opt_debug:
+                       *debug = 1;
+                       break;
+               case Opt_immutable:
+                       opts->sys_immutable = 1;
+                       break;
+               case Opt_uid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       opts->fs_uid = option;
+                       break;
+               case Opt_gid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       opts->fs_gid = option;
+                       break;
+               case Opt_umask:
+                       if (match_octal(&args[0], &option))
+                               return 0;
+                       opts->fs_fmask = opts->fs_dmask = option;
+                       break;
+               case Opt_dmask:
+                       if (match_octal(&args[0], &option))
+                               return 0;
+                       opts->fs_dmask = option;
+                       break;
+               case Opt_fmask:
+                       if (match_octal(&args[0], &option))
+                               return 0;
+                       opts->fs_fmask = option;
+                       break;
+               case Opt_codepage:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       opts->codepage = option;
+                       printk("MSDOS FS: Using codepage %d\n",
+                                       opts->codepage);
+                       break;
 
                /* vfat specific */
-               else if (is_vfat && !strcmp(this_char,"iocharset") && value) {
-                       p = value;
-                       while (*value && *value != ',')
-                               value++;
-                       len = value - p;
-                       if (len) {
-                               char *buffer;
-
-                               if (opts->iocharset != NULL) {
-                                       kfree(opts->iocharset);
-                                       opts->iocharset = NULL;
-                               }
-                               buffer = kmalloc(len + 1, GFP_KERNEL);
-                               if (buffer != NULL) {
-                                       opts->iocharset = buffer;
-                                       memcpy(buffer, p, len);
-                                       buffer[len] = 0;
-                               } else
-                                       ret = 0;
+               case Opt_charset:
+                       if (is_vfat) {
+                               kfree(opts->iocharset);
+                               opts->iocharset = match_strdup(&args[0]);
+                               if (!opts->iocharset)
+                                       return 0;
+                               printk("MSDOS FS: IO charset %s\n",
+                                       opts->iocharset);
                        }
-               }
-               else if (is_vfat && !strcmp(this_char,"utf8")) {
-                       ret = simple_getbool(value, &val);
-                       if (ret) opts->utf8 = val;
-               }
-               else if (is_vfat && !strcmp(this_char,"uni_xlate")) {
-                       ret = simple_getbool(value, &val);
-                       if (ret) opts->unicode_xlate = val;
-               }
-               else if (is_vfat && !strcmp(this_char,"posix")) {
-                       printk(KERN_INFO "FAT: posix option is obsolete, "
-                              "not supported now\n");
-               }
-               else if (is_vfat && !strcmp(this_char,"nonumtail")) {
-                       ret = simple_getbool(value, &val);
-                       if (ret) {
-                               opts->numtail = !val;
-                       }
-               }
-               else if (is_vfat && !strcmp(this_char, "shortname")) {
-                       if (!strcmp(value, "lower"))
+                       break;
+               case Opt_shortname_lower:
+                       if (is_vfat) {
                                opts->shortname = VFAT_SFN_DISPLAY_LOWER
                                                | VFAT_SFN_CREATE_WIN95;
-                       else if (!strcmp(value, "win95"))
+                       }
+                       break;
+               case Opt_shortname_win95:
+                       if (is_vfat) {
                                opts->shortname = VFAT_SFN_DISPLAY_WIN95
                                                | VFAT_SFN_CREATE_WIN95;
-                       else if (!strcmp(value, "winnt"))
+                       }
+                       break;
+               case Opt_shortname_winnt:
+                       if (is_vfat) {
                                opts->shortname = VFAT_SFN_DISPLAY_WINNT
                                                | VFAT_SFN_CREATE_WINNT;
-                       else if (!strcmp(value, "mixed"))
+                       }
+                       break;
+               case Opt_shortname_mixed:
+                       if (is_vfat) {
                                opts->shortname = VFAT_SFN_DISPLAY_WINNT
                                                | VFAT_SFN_CREATE_WIN95;
-                       else
-                               ret = 0;
-               } else {
-                       printk(KERN_ERR "FAT: Unrecognized mount option %s\n",
-                              this_char);
-                       ret = 0;
-               }
+                       }
+                       break;
+               case Opt_utf8_off:      /* 0 or no or false */
+               case Opt_utf8_no:
+               case Opt_utf8_false:
+                       if (is_vfat) {
+                               opts->utf8 = 0;
+                       }
+                       break;
+               case Opt_utf8_on:       /* empty or 1 or yes or true */
+               case Opt_utf8_opt:
+               case Opt_utf8_yes:
+               case Opt_utf8_true:
+                       if (is_vfat) {
+                               opts->utf8 = 1;
+                       }
+                       break;
+               case Opt_uni_xl_off:    /* 0 or no or false */
+               case Opt_uni_xl_no:
+               case Opt_uni_xl_false:
+                       if (is_vfat) {
+                               opts->unicode_xlate = 0;
+                       }
+                       break;
+               case Opt_uni_xl_on:     /* empty or 1 or yes or true */
+               case Opt_uni_xl_yes:
+               case Opt_uni_xl_true:
+               case Opt_uni_xl_opt:
+                       if (is_vfat) {
+                               opts->unicode_xlate = 1;
+                       }
+                       break;
+               case Opt_nonumtail_off:         /* 0 or no or false */
+               case Opt_nonumtail_no:
+               case Opt_nonumtail_false:
+                       if (is_vfat) {
+                                       opts->numtail = 1;      /* negated option */
+                       }
+                       break;
+               case Opt_nonumtail_on:          /* empty or 1 or yes or true */
+               case Opt_nonumtail_yes:
+               case Opt_nonumtail_true:
+               case Opt_nonumtail_opt:
+                       if (is_vfat) {
+                                       opts->numtail = 0;      /* negated option */
+                       }
+                       break;
 
-               if (ret == 0)
+               /* obsolete mount options */
+               case Opt_conv_b:
+               case Opt_conv_t:
+               case Opt_conv_a:
+                       print_obsolete_option("conv");
+                       break;
+               case Opt_blocksize:
+                       print_obsolete_option("blocksize");
+                       break;
+               case Opt_posix:
+                       print_obsolete_option("posix");
+                       break;
+               case Opt_fat:
+                       print_obsolete_option("fat");
+                       break;
+               case Opt_cvf_format:
+               case Opt_cvf_options:
+                       print_obsolete_option("cvf");
                        break;
+               /* unknown option */
+               default:
+                       printk(KERN_ERR "FAT: Unrecognized mount option \"%s\" "
+                                       "or missing value\n", p);
+                       return 0;
+               }
        }
-out:
+
        if (opts->unicode_xlate)
                opts->utf8 = 0;
        
-       return ret;
+       return 1;
 }
 
 static int fat_calc_dir_size(struct inode *inode)
index 408911021654e758d861139b52f8b165a96e3da6..e66e4ac9c1e23d5d5e8d95f5222cb1a59a2229d9 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/blkdev.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/parser.h>
 #include <linux/smp_lock.h>
 #include <linux/vfs.h>
 
@@ -211,6 +212,60 @@ static int hfs_statfs(struct super_block *sb, struct kstatfs *buf)
        return 0;
 }
 
+enum {
+       Opt_version, Opt_uid, Opt_gid, Opt_umask, Opt_part,
+       Opt_type, Opt_creator, Opt_quiet, Opt_afpd,
+       Opt_names_netatalk, Opt_names_trivial, Opt_names_alpha, Opt_names_latin,
+       Opt_names_7bit, Opt_names_8bit, Opt_names_cap,
+       Opt_fork_netatalk, Opt_fork_single, Opt_fork_double, Opt_fork_cap,
+       Opt_case_lower, Opt_case_asis,
+       Opt_conv_binary, Opt_conv_text, Opt_conv_auto,
+};
+
+static match_table_t tokens = {
+       {Opt_version, "version=%u"},
+       {Opt_uid, "uid=%u"},
+       {Opt_gid, "gid=%u"},
+       {Opt_umask, "umask=%o"},
+       {Opt_part, "part=%u"},
+       {Opt_type, "type=%s"},
+       {Opt_creator, "creator=%s"},
+       {Opt_quiet, "quiet"},
+       {Opt_afpd, "afpd"},
+       {Opt_names_netatalk, "names=netatalk"},
+       {Opt_names_trivial, "names=trivial"},
+       {Opt_names_alpha, "names=alpha"},
+       {Opt_names_latin, "names=latin"},
+       {Opt_names_7bit, "names=7bit"},
+       {Opt_names_8bit, "names=8bit"},
+       {Opt_names_cap, "names=cap"},
+       {Opt_names_netatalk, "names=n"},
+       {Opt_names_trivial, "names=t"},
+       {Opt_names_alpha, "names=a"},
+       {Opt_names_latin, "names=l"},
+       {Opt_names_7bit, "names=7"},
+       {Opt_names_8bit, "names=8"},
+       {Opt_names_cap, "names=c"},
+       {Opt_fork_netatalk, "fork=netatalk"},
+       {Opt_fork_single, "fork=single"},
+       {Opt_fork_double, "fork=double"},
+       {Opt_fork_cap, "fork=cap"},
+       {Opt_fork_netatalk, "fork=n"},
+       {Opt_fork_single, "fork=s"},
+       {Opt_fork_double, "fork=d"},
+       {Opt_fork_cap, "fork=c"},
+       {Opt_case_lower, "case=lower"},
+       {Opt_case_asis, "case=asis"},
+       {Opt_case_lower, "case=l"},
+       {Opt_case_asis, "case=a"},
+       {Opt_conv_binary, "conv=binary"},
+       {Opt_conv_text, "conv=text"},
+       {Opt_conv_auto, "conv=auto"},
+       {Opt_conv_binary, "conv=b"},
+       {Opt_conv_text, "conv=t"},
+       {Opt_conv_auto, "conv=a"},
+};
+
 /*
  * parse_options()
  * 
@@ -219,8 +274,10 @@ static int hfs_statfs(struct super_block *sb, struct kstatfs *buf)
  */
 static int parse_options(char *options, struct hfs_sb_info *hsb, int *part)
 {
-       char *this_char, *value;
+       char *p;
        char names, fork;
+       substring_t args[MAX_OPT_ARGS];
+       int option;
 
        /* initialize the sb with defaults */
        memset(hsb, 0, sizeof(*hsb));
@@ -243,117 +300,109 @@ static int parse_options(char *options, struct hfs_sb_info *hsb, int *part)
        if (!options) {
                goto done;
        }
-       while ((this_char = strsep(&options,",")) != NULL) {
-               if (!*this_char)
+       while ((p = strsep(&options,",")) != NULL) {
+               int token;
+               if (!*p)
                        continue;
-               if ((value = strchr(this_char,'=')) != NULL) {
-                       *value++ = 0;
-               }
-       /* Numeric-valued options */
-               if (!strcmp(this_char, "version")) {
-                       if (!value || !*value) {
-                               return 0;
-                       }
-                       hsb->s_version = simple_strtoul(value,&value,0);
-                       if (*value) {
-                               return 0;
-                       }
-               } else if (!strcmp(this_char,"uid")) {
-                       if (!value || !*value) {
-                               return 0;
-                       }
-                       hsb->s_uid = simple_strtoul(value,&value,0);
-                       if (*value) {
-                               return 0;
-                       }
-               } else if (!strcmp(this_char,"gid")) {
-                       if (!value || !*value) {
-                               return 0;
-                       }
-                       hsb->s_gid = simple_strtoul(value,&value,0);
-                       if (*value) {
-                               return 0;
-                       }
-               } else if (!strcmp(this_char,"umask")) {
-                       if (!value || !*value) {
+
+               token = match_token(p, tokens, args);
+               switch (token) {
+               /* Numeric-valued options */
+               case Opt_version:
+                       if (match_int(&args[0], &option))
                                return 0;
-                       }
-                       hsb->s_umask = simple_strtoul(value,&value,8);
-                       if (*value) {
+                       hsb->s_version = option;
+                       break;
+               case Opt_uid:
+                       if (match_int(&args[0], &option))
                                return 0;
-                       }
-               } else if (!strcmp(this_char,"part")) {
-                       if (!value || !*value) {
+                       hsb->s_uid = option;
+                       break;
+               case Opt_gid:
+                       if (match_int(&args[0], &option))
                                return 0;
-                       }
-                       *part = simple_strtoul(value,&value,0);
-                       if (*value) {
+                       hsb->s_gid = option;
+                       break;
+               case Opt_umask:
+                       if (match_octal(&args[0], &option))
                                return 0;
-                       }
-       /* String-valued options */
-               } else if (!strcmp(this_char,"type") && value) {
-                       if (strlen(value) != 4) {
+                       hsb->s_umask = option;
+                       break;
+               case Opt_part:
+                       if (match_int(&args[0], &option))
                                return 0;
-                       }
-                       hsb->s_type = hfs_get_nl(value);
-               } else if (!strcmp(this_char,"creator") && value) {
-                       if (strlen(value) != 4) {
+                       *part = option;
+                       break;
+               /* String-valued options */
+               case Opt_type:
+                       if (strlen(args[0].from) != 4) {
                                return 0;
                        }
-                       hsb->s_creator = hfs_get_nl(value);
-       /* Boolean-valued options */
-               } else if (!strcmp(this_char,"quiet")) {
-                       if (value) {
+                       hsb->s_type = hfs_get_nl(args[0].from);
+                       break;
+               case Opt_creator:
+                       if (strlen(args[0].from) != 4) {
                                return 0;
                        }
+                       hsb->s_creator = hfs_get_nl(args[0].from);
+                       break;
+               /* Boolean-valued options */
+               case Opt_quiet:
                        hsb->s_quiet = 1;
-               } else if (!strcmp(this_char,"afpd")) {
-                       if (value) {
-                               return 0;
-                       }
+                       break;
+               case Opt_afpd:
                        hsb->s_afpd = 1;
-       /* Multiple choice options */
-               } else if (!strcmp(this_char,"names") && value) {
-                       if ((*value && !value[1] && strchr("ntal78c",*value)) ||
-                           !strcmp(value,"netatalk") ||
-                           !strcmp(value,"trivial") ||
-                           !strcmp(value,"alpha") ||
-                           !strcmp(value,"latin") ||
-                           !strcmp(value,"7bit") ||
-                           !strcmp(value,"8bit") ||
-                           !strcmp(value,"cap")) {
-                               names = *value;
-                       } else {
-                               return 0;
-                       }
-               } else if (!strcmp(this_char,"fork") && value) {
-                       if ((*value && !value[1] && strchr("nsdc",*value)) ||
-                           !strcmp(value,"netatalk") ||
-                           !strcmp(value,"single") ||
-                           !strcmp(value,"double") ||
-                           !strcmp(value,"cap")) {
-                               fork = *value;
-                       } else {
-                               return 0;
-                       }
-               } else if (!strcmp(this_char,"case") && value) {
-                       if ((*value && !value[1] && strchr("la",*value)) ||
-                           !strcmp(value,"lower") ||
-                           !strcmp(value,"asis")) {
-                               hsb->s_lowercase = (*value == 'l');
-                       } else {
-                               return 0;
-                       }
-               } else if (!strcmp(this_char,"conv") && value) {
-                       if ((*value && !value[1] && strchr("bta",*value)) ||
-                           !strcmp(value,"binary") ||
-                           !strcmp(value,"text") ||
-                           !strcmp(value,"auto")) {
-                               hsb->s_conv = *value;
-                       } else {
-                               return 0;
-                       }
-               } else {
+                       break;
+               /* Multiple choice options */
+               case Opt_names_netatalk:
+                       names = 'n';
+                       break;
+               case Opt_names_trivial:
+                       names = 't';
+                       break;
+               case Opt_names_alpha:
+                       names = 'a';
+                       break;
+               case Opt_names_latin:
+                       names = 'l';
+                       break;
+               case Opt_names_7bit:
+                       names = '7';
+                       break;
+               case Opt_names_8bit:
+                       names = '8';
+                       break;
+               case Opt_names_cap:
+                       names = 'c';
+                       break;
+               case Opt_fork_netatalk:
+                       fork = 'n';
+                       break;
+               case Opt_fork_single:
+                       fork = 's';
+                       break;
+               case Opt_fork_double:
+                       fork = 'd';
+                       break;
+               case Opt_fork_cap:
+                       fork = 'c';
+                       break;
+               case Opt_case_lower:
+                       hsb->s_lowercase = 1;
+                       break;
+               case Opt_case_asis:
+                       hsb->s_lowercase = 0;
+                       break;
+               case Opt_conv_binary:
+                       hsb->s_conv = 'b';
+                       break;
+               case Opt_conv_text:
+                       hsb->s_conv = 't';
+                       break;
+               case Opt_conv_auto:
+                       hsb->s_conv = 'a';
+                       break;
+               default:
                        return 0;
                }
        }
index 5827a006dd9b7daf30809f198f8d3ab3e9a13b56..166a2d4168cc7877848bee91364fb592c402de9a 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/string.h>
 #include "hpfs_fn.h"
 #include <linux/module.h>
+#include <linux/parser.h>
 #include <linux/init.h>
 #include <linux/vfs.h>
 
@@ -219,15 +220,52 @@ static struct super_operations hpfs_sops =
 
 /*
  * A tiny parser for option strings, stolen from dosfs.
- *
  * Stolen again from read-only hpfs.
+ * And updated for table-driven option parsing.
  */
 
+enum {
+       Opt_help, Opt_uid, Opt_gid, Opt_umask, Opt_case_lower, Opt_case_asis,
+       Opt_conv_binary, Opt_conv_text, Opt_conv_auto,
+       Opt_check_none, Opt_check_normal, Opt_check_strict,
+       Opt_err_cont, Opt_err_ro, Opt_err_panic,
+       Opt_eas_no, Opt_eas_ro, Opt_eas_rw,
+       Opt_chkdsk_no, Opt_chkdsk_errors, Opt_chkdsk_always,
+       Opt_timeshift, Opt_err,
+};
+
+static match_table_t tokens = {
+       {Opt_help, "help"},
+       {Opt_uid, "uid=%u"},
+       {Opt_gid, "gid=%u"},
+       {Opt_umask, "umask=%o"},
+       {Opt_case_lower, "case=lower"},
+       {Opt_case_asis, "case=asis"},
+       {Opt_conv_binary, "conv=binary"},
+       {Opt_conv_text, "conv=text"},
+       {Opt_conv_auto, "conv=auto"},
+       {Opt_check_none, "check=none"},
+       {Opt_check_normal, "check=normal"},
+       {Opt_check_strict, "check=strict"},
+       {Opt_err_cont, "errors=continue"},
+       {Opt_err_ro, "errors=remount-ro"},
+       {Opt_err_panic, "errors=panic"},
+       {Opt_eas_no, "eas=no"},
+       {Opt_eas_ro, "eas=ro"},
+       {Opt_eas_rw, "eas=rw"},
+       {Opt_chkdsk_no, "chkdsk=no"},
+       {Opt_chkdsk_errors, "chkdsk=errors"},
+       {Opt_chkdsk_always, "chkdsk=always"},
+       {Opt_timeshift, "timeshift=%d"},
+       {Opt_err, NULL},
+};
+
 int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask,
               int *lowercase, int *conv, int *eas, int *chk, int *errs,
               int *chkdsk, int *timeshift)
 {
-       char *p, *rhs;
+       char *p;
+       int option;
 
        if (!opts)
                return 1;
@@ -235,34 +273,85 @@ int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask,
        /*printk("Parsing opts: '%s'\n",opts);*/
 
        while ((p = strsep(&opts, ",")) != NULL) {
+               substring_t args[MAX_OPT_ARGS];
+               int token;
                if (!*p)
                        continue;
-               if ((rhs = strchr(p, '=')) != 0)
-                       *rhs++ = '\0';
-               if (!strcmp(p, "help")) return 2;
-               if (!strcmp(p, "uid")) {
-                       if (!rhs || !*rhs)
-                               return 0;
-                       *uid = simple_strtoul(rhs, &rhs, 0);
-                       if (*rhs)
-                               return 0;
-               }
-               else if (!strcmp(p, "gid")) {
-                       if (!rhs || !*rhs)
-                               return 0;
-                       *gid = simple_strtoul(rhs, &rhs, 0);
-                       if (*rhs)
+
+               token = match_token(p, tokens, args);
+               switch (token) {
+               case Opt_help:
+                       return 2;
+               case Opt_uid:
+                       if (match_int(args, &option))
                                return 0;
-               }
-               else if (!strcmp(p, "umask")) {
-                       if (!rhs || !*rhs)
+                       *uid = option;
+                       break;
+               case Opt_gid:
+                       if (match_int(args, &option))
                                return 0;
-                       *umask = simple_strtoul(rhs, &rhs, 8);
-                       if (*rhs)
+                       *gid = option;
+                       break;
+               case Opt_umask:
+                       if (match_octal(args, &option))
                                return 0;
-               }
-               else if (!strcmp(p, "timeshift")) {
+                       *umask = option;
+                       break;
+               case Opt_case_lower:
+                       *lowercase = 1;
+                       break;
+               case Opt_case_asis:
+                       *lowercase = 0;
+                       break;
+               case Opt_conv_binary:
+                       *conv = CONV_BINARY;
+                       break;
+               case Opt_conv_text:
+                       *conv = CONV_TEXT;
+                       break;
+               case Opt_conv_auto:
+                       *conv = CONV_AUTO;
+                       break;
+               case Opt_check_none:
+                       *chk = 0;
+                       break;
+               case Opt_check_normal:
+                       *chk = 1;
+                       break;
+               case Opt_check_strict:
+                       *chk = 2;
+                       break;
+               case Opt_err_cont:
+                       *errs = 0;
+                       break;
+               case Opt_err_ro:
+                       *errs = 1;
+                       break;
+               case Opt_err_panic:
+                       *errs = 2;
+                       break;
+               case Opt_eas_no:
+                       *eas = 0;
+                       break;
+               case Opt_eas_ro:
+                       *eas = 1;
+                       break;
+               case Opt_eas_rw:
+                       *eas = 2;
+                       break;
+               case Opt_chkdsk_no:
+                       *chkdsk = 0;
+                       break;
+               case Opt_chkdsk_errors:
+                       *chkdsk = 1;
+                       break;
+               case Opt_chkdsk_always:
+                       *chkdsk = 2;
+                       break;
+               case Opt_timeshift:
+               {
                        int m = 1;
+                       char *rhs = args[0].from;
                        if (!rhs || !*rhs)
                                return 0;
                        if (*rhs == '-') m = -1;
@@ -270,79 +359,11 @@ int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask,
                        *timeshift = simple_strtoul(rhs, &rhs, 0) * m;
                        if (*rhs)
                                return 0;
+                       break;
                }
-               else if (!strcmp(p, "case")) {
-                       if (!rhs || !*rhs)
-                               return 0;
-                       if (!strcmp(rhs, "lower"))
-                               *lowercase = 1;
-                       else if (!strcmp(rhs, "asis"))
-                               *lowercase = 0;
-                       else
-                               return 0;
-               }
-               else if (!strcmp(p, "conv")) {
-                       if (!rhs || !*rhs)
-                               return 0;
-                       if (!strcmp(rhs, "binary"))
-                               *conv = CONV_BINARY;
-                       else if (!strcmp(rhs, "text"))
-                               *conv = CONV_TEXT;
-                       else if (!strcmp(rhs, "auto"))
-                               *conv = CONV_AUTO;
-                       else
-                               return 0;
-               }
-               else if (!strcmp(p, "check")) {
-                       if (!rhs || !*rhs)
-                               return 0;
-                       if (!strcmp(rhs, "none"))
-                               *chk = 0;
-                       else if (!strcmp(rhs, "normal"))
-                               *chk = 1;
-                       else if (!strcmp(rhs, "strict"))
-                               *chk = 2;
-                       else
-                               return 0;
-               }
-               else if (!strcmp(p, "errors")) {
-                       if (!rhs || !*rhs)
-                               return 0;
-                       if (!strcmp(rhs, "continue"))
-                               *errs = 0;
-                       else if (!strcmp(rhs, "remount-ro"))
-                               *errs = 1;
-                       else if (!strcmp(rhs, "panic"))
-                               *errs = 2;
-                       else
-                               return 0;
-               }
-               else if (!strcmp(p, "eas")) {
-                       if (!rhs || !*rhs)
-                               return 0;
-                       if (!strcmp(rhs, "no"))
-                               *eas = 0;
-                       else if (!strcmp(rhs, "ro"))
-                               *eas = 1;
-                       else if (!strcmp(rhs, "rw"))
-                               *eas = 2;
-                       else
-                               return 0;
-               }
-               else if (!strcmp(p, "chkdsk")) {
-                       if (!rhs || !*rhs)
-                               return 0;
-                       if (!strcmp(rhs, "no"))
-                               *chkdsk = 0;
-                       else if (!strcmp(rhs, "errors"))
-                               *chkdsk = 1;
-                       else if (!strcmp(rhs, "always"))
-                               *chkdsk = 2;
-                       else
-                               return 0;
-               }
-               else
+               default:
                        return 0;
+               }
        }
        return 1;
 }
index bbff5798e2d30e24812313c9609cc6cdc5082f1b..28fa42c5793211b31b7379773b4d4eb1b00c2d4e 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/blkdev.h>
 #include <linux/buffer_head.h>
 #include <linux/vfs.h>
+#include <linux/parser.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
@@ -328,9 +329,52 @@ isofs_dentry_cmpi_ms(struct dentry *dentry,struct qstr *a,struct qstr *b)
 }
 #endif
 
+enum {
+       Opt_block, Opt_check_r, Opt_check_s, Opt_cruft, Opt_gid, Opt_ignore,
+       Opt_iocharset, Opt_map_a, Opt_map_n, Opt_map_o, Opt_mode, Opt_nojoliet,
+       Opt_norock, Opt_sb, Opt_session, Opt_uid, Opt_unhide, Opt_utf8, Opt_err,
+       Opt_nocompress,
+};
+
+static match_table_t tokens = {
+       {Opt_norock, "norock"},
+       {Opt_nojoliet, "nojoliet"},
+       {Opt_unhide, "unhide"},
+       {Opt_cruft, "cruft"},
+       {Opt_utf8, "utf8"},
+       {Opt_iocharset, "iocharset=%s"},
+       {Opt_map_a, "map=acorn"},
+       {Opt_map_a, "map=a"},
+       {Opt_map_n, "map=normal"},
+       {Opt_map_n, "map=n"},
+       {Opt_map_o, "map=off"},
+       {Opt_map_o, "map=o"},
+       {Opt_session, "session=%u"},
+       {Opt_sb, "sbsector=%u"},
+       {Opt_check_r, "check=relaxed"},
+       {Opt_check_r, "check=r"},
+       {Opt_check_s, "check=strict"},
+       {Opt_check_s, "check=s"},
+       {Opt_uid, "uid=%u"},
+       {Opt_gid, "gid=%u"},
+       {Opt_mode, "mode=%u"},
+       {Opt_block, "block=%u"},
+       {Opt_ignore, "conv=binary"},
+       {Opt_ignore, "conv=b"},
+       {Opt_ignore, "conv=text"},
+       {Opt_ignore, "conv=t"},
+       {Opt_ignore, "conv=mtext"},
+       {Opt_ignore, "conv=m"},
+       {Opt_ignore, "conv=auto"},
+       {Opt_ignore, "conv=a"},
+       {Opt_nocompress, "nocompress"},
+       {Opt_err, NULL}
+};
+
 static int parse_options(char *options, struct iso9660_options * popt)
 {
-       char *this_char,*value;
+       char *p;
+       int option;
 
        popt->map = 'n';
        popt->rock = 'y';
@@ -350,112 +394,101 @@ static int parse_options(char *options, struct iso9660_options * popt)
        popt->utf8 = 0;
        popt->session=-1;
        popt->sbsector=-1;
-       if (!options) return 1;
-       while ((this_char = strsep(&options,",")) != NULL) {
-               if (!*this_char)
+       if (!options)
+               return 1;
+
+       while ((p = strsep(&options, ",")) != NULL) {
+               int token;
+               substring_t args[MAX_OPT_ARGS];
+               unsigned n;
+
+               if (!*p)
                        continue;
-               if (strncmp(this_char,"norock",6) == 0) {
-                 popt->rock = 'n';
-                 continue;
-               }
-               if (strncmp(this_char,"nojoliet",8) == 0) {
-                 popt->joliet = 'n';
-                 continue;
-               }
-               if (strncmp(this_char,"unhide",6) == 0) {
-                 popt->unhide = 'y';
-                 continue;
-               }
-               if (strncmp(this_char,"cruft",5) == 0) {
-                 popt->cruft = 'y';
-                 continue;
-               }
-               if (strncmp(this_char,"utf8",4) == 0) {
-                 popt->utf8 = 1;
-                 continue;
-               }
-               if (strncmp(this_char,"nocompress",10) == 0) {
-                 popt->nocompress = 1;
-                 continue;
-               }
-               if ((value = strchr(this_char,'=')) != NULL)
-                       *value++ = 0;
 
+               token = match_token(p, tokens, args);
+               switch (token) {
+               case Opt_norock:
+                       popt->rock = 'n';
+                       break;
+               case Opt_nojoliet:
+                       popt->joliet = 'n';
+                       break;
+               case Opt_unhide:
+                       popt->unhide = 'y';
+                       break;
+               case Opt_cruft:
+                       popt->cruft = 'y';
+                       break;
+               case Opt_utf8:
+                       popt->utf8 = 1;
+                       break;
 #ifdef CONFIG_JOLIET
-               if (!strcmp(this_char,"iocharset") && value) {
-                       popt->iocharset = value;
-                       while (*value && *value != ',')
-                               value++;
-                       if (value == popt->iocharset)
-                               return 0;
-                       *value = 0;
-               } else
+               case Opt_iocharset:
+                       popt->iocharset = match_strdup(&args[0]);
+                       break;
 #endif
-               if (!strcmp(this_char,"map") && value) {
-                       if (value[0] && !value[1] && strchr("ano",*value))
-                               popt->map = *value;
-                       else if (!strcmp(value,"off")) popt->map = 'o';
-                       else if (!strcmp(value,"normal")) popt->map = 'n';
-                       else if (!strcmp(value,"acorn")) popt->map = 'a';
-                       else return 0;
-               }
-               if (!strcmp(this_char,"session") && value) {
-                       char * vpnt = value;
-                       unsigned int ivalue = simple_strtoul(vpnt, &vpnt, 0);
-                       if(ivalue < 0 || ivalue >99) return 0;
-                       popt->session=ivalue+1;
-               }
-               if (!strcmp(this_char,"sbsector") && value) {
-                       char * vpnt = value;
-                       unsigned int ivalue = simple_strtoul(vpnt, &vpnt, 0);
-                       if(ivalue < 0 || ivalue >660*512) return 0;
-                       popt->sbsector=ivalue;
-               }
-               else if (!strcmp(this_char,"check") && value) {
-                       if (value[0] && !value[1] && strchr("rs",*value))
-                               popt->check = *value;
-                       else if (!strcmp(value,"relaxed")) popt->check = 'r';
-                       else if (!strcmp(value,"strict")) popt->check = 's';
-                       else return 0;
-               }
-               else if (!strcmp(this_char,"conv") && value) {
-                       /* no conversion is done anymore;
-                          we still accept the same mount options,
-                          but ignore them */
-                       if (value[0] && !value[1] && strchr("btma",*value)) ;
-                       else if (!strcmp(value,"binary")) ;
-                       else if (!strcmp(value,"text")) ;
-                       else if (!strcmp(value,"mtext")) ;
-                       else if (!strcmp(value,"auto")) ;
-                       else return 0;
-               }
-               else if (value &&
-                        (!strcmp(this_char,"block") ||
-                         !strcmp(this_char,"mode") ||
-                         !strcmp(this_char,"uid") ||
-                         !strcmp(this_char,"gid"))) {
-                 char * vpnt = value;
-                 unsigned int ivalue = simple_strtoul(vpnt, &vpnt, 0);
-                 if (*vpnt) return 0;
-                 switch(*this_char) {
-                 case 'b':
-                   if (   ivalue != 512
-                       && ivalue != 1024
-                       && ivalue != 2048) return 0;
-                   popt->blocksize = ivalue;
-                   break;
-                 case 'u':
-                   popt->uid = ivalue;
-                   break;
-                 case 'g':
-                   popt->gid = ivalue;
-                   break;
-                 case 'm':
-                   popt->mode = ivalue;
-                   break;
-                 }
+               case Opt_map_a:
+                       popt->map = 'a';
+                       break;
+               case Opt_map_o:
+                       popt->map = 'o';
+                       break;
+               case Opt_map_n:
+                       popt->map = 'n';
+                       break;
+               case Opt_session:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       n = option;
+                       if (n > 99)
+                               return 0;
+                       popt->session = n + 1;
+                       break;
+               case Opt_sb:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       n = option;
+                       if (n > 660 * 512)
+                               return 0;
+                       popt->sbsector = n;
+                       break;
+               case Opt_check_r:
+                       popt->check = 'r';
+                       break;
+               case Opt_check_s:
+                       popt->check = 's';
+                       break;
+               case Opt_ignore:
+                       break;
+               case Opt_uid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       popt->uid = option;
+                       break;
+               case Opt_gid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       popt->gid = option;
+                       break;
+               case Opt_mode:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       popt->mode = option;
+                       break;
+               case Opt_block:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       n = option;
+                       if (n != 512 && n != 1024 && n != 2048)
+                               return 0;
+                       popt->blocksize = n;
+                       break;
+               case Opt_nocompress:
+                       popt->nocompress = 1;
+                       break;
+               default:
+                       return 0;
                }
-               else return 1;
        }
        return 1;
 }
@@ -842,6 +875,9 @@ root_found:
        if (opt.check == 'r') table++;
        s->s_root->d_op = &isofs_dentry_ops[table];
 
+       if (opt.iocharset)
+               kfree(opt.iocharset);
+
        return 0;
 
        /*
@@ -879,6 +915,8 @@ out_unknown_format:
 out_freebh:
        brelse(bh);
 out_freesbi:
+       if (opt.iocharset)
+               kfree(opt.iocharset);
        kfree(sbi);
        s->s_fs_info = NULL;
        return -EINVAL;
index 2dee58a3556ef559bee035f225053d27a461608a..9efcf7137290adc595921c4cda2ee8d7c10e2d7c 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/fs.h>
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/parser.h>
 #include <linux/completion.h>
 #include <linux/vfs.h>
 #include <asm/uaccess.h>
@@ -164,59 +165,82 @@ static void jfs_put_super(struct super_block *sb)
        kfree(sbi);
 }
 
+enum {
+       Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize,
+       Opt_ignore, Opt_err,
+};
+
+static match_table_t tokens = {
+       {Opt_integrity, "integrity"},
+       {Opt_nointegrity, "nointegrity"},
+       {Opt_iocharset, "iocharset=%s"},
+       {Opt_resize, "resize=%u"},
+       {Opt_ignore, "noquota"},
+       {Opt_ignore, "quota"},
+       {Opt_ignore, "usrquota"},
+       {Opt_ignore, "grpquota"},
+       {Opt_err, NULL}
+};
+
 static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,
                         int *flag)
 {
        void *nls_map = NULL;
-       char *this_char;
-       char *value;
+       char *p;
        struct jfs_sb_info *sbi = JFS_SBI(sb);
 
        *newLVSize = 0;
 
        if (!options)
                return 1;
-       while ((this_char = strsep(&options, ",")) != NULL) {
-               if (!*this_char)
+
+       while ((p = strsep(&options, ",")) != NULL) {
+               substring_t args[MAX_OPT_ARGS];
+               int token;
+               if (!*p)
                        continue;
-               if ((value = strchr(this_char, '=')) != NULL)
-                       *value++ = 0;
-               if (!strcmp(this_char, "integrity")) {
+
+               token = match_token(p, tokens, args);
+               switch (token) {
+               case Opt_integrity:
                        *flag &= ~JFS_NOINTEGRITY;
-               } else  if (!strcmp(this_char, "nointegrity")) {
+                       break;
+               case Opt_nointegrity:
                        *flag |= JFS_NOINTEGRITY;
-               } else if (!strcmp(this_char, "iocharset")) {
-                       if (!value || !*value)
-                               goto needs_arg;
+                       break;
+               case Opt_ignore:
+                       /* Silently ignore the quota options */
+                       /* Don't do anything ;-) */
+                       break;
+               case Opt_iocharset:
                        if (nls_map)    /* specified iocharset twice! */
                                unload_nls(nls_map);
-                       nls_map = load_nls(value);
+                       nls_map = load_nls(args[0].from);
                        if (!nls_map) {
                                printk(KERN_ERR "JFS: charset not found\n");
                                goto cleanup;
                        }
-               } else if (!strcmp(this_char, "resize")) {
-                       if (!value || !*value) {
+                       break;
+               case Opt_resize:
+               {
+                       char *resize = args[0].from;
+                       if (!resize || !*resize) {
                                *newLVSize = sb->s_bdev->bd_inode->i_size >>
                                        sb->s_blocksize_bits;
                                if (*newLVSize == 0)
                                        printk(KERN_ERR
-                                        "JFS: Cannot determine volume size\n");
+                                       "JFS: Cannot determine volume size\n");
                        } else
-                               *newLVSize = simple_strtoull(value, &value, 0);
-
-                       /* Silently ignore the quota options */
-               } else if (!strcmp(this_char, "grpquota")
-                          || !strcmp(this_char, "noquota")
-                          || !strcmp(this_char, "quota")
-                          || !strcmp(this_char, "usrquota"))
-                       /* Don't do anything ;-) */ ;
-               else {
-                       printk("jfs: Unrecognized mount option %s\n",
-                              this_char);
+                               *newLVSize = simple_strtoull(resize, &resize, 0);
+                       break;
+               }
+               default:
+                       printk("jfs: Unrecognized mount option \"%s\" "
+                                       " or missing value\n", p);
                        goto cleanup;
                }
        }
+
        if (nls_map) {
                /* Discard old (if remount) */
                if (sbi->nls_tab)
@@ -224,8 +248,7 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,
                sbi->nls_tab = nls_map;
        }
        return 1;
-needs_arg:
-       printk(KERN_ERR "JFS: %s needs an argument\n", this_char);
+
 cleanup:
        if (nls_map)
                unload_nls(nls_map);
index 59adc1f7335b9553923b610e5219154dd48a0c4d..1427ffb57d5fd6ec309c24569bb07e7bdf24fee5 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/limits.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/parser.h>
 #include <linux/smp_lock.h>
 
 #include <asm/system.h>
@@ -135,34 +136,47 @@ static struct super_operations proc_sops = {
        .statfs         = simple_statfs,
 };
 
+enum {
+       Opt_uid, Opt_gid, Opt_err
+};
+
+static match_table_t tokens = {
+       {Opt_uid, "uid=%u"},
+       {Opt_gid, "gid=%u"},
+       {Opt_err, NULL}
+};
+
 static int parse_options(char *options,uid_t *uid,gid_t *gid)
 {
-       char *this_char,*value;
+       char *p;
+       int option;
 
        *uid = current->uid;
        *gid = current->gid;
        if (!options)
                return 1;
-       while ((this_char = strsep(&options,",")) != NULL) {
-               if (!*this_char)
+
+       while ((p = strsep(&options, ",")) != NULL) {
+               substring_t args[MAX_OPT_ARGS];
+               int token;
+               if (!*p)
                        continue;
-               if ((value = strchr(this_char,'=')) != NULL)
-                       *value++ = 0;
-               if (!strcmp(this_char,"uid")) {
-                       if (!value || !*value)
-                               return 0;
-                       *uid = simple_strtoul(value,&value,0);
-                       if (*value)
-                               return 0;
-               }
-               else if (!strcmp(this_char,"gid")) {
-                       if (!value || !*value)
+
+               token = match_token(p, tokens, args);
+               switch (token) {
+               case Opt_uid:
+                       if (match_int(args, &option))
                                return 0;
-                       *gid = simple_strtoul(value,&value,0);
-                       if (*value)
+                       *uid = option;
+                       break;
+               case Opt_gid:
+                       if (match_int(args, &option))
                                return 0;
+                       *gid = option;
+                       break;
+               default:
+                       return 0;
                }
-               else return 1;
        }
        return 1;
 }
index 827d7dce65aba7caf27bcc9faf55d27f9b53cba8..1f617b89aac3ed6b2d9f3521c0569575c8f4fbeb 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/parser.h>
 #include <linux/stat.h>
 #include <linux/cdrom.h>
 #include <linux/nls.h>
@@ -225,7 +226,7 @@ module_exit(exit_udf_fs)
  *     gid=            Set the default group.
  *     umask=          Set the default umask.
  *     uid=            Set the default user.
- *     bs=                     Set the block size.
+ *     bs=             Set the block size.
  *     unhide          Show otherwise hidden files.
  *     undelete        Show deleted files in lists.
  *     adinicb         Embed data in the inode (default)
@@ -259,18 +260,53 @@ module_exit(exit_udf_fs)
  *     uopts           Pointer to mount options variable.
  *
  * POST-CONDITIONS
- *     <return>        0       Mount options parsed okay.
- *     <return>        -1      Error parsing mount options.
+ *     <return>        1       Mount options parsed okay.
+ *     <return>        0       Error parsing mount options.
  *
  * HISTORY
  *     July 1, 1997 - Andrew E. Mileski
  *     Written, tested, and released.
  */
 
+enum {
+       Opt_novrs, Opt_nostrict, Opt_bs, Opt_unhide, Opt_undelete,
+       Opt_noadinicb, Opt_adinicb, Opt_shortad, Opt_longad,
+       Opt_gid, Opt_uid, Opt_umask, Opt_session, Opt_lastblock,
+       Opt_anchor, Opt_volume, Opt_partition, Opt_fileset,
+       Opt_rootdir, Opt_utf8, Opt_iocharset,
+       Opt_err
+};
+
+static match_table_t tokens = {
+       {Opt_novrs, "novrs"},
+       {Opt_nostrict, "nostrict"},
+       {Opt_bs, "bs=%u"},
+       {Opt_unhide, "unhide"},
+       {Opt_undelete, "undelete"},
+       {Opt_noadinicb, "noadinicb"},
+       {Opt_adinicb, "adinicb"},
+       {Opt_shortad, "shortad"},
+       {Opt_longad, "longad"},
+       {Opt_gid, "gid=%u"},
+       {Opt_uid, "uid=%u"},
+       {Opt_umask, "umask=%o"},
+       {Opt_session, "session=%u"},
+       {Opt_lastblock, "lastblock=%u"},
+       {Opt_anchor, "anchor=%u"},
+       {Opt_volume, "volume=%u"},
+       {Opt_partition, "partition=%u"},
+       {Opt_fileset, "fileset=%u"},
+       {Opt_rootdir, "rootdir=%u"},
+       {Opt_utf8, "utf8"},
+       {Opt_iocharset, "iocharset=%s"},
+       {Opt_err, NULL}
+};
+
 static int
 udf_parse_options(char *options, struct udf_options *uopt)
 {
-       char *opt, *val;
+       char *p;
+       int option;
 
        uopt->novrs = 0;
        uopt->blocksize = 2048;
@@ -286,71 +322,106 @@ udf_parse_options(char *options, struct udf_options *uopt)
        if (!options)
                return 1;
 
-       while ((opt = strsep(&options, ",")) != NULL)
-       {
-               if (!*opt)
+       while ((p = strsep(&options, ",")) != NULL) {
+               substring_t args[MAX_OPT_ARGS];
+               int token;
+               if (!*p)
                        continue;
-               /* Make "opt=val" into two strings */
-               val = strchr(opt, '=');
-               if (val)
-                       *(val++) = 0;
-               if (!strcmp(opt, "novrs") && !val)
+
+               token = match_token(p, tokens, args);
+               switch (token) {
+               case Opt_novrs:
                        uopt->novrs = 1;
-               else if (!strcmp(opt, "bs") && val)
-                       uopt->blocksize = simple_strtoul(val, NULL, 0);
-               else if (!strcmp(opt, "unhide") && !val)
+                       break;
+               case Opt_bs:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       uopt->blocksize = option;
+                       break;
+               case Opt_unhide:
                        uopt->flags |= (1 << UDF_FLAG_UNHIDE);
-               else if (!strcmp(opt, "undelete") && !val)
+                       break;
+               case Opt_undelete:
                        uopt->flags |= (1 << UDF_FLAG_UNDELETE);
-               else if (!strcmp(opt, "noadinicb") && !val)
+                       break;
+               case Opt_noadinicb:
                        uopt->flags &= ~(1 << UDF_FLAG_USE_AD_IN_ICB);
-               else if (!strcmp(opt, "adinicb") && !val)
+                       break;
+               case Opt_adinicb:
                        uopt->flags |= (1 << UDF_FLAG_USE_AD_IN_ICB);
-               else if (!strcmp(opt, "shortad") && !val)
+                       break;
+               case Opt_shortad:
                        uopt->flags |= (1 << UDF_FLAG_USE_SHORT_AD);
-               else if (!strcmp(opt, "longad") && !val)
+                       break;
+               case Opt_longad:
                        uopt->flags &= ~(1 << UDF_FLAG_USE_SHORT_AD);
-               else if (!strcmp(opt, "gid") && val)
-                       uopt->gid = simple_strtoul(val, NULL, 0);
-               else if (!strcmp(opt, "umask") && val)
-                       uopt->umask = simple_strtoul(val, NULL, 0);
-               else if (!strcmp(opt, "nostrict") && !val)
+                       break;
+               case Opt_gid:
+                       if (match_int(args, &option))
+                               return 0;
+                       uopt->gid = option;
+                       break;
+               case Opt_uid:
+                       if (match_int(args, &option))
+                               return 0;
+                       uopt->uid = option;
+                       break;
+               case Opt_umask:
+                       if (match_octal(args, &option))
+                               return 0;
+                       uopt->umask = option;
+                       break;
+               case Opt_nostrict:
                        uopt->flags &= ~(1 << UDF_FLAG_STRICT);
-               else if (!strcmp(opt, "uid") && val)
-                       uopt->uid = simple_strtoul(val, NULL, 0);
-               else if (!strcmp(opt, "session") && val)
-                       uopt->session = simple_strtoul(val, NULL, 0);
-               else if (!strcmp(opt, "lastblock") && val)
-                       uopt->lastblock = simple_strtoul(val, NULL, 0);
-               else if (!strcmp(opt, "anchor") && val)
-                       uopt->anchor = simple_strtoul(val, NULL, 0);
-               else if (!strcmp(opt, "volume") && val)
-                       uopt->volume = simple_strtoul(val, NULL, 0);
-               else if (!strcmp(opt, "partition") && val)
-                       uopt->partition = simple_strtoul(val, NULL, 0);
-               else if (!strcmp(opt, "fileset") && val)
-                       uopt->fileset = simple_strtoul(val, NULL, 0);
-               else if (!strcmp(opt, "rootdir") && val)
-                       uopt->rootdir = simple_strtoul(val, NULL, 0);
+                       break;
+               case Opt_session:
+                       if (match_int(args, &option))
+                               return 0;
+                       uopt->session = option;
+                       break;
+               case Opt_lastblock:
+                       if (match_int(args, &option))
+                               return 0;
+                       uopt->lastblock = option;
+                       break;
+               case Opt_anchor:
+                       if (match_int(args, &option))
+                               return 0;
+                       uopt->anchor = option;
+                       break;
+               case Opt_volume:
+                       if (match_int(args, &option))
+                               return 0;
+                       uopt->volume = option;
+                       break;
+               case Opt_partition:
+                       if (match_int(args, &option))
+                               return 0;
+                       uopt->partition = option;
+                       break;
+               case Opt_fileset:
+                       if (match_int(args, &option))
+                               return 0;
+                       uopt->fileset = option;
+                       break;
+               case Opt_rootdir:
+                       if (match_int(args, &option))
+                               return 0;
+                       uopt->rootdir = option;
+                       break;
+               case Opt_utf8:
+                       uopt->flags |= (1 << UDF_FLAG_UTF8);
+                       break;
 #ifdef CONFIG_NLS
-               else if (!strcmp(opt, "iocharset") && val)
-               {
-                       uopt->nls_map = load_nls(val);
+               case Opt_iocharset:
+                       uopt->nls_map = load_nls(args[0].from);
                        uopt->flags |= (1 << UDF_FLAG_NLS_MAP);
-               }
+                       break;
 #endif
-               else if (!strcmp(opt, "utf8") && !val)
-                       uopt->flags |= (1 << UDF_FLAG_UTF8);
-               else if (val)
-               {
-                       printk(KERN_ERR "udf: bad mount option \"%s=%s\"\n",
-                               opt, val);
-                       return 0;
-               }
-               else
-               {
-                       printk(KERN_ERR "udf: bad mount option \"%s\"\n",
-                               opt);
+               default:
+                       printk(KERN_ERR "udf: bad mount option \"%s\" "
+                                       "or missing value\n",
+                               p);
                        return 0;
                }
        }
index 802ca517153e1dbbf832343073bdaed55081c09b..db14bea446fcbe5cd34357face875cc6d3ca1d13 100644 (file)
@@ -79,6 +79,7 @@
 #include <linux/string.h>
 #include <linux/blkdev.h>
 #include <linux/init.h>
+#include <linux/parser.h>
 #include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/vfs.h>
@@ -250,64 +251,99 @@ void ufs_warning (struct super_block * sb, const char * function,
                sb->s_id, function, error_buf);
 }
 
+enum {
+       Opt_type_old, Opt_type_sunx86, Opt_type_sun, Opt_type_44bsd,
+       Opt_type_hp, Opt_type_nextstepcd, Opt_type_nextstep,
+       Opt_type_openstep, Opt_onerror_panic, Opt_onerror_lock,
+       Opt_onerror_umount, Opt_onerror_repair, Opt_err
+};
+
+static match_table_t tokens = {
+       {Opt_type_old, "ufstype=old"},
+       {Opt_type_sunx86, "ufstype=sunx86"},
+       {Opt_type_sun, "ufstype=sun"},
+       {Opt_type_44bsd, "ufstype=44bsd"},
+       {Opt_type_hp, "ufstype=hp"},
+       {Opt_type_nextstepcd, "ufstype=nextstep-cd"},
+       {Opt_type_nextstep, "ufstype=nextstep"},
+       {Opt_type_openstep, "ufstype=openstep"},
+       {Opt_onerror_panic, "onerror=panic"},
+       {Opt_onerror_lock, "onerror=lock"},
+       {Opt_onerror_umount, "onerror=umount"},
+       {Opt_onerror_repair, "onerror=repair"},
+       {Opt_err, NULL}
+};
+
 static int ufs_parse_options (char * options, unsigned * mount_options)
 {
-       char * this_char;
-       char * value;
+       char * p;
        
        UFSD(("ENTER\n"))
        
        if (!options)
                return 1;
 
-       while ((this_char = strsep (&options, ",")) != NULL) {
-               if (!*this_char)
+       while ((p = strsep(&options, ",")) != NULL) {
+               substring_t args[MAX_OPT_ARGS];
+               int token;
+               if (!*p)
                        continue;
-               if ((value = strchr (this_char, '=')) != NULL)
-                       *value++ = 0;
-               if (!strcmp (this_char, "ufstype")) {
+
+               token = match_token(p, tokens, args);
+               switch (token) {
+               case Opt_type_old:
                        ufs_clear_opt (*mount_options, UFSTYPE);
-                       if (!strcmp (value, "old"))
-                               ufs_set_opt (*mount_options, UFSTYPE_OLD);
-                       else if (!strcmp (value, "sun"))
-                               ufs_set_opt (*mount_options, UFSTYPE_SUN);
-                       else if (!strcmp (value, "44bsd"))
-                               ufs_set_opt (*mount_options, UFSTYPE_44BSD);
-                       else if (!strcmp (value, "nextstep"))
-                               ufs_set_opt (*mount_options, UFSTYPE_NEXTSTEP);
-                       else if (!strcmp (value, "nextstep-cd"))
-                               ufs_set_opt (*mount_options, UFSTYPE_NEXTSTEP_CD);
-                       else if (!strcmp (value, "openstep"))
-                               ufs_set_opt (*mount_options, UFSTYPE_OPENSTEP);
-                       else if (!strcmp (value, "sunx86"))
-                               ufs_set_opt (*mount_options, UFSTYPE_SUNx86);
-                       else if (!strcmp (value, "hp"))
-                               ufs_set_opt (*mount_options, UFSTYPE_HP);
-                       else {
-                               printk ("UFS-fs: Invalid type option: %s\n", value);
-                               return 0;
-                       }
-               }
-               else if (!strcmp (this_char, "onerror")) {
+                       ufs_set_opt (*mount_options, UFSTYPE_OLD);
+                       break;
+               case Opt_type_sunx86:
+                       ufs_clear_opt (*mount_options, UFSTYPE);
+                       ufs_set_opt (*mount_options, UFSTYPE_SUNx86);
+                       break;
+               case Opt_type_sun:
+                       ufs_clear_opt (*mount_options, UFSTYPE);
+                       ufs_set_opt (*mount_options, UFSTYPE_SUN);
+                       break;
+               case Opt_type_44bsd:
+                       ufs_clear_opt (*mount_options, UFSTYPE);
+                       ufs_set_opt (*mount_options, UFSTYPE_44BSD);
+                       break;
+               case Opt_type_hp:
+                       ufs_clear_opt (*mount_options, UFSTYPE);
+                       ufs_set_opt (*mount_options, UFSTYPE_HP);
+                       break;
+               case Opt_type_nextstepcd:
+                       ufs_clear_opt (*mount_options, UFSTYPE);
+                       ufs_set_opt (*mount_options, UFSTYPE_NEXTSTEP_CD);
+                       break;
+               case Opt_type_nextstep:
+                       ufs_clear_opt (*mount_options, UFSTYPE);
+                       ufs_set_opt (*mount_options, UFSTYPE_NEXTSTEP);
+                       break;
+               case Opt_type_openstep:
+                       ufs_clear_opt (*mount_options, UFSTYPE);
+                       ufs_set_opt (*mount_options, UFSTYPE_OPENSTEP);
+                       break;
+               case Opt_onerror_panic:
                        ufs_clear_opt (*mount_options, ONERROR);
-                       if (!strcmp (value, "panic"))
-                               ufs_set_opt (*mount_options, ONERROR_PANIC);
-                       else if (!strcmp (value, "lock"))
-                               ufs_set_opt (*mount_options, ONERROR_LOCK);
-                       else if (!strcmp (value, "umount"))
-                               ufs_set_opt (*mount_options, ONERROR_UMOUNT);
-                       else if (!strcmp (value, "repair")) {
-                               printk("UFS-fs: Unable to do repair on error, "
-                                       "will lock lock instead \n");
-                               ufs_set_opt (*mount_options, ONERROR_REPAIR);
-                       }
-                       else {
-                               printk ("UFS-fs: Invalid action onerror: %s\n", value);
-                               return 0;
-                       }
-               }
-               else {
-                       printk("UFS-fs: Invalid option: %s\n", this_char);
+                       ufs_set_opt (*mount_options, ONERROR_PANIC);
+                       break;
+               case Opt_onerror_lock:
+                       ufs_clear_opt (*mount_options, ONERROR);
+                       ufs_set_opt (*mount_options, ONERROR_LOCK);
+                       break;
+               case Opt_onerror_umount:
+                       ufs_clear_opt (*mount_options, ONERROR);
+                       ufs_set_opt (*mount_options, ONERROR_UMOUNT);
+                       break;
+               case Opt_onerror_repair:
+                       printk("UFS-fs: Unable to do repair on error, "
+                               "will lock lock instead\n");
+                       ufs_clear_opt (*mount_options, ONERROR);
+                       ufs_set_opt (*mount_options, ONERROR_REPAIR);
+                       break;
+               default:
+                       printk("UFS-fs: Invalid option: \"%s\" "
+                                       "or missing value\n", p);
                        return 0;
                }
        }
diff --git a/include/linux/parser.h b/include/linux/parser.h
new file mode 100644 (file)
index 0000000..5f982a1
--- /dev/null
@@ -0,0 +1,21 @@
+struct match_token {
+       int token;
+       char *pattern;
+};
+
+typedef struct match_token match_table_t[];
+
+enum {MAX_OPT_ARGS = 3};
+
+typedef struct {
+       char *from;
+       char *to;
+} substring_t;
+
+int match_token(char *s, match_table_t table, substring_t args[]);
+
+int match_int(substring_t *, int *result);
+int match_octal(substring_t *, int *result);
+int match_hex(substring_t *, int *result);
+void match_strcpy(char *, substring_t *);
+char *match_strdup(substring_t *);
index b26666dfb173368b0cabed14afa906f08a5a1846..3ba542f64d6d3d913a286f0f878529028b3311e5 100644 (file)
@@ -5,7 +5,7 @@
 
 lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \
         bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \
-        kobject.o idr.o div64.o
+        kobject.o idr.o div64.o parser.o
 
 lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
 lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
diff --git a/lib/parser.c b/lib/parser.c
new file mode 100644 (file)
index 0000000..8580613
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * lib/parser.c - simple parser for mount, etc. options.
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/parser.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+static int match_one(char *s, char *p, substring_t args[])
+{
+       char *meta;
+       int argc = 0;
+
+       if (!p)
+               return 1;
+
+       while(1) {
+               int len = -1;
+               meta = strchr(p, '%');
+               if (!meta)
+                       return strcmp(p, s) == 0;
+
+               if (strncmp(p, s, meta-p))
+                       return 0;
+
+               s += meta - p;
+               p = meta + 1;
+
+               if (isdigit(*p))
+                       len = simple_strtoul(p, &p, 10);
+               else if (*p == '%') {
+                       if (*s++ != '%')
+                               return 0;
+                       continue;
+               }
+
+               if (argc >= MAX_OPT_ARGS)
+                       return 0;
+
+               args[argc].from = s;
+               switch (*p++) {
+               case 's':
+                       if (len == -1 || len > strlen(s))
+                               len = strlen(s);
+                       args[argc].to = s + len;
+                       break;
+               case 'd':
+                       simple_strtol(s, &args[argc].to, 0);
+                       goto num;
+               case 'u':
+                       simple_strtoul(s, &args[argc].to, 0);
+                       goto num;
+               case 'o':
+                       simple_strtoul(s, &args[argc].to, 8);
+                       goto num;
+               case 'x':
+                       simple_strtoul(s, &args[argc].to, 16);
+               num:
+                       if (args[argc].to == args[argc].from)
+                               return 0;
+                       break;
+               default:
+                       return 0;
+               }
+               s = args[argc].to;
+               argc++;
+       }
+}
+
+int match_token(char *s, match_table_t table, substring_t args[])
+{
+       struct match_token *p;
+
+       for (p = table; !match_one(s, p->pattern, args) ; p++)
+               ;
+
+       return p->token;
+}
+
+static int match_number(substring_t *s, int *result, int base)
+{
+       char *endp;
+       char *buf;
+       int ret;
+
+       buf = kmalloc(s->to - s->from + 1, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       memcpy(buf, s->from, s->to - s->from);
+       buf[s->to - s->from] = '\0';
+       *result = simple_strtol(buf, &endp, base);
+       ret = 0;
+       if (endp == buf)
+               ret = -EINVAL;
+       kfree(buf);
+       return ret;
+}
+
+int match_int(substring_t *s, int *result)
+{
+       return match_number(s, result, 0);
+}
+
+int match_octal(substring_t *s, int *result)
+{
+       return match_number(s, result, 8);
+}
+
+int match_hex(substring_t *s, int *result)
+{
+       return match_number(s, result, 16);
+}
+
+void match_strcpy(char *to, substring_t *s)
+{
+       memcpy(to, s->from, s->to - s->from);
+       to[s->to - s->from] = '\0';
+}
+
+char *match_strdup(substring_t *s)
+{
+       char *p = kmalloc(s->to - s->from + 1, GFP_KERNEL);
+       if (p)
+               match_strcpy(p, s);
+       return p;
+}
+
+EXPORT_SYMBOL(match_token);
+EXPORT_SYMBOL(match_int);
+EXPORT_SYMBOL(match_octal);
+EXPORT_SYMBOL(match_hex);
+EXPORT_SYMBOL(match_strcpy);
+EXPORT_SYMBOL(match_strdup);