busybox/util-linux/rdate.c
James Byrne 6937487be7 libbb: reduce the overhead of single parameter bb_error_msg() calls
Back in 2007, commit 0c97c9d437 ("'simple' error message functions by
Loic Grenie") introduced bb_simple_perror_msg() to allow for a lower
overhead call to bb_perror_msg() when only a string was being printed
with no parameters. This saves space for some CPU architectures because
it avoids the overhead of a call to a variadic function. However there
has never been a simple version of bb_error_msg(), and since 2007 many
new calls to bb_perror_msg() have been added that only take a single
parameter and so could have been using bb_simple_perror_message().

This changeset introduces 'simple' versions of bb_info_msg(),
bb_error_msg(), bb_error_msg_and_die(), bb_herror_msg() and
bb_herror_msg_and_die(), and replaces all calls that only take a
single parameter, or use something like ("%s", arg), with calls to the
corresponding 'simple' version.

Since it is likely that single parameter calls to the variadic functions
may be accidentally reintroduced in the future a new debugging config
option WARN_SIMPLE_MSG has been introduced. This uses some macro magic
which will cause any such calls to generate a warning, but this is
turned off by default to avoid use of the unpleasant macros in normal
circumstances.

This is a large changeset due to the number of calls that have been
replaced. The only files that contain changes other than simple
substitution of function calls are libbb.h, libbb/herror_msg.c,
libbb/verror_msg.c and libbb/xfuncs_printf.c. In miscutils/devfsd.c,
networking/udhcp/common.h and util-linux/mdev.c additonal macros have
been added for logging so that single parameter and multiple parameter
logging variants exist.

The amount of space saved varies considerably by architecture, and was
found to be as follows (for 'defconfig' using GCC 7.4):

Arm:     -92 bytes
MIPS:    -52 bytes
PPC:   -1836 bytes
x86_64: -938 bytes

Note that for the MIPS architecture only an exception had to be made
disabling the 'simple' calls for 'udhcp' (in networking/udhcp/common.h)
because it made these files larger on MIPS.

Signed-off-by: James Byrne <james.byrne@origamienergy.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2019-07-02 11:35:03 +02:00

108 lines
3.1 KiB
C

/* vi: set sw=4 ts=4: */
/*
* The Rdate command will ask a time server for the RFC 868 time
* and optionally set the system time.
*
* by Sterling Huxley <sterling@europa.com>
*
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
*/
//config:config RDATE
//config: bool "rdate (5.6 kb)"
//config: default y
//config: help
//config: The rdate utility allows you to synchronize the date and time of your
//config: system clock with the date and time of a remote networked system using
//config: the RFC868 protocol, which is built into the inetd daemon on most
//config: systems.
//applet:IF_RDATE(APPLET(rdate, BB_DIR_USR_SBIN, BB_SUID_DROP))
//kbuild:lib-$(CONFIG_RDATE) += rdate.o
//usage:#define rdate_trivial_usage
//usage: "[-s/-p] HOST"
//usage:#define rdate_full_usage "\n\n"
//usage: "Set and print time from HOST using RFC 868\n"
//usage: "\n -s Only set system time"
//usage: "\n -p Only print time"
#include "libbb.h"
enum { RFC_868_BIAS = 2208988800UL };
static void socket_timeout(int sig UNUSED_PARAM)
{
bb_simple_error_msg_and_die("timeout connecting to time server");
}
static time_t askremotedate(const char *host)
{
uint32_t nett;
int fd;
/* Timeout for dead or inaccessible servers */
alarm(10);
signal(SIGALRM, socket_timeout);
fd = create_and_connect_stream_or_die(host, bb_lookup_std_port("time", "tcp", 37));
if (safe_read(fd, &nett, 4) != 4) /* read time from server */
bb_error_msg_and_die("%s: %s", host, "short read");
if (ENABLE_FEATURE_CLEAN_UP)
close(fd);
/* Convert from network byte order to local byte order.
* RFC 868 time is seconds since 1900-01-01 00:00 GMT.
* RFC 868 time 2,208,988,800 corresponds to 1970-01-01 00:00 GMT.
* Subtract the RFC 868 time to get Linux epoch.
*/
nett = ntohl(nett) - RFC_868_BIAS;
if (sizeof(time_t) > 4) {
/* Now we have 32-bit lsb of a wider time_t
* Imagine that nett = 0x00000001,
* current time cur = 0x123ffffffff.
* Assuming our time is not some 40 years off,
* remote time must be 0x12400000001.
* Need to adjust our time by (int32_t)(nett - cur).
*/
time_t cur = time(NULL);
int32_t adjust = (int32_t)(nett - (uint32_t)cur);
return cur + adjust;
}
/* This is not going to work, but what can we do */
return (time_t)nett;
}
int rdate_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int rdate_main(int argc UNUSED_PARAM, char **argv)
{
time_t remote_time;
unsigned flags;
flags = getopt32(argv, "^" "sp" "\0" "-1");
remote_time = askremotedate(argv[optind]);
/* Manpages of various Unixes are confusing. What happens is:
* (no opts) set and print time
* -s: set time ("do not print the time")
* -p: print time ("do not set, just print the remote time")
* -sp: print time (that's what we do, not sure this is right)
*/
if (!(flags & 2)) { /* no -p (-s may be present) */
if (time(NULL) == remote_time)
bb_simple_error_msg("current time matches remote time");
else
if (stime(&remote_time) < 0)
bb_simple_perror_msg_and_die("can't set time of day");
}
if (flags != 1) /* not lone -s */
printf("%s", ctime(&remote_time));
return EXIT_SUCCESS;
}