1 /* 2 * linux/fs/hfsplus/options.c 3 * 4 * Copyright (C) 2001 5 * Brad Boyer (flar@allandria.com) 6 * (C) 2003 Ardis Technologies <roman@ardistech.com> 7 * 8 * Option parsing 9 */ 10 11 #include <linux/string.h> 12 #include <linux/kernel.h> 13 #include <linux/sched.h> 14 #include <linux/parser.h> 15 #include <linux/nls.h> 16 #include <linux/mount.h> 17 #include <linux/seq_file.h> 18 #include <linux/slab.h> 19 #include "hfsplus_fs.h" 20 21 enum { 22 opt_creator, opt_type, 23 opt_umask, opt_uid, opt_gid, 24 opt_part, opt_session, opt_nls, 25 opt_nodecompose, opt_decompose, 26 opt_barrier, opt_nobarrier, 27 opt_force, opt_err 28 }; 29 30 static const match_table_t tokens = { 31 { opt_creator, "creator=%s" }, 32 { opt_type, "type=%s" }, 33 { opt_umask, "umask=%o" }, 34 { opt_uid, "uid=%u" }, 35 { opt_gid, "gid=%u" }, 36 { opt_part, "part=%u" }, 37 { opt_session, "session=%u" }, 38 { opt_nls, "nls=%s" }, 39 { opt_decompose, "decompose" }, 40 { opt_nodecompose, "nodecompose" }, 41 { opt_barrier, "barrier" }, 42 { opt_nobarrier, "nobarrier" }, 43 { opt_force, "force" }, 44 { opt_err, NULL } 45 }; 46 47 /* Initialize an options object to reasonable defaults */ 48 void hfsplus_fill_defaults(struct hfsplus_sb_info *opts) 49 { 50 if (!opts) 51 return; 52 53 opts->creator = HFSPLUS_DEF_CR_TYPE; 54 opts->type = HFSPLUS_DEF_CR_TYPE; 55 opts->umask = current_umask(); 56 opts->uid = current_uid(); 57 opts->gid = current_gid(); 58 opts->part = -1; 59 opts->session = -1; 60 } 61 62 /* convert a "four byte character" to a 32 bit int with error checks */ 63 static inline int match_fourchar(substring_t *arg, u32 *result) 64 { 65 if (arg->to - arg->from != 4) 66 return -EINVAL; 67 memcpy(result, arg->from, 4); 68 return 0; 69 } 70 71 int hfsplus_parse_options_remount(char *input, int *force) 72 { 73 char *p; 74 substring_t args[MAX_OPT_ARGS]; 75 int token; 76 77 if (!input) 78 return 0; 79 80 while ((p = strsep(&input, ",")) != NULL) { 81 if (!*p) 82 continue; 83 84 token = match_token(p, tokens, args); 85 switch (token) { 86 case opt_force: 87 *force = 1; 88 break; 89 default: 90 break; 91 } 92 } 93 94 return 1; 95 } 96 97 /* Parse options from mount. Returns 0 on failure */ 98 /* input is the options passed to mount() as a string */ 99 int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi) 100 { 101 char *p; 102 substring_t args[MAX_OPT_ARGS]; 103 int tmp, token; 104 105 if (!input) 106 goto done; 107 108 while ((p = strsep(&input, ",")) != NULL) { 109 if (!*p) 110 continue; 111 112 token = match_token(p, tokens, args); 113 switch (token) { 114 case opt_creator: 115 if (match_fourchar(&args[0], &sbi->creator)) { 116 printk(KERN_ERR "hfs: creator requires a 4 character value\n"); 117 return 0; 118 } 119 break; 120 case opt_type: 121 if (match_fourchar(&args[0], &sbi->type)) { 122 printk(KERN_ERR "hfs: type requires a 4 character value\n"); 123 return 0; 124 } 125 break; 126 case opt_umask: 127 if (match_octal(&args[0], &tmp)) { 128 printk(KERN_ERR "hfs: umask requires a value\n"); 129 return 0; 130 } 131 sbi->umask = (umode_t)tmp; 132 break; 133 case opt_uid: 134 if (match_int(&args[0], &tmp)) { 135 printk(KERN_ERR "hfs: uid requires an argument\n"); 136 return 0; 137 } 138 sbi->uid = (uid_t)tmp; 139 break; 140 case opt_gid: 141 if (match_int(&args[0], &tmp)) { 142 printk(KERN_ERR "hfs: gid requires an argument\n"); 143 return 0; 144 } 145 sbi->gid = (gid_t)tmp; 146 break; 147 case opt_part: 148 if (match_int(&args[0], &sbi->part)) { 149 printk(KERN_ERR "hfs: part requires an argument\n"); 150 return 0; 151 } 152 break; 153 case opt_session: 154 if (match_int(&args[0], &sbi->session)) { 155 printk(KERN_ERR "hfs: session requires an argument\n"); 156 return 0; 157 } 158 break; 159 case opt_nls: 160 if (sbi->nls) { 161 printk(KERN_ERR "hfs: unable to change nls mapping\n"); 162 return 0; 163 } 164 p = match_strdup(&args[0]); 165 if (p) 166 sbi->nls = load_nls(p); 167 if (!sbi->nls) { 168 printk(KERN_ERR "hfs: unable to load " 169 "nls mapping \"%s\"\n", 170 p); 171 kfree(p); 172 return 0; 173 } 174 kfree(p); 175 break; 176 case opt_decompose: 177 clear_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags); 178 break; 179 case opt_nodecompose: 180 set_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags); 181 break; 182 case opt_barrier: 183 clear_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags); 184 break; 185 case opt_nobarrier: 186 set_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags); 187 break; 188 case opt_force: 189 set_bit(HFSPLUS_SB_FORCE, &sbi->flags); 190 break; 191 default: 192 return 0; 193 } 194 } 195 196 done: 197 if (!sbi->nls) { 198 /* try utf8 first, as this is the old default behaviour */ 199 sbi->nls = load_nls("utf8"); 200 if (!sbi->nls) 201 sbi->nls = load_nls_default(); 202 if (!sbi->nls) 203 return 0; 204 } 205 206 return 1; 207 } 208 209 int hfsplus_show_options(struct seq_file *seq, struct dentry *root) 210 { 211 struct hfsplus_sb_info *sbi = HFSPLUS_SB(root->d_sb); 212 213 if (sbi->creator != HFSPLUS_DEF_CR_TYPE) 214 seq_printf(seq, ",creator=%.4s", (char *)&sbi->creator); 215 if (sbi->type != HFSPLUS_DEF_CR_TYPE) 216 seq_printf(seq, ",type=%.4s", (char *)&sbi->type); 217 seq_printf(seq, ",umask=%o,uid=%u,gid=%u", sbi->umask, 218 sbi->uid, sbi->gid); 219 if (sbi->part >= 0) 220 seq_printf(seq, ",part=%u", sbi->part); 221 if (sbi->session >= 0) 222 seq_printf(seq, ",session=%u", sbi->session); 223 if (sbi->nls) 224 seq_printf(seq, ",nls=%s", sbi->nls->charset); 225 if (test_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags)) 226 seq_printf(seq, ",nodecompose"); 227 if (test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags)) 228 seq_printf(seq, ",nobarrier"); 229 return 0; 230 } 231