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