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 /* 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 233 int 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. */ 239 int 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 265 int 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. */ 278 int 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 292 int 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. */ 298 static 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 353 int 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 363 int 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 383 int 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 400 int 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 410 extern struct kernel_param __start___param[], __stop___param[]; 411 412 struct param_attribute 413 { 414 struct module_attribute mattr; 415 struct kernel_param *param; 416 }; 417 418 struct 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 428 static 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. */ 446 static 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 */ 480 static __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 537 fail_free_new: 538 kfree(new); 539 fail: 540 mk->mp = NULL; 541 return err; 542 } 543 544 #ifdef CONFIG_MODULES 545 static 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 */ 561 int 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 */ 594 void 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 605 void destroy_params(const struct kernel_param *params, unsigned num) 606 { 607 /* FIXME: This should free kmalloced charp parameters. It doesn't. */ 608 } 609 610 static 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 */ 662 static 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 690 static 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 709 static 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 728 static struct sysfs_ops module_sysfs_ops = { 729 .show = module_attr_show, 730 .store = module_attr_store, 731 }; 732 733 static 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 742 static struct kset_uevent_ops module_uevent_ops = { 743 .filter = uevent_filter, 744 }; 745 746 struct kset *module_kset; 747 int module_sysfs_initialized; 748 749 struct kobj_type module_ktype = { 750 .sysfs_ops = &module_sysfs_ops, 751 }; 752 753 /* 754 * param_sysfs_init - wrapper for built-in params support 755 */ 756 static 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 } 770 subsys_initcall(param_sysfs_init); 771 772 #endif /* CONFIG_SYSFS */ 773 774 EXPORT_SYMBOL(param_set_byte); 775 EXPORT_SYMBOL(param_get_byte); 776 EXPORT_SYMBOL(param_set_short); 777 EXPORT_SYMBOL(param_get_short); 778 EXPORT_SYMBOL(param_set_ushort); 779 EXPORT_SYMBOL(param_get_ushort); 780 EXPORT_SYMBOL(param_set_int); 781 EXPORT_SYMBOL(param_get_int); 782 EXPORT_SYMBOL(param_set_uint); 783 EXPORT_SYMBOL(param_get_uint); 784 EXPORT_SYMBOL(param_set_long); 785 EXPORT_SYMBOL(param_get_long); 786 EXPORT_SYMBOL(param_set_ulong); 787 EXPORT_SYMBOL(param_get_ulong); 788 EXPORT_SYMBOL(param_set_charp); 789 EXPORT_SYMBOL(param_get_charp); 790 EXPORT_SYMBOL(param_set_bool); 791 EXPORT_SYMBOL(param_get_bool); 792 EXPORT_SYMBOL(param_set_invbool); 793 EXPORT_SYMBOL(param_get_invbool); 794 EXPORT_SYMBOL(param_array_set); 795 EXPORT_SYMBOL(param_array_get); 796 EXPORT_SYMBOL(param_set_copystring); 797 EXPORT_SYMBOL(param_get_string); 798