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