xref: /illumos-gate/usr/src/cmd/acct/acctprc1.c (revision e3ae4b35c024af1196582063ecee3ab79367227d)
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