1/* $NetBSD: time.c,v 1.24 2020/04/23 07:54:53 simonb Exp $ */ 2 3/* 4 * Copyright (c) 1987, 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33#ifndef lint 34__COPYRIGHT("@(#) Copyright (c) 1987, 1988, 1993\ 35 The Regents of the University of California. All rights reserved."); 36#endif /* not lint */ 37 38#ifndef lint 39#if 0 40static char sccsid[] = "@(#)time.c 8.1 (Berkeley) 6/6/93"; 41#endif 42__RCSID("$NetBSD: time.c,v 1.24 2020/04/23 07:54:53 simonb Exp $"); 43#endif /* not lint */ 44 45#include <sys/types.h> 46#include <sys/time.h> 47#include <sys/resource.h> 48#include <sys/wait.h> 49#include <errno.h> 50#include <err.h> 51#include <locale.h> 52#include <signal.h> 53#include <stdio.h> 54#include <stdlib.h> 55#include <unistd.h> 56 57#include "ext.h" 58 59__dead static void usage(void); 60static void prl(long, const char *); 61static void prts(const char *, const char *, const struct timespec *, 62 const char *); 63static void prtv(const char *, const char *, const struct timeval *, 64 const char *); 65 66int 67main(int argc, char ** volatile argv) 68{ 69 int pid; 70 int ch, status, prec; 71 int volatile portableflag; 72 int volatile lflag; 73 const char *decpt; 74 const char *fmt; 75 const struct lconv *lconv; 76 struct timespec before, after; 77 struct rusage ru; 78 79 (void)setlocale(LC_ALL, ""); 80 81 lflag = portableflag = 0; 82 prec = 1; 83 fmt = NULL; 84 while ((ch = getopt(argc, argv, "cf:lpt")) != -1) { 85 switch (ch) { 86 case 'f': 87 fmt = optarg; 88 portableflag = 0; 89 lflag = 0; 90 break; 91 case 'c': /* csh format */ 92 fmt = "%Uu %Ss %E %P %X+%Dk %I+%Oio %Fpf+%Ww"; 93 portableflag = 0; 94 lflag = 0; 95 break; 96 case 'p': /* POSIX.2 format */ 97 portableflag = 1; 98 fmt = NULL; 99 lflag = 0; 100 break; 101 case 'l': 102 lflag = 1; 103 portableflag = 0; 104 fmt = NULL; 105 break; 106 case 't': /* tcsh format */ 107 fmt = "%Uu %Ss %E %P\t%X+%Dk %I+%Oio %Fpf+%Ww"; 108 prec = 3; 109 portableflag = 0; 110 lflag = 0; 111 break; 112 case '?': 113 default: 114 usage(); 115 } 116 } 117 argc -= optind; 118 argv += optind; 119 120 if (argc < 1) 121 usage(); 122 123 (void)clock_gettime(CLOCK_MONOTONIC, &before); 124 switch(pid = vfork()) { 125 case -1: /* error */ 126 err(EXIT_FAILURE, "Vfork failed"); 127 /* NOTREACHED */ 128 case 0: /* child */ 129 /* LINTED will return only on failure */ 130 execvp(*argv, argv); 131 err((errno == ENOENT) ? 127 : 126, "Can't exec `%s'", *argv); 132 /* NOTREACHED */ 133 } 134 135 /* parent */ 136 (void)signal(SIGINT, SIG_IGN); 137 (void)signal(SIGQUIT, SIG_IGN); 138 if ((pid = wait4(pid, &status, 0, &ru)) == -1) 139 err(EXIT_FAILURE, "wait4 %d failed", pid); 140 (void)clock_gettime(CLOCK_MONOTONIC, &after); 141 if (!WIFEXITED(status)) 142 warnx("Command terminated abnormally."); 143 timespecsub(&after, &before, &after); 144 145 if ((lconv = localeconv()) == NULL || 146 (decpt = lconv->decimal_point) == NULL) 147 decpt = "."; 148 149 if (fmt) { 150 static struct rusage null_ru; 151 before.tv_sec = 0; 152 before.tv_nsec = 0; 153 prusage1(stderr, fmt, prec, &null_ru, &ru, &after, &before); 154 } else if (portableflag) { 155 prts("real ", decpt, &after, "\n"); 156 prtv("user ", decpt, &ru.ru_utime, "\n"); 157 prtv("sys ", decpt, &ru.ru_stime, "\n"); 158 } else { 159 prts("", decpt, &after, " real "); 160 prtv("", decpt, &ru.ru_utime, " user "); 161 prtv("", decpt, &ru.ru_stime, " sys\n"); 162 } 163 164 if (lflag) { 165 int hz = (int)sysconf(_SC_CLK_TCK); 166 unsigned long long ticks; 167#define SCALE(x) (long)(ticks ? x / ticks : 0) 168 169 ticks = hz * (ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) + 170 hz * (ru.ru_utime.tv_usec + ru.ru_stime.tv_usec) / 1000000; 171 prl(ru.ru_maxrss, "maximum resident set size"); 172 prl(SCALE(ru.ru_ixrss), "average shared memory size"); 173 prl(SCALE(ru.ru_idrss), "average unshared data size"); 174 prl(SCALE(ru.ru_isrss), "average unshared stack size"); 175 prl(ru.ru_minflt, "page reclaims"); 176 prl(ru.ru_majflt, "page faults"); 177 prl(ru.ru_nswap, "swaps"); 178 prl(ru.ru_inblock, "block input operations"); 179 prl(ru.ru_oublock, "block output operations"); 180 prl(ru.ru_msgsnd, "messages sent"); 181 prl(ru.ru_msgrcv, "messages received"); 182 prl(ru.ru_nsignals, "signals received"); 183 prl(ru.ru_nvcsw, "voluntary context switches"); 184 prl(ru.ru_nivcsw, "involuntary context switches"); 185 } 186 187 return (WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE); 188} 189 190static void 191usage(void) 192{ 193 194 (void)fprintf(stderr, 195 "Usage: %s [-clpt] [-f <fmt>] utility [argument ...]\n", 196 getprogname()); 197 exit(EXIT_FAILURE); 198} 199 200static void 201prl(long val, const char *expn) 202{ 203 204 (void)fprintf(stderr, "%10ld %s\n", val, expn); 205} 206 207static void 208prts(const char *pre, const char *decpt, const struct timespec *ts, 209 const char *post) 210{ 211 212 (void)fprintf(stderr, "%s%9lld%s%02ld%s", pre, (long long)ts->tv_sec, 213 decpt, (long)ts->tv_nsec / 10000000, post); 214} 215 216static void 217prtv(const char *pre, const char *decpt, const struct timeval *tv, 218 const char *post) 219{ 220 221 (void)fprintf(stderr, "%s%9lld%s%02ld%s", pre, (long long)tv->tv_sec, 222 decpt, (long)tv->tv_usec / 10000, post); 223} 224