1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 #include <sys/types.h>
30 #include <sys/times.h>
31 #include <sys/time.h>
32 #include <sys/param.h>
33 #include <sys/wait.h>
34 #include <unistd.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <signal.h>
38 #include <strings.h>
39 #include <time.h>
40 #include <errno.h>
41 #include <pwd.h>
42
43 #define NSEC_TO_TICK(nsec) ((nsec) / nsec_per_tick)
44 #define NSEC_TO_TICK_ROUNDUP(nsec) NSEC_TO_TICK((nsec) + \
45 nsec_per_tick/2)
46
47 char fname[20];
48 static int hz;
49 static int nsec_per_tick;
50
51 void printt(char *, hrtime_t);
52 void hmstime(char[]);
53 void usage();
54
55 int
main(int argc,char ** argv)56 main(int argc, char **argv)
57 {
58 struct tms buffer, obuffer;
59 int status;
60 register pid_t p;
61 int c;
62 hrtime_t before, after, timediff;
63 char stime[9], etime[9];
64 char cmd[80];
65 int pflg = 0, sflg = 0, oflg = 0;
66 char aopt[25];
67 FILE *pipin;
68 char ttyid[12], line[150];
69 char eol;
70 char fld[20][12];
71 int iline = 0, i, nfld;
72 int ichar, iblok;
73 long chars = 0, bloks = 0;
74
75 aopt[0] = '\0';
76
77 hz = sysconf(_SC_CLK_TCK);
78 nsec_per_tick = NANOSEC / hz;
79
80 /* check options; */
81 while ((c = getopt(argc, argv, "sopfhkmrt")) != EOF)
82 switch (c) {
83 case 's': sflg++; break;
84 case 'o': oflg++; break;
85 case 'p': pflg++; break;
86
87 case 'f': strcat(aopt, "-f "); break;
88 case 'h': strcat(aopt, "-h "); break;
89 case 'k': strcat(aopt, "-k "); break;
90 case 'm': strcat(aopt, "-m "); break;
91 case 'r': strcat(aopt, "-r "); break;
92 case 't': strcat(aopt, "-t "); break;
93
94 case '?': usage();
95 break;
96 }
97 if (optind >= argc) {
98 fprintf(stderr, "timex: Missing command\n");
99 usage();
100 }
101
102 /*
103 * Check to see if accounting is installed and print a somewhat
104 * meaninful message if not.
105 */
106 if (((oflg+pflg) != 0) && (access("/usr/bin/acctcom", 01) == -1)) {
107 oflg = 0;
108 pflg = 0;
109 fprintf(stderr,
110 "Information from -p and -o options not available\n");
111 fprintf(stderr,
112 " because process accounting is not operational.\n");
113 }
114
115 if (sflg) {
116 sprintf(fname, "/tmp/tmx%ld", getpid());
117 sprintf(cmd, "/usr/lib/sa/sadc 1 1 %s", fname);
118 system(cmd);
119 }
120 if (pflg + oflg) hmstime(stime);
121 before = gethrtime();
122 (void) times(&obuffer);
123 if ((p = fork()) == (pid_t)-1) {
124 perror("Fork Failed");
125 (void) unlink(fname);
126 exit(EXIT_FAILURE);
127 }
128 if (p == 0) {
129 setgid(getgid());
130 execvp(*(argv+optind), (argv+optind));
131 fprintf(stderr, "%s: %s\n", *(argv+optind), strerror(errno));
132 exit(EXIT_FAILURE);
133 }
134 signal(SIGINT, SIG_IGN);
135 signal(SIGQUIT, SIG_IGN);
136 while (wait(&status) != p)
137 ;
138 if ((status&0377) != 0)
139 fprintf(stderr, "Command terminated abnormally.\n");
140 signal(SIGINT, SIG_DFL);
141 signal(SIGQUIT, SIG_DFL);
142 (void) times(&buffer);
143 after = gethrtime();
144 timediff = after - before;
145 if (pflg + oflg) hmstime(etime);
146 if (sflg) system(cmd);
147
148 fprintf(stderr, "\n");
149 printt("real", NSEC_TO_TICK_ROUNDUP(timediff));
150 printt("user", buffer.tms_cutime - obuffer.tms_cutime);
151 printt("sys ", buffer.tms_cstime - obuffer.tms_cstime);
152 fprintf(stderr, "\n");
153
154 if (oflg+pflg) {
155 if (isatty(0))
156 sprintf(ttyid, "-l %s", ttyname(0)+5);
157 sprintf(cmd, "acctcom -S %s -E %s -u %s %s -i %s",
158 stime, etime, getpwuid(getuid())->pw_name, ttyid, aopt);
159 pipin = popen(cmd, "r");
160 while (fscanf(pipin, "%[^\n]%1c", line, &eol) > 1) {
161 if (pflg)
162 fprintf(stderr, "%s\n", line);
163 if (oflg) {
164 nfld = sscanf(line,
165 "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
166 fld[0], fld[1], fld[2], fld[3], fld[4],
167 fld[5], fld[6], fld[7], fld[8], fld[9],
168 fld[10], fld[11], fld[12], fld[13], fld[14],
169 fld[15], fld[16], fld[17], fld[18],
170 fld[19]);
171 if (++iline == 3)
172 for (i = 0; i < nfld; i++) {
173 if (strcmp(fld[i], "CHARS")
174 == 0)
175 ichar = i+2;
176 if (strcmp(fld[i], "BLOCKS")
177 == 0)
178 iblok = i+2;
179 }
180 if (iline > 4) {
181 chars += atol(fld[ichar]);
182 bloks += atol(fld[iblok]);
183 }
184 }
185 }
186 pclose(pipin);
187
188 if (oflg)
189 if (iline > 4)
190 fprintf(stderr,
191 "\nCHARS TRNSFD = %ld\n"
192 "BLOCKS READ = %ld\n", chars, bloks);
193 else
194 fprintf(stderr,
195 "\nNo process records found!\n");
196 }
197
198 if (sflg) {
199 sprintf(cmd, "/usr/bin/sar -ubdycwaqvmpgrk -f %s 1>&2", fname);
200 system(cmd);
201 unlink(fname);
202 }
203 exit(WEXITSTATUS(status));
204 }
205
206 void
printt(char * label,hrtime_t ticks)207 printt(char *label, hrtime_t ticks)
208 {
209 long tk; /* number of leftover ticks */
210 long ss; /* number of seconds */
211 long mm; /* number of minutes */
212 long hh; /* number of hours */
213 longlong_t total = ticks;
214
215 tk = total % hz; /* ticks % hz */
216 total /= hz;
217 ss = total % 60; /* ticks / hz % 60 */
218 total /= 60;
219 mm = total % 60; /* ticks / hz / 60 % 60 */
220 hh = total / 60; /* ticks / hz / 60 / 60 */
221
222 (void) fprintf(stderr, "%s ", label);
223
224 /* Display either padding or the elapsed hours */
225 if (hh == 0L) {
226 (void) fprintf(stderr, "%6c", ' ');
227 } else {
228 (void) fprintf(stderr, "%5ld:", hh);
229 }
230
231 /*
232 * Display either nothing or the elapsed minutes, zero
233 * padding (if hours > 0) or space padding (if not).
234 */
235 if (mm == 0L && hh == 0L) {
236 (void) fprintf(stderr, "%3c", ' ');
237 } else if (mm != 0L && hh == 0L) {
238 (void) fprintf(stderr, "%2ld:", mm);
239 } else {
240 (void) fprintf(stderr, "%02ld:", mm);
241 }
242
243 /*
244 * Display the elapsed seconds; seconds are always
245 * zero padded.
246 */
247 if (hh == 0L && mm == 0L) {
248 (void) fprintf(stderr, "%2ld.", ss);
249 } else {
250 (void) fprintf(stderr, "%02ld.", ss);
251 }
252
253 /* Display hundredths of a second. */
254 (void) fprintf(stderr, "%02ld\n", tk * 100/hz);
255 }
256
257 /*
258 * hmstime() sets current time in hh:mm:ss string format in stime;
259 */
260
261 void
hmstime(char stime[])262 hmstime(char stime[])
263 {
264 char *ltime;
265 time_t tme;
266
267 tme = time((time_t *)0);
268 ltime = ctime(&tme);
269 strncpy(stime, ltime+11, 8);
270 stime[8] = '\0';
271 }
272
273 void
usage()274 usage()
275 {
276 fprintf(stderr, "Usage: timex [-o] [-p [-fhkmrt]] [-s] command\n");
277 unlink(fname);
278 exit(EXIT_FAILURE);
279 }
280