xref: /netbsd/usr.bin/time/time.c (revision c4a72b64)
1 /*	$NetBSD: time.c,v 1.12 2002/07/16 15:41:57 christos 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. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <sys/cdefs.h>
37 #ifndef lint
38 __COPYRIGHT("@(#) Copyright (c) 1987, 1988, 1993\n\
39 	The Regents of the University of California.  All rights reserved.\n");
40 #endif /* not lint */
41 
42 #ifndef lint
43 #if 0
44 static char sccsid[] = "@(#)time.c	8.1 (Berkeley) 6/6/93";
45 #endif
46 __RCSID("$NetBSD: time.c,v 1.12 2002/07/16 15:41:57 christos Exp $");
47 #endif /* not lint */
48 
49 #include <sys/types.h>
50 #include <sys/time.h>
51 #include <sys/resource.h>
52 #include <sys/wait.h>
53 #include <errno.h>
54 #include <err.h>
55 #include <locale.h>
56 #include <signal.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <unistd.h>
60 
61 int		main(int, char **);
62 static void	usage(void);
63 static void	prl(long, const char *);
64 static void	prtv(const char *, const char *, const struct timeval *,
65     const char *);
66 
67 int
68 main(int argc, char **argv)
69 {
70 	int pid;
71 	int ch, status;
72 	int lflag, portableflag;
73 	const char *decpt;
74 	const struct lconv *lconv;
75 	struct timeval before, after;
76 	struct rusage ru;
77 
78 #ifdef __GNUC__		/* XXX: borken gcc */
79 	(void)&argv;
80 #endif
81 
82 	(void)setlocale(LC_ALL, "");
83 
84 	lflag = portableflag = 0;
85 	while ((ch = getopt(argc, argv, "lp")) != -1) {
86 		switch (ch) {
87 		case 'p':
88 			portableflag = 1;
89 			break;
90 		case 'l':
91 			lflag = 1;
92 			break;
93 		case '?':
94 		default:
95 			usage();
96 		}
97 	}
98 	argc -= optind;
99 	argv += optind;
100 
101 	if (argc < 1)
102 		usage();
103 
104 	gettimeofday(&before, (struct timezone *)NULL);
105 	switch(pid = vfork()) {
106 	case -1:			/* error */
107 		err(EXIT_FAILURE, "Vfork failed");
108 		/* NOTREACHED */
109 	case 0:				/* child */
110 		/* LINTED will return only on failure */
111 		execvp(*argv, argv);
112 		err((errno == ENOENT) ? 127 : 126, "Can't exec `%s'", *argv);
113 		/* NOTREACHED */
114 	}
115 
116 	/* parent */
117 	(void)signal(SIGINT, SIG_IGN);
118 	(void)signal(SIGQUIT, SIG_IGN);
119 	if ((pid = wait4(pid, &status, 0, &ru)) == -1)
120 		err(EXIT_FAILURE, "wait4 %d failed", pid);
121 	(void)gettimeofday(&after, (struct timezone *)NULL);
122 	if (!WIFEXITED(status))
123 		warnx("Command terminated abnormally.");
124 	timersub(&after, &before, &after);
125 
126 	if ((lconv = localeconv()) == NULL ||
127 	    (decpt = lconv->decimal_point) == NULL)
128 		decpt = ".";
129 
130 	if (portableflag) {
131 		prtv("real ", decpt, &after, "\n");
132 		prtv("user ", decpt, &ru.ru_utime, "\n");
133 		prtv("sys  ", decpt, &ru.ru_stime, "\n");
134 	} else {
135 		prtv("", decpt, &after, " real ");
136 		prtv("", decpt, &ru.ru_utime, " user ");
137 		prtv("", decpt, &ru.ru_stime, " sys\n");
138 	}
139 
140 	if (lflag) {
141 		int hz = (int)sysconf(_SC_CLK_TCK);
142 		unsigned long long ticks;
143 #define SCALE(x) (long)(ticks ? x / ticks : 0)
144 
145 		ticks = hz * (ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) +
146 		     hz * (ru.ru_utime.tv_usec + ru.ru_stime.tv_usec) / 1000000;
147 		prl(ru.ru_maxrss, "maximum resident set size");
148 		prl(SCALE(ru.ru_ixrss), "average shared memory size");
149 		prl(SCALE(ru.ru_idrss), "average unshared data size");
150 		prl(SCALE(ru.ru_isrss), "average unshared stack size");
151 		prl(ru.ru_minflt, "page reclaims");
152 		prl(ru.ru_majflt, "page faults");
153 		prl(ru.ru_nswap, "swaps");
154 		prl(ru.ru_inblock, "block input operations");
155 		prl(ru.ru_oublock, "block output operations");
156 		prl(ru.ru_msgsnd, "messages sent");
157 		prl(ru.ru_msgrcv, "messages received");
158 		prl(ru.ru_nsignals, "signals received");
159 		prl(ru.ru_nvcsw, "voluntary context switches");
160 		prl(ru.ru_nivcsw, "involuntary context switches");
161 	}
162 
163 	return (WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE);
164 }
165 
166 static void
167 usage()
168 {
169 	(void)fprintf(stderr, "Usage: %s [-lp] utility [argument ...]\n",
170 	    getprogname());
171 	exit(EXIT_FAILURE);
172 }
173 
174 static void
175 prl(long val, const char *expn)
176 {
177     (void)fprintf(stderr, "%10ld  %s\n", val, expn);
178 }
179 
180 static void
181 prtv(const char *pre, const char *decpt, const struct timeval *tv,
182     const char *post)
183 {
184     (void)fprintf(stderr, "%s%9ld%s%02ld%s", pre, (long)tv->tv_sec, decpt,
185 	(long)tv->tv_usec / 10000, post);
186 }
187