diff options
Diffstat (limited to 'busybox/modutils/modprobe.c')
-rw-r--r-- | busybox/modutils/modprobe.c | 654 |
1 files changed, 654 insertions, 0 deletions
diff --git a/busybox/modutils/modprobe.c b/busybox/modutils/modprobe.c new file mode 100644 index 000000000..83244fca5 --- /dev/null +++ b/busybox/modutils/modprobe.c | |||
@@ -0,0 +1,654 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Modprobe written from scratch for BusyBox | ||
4 | * | ||
5 | * Copyright (c) 2002 by Robert Griebl, griebl@gmx.de | ||
6 | * Copyright (c) 2003 by Andrew Dennison, andrew.dennison@motec.com.au | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <sys/utsname.h> | ||
25 | #include <getopt.h> | ||
26 | #include <stdlib.h> | ||
27 | #include <unistd.h> | ||
28 | #include <syslog.h> | ||
29 | #include <string.h> | ||
30 | #include <ctype.h> | ||
31 | #include <fcntl.h> | ||
32 | #include "busybox.h" | ||
33 | |||
34 | |||
35 | |||
36 | struct dep_t { | ||
37 | char * m_name; | ||
38 | char * m_path; | ||
39 | char * m_options; | ||
40 | |||
41 | int m_isalias : 1; | ||
42 | int m_reserved : 15; | ||
43 | |||
44 | int m_depcnt : 16; | ||
45 | char ** m_deparr; | ||
46 | |||
47 | struct dep_t * m_next; | ||
48 | }; | ||
49 | |||
50 | struct mod_list_t { | ||
51 | char * m_name; | ||
52 | char * m_path; | ||
53 | char * m_options; | ||
54 | |||
55 | struct mod_list_t * m_prev; | ||
56 | struct mod_list_t * m_next; | ||
57 | }; | ||
58 | |||
59 | |||
60 | static struct dep_t *depend; | ||
61 | static int autoclean, show_only, quiet, do_syslog, verbose; | ||
62 | static int k_version; | ||
63 | |||
64 | int parse_tag_value ( char *buffer, char **ptag, char **pvalue ) | ||
65 | { | ||
66 | char *tag, *value; | ||
67 | |||
68 | while ( isspace ( *buffer )) | ||
69 | buffer++; | ||
70 | tag = value = buffer; | ||
71 | while ( !isspace ( *value )) | ||
72 | if (!*value) return 0; | ||
73 | else value++; | ||
74 | *value++ = 0; | ||
75 | while ( isspace ( *value )) | ||
76 | value++; | ||
77 | if (!*value) return 0; | ||
78 | |||
79 | *ptag = tag; | ||
80 | *pvalue = value; | ||
81 | |||
82 | return 1; | ||
83 | } | ||
84 | |||
85 | /* Jump through hoops to simulate how fgets() grabs just one line at a | ||
86 | * time... Don't use any stdio since modprobe gets called from a kernel | ||
87 | * thread and stdio junk can overflow the limited stack... | ||
88 | */ | ||
89 | static char *reads ( int fd, char *buffer, size_t len ) | ||
90 | { | ||
91 | int n = read ( fd, buffer, len ); | ||
92 | |||
93 | if ( n > 0 ) { | ||
94 | char *p; | ||
95 | |||
96 | buffer [len-1] = 0; | ||
97 | p = strchr ( buffer, '\n' ); | ||
98 | |||
99 | if ( p ) { | ||
100 | off_t offset; | ||
101 | |||
102 | offset = lseek ( fd, 0L, SEEK_CUR ); // Get the current file descriptor offset | ||
103 | lseek ( fd, offset-n + (p-buffer) + 1, SEEK_SET ); // Set the file descriptor offset to right after the \n | ||
104 | |||
105 | p[1] = 0; | ||
106 | } | ||
107 | return buffer; | ||
108 | } | ||
109 | |||
110 | else | ||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static struct dep_t *build_dep ( void ) | ||
115 | { | ||
116 | int fd; | ||
117 | struct utsname un; | ||
118 | struct dep_t *first = 0; | ||
119 | struct dep_t *current = 0; | ||
120 | char buffer[2048]; | ||
121 | char *filename = buffer; | ||
122 | int continuation_line = 0; | ||
123 | |||
124 | k_version = 0; | ||
125 | if ( uname ( &un )) | ||
126 | return 0; | ||
127 | |||
128 | // check for buffer overflow in following code | ||
129 | if ( bb_strlen ( un.release ) > ( sizeof( buffer ) - 64 )) { | ||
130 | return 0; | ||
131 | } | ||
132 | if (un.release[0] == '2') { | ||
133 | k_version = un.release[2] - '0'; | ||
134 | } | ||
135 | |||
136 | strcpy ( filename, "/lib/modules/" ); | ||
137 | strcat ( filename, un.release ); | ||
138 | strcat ( filename, "/modules.dep" ); | ||
139 | |||
140 | if (( fd = open ( filename, O_RDONLY )) < 0 ) { | ||
141 | |||
142 | /* Ok, that didn't work. Fall back to looking in /lib/modules */ | ||
143 | if (( fd = open ( "/lib/modules/modules.dep", O_RDONLY )) < 0 ) { | ||
144 | return 0; | ||
145 | } | ||
146 | } | ||
147 | |||
148 | while ( reads ( fd, buffer, sizeof( buffer ))) { | ||
149 | int l = bb_strlen ( buffer ); | ||
150 | char *p = 0; | ||
151 | |||
152 | while ( isspace ( buffer [l-1] )) { | ||
153 | buffer [l-1] = 0; | ||
154 | l--; | ||
155 | } | ||
156 | |||
157 | if ( l == 0 ) { | ||
158 | continuation_line = 0; | ||
159 | continue; | ||
160 | } | ||
161 | |||
162 | if ( !continuation_line ) { | ||
163 | char *col = strchr ( buffer, ':' ); | ||
164 | char *dot = col; | ||
165 | |||
166 | if ( col ) { | ||
167 | char *mods; | ||
168 | char *modpath; | ||
169 | char *mod; | ||
170 | |||
171 | *col = 0; | ||
172 | mods = strrchr ( buffer, '/' ); | ||
173 | |||
174 | if ( !mods ) | ||
175 | mods = buffer; | ||
176 | else | ||
177 | mods++; | ||
178 | |||
179 | modpath = strchr ( buffer, '/' ); | ||
180 | if ( !modpath ) | ||
181 | modpath = buffer; | ||
182 | #if defined(CONFIG_FEATURE_2_6_MODULES) | ||
183 | if ((k_version > 4) && ( *(col-3) == '.' ) && | ||
184 | ( *(col-2) == 'k' ) && ( *(col-1) == 'o' )) | ||
185 | dot = col - 3; | ||
186 | else | ||
187 | #endif | ||
188 | if (( *(col-2) == '.' ) && ( *(col-1) == 'o' )) | ||
189 | dot = col - 2; | ||
190 | |||
191 | mod = bb_xstrndup ( mods, dot - mods ); | ||
192 | |||
193 | if ( !current ) { | ||
194 | first = current = (struct dep_t *) xmalloc ( sizeof ( struct dep_t )); | ||
195 | } | ||
196 | else { | ||
197 | current-> m_next = (struct dep_t *) xmalloc ( sizeof ( struct dep_t )); | ||
198 | current = current-> m_next; | ||
199 | } | ||
200 | current-> m_name = mod; | ||
201 | current-> m_path = bb_xstrdup(modpath); | ||
202 | current-> m_options = 0; | ||
203 | current-> m_isalias = 0; | ||
204 | current-> m_depcnt = 0; | ||
205 | current-> m_deparr = 0; | ||
206 | current-> m_next = 0; | ||
207 | |||
208 | //printf ( "%s:\n", mod ); | ||
209 | p = col + 1; | ||
210 | } | ||
211 | else | ||
212 | p = 0; | ||
213 | } | ||
214 | else | ||
215 | p = buffer; | ||
216 | |||
217 | while ( p && *p && isblank(*p)) | ||
218 | p++; | ||
219 | |||
220 | if ( p && *p ) { | ||
221 | char *end = &buffer [l-1]; | ||
222 | char *deps; | ||
223 | char *dep; | ||
224 | char *next; | ||
225 | int ext = 0; | ||
226 | |||
227 | while ( isblank ( *end ) || ( *end == '\\' )) | ||
228 | end--; | ||
229 | |||
230 | do | ||
231 | { | ||
232 | next = strchr (p, ' ' ); | ||
233 | if (next) | ||
234 | { | ||
235 | *next = 0; | ||
236 | next--; | ||
237 | } | ||
238 | else | ||
239 | next = end; | ||
240 | |||
241 | deps = strrchr ( p, '/' ); | ||
242 | |||
243 | if ( !deps || ( deps < p )) { | ||
244 | deps = p; | ||
245 | |||
246 | while ( isblank ( *deps )) | ||
247 | deps++; | ||
248 | } | ||
249 | else | ||
250 | deps++; | ||
251 | |||
252 | #if defined(CONFIG_FEATURE_2_6_MODULES) | ||
253 | if ((k_version > 4) && ( *(next-2) == '.' ) && *(next-1) == 'k' && | ||
254 | ( *next == 'o' )) | ||
255 | ext = 3; | ||
256 | else | ||
257 | #endif | ||
258 | if (( *(next-1) == '.' ) && ( *next == 'o' )) | ||
259 | ext = 2; | ||
260 | |||
261 | /* Cope with blank lines */ | ||
262 | if ((next-deps-ext+1) <= 0) | ||
263 | continue; | ||
264 | dep = bb_xstrndup ( deps, next - deps - ext + 1 ); | ||
265 | |||
266 | current-> m_depcnt++; | ||
267 | current-> m_deparr = (char **) xrealloc ( current-> m_deparr, | ||
268 | sizeof ( char *) * current-> m_depcnt ); | ||
269 | current-> m_deparr [current-> m_depcnt - 1] = dep; | ||
270 | |||
271 | //printf ( " %d) %s\n", current-> m_depcnt, current-> m_deparr [current-> m_depcnt -1] ); | ||
272 | p = next + 2; | ||
273 | } while (next < end); | ||
274 | } | ||
275 | |||
276 | if ( buffer [l-1] == '\\' ) | ||
277 | continuation_line = 1; | ||
278 | else | ||
279 | continuation_line = 0; | ||
280 | } | ||
281 | close ( fd ); | ||
282 | |||
283 | // alias parsing is not 100% correct (no correct handling of continuation lines within an alias) ! | ||
284 | |||
285 | #if defined(CONFIG_FEATURE_2_6_MODULES) | ||
286 | if (( fd = open ( "/etc/modprobe.conf", O_RDONLY )) < 0 ) | ||
287 | #endif | ||
288 | if (( fd = open ( "/etc/modules.conf", O_RDONLY )) < 0 ) | ||
289 | if (( fd = open ( "/etc/conf.modules", O_RDONLY )) < 0 ) | ||
290 | return first; | ||
291 | |||
292 | continuation_line = 0; | ||
293 | while ( reads ( fd, buffer, sizeof( buffer ))) { | ||
294 | int l; | ||
295 | char *p; | ||
296 | |||
297 | p = strchr ( buffer, '#' ); | ||
298 | if ( p ) | ||
299 | *p = 0; | ||
300 | |||
301 | l = bb_strlen ( buffer ); | ||
302 | |||
303 | while ( l && isspace ( buffer [l-1] )) { | ||
304 | buffer [l-1] = 0; | ||
305 | l--; | ||
306 | } | ||
307 | |||
308 | if ( l == 0 ) { | ||
309 | continuation_line = 0; | ||
310 | continue; | ||
311 | } | ||
312 | |||
313 | if ( !continuation_line ) { | ||
314 | if (( strncmp ( buffer, "alias", 5 ) == 0 ) && isspace ( buffer [5] )) { | ||
315 | char *alias, *mod; | ||
316 | |||
317 | if ( parse_tag_value ( buffer + 6, &alias, &mod )) { | ||
318 | // fprintf ( stderr, "ALIAS: '%s' -> '%s'\n", alias, mod ); | ||
319 | |||
320 | if ( !current ) { | ||
321 | first = current = (struct dep_t *) xcalloc ( 1, sizeof ( struct dep_t )); | ||
322 | } | ||
323 | else { | ||
324 | current-> m_next = (struct dep_t *) xcalloc ( 1, sizeof ( struct dep_t )); | ||
325 | current = current-> m_next; | ||
326 | } | ||
327 | current-> m_name = bb_xstrdup ( alias ); | ||
328 | current-> m_isalias = 1; | ||
329 | |||
330 | if (( strcmp ( mod, "off" ) == 0 ) || ( strcmp ( mod, "null" ) == 0 )) { | ||
331 | current-> m_depcnt = 0; | ||
332 | current-> m_deparr = 0; | ||
333 | } | ||
334 | else { | ||
335 | current-> m_depcnt = 1; | ||
336 | current-> m_deparr = xmalloc ( 1 * sizeof( char * )); | ||
337 | current-> m_deparr[0] = bb_xstrdup ( mod ); | ||
338 | } | ||
339 | current-> m_next = 0; | ||
340 | } | ||
341 | } | ||
342 | else if (( strncmp ( buffer, "options", 7 ) == 0 ) && isspace ( buffer [7] )) { | ||
343 | char *mod, *opt; | ||
344 | |||
345 | if ( parse_tag_value ( buffer + 8, &mod, &opt )) { | ||
346 | struct dep_t *dt; | ||
347 | |||
348 | for ( dt = first; dt; dt = dt-> m_next ) { | ||
349 | if ( strcmp ( dt-> m_name, mod ) == 0 ) | ||
350 | break; | ||
351 | } | ||
352 | if ( dt ) { | ||
353 | dt-> m_options = xrealloc ( dt-> m_options, bb_strlen( opt ) + 1 ); | ||
354 | strcpy ( dt-> m_options, opt ); | ||
355 | |||
356 | // fprintf ( stderr, "OPTION: '%s' -> '%s'\n", dt-> m_name, dt-> m_options ); | ||
357 | } | ||
358 | } | ||
359 | } | ||
360 | } | ||
361 | } | ||
362 | close ( fd ); | ||
363 | |||
364 | return first; | ||
365 | } | ||
366 | |||
367 | /* return 1 = loaded, 0 = not loaded, -1 = can't tell */ | ||
368 | static int already_loaded (const char *name) | ||
369 | { | ||
370 | int fd; | ||
371 | char buffer[4096]; | ||
372 | |||
373 | fd = open ("/proc/modules", O_RDONLY); | ||
374 | if (fd < 0) | ||
375 | return -1; | ||
376 | |||
377 | while ( reads ( fd, buffer, sizeof( buffer ))) { | ||
378 | char *p; | ||
379 | |||
380 | p = strchr (buffer, ' '); | ||
381 | if (p) { | ||
382 | *p = 0; | ||
383 | if (strcmp (name, buffer) == 0) { | ||
384 | close (fd); | ||
385 | return 1; | ||
386 | } | ||
387 | } | ||
388 | } | ||
389 | |||
390 | close (fd); | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static int mod_process ( struct mod_list_t *list, int do_insert ) | ||
395 | { | ||
396 | char lcmd [4096]; | ||
397 | int rc = 0; | ||
398 | |||
399 | while ( list ) { | ||
400 | *lcmd = '\0'; | ||
401 | if ( do_insert ) { | ||
402 | if (already_loaded (list->m_name) != 1) | ||
403 | snprintf ( lcmd, sizeof( lcmd ) - 1, "insmod %s %s %s %s %s", | ||
404 | do_syslog ? "-s" : "", autoclean ? "-k" : "", | ||
405 | quiet ? "-q" : "", list-> m_path, list-> m_options ? | ||
406 | list-> m_options : "" ); | ||
407 | } else { | ||
408 | /* modutils uses short name for removal */ | ||
409 | if (already_loaded (list->m_name) != 0) | ||
410 | snprintf ( lcmd, sizeof( lcmd ) - 1, "rmmod %s %s", | ||
411 | do_syslog ? "-s" : "", list-> m_name ); | ||
412 | } | ||
413 | |||
414 | if (*lcmd) { | ||
415 | if (verbose) { | ||
416 | printf("%s\n", lcmd); | ||
417 | } | ||
418 | if (!show_only) { | ||
419 | int rc2 = system(lcmd); | ||
420 | if (do_insert) { | ||
421 | rc = rc2; /* only last module matters */ | ||
422 | } | ||
423 | else if (!rc2) { | ||
424 | rc = 0; /* success if remove any mod */ | ||
425 | } | ||
426 | } | ||
427 | } | ||
428 | list = do_insert ? list-> m_prev : list-> m_next; | ||
429 | } | ||
430 | return (show_only) ? 0 : rc; | ||
431 | } | ||
432 | |||
433 | static void check_dep ( char *mod, struct mod_list_t **head, struct mod_list_t **tail ) | ||
434 | { | ||
435 | struct mod_list_t *find; | ||
436 | struct dep_t *dt; | ||
437 | char *opt = 0; | ||
438 | char *path = 0; | ||
439 | |||
440 | // check dependencies | ||
441 | for ( dt = depend; dt; dt = dt-> m_next ) { | ||
442 | if ( strcmp ( dt-> m_name, mod ) == 0) { | ||
443 | mod = dt-> m_name; | ||
444 | path = dt-> m_path; | ||
445 | opt = dt-> m_options; | ||
446 | break; | ||
447 | } | ||
448 | } | ||
449 | |||
450 | // resolve alias names | ||
451 | while ( dt && dt-> m_isalias ) { | ||
452 | if ( dt-> m_depcnt == 1 ) { | ||
453 | struct dep_t *adt; | ||
454 | |||
455 | for ( adt = depend; adt; adt = adt-> m_next ) { | ||
456 | if ( strcmp ( adt-> m_name, dt-> m_deparr [0] ) == 0 ) | ||
457 | break; | ||
458 | } | ||
459 | if ( adt ) { | ||
460 | dt = adt; | ||
461 | mod = dt-> m_name; | ||
462 | path = dt-> m_path; | ||
463 | if ( !opt ) | ||
464 | opt = dt-> m_options; | ||
465 | } | ||
466 | else | ||
467 | return; | ||
468 | } | ||
469 | else | ||
470 | return; | ||
471 | } | ||
472 | |||
473 | if ( !path ) { | ||
474 | bb_error_msg ("module %s not found.", mod); | ||
475 | return; | ||
476 | } | ||
477 | |||
478 | // search for duplicates | ||
479 | for ( find = *head; find; find = find-> m_next ) { | ||
480 | if ( !strcmp ( mod, find-> m_name )) { | ||
481 | // found -> dequeue it | ||
482 | |||
483 | if ( find-> m_prev ) | ||
484 | find-> m_prev-> m_next = find-> m_next; | ||
485 | else | ||
486 | *head = find-> m_next; | ||
487 | |||
488 | if ( find-> m_next ) | ||
489 | find-> m_next-> m_prev = find-> m_prev; | ||
490 | else | ||
491 | *tail = find-> m_prev; | ||
492 | |||
493 | break; // there can be only one duplicate | ||
494 | } | ||
495 | } | ||
496 | |||
497 | if ( !find ) { // did not find a duplicate | ||
498 | find = (struct mod_list_t *) xmalloc ( sizeof(struct mod_list_t)); | ||
499 | find-> m_name = mod; | ||
500 | find-> m_path = path; | ||
501 | find-> m_options = opt; | ||
502 | } | ||
503 | |||
504 | // enqueue at tail | ||
505 | if ( *tail ) | ||
506 | (*tail)-> m_next = find; | ||
507 | find-> m_prev = *tail; | ||
508 | find-> m_next = 0; | ||
509 | |||
510 | if ( !*head ) | ||
511 | *head = find; | ||
512 | *tail = find; | ||
513 | |||
514 | if ( dt ) { | ||
515 | int i; | ||
516 | |||
517 | for ( i = 0; i < dt-> m_depcnt; i++ ) | ||
518 | check_dep ( dt-> m_deparr [i], head, tail ); | ||
519 | } | ||
520 | } | ||
521 | |||
522 | |||
523 | |||
524 | static int mod_insert ( char *mod, int argc, char **argv ) | ||
525 | { | ||
526 | struct mod_list_t *tail = 0; | ||
527 | struct mod_list_t *head = 0; | ||
528 | int rc; | ||
529 | |||
530 | // get dep list for module mod | ||
531 | check_dep ( mod, &head, &tail ); | ||
532 | |||
533 | if ( head && tail ) { | ||
534 | #if defined(CONFIG_FEATURE_2_6_MODULES) | ||
535 | if ( argc ) { | ||
536 | int i; | ||
537 | int l = 0; | ||
538 | |||
539 | // append module args | ||
540 | for ( i = 0; i < argc; i++ ) | ||
541 | l += ( bb_strlen ( argv [i] ) + 1 ); | ||
542 | |||
543 | head-> m_options = xrealloc ( head-> m_options, l + 1 ); | ||
544 | head-> m_options [0] = 0; | ||
545 | |||
546 | for ( i = 0; i < argc; i++ ) { | ||
547 | strcat ( head-> m_options, argv [i] ); | ||
548 | strcat ( head-> m_options, " " ); | ||
549 | } | ||
550 | } | ||
551 | #endif | ||
552 | |||
553 | // process tail ---> head | ||
554 | rc = mod_process ( tail, 1 ); | ||
555 | } | ||
556 | else | ||
557 | rc = 1; | ||
558 | |||
559 | return rc; | ||
560 | } | ||
561 | |||
562 | static int mod_remove ( char *mod ) | ||
563 | { | ||
564 | int rc; | ||
565 | static struct mod_list_t rm_a_dummy = { "-a", 0, 0 }; | ||
566 | |||
567 | struct mod_list_t *head = 0; | ||
568 | struct mod_list_t *tail = 0; | ||
569 | |||
570 | if ( mod ) | ||
571 | check_dep ( mod, &head, &tail ); | ||
572 | else // autoclean | ||
573 | head = tail = &rm_a_dummy; | ||
574 | |||
575 | if ( head && tail ) | ||
576 | rc = mod_process ( head, 0 ); // process head ---> tail | ||
577 | else | ||
578 | rc = 1; | ||
579 | return rc; | ||
580 | |||
581 | } | ||
582 | |||
583 | extern int modprobe_main(int argc, char** argv) | ||
584 | { | ||
585 | int opt; | ||
586 | int remove_opt = 0; | ||
587 | |||
588 | autoclean = show_only = quiet = do_syslog = verbose = 0; | ||
589 | |||
590 | while ((opt = getopt(argc, argv, "acdklnqrst:vVC:")) != -1) { | ||
591 | switch(opt) { | ||
592 | case 'c': // no config used | ||
593 | case 'l': // no pattern matching | ||
594 | return EXIT_SUCCESS; | ||
595 | break; | ||
596 | case 'C': // no config used | ||
597 | case 't': // no pattern matching | ||
598 | bb_error_msg_and_die("-t and -C not supported"); | ||
599 | |||
600 | case 'a': // ignore | ||
601 | case 'd': // ignore | ||
602 | break; | ||
603 | case 'k': | ||
604 | autoclean++; | ||
605 | break; | ||
606 | case 'n': | ||
607 | show_only++; | ||
608 | break; | ||
609 | case 'q': | ||
610 | quiet++; | ||
611 | break; | ||
612 | case 'r': | ||
613 | remove_opt++; | ||
614 | break; | ||
615 | case 's': | ||
616 | do_syslog++; | ||
617 | break; | ||
618 | case 'v': | ||
619 | verbose++; | ||
620 | break; | ||
621 | case 'V': | ||
622 | default: | ||
623 | bb_show_usage(); | ||
624 | break; | ||
625 | } | ||
626 | } | ||
627 | |||
628 | depend = build_dep ( ); | ||
629 | |||
630 | if ( !depend ) | ||
631 | bb_error_msg_and_die ( "could not parse modules.dep\n" ); | ||
632 | |||
633 | if (remove_opt) { | ||
634 | int rc = EXIT_SUCCESS; | ||
635 | do { | ||
636 | if (mod_remove ( optind < argc ? | ||
637 | bb_xstrdup (argv [optind]) : NULL )) { | ||
638 | bb_error_msg ("failed to remove module %s", | ||
639 | argv [optind] ); | ||
640 | rc = EXIT_FAILURE; | ||
641 | } | ||
642 | } while ( ++optind < argc ); | ||
643 | |||
644 | return rc; | ||
645 | } | ||
646 | |||
647 | if (optind >= argc) | ||
648 | bb_error_msg_and_die ( "No module or pattern provided\n" ); | ||
649 | |||
650 | if ( mod_insert ( bb_xstrdup ( argv [optind] ), argc - optind - 1, argv + optind + 1 )) | ||
651 | bb_error_msg_and_die ( "failed to load module %s", argv [optind] ); | ||
652 | |||
653 | return EXIT_SUCCESS; | ||
654 | } | ||