aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modutils/Config.in14
-rw-r--r--modutils/depmod.c128
2 files changed, 121 insertions, 21 deletions
diff --git a/modutils/Config.in b/modutils/Config.in
index c69e1b376..fb7fb2266 100644
--- a/modutils/Config.in
+++ b/modutils/Config.in
@@ -11,6 +11,20 @@ config DEPMOD
11 help 11 help
12 depmod generates modules.dep (FIXME: elaborate) 12 depmod generates modules.dep (FIXME: elaborate)
13 13
14config FEATURE_DEPMOD_PRUNE_FANCY
15 bool "fancy dependency pruning"
16 default n
17 depends on DEPMOD
18 help
19 By default modules.dep contains all dependencies as listed by
20 the modules.
21 If you enable this option then we remove implied modules from
22 the dependencies.
23 This makes depmod somewhat bigger but generates a smaller
24 modules.dep file.
25
26 If unsure, say N.
27
14config INSMOD 28config INSMOD
15 bool "insmod" 29 bool "insmod"
16 default n 30 default n
diff --git a/modutils/depmod.c b/modutils/depmod.c
index e061501f6..b0b09c235 100644
--- a/modutils/depmod.c
+++ b/modutils/depmod.c
@@ -10,15 +10,27 @@
10#define _GNU_SOURCE 10#define _GNU_SOURCE
11#include <libbb.h> 11#include <libbb.h>
12#include <sys/utsname.h> /* uname() */ 12#include <sys/utsname.h> /* uname() */
13 13#if ENABLE_DEBUG
14#include <assert.h>
15#define dbg_assert assert
16#else
17#define dbg_assert(stuff) do {} while (0)
18#endif
14/* 19/*
15 * Theory of operation: 20 * Theory of operation:
16 * - iterate over all modules and record their full path 21 * - iterate over all modules and record their full path
17 * - iterate over all modules looking for "depends=" entries 22 * - iterate over all modules looking for "depends=" entries
18 * for each depends, look through our list of full paths and emit if found 23 * for each depends, look through our list of full paths and emit if found
19 */ 24 */
25
26typedef struct dep_lst_t {
27 char *name;
28 llist_t *dependencies;
29 struct dep_lst_t *next;
30} dep_lst_t;
31
20struct globals { 32struct globals {
21 llist_t *lst; /* modules without their corresponding extension */ 33 dep_lst_t *lst; /* modules without their corresponding extension */
22 size_t moddir_base_len; /* length of the "-b basedir" */ 34 size_t moddir_base_len; /* length of the "-b basedir" */
23}; 35};
24#define G (*(struct globals*)&bb_common_bufsiz1) 36#define G (*(struct globals*)&bb_common_bufsiz1)
@@ -28,22 +40,28 @@ struct globals {
28static int fill_lst(const char *modulename, struct stat ATTRIBUTE_UNUSED *sb, 40static int fill_lst(const char *modulename, struct stat ATTRIBUTE_UNUSED *sb,
29 void ATTRIBUTE_UNUSED *data, int ATTRIBUTE_UNUSED depth) 41 void ATTRIBUTE_UNUSED *data, int ATTRIBUTE_UNUSED depth)
30{ 42{
43
31 /* We get a file here. If the file does not have ".ko" but an 44 /* We get a file here. If the file does not have ".ko" but an
32 * intermittent dentry has, it's just their fault. 45 * intermittent dentry has, it's just their fault.
33 */ 46 */
34 if (strrstr(modulename, ".ko") != NULL) 47 if (strrstr(modulename, ".ko") != NULL) {
35 llist_add_to(&G.lst, xstrdup(modulename + G.moddir_base_len)); 48 dep_lst_t *new = xzalloc(sizeof(dep_lst_t));
49 new->name = xstrdup(modulename + G.moddir_base_len);
50 new->next = G.lst;
51 G.lst = new;
52 }
36 return TRUE; 53 return TRUE;
37} 54}
38 55
39static int fileAction(const char *fname, struct stat *sb, 56static int fileAction(const char *fname, struct stat *sb,
40 void *data, int ATTRIBUTE_UNUSED depth) 57 void ATTRIBUTE_UNUSED *data, int ATTRIBUTE_UNUSED depth)
41{ 58{
42 size_t len = sb->st_size; 59 size_t len = sb->st_size;
43 void *the_module; 60 void *the_module;
44 char *ptr; 61 char *ptr;
45 int fd; 62 int fd;
46 char *depends, *deps; 63 char *depends, *deps;
64 dep_lst_t *this;
47 65
48 if (strrstr(fname, ".ko") == NULL) /* not a module */ 66 if (strrstr(fname, ".ko") == NULL) /* not a module */
49 goto skip; 67 goto skip;
@@ -61,40 +79,44 @@ static int fileAction(const char *fname, struct stat *sb,
61 close(fd); 79 close(fd);
62 if (the_module == MAP_FAILED) 80 if (the_module == MAP_FAILED)
63 bb_perror_msg_and_die("mmap"); 81 bb_perror_msg_and_die("mmap");
64
65 ptr = the_module; 82 ptr = the_module;
66 83 this = G.lst;
67 fprintf((FILE*)data, "%s:", fname + G.moddir_base_len); 84 do {
85 if (!strcmp(fname + G.moddir_base_len, this->name))
86 break;
87 this = this->next;
88 } while (this);
89 dbg_assert (this);
68//bb_info_msg("fname='%s'", fname + G.moddir_base_len); 90//bb_info_msg("fname='%s'", fname + G.moddir_base_len);
69 do { 91 do {
70 /* search for a 'd' */ 92 /* search for a 'd' */
71 ptr = memchr(ptr, 'd', len - (ptr - (char*)the_module)); 93 ptr = memchr(ptr, 'd', len - (ptr - (char*)the_module));
72 if (ptr == NULL) /* no d left, done */ 94 if (ptr == NULL) /* no d left, done */
73 goto none; 95 goto none;
74 if (strncmp(ptr, "depends=", sizeof("depends=")-1) == 0) 96 if (!strncmp(ptr, "depends=", sizeof("depends=")-1))
75 break; 97 break;
76 ++ptr; 98 ++ptr;
77 } while (1); 99 } while (1);
78 deps = depends = xstrdup (ptr + sizeof("depends=")-1); 100 deps = depends = xstrdup (ptr + sizeof("depends=")-1);
79//bb_info_msg(" depends='%s'", depends); 101//bb_info_msg(" depends='%s'", depends);
80 while (deps) { 102 while (deps) {
81 llist_t * _lst = G.lst; 103 dep_lst_t *all = G.lst;
82 104
83 ptr = strsep(&deps, ","); 105 ptr = strsep(&deps, ",");
84 while (_lst) { 106 while (all) {
85 /* Compare the recorded filenames ignoring ".ko*" at the end. */ 107 /* Compare the recorded filenames ignoring ".ko*" at the end. */
86 char *tmp = bb_get_last_path_component_nostrip(_lst->data); 108 char *tmp = bb_get_last_path_component_nostrip(all->name);
87 if (strncmp(ptr, tmp, strrstr(tmp, ".ko") - tmp) == 0) 109 if (!strncmp(ptr, tmp, MAX(strlen(ptr),strrstr(tmp, ".ko") - tmp)))
88 break; /* found it */ 110 break; /* found it */
89 _lst = _lst->link; 111 all = all->next;
90 } 112 }
91 if (_lst) { 113 if (all) {
92//bb_info_msg("[%s] -> '%s'", (char*)ptr, _lst->data); 114 dbg_assert(all->name); /* this cannot be empty */
93 fprintf((FILE*)data, " %s", _lst->data); 115//bb_info_msg("[%s] -> '%s'", (char*)ptr, all->name);
116 llist_add_to_end(&this->dependencies, all->name);
94 } 117 }
95 } 118 }
96 free(depends); 119 free(depends);
97 fprintf((FILE*)data, "\n");
98 none: 120 none:
99 munmap(the_module, sb->st_size); 121 munmap(the_module, sb->st_size);
100 skip: 122 skip:
@@ -115,11 +137,14 @@ int depmod_main(int ATTRIBUTE_UNUSED argc, char **argv)
115 ARG_F = (1<<4), /* System.map that contains the symbols */ 137 ARG_F = (1<<4), /* System.map that contains the symbols */
116 ARG_n = (1<<5) /* dry-run, print to stdout only */ 138 ARG_n = (1<<5) /* dry-run, print to stdout only */
117 }; 139 };
140 INIT_G();
118 141
119 getopt32(argv, "aAb:eF:n", &moddir_base, &system_map); 142 getopt32(argv, "aAb:eF:n", &moddir_base, &system_map);
120 argv += optind; 143 argv += optind;
121 144
122 /* got a version to use? */ 145 /* If a version is provided, then that kernel version’s module directory
146 * is used, rather than the current kernel version (as returned by
147 * "uname -r"). */
123 if (*argv && (sscanf(*argv, "%d.%d.%d", &ret, &ret, &ret) == 3)) { 148 if (*argv && (sscanf(*argv, "%d.%d.%d", &ret, &ret, &ret) == 3)) {
124 moddir = concat_path_file(CONFIG_DEFAULT_MODULES_DIR, *argv++); 149 moddir = concat_path_file(CONFIG_DEFAULT_MODULES_DIR, *argv++);
125 } else { 150 } else {
@@ -160,6 +185,9 @@ int depmod_main(int ATTRIBUTE_UNUSED argc, char **argv)
160 else 185 else
161 return EXIT_FAILURE; 186 return EXIT_FAILURE;
162 } 187 }
188#if ENABLE_FEATURE_CLEAN_UP
189 else
190#endif
163 do { 191 do {
164 chp = option_mask32 & ARG_a ? moddir : *argv++; 192 chp = option_mask32 & ARG_a ? moddir : *argv++;
165 193
@@ -167,16 +195,74 @@ int depmod_main(int ATTRIBUTE_UNUSED argc, char **argv)
167 ACTION_RECURSE, /* flags */ 195 ACTION_RECURSE, /* flags */
168 fileAction, /* file action */ 196 fileAction, /* file action */
169 NULL, /* dir action */ 197 NULL, /* dir action */
170 (void*)filedes, /* user data */ 198 NULL, /* user data */
171 0)) { /* depth */ 199 0)) { /* depth */
172 ret = EXIT_FAILURE; 200 ret = EXIT_FAILURE;
173 } 201 }
174 } while (!(option_mask32 & ARG_a) && *argv); 202 } while (!(option_mask32 & ARG_a) && *argv);
175 203
204 /* modprobe allegedly wants dependencies without duplicates, i.e.
205 * mod1: mod2 mod3
206 * mod2: mod3
207 * mod3:
208 * implies that mod1 directly depends on mod2 and _not_ mod3 as mod3 is
209 * already implicitely pulled in via mod2. This leaves us with:
210 * mod1: mod2
211 * mod2: mod3
212 * mod3:
213 */
214 {
215 dep_lst_t *mods = G.lst;
216#if ENABLE_FEATURE_DEPMOD_PRUNE_FANCY
217 while (mods) {
218 llist_t *deps = mods->dependencies;
219 while (deps) {
220 dep_lst_t *all = G.lst;
221 while (all) {
222 if (!strcmp(all->name, deps->data)) {
223 llist_t *implied = all->dependencies;
224 while (implied) {
225 /* erm, nicer would be to just
226 * llist_unlink(&mods->dependencies, implied) */
227 llist_t *prune = mods->dependencies;
228 while (prune) {
229 if (!strcmp(implied->data, prune->data))
230 break;
231 prune = prune->link;
232 }
233//if (prune) bb_info_msg("[%s] '%s' implies '%s', removing", mods->name, all->name, implied->data);
234 llist_unlink(&mods->dependencies, prune);
235 implied = implied->link;
236 }
237 }
238 all = all->next;
239 }
240 deps = deps->link;
241 }
242 mods = mods->next;
243 }
244
245 mods = G.lst;
246#endif
247 /* Finally print them. */
248 while (mods) {
249 fprintf(filedes, "%s:", mods->name);
250 while (mods->dependencies)
251 fprintf(filedes, " %s", (char*)llist_pop(&mods->dependencies));
252 fprintf(filedes, "\n");
253 mods = mods->next;
254 }
255 }
256
176 if (ENABLE_FEATURE_CLEAN_UP) { 257 if (ENABLE_FEATURE_CLEAN_UP) {
177 fclose_if_not_stdin(filedes); 258 fclose_if_not_stdin(filedes);
178 llist_free(G.lst, free);
179 free(moddir); 259 free(moddir);
260 while (G.lst) {
261 dep_lst_t *old = G.lst;
262 G.lst = G.lst->next;
263 free(old->name);
264 free(old);
265 }
180 } 266 }
181 return ret; 267 return ret;
182} 268}