[git commit] ash: support platforms that don't have '%m' printf specifier

Denys Vlasenko vda.linux at googlemail.com
Fri Jul 28 13:39:26 UTC 2017


commit: https://git.busybox.net/busybox/commit/?id=be366e5afac1d9f5b3958bd3899a389308d5d9d3
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

The '%m' conversion specifier prints an error message based on the
current value of 'errno'.  It is available in the GNU C library,
Cygwin (since 2012), uClibc and musl.

It is not available in various BSDs, BSD-derived systems (MacOS,
Android) or Microsoft Windows.

Use a symbol defined in platform.h to control how error messages
can be formatted to display the 'errno' message.  On platforms that
support it use '%m'; on other platforms use '%s' and strerror().

On platforms that have '%m' there is essentially no change in the
size of the binary.  Otherwise:

function                                             old     new   delta
redirect                                            1287    1310     +23
xtcsetpgrp                                            27      44     +17
dup2_or_raise                                         34      51     +17
setinputfile                                         267     275      +8
.rodata                                           163379  163371      -8
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 4/1 up/down: 65/-8)              Total: 57 bytes

Signed-off-by: Ron Yorston <rmy at pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 include/platform.h |  4 ++++
 shell/ash.c        | 22 +++++++++++++++++-----
 2 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/include/platform.h b/include/platform.h
index ea49c7e..b81c59d 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -406,6 +406,7 @@ typedef unsigned smalluint;
 #define HAVE_MNTENT_H 1
 #define HAVE_NET_ETHERNET_H 1
 #define HAVE_SYS_STATFS_H 1
+#define HAVE_PRINTF_PERCENTM 1
 
 #if defined(__UCLIBC__)
 # if UCLIBC_VERSION < KERNEL_VERSION(0, 9, 32)
@@ -461,6 +462,7 @@ typedef unsigned smalluint;
 # undef HAVE_DPRINTF
 # undef HAVE_UNLOCKED_STDIO
 # undef HAVE_UNLOCKED_LINE_OPS
+# undef HAVE_PRINTF_PERCENTM
 #endif
 
 #if defined(__dietlibc__)
@@ -483,6 +485,7 @@ typedef unsigned smalluint;
 # undef HAVE_STRVERSCMP
 # undef HAVE_XTABS
 # undef HAVE_UNLOCKED_LINE_OPS
+# undef HAVE_PRINTF_PERCENTM
 # include <osreldate.h>
 # if __FreeBSD_version < 1000029
 #  undef HAVE_STRCHRNUL /* FreeBSD added strchrnul() between 1000028 and 1000029 */
@@ -517,6 +520,7 @@ typedef unsigned smalluint;
 # undef HAVE_STRVERSCMP
 # undef HAVE_UNLOCKED_LINE_OPS
 # undef HAVE_NET_ETHERNET_H
+# undef HAVE_PRINTF_PERCENTM
 #endif
 
 /*
diff --git a/shell/ash.c b/shell/ash.c
index 1f5a8da..f9c78ee 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -1306,6 +1306,18 @@ ash_msg_and_raise_error(const char *msg, ...)
 	va_end(ap);
 }
 
+/*
+ * Use '%m' to append error string on platforms that support it, '%s' and
+ * strerror() on those that don't.
+ *
+ * 'fmt' must be a string literal.
+ */
+#ifdef HAVE_PRINTF_PERCENTM
+#define ash_msg_and_raise_perror(fmt, ...) ash_msg_and_raise_error(fmt ": %m", ##__VA_ARGS__)
+#else
+#define ash_msg_and_raise_perror(fmt, ...) ash_msg_and_raise_error(fmt ": %s", ##__VA_ARGS__, strerror(errno))
+#endif
+
 static void raise_error_syntax(const char *) NORETURN;
 static void
 raise_error_syntax(const char *msg)
@@ -3827,7 +3839,7 @@ static void
 xtcsetpgrp(int fd, pid_t pgrp)
 {
 	if (tcsetpgrp(fd, pgrp))
-		ash_msg_and_raise_error("can't set tty process group (%m)");
+		ash_msg_and_raise_perror("can't set tty process group");
 }
 
 /*
@@ -5313,7 +5325,7 @@ savefd(int from)
 	err = newfd < 0 ? errno : 0;
 	if (err != EBADF) {
 		if (err)
-			ash_msg_and_raise_error("%d: %m", from);
+			ash_msg_and_raise_perror("%d", from);
 		close(from);
 		fcntl(newfd, F_SETFD, FD_CLOEXEC);
 	}
@@ -5328,7 +5340,7 @@ dup2_or_raise(int from, int to)
 	newfd = (from != to) ? dup2(from, to) : to;
 	if (newfd < 0) {
 		/* Happens when source fd is not open: try "echo >&99" */
-		ash_msg_and_raise_error("%d: %m", from);
+		ash_msg_and_raise_perror("%d", from);
 	}
 	return newfd;
 }
@@ -5459,7 +5471,7 @@ redirect(union node *redir, int flags)
 			/* "echo >&10" and 10 is a fd opened to a sh script? */
 			if (is_hidden_fd(sv, right_fd)) {
 				errno = EBADF; /* as if it is closed */
-				ash_msg_and_raise_error("%d: %m", right_fd);
+				ash_msg_and_raise_perror("%d", right_fd);
 			}
 			newfd = -1;
 		} else {
@@ -5493,7 +5505,7 @@ redirect(union node *redir, int flags)
 					if (newfd >= 0)
 						close(newfd);
 					errno = i;
-					ash_msg_and_raise_error("%d: %m", fd);
+					ash_msg_and_raise_perror("%d", fd);
 					/* NOTREACHED */
 				}
 				/* EBADF: it is not open - good, remember to close it */


More information about the busybox-cvs mailing list