1 /* vi: set sw=4 ts=4: */
3 * really dumb modprobe implementation for busybox
4 * Copyright (C) 2001 Lineo, davidm@lineo.com
6 * dependency specific stuff completly rewritten and
7 * copyright (c) 2002 by Robert Griebl, griebl@gmx.de
11 #include <sys/utsname.h>
32 struct dep_t * m_next;
38 struct mod_list_t * m_prev;
39 struct mod_list_t * m_next;
43 static struct dep_t *depend;
44 static int autoclean, show_only, quiet, do_syslog, verbose;
47 static struct dep_t *build_dep ( void )
51 struct dep_t *first = 0;
52 struct dep_t *current = 0;
54 char *filename = buffer;
55 int continuation_line = 0;
60 // check for buffer overflow in following code
61 if ( xstrlen ( un.release ) > ( sizeof( buffer ) - 64 )) {
65 strcpy ( filename, "/lib/modules/" );
66 strcat ( filename, un.release );
67 strcat ( filename, "/modules.dep" );
69 if ((fd = open ( filename, O_RDONLY )) < 0)
72 while ( (n = read(fd, buffer, 255)) > 0) {
76 /* Jump through hoops to simulate how fgets() grabs just one line at a
77 * time... Don't use any stdio since modprobe gets called from a kernel
78 * thread and stdio junk can overflow the limited stack... */
79 p = strchr ( buffer, '\n' );
82 /* Get the current file descriptor offset */
83 offset = lseek(fd, 0L, SEEK_CUR);
84 /* Set the file descriptor offset to right after the \n */
85 lseek(fd, offset-n+p-buffer+1, SEEK_SET);
89 l = xstrlen ( buffer );
90 while ( isspace ( buffer [l-1] )) {
96 continuation_line = 0;
100 if ( !continuation_line ) {
101 char *col = strchr ( buffer, ':' );
109 mods = strrchr ( buffer, '/' );
116 if (( *(col-2) == '.' ) && ( *(col-1) == 'o' ))
119 mod = xstrndup ( mods, col - mods - ext );
122 first = current = (struct dep_t *) xmalloc ( sizeof ( struct dep_t ));
125 current-> m_next = (struct dep_t *) xmalloc ( sizeof ( struct dep_t ));
126 current = current-> m_next;
128 current-> m_module = mod;
129 current-> m_isalias = 0;
130 current-> m_depcnt = 0;
131 current-> m_deparr = 0;
132 current-> m_next = 0;
134 //printf ( "%s:\n", mod );
145 char *end = &buffer [l-1];
146 char *deps = strrchr ( end, '/' );
150 while ( isblank ( *end ) || ( *end == '\\' ))
153 deps = strrchr ( p, '/' );
155 if ( !deps || ( deps < p )) {
158 while ( isblank ( *deps ))
164 if (( *(end-1) == '.' ) && ( *end == 'o' ))
167 dep = xstrndup ( deps, end - deps - ext + 1 );
169 current-> m_depcnt++;
170 current-> m_deparr = (char **) xrealloc ( current-> m_deparr, sizeof ( char *) * current-> m_depcnt );
171 current-> m_deparr [current-> m_depcnt - 1] = dep;
173 //printf ( " %d) %s\n", current-> m_depcnt, current-> m_deparr [current-> m_depcnt -1] );
176 if ( buffer [l-1] == '\\' )
177 continuation_line = 1;
179 continuation_line = 0;
183 // alias parsing is not 100% correct (no correct handling of continuation lines within an alias) !
185 if ((fd = open ( "/etc/modules.conf", O_RDONLY )) < 0)
186 if ((fd = open ( "/etc/conf.modules", O_RDONLY )) < 0)
189 continuation_line = 0;
190 while ( read(fd, buffer, 255) > 0) {
194 /* Jump through hoops to simulate how fgets() grabs just one line at a
195 * time... Don't use any stdio since modprobe gets called from a kernel
196 * thread and stdio junk can overflow the limited stack... */
197 p = strchr ( buffer, '\n' );
200 /* Get the current file descriptor offset */
201 offset = lseek(fd, 0L, SEEK_CUR);
202 /* Set the file descriptor offset to right after the \n */
203 lseek(fd, offset-n+p-buffer+1, SEEK_SET);
207 p = strchr ( buffer, '#' );
211 l = xstrlen ( buffer );
213 while ( l && isspace ( buffer [l-1] )) {
219 continuation_line = 0;
223 if ( !continuation_line ) {
224 if (( strncmp ( buffer, "alias", 5 ) == 0 ) && isspace ( buffer [5] )) {
229 while ( isspace ( *alias ))
232 while ( !isspace ( *mod ))
236 while ( isspace ( *mod ))
239 // fprintf ( stderr, "ALIAS: '%s' -> '%s'\n", alias, mod );
242 first = current = (struct dep_t *) xmalloc ( sizeof ( struct dep_t ));
245 current-> m_next = (struct dep_t *) xmalloc ( sizeof ( struct dep_t ));
246 current = current-> m_next;
248 current-> m_module = xstrdup ( alias );
249 current-> m_isalias = 1;
251 if (( strcmp ( alias, "off" ) == 0 ) || ( strcmp ( alias, "null" ) == 0 )) {
252 current-> m_depcnt = 0;
253 current-> m_deparr = 0;
256 current-> m_depcnt = 1;
257 current-> m_deparr = xmalloc ( 1 * sizeof( char * ));
258 current-> m_deparr[0] = xstrdup ( mod );
260 current-> m_next = 0;
270 static int mod_process ( struct mod_list_t *list, int do_insert )
280 snprintf ( lcmd, sizeof( lcmd ) - 1, "insmod %s %s %s %s 2>/dev/null", do_syslog ? "-s" : "", autoclean ? "-k" : "", quiet ? "-q" : "", list-> m_module );
282 snprintf ( lcmd, sizeof( lcmd ) - 1, "rmmod %s %s 2>/dev/null", do_syslog ? "-s" : "", list-> m_module );
285 printf ( "%s\n", lcmd );
287 rc |= system ( lcmd );
289 list = do_insert ? list-> m_prev : list-> m_next;
294 static void check_dep ( char *mod, struct mod_list_t **head, struct mod_list_t **tail )
296 struct mod_list_t *find;
301 // remove .o extension
302 lm = xstrlen ( mod );
303 if (( mod [lm-2] == '.' ) && ( mod [lm-1] == 'o' ))
306 // check dependencies
307 for ( dt = depend; dt; dt = dt-> m_next ) {
308 if ( strcmp ( dt-> m_module, mod ) == 0 )
311 // resolve alias names
312 if ( dt && dt-> m_isalias ) {
313 if ( dt-> m_depcnt == 1 )
314 check_dep ( dt-> m_deparr [0], head, tail );
315 printf ( "Got alias: %s -> %s\n", mod, dt-> m_deparr [0] );
320 // search for duplicates
321 for ( find = *head; find; find = find-> m_next ) {
322 if ( !strcmp ( mod, find-> m_module )) {
323 // found -> dequeue it
326 find-> m_prev-> m_next = find-> m_next;
328 *head = find-> m_next;
331 find-> m_next-> m_prev = find-> m_prev;
333 *tail = find-> m_prev;
335 break; // there can be only one duplicate
339 if ( !find ) { // did not find a duplicate
340 find = (struct mod_list_t *) xmalloc ( sizeof(struct mod_list_t));
341 find-> m_module = mod;
346 (*tail)-> m_next = find;
347 find-> m_prev = *tail;
357 for ( i = 0; i < dt-> m_depcnt; i++ )
358 check_dep ( dt-> m_deparr [i], head, tail );
364 static int mod_insert ( char *mod, int argc, char **argv )
366 struct mod_list_t *tail = 0;
367 struct mod_list_t *head = 0;
370 // get dep list for module mod
371 check_dep ( mod, &head, &tail );
373 if ( head && tail ) {
377 // append module args
378 l = xstrlen ( head-> m_module );
379 for ( i = 0; i < argc; i++ )
380 l += ( xstrlen ( argv [i] ) + 1 );
382 head-> m_module = xrealloc ( head-> m_module, l + 1 );
384 for ( i = 0; i < argc; i++ ) {
385 strcat ( head-> m_module, " " );
386 strcat ( head-> m_module, argv [i] );
389 // process tail ---> head
390 rc |= mod_process ( tail, 1 );
398 static void mod_remove ( char *mod )
400 static struct mod_list_t rm_a_dummy = { "-a", 0, 0 };
402 struct mod_list_t *head = 0;
403 struct mod_list_t *tail = 0;
406 check_dep ( mod, &head, &tail );
408 head = tail = &rm_a_dummy;
411 mod_process ( head, 0 ); // process head ---> tail
416 extern int modprobe_main(int argc, char** argv)
421 autoclean = show_only = quiet = do_syslog = verbose = 0;
423 while ((opt = getopt(argc, argv, "acdklnqrst:vVC:")) != -1) {
425 case 'c': // no config used
426 case 'l': // no pattern matching
429 case 'C': // no config used
430 case 't': // no pattern matching
431 error_msg_and_die("-t and -C not supported");
461 depend = build_dep ( );
464 error_msg_and_die ( "could not parse modules.dep\n" );
468 mod_remove ( optind < argc ? xstrdup ( argv [optind] ) : 0 );
469 } while ( ++optind < argc );
475 error_msg_and_die ( "No module or pattern provided\n" );
477 return mod_insert ( xstrdup ( argv [optind] ), argc - optind - 1, argv + optind + 1 ) ? \
478 EXIT_FAILURE : EXIT_SUCCESS;