Commit 5221f633 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] table-driven filesystems option parsing

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.
parent b2dd8674
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/vfs.h> #include <linux/vfs.h>
#include <linux/parser.h>
#include <asm/bitops.h> #include <asm/bitops.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -133,50 +134,56 @@ static void adfs_put_super(struct super_block *sb) ...@@ -133,50 +134,56 @@ static void adfs_put_super(struct super_block *sb)
sb->s_fs_info = NULL; 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) static int parse_options(struct super_block *sb, char *options)
{ {
char *value, *opt; char *p;
struct adfs_sb_info *asb = ADFS_SB(sb); struct adfs_sb_info *asb = ADFS_SB(sb);
int option;
if (!options) if (!options)
return 0; return 0;
while ((opt = strsep(&options, ",")) != NULL) { while ((p = strsep(&options, ",")) != NULL) {
if (!*opt) substring_t args[MAX_OPT_ARGS];
int token;
if (!*p)
continue; continue;
value = strchr(opt, '=');
if (value)
*value++ = '\0';
if (!strcmp(opt, "uid")) { /* owner of all files */ token = match_token(p, tokens, args);
if (!value || !*value) switch (token) {
return -EINVAL; case Opt_uid:
asb->s_uid = simple_strtoul(value, &value, 0); if (match_int(args, &option))
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; return -EINVAL;
} else asb->s_uid = option;
if (!strcmp(opt, "ownmask")) { /* owner permission mask */ break;
if (!value || !*value) case Opt_gid:
if (match_int(args, &option))
return -EINVAL; return -EINVAL;
asb->s_owner_mask = simple_strtoul(value, &value, 8); asb->s_gid = option;
if (*value) break;
return -EINVAL; case Opt_ownmask:
} else if (match_octal(args, &option))
if (!strcmp(opt, "othmask")) { /* others permission mask */
if (!value || !*value)
return -EINVAL; return -EINVAL;
asb->s_other_mask = simple_strtoul(value, &value, 8); asb->s_owner_mask = option;
if (*value) break;
case Opt_othmask:
if (match_octal(args, &option))
return -EINVAL; return -EINVAL;
} else { /* eh? say again. */ asb->s_other_mask = option;
printk("ADFS-fs: unrecognised mount option %s\n", opt); break;
default:
printk("ADFS-fs: unrecognised mount option \"%s\" "
"or missing value\n", p);
return -EINVAL; return -EINVAL;
} }
} }
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/vfs.h> #include <linux/vfs.h>
#include <linux/parser.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -142,12 +143,37 @@ static struct super_operations affs_sops = { ...@@ -142,12 +143,37 @@ static struct super_operations affs_sops = {
.remount_fs = affs_remount, .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 static int
parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s32 *root, 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) int *blocksize, char **prefix, char *volume, unsigned long *mount_opts)
{ {
char *this_char, *value, *optn; char *p;
int f; substring_t args[MAX_OPT_ARGS];
/* Fill in defaults */ /* Fill in defaults */
...@@ -161,109 +187,85 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s ...@@ -161,109 +187,85 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s
*mount_opts = 0; *mount_opts = 0;
if (!options) if (!options)
return 1; return 1;
while ((this_char = strsep(&options, ",")) != NULL) {
if (!*this_char) while ((p = strsep(&options, ",")) != NULL) {
int token, n, option;
if (!*p)
continue; continue;
f = 0;
if ((value = strchr(this_char,'=')) != NULL) token = match_token(p, tokens, args);
*value++ = 0; switch (token) {
if ((optn = "protect") && !strcmp(this_char, optn)) { case Opt_bs:
if (value) if (match_int(&args[0], &n))
goto out_inv_arg; return -EINVAL;
*mount_opts |= SF_IMMUTABLE; if (n != 512 && n != 1024 && n != 2048
} else if ((optn = "verbose") && !strcmp(this_char, optn)) { && n != 4096) {
if (value) printk ("AFFS: Invalid blocksize (512, 1024, 2048, 4096 allowed)\n");
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; return 0;
} }
*mount_opts |= f ? SF_SETUID : SF_SETGID; *blocksize = n;
} break;
} case Opt_mode:
} else if (!strcmp(this_char,"prefix")) { if (match_octal(&args[0], &option))
optn = "prefix"; return 1;
if (!value || !*value) *mode = option & 0777;
goto out_no_arg; *mount_opts |= SF_SETMODE;
break;
case Opt_mufs:
*mount_opts |= SF_MUFS;
break;
case Opt_prefix:
if (*prefix) { /* Free any previous prefix */ if (*prefix) { /* Free any previous prefix */
kfree(*prefix); kfree(*prefix);
*prefix = NULL; *prefix = NULL;
} }
*prefix = kmalloc(strlen(value) + 1,GFP_KERNEL); *prefix = match_strdup(&args[0]);
if (!*prefix) if (!*prefix)
return 0; return 0;
strcpy(*prefix,value);
*mount_opts |= SF_PREFIX; *mount_opts |= SF_PREFIX;
} else if (!strcmp(this_char,"volume")) { break;
optn = "volume"; case Opt_protect:
if (!value || !*value) *mount_opts |= SF_IMMUTABLE;
goto out_no_arg; break;
strlcpy(volume,value,31); case Opt_reserved:
} else if (!strcmp(this_char,"mode")) { if (match_int(&args[0], reserved))
optn = "mode"; return 1;
if (!value || !*value) break;
goto out_no_arg; case Opt_root:
*mode = simple_strtoul(value,&value,8) & 0777; if (match_int(&args[0], root))
if (*value) return 1;
return 0; break;
*mount_opts |= SF_SETMODE; case Opt_setgid:
} else if (!strcmp(this_char,"reserved")) { if (match_int(&args[0], &option))
optn = "reserved"; return 1;
if (!value || !*value) *gid = option;
goto out_no_arg; *mount_opts |= SF_SETGID;
*reserved = simple_strtoul(value,&value,0); break;
if (*value) case Opt_setuid:
return 0; if (match_int(&args[0], &option))
} else if (!strcmp(this_char,"root")) { return -EINVAL;
optn = "root"; *uid = option;
if (!value || !*value) *mount_opts |= SF_SETUID;
goto out_no_arg; break;
*root = simple_strtoul(value,&value,0); case Opt_verbose:
if (*value) *mount_opts |= SF_VERBOSE;
return 0; break;
} else if (!strcmp(this_char,"bs")) { case Opt_volume: {
optn = "bs"; char *vol = match_strdup(&args[0]);
if (!value || !*value) strlcpy(volume, vol, 32);
goto out_no_arg; kfree(vol);
*blocksize = simple_strtoul(value,&value,0); break;
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") case Opt_ignore:
|| !strcmp (this_char, "noquota")
|| !strcmp (this_char, "quota")
|| !strcmp (this_char, "usrquota"))
/* Silently ignore the quota options */ /* Silently ignore the quota options */
; break;
else { default:
printk("AFFS: Unrecognized mount option %s\n", this_char); printk("AFFS: Unrecognized mount option \"%s\" "
"or missing value\n", p);
return 0; return 0;
} }
} }
return 1; 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 /* This function definitely needs to be split up. Some fine day I'll
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/parser.h>
#include <asm/bitops.h> #include <asm/bitops.h>
#include "autofs_i.h" #include "autofs_i.h"
#include <linux/module.h> #include <linux/module.h>
...@@ -45,9 +46,23 @@ static struct super_operations autofs_sops = { ...@@ -45,9 +46,23 @@ static struct super_operations autofs_sops = {
.statfs = simple_statfs, .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) 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; *uid = current->uid;
*gid = current->gid; *gid = current->gid;
...@@ -57,55 +72,49 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, pid ...@@ -57,55 +72,49 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, pid
*pipefd = -1; *pipefd = -1;
if ( !options ) return 1; if (!options)
while ((this_char = strsep(&options,",")) != NULL) {
if (!*this_char)
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; return 1;
}
else if (!strcmp(this_char,"gid")) { while ((p = strsep(&options, ",")) != NULL) {
if (!value || !*value) int token;
return 1; if (!*p)
*gid = simple_strtoul(value,&value,0); continue;
if (*value)
token = match_token(p, autofs_tokens, args);
switch (token) {
case Opt_fd:
if (match_int(&args[0], &option))
return 1; return 1;
} *pipefd = option;
else if (!strcmp(this_char,"pgrp")) { break;
if (!value || !*value) case Opt_uid:
if (match_int(&args[0], &option))
return 1; return 1;
*pgrp = simple_strtoul(value,&value,0); *uid = option;
if (*value) break;
case Opt_gid:
if (match_int(&args[0], &option))
return 1; return 1;
} *gid = option;
else if (!strcmp(this_char,"minproto")) { break;
if (!value || !*value) case Opt_pgrp:
if (match_int(&args[0], &option))
return 1; return 1;
*minproto = simple_strtoul(value,&value,0); *pgrp = option;
if (*value) break;
case Opt_minproto:
if (match_int(&args[0], &option))
return 1; return 1;
} *minproto = option;
else if (!strcmp(this_char,"maxproto")) { break;
if (!value || !*value) case Opt_maxproto:
if (match_int(&args[0], &option))
return 1; return 1;
*maxproto = simple_strtoul(value,&value,0); *maxproto = option;
if (*value) break;
default:
return 1; return 1;
} }
else break;
} }
return (*pipefd < 0); return (*pipefd < 0);
} }
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/parser.h>
#include <asm/bitops.h> #include <asm/bitops.h>
#include "autofs_i.h" #include "autofs_i.h"
#include <linux/module.h> #include <linux/module.h>
...@@ -94,10 +95,24 @@ static struct super_operations autofs4_sops = { ...@@ -94,10 +95,24 @@ static struct super_operations autofs4_sops = {
.statfs = simple_statfs, .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, static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
pid_t *pgrp, int *minproto, int *maxproto) pid_t *pgrp, int *minproto, int *maxproto)
{ {
char *this_char, *value; char *p;
substring_t args[MAX_OPT_ARGS];
int option;
*uid = current->uid; *uid = current->uid;
*gid = current->gid; *gid = current->gid;
...@@ -108,55 +123,48 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, ...@@ -108,55 +123,48 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
*pipefd = -1; *pipefd = -1;
if ( !options ) return 1; if (!options)
while ((this_char = strsep(&options,",")) != NULL) {
if (!*this_char)
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; return 1;
}
else if (!strcmp(this_char,"gid")) { while ((p = strsep(&options, ",")) != NULL) {
if (!value || !*value) int token;
return 1; if (!*p)
*gid = simple_strtoul(value,&value,0); continue;
if (*value)
token = match_token(p, tokens, args);
switch (token) {
case Opt_fd:
if (match_int(args, pipefd))
return 1; return 1;
} break;
else if (!strcmp(this_char,"pgrp")) { case Opt_uid:
if (!value || !*value) if (match_int(args, &option))
return 1; return 1;
*pgrp = simple_strtoul(value,&value,0); *uid = option;
if (*value) break;
case Opt_gid:
if (match_int(args, &option))
return 1; return 1;
} *gid = option;
else if (!strcmp(this_char,"minproto")) { break;
if (!value || !*value) case Opt_pgrp:
if (match_int(args, &option))
return 1; return 1;
*minproto = simple_strtoul(value,&value,0); *pgrp = option;
if (*value) break;
case Opt_minproto:
if (match_int(args, &option))
return 1; return 1;
} *minproto = option;
else if (!strcmp(this_char,"maxproto")) { break;
if (!value || !*value) case Opt_maxproto:
if (match_int(args, &option))
return 1; return 1;
*maxproto = simple_strtoul(value,&value,0); *maxproto = option;
if (*value) break;
default:
return 1; return 1;
} }
else break;
} }
return (*pipefd < 0); return (*pipefd < 0);
} }
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/nls.h> #include <linux/nls.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/vfs.h> #include <linux/vfs.h>
#include <linux/parser.h>
#include "befs.h" #include "befs.h"
#include "btree.h" #include "btree.h"
...@@ -667,12 +668,27 @@ befs_nls2utf(struct super_block *sb, const char *in, ...@@ -667,12 +668,27 @@ befs_nls2utf(struct super_block *sb, const char *in,
return -EILSEQ; 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 static int
parse_options(char *options, befs_mount_options * opts) parse_options(char *options, befs_mount_options * opts)
{ {
char *this_char; char *p;
char *value; substring_t args[MAX_OPT_ARGS];
int ret = 1; int option;
/* Initialize options */ /* Initialize options */
opts->uid = 0; opts->uid = 0;
...@@ -683,64 +699,56 @@ parse_options(char *options, befs_mount_options * opts) ...@@ -683,64 +699,56 @@ parse_options(char *options, befs_mount_options * opts)
opts->debug = 0; opts->debug = 0;
if (!options) if (!options)
return ret; return 1;
while ((this_char = strsep(&options, ",")) != NULL) {
if ((value = strchr(this_char, '=')) != NULL) while ((p = strsep(&options, ",")) != NULL) {
*value++ = 0; int token;
if (!*p)
continue;
if (!strcmp(this_char, "uid")) { token = match_token(p, befs_tokens, args);
if (!value || !*value) { switch (token) {
ret = 0; case Opt_uid:
} else { if (match_int(&args[0], &option))
opts->uid = simple_strtoul(value, &value, 0); return 0;
opts->use_uid = 1; if (option < 0) {
if (*value) { printk(KERN_ERR "BeFS: Invalid uid %d, "
printk(KERN_ERR "BEFS: Invalid uid " "using default\n", option);
"option: %s\n", value); break;
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, "gid")) { opts->gid = option;
if (!value || !*value)
ret = 0;
else {
opts->gid = simple_strtoul(value, &value, 0);
opts->use_gid = 1; opts->use_gid = 1;
if (*value) { break;
printk(KERN_ERR case Opt_charset:
"BEFS: Invalid gid option: " kfree(opts->iocharset);
"%s\n", value); opts->iocharset = match_strdup(&args[0]);
ret = 0; if (!opts->iocharset) {
} printk(KERN_ERR "BeFS: allocation failure for "
} "iocharset string\n");
} else if (!strcmp(this_char, "iocharset") && value) { return 0;
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;
}
} }
} else if (!strcmp(this_char, "debug")) { break;
case Opt_debug:
opts->debug = 1; opts->debug = 1;
break;
default:
printk(KERN_ERR "BeFS: Unrecognized mount option \"%s\" "
"or missing value\n", p);
return 0;
} }
} }
return 1;
return ret;
} }
/* This function has the responsibiltiy of getting the /* This function has the responsibiltiy of getting the
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/parser.h>
#include <linux/random.h> #include <linux/random.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
...@@ -265,149 +266,157 @@ static unsigned long get_sb_block(void **data) ...@@ -265,149 +266,157 @@ static unsigned long get_sb_block(void **data)
return sb_block; return sb_block;
} }
static int want_value(char *value, char *option) enum {
{ Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
if (!value || !*value) { Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
printk(KERN_NOTICE "EXT2-fs: the %s option needs an argument\n", Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_nobh,
option); Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
return -1; Opt_ignore, Opt_err,
} };
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;
}
static int want_numeric(char *value, char *option, unsigned long *number) static match_table_t tokens = {
{ {Opt_bsd_df, "bsddf"},
if (want_value(value, option)) {Opt_minix_df, "minixdf"},
return -1; {Opt_grpid, "grpid"},
*number = simple_strtoul(value, &value, 0); {Opt_grpid, "bsdgroups"},
if (want_null_value(value, option)) {Opt_nogrpid, "nogrpid"},
return -1; {Opt_nogrpid, "sysvgroups"},
return 0; {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, static int parse_options (char * options,
struct ext2_sb_info *sbi) struct ext2_sb_info *sbi)
{ {
char * this_char; char * p;
char * value; substring_t args[MAX_OPT_ARGS];
unsigned long kind = EXT2_MOUNT_ERRORS_CONT;
int option;
if (!options) if (!options)
return 1; return 1;
while ((this_char = strsep (&options, ",")) != NULL) {
if (!*this_char) while ((p = strsep (&options, ",")) != NULL) {
int token;
if (!*p)
continue; continue;
if ((value = strchr (this_char, '=')) != NULL)
*value++ = 0; token = match_token(p, tokens, args);
#ifdef CONFIG_EXT2_FS_XATTR switch (token) {
if (!strcmp (this_char, "user_xattr")) case Opt_bsd_df:
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_EXT2_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"))
clear_opt (sbi->s_mount_opt, MINIX_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:
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); set_opt (sbi->s_mount_opt, NO_UID32);
} break;
else if (!strcmp (this_char, "check")) { case Opt_check:
if (!value || !*value || !strcmp (value, "none"))
clear_opt (sbi->s_mount_opt, CHECK);
else
#ifdef CONFIG_EXT2_CHECK #ifdef CONFIG_EXT2_CHECK
set_opt (sbi->s_mount_opt, CHECK); set_opt (sbi->s_mount_opt, CHECK);
#else #else
printk("EXT2 Check option not supported\n"); printk("EXT2 Check option not supported\n");
#endif #endif
} break;
else if (!strcmp (this_char, "debug")) case Opt_nocheck:
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); clear_opt (sbi->s_mount_opt, CHECK);
else if (!strcmp (this_char, "nogrpid") || break;
!strcmp (this_char, "sysvgroups")) case Opt_debug:
clear_opt (sbi->s_mount_opt, GRPID); set_opt (sbi->s_mount_opt, DEBUG);
else if (!strcmp (this_char, "resgid")) { break;
unsigned long v; case Opt_oldalloc:
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); set_opt (sbi->s_mount_opt, OLDALLOC);
else if (!strcmp (this_char, "orlov")) break;
case Opt_orlov:
clear_opt (sbi->s_mount_opt, OLDALLOC); clear_opt (sbi->s_mount_opt, OLDALLOC);
else if (!strcmp (this_char, "nobh")) break;
set_opt(sbi->s_mount_opt, NOBH); case Opt_nobh:
/* Silently ignore the quota options */ set_opt (sbi->s_mount_opt, NOBH);
else if (!strcmp (this_char, "grpquota") break;
|| !strcmp (this_char, "noquota") #ifdef CONFIG_EXT2_FS_XATTR
|| !strcmp (this_char, "quota") case Opt_user_xattr:
|| !strcmp (this_char, "usrquota")) set_opt (sbi->s_mount_opt, XATTR_USER);
/* Don't do anything ;-) */ ; break;
else { case Opt_nouser_xattr:
printk ("EXT2-fs: Unrecognized mount option %s\n", this_char); clear_opt (sbi->s_mount_opt, XATTR_USER);
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
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("EXT2 (no)acl options not supported\n");
break;
#endif
case Opt_ignore:
break;
default:
return 0; return 0;
} }
} }
sbi->s_mount_opt |= kind;
return 1; return 1;
} }
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/parser.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/vfs.h> #include <linux/vfs.h>
...@@ -526,36 +527,54 @@ static struct export_operations ext3_export_ops = { ...@@ -526,36 +527,54 @@ static struct export_operations ext3_export_ops = {
.get_parent = ext3_get_parent, .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) static match_table_t tokens = {
{ {Opt_bsd_df, "bsddf"},
if (!value || !*value) { {Opt_minix_df, "minixdf"},
printk(KERN_NOTICE "EXT3-fs: the %s option needs an argument\n", {Opt_grpid, "grpid"},
option); {Opt_grpid, "bsdgroups"},
return -1; {Opt_nogrpid, "nogrpid"},
} {Opt_nogrpid, "sysvgroups"},
return 0; {Opt_resgid, "resgid=%d"},
} {Opt_resuid, "resuid=%d"},
{Opt_sb, "sb=%d"},
static int want_null_value(char *value, char *option) {Opt_err_cont, "errors=continue"},
{ {Opt_err_panic, "errors=panic"},
if (*value) { {Opt_err_ro, "errors=remount-ro"},
printk(KERN_NOTICE "EXT3-fs: Invalid %s argument: %s\n", {Opt_nouid32, "nouid32"},
option, value); {Opt_nocheck, "nocheck"},
return -1; {Opt_nocheck, "check=none"},
} {Opt_check, "check"},
return 0; {Opt_debug, "debug"},
} {Opt_oldalloc, "oldalloc"},
{Opt_orlov, "orlov"},
static int want_numeric(char *value, char *option, unsigned long *number) {Opt_user_xattr, "user_xattr"},
{ {Opt_nouser_xattr, "nouser_xattr"},
if (want_value(value, option)) {Opt_acl, "acl"},
return -1; {Opt_noacl, "noacl"},
*number = simple_strtoul(value, &value, 0); {Opt_noload, "noload"},
if (want_null_value(value, option)) {Opt_commit, "commit=%u"},
return -1; {Opt_journal_update, "journal=update"},
return 0; {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) static unsigned long get_sb_block(void **data)
{ {
...@@ -577,114 +596,115 @@ static unsigned long get_sb_block(void **data) ...@@ -577,114 +596,115 @@ static unsigned long get_sb_block(void **data)
return sb_block; return sb_block;
} }
/*
* This function has been shamelessly adapted from the msdos fs
*/
static int parse_options (char * options, struct ext3_sb_info *sbi, static int parse_options (char * options, struct ext3_sb_info *sbi,
unsigned long * inum, int is_remount) unsigned long * inum, int is_remount)
{ {
char * this_char; char * p;
char * value; substring_t args[MAX_OPT_ARGS];
int data_opt = 0;
int option;
if (!options) if (!options)
return 1; return 1;
while ((this_char = strsep (&options, ",")) != NULL) {
if (!*this_char) while ((p = strsep (&options, ",")) != NULL) {
int token;
if (!*p)
continue; continue;
if ((value = strchr (this_char, '=')) != NULL)
*value++ = 0; token = match_token(p, tokens, args);
#ifdef CONFIG_EXT3_FS_XATTR switch (token) {
if (!strcmp (this_char, "user_xattr")) case Opt_bsd_df:
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"))
clear_opt (sbi->s_mount_opt, MINIX_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); set_opt (sbi->s_mount_opt, NO_UID32);
} break;
else if (!strcmp (this_char, "abort")) case Opt_check:
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
#ifdef CONFIG_EXT3_CHECK #ifdef CONFIG_EXT3_CHECK
set_opt (sbi->s_mount_opt, CHECK); set_opt (sbi->s_mount_opt, CHECK);
#else #else
printk(KERN_ERR printk(KERN_ERR
"EXT3 Check option not supported\n"); "EXT3 Check option not supported\n");
#endif #endif
} break;
else if (!strcmp (this_char, "debug")) case Opt_nocheck:
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"))
clear_opt (sbi->s_mount_opt, CHECK); clear_opt (sbi->s_mount_opt, CHECK);
else if (!strcmp (this_char, "nogrpid") || break;
!strcmp (this_char, "sysvgroups")) case Opt_debug:
clear_opt (sbi->s_mount_opt, GRPID); set_opt (sbi->s_mount_opt, DEBUG);
else if (!strcmp (this_char, "resgid")) { break;
unsigned long v; case Opt_oldalloc:
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); set_opt (sbi->s_mount_opt, OLDALLOC);
else if (!strcmp (this_char, "orlov")) break;
case Opt_orlov:
clear_opt (sbi->s_mount_opt, OLDALLOC); clear_opt (sbi->s_mount_opt, OLDALLOC);
/* Silently ignore the quota options */ break;
else if (!strcmp (this_char, "grpquota") #ifdef CONFIG_EXT3_FS_XATTR
|| !strcmp (this_char, "noquota") case Opt_user_xattr:
|| !strcmp (this_char, "quota") set_opt (sbi->s_mount_opt, XATTR_USER);
|| !strcmp (this_char, "usrquota")) break;
/* Don't do anything ;-) */ ; case Opt_nouser_xattr:
else if (!strcmp (this_char, "journal")) { 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 */ /* @@@ FIXME */
/* Eventually we will want to be able to create /* Eventually we will want to be able to create
a journal file here. For now, only allow the a journal file here. For now, only allow the
...@@ -695,36 +715,38 @@ static int parse_options (char * options, struct ext3_sb_info *sbi, ...@@ -695,36 +715,38 @@ static int parse_options (char * options, struct ext3_sb_info *sbi,
"journal on remount\n"); "journal on remount\n");
return 0; return 0;
} }
if (want_value(value, "journal"))
return 0;
if (!strcmp (value, "update"))
set_opt (sbi->s_mount_opt, UPDATE_JOURNAL); set_opt (sbi->s_mount_opt, UPDATE_JOURNAL);
else if (want_numeric(value, "journal", inum)) break;
case Opt_journal_inum:
if (is_remount) {
printk(KERN_ERR "EXT3-fs: cannot specify "
"journal on remount\n");
return 0; return 0;
} }
else if (!strcmp (this_char, "noload")) if (match_int(&args[0], &option))
return 0;
*inum = option;
break;
case Opt_noload:
set_opt (sbi->s_mount_opt, NOLOAD); set_opt (sbi->s_mount_opt, NOLOAD);
else if (!strcmp (this_char, "data")) { break;
int data_opt = 0; case Opt_commit:
if (match_int(&args[0], &option))
if (want_value(value, "data"))
return 0; return 0;
if (!strcmp (value, "journal")) sbi->s_commit_interval = HZ * option;
break;
case Opt_data_journal:
data_opt = EXT3_MOUNT_JOURNAL_DATA; data_opt = EXT3_MOUNT_JOURNAL_DATA;
else if (!strcmp (value, "ordered")) goto datacheck;
case Opt_data_ordered:
data_opt = EXT3_MOUNT_ORDERED_DATA; data_opt = EXT3_MOUNT_ORDERED_DATA;
else if (!strcmp (value, "writeback")) goto datacheck;
case Opt_data_writeback:
data_opt = EXT3_MOUNT_WRITEBACK_DATA; data_opt = EXT3_MOUNT_WRITEBACK_DATA;
else { datacheck:
printk (KERN_ERR
"EXT3-fs: Invalid data option: %s\n",
value);
return 0;
}
if (is_remount) { if (is_remount) {
if ((sbi->s_mount_opt & EXT3_MOUNT_DATA_FLAGS) != if ((sbi->s_mount_opt & EXT3_MOUNT_DATA_FLAGS)
data_opt) { != data_opt) {
printk(KERN_ERR printk(KERN_ERR
"EXT3-fs: cannot change data " "EXT3-fs: cannot change data "
"mode on remount\n"); "mode on remount\n");
...@@ -734,18 +756,20 @@ static int parse_options (char * options, struct ext3_sb_info *sbi, ...@@ -734,18 +756,20 @@ static int parse_options (char * options, struct ext3_sb_info *sbi,
sbi->s_mount_opt &= ~EXT3_MOUNT_DATA_FLAGS; sbi->s_mount_opt &= ~EXT3_MOUNT_DATA_FLAGS;
sbi->s_mount_opt |= data_opt; sbi->s_mount_opt |= data_opt;
} }
} else if (!strcmp (this_char, "commit")) { break;
unsigned long v; case Opt_abort:
if (want_numeric(value, "commit", &v)) set_opt(sbi->s_mount_opt, ABORT);
return 0; break;
sbi->s_commit_interval = (HZ * v); case Opt_ignore:
} else { break;
default:
printk (KERN_ERR printk (KERN_ERR
"EXT3-fs: Unrecognized mount option %s\n", "EXT3-fs: Unrecognized mount option \"%s\" "
this_char); "or missing value\n", p);
return 0; return 0;
} }
} }
return 1; return 1;
} }
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/vfs.h> #include <linux/vfs.h>
#include <linux/parser.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
/* /*
...@@ -183,20 +184,6 @@ void fat_put_super(struct super_block *sb) ...@@ -183,20 +184,6 @@ void fat_put_super(struct super_block *sb)
kfree(sbi); 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) static int fat_show_options(struct seq_file *m, struct vfsmount *mnt)
{ {
struct msdos_sb_info *sbi = MSDOS_SB(mnt->mnt_sb); 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) ...@@ -259,11 +246,95 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt)
return 0; 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, static int parse_options(char *options, int is_vfat, int *debug,
struct fat_mount_options *opts) struct fat_mount_options *opts)
{ {
char *this_char, *value, *p; char *p;
int ret = 1, val, len; substring_t args[MAX_OPT_ARGS];
int option;
opts->isvfat = is_vfat; opts->isvfat = is_vfat;
...@@ -284,183 +355,198 @@ static int parse_options(char *options, int is_vfat, int *debug, ...@@ -284,183 +355,198 @@ static int parse_options(char *options, int is_vfat, int *debug,
*debug = 0; *debug = 0;
if (!options) if (!options)
goto out; return 1;
while ((this_char = strsep(&options,",")) != NULL) {
if (!*this_char) while ((p = strsep(&options, ",")) != NULL) {
int token;
if (!*p)
continue; continue;
if ((value = strchr(this_char,'=')) != NULL)
*value++ = 0;
if (!strcmp(this_char,"check") && value) { token = match_token(p, FAT_tokens, args);
if (value[0] && !value[1] && strchr("rns",*value)) switch (token) {
opts->name_check = *value; case Opt_check_s:
else if (!strcmp(value,"relaxed")) opts->name_check = 's';
break;
case Opt_check_r:
opts->name_check = 'r'; opts->name_check = 'r';
else if (!strcmp(value,"normal")) break;
case Opt_check_n:
opts->name_check = 'n'; opts->name_check = 'n';
else if (!strcmp(value,"strict")) break;
opts->name_check = 's'; case Opt_dots: /* msdos specific */
else ret = 0; if (!is_vfat)
} opts->dotsOK = 1;
else if (!strcmp(this_char,"conv") && value) { break;
printk(KERN_INFO "FAT: conv option is obsolete, " case Opt_nodots: /* msdos specific */
"not supported now\n"); if (!is_vfat)
} opts->dotsOK = 0;
else if (!strcmp(this_char,"nocase")) { break;
case Opt_nocase:
if (!is_vfat) if (!is_vfat)
opts->nocase = 1; opts->nocase = 1;
else { else {
/* for backward compatible */ /* for backward compatibility */
opts->shortname = VFAT_SFN_DISPLAY_WIN95 opts->shortname = VFAT_SFN_DISPLAY_WIN95
| VFAT_SFN_CREATE_WIN95; | VFAT_SFN_CREATE_WIN95;
} }
} break;
else if (!strcmp(this_char,"showexec")) { case Opt_quiet:
opts->quiet = 1;
break;
case Opt_showexec:
opts->showexec = 1; opts->showexec = 1;
} break;
else if (!strcmp(this_char,"uid")) { case Opt_debug:
if (!value || !*value) ret = 0; *debug = 1;
else { break;
opts->fs_uid = simple_strtoul(value,&value,0); case Opt_immutable:
if (*value) ret = 0; opts->sys_immutable = 1;
} break;
} case Opt_uid:
else if (!strcmp(this_char,"gid")) { if (match_int(&args[0], &option))
if (!value || !*value) ret= 0; return 0;
else { opts->fs_uid = option;
opts->fs_gid = simple_strtoul(value,&value,0); break;
if (*value) ret = 0; case Opt_gid:
} if (match_int(&args[0], &option))
} return 0;
else if (!strcmp(this_char,"umask")) { opts->fs_gid = option;
if (!value || !*value) ret = 0; break;
else { case Opt_umask:
opts->fs_fmask = opts->fs_dmask = if (match_octal(&args[0], &option))
simple_strtoul(value,&value,8); return 0;
if (*value) ret = 0; opts->fs_fmask = opts->fs_dmask = option;
} break;
} case Opt_dmask:
else if (!strcmp(this_char,"fmask")) { if (match_octal(&args[0], &option))
if (!value || !*value) ret = 0; return 0;
else { opts->fs_dmask = option;
opts->fs_fmask = simple_strtoul(value,&value,8); break;
if (*value) ret = 0; case Opt_fmask:
} if (match_octal(&args[0], &option))
} return 0;
else if (!strcmp(this_char,"dmask")) { opts->fs_fmask = option;
if (!value || !*value) ret = 0; break;
else { case Opt_codepage:
opts->fs_dmask = simple_strtoul(value,&value,8); if (match_int(&args[0], &option))
if (*value) ret = 0; return 0;
} opts->codepage = option;
} printk("MSDOS FS: Using codepage %d\n",
else if (!strcmp(this_char,"debug")) { opts->codepage);
if (value) ret = 0; break;
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;
}
/* vfat specific */ /* vfat specific */
else if (is_vfat && !strcmp(this_char,"iocharset") && value) { case Opt_charset:
p = value; if (is_vfat) {
while (*value && *value != ',')
value++;
len = value - p;
if (len) {
char *buffer;
if (opts->iocharset != NULL) {
kfree(opts->iocharset); kfree(opts->iocharset);
opts->iocharset = NULL; opts->iocharset = match_strdup(&args[0]);
} if (!opts->iocharset)
buffer = kmalloc(len + 1, GFP_KERNEL); return 0;
if (buffer != NULL) { printk("MSDOS FS: IO charset %s\n",
opts->iocharset = buffer; opts->iocharset);
memcpy(buffer, p, len);
buffer[len] = 0;
} else
ret = 0;
}
}
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")) { break;
if (!strcmp(value, "lower")) case Opt_shortname_lower:
if (is_vfat) {
opts->shortname = VFAT_SFN_DISPLAY_LOWER opts->shortname = VFAT_SFN_DISPLAY_LOWER
| VFAT_SFN_CREATE_WIN95; | VFAT_SFN_CREATE_WIN95;
else if (!strcmp(value, "win95")) }
break;
case Opt_shortname_win95:
if (is_vfat) {
opts->shortname = VFAT_SFN_DISPLAY_WIN95 opts->shortname = VFAT_SFN_DISPLAY_WIN95
| VFAT_SFN_CREATE_WIN95; | VFAT_SFN_CREATE_WIN95;
else if (!strcmp(value, "winnt")) }
break;
case Opt_shortname_winnt:
if (is_vfat) {
opts->shortname = VFAT_SFN_DISPLAY_WINNT opts->shortname = VFAT_SFN_DISPLAY_WINNT
| VFAT_SFN_CREATE_WINNT; | VFAT_SFN_CREATE_WINNT;
else if (!strcmp(value, "mixed")) }
break;
case Opt_shortname_mixed:
if (is_vfat) {
opts->shortname = VFAT_SFN_DISPLAY_WINNT opts->shortname = VFAT_SFN_DISPLAY_WINNT
| VFAT_SFN_CREATE_WIN95; | 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; break;
/* unknown option */
default:
printk(KERN_ERR "FAT: Unrecognized mount option \"%s\" "
"or missing value\n", p);
return 0;
} }
out: }
if (opts->unicode_xlate) if (opts->unicode_xlate)
opts->utf8 = 0; opts->utf8 = 0;
return ret; return 1;
} }
static int fat_calc_dir_size(struct inode *inode) static int fat_calc_dir_size(struct inode *inode)
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/parser.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/vfs.h> #include <linux/vfs.h>
...@@ -211,6 +212,60 @@ static int hfs_statfs(struct super_block *sb, struct kstatfs *buf) ...@@ -211,6 +212,60 @@ static int hfs_statfs(struct super_block *sb, struct kstatfs *buf)
return 0; 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() * parse_options()
* *
...@@ -219,8 +274,10 @@ static int hfs_statfs(struct super_block *sb, struct kstatfs *buf) ...@@ -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) static int parse_options(char *options, struct hfs_sb_info *hsb, int *part)
{ {
char *this_char, *value; char *p;
char names, fork; char names, fork;
substring_t args[MAX_OPT_ARGS];
int option;
/* initialize the sb with defaults */ /* initialize the sb with defaults */
memset(hsb, 0, sizeof(*hsb)); memset(hsb, 0, sizeof(*hsb));
...@@ -243,117 +300,109 @@ static int parse_options(char *options, struct hfs_sb_info *hsb, int *part) ...@@ -243,117 +300,109 @@ static int parse_options(char *options, struct hfs_sb_info *hsb, int *part)
if (!options) { if (!options) {
goto done; goto done;
} }
while ((this_char = strsep(&options,",")) != NULL) { while ((p = strsep(&options,",")) != NULL) {
if (!*this_char) int token;
if (!*p)
continue; continue;
if ((value = strchr(this_char,'=')) != NULL) {
*value++ = 0; token = match_token(p, tokens, args);
} switch (token) {
/* Numeric-valued options */ /* Numeric-valued options */
if (!strcmp(this_char, "version")) { case Opt_version:
if (!value || !*value) { if (match_int(&args[0], &option))
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; return 0;
} hsb->s_version = option;
} else if (!strcmp(this_char,"umask")) { break;
if (!value || !*value) { case Opt_uid:
if (match_int(&args[0], &option))
return 0; return 0;
} hsb->s_uid = option;
hsb->s_umask = simple_strtoul(value,&value,8); break;
if (*value) { case Opt_gid:
if (match_int(&args[0], &option))
return 0; return 0;
} hsb->s_gid = option;
} else if (!strcmp(this_char,"part")) { break;
if (!value || !*value) { case Opt_umask:
if (match_octal(&args[0], &option))
return 0; return 0;
} hsb->s_umask = option;
*part = simple_strtoul(value,&value,0); break;
if (*value) { case Opt_part:
if (match_int(&args[0], &option))
return 0; return 0;
} *part = option;
break;
/* String-valued options */ /* String-valued options */
} else if (!strcmp(this_char,"type") && value) { case Opt_type:
if (strlen(value) != 4) { if (strlen(args[0].from) != 4) {
return 0; return 0;
} }
hsb->s_type = hfs_get_nl(value); hsb->s_type = hfs_get_nl(args[0].from);
} else if (!strcmp(this_char,"creator") && value) { break;
if (strlen(value) != 4) { case Opt_creator:
if (strlen(args[0].from) != 4) {
return 0; return 0;
} }
hsb->s_creator = hfs_get_nl(value); hsb->s_creator = hfs_get_nl(args[0].from);
break;
/* Boolean-valued options */ /* Boolean-valued options */
} else if (!strcmp(this_char,"quiet")) { case Opt_quiet:
if (value) {
return 0;
}
hsb->s_quiet = 1; hsb->s_quiet = 1;
} else if (!strcmp(this_char,"afpd")) { break;
if (value) { case Opt_afpd:
return 0;
}
hsb->s_afpd = 1; hsb->s_afpd = 1;
break;
/* Multiple choice options */ /* Multiple choice options */
} else if (!strcmp(this_char,"names") && value) { case Opt_names_netatalk:
if ((*value && !value[1] && strchr("ntal78c",*value)) || names = 'n';
!strcmp(value,"netatalk") || break;
!strcmp(value,"trivial") || case Opt_names_trivial:
!strcmp(value,"alpha") || names = 't';
!strcmp(value,"latin") || break;
!strcmp(value,"7bit") || case Opt_names_alpha:
!strcmp(value,"8bit") || names = 'a';
!strcmp(value,"cap")) { break;
names = *value; case Opt_names_latin:
} else { names = 'l';
return 0; break;
} case Opt_names_7bit:
} else if (!strcmp(this_char,"fork") && value) { names = '7';
if ((*value && !value[1] && strchr("nsdc",*value)) || break;
!strcmp(value,"netatalk") || case Opt_names_8bit:
!strcmp(value,"single") || names = '8';
!strcmp(value,"double") || break;
!strcmp(value,"cap")) { case Opt_names_cap:
fork = *value; names = 'c';
} else { break;
return 0; case Opt_fork_netatalk:
} fork = 'n';
} else if (!strcmp(this_char,"case") && value) { break;
if ((*value && !value[1] && strchr("la",*value)) || case Opt_fork_single:
!strcmp(value,"lower") || fork = 's';
!strcmp(value,"asis")) { break;
hsb->s_lowercase = (*value == 'l'); case Opt_fork_double:
} else { fork = 'd';
return 0; break;
} case Opt_fork_cap:
} else if (!strcmp(this_char,"conv") && value) { fork = 'c';
if ((*value && !value[1] && strchr("bta",*value)) || break;
!strcmp(value,"binary") || case Opt_case_lower:
!strcmp(value,"text") || hsb->s_lowercase = 1;
!strcmp(value,"auto")) { break;
hsb->s_conv = *value; case Opt_case_asis:
} else { hsb->s_lowercase = 0;
return 0; break;
} case Opt_conv_binary:
} else { 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; return 0;
} }
} }
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/string.h> #include <linux/string.h>
#include "hpfs_fn.h" #include "hpfs_fn.h"
#include <linux/module.h> #include <linux/module.h>
#include <linux/parser.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/vfs.h> #include <linux/vfs.h>
...@@ -219,15 +220,52 @@ static struct super_operations hpfs_sops = ...@@ -219,15 +220,52 @@ static struct super_operations hpfs_sops =
/* /*
* A tiny parser for option strings, stolen from dosfs. * A tiny parser for option strings, stolen from dosfs.
*
* Stolen again from read-only hpfs. * 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 parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask,
int *lowercase, int *conv, int *eas, int *chk, int *errs, int *lowercase, int *conv, int *eas, int *chk, int *errs,
int *chkdsk, int *timeshift) int *chkdsk, int *timeshift)
{ {
char *p, *rhs; char *p;
int option;
if (!opts) if (!opts)
return 1; return 1;
...@@ -235,115 +273,98 @@ int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask, ...@@ -235,115 +273,98 @@ int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask,
/*printk("Parsing opts: '%s'\n",opts);*/ /*printk("Parsing opts: '%s'\n",opts);*/
while ((p = strsep(&opts, ",")) != NULL) { while ((p = strsep(&opts, ",")) != NULL) {
substring_t args[MAX_OPT_ARGS];
int token;
if (!*p) if (!*p)
continue; continue;
if ((rhs = strchr(p, '=')) != 0)
*rhs++ = '\0'; token = match_token(p, tokens, args);
if (!strcmp(p, "help")) return 2; switch (token) {
if (!strcmp(p, "uid")) { case Opt_help:
if (!rhs || !*rhs) return 2;
return 0; case Opt_uid:
*uid = simple_strtoul(rhs, &rhs, 0); if (match_int(args, &option))
if (*rhs)
return 0;
}
else if (!strcmp(p, "gid")) {
if (!rhs || !*rhs)
return 0;
*gid = simple_strtoul(rhs, &rhs, 0);
if (*rhs)
return 0;
}
else if (!strcmp(p, "umask")) {
if (!rhs || !*rhs)
return 0;
*umask = simple_strtoul(rhs, &rhs, 8);
if (*rhs)
return 0;
}
else if (!strcmp(p, "timeshift")) {
int m = 1;
if (!rhs || !*rhs)
return 0; return 0;
if (*rhs == '-') m = -1; *uid = option;
if (*rhs == '+' || *rhs == '-') rhs++; break;
*timeshift = simple_strtoul(rhs, &rhs, 0) * m; case Opt_gid:
if (*rhs) if (match_int(args, &option))
return 0; return 0;
} *gid = option;
else if (!strcmp(p, "case")) { break;
if (!rhs || !*rhs) case Opt_umask:
if (match_octal(args, &option))
return 0; return 0;
if (!strcmp(rhs, "lower")) *umask = option;
break;
case Opt_case_lower:
*lowercase = 1; *lowercase = 1;
else if (!strcmp(rhs, "asis")) break;
case Opt_case_asis:
*lowercase = 0; *lowercase = 0;
else break;
return 0; case Opt_conv_binary:
}
else if (!strcmp(p, "conv")) {
if (!rhs || !*rhs)
return 0;
if (!strcmp(rhs, "binary"))
*conv = CONV_BINARY; *conv = CONV_BINARY;
else if (!strcmp(rhs, "text")) break;
case Opt_conv_text:
*conv = CONV_TEXT; *conv = CONV_TEXT;
else if (!strcmp(rhs, "auto")) break;
case Opt_conv_auto:
*conv = CONV_AUTO; *conv = CONV_AUTO;
else break;
return 0; case Opt_check_none:
}
else if (!strcmp(p, "check")) {
if (!rhs || !*rhs)
return 0;
if (!strcmp(rhs, "none"))
*chk = 0; *chk = 0;
else if (!strcmp(rhs, "normal")) break;
case Opt_check_normal:
*chk = 1; *chk = 1;
else if (!strcmp(rhs, "strict")) break;
case Opt_check_strict:
*chk = 2; *chk = 2;
else break;
return 0; case Opt_err_cont:
}
else if (!strcmp(p, "errors")) {
if (!rhs || !*rhs)
return 0;
if (!strcmp(rhs, "continue"))
*errs = 0; *errs = 0;
else if (!strcmp(rhs, "remount-ro")) break;
case Opt_err_ro:
*errs = 1; *errs = 1;
else if (!strcmp(rhs, "panic")) break;
case Opt_err_panic:
*errs = 2; *errs = 2;
else break;
return 0; case Opt_eas_no:
}
else if (!strcmp(p, "eas")) {
if (!rhs || !*rhs)
return 0;
if (!strcmp(rhs, "no"))
*eas = 0; *eas = 0;
else if (!strcmp(rhs, "ro")) break;
case Opt_eas_ro:
*eas = 1; *eas = 1;
else if (!strcmp(rhs, "rw")) break;
case Opt_eas_rw:
*eas = 2; *eas = 2;
else break;
return 0; case Opt_chkdsk_no:
}
else if (!strcmp(p, "chkdsk")) {
if (!rhs || !*rhs)
return 0;
if (!strcmp(rhs, "no"))
*chkdsk = 0; *chkdsk = 0;
else if (!strcmp(rhs, "errors")) break;
case Opt_chkdsk_errors:
*chkdsk = 1; *chkdsk = 1;
else if (!strcmp(rhs, "always")) break;
case Opt_chkdsk_always:
*chkdsk = 2; *chkdsk = 2;
else break;
case Opt_timeshift:
{
int m = 1;
char *rhs = args[0].from;
if (!rhs || !*rhs)
return 0; return 0;
if (*rhs == '-') m = -1;
if (*rhs == '+' || *rhs == '-') rhs++;
*timeshift = simple_strtoul(rhs, &rhs, 0) * m;
if (*rhs)
return 0;
break;
} }
else default:
return 0; return 0;
} }
}
return 1; return 1;
} }
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/vfs.h> #include <linux/vfs.h>
#include <linux/parser.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -328,9 +329,52 @@ isofs_dentry_cmpi_ms(struct dentry *dentry,struct qstr *a,struct qstr *b) ...@@ -328,9 +329,52 @@ isofs_dentry_cmpi_ms(struct dentry *dentry,struct qstr *a,struct qstr *b)
} }
#endif #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) static int parse_options(char *options, struct iso9660_options * popt)
{ {
char *this_char,*value; char *p;
int option;
popt->map = 'n'; popt->map = 'n';
popt->rock = 'y'; popt->rock = 'y';
...@@ -350,113 +394,102 @@ static int parse_options(char *options, struct iso9660_options * popt) ...@@ -350,113 +394,102 @@ static int parse_options(char *options, struct iso9660_options * popt)
popt->utf8 = 0; popt->utf8 = 0;
popt->session=-1; popt->session=-1;
popt->sbsector=-1; popt->sbsector=-1;
if (!options) return 1; if (!options)
while ((this_char = strsep(&options,",")) != NULL) { return 1;
if (!*this_char)
while ((p = strsep(&options, ",")) != NULL) {
int token;
substring_t args[MAX_OPT_ARGS];
unsigned n;
if (!*p)
continue; continue;
if (strncmp(this_char,"norock",6) == 0) {
token = match_token(p, tokens, args);
switch (token) {
case Opt_norock:
popt->rock = 'n'; popt->rock = 'n';
continue; break;
} case Opt_nojoliet:
if (strncmp(this_char,"nojoliet",8) == 0) {
popt->joliet = 'n'; popt->joliet = 'n';
continue; break;
} case Opt_unhide:
if (strncmp(this_char,"unhide",6) == 0) {
popt->unhide = 'y'; popt->unhide = 'y';
continue; break;
} case Opt_cruft:
if (strncmp(this_char,"cruft",5) == 0) {
popt->cruft = 'y'; popt->cruft = 'y';
continue; break;
} case Opt_utf8:
if (strncmp(this_char,"utf8",4) == 0) {
popt->utf8 = 1; popt->utf8 = 1;
continue; break;
}
if (strncmp(this_char,"nocompress",10) == 0) {
popt->nocompress = 1;
continue;
}
if ((value = strchr(this_char,'=')) != NULL)
*value++ = 0;
#ifdef CONFIG_JOLIET #ifdef CONFIG_JOLIET
if (!strcmp(this_char,"iocharset") && value) { case Opt_iocharset:
popt->iocharset = value; popt->iocharset = match_strdup(&args[0]);
while (*value && *value != ',') break;
value++;
if (value == popt->iocharset)
return 0;
*value = 0;
} else
#endif #endif
if (!strcmp(this_char,"map") && value) { case Opt_map_a:
if (value[0] && !value[1] && strchr("ano",*value)) popt->map = 'a';
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; break;
case 'u': case Opt_map_o:
popt->uid = ivalue; popt->map = 'o';
break; break;
case 'g': case Opt_map_n:
popt->gid = ivalue; popt->map = 'n';
break; break;
case 'm': case Opt_session:
popt->mode = ivalue; if (match_int(&args[0], &option))
return 0;
n = option;
if (n > 99)
return 0;
popt->session = n + 1;
break; 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; return 1;
} }
...@@ -842,6 +875,9 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) ...@@ -842,6 +875,9 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
if (opt.check == 'r') table++; if (opt.check == 'r') table++;
s->s_root->d_op = &isofs_dentry_ops[table]; s->s_root->d_op = &isofs_dentry_ops[table];
if (opt.iocharset)
kfree(opt.iocharset);
return 0; return 0;
/* /*
...@@ -879,6 +915,8 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) ...@@ -879,6 +915,8 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
out_freebh: out_freebh:
brelse(bh); brelse(bh);
out_freesbi: out_freesbi:
if (opt.iocharset)
kfree(opt.iocharset);
kfree(sbi); kfree(sbi);
s->s_fs_info = NULL; s->s_fs_info = NULL;
return -EINVAL; return -EINVAL;
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/config.h> #include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/parser.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/vfs.h> #include <linux/vfs.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -164,59 +165,82 @@ static void jfs_put_super(struct super_block *sb) ...@@ -164,59 +165,82 @@ static void jfs_put_super(struct super_block *sb)
kfree(sbi); 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, static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,
int *flag) int *flag)
{ {
void *nls_map = NULL; void *nls_map = NULL;
char *this_char; char *p;
char *value;
struct jfs_sb_info *sbi = JFS_SBI(sb); struct jfs_sb_info *sbi = JFS_SBI(sb);
*newLVSize = 0; *newLVSize = 0;
if (!options) if (!options)
return 1; 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; continue;
if ((value = strchr(this_char, '=')) != NULL)
*value++ = 0; token = match_token(p, tokens, args);
if (!strcmp(this_char, "integrity")) { switch (token) {
case Opt_integrity:
*flag &= ~JFS_NOINTEGRITY; *flag &= ~JFS_NOINTEGRITY;
} else if (!strcmp(this_char, "nointegrity")) { break;
case Opt_nointegrity:
*flag |= JFS_NOINTEGRITY; *flag |= JFS_NOINTEGRITY;
} else if (!strcmp(this_char, "iocharset")) { break;
if (!value || !*value) case Opt_ignore:
goto needs_arg; /* Silently ignore the quota options */
/* Don't do anything ;-) */
break;
case Opt_iocharset:
if (nls_map) /* specified iocharset twice! */ if (nls_map) /* specified iocharset twice! */
unload_nls(nls_map); unload_nls(nls_map);
nls_map = load_nls(value); nls_map = load_nls(args[0].from);
if (!nls_map) { if (!nls_map) {
printk(KERN_ERR "JFS: charset not found\n"); printk(KERN_ERR "JFS: charset not found\n");
goto cleanup; goto cleanup;
} }
} else if (!strcmp(this_char, "resize")) { break;
if (!value || !*value) { case Opt_resize:
{
char *resize = args[0].from;
if (!resize || !*resize) {
*newLVSize = sb->s_bdev->bd_inode->i_size >> *newLVSize = sb->s_bdev->bd_inode->i_size >>
sb->s_blocksize_bits; sb->s_blocksize_bits;
if (*newLVSize == 0) if (*newLVSize == 0)
printk(KERN_ERR printk(KERN_ERR
"JFS: Cannot determine volume size\n"); "JFS: Cannot determine volume size\n");
} else } else
*newLVSize = simple_strtoull(value, &value, 0); *newLVSize = simple_strtoull(resize, &resize, 0);
break;
/* Silently ignore the quota options */ }
} else if (!strcmp(this_char, "grpquota") default:
|| !strcmp(this_char, "noquota") printk("jfs: Unrecognized mount option \"%s\" "
|| !strcmp(this_char, "quota") " or missing value\n", p);
|| !strcmp(this_char, "usrquota"))
/* Don't do anything ;-) */ ;
else {
printk("jfs: Unrecognized mount option %s\n",
this_char);
goto cleanup; goto cleanup;
} }
} }
if (nls_map) { if (nls_map) {
/* Discard old (if remount) */ /* Discard old (if remount) */
if (sbi->nls_tab) if (sbi->nls_tab)
...@@ -224,8 +248,7 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, ...@@ -224,8 +248,7 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,
sbi->nls_tab = nls_map; sbi->nls_tab = nls_map;
} }
return 1; return 1;
needs_arg:
printk(KERN_ERR "JFS: %s needs an argument\n", this_char);
cleanup: cleanup:
if (nls_map) if (nls_map)
unload_nls(nls_map); unload_nls(nls_map);
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/limits.h> #include <linux/limits.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/parser.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -135,34 +136,47 @@ static struct super_operations proc_sops = { ...@@ -135,34 +136,47 @@ static struct super_operations proc_sops = {
.statfs = simple_statfs, .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) static int parse_options(char *options,uid_t *uid,gid_t *gid)
{ {
char *this_char,*value; char *p;
int option;
*uid = current->uid; *uid = current->uid;
*gid = current->gid; *gid = current->gid;
if (!options) if (!options)
return 1; 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; continue;
if ((value = strchr(this_char,'=')) != NULL)
*value++ = 0; token = match_token(p, tokens, args);
if (!strcmp(this_char,"uid")) { switch (token) {
if (!value || !*value) case Opt_uid:
return 0; if (match_int(args, &option))
*uid = simple_strtoul(value,&value,0);
if (*value)
return 0; return 0;
} *uid = option;
else if (!strcmp(this_char,"gid")) { break;
if (!value || !*value) case Opt_gid:
if (match_int(args, &option))
return 0; return 0;
*gid = simple_strtoul(value,&value,0); *gid = option;
if (*value) break;
default:
return 0; return 0;
} }
else return 1;
} }
return 1; return 1;
} }
......
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/parser.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/cdrom.h> #include <linux/cdrom.h>
#include <linux/nls.h> #include <linux/nls.h>
...@@ -259,18 +260,53 @@ module_exit(exit_udf_fs) ...@@ -259,18 +260,53 @@ module_exit(exit_udf_fs)
* uopts Pointer to mount options variable. * uopts Pointer to mount options variable.
* *
* POST-CONDITIONS * POST-CONDITIONS
* <return> 0 Mount options parsed okay. * <return> 1 Mount options parsed okay.
* <return> -1 Error parsing mount options. * <return> 0 Error parsing mount options.
* *
* HISTORY * HISTORY
* July 1, 1997 - Andrew E. Mileski * July 1, 1997 - Andrew E. Mileski
* Written, tested, and released. * 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 static int
udf_parse_options(char *options, struct udf_options *uopt) udf_parse_options(char *options, struct udf_options *uopt)
{ {
char *opt, *val; char *p;
int option;
uopt->novrs = 0; uopt->novrs = 0;
uopt->blocksize = 2048; uopt->blocksize = 2048;
...@@ -286,71 +322,106 @@ udf_parse_options(char *options, struct udf_options *uopt) ...@@ -286,71 +322,106 @@ udf_parse_options(char *options, struct udf_options *uopt)
if (!options) if (!options)
return 1; return 1;
while ((opt = strsep(&options, ",")) != NULL) while ((p = strsep(&options, ",")) != NULL) {
{ substring_t args[MAX_OPT_ARGS];
if (!*opt) int token;
if (!*p)
continue; continue;
/* Make "opt=val" into two strings */
val = strchr(opt, '='); token = match_token(p, tokens, args);
if (val) switch (token) {
*(val++) = 0; case Opt_novrs:
if (!strcmp(opt, "novrs") && !val)
uopt->novrs = 1; uopt->novrs = 1;
else if (!strcmp(opt, "bs") && val) break;
uopt->blocksize = simple_strtoul(val, NULL, 0); case Opt_bs:
else if (!strcmp(opt, "unhide") && !val) if (match_int(&args[0], &option))
return 0;
uopt->blocksize = option;
break;
case Opt_unhide:
uopt->flags |= (1 << UDF_FLAG_UNHIDE); uopt->flags |= (1 << UDF_FLAG_UNHIDE);
else if (!strcmp(opt, "undelete") && !val) break;
case Opt_undelete:
uopt->flags |= (1 << UDF_FLAG_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); 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); 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); 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); uopt->flags &= ~(1 << UDF_FLAG_USE_SHORT_AD);
else if (!strcmp(opt, "gid") && val) break;
uopt->gid = simple_strtoul(val, NULL, 0); case Opt_gid:
else if (!strcmp(opt, "umask") && val) if (match_int(args, &option))
uopt->umask = simple_strtoul(val, NULL, 0); return 0;
else if (!strcmp(opt, "nostrict") && !val) 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); uopt->flags &= ~(1 << UDF_FLAG_STRICT);
else if (!strcmp(opt, "uid") && val) break;
uopt->uid = simple_strtoul(val, NULL, 0); case Opt_session:
else if (!strcmp(opt, "session") && val) if (match_int(args, &option))
uopt->session = simple_strtoul(val, NULL, 0); return 0;
else if (!strcmp(opt, "lastblock") && val) uopt->session = option;
uopt->lastblock = simple_strtoul(val, NULL, 0); break;
else if (!strcmp(opt, "anchor") && val) case Opt_lastblock:
uopt->anchor = simple_strtoul(val, NULL, 0); if (match_int(args, &option))
else if (!strcmp(opt, "volume") && val) return 0;
uopt->volume = simple_strtoul(val, NULL, 0); uopt->lastblock = option;
else if (!strcmp(opt, "partition") && val) break;
uopt->partition = simple_strtoul(val, NULL, 0); case Opt_anchor:
else if (!strcmp(opt, "fileset") && val) if (match_int(args, &option))
uopt->fileset = simple_strtoul(val, NULL, 0); return 0;
else if (!strcmp(opt, "rootdir") && val) uopt->anchor = option;
uopt->rootdir = simple_strtoul(val, NULL, 0); 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 #ifdef CONFIG_NLS
else if (!strcmp(opt, "iocharset") && val) case Opt_iocharset:
{ uopt->nls_map = load_nls(args[0].from);
uopt->nls_map = load_nls(val);
uopt->flags |= (1 << UDF_FLAG_NLS_MAP); uopt->flags |= (1 << UDF_FLAG_NLS_MAP);
} break;
#endif #endif
else if (!strcmp(opt, "utf8") && !val) default:
uopt->flags |= (1 << UDF_FLAG_UTF8); printk(KERN_ERR "udf: bad mount option \"%s\" "
else if (val) "or missing value\n",
{ p);
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);
return 0; return 0;
} }
} }
......
...@@ -79,6 +79,7 @@ ...@@ -79,6 +79,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/parser.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/vfs.h> #include <linux/vfs.h>
...@@ -250,64 +251,99 @@ void ufs_warning (struct super_block * sb, const char * function, ...@@ -250,64 +251,99 @@ void ufs_warning (struct super_block * sb, const char * function,
sb->s_id, function, error_buf); 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) static int ufs_parse_options (char * options, unsigned * mount_options)
{ {
char * this_char; char * p;
char * value;
UFSD(("ENTER\n")) UFSD(("ENTER\n"))
if (!options) if (!options)
return 1; return 1;
while ((this_char = strsep (&options, ",")) != NULL) { while ((p = strsep(&options, ",")) != NULL) {
if (!*this_char) substring_t args[MAX_OPT_ARGS];
int token;
if (!*p)
continue; continue;
if ((value = strchr (this_char, '=')) != NULL)
*value++ = 0; token = match_token(p, tokens, args);
if (!strcmp (this_char, "ufstype")) { switch (token) {
case Opt_type_old:
ufs_clear_opt (*mount_options, UFSTYPE); ufs_clear_opt (*mount_options, UFSTYPE);
if (!strcmp (value, "old"))
ufs_set_opt (*mount_options, UFSTYPE_OLD); ufs_set_opt (*mount_options, UFSTYPE_OLD);
else if (!strcmp (value, "sun")) 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); ufs_set_opt (*mount_options, UFSTYPE_SUN);
else if (!strcmp (value, "44bsd")) break;
case Opt_type_44bsd:
ufs_clear_opt (*mount_options, UFSTYPE);
ufs_set_opt (*mount_options, UFSTYPE_44BSD); ufs_set_opt (*mount_options, UFSTYPE_44BSD);
else if (!strcmp (value, "nextstep")) break;
ufs_set_opt (*mount_options, UFSTYPE_NEXTSTEP); case Opt_type_hp:
else if (!strcmp (value, "nextstep-cd")) 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); ufs_set_opt (*mount_options, UFSTYPE_NEXTSTEP_CD);
else if (!strcmp (value, "openstep")) 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); ufs_set_opt (*mount_options, UFSTYPE_OPENSTEP);
else if (!strcmp (value, "sunx86")) break;
ufs_set_opt (*mount_options, UFSTYPE_SUNx86); case Opt_onerror_panic:
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_clear_opt (*mount_options, ONERROR); ufs_clear_opt (*mount_options, ONERROR);
if (!strcmp (value, "panic"))
ufs_set_opt (*mount_options, ONERROR_PANIC); ufs_set_opt (*mount_options, ONERROR_PANIC);
else if (!strcmp (value, "lock")) break;
case Opt_onerror_lock:
ufs_clear_opt (*mount_options, ONERROR);
ufs_set_opt (*mount_options, ONERROR_LOCK); ufs_set_opt (*mount_options, ONERROR_LOCK);
else if (!strcmp (value, "umount")) break;
case Opt_onerror_umount:
ufs_clear_opt (*mount_options, ONERROR);
ufs_set_opt (*mount_options, ONERROR_UMOUNT); ufs_set_opt (*mount_options, ONERROR_UMOUNT);
else if (!strcmp (value, "repair")) { break;
case Opt_onerror_repair:
printk("UFS-fs: Unable to do repair on error, " printk("UFS-fs: Unable to do repair on error, "
"will lock lock instead \n"); "will lock lock instead\n");
ufs_clear_opt (*mount_options, ONERROR);
ufs_set_opt (*mount_options, ONERROR_REPAIR); ufs_set_opt (*mount_options, ONERROR_REPAIR);
} break;
else { default:
printk ("UFS-fs: Invalid action onerror: %s\n", value); printk("UFS-fs: Invalid option: \"%s\" "
return 0; "or missing value\n", p);
}
}
else {
printk("UFS-fs: Invalid option: %s\n", this_char);
return 0; return 0;
} }
} }
......
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 *);
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \ lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \
bust_spinlocks.o rbtree.o radix-tree.o dump_stack.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_GENERIC_SPINLOCK) += rwsem-spinlock.o
lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
......
/*
* 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);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment