hwclock: size optimizations

libbb/time.c: new file, introducing monotonic_us()
pscan, traceroute, arping: use it instead of gettimeofday
ping, zcip: TODO

function                                             old     new   delta
monotonic_us                                           -      89     +89
find_pair                                            164     180     +16
.rodata                                           129747  129763     +16
refresh                                             1144    1152      +8
............
timeout                                                8       4      -4
static.start                                           8       4      -4
last                                                   8       4      -4
parse_conf                                          1303    1284     -19
time_main                                           1149    1124     -25
gettimeofday_us                                       39       -     -39
arping_main                                         2042    1969     -73
hwclock_main                                         594     501     -93
catcher                                              485     380    -105
traceroute_main                                     4300    4117    -183
------------------------------------------------------------------------------
(add/remove: 2/1 grow/shrink: 8/11 up/down: 157/-562)        Total: -405 bytes
This commit is contained in:
Denis Vlasenko 2007-06-17 19:09:05 +00:00
parent e79dd06782
commit 459be35234
10 changed files with 228 additions and 260 deletions

View File

@ -200,6 +200,7 @@ struct sysinfo {
}; };
int sysinfo(struct sysinfo* info); int sysinfo(struct sysinfo* info);
unsigned long long monotonic_us(void);
extern void chomp(char *s); extern void chomp(char *s);
extern void trim(char *s); extern void trim(char *s);

View File

@ -95,4 +95,14 @@ config FEATURE_EDITING_FANCY_PROMPT
Setting this option allows for prompts to use things like \w and Setting this option allows for prompts to use things like \w and
\$ and escape codes. \$ and escape codes.
config MONOTONIC_SYSCALL
bool "Use clock_gettime(CLOCK_MONOTONIC) syscall"
default y
help
Use clock_gettime(CLOCK_MONOTONIC) syscall for measuring
time intervals (time, ping, traceroute etc need this).
Probably requires Linux 2.6+. If not selected, gettimeofday
will be used instead (which gives wrong results if date/time
is reset).
endmenu endmenu

View File

@ -78,6 +78,7 @@ lib-y += simplify_path.o
lib-y += skip_whitespace.o lib-y += skip_whitespace.o
lib-y += speed_table.o lib-y += speed_table.o
lib-y += str_tolower.o lib-y += str_tolower.o
lib-y += time.o
lib-y += trim.o lib-y += trim.o
lib-y += u_signal_names.o lib-y += u_signal_names.o
lib-y += udp_io.o lib-y += udp_io.o

32
libbb/time.c Normal file
View File

@ -0,0 +1,32 @@
/* vi: set sw=4 ts=4: */
/*
* Utility routines.
*
* Copyright (C) 2007 Denis Vlasenko
*
* Licensed under GPL version 2, see file LICENSE in this tarball for details.
*/
#include "libbb.h"
#if ENABLE_MONOTONIC_SYSCALL
#include <sys/syscall.h>
/* libc has incredibly messy way of doing this,
* typically requiring -lrt. We just skip all this mess */
unsigned long long monotonic_us(void)
{
struct timespec ts;
if (syscall(__NR_clock_gettime, CLOCK_MONOTONIC, &ts))
bb_error_msg_and_die("clock_gettime(MONOTONIC) failed");
return ts.tv_sec * 1000000ULL + ts.tv_nsec/1000;
}
#else
unsigned long long monotonic_us(void)
{
struct timeval tv;
if (gettimeofday(&tv, NULL))
bb_error_msg_and_die("gettimeofday failed");
return tv.tv_sec * 1000000ULL + tv_usec;
}
#endif

View File

@ -11,28 +11,16 @@
#include "libbb.h" #include "libbb.h"
#define TV_MSEC tv_usec / 1000
/* Information on the resources used by a child process. */ /* Information on the resources used by a child process. */
typedef struct { typedef struct {
int waitstatus; int waitstatus;
struct rusage ru; struct rusage ru;
struct timeval start, elapsed; /* Wallclock time of process. */ unsigned elapsed_ms; /* Wallclock time of process. */
} resource_t; } resource_t;
/* msec = milliseconds = 1/1,000 (1*10e-3) second. /* msec = milliseconds = 1/1,000 (1*10e-3) second.
usec = microseconds = 1/1,000,000 (1*10e-6) second. */ usec = microseconds = 1/1,000,000 (1*10e-6) second. */
#ifndef TICKS_PER_SEC
#define TICKS_PER_SEC 100
#endif
/* The number of milliseconds in one `tick' used by the `rusage' structure. */
#define MSEC_PER_TICK (1000 / TICKS_PER_SEC)
/* Return the number of clock ticks that occur in M milliseconds. */
#define MSEC_TO_TICKS(m) ((m) / MSEC_PER_TICK)
#define UL unsigned long #define UL unsigned long
static const char default_format[] = "real\t%E\nuser\t%u\nsys\t%T"; static const char default_format[] = "real\t%E\nuser\t%u\nsys\t%T";
@ -76,7 +64,6 @@ static const char long_format[] =
static int resuse_end(pid_t pid, resource_t * resp) static int resuse_end(pid_t pid, resource_t * resp)
{ {
int status; int status;
pid_t caught; pid_t caught;
/* Ignore signals, but don't ignore the children. When wait3 /* Ignore signals, but don't ignore the children. When wait3
@ -85,18 +72,8 @@ static int resuse_end(pid_t pid, resource_t * resp)
if (caught == -1) if (caught == -1)
return 0; return 0;
} }
resp->elapsed_ms = (monotonic_us() / 1000) - resp->elapsed_ms;
gettimeofday(&resp->elapsed, (struct timezone *) 0);
resp->elapsed.tv_sec -= resp->start.tv_sec;
if (resp->elapsed.tv_usec < resp->start.tv_usec) {
/* Manually carry a one from the seconds field. */
resp->elapsed.tv_usec += 1000000;
--resp->elapsed.tv_sec;
}
resp->elapsed.tv_usec -= resp->start.tv_usec;
resp->waitstatus = status; resp->waitstatus = status;
return 1; return 1;
} }
@ -181,30 +158,30 @@ static unsigned long ptok(unsigned long pages)
COMMAND is the command and args that are being summarized. COMMAND is the command and args that are being summarized.
RESP is resource information on the command. */ RESP is resource information on the command. */
#ifndef TICKS_PER_SEC
#define TICKS_PER_SEC 100
#endif
static void summarize(const char *fmt, char **command, resource_t * resp) static void summarize(const char *fmt, char **command, resource_t * resp)
{ {
unsigned long r; /* Elapsed real milliseconds. */ unsigned vv_ms; /* Elapsed virtual (CPU) milliseconds */
unsigned long v; /* Elapsed virtual (CPU) milliseconds. */ unsigned cpu_ticks; /* Same, in "CPU ticks" */
if (WIFSTOPPED(resp->waitstatus)) if (WIFSTOPPED(resp->waitstatus))
printf("Command stopped by signal %d\n", printf("Command stopped by signal %u\n",
WSTOPSIG(resp->waitstatus)); WSTOPSIG(resp->waitstatus));
else if (WIFSIGNALED(resp->waitstatus)) else if (WIFSIGNALED(resp->waitstatus))
printf("Command terminated by signal %d\n", printf("Command terminated by signal %u\n",
WTERMSIG(resp->waitstatus)); WTERMSIG(resp->waitstatus));
else if (WIFEXITED(resp->waitstatus) && WEXITSTATUS(resp->waitstatus)) else if (WIFEXITED(resp->waitstatus) && WEXITSTATUS(resp->waitstatus))
printf("Command exited with non-zero status %d\n", printf("Command exited with non-zero status %u\n",
WEXITSTATUS(resp->waitstatus)); WEXITSTATUS(resp->waitstatus));
/* Convert all times to milliseconds. Occasionally, one of these values vv_ms = (resp->ru.ru_utime.tv_sec + resp->ru.ru_stime.tv_sec) * 1000
comes out as zero. Dividing by zero causes problems, so we first + (resp->ru.ru_utime.tv_usec + resp->ru.ru_stime.tv_usec) / 1000;
check the time value. If it is zero, then we take `evasive action'
instead of calculating a value. */
r = resp->elapsed.tv_sec * 1000 + resp->elapsed.tv_usec / 1000; cpu_ticks = vv_ms * TICKS_PER_SEC / 1000;
if (!cpu_ticks) cpu_ticks = 1; /* we divide by it, must be nonzero */
v = resp->ru.ru_utime.tv_sec * 1000 + resp->ru.ru_utime.TV_MSEC +
resp->ru.ru_stime.tv_sec * 1000 + resp->ru.ru_stime.TV_MSEC;
/* putchar() != putc(stdout) in glibc! */ /* putchar() != putc(stdout) in glibc! */
@ -245,127 +222,122 @@ static void summarize(const char *fmt, char **command, resource_t * resp)
break; break;
case 'D': /* Average unshared data size. */ case 'D': /* Average unshared data size. */
printf("%lu", printf("%lu",
MSEC_TO_TICKS(v) == 0 ? 0 : ptok((UL) resp->ru.ru_idrss) / cpu_ticks +
ptok((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS(v) + ptok((UL) resp->ru.ru_isrss) / cpu_ticks);
ptok((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS(v));
break; break;
case 'E': /* Elapsed real (wall clock) time. */ case 'E': { /* Elapsed real (wall clock) time. */
if (resp->elapsed.tv_sec >= 3600) /* One hour -> h:m:s. */ unsigned seconds = resp->elapsed_ms / 1000;
printf("%ldh %ldm %02lds", if (seconds >= 3600) /* One hour -> h:m:s. */
resp->elapsed.tv_sec / 3600, printf("%uh %um %02us",
(resp->elapsed.tv_sec % 3600) / 60, seconds / 3600,
resp->elapsed.tv_sec % 60); (seconds % 3600) / 60,
seconds % 60);
else else
printf("%ldm %ld.%02lds", /* -> m:s. */ printf("%um %u.%02us", /* -> m:s. */
resp->elapsed.tv_sec / 60, seconds / 60,
resp->elapsed.tv_sec % 60, seconds % 60,
resp->elapsed.tv_usec / 10000); (unsigned)(resp->elapsed_ms / 10) % 100);
break; break;
}
case 'F': /* Major page faults. */ case 'F': /* Major page faults. */
printf("%ld", resp->ru.ru_majflt); printf("%lu", resp->ru.ru_majflt);
break; break;
case 'I': /* Inputs. */ case 'I': /* Inputs. */
printf("%ld", resp->ru.ru_inblock); printf("%lu", resp->ru.ru_inblock);
break; break;
case 'K': /* Average mem usage == data+stack+text. */ case 'K': /* Average mem usage == data+stack+text. */
printf("%lu", printf("%lu",
MSEC_TO_TICKS(v) == 0 ? 0 : ptok((UL) resp->ru.ru_idrss) / cpu_ticks +
ptok((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS(v) + ptok((UL) resp->ru.ru_isrss) / cpu_ticks +
ptok((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS(v) + ptok((UL) resp->ru.ru_ixrss) / cpu_ticks);
ptok((UL) resp->ru.ru_ixrss) / MSEC_TO_TICKS(v));
break; break;
case 'M': /* Maximum resident set size. */ case 'M': /* Maximum resident set size. */
printf("%lu", ptok((UL) resp->ru.ru_maxrss)); printf("%lu", ptok((UL) resp->ru.ru_maxrss));
break; break;
case 'O': /* Outputs. */ case 'O': /* Outputs. */
printf("%ld", resp->ru.ru_oublock); printf("%lu", resp->ru.ru_oublock);
break; break;
case 'P': /* Percent of CPU this job got. */ case 'P': /* Percent of CPU this job got. */
/* % cpu is (total cpu time)/(elapsed time). */ /* % cpu is (total cpu time)/(elapsed time). */
if (r > 0) if (resp->elapsed_ms > 0)
printf("%lu%%", (v * 100 / r)); printf("%u%%", (unsigned)(vv_ms * 100 / resp->elapsed_ms));
else else
printf("?%%"); printf("?%%");
break; break;
case 'R': /* Minor page faults (reclaims). */ case 'R': /* Minor page faults (reclaims). */
printf("%ld", resp->ru.ru_minflt); printf("%lu", resp->ru.ru_minflt);
break; break;
case 'S': /* System time. */ case 'S': /* System time. */
printf("%ld.%02ld", printf("%u.%02u",
resp->ru.ru_stime.tv_sec, (unsigned)resp->ru.ru_stime.tv_sec,
resp->ru.ru_stime.TV_MSEC / 10); (unsigned)(resp->ru.ru_stime.tv_usec / 10000));
break; break;
case 'T': /* System time. */ case 'T': /* System time. */
if (resp->ru.ru_stime.tv_sec >= 3600) /* One hour -> h:m:s. */ if (resp->ru.ru_stime.tv_sec >= 3600) /* One hour -> h:m:s. */
printf("%ldh %ldm %02lds", printf("%uh %um %02us",
resp->ru.ru_stime.tv_sec / 3600, (unsigned)(resp->ru.ru_stime.tv_sec / 3600),
(resp->ru.ru_stime.tv_sec % 3600) / 60, (unsigned)(resp->ru.ru_stime.tv_sec % 3600) / 60,
resp->ru.ru_stime.tv_sec % 60); (unsigned)(resp->ru.ru_stime.tv_sec % 60));
else else
printf("%ldm %ld.%02lds", /* -> m:s. */ printf("%um %u.%02us", /* -> m:s. */
resp->ru.ru_stime.tv_sec / 60, (unsigned)(resp->ru.ru_stime.tv_sec / 60),
resp->ru.ru_stime.tv_sec % 60, (unsigned)(resp->ru.ru_stime.tv_sec % 60),
resp->ru.ru_stime.tv_usec / 10000); (unsigned)(resp->ru.ru_stime.tv_usec / 10000));
break; break;
case 'U': /* User time. */ case 'U': /* User time. */
printf("%ld.%02ld", printf("%u.%02u",
resp->ru.ru_utime.tv_sec, (unsigned)resp->ru.ru_utime.tv_sec,
resp->ru.ru_utime.TV_MSEC / 10); (unsigned)(resp->ru.ru_utime.tv_usec / 10000));
break; break;
case 'u': /* User time. */ case 'u': /* User time. */
if (resp->ru.ru_utime.tv_sec >= 3600) /* One hour -> h:m:s. */ if (resp->ru.ru_utime.tv_sec >= 3600) /* One hour -> h:m:s. */
printf("%ldh %ldm %02lds", printf("%uh %um %02us",
resp->ru.ru_utime.tv_sec / 3600, (unsigned)(resp->ru.ru_utime.tv_sec / 3600),
(resp->ru.ru_utime.tv_sec % 3600) / 60, (unsigned)(resp->ru.ru_utime.tv_sec % 3600) / 60,
resp->ru.ru_utime.tv_sec % 60); (unsigned)(resp->ru.ru_utime.tv_sec % 60));
else else
printf("%ldm %ld.%02lds", /* -> m:s. */ printf("%um %u.%02us", /* -> m:s. */
resp->ru.ru_utime.tv_sec / 60, (unsigned)(resp->ru.ru_utime.tv_sec / 60),
resp->ru.ru_utime.tv_sec % 60, (unsigned)(resp->ru.ru_utime.tv_sec % 60),
resp->ru.ru_utime.tv_usec / 10000); (unsigned)(resp->ru.ru_utime.tv_usec / 10000));
break; break;
case 'W': /* Times swapped out. */ case 'W': /* Times swapped out. */
printf("%ld", resp->ru.ru_nswap); printf("%lu", resp->ru.ru_nswap);
break; break;
case 'X': /* Average shared text size. */ case 'X': /* Average shared text size. */
printf("%lu", printf("%lu", ptok((UL) resp->ru.ru_ixrss) / cpu_ticks);
MSEC_TO_TICKS(v) == 0 ? 0 :
ptok((UL) resp->ru.ru_ixrss) / MSEC_TO_TICKS(v));
break; break;
case 'Z': /* Page size. */ case 'Z': /* Page size. */
printf("%d", getpagesize()); printf("%u", getpagesize());
break; break;
case 'c': /* Involuntary context switches. */ case 'c': /* Involuntary context switches. */
printf("%ld", resp->ru.ru_nivcsw); printf("%lu", resp->ru.ru_nivcsw);
break; break;
case 'e': /* Elapsed real time in seconds. */ case 'e': /* Elapsed real time in seconds. */
printf("%ld.%02ld", printf("%u.%02u",
resp->elapsed.tv_sec, resp->elapsed.tv_usec / 10000); (unsigned)resp->elapsed_ms / 1000,
(unsigned)(resp->elapsed_ms / 10) % 100);
break; break;
case 'k': /* Signals delivered. */ case 'k': /* Signals delivered. */
printf("%ld", resp->ru.ru_nsignals); printf("%lu", resp->ru.ru_nsignals);
break; break;
case 'p': /* Average stack segment. */ case 'p': /* Average stack segment. */
printf("%lu", printf("%lu", ptok((UL) resp->ru.ru_isrss) / cpu_ticks);
MSEC_TO_TICKS(v) == 0 ? 0 :
ptok((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS(v));
break; break;
case 'r': /* Incoming socket messages received. */ case 'r': /* Incoming socket messages received. */
printf("%ld", resp->ru.ru_msgrcv); printf("%lu", resp->ru.ru_msgrcv);
break; break;
case 's': /* Outgoing socket messages sent. */ case 's': /* Outgoing socket messages sent. */
printf("%ld", resp->ru.ru_msgsnd); printf("%lu", resp->ru.ru_msgsnd);
break; break;
case 't': /* Average resident set size. */ case 't': /* Average resident set size. */
printf("%lu", printf("%lu", ptok((UL) resp->ru.ru_idrss) / cpu_ticks);
MSEC_TO_TICKS(v) == 0 ? 0 :
ptok((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS(v));
break; break;
case 'w': /* Voluntary context switches. */ case 'w': /* Voluntary context switches. */
printf("%ld", resp->ru.ru_nvcsw); printf("%lu", resp->ru.ru_nvcsw);
break; break;
case 'x': /* Exit status. */ case 'x': /* Exit status. */
printf("%d", WEXITSTATUS(resp->waitstatus)); printf("%u", WEXITSTATUS(resp->waitstatus));
break; break;
} }
break; break;
@ -403,7 +375,7 @@ static void run_command(char *const *cmd, resource_t * resp)
pid_t pid; /* Pid of child. */ pid_t pid; /* Pid of child. */
__sighandler_t interrupt_signal, quit_signal; __sighandler_t interrupt_signal, quit_signal;
gettimeofday(&resp->start, (struct timezone *) 0); resp->elapsed_ms = monotonic_us() / 1000;
pid = vfork(); /* Run CMD as child process. */ pid = vfork(); /* Run CMD as child process. */
if (pid < 0) if (pid < 0)
bb_error_msg_and_die("cannot fork"); bb_error_msg_and_die("cannot fork");

View File

@ -8,9 +8,6 @@
* Busybox port: Nick Fedchik <nick@fedchik.org.ua> * Busybox port: Nick Fedchik <nick@fedchik.org.ua>
*/ */
//#include <sys/ioctl.h>
//#include <signal.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <net/if.h> #include <net/if.h>
#include <netinet/ether.h> #include <netinet/ether.h>
@ -18,42 +15,42 @@
#include "libbb.h" #include "libbb.h"
/* We don't expect to see 1000+ seconds delay, unsigned is enough */
#define MONOTONIC_US() ((unsigned)monotonic_us())
static struct in_addr src; static struct in_addr src;
static struct in_addr dst; static struct in_addr dst;
static struct sockaddr_ll me; static struct sockaddr_ll me;
static struct sockaddr_ll he; static struct sockaddr_ll he;
static struct timeval last; static unsigned last;
enum cfg_e { enum {
dad = 1, DAD = 1,
unsolicited = 2, UNSOLICITED = 2,
advert = 4, ADVERT = 4,
quiet = 8, QUIET = 8,
quit_on_reply = 16, QUIT_ON_REPLY = 16,
broadcast_only = 32, BCAST_ONLY = 32,
unicasting = 64 UNICASTING = 64
}; };
static int cfg; static int cfg;
static int s; static int s;
static unsigned count = UINT_MAX; static unsigned count = UINT_MAX;
static unsigned timeout; static unsigned timeout_us;
static int sent; static int sent;
static int brd_sent; static int brd_sent;
static int received; static int received;
static int brd_recv; static int brd_recv;
static int req_recv; static int req_recv;
#define MS_TDIFF(tv1,tv2) ( ((tv1).tv_sec-(tv2).tv_sec)*1000 + \
((tv1).tv_usec-(tv2).tv_usec)/1000 )
static int send_pack(int sock, struct in_addr *src_addr, static int send_pack(int sock, struct in_addr *src_addr,
struct in_addr *dst_addr, struct sockaddr_ll *ME, struct in_addr *dst_addr, struct sockaddr_ll *ME,
struct sockaddr_ll *HE) struct sockaddr_ll *HE)
{ {
int err; int err;
struct timeval now; unsigned now;
RESERVE_CONFIG_UBUFFER(buf, 256); unsigned char buf[256];
struct arphdr *ah = (struct arphdr *) buf; struct arphdr *ah = (struct arphdr *) buf;
unsigned char *p = (unsigned char *) (ah + 1); unsigned char *p = (unsigned char *) (ah + 1);
@ -62,7 +59,7 @@ static int send_pack(int sock, struct in_addr *src_addr,
ah->ar_pro = htons(ETH_P_IP); ah->ar_pro = htons(ETH_P_IP);
ah->ar_hln = ME->sll_halen; ah->ar_hln = ME->sll_halen;
ah->ar_pln = 4; ah->ar_pln = 4;
ah->ar_op = cfg & advert ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST); ah->ar_op = cfg & ADVERT ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST);
memcpy(p, &ME->sll_addr, ah->ar_hln); memcpy(p, &ME->sll_addr, ah->ar_hln);
p += ME->sll_halen; p += ME->sll_halen;
@ -70,7 +67,7 @@ static int send_pack(int sock, struct in_addr *src_addr,
memcpy(p, src_addr, 4); memcpy(p, src_addr, 4);
p += 4; p += 4;
if (cfg & advert) if (cfg & ADVERT)
memcpy(p, &ME->sll_addr, ah->ar_hln); memcpy(p, &ME->sll_addr, ah->ar_hln);
else else
memcpy(p, &HE->sll_addr, ah->ar_hln); memcpy(p, &HE->sll_addr, ah->ar_hln);
@ -79,21 +76,21 @@ static int send_pack(int sock, struct in_addr *src_addr,
memcpy(p, dst_addr, 4); memcpy(p, dst_addr, 4);
p += 4; p += 4;
gettimeofday(&now, NULL); now = MONOTONIC_US();
err = sendto(sock, buf, p - buf, 0, (struct sockaddr *) HE, sizeof(*HE)); err = sendto(sock, buf, p - buf, 0, (struct sockaddr *) HE, sizeof(*HE));
if (err == p - buf) { if (err == p - buf) {
last = now; last = now;
sent++; sent++;
if (!(cfg & unicasting)) if (!(cfg & UNICASTING))
brd_sent++; brd_sent++;
} }
RELEASE_CONFIG_BUFFER(buf);
return err; return err;
} }
static void finish(void) ATTRIBUTE_NORETURN;
static void finish(void) static void finish(void)
{ {
if (!(cfg & quiet)) { if (!(cfg & QUIET)) {
printf("Sent %d probe(s) (%d broadcast(s))\n" printf("Sent %d probe(s) (%d broadcast(s))\n"
"Received %d repl%s" "Received %d repl%s"
" (%d request(s), %d broadcast(s))\n", " (%d request(s), %d broadcast(s))\n",
@ -101,30 +98,31 @@ static void finish(void)
received, (received == 1) ? "ies" : "y", received, (received == 1) ? "ies" : "y",
req_recv, brd_recv); req_recv, brd_recv);
} }
if (cfg & dad) if (cfg & DAD)
exit(!!received); exit(!!received);
if (cfg & unsolicited) if (cfg & UNSOLICITED)
exit(0); exit(0);
exit(!received); exit(!received);
} }
static void catcher(void) static void catcher(void)
{ {
struct timeval tv; static unsigned start;
static struct timeval start;
gettimeofday(&tv, NULL); unsigned now;
if (start.tv_sec == 0) now = MONOTONIC_US();
start = tv; if (start == 0)
start = now;
if (count-- == 0 if (count == 0 || (timeout_us && (now - start) > (timeout_us + 500000)))
|| (timeout && MS_TDIFF(tv, start) > timeout * 1000 + 500))
finish(); finish();
if (last.tv_sec == 0 || MS_TDIFF(tv, last) > 500) { count--;
if (last == 0 || (now - last) > 500000) {
send_pack(s, &src, &dst, &me, &he); send_pack(s, &src, &dst, &me, &he);
if (count == 0 && (cfg & unsolicited)) if (count == 0 && (cfg & UNSOLICITED))
finish(); finish();
} }
alarm(1); alarm(1);
@ -162,7 +160,7 @@ static int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
return 0; return 0;
memcpy(&src_ip, p + ah->ar_hln, 4); memcpy(&src_ip, p + ah->ar_hln, 4);
memcpy(&dst_ip, p + ah->ar_hln + 4 + ah->ar_hln, 4); memcpy(&dst_ip, p + ah->ar_hln + 4 + ah->ar_hln, 4);
if (!(cfg & dad)) { if (!(cfg & DAD)) {
if (src_ip.s_addr != dst.s_addr) if (src_ip.s_addr != dst.s_addr)
return 0; return 0;
if (src.s_addr != dst_ip.s_addr) if (src.s_addr != dst_ip.s_addr)
@ -190,11 +188,8 @@ static int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
if (src.s_addr && src.s_addr != dst_ip.s_addr) if (src.s_addr && src.s_addr != dst_ip.s_addr)
return 0; return 0;
} }
if (!(cfg & quiet)) { if (!(cfg & QUIET)) {
int s_printed = 0; int s_printed = 0;
struct timeval tv;
gettimeofday(&tv, NULL);
printf("%scast re%s from %s [%s]", printf("%scast re%s from %s [%s]",
FROM->sll_pkttype == PACKET_HOST ? "Uni" : "Broad", FROM->sll_pkttype == PACKET_HOST ? "Uni" : "Broad",
@ -212,13 +207,8 @@ static int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
ether_ntoa((struct ether_addr *) p + ah->ar_hln + 4)); ether_ntoa((struct ether_addr *) p + ah->ar_hln + 4));
} }
if (last.tv_sec) { if (last) {
long usecs = (tv.tv_sec - last.tv_sec) * 1000000 + printf(" %u.%03ums\n", last / 1000, last % 1000);
tv.tv_usec - last.tv_usec;
long msecs = (usecs + 500) / 1000;
usecs -= msecs * 1000 - 500;
printf(" %ld.%03ldms\n", msecs, usecs);
} else { } else {
printf(" UNSOLICITED?\n"); printf(" UNSOLICITED?\n");
} }
@ -229,11 +219,11 @@ static int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
brd_recv++; brd_recv++;
if (ah->ar_op == htons(ARPOP_REQUEST)) if (ah->ar_op == htons(ARPOP_REQUEST))
req_recv++; req_recv++;
if (cfg & quit_on_reply) if (cfg & QUIT_ON_REPLY)
finish(); finish();
if (!(cfg & broadcast_only)) { if (!(cfg & BCAST_ONLY)) {
memcpy(he.sll_addr, p, me.sll_halen); memcpy(he.sll_addr, p, me.sll_halen);
cfg |= unicasting; cfg |= UNICASTING;
} }
return 1; return 1;
} }
@ -245,6 +235,7 @@ int arping_main(int argc, char **argv)
int ifindex; int ifindex;
char *source = NULL; char *source = NULL;
char *target; char *target;
unsigned char *packet;
s = xsocket(PF_PACKET, SOCK_DGRAM, 0); s = xsocket(PF_PACKET, SOCK_DGRAM, 0);
@ -258,28 +249,23 @@ int arping_main(int argc, char **argv)
/* Dad also sets quit_on_reply. /* Dad also sets quit_on_reply.
* Advert also sets unsolicited. * Advert also sets unsolicited.
*/ */
opt_complementary = "Df:AU"; opt_complementary = "=1:Df:AU";
opt = getopt32(argc, argv, "DUAqfbc:w:I:s:", opt = getopt32(argc, argv, "DUAqfbc:w:I:s:",
&_count, &_timeout, &device, &source); &_count, &_timeout, &device, &source);
cfg |= opt & 0x3f; /* set respective flags */ cfg |= opt & 0x3f; /* set respective flags */
if (opt & 0x40) /* -c: count */ if (opt & 0x40) /* -c: count */
count = xatou(_count); count = xatou(_count);
if (opt & 0x80) /* -w: timeout */ if (opt & 0x80) /* -w: timeout */
timeout = xatoul_range(_timeout, 0, INT_MAX/2000); timeout_us = xatou_range(_timeout, 0, INT_MAX/2000000) * 1000000;
//if (opt & 0x100) /* -i: interface */ //if (opt & 0x100) /* -I: interface */
if (strlen(device) > IF_NAMESIZE) { if (strlen(device) >= IF_NAMESIZE) {
bb_error_msg_and_die("interface name '%s' is too long", bb_error_msg_and_die("interface name '%s' is too long",
device); device);
} }
//if (opt & 0x200) /* -s: source */ //if (opt & 0x200) /* -s: source */
} }
argc -= optind;
argv += optind;
if (argc != 1) target = argv[optind];
bb_show_usage();
target = *argv;
xfunc_error_retval = 2; xfunc_error_retval = 2;
@ -301,7 +287,7 @@ int arping_main(int argc, char **argv)
} }
if (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) { if (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) {
bb_error_msg("interface %s is not ARPable", device); bb_error_msg("interface %s is not ARPable", device);
return (cfg & dad ? 0 : 2); return (cfg & DAD ? 0 : 2);
} }
} }
@ -317,10 +303,10 @@ int arping_main(int argc, char **argv)
bb_error_msg_and_die("invalid source address %s", source); bb_error_msg_and_die("invalid source address %s", source);
} }
if (!(cfg & dad) && (cfg & unsolicited) && src.s_addr == 0) if (!(cfg & DAD) && (cfg & UNSOLICITED) && src.s_addr == 0)
src = dst; src = dst;
if (!(cfg & dad) || src.s_addr) { if (!(cfg & DAD) || src.s_addr) {
struct sockaddr_in saddr; struct sockaddr_in saddr;
int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0); int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0);
@ -333,7 +319,7 @@ int arping_main(int argc, char **argv)
if (src.s_addr) { if (src.s_addr) {
saddr.sin_addr = src; saddr.sin_addr = src;
xbind(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); xbind(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr));
} else if (!(cfg & dad)) { } else if (!(cfg & DAD)) {
socklen_t alen = sizeof(saddr); socklen_t alen = sizeof(saddr);
saddr.sin_port = htons(1025); saddr.sin_port = htons(1025);
@ -364,18 +350,18 @@ int arping_main(int argc, char **argv)
} }
if (me.sll_halen == 0) { if (me.sll_halen == 0) {
bb_error_msg("interface \"%s\" is not ARPable (no ll address)", device); bb_error_msg("interface \"%s\" is not ARPable (no ll address)", device);
return (cfg & dad ? 0 : 2); return (cfg & DAD ? 0 : 2);
} }
he = me; he = me;
memset(he.sll_addr, -1, he.sll_halen); memset(he.sll_addr, -1, he.sll_halen);
if (!(cfg & quiet)) { if (!(cfg & QUIET)) {
printf("ARPING to %s from %s via %s\n", printf("ARPING to %s from %s via %s\n",
inet_ntoa(dst), inet_ntoa(src), inet_ntoa(dst), inet_ntoa(src),
device ? device : "unknown"); device ? device : "unknown");
} }
if (!src.s_addr && !(cfg & dad)) { if (!src.s_addr && !(cfg & DAD)) {
bb_error_msg_and_die("no src address in the non-DAD mode"); bb_error_msg_and_die("no src address in the non-DAD mode");
} }
@ -394,9 +380,9 @@ int arping_main(int argc, char **argv)
catcher(); catcher();
packet = xmalloc(4096);
while (1) { while (1) {
sigset_t sset, osset; sigset_t sset, osset;
RESERVE_CONFIG_UBUFFER(packet, 4096);
struct sockaddr_ll from; struct sockaddr_ll from;
socklen_t alen = sizeof(from); socklen_t alen = sizeof(from);
int cc; int cc;
@ -412,6 +398,5 @@ int arping_main(int argc, char **argv)
sigprocmask(SIG_BLOCK, &sset, &osset); sigprocmask(SIG_BLOCK, &sset, &osset);
recv_pack(packet, cc, &from); recv_pack(packet, cc, &from);
sigprocmask(SIG_SETMASK, &osset, NULL); sigprocmask(SIG_SETMASK, &osset, NULL);
RELEASE_CONFIG_BUFFER(packet);
} }
} }

View File

@ -17,19 +17,6 @@
#define DERR(...) ((void)0) #define DERR(...) ((void)0)
#endif #endif
/* return time in usec */
// TODO: move to libbb and use in traceroute, zcip, arping etc
// (maybe also use absolute monotonic clock - no time warps
// due to admin resetting date/time?)
static unsigned gettimeofday_us(void)
{
struct timeval now;
if (gettimeofday(&now, NULL))
return 0;
return (now.tv_sec * 1000000 + now.tv_usec);
}
static const char *port_name(unsigned port) static const char *port_name(unsigned port)
{ {
struct servent *server; struct servent *server;
@ -40,6 +27,9 @@ static const char *port_name(unsigned port)
return "unknown"; return "unknown";
} }
/* We don't expect to see 1000+ seconds delay, unsigned is enough */
#define MONOTONIC_US() ((unsigned)monotonic_us())
int pscan_main(int argc, char **argv); int pscan_main(int argc, char **argv);
int pscan_main(int argc, char **argv) int pscan_main(int argc, char **argv)
{ {
@ -91,7 +81,7 @@ int pscan_main(int argc, char **argv)
/* Nonblocking connect typically "fails" with errno == EINPROGRESS */ /* Nonblocking connect typically "fails" with errno == EINPROGRESS */
ndelay_on(s); ndelay_on(s);
DMSG("connect to port %u", port); DMSG("connect to port %u", port);
start = gettimeofday_us(); start = MONOTONIC_US();
if (connect(s, &lsap->sa, lsap->len) == 0) { if (connect(s, &lsap->sa, lsap->len) == 0) {
/* Unlikely, for me even localhost fails :) */ /* Unlikely, for me even localhost fails :) */
DMSG("connect succeeded"); DMSG("connect succeeded");
@ -110,15 +100,15 @@ int pscan_main(int argc, char **argv)
closed_ports++; closed_ports++;
break; break;
} }
DERR("port %u errno %d @%u", port, errno, gettimeofday_us() - start); DERR("port %u errno %d @%u", port, errno, MONOTONIC_US() - start);
if ((gettimeofday_us() - start) > rtt_4) if ((MONOTONIC_US() - start) > rtt_4)
break; break;
/* Can sleep (much) longer than specified delay. /* Can sleep (much) longer than specified delay.
* We check rtt BEFORE we usleep, otherwise * We check rtt BEFORE we usleep, otherwise
* on localhost we'll do zero writes done (!) * on localhost we'll do zero writes done (!)
* before we exceed (rather small) rtt */ * before we exceed (rather small) rtt */
usleep(rtt_4/8); usleep(rtt_4/8);
DMSG("write to port %u @%u", port, gettimeofday_us() - start); DMSG("write to port %u @%u", port, MONOTONIC_US() - start);
if (write(s, " ", 1) >= 0) { /* We were able to write to the socket */ if (write(s, " ", 1) >= 0) { /* We were able to write to the socket */
open: open:
open_ports++; open_ports++;
@ -126,13 +116,13 @@ int pscan_main(int argc, char **argv)
break; break;
} }
} }
DMSG("out of loop @%u", gettimeofday_us() - start); DMSG("out of loop @%u", MONOTONIC_US() - start);
/* Estimate new rtt - we don't want to wait entire timeout /* Estimate new rtt - we don't want to wait entire timeout
* for each port. *4 allows for rise in net delay. * for each port. *4 allows for rise in net delay.
* We increase rtt quickly (*4), decrease slowly (4/8 == 1/2) * We increase rtt quickly (*4), decrease slowly (4/8 == 1/2)
* because we don't want to accidentally miss ports. */ * because we don't want to accidentally miss ports. */
rtt_4 = (gettimeofday_us() - start) * 4; rtt_4 = (MONOTONIC_US() - start) * 4;
if (rtt_4 < min_rtt) if (rtt_4 < min_rtt)
rtt_4 = min_rtt; rtt_4 = min_rtt;
if (rtt_4 > timeout) if (rtt_4 > timeout)

View File

@ -275,7 +275,8 @@ struct hostinfo {
struct outdata { struct outdata {
unsigned char seq; /* sequence number of this packet */ unsigned char seq; /* sequence number of this packet */
unsigned char ttl; /* ttl packet left with */ unsigned char ttl; /* ttl packet left with */
struct timeval tv ATTRIBUTE_PACKED; /* time packet left */ // UNUSED. Retaining to have the same packet size.
struct timeval tv_UNUSED ATTRIBUTE_PACKED; /* time packet left */
}; };
struct IFADDRLIST { struct IFADDRLIST {
@ -533,37 +534,19 @@ findsaddr(const struct sockaddr_in *to, struct sockaddr_in *from)
*/ */
/*
* Subtract 2 timeval structs: out = out - in.
* Out is assumed to be >= in.
*/
static inline void
tvsub(struct timeval *out, struct timeval *in)
{
if ((out->tv_usec -= in->tv_usec) < 0) {
--out->tv_sec;
out->tv_usec += 1000000;
}
out->tv_sec -= in->tv_sec;
}
static int static int
wait_for_reply(int sock, struct sockaddr_in *fromp, const struct timeval *tp) wait_for_reply(int sock, struct sockaddr_in *fromp)
{ {
fd_set fds; fd_set fds;
struct timeval now, tvwait; struct timeval tvwait;
struct timezone tz;
int cc = 0; int cc = 0;
socklen_t fromlen = sizeof(*fromp); socklen_t fromlen = sizeof(*fromp);
FD_ZERO(&fds); FD_ZERO(&fds);
FD_SET(sock, &fds); FD_SET(sock, &fds);
tvwait.tv_sec = tp->tv_sec + waittime; tvwait.tv_sec = waittime;
tvwait.tv_usec = tp->tv_usec; tvwait.tv_usec = 0;
(void)gettimeofday(&now, &tz);
tvsub(&tvwait, &now);
if (select(sock + 1, &fds, NULL, NULL, &tvwait) > 0) if (select(sock + 1, &fds, NULL, NULL, &tvwait) > 0)
cc = recvfrom(sock, (char *)packet, sizeof(packet), 0, cc = recvfrom(sock, (char *)packet, sizeof(packet), 0,
@ -609,7 +592,7 @@ in_cksum(uint16_t *addr, int len)
static void static void
send_probe(int seq, int ttl, struct timeval *tp) send_probe(int seq, int ttl)
{ {
int cc; int cc;
struct udpiphdr *ui, *oui; struct udpiphdr *ui, *oui;
@ -633,7 +616,8 @@ send_probe(int seq, int ttl, struct timeval *tp)
/* Payload */ /* Payload */
outdata->seq = seq; outdata->seq = seq;
outdata->ttl = ttl; outdata->ttl = ttl;
memcpy(&outdata->tv, tp, sizeof(outdata->tv)); // UNUSED: was storing gettimeofday's result there, but never ever checked it
/*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/
#if ENABLE_FEATURE_TRACEROUTE_USE_ICMP #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
if (useicmp) if (useicmp)
@ -706,7 +690,6 @@ send_probe(int seq, int ttl, struct timeval *tp)
packlen, (struct sockaddr *)&whereto, sizeof(whereto)); packlen, (struct sockaddr *)&whereto, sizeof(whereto));
if (cc != packlen) { if (cc != packlen) {
bb_info_msg("wrote %s %d chars, ret=%d", hostname, packlen, cc); bb_info_msg("wrote %s %d chars, ret=%d", hostname, packlen, cc);
// (void)fflush(stdout);
} }
} }
@ -908,9 +891,9 @@ getaddr(uint32_t *ap, const char *host)
#endif #endif
static void static void
print_delta_ms(struct timeval *t1p, struct timeval *t2p) print_delta_ms(unsigned t1p, unsigned t2p)
{ {
unsigned tt = (t2p->tv_sec - t1p->tv_sec) * 1000000 + (t2p->tv_usec - t1p->tv_usec); unsigned tt = t2p - t1p;
printf(" %u.%03u ms", tt/1000, tt%1000); printf(" %u.%03u ms", tt/1000, tt%1000);
} }
@ -1230,17 +1213,17 @@ int traceroute_main(int argc, char **argv)
printf("%2d ", ttl); printf("%2d ", ttl);
for (probe = 0; probe < nprobes; ++probe) { for (probe = 0; probe < nprobes; ++probe) {
int cc; int cc;
struct timeval t1, t2; unsigned t1;
struct timezone tz; unsigned t2;
struct ip *ip; struct ip *ip;
if (sentfirst && pausemsecs > 0) if (sentfirst && pausemsecs > 0)
usleep(pausemsecs * 1000); usleep(pausemsecs * 1000);
(void)gettimeofday(&t1, &tz); t1 = monotonic_us();
send_probe(++seq, ttl, &t1); send_probe(++seq, ttl);
++sentfirst; ++sentfirst;
while ((cc = wait_for_reply(s, from, &t1)) != 0) { while ((cc = wait_for_reply(s, from)) != 0) {
(void)gettimeofday(&t2, &tz); t2 = monotonic_us();
i = packet_ok(packet, cc, from, seq); i = packet_ok(packet, cc, from, seq);
/* Skip short packet */ /* Skip short packet */
if (i == 0) if (i == 0)
@ -1251,7 +1234,7 @@ int traceroute_main(int argc, char **argv)
lastaddr = from->sin_addr.s_addr; lastaddr = from->sin_addr.s_addr;
++gotlastaddr; ++gotlastaddr;
} }
print_delta_ms(&t1, &t2); print_delta_ms(t1, t2);
ip = (struct ip *)packet; ip = (struct ip *)packet;
if (op & OPT_TTL_FLAG) if (op & OPT_TTL_FLAG)
printf(" (%d)", ip->ip_ttl); printf(" (%d)", ip->ip_ttl);

View File

@ -705,7 +705,7 @@ progressmeter(int flag)
ratio = 100; ratio = 100;
if (totalsize != 0 && !chunked) { if (totalsize != 0 && !chunked) {
/* long long helps to have working ETA even if !LFS */ /* long long helps to have working ETA even if !LFS */
ratio = (int) (100 * (unsigned long long)(transferred+beg_range) / totalsize); ratio = (int) (100ULL * (transferred+beg_range) / totalsize);
ratio = MIN(ratio, 100); ratio = MIN(ratio, 100);
} }

View File

@ -7,7 +7,6 @@
* Licensed under GPLv2 or later, see file LICENSE in this tarball for details. * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/ */
//#include <sys/ioctl.h>
#include <sys/utsname.h> #include <sys/utsname.h>
#include <getopt.h> #include <getopt.h>
#include "libbb.h" #include "libbb.h"
@ -98,49 +97,42 @@ static void write_rtc(time_t t, int utc)
close(rtc); close(rtc);
} }
static int show_clock(int utc) static void show_clock(int utc)
{ {
struct tm *ptm; //struct tm *ptm;
time_t t; time_t t;
RESERVE_CONFIG_BUFFER(buffer, 64); char *cp;
t = read_rtc(utc); t = read_rtc(utc);
ptm = localtime(&t); /* Sets 'tzname[]' */ //ptm = localtime(&t); /* Sets 'tzname[]' */
safe_strncpy(buffer, ctime(&t), 64); cp = ctime(&t);
if (buffer[0]) if (cp[0])
buffer[strlen(buffer) - 1] = 0; cp[strlen(cp) - 1] = '\0';
//printf("%s %.6f seconds %s\n", buffer, 0.0, utc ? "" : (ptm->tm_isdst ? tzname[1] : tzname[0])); //printf("%s %.6f seconds %s\n", cp, 0.0, utc ? "" : (ptm->tm_isdst ? tzname[1] : tzname[0]));
printf( "%s %.6f seconds\n", buffer, 0.0); printf("%s 0.000000 seconds\n", cp);
RELEASE_CONFIG_BUFFER(buffer);
return 0;
} }
static int to_sys_clock(int utc) static void to_sys_clock(int utc)
{ {
struct timeval tv = { 0, 0 }; struct timeval tv;
const struct timezone tz = { timezone/60 - 60*daylight, 0 }; const struct timezone tz = { timezone/60 - 60*daylight, 0 };
tv.tv_sec = read_rtc(utc); tv.tv_sec = read_rtc(utc);
tv.tv_usec = 0;
if (settimeofday(&tv, &tz)) if (settimeofday(&tv, &tz))
bb_perror_msg_and_die("settimeofday() failed"); bb_perror_msg_and_die("settimeofday() failed");
return 0;
} }
static int from_sys_clock(int utc) static void from_sys_clock(int utc)
{ {
struct timeval tv = { 0, 0 }; struct timeval tv;
struct timezone tz = { 0, 0 };
if (gettimeofday(&tv, &tz))
bb_perror_msg_and_die("gettimeofday() failed");
gettimeofday(&tv, NULL);
//if (gettimeofday(&tv, NULL))
// bb_perror_msg_and_die("gettimeofday() failed");
write_rtc(tv.tv_sec, utc); write_rtc(tv.tv_sec, utc);
return 0;
} }
#ifdef CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS #ifdef CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS
@ -210,12 +202,14 @@ int hwclock_main(int argc, char **argv )
utc = check_utc(); utc = check_utc();
if (opt & HWCLOCK_OPT_HCTOSYS) { if (opt & HWCLOCK_OPT_HCTOSYS) {
return to_sys_clock(utc); to_sys_clock(utc);
return 0;
}
if (opt & HWCLOCK_OPT_SYSTOHC) {
from_sys_clock(utc);
return 0;
} }
else if (opt & HWCLOCK_OPT_SYSTOHC) {
return from_sys_clock(utc);
} else {
/* default HWCLOCK_OPT_SHOW */ /* default HWCLOCK_OPT_SHOW */
return show_clock(utc); show_clock(utc);
} return 0;
} }