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