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 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.11 */ 31 32 /* 33 * acctprc1 [ctmpfile] 34 * reads std. input (acct.h format), adds login names 35 * writes std. output (ptmp.h/ascii format) 36 * if ctmpfile is given, it is expected have ctmp.h/ascii data, 37 * sorted by uid/name; it is used to make better guesses at login names 38 */ 39 40 #include <sys/types.h> 41 #include <sys/param.h> 42 #include "acctdef.h" 43 #include <stdio.h> 44 #include <errno.h> 45 #include <sys/acct.h> 46 #define MYKIND(flag) ((flag & ACCTF) == 0) 47 48 struct acct ab; 49 struct ctmp cb; 50 struct ptmp pb; 51 52 int a_usize = A_USIZE; 53 struct urec { /* 1 for each distinct uid/name */ 54 uid_t ur_uid; /* sorted by uid/name */ 55 char ur_name[NSZ]; 56 struct srec *ur_srec; /* ptr to first session */ 57 short ur_cnt; /* # sessions */ 58 } * ur; 59 60 struct urec *urlast; 61 62 int a_ssize = A_SSIZE; 63 int ssize; 64 65 struct srec { /* 1 for each distinct session */ 66 dev_t sr_tty; /* dev, used to connect with process*/ 67 time_t sr_start; /* start time of session */ 68 time_t sr_end; /* end time of session */ 69 } * sr; 70 71 char *getname(uid_t, dev_t, time_t); 72 void readctmp(char *); 73 char *getnamc(uid_t, dev_t, time_t); 74 int aread(int); 75 76 char *uidtonam(); 77 78 int 79 main(int argc, char **argv) 80 { 81 long elaps[2]; 82 ulong_t etime, stime; 83 unsigned long mem; 84 ulong_t expand(); 85 int ver; /* version of acct struct */ 86 int aread(); 87 88 if ((ur = (struct urec *) calloc(a_usize, 89 sizeof (struct urec))) == NULL) { 90 fprintf(stderr, "acctpr1: Cannot allocate memory\n"); 91 exit(3); 92 } 93 94 urlast = ur; 95 if ((sr = (struct srec *) calloc(a_ssize, 96 sizeof (struct srec))) == NULL) { 97 fprintf(stderr, "acctpr1: Cannot allocate memory\n"); 98 exit(3); 99 } 100 101 while (--argc > 0) { 102 if (**++argv == '-') 103 switch(*++*argv) { 104 } 105 else { 106 readctmp(*argv); 107 } 108 } 109 110 111 if (fread((char *)&ab, sizeof(struct acct), 1, stdin) != 1) 112 return; 113 else if (ab.ac_flag & AEXPND) 114 ver = 2; /* 4.0 acct structure */ 115 else 116 ver = 1; /* 3.x acct structure */ 117 118 rewind(stdin); 119 120 while (aread(ver) == 1) { 121 if (!MYKIND(ab.ac_flag)) 122 continue; 123 pb.pt_uid = ab.ac_uid; 124 CPYN(pb.pt_name, getname(ab.ac_uid, ab.ac_tty, ab.ac_btime)); 125 /* 126 * approximate cpu P/NP split as same as elapsed time 127 */ 128 if ((etime = SECS(expand(ab.ac_etime))) == 0) 129 etime = 1; 130 stime = expand(ab.ac_stime) + expand(ab.ac_utime); 131 mem = expand(ab.ac_mem); 132 if(pnpsplit(ab.ac_btime, etime, elaps) == 0) { 133 fprintf(stderr, "acctprc1: could not calculate prime/non-prime hours\n"); 134 135 exit(1); 136 } 137 pb.pt_cpu[0] = (double)stime * (double)elaps[0] / etime; 138 pb.pt_cpu[1] = (stime > pb.pt_cpu[0])? stime - pb.pt_cpu[0] : 0; 139 pb.pt_cpu[1] = stime - pb.pt_cpu[0]; 140 if (stime) 141 pb.pt_mem = (mem + stime - 1) / stime; 142 else 143 pb.pt_mem = 0; /* unlikely */ 144 printf("%ld\t%.*s\t%lu\t%lu\t%u\n", 145 pb.pt_uid, 146 OUTPUT_NSZ, 147 pb.pt_name, 148 pb.pt_cpu[0], pb.pt_cpu[1], 149 pb.pt_mem); 150 } 151 152 exit(0); 153 } 154 155 /* 156 * return ptr to name corresponding to uid 157 * try ctmp first, then use uidtonam (internal list or passwd file) 158 */ 159 char * 160 getname(uid_t uid, dev_t tty, time_t start) 161 { 162 char *p; 163 164 if ((p = getnamc(uid, tty, start)) != NULL) 165 return (p); 166 return (uidtonam(uid)); 167 } 168 169 /* 170 * read ctmp file, build up urec-srec data structures for 171 * later use by getnamc 172 */ 173 void 174 readctmp(char *fname) 175 { 176 FILE *fp; 177 struct urec *up; 178 struct srec *sp; 179 int i = 0, j = 0, k=0; 180 181 if ((fp = fopen(fname, "r")) == NULL) { 182 fprintf(stderr, "acctprc1: can't open %s\n", fname); 183 return; 184 } 185 186 up = NULL; 187 sp = sr; 188 189 while (fscanf(fp, "%hd\t%ld\t%s\t%lu\t%lu\t%lu\t%*[^\n]", 190 &cb.ct_tty, 191 &cb.ct_uid, 192 cb.ct_name, 193 &cb.ct_con[0], 194 &cb.ct_con[1], 195 &cb.ct_start) != EOF) { 196 if (up == NULL || cb.ct_uid != up->ur_uid || 197 !EQN(cb.ct_name, up->ur_name)) { 198 if (up == NULL) 199 up = ur; 200 if (++up >= &ur[a_usize]) { 201 a_usize = a_usize + A_USIZE; 202 if ((ur = (struct urec *) realloc(ur, a_usize * 203 sizeof (struct urec))) == NULL) { 204 fprintf(stderr, "acctprc1: 1 Cannot reallocate memory\n"); 205 exit(2); 206 } 207 up = &ur[a_usize - A_USIZE]; 208 } 209 up->ur_uid = cb.ct_uid; 210 CPYN(up->ur_name, cb.ct_name); 211 up->ur_srec = sp; 212 up->ur_cnt = 0; 213 } 214 215 if (sp >= &sr[a_ssize-1]) { 216 a_ssize = a_ssize + A_SSIZE; 217 if ((sr = (struct srec *) realloc(sr, a_ssize * 218 sizeof (struct srec))) == NULL) { 219 fprintf(stderr, "acctprc1: 2 Cannot reallocate memory\n"); 220 printf("errno=%d\n", errno); 221 exit(2); 222 } 223 sp = &sr[a_ssize - A_SSIZE]; 224 } 225 226 sp->sr_tty = cb.ct_tty; 227 sp->sr_start = cb.ct_start; 228 sp->sr_end = cb.ct_start + cb.ct_con[0] + cb.ct_con[1]; 229 sp++; 230 up->ur_cnt++; 231 } 232 if (up != NULL) 233 urlast = ++up; 234 fclose(fp); 235 } 236 237 /* 238 * using urec-srec data (if any), make best guess at login name 239 * corresponding to uid, return ptr to the name. 240 * must match on tty; use start time to help guess 241 * for any urec having same uid as uid, search array of associated 242 * srecs for those having same tty 243 * if start time of process is within range of session, that's it 244 * if none can be found within range, give it to person of same uid 245 * who last logged off on that terminal 246 */ 247 char * 248 getnamc(uid_t uid, dev_t tty, time_t start) 249 { 250 struct urec *up; 251 struct srec *sp; 252 struct srec *splast; 253 long latest; 254 char *guess; 255 256 latest = 0; 257 guess = NULL; 258 for (up = ur; up < urlast && uid >= up->ur_uid; up++) 259 if (uid == up->ur_uid) { 260 sp = up->ur_srec; 261 splast = sp+up->ur_cnt; 262 for (; sp < splast; sp++) 263 if (tty == sp->sr_tty) { 264 if (start >= sp->sr_start && 265 start <= sp->sr_end) 266 return(up->ur_name); 267 if (start >= sp->sr_start && 268 sp->sr_end > latest) { 269 latest = sp->sr_end; 270 guess = up->ur_name; 271 } 272 } 273 } 274 275 return(guess); 276 } 277 int 278 aread(int ver) 279 { 280 struct o_acct oab; 281 int ret; 282 283 if (ver != 2) { 284 if ((ret = fread((char *)&oab, sizeof(struct o_acct), 1, stdin)) == 1){ 285 /* copy SVR3 acct struct to SVR4 acct struct */ 286 ab.ac_flag = oab.ac_flag | AEXPND; 287 ab.ac_stat = oab.ac_stat; 288 ab.ac_uid = (uid_t) oab.ac_uid; 289 ab.ac_gid = (gid_t) oab.ac_gid; 290 ab.ac_tty = (dev_t) oab.ac_tty; 291 ab.ac_btime = oab.ac_btime; 292 ab.ac_utime = oab.ac_utime; 293 ab.ac_stime = oab.ac_stime; 294 ab.ac_mem = oab.ac_mem; 295 ab.ac_io = oab.ac_io; 296 ab.ac_rw = oab.ac_rw; 297 strcpy(ab.ac_comm, oab.ac_comm); 298 } 299 } else 300 ret = fread((char *)&ab, sizeof(struct acct), 1, stdin); 301 302 303 return(ret != 1 ? 0 : 1); 304 } 305