block: add support for mounting swap files
[project/ubox.git] / kmodloader.c
1 /*
2 * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
3 * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License version 2.1
7 * as published by the Free Software Foundation
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15 #define _GNU_SOURCE
16 #include <sys/syscall.h>
17 #include <sys/mman.h>
18 #include <sys/utsname.h>
19
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <sys/syscall.h>
23 #include <sys/types.h>
24 #include <values.h>
25 #include <errno.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <syslog.h>
31 #include <glob.h>
32 #include <elf.h>
33
34 #include <libubox/avl.h>
35 #include <libubox/avl-cmp.h>
36 #include <libubox/utils.h>
37
38 #define DEF_MOD_PATH "/lib/modules/%s/"
39
40 enum {
41 SCANNED,
42 PROBE,
43 LOADED,
44 FAILED,
45 };
46
47 struct module {
48 struct avl_node avl;
49
50 char *name;
51 char *depends;
52
53 int size;
54 int usage;
55 int state;
56 };
57
58 static struct avl_tree modules;
59 static char *prefix = "";
60
61 static struct module *find_module(const char *name)
62 {
63 struct module *m;
64 return avl_find_element(&modules, name, m, avl);
65 }
66
67 static void free_modules(void)
68 {
69 struct module *m, *tmp;
70
71 avl_remove_all_elements(&modules, m, avl, tmp)
72 free(m);
73 }
74
75 static char* get_module_path(char *name)
76 {
77 static char path[256];
78 struct utsname ver;
79 struct stat s;
80 char *t;
81
82 if (!stat(name, &s))
83 return name;
84
85 uname(&ver);
86 snprintf(path, 256, "%s" DEF_MOD_PATH "%s.ko", prefix, ver.release, name);
87
88 if (!stat(path, &s))
89 return path;
90
91 t = name;
92 while (t && *t) {
93 if (*t == '_')
94 *t = '-';
95 t++;
96 }
97
98 snprintf(path, 256, "%s" DEF_MOD_PATH "%s.ko", prefix, ver.release, name);
99
100 if (!stat(path, &s))
101 return path;
102
103 return NULL;
104 }
105
106 static char* get_module_name(char *path)
107 {
108 static char name[32];
109 char *t;
110
111 strncpy(name, basename(path), sizeof(name));
112
113 t = strstr(name, ".ko");
114 if (t)
115 *t = '\0';
116 t = name;
117 while (t && *t) {
118 if (*t == '-')
119 *t = '_';
120 t++;
121 }
122
123 return name;
124 }
125
126 #if __WORDSIZE == 64
127 static int elf_find_section(char *map, const char *section, unsigned int *offset, unsigned int *size)
128 {
129 const char *secnames;
130 Elf64_Ehdr *e;
131 Elf64_Shdr *sh;
132 int i;
133
134 e = (Elf64_Ehdr *) map;
135 sh = (Elf64_Shdr *) (map + e->e_shoff);
136
137 secnames = map + sh[e->e_shstrndx].sh_offset;
138 for (i = 0; i < e->e_shnum; i++) {
139 if (!strcmp(section, secnames + sh[i].sh_name)) {
140 *size = sh[i].sh_size;
141 *offset = sh[i].sh_offset;
142 return 0;
143 }
144 }
145
146 return -1;
147 }
148 #else
149 static int elf_find_section(char *map, const char *section, unsigned int *offset, unsigned int *size)
150 {
151 const char *secnames;
152 Elf32_Ehdr *e;
153 Elf32_Shdr *sh;
154 int i;
155
156 e = (Elf32_Ehdr *) map;
157 sh = (Elf32_Shdr *) (map + e->e_shoff);
158
159 secnames = map + sh[e->e_shstrndx].sh_offset;
160 for (i = 0; i < e->e_shnum; i++) {
161 if (!strcmp(section, secnames + sh[i].sh_name)) {
162 *size = sh[i].sh_size;
163 *offset = sh[i].sh_offset;
164 return 0;
165 }
166 }
167
168 return -1;
169 }
170 #endif
171
172 static struct module *
173 alloc_module(const char *name, const char *depends, int size)
174 {
175 struct module *m;
176 char *_name, *_dep;
177
178 m = calloc_a(sizeof(*m),
179 &_name, strlen(name) + 1,
180 &_dep, depends ? strlen(depends) + 1 : 0);
181 if (!m)
182 return NULL;
183
184 m->avl.key = m->name = strcpy(_name, name);
185 if (depends)
186 m->depends = strcpy(_dep, depends);
187
188 m->size = size;
189 avl_insert(&modules, &m->avl);
190 return m;
191 }
192
193 static int scan_loaded_modules(void)
194 {
195 size_t buf_len = 0;
196 char *buf = NULL;
197 FILE *fp;
198
199 fp = fopen("/proc/modules", "r");
200 if (!fp) {
201 fprintf(stderr, "failed to open /proc/modules\n");
202 return -1;
203 }
204
205 while (getline(&buf, &buf_len, fp) > 0) {
206 struct module m;
207 struct module *n;
208
209 m.name = strtok(buf, " ");
210 m.size = atoi(strtok(NULL, " "));
211 m.usage = atoi(strtok(NULL, " "));
212 m.depends = strtok(NULL, " ");
213
214 if (!m.name || !m.depends)
215 continue;
216
217 n = alloc_module(m.name, m.depends, m.size);
218 n->usage = m.usage;
219 n->state = LOADED;
220 }
221 free(buf);
222 fclose(fp);
223
224 return 0;
225 }
226
227 static struct module* get_module_info(const char *module, const char *name)
228 {
229 int fd = open(module, O_RDONLY);
230 unsigned int offset, size;
231 char *map, *strings, *dep = NULL;
232 struct module *m;
233 struct stat s;
234
235 if (!fd) {
236 fprintf(stderr, "failed to open %s\n", module);
237 return NULL;
238 }
239
240 if (fstat(fd, &s) == -1) {
241 fprintf(stderr, "failed to stat %s\n", module);
242 return NULL;
243 }
244
245 map = mmap(NULL, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
246 if (map == MAP_FAILED) {
247 fprintf(stderr, "failed to mmap %s\n", module);
248 return NULL;
249 }
250
251 if (elf_find_section(map, ".modinfo", &offset, &size)) {
252 fprintf(stderr, "failed to load the .modinfo section from %s\n", module);
253 return NULL;
254 }
255
256 strings = map + offset;
257 while (strings && (strings < map + offset + size)) {
258 char *sep;
259 int len;
260
261 while (!strings[0])
262 strings++;
263 sep = strstr(strings, "=");
264 if (!sep)
265 break;
266 len = sep - strings;
267 sep++;
268 if (!strncmp(strings, "depends=", len + 1))
269 dep = sep;
270 strings = &sep[strlen(sep)];
271 }
272
273 m = alloc_module(name, dep, s.st_size);
274 if (!m)
275 return NULL;
276
277 m->state = SCANNED;
278
279 return m;
280 }
281
282 static int scan_module_folder(char *dir)
283 {
284 int gl_flags = GLOB_NOESCAPE | GLOB_MARK;
285 int j;
286 glob_t gl;
287
288 if (glob(dir, gl_flags, NULL, &gl) < 0)
289 return -1;
290
291 for (j = 0; j < gl.gl_pathc; j++) {
292 char *name = get_module_name(gl.gl_pathv[j]);
293 struct module *m;
294
295 if (!name)
296 continue;
297
298 m = find_module(name);
299 if (!m)
300 get_module_info(gl.gl_pathv[j], name);
301 }
302
303 globfree(&gl);
304
305 return 0;
306 }
307
308 static int print_modinfo(char *module)
309 {
310 int fd = open(module, O_RDONLY);
311 unsigned int offset, size;
312 struct stat s;
313 char *map, *strings;
314
315 if (!fd) {
316 fprintf(stderr, "failed to open %s\n", module);
317 return -1;
318 }
319
320 if (fstat(fd, &s) == -1) {
321 fprintf(stderr, "failed to stat %s\n", module);
322 return -1;
323 }
324
325 map = mmap(NULL, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
326 if (map == MAP_FAILED) {
327 fprintf(stderr, "failed to mmap %s\n", module);
328 return -1;
329 }
330
331 if (elf_find_section(map, ".modinfo", &offset, &size)) {
332 fprintf(stderr, "failed to load the .modinfo section from %s\n", module);
333 return -1;
334 }
335
336 strings = map + offset;
337 printf("module:\t\t%s\n", module);
338 while (strings && (strings < map + offset + size)) {
339 char *dup = NULL;
340 char *sep;
341
342 while (!strings[0])
343 strings++;
344 sep = strstr(strings, "=");
345 if (!sep)
346 break;
347 dup = strndup(strings, sep - strings);
348 sep++;
349 if (strncmp(strings, "parm", 4)) {
350 if (strlen(dup) < 7)
351 printf("%s:\t\t%s\n", dup, sep);
352 else
353 printf("%s:\t%s\n", dup, sep);
354 }
355 strings = &sep[strlen(sep)];
356 if (dup)
357 free(dup);
358 }
359
360 return 0;
361 }
362
363 static int insert_module(char *path, const char *options)
364 {
365 void *data = 0;
366 struct stat s;
367 int fd, ret = -1;
368
369 if (stat(path, &s)) {
370 fprintf(stderr, "missing module %s\n", path);
371 return ret;
372 }
373
374 fd = open(path, O_RDONLY);
375 if (!fd) {
376 fprintf(stderr, "cannot open %s\n", path);
377 return ret;
378 }
379
380 data = malloc(s.st_size);
381 if (read(fd, data, s.st_size) == s.st_size) {
382 ret = syscall(__NR_init_module, data, s.st_size, options);
383 if (ret)
384 fprintf(stderr, "failed to insert %s\n", path);
385 } else {
386 fprintf(stderr, "failed to read full module %s\n", path);
387 }
388
389 close(fd);
390 free(data);
391
392 return ret;
393 }
394
395 static int deps_available(struct module *m)
396 {
397 char *deps = m->depends;
398 char *comma;
399
400 if (!strcmp(deps, "-"))
401 return 0;
402 while (*deps && (NULL != ((comma = strstr(deps, ","))))) {
403 *comma = '\0';
404
405 m = find_module(deps);
406
407 if (!m || (m->state != LOADED))
408 return -1;
409
410 deps = ++comma;
411 }
412
413 return 0;
414 }
415
416 static int load_depmod(void)
417 {
418 int loaded, todo;
419 struct module *m;
420
421 do {
422 loaded = 0;
423 todo = 0;
424 avl_for_each_element(&modules, m, avl) {
425 if ((m->state == PROBE) && (!deps_available(m))) {
426 if (!insert_module(get_module_path(m->name), "")) {
427 m->state = LOADED;
428 loaded++;
429 continue;
430 }
431 m->state = FAILED;
432 } else if (m->state == PROBE) {
433 todo++;
434 }
435 }
436 // printf("loaded %d modules this pass\n", loaded);
437 } while (loaded);
438
439 // printf("missing todos %d\n", todo);
440
441 return -todo;
442 }
443
444 static int print_insmod_usage(void)
445 {
446 fprintf(stderr, "Usage:\n\tinsmod filename [args]\n");
447
448 return -1;
449 }
450
451 static int print_usage(char *arg)
452 {
453 fprintf(stderr, "Usage:\n\t%s module\n", arg);
454
455 return -1;
456 }
457
458 static int main_insmod(int argc, char **argv)
459 {
460 char *name, *cur, *options;
461 int i, ret, len;
462
463 if (argc < 2)
464 return print_insmod_usage();
465
466 name = get_module_name(argv[1]);
467 if (!name) {
468 fprintf(stderr, "cannot find module - %s\n", argv[1]);
469 return -1;
470 }
471
472 if (scan_loaded_modules())
473 return -1;
474
475 if (find_module(name)) {
476 fprintf(stderr, "module is already loaded - %s\n", name);
477 return -1;
478
479 }
480
481 free_modules();
482
483 for (len = 0, i = 2; i < argc; i++)
484 len += strlen(argv[i]) + 1;
485
486 options = malloc(len);
487 options[0] = 0;
488 cur = options;
489 for (i = 2; i < argc; i++) {
490 if (options[0]) {
491 *cur = ' ';
492 cur++;
493 }
494 cur += sprintf(cur, "%s", argv[i]);
495 }
496
497 ret = insert_module(get_module_path(name), options);
498 free(options);
499
500 return ret;
501 }
502
503 static int main_rmmod(int argc, char **argv)
504 {
505 struct module *m;
506 char *name;
507 int ret;
508
509 if (argc != 2)
510 return print_usage("rmmod");
511
512 if (scan_loaded_modules())
513 return -1;
514
515 name = get_module_name(argv[1]);
516 m = find_module(name);
517 if (!m) {
518 fprintf(stderr, "module is not loaded\n");
519 return -1;
520 }
521 free_modules();
522
523 ret = syscall(__NR_delete_module, name, 0);
524
525 if (ret)
526 fprintf(stderr, "unloading the module failed\n");
527
528 return ret;
529 }
530
531 static int main_lsmod(int argc, char **argv)
532 {
533 struct module *m;
534
535 if (scan_loaded_modules())
536 return -1;
537
538 avl_for_each_element(&modules, m, avl)
539 if (m->state == LOADED)
540 printf("%-20s%8d%3d %s\n",
541 m->name, m->size, m->usage,
542 (*m->depends == '-') ? ("") : (m->depends));
543
544 free_modules();
545
546 return 0;
547 }
548
549 static int main_modinfo(int argc, char **argv)
550 {
551 char *module;
552
553 if (argc != 2)
554 return print_usage("modinfo");
555
556 module = get_module_path(argv[1]);
557 if (!module) {
558 fprintf(stderr, "cannot find module - %s\n", argv[1]);
559 return -1;
560 }
561
562 print_modinfo(module);
563
564 return 0;
565 }
566
567 static int main_depmod(int argc, char **argv)
568 {
569 struct utsname ver;
570 struct module *m;
571 char *path;
572 char *name;
573
574 if (argc != 2)
575 return print_usage("depmod");
576
577 if (scan_loaded_modules())
578 return -1;
579
580 uname(&ver);
581 path = alloca(sizeof(DEF_MOD_PATH "*.ko") + strlen(ver.release) + 1);
582 sprintf(path, DEF_MOD_PATH "*.ko", ver.release);
583
584 scan_module_folder(path);
585
586 name = get_module_name(argv[1]);
587 m = find_module(name);
588 if (m && m->state == LOADED) {
589 fprintf(stderr, "%s is already loaded\n", name);
590 return -1;
591 } else if (!m) {
592 fprintf(stderr, "failed to find a module named %s\n", name);
593 } else {
594 m->state = PROBE;
595 load_depmod();
596 }
597
598 free_modules();
599
600 return 0;
601 }
602
603 static int main_loader(int argc, char **argv)
604 {
605 int gl_flags = GLOB_NOESCAPE | GLOB_MARK;
606 char *dir = "/etc/modules.d/*";
607 glob_t gl;
608 char *path;
609 int j;
610
611 if (argc > 1)
612 dir = argv[1];
613
614 if (argc > 2)
615 prefix = argv[2];
616
617 path = malloc(strlen(dir) + 2);
618 strcpy(path, dir);
619 strcat(path, "*");
620
621 scan_loaded_modules();
622
623 syslog(0, "kmodloader: loading kernel modules from %s\n", path);
624
625 if (glob(path, gl_flags, NULL, &gl) < 0)
626 goto out;
627
628 for (j = 0; j < gl.gl_pathc; j++) {
629 FILE *fp = fopen(gl.gl_pathv[j], "r");
630 size_t mod_len = 0;
631 char *mod = NULL;
632
633 if (!fp) {
634 fprintf(stderr, "failed to open %s\n", gl.gl_pathv[j]);
635 continue;
636 }
637
638 while (getline(&mod, &mod_len, fp) > 0) {
639 char *nl = strchr(mod, '\n');
640 struct module *m;
641 char *opts;
642
643 if (nl)
644 *nl = '\0';
645
646 opts = strchr(mod, ' ');
647 if (opts)
648 *opts++ = '\0';
649
650 m = find_module(get_module_name(mod));
651 if (m)
652 continue;
653 insert_module(get_module_path(mod), (opts) ? (opts) : (""));
654 }
655 free(mod);
656 fclose(fp);
657 }
658
659 out:
660 globfree(&gl);
661 free(path);
662
663 return 0;
664 }
665
666 int main(int argc, char **argv)
667 {
668 char *exec = basename(*argv);
669
670 avl_init(&modules, avl_strcmp, false, NULL);
671 if (!strcmp(exec, "insmod"))
672 return main_insmod(argc, argv);
673
674 if (!strcmp(exec, "rmmod"))
675 return main_rmmod(argc, argv);
676
677 if (!strcmp(exec, "lsmod"))
678 return main_lsmod(argc, argv);
679
680 if (!strcmp(exec, "modinfo"))
681 return main_modinfo(argc, argv);
682
683 if (!strcmp(exec, "depmod"))
684 return main_depmod(argc, argv);
685
686 return main_loader(argc, argv);
687 }