[RFC][PATCH] parser for mount options

From: Alexander Viro (viro@math.psu.edu)
Date: Tue Aug 07 2001 - 12:02:05 EST


        OK, folks - here's an implementation of parser for mount options.
Patch contains parser itself (lib/parser.c, include/linux/parser.h) and
switches parse_options() in several filesystems to using it instead of
the current ad-hackery.

        Patch works and AFAICS it shouldn't be hard to convert the rest.

What I wanted to get:
        * set of options accepted by fs and syntax of their arguments
should be visible in source. Explicitly.
        * no cascades of strcmp/strncmp/peeking at individual characters
by hands.
        * simple and regular parse_options() implementations.
        * being able to use that mechanism for procfs ->write() and its ilk.
        * parser itself should be small.

What had been done:
        * match_table_t is an array of pairs (number [== enum member], pattern)
It describes the acceptable options. Patterns are small subset of scanf
formats - the only things recognized by now are %d, %u, %o, %x, %s and
%<num>s. E.g. "uid=%u" or "iocharset=%20s". NULL is a catch-all - everything
matches it.
        * function match_token() looks for the first pattern in the table
that matches given string _and_ fills the array of arguments. Said array
consists of struct { char *from; char *to;} - no conversion, we just find
the substrings.
        * match_int(), match_octal(), etc. take a pointer to such structure
and do the conversion. IOW, usually code will look like
        token = match_token(s, table, argv);
        switch (token) {
                case Opt_uid:
                        uid = match_int(&argv[0]);
                        break;
                ...
        }
        * for %s we have two kinds of conversion - match_strcpy() and
match_strdup(). Meaning should be obvious (allocation is done with
kmalloc(..., GFP_KERNEL);

        It works surprisingly well - syntax is immediately visible in
the table, code is not crapped with tons of global variables and parser
itself is not large.

        Patch applies clean at least to -pre4 and -pre5. Comments,
suggestions and flames are welcome. I hope that it got enough
filesystems converted to be representative - adfs, autofs, devpts,
ext2, fat and isofs.
                                                                Al

Patch follows:

diff -urN S8-pre5/fs/adfs/super.c S8-pre5-opt/fs/adfs/super.c
--- S8-pre5/fs/adfs/super.c Thu Apr 19 23:46:42 2001
+++ S8-pre5-opt/fs/adfs/super.c Tue Aug 7 11:25:29 2001
@@ -18,6 +18,7 @@
 #include <linux/string.h>
 #include <linux/locks.h>
 #include <linux/init.h>
+#include <linux/parser.h>
 
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
@@ -164,48 +165,43 @@
         kfree(sb->u.adfs_sb.s_map);
 }
 
+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;
 
         if (!options)
                 return 0;
 
- for (opt = strtok(options, ","); opt != NULL; opt = strtok(NULL, ",")) {
- value = strchr(opt, '=');
- if (value)
- *value++ = '\0';
-
- if (!strcmp(opt, "uid")) { /* owner of all files */
- if (!value || !*value)
- return -EINVAL;
- sb->u.adfs_sb.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;
- sb->u.adfs_sb.s_gid = simple_strtoul(value, &value, 0);
- if (*value)
- return -EINVAL;
- } else
- if (!strcmp(opt, "ownmask")) { /* owner permission mask */
- if (!value || !*value)
- return -EINVAL;
- sb->u.adfs_sb.s_owner_mask = simple_strtoul(value, &value, 8);
- if (*value)
- return -EINVAL;
- } else
- if (!strcmp(opt, "othmask")) { /* others permission mask */
- if (!value || !*value)
- return -EINVAL;
- sb->u.adfs_sb.s_other_mask = simple_strtoul(value, &value, 8);
- if (*value)
+ for (p = strtok(options, ","); p != NULL; p = strtok(NULL, ",")) {
+ substring_t args[MAX_OPT_ARGS];
+ int token = match_token(p, tokens, args);
+
+ switch (token) {
+ case Opt_uid:
+ sb->u.adfs_sb.s_uid = match_int(args);
+ break;
+ case Opt_gid:
+ sb->u.adfs_sb.s_gid = match_int(args);
+ break;
+ case Opt_ownmask:
+ sb->u.adfs_sb.s_owner_mask = match_octal(args);
+ break;
+ case Opt_othmask:
+ sb->u.adfs_sb.s_other_mask = match_octal(args);
+ break;
+ default:
+ printk("ADFS-fs: unrecognised mount option %s\n", p);
                                 return -EINVAL;
- } else { /* eh? say again. */
- printk("ADFS-fs: unrecognised mount option %s\n", opt);
- return -EINVAL;
                 }
         }
         return 0;
diff -urN S8-pre5/fs/autofs/inode.c S8-pre5-opt/fs/autofs/inode.c
--- S8-pre5/fs/autofs/inode.c Tue Jul 3 21:09:13 2001
+++ S8-pre5-opt/fs/autofs/inode.c Tue Aug 7 11:25:29 2001
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/file.h>
 #include <linux/locks.h>
+#include <linux/parser.h>
 #include <asm/bitops.h>
 #include "autofs_i.h"
 #define __NO_VERSION__
@@ -47,9 +48,21 @@
         statfs: autofs_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];
         
         *uid = current->uid;
         *gid = current->gid;
@@ -59,53 +72,32 @@
 
         *pipefd = -1;
 
- if ( !options ) return 1;
- for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
- 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)
- return 1;
- *pgrp = simple_strtoul(value,&value,0);
- if (*value)
- return 1;
- }
- else if (!strcmp(this_char,"minproto")) {
- if (!value || !*value)
- return 1;
- *minproto = simple_strtoul(value,&value,0);
- if (*value)
- return 1;
- }
- else if (!strcmp(this_char,"maxproto")) {
- if (!value || !*value)
- return 1;
- *maxproto = simple_strtoul(value,&value,0);
- if (*value)
+ if ( !options )
+ return 1;
+ for (p = strtok(options,","); p; p = strtok(NULL,",")) {
+ int token = match_token(p, autofs_tokens, args);
+ switch (token) {
+ case Opt_fd:
+ *pipefd = match_int(&args[0]);
+ break;
+ case Opt_uid:
+ *uid = match_int(&args[0]);
+ break;
+ case Opt_gid:
+ *gid = match_int(&args[0]);
+ break;
+ case Opt_pgrp:
+ *pgrp = match_int(&args[0]);
+ break;
+ case Opt_minproto:
+ *minproto = match_int(&args[0]);
+ break;
+ case Opt_maxproto:
+ *maxproto = match_int(&args[0]);
+ break;
+ default:
                                 return 1;
                 }
- else break;
         }
         return (*pipefd < 0);
 }
diff -urN S8-pre5/fs/devpts/inode.c S8-pre5-opt/fs/devpts/inode.c
--- S8-pre5/fs/devpts/inode.c Wed Apr 18 00:35:58 2001
+++ S8-pre5-opt/fs/devpts/inode.c Tue Aug 7 11:25:29 2001
@@ -22,6 +22,7 @@
 #include <linux/slab.h>
 #include <linux/stat.h>
 #include <linux/tty.h>
+#include <linux/parser.h>
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
 
@@ -57,6 +58,15 @@
         remount_fs: devpts_remount,
 };
 
+enum {Opt_uid, Opt_gid, Opt_mode, Opt_err};
+
+static match_table_t tokens = {
+ {Opt_uid, "uid=%u"},
+ {Opt_gid, "gid=%u"},
+ {Opt_mode, "mode=%o"},
+ {Opt_err, NULL}
+};
+
 static int devpts_parse_options(char *options, struct devpts_sb_info *sbi)
 {
         int setuid = 0;
@@ -64,39 +74,28 @@
         uid_t uid = 0;
         gid_t gid = 0;
         umode_t mode = 0600;
- char *this_char, *value;
+ char *p = NULL;
 
- this_char = NULL;
         if ( options )
- this_char = strtok(options,",");
- for ( ; this_char; this_char = strtok(NULL,",")) {
- if ((value = strchr(this_char,'=')) != NULL)
- *value++ = 0;
- if (!strcmp(this_char,"uid")) {
- if (!value || !*value)
- return 1;
- uid = simple_strtoul(value,&value,0);
- if (*value)
- return 1;
- setuid = 1;
- }
- else if (!strcmp(this_char,"gid")) {
- if (!value || !*value)
- return 1;
- gid = simple_strtoul(value,&value,0);
- if (*value)
- return 1;
- setgid = 1;
- }
- else if (!strcmp(this_char,"mode")) {
- if (!value || !*value)
- return 1;
- mode = simple_strtoul(value,&value,8);
- if (*value)
+ p = strtok(options,",");
+ for ( ; p; p = strtok(NULL,",")) {
+ substring_t args[MAX_OPT_ARGS];
+ int token = match_token(p, tokens, args);
+ switch(token) {
+ case Opt_uid:
+ uid = match_int(args);
+ setuid = 1;
+ break;
+ case Opt_gid:
+ gid = match_int(args);
+ setgid = 1;
+ break;
+ case Opt_mode:
+ mode = match_octal(args);
+ break;
+ default:
                                 return 1;
                 }
- else
- return 1;
         }
         sbi->setuid = setuid;
         sbi->setgid = setgid;
diff -urN S8-pre5/fs/ext2/super.c S8-pre5-opt/fs/ext2/super.c
--- S8-pre5/fs/ext2/super.c Sun Jul 29 01:54:47 2001
+++ S8-pre5-opt/fs/ext2/super.c Tue Aug 7 11:25:29 2001
@@ -25,6 +25,7 @@
 #include <linux/init.h>
 #include <linux/locks.h>
 #include <linux/blkdev.h>
+#include <linux/parser.h>
 #include <asm/uaccess.h>
 
 
@@ -154,127 +155,102 @@
         remount_fs: ext2_remount,
 };
 
-/*
- * This function has been shamelessly adapted from the msdos fs
- */
+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_ignore, Opt_err,
+};
+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_check, "check"},
+ {Opt_nocheck, "nocheck"},
+ {Opt_nocheck, "check=none"},
+ {Opt_debug, "debug"},
+ {Opt_ignore, "grpquota"},
+ {Opt_ignore, "noquota"},
+ {Opt_ignore, "quota"},
+ {Opt_ignore, "usrquota"},
+ {Opt_err, NULL}
+};
+
 static int parse_options (char * options, unsigned long * sb_block,
                           unsigned short *resuid, unsigned short * resgid,
                           unsigned long * mount_options)
 {
- char * this_char;
- char * value;
+ char * p;
+ substring_t args[MAX_OPT_ARGS];
+ int kind = EXT2_MOUNT_ERRORS_CONT;
 
         if (!options)
                 return 1;
- for (this_char = strtok (options, ",");
- this_char != NULL;
- this_char = strtok (NULL, ",")) {
- if ((value = strchr (this_char, '=')) != NULL)
- *value++ = 0;
- if (!strcmp (this_char, "bsddf"))
- clear_opt (*mount_options, MINIX_DF);
- else if (!strcmp (this_char, "nouid32")) {
- set_opt (*mount_options, NO_UID32);
- }
- else if (!strcmp (this_char, "check")) {
- if (!value || !*value || !strcmp (value, "none"))
- clear_opt (*mount_options, CHECK);
- else
+ for (p = strtok (options, ","); p; p = strtok (NULL, ",")) {
+ int token = match_token(p, tokens, args);
+ switch (token) {
+ case Opt_bsd_df:
+ clear_opt (*mount_options, MINIX_DF);
+ break;
+ case Opt_minix_df:
+ set_opt (*mount_options, MINIX_DF);
+ break;
+ case Opt_grpid:
+ set_opt (*mount_options, GRPID);
+ break;
+ case Opt_nogrpid:
+ clear_opt (*mount_options, GRPID);
+ break;
+ case Opt_resuid:
+ *resuid = match_int(&args[0]);
+ break;
+ case Opt_resgid:
+ *resgid = match_int(&args[0]);
+ break;
+ case Opt_sb:
+ *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 (*mount_options, NO_UID32);
+ break;
+ case Opt_check:
 #ifdef CONFIG_EXT2_CHECK
                                 set_opt (*mount_options, CHECK);
 #else
                                 printk("EXT2 Check option not supported\n");
 #endif
- }
- else if (!strcmp (this_char, "debug"))
- set_opt (*mount_options, 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 (*mount_options, ERRORS_RO);
- clear_opt (*mount_options, ERRORS_PANIC);
- set_opt (*mount_options, ERRORS_CONT);
- }
- else if (!strcmp (value, "remount-ro")) {
- clear_opt (*mount_options, ERRORS_CONT);
- clear_opt (*mount_options, ERRORS_PANIC);
- set_opt (*mount_options, ERRORS_RO);
- }
- else if (!strcmp (value, "panic")) {
- clear_opt (*mount_options, ERRORS_CONT);
- clear_opt (*mount_options, ERRORS_RO);
- set_opt (*mount_options, 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 (*mount_options, GRPID);
- else if (!strcmp (this_char, "minixdf"))
- set_opt (*mount_options, MINIX_DF);
- else if (!strcmp (this_char, "nocheck"))
- clear_opt (*mount_options, CHECK);
- else if (!strcmp (this_char, "nogrpid") ||
- !strcmp (this_char, "sysvgroups"))
- clear_opt (*mount_options, GRPID);
- else if (!strcmp (this_char, "resgid")) {
- if (!value || !*value) {
- printk ("EXT2-fs: the resgid option requires "
- "an argument\n");
- return 0;
- }
- *resgid = simple_strtoul (value, &value, 0);
- if (*value) {
- printk ("EXT2-fs: Invalid resgid option: %s\n",
- value);
- return 0;
- }
- }
- else if (!strcmp (this_char, "resuid")) {
- if (!value || !*value) {
- printk ("EXT2-fs: the resuid option requires "
- "an argument");
- return 0;
- }
- *resuid = simple_strtoul (value, &value, 0);
- if (*value) {
- printk ("EXT2-fs: Invalid resuid option: %s\n",
- value);
- return 0;
- }
- }
- else if (!strcmp (this_char, "sb")) {
- if (!value || !*value) {
- printk ("EXT2-fs: the sb option requires "
- "an argument");
- return 0;
- }
- *sb_block = simple_strtoul (value, &value, 0);
- if (*value) {
- printk ("EXT2-fs: Invalid sb option: %s\n",
- value);
+ break;
+ case Opt_nocheck:
+ clear_opt (*mount_options, CHECK);
+ break;
+ case Opt_debug:
+ set_opt (*mount_options, DEBUG);
+ break;
+ case Opt_ignore:
+ break;
+ default:
                                 return 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 ("EXT2-fs: Unrecognized mount option %s\n", this_char);
- return 0;
                 }
         }
+ *mount_options |= kind;
         return 1;
 }
 
diff -urN S8-pre5/fs/fat/inode.c S8-pre5-opt/fs/fat/inode.c
--- S8-pre5/fs/fat/inode.c Tue Aug 7 05:57:47 2001
+++ S8-pre5-opt/fs/fat/inode.c Tue Aug 7 11:25:29 2001
@@ -30,6 +30,7 @@
 #include <linux/slab.h>
 #include <linux/bitops.h>
 #include <linux/smp_lock.h>
+#include <linux/parser.h>
 
 #include "msbuffer.h"
 
@@ -201,14 +202,53 @@
         }
 }
 
+enum {
+Opt_bits, Opt_blocksize, Opt_charset, Opt_check_n, Opt_check_r, Opt_check_s,
+Opt_codepage, Opt_conv_a, Opt_conv_b, Opt_conv_t, Opt_cvf_format,
+Opt_cvf_options, Opt_debug, Opt_dots, Opt_err, Opt_gid, Opt_immutable,
+Opt_nocase, Opt_nodots, Opt_quiet, Opt_showexec, Opt_uid, Opt_umask,
+};
+
+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_dots, "dots"},
+ {Opt_dots, "dotsOK=yes"},
+ {Opt_nodots, "nodots"},
+ {Opt_dots, "dotsOK=no"},
+ {Opt_uid, "uid=%d"},
+ {Opt_gid, "gid=%d"},
+ {Opt_umask, "umask=%o"},
+ {Opt_bits, "fat=%d"},
+ {Opt_codepage, "codepage=%d"},
+ {Opt_charset, "iocharset=%s"},
+ {Opt_cvf_format, "cvf_format=%20s"},
+ {Opt_cvf_options, "cvf_options=%100s"},
+ {Opt_blocksize, "blocksize=%d"},
+ {Opt_nocase, "nocase"},
+ {Opt_quiet, "quiet"},
+ {Opt_showexec, "showexec"},
+ {Opt_debug, "debug"},
+ {Opt_immutable, "sys_immutable"},
+ {Opt_err, NULL}
+};
 
 static int parse_options(char *options,int *fat, int *debug,
                          struct fat_mount_options *opts,
                          char *cvf_format, char *cvf_options)
 {
- char *this_char,*value,save,*savep;
+ substring_t args[MAX_OPT_ARGS];
         char *p;
- int ret = 1, len;
 
         opts->name_check = 'n';
         opts->conversion = 'b';
@@ -223,141 +263,89 @@
         *debug = *fat = 0;
 
         if (!options)
- goto out;
- save = 0;
- savep = NULL;
- for (this_char = strtok(options,","); this_char;
- this_char = strtok(NULL,",")) {
- if ((value = strchr(this_char,'=')) != NULL) {
- save = *value;
- savep = value;
- *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"))
+ return 1;
+
+ for (p = strtok(options,","); p; p = strtok(NULL,",")) {
+ int 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';
- else if (!strcmp(value,"normal"))
+ break;
+ case Opt_check_n:
                                 opts->name_check = 'n';
- else if (!strcmp(value,"strict"))
- opts->name_check = 's';
- else ret = 0;
- }
- else if (!strcmp(this_char,"conv") && value) {
- if (value[0] && !value[1] && strchr("bta",*value))
- opts->conversion = *value;
- else if (!strcmp(value,"binary"))
- opts->conversion = 'b';
- else if (!strcmp(value,"text"))
- opts->conversion = 't';
- else if (!strcmp(value,"auto"))
- opts->conversion = 'a';
- else ret = 0;
- }
- else if (!strcmp(this_char,"dots")) {
- opts->dotsOK = 1;
- }
- else if (!strcmp(this_char,"nocase")) {
- opts->nocase = 1;
- }
- else if (!strcmp(this_char,"nodots")) {
- opts->dotsOK = 0;
- }
- else if (!strcmp(this_char,"showexec")) {
- opts->showexec = 1;
- }
- else if (!strcmp(this_char,"dotsOK") && value) {
- if (!strcmp(value,"yes")) opts->dotsOK = 1;
- else if (!strcmp(value,"no")) opts->dotsOK = 0;
- else ret = 0;
- }
- 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_umask = 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")) {
- if (!value || !*value) ret = 0;
- else {
- *fat = simple_strtoul(value,&value,0);
- if (*value || (*fat != 12 && *fat != 16 &&
- *fat != 32))
- ret = 0;
- }
- }
- else if (!strcmp(this_char,"quiet")) {
- if (value) ret = 0;
- else opts->quiet = 1;
- }
- else if (!strcmp(this_char,"blocksize")) {
- printk("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;
- else printk ("MSDOS FS: Using codepage %d\n",
+ break;
+ case Opt_conv_b:
+ opts->name_check = 'b';
+ break;
+ case Opt_conv_t:
+ opts->name_check = 't';
+ break;
+ case Opt_conv_a:
+ opts->name_check = 'a';
+ break;
+ case Opt_dots:
+ opts->dotsOK = 1;
+ break;
+ case Opt_nodots:
+ opts->dotsOK = 0;
+ break;
+ case Opt_uid:
+ opts->fs_uid = match_int(&args[0]);
+ break;
+ case Opt_gid:
+ opts->fs_gid = match_int(&args[0]);
+ break;
+ case Opt_umask:
+ opts->fs_umask = match_octal(&args[0]);
+ break;
+ case Opt_bits:
+ *fat = match_int(&args[0]);
+ if (*fat != 12 && *fat != 16 && *fat != 32)
+ return 0;
+ break;
+ case Opt_codepage:
+ opts->codepage = match_int(&args[0]);
+ printk("MSDOS FS: Using codepage %d\n",
                                         opts->codepage);
+ break;
+ case Opt_charset:
+ opts->iocharset = match_strdup(&args[0]);
+ if (!opts->iocharset)
+ return 0;
+ printk("MSDOS FS: IO charset %s\n",
+ opts->iocharset);
+ break;
+ case Opt_cvf_format:
+ match_strcpy(cvf_format, &args[0]);
+ break;
+ case Opt_cvf_options:
+ match_strcpy(cvf_options, &args[0]);
+ break;
+ case Opt_blocksize:
+ printk("FAT: blocksize option is obsolete, "
+ "not supported now\n");
+ break;
+ case Opt_nocase:
+ opts->nocase = 1;
+ break;
+ case Opt_quiet:
+ opts->quiet = 1;
+ break;
+ case Opt_showexec:
+ opts->showexec = 1;
+ break;
+ case Opt_debug:
+ *debug = 1;
+ break;
+ case Opt_immutable:
+ opts->sys_immutable = 1;
+ break;
                 }
- else if (!strcmp(this_char,"iocharset") && value) {
- p = value;
- while (*value && *value != ',') value++;
- len = value - p;
- if (len) {
- char * buffer = kmalloc(len+1, GFP_KERNEL);
- if (buffer) {
- opts->iocharset = buffer;
- memcpy(buffer, p, len);
- buffer[len] = 0;
- printk("MSDOS FS: IO charset %s\n",
- buffer);
- } else
- ret = 0;
- }
- }
- else if (!strcmp(this_char,"cvf_format")) {
- if (!value)
- return 0;
- strncpy(cvf_format,value,20);
- }
- else if (!strcmp(this_char,"cvf_options")) {
- if (!value)
- return 0;
- strncpy(cvf_options,value,100);
- }
-
- if (this_char != options) *(this_char-1) = ',';
- if (value) *savep = save;
- if (ret == 0)
- break;
         }
-out:
- return ret;
+ return 1;
 }
 
 static void fat_read_root(struct inode *inode)
diff -urN S8-pre5/fs/isofs/inode.c S8-pre5-opt/fs/isofs/inode.c
--- S8-pre5/fs/isofs/inode.c Thu Apr 19 23:46:45 2001
+++ S8-pre5-opt/fs/isofs/inode.c Tue Aug 7 11:25:29 2001
@@ -28,6 +28,7 @@
 #include <linux/ctype.h>
 #include <linux/smp_lock.h>
 #include <linux/blkdev.h>
+#include <linux/parser.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -268,9 +269,48 @@
 }
 #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
+};
+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=a"},
+ {Opt_map_a, "map=acorn"},
+ {Opt_map_n, "map=n"},
+ {Opt_map_n, "map=normal"},
+ {Opt_map_o, "map=o"},
+ {Opt_map_o, "map=off"},
+ {Opt_session, "session=%u"},
+ {Opt_sb, "sbsector=%u"},
+ {Opt_check_r, "check=r"},
+ {Opt_check_r, "check=relaxed"},
+ {Opt_check_s, "check=s"},
+ {Opt_check_s, "check=strict"},
+ {Opt_uid, "uid=%u"},
+ {Opt_gid, "gid=%u"},
+ {Opt_mode, "mode=%u"},
+ {Opt_block, "block=%u"},
+ {Opt_ignore, "conv=b"},
+ {Opt_ignore, "conv=t"},
+ {Opt_ignore, "conv=m"},
+ {Opt_ignore, "conv=a"},
+ {Opt_ignore, "conv=binary"},
+ {Opt_ignore, "conv=text"},
+ {Opt_ignore, "conv=mtext"},
+ {Opt_ignore, "conv=auto"},
+ {Opt_err, NULL}
+};
+
 static int parse_options(char *options, struct iso9660_options * popt)
 {
- char *this_char,*value;
+ char *p;
 
         popt->map = 'n';
         popt->rock = 'y';
@@ -289,106 +329,82 @@
         popt->utf8 = 0;
         popt->session=-1;
         popt->sbsector=-1;
- if (!options) return 1;
- for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
- 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 ((value = strchr(this_char,'=')) != NULL)
- *value++ = 0;
+ if (!options)
+ return 1;
 
+ for (p = strtok(options,","); p; p = strtok(NULL,",")) {
+ substring_t args[MAX_OPT_ARGS];
+ int token = match_token(p, tokens, args);
+ unsigned n;
+
+ 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->cruft = 1;
+ break;
 #ifdef CONFIG_JOLIET
- if (!strcmp(this_char,"iocharset") && value) {
- popt->iocharset = value;
- while (*value && *value != ',')
- value++;
- if (value == popt->iocharset)
+ case Opt_iocharset:
+ popt->iocharset = match_strdup(&args[0]);
+ break;
+#endif
+ 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:
+ n = match_int(&args[0]);
+ if (n > 99)
+ return 0;
+ popt->session = n + 1;
+ break;
+ case Opt_sb:
+ n = match_int(&args[0]);
+ 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:
+ popt->uid = match_int(&args[0]);
+ break;
+ case Opt_gid:
+ popt->gid = match_int(&args[0]);
+ break;
+ case Opt_mode:
+ popt->mode = match_int(&args[0]);
+ break;
+ case Opt_block:
+ n = match_int(&args[0]);
+ if (n != 512 && n != 1024 && n != 2048)
+ return 0;
+ popt->blocksize = n;
+ break;
+ default:
                                 return 0;
- *value = 0;
- } else
-#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;
- }
- }
- else return 1;
         }
         return 1;
 }
@@ -814,6 +830,9 @@
         if (opt.check == 'r') table++;
         s->s_root->d_op = &isofs_dentry_ops[table];
 
+ if (opt.iocharset)
+ kfree(opt.iocharset);
+
         return s;
 
         /*
@@ -856,6 +875,8 @@
 out_freebh:
         brelse(bh);
 out_unlock:
+ if (opt.iocharset)
+ kfree(opt.iocharset);
         return NULL;
 }
 
diff -urN S8-pre5/include/linux/parser.h S8-pre5-opt/include/linux/parser.h
--- S8-pre5/include/linux/parser.h Wed Dec 31 19:00:00 1969
+++ S8-pre5-opt/include/linux/parser.h Tue Aug 7 11:25:29 2001
@@ -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 match_octal(substring_t *);
+int match_hex(substring_t *);
+void match_strcpy(char *, substring_t *);
+char *match_strdup(substring_t *);
diff -urN S8-pre5/lib/Makefile S8-pre5-opt/lib/Makefile
--- S8-pre5/lib/Makefile Fri Apr 27 06:30:47 2001
+++ S8-pre5-opt/lib/Makefile Tue Aug 7 11:25:29 2001
@@ -8,9 +8,9 @@
 
 L_TARGET := lib.a
 
-export-objs := cmdline.o rwsem-spinlock.o rwsem.o
+export-objs := cmdline.o rwsem-spinlock.o rwsem.o parser.o
 
-obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o
+obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o parser.o
 
 obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
 obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
diff -urN S8-pre5/lib/parser.c S8-pre5-opt/lib/parser.c
--- S8-pre5/lib/parser.c Wed Dec 31 19:00:00 1969
+++ S8-pre5-opt/lib/parser.c Tue Aug 7 11:26:50 2001
@@ -0,0 +1,131 @@
+/*
+ * lib/parser.c - simple parser for mount, etc. options.
+ */
+
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/parser.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+static int match_one(char *s, char *p, substring_t args[])
+{
+ char *meta;
+ int argc = 0;
+
+ if (!p)
+ return 1;
+
+ if (*p != *s && *p != '%')
+ return 0;
+
+ 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;
+}
+
+int match_int(substring_t *s)
+{
+ char buf[s->to - s->from + 1];
+
+ memcpy(buf, s->from, s->to - s->from);
+ buf[s->to - s->from] = '\0';
+ return simple_strtol(buf, NULL, 0);
+}
+
+int match_octal(substring_t *s)
+{
+ char buf[s->to - s->from + 1];
+
+ memcpy(buf, s->from, s->to - s->from);
+ buf[s->to - s->from] = '\0';
+ return simple_strtoul(buf, NULL, 8);
+}
+
+int match_hex(substring_t *s)
+{
+ char buf[s->to - s->from + 1];
+
+ memcpy(buf, s->from, s->to - s->from);
+ buf[s->to - s->from] = '\0';
+ return simple_strtoul(buf, NULL, 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);

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Tue Aug 07 2001 - 21:00:45 EST