Root/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 <linux/moduleparam.h>
19#include <linux/kernel.h>
20#include <linux/string.h>
21#include <linux/errno.h>
22#include <linux/module.h>
23#include <linux/device.h>
24#include <linux/err.h>
25#include <linux/slab.h>
26#include <linux/ctype.h>
27
28#if 0
29#define DEBUGP printk
30#else
31#define DEBUGP(fmt, a...)
32#endif
33
34static inline char dash2underscore(char c)
35{
36    if (c == '-')
37        return '_';
38    return c;
39}
40
41static inline int parameq(const char *input, const char *paramname)
42{
43    unsigned int i;
44    for (i = 0; dash2underscore(input[i]) == paramname[i]; i++)
45        if (input[i] == '\0')
46            return 1;
47    return 0;
48}
49
50static int parse_one(char *param,
51             char *val,
52             struct kernel_param *params,
53             unsigned num_params,
54             int (*handle_unknown)(char *param, char *val))
55{
56    unsigned int i;
57
58    /* Find parameter */
59    for (i = 0; i < num_params; i++) {
60        if (parameq(param, params[i].name)) {
61            DEBUGP("They are equal! Calling %p\n",
62                   params[i].set);
63            return params[i].set(val, &params[i]);
64        }
65    }
66
67    if (handle_unknown) {
68        DEBUGP("Unknown argument: calling %p\n", handle_unknown);
69        return handle_unknown(param, val);
70    }
71
72    DEBUGP("Unknown argument `%s'\n", param);
73    return -ENOENT;
74}
75
76/* You can use " around spaces, but can't escape ". */
77/* Hyphens and underscores equivalent in parameter names. */
78static char *next_arg(char *args, char **param, char **val)
79{
80    unsigned int i, equals = 0;
81    int in_quote = 0, quoted = 0;
82    char *next;
83
84    if (*args == '"') {
85        args++;
86        in_quote = 1;
87        quoted = 1;
88    }
89
90    for (i = 0; args[i]; i++) {
91        if (isspace(args[i]) && !in_quote)
92            break;
93        if (equals == 0) {
94            if (args[i] == '=')
95                equals = i;
96        }
97        if (args[i] == '"')
98            in_quote = !in_quote;
99    }
100
101    *param = args;
102    if (!equals)
103        *val = NULL;
104    else {
105        args[equals] = '\0';
106        *val = args + equals + 1;
107
108        /* Don't include quotes in value. */
109        if (**val == '"') {
110            (*val)++;
111            if (args[i-1] == '"')
112                args[i-1] = '\0';
113        }
114        if (quoted && args[i-1] == '"')
115            args[i-1] = '\0';
116    }
117
118    if (args[i]) {
119        args[i] = '\0';
120        next = args + i + 1;
121    } else
122        next = args + i;
123
124    /* Chew up trailing spaces. */
125    while (isspace(*next))
126        next++;
127    return next;
128}
129
130/* Args looks like "foo=bar,bar2 baz=fuz wiz". */
131int parse_args(const char *name,
132           char *args,
133           struct kernel_param *params,
134           unsigned num,
135           int (*unknown)(char *param, char *val))
136{
137    char *param, *val;
138
139    DEBUGP("Parsing ARGS: %s\n", args);
140
141    /* Chew leading spaces */
142    while (isspace(*args))
143        args++;
144
145    while (*args) {
146        int ret;
147        int irq_was_disabled;
148
149        args = next_arg(args, &param, &val);
150        irq_was_disabled = irqs_disabled();
151        ret = parse_one(param, val, params, num, unknown);
152        if (irq_was_disabled && !irqs_disabled()) {
153            printk(KERN_WARNING "parse_args(): option '%s' enabled "
154                    "irq's!\n", param);
155        }
156        switch (ret) {
157        case -ENOENT:
158            printk(KERN_ERR "%s: Unknown parameter `%s'\n",
159                   name, param);
160            return ret;
161        case -ENOSPC:
162            printk(KERN_ERR
163                   "%s: `%s' too large for parameter `%s'\n",
164                   name, val ?: "", param);
165            return ret;
166        case 0:
167            break;
168        default:
169            printk(KERN_ERR
170                   "%s: `%s' invalid for parameter `%s'\n",
171                   name, val ?: "", param);
172            return ret;
173        }
174    }
175
176    /* All parsed OK. */
177    return 0;
178}
179
180/* Lazy bastard, eh? */
181#define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn) \
182    int param_set_##name(const char *val, struct kernel_param *kp) \
183    { \
184        tmptype l; \
185        int ret; \
186                                    \
187        if (!val) return -EINVAL; \
188        ret = strtolfn(val, 0, &l); \
189        if (ret == -EINVAL || ((type)l != l)) \
190            return -EINVAL; \
191        *((type *)kp->arg) = l; \
192        return 0; \
193    } \
194    int param_get_##name(char *buffer, struct kernel_param *kp) \
195    { \
196        return sprintf(buffer, format, *((type *)kp->arg)); \
197    }
198
199STANDARD_PARAM_DEF(byte, unsigned char, "%c", unsigned long, strict_strtoul);
200STANDARD_PARAM_DEF(short, short, "%hi", long, strict_strtol);
201STANDARD_PARAM_DEF(ushort, unsigned short, "%hu", unsigned long, strict_strtoul);
202STANDARD_PARAM_DEF(int, int, "%i", long, strict_strtol);
203STANDARD_PARAM_DEF(uint, unsigned int, "%u", unsigned long, strict_strtoul);
204STANDARD_PARAM_DEF(long, long, "%li", long, strict_strtol);
205STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", unsigned long, strict_strtoul);
206
207int param_set_charp(const char *val, struct kernel_param *kp)
208{
209    if (!val) {
210        printk(KERN_ERR "%s: string parameter expected\n",
211               kp->name);
212        return -EINVAL;
213    }
214
215    if (strlen(val) > 1024) {
216        printk(KERN_ERR "%s: string parameter too long\n",
217               kp->name);
218        return -ENOSPC;
219    }
220
221    /* This is a hack. We can't need to strdup in early boot, and we
222     * don't need to; this mangled commandline is preserved. */
223    if (slab_is_available()) {
224        *(char **)kp->arg = kstrdup(val, GFP_KERNEL);
225        if (!*(char **)kp->arg)
226            return -ENOMEM;
227    } else
228        *(const char **)kp->arg = val;
229
230    return 0;
231}
232
233int param_get_charp(char *buffer, struct kernel_param *kp)
234{
235    return sprintf(buffer, "%s", *((char **)kp->arg));
236}
237
238/* Actually could be a bool or an int, for historical reasons. */
239int param_set_bool(const char *val, struct kernel_param *kp)
240{
241    bool v;
242
243    /* No equals means "set"... */
244    if (!val) val = "1";
245
246    /* One of =[yYnN01] */
247    switch (val[0]) {
248    case 'y': case 'Y': case '1':
249        v = true;
250        break;
251    case 'n': case 'N': case '0':
252        v = false;
253        break;
254    default:
255        return -EINVAL;
256    }
257
258    if (kp->flags & KPARAM_ISBOOL)
259        *(bool *)kp->arg = v;
260    else
261        *(int *)kp->arg = v;
262    return 0;
263}
264
265int param_get_bool(char *buffer, struct kernel_param *kp)
266{
267    bool val;
268    if (kp->flags & KPARAM_ISBOOL)
269        val = *(bool *)kp->arg;
270    else
271        val = *(int *)kp->arg;
272
273    /* Y and N chosen as being relatively non-coder friendly */
274    return sprintf(buffer, "%c", val ? 'Y' : 'N');
275}
276
277/* This one must be bool. */
278int param_set_invbool(const char *val, struct kernel_param *kp)
279{
280    int ret;
281    bool boolval;
282    struct kernel_param dummy;
283
284    dummy.arg = &boolval;
285    dummy.flags = KPARAM_ISBOOL;
286    ret = param_set_bool(val, &dummy);
287    if (ret == 0)
288        *(bool *)kp->arg = !boolval;
289    return ret;
290}
291
292int param_get_invbool(char *buffer, struct kernel_param *kp)
293{
294    return sprintf(buffer, "%c", (*(bool *)kp->arg) ? 'N' : 'Y');
295}
296
297/* We break the rule and mangle the string. */
298static int param_array(const char *name,
299               const char *val,
300               unsigned int min, unsigned int max,
301               void *elem, int elemsize,
302               int (*set)(const char *, struct kernel_param *kp),
303               u16 flags,
304               unsigned int *num)
305{
306    int ret;
307    struct kernel_param kp;
308    char save;
309
310    /* Get the name right for errors. */
311    kp.name = name;
312    kp.arg = elem;
313    kp.flags = flags;
314
315    /* No equals sign? */
316    if (!val) {
317        printk(KERN_ERR "%s: expects arguments\n", name);
318        return -EINVAL;
319    }
320
321    *num = 0;
322    /* We expect a comma-separated list of values. */
323    do {
324        int len;
325
326        if (*num == max) {
327            printk(KERN_ERR "%s: can only take %i arguments\n",
328                   name, max);
329            return -EINVAL;
330        }
331        len = strcspn(val, ",");
332
333        /* nul-terminate and parse */
334        save = val[len];
335        ((char *)val)[len] = '\0';
336        ret = set(val, &kp);
337
338        if (ret != 0)
339            return ret;
340        kp.arg += elemsize;
341        val += len+1;
342        (*num)++;
343    } while (save == ',');
344
345    if (*num < min) {
346        printk(KERN_ERR "%s: needs at least %i arguments\n",
347               name, min);
348        return -EINVAL;
349    }
350    return 0;
351}
352
353int param_array_set(const char *val, struct kernel_param *kp)
354{
355    const struct kparam_array *arr = kp->arr;
356    unsigned int temp_num;
357
358    return param_array(kp->name, val, 1, arr->max, arr->elem,
359               arr->elemsize, arr->set, kp->flags,
360               arr->num ?: &temp_num);
361}
362
363int param_array_get(char *buffer, struct kernel_param *kp)
364{
365    int i, off, ret;
366    const struct kparam_array *arr = kp->arr;
367    struct kernel_param p;
368
369    p = *kp;
370    for (i = off = 0; i < (arr->num ? *arr->num : arr->max); i++) {
371        if (i)
372            buffer[off++] = ',';
373        p.arg = arr->elem + arr->elemsize * i;
374        ret = arr->get(buffer + off, &p);
375        if (ret < 0)
376            return ret;
377        off += ret;
378    }
379    buffer[off] = '\0';
380    return off;
381}
382
383int param_set_copystring(const char *val, struct kernel_param *kp)
384{
385    const struct kparam_string *kps = kp->str;
386
387    if (!val) {
388        printk(KERN_ERR "%s: missing param set value\n", kp->name);
389        return -EINVAL;
390    }
391    if (strlen(val)+1 > kps->maxlen) {
392        printk(KERN_ERR "%s: string doesn't fit in %u chars.\n",
393               kp->name, kps->maxlen-1);
394        return -ENOSPC;
395    }
396    strcpy(kps->string, val);
397    return 0;
398}
399
400int param_get_string(char *buffer, struct kernel_param *kp)
401{
402    const struct kparam_string *kps = kp->str;
403    return strlcpy(buffer, kps->string, kps->maxlen);
404}
405
406/* sysfs output in /sys/modules/XYZ/parameters/ */
407#define to_module_attr(n) container_of(n, struct module_attribute, attr);
408#define to_module_kobject(n) container_of(n, struct module_kobject, kobj);
409
410extern struct kernel_param __start___param[], __stop___param[];
411
412struct param_attribute
413{
414    struct module_attribute mattr;
415    struct kernel_param *param;
416};
417
418struct module_param_attrs
419{
420    unsigned int num;
421    struct attribute_group grp;
422    struct param_attribute attrs[0];
423};
424
425#ifdef CONFIG_SYSFS
426#define to_param_attr(n) container_of(n, struct param_attribute, mattr);
427
428static ssize_t param_attr_show(struct module_attribute *mattr,
429                   struct module *mod, char *buf)
430{
431    int count;
432    struct param_attribute *attribute = to_param_attr(mattr);
433
434    if (!attribute->param->get)
435        return -EPERM;
436
437    count = attribute->param->get(buf, attribute->param);
438    if (count > 0) {
439        strcat(buf, "\n");
440        ++count;
441    }
442    return count;
443}
444
445/* sysfs always hands a nul-terminated string in buf. We rely on that. */
446static ssize_t param_attr_store(struct module_attribute *mattr,
447                struct module *owner,
448                const char *buf, size_t len)
449{
450     int err;
451    struct param_attribute *attribute = to_param_attr(mattr);
452
453    if (!attribute->param->set)
454        return -EPERM;
455
456    err = attribute->param->set(buf, attribute->param);
457    if (!err)
458        return len;
459    return err;
460}
461#endif
462
463#ifdef CONFIG_MODULES
464#define __modinit
465#else
466#define __modinit __init
467#endif
468
469#ifdef CONFIG_SYSFS
470/*
471 * add_sysfs_param - add a parameter to sysfs
472 * @mk: struct module_kobject
473 * @kparam: the actual parameter definition to add to sysfs
474 * @name: name of parameter
475 *
476 * Create a kobject if for a (per-module) parameter if mp NULL, and
477 * create file in sysfs. Returns an error on out of memory. Always cleans up
478 * if there's an error.
479 */
480static __modinit int add_sysfs_param(struct module_kobject *mk,
481                     struct kernel_param *kp,
482                     const char *name)
483{
484    struct module_param_attrs *new;
485    struct attribute **attrs;
486    int err, num;
487
488    /* We don't bother calling this with invisible parameters. */
489    BUG_ON(!kp->perm);
490
491    if (!mk->mp) {
492        num = 0;
493        attrs = NULL;
494    } else {
495        num = mk->mp->num;
496        attrs = mk->mp->grp.attrs;
497    }
498
499    /* Enlarge. */
500    new = krealloc(mk->mp,
501               sizeof(*mk->mp) + sizeof(mk->mp->attrs[0]) * (num+1),
502               GFP_KERNEL);
503    if (!new) {
504        kfree(mk->mp);
505        err = -ENOMEM;
506        goto fail;
507    }
508    attrs = krealloc(attrs, sizeof(new->grp.attrs[0])*(num+2), GFP_KERNEL);
509    if (!attrs) {
510        err = -ENOMEM;
511        goto fail_free_new;
512    }
513
514    /* Sysfs wants everything zeroed. */
515    memset(new, 0, sizeof(*new));
516    memset(&new->attrs[num], 0, sizeof(new->attrs[num]));
517    memset(&attrs[num], 0, sizeof(attrs[num]));
518    new->grp.name = "parameters";
519    new->grp.attrs = attrs;
520
521    /* Tack new one on the end. */
522    new->attrs[num].param = kp;
523    new->attrs[num].mattr.show = param_attr_show;
524    new->attrs[num].mattr.store = param_attr_store;
525    new->attrs[num].mattr.attr.name = (char *)name;
526    new->attrs[num].mattr.attr.mode = kp->perm;
527    new->num = num+1;
528
529    /* Fix up all the pointers, since krealloc can move us */
530    for (num = 0; num < new->num; num++)
531        new->grp.attrs[num] = &new->attrs[num].mattr.attr;
532    new->grp.attrs[num] = NULL;
533
534    mk->mp = new;
535    return 0;
536
537fail_free_new:
538    kfree(new);
539fail:
540    mk->mp = NULL;
541    return err;
542}
543
544#ifdef CONFIG_MODULES
545static void free_module_param_attrs(struct module_kobject *mk)
546{
547    kfree(mk->mp->grp.attrs);
548    kfree(mk->mp);
549    mk->mp = NULL;
550}
551
552/*
553 * module_param_sysfs_setup - setup sysfs support for one module
554 * @mod: module
555 * @kparam: module parameters (array)
556 * @num_params: number of module parameters
557 *
558 * Adds sysfs entries for module parameters under
559 * /sys/module/[mod->name]/parameters/
560 */
561int module_param_sysfs_setup(struct module *mod,
562                 struct kernel_param *kparam,
563                 unsigned int num_params)
564{
565    int i, err;
566    bool params = false;
567
568    for (i = 0; i < num_params; i++) {
569        if (kparam[i].perm == 0)
570            continue;
571        err = add_sysfs_param(&mod->mkobj, &kparam[i], kparam[i].name);
572        if (err)
573            return err;
574        params = true;
575    }
576
577    if (!params)
578        return 0;
579
580    /* Create the param group. */
581    err = sysfs_create_group(&mod->mkobj.kobj, &mod->mkobj.mp->grp);
582    if (err)
583        free_module_param_attrs(&mod->mkobj);
584    return err;
585}
586
587/*
588 * module_param_sysfs_remove - remove sysfs support for one module
589 * @mod: module
590 *
591 * Remove sysfs entries for module parameters and the corresponding
592 * kobject.
593 */
594void module_param_sysfs_remove(struct module *mod)
595{
596    if (mod->mkobj.mp) {
597        sysfs_remove_group(&mod->mkobj.kobj, &mod->mkobj.mp->grp);
598        /* We are positive that no one is using any param
599         * attrs at this point. Deallocate immediately. */
600        free_module_param_attrs(&mod->mkobj);
601    }
602}
603#endif
604
605void destroy_params(const struct kernel_param *params, unsigned num)
606{
607    /* FIXME: This should free kmalloced charp parameters. It doesn't. */
608}
609
610static void __init kernel_add_sysfs_param(const char *name,
611                      struct kernel_param *kparam,
612                      unsigned int name_skip)
613{
614    struct module_kobject *mk;
615    struct kobject *kobj;
616    int err;
617
618    kobj = kset_find_obj(module_kset, name);
619    if (kobj) {
620        /* We already have one. Remove params so we can add more. */
621        mk = to_module_kobject(kobj);
622        /* We need to remove it before adding parameters. */
623        sysfs_remove_group(&mk->kobj, &mk->mp->grp);
624    } else {
625        mk = kzalloc(sizeof(struct module_kobject), GFP_KERNEL);
626        BUG_ON(!mk);
627
628        mk->mod = THIS_MODULE;
629        mk->kobj.kset = module_kset;
630        err = kobject_init_and_add(&mk->kobj, &module_ktype, NULL,
631                       "%s", name);
632        if (err) {
633            kobject_put(&mk->kobj);
634            printk(KERN_ERR "Module '%s' failed add to sysfs, "
635                   "error number %d\n", name, err);
636            printk(KERN_ERR "The system will be unstable now.\n");
637            return;
638        }
639        /* So that exit path is even. */
640        kobject_get(&mk->kobj);
641    }
642
643    /* These should not fail at boot. */
644    err = add_sysfs_param(mk, kparam, kparam->name + name_skip);
645    BUG_ON(err);
646    err = sysfs_create_group(&mk->kobj, &mk->mp->grp);
647    BUG_ON(err);
648    kobject_uevent(&mk->kobj, KOBJ_ADD);
649    kobject_put(&mk->kobj);
650}
651
652/*
653 * param_sysfs_builtin - add contents in /sys/parameters for built-in modules
654 *
655 * Add module_parameters to sysfs for "modules" built into the kernel.
656 *
657 * The "module" name (KBUILD_MODNAME) is stored before a dot, the
658 * "parameter" name is stored behind a dot in kernel_param->name. So,
659 * extract the "module" name for all built-in kernel_param-eters,
660 * and for all who have the same, call kernel_add_sysfs_param.
661 */
662static void __init param_sysfs_builtin(void)
663{
664    struct kernel_param *kp;
665    unsigned int name_len;
666    char modname[MODULE_NAME_LEN];
667
668    for (kp = __start___param; kp < __stop___param; kp++) {
669        char *dot;
670
671        if (kp->perm == 0)
672            continue;
673
674        dot = strchr(kp->name, '.');
675        if (!dot) {
676            /* This happens for core_param() */
677            strcpy(modname, "kernel");
678            name_len = 0;
679        } else {
680            name_len = dot - kp->name + 1;
681            strlcpy(modname, kp->name, name_len);
682        }
683        kernel_add_sysfs_param(modname, kp, name_len);
684    }
685}
686
687
688/* module-related sysfs stuff */
689
690static ssize_t module_attr_show(struct kobject *kobj,
691                struct attribute *attr,
692                char *buf)
693{
694    struct module_attribute *attribute;
695    struct module_kobject *mk;
696    int ret;
697
698    attribute = to_module_attr(attr);
699    mk = to_module_kobject(kobj);
700
701    if (!attribute->show)
702        return -EIO;
703
704    ret = attribute->show(attribute, mk->mod, buf);
705
706    return ret;
707}
708
709static ssize_t module_attr_store(struct kobject *kobj,
710                struct attribute *attr,
711                const char *buf, size_t len)
712{
713    struct module_attribute *attribute;
714    struct module_kobject *mk;
715    int ret;
716
717    attribute = to_module_attr(attr);
718    mk = to_module_kobject(kobj);
719
720    if (!attribute->store)
721        return -EIO;
722
723    ret = attribute->store(attribute, mk->mod, buf, len);
724
725    return ret;
726}
727
728static struct sysfs_ops module_sysfs_ops = {
729    .show = module_attr_show,
730    .store = module_attr_store,
731};
732
733static int uevent_filter(struct kset *kset, struct kobject *kobj)
734{
735    struct kobj_type *ktype = get_ktype(kobj);
736
737    if (ktype == &module_ktype)
738        return 1;
739    return 0;
740}
741
742static struct kset_uevent_ops module_uevent_ops = {
743    .filter = uevent_filter,
744};
745
746struct kset *module_kset;
747int module_sysfs_initialized;
748
749struct kobj_type module_ktype = {
750    .sysfs_ops = &module_sysfs_ops,
751};
752
753/*
754 * param_sysfs_init - wrapper for built-in params support
755 */
756static int __init param_sysfs_init(void)
757{
758    module_kset = kset_create_and_add("module", &module_uevent_ops, NULL);
759    if (!module_kset) {
760        printk(KERN_WARNING "%s (%d): error creating kset\n",
761            __FILE__, __LINE__);
762        return -ENOMEM;
763    }
764    module_sysfs_initialized = 1;
765
766    param_sysfs_builtin();
767
768    return 0;
769}
770subsys_initcall(param_sysfs_init);
771
772#endif /* CONFIG_SYSFS */
773
774EXPORT_SYMBOL(param_set_byte);
775EXPORT_SYMBOL(param_get_byte);
776EXPORT_SYMBOL(param_set_short);
777EXPORT_SYMBOL(param_get_short);
778EXPORT_SYMBOL(param_set_ushort);
779EXPORT_SYMBOL(param_get_ushort);
780EXPORT_SYMBOL(param_set_int);
781EXPORT_SYMBOL(param_get_int);
782EXPORT_SYMBOL(param_set_uint);
783EXPORT_SYMBOL(param_get_uint);
784EXPORT_SYMBOL(param_set_long);
785EXPORT_SYMBOL(param_get_long);
786EXPORT_SYMBOL(param_set_ulong);
787EXPORT_SYMBOL(param_get_ulong);
788EXPORT_SYMBOL(param_set_charp);
789EXPORT_SYMBOL(param_get_charp);
790EXPORT_SYMBOL(param_set_bool);
791EXPORT_SYMBOL(param_get_bool);
792EXPORT_SYMBOL(param_set_invbool);
793EXPORT_SYMBOL(param_get_invbool);
794EXPORT_SYMBOL(param_array_set);
795EXPORT_SYMBOL(param_array_get);
796EXPORT_SYMBOL(param_set_copystring);
797EXPORT_SYMBOL(param_get_string);
798

Archive Download this file



interactive