+
+ if (!stat(name, &s) && S_ISREG(s.st_mode))
+ return name;
+
+ for (p = module_folders; *p; p++) {
+ snprintf(path, sizeof(path), "%s%s.ko", *p, name);
+ if (!stat(path, &s) && S_ISREG(s.st_mode))
+ return path;
+ }
+
+ return NULL;
+}
+
+static char* get_module_name(char *path)
+{
+ static char name[32];
+ char *t;
+
+ strncpy(name, basename(path), sizeof(name));
+
+ t = strstr(name, ".ko");
+ if (t)
+ *t = '\0';
+
+ return name;
+}
+
+static int elf64_find_section(char *map, const char *section, unsigned int *offset, unsigned int *size)
+{
+ const char *secnames;
+ Elf64_Ehdr *e;
+ Elf64_Shdr *sh;
+ int i;
+
+ e = (Elf64_Ehdr *) map;
+ sh = (Elf64_Shdr *) (map + e->e_shoff);
+
+ secnames = map + sh[e->e_shstrndx].sh_offset;
+ for (i = 0; i < e->e_shnum; i++) {
+ if (!strcmp(section, secnames + sh[i].sh_name)) {
+ *size = sh[i].sh_size;
+ *offset = sh[i].sh_offset;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+static int elf32_find_section(char *map, const char *section, unsigned int *offset, unsigned int *size)
+{
+ const char *secnames;
+ Elf32_Ehdr *e;
+ Elf32_Shdr *sh;
+ int i;
+
+ e = (Elf32_Ehdr *) map;
+ sh = (Elf32_Shdr *) (map + e->e_shoff);
+
+ secnames = map + sh[e->e_shstrndx].sh_offset;
+ for (i = 0; i < e->e_shnum; i++) {
+ if (!strcmp(section, secnames + sh[i].sh_name)) {
+ *size = sh[i].sh_size;
+ *offset = sh[i].sh_offset;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+static int elf_find_section(char *map, const char *section, unsigned int *offset, unsigned int *size)
+{
+ int clazz = map[EI_CLASS];
+
+ if (clazz == ELFCLASS32)
+ return elf32_find_section(map, section, offset, size);
+ else if (clazz == ELFCLASS64)
+ return elf64_find_section(map, section, offset, size);
+
+ ULOG_ERR("unknown elf format %d\n", clazz);
+
+ return -1;
+}
+
+static struct module *
+alloc_module(const char *name, const char *depends, int size)
+{
+ struct module *m;
+ char *_name, *_dep;
+
+ m = calloc_a(sizeof(*m),
+ &_name, strlen(name) + 1,
+ &_dep, depends ? strlen(depends) + 2 : 0);
+ if (!m)
+ return NULL;
+
+ m->avl.key = m->name = strcpy(_name, name);
+ m->opts = 0;
+
+ if (depends) {
+ m->depends = strcpy(_dep, depends);
+ while (*_dep) {
+ if (*_dep == ',')
+ *_dep = '\0';
+ _dep++;
+ }
+ }
+
+ m->size = size;
+ avl_insert(&modules, &m->avl);
+
+ return m;
+}
+
+static int scan_loaded_modules(void)
+{
+ size_t buf_len = 0;
+ char *buf = NULL;
+ FILE *fp;
+
+ fp = fopen("/proc/modules", "r");
+ if (!fp) {
+ ULOG_ERR("failed to open /proc/modules\n");
+ return -1;
+ }
+
+ while (getline(&buf, &buf_len, fp) > 0) {
+ struct module m;
+ struct module *n;
+
+ m.name = strtok(buf, " ");
+ m.size = atoi(strtok(NULL, " "));
+ m.usage = atoi(strtok(NULL, " "));
+ m.depends = strtok(NULL, " ");
+
+ if (!m.name || !m.depends)
+ continue;
+
+ n = alloc_module(m.name, m.depends, m.size);
+ n->usage = m.usage;
+ n->state = LOADED;
+ }
+ free(buf);
+ fclose(fp);
+
+ return 0;
+}
+
+static struct module* get_module_info(const char *module, const char *name)
+{
+ int fd = open(module, O_RDONLY);
+ unsigned int offset, size;
+ char *map = MAP_FAILED, *strings, *dep = NULL;
+ struct module *m = NULL;
+ struct stat s;
+
+ if (fd < 0) {
+ ULOG_ERR("failed to open %s\n", module);
+ goto out;
+ }
+
+ if (fstat(fd, &s) == -1) {
+ ULOG_ERR("failed to stat %s\n", module);
+ goto out;
+ }
+
+ map = mmap(NULL, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (map == MAP_FAILED) {
+ ULOG_ERR("failed to mmap %s\n", module);
+ goto out;
+ }
+
+ if (elf_find_section(map, ".modinfo", &offset, &size)) {
+ ULOG_ERR("failed to load the .modinfo section from %s\n", module);
+ goto out;
+ }
+
+ strings = map + offset;
+ while (strings && (strings < map + offset + size)) {
+ char *sep;
+ int len;
+
+ while (!strings[0])
+ strings++;
+ sep = strstr(strings, "=");
+ if (!sep)
+ break;
+ len = sep - strings;
+ sep++;
+ if (!strncmp(strings, "depends=", len + 1))
+ dep = sep;
+ strings = &sep[strlen(sep)];
+ }
+
+ m = alloc_module(name, dep, s.st_size);
+
+ if (m)
+ m->state = SCANNED;
+
+out:
+ if (map != MAP_FAILED)
+ munmap(map, s.st_size);
+
+ if (fd >= 0)
+ close(fd);
+
+ return m;
+}
+
+static int scan_module_folder(const char *dir)
+{
+ int gl_flags = GLOB_NOESCAPE | GLOB_MARK;
+ struct utsname ver;
+ char *path;
+ glob_t gl;
+ int j;