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