1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28#define FOR_modprobe
29#include "toys.h"
30#include <sys/syscall.h>
31
32GLOBALS(
33 struct arg_list *dirs;
34
35 struct arg_list *probes;
36 struct arg_list *dbase[256];
37 char *cmdopts;
38 int nudeps;
39 uint8_t symreq;
40)
41
42
43
44
45#define DBASE_SIZE 256
46#define MODNAME_LEN 256
47
48
49#define MOD_ALOADED 0x0001
50#define MOD_BLACKLIST 0x0002
51#define MOD_FNDDEPMOD 0x0004
52#define MOD_NDDEPS 0x0008
53
54
55struct module_s {
56 uint32_t flags;
57 char *cmdname, *name, *depent, *opts;
58 struct arg_list *rnames, *dep;
59};
60
61
62static char *path2mod(char *file, char *mod)
63{
64 int i;
65 char *from;
66
67 if (!file) return NULL;
68 if (!mod) mod = xmalloc(MODNAME_LEN);
69
70 from = getbasename(file);
71
72 for (i = 0; i < (MODNAME_LEN-1) && from[i] && from[i] != '.'; i++)
73 mod[i] = (from[i] == '-') ? '_' : from[i];
74 mod[i] = '\0';
75 return mod;
76}
77
78
79static char *add_opts(char *opts, char *toadd)
80{
81 if (toadd) {
82 int optlen = 0;
83
84 if (opts) optlen = strlen(opts);
85 opts = xrealloc(opts, optlen + strlen(toadd) + 2);
86 sprintf(opts + optlen, " %s", toadd);
87 }
88 return opts;
89}
90
91
92static void *llist_popme(struct arg_list **head)
93{
94 char *data = NULL;
95 struct arg_list *temp = *head;
96
97 if (temp) {
98 data = temp->arg;
99 *head = temp->next;
100 free(temp);
101 }
102 return data;
103}
104
105
106static void llist_add(struct arg_list **old, void *data)
107{
108 struct arg_list *new = xmalloc(sizeof(struct arg_list));
109
110 new->arg = (char*)data;
111 new->next = *old;
112 *old = new;
113}
114
115
116static void llist_add_tail(struct arg_list **head, void *data)
117{
118 while (*head) head = &(*head)->next;
119 *head = xzalloc(sizeof(struct arg_list));
120 (*head)->arg = (char*)data;
121}
122
123
124static struct arg_list *llist_rev(struct arg_list *list)
125{
126 struct arg_list *rev = NULL;
127
128 while (list) {
129 struct arg_list *next = list->next;
130
131 list->next = rev;
132 rev = list;
133 list = next;
134 }
135 return rev;
136}
137
138
139
140
141
142static struct module_s *get_mod(char *mod, uint8_t add)
143{
144 char name[MODNAME_LEN];
145 struct module_s *modentry;
146 struct arg_list *temp;
147 unsigned i, hash = 0;
148
149 path2mod(mod, name);
150 for (i = 0; name[i]; i++) hash = ((hash*31) + hash) + name[i];
151 hash %= DBASE_SIZE;
152 for (temp = TT.dbase[hash]; temp; temp = temp->next) {
153 modentry = (struct module_s *) temp->arg;
154 if (!strcmp(modentry->name, name)) return modentry;
155 }
156 if (!add) return NULL;
157 modentry = xzalloc(sizeof(*modentry));
158 modentry->name = xstrdup(name);
159 llist_add(&TT.dbase[hash], modentry);
160 return modentry;
161}
162
163
164
165
166
167static int read_line(FILE *fl, char **li)
168{
169 char *nxtline = NULL, *line;
170 ssize_t len, nxtlen;
171 size_t linelen, nxtlinelen;
172
173 while (1) {
174 line = NULL;
175 linelen = nxtlinelen = 0;
176 len = getline(&line, &linelen, fl);
177 if (len <= 0) {
178 free(line);
179 return len;
180 }
181
182 if (line[0] != '#') break;
183 free(line);
184 }
185 for (;;) {
186 if (line[len - 1] == '\n') len--;
187 if (!len) {
188 free(line);
189 return len;
190 } else if (line[len - 1] != '\\') break;
191
192 len--;
193 nxtlen = getline(&nxtline, &nxtlinelen, fl);
194 if (nxtlen <= 0) break;
195 if (linelen < len + nxtlen + 1) {
196 linelen = len + nxtlen + 1;
197 line = xrealloc(line, linelen);
198 }
199 memcpy(&line[len], nxtline, nxtlen);
200 len += nxtlen;
201 }
202 line[len] = '\0';
203 *li = xstrdup(line);
204 free(line);
205 if (nxtline) free(nxtline);
206 return len;
207}
208
209
210
211
212
213static int config_action(struct dirtree *node)
214{
215 FILE *fc;
216 char *filename, *tokens[3], *line, *linecp;
217 struct module_s *modent;
218 int tcount = 0;
219
220 if (!dirtree_notdotdot(node)) return 0;
221 if (S_ISDIR(node->st.st_mode)) return DIRTREE_RECURSE;
222
223 if (!S_ISREG(node->st.st_mode)) return 0;
224 filename = dirtree_path(node, NULL);
225 if (!(fc = fopen(filename, "r"))) {
226 free(filename);
227 return 0;
228 }
229 for (line = linecp = NULL; read_line(fc, &line) > 0;
230 free(line), free(linecp), line = linecp = NULL) {
231 char *tk = NULL;
232
233 if (!strlen(line)) continue;
234 linecp = xstrdup(line);
235 for (tk = strtok(linecp, "# \t"), tcount = 0; tk;
236 tk = strtok(NULL, "# \t"), tcount++) {
237 tokens[tcount] = tk;
238 if (tcount == 2) {
239 tokens[2] = line + strlen(tokens[0]) + strlen(tokens[1]) + 2;
240 break;
241 }
242 }
243 if (!tk) continue;
244
245 if (!strcmp(tokens[0], "alias")) {
246 struct arg_list *temp;
247 char aliase[MODNAME_LEN], *realname;
248
249 if (!tokens[2]) continue;
250 path2mod(tokens[1], aliase);
251 for (temp = TT.probes; temp; temp = temp->next) {
252 modent = (struct module_s *) temp->arg;
253 if (fnmatch(aliase, modent->name, 0)) continue;
254 realname = path2mod(tokens[2], NULL);
255 llist_add(&modent->rnames, realname);
256 if (modent->flags & MOD_NDDEPS) {
257 modent->flags &= ~MOD_NDDEPS;
258 TT.nudeps--;
259 }
260 modent = get_mod(realname, 1);
261 if (!(modent->flags & MOD_NDDEPS)) {
262 modent->flags |= MOD_NDDEPS;
263 TT.nudeps++;
264 }
265 }
266 } else if (!strcmp(tokens[0], "options")) {
267 if (!tokens[2]) continue;
268 modent = get_mod(tokens[1], 1);
269 modent->opts = add_opts(modent->opts, tokens[2]);
270 } else if (!strcmp(tokens[0], "include"))
271 dirtree_read(tokens[1], config_action);
272 else if (!strcmp(tokens[0], "blacklist"))
273 get_mod(tokens[1], 1)->flags |= MOD_BLACKLIST;
274 else if (!strcmp(tokens[0], "install")) continue;
275 else if (!strcmp(tokens[0], "remove")) continue;
276 else if (toys.optflags & FLAG_q)
277 error_msg("Invalid option %s found in file %s", tokens[0], filename);
278 }
279 fclose(fc);
280 free(filename);
281 return 0;
282}
283
284
285static int depmode_read_entry(char *cmdname)
286{
287 char *line;
288 int ret = -1;
289 FILE *fe = xfopen("modules.dep", "r");
290
291 while (read_line(fe, &line) > 0) {
292 char *tmp = strchr(line, ':');
293
294 if (tmp) {
295 *tmp = '\0';
296 char *name = basename(line);
297
298 tmp = strchr(name, '.');
299 if (tmp) *tmp = '\0';
300 if (!cmdname || !fnmatch(cmdname, name, 0)) {
301 if (tmp) *tmp = '.';
302 if (toys.optflags&FLAG_v) puts(line);
303 ret = 0;
304 }
305 }
306 free(line);
307 }
308 fclose(fe);
309 return ret;
310}
311
312
313static void find_dep(void)
314{
315 char *line = NULL;
316 struct module_s *mod;
317 FILE *fe = xfopen("modules.dep", "r");
318
319 for (; read_line(fe, &line) > 0; free(line)) {
320 char *tmp = strchr(line, ':');
321
322 if (tmp) {
323 *tmp = '\0';
324 mod = get_mod(line, 0);
325 if (!mod) continue;
326 if ((mod->flags & MOD_ALOADED) &&
327 !(toys.optflags & (FLAG_r | FLAG_D))) continue;
328
329 mod->flags |= MOD_FNDDEPMOD;
330 if ((mod->flags & MOD_NDDEPS) && (!mod->dep)) {
331 TT.nudeps--;
332 llist_add(&mod->dep, xstrdup(line));
333 tmp++;
334 if (*tmp) {
335 char *tok;
336
337 while ((tok = strsep(&tmp, " \t"))) {
338 if (!*tok) continue;
339 llist_add_tail(&mod->dep, xstrdup(tok));
340 }
341 }
342 }
343 }
344 }
345 fclose(fe);
346}
347
348
349static int rm_mod(char *modules, uint32_t flags)
350{
351 if (modules) {
352 int len = strlen(modules);
353
354 if (len > 3 && !strcmp(modules+len-3, ".ko" )) modules[len-3] = 0;
355 }
356
357 errno = 0;
358 syscall(__NR_delete_module, modules, flags ? flags : O_NONBLOCK|O_EXCL);
359
360 return errno;
361}
362
363
364static int ins_mod(char *modules, char *flags)
365{
366 char *buf = NULL;
367 int len, res;
368 int fd = xopenro(modules);
369
370 while (flags && strlen(toybuf) + strlen(flags) + 2 < sizeof(toybuf)) {
371 strcat(toybuf, flags);
372 strcat(toybuf, " ");
373 }
374
375#ifdef __NR_finit_module
376 res = syscall(__NR_finit_module, fd, toybuf, 0);
377 if (!res || errno != ENOSYS) {
378 xclose(fd);
379 return res;
380 }
381#endif
382
383
384
385 len = fdlength(fd);
386 buf = xmalloc(len);
387 xreadall(fd, buf, len);
388 xclose(fd);
389
390 res = syscall(__NR_init_module, buf, len, toybuf);
391 if (CFG_TOYBOX_FREE && buf != toybuf) free(buf);
392 return res;
393}
394
395
396static void add_mod(char *name)
397{
398 struct module_s *mod = get_mod(name, 1);
399
400 if (!(toys.optflags & (FLAG_r | FLAG_D)) && (mod->flags & MOD_ALOADED)) {
401 if (toys.optflags&FLAG_v) printf("skipping %s, already loaded\n", name);
402 return;
403 }
404 if (toys.optflags&FLAG_v) printf("queuing %s\n", name);
405 mod->cmdname = name;
406 mod->flags |= MOD_NDDEPS;
407 llist_add_tail(&TT.probes, mod);
408 TT.nudeps++;
409 if (!strncmp(mod->name, "symbol:", 7)) TT.symreq = 1;
410}
411
412
413static char *add_cmdopt(char **argv)
414{
415 char *opt = xzalloc(1);
416 int lopt = 0;
417
418 while (*++argv) {
419 char *fmt, *var, *val;
420
421 var = *argv;
422 opt = xrealloc(opt, lopt + 2 + strlen(var) + 2);
423
424 fmt = "%.*s%s ";
425 for (val = var; *val && *val != '='; val++);
426 if (*val && strchr(++val, ' ')) fmt = "%.*s\"%s\" ";
427 lopt += sprintf(opt + lopt, fmt, (int) (val - var), var, val);
428 }
429 return opt;
430}
431
432
433static int go_probe(struct module_s *m)
434{
435 int rc = 0, first = 1;
436
437 if (!(m->flags & MOD_FNDDEPMOD)) {
438 if (!(toys.optflags & FLAG_q))
439 error_msg("module %s not found in modules.dep", m->name);
440 return -ENOENT;
441 }
442 if (toys.optflags & FLAG_v) printf("go_prob'ing %s\n", m->name);
443 if (!(toys.optflags & FLAG_r)) m->dep = llist_rev(m->dep);
444
445 while (m->dep) {
446 struct module_s *m2;
447 char *fn, *options;
448
449 rc = 0;
450 fn = llist_popme(&m->dep);
451 m2 = get_mod(fn, 1);
452
453 if (toys.optflags & FLAG_r) {
454 if (m2->flags & MOD_ALOADED) {
455 if ((rc = rm_mod(m2->name, O_EXCL))) {
456 if (first) {
457 perror_msg("can't unload module %s", m2->name);
458 break;
459 }
460 } else m2->flags &= ~MOD_ALOADED;
461 }
462 first = 0;
463 continue;
464 }
465 options = m2->opts;
466 m2->opts = NULL;
467 if (m == m2) options = add_opts(options, TT.cmdopts);
468
469
470 if (toys.optflags & FLAG_D) {
471 if (toys.optflags & FLAG_v)
472 printf(options ? "insmod %s %s\n" : "insmod %s\n", fn, options);
473 if (options) free(options);
474 continue;
475 }
476 if (m2->flags & MOD_ALOADED) {
477 if (toys.optflags&FLAG_v)
478 printf("%s is already loaded, skipping\n", fn);
479 if (options) free(options);
480 continue;
481 }
482
483 errno = 0;
484 rc = ins_mod(fn, options);
485 if (toys.optflags&FLAG_v)
486 printf("loaded %s '%s': %s\n", fn, options, strerror(errno));
487 if (errno == EEXIST) rc = 0;
488 free(options);
489 if (rc) {
490 perror_msg("can't load module %s (%s)", m2->name, fn);
491 break;
492 }
493 m2->flags |= MOD_ALOADED;
494 }
495 return rc;
496}
497
498void modprobe_main(void)
499{
500 struct utsname uts;
501 char **argv = toys.optargs, *procline = NULL;
502 FILE *fs;
503 struct module_s *module;
504 unsigned flags = toys.optflags;
505 struct arg_list *dirs;
506
507 if ((toys.optc < 1) && (((flags & FLAG_r) && (flags & FLAG_l))
508 ||(!((flags & FLAG_r)||(flags & FLAG_l)))))
509 {
510 help_exit("bad syntax");
511 }
512
513 if ((flags & FLAG_r) && !toys.optc) {
514 if (rm_mod(NULL, O_NONBLOCK | O_EXCL)) perror_exit("rmmod");
515 return;
516 }
517
518 if (!TT.dirs) {
519 uname(&uts);
520 TT.dirs = xzalloc(sizeof(struct arg_list));
521 TT.dirs->arg = xmprintf("/lib/modules/%s", uts.release);
522 }
523
524
525 if (flags & FLAG_l) {
526 for (dirs = TT.dirs; dirs; dirs = dirs->next) {
527 xchdir(dirs->arg);
528 if (!depmode_read_entry(toys.optargs[0])) return;
529 }
530 error_exit("no module found.");
531 }
532
533
534 fs = xfopen("/proc/modules", "r");
535
536 while (read_line(fs, &procline) > 0) {
537 *(strchr(procline, ' ')) = '\0';
538 get_mod(procline, 1)->flags = MOD_ALOADED;
539 free(procline);
540 procline = NULL;
541 }
542 fclose(fs);
543 if ((flags & FLAG_a) || (flags & FLAG_r)) {
544 do {
545 add_mod(*argv++);
546 } while (*argv);
547 } else {
548 add_mod(argv[0]);
549 TT.cmdopts = add_cmdopt(argv);
550 }
551 if (!TT.probes) {
552 if (toys.optflags&FLAG_v) puts("All modules loaded");
553 return;
554 }
555 dirtree_flagread("/etc/modprobe.conf", DIRTREE_SHUTUP, config_action);
556 dirtree_flagread("/etc/modprobe.d", DIRTREE_SHUTUP, config_action);
557
558 for (dirs = TT.dirs; dirs; dirs = dirs->next) {
559 xchdir(dirs->arg);
560 if (TT.symreq) dirtree_read("modules.symbols", config_action);
561 if (TT.nudeps) dirtree_read("modules.alias", config_action);
562 }
563
564 for (dirs = TT.dirs; dirs; dirs = dirs->next) {
565 xchdir(dirs->arg);
566 find_dep();
567 }
568
569 while ((module = llist_popme(&TT.probes))) {
570 if (!module->rnames) {
571 if (toys.optflags&FLAG_v) puts("probing by module name");
572
573
574
575 if (!(flags & FLAG_b) || !(module->flags & MOD_BLACKLIST))
576 go_probe(module);
577 continue;
578 }
579 do {
580 char *real = ((struct arg_list*)llist_pop(&module->rnames))->arg;
581 struct module_s *m2 = get_mod(real, 0);
582
583 if (toys.optflags&FLAG_v)
584 printf("probing alias %s by realname %s\n", module->name, real);
585 if (!m2) continue;
586 if (!(m2->flags & MOD_BLACKLIST)
587 && (!(m2->flags & MOD_ALOADED) || (flags & (FLAG_r | FLAG_D))))
588 go_probe(m2);
589 free(real);
590 } while (module->rnames);
591 }
592}
593