blob: b2bbc79406c12eabbc90aff2777abb74c76c43e3 [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-Fischer55e547e2008-05-26 12:01:49 +000034};
35#define G (*(struct globals*)&bb_common_bufsiz1)
36/* We have to zero it out because of NOEXEC */
37#define INIT_G() memset(&G, 0, sizeof(G))
38
39static int fill_lst(const char *modulename, struct stat ATTRIBUTE_UNUSED *sb,
40 void ATTRIBUTE_UNUSED *data, int ATTRIBUTE_UNUSED depth)
41{
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +000042
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +000043 /* We get a file here. If the file does not have ".ko" but an
44 * intermittent dentry has, it's just their fault.
45 */
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +000046 if (strrstr(modulename, ".ko") != NULL) {
47 dep_lst_t *new = xzalloc(sizeof(dep_lst_t));
Bernhard Reutner-Fischerd4281672008-06-02 13:34:36 +000048 new->name = xstrdup(modulename);
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +000049 new->next = G.lst;
50 G.lst = new;
51 }
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +000052 return TRUE;
53}
54
Bernhard Reutner-Fischercf180102008-05-26 15:12:01 +000055static int fileAction(const char *fname, struct stat *sb,
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +000056 void ATTRIBUTE_UNUSED *data, int ATTRIBUTE_UNUSED depth)
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +000057{
Bernhard Reutner-Fischercf180102008-05-26 15:12:01 +000058 size_t len = sb->st_size;
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +000059 void *the_module;
60 char *ptr;
Bernhard Reutner-Fischercf180102008-05-26 15:12:01 +000061 int fd;
62 char *depends, *deps;
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +000063 dep_lst_t *this;
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +000064
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +000065 if (strrstr(fname, ".ko") == NULL) /* not a module */
66 goto skip;
67
Bernhard Reutner-Fischercf180102008-05-26 15:12:01 +000068/*XXX: FIXME: does not handle compressed modules!
69 * There should be a function that looks at the extension and sets up
70 * open_transformer for us.
71 */
Bernhard Reutner-Fischercf180102008-05-26 15:12:01 +000072 fd = xopen(fname, O_RDONLY);
73 the_module = mmap(NULL, len, PROT_READ, MAP_SHARED
74#if defined MAP_POPULATE
75 |MAP_POPULATE
76#endif
77 , fd, 0);
78 close(fd);
79 if (the_module == MAP_FAILED)
80 bb_perror_msg_and_die("mmap");
Bernhard Reutner-Fischercf180102008-05-26 15:12:01 +000081 ptr = the_module;
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +000082 this = G.lst;
83 do {
Bernhard Reutner-Fischerd4281672008-06-02 13:34:36 +000084 if (!strcmp(fname, this->name))
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +000085 break;
86 this = this->next;
87 } while (this);
88 dbg_assert (this);
Bernhard Reutner-Fischerd4281672008-06-02 13:34:36 +000089//bb_info_msg("fname='%s'", fname);
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +000090 do {
91 /* search for a 'd' */
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +000092 ptr = memchr(ptr, 'd', len - (ptr - (char*)the_module));
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +000093 if (ptr == NULL) /* no d left, done */
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +000094 goto none;
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +000095 if (!strncmp(ptr, "depends=", sizeof("depends=")-1))
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +000096 break;
Bernhard Reutner-Fischerc21d9c72008-05-28 10:35:51 +000097 ++ptr;
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +000098 } while (1);
Bernhard Reutner-Fischer6bb55cf2008-05-26 17:04:01 +000099 deps = depends = xstrdup (ptr + sizeof("depends=")-1);
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000100//bb_info_msg(" depends='%s'", depends);
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +0000101 while (deps) {
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +0000102 dep_lst_t *all = G.lst;
Bernhard Reutner-Fischercf180102008-05-26 15:12:01 +0000103
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +0000104 ptr = strsep(&deps, ",");
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +0000105 while (all) {
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +0000106 /* Compare the recorded filenames ignoring ".ko*" at the end. */
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +0000107 char *tmp = bb_get_last_path_component_nostrip(all->name);
108 if (!strncmp(ptr, tmp, MAX(strlen(ptr),strrstr(tmp, ".ko") - tmp)))
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000109 break; /* found it */
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +0000110 all = all->next;
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000111 }
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +0000112 if (all) {
113 dbg_assert(all->name); /* this cannot be empty */
114//bb_info_msg("[%s] -> '%s'", (char*)ptr, all->name);
115 llist_add_to_end(&this->dependencies, all->name);
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000116 }
117 }
Bernhard Reutner-Fischercf180102008-05-26 15:12:01 +0000118 free(depends);
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +0000119 none:
Bernhard Reutner-Fischercf180102008-05-26 15:12:01 +0000120 munmap(the_module, sb->st_size);
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +0000121 skip:
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000122 return TRUE;
123}
124
125int depmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
126int depmod_main(int ATTRIBUTE_UNUSED argc, char **argv)
127{
Bernhard Reutner-Fischerc21d9c72008-05-28 10:35:51 +0000128 int ret;
Bernhard Reutner-Fischer1ea25682008-05-26 21:33:05 +0000129 char *moddir_base = NULL, *moddir, *system_map, *chp;
Bernhard Reutner-Fischer6bb55cf2008-05-26 17:04:01 +0000130 FILE *filedes = stdout;
131 enum {
132 ARG_a = (1<<0), /* All modules, ignore mods in argv */
133 ARG_A = (1<<1), /* Only emit .ko that are newer than modules.dep file */
134 ARG_b = (1<<2), /* not /lib/modules/$(uname -r)/ but this base-dir */
135 ARG_e = (1<<3), /* with -F, print unresolved symbols */
136 ARG_F = (1<<4), /* System.map that contains the symbols */
137 ARG_n = (1<<5) /* dry-run, print to stdout only */
138 };
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +0000139 INIT_G();
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000140
Bernhard Reutner-Fischer6bb55cf2008-05-26 17:04:01 +0000141 getopt32(argv, "aAb:eF:n", &moddir_base, &system_map);
142 argv += optind;
Bernhard Reutner-Fischerc21d9c72008-05-28 10:35:51 +0000143
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +0000144 /* If a version is provided, then that kernel version’s module directory
145 * is used, rather than the current kernel version (as returned by
146 * "uname -r"). */
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +0000147 if (*argv && (sscanf(*argv, "%d.%d.%d", &ret, &ret, &ret) == 3)) {
Bernhard Reutner-Fischerc21d9c72008-05-28 10:35:51 +0000148 moddir = concat_path_file(CONFIG_DEFAULT_MODULES_DIR, *argv++);
Bernhard Reutner-Fischer1ea25682008-05-26 21:33:05 +0000149 } else {
Bernhard Reutner-Fischer6bb55cf2008-05-26 17:04:01 +0000150 struct utsname uts;
151 if (uname(&uts) < 0)
152 bb_simple_perror_msg_and_die("uname");
Bernhard Reutner-Fischerc21d9c72008-05-28 10:35:51 +0000153 moddir = concat_path_file(CONFIG_DEFAULT_MODULES_DIR, uts.release);
Bernhard Reutner-Fischer6bb55cf2008-05-26 17:04:01 +0000154 }
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +0000155 /* If no modules are given on the command-line, -a is on per default. */
Bernhard Reutner-Fischer1ea25682008-05-26 21:33:05 +0000156 option_mask32 |= *argv == NULL;
157
Bernhard Reutner-Fischer1ea25682008-05-26 21:33:05 +0000158 if (option_mask32 & ARG_b) {
Bernhard Reutner-Fischerd4281672008-06-02 13:34:36 +0000159 xchdir(moddir_base);
Bernhard Reutner-Fischer6bb55cf2008-05-26 17:04:01 +0000160 }
Bernhard Reutner-Fischer1ea25682008-05-26 21:33:05 +0000161
162 if (!(option_mask32 & ARG_n)) { /* --dry-run */
Bernhard Reutner-Fischerb85fb692008-05-27 10:55:34 +0000163 chp = concat_path_file(moddir, CONFIG_DEFAULT_DEPMOD_FILE);
Bernhard Reutner-Fischer1ea25682008-05-26 21:33:05 +0000164 filedes = xfopen(chp, "w");
165 if (ENABLE_FEATURE_CLEAN_UP)
166 free(chp);
167 }
Bernhard Reutner-Fischerc21d9c72008-05-28 10:35:51 +0000168 ret = EXIT_SUCCESS;
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +0000169 /* We have to do a full walk to collect all needed data. */
Bernhard Reutner-Fischer1ea25682008-05-26 21:33:05 +0000170 if (!recursive_action(moddir,
171 ACTION_RECURSE, /* flags */
172 fill_lst, /* file action */
173 NULL, /* dir action */
174 NULL, /* user data */
Bernhard Reutner-Fischer634b0222008-05-28 14:20:20 +0000175 0)) { /* depth */
176 if (ENABLE_FEATURE_CLEAN_UP)
177 ret = EXIT_FAILURE;
178 else
179 return EXIT_FAILURE;
180 }
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +0000181#if ENABLE_FEATURE_CLEAN_UP
182 else
183#endif
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000184 do {
Bernhard Reutner-Fischerc21d9c72008-05-28 10:35:51 +0000185 chp = option_mask32 & ARG_a ? moddir : *argv++;
Bernhard Reutner-Fischer6bb55cf2008-05-26 17:04:01 +0000186
187 if (!recursive_action(chp,
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000188 ACTION_RECURSE, /* flags */
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000189 fileAction, /* file action */
190 NULL, /* dir action */
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +0000191 NULL, /* user data */
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000192 0)) { /* depth */
Bernhard Reutner-Fischerc21d9c72008-05-28 10:35:51 +0000193 ret = EXIT_FAILURE;
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000194 }
Bernhard Reutner-Fischer1ea25682008-05-26 21:33:05 +0000195 } while (!(option_mask32 & ARG_a) && *argv);
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000196
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +0000197 /* modprobe allegedly wants dependencies without duplicates, i.e.
198 * mod1: mod2 mod3
199 * mod2: mod3
200 * mod3:
201 * implies that mod1 directly depends on mod2 and _not_ mod3 as mod3 is
202 * already implicitely pulled in via mod2. This leaves us with:
203 * mod1: mod2
204 * mod2: mod3
205 * mod3:
206 */
207 {
208 dep_lst_t *mods = G.lst;
209#if ENABLE_FEATURE_DEPMOD_PRUNE_FANCY
210 while (mods) {
211 llist_t *deps = mods->dependencies;
212 while (deps) {
213 dep_lst_t *all = G.lst;
214 while (all) {
215 if (!strcmp(all->name, deps->data)) {
216 llist_t *implied = all->dependencies;
217 while (implied) {
218 /* erm, nicer would be to just
219 * llist_unlink(&mods->dependencies, implied) */
220 llist_t *prune = mods->dependencies;
221 while (prune) {
222 if (!strcmp(implied->data, prune->data))
223 break;
224 prune = prune->link;
225 }
226//if (prune) bb_info_msg("[%s] '%s' implies '%s', removing", mods->name, all->name, implied->data);
227 llist_unlink(&mods->dependencies, prune);
228 implied = implied->link;
229 }
230 }
231 all = all->next;
232 }
233 deps = deps->link;
234 }
235 mods = mods->next;
236 }
237
238 mods = G.lst;
239#endif
240 /* Finally print them. */
241 while (mods) {
242 fprintf(filedes, "%s:", mods->name);
243 while (mods->dependencies)
244 fprintf(filedes, " %s", (char*)llist_pop(&mods->dependencies));
245 fprintf(filedes, "\n");
246 mods = mods->next;
247 }
248 }
249
Bernhard Reutner-Fischerdc5d7fe2008-05-26 13:30:41 +0000250 if (ENABLE_FEATURE_CLEAN_UP) {
Bernhard Reutner-Fischerc21d9c72008-05-28 10:35:51 +0000251 fclose_if_not_stdin(filedes);
Bernhard Reutner-Fischer1ea25682008-05-26 21:33:05 +0000252 free(moddir);
Bernhard Reutner-Fischerbeac1bd2008-06-02 13:28:47 +0000253 while (G.lst) {
254 dep_lst_t *old = G.lst;
255 G.lst = G.lst->next;
256 free(old->name);
257 free(old);
258 }
Bernhard Reutner-Fischerdc5d7fe2008-05-26 13:30:41 +0000259 }
Bernhard Reutner-Fischerc21d9c72008-05-28 10:35:51 +0000260 return ret;
Bernhard Reutner-Fischer55e547e2008-05-26 12:01:49 +0000261}