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