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