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 21enum { 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 30static 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 */ 48void 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 */ 63static 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 71int 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 1; 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 */ 99int 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 pr_err("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 pr_err("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 pr_err("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 pr_err("uid requires an argument\n"); 136 return 0; 137 } 138 sbi->uid = make_kuid(current_user_ns(), (uid_t)tmp); 139 if (!uid_valid(sbi->uid)) { 140 pr_err("invalid uid specified\n"); 141 return 0; 142 } 143 break; 144 case opt_gid: 145 if (match_int(&args[0], &tmp)) { 146 pr_err("gid requires an argument\n"); 147 return 0; 148 } 149 sbi->gid = make_kgid(current_user_ns(), (gid_t)tmp); 150 if (!gid_valid(sbi->gid)) { 151 pr_err("invalid gid specified\n"); 152 return 0; 153 } 154 break; 155 case opt_part: 156 if (match_int(&args[0], &sbi->part)) { 157 pr_err("part requires an argument\n"); 158 return 0; 159 } 160 break; 161 case opt_session: 162 if (match_int(&args[0], &sbi->session)) { 163 pr_err("session requires an argument\n"); 164 return 0; 165 } 166 break; 167 case opt_nls: 168 if (sbi->nls) { 169 pr_err("unable to change nls mapping\n"); 170 return 0; 171 } 172 p = match_strdup(&args[0]); 173 if (p) 174 sbi->nls = load_nls(p); 175 if (!sbi->nls) { 176 pr_err("unable to load nls mapping \"%s\"\n", 177 p); 178 kfree(p); 179 return 0; 180 } 181 kfree(p); 182 break; 183 case opt_decompose: 184 clear_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags); 185 break; 186 case opt_nodecompose: 187 set_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags); 188 break; 189 case opt_barrier: 190 clear_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags); 191 break; 192 case opt_nobarrier: 193 set_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags); 194 break; 195 case opt_force: 196 set_bit(HFSPLUS_SB_FORCE, &sbi->flags); 197 break; 198 default: 199 return 0; 200 } 201 } 202 203done: 204 if (!sbi->nls) { 205 /* try utf8 first, as this is the old default behaviour */ 206 sbi->nls = load_nls("utf8"); 207 if (!sbi->nls) 208 sbi->nls = load_nls_default(); 209 if (!sbi->nls) 210 return 0; 211 } 212 213 return 1; 214} 215 216int hfsplus_show_options(struct seq_file *seq, struct dentry *root) 217{ 218 struct hfsplus_sb_info *sbi = HFSPLUS_SB(root->d_sb); 219 220 if (sbi->creator != HFSPLUS_DEF_CR_TYPE) 221 seq_show_option_n(seq, "creator", (char *)&sbi->creator, 4); 222 if (sbi->type != HFSPLUS_DEF_CR_TYPE) 223 seq_show_option_n(seq, "type", (char *)&sbi->type, 4); 224 seq_printf(seq, ",umask=%o,uid=%u,gid=%u", sbi->umask, 225 from_kuid_munged(&init_user_ns, sbi->uid), 226 from_kgid_munged(&init_user_ns, sbi->gid)); 227 if (sbi->part >= 0) 228 seq_printf(seq, ",part=%u", sbi->part); 229 if (sbi->session >= 0) 230 seq_printf(seq, ",session=%u", sbi->session); 231 if (sbi->nls) 232 seq_printf(seq, ",nls=%s", sbi->nls->charset); 233 if (test_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags)) 234 seq_puts(seq, ",nodecompose"); 235 if (test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags)) 236 seq_puts(seq, ",nobarrier"); 237 return 0; 238} 239