diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-07-10 14:14:45 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-07-10 14:14:45 +0000 |
commit | 7f950a93ffd00cdeda83f06a447943c360005c34 (patch) | |
tree | 46351af3216642f9bbfce907205f28f47a622ee6 | |
parent | 784369987f3014d5841e319fdef5211fc6b97236 (diff) | |
download | busybox-w32-7f950a93ffd00cdeda83f06a447943c360005c34.tar.gz busybox-w32-7f950a93ffd00cdeda83f06a447943c360005c34.tar.bz2 busybox-w32-7f950a93ffd00cdeda83f06a447943c360005c34.zip |
modprobe-small: add depfile creation
-rw-r--r-- | modutils/modprobe-small.c | 115 |
1 files changed, 108 insertions, 7 deletions
diff --git a/modutils/modprobe-small.c b/modutils/modprobe-small.c index 1a9d98422..cf9be47a6 100644 --- a/modutils/modprobe-small.c +++ b/modutils/modprobe-small.c | |||
@@ -43,6 +43,7 @@ typedef struct module_info { | |||
43 | struct globals { | 43 | struct globals { |
44 | module_info *modinfo; | 44 | module_info *modinfo; |
45 | char *module_load_options; | 45 | char *module_load_options; |
46 | smallint dep_bb_seen; | ||
46 | int module_count; | 47 | int module_count; |
47 | int module_found_idx; | 48 | int module_found_idx; |
48 | int stringbuf_idx; | 49 | int stringbuf_idx; |
@@ -51,6 +52,7 @@ struct globals { | |||
51 | }; | 52 | }; |
52 | #define G (*ptr_to_globals) | 53 | #define G (*ptr_to_globals) |
53 | #define modinfo (G.modinfo ) | 54 | #define modinfo (G.modinfo ) |
55 | #define dep_bb_seen (G.dep_bb_seen ) | ||
54 | #define module_count (G.module_count ) | 56 | #define module_count (G.module_count ) |
55 | #define module_found_idx (G.module_found_idx ) | 57 | #define module_found_idx (G.module_found_idx ) |
56 | #define module_load_options (G.module_load_options) | 58 | #define module_load_options (G.module_load_options) |
@@ -320,13 +322,28 @@ static FAST_FUNC int fileAction(const char *pathname, | |||
320 | return TRUE; | 322 | return TRUE; |
321 | } | 323 | } |
322 | 324 | ||
323 | static void load_dep_bb(void) | 325 | static int load_dep_bb(void) |
324 | { | 326 | { |
325 | char *line; | 327 | char *line; |
326 | FILE *fp = fopen(DEPFILE_BB, "r"); | 328 | FILE *fp = fopen(DEPFILE_BB, "r"); |
327 | 329 | ||
328 | if (!fp) | 330 | if (!fp) |
329 | return; | 331 | return 0; |
332 | |||
333 | dep_bb_seen = 1; | ||
334 | dbg1_error_msg("loading "DEPFILE_BB); | ||
335 | |||
336 | /* Why? There is a rare scenario: we did not find modprobe.dep.bb, | ||
337 | * we scanned the dir and found no module by name, then we search | ||
338 | * for alias (full scan), and we decided to generate modprobe.dep.bb. | ||
339 | * But we see modprobe.dep.bb.new! Other modprobe is at work! | ||
340 | * We wait and other modprobe renames it to modprobe.dep.bb. | ||
341 | * Now we can use it. | ||
342 | * But we already have modinfo[] filled, and "module_count = 0" | ||
343 | * makes us start anew. Yes, we leak modinfo[].xxx pointers - | ||
344 | * there is not much of data there anyway. */ | ||
345 | module_count = 0; | ||
346 | memset(&modinfo[0], 0, sizeof(modinfo[0])); | ||
330 | 347 | ||
331 | while ((line = xmalloc_fgetline(fp)) != NULL) { | 348 | while ((line = xmalloc_fgetline(fp)) != NULL) { |
332 | char* space; | 349 | char* space; |
@@ -355,13 +372,74 @@ static void load_dep_bb(void) | |||
355 | free(line); | 372 | free(line); |
356 | } | 373 | } |
357 | } | 374 | } |
375 | return 1; | ||
376 | } | ||
377 | |||
378 | static int start_dep_bb_writeout(void) | ||
379 | { | ||
380 | int fd; | ||
381 | |||
382 | fd = open(DEPFILE_BB".new", O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0644); | ||
383 | if (fd < 0) { | ||
384 | if (errno == EEXIST) { | ||
385 | int count = 5 * 20; | ||
386 | dbg1_error_msg(DEPFILE_BB".new exists, waiting for "DEPFILE_BB); | ||
387 | while (1) { | ||
388 | usleep(1000*1000 / 20); | ||
389 | if (load_dep_bb()) { | ||
390 | dbg1_error_msg(DEPFILE_BB" appeared"); | ||
391 | return -2; /* magic number */ | ||
392 | } | ||
393 | if (!--count) | ||
394 | break; | ||
395 | } | ||
396 | bb_error_msg("deleting stale %s", DEPFILE_BB".new"); | ||
397 | fd = open_or_warn(DEPFILE_BB".new", O_WRONLY | O_CREAT | O_TRUNC); | ||
398 | } | ||
399 | } | ||
400 | dbg1_error_msg("opened "DEPFILE_BB".new:%d", fd); | ||
401 | return fd; | ||
402 | } | ||
403 | |||
404 | static void write_out_dep_bb(int fd) | ||
405 | { | ||
406 | int i; | ||
407 | FILE *fp; | ||
408 | |||
409 | /* We want good error reporting. fdprintf is not good enough. */ | ||
410 | fp = fdopen(fd, "w"); | ||
411 | if (!fp) { | ||
412 | close(fd); | ||
413 | goto err; | ||
414 | } | ||
415 | i = 0; | ||
416 | while (modinfo[i].pathname) { | ||
417 | fprintf(fp, "%s%s%s\n" "%s%s\n", | ||
418 | modinfo[i].pathname, modinfo[i].aliases[0] ? " " : "", modinfo[i].aliases, | ||
419 | modinfo[i].deps, modinfo[i].deps[0] ? "\n" : ""); | ||
420 | i++; | ||
421 | } | ||
422 | /* Badly formatted depfile is a no-no. Be paranoid. */ | ||
423 | errno = 0; | ||
424 | if (ferror(fp) | fclose(fp)) | ||
425 | goto err; | ||
426 | if (rename(DEPFILE_BB".new", DEPFILE_BB) != 0) { | ||
427 | err: | ||
428 | bb_perror_msg("can't create %s", DEPFILE_BB); | ||
429 | unlink(DEPFILE_BB".new"); | ||
430 | } else { | ||
431 | dbg1_error_msg("created "DEPFILE_BB); | ||
432 | } | ||
358 | } | 433 | } |
359 | 434 | ||
360 | static module_info* find_alias(const char *alias) | 435 | static module_info* find_alias(const char *alias) |
361 | { | 436 | { |
362 | int i; | 437 | int i; |
438 | int dep_bb_fd; | ||
439 | module_info *result; | ||
363 | dbg1_error_msg("find_alias('%s')", alias); | 440 | dbg1_error_msg("find_alias('%s')", alias); |
364 | 441 | ||
442 | try_again: | ||
365 | /* First try to find by name (cheaper) */ | 443 | /* First try to find by name (cheaper) */ |
366 | i = 0; | 444 | i = 0; |
367 | while (modinfo[i].pathname) { | 445 | while (modinfo[i].pathname) { |
@@ -376,13 +454,22 @@ static module_info* find_alias(const char *alias) | |||
376 | i++; | 454 | i++; |
377 | } | 455 | } |
378 | 456 | ||
457 | /* Ok, we definitely have to scan module bodies. This is a good | ||
458 | * moment to generate modprobe.dep.bb, if it does not exist yet */ | ||
459 | dep_bb_fd = dep_bb_seen ? -1 : start_dep_bb_writeout(); | ||
460 | if (dep_bb_fd == -2) /* modprobe.dep.bb appeared? */ | ||
461 | goto try_again; | ||
462 | |||
379 | /* Scan all module bodies, extract modinfo (it contains aliases) */ | 463 | /* Scan all module bodies, extract modinfo (it contains aliases) */ |
380 | i = 0; | 464 | i = 0; |
465 | result = NULL; | ||
381 | while (modinfo[i].pathname) { | 466 | while (modinfo[i].pathname) { |
382 | char *desc, *s; | 467 | char *desc, *s; |
383 | if (!modinfo[i].aliases) { | 468 | if (!modinfo[i].aliases) { |
384 | parse_module(&modinfo[i], modinfo[i].pathname); | 469 | parse_module(&modinfo[i], modinfo[i].pathname); |
385 | } | 470 | } |
471 | if (result) | ||
472 | continue; | ||
386 | /* "alias1 symbol:sym1 alias2 symbol:sym2" */ | 473 | /* "alias1 symbol:sym1 alias2 symbol:sym2" */ |
387 | desc = str_2_list(modinfo[i].aliases); | 474 | desc = str_2_list(modinfo[i].aliases); |
388 | /* Does matching substring exist? */ | 475 | /* Does matching substring exist? */ |
@@ -392,17 +479,25 @@ static module_info* find_alias(const char *alias) | |||
392 | * "pci:v000010DEd000000D9sv*sd*bc*sc*i*". | 479 | * "pci:v000010DEd000000D9sv*sd*bc*sc*i*". |
393 | * Plain strcmp() won't catch that */ | 480 | * Plain strcmp() won't catch that */ |
394 | if (fnmatch(s, alias, 0) == 0) { | 481 | if (fnmatch(s, alias, 0) == 0) { |
395 | free(desc); | ||
396 | dbg1_error_msg("found alias '%s' in module '%s'", | 482 | dbg1_error_msg("found alias '%s' in module '%s'", |
397 | alias, modinfo[i].pathname); | 483 | alias, modinfo[i].pathname); |
398 | return &modinfo[i]; | 484 | result = &modinfo[i]; |
485 | break; | ||
399 | } | 486 | } |
400 | } | 487 | } |
401 | free(desc); | 488 | free(desc); |
489 | if (result && dep_bb_fd < 0) | ||
490 | return result; | ||
402 | i++; | 491 | i++; |
403 | } | 492 | } |
404 | dbg1_error_msg("find_alias '%s' returns NULL", alias); | 493 | |
405 | return NULL; | 494 | /* Create module.dep.bb if needed */ |
495 | if (dep_bb_fd >= 0) { | ||
496 | write_out_dep_bb(dep_bb_fd); | ||
497 | } | ||
498 | |||
499 | dbg1_error_msg("find_alias '%s' returns %p", alias, result); | ||
500 | return result; | ||
406 | } | 501 | } |
407 | 502 | ||
408 | #if ENABLE_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED | 503 | #if ENABLE_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED |
@@ -497,7 +592,7 @@ static void process_module(char *name, const char *cmdline_options) | |||
497 | 592 | ||
498 | /* rmmod? unload it by name */ | 593 | /* rmmod? unload it by name */ |
499 | if (is_rmmod) { | 594 | if (is_rmmod) { |
500 | if (delete_module(name, O_NONBLOCK|O_EXCL) != 0 | 595 | if (delete_module(name, O_NONBLOCK | O_EXCL) != 0 |
501 | && !(option_mask32 & OPT_q) | 596 | && !(option_mask32 & OPT_q) |
502 | ) { | 597 | ) { |
503 | bb_perror_msg("remove '%s'", name); | 598 | bb_perror_msg("remove '%s'", name); |
@@ -511,6 +606,8 @@ static void process_module(char *name, const char *cmdline_options) | |||
511 | } | 606 | } |
512 | 607 | ||
513 | if (!info) { /* both dirscan and find_alias found nothing */ | 608 | if (!info) { /* both dirscan and find_alias found nothing */ |
609 | bb_error_msg("module '%s' not found", name); | ||
610 | //TODO: _and_die()? | ||
514 | goto ret; | 611 | goto ret; |
515 | } | 612 | } |
516 | 613 | ||
@@ -637,6 +734,10 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) | |||
637 | argv[1] = NULL; | 734 | argv[1] = NULL; |
638 | #endif | 735 | #endif |
639 | 736 | ||
737 | /* Prevent ugly corner cases with no modules at all */ | ||
738 | modinfo = xzalloc(sizeof(modinfo[0])); | ||
739 | |||
740 | /* Try to load modprobe.dep.bb */ | ||
640 | load_dep_bb(); | 741 | load_dep_bb(); |
641 | 742 | ||
642 | /* Load/remove modules. | 743 | /* Load/remove modules. |