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