Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Merge branch 'devel'
[palacios.git] / kitten / kernel / params.c
1 /* Helpers for initial module or kernel cmdline parsing
2    Copyright (C) 2001 Rusty Russell.
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 */
18 #include <lwk/kernel.h>
19 #include <lwk/string.h>
20 #include <lwk/errno.h>
21 #include <lwk/params.h>
22
23 #if 0
24 #define DEBUGP printk
25 #else
26 #define DEBUGP(fmt, a...)
27 #endif
28
29 static inline char dash2underscore(char c)
30 {
31         if (c == '-')
32                 return '_';
33         return c;
34 }
35
36 static inline int parameq(const char *input, const char *paramname)
37 {
38         unsigned int i;
39         for (i = 0; dash2underscore(input[i]) == paramname[i]; i++)
40                 if (input[i] == '\0')
41                         return 1;
42         return 0;
43 }
44
45 static int parse_one(char *param,
46                      char *val,
47                      struct kernel_param *params, 
48                      unsigned num_params,
49                      int (*handle_unknown)(char *param, char *val))
50 {
51         unsigned int i;
52 printk("in parse_one(%s, %s)\n", param, val);
53
54         /* Find parameter */
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, &params[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         /* Ignore unknown args if no handle_unknown function specified */
69         printk("Unknown argument `%s'\n", param);
70         return 0;
71 }
72
73 /* You can use " around spaces, but can't escape ". */
74 /* Hyphens and underscores equivalent in parameter names. */
75 static char *next_arg(char *args, char **param, char **val)
76 {
77         unsigned int i, equals = 0;
78         int in_quote = 0, quoted = 0;
79         char *next;
80
81         if (*args == '"') {
82                 args++;
83                 in_quote = 1;
84                 quoted = 1;
85         }
86
87         for (i = 0; args[i]; i++) {
88                 if (args[i] == ' ' && !in_quote)
89                         break;
90                 if (equals == 0) {
91                         if (args[i] == '=')
92                                 equals = i;
93                 }
94                 if (args[i] == '"')
95                         in_quote = !in_quote;
96         }
97
98         *param = args;
99         if (!equals)
100                 *val = NULL;
101         else {
102                 args[equals] = '\0';
103                 *val = args + equals + 1;
104
105                 /* Don't include quotes in value. */
106                 if (**val == '"') {
107                         (*val)++;
108                         if (args[i-1] == '"')
109                                 args[i-1] = '\0';
110                 }
111                 if (quoted && args[i-1] == '"')
112                         args[i-1] = '\0';
113         }
114
115         if (args[i]) {
116                 args[i] = '\0';
117                 next = args + i + 1;
118         } else
119                 next = args + i;
120
121         /* Chew up trailing spaces. */
122         while (*next == ' ')
123                 next++;
124         return next;
125 }
126
127 /* Args looks like "foo=bar,bar2 baz=fuz wiz". */
128 int parse_args(const char *name,
129                char *args,
130                struct kernel_param *params,
131                unsigned num,
132                int (*unknown)(char *param, char *val))
133 {
134         char *param, *val;
135
136         DEBUGP("Parsing ARGS: %s\n", args);
137
138         /* Chew leading spaces */
139         while (*args == ' ')
140                 args++;
141
142         while (*args) {
143                 int ret;
144
145                 args = next_arg(args, &param, &val);
146                 ret = parse_one(param, val, params, num, unknown);
147                 switch (ret) {
148                 case -ENOENT:
149                         printk(KERN_ERR "%s: Unknown parameter `%s'\n",
150                                name, param);
151                         return ret;
152                 case -ENOSPC:
153                         printk(KERN_ERR
154                                "%s: `%s' too large for parameter `%s'\n",
155                                name, val ?: "", param);
156                         return ret;
157                 case 0:
158                         break;
159                 default:
160                         printk(KERN_ERR
161                                "%s: `%s' invalid for parameter `%s'\n",
162                                name, val ?: "", param);
163                         return ret;
164                 }
165         }
166
167         /* All parsed OK. */
168         return 0;
169 }
170
171 /* Lazy bastard, eh? */
172 #define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn)       \
173         int param_set_##name(const char *val, struct kernel_param *kp)  \
174         {                                                               \
175                 char *endp;                                             \
176                 tmptype l;                                              \
177                                                                         \
178                 if (!val) return -EINVAL;                               \
179                 l = strtolfn(val, &endp, 0);                            \
180                 if (endp == val || ((type)l != l))                      \
181                         return -EINVAL;                                 \
182                 *((type *)kp->arg) = l;                                 \
183                 return 0;                                               \
184         }                                                               \
185         int param_get_##name(char *buffer, struct kernel_param *kp)     \
186         {                                                               \
187                 return sprintf(buffer, format, *((type *)kp->arg));     \
188         }
189
190 STANDARD_PARAM_DEF(byte, unsigned char, "%c", unsigned long, simple_strtoul);
191 STANDARD_PARAM_DEF(short, short, "%hi", long, simple_strtol);
192 STANDARD_PARAM_DEF(ushort, unsigned short, "%hu", unsigned long, simple_strtoul);
193 STANDARD_PARAM_DEF(int, int, "%i", long, simple_strtol);
194 STANDARD_PARAM_DEF(uint, unsigned int, "%u", unsigned long, simple_strtoul);
195 STANDARD_PARAM_DEF(long, long, "%li", long, simple_strtol);
196 STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", unsigned long, simple_strtoul);
197
198 int param_set_charp(const char *val, struct kernel_param *kp)
199 {
200         if (!val) {
201                 printk(KERN_ERR "%s: string parameter expected\n",
202                        kp->name);
203                 return -EINVAL;
204         }
205
206         if (strlen(val) > 1024) {
207                 printk(KERN_ERR "%s: string parameter too long\n",
208                        kp->name);
209                 return -ENOSPC;
210         }
211
212         *(char **)kp->arg = (char *)val;
213         return 0;
214 }
215
216 int param_get_charp(char *buffer, struct kernel_param *kp)
217 {
218         return sprintf(buffer, "%s", *((char **)kp->arg));
219 }
220
221 int param_set_bool(const char *val, struct kernel_param *kp)
222 {
223         /* No equals means "set"... */
224         if (!val) val = "1";
225
226         /* One of =[yYnN01] */
227         switch (val[0]) {
228         case 'y': case 'Y': case '1':
229                 *(int *)kp->arg = 1;
230                 return 0;
231         case 'n': case 'N': case '0':
232                 *(int *)kp->arg = 0;
233                 return 0;
234         }
235         return -EINVAL;
236 }
237
238 int param_get_bool(char *buffer, struct kernel_param *kp)
239 {
240         /* Y and N chosen as being relatively non-coder friendly */
241         return sprintf(buffer, "%c", (*(int *)kp->arg) ? 'Y' : 'N');
242 }
243
244 int param_set_invbool(const char *val, struct kernel_param *kp)
245 {
246         int boolval, ret;
247         struct kernel_param dummy = { .arg = &boolval };
248
249         ret = param_set_bool(val, &dummy);
250         if (ret == 0)
251                 *(int *)kp->arg = !boolval;
252         return ret;
253 }
254
255 int param_get_invbool(char *buffer, struct kernel_param *kp)
256 {
257         int val;
258         struct kernel_param dummy = { .arg = &val };
259
260         val = !*(int *)kp->arg;
261         return param_get_bool(buffer, &dummy);
262 }
263
264 /* We cheat here and temporarily mangle the string. */
265 static int _param_array(const char *name,
266                        const char *val,
267                        unsigned int min, unsigned int max,
268                        void *elem, int elemsize,
269                        int (*set)(const char *, struct kernel_param *kp),
270                        int *num)
271 {
272         int ret;
273         struct kernel_param kp;
274         char save;
275
276         /* Get the name right for errors. */
277         kp.name = name;
278         kp.arg = elem;
279
280         /* No equals sign? */
281         if (!val) {
282                 printk(KERN_ERR "%s: expects arguments\n", name);
283                 return -EINVAL;
284         }
285
286         *num = 0;
287         /* We expect a comma-separated list of values. */
288         do {
289                 int len;
290
291                 if (*num == max) {
292                         printk(KERN_ERR "%s: can only take %i arguments\n",
293                                name, max);
294                         return -EINVAL;
295                 }
296                 len = strcspn(val, ",");
297
298                 /* nul-terminate and parse */
299                 save = val[len];
300                 ((char *)val)[len] = '\0';
301                 ret = set(val, &kp);
302
303                 if (ret != 0)
304                         return ret;
305                 kp.arg += elemsize;
306                 val += len+1;
307                 (*num)++;
308         } while (save == ',');
309
310         if (*num < min) {
311                 printk(KERN_ERR "%s: needs at least %i arguments\n",
312                        name, min);
313                 return -EINVAL;
314         }
315         return 0;
316 }
317
318 int param_array_set(const char *val, struct kernel_param *kp)
319 {
320         struct kparam_array *arr = kp->arg;
321         unsigned int temp_num;
322
323         return _param_array(kp->name, val, 1, arr->max, arr->elem,
324                            arr->elemsize, arr->set, arr->num ?: &temp_num);
325 }
326
327 int param_array_get(char *buffer, struct kernel_param *kp)
328 {
329         int i, off, ret;
330         struct kparam_array *arr = kp->arg;
331         struct kernel_param p;
332
333         p = *kp;
334         for (i = off = 0; i < (arr->num ? *arr->num : arr->max); i++) {
335                 if (i)
336                         buffer[off++] = ',';
337                 p.arg = arr->elem + arr->elemsize * i;
338                 ret = arr->get(buffer + off, &p);
339                 if (ret < 0)
340                         return ret;
341                 off += ret;
342         }
343         buffer[off] = '\0';
344         return off;
345 }
346
347 int param_set_copystring(const char *val, struct kernel_param *kp)
348 {
349         struct kparam_string *kps = kp->arg;
350
351         if (strlen(val)+1 > kps->maxlen) {
352                 printk(KERN_ERR "%s: string doesn't fit in %u chars.\n",
353                        kp->name, kps->maxlen-1);
354                 return -ENOSPC;
355         }
356         strcpy(kps->string, val);
357         return 0;
358 }
359
360 int param_get_string(char *buffer, struct kernel_param *kp)
361 {
362         struct kparam_string *kps = kp->arg;
363         return strlcpy(buffer, kps->string, kps->maxlen);
364 }
365
366 /**
367  * Parses all parameters from the input string.
368  */
369 int parse_params(const char *str)
370 {
371         struct kernel_param * params     = __start___param;
372         unsigned int          num_params = __stop___param - __start___param;
373         char tmp[2048];
374
375         // Make a temporary copy of the string since parse_args modifies it
376         if (strlen(str)+1 > sizeof(tmp)) {
377                 printk(KERN_ERR "parse_params: input string too large");
378                 return -ENOSPC;
379         }
380         
381         strcpy(tmp, str);
382         return parse_args("Parsing Arguments", tmp, params, num_params, NULL);
383 }
384
385 /**
386  * Manually sets the specified parameter.
387  */
388 int param_set_by_name_int(char *param, int val)
389 {
390         struct kernel_param * params     = __start___param;
391         unsigned int          num_params = __stop___param - __start___param;
392         char valstr[128];
393
394         sprintf(valstr, "%d", val);
395         return parse_one(param, valstr, params, num_params, NULL);
396 }
397