modprobe.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. /* modprobe.c - modprobe utility.
  2. *
  3. * Copyright 2012 Madhur Verma <mad.flexi@gmail.com>
  4. * Copyright 2013 Kyungwan Han <asura321@gmail.com>
  5. *
  6. * No Standard.
  7. USE_MODPROBE(NEWTOY(modprobe, "alrqvsDbd*", TOYFLAG_SBIN))
  8. config MODPROBE
  9. bool "modprobe"
  10. default n
  11. help
  12. usage: modprobe [-alrqvsDb] [-d DIR] MODULE [symbol=value][...]
  13. modprobe utility - inserts modules and dependencies.
  14. -a Load multiple MODULEs
  15. -b Apply blacklist to module names too
  16. -D Show dependencies
  17. -d Load modules from DIR, option may be used multiple times
  18. -l List (MODULE is a pattern)
  19. -q Quiet
  20. -r Remove MODULE (stacks) or do autoclean
  21. -s Log to syslog
  22. -v Verbose
  23. */
  24. #define FOR_modprobe
  25. #include "toys.h"
  26. GLOBALS(
  27. struct arg_list *dirs;
  28. struct arg_list *probes, *dbase[256];
  29. char *cmdopts;
  30. int nudeps, symreq;
  31. )
  32. #define MODNAME_LEN 256
  33. // Modules flag definations
  34. #define MOD_ALOADED 0x0001
  35. #define MOD_BLACKLIST 0x0002
  36. #define MOD_FNDDEPMOD 0x0004
  37. #define MOD_NDDEPS 0x0008
  38. // Current probing modules info
  39. struct module_s {
  40. uint32_t flags;
  41. char *cmdname, *name, *depent, *opts;
  42. struct arg_list *rnames, *dep;
  43. };
  44. // Converts path name FILE to module name.
  45. static char *path2mod(char *file, char *mod)
  46. {
  47. int i;
  48. char *from;
  49. if (!file) return NULL;
  50. if (!mod) mod = xmalloc(MODNAME_LEN);
  51. from = getbasename(file);
  52. for (i = 0; i < (MODNAME_LEN-1) && from[i] && from[i] != '.'; i++)
  53. mod[i] = (from[i] == '-') ? '_' : from[i];
  54. mod[i] = '\0';
  55. return mod;
  56. }
  57. // Add options in opts from toadd.
  58. static char *add_opts(char *opts, char *toadd)
  59. {
  60. if (toadd) {
  61. int optlen = 0;
  62. if (opts) optlen = strlen(opts);
  63. opts = xrealloc(opts, optlen + strlen(toadd) + 2);
  64. sprintf(opts + optlen, " %s", toadd);
  65. }
  66. return opts;
  67. }
  68. // Remove first element from the list and return it.
  69. static void *llist_popme(struct arg_list **head)
  70. {
  71. char *data = NULL;
  72. struct arg_list *temp = *head;
  73. if (temp) {
  74. data = temp->arg;
  75. *head = temp->next;
  76. free(temp);
  77. }
  78. return data;
  79. }
  80. // Add new node at the beginning of the list.
  81. static void llist_add(struct arg_list **old, void *data)
  82. {
  83. struct arg_list *new = xmalloc(sizeof(struct arg_list));
  84. new->arg = (char*)data;
  85. new->next = *old;
  86. *old = new;
  87. }
  88. // Add new node at tail of list.
  89. static void llist_add_tail(struct arg_list **head, void *data)
  90. {
  91. while (*head) head = &(*head)->next;
  92. *head = xzalloc(sizeof(struct arg_list));
  93. (*head)->arg = (char*)data;
  94. }
  95. // Reverse list order.
  96. static struct arg_list *llist_rev(struct arg_list *list)
  97. {
  98. struct arg_list *rev = NULL;
  99. while (list) {
  100. struct arg_list *next = list->next;
  101. list->next = rev;
  102. rev = list;
  103. list = next;
  104. }
  105. return rev;
  106. }
  107. /*
  108. * Returns struct module_s from the data base if found, NULL otherwise.
  109. * if add - create module entry, add it to data base and return the same mod.
  110. */
  111. static struct module_s *get_mod(char *mod, uint8_t add)
  112. {
  113. char name[MODNAME_LEN];
  114. struct module_s *modentry;
  115. struct arg_list *temp;
  116. unsigned i, hash = 0;
  117. path2mod(mod, name);
  118. for (i = 0; name[i]; i++) hash = ((hash*31) + hash) + name[i];
  119. hash %= ARRAY_LEN(TT.dbase);
  120. for (temp = TT.dbase[hash]; temp; temp = temp->next) {
  121. modentry = (struct module_s *) temp->arg;
  122. if (!strcmp(modentry->name, name)) return modentry;
  123. }
  124. if (!add) return NULL;
  125. modentry = xzalloc(sizeof(*modentry));
  126. modentry->name = xstrdup(name);
  127. llist_add(&TT.dbase[hash], modentry);
  128. return modentry;
  129. }
  130. /*
  131. * Read a line from file with \ continuation and skip commented lines.
  132. * Return the line in allocated string (*li)
  133. */
  134. static int read_line(FILE *fl, char **li)
  135. {
  136. char *nxtline = NULL, *line;
  137. ssize_t len, nxtlen;
  138. size_t linelen, nxtlinelen;
  139. for (;;) {
  140. line = NULL;
  141. linelen = nxtlinelen = 0;
  142. len = getline(&line, &linelen, fl);
  143. if (len <= 0) {
  144. free(line);
  145. return len;
  146. }
  147. // checking for commented lines.
  148. if (line[0] != '#') break;
  149. free(line);
  150. }
  151. for (;;) {
  152. if (line[len - 1] == '\n') len--;
  153. if (!len) {
  154. free(line);
  155. return len;
  156. } else if (line[len - 1] != '\\') break;
  157. len--;
  158. nxtlen = getline(&nxtline, &nxtlinelen, fl);
  159. if (nxtlen <= 0) break;
  160. if (linelen < len + nxtlen + 1) {
  161. linelen = len + nxtlen + 1;
  162. line = xrealloc(line, linelen);
  163. }
  164. memcpy(&line[len], nxtline, nxtlen);
  165. len += nxtlen;
  166. }
  167. line[len] = '\0';
  168. *li = xstrdup(line);
  169. free(line);
  170. if (nxtline) free(nxtline);
  171. return len;
  172. }
  173. /*
  174. * Action to be taken on all config files in default directories
  175. * checks for aliases, options, install, remove and blacklist
  176. */
  177. static int config_action(struct dirtree *node)
  178. {
  179. FILE *fc;
  180. char *filename, *tokens[3], *line, *linecp;
  181. struct module_s *modent;
  182. int tcount = 0;
  183. if (!dirtree_notdotdot(node)) return 0;
  184. if (S_ISDIR(node->st.st_mode)) return DIRTREE_RECURSE;
  185. if (!S_ISREG(node->st.st_mode)) return 0; // process only regular file
  186. filename = dirtree_path(node, NULL);
  187. if (!(fc = fopen(filename, "r"))) {
  188. free(filename);
  189. return 0;
  190. }
  191. for (line = linecp = NULL; read_line(fc, &line) >= 0;
  192. free(line), free(linecp), line = linecp = NULL) {
  193. char *tk = NULL;
  194. if (!strlen(line)) continue;
  195. linecp = xstrdup(line);
  196. for (tk = strtok(linecp, "# \t"), tcount = 0; tk;
  197. tk = strtok(NULL, "# \t"), tcount++) {
  198. tokens[tcount] = tk;
  199. if (tcount == 2) {
  200. tokens[2] = line + strlen(tokens[0]) + strlen(tokens[1]) + 2;
  201. break;
  202. }
  203. }
  204. // Every command requires at least one argument.
  205. if (tcount < 2) continue;
  206. // process the tokens[0] contains first word of config line.
  207. if (!strcmp(tokens[0], "alias")) {
  208. struct arg_list *temp;
  209. char alias[MODNAME_LEN], *realname;
  210. if (!tokens[2]) continue;
  211. path2mod(tokens[1], alias);
  212. for (temp = TT.probes; temp; temp = temp->next) {
  213. modent = (struct module_s *) temp->arg;
  214. if (fnmatch(alias, modent->name, 0)) continue;
  215. realname = path2mod(tokens[2], NULL);
  216. llist_add(&modent->rnames, realname);
  217. if (modent->flags & MOD_NDDEPS) {
  218. modent->flags &= ~MOD_NDDEPS;
  219. TT.nudeps--;
  220. }
  221. modent = get_mod(realname, 1);
  222. if (!(modent->flags & MOD_NDDEPS)) {
  223. modent->flags |= MOD_NDDEPS;
  224. TT.nudeps++;
  225. }
  226. }
  227. } else if (!strcmp(tokens[0], "options")) {
  228. if (!tokens[2]) continue;
  229. modent = get_mod(tokens[1], 1);
  230. modent->opts = add_opts(modent->opts, tokens[2]);
  231. } else if (!strcmp(tokens[0], "include"))
  232. dirtree_read(tokens[1], config_action);
  233. else if (!strcmp(tokens[0], "blacklist"))
  234. get_mod(tokens[1], 1)->flags |= MOD_BLACKLIST;
  235. else if (!strcmp(tokens[0], "install")) continue;
  236. else if (!strcmp(tokens[0], "remove")) continue;
  237. else if (!FLAG(q))
  238. error_msg("Invalid option %s found in file %s", tokens[0], filename);
  239. }
  240. fclose(fc);
  241. free(filename);
  242. return 0;
  243. }
  244. // Show matched modules else return -1 on failure.
  245. static int depmode_read_entry(char *cmdname)
  246. {
  247. char *line, *name;
  248. int ret = -1;
  249. FILE *fe = xfopen("modules.dep", "r");
  250. while (read_line(fe, &line) >= 0) {
  251. char *tmp = strchr(line, ':');
  252. if (tmp) {
  253. *tmp = '\0';
  254. name = basename(line);
  255. tmp = strchr(name, '.');
  256. if (tmp) *tmp = '\0';
  257. if (!cmdname || !fnmatch(cmdname, name, 0)) {
  258. if (tmp) *tmp = '.';
  259. if (FLAG(v)) puts(line);
  260. ret = 0;
  261. }
  262. }
  263. free(line);
  264. }
  265. fclose(fe);
  266. return ret;
  267. }
  268. // Finds dependencies for modules from the modules.dep file.
  269. static void find_dep(void)
  270. {
  271. char *line = NULL;
  272. struct module_s *mod;
  273. FILE *fe = xfopen("modules.dep", "r");
  274. for (; read_line(fe, &line) >= 0; free(line)) {
  275. char *tmp = strchr(line, ':');
  276. if (tmp) {
  277. *tmp = '\0';
  278. mod = get_mod(line, 0);
  279. if (!mod) continue;
  280. if ((mod->flags & MOD_ALOADED) && !(FLAG(r)|FLAG(D))) continue;
  281. mod->flags |= MOD_FNDDEPMOD;
  282. if ((mod->flags & MOD_NDDEPS) && !mod->dep) {
  283. TT.nudeps--;
  284. llist_add(&mod->dep, xstrdup(line));
  285. tmp++;
  286. if (*tmp) {
  287. char *tok;
  288. while ((tok = strsep(&tmp, " \t"))) {
  289. if (!*tok) continue;
  290. llist_add_tail(&mod->dep, xstrdup(tok));
  291. }
  292. }
  293. }
  294. }
  295. }
  296. fclose(fe);
  297. }
  298. // Remove a module from the Linux Kernel. if !modules does auto remove.
  299. static int rm_mod(char *modules)
  300. {
  301. char *s;
  302. if (modules && (s = strend(modules, ".ko"))) *s = 0;
  303. return syscall(__NR_delete_module, modules, O_NONBLOCK);
  304. }
  305. // Insert module; simpler than insmod(1) because we already flattened the array
  306. // of flags, and don't need to support loading from stdin.
  307. static int ins_mod(char *modules, char *flags)
  308. {
  309. int fd = xopenro(modules), rc = syscall(__NR_finit_module, fd, flags, 0);
  310. xclose(fd);
  311. return rc;
  312. }
  313. // Add module in probes list, if not loaded.
  314. static void add_mod(char *name)
  315. {
  316. struct module_s *mod = get_mod(name, 1);
  317. if (!(FLAG(r)|FLAG(D)) && (mod->flags & MOD_ALOADED)) {
  318. if (FLAG(v)) printf("%s already loaded\n", name);
  319. return;
  320. }
  321. if (FLAG(v)) printf("queuing %s\n", name);
  322. mod->cmdname = name;
  323. mod->flags |= MOD_NDDEPS;
  324. llist_add_tail(&TT.probes, mod);
  325. TT.nudeps++;
  326. if (!strncmp(mod->name, "symbol:", 7)) TT.symreq = 1;
  327. }
  328. // Parse cmdline options suplied for module.
  329. static char *add_cmdopt(char **argv)
  330. {
  331. char *opt = xzalloc(1);
  332. int lopt = 0;
  333. while (*++argv) {
  334. char *fmt, *var, *val;
  335. var = *argv;
  336. opt = xrealloc(opt, lopt + 2 + strlen(var) + 2);
  337. // check for key=val or key = val.
  338. fmt = "%.*s%s ";
  339. for (val = var; *val && *val != '='; val++);
  340. if (*val && strchr(++val, ' ')) fmt = "%.*s\"%s\" ";
  341. lopt += sprintf(opt + lopt, fmt, (int) (val - var), var, val);
  342. }
  343. return opt;
  344. }
  345. // Probes a single module and loads all its dependencies.
  346. static void go_probe(struct module_s *m)
  347. {
  348. int rc = 0, first = 1;
  349. if (!(m->flags & MOD_FNDDEPMOD)) {
  350. if (!FLAG(q)) error_msg("module %s not found in modules.dep", m->name);
  351. return;
  352. }
  353. if (FLAG(v)) printf("go_prob'ing %s\n", m->name);
  354. if (!FLAG(r)) m->dep = llist_rev(m->dep);
  355. while (m->dep) {
  356. struct module_s *m2;
  357. char *fn, *options;
  358. rc = 0;
  359. fn = llist_popme(&m->dep);
  360. m2 = get_mod(fn, 1);
  361. // are we removing ?
  362. if (FLAG(r)) {
  363. if (m2->flags & MOD_ALOADED) {
  364. if (rm_mod(m2->name)) {
  365. if (first) {
  366. perror_msg("can't unload module %s", m2->name);
  367. break;
  368. }
  369. } else m2->flags &= ~MOD_ALOADED;
  370. }
  371. first = 0;
  372. continue;
  373. }
  374. // TODO how does free work here without leaking?
  375. options = m2->opts;
  376. m2->opts = NULL;
  377. if (m == m2) options = add_opts(options, TT.cmdopts);
  378. // are we only checking dependencies ?
  379. if (FLAG(D)) {
  380. if (FLAG(v))
  381. printf(options ? "insmod %s %s\n" : "insmod %s\n", fn, options);
  382. if (options) free(options);
  383. continue;
  384. }
  385. if (m2->flags & MOD_ALOADED) {
  386. if (FLAG(v)) printf("%s already loaded\n", fn);
  387. if (options) free(options);
  388. continue;
  389. }
  390. // none of above is true insert the module.
  391. errno = 0;
  392. rc = ins_mod(fn, options);
  393. if (FLAG(v))
  394. printf("loaded %s '%s': %s\n", fn, options, strerror(errno));
  395. if (errno == EEXIST) rc = 0;
  396. free(options);
  397. if (rc) {
  398. perror_msg("can't load module %s (%s)", m2->name, fn);
  399. break;
  400. }
  401. m2->flags |= MOD_ALOADED;
  402. }
  403. }
  404. void modprobe_main(void)
  405. {
  406. char **argv = toys.optargs, *procline = NULL;
  407. FILE *fs;
  408. struct module_s *module;
  409. struct arg_list *dirs;
  410. if (toys.optc<1 && !FLAG(r) == !FLAG(l)) help_exit("bad syntax");
  411. // Check for -r flag without arg if yes then do auto remove.
  412. if (FLAG(r) && !toys.optc) {
  413. if (rm_mod(0)) perror_exit("rmmod");
  414. return;
  415. }
  416. if (!TT.dirs) {
  417. struct utsname uts;
  418. uname(&uts);
  419. TT.dirs = xzalloc(sizeof(struct arg_list));
  420. TT.dirs->arg = xmprintf("/lib/modules/%s", uts.release);
  421. }
  422. // modules.dep processing for dependency check.
  423. if (FLAG(l)) {
  424. for (dirs = TT.dirs; dirs; dirs = dirs->next) {
  425. xchdir(dirs->arg);
  426. if (!depmode_read_entry(*toys.optargs)) return;
  427. }
  428. error_exit("no module found.");
  429. }
  430. // Read /proc/modules to get loaded modules.
  431. fs = xfopen("/proc/modules", "r");
  432. while (read_line(fs, &procline) > 0) {
  433. *strchr(procline, ' ') = 0;
  434. get_mod(procline, 1)->flags = MOD_ALOADED;
  435. free(procline);
  436. procline = NULL;
  437. }
  438. fclose(fs);
  439. if (FLAG(a) || FLAG(r)) for (; *argv; argv++) add_mod(*argv);
  440. else {
  441. add_mod(*argv);
  442. TT.cmdopts = add_cmdopt(argv);
  443. }
  444. if (!TT.probes) {
  445. if (FLAG(v)) puts("All modules loaded");
  446. return;
  447. }
  448. dirtree_flagread("/etc/modprobe.conf", DIRTREE_SHUTUP, config_action);
  449. dirtree_flagread("/etc/modprobe.d", DIRTREE_SHUTUP, config_action);
  450. for (dirs = TT.dirs; dirs; dirs = dirs->next) {
  451. xchdir(dirs->arg);
  452. if (TT.symreq) dirtree_read("modules.symbols", config_action);
  453. if (TT.nudeps) dirtree_read("modules.alias", config_action);
  454. }
  455. for (dirs = TT.dirs; dirs; dirs = dirs->next) {
  456. xchdir(dirs->arg);
  457. find_dep();
  458. }
  459. while ((module = llist_popme(&TT.probes))) {
  460. if (!module->rnames) {
  461. if (FLAG(v)) puts("probing by module name");
  462. /* This is not an alias. Literal names are blacklisted
  463. * only if '-b' is given.
  464. */
  465. if (!FLAG(b) || !(module->flags & MOD_BLACKLIST))
  466. go_probe(module);
  467. continue;
  468. }
  469. do { // Probe all real names for the alias.
  470. char *real = ((struct arg_list *)llist_pop(&module->rnames))->arg;
  471. struct module_s *m2 = get_mod(real, 0);
  472. if (FLAG(v))
  473. printf("probing alias %s by realname %s\n", module->name, real);
  474. if (!m2) continue;
  475. if (!(m2->flags & MOD_BLACKLIST)
  476. && (!(m2->flags & MOD_ALOADED) || FLAG(r) || FLAG(D)))
  477. go_probe(m2);
  478. free(real);
  479. } while (module->rnames);
  480. }
  481. }