X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=modutils%2Fmodprobe.c;h=59c06ee1ed7bfffd4ca782a8297525b70b08ce4f;hb=e2e56c7c4129de7d20df42e8239fd304c81ef29b;hp=844eb99c5ee3d36a95b3939ca9158fa62a2b4697;hpb=199501f2a00956265a5dba74ea01badab6c331ac;p=oweals%2Fbusybox.git diff --git a/modutils/modprobe.c b/modutils/modprobe.c index 844eb99c5..59c06ee1e 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c @@ -55,7 +55,30 @@ struct mod_list_t { /* two-way list of modules to process */ static struct dep_t *depend; -static int autoclean, show_only, quiet, do_syslog, verbose; + +#define main_options "acdklnqrst:vVC:" +#define INSERT_ALL 1 /* a */ +#define DUMP_CONF_EXIT 2 /* c */ +#define D_OPT_IGNORED 4 /* d */ +#define AUTOCLEAN_FLG 8 /* k */ +#define LIST_ALL 16 /* l */ +#define SHOW_ONLY 32 /* n */ +#define QUIET 64 /* q */ +#define REMOVE_OPT 128 /* r */ +#define DO_SYSLOG 256 /* s */ +#define RESTRICT_DIR 512 /* t */ +#define VERBOSE 1024 /* v */ +#define VERSION_ONLY 2048 /* V */ +#define CONFIG_FILE 4096 /* C */ + +#define autoclean (main_opts & AUTOCLEAN_FLG) +#define show_only (main_opts & SHOW_ONLY) +#define quiet (main_opts & QUIET) +#define remove_opt (main_opts & REMOVE_OPT) +#define do_syslog (main_opts & DO_SYSLOG) +#define verbose (main_opts & VERBOSE) + +static int main_opts; static int parse_tag_value ( char *buffer, char **ptag, char **pvalue ) { @@ -110,7 +133,7 @@ static char *reads ( int fd, char *buffer, size_t len ) /* * This function appends an option to a list */ -struct mod_opt_t *append_option( struct mod_opt_t *opt_list, char *opt ) +static struct mod_opt_t *append_option( struct mod_opt_t *opt_list, char *opt ) { struct mod_opt_t *ol = opt_list; @@ -234,8 +257,8 @@ static char *parse_command_string( char *src, char **dst ) 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 ) ); + *tmp_str++ = '\0'; + *dst = xrealloc( *dst, (tmp_str - *dst ) ); return src; } #else @@ -243,8 +266,106 @@ static char *parse_command_string( char *src, char **dst ) #endif /* ENABLE_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 + * This function reads aliases and default module options from a configuration file + * (/etc/modprobe.conf syntax). It supports includes (only files, no directories). + */ +static void include_conf ( struct dep_t **first, struct dep_t **current, char *buffer, int buflen, int fd ) +{ + int continuation_line = 0; + + // alias parsing is not 100% correct (no correct handling of continuation lines within an alias) ! + + while ( reads ( fd, buffer, buflen)) { + int l; + char *p; + + p = strchr ( buffer, '#' ); + if ( p ) + *p = 0; + + l = strlen ( buffer ); + + while ( l && isspace ( buffer [l-1] )) { + buffer [l-1] = 0; + l--; + } + + if ( l == 0 ) { + continuation_line = 0; + continue; + } + + if ( !continuation_line ) { + if (( strncmp ( buffer, "alias", 5 ) == 0 ) && isspace ( buffer [5] )) { + char *alias, *mod; + + if ( parse_tag_value ( buffer + 6, &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 )); + } + else { + (*current)-> m_next = (struct dep_t *) xcalloc ( 1, sizeof ( struct dep_t )); + (*current) = (*current)-> m_next; + } + (*current)-> m_name = bb_xstrdup ( alias ); + (*current)-> m_isalias = 1; + + if (( strcmp ( mod, "off" ) == 0 ) || ( strcmp ( mod, "null" ) == 0 )) { + (*current)-> m_depcnt = 0; + (*current)-> m_deparr = 0; + } + else { + (*current)-> m_depcnt = 1; + (*current)-> m_deparr = xmalloc ( 1 * sizeof( char * )); + (*current)-> m_deparr[0] = bb_xstrdup ( mod ); + } + (*current)-> m_next = 0; + } + } + 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 ) { + if ( ENABLE_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 ); + } + } + } + } + else if (( strncmp ( buffer, "include", 7 ) == 0 ) && isspace ( buffer [7] )) { + + int fdi; char *filename = buffer + 8; + + while ( isspace ( *filename )) + filename++; + + if (( fdi = open ( filename, O_RDONLY )) >= 0 ) { + include_conf(first, current, buffer, buflen, fdi); + close(fdi); + } + } + } + } +} + +/* + * 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 ) @@ -254,7 +375,7 @@ static struct dep_t *build_dep ( void ) struct dep_t *first = 0; struct dep_t *current = 0; char buffer[2048]; - char *filename = buffer; + char *filename; int continuation_line = 0; int k_version; @@ -262,20 +383,15 @@ static struct dep_t *build_dep ( void ) if ( uname ( &un )) 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 )) { - return 0; - } if (un.release[0] == '2') { k_version = un.release[2] - '0'; } - strcpy ( filename, "/lib/modules/" ); - strcat ( filename, un.release ); - strcat ( filename, "/modules.dep" ); - - if (( fd = open ( filename, O_RDONLY )) < 0 ) { - + filename = bb_xasprintf("/lib/modules/%s/modules.dep", un.release ); + fd = open ( filename, O_RDONLY ); + if (ENABLE_FEATURE_CLEAN_UP) + free(filename); + if (fd < 0) { /* Ok, that didn't work. Fall back to looking in /lib/modules */ if (( fd = open ( "/lib/modules/modules.dep", O_RDONLY )) < 0 ) { return 0; @@ -283,10 +399,10 @@ static struct dep_t *build_dep ( void ) } while ( reads ( fd, buffer, sizeof( buffer ))) { - int l = bb_strlen ( buffer ); + int l = strlen ( buffer ); char *p = 0; - while ( isspace ( buffer [l-1] )) { + while ( l > 0 && isspace ( buffer [l-1] )) { buffer [l-1] = 0; l--; } @@ -428,90 +544,28 @@ static struct dep_t *build_dep ( void ) } close ( fd ); - // alias parsing is not 100% correct (no correct handling of continuation lines within an alias) ! - if (!ENABLE_FEATURE_2_6_MODULES || ( fd = open ( "/etc/modprobe.conf", O_RDONLY )) < 0 ) if (( fd = open ( "/etc/modules.conf", O_RDONLY )) < 0 ) if (( fd = open ( "/etc/conf.modules", O_RDONLY )) < 0 ) return first; - continuation_line = 0; - while ( reads ( fd, buffer, sizeof( buffer ))) { - int l; - char *p; - - p = strchr ( buffer, '#' ); - if ( p ) - *p = 0; - - l = bb_strlen ( buffer ); - - while ( l && isspace ( buffer [l-1] )) { - buffer [l-1] = 0; - l--; - } + include_conf (&first, ¤t, buffer, sizeof(buffer), fd); + close(fd); - if ( l == 0 ) { - continuation_line = 0; - continue; - } - - if ( !continuation_line ) { - if (( strncmp ( buffer, "alias", 5 ) == 0 ) && isspace ( buffer [5] )) { - char *alias, *mod; - - if ( parse_tag_value ( buffer + 6, &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 )); - } - else { - current-> m_next = (struct dep_t *) xcalloc ( 1, sizeof ( struct dep_t )); - current = current-> m_next; - } - current-> m_name = bb_xstrdup ( alias ); - current-> m_isalias = 1; - - if (( strcmp ( mod, "off" ) == 0 ) || ( strcmp ( mod, "null" ) == 0 )) { - current-> m_depcnt = 0; - current-> m_deparr = 0; - } - else { - current-> m_depcnt = 1; - current-> m_deparr = xmalloc ( 1 * sizeof( char * )); - current-> m_deparr[0] = bb_xstrdup ( mod ); - } - current-> m_next = 0; - } - } - 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 ) { - if ( ENABLE_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 ); - } - } - } - } + filename = bb_xasprintf("/lib/modules/%s/modules.alias", un.release); + fd = open ( filename, O_RDONLY ); + if (ENABLE_FEATURE_CLEAN_UP) + free(filename); + if (fd < 0) { + /* Ok, that didn't work. Fall back to looking in /lib/modules */ + if (( fd = open ( "/lib/modules/modules.alias", O_RDONLY )) < 0 ) { + return first; } } - close ( fd ); + + include_conf (&first, ¤t, buffer, sizeof(buffer), fd); + close(fd); return first; } @@ -787,7 +841,7 @@ static int mod_insert ( char *mod, int argc, char **argv ) static int mod_remove ( char *mod ) { int rc; - static struct mod_list_t rm_a_dummy = { "-a", 0, 0 }; + static struct mod_list_t rm_a_dummy = { "-a", NULL, NULL, NULL, NULL }; struct mod_list_t *head = 0; struct mod_list_t *tail = 0; @@ -805,52 +859,19 @@ static int mod_remove ( char *mod ) } -extern int modprobe_main(int argc, char** argv) +int modprobe_main(int argc, char** argv) { - int opt; int rc = EXIT_SUCCESS; - int remove_opt = 0; + char *unused; - autoclean = show_only = quiet = do_syslog = verbose = 0; - - while ((opt = getopt(argc, argv, "acdklnqrst:vVC:")) != -1) { - switch(opt) { - case 'c': // no config used - case 'l': // no pattern matching + bb_opt_complementally = "?V-:q-v:v-q"; + main_opts = bb_getopt_ulflags(argc, argv, "acdklnqrst:vVC:", + &unused, &unused); + if((main_opts & (DUMP_CONF_EXIT | LIST_ALL))) return EXIT_SUCCESS; - break; - case 'C': // no config used - case 't': // no pattern matching + if((main_opts & (RESTRICT_DIR | CONFIG_FILE))) bb_error_msg_and_die("-t and -C not supported"); - case 'a': // ignore - case 'd': // ignore - break; - case 'k': - autoclean++; - break; - case 'n': - show_only++; - break; - case 'q': - quiet++; verbose=0; - break; - case 'r': - remove_opt++; - break; - case 's': - do_syslog++; - break; - case 'v': - verbose++; quiet=0; - break; - case 'V': - default: - bb_show_usage(); - break; - } - } - depend = build_dep ( ); if ( !depend ) @@ -859,7 +880,7 @@ extern int modprobe_main(int argc, char** argv) if (remove_opt) { do { if (mod_remove ( optind < argc ? - bb_xstrdup (argv [optind]) : NULL )) { + argv [optind] : NULL )) { bb_error_msg ("failed to remove module %s", argv [optind] ); rc = EXIT_FAILURE; @@ -869,7 +890,7 @@ extern int modprobe_main(int argc, char** argv) if (optind >= argc) bb_error_msg_and_die ( "No module or pattern provided\n" ); - if ( mod_insert ( bb_xstrdup ( argv [optind] ), argc - optind - 1, argv + optind + 1 )) + if ( mod_insert ( argv [optind], argc - optind - 1, argv + optind + 1 )) bb_error_msg_and_die ( "failed to load module %s", argv [optind] ); }