xref: /original-bsd/usr.sbin/pstat/pstat.c (revision ec7df300)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 char copyright[] =
9 "@(#) Copyright (c) 1980 Regents of the University of California.\n\
10  All rights reserved.\n";
11 #endif not lint
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)pstat.c	5.1 (Berkeley) 06/04/85";
15 #endif not lint
16 
17 /*
18  * Print system stuff
19  */
20 
21 #define mask(x) (x&0377)
22 #define	clear(x) ((int)x&0x7fffffff)
23 
24 #include <sys/param.h>
25 #include <sys/dir.h>
26 #define	KERNEL
27 #include <sys/file.h>
28 #undef	KERNEL
29 #include <sys/user.h>
30 #include <sys/proc.h>
31 #include <sys/text.h>
32 #include <sys/inode.h>
33 #include <sys/map.h>
34 #include <sys/ioctl.h>
35 #include <sys/tty.h>
36 #include <sys/conf.h>
37 #include <sys/vm.h>
38 #include <nlist.h>
39 #include <machine/pte.h>
40 
41 char	*fcore	= "/dev/kmem";
42 char	*fmem	= "/dev/mem";
43 char	*fnlist	= "/vmunix";
44 int	fc, fm;
45 
46 struct nlist nl[] = {
47 #define	SINODE	0
48 	{ "_inode" },
49 #define	STEXT	1
50 	{ "_text" },
51 #define	SPROC	2
52 	{ "_proc" },
53 #define	SDZ	3
54 	{ "_dz_tty" },
55 #define	SNDZ	4
56 	{ "_dz_cnt" },
57 #define	SKL	5
58 	{ "_cons" },
59 #define	SFIL	6
60 	{ "_file" },
61 #define	USRPTMA	7
62 	{ "_Usrptmap" },
63 #define	USRPT	8
64 	{ "_usrpt" },
65 #define	SWAPMAP	9
66 	{ "_swapmap" },
67 #define	SDH	10
68 	{ "_dh11" },
69 #define	SNDH	11
70 	{ "_ndh11" },
71 #define	SNPROC	12
72 	{ "_nproc" },
73 #define	SNTEXT	13
74 	{ "_ntext" },
75 #define	SNFILE	14
76 	{ "_nfile" },
77 #define	SNINODE	15
78 	{ "_ninode" },
79 #define	SNSWAPMAP 16
80 	{ "_nswapmap" },
81 #define	SPTY	17
82 	{ "_pt_tty" },
83 #define	SDMMIN	18
84 	{ "_dmmin" },
85 #define	SDMMAX	19
86 	{ "_dmmax" },
87 #define	SNSWDEV	20
88 	{ "_nswdev" },
89 #define	SSWDEVT	21
90 	{ "_swdevt" },
91 #define	SDMF	22
92 	{ "_dmf_tty" },
93 #define	SNDMF	23
94 	{ "_ndmf" },
95 #define	SNPTY	24
96 	{ "_npty" },
97 	{ "" }
98 };
99 
100 int	inof;
101 int	txtf;
102 int	prcf;
103 int	ttyf;
104 int	usrf;
105 long	ubase;
106 int	filf;
107 int	swpf;
108 int	totflg;
109 char	partab[1];
110 struct	cdevsw	cdevsw[1];
111 struct	bdevsw	bdevsw[1];
112 int	allflg;
113 int	kflg;
114 struct	pte *Usrptma;
115 struct	pte *usrpt;
116 
117 main(argc, argv)
118 char **argv;
119 {
120 	register char *argp;
121 	int allflags;
122 
123 	argc--, argv++;
124 	while (argc > 0 && **argv == '-') {
125 		argp = *argv++;
126 		argp++;
127 		argc--;
128 		while (*argp++)
129 		switch (argp[-1]) {
130 
131 		case 'T':
132 			totflg++;
133 			break;
134 
135 		case 'a':
136 			allflg++;
137 			break;
138 
139 		case 'i':
140 			inof++;
141 			break;
142 
143 		case 'k':
144 			kflg++;
145 			fcore = fmem = "/vmcore";
146 			break;
147 
148 		case 'x':
149 			txtf++;
150 			break;
151 
152 		case 'p':
153 			prcf++;
154 			break;
155 
156 		case 't':
157 			ttyf++;
158 			break;
159 
160 		case 'u':
161 			if (argc == 0)
162 				break;
163 			argc--;
164 			usrf++;
165 			sscanf( *argv++, "%x", &ubase);
166 			break;
167 
168 		case 'f':
169 			filf++;
170 			break;
171 		case 's':
172 			swpf++;
173 			break;
174 		default:
175 			usage();
176 			exit(1);
177 		}
178 	}
179 	if (argc>1)
180 		fcore = fmem = argv[1];
181 	if ((fc = open(fcore, 0)) < 0) {
182 		printf("Can't find %s\n", fcore);
183 		exit(1);
184 	}
185 	if ((fm = open(fmem, 0)) < 0) {
186 		printf("Can't find %s\n", fmem);
187 		exit(1);
188 	}
189 	if (argc>0)
190 		fnlist = argv[0];
191 	nlist(fnlist, nl);
192 	usrpt = (struct pte *)nl[USRPT].n_value;
193 	Usrptma = (struct pte *)nl[USRPTMA].n_value;
194 	if (nl[0].n_type == 0) {
195 		printf("no namelist\n");
196 		exit(1);
197 	}
198 	allflags = filf | totflg | inof | prcf | txtf | ttyf | usrf | swpf;
199 	if (allflags == 0) {
200 		printf("pstat: one or more of -[aixptfsu] is required\n");
201 		exit(1);
202 	}
203 	if (filf||totflg)
204 		dofile();
205 	if (inof||totflg)
206 		doinode();
207 	if (prcf||totflg)
208 		doproc();
209 	if (txtf||totflg)
210 		dotext();
211 	if (ttyf)
212 		dotty();
213 	if (usrf)
214 		dousr();
215 	if (swpf||totflg)
216 		doswap();
217 }
218 
219 usage()
220 {
221 
222 	printf("usage: pstat -[aixptfs] [-u [ubase]] [system] [core]\n");
223 }
224 
225 doinode()
226 {
227 	register struct inode *ip;
228 	struct inode *xinode, *ainode;
229 	register int nin;
230 	int ninode;
231 
232 	nin = 0;
233 	ninode = getw(nl[SNINODE].n_value);
234 	xinode = (struct inode *)calloc(ninode, sizeof (struct inode));
235 	lseek(fc, (int)(ainode = (struct inode *)getw(nl[SINODE].n_value)), 0);
236 	read(fc, xinode, ninode * sizeof(struct inode));
237 	for (ip = xinode; ip < &xinode[ninode]; ip++)
238 		if (ip->i_count)
239 			nin++;
240 	if (totflg) {
241 		printf("%3d/%3d inodes\n", nin, ninode);
242 		return;
243 	}
244 	printf("%d/%d active inodes\n", nin, ninode);
245 printf("   LOC      FLAGS    CNT DEVICE  RDC WRC  INO  MODE  NLK UID   SIZE/DEV\n");
246 	for (ip = xinode; ip < &xinode[ninode]; ip++) {
247 		if (ip->i_count == 0)
248 			continue;
249 		printf("%8.1x ", ainode + (ip - xinode));
250 		putf(ip->i_flag&ILOCKED, 'L');
251 		putf(ip->i_flag&IUPD, 'U');
252 		putf(ip->i_flag&IACC, 'A');
253 		putf(ip->i_flag&IMOUNT, 'M');
254 		putf(ip->i_flag&IWANT, 'W');
255 		putf(ip->i_flag&ITEXT, 'T');
256 		putf(ip->i_flag&ICHG, 'C');
257 		putf(ip->i_flag&ISHLOCK, 'S');
258 		putf(ip->i_flag&IEXLOCK, 'E');
259 		putf(ip->i_flag&ILWAIT, 'Z');
260 		printf("%4d", ip->i_count&0377);
261 		printf("%4d,%3d", major(ip->i_dev), minor(ip->i_dev));
262 		printf("%4d", ip->i_shlockc&0377);
263 		printf("%4d", ip->i_exlockc&0377);
264 		printf("%6d", ip->i_number);
265 		printf("%6x", ip->i_mode & 0xffff);
266 		printf("%4d", ip->i_nlink);
267 		printf("%4d", ip->i_uid);
268 		if ((ip->i_mode&IFMT)==IFBLK || (ip->i_mode&IFMT)==IFCHR)
269 			printf("%6d,%3d", major(ip->i_rdev), minor(ip->i_rdev));
270 		else
271 			printf("%10ld", ip->i_size);
272 		printf("\n");
273 	}
274 	free(xinode);
275 }
276 
277 getw(loc)
278 	off_t loc;
279 {
280 	int word;
281 
282 	if (kflg)
283 		loc &= 0x7fffffff;
284 	lseek(fc, loc, 0);
285 	read(fc, &word, sizeof (word));
286 	if (kflg)
287 		word &= 0x7fffffff;
288 	return (word);
289 }
290 
291 putf(v, n)
292 {
293 	if (v)
294 		printf("%c", n);
295 	else
296 		printf(" ");
297 }
298 
299 dotext()
300 {
301 	register struct text *xp;
302 	int ntext;
303 	struct text *xtext, *atext;
304 	int ntx;
305 
306 	ntx = 0;
307 	ntext = getw(nl[SNTEXT].n_value);
308 	xtext = (struct text *)calloc(ntext, sizeof (struct text));
309 	lseek(fc, (int)(atext = (struct text *)getw(nl[STEXT].n_value)), 0);
310 	read(fc, xtext, ntext * sizeof (struct text));
311 	for (xp = xtext; xp < &xtext[ntext]; xp++)
312 		if (xp->x_iptr!=NULL)
313 			ntx++;
314 	if (totflg) {
315 		printf("%3d/%3d texts\n", ntx, ntext);
316 		return;
317 	}
318 	printf("%d/%d active texts\n", ntx, ntext);
319 	printf("   LOC   FLAGS DADDR      CADDR  RSS SIZE      IPTR  CNT CCNT\n");
320 	for (xp = xtext; xp < &xtext[ntext]; xp++) {
321 		if (xp->x_iptr == NULL)
322 			continue;
323 		printf("%8.1x", atext + (xp - xtext));
324 		printf(" ");
325 		putf(xp->x_flag&XPAGI, 'P');
326 		putf(xp->x_flag&XTRC, 'T');
327 		putf(xp->x_flag&XWRIT, 'W');
328 		putf(xp->x_flag&XLOAD, 'L');
329 		putf(xp->x_flag&XLOCK, 'K');
330 		putf(xp->x_flag&XWANT, 'w');
331 		printf("%5x", xp->x_daddr[0]);
332 		printf("%11x", xp->x_caddr);
333 		printf("%5d", xp->x_rssize);
334 		printf("%5d", xp->x_size);
335 		printf("%10.1x", xp->x_iptr);
336 		printf("%5d", xp->x_count&0377);
337 		printf("%5d", xp->x_ccount);
338 		printf("\n");
339 	}
340 	free(xtext);
341 }
342 
343 doproc()
344 {
345 	struct proc *xproc, *aproc;
346 	int nproc;
347 	register struct proc *pp;
348 	register loc, np;
349 	struct pte apte;
350 
351 	nproc = getw(nl[SNPROC].n_value);
352 	xproc = (struct proc *)calloc(nproc, sizeof (struct proc));
353 	lseek(fc, (int)(aproc = (struct proc *)getw(nl[SPROC].n_value)), 0);
354 	read(fc, xproc, nproc * sizeof (struct proc));
355 	np = 0;
356 	for (pp=xproc; pp < &xproc[nproc]; pp++)
357 		if (pp->p_stat)
358 			np++;
359 	if (totflg) {
360 		printf("%3d/%3d processes\n", np, nproc);
361 		return;
362 	}
363 	printf("%d/%d processes\n", np, nproc);
364 	printf("   LOC    S    F POIP PRI      SIG  UID SLP TIM  CPU  NI   PGRP    PID   PPID    ADDR   RSS SRSS SIZE    WCHAN    LINK   TEXTP\n");
365 	for (pp=xproc; pp<&xproc[nproc]; pp++) {
366 		if (pp->p_stat==0 && allflg==0)
367 			continue;
368 		printf("%8x", aproc + (pp - xproc));
369 		printf(" %2d", pp->p_stat);
370 		printf(" %4x", pp->p_flag & 0xffff);
371 		printf(" %4d", pp->p_poip);
372 		printf(" %3d", pp->p_pri);
373 		printf(" %8x", pp->p_sig);
374 		printf(" %4d", pp->p_uid);
375 		printf(" %3d", pp->p_slptime);
376 		printf(" %3d", pp->p_time);
377 		printf(" %4d", pp->p_cpu&0377);
378 		printf(" %3d", pp->p_nice);
379 		printf(" %6d", pp->p_pgrp);
380 		printf(" %6d", pp->p_pid);
381 		printf(" %6d", pp->p_ppid);
382 		if (kflg)
383 			pp->p_addr = (struct pte *)clear((int)pp->p_addr);
384 		if (pp->p_flag & SLOAD) {
385 			lseek(fc, (long)pp->p_addr, 0);
386 			read(fc, &apte, sizeof(apte));
387 			printf(" %8x", apte.pg_pfnum);
388 		} else
389 			printf(" %8x", pp->p_swaddr);
390 		printf(" %4x", pp->p_rssize);
391 		printf(" %4x", pp->p_swrss);
392 		printf(" %5x", pp->p_dsize+pp->p_ssize);
393 		printf(" %7x", clear(pp->p_wchan));
394 		printf(" %7x", clear(pp->p_link));
395 		printf(" %7x", clear(pp->p_textp));
396 		printf("\n");
397 	}
398 }
399 
400 dotty()
401 {
402 	struct tty *tty;
403 	int ntty, ttyspace = 128;
404 	register struct tty *tp;
405 	extern char *malloc(), *realloc();
406 	static char mesg[] =
407 	" # RAW CAN OUT     MODE     ADDR DEL COL     STATE  PGRP DISC\n";
408 
409 	if ((tty = (struct tty *)malloc(ttyspace * sizeof(*tty))) == 0) {
410 		printf("pstat: out of memory\n");
411 		return;
412 	}
413 	printf("1 cons\n");
414 	if (kflg)
415 		nl[SKL].n_value = clear(nl[SKL].n_value);
416 	lseek(fc, (long)nl[SKL].n_value, 0);
417 	read(fc, tty, sizeof(*tty));
418 	printf(mesg);
419 	ttyprt(&tty[0], 0);
420 	if (nl[SNDZ].n_type == 0)
421 		goto dh;
422 	if (kflg) {
423 		nl[SNDZ].n_value = clear(nl[SNDZ].n_value);
424 		nl[SDZ].n_value = clear(nl[SDZ].n_value);
425 	}
426 	lseek(fc, (long)nl[SNDZ].n_value, 0);
427 	read(fc, &ntty, sizeof(ntty));
428 	printf("%d dz lines\n", ntty);
429 	if (ntty > ttyspace) {
430 		ttyspace = ntty;
431 		if ((tty = (struct tty *)realloc(tty, ttyspace * sizeof(*tty))) == 0) {
432 			printf("pstat: out of memory\n");
433 			return;
434 		}
435 	}
436 	lseek(fc, (long)nl[SDZ].n_value, 0);
437 	read(fc, tty, ntty * sizeof (struct tty));
438 	printf(mesg);
439 	for (tp = tty; tp < &tty[ntty]; tp++)
440 		ttyprt(tp, tp - tty);
441 dh:
442 	if (nl[SNDH].n_type == 0)
443 		goto dmf;
444 	if (kflg) {
445 		nl[SNDH].n_value = clear(nl[SNDH].n_value);
446 		nl[SDH].n_value = clear(nl[SDH].n_value);
447 	}
448 	lseek(fc, (long)nl[SNDH].n_value, 0);
449 	read(fc, &ntty, sizeof(ntty));
450 	printf("%d dh lines\n", ntty);
451 	if (ntty > ttyspace) {
452 		ttyspace = ntty;
453 		if ((tty = (struct tty *)realloc(tty, ttyspace * sizeof(*tty))) == 0) {
454 			printf("pstat: out of memory\n");
455 			return;
456 		}
457 	}
458 	lseek(fc, (long)nl[SDH].n_value, 0);
459 	read(fc, tty, ntty * sizeof(struct tty));
460 	printf(mesg);
461 	for (tp = tty; tp < &tty[ntty]; tp++)
462 		ttyprt(tp, tp - tty);
463 dmf:
464 	if (nl[SNDMF].n_type == 0)
465 		goto pty;
466 	if (kflg) {
467 		nl[SNDMF].n_value = clear(nl[SNDMF].n_value);
468 		nl[SDMF].n_value = clear(nl[SDMF].n_value);
469 	}
470 	lseek(fc, (long)nl[SNDMF].n_value, 0);
471 	read(fc, &ntty, sizeof(ntty));
472 	printf("%d dmf lines\n", ntty);
473 	if (ntty > ttyspace) {
474 		ttyspace = ntty;
475 		if ((tty = (struct tty *)realloc(tty, ttyspace * sizeof(*tty))) == 0) {
476 			printf("pstat: out of memory\n");
477 			return;
478 		}
479 	}
480 	lseek(fc, (long)nl[SDMF].n_value, 0);
481 	read(fc, tty, ntty * sizeof(struct tty));
482 	printf(mesg);
483 	for (tp = tty; tp < &tty[ntty]; tp++)
484 		ttyprt(tp, tp - tty);
485 pty:
486 	if (nl[SPTY].n_type == 0)
487 		return;
488 	if (kflg) {
489 		nl[SPTY].n_value = clear(nl[SPTY].n_value);
490 		nl[SNPTY].n_value = clear(nl[SNPTY].n_value);
491 	}
492 	lseek(fc, (long)nl[SNPTY].n_value, 0);
493 	read(fc, &ntty, sizeof(ntty));
494 	printf("%d pty lines\n", ntty);
495 	if (ntty > ttyspace) {
496 		ttyspace = ntty;
497 		if ((tty = (struct tty *)realloc(tty, ttyspace * sizeof(*tty))) == 0) {
498 			printf("pstat: out of memory\n");
499 			return;
500 		}
501 	}
502 	lseek(fc, (long)nl[SPTY].n_value, 0);
503 	read(fc, tty, ntty*sizeof(struct tty));
504 	printf(mesg);
505 	for (tp = tty; tp < &tty[ntty]; tp++)
506 		ttyprt(tp, tp - tty);
507 }
508 
509 ttyprt(atp, line)
510 struct tty *atp;
511 {
512 	register struct tty *tp;
513 
514 	printf("%2d", line);
515 	tp = atp;
516 	switch (tp->t_line) {
517 
518 /*
519 	case NETLDISC:
520 		if (tp->t_rec)
521 			printf("%4d%4d", 0, tp->t_inbuf);
522 		else
523 			printf("%4d%4d", tp->t_inbuf, 0);
524 		break;
525 */
526 
527 	default:
528 		printf("%4d%4d", tp->t_rawq.c_cc, tp->t_canq.c_cc);
529 	}
530 	printf("%4d %8x %8x%4d%4d", tp->t_outq.c_cc, tp->t_flags,
531 		tp->t_addr, tp->t_delct, tp->t_col);
532 	putf(tp->t_state&TS_TIMEOUT, 'T');
533 	putf(tp->t_state&TS_WOPEN, 'W');
534 	putf(tp->t_state&TS_ISOPEN, 'O');
535 	putf(tp->t_state&TS_FLUSH, 'F');
536 	putf(tp->t_state&TS_CARR_ON, 'C');
537 	putf(tp->t_state&TS_BUSY, 'B');
538 	putf(tp->t_state&TS_ASLEEP, 'A');
539 	putf(tp->t_state&TS_XCLUDE, 'X');
540 	putf(tp->t_state&TS_TTSTOP, 'S');
541 	putf(tp->t_state&TS_HUPCLS, 'H');
542 	printf("%6d", tp->t_pgrp);
543 	switch (tp->t_line) {
544 
545 	case OTTYDISC:
546 		printf("\n");
547 		break;
548 
549 	case NTTYDISC:
550 		printf(" ntty\n");
551 		break;
552 
553 	case NETLDISC:
554 		printf(" net\n");
555 		break;
556 
557 	case TABLDISC:
558 		printf(" tab\n");
559 		break;
560 
561 	case NTABLDISC:
562 		printf(" ntab\n");
563 		break;
564 
565 	default:
566 		printf(" %d\n", tp->t_line);
567 	}
568 }
569 
570 dousr()
571 {
572 	struct user U;
573 	register i, j, *ip;
574 	register struct nameidata *nd = &U.u_nd;
575 
576 	/* This wins only if CLBYTES >= sizeof (struct user) */
577 	lseek(fm, ubase * NBPG, 0);
578 	read(fm, &U, sizeof(U));
579 	printf("pcb");
580 	ip = (int *)&U.u_pcb;
581 	while (ip < &U.u_arg[0]) {
582 		if ((ip - (int *)&U.u_pcb) % 4 == 0)
583 			printf("\t");
584 		printf("%x ", *ip++);
585 		if ((ip - (int *)&U.u_pcb) % 4 == 0)
586 			printf("\n");
587 	}
588 	if ((ip - (int *)&U.u_pcb) % 4 != 0)
589 		printf("\n");
590 	printf("arg");
591 	for (i=0; i<sizeof(U.u_arg)/sizeof(U.u_arg[0]); i++) {
592 		if (i%5==0)
593 			printf("\t");
594 		printf(" %.1x", U.u_arg[i]);
595 		if (i%5==4)
596 			printf("\n");
597 	}
598 	if (i%5)
599 		printf("\n");
600 	printf("segflg\t%d\nerror %d\n", nd->ni_segflg, U.u_error);
601 	printf("uids\t%d,%d,%d,%d\n", U.u_uid,U.u_gid,U.u_ruid,U.u_rgid);
602 	printf("procp\t%.1x\n", U.u_procp);
603 	printf("ap\t%.1x\n", U.u_ap);
604 	printf("r_val?\t%.1x %.1x\n", U.u_r.r_val1, U.u_r.r_val2);
605 	printf("base, count, offset %.1x %.1x %ld\n", nd->ni_base,
606 		nd->ni_count, nd->ni_offset);
607 	printf("cdir rdir %.1x %.1x\n", U.u_cdir, U.u_rdir);
608 	printf("dirp %.1x\n", nd->ni_dirp);
609 	printf("dent %d %.14s\n", nd->ni_dent.d_ino, nd->ni_dent.d_name);
610 	printf("pdir %.1o\n", nd->ni_pdir);
611 	printf("file");
612 	for (i=0; i<NOFILE; i++) {
613 		if (i % 8 == 0)
614 			printf("\t");
615 		printf("%9.1x", U.u_ofile[i]);
616 		if (i % 8 == 7)
617 			printf("\n");
618 	}
619 	if (i % 8)
620 		printf("\n");
621 	printf("pofile");
622 	for (i=0; i<NOFILE; i++) {
623 		if (i % 8 == 0)
624 			printf("\t");
625 		printf("%9.1x", U.u_pofile[i]);
626 		if (i % 8 == 7)
627 			printf("\n");
628 	}
629 	if (i % 8)
630 		printf("\n");
631 	printf("ssave");
632 	for (i=0; i<sizeof(label_t)/sizeof(int); i++) {
633 		if (i%5==0)
634 			printf("\t");
635 		printf("%9.1x", U.u_ssave.val[i]);
636 		if (i%5==4)
637 			printf("\n");
638 	}
639 	if (i%5)
640 		printf("\n");
641 	printf("sigs");
642 	for (i=0; i<NSIG; i++) {
643 		if (i % 8 == 0)
644 			printf("\t");
645 		printf("%.1x ", U.u_signal[i]);
646 		if (i % 8 == 7)
647 			printf("\n");
648 	}
649 	if (i % 8)
650 		printf("\n");
651 	printf("code\t%.1x\n", U.u_code);
652 	printf("ar0\t%.1x\n", U.u_ar0);
653 	printf("prof\t%X %X %X %X\n", U.u_prof.pr_base, U.u_prof.pr_size,
654 	    U.u_prof.pr_off, U.u_prof.pr_scale);
655 	printf("\neosys\t%d\n", U.u_eosys);
656 	printf("ttyp\t%.1x\n", U.u_ttyp);
657 	printf("ttyd\t%d,%d\n", major(U.u_ttyd), minor(U.u_ttyd));
658 	printf("comm %.14s\n", U.u_comm);
659 	printf("start\t%D\n", U.u_start);
660 	printf("acflag\t%D\n", U.u_acflag);
661 	printf("cmask\t%D\n", U.u_cmask);
662 	printf("sizes\t%.1x %.1x %.1x\n", U.u_tsize, U.u_dsize, U.u_ssize);
663 	printf("ru\t");
664 	ip = (int *)&U.u_ru;
665 	for (i = 0; i < sizeof(U.u_ru)/sizeof(int); i++)
666 		printf("%D ", ip[i]);
667 	printf("\n");
668 	ip = (int *)&U.u_cru;
669 	printf("cru\t");
670 	for (i = 0; i < sizeof(U.u_cru)/sizeof(int); i++)
671 		printf("%D ", ip[i]);
672 	printf("\n");
673 /*
674 	i =  U.u_stack - &U;
675 	while (U[++i] == 0);
676 	i &= ~07;
677 	while (i < 512) {
678 		printf("%x ", 0140000+2*i);
679 		for (j=0; j<8; j++)
680 			printf("%9x", U[i++]);
681 		printf("\n");
682 	}
683 */
684 }
685 
686 oatoi(s)
687 char *s;
688 {
689 	register v;
690 
691 	v = 0;
692 	while (*s)
693 		v = (v<<3) + *s++ - '0';
694 	return(v);
695 }
696 
697 dofile()
698 {
699 	int nfile;
700 	struct file *xfile, *afile;
701 	register struct file *fp;
702 	register nf;
703 	int loc;
704 	static char *dtypes[] = { "???", "inode", "socket" };
705 
706 	nf = 0;
707 	nfile = getw(nl[SNFILE].n_value);
708 	xfile = (struct file *)calloc(nfile, sizeof (struct file));
709 	lseek(fc, (int)(afile = (struct file *)getw(nl[SFIL].n_value)), 0);
710 	read(fc, xfile, nfile * sizeof (struct file));
711 	for (fp=xfile; fp < &xfile[nfile]; fp++)
712 		if (fp->f_count)
713 			nf++;
714 	if (totflg) {
715 		printf("%3d/%3d files\n", nf, nfile);
716 		return;
717 	}
718 	printf("%d/%d open files\n", nf, nfile);
719 	printf("   LOC   TYPE    FLG     CNT  MSG    DATA    OFFSET\n");
720 	for (fp=xfile,loc=(int)afile; fp < &xfile[nfile]; fp++,loc+=sizeof(xfile[0])) {
721 		if (fp->f_count==0)
722 			continue;
723 		printf("%8x ", loc);
724 		if (fp->f_type <= DTYPE_SOCKET)
725 			printf("%-8.8s", dtypes[fp->f_type]);
726 		else
727 			printf("8d", fp->f_type);
728 		putf(fp->f_flag&FREAD, 'R');
729 		putf(fp->f_flag&FWRITE, 'W');
730 		putf(fp->f_flag&FAPPEND, 'A');
731 		putf(fp->f_flag&FSHLOCK, 'S');
732 		putf(fp->f_flag&FEXLOCK, 'X');
733 		putf(fp->f_flag&FASYNC, 'I');
734 		printf("  %3d", mask(fp->f_count));
735 		printf("  %3d", mask(fp->f_msgcount));
736 		printf("  %8.1x", fp->f_data);
737 		if (fp->f_offset < 0)
738 			printf("  %x\n", fp->f_offset);
739 		else
740 			printf("  %ld\n", fp->f_offset);
741 	}
742 }
743 
744 int dmmin, dmmax, nswdev;
745 
746 doswap()
747 {
748 	struct proc *proc;
749 	int nproc;
750 	struct text *xtext;
751 	int ntext;
752 	struct map *swapmap;
753 	int nswapmap;
754 	struct swdevt *swdevt, *sw;
755 	register struct proc *pp;
756 	int nswap, used, tused, free, waste;
757 	int db, sb;
758 	register struct mapent *me;
759 	register struct text *xp;
760 	int i, j;
761 
762 	nproc = getw(nl[SNPROC].n_value);
763 	proc = (struct proc *)calloc(nproc, sizeof (struct proc));
764 	ntext = getw(nl[SNTEXT].n_value);
765 	xtext = (struct text *)calloc(ntext, sizeof (struct text));
766 	nswapmap = getw(nl[SNSWAPMAP].n_value);
767 	swapmap = (struct map *)calloc(nswapmap, sizeof (struct map));
768 	nswdev = getw(nl[SNSWDEV].n_value);
769 	swdevt = (struct swdevt *)calloc(nswdev, sizeof (struct swdevt));
770 	lseek(fc, nl[SSWDEVT].n_value, L_SET);
771 	read(fc, swdevt, nswdev * sizeof (struct swdevt));
772 	lseek(fc, getw(nl[SPROC].n_value), 0);
773 	read(fc, proc, nproc * sizeof (struct proc));
774 	lseek(fc, getw(nl[STEXT].n_value), 0);
775 	read(fc, xtext, ntext * sizeof (struct text));
776 	lseek(fc, getw(nl[SWAPMAP].n_value), 0);
777 	read(fc, swapmap, nswapmap * sizeof (struct map));
778 	swapmap->m_name = "swap";
779 	swapmap->m_limit = (struct mapent *)&swapmap[nswapmap];
780 	dmmin = getw(nl[SDMMIN].n_value);
781 	dmmax = getw(nl[SDMMAX].n_value);
782 	nswap = 0;
783 	for (sw = swdevt; sw < &swdevt[nswdev]; sw++)
784 		nswap += sw->sw_nblks,
785 	free = 0;
786 	for (me = (struct mapent *)(swapmap+1);
787 	    me < (struct mapent *)&swapmap[nswapmap]; me++)
788 		free += me->m_size;
789 	tused = 0;
790 	for (xp = xtext; xp < &xtext[ntext]; xp++)
791 		if (xp->x_iptr!=NULL) {
792 			tused += ctod(clrnd(xp->x_size));
793 			if (xp->x_flag & XPAGI)
794 				tused += ctod(clrnd(ctopt(xp->x_size)));
795 		}
796 	used = tused;
797 	waste = 0;
798 	for (pp = proc; pp < &proc[nproc]; pp++) {
799 		if (pp->p_stat == 0 || pp->p_stat == SZOMB)
800 			continue;
801 		if (pp->p_flag & SSYS)
802 			continue;
803 		db = ctod(pp->p_dsize), sb = up(db);
804 		used += sb;
805 		waste += sb - db;
806 		db = ctod(pp->p_ssize), sb = up(db);
807 		used += sb;
808 		waste += sb - db;
809 		if ((pp->p_flag&SLOAD) == 0)
810 			used += ctod(vusize(pp));
811 	}
812 	if (totflg) {
813 #define	btok(x)	((x) / (1024 / DEV_BSIZE))
814 		printf("%3d/%3d 00k swap\n",
815 		    btok(used/100), btok((used+free)/100));
816 		return;
817 	}
818 	printf("%dk used (%dk text), %dk free, %dk wasted, %dk missing\n",
819 	    btok(used), btok(tused), btok(free), btok(waste),
820 /* a dmmax/2 block goes to argmap */
821 	    btok(nswap - dmmax/2 - (used + free)));
822 	printf("avail: ");
823 	for (i = dmmax; i >= dmmin; i /= 2) {
824 		j = 0;
825 		while (rmalloc(swapmap, i) != 0)
826 			j++;
827 		if (j) printf("%d*%dk ", j, btok(i));
828 	}
829 	free = 0;
830 	for (me = (struct mapent *)(swapmap+1);
831 	    me < (struct mapent *)&swapmap[nswapmap]; me++)
832 		free += me->m_size;
833 	printf("%d*1k\n", btok(free));
834 }
835 
836 up(size)
837 	register int size;
838 {
839 	register int i, block;
840 
841 	i = 0;
842 	block = dmmin;
843 	while (i < size) {
844 		i += block;
845 		if (block < dmmax)
846 			block *= 2;
847 	}
848 	return (i);
849 }
850 
851 /*
852  * Compute number of pages to be allocated to the u. area
853  * and data and stack area page tables, which are stored on the
854  * disk immediately after the u. area.
855  */
856 vusize(p)
857 	register struct proc *p;
858 {
859 	register int tsz = p->p_tsize / NPTEPG;
860 
861 	/*
862 	 * We do not need page table space on the disk for page
863 	 * table pages wholly containing text.
864 	 */
865 	return (clrnd(UPAGES +
866 	    clrnd(ctopt(p->p_tsize+p->p_dsize+p->p_ssize+UPAGES)) - tsz));
867 }
868 
869 /*
870  * Allocate 'size' units from the given
871  * map. Return the base of the allocated space.
872  * In a map, the addresses are increasing and the
873  * list is terminated by a 0 size.
874  *
875  * Algorithm is first-fit.
876  *
877  * This routine knows about the interleaving of the swapmap
878  * and handles that.
879  */
880 long
881 rmalloc(mp, size)
882 	register struct map *mp;
883 	long size;
884 {
885 	register struct mapent *ep = (struct mapent *)(mp+1);
886 	register int addr;
887 	register struct mapent *bp;
888 	swblk_t first, rest;
889 
890 	if (size <= 0 || size > dmmax)
891 		return (0);
892 	/*
893 	 * Search for a piece of the resource map which has enough
894 	 * free space to accomodate the request.
895 	 */
896 	for (bp = ep; bp->m_size; bp++) {
897 		if (bp->m_size >= size) {
898 			/*
899 			 * If allocating from swapmap,
900 			 * then have to respect interleaving
901 			 * boundaries.
902 			 */
903 			if (nswdev > 1 &&
904 			    (first = dmmax - bp->m_addr%dmmax) < bp->m_size) {
905 				if (bp->m_size - first < size)
906 					continue;
907 				addr = bp->m_addr + first;
908 				rest = bp->m_size - first - size;
909 				bp->m_size = first;
910 				if (rest)
911 					rmfree(mp, rest, addr+size);
912 				return (addr);
913 			}
914 			/*
915 			 * Allocate from the map.
916 			 * If there is no space left of the piece
917 			 * we allocated from, move the rest of
918 			 * the pieces to the left.
919 			 */
920 			addr = bp->m_addr;
921 			bp->m_addr += size;
922 			if ((bp->m_size -= size) == 0) {
923 				do {
924 					bp++;
925 					(bp-1)->m_addr = bp->m_addr;
926 				} while ((bp-1)->m_size = bp->m_size);
927 			}
928 			if (addr % CLSIZE)
929 				return (0);
930 			return (addr);
931 		}
932 	}
933 	return (0);
934 }
935 
936 /*
937  * Free the previously allocated space at addr
938  * of size units into the specified map.
939  * Sort addr into map and combine on
940  * one or both ends if possible.
941  */
942 rmfree(mp, size, addr)
943 	struct map *mp;
944 	long size, addr;
945 {
946 	struct mapent *firstbp;
947 	register struct mapent *bp;
948 	register int t;
949 
950 	/*
951 	 * Both address and size must be
952 	 * positive, or the protocol has broken down.
953 	 */
954 	if (addr <= 0 || size <= 0)
955 		goto badrmfree;
956 	/*
957 	 * Locate the piece of the map which starts after the
958 	 * returned space (or the end of the map).
959 	 */
960 	firstbp = bp = (struct mapent *)(mp + 1);
961 	for (; bp->m_addr <= addr && bp->m_size != 0; bp++)
962 		continue;
963 	/*
964 	 * If the piece on the left abuts us,
965 	 * then we should combine with it.
966 	 */
967 	if (bp > firstbp && (bp-1)->m_addr+(bp-1)->m_size >= addr) {
968 		/*
969 		 * Check no overlap (internal error).
970 		 */
971 		if ((bp-1)->m_addr+(bp-1)->m_size > addr)
972 			goto badrmfree;
973 		/*
974 		 * Add into piece on the left by increasing its size.
975 		 */
976 		(bp-1)->m_size += size;
977 		/*
978 		 * If the combined piece abuts the piece on
979 		 * the right now, compress it in also,
980 		 * by shifting the remaining pieces of the map over.
981 		 */
982 		if (bp->m_addr && addr+size >= bp->m_addr) {
983 			if (addr+size > bp->m_addr)
984 				goto badrmfree;
985 			(bp-1)->m_size += bp->m_size;
986 			while (bp->m_size) {
987 				bp++;
988 				(bp-1)->m_addr = bp->m_addr;
989 				(bp-1)->m_size = bp->m_size;
990 			}
991 		}
992 		goto done;
993 	}
994 	/*
995 	 * Don't abut on the left, check for abutting on
996 	 * the right.
997 	 */
998 	if (addr+size >= bp->m_addr && bp->m_size) {
999 		if (addr+size > bp->m_addr)
1000 			goto badrmfree;
1001 		bp->m_addr -= size;
1002 		bp->m_size += size;
1003 		goto done;
1004 	}
1005 	/*
1006 	 * Don't abut at all.  Make a new entry
1007 	 * and check for map overflow.
1008 	 */
1009 	do {
1010 		t = bp->m_addr;
1011 		bp->m_addr = addr;
1012 		addr = t;
1013 		t = bp->m_size;
1014 		bp->m_size = size;
1015 		bp++;
1016 	} while (size = t);
1017 	/*
1018 	 * Segment at bp is to be the delimiter;
1019 	 * If there is not room for it
1020 	 * then the table is too full
1021 	 * and we must discard something.
1022 	 */
1023 	if (bp+1 > mp->m_limit) {
1024 		/*
1025 		 * Back bp up to last available segment.
1026 		 * which contains a segment already and must
1027 		 * be made into the delimiter.
1028 		 * Discard second to last entry,
1029 		 * since it is presumably smaller than the last
1030 		 * and move the last entry back one.
1031 		 */
1032 		bp--;
1033 		printf("%s: rmap ovflo, lost [%d,%d)\n", mp->m_name,
1034 		    (bp-1)->m_addr, (bp-1)->m_addr+(bp-1)->m_size);
1035 		bp[-1] = bp[0];
1036 		bp[0].m_size = bp[0].m_addr = 0;
1037 	}
1038 done:
1039 	return;
1040 badrmfree:
1041 	printf("bad rmfree\n");
1042 }
1043