3
0

modprobe.c 22 KB

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