diff options
| author | Rob Landley <rob@landley.net> | 2005-11-15 00:08:29 +0000 |
|---|---|---|
| committer | Rob Landley <rob@landley.net> | 2005-11-15 00:08:29 +0000 |
| commit | 79e1cab0d16468b114ea93e53eb63b76b5d39b62 (patch) | |
| tree | 01661313c86e843b107b40aa78a3cfceed9c48c5 /modutils | |
| parent | 9033453c1849df49d2be39bca92c5b7cdb3234e3 (diff) | |
| download | busybox-w32-79e1cab0d16468b114ea93e53eb63b76b5d39b62.tar.gz busybox-w32-79e1cab0d16468b114ea93e53eb63b76b5d39b62.tar.bz2 busybox-w32-79e1cab0d16468b114ea93e53eb63b76b5d39b62.zip | |
Yann Morin's modprobe multiple options patch. There's more work to be done,
but let's ship 1.1 first...
Diffstat (limited to 'modutils')
| -rw-r--r-- | modutils/Config.in | 19 | ||||
| -rw-r--r-- | modutils/modprobe.c | 189 |
2 files changed, 186 insertions, 22 deletions
diff --git a/modutils/Config.in b/modutils/Config.in index 986b65c6a..bf19a3e67 100644 --- a/modutils/Config.in +++ b/modutils/Config.in | |||
| @@ -100,6 +100,25 @@ config CONFIG_MODPROBE | |||
| 100 | Handle the loading of modules, and their dependancies on a high | 100 | Handle the loading of modules, and their dependancies on a high |
| 101 | level. | 101 | level. |
| 102 | 102 | ||
| 103 | Note that, in the state it is, modprobe can pass only one option | ||
| 104 | to the modules it loads. See option below. | ||
| 105 | |||
| 106 | config CONFIG_MODPROBE_MULTIPLE_OPTIONS | ||
| 107 | bool "Multiple options parsing" | ||
| 108 | default y | ||
| 109 | depends on CONFIG_MODPROBE | ||
| 110 | help | ||
| 111 | Allow modprobe to understand more than one option to pass to | ||
| 112 | modules. | ||
| 113 | |||
| 114 | This is a WIP, while waiting for a common argument parsing | ||
| 115 | common amongst all BB applets (shell, modprobe, etc...) and | ||
| 116 | adds around 600 bytes on x86, 700 bytes on ARM. The code is | ||
| 117 | biggish and uggly, but just works. | ||
| 118 | |||
| 119 | Saying Y here is not a bad idea if you're not that short | ||
| 120 | on storage capacity. | ||
| 121 | |||
| 103 | config CONFIG_RMMOD | 122 | config CONFIG_RMMOD |
| 104 | bool "rmmod" | 123 | bool "rmmod" |
| 105 | default n | 124 | default n |
diff --git a/modutils/modprobe.c b/modutils/modprobe.c index 8d739ef3c..998c8668e 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c | |||
| @@ -6,20 +6,7 @@ | |||
| 6 | * Copyright (c) 2003 by Andrew Dennison, andrew.dennison@motec.com.au | 6 | * Copyright (c) 2003 by Andrew Dennison, andrew.dennison@motec.com.au |
| 7 | * Copyright (c) 2005 by Jim Bauer, jfbauer@nfr.com | 7 | * Copyright (c) 2005 by Jim Bauer, jfbauer@nfr.com |
| 8 | * | 8 | * |
| 9 | * This program is free software; you can redistribute it and/or modify | 9 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
| 10 | * it under the terms of the GNU General Public License as published by | ||
| 11 | * the Free Software Foundation; either version 2 of the License, or | ||
| 12 | * (at your option) any later version. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 17 | * General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License | ||
| 20 | * along with this program; if not, write to the Free Software | ||
| 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 22 | * | ||
| 23 | */ | 10 | */ |
| 24 | 11 | ||
| 25 | #include <sys/utsname.h> | 12 | #include <sys/utsname.h> |
| @@ -394,16 +381,139 @@ static int already_loaded (const char *name) | |||
| 394 | return 0; | 381 | return 0; |
| 395 | } | 382 | } |
| 396 | 383 | ||
| 384 | #ifdef CONFIG_MODPROBE_MULTIPLE_OPTIONS | ||
| 385 | /* static char* parse_command_string( char* src, char **dst ); | ||
| 386 | * src: pointer to string containing argument | ||
| 387 | * dst: pointer to where to store the parsed argument | ||
| 388 | * return value: the pointer to the first char after the parsed argument, | ||
| 389 | * NULL if there was no argument parsed (only trailing spaces). | ||
| 390 | * Note that memory is allocated with bb_xstrdup when a new argument was | ||
| 391 | * parsed. Don't forget to free it! | ||
| 392 | */ | ||
| 393 | #define ARG_EMPTY 0x00 | ||
| 394 | #define ARG_IN_DQUOTES 0x01 | ||
| 395 | #define ARG_IN_SQUOTES 0x02 | ||
| 396 | static char *parse_command_string( char *src, char **dst ) | ||
| 397 | { | ||
| 398 | int opt_status = ARG_EMPTY; | ||
| 399 | char* tmp_str; | ||
| 400 | |||
| 401 | /* Dumb you, I have nothing to do... */ | ||
| 402 | if( src == NULL ) return src; | ||
| 403 | |||
| 404 | /* Skip leading spaces */ | ||
| 405 | while( *src == ' ' ) { | ||
| 406 | src++; | ||
| 407 | } | ||
| 408 | /* Is the end of string reached? */ | ||
| 409 | if( *src == '\0' ) { | ||
| 410 | return NULL; | ||
| 411 | } | ||
| 412 | /* Reached the start of an argument | ||
| 413 | * By the way, we duplicate a little too much here :-/ but that's the easy way: | ||
| 414 | * cost effective wrt code, cost consumming wrt memory usage. */ | ||
| 415 | *dst = tmp_str = bb_xstrdup( src ); | ||
| 416 | /* Get to the end of that argument */ | ||
| 417 | while( ( *tmp_str != '\0' ) | ||
| 418 | && ( ( *tmp_str != ' ' ) | ||
| 419 | || ( opt_status & ( ARG_IN_DQUOTES | ARG_IN_SQUOTES ) ) ) ) { | ||
| 420 | switch( *tmp_str ) { | ||
| 421 | case '\'': | ||
| 422 | if( opt_status & ARG_IN_DQUOTES ) { | ||
| 423 | /* Already in double quotes, keep current char as is */ | ||
| 424 | } else { | ||
| 425 | /* shift left 1 char, until end of string: get rid of the opening/closing quotes */ | ||
| 426 | memmove( tmp_str, tmp_str + 1, strlen( tmp_str ) ); | ||
| 427 | /* mark me: we enter or leave single quotes */ | ||
| 428 | opt_status ^= ARG_IN_SQUOTES; | ||
| 429 | /* Back one char, as we need to re-scan the new char there. */ | ||
| 430 | tmp_str--; | ||
| 431 | } | ||
| 432 | break; | ||
| 433 | case '"': | ||
| 434 | if( opt_status & ARG_IN_SQUOTES ) { | ||
| 435 | /* Already in single quotes, keep current char as is */ | ||
| 436 | } else { | ||
| 437 | /* shift left 1 char, until end of string: get rid of the opening/closing quotes */ | ||
| 438 | memmove( tmp_str, tmp_str + 1, strlen( tmp_str ) ); | ||
| 439 | /* mark me: we enter or leave double quotes */ | ||
| 440 | opt_status ^= ARG_IN_DQUOTES; | ||
| 441 | /* Back one char, as we need to re-scan the new char there. */ | ||
| 442 | tmp_str--; | ||
| 443 | } | ||
| 444 | break; | ||
| 445 | case '\\': | ||
| 446 | if( opt_status & ARG_IN_SQUOTES ) { | ||
| 447 | /* Between single quotes: keep as is. */ | ||
| 448 | } else { | ||
| 449 | switch( *(tmp_str+1) ) { | ||
| 450 | case 'a': | ||
| 451 | case 'b': | ||
| 452 | case 't': | ||
| 453 | case 'n': | ||
| 454 | case 'v': | ||
| 455 | case 'f': | ||
| 456 | case 'r': | ||
| 457 | case '0': | ||
| 458 | /* We escaped a special character. For now, keep | ||
| 459 | * both the back-slash and the following char. */ | ||
| 460 | tmp_str++; src++; | ||
| 461 | break; | ||
| 462 | default: | ||
| 463 | /* We escaped a space or a single or double quote, | ||
| 464 | * or a back-slash, or a non-escapable char. Remove | ||
| 465 | * the '\' and keep the new current char as is. */ | ||
| 466 | memmove( tmp_str, tmp_str + 1, strlen( tmp_str ) ); | ||
| 467 | break; | ||
| 468 | } | ||
| 469 | } | ||
| 470 | break; | ||
| 471 | /* Any other char that is special shall appear here. | ||
| 472 | * Example: $ starts a variable | ||
| 473 | case '$': | ||
| 474 | do_variable_expansion(); | ||
| 475 | break; | ||
| 476 | * */ | ||
| 477 | default: | ||
| 478 | /* any other char is kept as is. */ | ||
| 479 | break; | ||
| 480 | } | ||
| 481 | tmp_str++; /* Go to next char */ | ||
| 482 | src++; /* Go to next char to find the end of the argument. */ | ||
| 483 | } | ||
| 484 | /* End of string, but still no ending quote */ | ||
| 485 | if( opt_status & ( ARG_IN_DQUOTES | ARG_IN_SQUOTES ) ) { | ||
| 486 | bb_error_msg_and_die( "unterminated (single or double) quote in options list: %s", src ); | ||
| 487 | } | ||
| 488 | *tmp_str = '\0'; | ||
| 489 | return src; | ||
| 490 | } | ||
| 491 | #endif /* CONFIG_MODPROBE_MULTIPLE_OPTIONS */ | ||
| 492 | |||
| 397 | static int mod_process ( struct mod_list_t *list, int do_insert ) | 493 | static int mod_process ( struct mod_list_t *list, int do_insert ) |
| 398 | { | 494 | { |
| 399 | int rc = 0; | 495 | int rc = 0; |
| 496 | #ifdef CONFIG_MODPROBE_MULTIPLE_OPTIONS | ||
| 497 | char **argv = NULL; | ||
| 498 | char *opts; | ||
| 499 | #ifdef CONFIG_FEATURE_CLEAN_UP | ||
| 500 | int argc_malloc; | ||
| 501 | #endif | ||
| 502 | #else /* CONFIG_MODPROBE_MULTIPLE_OPTIONS */ | ||
| 400 | char *argv[10]; | 503 | char *argv[10]; |
| 504 | #endif | ||
| 401 | int argc; | 505 | int argc; |
| 402 | 506 | ||
| 403 | while ( list ) { | 507 | while ( list ) { |
| 404 | argc = 0; | 508 | argc = 0; |
| 509 | #ifdef CONFIG_MODPROBE_MULTIPLE_OPTIONS | ||
| 510 | #ifdef CONFIG_FEATURE_CLEAN_UP | ||
| 511 | argc_malloc = 0; | ||
| 512 | #endif | ||
| 513 | argv = (char**) malloc( 6 * sizeof( char* ) ); /* enough for minimal insmod (5 args + NULL) or rmmod (3 args + NULL) */ | ||
| 514 | #endif | ||
| 405 | if ( do_insert ) { | 515 | if ( do_insert ) { |
| 406 | if (already_loaded (list->m_name) != 1) { | 516 | if (already_loaded (list->m_name) != 1) { |
| 407 | argv[argc++] = "insmod"; | 517 | argv[argc++] = "insmod"; |
| 408 | if (do_syslog) | 518 | if (do_syslog) |
| 409 | argv[argc++] = "-s"; | 519 | argv[argc++] = "-s"; |
| @@ -411,17 +521,34 @@ static int mod_process ( struct mod_list_t *list, int do_insert ) | |||
| 411 | argv[argc++] = "-k"; | 521 | argv[argc++] = "-k"; |
| 412 | if (quiet) | 522 | if (quiet) |
| 413 | argv[argc++] = "-q"; | 523 | argv[argc++] = "-q"; |
| 524 | else if(verbose) /* verbose and quiet are mutually exclusive */ | ||
| 525 | argv[argc++] = "-v"; | ||
| 414 | argv[argc++] = list-> m_path; | 526 | argv[argc++] = list-> m_path; |
| 527 | #ifdef CONFIG_MODPROBE_MULTIPLE_OPTIONS | ||
| 528 | #ifdef CONFIG_FEATURE_CLEAN_UP | ||
| 529 | argc_malloc = argc; | ||
| 530 | #endif | ||
| 531 | opts = list-> m_options; | ||
| 532 | while( ( opts = parse_command_string( opts, &(argv[argc]) ) ) != NULL ) { | ||
| 533 | /* Increase the argv array by 1 */ | ||
| 534 | argc++; | ||
| 535 | argv = (char**) xrealloc( argv, ( argc + 1 ) * sizeof( char* ) ); | ||
| 536 | } | ||
| 537 | #else /* CONFIG_MODPROBE_MULTIPLE_OPTIONS */ | ||
| 415 | if (list-> m_options) | 538 | if (list-> m_options) |
| 416 | argv[argc++] = list-> m_options; | 539 | argv[argc++] = list-> m_options; |
| 540 | #endif /* CONFIG_MODPROBE_MULTIPLE_OPTIONS */ | ||
| 417 | } | 541 | } |
| 418 | } else { | 542 | } else { |
| 419 | /* modutils uses short name for removal */ | 543 | /* modutils uses short name for removal */ |
| 420 | if (already_loaded (list->m_name) != 0) { | 544 | if (already_loaded (list->m_name) != 0) { |
| 421 | argv[argc++] = "rmmod"; | 545 | argv[argc++] = "rmmod"; |
| 422 | if (do_syslog) | 546 | if (do_syslog) |
| 423 | argv[argc++] = "-s"; | 547 | argv[argc++] = "-s"; |
| 424 | argv[argc++] = list->m_name; | 548 | argv[argc++] = list->m_name; |
| 549 | #if ( defined CONFIG_MODPROBE_MULTIPLE_OPTIONS ) && ( defined CONFIG_FEATURE_CLEAN_UP ) | ||
| 550 | argc_malloc = argc; | ||
| 551 | #endif | ||
| 425 | } | 552 | } |
| 426 | } | 553 | } |
| 427 | argv[argc] = NULL; | 554 | argv[argc] = NULL; |
| @@ -429,9 +556,9 @@ static int mod_process ( struct mod_list_t *list, int do_insert ) | |||
| 429 | if (argc) { | 556 | if (argc) { |
| 430 | if (verbose) { | 557 | if (verbose) { |
| 431 | int i; | 558 | int i; |
| 559 | printf("argc=%d\n", argc ); | ||
| 432 | for (i=0; i<argc; i++) | 560 | for (i=0; i<argc; i++) |
| 433 | printf("%s ", argv[i]); | 561 | printf("argv[%02d]=\"%s\"\n", i, argv[i]); |
| 434 | printf("\n"); | ||
| 435 | } | 562 | } |
| 436 | if (!show_only) { | 563 | if (!show_only) { |
| 437 | int rc2 = 0; | 564 | int rc2 = 0; |
| @@ -462,7 +589,27 @@ static int mod_process ( struct mod_list_t *list, int do_insert ) | |||
| 462 | rc = 0; /* success if remove any mod */ | 589 | rc = 0; /* success if remove any mod */ |
| 463 | } | 590 | } |
| 464 | } | 591 | } |
| 592 | #if ( defined CONFIG_MODPROBE_MULTIPLE_OPTIONS ) && ( defined CONFIG_FEATURE_CLEAN_UP ) | ||
| 593 | /* the last value in the array has index == argc, but | ||
| 594 | * it is the terminatign NULL, so we must not free it. */ | ||
| 595 | while( argc_malloc < argc ) { | ||
| 596 | free( argv[argc_malloc++] ); | ||
| 597 | } | ||
| 465 | } | 598 | } |
| 599 | free( argv ); | ||
| 600 | /* If CONFIG_FEATURE_CLEAN_UP is not defined, then we leak memory | ||
| 601 | * here. But it is (quite) small amounts of memory that leak each | ||
| 602 | * time a module is loaded, and it is reclaimed when modprobe | ||
| 603 | * exits anyway. | ||
| 604 | * This could become a problem when loading a module with LOTS of | ||
| 605 | * dependencies, with LOTS of options for each dependencies, with | ||
| 606 | * very little memory on the target... But in that case, the module | ||
| 607 | * would not load because there is no more memory, so there's no | ||
| 608 | * problem. Hmm, wait... Is this true, whatever the allocation policy? */ | ||
| 609 | argv = NULL; | ||
| 610 | #else /* CONFIG_MODPROBE_MULTIPLE_OPTIONS && CONFIG_FEATURE_CLEAN_UP */ | ||
| 611 | } | ||
| 612 | #endif | ||
| 466 | list = do_insert ? list-> m_prev : list-> m_next; | 613 | list = do_insert ? list-> m_prev : list-> m_next; |
| 467 | } | 614 | } |
| 468 | return (show_only) ? 0 : rc; | 615 | return (show_only) ? 0 : rc; |
| @@ -557,8 +704,6 @@ static void check_dep ( char *mod, struct mod_list_t **head, struct mod_list_t * | |||
| 557 | } | 704 | } |
| 558 | } | 705 | } |
| 559 | 706 | ||
| 560 | |||
| 561 | |||
| 562 | static int mod_insert ( char *mod, int argc, char **argv ) | 707 | static int mod_insert ( char *mod, int argc, char **argv ) |
| 563 | { | 708 | { |
| 564 | struct mod_list_t *tail = 0; | 709 | struct mod_list_t *tail = 0; |
| @@ -645,7 +790,7 @@ extern int modprobe_main(int argc, char** argv) | |||
| 645 | show_only++; | 790 | show_only++; |
| 646 | break; | 791 | break; |
| 647 | case 'q': | 792 | case 'q': |
| 648 | quiet++; | 793 | quiet++; verbose=0; |
| 649 | break; | 794 | break; |
| 650 | case 'r': | 795 | case 'r': |
| 651 | remove_opt++; | 796 | remove_opt++; |
| @@ -654,7 +799,7 @@ extern int modprobe_main(int argc, char** argv) | |||
| 654 | do_syslog++; | 799 | do_syslog++; |
| 655 | break; | 800 | break; |
| 656 | case 'v': | 801 | case 'v': |
| 657 | verbose++; | 802 | verbose++; quiet=0; |
| 658 | break; | 803 | break; |
| 659 | case 'V': | 804 | case 'V': |
| 660 | default: | 805 | default: |
