blob: b0b09c2358df4d36d8596488c4e2caf757b5de2f [file] [log] [blame]
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +00001/* vi: set sw=4 ts=4: */
2/*
3 * depmod - generate modules.dep
4 * Copyright (c) 2008 Bernhard Fischer
5 *
6 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
7 */
8
9#undef _GNU_SOURCE
10#define _GNU_SOURCE
11#include <libbb.h>
12#include <sys/utsname.h> /* uname() */
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +000013#if ENABLE_DEBUG
14#include <assert.h>
15#define dbg_assert assert
16#else
17#define dbg_assert(stuff) do {} while (0)
18#endif
Bernhard Reutner-Fischercf180102008-05-26 15:12:01 +000019/*
20 * Theory of operation:
21 * - iterate over all modules and record their full path
22 * - iterate over all modules looking for "depends=" entries
23 * for each depends, look through our list of full paths and emit if found
24 */
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +000025
26typedef struct dep_lst_t {
27 char *name;
28 llist_t *dependencies;
29 struct dep_lst_t *next;
30} dep_lst_t;
31
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +000032struct globals {
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +000033 dep_lst_t *lst; /* modules without their corresponding extension */
Bernhard Reutner-Fischeref729dd2008-06-02 13:40:13 +000034 size_t moddir_base_len; /* length of the "-b basedir" */
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +000035};
36#define G (*(struct globals*)&bb_common_bufsiz1)
37/* We have to zero it out because of NOEXEC */
38#define INIT_G() memset(&G, 0, sizeof(G))
39
40static int fill_lst(const char *modulename, struct stat ATTRIBUTE_UNUSED *sb,
41 void ATTRIBUTE_UNUSED *data, int ATTRIBUTE_UNUSED depth)
42{
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +000043
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +000044 /* We get a file here. If the file does not have ".ko" but an
45 * intermittent dentry has, it's just their fault.
46 */
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +000047 if (strrstr(modulename, ".ko") != NULL) {
48 dep_lst_t *new = xzalloc(sizeof(dep_lst_t));
Bernhard Reutner-Fischeref729dd2008-06-02 13:40:13 +000049 new->name = xstrdup(modulename + G.moddir_base_len);
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +000050 new->next = G.lst;
51 G.lst = new;
52 }
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +000053 return TRUE;
54}
55
Bernhard Reutner-Fischercf180102008-05-26 15:12:01 +000056static int fileAction(const char *fname, struct stat *sb,
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +000057 void ATTRIBUTE_UNUSED *data, int ATTRIBUTE_UNUSED depth)
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +000058{
Bernhard Reutner-Fischercf180102008-05-26 15:12:01 +000059 size_t len = sb->st_size;
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +000060 void *the_module;
61 char *ptr;
Bernhard Reutner-Fischercf180102008-05-26 15:12:01 +000062 int fd;
63 char *depends, *deps;
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +000064 dep_lst_t *this;
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +000065
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +000066 if (strrstr(fname, ".ko") == NULL) /* not a module */
67 goto skip;
68
Bernhard Reutner-Fischercf180102008-05-26 15:12:01 +000069/*XXX: FIXME: does not handle compressed modules!
70 * There should be a function that looks at the extension and sets up
71 * open_transformer for us.
72 */
Bernhard Reutner-Fischercf180102008-05-26 15:12:01 +000073 fd = xopen(fname, O_RDONLY);
74 the_module = mmap(NULL, len, PROT_READ, MAP_SHARED
75#if defined MAP_POPULATE
76 |MAP_POPULATE
77#endif
78 , fd, 0);
79 close(fd);
80 if (the_module == MAP_FAILED)
81 bb_perror_msg_and_die("mmap");
Bernhard Reutner-Fischercf180102008-05-26 15:12:01 +000082 ptr = the_module;
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +000083 this = G.lst;
84 do {
Bernhard Reutner-Fischeref729dd2008-06-02 13:40:13 +000085 if (!strcmp(fname + G.moddir_base_len, this->name))
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +000086 break;
87 this = this->next;
88 } while (this);
89 dbg_assert (this);
Bernhard Reutner-Fischeref729dd2008-06-02 13:40:13 +000090//bb_info_msg("fname='%s'", fname + G.moddir_base_len);
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +000091 do {
92 /* search for a 'd' */
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +000093 ptr = memchr(ptr, 'd', len - (ptr - (char*)the_module));
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +000094 if (ptr == NULL) /* no d left, done */
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +000095 goto none;
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +000096 if (!strncmp(ptr, "depends=", sizeof("depends=")-1))
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +000097 break;
Bernhard Reutner-Fischerc21d9c72008-05-28 10:35:51 +000098 ++ptr;
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +000099 } while (1);
Bernhard Reutner-Fischer6bb55cf2008-05-26 17:04:01 +0000100 deps = depends = xstrdup (ptr + sizeof("depends=")-1);
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000101//bb_info_msg(" depends='%s'", depends);
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +0000102 while (deps) {
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +0000103 dep_lst_t *all = G.lst;
Bernhard Reutner-Fischercf180102008-05-26 15:12:01 +0000104
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +0000105 ptr = strsep(&deps, ",");
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +0000106 while (all) {
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +0000107 /* Compare the recorded filenames ignoring ".ko*" at the end. */
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +0000108 char *tmp = bb_get_last_path_component_nostrip(all->name);
109 if (!strncmp(ptr, tmp, MAX(strlen(ptr),strrstr(tmp, ".ko") - tmp)))
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000110 break; /* found it */
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +0000111 all = all->next;
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000112 }
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +0000113 if (all) {
114 dbg_assert(all->name); /* this cannot be empty */
115//bb_info_msg("[%s] -> '%s'", (char*)ptr, all->name);
116 llist_add_to_end(&this->dependencies, all->name);
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000117 }
118 }
Bernhard Reutner-Fischercf180102008-05-26 15:12:01 +0000119 free(depends);
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +0000120 none:
Bernhard Reutner-Fischercf180102008-05-26 15:12:01 +0000121 munmap(the_module, sb->st_size);
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +0000122 skip:
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000123 return TRUE;
124}
125
126int depmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
127int depmod_main(int ATTRIBUTE_UNUSED argc, char **argv)
128{
Bernhard Reutner-Fischerc21d9c72008-05-28 10:35:51 +0000129 int ret;
Bernhard Reutner-Fischer1ea25682008-05-26 21:33:05 +0000130 char *moddir_base = NULL, *moddir, *system_map, *chp;
Bernhard Reutner-Fischer6bb55cf2008-05-26 17:04:01 +0000131 FILE *filedes = stdout;
132 enum {
133 ARG_a = (1<<0), /* All modules, ignore mods in argv */
134 ARG_A = (1<<1), /* Only emit .ko that are newer than modules.dep file */
135 ARG_b = (1<<2), /* not /lib/modules/$(uname -r)/ but this base-dir */
136 ARG_e = (1<<3), /* with -F, print unresolved symbols */
137 ARG_F = (1<<4), /* System.map that contains the symbols */
138 ARG_n = (1<<5) /* dry-run, print to stdout only */
139 };
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +0000140 INIT_G();
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000141
Bernhard Reutner-Fischer6bb55cf2008-05-26 17:04:01 +0000142 getopt32(argv, "aAb:eF:n", &moddir_base, &system_map);
143 argv += optind;
Bernhard Reutner-Fischerc21d9c72008-05-28 10:35:51 +0000144
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +0000145 /* 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"). */
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +0000148 if (*argv && (sscanf(*argv, "%d.%d.%d", &ret, &ret, &ret) == 3)) {
Bernhard Reutner-Fischerc21d9c72008-05-28 10:35:51 +0000149 moddir = concat_path_file(CONFIG_DEFAULT_MODULES_DIR, *argv++);
Bernhard Reutner-Fischer1ea25682008-05-26 21:33:05 +0000150 } else {
Bernhard Reutner-Fischer6bb55cf2008-05-26 17:04:01 +0000151 struct utsname uts;
152 if (uname(&uts) < 0)
153 bb_simple_perror_msg_and_die("uname");
Bernhard Reutner-Fischerc21d9c72008-05-28 10:35:51 +0000154 moddir = concat_path_file(CONFIG_DEFAULT_MODULES_DIR, uts.release);
Bernhard Reutner-Fischer6bb55cf2008-05-26 17:04:01 +0000155 }
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +0000156 /* If no modules are given on the command-line, -a is on per default. */
Bernhard Reutner-Fischer1ea25682008-05-26 21:33:05 +0000157 option_mask32 |= *argv == NULL;
158
Bernhard Reutner-Fischer1ea25682008-05-26 21:33:05 +0000159 if (option_mask32 & ARG_b) {
Bernhard Reutner-Fischeref729dd2008-06-02 13:40:13 +0000160 G.moddir_base_len = strlen(moddir_base);
161 if (ENABLE_FEATURE_CLEAN_UP) {
162 chp = moddir;
163 moddir = concat_path_file(moddir_base, moddir);
164 free (chp);
165 } else
166 moddir = concat_path_file(moddir_base, moddir);
Bernhard Reutner-Fischer6bb55cf2008-05-26 17:04:01 +0000167 }
Bernhard Reutner-Fischer1ea25682008-05-26 21:33:05 +0000168
169 if (!(option_mask32 & ARG_n)) { /* --dry-run */
Bernhard Reutner-Fischerb85fb692008-05-27 10:55:34 +0000170 chp = concat_path_file(moddir, CONFIG_DEFAULT_DEPMOD_FILE);
Bernhard Reutner-Fischer1ea25682008-05-26 21:33:05 +0000171 filedes = xfopen(chp, "w");
172 if (ENABLE_FEATURE_CLEAN_UP)
173 free(chp);
174 }
Bernhard Reutner-Fischerc21d9c72008-05-28 10:35:51 +0000175 ret = EXIT_SUCCESS;
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +0000176 /* We have to do a full walk to collect all needed data. */
Bernhard Reutner-Fischer1ea25682008-05-26 21:33:05 +0000177 if (!recursive_action(moddir,
178 ACTION_RECURSE, /* flags */
179 fill_lst, /* file action */
180 NULL, /* dir action */
181 NULL, /* user data */
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +0000182 0)) { /* depth */
183 if (ENABLE_FEATURE_CLEAN_UP)
184 ret = EXIT_FAILURE;
185 else
186 return EXIT_FAILURE;
187 }
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +0000188#if ENABLE_FEATURE_CLEAN_UP
189 else
190#endif
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000191 do {
Bernhard Reutner-Fischerc21d9c72008-05-28 10:35:51 +0000192 chp = option_mask32 & ARG_a ? moddir : *argv++;
Bernhard Reutner-Fischer6bb55cf2008-05-26 17:04:01 +0000193
194 if (!recursive_action(chp,
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000195 ACTION_RECURSE, /* flags */
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000196 fileAction, /* file action */
197 NULL, /* dir action */
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +0000198 NULL, /* user data */
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000199 0)) { /* depth */
Bernhard Reutner-Fischerc21d9c72008-05-28 10:35:51 +0000200 ret = EXIT_FAILURE;
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000201 }
Bernhard Reutner-Fischer1ea25682008-05-26 21:33:05 +0000202 } while (!(option_mask32 & ARG_a) && *argv);
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000203
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +0000204 /* 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
Bernhard Reutner-Fischerdc5d7fe2008-05-26 13:30:41 +0000257 if (ENABLE_FEATURE_CLEAN_UP) {
Bernhard Reutner-Fischerc21d9c72008-05-28 10:35:51 +0000258 fclose_if_not_stdin(filedes);
Bernhard Reutner-Fischer1ea25682008-05-26 21:33:05 +0000259 free(moddir);
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +0000260 while (G.lst) {
261 dep_lst_t *old = G.lst;
262 G.lst = G.lst->next;
263 free(old->name);
264 free(old);
265 }
Bernhard Reutner-Fischerdc5d7fe2008-05-26 13:30:41 +0000266 }
Bernhard Reutner-Fischerc21d9c72008-05-28 10:35:51 +0000267 return ret;
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000268}