aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-07-04 10:25:44 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-07-04 10:25:44 +0000
commit671691cf2107b846b40c165e6d5b2806172b6030 (patch)
tree0a2210ed36cb41846d0bacd1b08777ddf7e6ec95
parent8ae5b28b4bff5f1099a4a77af89e1a7e23ad77e2 (diff)
downloadbusybox-w32-671691cf2107b846b40c165e6d5b2806172b6030.tar.gz
busybox-w32-671691cf2107b846b40c165e6d5b2806172b6030.tar.bz2
busybox-w32-671691cf2107b846b40c165e6d5b2806172b6030.zip
modutils: optional modutils-small by Vladimir Dronnikov.
15kb smaller than standard one. libbb/recursive_action.c: commented-out code for aborting the scan.
-rw-r--r--include/applets.h5
-rw-r--r--libbb/recursive_action.c13
-rw-r--r--modutils/Config.in61
-rw-r--r--modutils/Kbuild11
-rw-r--r--modutils/modprobe-small.c648
5 files changed, 726 insertions, 12 deletions
diff --git a/include/applets.h b/include/applets.h
index 591d715c8..aff9070bb 100644
--- a/include/applets.h
+++ b/include/applets.h
@@ -116,6 +116,7 @@ USE_DEALLOCVT(APPLET(deallocvt, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
116USE_DELGROUP(APPLET_ODDNAME(delgroup, deluser, _BB_DIR_BIN, _BB_SUID_NEVER, delgroup)) 116USE_DELGROUP(APPLET_ODDNAME(delgroup, deluser, _BB_DIR_BIN, _BB_SUID_NEVER, delgroup))
117USE_DELUSER(APPLET(deluser, _BB_DIR_BIN, _BB_SUID_NEVER)) 117USE_DELUSER(APPLET(deluser, _BB_DIR_BIN, _BB_SUID_NEVER))
118USE_DEPMOD(APPLET(depmod, _BB_DIR_SBIN, _BB_SUID_NEVER)) 118USE_DEPMOD(APPLET(depmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
119USE_MODPROBE_SMALL(APPLET_ODDNAME(depmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe))
119USE_DEVFSD(APPLET(devfsd, _BB_DIR_SBIN, _BB_SUID_NEVER)) 120USE_DEVFSD(APPLET(devfsd, _BB_DIR_SBIN, _BB_SUID_NEVER))
120USE_DF(APPLET(df, _BB_DIR_BIN, _BB_SUID_NEVER)) 121USE_DF(APPLET(df, _BB_DIR_BIN, _BB_SUID_NEVER))
121USE_APP_DHCPRELAY(APPLET(dhcprelay, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) 122USE_APP_DHCPRELAY(APPLET(dhcprelay, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
@@ -188,6 +189,7 @@ USE_INETD(APPLET(inetd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
188USE_INIT(APPLET(init, _BB_DIR_SBIN, _BB_SUID_NEVER)) 189USE_INIT(APPLET(init, _BB_DIR_SBIN, _BB_SUID_NEVER))
189USE_INOTIFYD(APPLET(inotifyd, _BB_DIR_SBIN, _BB_SUID_NEVER)) 190USE_INOTIFYD(APPLET(inotifyd, _BB_DIR_SBIN, _BB_SUID_NEVER))
190USE_INSMOD(APPLET(insmod, _BB_DIR_SBIN, _BB_SUID_NEVER)) 191USE_INSMOD(APPLET(insmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
192USE_MODPROBE_SMALL(APPLET_ODDNAME(insmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe))
191USE_INSTALL(APPLET(install, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) 193USE_INSTALL(APPLET(install, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
192#if ENABLE_FEATURE_IP_ADDRESS \ 194#if ENABLE_FEATURE_IP_ADDRESS \
193 || ENABLE_FEATURE_IP_ROUTE \ 195 || ENABLE_FEATURE_IP_ROUTE \
@@ -231,6 +233,7 @@ USE_LPR(APPLET_ODDNAME(lpr, lpqr, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lpr))
231USE_LS(APPLET_NOEXEC(ls, ls, _BB_DIR_BIN, _BB_SUID_NEVER, ls)) 233USE_LS(APPLET_NOEXEC(ls, ls, _BB_DIR_BIN, _BB_SUID_NEVER, ls))
232USE_LSATTR(APPLET(lsattr, _BB_DIR_BIN, _BB_SUID_NEVER)) 234USE_LSATTR(APPLET(lsattr, _BB_DIR_BIN, _BB_SUID_NEVER))
233USE_LSMOD(APPLET(lsmod, _BB_DIR_SBIN, _BB_SUID_NEVER)) 235USE_LSMOD(APPLET(lsmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
236USE_MODPROBE_SMALL(APPLET_ODDNAME(lsmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe))
234USE_UNLZMA(APPLET_ODDNAME(lzmacat, unlzma, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lzmacat)) 237USE_UNLZMA(APPLET_ODDNAME(lzmacat, unlzma, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lzmacat))
235USE_MAKEDEVS(APPLET(makedevs, _BB_DIR_SBIN, _BB_SUID_NEVER)) 238USE_MAKEDEVS(APPLET(makedevs, _BB_DIR_SBIN, _BB_SUID_NEVER))
236USE_MAN(APPLET(man, _BB_DIR_SBIN, _BB_SUID_NEVER)) 239USE_MAN(APPLET(man, _BB_DIR_SBIN, _BB_SUID_NEVER))
@@ -249,6 +252,7 @@ USE_MKNOD(APPLET(mknod, _BB_DIR_BIN, _BB_SUID_NEVER))
249USE_MKSWAP(APPLET(mkswap, _BB_DIR_SBIN, _BB_SUID_NEVER)) 252USE_MKSWAP(APPLET(mkswap, _BB_DIR_SBIN, _BB_SUID_NEVER))
250USE_MKTEMP(APPLET(mktemp, _BB_DIR_BIN, _BB_SUID_NEVER)) 253USE_MKTEMP(APPLET(mktemp, _BB_DIR_BIN, _BB_SUID_NEVER))
251USE_MODPROBE(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER)) 254USE_MODPROBE(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER))
255USE_MODPROBE_SMALL(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER))
252USE_MORE(APPLET(more, _BB_DIR_BIN, _BB_SUID_NEVER)) 256USE_MORE(APPLET(more, _BB_DIR_BIN, _BB_SUID_NEVER))
253USE_MOUNT(APPLET(mount, _BB_DIR_BIN, USE_DESKTOP(_BB_SUID_MAYBE) SKIP_DESKTOP(_BB_SUID_NEVER))) 257USE_MOUNT(APPLET(mount, _BB_DIR_BIN, USE_DESKTOP(_BB_SUID_MAYBE) SKIP_DESKTOP(_BB_SUID_NEVER)))
254USE_MOUNTPOINT(APPLET(mountpoint, _BB_DIR_BIN, _BB_SUID_NEVER)) 258USE_MOUNTPOINT(APPLET(mountpoint, _BB_DIR_BIN, _BB_SUID_NEVER))
@@ -293,6 +297,7 @@ USE_RESTORECON(APPLET_ODDNAME(restorecon, setfiles, _BB_DIR_SBIN, _BB_SUID_NEVER
293USE_RM(APPLET_NOFORK(rm, rm, _BB_DIR_BIN, _BB_SUID_NEVER, rm)) 297USE_RM(APPLET_NOFORK(rm, rm, _BB_DIR_BIN, _BB_SUID_NEVER, rm))
294USE_RMDIR(APPLET_NOFORK(rmdir, rmdir, _BB_DIR_BIN, _BB_SUID_NEVER, rmdir)) 298USE_RMDIR(APPLET_NOFORK(rmdir, rmdir, _BB_DIR_BIN, _BB_SUID_NEVER, rmdir))
295USE_RMMOD(APPLET(rmmod, _BB_DIR_SBIN, _BB_SUID_NEVER)) 299USE_RMMOD(APPLET(rmmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
300USE_MODPROBE_SMALL(APPLET_ODDNAME(rmmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe))
296USE_ROUTE(APPLET(route, _BB_DIR_SBIN, _BB_SUID_NEVER)) 301USE_ROUTE(APPLET(route, _BB_DIR_SBIN, _BB_SUID_NEVER))
297USE_RPM(APPLET(rpm, _BB_DIR_BIN, _BB_SUID_NEVER)) 302USE_RPM(APPLET(rpm, _BB_DIR_BIN, _BB_SUID_NEVER))
298USE_RPM2CPIO(APPLET(rpm2cpio, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) 303USE_RPM2CPIO(APPLET(rpm2cpio, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
diff --git a/libbb/recursive_action.c b/libbb/recursive_action.c
index 9b6951f43..66bf6aa62 100644
--- a/libbb/recursive_action.c
+++ b/libbb/recursive_action.c
@@ -111,16 +111,23 @@ int FAST_FUNC recursive_action(const char *fileName,
111 } 111 }
112 status = TRUE; 112 status = TRUE;
113 while ((next = readdir(dir)) != NULL) { 113 while ((next = readdir(dir)) != NULL) {
114 /*int s;*/
114 char *nextFile; 115 char *nextFile;
115 116
116 nextFile = concat_subpath_file(fileName, next->d_name); 117 nextFile = concat_subpath_file(fileName, next->d_name);
117 if (nextFile == NULL) 118 if (nextFile == NULL)
118 continue; 119 continue;
119 /* process every file (NB: ACTION_RECURSE is set in flags) */ 120 /* process every file (NB: ACTION_RECURSE is set in flags) */
120 if (!recursive_action(nextFile, flags, fileAction, dirAction, 121 /*s =*/ recursive_action(nextFile, flags, fileAction, dirAction,
121 userData, depth + 1)) 122 userData, depth + 1);
122 status = FALSE;
123 free(nextFile); 123 free(nextFile);
124//#define RECURSE_RESULT_ABORT 3
125// if (s == RECURSE_RESULT_ABORT) {
126// closedir(dir);
127// return s;
128// }
129// if (s == FALSE)
130// status = FALSE;
124 } 131 }
125 closedir(dir); 132 closedir(dir);
126 133
diff --git a/modutils/Config.in b/modutils/Config.in
index 2b0bcdd6e..25841b8ff 100644
--- a/modutils/Config.in
+++ b/modutils/Config.in
@@ -5,14 +5,63 @@
5 5
6menu "Linux Module Utilities" 6menu "Linux Module Utilities"
7 7
8config MODPROBE_SMALL
9 bool "Simplified modutils"
10 default n
11 help
12 Simplified modutils.
13
14 With this option modprobe does not use or require
15 modules.dep or /etc/modules.conf files.
16 It scans module files in /lib/modules/`uname -r` and
17 determines dependencies and module alias names on the fly.
18 This may make module loading slower, most notably
19 when one needs to load module by alias (this requires
20 scanning through module _bodies_).
21
22 Additional module parameters can be stored in
23 /etc/modules/$module_name files.
24
25 Apart from modprobe, other utilities are also provided:
26 - insmod is an alias to modprobe
27 - rmmod is an alias to modprobe -r
28 - depmod is provided but does nothing
29
30 As of 2008-07, this code is experimental. It it 15kb smaller
31 than "non-small" modutils.
32
33config FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE
34 bool "module options on cmdline"
35 default n
36 depends on MODPROBE_SMALL
37 help
38 Allow insmod and modprobe take module options from command line.
39 N.B. Very bloaty.
40
41config FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED
42 bool "Skip loading of already loaded modules"
43 default n
44 depends on MODPROBE_SMALL
45 help
46 Check if the module is already loaded.
47 N.B. It's racy.
48
49config FEATURE_MODPROBE_SMALL_ZIPPED
50 bool "Handle gzipped or bzipped modules"
51 default n
52 depends on MODPROBE_SMALL
53 help
54 Handle compressed modules. Bloaty. Sloooow.
55
8config DEPMOD 56config DEPMOD
9 bool "depmod" 57 bool "depmod"
10 default n 58 default n
59 depends on !MODPROBE_SMALL
11 help 60 help
12 depmod generates modules.dep (FIXME: elaborate) 61 depmod generates modules.dep (FIXME: elaborate)
13 62
14config FEATURE_DEPMOD_PRUNE_FANCY 63config FEATURE_DEPMOD_PRUNE_FANCY
15 bool "fancy dependency pruning" 64 bool "Fancy dependency pruning"
16 default n 65 default n
17 depends on DEPMOD 66 depends on DEPMOD
18 help 67 help
@@ -26,7 +75,7 @@ config FEATURE_DEPMOD_PRUNE_FANCY
26 If unsure, say N. 75 If unsure, say N.
27 76
28config FEATURE_DEPMOD_ALIAS 77config FEATURE_DEPMOD_ALIAS
29 bool "alias support" 78 bool "Alias support"
30 default n 79 default n
31 depends on DEPMOD 80 depends on DEPMOD
32 help 81 help
@@ -38,6 +87,7 @@ config FEATURE_DEPMOD_ALIAS
38config INSMOD 87config INSMOD
39 bool "insmod" 88 bool "insmod"
40 default n 89 default n
90 depends on !MODPROBE_SMALL
41 help 91 help
42 insmod is used to load specified modules in the running kernel. 92 insmod is used to load specified modules in the running kernel.
43 93
@@ -93,12 +143,14 @@ config FEATURE_INSMOD_LOAD_MAP_FULL
93config RMMOD 143config RMMOD
94 bool "rmmod" 144 bool "rmmod"
95 default n 145 default n
146 depends on !MODPROBE_SMALL
96 help 147 help
97 rmmod is used to unload specified modules from the kernel. 148 rmmod is used to unload specified modules from the kernel.
98 149
99config LSMOD 150config LSMOD
100 bool "lsmod" 151 bool "lsmod"
101 default n 152 default n
153 depends on !MODPROBE_SMALL
102 help 154 help
103 lsmod is used to display a list of loaded modules. 155 lsmod is used to display a list of loaded modules.
104 156
@@ -113,6 +165,7 @@ config FEATURE_LSMOD_PRETTY_2_6_OUTPUT
113config MODPROBE 165config MODPROBE
114 bool "modprobe" 166 bool "modprobe"
115 default n 167 default n
168 depends on !MODPROBE_SMALL
116 help 169 help
117 Handle the loading of modules, and their dependencies on a high 170 Handle the loading of modules, and their dependencies on a high
118 level. 171 level.
@@ -196,7 +249,7 @@ config DEFAULT_MODULES_DIR
196 # Simulate indentation 249 # Simulate indentation
197 string "Default directory containing modules" 250 string "Default directory containing modules"
198 default "/lib/modules" 251 default "/lib/modules"
199 depends on INSMOD || RMMOD || MODPROBE || DEPMOD 252 depends on INSMOD || RMMOD || MODPROBE || MODPROBE_SMALL || DEPMOD
200 help 253 help
201 Directory that contains kernel modules. 254 Directory that contains kernel modules.
202 Defaults to "/lib/modules" 255 Defaults to "/lib/modules"
@@ -205,7 +258,7 @@ config DEFAULT_DEPMOD_FILE
205 # Simulate indentation 258 # Simulate indentation
206 string "Default name of modules.dep" 259 string "Default name of modules.dep"
207 default "modules.dep" 260 default "modules.dep"
208 depends on INSMOD || RMMOD || MODPROBE || DEPMOD 261 depends on INSMOD || RMMOD || MODPROBE || MODPROBE_SMALL || DEPMOD
209 help 262 help
210 Filename that contains kernel modules dependencies. 263 Filename that contains kernel modules dependencies.
211 Defaults to "modules.dep" 264 Defaults to "modules.dep"
diff --git a/modutils/Kbuild b/modutils/Kbuild
index 40ea0efbe..828070114 100644
--- a/modutils/Kbuild
+++ b/modutils/Kbuild
@@ -5,8 +5,9 @@
5# Licensed under the GPL v2, see the file LICENSE in this tarball. 5# Licensed under the GPL v2, see the file LICENSE in this tarball.
6 6
7lib-y:= 7lib-y:=
8lib-$(CONFIG_DEPMOD) += depmod.o 8lib-$(CONFIG_DEPMOD) += depmod.o
9lib-$(CONFIG_INSMOD) += insmod.o 9lib-$(CONFIG_INSMOD) += insmod.o
10lib-$(CONFIG_LSMOD) += lsmod.o 10lib-$(CONFIG_LSMOD) += lsmod.o
11lib-$(CONFIG_MODPROBE) += modprobe.o 11lib-$(CONFIG_MODPROBE) += modprobe.o
12lib-$(CONFIG_RMMOD) += rmmod.o 12lib-$(CONFIG_MODPROBE_SMALL) += modprobe-small.o
13lib-$(CONFIG_RMMOD) += rmmod.o
diff --git a/modutils/modprobe-small.c b/modutils/modprobe-small.c
new file mode 100644
index 000000000..bbcd9895e
--- /dev/null
+++ b/modutils/modprobe-small.c
@@ -0,0 +1,648 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * simplified modprobe
4 *
5 * Copyright (c) 2008 Vladimir Dronnikov
6 * Copyright (c) 2008 Bernhard Fischer (initial depmod code)
7 *
8 * Licensed under GPLv2, see file LICENSE in this tarball for details.
9 */
10
11#include "libbb.h"
12#include "unarchive.h"
13
14#include <sys/utsname.h> /* uname() */
15#include <fnmatch.h>
16
17/* libbb candidate */
18static void *xmalloc_read(int fd, size_t *sizep)
19{
20 char *buf;
21 size_t size, rd_size, total;
22 off_t to_read;
23 struct stat st;
24
25 to_read = sizep ? *sizep : INT_MAX; /* max to read */
26
27 /* Estimate file size */
28 st.st_size = 0; /* in case fstat fails, assume 0 */
29 fstat(fd, &st);
30 /* /proc/N/stat files report st_size 0 */
31 /* In order to make such files readable, we add small const */
32 size = (st.st_size | 0x3ff) + 1;
33
34 total = 0;
35 buf = NULL;
36 while (1) {
37 if (to_read < size)
38 size = to_read;
39 buf = xrealloc(buf, total + size + 1);
40 rd_size = full_read(fd, buf + total, size);
41 if ((ssize_t)rd_size < 0) { /* error */
42 free(buf);
43 return NULL;
44 }
45 total += rd_size;
46 if (rd_size < size) /* EOF */
47 break;
48 to_read -= rd_size;
49 if (to_read <= 0)
50 break;
51 /* grow by 1/8, but in [1k..64k] bounds */
52 size = ((total / 8) | 0x3ff) + 1;
53 if (size > 64*1024)
54 size = 64*1024;
55 }
56 xrealloc(buf, total + 1);
57 buf[total] = '\0';
58
59 if (sizep)
60 *sizep = total;
61 return buf;
62}
63
64
65//#define dbg1_error_msg(...) ((void)0)
66//#define dbg2_error_msg(...) ((void)0)
67#define dbg1_error_msg(...) bb_error_msg(__VA_ARGS__)
68#define dbg2_error_msg(...) bb_error_msg(__VA_ARGS__)
69
70extern int init_module(void *module, unsigned long len, const char *options);
71extern int delete_module(const char *module, unsigned flags);
72extern int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret);
73
74enum {
75 OPT_q = (1 << 0), /* be quiet */
76 OPT_r = (1 << 1), /* module removal instead of loading */
77};
78
79typedef struct module_info {
80 char *pathname;
81 char *desc;
82} module_info;
83
84/*
85 * GLOBALS
86 */
87struct globals {
88 module_info *modinfo;
89 char *module_load_options;
90 int module_count;
91 int module_found_idx;
92 int stringbuf_idx;
93 char stringbuf[32 * 1024]; /* some modules have lots of stuff */
94 /* for example, drivers/media/video/saa7134/saa7134.ko */
95};
96#define G (*ptr_to_globals)
97#define modinfo (G.modinfo )
98#define module_count (G.module_count )
99#define module_found_idx (G.module_found_idx )
100#define module_load_options (G.module_load_options)
101#define stringbuf_idx (G.stringbuf_idx )
102#define stringbuf (G.stringbuf )
103#define INIT_G() do { \
104 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
105} while (0)
106
107
108static void appendc(char c)
109{
110 if (stringbuf_idx < sizeof(stringbuf))
111 stringbuf[stringbuf_idx++] = c;
112}
113
114static void append(const char *s)
115{
116 size_t len = strlen(s);
117 if (stringbuf_idx + len < sizeof(stringbuf)) {
118 memcpy(stringbuf + stringbuf_idx, s, len);
119 stringbuf_idx += len;
120 }
121}
122
123static void reset_stringbuf(void)
124{
125 stringbuf_idx = 0;
126}
127
128static char* copy_stringbuf(void)
129{
130 char *copy = xmalloc(stringbuf_idx);
131 return memcpy(copy, stringbuf, stringbuf_idx);
132}
133
134static char* find_keyword(char *ptr, size_t len, const char *word)
135{
136 int wlen;
137
138 if (!ptr) /* happens if read_module cannot read it */
139 return NULL;
140
141 wlen = strlen(word);
142 len -= wlen - 1;
143 while ((ssize_t)len > 0) {
144 char *old = ptr;
145 /* search for the first char in word */
146 ptr = memchr(ptr, *word, len);
147 if (ptr == NULL) /* no occurance left, done */
148 break;
149 if (strncmp(ptr, word, wlen) == 0)
150 return ptr + wlen; /* found, return ptr past it */
151 ++ptr;
152 len -= (ptr - old);
153 }
154 return NULL;
155}
156
157static void replace(char *s, char what, char with)
158{
159 while (*s) {
160 if (what == *s)
161 *s = with;
162 ++s;
163 }
164}
165
166#if ENABLE_FEATURE_MODPROBE_SMALL_ZIPPED
167static char *xmalloc_open_zipped_read_close(const char *fname, size_t *sizep)
168{
169 size_t len;
170 char *image;
171 char *suffix;
172
173 int fd = open_or_warn(fname, O_RDONLY);
174 if (fd < 0)
175 return NULL;
176
177 suffix = strrchr(fname, '.');
178 if (suffix) {
179 if (strcmp(suffix, ".gz") == 0)
180 fd = open_transformer(fd, unpack_gz_stream, "gunzip");
181 else if (strcmp(suffix, ".bz2") == 0)
182 fd = open_transformer(fd, unpack_bz2_stream, "bunzip2");
183 }
184
185 len = (sizep) ? *sizep : 64 * 1024 * 1024;
186 image = xmalloc_read(fd, &len);
187 if (!image)
188 bb_perror_msg("read error from '%s'", fname);
189 close(fd);
190
191 if (sizep)
192 *sizep = len;
193 return image;
194}
195# define read_module xmalloc_open_zipped_read_close
196#else
197# define read_module xmalloc_open_read_close
198#endif
199
200/* We use error numbers in a loose translation... */
201static const char *moderror(int err)
202{
203 switch (err) {
204 case ENOEXEC:
205 return "invalid module format";
206 case ENOENT:
207 return "unknown symbol in module or invalid parameter";
208 case ESRCH:
209 return "module has wrong symbol version";
210 case EINVAL: /* "invalid parameter" */
211 return "unknown symbol in module or invalid parameter"
212 + sizeof("unknown symbol in module or");
213 default:
214 return strerror(err);
215 }
216}
217
218static int load_module(const char *fname, const char *options)
219{
220#if 1
221 int r;
222 size_t len = MAXINT(ssize_t);
223 char *module_image;
224 dbg1_error_msg("load_module('%s','%s')", fname, options);
225
226 module_image = read_module(fname, &len);
227 r = (!module_image || init_module(module_image, len, options ? options : "") != 0);
228 free(module_image);
229 dbg1_error_msg("load_module:%d", r);
230 return r; /* 0 = success */
231#else
232 /* For testing */
233 dbg1_error_msg("load_module('%s','%s')", fname, options);
234 return 1;
235#endif
236}
237
238static char* parse_module(const char *pathname, const char *name)
239{
240 char *module_image;
241 char *ptr;
242 size_t len;
243 size_t pos;
244 dbg1_error_msg("parse_module('%s','%s')", pathname, name);
245
246 /* Read (possibly compressed) module */
247 len = 64 * 1024 * 1024; /* 64 Mb at most */
248 module_image = read_module(pathname, &len);
249
250 reset_stringbuf();
251
252 /* First desc line's format is
253 * "modname alias1 symbol:sym1 alias2 symbol:sym2 " (note trailing ' ')
254 */
255 append(name);
256 appendc(' ');
257 /* Aliases */
258 pos = 0;
259 while (1) {
260 ptr = find_keyword(module_image + pos, len - pos, "alias=");
261 if (!ptr) {
262 ptr = find_keyword(module_image + pos, len - pos, "__ksymtab_");
263 if (!ptr)
264 break;
265 /* DOCME: __ksymtab_gpl and __ksymtab_strings occur
266 * in many modules. What do they mean? */
267 if (strcmp(ptr, "gpl") != 0 && strcmp(ptr, "strings") != 0) {
268 dbg2_error_msg("alias: 'symbol:%s'", ptr);
269 append("symbol:");
270 }
271 } else {
272 dbg2_error_msg("alias: '%s'", ptr);
273 }
274 append(ptr);
275 appendc(' ');
276 pos = (ptr - module_image);
277 }
278 appendc('\0');
279
280 /* Second line: "dependency1 depandency2 " (note trailing ' ') */
281 ptr = find_keyword(module_image, len, "depends=");
282 if (ptr && *ptr) {
283 replace(ptr, ',', ' ');
284 replace(ptr, '-', '_');
285 dbg2_error_msg("dep:'%s'", ptr);
286 append(ptr);
287 }
288 appendc(' '); appendc('\0');
289
290 free(module_image);
291 return copy_stringbuf();
292}
293
294static char* pathname_2_modname(const char *pathname)
295{
296 const char *fname = bb_get_last_path_component_nostrip(pathname);
297 const char *suffix = strrstr(fname, ".ko");
298 char *name = xstrndup(fname, suffix - fname);
299 replace(name, '-', '_');
300 return name;
301}
302
303static FAST_FUNC int fileAction(const char *pathname,
304 struct stat *sb ATTRIBUTE_UNUSED,
305 void *data,
306 int depth ATTRIBUTE_UNUSED)
307{
308 int cur;
309 char *name;
310 const char *fname;
311
312 pathname += 2; /* skip "./" */
313 fname = bb_get_last_path_component_nostrip(pathname);
314 if (!strrstr(fname, ".ko")) {
315 dbg1_error_msg("'%s' is not a module", pathname);
316 return TRUE; /* not a module, continue search */
317 }
318
319 cur = module_count++;
320 if (!(cur & 0xfff)) {
321 modinfo = xrealloc(modinfo, sizeof(modinfo[0]) * (cur + 0x1001));
322 }
323 modinfo[cur].pathname = xstrdup(pathname);
324 modinfo[cur].desc = NULL;
325 modinfo[cur+1].pathname = NULL;
326 modinfo[cur+1].desc = NULL;
327
328 name = pathname_2_modname(fname);
329 if (strcmp(name, data) != 0) {
330 free(name);
331 dbg1_error_msg("'%s' module name doesn't match", pathname);
332 return TRUE; /* module name doesn't match, continue search */
333 }
334
335 dbg1_error_msg("'%s' module name matches", pathname);
336 module_found_idx = cur;
337 modinfo[cur].desc = parse_module(pathname, name);
338
339 if (!(option_mask32 & OPT_r)) {
340 if (load_module(pathname, module_load_options) == 0) {
341 /* Load was successful, there is nothing else to do.
342 * This can happen ONLY for "top-level" module load,
343 * not a dep, because deps dont do dirscan. */
344 exit(EXIT_SUCCESS);
345 /*free(name);return RECURSE_RESULT_ABORT;*/
346 }
347 }
348
349 free(name);
350 return TRUE;
351}
352
353static module_info* find_alias(const char *alias)
354{
355 int i;
356 dbg1_error_msg("find_alias('%s')", alias);
357
358 /* First try to find by name (cheaper) */
359 i = 0;
360 while (modinfo[i].pathname) {
361 char *name = pathname_2_modname(modinfo[i].pathname);
362 if (strcmp(name, alias) == 0) {
363 dbg1_error_msg("found '%s' in module '%s'",
364 alias, modinfo[i].pathname);
365 if (!modinfo[i].desc)
366 modinfo[i].desc = parse_module(modinfo[i].pathname, name);
367 free(name);
368 return &modinfo[i];
369 }
370 free(name);
371 i++;
372 }
373
374 /* Scan all module bodies, extract modinfo (it contains aliases) */
375 i = 0;
376 while (modinfo[i].pathname) {
377 char *desc, *s;
378 if (!modinfo[i].desc) {
379 char *name = pathname_2_modname(modinfo[i].pathname);
380 modinfo[i].desc = parse_module(modinfo[i].pathname, name);
381 free(name);
382 }
383 /* "modname alias1 symbol:sym1 alias2 symbol:sym2 " */
384 desc = xstrdup(modinfo[i].desc);
385 /* Does matching substring exist? */
386 replace(desc, ' ', '\0');
387 for (s = desc; *s; s += strlen(s) + 1) {
388 if (strcmp(s, alias) == 0) {
389 free(desc);
390 dbg1_error_msg("found alias '%s' in module '%s'",
391 alias, modinfo[i].pathname);
392 return &modinfo[i];
393 }
394 }
395 free(desc);
396 i++;
397 }
398 dbg1_error_msg("find_alias '%s' returns NULL", alias);
399 return NULL;
400}
401
402#if ENABLE_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED
403static int already_loaded(const char *name)
404{
405 int ret = 0;
406 int len = strlen(name);
407 char *line;
408 FILE* modules;
409
410 modules = xfopen("/proc/modules", "r");
411 while ((line = xmalloc_fgets(modules)) != NULL) {
412 if (strncmp(line, name, len) == 0 && line[len] == ' ') {
413 free(line);
414 ret = 1;
415 break;
416 }
417 free(line);
418 }
419 fclose(modules);
420 return ret;
421}
422#else
423#define already_loaded(name) is_rmmod
424#endif
425
426/*
427 Given modules definition and module name (or alias, or symbol)
428 load/remove the module respecting dependencies
429*/
430#if !ENABLE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE
431#define process_module(a,b) process_module(a)
432#define cmdline_options ""
433#endif
434static void process_module(char *name, const char *cmdline_options)
435{
436 char *s, *deps, *options;
437 module_info *info;
438 int is_rmmod = (option_mask32 & OPT_r) != 0;
439 dbg1_error_msg("process_module('%s','%s')", name, cmdline_options);
440
441 replace(name, '-', '_');
442
443 dbg1_error_msg("already_loaded:%d is_rmmod:%d", already_loaded(name), is_rmmod);
444 if (already_loaded(name) != is_rmmod) {
445 dbg1_error_msg("nothing to do for '%s'", name);
446 return;
447 }
448
449 options = NULL;
450 if (!is_rmmod) {
451 char *opt_filename = xasprintf("/etc/modules/%s", name);
452 options = xmalloc_open_read_close(opt_filename, NULL);
453 if (options)
454 replace(options, '\n', ' ');
455#if ENABLE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE
456 if (cmdline_options) {
457 /* NB: cmdline_options always have one leading ' '
458 * (see main()), we remove it here */
459 char *op = xasprintf(options ? "%s %s" : "%s %s" + 3,
460 cmdline_options + 1, options);
461 free(options);
462 options = op;
463 }
464#endif
465 free(opt_filename);
466 module_load_options = options;
467 dbg1_error_msg("process_module('%s'): options:'%s'", name, options);
468 }
469
470 if (!module_count) {
471 /* Scan module directory. This is done only once.
472 * It will attempt module load, and will exit(EXIT_SUCCESS)
473 * on success. */
474 module_found_idx = -1;
475 recursive_action(".",
476 ACTION_RECURSE, /* flags */
477 fileAction, /* file action */
478 NULL, /* dir action */
479 name, /* user data */
480 0); /* depth */
481 dbg1_error_msg("dirscan complete");
482 /* Module was not found, or load failed, or is_rmmod */
483 if (module_found_idx >= 0) { /* module was found */
484 info = &modinfo[module_found_idx];
485 } else { /* search for alias, not a plain module name */
486 info = find_alias(name);
487 }
488 } else {
489 info = find_alias(name);
490 }
491
492 /* rmmod? unload it by name */
493 if (is_rmmod) {
494 if (delete_module(name, O_NONBLOCK|O_EXCL) != 0
495 && !(option_mask32 & OPT_q)
496 ) {
497 bb_perror_msg("remove '%s'", name);
498 goto ret;
499 }
500 /* N.B. we do not stop here -
501 * continue to unload modules on which the module depends:
502 * "-r --remove: option causes modprobe to remove a module.
503 * If the modules it depends on are also unused, modprobe
504 * will try to remove them, too." */
505 }
506
507 if (!info) { /* both dirscan and find_alias found nothing */
508 goto ret;
509 }
510
511 /* Second line of desc contains dependencies */
512 deps = xstrdup(info->desc + strlen(info->desc) + 1);
513
514 /* Transform deps to string list */
515 replace(deps, ' ', '\0');
516 /* Iterate thru dependencies, trying to (un)load them */
517 for (s = deps; *s; s += strlen(s) + 1) {
518 //if (strcmp(name, s) != 0) // N.B. do loops exist?
519 dbg1_error_msg("recurse on dep '%s'", s);
520 process_module(s, NULL);
521 dbg1_error_msg("recurse on dep '%s' done", s);
522 }
523 free(deps);
524
525 /* insmod -> load it */
526 if (!is_rmmod) {
527 errno = 0;
528 if (load_module(info->pathname, options) != 0) {
529 if (EEXIST != errno) {
530 bb_error_msg("insert '%s' %s: %s",
531 info->pathname, options,
532 moderror(errno));
533 } else {
534 dbg1_error_msg("insert '%s' %s: %s",
535 info->pathname, options,
536 moderror(errno));
537 }
538 }
539 }
540 ret:
541 free(options);
542//TODO: return load attempt result from process_module.
543//If dep didn't load ok, continuing makes little sense.
544}
545#undef cmdline_options
546
547
548/* For reference, module-init-tools-0.9.15-pre2 options:
549
550# insmod
551Usage: insmod filename [args]
552
553# rmmod --help
554Usage: rmmod [-fhswvV] modulename ...
555 -f (or --force) forces a module unload, and may crash your machine.
556 -s (or --syslog) says use syslog, not stderr
557 -v (or --verbose) enables more messages
558 -w (or --wait) begins a module removal even if it is used
559 and will stop new users from accessing the module (so it
560 should eventually fall to zero).
561
562# modprobe
563Usage: modprobe [--verbose|--version|--config|--remove] filename [options]
564
565# depmod --help
566depmod 0.9.15-pre2 -- part of module-init-tools
567depmod -[aA] [-n -e -v -q -V -r -u] [-b basedirectory] [forced_version]
568depmod [-n -e -v -q -r -u] [-F kernelsyms] module1.o module2.o ...
569If no arguments (except options) are given, "depmod -a" is assumed
570
571depmod will output a dependancy list suitable for the modprobe utility.
572
573Options:
574 -a, --all Probe all modules
575 -n, --show Write the dependency file on stdout only
576 -b basedirectory
577 --basedir basedirectory Use an image of a module tree.
578 -F kernelsyms
579 --filesyms kernelsyms Use the file instead of the
580 current kernel symbols.
581*/
582
583int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
584int modprobe_main(int ATTRIBUTE_UNUSED argc, char **argv)
585{
586 struct utsname uts;
587 char applet0 = applet_name[0];
588 USE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(char *options;)
589
590 /* depmod is a stub */
591 if ('d' == applet0)
592 return EXIT_SUCCESS;
593
594 /* are we lsmod? -> just dump /proc/modules */
595 if ('l' == applet0) {
596 xprint_and_close_file(xfopen("/proc/modules", "r"));
597 return EXIT_SUCCESS;
598 }
599
600 INIT_G();
601
602 /* insmod, modprobe, rmmod require at least one argument */
603 opt_complementary = "-1";
604 /* only -q (quiet) and -r (rmmod),
605 * the rest are accepted and ignored (compat) */
606 getopt32(argv, "qrfsvw");
607 argv += optind;
608
609 /* are we rmmod? -> simulate modprobe -r */
610 if ('r' == applet0) {
611 option_mask32 |= OPT_r;
612 }
613
614 /* goto modules directory */
615 xchdir(CONFIG_DEFAULT_MODULES_DIR);
616 uname(&uts); /* never fails */
617 xchdir(uts.release);
618
619#if ENABLE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE
620 /* If not rmmod, parse possible module options given on command line.
621 * insmod/modprobe takes one module name, the rest are parameters. */
622 options = NULL;
623 if ('r' != applet0) {
624 char **arg = argv;
625 while (*++arg) {
626 /* Enclose options in quotes */
627 char *s = options;
628 options = xasprintf("%s \"%s\"", s ? s : "", *arg);
629 free(s);
630 *arg = NULL;
631 }
632 }
633#else
634 if ('r' != applet0)
635 argv[1] = NULL;
636#endif
637
638 /* Load/remove modules.
639 * Only rmmod loops here, insmod/modprobe has only argv[0] */
640 do {
641 process_module(*argv++, options);
642 } while (*argv);
643
644 if (ENABLE_FEATURE_CLEAN_UP) {
645 USE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(free(options);)
646 }
647 return EXIT_SUCCESS;
648}