aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2007-04-14 10:09:57 +0000
committervda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2007-04-14 10:09:57 +0000
commit1f7c156d56726cdeeadc5983149304f2e3be36ad (patch)
tree95a0c3632c8c2b20fa6b60f1e1a33e4fc4b24d4f
parent86b5b2210f0ea0158af81b9da1f6849ea7dcea5d (diff)
downloadbusybox-w32-1f7c156d56726cdeeadc5983149304f2e3be36ad.tar.gz
busybox-w32-1f7c156d56726cdeeadc5983149304f2e3be36ad.tar.bz2
busybox-w32-1f7c156d56726cdeeadc5983149304f2e3be36ad.zip
hush: use NOFORK applets as appropriate. Net reduction of code size.
git-svn-id: svn://busybox.net/trunk/busybox@18436 69ca8d6d-28ef-0310-b511-8ec308f3f277
-rw-r--r--applets/applets.c30
-rw-r--r--findutils/xargs.c4
-rw-r--r--include/libbb.h64
-rw-r--r--libbb/vfork_daemon_rexec.c89
-rw-r--r--shell/ash.c4
-rw-r--r--shell/hush.c41
-rw-r--r--shell/lash.c7
7 files changed, 125 insertions, 114 deletions
diff --git a/applets/applets.c b/applets/applets.c
index 82a7eeea1..fb37fbea5 100644
--- a/applets/applets.c
+++ b/applets/applets.c
@@ -514,14 +514,14 @@ static void install_links(const char *busybox, int use_symbolic_links)
514 514
515 515
516/* If we were called as "busybox..." */ 516/* If we were called as "busybox..." */
517static int busybox_main(int argc, char **argv) 517static int busybox_main(char **argv)
518{ 518{
519 if (ENABLE_FEATURE_INSTALLER && argc > 1 && !strcmp(argv[1], "--install")) { 519 if (ENABLE_FEATURE_INSTALLER && argv[1] && !strcmp(argv[1], "--install")) {
520 int use_symbolic_links = 0; 520 int use_symbolic_links = 0;
521 char *busybox; 521 char *busybox;
522 522
523 /* to use symlinks, or not to use symlinks... */ 523 /* to use symlinks, or not to use symlinks... */
524 if (argc > 2) 524 if (argv[2])
525 if (strcmp(argv[2], "-s") == 0) 525 if (strcmp(argv[2], "-s") == 0)
526 use_symbolic_links = 1; 526 use_symbolic_links = 1;
527 527
@@ -537,11 +537,12 @@ static int busybox_main(int argc, char **argv)
537 537
538 /* Deal with --help. Also print help when called with no arguments */ 538 /* Deal with --help. Also print help when called with no arguments */
539 539
540 if (argc == 1 || !strcmp(argv[1], "--help") ) { 540 if (!argv[1] || !strcmp(argv[1], "--help") ) {
541 if (argc > 2) { 541 if (argv[2]) {
542 /* set name for proper "<name>: applet not found" */ 542 /* set name for proper "<name>: applet not found" */
543 applet_name = argv[2]; 543 applet_name = argv[2];
544 run_applet_and_exit(applet_name, 2, argv); 544 argv[2] = NULL;
545 run_applet_and_exit(applet_name, argv);
545 } else { 546 } else {
546 const struct bb_applet *a; 547 const struct bb_applet *a;
547 int col, output_width; 548 int col, output_width;
@@ -582,14 +583,19 @@ static int busybox_main(int argc, char **argv)
582 } else { 583 } else {
583 /* we want "<argv[1]>: applet not found", not "busybox: ..." */ 584 /* we want "<argv[1]>: applet not found", not "busybox: ..." */
584 applet_name = argv[1]; 585 applet_name = argv[1];
585 run_applet_and_exit(argv[1], argc - 1, argv + 1); 586 run_applet_and_exit(argv[1], argv + 1);
586 } 587 }
587 588
588 bb_error_msg_and_die("applet not found"); 589 bb_error_msg_and_die("applet not found");
589} 590}
590 591
591void run_current_applet_and_exit(int argc, char **argv) 592void run_current_applet_and_exit(char **argv)
592{ 593{
594 int argc = 1;
595
596 while (argv[argc])
597 argc++;
598
593 /* Reinit some shared global data */ 599 /* Reinit some shared global data */
594 optind = 1; 600 optind = 1;
595 xfunc_error_retval = EXIT_FAILURE; 601 xfunc_error_retval = EXIT_FAILURE;
@@ -602,13 +608,13 @@ void run_current_applet_and_exit(int argc, char **argv)
602 exit(current_applet->main(argc, argv)); 608 exit(current_applet->main(argc, argv));
603} 609}
604 610
605void run_applet_and_exit(const char *name, int argc, char **argv) 611void run_applet_and_exit(const char *name, char **argv)
606{ 612{
607 current_applet = find_applet_by_name(name); 613 current_applet = find_applet_by_name(name);
608 if (current_applet) 614 if (current_applet)
609 run_current_applet_and_exit(argc, argv); 615 run_current_applet_and_exit(argv);
610 if (!strncmp(name, "busybox", 7)) 616 if (!strncmp(name, "busybox", 7))
611 exit(busybox_main(argc, argv)); 617 exit(busybox_main(argv));
612} 618}
613 619
614 620
@@ -637,6 +643,6 @@ int main(int argc, char **argv)
637 if (ENABLE_LOCALE_SUPPORT && getpid() != 1) 643 if (ENABLE_LOCALE_SUPPORT && getpid() != 1)
638 setlocale(LC_ALL, ""); 644 setlocale(LC_ALL, "");
639 645
640 run_applet_and_exit(applet_name, argc, argv); 646 run_applet_and_exit(applet_name, argv);
641 bb_error_msg_and_die("applet not found"); 647 bb_error_msg_and_die("applet not found");
642} 648}
diff --git a/findutils/xargs.c b/findutils/xargs.c
index a430e5f3d..b90f44ca4 100644
--- a/findutils/xargs.c
+++ b/findutils/xargs.c
@@ -176,7 +176,7 @@ set:
176 } 176 }
177 if (!eof_str_detected) { 177 if (!eof_str_detected) {
178 size_t length = (p - buf); 178 size_t length = (p - buf);
179 179// TODO: smarter llist_t
180 cur = xzalloc(sizeof(xlist_t) + length); 180 cur = xzalloc(sizeof(xlist_t) + length);
181 cur->data = memcpy(cur + 1, s, length); 181 cur->data = memcpy(cur + 1, s, length);
182 cur->length = length; 182 cur->length = length;
@@ -247,6 +247,7 @@ static xlist_t *process_stdin(xlist_t *list_arg,
247 size_t length = (p - buf); 247 size_t length = (p - buf);
248 248
249 cur = xzalloc(sizeof(xlist_t) + length); 249 cur = xzalloc(sizeof(xlist_t) + length);
250// TODO: smarter llist_t
250 cur->data = memcpy(cur + 1, s, length); 251 cur->data = memcpy(cur + 1, s, length);
251 cur->length = length; 252 cur->length = length;
252 /*cur->link = NULL;*/ 253 /*cur->link = NULL;*/
@@ -329,6 +330,7 @@ static xlist_t *process0_stdin(xlist_t *list_arg,
329 size_t length = (p - buf); 330 size_t length = (p - buf);
330 331
331 cur = xzalloc(sizeof(xlist_t) + length); 332 cur = xzalloc(sizeof(xlist_t) + length);
333// TODO: smarter llist_t
332 cur->data = memcpy(cur + 1, s, length); 334 cur->data = memcpy(cur + 1, s, length);
333 cur->length = length; 335 cur->length = length;
334 /*cur->link = NULL;*/ 336 /*cur->link = NULL;*/
diff --git a/include/libbb.h b/include/libbb.h
index 212b048de..77f1e0a44 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -123,35 +123,6 @@
123/* scary. better ideas? (but do *test* them first!) */ 123/* scary. better ideas? (but do *test* them first!) */
124#define OFF_T_MAX ((off_t)~((off_t)1 << (sizeof(off_t)*8-1))) 124#define OFF_T_MAX ((off_t)~((off_t)1 << (sizeof(off_t)*8-1)))
125 125
126/* This structure defines protocol families and their handlers. */
127struct aftype {
128 const char *name;
129 const char *title;
130 int af;
131 int alen;
132 char *(*print) (unsigned char *);
133 const char *(*sprint) (struct sockaddr *, int numeric);
134 int (*input) (/*int type,*/ const char *bufp, struct sockaddr *);
135 void (*herror) (char *text);
136 int (*rprint) (int options);
137 int (*rinput) (int typ, int ext, char **argv);
138
139 /* may modify src */
140 int (*getmask) (char *src, struct sockaddr * mask, char *name);
141};
142
143/* This structure defines hardware protocols and their handlers. */
144struct hwtype {
145 const char *name;
146 const char *title;
147 int type;
148 int alen;
149 char *(*print) (unsigned char *);
150 int (*input) (const char *, struct sockaddr *);
151 int (*activate) (int fd);
152 int suppress_null_addr;
153};
154
155/* Some useful definitions */ 126/* Some useful definitions */
156#undef FALSE 127#undef FALSE
157#define FALSE ((int) 0) 128#define FALSE ((int) 0)
@@ -504,6 +475,7 @@ void clear_username_cache(void);
504enum { USERNAME_MAX_SIZE = 16 - sizeof(int) }; 475enum { USERNAME_MAX_SIZE = 16 - sizeof(int) };
505 476
506 477
478struct bb_applet;
507int execable_file(const char *name); 479int execable_file(const char *name);
508char *find_execable(const char *filename); 480char *find_execable(const char *filename);
509int exists_execable(const char *filename); 481int exists_execable(const char *filename);
@@ -537,6 +509,8 @@ int wait_nohang(int *wstat);
537#define wait_exitcode(w) ((w) >> 8) 509#define wait_exitcode(w) ((w) >> 8)
538#define wait_stopsig(w) ((w) >> 8) 510#define wait_stopsig(w) ((w) >> 8)
539#define wait_stopped(w) (((w) & 127) == 127) 511#define wait_stopped(w) (((w) & 127) == 127)
512/* Does NOT check that applet is NOFORK, just blindly runs it */
513int run_nofork_applet(const struct bb_applet *a, char **argv);
540/* wait4pid(spawn(argv)) + NOFORK/NOEXEC (if configured) */ 514/* wait4pid(spawn(argv)) + NOFORK/NOEXEC (if configured) */
541int spawn_and_wait(char **argv); 515int spawn_and_wait(char **argv);
542 516
@@ -669,6 +643,33 @@ int bbunpack(char **argv,
669int create_icmp_socket(void); 643int create_icmp_socket(void);
670int create_icmp6_socket(void); 644int create_icmp6_socket(void);
671/* interface.c */ 645/* interface.c */
646/* This structure defines protocol families and their handlers. */
647struct aftype {
648 const char *name;
649 const char *title;
650 int af;
651 int alen;
652 char *(*print) (unsigned char *);
653 const char *(*sprint) (struct sockaddr *, int numeric);
654 int (*input) (/*int type,*/ const char *bufp, struct sockaddr *);
655 void (*herror) (char *text);
656 int (*rprint) (int options);
657 int (*rinput) (int typ, int ext, char **argv);
658
659 /* may modify src */
660 int (*getmask) (char *src, struct sockaddr * mask, char *name);
661};
662/* This structure defines hardware protocols and their handlers. */
663struct hwtype {
664 const char *name;
665 const char *title;
666 int type;
667 int alen;
668 char *(*print) (unsigned char *);
669 int (*input) (const char *, struct sockaddr *);
670 int (*activate) (int fd);
671 int suppress_null_addr;
672};
672extern int interface_opt_a; 673extern int interface_opt_a;
673int display_interfaces(char *ifname); 674int display_interfaces(char *ifname);
674const struct aftype *get_aftype(const char *name); 675const struct aftype *get_aftype(const char *name);
@@ -677,11 +678,10 @@ const struct hwtype *get_hwntype(int type);
677 678
678 679
679#ifndef BUILD_INDIVIDUAL 680#ifndef BUILD_INDIVIDUAL
680struct bb_applet;
681extern const struct bb_applet *find_applet_by_name(const char *name); 681extern const struct bb_applet *find_applet_by_name(const char *name);
682/* Returns only if applet is not found. */ 682/* Returns only if applet is not found. */
683extern void run_applet_and_exit(const char *name, int argc, char **argv); 683extern void run_applet_and_exit(const char *name, char **argv);
684extern void run_current_applet_and_exit(int argc, char **argv) ATTRIBUTE_NORETURN; 684extern void run_current_applet_and_exit(char **argv) ATTRIBUTE_NORETURN;
685#endif 685#endif
686 686
687extern int match_fstype(const struct mntent *mt, const char *fstypes); 687extern int match_fstype(const struct mntent *mt, const char *fstypes);
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index 7dbc152e2..78f3c4ad4 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -100,6 +100,52 @@ int wait_pid(int *wstat, int pid)
100 return r; 100 return r;
101} 101}
102 102
103int run_nofork_applet(const struct bb_applet *a, char **argv)
104{
105 int rc, argc;
106
107 /* Save some shared globals */
108 const struct bb_applet *old_a = current_applet;
109 int old_x = xfunc_error_retval;
110 uint32_t old_m = option_mask32;
111 int old_sleep = die_sleep;
112
113 current_applet = a;
114 applet_name = a->name;
115 xfunc_error_retval = EXIT_FAILURE;
116 /*option_mask32 = 0; - not needed */
117 /* special flag for xfunc_die(). If xfunc will "die"
118 * in NOFORK applet, xfunc_die() sees negative
119 * die_sleep and longjmp here instead. */
120 die_sleep = -1;
121
122 argc = 1;
123 while (argv[argc])
124 argc++;
125
126 rc = setjmp(die_jmp);
127 if (!rc) {
128 /* Some callers (xargs)
129 * need argv untouched because they free argv[i]! */
130 char *tmp_argv[argc+1];
131 memcpy(tmp_argv, argv, (argc+1) * sizeof(tmp_argv[0]));
132 /* Finally we can call NOFORK applet's main() */
133 rc = a->main(argc, tmp_argv);
134 } else { /* xfunc died in NOFORK applet */
135 /* in case they meant to return 0... */
136 if (rc == -111)
137 rc = 0;
138 }
139
140 /* Restoring globals */
141 current_applet = old_a;
142 applet_name = old_a->name;
143 xfunc_error_retval = old_x;
144 option_mask32 = old_m;
145 die_sleep = old_sleep;
146 return rc;
147}
148
103int spawn_and_wait(char **argv) 149int spawn_and_wait(char **argv)
104{ 150{
105 int rc; 151 int rc;
@@ -111,50 +157,11 @@ int spawn_and_wait(char **argv)
111 || a->noexec /* NOEXEC trick needs fork() */ 157 || a->noexec /* NOEXEC trick needs fork() */
112#endif 158#endif
113 )) { 159 )) {
114 int argc = 1;
115 char **pp = argv;
116 while (*++pp)
117 argc++;
118#if BB_MMU 160#if BB_MMU
119 if (a->nofork) 161 if (a->nofork)
120#endif 162#endif
121 { 163 {
122 /* Save some shared globals */ 164 return run_nofork_applet(a, argv);
123 const struct bb_applet *old_a = current_applet;
124 int old_x = xfunc_error_retval;
125 uint32_t old_m = option_mask32;
126 int old_sleep = die_sleep;
127
128 current_applet = a;
129 applet_name = a->name;
130 xfunc_error_retval = EXIT_FAILURE;
131 /*option_mask32 = 0; - not needed */
132 /* special flag for xfunc_die(). If xfunc will "die"
133 * in NOFORK applet, xfunc_die() sees negative
134 * die_sleep and longjmp here instead. */
135 die_sleep = -1;
136
137 rc = setjmp(die_jmp);
138 if (!rc) {
139 /* Some callers (xargs)
140 * need argv untouched because they free argv[i]! */
141 char *tmp_argv[argc+1];
142 memcpy(tmp_argv, argv, (argc+1) * sizeof(tmp_argv[0]));
143 /* Finally we can call NOFORK applet's main() */
144 rc = a->main(argc, tmp_argv);
145 } else { /* xfunc died in NOFORK applet */
146 /* in case they meant to return 0... */
147 if (rc == -111)
148 rc = 0;
149 }
150
151 /* Restoring globals */
152 current_applet = old_a;
153 applet_name = old_a->name;
154 xfunc_error_retval = old_x;
155 option_mask32 = old_m;
156 die_sleep = old_sleep;
157 return rc;
158 } 165 }
159#if BB_MMU 166#if BB_MMU
160 /* MMU only */ 167 /* MMU only */
@@ -165,7 +172,7 @@ int spawn_and_wait(char **argv)
165 /* child */ 172 /* child */
166 xfunc_error_retval = EXIT_FAILURE; 173 xfunc_error_retval = EXIT_FAILURE;
167 current_applet = a; 174 current_applet = a;
168 run_current_applet_and_exit(argc, argv); 175 run_current_applet_and_exit(argv);
169#endif 176#endif
170 } 177 }
171#endif /* FEATURE_PREFER_APPLETS */ 178#endif /* FEATURE_PREFER_APPLETS */
diff --git a/shell/ash.c b/shell/ash.c
index 63f039df4..90936fcc0 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -6539,10 +6539,8 @@ tryexec(char *cmd, char **argv, char **envp)
6539 a = find_applet_by_name(cmd); 6539 a = find_applet_by_name(cmd);
6540 if (a) { 6540 if (a) {
6541 if (a->noexec) { 6541 if (a->noexec) {
6542 char **c = argv;
6543 while (*c) c++;
6544 current_applet = a; 6542 current_applet = a;
6545 run_current_applet_and_exit(c - argv, argv); 6543 run_current_applet_and_exit(argv);
6546 } 6544 }
6547 /* re-exec ourselves with the new arguments */ 6545 /* re-exec ourselves with the new arguments */
6548 execve(CONFIG_BUSYBOX_EXEC_PATH, argv, envp); 6546 execve(CONFIG_BUSYBOX_EXEC_PATH, argv, envp);
diff --git a/shell/hush.c b/shell/hush.c
index 035919500..9362e5916 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -765,7 +765,7 @@ static int b_check_space(o_string *o, int len)
765 * in here, such as setting a maximum string length */ 765 * in here, such as setting a maximum string length */
766 if (o->length + len > o->maxlen) { 766 if (o->length + len > o->maxlen) {
767 char *old_data = o->data; 767 char *old_data = o->data;
768 /* assert (data == NULL || o->maxlen != 0); */ 768 /* assert(data == NULL || o->maxlen != 0); */
769 o->maxlen += max(2*len, B_CHUNK); 769 o->maxlen += max(2*len, B_CHUNK);
770 o->data = realloc(o->data, 1 + o->maxlen); 770 o->data = realloc(o->data, 1 + o->maxlen);
771 if (o->data == NULL) { 771 if (o->data == NULL) {
@@ -1113,17 +1113,10 @@ static void pseudo_exec(struct child_prog *child)
1113 * from global_argv[0], but if we are in a chroot, we may not be able 1113 * from global_argv[0], but if we are in a chroot, we may not be able
1114 * to find ourself... */ 1114 * to find ourself... */
1115#if ENABLE_FEATURE_SH_STANDALONE 1115#if ENABLE_FEATURE_SH_STANDALONE
1116 { 1116 debug_printf("running applet %s\n", child->argv[0]);
1117 int argc_l; 1117 run_applet_and_exit(child->argv[0], child->argv);
1118 char** argv_l = child->argv; 1118// is it ok that run_applet_and_exit() does exit(), not _exit()?
1119 char *name = child->argv[0]; 1119// NB: IIRC on NOMMU we are after _vfork_, not fork!
1120
1121 /* Count argc for use in a second... */
1122 for (argc_l = 0; *argv_l; argv_l++, argc_l++)
1123 continue;
1124 debug_printf("running applet %s\n", name);
1125 run_applet_and_exit(name, argc_l, child->argv);
1126 }
1127#endif 1120#endif
1128 debug_printf("exec of %s\n", child->argv[0]); 1121 debug_printf("exec of %s\n", child->argv[0]);
1129 execvp(child->argv[0], child->argv); 1122 execvp(child->argv[0], child->argv);
@@ -1304,6 +1297,9 @@ static int run_pipe_real(struct pipe *pi)
1304 struct child_prog *child; 1297 struct child_prog *child;
1305 const struct built_in_command *x; 1298 const struct built_in_command *x;
1306 char *p; 1299 char *p;
1300 /* it is not always needed, but we aim to smaller code */
1301 int squirrel[] = { -1, -1, -1 };
1302 int rcode;
1307 1303
1308 nextin = 0; 1304 nextin = 0;
1309 pi->pgrp = -1; 1305 pi->pgrp = -1;
@@ -1314,8 +1310,6 @@ static int run_pipe_real(struct pipe *pi)
1314 */ 1310 */
1315 child = &(pi->progs[0]); 1311 child = &(pi->progs[0]);
1316 if (pi->num_progs == 1 && child->group && child->subshell == 0) { 1312 if (pi->num_progs == 1 && child->group && child->subshell == 0) {
1317 int squirrel[] = { -1, -1, -1 };
1318 int rcode;
1319 debug_printf("non-subshell grouping\n"); 1313 debug_printf("non-subshell grouping\n");
1320 setup_redirects(child, squirrel); 1314 setup_redirects(child, squirrel);
1321 /* XXX could we merge code with following builtin case, 1315 /* XXX could we merge code with following builtin case,
@@ -1366,15 +1360,13 @@ static int run_pipe_real(struct pipe *pi)
1366 if (child->sp) { 1360 if (child->sp) {
1367 char *str; 1361 char *str;
1368 1362
1369 str = make_string((child->argv + i)); 1363 str = make_string(child->argv + i);
1370 parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING); 1364 parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING);
1371 free(str); 1365 free(str);
1372 return last_return_code; 1366 return last_return_code;
1373 } 1367 }
1374 for (x = bltins; x->cmd; x++) { 1368 for (x = bltins; x->cmd; x++) {
1375 if (strcmp(child->argv[i], x->cmd) == 0) { 1369 if (strcmp(child->argv[i], x->cmd) == 0) {
1376 int squirrel[] = { -1, -1, -1 };
1377 int rcode;
1378 if (x->function == builtin_exec && child->argv[i+1] == NULL) { 1370 if (x->function == builtin_exec && child->argv[i+1] == NULL) {
1379 debug_printf("magic exec\n"); 1371 debug_printf("magic exec\n");
1380 setup_redirects(child, NULL); 1372 setup_redirects(child, NULL);
@@ -1393,6 +1385,17 @@ static int run_pipe_real(struct pipe *pi)
1393 return rcode; 1385 return rcode;
1394 } 1386 }
1395 } 1387 }
1388#if ENABLE_FEATURE_SH_STANDALONE
1389 {
1390 const struct bb_applet *a = find_applet_by_name(child->argv[i]);
1391 if (a && a->nofork) {
1392 setup_redirects(child, squirrel);
1393 rcode = run_nofork_applet(a, child->argv + i);
1394 restore_redirects(squirrel);
1395 return rcode;
1396 }
1397 }
1398#endif
1396 } 1399 }
1397 1400
1398 for (i = 0; i < pi->num_progs; i++) { 1401 for (i = 0; i < pi->num_progs; i++) {
@@ -2587,8 +2590,8 @@ int parse_stream(o_string *dest, struct p_context *ctx,
2587 2590
2588static void mapset(const char *set, int code) 2591static void mapset(const char *set, int code)
2589{ 2592{
2590 while (*s) 2593 while (*set)
2591 map[(unsigned char)*s++] = code; 2594 map[(unsigned char)*set++] = code;
2592} 2595}
2593 2596
2594static void update_ifs_map(void) 2597static void update_ifs_map(void)
diff --git a/shell/lash.c b/shell/lash.c
index c74684bf7..6fe2ddc76 100644
--- a/shell/lash.c
+++ b/shell/lash.c
@@ -1158,12 +1158,7 @@ static int pseudo_exec(struct child_prog *child)
1158 * /bin/foo is a symlink to busybox. 1158 * /bin/foo is a symlink to busybox.
1159 */ 1159 */
1160 if (ENABLE_FEATURE_SH_STANDALONE) { 1160 if (ENABLE_FEATURE_SH_STANDALONE) {
1161 char **argv_l = child->argv; 1161 run_applet_and_exit(child->argv[0], child->argv);
1162 int argc_l;
1163
1164 for (argc_l = 0; *argv_l; argv_l++, argc_l++)
1165 continue;
1166 run_applet_and_exit(child->argv[0], argc_l, child->argv);
1167 } 1162 }
1168 1163
1169 execvp(child->argv[0], child->argv); 1164 execvp(child->argv[0], child->argv);