Index: shell/ash.c =================================================================== --- shell/ash.c (revision 22011) +++ shell/ash.c (working copy) @@ -8488,17 +8488,18 @@ * Apart from the above, [[ expr ]] should work as [ expr ] */ -#define testcmd test_main -#define echocmd echo_main +#define echocmd echo_main +#define printfcmd printf_main +#define testcmd test_main /* Keep these in proper order since it is searched via bsearch() */ static const struct builtincmd builtintab[] = { { BUILTIN_SPEC_REG ".", dotcmd }, { BUILTIN_SPEC_REG ":", truecmd }, #if ENABLE_ASH_BUILTIN_TEST - { BUILTIN_REGULAR "[", testcmd }, + { BUILTIN_REGULAR "[", testcmd }, #if ENABLE_ASH_BASH_COMPAT - { BUILTIN_REGULAR "[[", testcmd }, + { BUILTIN_REGULAR "[[", testcmd }, #endif #endif #if ENABLE_ASH_ALIAS @@ -8540,6 +8541,9 @@ { BUILTIN_NOSPEC "let", letcmd }, #endif { BUILTIN_ASSIGN "local", localcmd }, +#if ENABLE_ASH_BUILTIN_PRINTF + { BUILTIN_REGULAR "printf", printfcmd }, +#endif { BUILTIN_NOSPEC "pwd", pwdcmd }, { BUILTIN_REGULAR "read", readcmd }, { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd }, @@ -8548,7 +8552,7 @@ { BUILTIN_SPEC_REG "shift", shiftcmd }, { BUILTIN_SPEC_REG "source", dotcmd }, #if ENABLE_ASH_BUILTIN_TEST - { BUILTIN_REGULAR "test", testcmd }, + { BUILTIN_REGULAR "test", testcmd }, #endif { BUILTIN_SPEC_REG "times", timescmd }, { BUILTIN_SPEC_REG "trap", trapcmd }, Index: shell/Config.in =================================================================== --- shell/Config.in (revision 22001) +++ shell/Config.in (working copy) @@ -114,6 +114,13 @@ help Enable support for echo, builtin to ash. +config ASH_BUILTIN_PRINTF + bool "Builtin version of 'printf'" + default y + depends on ASH + help + Enable support for printf, builtin to ash. + config ASH_BUILTIN_TEST bool "Builtin version of 'test'" default y Index: coreutils/printf.c =================================================================== --- coreutils/printf.c (revision 22165) +++ coreutils/printf.c (working copy) @@ -264,8 +264,11 @@ precision, ""); break; case '\\': - if (*++f == 'c') - exit(EXIT_SUCCESS); + if (*++f == 'c') { + while (*argv) + argv++; + goto nomore; + } bb_putchar(bb_process_escape_sequence((const char **)&f)); f--; break; @@ -273,16 +276,26 @@ bb_putchar(*f); } } - + nomore: return argv; } -int printf_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int printf_main(int argc ATTRIBUTE_UNUSED, char **argv) { char *format; char **argv2; + /* We must check that stdout is not closed. + * The reason for this is highly non-obvious. + * echo_main is used from shell. Shell must correctly handle "echo foo" + * if stdout is closed. With stdio, output gets shoveled into + * stdout buffer, and even fflush cannot clear it out. It seems that + * even if libc receives EBADF on write attempts, it feels determined + * to output data no matter what. So it will try later, + * and possibly will clobber future output. Not good. */ + if (dup2(1, 1) != 1) + return -1; + /* bash builtin errors out on "printf '-%s-\n' foo", * coreutils-6.9 works. Both work with "printf -- '-%s-\n' foo". * We will mimic coreutils. */ Index: include/applets.h =================================================================== --- include/applets.h (revision 22084) +++ include/applets.h (working copy) @@ -275,7 +275,7 @@ USE_PKILL(APPLET_ODDNAME(pkill, pgrep, _BB_DIR_USR_BIN, _BB_SUID_NEVER, pkill)) USE_HALT(APPLET_ODDNAME(poweroff, halt, _BB_DIR_SBIN, _BB_SUID_NEVER, poweroff)) USE_PRINTENV(APPLET(printenv, _BB_DIR_BIN, _BB_SUID_NEVER)) -USE_PRINTF(APPLET(printf, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) +USE_PRINTF(APPLET_NOFORK(printf, printf, _BB_DIR_USR_BIN, _BB_SUID_NEVER, printf)) USE_PS(APPLET(ps, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_PSCAN(APPLET(pscan, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_PWD(APPLET_NOFORK(pwd, pwd, _BB_DIR_BIN, _BB_SUID_NEVER, pwd)) Index: include/libbb.h =================================================================== --- include/libbb.h (revision 22110) +++ include/libbb.h (working copy) @@ -882,6 +882,7 @@ int bb_cat(char** argv); /* If shell needs them, these three "exist" even if not enabled as applets */ int echo_main(int argc, char** argv) USE_ECHO(MAIN_EXTERNALLY_VISIBLE); +int printf_main(int argc, char **argv) USE_PRINTF(MAIN_EXTERNALLY_VISIBLE); int test_main(int argc, char **argv) USE_TEST(MAIN_EXTERNALLY_VISIBLE); int kill_main(int argc, char **argv) USE_KILL(MAIN_EXTERNALLY_VISIBLE); int chown_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;