source: MondoRescue/branches/stable/mindi-busybox/modutils/modprobe.c@ 1770

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 16 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

File size: 23.0 KB
RevLine 
[821]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 * Copyright (c) 2005 by Jim Bauer, jfbauer@nfr.com
8 *
9 * Portions Copyright (c) 2005 by Yann E. MORIN, yann.morin.1998@anciens.enib.fr
10 *
11 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
12*/
13
[1770]14#include "libbb.h"
[821]15#include <sys/utsname.h>
16#include <fnmatch.h>
17
18struct mod_opt_t { /* one-way list of options to pass to a module */
19 char * m_opt_val;
20 struct mod_opt_t * m_next;
21};
22
23struct dep_t { /* one-way list of dependency rules */
24 /* a dependency rule */
[1770]25 char * m_name; /* the module name*/
26 char * m_path; /* the module file path */
27 struct mod_opt_t * m_options; /* the module options */
[821]28
[1770]29 int m_isalias : 1; /* the module is an alias */
30 int m_reserved : 15; /* stuffin' */
[821]31
[1770]32 int m_depcnt : 16; /* the number of dependable module(s) */
33 char ** m_deparr; /* the list of dependable module(s) */
[821]34
[1770]35 struct dep_t * m_next; /* the next dependency rule */
[821]36};
37
38struct mod_list_t { /* two-way list of modules to process */
39 /* a module description */
[1770]40 const char * m_name;
41 char * m_path;
42 struct mod_opt_t * m_options;
[821]43
44 struct mod_list_t * m_prev;
45 struct mod_list_t * m_next;
46};
47
48
49static struct dep_t *depend;
50
51#define main_options "acdklnqrst:vVC:"
52#define INSERT_ALL 1 /* a */
53#define DUMP_CONF_EXIT 2 /* c */
54#define D_OPT_IGNORED 4 /* d */
55#define AUTOCLEAN_FLG 8 /* k */
56#define LIST_ALL 16 /* l */
57#define SHOW_ONLY 32 /* n */
58#define QUIET 64 /* q */
59#define REMOVE_OPT 128 /* r */
60#define DO_SYSLOG 256 /* s */
61#define RESTRICT_DIR 512 /* t */
62#define VERBOSE 1024 /* v */
63#define VERSION_ONLY 2048 /* V */
64#define CONFIG_FILE 4096 /* C */
65
66#define autoclean (main_opts & AUTOCLEAN_FLG)
67#define show_only (main_opts & SHOW_ONLY)
68#define quiet (main_opts & QUIET)
69#define remove_opt (main_opts & REMOVE_OPT)
70#define do_syslog (main_opts & DO_SYSLOG)
71#define verbose (main_opts & VERBOSE)
72
73static int main_opts;
74
[1770]75static int parse_tag_value(char *buffer, char **ptag, char **pvalue)
[821]76{
77 char *tag, *value;
78
[1770]79 buffer = skip_whitespace(buffer);
[821]80 tag = value = buffer;
[1770]81 while (!isspace(*value))
[821]82 if (!*value) return 0;
83 else value++;
84 *value++ = 0;
[1770]85 value = skip_whitespace(value);
[821]86 if (!*value) return 0;
87
88 *ptag = tag;
89 *pvalue = value;
90
91 return 1;
92}
93
94/*
95 * This function appends an option to a list
96 */
[1770]97static struct mod_opt_t *append_option(struct mod_opt_t *opt_list, char *opt)
[821]98{
99 struct mod_opt_t *ol = opt_list;
100
[1770]101 if (ol) {
102 while (ol->m_next) {
103 ol = ol->m_next;
[821]104 }
[1770]105 ol->m_next = xmalloc(sizeof(struct mod_opt_t));
106 ol = ol->m_next;
[821]107 } else {
[1770]108 ol = opt_list = xmalloc(sizeof(struct mod_opt_t));
[821]109 }
110
[1770]111 ol->m_opt_val = xstrdup(opt);
112 ol->m_next = NULL;
[821]113
114 return opt_list;
115}
116
117#if ENABLE_FEATURE_MODPROBE_MULTIPLE_OPTIONS
[1770]118/* static char* parse_command_string(char* src, char **dst);
[821]119 * src: pointer to string containing argument
120 * dst: pointer to where to store the parsed argument
121 * return value: the pointer to the first char after the parsed argument,
122 * NULL if there was no argument parsed (only trailing spaces).
[1770]123 * Note that memory is allocated with xstrdup when a new argument was
[821]124 * parsed. Don't forget to free it!
125 */
126#define ARG_EMPTY 0x00
127#define ARG_IN_DQUOTES 0x01
128#define ARG_IN_SQUOTES 0x02
[1770]129static char *parse_command_string(char *src, char **dst)
[821]130{
131 int opt_status = ARG_EMPTY;
132 char* tmp_str;
133
134 /* Dumb you, I have nothing to do... */
[1770]135 if (src == NULL) return src;
[821]136
137 /* Skip leading spaces */
[1770]138 while (*src == ' ') {
[821]139 src++;
140 }
141 /* Is the end of string reached? */
[1770]142 if (*src == '\0') {
[821]143 return NULL;
144 }
145 /* Reached the start of an argument
146 * By the way, we duplicate a little too much
147 * here but what is too much is freed later. */
[1770]148 *dst = tmp_str = xstrdup(src);
[821]149 /* Get to the end of that argument */
[1770]150 while (*tmp_str != '\0'
151 && (*tmp_str != ' ' || (opt_status & (ARG_IN_DQUOTES | ARG_IN_SQUOTES)))
152 ) {
153 switch (*tmp_str) {
154 case '\'':
155 if (opt_status & ARG_IN_DQUOTES) {
156 /* Already in double quotes, keep current char as is */
157 } else {
158 /* shift left 1 char, until end of string: get rid of the opening/closing quotes */
159 memmove(tmp_str, tmp_str + 1, strlen(tmp_str));
160 /* mark me: we enter or leave single quotes */
161 opt_status ^= ARG_IN_SQUOTES;
162 /* Back one char, as we need to re-scan the new char there. */
163 tmp_str--;
164 }
[821]165 break;
[1770]166 case '"':
167 if (opt_status & ARG_IN_SQUOTES) {
168 /* Already in single quotes, keep current char as is */
169 } else {
170 /* shift left 1 char, until end of string: get rid of the opening/closing quotes */
171 memmove(tmp_str, tmp_str + 1, strlen(tmp_str));
172 /* mark me: we enter or leave double quotes */
173 opt_status ^= ARG_IN_DQUOTES;
174 /* Back one char, as we need to re-scan the new char there. */
175 tmp_str--;
176 }
[821]177 break;
[1770]178 case '\\':
179 if (opt_status & ARG_IN_SQUOTES) {
180 /* Between single quotes: keep as is. */
181 } else {
182 switch (*(tmp_str+1)) {
183 case 'a':
184 case 'b':
185 case 't':
186 case 'n':
187 case 'v':
188 case 'f':
189 case 'r':
190 case '0':
191 /* We escaped a special character. For now, keep
192 * both the back-slash and the following char. */
193 tmp_str++; src++;
194 break;
195 default:
196 /* We escaped a space or a single or double quote,
197 * or a back-slash, or a non-escapable char. Remove
198 * the '\' and keep the new current char as is. */
199 memmove(tmp_str, tmp_str + 1, strlen(tmp_str));
200 break;
[821]201 }
[1770]202 }
[821]203 break;
[1770]204 /* Any other char that is special shall appear here.
205 * Example: $ starts a variable
206 case '$':
207 do_variable_expansion();
208 break;
209 * */
210 default:
211 /* any other char is kept as is. */
212 break;
[821]213 }
214 tmp_str++; /* Go to next char */
215 src++; /* Go to next char to find the end of the argument. */
216 }
217 /* End of string, but still no ending quote */
[1770]218 if (opt_status & (ARG_IN_DQUOTES | ARG_IN_SQUOTES)) {
219 bb_error_msg_and_die("unterminated (single or double) quote in options list: %s", src);
[821]220 }
221 *tmp_str++ = '\0';
[1770]222 *dst = xrealloc(*dst, (tmp_str - *dst));
[821]223 return src;
224}
225#else
226#define parse_command_string(src, dst) (0)
227#endif /* ENABLE_FEATURE_MODPROBE_MULTIPLE_OPTIONS */
228
229/*
230 * This function reads aliases and default module options from a configuration file
231 * (/etc/modprobe.conf syntax). It supports includes (only files, no directories).
232 */
[1770]233static void include_conf(struct dep_t **first, struct dep_t **current, char *buffer, int buflen, int fd)
[821]234{
235 int continuation_line = 0;
236
[1770]237 // alias parsing is not 100% correct (no correct handling of continuation lines within an alias)!
[821]238
[1770]239 while (reads(fd, buffer, buflen)) {
[821]240 int l;
241 char *p;
242
[1770]243 p = strchr(buffer, '#');
244 if (p)
[821]245 *p = 0;
246
[1770]247 l = strlen(buffer);
[821]248
[1770]249 while (l && isspace(buffer[l-1])) {
250 buffer[l-1] = 0;
[821]251 l--;
252 }
253
[1770]254 if (l == 0) {
[821]255 continuation_line = 0;
256 continue;
257 }
258
[1770]259 if (!continuation_line) {
260 if ((strncmp(buffer, "alias", 5) == 0) && isspace(buffer[5])) {
[821]261 char *alias, *mod;
262
[1770]263 if (parse_tag_value(buffer + 6, &alias, &mod)) {
[821]264 /* handle alias as a module dependent on the aliased module */
[1770]265 if (!*current) {
266 (*first) = (*current) = xzalloc(sizeof(struct dep_t));
267 } else {
268 (*current)->m_next = xzalloc(sizeof(struct dep_t));
269 (*current) = (*current)->m_next;
[821]270 }
[1770]271 (*current)->m_name = xstrdup(alias);
272 (*current)->m_isalias = 1;
[821]273
[1770]274 if ((strcmp(mod, "off") == 0) || (strcmp(mod, "null") == 0)) {
275 (*current)->m_depcnt = 0;
276 (*current)->m_deparr = 0;
277 } else {
278 (*current)->m_depcnt = 1;
279 (*current)->m_deparr = xmalloc(1 * sizeof(char *));
280 (*current)->m_deparr[0] = xstrdup(mod);
[821]281 }
[1770]282 (*current)->m_next = 0;
[821]283 }
[1770]284 } else if ((strncmp(buffer, "options", 7) == 0) && isspace(buffer[7])) {
[821]285 char *mod, *opt;
286
287 /* split the line in the module/alias name, and options */
[1770]288 if (parse_tag_value(buffer + 8, &mod, &opt)) {
[821]289 struct dep_t *dt;
290
291 /* find the corresponding module */
[1770]292 for (dt = *first; dt; dt = dt->m_next) {
293 if (strcmp(dt->m_name, mod) == 0)
[821]294 break;
295 }
[1770]296 if (dt) {
297 if (ENABLE_FEATURE_MODPROBE_MULTIPLE_OPTIONS) {
[821]298 char* new_opt = NULL;
[1770]299 while ((opt = parse_command_string(opt, &new_opt))) {
300 dt->m_options = append_option(dt->m_options, new_opt);
[821]301 }
302 } else {
[1770]303 dt->m_options = append_option(dt->m_options, opt);
[821]304 }
305 }
306 }
[1770]307 } else if ((strncmp(buffer, "include", 7) == 0) && isspace(buffer[7])) {
308 int fdi; char *filename;
[821]309
[1770]310 filename = skip_whitespace(buffer + 8);
[821]311
[1770]312 if ((fdi = open(filename, O_RDONLY)) >= 0) {
[821]313 include_conf(first, current, buffer, buflen, fdi);
314 close(fdi);
315 }
316 }
317 }
318 }
319}
320
321/*
[1770]322 * This function builds a list of dependency rules from /lib/modules/`uname -r`/modules.dep.
[821]323 * It then fills every modules and aliases with their default options, found by parsing
324 * modprobe.conf (or modules.conf, or conf.modules).
325 */
[1770]326static struct dep_t *build_dep(void)
[821]327{
328 int fd;
329 struct utsname un;
330 struct dep_t *first = 0;
331 struct dep_t *current = 0;
332 char buffer[2048];
333 char *filename;
334 int continuation_line = 0;
335 int k_version;
336
[1770]337 if (uname(&un))
[821]338 bb_error_msg_and_die("can't determine kernel version");
339
[1770]340 k_version = 0;
[821]341 if (un.release[0] == '2') {
342 k_version = un.release[2] - '0';
343 }
344
[1770]345 filename = xasprintf("/lib/modules/%s/modules.dep", un.release);
346 fd = open(filename, O_RDONLY);
[821]347 if (ENABLE_FEATURE_CLEAN_UP)
348 free(filename);
349 if (fd < 0) {
350 /* Ok, that didn't work. Fall back to looking in /lib/modules */
[1770]351 fd = open("/lib/modules/modules.dep", O_RDONLY);
352 if (fd < 0) {
[821]353 return 0;
354 }
355 }
356
[1770]357 while (reads(fd, buffer, sizeof(buffer))) {
358 int l = strlen(buffer);
[821]359 char *p = 0;
360
[1770]361 while (l > 0 && isspace(buffer[l-1])) {
362 buffer[l-1] = 0;
[821]363 l--;
364 }
365
[1770]366 if (l == 0) {
[821]367 continuation_line = 0;
368 continue;
369 }
370
371 /* Is this a new module dep description? */
[1770]372 if (!continuation_line) {
[821]373 /* find the dep beginning */
[1770]374 char *col = strchr(buffer, ':');
[821]375 char *dot = col;
376
[1770]377 if (col) {
[821]378 /* This line is a dep description */
[1770]379 const char *mods;
[821]380 char *modpath;
381 char *mod;
382
383 /* Find the beginning of the module file name */
384 *col = 0;
[1770]385 mods = bb_basename(buffer);
[821]386
387 /* find the path of the module */
[1770]388 modpath = strchr(buffer, '/'); /* ... and this is the path */
389 if (!modpath)
[821]390 modpath = buffer; /* module with no path */
391 /* find the end of the module name in the file name */
[1770]392 if (ENABLE_FEATURE_2_6_MODULES &&
393 (k_version > 4) && (*(col-3) == '.') &&
394 (*(col-2) == 'k') && (*(col-1) == 'o'))
[821]395 dot = col - 3;
396 else
[1770]397 if ((*(col-2) == '.') && (*(col-1) == 'o'))
[821]398 dot = col - 2;
399
[1770]400 mod = xstrndup(mods, dot - mods);
[821]401
402 /* enqueue new module */
[1770]403 if (!current) {
404 first = current = xmalloc(sizeof(struct dep_t));
405 } else {
406 current->m_next = xmalloc(sizeof(struct dep_t));
407 current = current->m_next;
[821]408 }
[1770]409 current->m_name = mod;
410 current->m_path = xstrdup(modpath);
411 current->m_options = NULL;
412 current->m_isalias = 0;
413 current->m_depcnt = 0;
414 current->m_deparr = 0;
415 current->m_next = 0;
[821]416
417 p = col + 1;
[1770]418 } else
[821]419 /* this line is not a dep description */
420 p = 0;
[1770]421 } else
[821]422 /* It's a dep description continuation */
423 p = buffer;
424
[1770]425 while (p && *p && isblank(*p))
[821]426 p++;
427
428 /* p points to the first dependable module; if NULL, no dependable module */
[1770]429 if (p && *p) {
430 char *end = &buffer[l-1];
431 const char *deps;
[821]432 char *dep;
433 char *next;
434 int ext = 0;
435
[1770]436 while (isblank(*end) || (*end == '\\'))
[821]437 end--;
438
[1770]439 do {
[821]440 /* search the end of the dependency */
[1770]441 next = strchr(p, ' ');
442 if (next) {
[821]443 *next = 0;
444 next--;
[1770]445 } else
[821]446 next = end;
447
448 /* find the beginning of the module file name */
[1770]449 deps = bb_basename(p);
450 if (deps == p) {
451 while (isblank(*deps))
[821]452 deps++;
453 }
454
455 /* find the end of the module name in the file name */
[1770]456 if (ENABLE_FEATURE_2_6_MODULES
457 && (k_version > 4) && (*(next-2) == '.')
458 && (*(next-1) == 'k') && (*next == 'o'))
[821]459 ext = 3;
460 else
[1770]461 if ((*(next-1) == '.') && (*next == 'o'))
[821]462 ext = 2;
463
464 /* Cope with blank lines */
465 if ((next-deps-ext+1) <= 0)
466 continue;
[1770]467 dep = xstrndup(deps, next - deps - ext + 1);
[821]468
469 /* Add the new dependable module name */
[1770]470 current->m_depcnt++;
471 current->m_deparr = xrealloc(current->m_deparr,
472 sizeof(char *) * current->m_depcnt);
473 current->m_deparr[current->m_depcnt - 1] = dep;
[821]474
475 p = next + 2;
476 } while (next < end);
477 }
478
479 /* is there other dependable module(s) ? */
[1770]480 if (buffer[l-1] == '\\')
[821]481 continuation_line = 1;
482 else
483 continuation_line = 0;
484 }
[1770]485 close(fd);
[821]486
487 /*
488 * First parse system-specific options and aliases
489 * as they take precedence over the kernel ones.
[1770]490 * >=2.6: we only care about modprobe.conf
491 * <=2.4: we care about modules.conf and conf.modules
[821]492 */
[1770]493 if (ENABLE_FEATURE_2_6_MODULES
494 && (fd = open("/etc/modprobe.conf", O_RDONLY)) < 0)
495 if (ENABLE_FEATURE_2_4_MODULES
496 && (fd = open("/etc/modules.conf", O_RDONLY)) < 0)
497 if (ENABLE_FEATURE_2_4_MODULES)
498 fd = open("/etc/conf.modules", O_RDONLY);
[821]499
500 if (fd >= 0) {
[1770]501 include_conf(&first, &current, buffer, sizeof(buffer), fd);
[821]502 close(fd);
503 }
504
505 /* Only 2.6 has a modules.alias file */
506 if (ENABLE_FEATURE_2_6_MODULES) {
[1770]507 /* Parse kernel-declared module aliases */
508 filename = xasprintf("/lib/modules/%s/modules.alias", un.release);
509 fd = open(filename, O_RDONLY);
510 if (fd < 0) {
[821]511 /* Ok, that didn't work. Fall back to looking in /lib/modules */
[1770]512 fd = open("/lib/modules/modules.alias", O_RDONLY);
[821]513 }
514 if (ENABLE_FEATURE_CLEAN_UP)
515 free(filename);
516
517 if (fd >= 0) {
[1770]518 include_conf(&first, &current, buffer, sizeof(buffer), fd);
[821]519 close(fd);
520 }
[1770]521
522 /* Parse kernel-declared symbol aliases */
523 filename = xasprintf("/lib/modules/%s/modules.symbols", un.release);
524 fd = open(filename, O_RDONLY);
525 if (fd < 0) {
526 /* Ok, that didn't work. Fall back to looking in /lib/modules */
527 fd = open("/lib/modules/modules.symbols", O_RDONLY);
528 }
529 if (ENABLE_FEATURE_CLEAN_UP)
530 free(filename);
531
532 if (fd >= 0) {
533 include_conf(&first, &current, buffer, sizeof(buffer), fd);
534 close(fd);
535 }
[821]536 }
537
538 return first;
539}
540
541/* return 1 = loaded, 0 = not loaded, -1 = can't tell */
[1770]542static int already_loaded(const char *name)
[821]543{
544 int fd, ret = 0;
545 char buffer[4096];
546
[1770]547 fd = open("/proc/modules", O_RDONLY);
[821]548 if (fd < 0)
549 return -1;
550
[1770]551 while (reads(fd, buffer, sizeof(buffer))) {
[821]552 char *p;
553
554 p = strchr (buffer, ' ');
555 if (p) {
556 const char *n;
557
558 // Truncate buffer at first space and check for matches, with
559 // the idiosyncrasy that _ and - are interchangeable because the
560 // 2.6 kernel does weird things.
561
562 *p = 0;
563 for (p = buffer, n = name; ; p++, n++) {
564 if (*p != *n) {
565 if ((*p == '_' || *p == '-') && (*n == '_' || *n == '-'))
566 continue;
567 break;
568 }
569 // If we made it to the end, that's a match.
570 if (!*p) {
571 ret = 1;
572 goto done;
573 }
574 }
575 }
576 }
577done:
578 close (fd);
579 return ret;
580}
581
[1770]582static int mod_process(const struct mod_list_t *list, int do_insert)
[821]583{
584 int rc = 0;
585 char **argv = NULL;
586 struct mod_opt_t *opts;
587 int argc_malloc; /* never used when CONFIG_FEATURE_CLEAN_UP not defined */
588 int argc;
589
[1770]590 while (list) {
[821]591 argc = 0;
[1770]592 if (ENABLE_FEATURE_CLEAN_UP)
[821]593 argc_malloc = 0;
594 /* If CONFIG_FEATURE_CLEAN_UP is not defined, then we leak memory
595 * each time we allocate memory for argv.
596 * But it is (quite) small amounts of memory that leak each
597 * time a module is loaded, and it is reclaimed when modprobe
598 * exits anyway (even when standalone shell?).
599 * This could become a problem when loading a module with LOTS of
600 * dependencies, with LOTS of options for each dependencies, with
601 * very little memory on the target... But in that case, the module
602 * would not load because there is no more memory, so there's no
603 * problem. */
604 /* enough for minimal insmod (5 args + NULL) or rmmod (3 args + NULL) */
[1770]605 argv = xmalloc(6 * sizeof(char*));
606 if (do_insert) {
607 if (already_loaded(list->m_name) != 1) {
608 argv[argc++] = (char*)"insmod";
[821]609 if (ENABLE_FEATURE_2_4_MODULES) {
610 if (do_syslog)
[1770]611 argv[argc++] = (char*)"-s";
[821]612 if (autoclean)
[1770]613 argv[argc++] = (char*)"-k";
[821]614 if (quiet)
[1770]615 argv[argc++] = (char*)"-q";
616 else if (verbose) /* verbose and quiet are mutually exclusive */
617 argv[argc++] = (char*)"-v";
[821]618 }
[1770]619 argv[argc++] = list->m_path;
620 if (ENABLE_FEATURE_CLEAN_UP)
[821]621 argc_malloc = argc;
[1770]622 opts = list->m_options;
623 while (opts) {
[821]624 /* Add one more option */
625 argc++;
[1770]626 argv = xrealloc(argv,(argc + 1)* sizeof(char*));
627 argv[argc-1] = opts->m_opt_val;
628 opts = opts->m_next;
[821]629 }
630 }
631 } else {
632 /* modutils uses short name for removal */
[1770]633 if (already_loaded(list->m_name) != 0) {
634 argv[argc++] = (char*)"rmmod";
[821]635 if (do_syslog)
[1770]636 argv[argc++] = (char*)"-s";
637 argv[argc++] = (char*)list->m_name;
638 if (ENABLE_FEATURE_CLEAN_UP)
[821]639 argc_malloc = argc;
640 }
641 }
642 argv[argc] = NULL;
643
644 if (argc) {
645 if (verbose) {
[1770]646 printf("%s module %s\n", do_insert?"Loading":"Unloading", list->m_name);
[821]647 }
648 if (!show_only) {
[1770]649 int rc2 = wait4pid(spawn(argv));
[902]650
[821]651 if (do_insert) {
652 rc = rc2; /* only last module matters */
[1770]653 } else if (!rc2) {
[821]654 rc = 0; /* success if remove any mod */
655 }
656 }
[1770]657 if (ENABLE_FEATURE_CLEAN_UP) {
[821]658 /* the last value in the array has index == argc, but
659 * it is the terminating NULL, so we must not free it. */
[1770]660 while (argc_malloc < argc) {
661 free(argv[argc_malloc++]);
662 }
[821]663 }
664 }
[1770]665 if (ENABLE_FEATURE_CLEAN_UP) {
666 free(argv);
[821]667 argv = NULL;
668 }
[1770]669 list = do_insert ? list->m_prev : list->m_next;
[821]670 }
671 return (show_only) ? 0 : rc;
672}
673
674/*
[1770]675 * Check the matching between a pattern and a module name.
676 * We need this as *_* is equivalent to *-*, even in pattern matching.
677 */
678static int check_pattern(const char* pat_src, const char* mod_src)
679{
680 int ret;
681
682 if (ENABLE_FEATURE_MODPROBE_FANCY_ALIAS) {
683 char* pat;
684 char* mod;
685 char* p;
686
687 pat = xstrdup(pat_src);
688 mod = xstrdup(mod_src);
689
690 for (p = pat; (p = strchr(p, '-')); *p++ = '_');
691 for (p = mod; (p = strchr(p, '-')); *p++ = '_');
692
693 ret = fnmatch(pat, mod, 0);
694
695 if (ENABLE_FEATURE_CLEAN_UP) {
696 free(pat);
697 free(mod);
698 }
699
700 return ret;
701 } else {
702 return fnmatch(pat_src, mod_src, 0);
703 }
704}
705
706/*
[821]707 * Builds the dependency list (aka stack) of a module.
708 * head: the highest module in the stack (last to insmod, first to rmmod)
709 * tail: the lowest module in the stack (first to insmod, last to rmmod)
710 */
[1770]711static void check_dep(char *mod, struct mod_list_t **head, struct mod_list_t **tail)
[821]712{
713 struct mod_list_t *find;
714 struct dep_t *dt;
715 struct mod_opt_t *opt = 0;
716 char *path = 0;
717
718 /* Search for the given module name amongst all dependency rules.
719 * The module name in a dependency rule can be a shell pattern,
720 * so try to match the given module name against such a pattern.
721 * Of course if the name in the dependency rule is a plain string,
722 * then we consider it a pattern, and matching will still work. */
[1770]723 for (dt = depend; dt; dt = dt->m_next) {
724 if (check_pattern(dt->m_name, mod) == 0) {
[821]725 break;
726 }
727 }
728
[1770]729 if (!dt) {
730 bb_error_msg("module %s not found", mod);
[821]731 return;
732 }
733
734 // resolve alias names
[1770]735 while (dt->m_isalias) {
736 if (dt->m_depcnt == 1) {
[821]737 struct dep_t *adt;
738
[1770]739 for (adt = depend; adt; adt = adt->m_next) {
740 if (check_pattern(adt->m_name, dt->m_deparr[0]) == 0)
[821]741 break;
742 }
[1770]743 if (adt) {
[821]744 /* This is the module we are aliased to */
[1770]745 struct mod_opt_t *opts = dt->m_options;
[821]746 /* Option of the alias are appended to the options of the module */
[1770]747 while (opts) {
748 adt->m_options = append_option(adt->m_options, opts->m_opt_val);
749 opts = opts->m_next;
[821]750 }
751 dt = adt;
[1770]752 } else {
753 bb_error_msg("module %s not found", mod);
[821]754 return;
755 }
[1770]756 } else {
757 bb_error_msg("bad alias %s", dt->m_name);
[821]758 return;
759 }
760 }
761
[1770]762 mod = dt->m_name;
763 path = dt->m_path;
764 opt = dt->m_options;
[821]765
766 // search for duplicates
[1770]767 for (find = *head; find; find = find->m_next) {
768 if (!strcmp(mod, find->m_name)) {
769 // found ->dequeue it
[821]770
[1770]771 if (find->m_prev)
772 find->m_prev->m_next = find->m_next;
[821]773 else
[1770]774 *head = find->m_next;
[821]775
[1770]776 if (find->m_next)
777 find->m_next->m_prev = find->m_prev;
[821]778 else
[1770]779 *tail = find->m_prev;
[821]780
781 break; // there can be only one duplicate
782 }
783 }
784
[1770]785 if (!find) { // did not find a duplicate
786 find = xmalloc(sizeof(struct mod_list_t));
787 find->m_name = mod;
788 find->m_path = path;
789 find->m_options = opt;
[821]790 }
791
792 // enqueue at tail
[1770]793 if (*tail)
794 (*tail)->m_next = find;
795 find->m_prev = *tail;
796 find->m_next = 0;
[821]797
[1770]798 if (!*head)
[821]799 *head = find;
800 *tail = find;
801
[1770]802 if (dt) {
[821]803 int i;
804
805 /* Add all dependable module for that new module */
[1770]806 for (i = 0; i < dt->m_depcnt; i++)
807 check_dep(dt->m_deparr[i], head, tail);
[821]808 }
809}
810
[1770]811static int mod_insert(char *mod, int argc, char **argv)
[821]812{
[1770]813 struct mod_list_t *tail = NULL;
814 struct mod_list_t *head = NULL;
[821]815 int rc;
816
817 // get dep list for module mod
[1770]818 check_dep(mod, &head, &tail);
[821]819
[1770]820 rc = 1;
821 if (head && tail) {
822 if (argc) {
[821]823 int i;
824 // append module args
[1770]825 for (i = 0; i < argc; i++)
826 head->m_options = append_option(head->m_options, argv[i]);
[821]827 }
828
829 // process tail ---> head
[1770]830 rc = mod_process(tail, 1);
831 if (rc) {
[902]832 /*
833 * In case of using udev, multiple instances of modprobe can be
834 * spawned to load the same module (think of two same usb devices,
835 * for example; or cold-plugging at boot time). Thus we shouldn't
836 * fail if the module was loaded, and not by us.
837 */
[1770]838 if (already_loaded(mod))
[902]839 rc = 0;
840 }
[821]841 }
842 return rc;
843}
844
[1770]845static int mod_remove(char *mod)
[821]846{
847 int rc;
[1770]848 static const struct mod_list_t rm_a_dummy = { "-a", NULL, NULL, NULL, NULL };
[821]849
[1770]850 struct mod_list_t *head = NULL;
851 struct mod_list_t *tail = NULL;
[821]852
[1770]853 if (mod)
854 check_dep(mod, &head, &tail);
[821]855 else // autoclean
[1770]856 head = tail = (struct mod_list_t*) &rm_a_dummy;
[821]857
[1770]858 rc = 1;
859 if (head && tail)
860 rc = mod_process(head, 0); // process head ---> tail
[821]861 return rc;
862}
863
[1770]864int modprobe_main(int argc, char** argv);
[821]865int modprobe_main(int argc, char** argv)
866{
867 int rc = EXIT_SUCCESS;
868 char *unused;
869
[1770]870 opt_complementary = "?V-:q-v:v-q";
871 main_opts = getopt32(argv, "acdklnqrst:vVC:",
[821]872 &unused, &unused);
[1770]873 if (main_opts & (DUMP_CONF_EXIT | LIST_ALL))
874 return EXIT_SUCCESS;
875 if (main_opts & (RESTRICT_DIR | CONFIG_FILE))
876 bb_error_msg_and_die("-t and -C not supported");
[821]877
[1770]878 depend = build_dep();
[821]879
[1770]880 if (!depend)
881 bb_error_msg_and_die("cannot parse modules.dep");
[821]882
883 if (remove_opt) {
884 do {
[1770]885 if (mod_remove(optind < argc ?
886 argv[optind] : NULL)) {
887 bb_error_msg("failed to remove module %s",
888 argv[optind]);
[821]889 rc = EXIT_FAILURE;
890 }
[1770]891 } while (++optind < argc);
[821]892 } else {
893 if (optind >= argc)
[1770]894 bb_error_msg_and_die("no module or pattern provided");
[821]895
[1770]896 if (mod_insert(argv[optind], argc - optind - 1, argv + optind + 1))
897 bb_error_msg_and_die("failed to load module %s", argv[optind]);
[821]898 }
899
900 /* Here would be a good place to free up memory allocated during the dependencies build. */
901
902 return rc;
903}
Note: See TracBrowser for help on using the repository browser.