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 34 static inline char dash2underscore(char c) 35 { 36 if (c == '-') 37 return '_'; 38 return c; 39 } 40 41 static 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 50 static 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, ¶ms[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. */ 78 static 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". */ 131 int 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, ¶m, &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 199 STANDARD_PARAM_DEF(byte, unsigned char, "%c", unsigned long, strict_strtoul); 200 STANDARD_PARAM_DEF(short, short, "%hi", long, strict_strtol); 201 STANDARD_PARAM_DEF(ushort, unsigned short, "%hu", unsigned long, strict_strtoul); 202 STANDARD_PARAM_DEF(int, int, "%i", long, strict_strtol); 203 STANDARD_PARAM_DEF(uint, unsigned int, "%u", unsigned long, strict_strtoul); 204 STANDARD_PARAM_DEF(long, long, "%li", long, strict_strtol); 205 STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", unsigned long, strict_strtoul); 206 207 int 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 if (kp->flags & KPARAM_KMALLOCED) 222 kfree(*(char **)kp->arg); 223 224 /* This is a hack. We can't need to strdup in early boot, and we 225 * don't need to; this mangled commandline is preserved. */ 226 if (slab_is_available()) { 227 kp->flags |= KPARAM_KMALLOCED; 228 *(char **)kp->arg = kstrdup(val, GFP_KERNEL); 229 if (!kp->arg) 230 return -ENOMEM; 231 } else 232 *(const char **)kp->arg = val; 233 234 return 0; 235 } 236 237 int param_get_charp(char *buffer, struct kernel_param *kp) 238 { 239 return sprintf(buffer, "%s", *((char **)kp->arg)); 240 } 241 242 /* Actually could be a bool or an int, for historical reasons. */ 243 int param_set_bool(const char *val, struct kernel_param *kp) 244 { 245 bool v; 246 247 /* No equals means "set"... */ 248 if (!val) val = "1"; 249 250 /* One of =[yYnN01] */ 251 switch (val[0]) { 252 case 'y': case 'Y': case '1': 253 v = true; 254 break; 255 case 'n': case 'N': case '0': 256 v = false; 257 break; 258 default: 259 return -EINVAL; 260 } 261 262 if (kp->flags & KPARAM_ISBOOL) 263 *(bool *)kp->arg = v; 264 else 265 *(int *)kp->arg = v; 266 return 0; 267 } 268 269 int param_get_bool(char *buffer, struct kernel_param *kp) 270 { 271 bool val; 272 if (kp->flags & KPARAM_ISBOOL) 273 val = *(bool *)kp->arg; 274 else 275 val = *(int *)kp->arg; 276 277 /* Y and N chosen as being relatively non-coder friendly */ 278 return sprintf(buffer, "%c", val ? 'Y' : 'N'); 279 } 280 281 /* This one must be bool. */ 282 int param_set_invbool(const char *val, struct kernel_param *kp) 283 { 284 int ret; 285 bool boolval; 286 struct kernel_param dummy; 287 288 dummy.arg = &boolval; 289 dummy.flags = KPARAM_ISBOOL; 290 ret = param_set_bool(val, &dummy); 291 if (ret == 0) 292 *(bool *)kp->arg = !boolval; 293 return ret; 294 } 295 296 int param_get_invbool(char *buffer, struct kernel_param *kp) 297 { 298 return sprintf(buffer, "%c", (*(bool *)kp->arg) ? 'N' : 'Y'); 299 } 300 301 /* We break the rule and mangle the string. */ 302 static int param_array(const char *name, 303 const char *val, 304 unsigned int min, unsigned int max, 305 void *elem, int elemsize, 306 int (*set)(const char *, struct kernel_param *kp), 307 unsigned int *num) 308 { 309 int ret; 310 struct kernel_param kp; 311 char save; 312 313 /* Get the name right for errors. */ 314 kp.name = name; 315 kp.arg = elem; 316 317 /* No equals sign? */ 318 if (!val) { 319 printk(KERN_ERR "%s: expects arguments\n", name); 320 return -EINVAL; 321 } 322 323 *num = 0; 324 /* We expect a comma-separated list of values. */ 325 do { 326 int len; 327 328 if (*num == max) { 329 printk(KERN_ERR "%s: can only take %i arguments\n", 330 name, max); 331 return -EINVAL; 332 } 333 len = strcspn(val, ","); 334 335 /* nul-terminate and parse */ 336 save = val[len]; 337 ((char *)val)[len] = '\0'; 338 ret = set(val, &kp); 339 340 if (ret != 0) 341 return ret; 342 kp.arg += elemsize; 343 val += len+1; 344 (*num)++; 345 } while (save == ','); 346 347 if (*num < min) { 348 printk(KERN_ERR "%s: needs at least %i arguments\n", 349 name, min); 350 return -EINVAL; 351 } 352 return 0; 353 } 354 355 int param_array_set(const char *val, struct kernel_param *kp) 356 { 357 const struct kparam_array *arr = kp->arr; 358 unsigned int temp_num; 359 360 return param_array(kp->name, val, 1, arr->max, arr->elem, 361 arr->elemsize, arr->set, arr->num ?: &temp_num); 362 } 363 364 int param_array_get(char *buffer, struct kernel_param *kp) 365 { 366 int i, off, ret; 367 const struct kparam_array *arr = kp->arr; 368 struct kernel_param p; 369 370 p = *kp; 371 for (i = off = 0; i < (arr->num ? *arr->num : arr->max); i++) { 372 if (i) 373 buffer[off++] = ','; 374 p.arg = arr->elem + arr->elemsize * i; 375 ret = arr->get(buffer + off, &p); 376 if (ret < 0) 377 return ret; 378 off += ret; 379 } 380 buffer[off] = '\0'; 381 return off; 382 } 383 384 int param_set_copystring(const char *val, struct kernel_param *kp) 385 { 386 const struct kparam_string *kps = kp->str; 387 388 if (!val) { 389 printk(KERN_ERR "%s: missing param set value\n", kp->name); 390 return -EINVAL; 391 } 392 if (strlen(val)+1 > kps->maxlen) { 393 printk(KERN_ERR "%s: string doesn't fit in %u chars.\n", 394 kp->name, kps->maxlen-1); 395 return -ENOSPC; 396 } 397 strcpy(kps->string, val); 398 return 0; 399 } 400 401 int param_get_string(char *buffer, struct kernel_param *kp) 402 { 403 const struct kparam_string *kps = kp->str; 404 return strlcpy(buffer, kps->string, kps->maxlen); 405 } 406 407 /* sysfs output in /sys/modules/XYZ/parameters/ */ 408 #define to_module_attr(n) container_of(n, struct module_attribute, attr); 409 #define to_module_kobject(n) container_of(n, struct module_kobject, kobj); 410 411 extern struct kernel_param __start___param[], __stop___param[]; 412 413 struct param_attribute 414 { 415 struct module_attribute mattr; 416 struct kernel_param *param; 417 }; 418 419 struct module_param_attrs 420 { 421 unsigned int num; 422 struct attribute_group grp; 423 struct param_attribute attrs[0]; 424 }; 425 426 #ifdef CONFIG_SYSFS 427 #define to_param_attr(n) container_of(n, struct param_attribute, mattr); 428 429 static ssize_t param_attr_show(struct module_attribute *mattr, 430 struct module *mod, char *buf) 431 { 432 int count; 433 struct param_attribute *attribute = to_param_attr(mattr); 434 435 if (!attribute->param->get) 436 return -EPERM; 437 438 count = attribute->param->get(buf, attribute->param); 439 if (count > 0) { 440 strcat(buf, "\n"); 441 ++count; 442 } 443 return count; 444 } 445 446 /* sysfs always hands a nul-terminated string in buf. We rely on that. */ 447 static ssize_t param_attr_store(struct module_attribute *mattr, 448 struct module *owner, 449 const char *buf, size_t len) 450 { 451 int err; 452 struct param_attribute *attribute = to_param_attr(mattr); 453 454 if (!attribute->param->set) 455 return -EPERM; 456 457 err = attribute->param->set(buf, attribute->param); 458 if (!err) 459 return len; 460 return err; 461 } 462 #endif 463 464 #ifdef CONFIG_MODULES 465 #define __modinit 466 #else 467 #define __modinit __init 468 #endif 469 470 #ifdef CONFIG_SYSFS 471 /* 472 * add_sysfs_param - add a parameter to sysfs 473 * @mk: struct module_kobject 474 * @kparam: the actual parameter definition to add to sysfs 475 * @name: name of parameter 476 * 477 * Create a kobject if for a (per-module) parameter if mp NULL, and 478 * create file in sysfs. Returns an error on out of memory. Always cleans up 479 * if there's an error. 480 */ 481 static __modinit int add_sysfs_param(struct module_kobject *mk, 482 struct kernel_param *kp, 483 const char *name) 484 { 485 struct module_param_attrs *new; 486 struct attribute **attrs; 487 int err, num; 488 489 /* We don't bother calling this with invisible parameters. */ 490 BUG_ON(!kp->perm); 491 492 if (!mk->mp) { 493 num = 0; 494 attrs = NULL; 495 } else { 496 num = mk->mp->num; 497 attrs = mk->mp->grp.attrs; 498 } 499 500 /* Enlarge. */ 501 new = krealloc(mk->mp, 502 sizeof(*mk->mp) + sizeof(mk->mp->attrs[0]) * (num+1), 503 GFP_KERNEL); 504 if (!new) { 505 kfree(mk->mp); 506 err = -ENOMEM; 507 goto fail; 508 } 509 attrs = krealloc(attrs, sizeof(new->grp.attrs[0])*(num+2), GFP_KERNEL); 510 if (!attrs) { 511 err = -ENOMEM; 512 goto fail_free_new; 513 } 514 515 /* Sysfs wants everything zeroed. */ 516 memset(new, 0, sizeof(*new)); 517 memset(&new->attrs[num], 0, sizeof(new->attrs[num])); 518 memset(&attrs[num], 0, sizeof(attrs[num])); 519 new->grp.name = "parameters"; 520 new->grp.attrs = attrs; 521 522 /* Tack new one on the end. */ 523 new->attrs[num].param = kp; 524 new->attrs[num].mattr.show = param_attr_show; 525 new->attrs[num].mattr.store = param_attr_store; 526 new->attrs[num].mattr.attr.name = (char *)name; 527 new->attrs[num].mattr.attr.mode = kp->perm; 528 new->num = num+1; 529 530 /* Fix up all the pointers, since krealloc can move us */ 531 for (num = 0; num < new->num; num++) 532 new->grp.attrs[num] = &new->attrs[num].mattr.attr; 533 new->grp.attrs[num] = NULL; 534 535 mk->mp = new; 536 return 0; 537 538 fail_free_new: 539 kfree(new); 540 fail: 541 mk->mp = NULL; 542 return err; 543 } 544 545 #ifdef CONFIG_MODULES 546 static void free_module_param_attrs(struct module_kobject *mk) 547 { 548 kfree(mk->mp->grp.attrs); 549 kfree(mk->mp); 550 mk->mp = NULL; 551 } 552 553 /* 554 * module_param_sysfs_setup - setup sysfs support for one module 555 * @mod: module 556 * @kparam: module parameters (array) 557 * @num_params: number of module parameters 558 * 559 * Adds sysfs entries for module parameters under 560 * /sys/module/[mod->name]/parameters/ 561 */ 562 int module_param_sysfs_setup(struct module *mod, 563 struct kernel_param *kparam, 564 unsigned int num_params) 565 { 566 int i, err; 567 bool params = false; 568 569 for (i = 0; i < num_params; i++) { 570 if (kparam[i].perm == 0) 571 continue; 572 err = add_sysfs_param(&mod->mkobj, &kparam[i], kparam[i].name); 573 if (err) 574 return err; 575 params = true; 576 } 577 578 if (!params) 579 return 0; 580 581 /* Create the param group. */ 582 err = sysfs_create_group(&mod->mkobj.kobj, &mod->mkobj.mp->grp); 583 if (err) 584 free_module_param_attrs(&mod->mkobj); 585 return err; 586 } 587 588 /* 589 * module_param_sysfs_remove - remove sysfs support for one module 590 * @mod: module 591 * 592 * Remove sysfs entries for module parameters and the corresponding 593 * kobject. 594 */ 595 void module_param_sysfs_remove(struct module *mod) 596 { 597 if (mod->mkobj.mp) { 598 sysfs_remove_group(&mod->mkobj.kobj, &mod->mkobj.mp->grp); 599 /* We are positive that no one is using any param 600 * attrs at this point. Deallocate immediately. */ 601 free_module_param_attrs(&mod->mkobj); 602 } 603 } 604 #endif 605 606 void destroy_params(const struct kernel_param *params, unsigned num) 607 { 608 unsigned int i; 609 610 for (i = 0; i < num; i++) 611 if (params[i].flags & KPARAM_KMALLOCED) 612 kfree(*(char **)params[i].arg); 613 } 614 615 static void __init kernel_add_sysfs_param(const char *name, 616 struct kernel_param *kparam, 617 unsigned int name_skip) 618 { 619 struct module_kobject *mk; 620 struct kobject *kobj; 621 int err; 622 623 kobj = kset_find_obj(module_kset, name); 624 if (kobj) { 625 /* We already have one. Remove params so we can add more. */ 626 mk = to_module_kobject(kobj); 627 /* We need to remove it before adding parameters. */ 628 sysfs_remove_group(&mk->kobj, &mk->mp->grp); 629 } else { 630 mk = kzalloc(sizeof(struct module_kobject), GFP_KERNEL); 631 BUG_ON(!mk); 632 633 mk->mod = THIS_MODULE; 634 mk->kobj.kset = module_kset; 635 err = kobject_init_and_add(&mk->kobj, &module_ktype, NULL, 636 "%s", name); 637 if (err) { 638 kobject_put(&mk->kobj); 639 printk(KERN_ERR "Module '%s' failed add to sysfs, " 640 "error number %d\n", name, err); 641 printk(KERN_ERR "The system will be unstable now.\n"); 642 return; 643 } 644 /* So that exit path is even. */ 645 kobject_get(&mk->kobj); 646 } 647 648 /* These should not fail at boot. */ 649 err = add_sysfs_param(mk, kparam, kparam->name + name_skip); 650 BUG_ON(err); 651 err = sysfs_create_group(&mk->kobj, &mk->mp->grp); 652 BUG_ON(err); 653 kobject_uevent(&mk->kobj, KOBJ_ADD); 654 kobject_put(&mk->kobj); 655 } 656 657 /* 658 * param_sysfs_builtin - add contents in /sys/parameters for built-in modules 659 * 660 * Add module_parameters to sysfs for "modules" built into the kernel. 661 * 662 * The "module" name (KBUILD_MODNAME) is stored before a dot, the 663 * "parameter" name is stored behind a dot in kernel_param->name. So, 664 * extract the "module" name for all built-in kernel_param-eters, 665 * and for all who have the same, call kernel_add_sysfs_param. 666 */ 667 static void __init param_sysfs_builtin(void) 668 { 669 struct kernel_param *kp; 670 unsigned int name_len; 671 char modname[MODULE_NAME_LEN]; 672 673 for (kp = __start___param; kp < __stop___param; kp++) { 674 char *dot; 675 676 if (kp->perm == 0) 677 continue; 678 679 dot = strchr(kp->name, '.'); 680 if (!dot) { 681 /* This happens for core_param() */ 682 strcpy(modname, "kernel"); 683 name_len = 0; 684 } else { 685 name_len = dot - kp->name + 1; 686 strlcpy(modname, kp->name, name_len); 687 } 688 kernel_add_sysfs_param(modname, kp, name_len); 689 } 690 } 691 692 693 /* module-related sysfs stuff */ 694 695 static ssize_t module_attr_show(struct kobject *kobj, 696 struct attribute *attr, 697 char *buf) 698 { 699 struct module_attribute *attribute; 700 struct module_kobject *mk; 701 int ret; 702 703 attribute = to_module_attr(attr); 704 mk = to_module_kobject(kobj); 705 706 if (!attribute->show) 707 return -EIO; 708 709 ret = attribute->show(attribute, mk->mod, buf); 710 711 return ret; 712 } 713 714 static ssize_t module_attr_store(struct kobject *kobj, 715 struct attribute *attr, 716 const char *buf, size_t len) 717 { 718 struct module_attribute *attribute; 719 struct module_kobject *mk; 720 int ret; 721 722 attribute = to_module_attr(attr); 723 mk = to_module_kobject(kobj); 724 725 if (!attribute->store) 726 return -EIO; 727 728 ret = attribute->store(attribute, mk->mod, buf, len); 729 730 return ret; 731 } 732 733 static struct sysfs_ops module_sysfs_ops = { 734 .show = module_attr_show, 735 .store = module_attr_store, 736 }; 737 738 static int uevent_filter(struct kset *kset, struct kobject *kobj) 739 { 740 struct kobj_type *ktype = get_ktype(kobj); 741 742 if (ktype == &module_ktype) 743 return 1; 744 return 0; 745 } 746 747 static struct kset_uevent_ops module_uevent_ops = { 748 .filter = uevent_filter, 749 }; 750 751 struct kset *module_kset; 752 int module_sysfs_initialized; 753 754 struct kobj_type module_ktype = { 755 .sysfs_ops = &module_sysfs_ops, 756 }; 757 758 /* 759 * param_sysfs_init - wrapper for built-in params support 760 */ 761 static int __init param_sysfs_init(void) 762 { 763 module_kset = kset_create_and_add("module", &module_uevent_ops, NULL); 764 if (!module_kset) { 765 printk(KERN_WARNING "%s (%d): error creating kset\n", 766 __FILE__, __LINE__); 767 return -ENOMEM; 768 } 769 module_sysfs_initialized = 1; 770 771 param_sysfs_builtin(); 772 773 return 0; 774 } 775 subsys_initcall(param_sysfs_init); 776 777 #endif /* CONFIG_SYSFS */ 778 779 EXPORT_SYMBOL(param_set_byte); 780 EXPORT_SYMBOL(param_get_byte); 781 EXPORT_SYMBOL(param_set_short); 782 EXPORT_SYMBOL(param_get_short); 783 EXPORT_SYMBOL(param_set_ushort); 784 EXPORT_SYMBOL(param_get_ushort); 785 EXPORT_SYMBOL(param_set_int); 786 EXPORT_SYMBOL(param_get_int); 787 EXPORT_SYMBOL(param_set_uint); 788 EXPORT_SYMBOL(param_get_uint); 789 EXPORT_SYMBOL(param_set_long); 790 EXPORT_SYMBOL(param_get_long); 791 EXPORT_SYMBOL(param_set_ulong); 792 EXPORT_SYMBOL(param_get_ulong); 793 EXPORT_SYMBOL(param_set_charp); 794 EXPORT_SYMBOL(param_get_charp); 795 EXPORT_SYMBOL(param_set_bool); 796 EXPORT_SYMBOL(param_get_bool); 797 EXPORT_SYMBOL(param_set_invbool); 798 EXPORT_SYMBOL(param_get_invbool); 799 EXPORT_SYMBOL(param_array_set); 800 EXPORT_SYMBOL(param_array_get); 801 EXPORT_SYMBOL(param_set_copystring); 802 EXPORT_SYMBOL(param_get_string); 803