1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <stdio.h> 30*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 31*7c478bd9Sstevel@tonic-gate #include <unistd.h> 32*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 33*7c478bd9Sstevel@tonic-gate #include <string.h> 34*7c478bd9Sstevel@tonic-gate #include <errno.h> 35*7c478bd9Sstevel@tonic-gate #include <math.h> 36*7c478bd9Sstevel@tonic-gate #include <wait.h> 37*7c478bd9Sstevel@tonic-gate #include <signal.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/time.h> 40*7c478bd9Sstevel@tonic-gate #include <signal.h> 41*7c478bd9Sstevel@tonic-gate #include <libproc.h> 42*7c478bd9Sstevel@tonic-gate 43*7c478bd9Sstevel@tonic-gate static int look(pid_t); 44*7c478bd9Sstevel@tonic-gate static void hr_min_sec(char *, long); 45*7c478bd9Sstevel@tonic-gate static void prtime(char *, timestruc_t *); 46*7c478bd9Sstevel@tonic-gate static int perr(const char *); 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate static void tsadd(timestruc_t *result, timestruc_t *a, timestruc_t *b); 49*7c478bd9Sstevel@tonic-gate static void tssub(timestruc_t *result, timestruc_t *a, timestruc_t *b); 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate static char *command; 52*7c478bd9Sstevel@tonic-gate static char procname[64]; 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate int 55*7c478bd9Sstevel@tonic-gate main(int argc, char **argv) 56*7c478bd9Sstevel@tonic-gate { 57*7c478bd9Sstevel@tonic-gate pid_t pid; 58*7c478bd9Sstevel@tonic-gate struct siginfo info; 59*7c478bd9Sstevel@tonic-gate int status; 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate if ((command = strrchr(argv[0], '/')) != NULL) 62*7c478bd9Sstevel@tonic-gate command++; 63*7c478bd9Sstevel@tonic-gate else 64*7c478bd9Sstevel@tonic-gate command = argv[0]; 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate if (argc <= 1) { 67*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 68*7c478bd9Sstevel@tonic-gate "usage:\t%s command [ args ... ]\n", command); 69*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 70*7c478bd9Sstevel@tonic-gate " (time a command using microstate accounting)\n"); 71*7c478bd9Sstevel@tonic-gate return (1); 72*7c478bd9Sstevel@tonic-gate } 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate switch (pid = fork()) { 75*7c478bd9Sstevel@tonic-gate case -1: 76*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot fork: %s\n", 77*7c478bd9Sstevel@tonic-gate command, strerror(errno)); 78*7c478bd9Sstevel@tonic-gate return (2); 79*7c478bd9Sstevel@tonic-gate case 0: 80*7c478bd9Sstevel@tonic-gate (void) execvp(argv[1], &argv[1]); 81*7c478bd9Sstevel@tonic-gate status = (errno == ENOENT) ? 127 : 126; /* see time(1) */ 82*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: failed to exec %s: %s\n", 83*7c478bd9Sstevel@tonic-gate command, argv[1], strerror(errno)); 84*7c478bd9Sstevel@tonic-gate _exit(status); 85*7c478bd9Sstevel@tonic-gate } 86*7c478bd9Sstevel@tonic-gate 87*7c478bd9Sstevel@tonic-gate (void) sprintf(procname, "%d", (int)pid); /* for perr() */ 88*7c478bd9Sstevel@tonic-gate (void) signal(SIGINT, SIG_IGN); 89*7c478bd9Sstevel@tonic-gate (void) signal(SIGQUIT, SIG_IGN); 90*7c478bd9Sstevel@tonic-gate (void) waitid(P_PID, pid, &info, WEXITED | WNOWAIT); 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate (void) look(pid); 93*7c478bd9Sstevel@tonic-gate 94*7c478bd9Sstevel@tonic-gate (void) waitpid(pid, &status, 0); 95*7c478bd9Sstevel@tonic-gate 96*7c478bd9Sstevel@tonic-gate if (WIFEXITED(status)) 97*7c478bd9Sstevel@tonic-gate return (WEXITSTATUS(status)); 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate if (WIFSIGNALED(status)) { 100*7c478bd9Sstevel@tonic-gate int sig = WTERMSIG(status); 101*7c478bd9Sstevel@tonic-gate char name[SIG2STR_MAX]; 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: command terminated abnormally by " 104*7c478bd9Sstevel@tonic-gate "%s\n", command, proc_signame(sig, name, sizeof (name))); 105*7c478bd9Sstevel@tonic-gate } 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate return (status | WCOREFLG); /* see time(1) */ 108*7c478bd9Sstevel@tonic-gate } 109*7c478bd9Sstevel@tonic-gate 110*7c478bd9Sstevel@tonic-gate static int 111*7c478bd9Sstevel@tonic-gate look(pid_t pid) 112*7c478bd9Sstevel@tonic-gate { 113*7c478bd9Sstevel@tonic-gate char pathname[100]; 114*7c478bd9Sstevel@tonic-gate int rval = 0; 115*7c478bd9Sstevel@tonic-gate int fd; 116*7c478bd9Sstevel@tonic-gate psinfo_t psinfo; 117*7c478bd9Sstevel@tonic-gate prusage_t prusage; 118*7c478bd9Sstevel@tonic-gate timestruc_t real, user, sys; 119*7c478bd9Sstevel@tonic-gate prusage_t *pup = &prusage; 120*7c478bd9Sstevel@tonic-gate 121*7c478bd9Sstevel@tonic-gate if (proc_get_psinfo(pid, &psinfo) < 0) 122*7c478bd9Sstevel@tonic-gate return (perr("read psinfo")); 123*7c478bd9Sstevel@tonic-gate 124*7c478bd9Sstevel@tonic-gate (void) sprintf(pathname, "/proc/%d/usage", (int)pid); 125*7c478bd9Sstevel@tonic-gate if ((fd = open(pathname, O_RDONLY)) < 0) 126*7c478bd9Sstevel@tonic-gate return (perr("open usage")); 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate if (read(fd, &prusage, sizeof (prusage)) != sizeof (prusage)) 129*7c478bd9Sstevel@tonic-gate rval = perr("read usage"); 130*7c478bd9Sstevel@tonic-gate else { 131*7c478bd9Sstevel@tonic-gate real = pup->pr_term; 132*7c478bd9Sstevel@tonic-gate tssub(&real, &real, &pup->pr_create); 133*7c478bd9Sstevel@tonic-gate user = pup->pr_utime; 134*7c478bd9Sstevel@tonic-gate sys = pup->pr_stime; 135*7c478bd9Sstevel@tonic-gate tsadd(&sys, &sys, &pup->pr_ttime); 136*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\n"); 137*7c478bd9Sstevel@tonic-gate prtime("real", &real); 138*7c478bd9Sstevel@tonic-gate prtime("user", &user); 139*7c478bd9Sstevel@tonic-gate prtime("sys", &sys); 140*7c478bd9Sstevel@tonic-gate } 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate (void) close(fd); 143*7c478bd9Sstevel@tonic-gate return (rval); 144*7c478bd9Sstevel@tonic-gate } 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate static void 147*7c478bd9Sstevel@tonic-gate hr_min_sec(char *buf, long sec) 148*7c478bd9Sstevel@tonic-gate { 149*7c478bd9Sstevel@tonic-gate if (sec >= 3600) 150*7c478bd9Sstevel@tonic-gate (void) sprintf(buf, "%ld:%.2ld:%.2ld", 151*7c478bd9Sstevel@tonic-gate sec / 3600, (sec % 3600) / 60, sec % 60); 152*7c478bd9Sstevel@tonic-gate else if (sec >= 60) 153*7c478bd9Sstevel@tonic-gate (void) sprintf(buf, "%ld:%.2ld", 154*7c478bd9Sstevel@tonic-gate sec / 60, sec % 60); 155*7c478bd9Sstevel@tonic-gate else 156*7c478bd9Sstevel@tonic-gate (void) sprintf(buf, "%ld", sec); 157*7c478bd9Sstevel@tonic-gate } 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate static void 160*7c478bd9Sstevel@tonic-gate prtime(char *name, timestruc_t *ts) 161*7c478bd9Sstevel@tonic-gate { 162*7c478bd9Sstevel@tonic-gate char buf[32]; 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate hr_min_sec(buf, ts->tv_sec); 165*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%-4s %8s.%.3u\n", 166*7c478bd9Sstevel@tonic-gate name, buf, (uint_t)ts->tv_nsec/1000000); 167*7c478bd9Sstevel@tonic-gate } 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate static int 170*7c478bd9Sstevel@tonic-gate perr(const char *s) 171*7c478bd9Sstevel@tonic-gate { 172*7c478bd9Sstevel@tonic-gate if (s) 173*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", procname); 174*7c478bd9Sstevel@tonic-gate else 175*7c478bd9Sstevel@tonic-gate s = procname; 176*7c478bd9Sstevel@tonic-gate perror(s); 177*7c478bd9Sstevel@tonic-gate return (1); 178*7c478bd9Sstevel@tonic-gate } 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate static void 181*7c478bd9Sstevel@tonic-gate tsadd(timestruc_t *result, timestruc_t *a, timestruc_t *b) 182*7c478bd9Sstevel@tonic-gate { 183*7c478bd9Sstevel@tonic-gate result->tv_sec = a->tv_sec + b->tv_sec; 184*7c478bd9Sstevel@tonic-gate if ((result->tv_nsec = a->tv_nsec + b->tv_nsec) >= 1000000000) { 185*7c478bd9Sstevel@tonic-gate result->tv_nsec -= 1000000000; 186*7c478bd9Sstevel@tonic-gate result->tv_sec += 1; 187*7c478bd9Sstevel@tonic-gate } 188*7c478bd9Sstevel@tonic-gate } 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate static void 191*7c478bd9Sstevel@tonic-gate tssub(timestruc_t *result, timestruc_t *a, timestruc_t *b) 192*7c478bd9Sstevel@tonic-gate { 193*7c478bd9Sstevel@tonic-gate result->tv_sec = a->tv_sec - b->tv_sec; 194*7c478bd9Sstevel@tonic-gate if ((result->tv_nsec = a->tv_nsec - b->tv_nsec) < 0) { 195*7c478bd9Sstevel@tonic-gate result->tv_nsec += 1000000000; 196*7c478bd9Sstevel@tonic-gate result->tv_sec -= 1; 197*7c478bd9Sstevel@tonic-gate } 198*7c478bd9Sstevel@tonic-gate } 199