ash: optional printf builtin. +25 bytes if off, +35 if on.
by Cristian Ionescu-Idbohrn.

diff --git a/coreutils/Kbuild b/coreutils/Kbuild
index cb45439..a5a2d4c 100644
--- a/coreutils/Kbuild
+++ b/coreutils/Kbuild
@@ -54,6 +54,7 @@
 lib-$(CONFIG_OD)        += od.o
 lib-$(CONFIG_PRINTENV)  += printenv.o
 lib-$(CONFIG_PRINTF)    += printf.o
+lib-$(CONFIG_ASH_BUILTIN_PRINTF) += printf.o
 lib-$(CONFIG_PWD)       += pwd.o
 lib-$(CONFIG_READLINK)  += readlink.o
 lib-$(CONFIG_REALPATH)  += realpath.o
diff --git a/coreutils/chown.c b/coreutils/chown.c
index eaaefaf..78377e6 100644
--- a/coreutils/chown.c
+++ b/coreutils/chown.c
@@ -61,7 +61,6 @@
 	return FALSE;
 }
 
-int chown_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int chown_main(int argc ATTRIBUTE_UNUSED, char **argv)
 {
 	int retval = EXIT_SUCCESS;
diff --git a/coreutils/printf.c b/coreutils/printf.c
index ebe9615..b775236 100644
--- a/coreutils/printf.c
+++ b/coreutils/printf.c
@@ -193,6 +193,7 @@
 	unsigned direc_length;  /* Length of % directive.  */
 	int field_width;        /* Arg to first '*', or -1 if none.  */
 	int precision;          /* Arg to second '*', or -1 if none.  */
+	char **saved_argv = argv;
 
 	for (; *f; ++f) {
 		switch (*f) {
@@ -264,8 +265,9 @@
 							precision, "");
 			break;
 		case '\\':
-			if (*++f == 'c')
-				exit(EXIT_SUCCESS);
+			if (*++f == 'c') {
+				return saved_argv; /* causes main() to exit */
+			}
 			bb_putchar(bb_process_escape_sequence((const char **)&f));
 			f--;
 			break;
@@ -277,12 +279,22 @@
 	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. printf_main is used from shell.
+	 * Shell must correctly handle 'printf "%s" 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. */