Changeset View
Changeset View
Standalone View
Standalone View
head/usr.bin/time/time.c
Show First 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | |||||
#include <err.h> | #include <err.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <locale.h> | #include <locale.h> | ||||
#include <signal.h> | #include <signal.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <stdint.h> | #include <stdint.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <time.h> | |||||
#include <unistd.h> | #include <unistd.h> | ||||
static int getstathz(void); | static int getstathz(void); | ||||
static void humantime(FILE *, long, long); | static void humantime(FILE *, long, long); | ||||
static void showtime(FILE *, struct timeval *, struct timeval *, | static void showtime(FILE *, struct timespec *, struct timespec *, | ||||
struct rusage *); | struct rusage *); | ||||
static void siginfo(int); | static void siginfo(int); | ||||
static void usage(void); | static void usage(void); | ||||
static sig_atomic_t siginfo_recvd; | static sig_atomic_t siginfo_recvd; | ||||
static char decimal_point; | static char decimal_point; | ||||
static struct timeval before_tv; | static struct timespec before_ts; | ||||
static int hflag, pflag; | static int hflag, pflag; | ||||
int | int | ||||
main(int argc, char **argv) | main(int argc, char **argv) | ||||
{ | { | ||||
int aflag, ch, lflag, status; | int aflag, ch, lflag, status; | ||||
int exitonsig; | int exitonsig; | ||||
pid_t pid; | pid_t pid; | ||||
struct rlimit rl; | struct rlimit rl; | ||||
struct rusage ru; | struct rusage ru; | ||||
struct timeval after; | struct timespec after; | ||||
char *ofn = NULL; | char *ofn = NULL; | ||||
FILE *out = stderr; | FILE *out = stderr; | ||||
(void) setlocale(LC_NUMERIC, ""); | (void) setlocale(LC_NUMERIC, ""); | ||||
decimal_point = localeconv()->decimal_point[0]; | decimal_point = localeconv()->decimal_point[0]; | ||||
aflag = hflag = lflag = pflag = 0; | aflag = hflag = lflag = pflag = 0; | ||||
while ((ch = getopt(argc, argv, "ahlo:p")) != -1) | while ((ch = getopt(argc, argv, "ahlo:p")) != -1) | ||||
Show All 23 Lines | main(int argc, char **argv) | ||||
argv += optind; | argv += optind; | ||||
if (ofn) { | if (ofn) { | ||||
if ((out = fopen(ofn, aflag ? "ae" : "we")) == NULL) | if ((out = fopen(ofn, aflag ? "ae" : "we")) == NULL) | ||||
err(1, "%s", ofn); | err(1, "%s", ofn); | ||||
setvbuf(out, (char *)NULL, _IONBF, (size_t)0); | setvbuf(out, (char *)NULL, _IONBF, (size_t)0); | ||||
} | } | ||||
(void)gettimeofday(&before_tv, NULL); | if (clock_gettime(CLOCK_REALTIME, &before_ts)) | ||||
err(1, "clock_gettime"); | |||||
switch(pid = fork()) { | switch(pid = fork()) { | ||||
case -1: /* error */ | case -1: /* error */ | ||||
err(1, "time"); | err(1, "time"); | ||||
/* NOTREACHED */ | /* NOTREACHED */ | ||||
case 0: /* child */ | case 0: /* child */ | ||||
execvp(*argv, argv); | execvp(*argv, argv); | ||||
err(errno == ENOENT ? 127 : 126, "%s", *argv); | err(errno == ENOENT ? 127 : 126, "%s", *argv); | ||||
/* NOTREACHED */ | /* NOTREACHED */ | ||||
} | } | ||||
/* parent */ | /* parent */ | ||||
(void)signal(SIGINT, SIG_IGN); | (void)signal(SIGINT, SIG_IGN); | ||||
(void)signal(SIGQUIT, SIG_IGN); | (void)signal(SIGQUIT, SIG_IGN); | ||||
siginfo_recvd = 0; | siginfo_recvd = 0; | ||||
(void)signal(SIGINFO, siginfo); | (void)signal(SIGINFO, siginfo); | ||||
(void)siginterrupt(SIGINFO, 1); | (void)siginterrupt(SIGINFO, 1); | ||||
while (wait4(pid, &status, 0, &ru) != pid) { | while (wait4(pid, &status, 0, &ru) != pid) { | ||||
if (siginfo_recvd) { | if (siginfo_recvd) { | ||||
siginfo_recvd = 0; | siginfo_recvd = 0; | ||||
(void)gettimeofday(&after, NULL); | if (clock_gettime(CLOCK_REALTIME, &after)) | ||||
err(1, "clock_gettime"); | |||||
getrusage(RUSAGE_CHILDREN, &ru); | getrusage(RUSAGE_CHILDREN, &ru); | ||||
showtime(stdout, &before_tv, &after, &ru); | showtime(stdout, &before_ts, &after, &ru); | ||||
} | } | ||||
} | } | ||||
(void)gettimeofday(&after, NULL); | if (clock_gettime(CLOCK_REALTIME, &after)) | ||||
err(1, "clock_gettime"); | |||||
if ( ! WIFEXITED(status)) | if ( ! WIFEXITED(status)) | ||||
warnx("command terminated abnormally"); | warnx("command terminated abnormally"); | ||||
exitonsig = WIFSIGNALED(status) ? WTERMSIG(status) : 0; | exitonsig = WIFSIGNALED(status) ? WTERMSIG(status) : 0; | ||||
showtime(out, &before_tv, &after, &ru); | showtime(out, &before_ts, &after, &ru); | ||||
if (lflag) { | if (lflag) { | ||||
int hz = getstathz(); | int hz = getstathz(); | ||||
u_long ticks; | u_long ticks; | ||||
ticks = hz * (ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) + | ticks = hz * (ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) + | ||||
hz * (ru.ru_utime.tv_usec + ru.ru_stime.tv_usec) / 1000000; | hz * (ru.ru_utime.tv_usec + ru.ru_stime.tv_usec) / 1000000; | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | getstathz(void) | ||||
mib[1] = KERN_CLOCKRATE; | mib[1] = KERN_CLOCKRATE; | ||||
size = sizeof clockrate; | size = sizeof clockrate; | ||||
if (sysctl(mib, 2, &clockrate, &size, NULL, 0) == -1) | if (sysctl(mib, 2, &clockrate, &size, NULL, 0) == -1) | ||||
err(1, "sysctl kern.clockrate"); | err(1, "sysctl kern.clockrate"); | ||||
return clockrate.stathz; | return clockrate.stathz; | ||||
} | } | ||||
static void | static void | ||||
humantime(FILE *out, long sec, long usec) | humantime(FILE *out, long sec, long centisec) | ||||
{ | { | ||||
long days, hrs, mins; | long days, hrs, mins; | ||||
days = sec / (60L * 60 * 24); | days = sec / (60L * 60 * 24); | ||||
sec %= (60L * 60 * 24); | sec %= (60L * 60 * 24); | ||||
hrs = sec / (60L * 60); | hrs = sec / (60L * 60); | ||||
sec %= (60L * 60); | sec %= (60L * 60); | ||||
mins = sec / 60; | mins = sec / 60; | ||||
sec %= 60; | sec %= 60; | ||||
fprintf(out, "\t"); | fprintf(out, "\t"); | ||||
if (days) | if (days) | ||||
fprintf(out, "%ldd", days); | fprintf(out, "%ldd", days); | ||||
if (hrs) | if (hrs) | ||||
fprintf(out, "%ldh", hrs); | fprintf(out, "%ldh", hrs); | ||||
if (mins) | if (mins) | ||||
fprintf(out, "%ldm", mins); | fprintf(out, "%ldm", mins); | ||||
fprintf(out, "%ld%c%02lds", sec, decimal_point, usec); | fprintf(out, "%ld%c%02lds", sec, decimal_point, centisec); | ||||
} | } | ||||
static void | static void | ||||
showtime(FILE *out, struct timeval *before, struct timeval *after, | showtime(FILE *out, struct timespec *before, struct timespec *after, | ||||
struct rusage *ru) | struct rusage *ru) | ||||
{ | { | ||||
after->tv_sec -= before->tv_sec; | after->tv_sec -= before->tv_sec; | ||||
after->tv_usec -= before->tv_usec; | after->tv_nsec -= before->tv_nsec; | ||||
if (after->tv_usec < 0) | if (after->tv_nsec < 0) | ||||
after->tv_sec--, after->tv_usec += 1000000; | after->tv_sec--, after->tv_nsec += 1000000000; | ||||
if (pflag) { | if (pflag) { | ||||
/* POSIX wants output that must look like | /* POSIX wants output that must look like | ||||
"real %f\nuser %f\nsys %f\n" and requires | "real %f\nuser %f\nsys %f\n" and requires | ||||
at least two digits after the radix. */ | at least two digits after the radix. */ | ||||
fprintf(out, "real %jd%c%02ld\n", | fprintf(out, "real %jd%c%02ld\n", | ||||
(intmax_t)after->tv_sec, decimal_point, | (intmax_t)after->tv_sec, decimal_point, | ||||
after->tv_usec/10000); | after->tv_nsec/10000000); | ||||
fprintf(out, "user %jd%c%02ld\n", | fprintf(out, "user %jd%c%02ld\n", | ||||
(intmax_t)ru->ru_utime.tv_sec, decimal_point, | (intmax_t)ru->ru_utime.tv_sec, decimal_point, | ||||
ru->ru_utime.tv_usec/10000); | ru->ru_utime.tv_usec/10000); | ||||
fprintf(out, "sys %jd%c%02ld\n", | fprintf(out, "sys %jd%c%02ld\n", | ||||
(intmax_t)ru->ru_stime.tv_sec, decimal_point, | (intmax_t)ru->ru_stime.tv_sec, decimal_point, | ||||
ru->ru_stime.tv_usec/10000); | ru->ru_stime.tv_usec/10000); | ||||
} else if (hflag) { | } else if (hflag) { | ||||
humantime(out, after->tv_sec, after->tv_usec/10000); | humantime(out, after->tv_sec, after->tv_nsec/10000000); | ||||
fprintf(out, " real\t"); | fprintf(out, " real\t"); | ||||
humantime(out, ru->ru_utime.tv_sec, ru->ru_utime.tv_usec/10000); | humantime(out, ru->ru_utime.tv_sec, ru->ru_utime.tv_usec/10000); | ||||
fprintf(out, " user\t"); | fprintf(out, " user\t"); | ||||
humantime(out, ru->ru_stime.tv_sec, ru->ru_stime.tv_usec/10000); | humantime(out, ru->ru_stime.tv_sec, ru->ru_stime.tv_usec/10000); | ||||
fprintf(out, " sys\n"); | fprintf(out, " sys\n"); | ||||
} else { | } else { | ||||
fprintf(out, "%9jd%c%02ld real ", | fprintf(out, "%9jd%c%02ld real ", | ||||
(intmax_t)after->tv_sec, decimal_point, | (intmax_t)after->tv_sec, decimal_point, | ||||
after->tv_usec/10000); | after->tv_nsec/10000000); | ||||
fprintf(out, "%9jd%c%02ld user ", | fprintf(out, "%9jd%c%02ld user ", | ||||
(intmax_t)ru->ru_utime.tv_sec, decimal_point, | (intmax_t)ru->ru_utime.tv_sec, decimal_point, | ||||
ru->ru_utime.tv_usec/10000); | ru->ru_utime.tv_usec/10000); | ||||
fprintf(out, "%9jd%c%02ld sys\n", | fprintf(out, "%9jd%c%02ld sys\n", | ||||
(intmax_t)ru->ru_stime.tv_sec, decimal_point, | (intmax_t)ru->ru_stime.tv_sec, decimal_point, | ||||
ru->ru_stime.tv_usec/10000); | ru->ru_stime.tv_usec/10000); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
siginfo(int sig __unused) | siginfo(int sig __unused) | ||||
{ | { | ||||
siginfo_recvd = 1; | siginfo_recvd = 1; | ||||
} | } |