aboutsummaryrefslogtreecommitdiff
path: root/modutils/depmod.c
diff options
context:
space:
mode:
Diffstat (limited to 'modutils/depmod.c')
-rw-r--r--modutils/depmod.c378
1 files changed, 152 insertions, 226 deletions
diff --git a/modutils/depmod.c b/modutils/depmod.c
index b6a914eb0..35df4a8e2 100644
--- a/modutils/depmod.c
+++ b/modutils/depmod.c
@@ -2,6 +2,8 @@
2/* 2/*
3 * depmod - generate modules.dep 3 * depmod - generate modules.dep
4 * Copyright (c) 2008 Bernhard Fischer 4 * Copyright (c) 2008 Bernhard Fischer
5 * Copyrihgt (c) 2008 Timo Teras <timo.teras@iki.fi>
6 * Copyright (c) 2008 Vladimir Dronnikov
5 * 7 *
6 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
7 */ 9 */
@@ -10,6 +12,8 @@
10#define _GNU_SOURCE 12#define _GNU_SOURCE
11#include <libbb.h> 13#include <libbb.h>
12#include <sys/utsname.h> /* uname() */ 14#include <sys/utsname.h> /* uname() */
15#include "modutils.h"
16
13/* 17/*
14 * Theory of operation: 18 * Theory of operation:
15 * - iterate over all modules and record their full path 19 * - iterate over all modules and record their full path
@@ -17,272 +21,194 @@
17 * for each depends, look through our list of full paths and emit if found 21 * for each depends, look through our list of full paths and emit if found
18 */ 22 */
19 23
20typedef struct dep_lst_t { 24typedef struct module_info {
21 char *name; 25 struct module_info *next;
26 char *name, *modname;
22 llist_t *dependencies; 27 llist_t *dependencies;
23 llist_t *aliases; 28 llist_t *aliases;
24 struct dep_lst_t *next; 29 llist_t *symbols;
25} dep_lst_t; 30 struct module_info *dnext, *dprev;
26 31} module_info;
27struct globals { 32
28 dep_lst_t *lst; /* modules without their corresponding extension */ 33enum {
34 ARG_a = (1<<0), /* All modules, ignore mods in argv */
35 ARG_A = (1<<1), /* Only emit .ko that are newer than modules.dep file */
36 ARG_b = (1<<2), /* not /lib/modules/$(uname -r)/ but this base-dir */
37 ARG_e = (1<<3), /* with -F, print unresolved symbols */
38 ARG_F = (1<<4), /* System.map that contains the symbols */
39 ARG_n = (1<<5) /* dry-run, print to stdout only */
29}; 40};
30#define G (*(struct globals*)&bb_common_bufsiz1)
31/* We have to zero it out because of NOEXEC */
32#define INIT_G() memset(&G, 0, sizeof(G))
33 41
34static char* find_keyword(void *the_module, size_t len, const char * const word) 42static int FAST_FUNC parse_module(const char *fname, struct stat *sb,
43 void *data, int UNUSED_PARAM depth)
35{ 44{
36 char *ptr = the_module; 45 module_info **first = (module_info **) data;
37 do { 46 char *image, *ptr;
38 /* search for the first char in word */ 47 module_info *info;
39 ptr = memchr(ptr, *word, len - (ptr - (char*)the_module)); 48 size_t len = sb->st_size;
40 if (ptr == NULL) /* no occurance left, done */ 49
41 return NULL; 50 if (strrstr(fname, ".ko") == NULL)
42 if (!strncmp(ptr, word, strlen(word))) { 51 return TRUE;
43 ptr += strlen(word); 52
44 break; 53 image = (char *) xmalloc_open_zipped_read_close(fname, &len);
54 info = xzalloc(sizeof(module_info));
55
56 info->next = *first;
57 *first = info;
58
59 info->dnext = info->dprev = info;
60 info->name = xstrdup(fname);
61 info->modname = filename2modname(fname, NULL);
62 for (ptr = image; ptr < image + len - 10; ptr++) {
63 if (strncmp(ptr, "depends=", 8) == 0) {
64 char *u;
65
66 ptr += 8;
67 for (u = ptr; *u; u++)
68 if (*u == '-')
69 *u = '_';
70 ptr += string_to_llist(ptr, &info->dependencies, ",");
71 } else if (ENABLE_FEATURE_MODUTILS_ALIAS &&
72 strncmp(ptr, "alias=", 6) == 0) {
73 llist_add_to(&info->aliases, xstrdup(ptr + 6));
74 ptr += strlen(ptr);
75 } else if (ENABLE_FEATURE_MODUTILS_SYMBOLS &&
76 strncmp(ptr, "__ksymtab_", 10) == 0) {
77 ptr += 10;
78 if (strncmp(ptr, "gpl", 3) == 0 ||
79 strcmp(ptr, "strings") == 0)
80 continue;
81 llist_add_to(&info->symbols, xstrdup(ptr));
82 ptr += strlen(ptr);
45 } 83 }
46 ++ptr; 84 }
47 } while (1); 85 free(image);
48 return ptr; 86
87 return TRUE;
49} 88}
50static int FAST_FUNC fileAction(const char *fname, struct stat *sb,
51 void UNUSED_PARAM *data, int UNUSED_PARAM depth)
52{
53 size_t len = sb->st_size;
54 void *the_module;
55 char *ptr;
56 int fd;
57 char *depends, *deps;
58 dep_lst_t *this;
59 89
60 if (strrstr(fname, ".ko") == NULL) /* not a module */ 90static module_info *find_module(module_info *modules, const char *modname)
61 goto skip; 91{
92 module_info *m;
62 93
63/*XXX: FIXME: does not handle compressed modules! 94 for (m = modules; m != NULL; m = m->next)
64 * There should be a function that looks at the extension and sets up 95 if (strcmp(m->modname, modname) == 0)
65 * open_transformer for us. 96 return m;
66 */ 97 return NULL;
67 fd = xopen(fname, O_RDONLY); 98}
68 the_module = mmap(NULL, len, PROT_READ, MAP_SHARED
69#if defined MAP_POPULATE
70 |MAP_POPULATE
71#endif
72 , fd, 0);
73 close(fd);
74 if (the_module == MAP_FAILED)
75 bb_perror_msg_and_die("mmap");
76 99
77 this = xzalloc(sizeof(dep_lst_t)); 100static void order_dep_list(module_info *modules, module_info *start,
78 this->name = xstrdup(fname); 101 llist_t *add)
79 this->next = G.lst; 102{
80 G.lst = this; 103 module_info *m;
81//bb_info_msg("fname='%s'", fname); 104 llist_t *n;
82 ptr = find_keyword(the_module, len, "depends="); 105
83 if (!*ptr) 106 for (n = add; n != NULL; n = n->link) {
84 goto d_none; 107 m = find_module(modules, n->data);
85 deps = depends = xstrdup(ptr); 108 if (m == NULL)
86//bb_info_msg(" depends='%s'", depends); 109 continue;
87 while (deps) { 110
88 ptr = strsep(&deps, ","); 111 /* unlink current entry */
89//bb_info_msg("[%s] -> '%s'", fname, (char*)ptr); 112 m->dnext->dprev = m->dprev;
90 llist_add_to_end(&this->dependencies, xstrdup(ptr)); 113 m->dprev->dnext = m->dnext;
91 } 114
92 free(depends); 115 /* and add it to tail */
93 d_none: 116 m->dnext = start;
94 if (ENABLE_FEATURE_DEPMOD_ALIAS) 117 m->dprev = start->dprev;
95 { 118 start->dprev->dnext = m;
96 size_t pos = 0; 119 start->dprev = m;
97 do { 120
98 ptr = find_keyword(the_module + pos, len - pos, "alias="); 121 /* recurse */
99 if (ptr) { 122 order_dep_list(modules, start, m->dependencies);
100//bb_info_msg("[%s] alias '%s'", fname, (char*)ptr);
101 llist_add_to_end(&this->aliases, xstrdup(ptr));
102 } else
103 break;
104 pos = (ptr - (char*)the_module);
105 } while (1);
106 } 123 }
107 munmap(the_module, sb->st_size);
108 skip:
109 return TRUE;
110} 124}
111 125
112int depmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 126int depmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
113int depmod_main(int argc UNUSED_PARAM, char **argv) 127int depmod_main(int argc UNUSED_PARAM, char **argv)
114{ 128{
115 int ret; 129 module_info *modules = NULL, *m, *dep;
116 size_t moddir_base_len = 0; /* length of the "-b basedir" */ 130 char *moddir_base = (char *)CONFIG_DEFAULT_MODULES_DIR;
117 char *moddir_base = NULL, *moddir, *system_map, *chp; 131 int tmp;
118 FILE *filedes = stdout;
119 enum {
120 ARG_a = (1<<0), /* All modules, ignore mods in argv */
121 ARG_A = (1<<1), /* Only emit .ko that are newer than modules.dep file */
122 ARG_b = (1<<2), /* not /lib/modules/$(uname -r)/ but this base-dir */
123 ARG_e = (1<<3), /* with -F, print unresolved symbols */
124 ARG_F = (1<<4), /* System.map that contains the symbols */
125 ARG_n = (1<<5) /* dry-run, print to stdout only */
126 };
127 INIT_G();
128 132
129 getopt32(argv, "aAb:eF:n", &moddir_base, &system_map); 133 getopt32(argv, "aAb:eF:n", &moddir_base, NULL);
130 argv += optind; 134 argv += optind;
131 135
132 /* If a version is provided, then that kernel version’s module directory 136 /* goto modules location */
137
138 /* If a version is provided, then that kernel version's module directory
133 * is used, rather than the current kernel version (as returned by 139 * is used, rather than the current kernel version (as returned by
134 * "uname -r"). */ 140 * "uname -r"). */
135 if (*argv && (sscanf(*argv, "%d.%d.%d", &ret, &ret, &ret) == 3)) { 141 xchdir(moddir_base);
136 moddir = concat_path_file(CONFIG_DEFAULT_MODULES_DIR, *argv++); 142 if (*argv && (sscanf(*argv, "%d.%d.%d", &tmp, &tmp, &tmp) == 3)) {
143 xchdir(*argv++);
137 } else { 144 } else {
138 struct utsname uts; 145 struct utsname uts;
139 if (uname(&uts) < 0) 146 uname(&uts);
140 bb_simple_perror_msg_and_die("uname"); 147 xchdir(uts.release);
141 moddir = concat_path_file(CONFIG_DEFAULT_MODULES_DIR, uts.release);
142 } 148 }
143 /* If no modules are given on the command-line, -a is on per default. */ 149 /* If no modules are given on the command-line, -a is on per default. */
144 option_mask32 |= *argv == NULL; 150 option_mask32 |= *argv == NULL;
145 151
146 if (option_mask32 & ARG_b) { 152 /* Scan modules */
147 moddir_base_len = strlen(moddir_base) + 1; 153 moddir_base = xrealloc_getcwd_or_warn(NULL);
148 xchdir(moddir_base);
149 }
150
151 if (!(option_mask32 & ARG_n)) { /* --dry-run */
152 chp = concat_path_file(moddir, CONFIG_DEFAULT_DEPMOD_FILE);
153 filedes = xfopen_for_write(chp);
154 if (ENABLE_FEATURE_CLEAN_UP)
155 free(chp);
156 }
157 ret = EXIT_SUCCESS;
158 do { 154 do {
159 chp = option_mask32 & ARG_a ? moddir : (*argv + moddir_base_len); 155 recursive_action((option_mask32 & ARG_a) ? moddir_base : *argv,
160 156 ACTION_RECURSE, parse_module, NULL, &modules, 0);
161 if (!recursive_action(chp, 157 } while (!(option_mask32 & ARG_a) && *(++argv));
162 ACTION_RECURSE, /* flags */ 158 if (ENABLE_FEATURE_CLEAN_UP)
163 fileAction, /* file action */ 159 free(moddir_base);
164 NULL, /* dir action */ 160
165 NULL, /* user data */ 161 /* Generate dependency and alias files */
166 0)) { /* depth */ 162 if (!(option_mask32 & ARG_n))
167 ret = EXIT_FAILURE; 163 freopen(CONFIG_DEFAULT_DEPMOD_FILE, "w", stdout);
164 for (m = modules; m != NULL; m = m->next) {
165 printf("%s:", m->name);
166
167 order_dep_list(modules, m, m->dependencies);
168 while (m->dnext != m) {
169 dep = m->dnext;
170 printf(" %s", dep->name);
171
172 /* unlink current entry */
173 dep->dnext->dprev = dep->dprev;
174 dep->dprev->dnext = dep->dnext;
175 dep->dnext = dep->dprev = dep;
168 } 176 }
169 } while (!(option_mask32 & ARG_a) && *++argv); 177 puts("");
170
171 {
172 dep_lst_t *mods = G.lst;
173
174 /* Fixup the module names in the depends list */
175 while (mods) {
176 llist_t *deps = NULL, *old_deps = mods->dependencies;
177
178 while (old_deps) {
179 dep_lst_t *all = G.lst;
180 char *longname = NULL;
181 char *shortname = llist_pop(&old_deps);
182
183 while (all) {
184 char *nam =
185 xstrdup(bb_get_last_path_component_nostrip(all->name));
186 char *tmp = strrstr(nam, ".ko");
187
188 *tmp = '\0';
189 if (!strcmp(nam, shortname)) {
190 if (ENABLE_FEATURE_CLEAN_UP)
191 free(nam);
192 longname = all->name;
193 break;
194 }
195 free(nam);
196 all = all->next;
197 }
198 llist_add_to_end(&deps, longname);
199 }
200 mods->dependencies = deps;
201 mods = mods->next;
202 } 178 }
203 179
204#if ENABLE_FEATURE_DEPMOD_PRUNE_FANCY 180#if ENABLE_FEATURE_MODUTILS_ALIAS
205 /* modprobe allegedly wants dependencies without duplicates, i.e. 181 if (!(option_mask32 & ARG_n))
206 * mod1: mod2 mod3 182 freopen("modules.alias", "w", stdout);
207 * mod2: mod3 183 for (m = modules; m != NULL; m = m->next) {
208 * mod3: 184 while (m->aliases) {
209 * implies that mod1 directly depends on mod2 and _not_ mod3 as mod3 is 185 printf("alias %s %s\n",
210 * already implicitely pulled in via mod2. This leaves us with: 186 (char*)llist_pop(&m->aliases),
211 * mod1: mod2 187 m->modname);
212 * mod2: mod3
213 * mod3:
214 */
215 mods = G.lst;
216 while (mods) {
217 llist_t *deps = mods->dependencies;
218 while (deps) {
219 dep_lst_t *all = G.lst;
220 while (all) {
221 if (!strcmp(all->name, deps->data)) {
222 llist_t *implied = all->dependencies;
223 while (implied) {
224 /* XXX:FIXME: erm, it would be nicer to just
225 * llist_unlink(&mods->dependencies, implied) */
226 llist_t *prune = mods->dependencies;
227 while (prune) {
228 if (!strcmp(implied->data, prune->data))
229 break;
230 prune = prune->link;
231 }
232//if (prune) bb_info_msg("[%s] '%s' implies '%s', removing", mods->name, all->name, implied->data);
233 llist_unlink(&mods->dependencies, prune);
234 implied = implied->link;
235 }
236 }
237 all = all->next;
238 }
239 deps = deps->link;
240 } 188 }
241 mods = mods->next;
242 } 189 }
243#endif 190#endif
244 191#if ENABLE_FEATURE_MODUTILS_SYMBOLS
245 mods = G.lst; 192 if (!(option_mask32 & ARG_n))
246 /* Finally print them. */ 193 freopen("modules.symbols", "w", stdout);
247 while (mods) { 194 for (m = modules; m != NULL; m = m->next) {
248 fprintf(filedes, "%s:", mods->name); 195 while (m->symbols) {
249 /* If we did not resolve all modules, then it's likely that we just did 196 printf("alias symbol:%s %s\n",
250 * not see the names of all prerequisites (which will be NULL in this 197 (char*)llist_pop(&m->symbols),
251 * case). */ 198 m->modname);
252 while (mods->dependencies) {
253 char *the_dep = llist_pop(&mods->dependencies);
254 if (the_dep)
255 fprintf(filedes, " %s", the_dep);
256 }
257 fprintf(filedes, "\n");
258 if (ENABLE_FEATURE_DEPMOD_ALIAS)
259 {
260 char *shortname =
261 xstrdup(bb_get_last_path_component_nostrip(mods->name));
262 char *tmp = strrstr(shortname, ".ko");
263
264 *tmp = '\0';
265
266 while (mods->aliases) {
267 fprintf(filedes, "alias %s %s\n",
268 (char*)llist_pop(&mods->aliases),
269 shortname);
270 }
271 free(shortname);
272 } 199 }
273 mods = mods->next;
274 }
275 } 200 }
201#endif
276 202
277 if (ENABLE_FEATURE_CLEAN_UP) { 203 if (ENABLE_FEATURE_CLEAN_UP) {
278 fclose_if_not_stdin(filedes); 204 while (modules) {
279 free(moddir); 205 module_info *old = modules;
280 while (G.lst) { 206 modules = modules->next;
281 dep_lst_t *old = G.lst;
282 G.lst = G.lst->next;
283 free(old->name); 207 free(old->name);
208 free(old->modname);
284 free(old); 209 free(old);
285 } 210 }
286 } 211 }
287 return ret; 212
213 return EXIT_SUCCESS;
288} 214}