modprobe.c 23 KB

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