- improve help-text
[oweals/busybox.git] / modutils / depmod.c
1 /* 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() */
13
14 #ifndef DEFAULT_MODULES_DIR
15 #define DEFAULT_MODULES_DIR "/lib/modules"
16 #endif
17 #ifndef DEFAULT_DEPMOD_FILE
18 #define DEFAULT_DEPMOD_FILE "modules.dep"
19 #endif
20 /*
21  * Theory of operation:
22  * - iterate over all modules and record their full path
23  * - iterate over all modules looking for "depends=" entries
24  *   for each depends, look through our list of full paths and emit if found
25  */
26 struct globals {
27         llist_t *lst;
28 };
29 #define G (*(struct globals*)&bb_common_bufsiz1)
30 /* We have to zero it out because of NOEXEC */
31 #define INIT_G() memset(&G, 0, sizeof(G))
32
33 static int fill_lst(const char *modulename, struct stat ATTRIBUTE_UNUSED *sb,
34                                         void ATTRIBUTE_UNUSED *data, int ATTRIBUTE_UNUSED depth)
35 {
36         llist_add_to(&G.lst, xstrdup(modulename));
37         return TRUE;
38 }
39
40 static int fileAction(const char *fname, struct stat *sb,
41                                         void *data, int ATTRIBUTE_UNUSED depth)
42 {
43         size_t len = sb->st_size;
44         void *the_module, *ptr;
45         int fd;
46         char *depends, *deps;
47
48 /*XXX: FIXME: does not handle compressed modules!
49  * There should be a function that looks at the extension and sets up
50  * open_transformer for us.
51  */
52         if (last_char_is(fname, 'o') == NULL) /* not a module */
53                 goto skip;
54
55         fd = xopen(fname, O_RDONLY);
56         the_module = mmap(NULL, len, PROT_READ, MAP_SHARED
57 #if defined MAP_POPULATE
58                                                 |MAP_POPULATE
59 #endif
60                                                 , fd, 0);
61         close(fd);
62         if (the_module == MAP_FAILED)
63                 bb_perror_msg_and_die("mmap");
64
65         ptr = the_module;
66
67         fprintf((FILE*)data, "\n%s:", fname);
68 //bb_info_msg("fname='%s'", fname);
69         do {
70                 /* search for a 'd' */
71                 ptr = memchr(ptr, 'd', len);
72                 if (ptr == NULL) /* no d left, done */
73                         goto done;
74                 if (memcmp(ptr, "depends=", sizeof("depends=")-1) == 0)
75                         break;
76                 len -= ++ptr - the_module;
77         } while (1);
78         deps = depends = xstrdup (ptr + sizeof("depends=")-1);
79 //bb_info_msg(" depends='%s'", depends);
80         while (*deps) {
81                 llist_t * _lst = G.lst;
82                 char *buf1;
83
84                 ptr = strchr(deps, ',');
85                 if (ptr != NULL)
86                         *(char*)ptr = '\0';
87                 /* remember the length of the current dependency plus eventual 0 byte */
88                 len = strlen(deps) + (ptr != NULL);
89                 buf1 = xmalloc(len + 3);
90                 sprintf(buf1, "/%s.", deps); /* make sure we match the correct file */
91                 while (_lst) {
92                         ptr = strstr(_lst->data, buf1);
93                         if (ptr != NULL)
94                                 break; /* found it */
95                         _lst = _lst->link;
96                 }
97                 free(buf1);
98                 if (_lst /*&& _lst->data*/) {
99 //bb_info_msg("[%s] -> '%s'", deps, _lst->data);
100                         fprintf((FILE*)data, " %s", _lst->data);
101                         deps += len;
102                 }
103         }
104         free(depends);
105 done:
106         munmap(the_module, sb->st_size);
107 skip:
108         return TRUE;
109 }
110
111 int depmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
112 int depmod_main(int ATTRIBUTE_UNUSED argc, char **argv)
113 {
114         int retval = EXIT_SUCCESS;
115         char *moddir_base = NULL, *moddir, *system_map, *chp;
116         FILE *filedes = stdout;
117         enum {
118                 ARG_a = (1<<0), /* All modules, ignore mods in argv */
119                 ARG_A = (1<<1), /* Only emit .ko that are newer than modules.dep file */
120                 ARG_b = (1<<2), /* not /lib/modules/$(uname -r)/ but this base-dir */
121                 ARG_e = (1<<3), /* with -F, print unresolved symbols */
122                 ARG_F = (1<<4), /* System.map that contains the symbols */
123                 ARG_n = (1<<5)  /* dry-run, print to stdout only */
124         };
125
126         getopt32(argv, "aAb:eF:n", &moddir_base, &system_map);
127         argv += optind;
128         if (*argv) {/* got a version to use? */
129                 chp = *argv++;
130 //              if (memchr(chp, '/', strlen(chp)) != NULL) /* XXX: drop this */
131 //                      bb_show_usage();
132         } else {
133                 struct utsname uts;
134                 if (uname(&uts) < 0)
135                         bb_simple_perror_msg_and_die("uname");
136                 chp = xstrdup(uts.release);
137         }
138         /* if no modules are given on the command-line, -a is on per default */
139         option_mask32 |= *argv == NULL;
140
141         moddir = concat_path_file(DEFAULT_MODULES_DIR, chp);
142 //      if (ENABLE_FEATURE_CLEAN_UP)
143 //              free(chp);
144         if (option_mask32 & ARG_b) {
145                 char *old_moddir = moddir;
146                 moddir = concat_path_file(moddir_base, moddir);
147                 if (ENABLE_FEATURE_CLEAN_UP)
148                         free(old_moddir);
149         }
150
151         if (!(option_mask32 & ARG_n)) { /* --dry-run */
152                 chp = concat_path_file(moddir, DEFAULT_DEPMOD_FILE);
153                 filedes = xfopen(chp, "w");
154                 if (ENABLE_FEATURE_CLEAN_UP)
155                         free(chp);
156         }
157         /* have to do a full walk to collect all needed data */
158         if (!recursive_action(moddir,
159                         ACTION_RECURSE, /* flags */
160                         fill_lst, /* file action */
161                         NULL, /* dir action */
162                         NULL, /* user data */
163                         0)) {
164                 retval = EXIT_FAILURE;
165         } else
166         do {
167                 chp = concat_path_file(option_mask32 & ARG_a ?  moddir : moddir_base,
168                                 option_mask32 & ARG_a ? "" : *argv++);
169
170                 if (!recursive_action(chp,
171                                 ACTION_RECURSE, /* flags */
172                                 fileAction, /* file action */
173                                 NULL, /* dir action */
174                                 (void*)filedes, /* user data */
175                                 0)) { /* depth */
176                         retval = EXIT_FAILURE;
177                 }
178                 if (ENABLE_FEATURE_CLEAN_UP)
179                         free(chp);
180         } while (!(option_mask32 & ARG_a) && *argv);
181
182         if (ENABLE_FEATURE_CLEAN_UP) {
183                 fclose(filedes);
184                 llist_free(G.lst, free);
185                 free(moddir);
186         }
187         return retval;
188 }