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
No binary (build failed)
—
(log yok)
| @@ -244,7 +244,8 @@ config FEATURE_EXEC_PREFER_APPLETS | |
| help | |
| This is an experimental option which directs applets about to | |
| 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 | |
| string "Path to BusyBox executable" | |
| @@ -20,86 +20,85 @@ | |
| * 1) In handling '\c' escape, the previous version only suppressed the | |
| * trailing newline. SUSv3 specifies _no_ output after '\c'. | |
| * 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" | |
| int bb_echo(char **argv) | |
| { | |
| - | #ifndef CONFIG_FEATURE_FANCY_ECHO |
| + | const char *arg; |
| + | #if !ENABLE_FEATURE_FANCY_ECHO |
| #define eflag '\\' | |
| ++argv; | |
| #else | |
| const char *p; | |
| - | int nflag = 1; |
| - | int eflag = 0; |
| + | char nflag = 1; |
| + | 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 | |
| * that all of the options specified are actually valid. | |
| * Otherwise, the string should just be echoed. | |
| */ | |
| - | |
| - | if (!*(p = *argv + 1)) { /* A single '-', so echo it. */ |
| + | p = arg + 1; |
| + | if (!*p) /* A single '-', so echo it. */ |
| goto just_echo; | |
| - | } |
| do { | |
| - | if (strrchr("neE", *p) == 0) { |
| + | if (!strrchr("neE", *p)) |
| goto just_echo; | |
| - | } |
| } while (*++p); | |
| /* All of the options in this arg are valid, so handle them. */ | |
| - | p = *argv + 1; |
| + | p = arg + 1; |
| do { | |
| - | if (*p == 'n') { |
| + | if (*p == 'n') |
| nflag = 0; | |
| - | } else if (*p == 'e') { |
| + | if (*p == 'e') |
| eflag = '\\'; | |
| - | } else { |
| - | eflag = 0; |
| - | } |
| } while (*++p); | |
| } | |
| - | |
| - | just_echo: |
| + | just_echo: |
| #endif | |
| - | while (*argv) { |
| + | while (1) { |
| + | /* arg is already = *argv and isn't NULL */ |
| int c; | |
| - | while ((c = *(*argv)++)) { |
| + | while ((c = *arg++)) { |
| if (c == eflag) { /* Check for escape seq. */ | |
| - | if (**argv == 'c') { |
| + | if (*arg == 'c') { |
| /* '\c' means cancel newline and | |
| * 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'. */ | |
| - | if (((unsigned int)(**argv - '1')) >= 7) |
| + | if ( (((unsigned char)*arg) - '1') >= 7) |
| #endif | |
| { | |
| /* Since SUSv3 mandates a first digit of 0, 4-digit octals | |
| * of the form \0### are accepted. */ | |
| - | if ((**argv == '0') && (((unsigned int)(argv[0][1] - '0')) < 8)) { |
| - | (*argv)++; |
| + | if (*arg == '0' && ((unsigned char)(arg[1]) - '0') < 8) { |
| + | arg++; |
| } | |
| /* bb_process_escape_sequence can handle nul correctly */ | |
| - | c = bb_process_escape_sequence((const char **) argv); |
| + | c = bb_process_escape_sequence(&arg); |
| } | |
| } | |
| putchar(c); | |
| } | |
| - | if (*++argv) { |
| - | putchar(' '); |
| - | } |
| + | arg = *++argv; |
| + | if (!arg) |
| + | break; |
| + | putchar(' '); |
| } | |
| #ifdef CONFIG_FEATURE_FANCY_ECHO | |
| @@ -109,14 +108,16 @@ just_echo: | |
| #else | |
| putchar('\n'); | |
| #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) | |
| { | |
| - | (void)bb_echo(argv); |
| - | fflush_stdout_and_exit(EXIT_SUCCESS); |
| + | return bb_echo(argv); |
| } | |
| /*- | |
| @@ -242,9 +242,30 @@ ACTF(exec) | |
| for (i = 0; i < ap->exec_argc; i++) | |
| argv[i] = subst(ap->exec_argv[i], ap->subst_count[i], fileName); | |
| 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]); | |
| + | f: |
| for (i = 0; i < ap->exec_argc; i++) | |
| free(argv[i]); | |
| return rc == 0; /* return 1 if success */ | |
| @@ -28,24 +28,28 @@ s - suid type: | |
| # 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_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 | |
| # 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_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_NOFORK(name,main,l,s,name2) name2##_trivial_usage "\n\n" name2##_full_usage "\0" |
| #elif defined(MAKE_USAGE) && !ENABLE_FEATURE_VERBOSE_USAGE | |
| # define APPLET(name,l,s) name##_trivial_usage "\0" | |
| # define APPLET_NOUSAGE(name,main,l,s) "\b\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_NOFORK(name,main,l,s,name2) name2##_trivial_usage "\0" |
| #elif defined(MAKE_LINKS) | |
| # define APPLET(name,l,c) 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_NOEXEC(name,main,l,s,name2) LINK l name | |
| + | # define APPLET_NOFORK(name,main,l,s,name2) LINK l name |
| #else | |
| 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_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_NOFORK(name,main,l,s,name2) {#name,main##_main,l,s,1,1}, |
| #endif | |
| #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_E2FSCK(APPLET(e2fsck, _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_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)) | |
| @@ -8,9 +8,6 @@ | |
| * 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" | |
| #define WANT_HEX_ESCAPES 1 | |
| @@ -46,10 +43,10 @@ char bb_process_escape_sequence(const char **ptr) | |
| #endif | |
| do { | |
| - | d = (unsigned int)(*q - '0'); |
| + | d = (unsigned char)(*q) - '0'; |
| #ifdef WANT_HEX_ESCAPES | |
| if (d >= 10) { | |
| - | d = ((unsigned int)(_tolower(*q) - 'a')) + 10; |
| + | d = (unsigned char)(_tolower(*q)) - 'a' + 10; |
| } | |
| #endif | |
| @@ -80,7 +77,7 @@ char bb_process_escape_sequence(const char **ptr) | |
| break; | |
| } | |
| } while (*++p); | |
| - | n = *(p+(sizeof(charmap)/2)); |
| + | n = *(p + (sizeof(charmap)/2)); |
| } | |
| *ptr = q; | |
| @@ -26,14 +26,16 @@ pid_t spawn(char **argv) | |
| volatile int failed; | |
| pid_t pid; | |
| - | // Be nice to nommu machines. |
| + | // Ain't it a good place to fflush(NULL)? |
| + | |
| + | /* Be nice to nommu machines. */ |
| failed = 0; | |
| pid = vfork(); | |
| if (pid < 0) /* error */ | |
| return pid; | |
| if (!pid) { /* child */ | |
| - | /* Don't use BB_EXECVP tricks here! */ |
| - | execvp(argv[0], argv); |
| + | /* This macro is ok - it doesn't do NOEXEC/NOFORK tricks */ |
| + | BB_EXECVP(argv[0], argv); |
| /* We are (maybe) sharing a stack with blocked parent, | |
| * let parent know we failed and then exit to unblock parent | |