1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/moduleparam.h>
19#include <linux/kernel.h>
20#include <linux/string.h>
21#include <linux/errno.h>
22#include <linux/module.h>
23
24#if 0
25#define DEBUGP printk
26#else
27#define DEBUGP(fmt, a...)
28#endif
29
30static inline int dash2underscore(char c)
31{
32 if (c == '-')
33 return '_';
34 return c;
35}
36
37static inline int parameq(const char *input, const char *paramname)
38{
39 unsigned int i;
40 for (i = 0; dash2underscore(input[i]) == paramname[i]; i++)
41 if (input[i] == '\0')
42 return 1;
43 return 0;
44}
45
46static int parse_one(char *param,
47 char *val,
48 struct kernel_param *params,
49 unsigned num_params,
50 int (*handle_unknown)(char *param, char *val))
51{
52 unsigned int i;
53
54
55 for (i = 0; i < num_params; i++) {
56 if (parameq(param, params[i].name)) {
57 DEBUGP("They are equal! Calling %p\n",
58 params[i].set);
59 return params[i].set(val, ¶ms[i]);
60 }
61 }
62
63 if (handle_unknown) {
64 DEBUGP("Unknown argument: calling %p\n", handle_unknown);
65 return handle_unknown(param, val);
66 }
67
68 DEBUGP("Unknown argument `%s'\n", param);
69 return -ENOENT;
70}
71
72
73
74static char *next_arg(char *args, char **param, char **val)
75{
76 unsigned int i, equals = 0;
77 int in_quote = 0;
78
79
80 while (*args == ' ') args++;
81
82 for (i = 0; args[i]; i++) {
83 if (args[i] == ' ' && !in_quote)
84 break;
85 if (equals == 0) {
86 if (args[i] == '=')
87 equals = i;
88 }
89 if (args[i] == '"')
90 in_quote = !in_quote;
91 }
92
93 *param = args;
94 if (!equals)
95 *val = NULL;
96 else {
97 args[equals] = '\0';
98 *val = args + equals + 1;
99
100
101 if (**val == '"') {
102 (*val)++;
103 if (args[i-1] == '"')
104 args[i-1] = '\0';
105 }
106 }
107
108 if (args[i]) {
109 args[i] = '\0';
110 return args + i + 1;
111 } else
112 return args + i;
113}
114
115
116int parse_args(const char *name,
117 char *args,
118 struct kernel_param *params,
119 unsigned num,
120 int (*unknown)(char *param, char *val))
121{
122 char *param, *val;
123
124 DEBUGP("Parsing ARGS: %s\n", args);
125
126 while (*args) {
127 int ret;
128
129 args = next_arg(args, ¶m, &val);
130 ret = parse_one(param, val, params, num, unknown);
131 switch (ret) {
132 case -ENOENT:
133 printk(KERN_ERR "%s: Unknown parameter `%s'\n",
134 name, param);
135 return ret;
136 case -ENOSPC:
137 printk(KERN_ERR
138 "%s: `%s' too large for parameter `%s'\n",
139 name, val ?: "", param);
140 return ret;
141 case 0:
142 break;
143 default:
144 printk(KERN_ERR
145 "%s: `%s' invalid for parameter `%s'\n",
146 name, val ?: "", param);
147 return ret;
148 }
149 }
150
151
152 return 0;
153}
154
155
156#define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn) \
157 int param_set_##name(const char *val, struct kernel_param *kp) \
158 { \
159 char *endp; \
160 tmptype l; \
161 \
162 if (!val) return -EINVAL; \
163 l = strtolfn(val, &endp, 0); \
164 if (endp == val || ((type)l != l)) \
165 return -EINVAL; \
166 *((type *)kp->arg) = l; \
167 return 0; \
168 } \
169 int param_get_##name(char *buffer, struct kernel_param *kp) \
170 { \
171 return sprintf(buffer, format, *((type *)kp->arg)); \
172 }
173
174STANDARD_PARAM_DEF(byte, unsigned char, "%c", unsigned long, simple_strtoul);
175STANDARD_PARAM_DEF(short, short, "%hi", long, simple_strtol);
176STANDARD_PARAM_DEF(ushort, unsigned short, "%hu", unsigned long, simple_strtoul);
177STANDARD_PARAM_DEF(int, int, "%i", long, simple_strtol);
178STANDARD_PARAM_DEF(uint, unsigned int, "%u", unsigned long, simple_strtoul);
179STANDARD_PARAM_DEF(long, long, "%li", long, simple_strtol);
180STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", unsigned long, simple_strtoul);
181
182int param_set_charp(const char *val, struct kernel_param *kp)
183{
184 if (!val) {
185 printk(KERN_ERR "%s: string parameter expected\n",
186 kp->name);
187 return -EINVAL;
188 }
189
190 if (strlen(val) > 1024) {
191 printk(KERN_ERR "%s: string parameter too long\n",
192 kp->name);
193 return -ENOSPC;
194 }
195
196 *(char **)kp->arg = (char *)val;
197 return 0;
198}
199
200int param_get_charp(char *buffer, struct kernel_param *kp)
201{
202 return sprintf(buffer, "%s", *((char **)kp->arg));
203}
204
205int param_set_bool(const char *val, struct kernel_param *kp)
206{
207
208 if (!val) val = "1";
209
210
211 switch (val[0]) {
212 case 'y': case 'Y': case '1':
213 *(int *)kp->arg = 1;
214 return 0;
215 case 'n': case 'N': case '0':
216 *(int *)kp->arg = 0;
217 return 0;
218 }
219 return -EINVAL;
220}
221
222int param_get_bool(char *buffer, struct kernel_param *kp)
223{
224
225 return sprintf(buffer, "%c", (*(int *)kp->arg) ? 'Y' : 'N');
226}
227
228int param_set_invbool(const char *val, struct kernel_param *kp)
229{
230 int boolval, ret;
231 struct kernel_param dummy = { .arg = &boolval };
232
233 ret = param_set_bool(val, &dummy);
234 if (ret == 0)
235 *(int *)kp->arg = !boolval;
236 return ret;
237}
238
239int param_get_invbool(char *buffer, struct kernel_param *kp)
240{
241 int val;
242 struct kernel_param dummy = { .arg = &val };
243
244 val = !*(int *)kp->arg;
245 return param_get_bool(buffer, &dummy);
246}
247
248
249int param_array(const char *name,
250 const char *val,
251 unsigned int min, unsigned int max,
252 void *elem, int elemsize,
253 int (*set)(const char *, struct kernel_param *kp),
254 int *num)
255{
256 int ret;
257 struct kernel_param kp;
258 char save;
259
260
261 kp.name = name;
262 kp.arg = elem;
263
264
265 if (!val) {
266 printk(KERN_ERR "%s: expects arguments\n", name);
267 return -EINVAL;
268 }
269
270 *num = 0;
271
272 do {
273 int len;
274
275 if (*num == max) {
276 printk(KERN_ERR "%s: can only take %i arguments\n",
277 name, max);
278 return -EINVAL;
279 }
280 len = strcspn(val, ",");
281
282
283 save = val[len];
284 ((char *)val)[len] = '\0';
285 ret = set(val, &kp);
286
287 if (ret != 0)
288 return ret;
289 kp.arg += elemsize;
290 val += len+1;
291 (*num)++;
292 } while (save == ',');
293
294 if (*num < min) {
295 printk(KERN_ERR "%s: needs at least %i arguments\n",
296 name, min);
297 return -EINVAL;
298 }
299 return 0;
300}
301
302int param_array_set(const char *val, struct kernel_param *kp)
303{
304 struct kparam_array *arr = kp->arg;
305
306 return param_array(kp->name, val, 1, arr->max, arr->elem,
307 arr->elemsize, arr->set, arr->num);
308}
309
310int param_array_get(char *buffer, struct kernel_param *kp)
311{
312 int i, off, ret;
313 struct kparam_array *arr = kp->arg;
314 struct kernel_param p;
315
316 p = *kp;
317 for (i = off = 0; i < *arr->num; i++) {
318 if (i)
319 buffer[off++] = ',';
320 p.arg = arr->elem + arr->elemsize * i;
321 ret = arr->get(buffer + off, &p);
322 if (ret < 0)
323 return ret;
324 off += ret;
325 }
326 buffer[off] = '\0';
327 return off;
328}
329
330int param_set_copystring(const char *val, struct kernel_param *kp)
331{
332 struct kparam_string *kps = kp->arg;
333
334 if (strlen(val)+1 > kps->maxlen) {
335 printk(KERN_ERR "%s: string doesn't fit in %u chars.\n",
336 kp->name, kps->maxlen-1);
337 return -ENOSPC;
338 }
339 strcpy(kps->string, val);
340 return 0;
341}
342
343int param_get_string(char *buffer, struct kernel_param *kp)
344{
345 struct kparam_string *kps = kp->arg;
346 return strlcpy(buffer, kps->string, kps->maxlen);
347}
348
349EXPORT_SYMBOL(param_set_byte);
350EXPORT_SYMBOL(param_get_byte);
351EXPORT_SYMBOL(param_set_short);
352EXPORT_SYMBOL(param_get_short);
353EXPORT_SYMBOL(param_set_ushort);
354EXPORT_SYMBOL(param_get_ushort);
355EXPORT_SYMBOL(param_set_int);
356EXPORT_SYMBOL(param_get_int);
357EXPORT_SYMBOL(param_set_uint);
358EXPORT_SYMBOL(param_get_uint);
359EXPORT_SYMBOL(param_set_long);
360EXPORT_SYMBOL(param_get_long);
361EXPORT_SYMBOL(param_set_ulong);
362EXPORT_SYMBOL(param_get_ulong);
363EXPORT_SYMBOL(param_set_charp);
364EXPORT_SYMBOL(param_get_charp);
365EXPORT_SYMBOL(param_set_bool);
366EXPORT_SYMBOL(param_get_bool);
367EXPORT_SYMBOL(param_set_invbool);
368EXPORT_SYMBOL(param_get_invbool);
369EXPORT_SYMBOL(param_array_set);
370EXPORT_SYMBOL(param_array_get);
371EXPORT_SYMBOL(param_set_copystring);
372EXPORT_SYMBOL(param_get_string);
373