Implement first instance of NOFORK applet - echo

find: use NOFORK/NOEXEC; small -exec buglet also eliminated
vfork_daemon_rexec: honor PREFER_APPLETS
echo: small size improvements

find -exec echo {} \; with PREFER_APPLETS=y runs 4 times faster
This commit is contained in:
Denis Vlasenko 2007-04-09 13:04:50 +00:00
parent 2dfdd44d9d
commit 7e754f12d3
6 changed files with 77 additions and 50 deletions

View File

@ -244,7 +244,8 @@ config FEATURE_EXEC_PREFER_APPLETS
help help
This is an experimental option which directs applets about to This is an experimental option which directs applets about to
call 'exec' to try and find an applicable busybox applet before call 'exec' to try and find an applicable busybox applet before
searching the executable path for a binary or symlink to execute. searching the PATH. This may affect shell, find -exec, xargs and
similar programs.
config BUSYBOX_EXEC_PATH config BUSYBOX_EXEC_PATH
string "Path to BusyBox executable" string "Path to BusyBox executable"

View File

@ -20,86 +20,85 @@
* 1) In handling '\c' escape, the previous version only suppressed the * 1) In handling '\c' escape, the previous version only suppressed the
* trailing newline. SUSv3 specifies _no_ output after '\c'. * trailing newline. SUSv3 specifies _no_ output after '\c'.
* 2) SUSv3 specifies that octal escapes are of the form \0{#{#{#}}}. * 2) SUSv3 specifies that octal escapes are of the form \0{#{#{#}}}.
* The previous version version did not allow 4-digit octals. * The previous version did not allow 4-digit octals.
*/ */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "busybox.h" #include "busybox.h"
int bb_echo(char **argv) int bb_echo(char **argv)
{ {
#ifndef CONFIG_FEATURE_FANCY_ECHO const char *arg;
#if !ENABLE_FEATURE_FANCY_ECHO
#define eflag '\\' #define eflag '\\'
++argv; ++argv;
#else #else
const char *p; const char *p;
int nflag = 1; char nflag = 1;
int eflag = 0; char eflag = 0;
while (1) {
arg = *++argv;
if (!arg)
goto ret;
if (*arg != '-')
break;
while (*++argv && (**argv == '-')) {
/* If it appears that we are handling options, then make sure /* If it appears that we are handling options, then make sure
* that all of the options specified are actually valid. * that all of the options specified are actually valid.
* Otherwise, the string should just be echoed. * Otherwise, the string should just be echoed.
*/ */
p = arg + 1;
if (!*(p = *argv + 1)) { /* A single '-', so echo it. */ if (!*p) /* A single '-', so echo it. */
goto just_echo; goto just_echo;
}
do { do {
if (strrchr("neE", *p) == 0) { if (!strrchr("neE", *p))
goto just_echo; goto just_echo;
}
} while (*++p); } while (*++p);
/* All of the options in this arg are valid, so handle them. */ /* All of the options in this arg are valid, so handle them. */
p = *argv + 1; p = arg + 1;
do { do {
if (*p == 'n') { if (*p == 'n')
nflag = 0; nflag = 0;
} else if (*p == 'e') { if (*p == 'e')
eflag = '\\'; eflag = '\\';
} else {
eflag = 0;
}
} while (*++p); } while (*++p);
} }
just_echo:
just_echo:
#endif #endif
while (*argv) { while (1) {
/* arg is already = *argv and isn't NULL */
int c; int c;
while ((c = *(*argv)++)) { while ((c = *arg++)) {
if (c == eflag) { /* Check for escape seq. */ if (c == eflag) { /* Check for escape seq. */
if (**argv == 'c') { if (*arg == 'c') {
/* '\c' means cancel newline and /* '\c' means cancel newline and
* ignore all subsequent chars. */ * ignore all subsequent chars. */
return 0; goto ret;
} }
#ifndef CONFIG_FEATURE_FANCY_ECHO #if !ENABLE_FEATURE_FANCY_ECHO
/* SUSv3 specifies that octal escapes must begin with '0'. */ /* SUSv3 specifies that octal escapes must begin with '0'. */
if (((unsigned int)(**argv - '1')) >= 7) if ( (((unsigned char)*arg) - '1') >= 7)
#endif #endif
{ {
/* Since SUSv3 mandates a first digit of 0, 4-digit octals /* Since SUSv3 mandates a first digit of 0, 4-digit octals
* of the form \0### are accepted. */ * of the form \0### are accepted. */
if ((**argv == '0') && (((unsigned int)(argv[0][1] - '0')) < 8)) { if (*arg == '0' && ((unsigned char)(arg[1]) - '0') < 8) {
(*argv)++; arg++;
} }
/* bb_process_escape_sequence can handle nul correctly */ /* bb_process_escape_sequence can handle nul correctly */
c = bb_process_escape_sequence((const char **) argv); c = bb_process_escape_sequence(&arg);
} }
} }
putchar(c); putchar(c);
} }
if (*++argv) { arg = *++argv;
putchar(' '); if (!arg)
} break;
putchar(' ');
} }
#ifdef CONFIG_FEATURE_FANCY_ECHO #ifdef CONFIG_FEATURE_FANCY_ECHO
@ -109,14 +108,16 @@ just_echo:
#else #else
putchar('\n'); putchar('\n');
#endif #endif
return 0; ret:
return fflush(stdout);
} }
/* This is a NOFORK applet. Be very careful! */
int echo_main(int argc, char** argv); int echo_main(int argc, char** argv);
int echo_main(int argc, char** argv) int echo_main(int argc, char** argv)
{ {
(void)bb_echo(argv); return bb_echo(argv);
fflush_stdout_and_exit(EXIT_SUCCESS);
} }
/*- /*-

View File

@ -242,9 +242,30 @@ ACTF(exec)
for (i = 0; i < ap->exec_argc; i++) for (i = 0; i < ap->exec_argc; i++)
argv[i] = subst(ap->exec_argv[i], ap->subst_count[i], fileName); argv[i] = subst(ap->exec_argv[i], ap->subst_count[i], fileName);
argv[i] = NULL; /* terminate the list */ argv[i] = NULL; /* terminate the list */
rc = wait4pid(spawn(argv));
if (rc) if (ENABLE_FEATURE_EXEC_PREFER_APPLETS) {
const struct BB_applet *a = find_applet_by_name(argv[0]);
if (a) {
if (a->nofork) {
rc = a->main(ap->exec_argc, argv);
goto f;
}
#ifndef BB_NOMMU
if (a->noexec) {
rc = fork();
if (rc) goto w;
current_applet = a;
run_current_applet_and_exit(ap->exec_argc, argv);
}
#endif
}
}
rc = spawn(argv);
w:
rc = wait4pid(rc);
if (rc < 0)
bb_perror_msg("%s", argv[0]); bb_perror_msg("%s", argv[0]);
f:
for (i = 0; i < ap->exec_argc; i++) for (i = 0; i < ap->exec_argc; i++)
free(argv[i]); free(argv[i]);
return rc == 0; /* return 1 if success */ return rc == 0; /* return 1 if success */

View File

@ -28,24 +28,28 @@ s - suid type:
# define APPLET_NOUSAGE(name,main,l,s) int main##_main(int argc, char **argv); # define APPLET_NOUSAGE(name,main,l,s) int main##_main(int argc, char **argv);
# define APPLET_ODDNAME(name,main,l,s,name2) int main##_main(int argc, char **argv); # define APPLET_ODDNAME(name,main,l,s,name2) int main##_main(int argc, char **argv);
# define APPLET_NOEXEC(name,main,l,s,name2) int main##_main(int argc, char **argv); # define APPLET_NOEXEC(name,main,l,s,name2) int main##_main(int argc, char **argv);
# define APPLET_NOFORK(name,main,l,s,name2) int main##_main(int argc, char **argv);
#elif defined(MAKE_USAGE) && ENABLE_FEATURE_VERBOSE_USAGE #elif defined(MAKE_USAGE) && ENABLE_FEATURE_VERBOSE_USAGE
# define APPLET(name,l,s) name##_trivial_usage "\n\n" name##_full_usage "\0" # define APPLET(name,l,s) name##_trivial_usage "\n\n" name##_full_usage "\0"
# define APPLET_NOUSAGE(name,main,l,s) "\b\0" # define APPLET_NOUSAGE(name,main,l,s) "\b\0"
# define APPLET_ODDNAME(name,main,l,s,name2) name2##_trivial_usage "\n\n" name2##_full_usage "\0" # define APPLET_ODDNAME(name,main,l,s,name2) name2##_trivial_usage "\n\n" name2##_full_usage "\0"
# define APPLET_NOEXEC(name,main,l,s,name2) name2##_trivial_usage "\n\n" name2##_full_usage "\0" # define APPLET_NOEXEC(name,main,l,s,name2) name2##_trivial_usage "\n\n" name2##_full_usage "\0"
# define APPLET_NOFORK(name,main,l,s,name2) name2##_trivial_usage "\n\n" name2##_full_usage "\0"
#elif defined(MAKE_USAGE) && !ENABLE_FEATURE_VERBOSE_USAGE #elif defined(MAKE_USAGE) && !ENABLE_FEATURE_VERBOSE_USAGE
# define APPLET(name,l,s) name##_trivial_usage "\0" # define APPLET(name,l,s) name##_trivial_usage "\0"
# define APPLET_NOUSAGE(name,main,l,s) "\b\0" # define APPLET_NOUSAGE(name,main,l,s) "\b\0"
# define APPLET_ODDNAME(name,main,l,s,name2) name2##_trivial_usage "\0" # define APPLET_ODDNAME(name,main,l,s,name2) name2##_trivial_usage "\0"
# define APPLET_NOEXEC(name,main,l,s,name2) name2##_trivial_usage "\0" # define APPLET_NOEXEC(name,main,l,s,name2) name2##_trivial_usage "\0"
# define APPLET_NOFORK(name,main,l,s,name2) name2##_trivial_usage "\0"
#elif defined(MAKE_LINKS) #elif defined(MAKE_LINKS)
# define APPLET(name,l,c) LINK l name # define APPLET(name,l,c) LINK l name
# define APPLET_NOUSAGE(name,main,l,s) LINK l name # define APPLET_NOUSAGE(name,main,l,s) LINK l name
# define APPLET_ODDNAME(name,main,l,s,name2) LINK l name # define APPLET_ODDNAME(name,main,l,s,name2) LINK l name
# define APPLET_NOEXEC(name,main,l,s,name2) LINK l name # define APPLET_NOEXEC(name,main,l,s,name2) LINK l name
# define APPLET_NOFORK(name,main,l,s,name2) LINK l name
#else #else
const struct BB_applet applets[] = { /* name,main,location,need_suid */ const struct BB_applet applets[] = { /* name,main,location,need_suid */
@ -53,6 +57,7 @@ s - suid type:
# define APPLET_NOUSAGE(name,main,l,s) {#name,main##_main,l,s}, # define APPLET_NOUSAGE(name,main,l,s) {#name,main##_main,l,s},
# define APPLET_ODDNAME(name,main,l,s,name2) {#name,main##_main,l,s}, # define APPLET_ODDNAME(name,main,l,s,name2) {#name,main##_main,l,s},
# define APPLET_NOEXEC(name,main,l,s,name2) {#name,main##_main,l,s,1}, # define APPLET_NOEXEC(name,main,l,s,name2) {#name,main##_main,l,s,1},
# define APPLET_NOFORK(name,main,l,s,name2) {#name,main##_main,l,s,1,1},
#endif #endif
#if ENABLE_INSTALL_NO_USR #if ENABLE_INSTALL_NO_USR
@ -118,7 +123,7 @@ USE_DUMPKMAP(APPLET(dumpkmap, _BB_DIR_BIN, _BB_SUID_NEVER))
USE_APP_DUMPLEASES(APPLET(dumpleases, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_APP_DUMPLEASES(APPLET(dumpleases, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
//USE_E2FSCK(APPLET(e2fsck, _BB_DIR_SBIN, _BB_SUID_NEVER)) //USE_E2FSCK(APPLET(e2fsck, _BB_DIR_SBIN, _BB_SUID_NEVER))
//USE_E2LABEL(APPLET_NOUSAGE(e2label, tune2fs, _BB_DIR_SBIN, _BB_SUID_NEVER)) //USE_E2LABEL(APPLET_NOUSAGE(e2label, tune2fs, _BB_DIR_SBIN, _BB_SUID_NEVER))
USE_ECHO(APPLET_NOEXEC(echo, echo, _BB_DIR_BIN, _BB_SUID_NEVER, echo)) USE_ECHO(APPLET_NOFORK(echo, echo, _BB_DIR_BIN, _BB_SUID_NEVER, echo))
USE_ED(APPLET(ed, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_ED(APPLET(ed, _BB_DIR_BIN, _BB_SUID_NEVER))
USE_FEATURE_GREP_EGREP_ALIAS(APPLET_NOUSAGE(egrep, grep, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_FEATURE_GREP_EGREP_ALIAS(APPLET_NOUSAGE(egrep, grep, _BB_DIR_BIN, _BB_SUID_NEVER))
USE_EJECT(APPLET(eject, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_EJECT(APPLET(eject, _BB_DIR_USR_BIN, _BB_SUID_NEVER))

View File

@ -8,9 +8,6 @@
* Licensed under GPLv2 or later, see file LICENSE in this tarball for details. * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/ */
#include <stdio.h>
#include <limits.h>
#include <ctype.h>
#include "libbb.h" #include "libbb.h"
#define WANT_HEX_ESCAPES 1 #define WANT_HEX_ESCAPES 1
@ -46,10 +43,10 @@ char bb_process_escape_sequence(const char **ptr)
#endif #endif
do { do {
d = (unsigned int)(*q - '0'); d = (unsigned char)(*q) - '0';
#ifdef WANT_HEX_ESCAPES #ifdef WANT_HEX_ESCAPES
if (d >= 10) { if (d >= 10) {
d = ((unsigned int)(_tolower(*q) - 'a')) + 10; d = (unsigned char)(_tolower(*q)) - 'a' + 10;
} }
#endif #endif
@ -80,7 +77,7 @@ char bb_process_escape_sequence(const char **ptr)
break; break;
} }
} while (*++p); } while (*++p);
n = *(p+(sizeof(charmap)/2)); n = *(p + (sizeof(charmap)/2));
} }
*ptr = q; *ptr = q;

View File

@ -26,14 +26,16 @@ pid_t spawn(char **argv)
volatile int failed; volatile int failed;
pid_t pid; pid_t pid;
// Be nice to nommu machines. // Ain't it a good place to fflush(NULL)?
/* Be nice to nommu machines. */
failed = 0; failed = 0;
pid = vfork(); pid = vfork();
if (pid < 0) /* error */ if (pid < 0) /* error */
return pid; return pid;
if (!pid) { /* child */ if (!pid) { /* child */
/* Don't use BB_EXECVP tricks here! */ /* This macro is ok - it doesn't do NOEXEC/NOFORK tricks */
execvp(argv[0], argv); BB_EXECVP(argv[0], argv);
/* We are (maybe) sharing a stack with blocked parent, /* We are (maybe) sharing a stack with blocked parent,
* let parent know we failed and then exit to unblock parent * let parent know we failed and then exit to unblock parent