From e9190962719e6a41a1423208125bc2a173dac1ae Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Mon, 12 Dec 2005 19:38:44 +0000 Subject: [PATCH] Patch from Yann E. Morin, something to do with bugs 276 and 272. --- modutils/modprobe.c | 505 ++++++++++++++++++++++++-------------------- 1 file changed, 273 insertions(+), 232 deletions(-) diff --git a/modutils/modprobe.c b/modutils/modprobe.c index 74fadc326..96b442cab 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c @@ -5,6 +5,8 @@ * Copyright (c) 2002 by Robert Griebl, griebl@gmx.de * Copyright (c) 2003 by Andrew Dennison, andrew.dennison@motec.com.au * Copyright (c) 2005 by Jim Bauer, jfbauer@nfr.com + * + * Portions Copyright (c) 2005 by Yann E. MORIN, yann.morin.1998@anciens.enib.fr * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ @@ -21,26 +23,31 @@ #include #include "busybox.h" +struct mod_opt_t { /* one-way list of options to pass to a module */ + char * m_opt_val; + struct mod_opt_t * m_next; +}; +struct dep_t { /* one-way list of dependency rules */ + /* a dependency rule */ + char * m_name; /* the module name*/ + char * m_path; /* the module file path */ + struct mod_opt_t * m_options; /* the module options */ + + int m_isalias : 1; /* the module is an alias */ + int m_reserved : 15; /* stuffin' */ -struct dep_t { - char * m_name; - char * m_path; - char * m_options; - - int m_isalias : 1; - int m_reserved : 15; - - int m_depcnt : 16; - char ** m_deparr; + int m_depcnt : 16; /* the number of dependable module(s) */ + char ** m_deparr; /* the list of dependable module(s) */ - struct dep_t * m_next; + struct dep_t * m_next; /* the next dependency rule */ }; -struct mod_list_t { +struct mod_list_t { /* two-way list of modules to process */ + /* a module description */ char * m_name; char * m_path; - char * m_options; + struct mod_opt_t * m_options; struct mod_list_t * m_prev; struct mod_list_t * m_next; @@ -49,7 +56,6 @@ struct mod_list_t { static struct dep_t *depend; static int autoclean, show_only, quiet, do_syslog, verbose; -static int k_version; static int parse_tag_value ( char *buffer, char **ptag, char **pvalue ) { @@ -101,6 +107,144 @@ static char *reads ( int fd, char *buffer, size_t len ) return 0; } +/* + * This function appends an option to a list + */ +struct mod_opt_t *append_option( struct mod_opt_t *opt_list, char *opt ) +{ + struct mod_opt_t *ol = opt_list; + + if( ol ) { + while( ol-> m_next ) { + ol = ol-> m_next; + } + ol-> m_next = xmalloc( sizeof( struct mod_opt_t ) ); + ol = ol-> m_next; + } else { + ol = opt_list = xmalloc( sizeof( struct mod_opt_t ) ); + } + + ol-> m_opt_val = bb_xstrdup( opt ); + ol-> m_next = NULL; + + return opt_list; +} + +#if (defined CONFIG_FEATURE_MODPROBE_MULTIPLE_OPTIONS) +/* static char* parse_command_string( char* src, char **dst ); + * src: pointer to string containing argument + * dst: pointer to where to store the parsed argument + * return value: the pointer to the first char after the parsed argument, + * NULL if there was no argument parsed (only trailing spaces). + * Note that memory is allocated with bb_xstrdup when a new argument was + * parsed. Don't forget to free it! + */ +#define ARG_EMPTY 0x00 +#define ARG_IN_DQUOTES 0x01 +#define ARG_IN_SQUOTES 0x02 +static char *parse_command_string( char *src, char **dst ) +{ + int opt_status = ARG_EMPTY; + char* tmp_str; + + /* Dumb you, I have nothing to do... */ + if( src == NULL ) return src; + + /* Skip leading spaces */ + while( *src == ' ' ) { + src++; + } + /* Is the end of string reached? */ + if( *src == '\0' ) { + return NULL; + } + /* Reached the start of an argument + * By the way, we duplicate a little too much + * here but what is too much is freed later. */ + *dst = tmp_str = bb_xstrdup( src ); + /* Get to the end of that argument */ + while( ( *tmp_str != '\0' ) + && ( ( *tmp_str != ' ' ) + || ( opt_status & ( ARG_IN_DQUOTES | ARG_IN_SQUOTES ) ) ) ) { + switch( *tmp_str ) { + case '\'': + if( opt_status & ARG_IN_DQUOTES ) { + /* Already in double quotes, keep current char as is */ + } else { + /* shift left 1 char, until end of string: get rid of the opening/closing quotes */ + memmove( tmp_str, tmp_str + 1, strlen( tmp_str ) ); + /* mark me: we enter or leave single quotes */ + opt_status ^= ARG_IN_SQUOTES; + /* Back one char, as we need to re-scan the new char there. */ + tmp_str--; + } + break; + case '"': + if( opt_status & ARG_IN_SQUOTES ) { + /* Already in single quotes, keep current char as is */ + } else { + /* shift left 1 char, until end of string: get rid of the opening/closing quotes */ + memmove( tmp_str, tmp_str + 1, strlen( tmp_str ) ); + /* mark me: we enter or leave double quotes */ + opt_status ^= ARG_IN_DQUOTES; + /* Back one char, as we need to re-scan the new char there. */ + tmp_str--; + } + break; + case '\\': + if( opt_status & ARG_IN_SQUOTES ) { + /* Between single quotes: keep as is. */ + } else { + switch( *(tmp_str+1) ) { + case 'a': + case 'b': + case 't': + case 'n': + case 'v': + case 'f': + case 'r': + case '0': + /* We escaped a special character. For now, keep + * both the back-slash and the following char. */ + tmp_str++; src++; + break; + default: + /* We escaped a space or a single or double quote, + * or a back-slash, or a non-escapable char. Remove + * the '\' and keep the new current char as is. */ + memmove( tmp_str, tmp_str + 1, strlen( tmp_str ) ); + break; + } + } + break; + /* Any other char that is special shall appear here. + * Example: $ starts a variable + case '$': + do_variable_expansion(); + break; + * */ + default: + /* any other char is kept as is. */ + break; + } + tmp_str++; /* Go to next char */ + src++; /* Go to next char to find the end of the argument. */ + } + /* End of string, but still no ending quote */ + if( opt_status & ( ARG_IN_DQUOTES | ARG_IN_SQUOTES ) ) { + bb_error_msg_and_die( "unterminated (single or double) quote in options list: %s", src ); + } + *tmp_str = '\0'; + *dst = xrealloc( *dst, strlen( *dst ) ); + return src; +} +#endif /* CONFIG_FEATURE_MODPROBE_MULTIPLE_OPTIONS */ + +/* + * This function builds a list of dependency rules from /lib/modules/`uname -r\modules.dep. + * It then fills every modules and aliases with their default options, found by parsing + * modprobe.conf (or modules.conf, or conf.modules). + */ static struct dep_t *build_dep ( void ) { int fd; @@ -110,10 +254,11 @@ static struct dep_t *build_dep ( void ) char buffer[2048]; char *filename = buffer; int continuation_line = 0; + int k_version; k_version = 0; if ( uname ( &un )) - return 0; + bb_error_msg_and_die("can't determine kernel version"); // check for buffer overflow in following code if ( bb_strlen ( un.release ) > ( sizeof( buffer ) - 64 )) { @@ -149,37 +294,43 @@ static struct dep_t *build_dep ( void ) continue; } + /* Is this a new module dep description? */ if ( !continuation_line ) { + /* find the dep begining */ char *col = strchr ( buffer, ':' ); char *dot = col; if ( col ) { + /* This line is a dep description */ char *mods; char *modpath; char *mod; + /* Find the beginning of the module file name */ *col = 0; mods = strrchr ( buffer, '/' ); if ( !mods ) - mods = buffer; + mods = buffer; /* no path for this module */ else - mods++; + mods++; /* there was a path for this module... */ - modpath = strchr ( buffer, '/' ); + /* find the path of the module */ + modpath = strchr ( buffer, '/' ); /* ... and this is the path */ if ( !modpath ) - modpath = buffer; -#if defined(CONFIG_FEATURE_2_6_MODULES) - if ((k_version > 4) && ( *(col-3) == '.' ) && - ( *(col-2) == 'k' ) && ( *(col-1) == 'o' )) + modpath = buffer; /* module with no path */ + /* find the end of the module name in the file name */ + if ( ENABLE_FEATURE_2_6_MODULES && + (k_version > 4) && ( *(col-3) == '.' ) && + ( *(col-2) == 'k' ) && ( *(col-1) == 'o' ) ) dot = col - 3; else -#endif if (( *(col-2) == '.' ) && ( *(col-1) == 'o' )) dot = col - 2; mod = bb_xstrndup ( mods, dot - mods ); + /* enqueue new module */ if ( !current ) { first = current = (struct dep_t *) xmalloc ( sizeof ( struct dep_t )); } @@ -189,24 +340,26 @@ static struct dep_t *build_dep ( void ) } current-> m_name = mod; current-> m_path = bb_xstrdup(modpath); - current-> m_options = 0; + current-> m_options = NULL; current-> m_isalias = 0; current-> m_depcnt = 0; current-> m_deparr = 0; current-> m_next = 0; - //printf ( "%s:\n", mod ); p = col + 1; } else + /* this line is not a dep description */ p = 0; } else + /* It's a dep description continuation */ p = buffer; while ( p && *p && isblank(*p)) p++; + /* p points to the first dependable module; if NULL, no dependable module */ if ( p && *p ) { char *end = &buffer [l-1]; char *deps; @@ -219,6 +372,7 @@ static struct dep_t *build_dep ( void ) do { + /* search the end of the dependency */ next = strchr (p, ' ' ); if (next) { @@ -228,6 +382,7 @@ static struct dep_t *build_dep ( void ) else next = end; + /* find the begining of the module file name */ deps = strrchr ( p, '/' ); if ( !deps || ( deps < p )) { @@ -239,12 +394,12 @@ static struct dep_t *build_dep ( void ) else deps++; -#if defined(CONFIG_FEATURE_2_6_MODULES) - if ((k_version > 4) && ( *(next-2) == '.' ) && *(next-1) == 'k' && - ( *next == 'o' )) + /* find the end of the module name in the file name */ + if ( ENABLE_FEATURE_2_6_MODULES && + (k_version > 4) && ( *(next-2) == '.' ) && + ( *(next-1) == 'k' ) && ( *next == 'o' ) ) ext = 3; else -#endif if (( *(next-1) == '.' ) && ( *next == 'o' )) ext = 2; @@ -253,16 +408,17 @@ static struct dep_t *build_dep ( void ) continue; dep = bb_xstrndup ( deps, next - deps - ext + 1 ); + /* Add the new dependable module name */ current-> m_depcnt++; current-> m_deparr = (char **) xrealloc ( current-> m_deparr, sizeof ( char *) * current-> m_depcnt ); current-> m_deparr [current-> m_depcnt - 1] = dep; - //printf ( " %d) %s\n", current-> m_depcnt, current-> m_deparr [current-> m_depcnt -1] ); p = next + 2; } while (next < end); } + /* is there other dependable module(s) ? */ if ( buffer [l-1] == '\\' ) continuation_line = 1; else @@ -305,8 +461,7 @@ static struct dep_t *build_dep ( void ) char *alias, *mod; if ( parse_tag_value ( buffer + 6, &alias, &mod )) { - // fprintf ( stderr, "ALIAS: '%s' -> '%s'\n", alias, mod ); - + /* handle alias as a module dependent on the aliased module */ if ( !current ) { first = current = (struct dep_t *) xcalloc ( 1, sizeof ( struct dep_t )); } @@ -332,18 +487,24 @@ static struct dep_t *build_dep ( void ) else if (( strncmp ( buffer, "options", 7 ) == 0 ) && isspace ( buffer [7] )) { char *mod, *opt; + /* split the line in the module/alias name, and options */ if ( parse_tag_value ( buffer + 8, &mod, &opt )) { struct dep_t *dt; + /* find the corresponding module */ for ( dt = first; dt; dt = dt-> m_next ) { if ( strcmp ( dt-> m_name, mod ) == 0 ) break; } if ( dt ) { - dt-> m_options = xrealloc ( dt-> m_options, bb_strlen( opt ) + 1 ); - strcpy ( dt-> m_options, opt ); - - // fprintf ( stderr, "OPTION: '%s' -> '%s'\n", dt-> m_name, dt-> m_options ); + if ( CONFIG_FEATURE_MODPROBE_MULTIPLE_OPTIONS ) { + char* new_opt = NULL; + while( ( opt = parse_command_string( opt, &new_opt ) ) ) { + dt-> m_options = append_option( dt-> m_options, new_opt ); + } + } else { + dt-> m_options = append_option( dt-> m_options, opt ); + } } } } @@ -370,6 +531,9 @@ static int already_loaded (const char *name) p = strchr (buffer, ' '); if (p) { *p = 0; + for( p = buffer; ENABLE_FEATURE_2_6_MODULES && *p; p++ ) { + *p = ((*p)=='-')?'_':*p; + } if (strcmp (name, buffer) == 0) { close (fd); return 1; @@ -381,137 +545,30 @@ static int already_loaded (const char *name) return 0; } -#ifdef CONFIG_FEATURE_MODPROBE_MULTIPLE_OPTIONS -/* static char* parse_command_string( char* src, char **dst ); - * src: pointer to string containing argument - * dst: pointer to where to store the parsed argument - * return value: the pointer to the first char after the parsed argument, - * NULL if there was no argument parsed (only trailing spaces). - * Note that memory is allocated with bb_xstrdup when a new argument was - * parsed. Don't forget to free it! - */ -#define ARG_EMPTY 0x00 -#define ARG_IN_DQUOTES 0x01 -#define ARG_IN_SQUOTES 0x02 -static char *parse_command_string( char *src, char **dst ) -{ - int opt_status = ARG_EMPTY; - char* tmp_str; - - /* Dumb you, I have nothing to do... */ - if( src == NULL ) return src; - - /* Skip leading spaces */ - while( *src == ' ' ) { - src++; - } - /* Is the end of string reached? */ - if( *src == '\0' ) { - return NULL; - } - /* Reached the start of an argument - * By the way, we duplicate a little too much here :-/ but that's the easy way: - * cost effective wrt code, cost consumming wrt memory usage. */ - *dst = tmp_str = bb_xstrdup( src ); - /* Get to the end of that argument */ - while( ( *tmp_str != '\0' ) - && ( ( *tmp_str != ' ' ) - || ( opt_status & ( ARG_IN_DQUOTES | ARG_IN_SQUOTES ) ) ) ) { - switch( *tmp_str ) { - case '\'': - if( opt_status & ARG_IN_DQUOTES ) { - /* Already in double quotes, keep current char as is */ - } else { - /* shift left 1 char, until end of string: get rid of the opening/closing quotes */ - memmove( tmp_str, tmp_str + 1, strlen( tmp_str ) ); - /* mark me: we enter or leave single quotes */ - opt_status ^= ARG_IN_SQUOTES; - /* Back one char, as we need to re-scan the new char there. */ - tmp_str--; - } - break; - case '"': - if( opt_status & ARG_IN_SQUOTES ) { - /* Already in single quotes, keep current char as is */ - } else { - /* shift left 1 char, until end of string: get rid of the opening/closing quotes */ - memmove( tmp_str, tmp_str + 1, strlen( tmp_str ) ); - /* mark me: we enter or leave double quotes */ - opt_status ^= ARG_IN_DQUOTES; - /* Back one char, as we need to re-scan the new char there. */ - tmp_str--; - } - break; - case '\\': - if( opt_status & ARG_IN_SQUOTES ) { - /* Between single quotes: keep as is. */ - } else { - switch( *(tmp_str+1) ) { - case 'a': - case 'b': - case 't': - case 'n': - case 'v': - case 'f': - case 'r': - case '0': - /* We escaped a special character. For now, keep - * both the back-slash and the following char. */ - tmp_str++; src++; - break; - default: - /* We escaped a space or a single or double quote, - * or a back-slash, or a non-escapable char. Remove - * the '\' and keep the new current char as is. */ - memmove( tmp_str, tmp_str + 1, strlen( tmp_str ) ); - break; - } - } - break; - /* Any other char that is special shall appear here. - * Example: $ starts a variable - case '$': - do_variable_expansion(); - break; - * */ - default: - /* any other char is kept as is. */ - break; - } - tmp_str++; /* Go to next char */ - src++; /* Go to next char to find the end of the argument. */ - } - /* End of string, but still no ending quote */ - if( opt_status & ( ARG_IN_DQUOTES | ARG_IN_SQUOTES ) ) { - bb_error_msg_and_die( "unterminated (single or double) quote in options list: %s", src ); - } - *tmp_str = '\0'; - return src; -} -#endif /* CONFIG_FEATURE_MODPROBE_MULTIPLE_OPTIONS */ - static int mod_process ( struct mod_list_t *list, int do_insert ) { int rc = 0; -#ifdef CONFIG_FEATURE_MODPROBE_MULTIPLE_OPTIONS char **argv = NULL; - char *opts; -#ifdef CONFIG_FEATURE_CLEAN_UP - int argc_malloc; -#endif -#else /* CONFIG_FEATURE_MODPROBE_MULTIPLE_OPTIONS */ - char *argv[10]; -#endif + struct mod_opt_t *opts; + int argc_malloc; /* never used when CONFIG_FEATURE_CLEAN_UP not defined */ int argc; while ( list ) { argc = 0; -#ifdef CONFIG_FEATURE_MODPROBE_MULTIPLE_OPTIONS -#ifdef CONFIG_FEATURE_CLEAN_UP - argc_malloc = 0; -#endif - argv = (char**) malloc( 6 * sizeof( char* ) ); /* enough for minimal insmod (5 args + NULL) or rmmod (3 args + NULL) */ -#endif + if( ENABLE_FEATURE_CLEAN_UP ) + argc_malloc = 0; + /* If CONFIG_FEATURE_CLEAN_UP is not defined, then we leak memory + * each time we allocate memory for argv. + * But it is (quite) small amounts of memory that leak each + * time a module is loaded, and it is reclaimed when modprobe + * exits anyway (even when standalone shell?). + * This could become a problem when loading a module with LOTS of + * dependencies, with LOTS of options for each dependencies, with + * very little memory on the target... But in that case, the module + * would not load because there is no more memory, so there's no + * problem. */ + /* enough for minimal insmod (5 args + NULL) or rmmod (3 args + NULL) */ + argv = (char**) malloc( 6 * sizeof( char* ) ); if ( do_insert ) { if (already_loaded (list->m_name) != 1) { argv[argc++] = "insmod"; @@ -524,20 +581,16 @@ static int mod_process ( struct mod_list_t *list, int do_insert ) else if(verbose) /* verbose and quiet are mutually exclusive */ argv[argc++] = "-v"; argv[argc++] = list-> m_path; -#ifdef CONFIG_FEATURE_MODPROBE_MULTIPLE_OPTIONS -#ifdef CONFIG_FEATURE_CLEAN_UP - argc_malloc = argc; -#endif + if( ENABLE_FEATURE_CLEAN_UP ) + argc_malloc = argc; opts = list-> m_options; - while( ( opts = parse_command_string( opts, &(argv[argc]) ) ) != NULL ) { - /* Increase the argv array by 1 */ + while( opts ) { + /* Add one more option */ argc++; argv = (char**) xrealloc( argv, ( argc + 1 ) * sizeof( char* ) ); + argv[argc-1] = opts-> m_opt_val; + opts = opts-> m_next; } -#else /* CONFIG_FEATURE_MODPROBE_MULTIPLE_OPTIONS */ - if (list-> m_options) - argv[argc++] = list-> m_options; -#endif /* CONFIG_FEATURE_MODPROBE_MULTIPLE_OPTIONS */ } } else { /* modutils uses short name for removal */ @@ -546,19 +599,15 @@ static int mod_process ( struct mod_list_t *list, int do_insert ) if (do_syslog) argv[argc++] = "-s"; argv[argc++] = list->m_name; -#if ( defined CONFIG_FEATURE_MODPROBE_MULTIPLE_OPTIONS ) && ( defined CONFIG_FEATURE_CLEAN_UP ) - argc_malloc = argc; -#endif + if( ENABLE_FEATURE_CLEAN_UP ) + argc_malloc = argc; } } argv[argc] = NULL; if (argc) { if (verbose) { - int i; - printf("argc=%d\n", argc ); - for (i=0; i m_name ); } if (!show_only) { int rc2 = 0; @@ -589,51 +638,48 @@ static int mod_process ( struct mod_list_t *list, int do_insert ) rc = 0; /* success if remove any mod */ } } -#if ( defined CONFIG_FEATURE_MODPROBE_MULTIPLE_OPTIONS ) && ( defined CONFIG_FEATURE_CLEAN_UP ) - /* the last value in the array has index == argc, but - * it is the terminatign NULL, so we must not free it. */ - while( argc_malloc < argc ) { - free( argv[argc_malloc++] ); + if( ENABLE_FEATURE_CLEAN_UP ) + /* the last value in the array has index == argc, but + * it is the terminating NULL, so we must not free it. */ + while( argc_malloc < argc ) { + free( argv[argc_malloc++] ); } } - free( argv ); - /* If CONFIG_FEATURE_CLEAN_UP is not defined, then we leak memory - * here. But it is (quite) small amounts of memory that leak each - * time a module is loaded, and it is reclaimed when modprobe - * exits anyway. - * This could become a problem when loading a module with LOTS of - * dependencies, with LOTS of options for each dependencies, with - * very little memory on the target... But in that case, the module - * would not load because there is no more memory, so there's no - * problem. Hmm, wait... Is this true, whatever the allocation policy? */ - argv = NULL; -#else /* CONFIG_FEATURE_MODPROBE_MULTIPLE_OPTIONS && CONFIG_FEATURE_CLEAN_UP */ + if( ENABLE_FEATURE_CLEAN_UP ) { + free( argv ); + argv = NULL; } -#endif list = do_insert ? list-> m_prev : list-> m_next; } return (show_only) ? 0 : rc; } +/* + * Builds the dependency list (aka stack) of a module. + * head: the highest module in the stack (last to insmod, first to rmmod) + * tail: the lowest module in the stack (first to insmod, last to rmmod) + */ static void check_dep ( char *mod, struct mod_list_t **head, struct mod_list_t **tail ) { struct mod_list_t *find; struct dep_t *dt; - char *opt = 0; + struct mod_opt_t *opt = 0; char *path = 0; // check dependencies for ( dt = depend; dt; dt = dt-> m_next ) { if ( strcmp ( dt-> m_name, mod ) == 0) { - mod = dt-> m_name; - path = dt-> m_path; - opt = dt-> m_options; break; } } + if( !dt ) { + bb_error_msg ("module %s not found.", mod); + return; + } + // resolve alias names - while ( dt && dt-> m_isalias ) { + while ( dt-> m_isalias ) { if ( dt-> m_depcnt == 1 ) { struct dep_t *adt; @@ -642,24 +688,30 @@ static void check_dep ( char *mod, struct mod_list_t **head, struct mod_list_t * break; } if ( adt ) { + /* This is the module we are aliased to */ + struct mod_opt_t *opts = dt-> m_options; + /* Option of the alias are appended to the options of the module */ + while( opts ) { + adt-> m_options = append_option( adt-> m_options, opts-> m_opt_val ); + opts = opts-> m_next; + } dt = adt; - mod = dt-> m_name; - path = dt-> m_path; - if ( !opt ) - opt = dt-> m_options; } - else + else { + bb_error_msg ("module %s not found.", mod); return; + } } - else + else { + bb_error_msg ("Bad alias %s", dt-> m_name); return; + } } - if ( !path ) { - bb_error_msg ("module %s not found.", mod); - return; - } - + mod = dt-> m_name; + path = dt-> m_path; + opt = dt-> m_options; + // search for duplicates for ( find = *head; find; find = find-> m_next ) { if ( !strcmp ( mod, find-> m_name )) { @@ -699,6 +751,7 @@ static void check_dep ( char *mod, struct mod_list_t **head, struct mod_list_t * if ( dt ) { int i; + /* Add all dependable module for that new module */ for ( i = 0; i < dt-> m_depcnt; i++ ) check_dep ( dt-> m_deparr [i], head, tail ); } @@ -714,24 +767,12 @@ static int mod_insert ( char *mod, int argc, char **argv ) check_dep ( mod, &head, &tail ); if ( head && tail ) { -#if defined(CONFIG_FEATURE_2_6_MODULES) - if ( argc ) { + if( argc ) { int i; - int l = 0; - // append module args for ( i = 0; i < argc; i++ ) - l += ( bb_strlen ( argv [i] ) + 1 ); - - head-> m_options = xrealloc ( head-> m_options, l + 1 ); - head-> m_options [0] = 0; - - for ( i = 0; i < argc; i++ ) { - strcat ( head-> m_options, argv [i] ); - strcat ( head-> m_options, " " ); - } + head->m_options = append_option( head->m_options, argv[i] ); } -#endif // process tail ---> head rc = mod_process ( tail, 1 ); @@ -766,6 +807,7 @@ static int mod_remove ( char *mod ) extern int modprobe_main(int argc, char** argv) { int opt; + int rc = EXIT_SUCCESS; int remove_opt = 0; autoclean = show_only = quiet = do_syslog = verbose = 0; @@ -814,7 +856,6 @@ extern int modprobe_main(int argc, char** argv) bb_error_msg_and_die ( "could not parse modules.dep\n" ); if (remove_opt) { - int rc = EXIT_SUCCESS; do { if (mod_remove ( optind < argc ? bb_xstrdup (argv [optind]) : NULL )) { @@ -823,15 +864,15 @@ extern int modprobe_main(int argc, char** argv) rc = EXIT_FAILURE; } } while ( ++optind < argc ); + } else { + if (optind >= argc) + bb_error_msg_and_die ( "No module or pattern provided\n" ); - return rc; + if ( mod_insert ( bb_xstrdup ( argv [optind] ), argc - optind - 1, argv + optind + 1 )) + bb_error_msg_and_die ( "failed to load module %s", argv [optind] ); } - if (optind >= argc) - bb_error_msg_and_die ( "No module or pattern provided\n" ); + /* Here would be a good place to free up memory allocated during the dependencies build. */ - if ( mod_insert ( bb_xstrdup ( argv [optind] ), argc - optind - 1, argv + optind + 1 )) - bb_error_msg_and_die ( "failed to load module %s", argv [optind] ); - - return EXIT_SUCCESS; + return rc; } -- 2.25.1