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 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 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 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 274 usage() 275 { 276 fprintf(stderr, "Usage: timex [-o] [-p [-fhkmrt]] [-s] command\n"); 277 unlink(fname); 278 exit(EXIT_FAILURE); 279 } 280