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