aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2015-11-06 16:38:39 +0000
committerRon Yorston <rmy@pobox.com>2015-11-06 16:38:39 +0000
commitd6c9296168ad0a770967714515ffa1fca5e60145 (patch)
treed72556385814a18a0ac039ee0b43ef6f561c317f
parentb60a9b30ba420808c4c9f540dcf92b11ee87a87b (diff)
parent196e400441652946b9c7ad7bc2d78c73885f2359 (diff)
downloadbusybox-w32-d6c9296168ad0a770967714515ffa1fca5e60145.tar.gz
busybox-w32-d6c9296168ad0a770967714515ffa1fca5e60145.tar.bz2
busybox-w32-d6c9296168ad0a770967714515ffa1fca5e60145.zip
Merge branch 'busybox' into merge
-rw-r--r--TODO2
-rw-r--r--miscutils/i2c_tools.c37
-rw-r--r--modutils/depmod.c86
-rw-r--r--modutils/modprobe.c66
-rw-r--r--modutils/modutils.c51
-rw-r--r--modutils/modutils.h30
-rw-r--r--networking/ifupdown.c4
-rw-r--r--shell/ash.c101
-rw-r--r--shell/ash_test/ash-misc/func1.right6
-rwxr-xr-xshell/ash_test/ash-misc/func1.tests16
-rw-r--r--shell/ash_test/ash-misc/func2.right5
-rwxr-xr-xshell/ash_test/ash-misc/func2.tests9
-rw-r--r--shell/ash_test/ash-misc/func3.right4
-rwxr-xr-xshell/ash_test/ash-misc/func3.tests8
-rw-r--r--shell/ash_test/ash-misc/func4.right2
-rwxr-xr-xshell/ash_test/ash-misc/func4.tests7
-rw-r--r--shell/ash_test/ash-misc/func5.right6
-rwxr-xr-xshell/ash_test/ash-misc/func5.tests13
-rw-r--r--shell/ash_test/ash-misc/func_args1.right5
-rwxr-xr-xshell/ash_test/ash-misc/func_args1.tests8
-rw-r--r--shell/ash_test/ash-misc/func_bash1.right12
-rwxr-xr-xshell/ash_test/ash-misc/func_bash1.tests28
-rw-r--r--shell/ash_test/ash-misc/func_local1.right3
-rwxr-xr-xshell/ash_test/ash-misc/func_local1.tests5
-rw-r--r--shell/ash_test/ash-misc/func_local2.right14
-rwxr-xr-xshell/ash_test/ash-misc/func_local2.tests7
-rwxr-xr-xshell/hush_test/hush-misc/func_args1.tests2
27 files changed, 366 insertions, 171 deletions
diff --git a/TODO b/TODO
index dcf48c2c2..8904b2135 100644
--- a/TODO
+++ b/TODO
@@ -258,5 +258,3 @@ vdprintf() -> similar sized functionality
258 258
259* more support for advanced linux 2.6.x features, see: iotop 259* more support for advanced linux 2.6.x features, see: iotop
260 most likely there is more 260 most likely there is more
261
262* even more support for statistics: mpstat, iostat, powertop....
diff --git a/miscutils/i2c_tools.c b/miscutils/i2c_tools.c
index d77e6bacf..aa1c7c5cc 100644
--- a/miscutils/i2c_tools.c
+++ b/miscutils/i2c_tools.c
@@ -723,16 +723,18 @@ static int read_block_data(int buf_fd, int mode, int *block)
723 uint8_t cblock[I2C_SMBUS_BLOCK_MAX + I2CDUMP_NUM_REGS]; 723 uint8_t cblock[I2C_SMBUS_BLOCK_MAX + I2CDUMP_NUM_REGS];
724 int res, blen = 0, tmp, i; 724 int res, blen = 0, tmp, i;
725 725
726 if (mode == I2C_SMBUS_BLOCK_DATA || mode == I2C_SMBUS_I2C_BLOCK_DATA) { 726 if (mode == I2C_SMBUS_BLOCK_DATA) {
727 res = i2c_smbus_read_block_data(buf_fd, 0, cblock); 727 blen = i2c_smbus_read_block_data(buf_fd, 0, cblock);
728 blen = res; 728 if (blen <= 0)
729 goto fail;
729 } else { 730 } else {
730 for (res = 0; res < I2CDUMP_NUM_REGS; res += tmp) { 731 for (res = 0; res < I2CDUMP_NUM_REGS; res += tmp) {
731 tmp = i2c_smbus_read_i2c_block_data( 732 tmp = i2c_smbus_read_i2c_block_data(
732 buf_fd, res, I2C_SMBUS_BLOCK_MAX, 733 buf_fd, res, I2C_SMBUS_BLOCK_MAX,
733 cblock + res); 734 cblock + res);
734 if (tmp < 0) { 735 if (tmp <= 0) {
735 bb_error_msg_and_die("block read failed"); 736 blen = tmp;
737 goto fail;
736 } 738 }
737 } 739 }
738 740
@@ -748,6 +750,9 @@ static int read_block_data(int buf_fd, int mode, int *block)
748 } 750 }
749 751
750 return blen; 752 return blen;
753
754 fail:
755 bb_error_msg_and_die("block read failed: %d", blen);
751} 756}
752 757
753/* Dump all but word data. */ 758/* Dump all but word data. */
@@ -904,7 +909,7 @@ int i2cdump_main(int argc UNUSED_PARAM, char **argv)
904 unsigned first = 0x00, last = 0xff, opts; 909 unsigned first = 0x00, last = 0xff, opts;
905 int *block = (int *)bb_common_bufsiz1; 910 int *block = (int *)bb_common_bufsiz1;
906 char *opt_r_str, *dash; 911 char *opt_r_str, *dash;
907 int fd, res, blen; 912 int fd, res;
908 913
909 opt_complementary = "-2:?3"; /* from 2 to 3 args */ 914 opt_complementary = "-2:?3"; /* from 2 to 3 args */
910 opts = getopt32(argv, optstr, &opt_r_str); 915 opts = getopt32(argv, optstr, &opt_r_str);
@@ -971,7 +976,10 @@ int i2cdump_main(int argc UNUSED_PARAM, char **argv)
971 976
972 /* All but word data. */ 977 /* All but word data. */
973 if (mode != I2C_SMBUS_WORD_DATA || even) { 978 if (mode != I2C_SMBUS_WORD_DATA || even) {
974 blen = read_block_data(fd, mode, block); 979 int blen = 0;
980
981 if (mode == I2C_SMBUS_BLOCK_DATA || mode == I2C_SMBUS_I2C_BLOCK_DATA)
982 blen = read_block_data(fd, mode, block);
975 983
976 if (mode == I2C_SMBUS_BYTE) { 984 if (mode == I2C_SMBUS_BYTE) {
977 res = i2c_smbus_write_byte(fd, first); 985 res = i2c_smbus_write_byte(fd, first);
@@ -1200,7 +1208,7 @@ int i2cdetect_main(int argc UNUSED_PARAM, char **argv)
1200 opt_F = (1 << 4), opt_l = (1 << 5); 1208 opt_F = (1 << 4), opt_l = (1 << 5);
1201 const char *const optstr = "yaqrFl"; 1209 const char *const optstr = "yaqrFl";
1202 1210
1203 int fd, bus_num, i, j, mode = I2CDETECT_MODE_AUTO, status; 1211 int fd, bus_num, i, j, mode = I2CDETECT_MODE_AUTO, status, cmd;
1204 unsigned first = 0x03, last = 0x77, opts; 1212 unsigned first = 0x03, last = 0x77, opts;
1205 unsigned long funcs; 1213 unsigned long funcs;
1206 1214
@@ -1270,22 +1278,23 @@ int i2cdetect_main(int argc UNUSED_PARAM, char **argv)
1270 puts(" 0 1 2 3 4 5 6 7 8 9 a b c d e f"); 1278 puts(" 0 1 2 3 4 5 6 7 8 9 a b c d e f");
1271 for (i = 0; i < 128; i += 16) { 1279 for (i = 0; i < 128; i += 16) {
1272 printf("%02x: ", i); 1280 printf("%02x: ", i);
1273 for(j = 0; j < 16; j++) { 1281 for (j = 0; j < 16; j++) {
1274 fflush_all(); 1282 fflush_all();
1275 1283
1284 cmd = mode;
1276 if (mode == I2CDETECT_MODE_AUTO) { 1285 if (mode == I2CDETECT_MODE_AUTO) {
1277 if ((i+j >= 0x30 && i+j <= 0x37) || 1286 if ((i+j >= 0x30 && i+j <= 0x37) ||
1278 (i+j >= 0x50 && i+j <= 0x5F)) 1287 (i+j >= 0x50 && i+j <= 0x5F))
1279 mode = I2CDETECT_MODE_READ; 1288 cmd = I2CDETECT_MODE_READ;
1280 else 1289 else
1281 mode = I2CDETECT_MODE_QUICK; 1290 cmd = I2CDETECT_MODE_QUICK;
1282 } 1291 }
1283 1292
1284 /* Skip unwanted addresses. */ 1293 /* Skip unwanted addresses. */
1285 if (i+j < first 1294 if (i+j < first
1286 || i+j > last 1295 || i+j > last
1287 || (mode == I2CDETECT_MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE)) 1296 || (cmd == I2CDETECT_MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE))
1288 || (mode == I2CDETECT_MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK))) 1297 || (cmd == I2CDETECT_MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK)))
1289 { 1298 {
1290 printf(" "); 1299 printf(" ");
1291 continue; 1300 continue;
@@ -1302,7 +1311,7 @@ int i2cdetect_main(int argc UNUSED_PARAM, char **argv)
1302 "can't set address to 0x%02x", i + j); 1311 "can't set address to 0x%02x", i + j);
1303 } 1312 }
1304 1313
1305 switch (mode) { 1314 switch (cmd) {
1306 case I2CDETECT_MODE_READ: 1315 case I2CDETECT_MODE_READ:
1307 /* 1316 /*
1308 * This is known to lock SMBus on various 1317 * This is known to lock SMBus on various
diff --git a/modutils/depmod.c b/modutils/depmod.c
index 9713aef92..e5f0e3d2b 100644
--- a/modutils/depmod.c
+++ b/modutils/depmod.c
@@ -21,21 +21,13 @@
21 * for each depends, look through our list of full paths and emit if found 21 * for each depends, look through our list of full paths and emit if found
22 */ 22 */
23 23
24typedef struct module_info {
25 struct module_info *next;
26 char *name, *modname;
27 llist_t *dependencies;
28 llist_t *aliases;
29 llist_t *symbols;
30 struct module_info *dnext, *dprev;
31} module_info;
32
33static int FAST_FUNC parse_module(const char *fname, struct stat *sb UNUSED_PARAM, 24static int FAST_FUNC parse_module(const char *fname, struct stat *sb UNUSED_PARAM,
34 void *data, int depth UNUSED_PARAM) 25 void *data, int depth UNUSED_PARAM)
35{ 26{
36 module_info **first = (module_info **) data; 27 module_db *modules = data;
37 char *image, *ptr; 28 char *image, *ptr;
38 module_info *info; 29 module_entry *e;
30
39 /* Arbitrary. Was sb->st_size, but that breaks .gz etc */ 31 /* Arbitrary. Was sb->st_size, but that breaks .gz etc */
40 size_t len = (64*1024*1024 - 4096); 32 size_t len = (64*1024*1024 - 4096);
41 33
@@ -43,17 +35,10 @@ static int FAST_FUNC parse_module(const char *fname, struct stat *sb UNUSED_PARA
43 return TRUE; 35 return TRUE;
44 36
45 image = xmalloc_open_zipped_read_close(fname, &len); 37 image = xmalloc_open_zipped_read_close(fname, &len);
46 info = xzalloc(sizeof(*info));
47 38
48 info->next = *first; 39 e = moddb_get_or_create(modules, bb_get_last_path_component_nostrip(fname));
49 *first = info; 40 e->name = xstrdup(fname + 2); /* skip "./" */
50 41
51 info->dnext = info->dprev = info;
52 info->name = xstrdup(fname + 2); /* skip "./" */
53 info->modname = filename2modname(
54 bb_get_last_path_component_nostrip(fname),
55 NULL
56 );
57 for (ptr = image; ptr < image + len - 10; ptr++) { 42 for (ptr = image; ptr < image + len - 10; ptr++) {
58 if (is_prefixed_with(ptr, "depends=")) { 43 if (is_prefixed_with(ptr, "depends=")) {
59 char *u; 44 char *u;
@@ -62,11 +47,11 @@ static int FAST_FUNC parse_module(const char *fname, struct stat *sb UNUSED_PARA
62 for (u = ptr; *u; u++) 47 for (u = ptr; *u; u++)
63 if (*u == '-') 48 if (*u == '-')
64 *u = '_'; 49 *u = '_';
65 ptr += string_to_llist(ptr, &info->dependencies, ","); 50 ptr += string_to_llist(ptr, &e->deps, ",");
66 } else if (ENABLE_FEATURE_MODUTILS_ALIAS 51 } else if (ENABLE_FEATURE_MODUTILS_ALIAS
67 && is_prefixed_with(ptr, "alias=") 52 && is_prefixed_with(ptr, "alias=")
68 ) { 53 ) {
69 llist_add_to(&info->aliases, xstrdup(ptr + 6)); 54 llist_add_to(&e->aliases, xstrdup(ptr + 6));
70 ptr += strlen(ptr); 55 ptr += strlen(ptr);
71 } else if (ENABLE_FEATURE_MODUTILS_SYMBOLS 56 } else if (ENABLE_FEATURE_MODUTILS_SYMBOLS
72 && is_prefixed_with(ptr, "__ksymtab_") 57 && is_prefixed_with(ptr, "__ksymtab_")
@@ -77,7 +62,7 @@ static int FAST_FUNC parse_module(const char *fname, struct stat *sb UNUSED_PARA
77 ) { 62 ) {
78 continue; 63 continue;
79 } 64 }
80 llist_add_to(&info->symbols, xstrdup(ptr)); 65 llist_add_to(&e->symbols, xstrdup(ptr));
81 ptr += strlen(ptr); 66 ptr += strlen(ptr);
82 } 67 }
83 } 68 }
@@ -86,24 +71,13 @@ static int FAST_FUNC parse_module(const char *fname, struct stat *sb UNUSED_PARA
86 return TRUE; 71 return TRUE;
87} 72}
88 73
89static module_info *find_module(module_info *modules, const char *modname) 74static void order_dep_list(module_db *modules, module_entry *start, llist_t *add)
90{
91 module_info *m;
92
93 for (m = modules; m != NULL; m = m->next)
94 if (strcmp(m->modname, modname) == 0)
95 return m;
96 return NULL;
97}
98
99static void order_dep_list(module_info *modules, module_info *start,
100 llist_t *add)
101{ 75{
102 module_info *m; 76 module_entry *m;
103 llist_t *n; 77 llist_t *n;
104 78
105 for (n = add; n != NULL; n = n->link) { 79 for (n = add; n != NULL; n = n->link) {
106 m = find_module(modules, n->data); 80 m = moddb_get(modules, n->data);
107 if (m == NULL) 81 if (m == NULL)
108 continue; 82 continue;
109 83
@@ -118,7 +92,7 @@ static void order_dep_list(module_info *modules, module_info *start,
118 start->dprev = m; 92 start->dprev = m;
119 93
120 /* recurse */ 94 /* recurse */
121 order_dep_list(modules, start, m->dependencies); 95 order_dep_list(modules, start, m->deps);
122 } 96 }
123} 97}
124 98
@@ -184,10 +158,12 @@ enum {
184int depmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 158int depmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
185int depmod_main(int argc UNUSED_PARAM, char **argv) 159int depmod_main(int argc UNUSED_PARAM, char **argv)
186{ 160{
187 module_info *modules, *m, *dep; 161 module_db modules;
162 module_entry *m, *dep;
188 const char *moddir_base = "/"; 163 const char *moddir_base = "/";
189 char *moddir, *version; 164 char *moddir, *version;
190 struct utsname uts; 165 struct utsname uts;
166 unsigned i;
191 int tmp; 167 int tmp;
192 168
193 getopt32(argv, "aAb:eF:nruqC:", &moddir_base, NULL, NULL); 169 getopt32(argv, "aAb:eF:nruqC:", &moddir_base, NULL, NULL);
@@ -211,7 +187,7 @@ int depmod_main(int argc UNUSED_PARAM, char **argv)
211 free(moddir); 187 free(moddir);
212 188
213 /* Scan modules */ 189 /* Scan modules */
214 modules = NULL; 190 memset(&modules, 0, sizeof(modules));
215 if (*argv) { 191 if (*argv) {
216 do { 192 do {
217 parse_module(*argv, /*sb (unused):*/ NULL, &modules, 0); 193 parse_module(*argv, /*sb (unused):*/ NULL, &modules, 0);
@@ -224,10 +200,11 @@ int depmod_main(int argc UNUSED_PARAM, char **argv)
224 /* Generate dependency and alias files */ 200 /* Generate dependency and alias files */
225 if (!(option_mask32 & OPT_n)) 201 if (!(option_mask32 & OPT_n))
226 xfreopen_write(CONFIG_DEFAULT_DEPMOD_FILE, stdout); 202 xfreopen_write(CONFIG_DEFAULT_DEPMOD_FILE, stdout);
227 for (m = modules; m != NULL; m = m->next) { 203
204 moddb_foreach_module(&modules, m, i) {
228 printf("%s:", m->name); 205 printf("%s:", m->name);
229 206
230 order_dep_list(modules, m, m->dependencies); 207 order_dep_list(&modules, m, m->deps);
231 while (m->dnext != m) { 208 while (m->dnext != m) {
232 dep = m->dnext; 209 dep = m->dnext;
233 printf(" %s", dep->name); 210 printf(" %s", dep->name);
@@ -243,10 +220,7 @@ int depmod_main(int argc UNUSED_PARAM, char **argv)
243#if ENABLE_FEATURE_MODUTILS_ALIAS 220#if ENABLE_FEATURE_MODUTILS_ALIAS
244 if (!(option_mask32 & OPT_n)) 221 if (!(option_mask32 & OPT_n))
245 xfreopen_write("modules.alias", stdout); 222 xfreopen_write("modules.alias", stdout);
246 for (m = modules; m != NULL; m = m->next) { 223 moddb_foreach_module(&modules, m, i) {
247 char modname[MODULE_NAME_LEN];
248 const char *fname = bb_basename(m->name);
249 filename2modname(fname, modname);
250 while (m->aliases) { 224 while (m->aliases) {
251 /* 225 /*
252 * Last word used to be a basename 226 * Last word used to be a basename
@@ -256,34 +230,24 @@ int depmod_main(int argc UNUSED_PARAM, char **argv)
256 */ 230 */
257 printf("alias %s %s\n", 231 printf("alias %s %s\n",
258 (char*)llist_pop(&m->aliases), 232 (char*)llist_pop(&m->aliases),
259 modname); 233 m->modname);
260 } 234 }
261 } 235 }
262#endif 236#endif
263#if ENABLE_FEATURE_MODUTILS_SYMBOLS 237#if ENABLE_FEATURE_MODUTILS_SYMBOLS
264 if (!(option_mask32 & OPT_n)) 238 if (!(option_mask32 & OPT_n))
265 xfreopen_write("modules.symbols", stdout); 239 xfreopen_write("modules.symbols", stdout);
266 for (m = modules; m != NULL; m = m->next) { 240 moddb_foreach_module(&modules, m, i) {
267 char modname[MODULE_NAME_LEN];
268 const char *fname = bb_basename(m->name);
269 filename2modname(fname, modname);
270 while (m->symbols) { 241 while (m->symbols) {
271 printf("alias symbol:%s %s\n", 242 printf("alias symbol:%s %s\n",
272 (char*)llist_pop(&m->symbols), 243 (char*)llist_pop(&m->symbols),
273 modname); 244 m->modname);
274 } 245 }
275 } 246 }
276#endif 247#endif
277 248
278 if (ENABLE_FEATURE_CLEAN_UP) { 249 if (ENABLE_FEATURE_CLEAN_UP)
279 while (modules) { 250 moddb_free(&modules);
280 module_info *old = modules;
281 modules = modules->next;
282 free(old->name);
283 free(old->modname);
284 free(old);
285 }
286 }
287 251
288 return EXIT_SUCCESS; 252 return EXIT_SUCCESS;
289} 253}
diff --git a/modutils/modprobe.c b/modutils/modprobe.c
index 05bf02cf8..ec490b74d 100644
--- a/modutils/modprobe.c
+++ b/modutils/modprobe.c
@@ -150,19 +150,6 @@ static const char modprobe_longopts[] ALIGN1 =
150#define MODULE_FLAG_FOUND_IN_MODDEP 0x0004 150#define MODULE_FLAG_FOUND_IN_MODDEP 0x0004
151#define MODULE_FLAG_BLACKLISTED 0x0008 151#define MODULE_FLAG_BLACKLISTED 0x0008
152 152
153struct module_entry { /* I'll call it ME. */
154 unsigned flags;
155 char *modname; /* stripped of /path/, .ext and s/-/_/g */
156 const char *probed_name; /* verbatim as seen on cmdline */
157 char *options; /* options from config files */
158 llist_t *realnames; /* strings. if this module is an alias, */
159 /* real module name is one of these. */
160//Can there really be more than one? Example from real kernel?
161 llist_t *deps; /* strings. modules we depend on */
162};
163
164#define DB_HASH_SIZE 256
165
166struct globals { 153struct globals {
167 llist_t *probes; /* MEs of module(s) requested on cmdline */ 154 llist_t *probes; /* MEs of module(s) requested on cmdline */
168 char *cmdline_mopts; /* module options from cmdline */ 155 char *cmdline_mopts; /* module options from cmdline */
@@ -170,7 +157,7 @@ struct globals {
170 /* bool. "Did we have 'symbol:FOO' requested on cmdline?" */ 157 /* bool. "Did we have 'symbol:FOO' requested on cmdline?" */
171 smallint need_symbols; 158 smallint need_symbols;
172 struct utsname uts; 159 struct utsname uts;
173 llist_t *db[DB_HASH_SIZE]; /* MEs of all modules ever seen (caching for speed) */ 160 module_db db;
174} FIX_ALIASING; 161} FIX_ALIASING;
175#define G (*ptr_to_globals) 162#define G (*ptr_to_globals)
176#define INIT_G() do { \ 163#define INIT_G() do { \
@@ -195,51 +182,9 @@ static char *gather_options_str(char *opts, const char *append)
195 return opts; 182 return opts;
196} 183}
197 184
198/* These three functions called many times, optimizing for speed. 185static struct module_entry *get_or_add_modentry(const char *module)
199 * Users reported minute-long delays when they runn iptables repeatedly
200 * (iptables use modprobe to install needed kernel modules).
201 */
202static struct module_entry *helper_get_module(const char *module, int create)
203{
204 char modname[MODULE_NAME_LEN];
205 struct module_entry *e;
206 llist_t *l;
207 unsigned i;
208 unsigned hash;
209
210 filename2modname(module, modname);
211
212 hash = 0;
213 for (i = 0; modname[i]; i++)
214 hash = ((hash << 5) + hash) + modname[i];
215 hash %= DB_HASH_SIZE;
216
217 for (l = G.db[hash]; l; l = l->link) {
218 e = (struct module_entry *) l->data;
219 if (strcmp(e->modname, modname) == 0)
220 return e;
221 }
222 if (!create)
223 return NULL;
224
225 e = xzalloc(sizeof(*e));
226 e->modname = xstrdup(modname);
227 llist_add_to(&G.db[hash], e);
228
229 return e;
230}
231static ALWAYS_INLINE struct module_entry *get_or_add_modentry(const char *module)
232{ 186{
233 return helper_get_module(module, 1); 187 return moddb_get_or_create(&G.db, module);
234}
235/* So far this function always gets a module pathname, never an alias name.
236 * The crucial difference is that pathname needs dirname stripping,
237 * while alias name must NOT do it!
238 * Testcase where dirname stripping is likely to go wrong: "modprobe devname:snd/timer"
239 */
240static ALWAYS_INLINE struct module_entry *get_modentry(const char *pathname)
241{
242 return helper_get_module(bb_get_last_path_component_nostrip(pathname), 0);
243} 188}
244 189
245static void add_probe(const char *name) 190static void add_probe(const char *name)
@@ -536,7 +481,7 @@ static void load_modules_dep(void)
536 continue; 481 continue;
537 *colon = '\0'; 482 *colon = '\0';
538 483
539 m = get_modentry(tokens[0]); 484 m = moddb_get(&G.db, bb_get_last_path_component_nostrip(tokens[0]));
540 if (m == NULL) 485 if (m == NULL)
541 continue; 486 continue;
542 487
@@ -697,5 +642,8 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
697 } while (me->realnames != NULL); 642 } while (me->realnames != NULL);
698 } 643 }
699 644
645 if (ENABLE_FEATURE_CLEAN_UP)
646 moddb_free(&G.db);
647
700 return (rc != 0); 648 return (rc != 0);
701} 649}
diff --git a/modutils/modutils.c b/modutils/modutils.c
index ef4134af5..0a056731d 100644
--- a/modutils/modutils.c
+++ b/modutils/modutils.c
@@ -16,6 +16,57 @@ extern int delete_module(const char *module, unsigned int flags);
16# define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags) 16# define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags)
17#endif 17#endif
18 18
19static module_entry *helper_get_module(module_db *db, const char *module, int create)
20{
21 char modname[MODULE_NAME_LEN];
22 struct module_entry *e;
23 unsigned i, hash;
24
25 filename2modname(module, modname);
26
27 hash = 0;
28 for (i = 0; modname[i]; i++)
29 hash = ((hash << 5) + hash) + modname[i];
30 hash %= MODULE_HASH_SIZE;
31
32 for (e = db->buckets[hash]; e; e = e->next)
33 if (strcmp(e->modname, modname) == 0)
34 return e;
35 if (!create)
36 return NULL;
37
38 e = xzalloc(sizeof(*e));
39 e->modname = xstrdup(modname);
40 e->next = db->buckets[hash];
41 db->buckets[hash] = e;
42 IF_DEPMOD(e->dnext = e->dprev = e;)
43
44 return e;
45}
46module_entry* FAST_FUNC moddb_get(module_db *db, const char *module)
47{
48 return helper_get_module(db, module, 0);
49}
50module_entry* FAST_FUNC moddb_get_or_create(module_db *db, const char *module)
51{
52 return helper_get_module(db, module, 1);
53}
54
55void FAST_FUNC moddb_free(module_db *db)
56{
57 module_entry *e, *n;
58 unsigned i;
59
60 for (i = 0; i < MODULE_HASH_SIZE; i++) {
61 for (e = db->buckets[i]; e; e = n) {
62 n = e->next;
63 free(e->name);
64 free(e->modname);
65 free(e);
66 }
67 }
68}
69
19void FAST_FUNC replace(char *s, char what, char with) 70void FAST_FUNC replace(char *s, char what, char with)
20{ 71{
21 while (*s) { 72 while (*s) {
diff --git a/modutils/modutils.h b/modutils/modutils.h
index 5f059c716..2cbd1448a 100644
--- a/modutils/modutils.h
+++ b/modutils/modutils.h
@@ -16,6 +16,36 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
16/* linux/include/linux/module.h has 64, but this is also used 16/* linux/include/linux/module.h has 64, but this is also used
17 * internally for the maximum alias name length, which can be quite long */ 17 * internally for the maximum alias name length, which can be quite long */
18#define MODULE_NAME_LEN 256 18#define MODULE_NAME_LEN 256
19#define MODULE_HASH_SIZE 256
20
21typedef struct module_entry {
22 struct module_entry *next;
23 char *name, *modname;
24 llist_t *deps;
25 IF_MODPROBE(
26 llist_t *realnames;
27 unsigned flags;
28 const char *probed_name; /* verbatim as seen on cmdline */
29 char *options; /* options from config files */
30 )
31 IF_DEPMOD(
32 llist_t *aliases;
33 llist_t *symbols;
34 struct module_entry *dnext, *dprev;
35 )
36} module_entry;
37
38typedef struct module_db {
39 module_entry *buckets[MODULE_HASH_SIZE];
40} module_db;
41
42#define moddb_foreach_module(db, module, index) \
43 for ((index) = 0; (index) < MODULE_HASH_SIZE; (index)++) \
44 for (module = (db)->buckets[index]; module; module = module->next)
45
46module_entry *moddb_get(module_db *db, const char *s) FAST_FUNC;
47module_entry *moddb_get_or_create(module_db *db, const char *s) FAST_FUNC;
48void moddb_free(module_db *db) FAST_FUNC;
19 49
20void replace(char *s, char what, char with) FAST_FUNC; 50void replace(char *s, char what, char with) FAST_FUNC;
21char *replace_underscores(char *s) FAST_FUNC; 51char *replace_underscores(char *s) FAST_FUNC;
diff --git a/networking/ifupdown.c b/networking/ifupdown.c
index d477ff6d1..766dfabbd 100644
--- a/networking/ifupdown.c
+++ b/networking/ifupdown.c
@@ -535,7 +535,7 @@ static const struct dhcp_client_t ext_dhcp_clients[] = {
535 "pump -i %iface% -k", 535 "pump -i %iface% -k",
536 }, 536 },
537 { "udhcpc", 537 { "udhcpc",
538 "udhcpc " UDHCPC_CMD_OPTIONS " -p /var/run/udhcpc.%iface%.pid -i %iface%[[ -H %hostname%]][[ -c %client%]]" 538 "udhcpc " UDHCPC_CMD_OPTIONS " -p /var/run/udhcpc.%iface%.pid -i %iface%[[ -x hostname:%hostname%]][[ -c %client%]]"
539 "[[ -s %script%]][[ %udhcpc_opts%]]", 539 "[[ -s %script%]][[ %udhcpc_opts%]]",
540 "kill `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null", 540 "kill `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null",
541 }, 541 },
@@ -575,7 +575,7 @@ static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd, execfn *exec)
575 return 0; 575 return 0;
576# endif 576# endif
577 return execute("udhcpc " UDHCPC_CMD_OPTIONS " -p /var/run/udhcpc.%iface%.pid " 577 return execute("udhcpc " UDHCPC_CMD_OPTIONS " -p /var/run/udhcpc.%iface%.pid "
578 "-i %iface%[[ -H %hostname%]][[ -c %client%]][[ -s %script%]][[ %udhcpc_opts%]]", 578 "-i %iface%[[ -x hostname:%hostname%]][[ -c %client%]][[ -s %script%]][[ %udhcpc_opts%]]",
579 ifd, exec); 579 ifd, exec);
580} 580}
581# else 581# else
diff --git a/shell/ash.c b/shell/ash.c
index 08b6aa430..de5c44ead 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -8073,36 +8073,40 @@ changepath(const char *new)
8073 clearcmdentry(firstchange); 8073 clearcmdentry(firstchange);
8074 builtinloc = idx_bltin; 8074 builtinloc = idx_bltin;
8075} 8075}
8076 8076enum {
8077#define TEOF 0 8077 TEOF,
8078#define TNL 1 8078 TNL,
8079#define TREDIR 2 8079 TREDIR,
8080#define TWORD 3 8080 TWORD,
8081#define TSEMI 4 8081 TSEMI,
8082#define TBACKGND 5 8082 TBACKGND,
8083#define TAND 6 8083 TAND,
8084#define TOR 7 8084 TOR,
8085#define TPIPE 8 8085 TPIPE,
8086#define TLP 9 8086 TLP,
8087#define TRP 10 8087 TRP,
8088#define TENDCASE 11 8088 TENDCASE,
8089#define TENDBQUOTE 12 8089 TENDBQUOTE,
8090#define TNOT 13 8090 TNOT,
8091#define TCASE 14 8091 TCASE,
8092#define TDO 15 8092 TDO,
8093#define TDONE 16 8093 TDONE,
8094#define TELIF 17 8094 TELIF,
8095#define TELSE 18 8095 TELSE,
8096#define TESAC 19 8096 TESAC,
8097#define TFI 20 8097 TFI,
8098#define TFOR 21 8098 TFOR,
8099#define TIF 22 8099#if ENABLE_ASH_BASH_COMPAT
8100#define TIN 23 8100 TFUNCTION,
8101#define TTHEN 24 8101#endif
8102#define TUNTIL 25 8102 TIF,
8103#define TWHILE 26 8103 TIN,
8104#define TBEGIN 27 8104 TTHEN,
8105#define TEND 28 8105 TUNTIL,
8106 TWHILE,
8107 TBEGIN,
8108 TEND
8109};
8106typedef smallint token_id_t; 8110typedef smallint token_id_t;
8107 8111
8108/* first char is indicating which tokens mark the end of a list */ 8112/* first char is indicating which tokens mark the end of a list */
@@ -8131,6 +8135,9 @@ static const char *const tokname_array[] = {
8131 "\1esac", 8135 "\1esac",
8132 "\1fi", 8136 "\1fi",
8133 "\0for", 8137 "\0for",
8138#if ENABLE_ASH_BASH_COMPAT
8139 "\0function",
8140#endif
8134 "\0if", 8141 "\0if",
8135 "\0in", 8142 "\0in",
8136 "\1then", 8143 "\1then",
@@ -11205,6 +11212,7 @@ simplecmd(void)
11205 int savecheckkwd; 11212 int savecheckkwd;
11206#if ENABLE_ASH_BASH_COMPAT 11213#if ENABLE_ASH_BASH_COMPAT
11207 smallint double_brackets_flag = 0; 11214 smallint double_brackets_flag = 0;
11215 smallint function_flag = 0;
11208#endif 11216#endif
11209 11217
11210 args = NULL; 11218 args = NULL;
@@ -11221,6 +11229,11 @@ simplecmd(void)
11221 t = readtoken(); 11229 t = readtoken();
11222 switch (t) { 11230 switch (t) {
11223#if ENABLE_ASH_BASH_COMPAT 11231#if ENABLE_ASH_BASH_COMPAT
11232 case TFUNCTION:
11233 if (peektoken() != TWORD)
11234 raise_error_unexpected_syntax(TWORD);
11235 function_flag = 1;
11236 break;
11224 case TAND: /* "&&" */ 11237 case TAND: /* "&&" */
11225 case TOR: /* "||" */ 11238 case TOR: /* "||" */
11226 if (!double_brackets_flag) { 11239 if (!double_brackets_flag) {
@@ -11249,6 +11262,29 @@ simplecmd(void)
11249 app = &n->narg.next; 11262 app = &n->narg.next;
11250 savecheckkwd = 0; 11263 savecheckkwd = 0;
11251 } 11264 }
11265#if ENABLE_ASH_BASH_COMPAT
11266 if (function_flag) {
11267 checkkwd = CHKNL | CHKKWD;
11268 switch (peektoken()) {
11269 case TBEGIN:
11270 case TIF:
11271 case TCASE:
11272 case TUNTIL:
11273 case TWHILE:
11274 case TFOR:
11275 goto do_func;
11276 case TLP:
11277 function_flag = 0;
11278 break;
11279 case TWORD:
11280 if (strcmp("[[", wordtext) == 0)
11281 goto do_func;
11282 /* fall through */
11283 default:
11284 raise_error_unexpected_syntax(-1);
11285 }
11286 }
11287#endif
11252 break; 11288 break;
11253 case TREDIR: 11289 case TREDIR:
11254 *rpp = n = redirnode; 11290 *rpp = n = redirnode;
@@ -11256,6 +11292,7 @@ simplecmd(void)
11256 parsefname(); /* read name of redirection file */ 11292 parsefname(); /* read name of redirection file */
11257 break; 11293 break;
11258 case TLP: 11294 case TLP:
11295 IF_ASH_BASH_COMPAT(do_func:)
11259 if (args && app == &args->narg.next 11296 if (args && app == &args->narg.next
11260 && !vars && !redir 11297 && !vars && !redir
11261 ) { 11298 ) {
@@ -11263,7 +11300,7 @@ simplecmd(void)
11263 const char *name; 11300 const char *name;
11264 11301
11265 /* We have a function */ 11302 /* We have a function */
11266 if (readtoken() != TRP) 11303 if (IF_ASH_BASH_COMPAT(!function_flag &&) readtoken() != TRP)
11267 raise_error_unexpected_syntax(TRP); 11304 raise_error_unexpected_syntax(TRP);
11268 name = n->narg.text; 11305 name = n->narg.text;
11269 if (!goodname(name) 11306 if (!goodname(name)
@@ -11276,6 +11313,7 @@ simplecmd(void)
11276 n->narg.next = parse_command(); 11313 n->narg.next = parse_command();
11277 return n; 11314 return n;
11278 } 11315 }
11316 IF_ASH_BASH_COMPAT(function_flag = 0;)
11279 /* fall through */ 11317 /* fall through */
11280 default: 11318 default:
11281 tokpushback = 1; 11319 tokpushback = 1;
@@ -11456,6 +11494,7 @@ parse_command(void)
11456 n1 = list(0); 11494 n1 = list(0);
11457 t = TEND; 11495 t = TEND;
11458 break; 11496 break;
11497 IF_ASH_BASH_COMPAT(case TFUNCTION:)
11459 case TWORD: 11498 case TWORD:
11460 case TREDIR: 11499 case TREDIR:
11461 tokpushback = 1; 11500 tokpushback = 1;
diff --git a/shell/ash_test/ash-misc/func1.right b/shell/ash_test/ash-misc/func1.right
new file mode 100644
index 000000000..e21665aaf
--- /dev/null
+++ b/shell/ash_test/ash-misc/func1.right
@@ -0,0 +1,6 @@
1Hello
2Zero: 0
3One: 1 Param1: World
4Zero: 0 Param1: Restored
5Multi line function
6One: 1
diff --git a/shell/ash_test/ash-misc/func1.tests b/shell/ash_test/ash-misc/func1.tests
new file mode 100755
index 000000000..ffb269fad
--- /dev/null
+++ b/shell/ash_test/ash-misc/func1.tests
@@ -0,0 +1,16 @@
1f() { echo Hello; }
2g () { echo One: $# Param1: $1; }
3h ( )
4{
5 echo -n 'Multi ' && echo -n 'line '
6 echo function
7 false
8}
9
10f
11echo Zero: $?
12set -- Restored
13{ g World; }
14echo Zero: $? Param1: $1
15( h )
16echo One: $?
diff --git a/shell/ash_test/ash-misc/func2.right b/shell/ash_test/ash-misc/func2.right
new file mode 100644
index 000000000..f2a041da7
--- /dev/null
+++ b/shell/ash_test/ash-misc/func2.right
@@ -0,0 +1,5 @@
1First 0
2Second 0
3First 1
4Second 1
5Done
diff --git a/shell/ash_test/ash-misc/func2.tests b/shell/ash_test/ash-misc/func2.tests
new file mode 100755
index 000000000..763203f15
--- /dev/null
+++ b/shell/ash_test/ash-misc/func2.tests
@@ -0,0 +1,9 @@
1i=0
2while test $i != 2; do
3 f() { echo First $i; }
4 f
5 f() { echo Second $i; }
6 f
7 : $((i++))
8done
9echo Done
diff --git a/shell/ash_test/ash-misc/func3.right b/shell/ash_test/ash-misc/func3.right
new file mode 100644
index 000000000..b6d73459a
--- /dev/null
+++ b/shell/ash_test/ash-misc/func3.right
@@ -0,0 +1,4 @@
1One:1
2Zero:0
3One:1
4Five:5
diff --git a/shell/ash_test/ash-misc/func3.tests b/shell/ash_test/ash-misc/func3.tests
new file mode 100755
index 000000000..fa6f26a23
--- /dev/null
+++ b/shell/ash_test/ash-misc/func3.tests
@@ -0,0 +1,8 @@
1f() { false; return; echo BAD; };
2{ f; echo One:$?; }; echo Zero:$?
3
4f() { false; return; };
5f; echo One:$?
6
7f() { return 5; };
8f; echo Five:$?
diff --git a/shell/ash_test/ash-misc/func4.right b/shell/ash_test/ash-misc/func4.right
new file mode 100644
index 000000000..0c87e316a
--- /dev/null
+++ b/shell/ash_test/ash-misc/func4.right
@@ -0,0 +1,2 @@
124
2Done
diff --git a/shell/ash_test/ash-misc/func4.tests b/shell/ash_test/ash-misc/func4.tests
new file mode 100755
index 000000000..74c1b9a46
--- /dev/null
+++ b/shell/ash_test/ash-misc/func4.tests
@@ -0,0 +1,7 @@
1func() {
2 eval "echo \"\${val_${1}}\""
3}
4
5val_x=24
6(func x)
7echo Done
diff --git a/shell/ash_test/ash-misc/func5.right b/shell/ash_test/ash-misc/func5.right
new file mode 100644
index 000000000..2c9d316b3
--- /dev/null
+++ b/shell/ash_test/ash-misc/func5.right
@@ -0,0 +1,6 @@
11
22
33
41
52
63
diff --git a/shell/ash_test/ash-misc/func5.tests b/shell/ash_test/ash-misc/func5.tests
new file mode 100755
index 000000000..e967208cc
--- /dev/null
+++ b/shell/ash_test/ash-misc/func5.tests
@@ -0,0 +1,13 @@
1f() { echo $1; }
2f 1
3
4f() ( echo $1; )
5f 2
6
7f() ( echo $1 )
8f 3
9
10f() for i in 1 2 3; do
11 echo $i
12done
13f
diff --git a/shell/ash_test/ash-misc/func_args1.right b/shell/ash_test/ash-misc/func_args1.right
new file mode 100644
index 000000000..2dfb9629b
--- /dev/null
+++ b/shell/ash_test/ash-misc/func_args1.right
@@ -0,0 +1,5 @@
1params: a b c
2'f 1 2 3' called
3params: a b c
4'f 1 2 3' called
5params: a b c
diff --git a/shell/ash_test/ash-misc/func_args1.tests b/shell/ash_test/ash-misc/func_args1.tests
new file mode 100755
index 000000000..d394c637f
--- /dev/null
+++ b/shell/ash_test/ash-misc/func_args1.tests
@@ -0,0 +1,8 @@
1f() { echo "'f $1 $2 $3' called"; }
2
3set -- a b c
4echo "params: $1 $2 $3"
5f 1 2 3
6echo "params: $1 $2 $3"
7true | f 1 2 3
8echo "params: $1 $2 $3"
diff --git a/shell/ash_test/ash-misc/func_bash1.right b/shell/ash_test/ash-misc/func_bash1.right
new file mode 100644
index 000000000..41bf8828c
--- /dev/null
+++ b/shell/ash_test/ash-misc/func_bash1.right
@@ -0,0 +1,12 @@
11
22
33
41
52
63
71
82
93
101
112
123
diff --git a/shell/ash_test/ash-misc/func_bash1.tests b/shell/ash_test/ash-misc/func_bash1.tests
new file mode 100755
index 000000000..2cc0970e8
--- /dev/null
+++ b/shell/ash_test/ash-misc/func_bash1.tests
@@ -0,0 +1,28 @@
1function f() { echo $1; }
2f 1
3
4function f() ( echo $1; )
5f 2
6
7function f() ( echo $1 )
8f 3
9
10function f() for i in 1 2 3; do
11 echo $i
12done
13f
14
15function f { echo $1; }
16f 1
17
18# the next two don't work
19#function f ( echo $1; )
20f 2
21
22#function f ( echo $1 )
23f 3
24
25function f for i in 1 2 3; do
26 echo $i
27done
28f
diff --git a/shell/ash_test/ash-misc/func_local1.right b/shell/ash_test/ash-misc/func_local1.right
new file mode 100644
index 000000000..312178366
--- /dev/null
+++ b/shell/ash_test/ash-misc/func_local1.right
@@ -0,0 +1,3 @@
1z=a
2z=z
3Done
diff --git a/shell/ash_test/ash-misc/func_local1.tests b/shell/ash_test/ash-misc/func_local1.tests
new file mode 100755
index 000000000..1d594e20c
--- /dev/null
+++ b/shell/ash_test/ash-misc/func_local1.tests
@@ -0,0 +1,5 @@
1export z=z
2f() { local z=a; env | grep ^z; }
3f
4env | grep ^z
5echo Done
diff --git a/shell/ash_test/ash-misc/func_local2.right b/shell/ash_test/ash-misc/func_local2.right
new file mode 100644
index 000000000..fe9343ac8
--- /dev/null
+++ b/shell/ash_test/ash-misc/func_local2.right
@@ -0,0 +1,14 @@
11
22
31
42
51
61
72
82
93
102
112
123
131
14Done
diff --git a/shell/ash_test/ash-misc/func_local2.tests b/shell/ash_test/ash-misc/func_local2.tests
new file mode 100755
index 000000000..1a9ae559d
--- /dev/null
+++ b/shell/ash_test/ash-misc/func_local2.tests
@@ -0,0 +1,7 @@
1x=1
2f() { echo $x; local x=$((x+1)); echo $x; }
3g() { f; echo $x; f; local x=$((x+1)); f; echo $x; f; }
4f
5g
6echo $x
7echo Done
diff --git a/shell/hush_test/hush-misc/func_args1.tests b/shell/hush_test/hush-misc/func_args1.tests
index 157921fb1..d394c637f 100755
--- a/shell/hush_test/hush-misc/func_args1.tests
+++ b/shell/hush_test/hush-misc/func_args1.tests
@@ -1,5 +1,3 @@
1# UNFIXED BUG
2
3f() { echo "'f $1 $2 $3' called"; } 1f() { echo "'f $1 $2 $3' called"; }
4 2
5set -- a b c 3set -- a b c