ash: support platforms that don't have '%m' printf specifier

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@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Ron Yorston
2017-07-27 13:53:39 +01:00
committed by Denys Vlasenko
parent 619d9b5e68
commit be366e5afa
2 changed files with 21 additions and 5 deletions

View File

@@ -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 */