xref: /original-bsd/usr.sbin/sa/sa.c (revision d25e1985)
1 static char *sccsid = "@(#)sa.c	4.1 (Berkeley) 10/01/80";
2 #include <stdio.h>
3 #include <sys/types.h>
4 #include <sys/acct.h>
5 #include <signal.h>
6 
7 /* interpret command time accounting */
8 
9 #define	size 	2500
10 #define	NC	sizeof(acctbuf.ac_comm)
11 struct acct acctbuf;
12 int	lflg;
13 int	cflg;
14 int	Dflg;
15 int	dflg;
16 int	iflg;
17 int	jflg;
18 int	Kflg;
19 int	kflg;
20 int	nflg;
21 int	aflg;
22 int	rflg;
23 int	oflg;
24 int	tflg;
25 int	vflg;
26 int	uflg;
27 int	thres	= 1;
28 int	sflg;
29 int	bflg;
30 int	mflg;
31 
32 struct	user {
33 	int	us_cnt;
34 	double	us_ctime;
35 	double	us_io;
36 	double	us_imem;
37 } user[1000];
38 
39 struct	tab {
40 	char	name[NC];
41 	int	count;
42 	double	realt;
43 	double	cput;
44 	double	syst;
45 	double	imem;
46 	double	io;
47 } tab[size];
48 
49 double	treal;
50 double	tcpu;
51 double	tsys;
52 double	tio;
53 double	timem;
54 int	junkp = -1;
55 char	*sname;
56 double	ncom;
57 time_t	expand();
58 char	*getname();
59 
60 main(argc, argv)
61 char **argv;
62 {
63 	FILE *ff;
64 	int i, j, k;
65 	int (*cmp)();
66 	extern tcmp(), ncmp(), bcmp(), dcmp(), Dcmp(), kcmp(), Kcmp();
67 	extern double sum();
68 	double ft;
69 
70 	cmp = tcmp;
71 	if (argc>1)
72 	if (argv[1][0]=='-') {
73 		argv++;
74 		argc--;
75 		for(i=1; argv[0][i]; i++)
76 		switch(argv[0][i]) {
77 
78 		case 'o':
79 			oflg++;
80 			break;
81 
82 		case 'i':
83 			iflg++;
84 			break;
85 
86 		case 'b':
87 			bflg++;
88 			cmp = bcmp;
89 			break;
90 
91 		case 'l':
92 			lflg++;
93 			break;
94 
95 		case 'c':
96 			cflg++;
97 			break;
98 
99 		case 'd':
100 			dflg++;
101 			cmp = dcmp;
102 			break;
103 
104 		case 'D':
105 			Dflg++;
106 			cmp = Dcmp;
107 			break;
108 
109 		case 'j':
110 			jflg++;
111 			break;
112 
113 		case 'k':
114 			kflg++;
115 			cmp = kcmp;
116 			break;
117 
118 		case 'K':
119 			Kflg++;
120 			cmp = Kcmp;
121 			break;
122 
123 		case 'n':
124 			nflg++;
125 			cmp = ncmp;
126 			break;
127 
128 		case 'a':
129 			aflg++;
130 			break;
131 
132 		case 'r':
133 			rflg++;
134 			break;
135 
136 		case 't':
137 			tflg++;
138 			break;
139 
140 		case 's':
141 			sflg++;
142 			aflg++;
143 			break;
144 
145 		case '0':
146 		case '1':
147 		case '2':
148 		case '3':
149 		case '4':
150 		case '5':
151 		case '6':
152 		case '7':
153 		case '8':
154 		case '9':
155 			thres = argv[0][i]-'0';
156 			break;
157 
158 		case 'v':
159 			vflg++;
160 			break;
161 
162 		case 'u':
163 			uflg++;
164 			break;
165 
166 		case 'm':
167 			mflg++;
168 			break;
169 		}
170 	}
171 	if (iflg==0)
172 		init();
173 	if (argc<2)
174 		doacct("/usr/adm/acct");
175 	else while (--argc)
176 		doacct(*++argv);
177 	if (uflg) {
178 		return;
179 	}
180 
181 /*
182  * cleanup pass
183  * put junk together
184  */
185 
186 	if (vflg)
187 		strip();
188 	if(!aflg)
189 	for (i=0; i<size; i++)
190 	if (tab[i].name[0]) {
191 		for(j=0; j<NC; j++)
192 			if(tab[i].name[j] == '?')
193 				goto yes;
194 		if(tab[i].count != 1)
195 			continue;
196 	yes:
197 		if(junkp == -1)
198 			junkp = enter("***other");
199 		tab[junkp].count += tab[i].count;
200 		tab[junkp].realt += tab[i].realt;
201 		tab[junkp].cput += tab[i].cput;
202 		tab[junkp].syst += tab[i].syst;
203 		tab[junkp].imem += tab[i].imem;
204 		tab[junkp].io += tab[i].io;
205 		tab[i].name[0] = 0;
206 	}
207 	for(i=k=0; i<size; i++)
208 	if(tab[i].name[0]) {
209 		tab[k] = tab[i];
210 		k++;
211 	}
212 	if (sflg) {
213 		signal(SIGINT, SIG_IGN);
214 		if ((ff = fopen("/usr/adm/usracct", "w")) != NULL) {
215 			fwrite((char *)user, sizeof(user), 1, ff);
216 			fclose(ff);
217 		}
218 		if ((ff = fopen("/usr/adm/savacct", "w")) == NULL) {
219 			printf("Can't save\n");
220 			exit(0);
221 		}
222 		fwrite((char *)tab, sizeof(tab[0]), k, ff);
223 		fclose(ff);
224 		creat("/usr/adm/acct", 0644);
225 		signal(SIGINT, SIG_DFL);
226 	}
227 /*
228  * sort and print
229  */
230 
231 	if (mflg) {
232 		printmoney();
233 		exit(0);
234 	}
235 	qsort(tab, k, sizeof(tab[0]), cmp);
236 	column(ncom, treal, tcpu, tsys, timem, tio);
237 	printf("\n");
238 	for (i=0; i<k; i++)
239 	if (tab[i].name[0]) {
240 		ft = tab[i].count;
241 		column(ft, tab[i].realt, tab[i].cput, tab[i].syst, tab[i].imem, tab[i].io);
242 		printf("   %.14s\n", tab[i].name);
243 	}
244 }
245 
246 printmoney()
247 {
248 	register i;
249 	char buf[128];
250 	register char *cp;
251 
252 	for (i=0; i<sizeof(user)/sizeof(user[0]); i++) {
253 		if (user[i].us_cnt && user[i].us_ctime) {
254 			cp = getname(i);
255 			if (cp == 0)
256 				printf("%-8d", i);
257 			else
258 				printf("%-8s", cp);
259 			printf("%7u %9.2fcpu %10.0ftio %12.0fk*sec\n",
260 			    user[i].us_cnt, user[i].us_ctime/60,
261 			    user[i].us_io,
262 			    user[i].us_imem / (60 * 2));
263 		}
264 	}
265 }
266 
267 column(n, a, b, c, d, e)
268 double n, a, b, c, d, e;
269 {
270 
271 	printf("%8.0f", n);
272 	if(cflg) {
273 		if(n == ncom)
274 			printf("%9s", ""); else
275 			printf("%8.2f%%", 100.*n/ncom);
276 	}
277 	col(n, a, treal, "re");
278 	if (oflg)
279 		col(n, 3600*(b/(b+c)), tcpu+tsys, "u/s");
280 	else if(lflg) {
281 		col(n, b, tcpu, "u");
282 		col(n, c, tsys, "s");
283 	} else
284 		col(n, b+c, tcpu+tsys, "cp");
285 	if(tflg)
286 		printf("%8.1f", a/(b+c), "re/cp");
287 	if(dflg || !Dflg)
288 		printf("%10.0favio", e/(n?n:1));
289 	else
290 		printf("%10.0ftio", e);
291 	if (kflg || !Kflg)
292 		printf("%10.0fk", d/(2*((b+c)!=0.0?(b+c):1.0)));
293 	else
294 		printf("%10.0fk*sec", d/(2*60));
295 }
296 
297 col(n, a, m, cp)
298 double n, a, m;
299 char *cp;
300 {
301 
302 	if(jflg)
303 		printf("%11.2f%s", a/(n*60.), cp); else
304 		printf("%11.2f%s", a/3600., cp);
305 	if(cflg) {
306 		if(a == m)
307 			printf("%9s", ""); else
308 			printf("%8.2f%%", 100.*a/m);
309 	}
310 }
311 
312 doacct(f)
313 char *f;
314 {
315 	int i;
316 	FILE *ff;
317 	long x, y, z;
318 	struct acct fbuf;
319 	register char *cp;
320 	register int c;
321 
322 	if (sflg && sname) {
323 		printf("Only 1 file with -s\n");
324 		exit(0);
325 	}
326 	if (sflg)
327 		sname = f;
328 	if ((ff = fopen(f, "r"))==NULL) {
329 		printf("Can't open %s\n", f);
330 		return;
331 	}
332 	while (fread((char *)&fbuf, sizeof(fbuf), 1, ff) == 1) {
333 		if (fbuf.ac_comm[0]==0) {
334 			fbuf.ac_comm[0] = '?';
335 		}
336 		for (cp = fbuf.ac_comm; cp < &fbuf.ac_comm[NC]; cp++) {
337 			c = *cp & 0377;
338 			if (c && (c < ' ' || c >= 0200)) {
339 				*cp = '?';
340 			}
341 		}
342 		if (fbuf.ac_flag&AFORK) {
343 			for (cp=fbuf.ac_comm; cp < &fbuf.ac_comm[NC]; cp++)
344 				if (*cp==0) {
345 					*cp = '*';
346 					break;
347 				}
348 		}
349 		x = expand(fbuf.ac_utime) + expand(fbuf.ac_stime);
350 		y = fbuf.ac_mem;
351 		z = expand(fbuf.ac_io);
352 		if (uflg) {
353 			printf("%3d%6.1fcp %6dmem %6dio %.14s\n",
354 			    fbuf.ac_uid, x/60.0, y, z,
355 			    fbuf.ac_comm);
356 			continue;
357 		}
358 		c = fbuf.ac_uid;
359 		user[c].us_cnt++;
360 		user[c].us_ctime += x/60.;
361 		user[c].us_imem += x * y;
362 		user[c].us_io += z;
363 		ncom += 1.0;
364 		i = enter(fbuf.ac_comm);
365 		tab[i].imem += x * y;
366 		timem += x * y;
367 		tab[i].count++;
368 		x = expand(fbuf.ac_etime)*60;
369 		tab[i].realt += x;
370 		treal += x;
371 		x = expand(fbuf.ac_utime);
372 		tab[i].cput += x;
373 		tcpu += x;
374 		x = expand(fbuf.ac_stime);
375 		tab[i].syst += x;
376 		tsys += x;
377 		tab[i].io += z;
378 		tio += z;
379 	}
380 	fclose(ff);
381 }
382 
383 ncmp(p1, p2)
384 struct tab *p1, *p2;
385 {
386 
387 	if(p1->count == p2->count)
388 		return(tcmp(p1, p2));
389 	if(rflg)
390 		return(p1->count - p2->count);
391 	return(p2->count - p1->count);
392 }
393 
394 bcmp(p1, p2)
395 struct tab *p1, *p2;
396 {
397 	double f1, f2;
398 	double sum();
399 
400 	f1 = sum(p1)/p1->count;
401 	f2 = sum(p2)/p2->count;
402 	if(f1 < f2) {
403 		if(rflg)
404 			return(-1);
405 		return(1);
406 	}
407 	if(f1 > f2) {
408 		if(rflg)
409 			return(1);
410 		return(-1);
411 	}
412 	return(0);
413 }
414 
415 Kcmp(p1, p2)
416 struct tab *p1, *p2;
417 {
418 
419 	if (p1->imem < p2->imem) {
420 		if(rflg)
421 			return(-1);
422 		return(1);
423 	}
424 	if (p1->imem > p2->imem) {
425 		if(rflg)
426 			return(1);
427 		return(-1);
428 	}
429 	return(0);
430 }
431 
432 kcmp(p1, p2)
433 struct tab *p1, *p2;
434 {
435 	double a1, a2;
436 
437 	a1 = p1->imem / ((p1->cput+p1->syst)?(p1->cput+p1->syst):1);
438 	a2 = p2->imem / ((p2->cput+p2->syst)?(p2->cput+p2->syst):1);
439 	if (a1 < a2) {
440 		if(rflg)
441 			return(-1);
442 		return(1);
443 	}
444 	if (a1 > a2) {
445 		if(rflg)
446 			return(1);
447 		return(-1);
448 	}
449 	return(0);
450 }
451 
452 dcmp(p1, p2)
453 struct tab *p1, *p2;
454 {
455 	double a1, a2;
456 
457 	a1 = p1->io / (p1->count?p1->count:1);
458 	a2 = p2->io / (p2->count?p2->count:1);
459 	if (a1 < a2) {
460 		if(rflg)
461 			return(-1);
462 		return(1);
463 	}
464 	if (a1 > a2) {
465 		if(rflg)
466 			return(1);
467 		return(-1);
468 	}
469 	return(0);
470 }
471 
472 Dcmp(p1, p2)
473 struct tab *p1, *p2;
474 {
475 
476 	if (p1->io < p2->io) {
477 		if(rflg)
478 			return(-1);
479 		return(1);
480 	}
481 	if (p1->io > p2->io) {
482 		if(rflg)
483 			return(1);
484 		return(-1);
485 	}
486 	return(0);
487 }
488 
489 tcmp(p1, p2)
490 struct tab *p1, *p2;
491 {
492 	extern double sum();
493 	double f1, f2;
494 
495 	f1 = sum(p1);
496 	f2 = sum(p2);
497 	if(f1 < f2) {
498 		if(rflg)
499 			return(-1);
500 		return(1);
501 	}
502 	if(f1 > f2) {
503 		if(rflg)
504 			return(1);
505 		return(-1);
506 	}
507 	return(0);
508 }
509 
510 double sum(p)
511 struct tab *p;
512 {
513 
514 	if(p->name[0] == 0)
515 		return(0.0);
516 	return(
517 		p->cput+
518 		p->syst);
519 }
520 
521 init()
522 {
523 	struct tab tbuf;
524 	int i;
525 	FILE *f;
526 
527 	if ((f = fopen("/usr/adm/savacct", "r")) == NULL)
528 		goto gshm;
529 	while (fread((char *)&tbuf, sizeof(tbuf), 1, f) == 1) {
530 		i = enter(tbuf.name);
531 		ncom += tbuf.count;
532 		tab[i].count = tbuf.count;
533 		treal += tbuf.realt;
534 		tab[i].realt = tbuf.realt;
535 		tcpu += tbuf.cput;
536 		tab[i].cput = tbuf.cput;
537 		tsys += tbuf.syst;
538 		tab[i].syst = tbuf.syst;
539 		tio += tbuf.io;
540 		tab[i].io = tbuf.io;
541 		timem += tbuf.imem;
542 		tab[i].imem = tbuf.imem;
543 	}
544 	fclose(f);
545  gshm:
546 	if ((f = fopen("/usr/adm/usracct", "r")) == NULL)
547 		return;
548 	fread((char *)user, sizeof(user), 1, f);
549 	fclose(f);
550 }
551 
552 enter(np)
553 char *np;
554 {
555 	int i, j;
556 
557 	for (i=j=0; i<NC; i++) {
558 		if (np[i]==0)
559 			j = i;
560 		if (j)
561 			np[i] = 0;
562 	}
563 	for (i=j=0; j<NC; j++) {
564 		i = i*7 + np[j];
565 	}
566 	if (i < 0)
567 		i = -i;
568 	for (i%=size; tab[i].name[0]; i = (i+1)%size) {
569 		for (j=0; j<NC; j++)
570 			if (tab[i].name[j]!=np[j])
571 				goto no;
572 		goto yes;
573 	no:;
574 	}
575 	for (j=0; j<NC; j++)
576 		tab[i].name[j] = np[j];
577 yes:
578 	return(i);
579 }
580 
581 strip()
582 {
583 	int i, j, c;
584 
585 	j = enter("**junk**");
586 	for (i = 0; i<size; i++) {
587 		if (tab[i].name[0] && tab[i].count<=thres) {
588 			printf("%.14s--", tab[i].name);
589 			if ((c=getchar())=='y') {
590 				tab[i].name[0] = '\0';
591 				tab[j].count += tab[i].count;
592 				tab[j].realt += tab[i].realt;
593 				tab[j].cput += tab[i].cput;
594 				tab[j].syst += tab[i].syst;
595 			}
596 			while (c && c!='\n')
597 				c = getchar();
598 		}
599 	}
600 }
601 
602 time_t
603 expand(t)
604 unsigned t;
605 {
606 	register time_t nt;
607 
608 	nt = t&017777;
609 	t >>= 13;
610 	while (t!=0) {
611 		t--;
612 		nt <<= 3;
613 	}
614 	return(nt);
615 }
616 
617 #include <utmp.h>
618 #include <pwd.h>
619 
620 struct	utmp utmp;
621 #define	NMAX	sizeof (utmp.ut_name)
622 #define	NUID	2048
623 
624 char	names[NUID][NMAX+1];
625 
626 char *
627 getname(uid)
628 {
629 	register struct passwd *pw;
630 	static init;
631 	struct passwd *getpwent();
632 
633 	if (names[uid][0])
634 		return (&names[uid][0]);
635 	if (init == 2)
636 		return (0);
637 	if (init == 0)
638 		setpwent(), init = 1;
639 	while (pw = getpwent()) {
640 		if (pw->pw_uid >= NUID)
641 			continue;
642 		if (names[pw->pw_uid][0])
643 			continue;
644 		strncpy(names[pw->pw_uid], pw->pw_name, NMAX);
645 		if (pw->pw_uid == uid)
646 			return (&names[uid][0]);
647 	}
648 	init = 2;
649 	endpwent();
650 	return (0);
651 }
652