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