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