diff options
author | Ron Yorston <rmy@pobox.com> | 2015-11-06 16:38:39 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2015-11-06 16:38:39 +0000 |
commit | d6c9296168ad0a770967714515ffa1fca5e60145 (patch) | |
tree | d72556385814a18a0ac039ee0b43ef6f561c317f | |
parent | b60a9b30ba420808c4c9f540dcf92b11ee87a87b (diff) | |
parent | 196e400441652946b9c7ad7bc2d78c73885f2359 (diff) | |
download | busybox-w32-d6c9296168ad0a770967714515ffa1fca5e60145.tar.gz busybox-w32-d6c9296168ad0a770967714515ffa1fca5e60145.tar.bz2 busybox-w32-d6c9296168ad0a770967714515ffa1fca5e60145.zip |
Merge branch 'busybox' into merge
27 files changed, 366 insertions, 171 deletions
@@ -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 | ||
24 | typedef 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 | |||
33 | static int FAST_FUNC parse_module(const char *fname, struct stat *sb UNUSED_PARAM, | 24 | static 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 | ||
89 | static module_info *find_module(module_info *modules, const char *modname) | 74 | static 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 | |||
99 | static 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 { | |||
184 | int depmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 158 | int depmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
185 | int depmod_main(int argc UNUSED_PARAM, char **argv) | 159 | int 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 | ||
153 | struct 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 | |||
166 | struct globals { | 153 | struct 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. | 185 | static 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 | */ | ||
202 | static 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 | } | ||
231 | static 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 | */ | ||
240 | static 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 | ||
245 | static void add_probe(const char *name) | 190 | static 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 | ||
19 | static 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 | } | ||
46 | module_entry* FAST_FUNC moddb_get(module_db *db, const char *module) | ||
47 | { | ||
48 | return helper_get_module(db, module, 0); | ||
49 | } | ||
50 | module_entry* FAST_FUNC moddb_get_or_create(module_db *db, const char *module) | ||
51 | { | ||
52 | return helper_get_module(db, module, 1); | ||
53 | } | ||
54 | |||
55 | void 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 | |||
19 | void FAST_FUNC replace(char *s, char what, char with) | 70 | void 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 | |||
21 | typedef 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 | |||
38 | typedef 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 | |||
46 | module_entry *moddb_get(module_db *db, const char *s) FAST_FUNC; | ||
47 | module_entry *moddb_get_or_create(module_db *db, const char *s) FAST_FUNC; | ||
48 | void moddb_free(module_db *db) FAST_FUNC; | ||
19 | 49 | ||
20 | void replace(char *s, char what, char with) FAST_FUNC; | 50 | void replace(char *s, char what, char with) FAST_FUNC; |
21 | char *replace_underscores(char *s) FAST_FUNC; | 51 | char *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 | 8076 | enum { | |
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 | }; | ||
8106 | typedef smallint token_id_t; | 8110 | typedef 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 @@ | |||
1 | Hello | ||
2 | Zero: 0 | ||
3 | One: 1 Param1: World | ||
4 | Zero: 0 Param1: Restored | ||
5 | Multi line function | ||
6 | One: 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 @@ | |||
1 | f() { echo Hello; } | ||
2 | g () { echo One: $# Param1: $1; } | ||
3 | h ( ) | ||
4 | { | ||
5 | echo -n 'Multi ' && echo -n 'line ' | ||
6 | echo function | ||
7 | false | ||
8 | } | ||
9 | |||
10 | f | ||
11 | echo Zero: $? | ||
12 | set -- Restored | ||
13 | { g World; } | ||
14 | echo Zero: $? Param1: $1 | ||
15 | ( h ) | ||
16 | echo 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 @@ | |||
1 | First 0 | ||
2 | Second 0 | ||
3 | First 1 | ||
4 | Second 1 | ||
5 | Done | ||
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 @@ | |||
1 | i=0 | ||
2 | while test $i != 2; do | ||
3 | f() { echo First $i; } | ||
4 | f | ||
5 | f() { echo Second $i; } | ||
6 | f | ||
7 | : $((i++)) | ||
8 | done | ||
9 | echo 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 @@ | |||
1 | One:1 | ||
2 | Zero:0 | ||
3 | One:1 | ||
4 | Five: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 @@ | |||
1 | f() { false; return; echo BAD; }; | ||
2 | { f; echo One:$?; }; echo Zero:$? | ||
3 | |||
4 | f() { false; return; }; | ||
5 | f; echo One:$? | ||
6 | |||
7 | f() { return 5; }; | ||
8 | f; 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 @@ | |||
1 | 24 | ||
2 | Done | ||
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 @@ | |||
1 | func() { | ||
2 | eval "echo \"\${val_${1}}\"" | ||
3 | } | ||
4 | |||
5 | val_x=24 | ||
6 | (func x) | ||
7 | echo 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 @@ | |||
1 | 1 | ||
2 | 2 | ||
3 | 3 | ||
4 | 1 | ||
5 | 2 | ||
6 | 3 | ||
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 @@ | |||
1 | f() { echo $1; } | ||
2 | f 1 | ||
3 | |||
4 | f() ( echo $1; ) | ||
5 | f 2 | ||
6 | |||
7 | f() ( echo $1 ) | ||
8 | f 3 | ||
9 | |||
10 | f() for i in 1 2 3; do | ||
11 | echo $i | ||
12 | done | ||
13 | f | ||
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 @@ | |||
1 | params: a b c | ||
2 | 'f 1 2 3' called | ||
3 | params: a b c | ||
4 | 'f 1 2 3' called | ||
5 | params: 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 @@ | |||
1 | f() { echo "'f $1 $2 $3' called"; } | ||
2 | |||
3 | set -- a b c | ||
4 | echo "params: $1 $2 $3" | ||
5 | f 1 2 3 | ||
6 | echo "params: $1 $2 $3" | ||
7 | true | f 1 2 3 | ||
8 | echo "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 @@ | |||
1 | 1 | ||
2 | 2 | ||
3 | 3 | ||
4 | 1 | ||
5 | 2 | ||
6 | 3 | ||
7 | 1 | ||
8 | 2 | ||
9 | 3 | ||
10 | 1 | ||
11 | 2 | ||
12 | 3 | ||
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 @@ | |||
1 | function f() { echo $1; } | ||
2 | f 1 | ||
3 | |||
4 | function f() ( echo $1; ) | ||
5 | f 2 | ||
6 | |||
7 | function f() ( echo $1 ) | ||
8 | f 3 | ||
9 | |||
10 | function f() for i in 1 2 3; do | ||
11 | echo $i | ||
12 | done | ||
13 | f | ||
14 | |||
15 | function f { echo $1; } | ||
16 | f 1 | ||
17 | |||
18 | # the next two don't work | ||
19 | #function f ( echo $1; ) | ||
20 | f 2 | ||
21 | |||
22 | #function f ( echo $1 ) | ||
23 | f 3 | ||
24 | |||
25 | function f for i in 1 2 3; do | ||
26 | echo $i | ||
27 | done | ||
28 | f | ||
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 @@ | |||
1 | z=a | ||
2 | z=z | ||
3 | Done | ||
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 @@ | |||
1 | export z=z | ||
2 | f() { local z=a; env | grep ^z; } | ||
3 | f | ||
4 | env | grep ^z | ||
5 | echo 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 @@ | |||
1 | 1 | ||
2 | 2 | ||
3 | 1 | ||
4 | 2 | ||
5 | 1 | ||
6 | 1 | ||
7 | 2 | ||
8 | 2 | ||
9 | 3 | ||
10 | 2 | ||
11 | 2 | ||
12 | 3 | ||
13 | 1 | ||
14 | Done | ||
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 @@ | |||
1 | x=1 | ||
2 | f() { echo $x; local x=$((x+1)); echo $x; } | ||
3 | g() { f; echo $x; f; local x=$((x+1)); f; echo $x; f; } | ||
4 | f | ||
5 | g | ||
6 | echo $x | ||
7 | echo 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 | |||
3 | f() { echo "'f $1 $2 $3' called"; } | 1 | f() { echo "'f $1 $2 $3' called"; } |
4 | 2 | ||
5 | set -- a b c | 3 | set -- a b c |