/* * 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; struct utsname un; struct dep_t *first = 0; struct dep_t *current = 0; char buffer[2048]; char *filename; int continuation_line = 0; int k_version; k_version = 0; if ( uname ( &un )) bb_error_msg_and_die("can't determine kernel version"); if (un.release[0] == '2') { k_version = un.release[2] - '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; } } while ( reads ( fd, buffer, sizeof( buffer ))) { int l = strlen ( buffer ); char *p = 0; while ( l > 0 && isspace ( buffer [l-1] )) { buffer [l-1] = 0; l--; } if ( l == 0 ) { continuation_line = 0; continue; } /* Is this a new module dep description? */ if ( !continuation_line ) { /* find the dep beginning */ 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; /* no path for this module */ else mods++; /* there was a path for this module... */ /* find the path of the module */ modpath = strchr ( buffer, '/' ); /* ... and this is the path */ if ( !modpath ) 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 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 )); } else { current-> m_next = (struct dep_t *) xmalloc ( sizeof ( struct dep_t )); current = current-> m_next; } current-> m_name = mod; current-> m_path = bb_xstrdup(modpath); current-> m_options = NULL; current-> m_isalias = 0; current-> m_depcnt = 0; current-> m_deparr = 0; current-> m_next = 0; 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; char *dep; char *next; int ext = 0; while ( isblank ( *end ) || ( *end == '\\' )) end--; do { /* search the end of the dependency */ next = strchr (p, ' ' ); if (next) { *next = 0; next--; } else next = end; /* find the beginning of the module file name */ deps = strrchr ( p, '/' ); if ( !deps || ( deps < p )) { deps = p; while ( isblank ( *deps )) deps++; } else deps++; /* 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 if (( *(next-1) == '.' ) && ( *next == 'o' )) ext = 2; /* Cope with blank lines */ if ((next-deps-ext+1) <= 0) 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; p = next + 2; } while (next < end); } /* is there other dependable module(s) ? */ if ( buffer [l-1] == '\\' ) continuation_line = 1; else continuation_line = 0; } close ( fd ); /* * First parse system-specific options and aliases * as they take precedence over the kernel ones. */ if (!ENABLE_FEATURE_2_6_MODULES || ( fd = open ( "/etc/modprobe.conf", O_RDONLY )) < 0 ) if (( fd = open ( "/etc/modules.conf", O_RDONLY )) < 0 ) fd = open ( "/etc/conf.modules", O_RDONLY ); if (fd >= 0) { include_conf (&first, ¤t, buffer, sizeof(buffer), fd); close(fd); } /* Only 2.6 has a modules.alias file */ if (ENABLE_FEATURE_2_6_MODULES) { /* Parse kernel-declared aliases */ filename = bb_xasprintf("/lib/modules/%s/modules.alias", un.release); if ((fd = open ( filename, O_RDONLY )) < 0) { /* Ok, that didn't work. Fall back to looking in /lib/modules */ fd = open ( "/lib/modules/modules.alias", O_RDONLY ); } if (ENABLE_FEATURE_CLEAN_UP) free(filename); if (fd >= 0) { include_conf (&first, ¤t, buffer, sizeof(buffer), fd); close(fd); } } return first; }
/* * 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; struct utsname un; struct dep_t *first = NULL; struct dep_t *current = NULL; char *filename; int continuation_line = 0; int k_version; if (uname(&un)) bb_error_msg_and_die("can't determine kernel version"); k_version = 0; if (un.release[0] == '2') { k_version = un.release[2] - '0'; } filename = xasprintf(CONFIG_DEFAULT_MODULES_DIR"/%s/"CONFIG_DEFAULT_DEPMOD_FILE, 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 */ fd = open(CONFIG_DEFAULT_MODULES_DIR"/"CONFIG_DEFAULT_DEPMOD_FILE, O_RDONLY); if (fd < 0) { bb_error_msg_and_die("cannot parse " CONFIG_DEFAULT_DEPMOD_FILE); } } while (reads(fd, line_buffer, sizeof(line_buffer))) { int l = strlen(line_buffer); char *p = 0; while (l > 0 && isspace(line_buffer[l-1])) { line_buffer[l-1] = '\0'; l--; } if (l == 0) { continuation_line = 0; continue; } /* Is this a new module dep description? */ if (!continuation_line) { /* find the dep beginning */ char *col = strchr(line_buffer, ':'); char *dot = col; if (col) { /* This line is a dep description */ const char *mods; char *modpath; char *mod; /* Find the beginning of the module file name */ *col = '\0'; mods = bb_basename(line_buffer); /* find the path of the module */ modpath = strchr(line_buffer, '/'); /* ... and this is the path */ if (!modpath) modpath = line_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 if ((col[-2] == '.') && (col[-1] == 'o')) dot = col - 2; mod = xstrndup(mods, dot - mods); /* enqueue new module */ if (!current) { first = current = xzalloc(sizeof(struct dep_t)); } else { current->m_next = xzalloc(sizeof(struct dep_t)); current = current->m_next; } current->m_name = mod; current->m_path = xstrdup(modpath); /*current->m_options = NULL; - xzalloc did it*/ /*current->m_isalias = 0;*/ /*current->m_depcnt = 0;*/ /*current->m_deparr = 0;*/ /*current->m_next = 0;*/ p = col + 1; } else /* this line is not a dep description */ p = NULL; } else /* It's a dep description continuation */ p = line_buffer; /* p points to the first dependable module; if NULL, no dependable module */ if (p && (p = skip_whitespace(p))[0] != '\0') { char *end = &line_buffer[l-1]; const char *deps; char *dep; char *next; int ext = 0; while (isblank(*end) || (*end == '\\')) end--; do { /* search the end of the dependency */ next = strchr(p, ' '); if (next) { *next = '\0'; next--; } else next = end; /* find the beginning of the module file name */ deps = bb_basename(p); if (deps == p) deps = skip_whitespace(deps); /* 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[0] == 'o')) ext = 3; else if ((next[-1] == '.') && (next[0] == 'o')) ext = 2; /* Cope with blank lines */ if ((next-deps-ext+1) <= 0) continue; dep = xstrndup(deps, next - deps - ext + 1); /* Add the new dependable module name */ current->m_depcnt++; current->m_deparr = xrealloc(current->m_deparr, sizeof(char *) * current->m_depcnt); current->m_deparr[current->m_depcnt - 1] = dep; p = next + 2; } while (next < end); } /* is there other dependable module(s) ? */ continuation_line = (line_buffer[l-1] == '\\'); } /* while (reads(...)) */ close(fd); /* * First parse system-specific options and aliases * as they take precedence over the kernel ones. * >=2.6: we only care about modprobe.conf * <=2.4: we care about modules.conf and conf.modules */ if (ENABLE_FEATURE_2_6_MODULES && (fd = open("/etc/modprobe.conf", O_RDONLY)) < 0) if (ENABLE_FEATURE_2_4_MODULES && (fd = open("/etc/modules.conf", O_RDONLY)) < 0) if (ENABLE_FEATURE_2_4_MODULES) fd = open("/etc/conf.modules", O_RDONLY); if (fd >= 0) { include_conf(&first, ¤t, line_buffer, sizeof(line_buffer), fd); close(fd); } /* Only 2.6 has a modules.alias file */ if (ENABLE_FEATURE_2_6_MODULES) { /* Parse kernel-declared module aliases */ filename = xasprintf(CONFIG_DEFAULT_MODULES_DIR"/%s/modules.alias", un.release); fd = open(filename, O_RDONLY); if (fd < 0) { /* Ok, that didn't work. Fall back to looking in /lib/modules */ fd = open(CONFIG_DEFAULT_MODULES_DIR"/modules.alias", O_RDONLY); } if (ENABLE_FEATURE_CLEAN_UP) free(filename); if (fd >= 0) { include_conf(&first, ¤t, line_buffer, sizeof(line_buffer), fd); close(fd); } /* Parse kernel-declared symbol aliases */ filename = xasprintf(CONFIG_DEFAULT_MODULES_DIR"/%s/modules.symbols", un.release); fd = open(filename, O_RDONLY); if (fd < 0) { /* Ok, that didn't work. Fall back to looking in /lib/modules */ fd = open(CONFIG_DEFAULT_MODULES_DIR"/modules.symbols", O_RDONLY); } if (ENABLE_FEATURE_CLEAN_UP) free(filename); if (fd >= 0) { include_conf(&first, ¤t, line_buffer, sizeof(line_buffer), fd); close(fd); } } return first; }
/* * 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 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; *strchrnul(buffer, '#') = '\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) continue; if (is_conf_command(buffer, "alias")) { 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) = xzalloc(sizeof(struct dep_t)); } else { (*current)->m_next = xzalloc(sizeof(struct dep_t)); (*current) = (*current)->m_next; } (*current)->m_name = xstrdup(alias); (*current)->m_isalias = 1; if ((strcmp(mod, "off") == 0) || (strcmp(mod, "null") == 0)) { /*(*current)->m_depcnt = 0; - done by xzalloc */ /*(*current)->m_deparr = 0;*/ } else { (*current)->m_depcnt = 1; (*current)->m_deparr = xmalloc(sizeof(char *)); (*current)->m_deparr[0] = xstrdup(mod); } /*(*current)->m_next = NULL; - done by xzalloc */ } } else if (is_conf_command(buffer, "options")) { 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 (is_conf_command(buffer, "include")) { int fdi; char *filename; filename = skip_whitespace(buffer + 8); fdi = open(filename, O_RDONLY); if (fdi >= 0) { include_conf(first, current, buffer, buflen, fdi); close(fdi); } } else if (ENABLE_FEATURE_MODPROBE_BLACKLIST && (is_conf_command(buffer, "blacklist"))) { char *mod; struct dep_t *dt; mod = skip_whitespace(buffer + 10); for (dt = *first; dt; dt = dt->m_next) { if (strcmp(dt->m_name, mod) == 0) break; } if (dt) dt->m_isblacklisted = 1; } } /* while (reads(...)) */ }