xref: /original-bsd/usr.sbin/pstat/pstat.c (revision 3b6250d9)
1 /*-
2  * Copyright (c) 1980, 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1980, 1991 The Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)pstat.c	5.38 (Berkeley) 01/27/92";
16 #endif /* not lint */
17 
18 #include <sys/param.h>
19 #include <sys/user.h>
20 #include <sys/proc.h>
21 #include <sys/time.h>
22 #include <sys/vnode.h>
23 #include <sys/map.h>
24 #define KERNEL
25 #define NFS
26 #include <sys/file.h>
27 #include <sys/mount.h>
28 #include <ufs/ufs/quota.h>
29 #include <ufs/ufs/inode.h>
30 #include <sys/stat.h>
31 #include <nfs/nfsv2.h>
32 #include <nfs/nfs.h>
33 #include <nfs/nfsnode.h>
34 #include <sys/ioctl.h>
35 #include <sys/tty.h>
36 #undef KERNEL
37 #include <sys/conf.h>
38 
39 #ifdef SPPWAIT
40 #define NEWVM
41 #endif
42 
43 #ifndef NEWVM
44 #include <sys/vm.h>
45 #include <machine/pte.h>
46 #include <sys/text.h>
47 #endif
48 #include <sys/kinfo.h>
49 
50 #include <nlist.h>
51 #include <kvm.h>
52 #include <stdio.h>
53 #include "pathnames.h"
54 
55 #define mask(x)		(x&0377)
56 #define	clear(x)	((int)x &~ KERNBASE)
57 
58 char	*nlistf	= NULL;
59 char	*memf	= NULL;
60 
61 struct nlist nl[] = {
62 #define	SWAPMAP	0
63 	{ "_swapmap" },
64 #define	SNSWAPMAP 1
65 	{ "_nswapmap" },
66 #define	SDMMIN	2
67 	{ "_dmmin" },
68 #define	SDMMAX	3
69 	{ "_dmmax" },
70 #define	SNSWDEV	4
71 	{ "_nswdev" },
72 #define	SSWDEVT	5
73 	{ "_swdevt" },
74 #define NLMANDATORY SSWDEVT	/* names up to here are mandatory */
75 #define	SCONS	NLMANDATORY + 1
76 	{ "_cons" },
77 #define	SPTY	NLMANDATORY + 2
78 	{ "_pt_tty" },
79 #define	SNPTY	NLMANDATORY + 3
80 	{ "_npty" },
81 #ifdef vax
82 #define	SDZ	(SNPTY+1)
83 	{ "_dz_tty" },
84 #define	SNDZ	(SNPTY+2)
85 	{ "_dz_cnt" },
86 #define	SDMF	(SNPTY+3)
87 	{ "_dmf_tty" },
88 #define	SNDMF	(SNPTY+4)
89 	{ "_ndmf" },
90 #define	SDH	(SNPTY+5)
91 	{ "_dh11" },
92 #define	SNDH	(SNPTY+6)
93 	{ "_ndh11" },
94 #define	SDHU	(SNPTY+7)
95 	{ "_dhu_tty" },
96 #define	SNDHU	(SNPTY+8)
97 	{ "_ndhu" },
98 #define	SDMZ	(SNPTY+9)
99 	{ "_dmz_tty" },
100 #define	SNDMZ	(SNPTY+10)
101 	{ "_ndmz" },
102 #define	SQD	(SNPTY+11)
103 	{ "_qd_tty" },
104 #define	SNQD	(SNPTY+12)
105 	{ "_nNQD" },
106 #endif
107 
108 #ifdef tahoe
109 #define	SVX	(SNPTY+1)
110 	{ "_vx_tty" },
111 #define	SNVX	(SNPTY+2)
112 	{ "_nvx" },
113 #define SMP	(SNPTY+3)
114 	{ "_mp_tty" },
115 #define SNMP	(SNPTY+4)
116 	{ "_nmp" },
117 #endif
118 
119 #ifdef hp300
120 #define	SDCA	(SNPTY+1)
121 	{ "_dca_tty" },
122 #define	SNDCA	(SNPTY+2)
123 	{ "_ndca" },
124 #define	SDCM	(SNPTY+3)
125 	{ "_dcm_tty" },
126 #define	SNDCM	(SNPTY+4)
127 	{ "_ndcm" },
128 #define	SDCL	(SNPTY+5)
129 	{ "_dcl_tty" },
130 #define	SNDCL	(SNPTY+6)
131 	{ "_ndcl" },
132 #define	SITE	(SNPTY+7)
133 	{ "_ite_tty" },
134 #define	SNITE	(SNPTY+8)
135 	{ "_nite" },
136 #endif
137 	{ "" }
138 };
139 
140 int	vnof;
141 int	txtf;
142 int	prcf;
143 int	ttyf;
144 int	usrf;
145 int	upid;
146 int	filf;
147 int	swpf;
148 int	totflg;
149 char	partab[1];
150 struct	cdevsw	cdevsw[1];
151 struct	bdevsw	bdevsw[1];
152 int	allflg;
153 int	nflg;
154 u_long	getword();
155 off_t	mkphys();
156 
157 #define V(x)	(void *)(x)
158 
159 main(argc, argv)
160 	int argc;
161 	char *argv[];
162 {
163 	extern char *optarg;
164 	extern int optind;
165 	int ch, ret;
166 
167 	while ((ch = getopt(argc, argv, "TafvikptU:sxnu")) != EOF)
168 		switch (ch) {
169 		case 'T':
170 			totflg++;
171 			break;
172 		case 'a':
173 			allflg++;
174 			/*FALLTHROUGH*/
175 		case 'p':
176 			prcf++;
177 			break;
178 		case 'f':
179 			filf++;
180 			break;
181 		case 'v':
182 		case 'i':
183 			vnof++;
184 			break;
185 		case 't':
186 			ttyf++;
187 			break;
188 		case 'U':
189 			usrf++;
190 			sscanf(optarg, "%d", &upid);
191 			break;
192 		case 's':
193 			swpf++;
194 			break;
195 		case 'x':
196 			txtf++;
197 			break;
198 		case 'n':
199 			nflg++;
200 			break;
201 		case 'u':
202 			fprintf(stderr, "pstat: use [ -U pid ] for -u\n");
203 			exit(1);
204 		case '?':
205 		default:
206 			fprintf(stderr, "usage: pstat -[Tafiptsx] [-U [pid]] [system] [core]\n");
207 			exit(1);
208 		}
209 	argc -= optind;
210 	argv += optind;
211 
212 	if (argc > 1)
213 		memf = argv[1];
214 	if (argc > 0)
215 		nlistf = argv[0];
216 
217 	/*
218 	 * Discard setgid privileges if not the running kernel so that bad
219 	 * guys can't print interesting stuff from kernel memory.
220 	 */
221 	if (nlistf != NULL || memf != NULL)
222 		setgid(getgid());
223 
224 	if (kvm_openfiles(nlistf, memf, NULL) == -1) {
225 		error("kvm_openfiles: %s", kvm_geterr());
226 		exit(1);
227 	}
228 	if ((ret = kvm_nlist(nl)) != 0) {
229 		int i, quit = 0;
230 
231 		if (ret == -1) {
232 			error("kvm_nlist: %s", kvm_geterr());
233 			exit(1);
234 		}
235 		for (i = 0; i <= NLMANDATORY; i++) {
236 			if (!nl[i].n_value) {
237 				quit = 1;
238 				error("undefined symbol: %s\n",
239 					nl[i].n_name);
240 			}
241 		}
242 		if (quit)
243 			exit(1);
244 	}
245 	if (!(filf | totflg | vnof | prcf | txtf | ttyf | usrf | swpf)) {
246 		printf("pstat: one or more of -[aivxptfsU] is required\n");
247 		exit(1);
248 	}
249 	if (filf||totflg)
250 		dofile();
251 	if (vnof||totflg)
252 		dovnode();
253 	if (prcf||totflg)
254 		doproc();
255 	if (txtf||totflg)
256 		dotext();
257 	if (ttyf)
258 		dotty();
259 	if (usrf)
260 		dousr();
261 	if (swpf||totflg)
262 		doswap();
263 }
264 
265 struct e_vnode {
266 	struct vnode *avnode;
267 	struct vnode vnode;
268 };
269 
270 dovnode()
271 {
272 	register struct e_vnode *e_vnodebase, *endvnode, *evp;
273 	register struct vnode *vp;
274 	register struct mount *maddr = NULL, *mp;
275 	int numvnodes;
276 	struct e_vnode *loadvnodes();
277 	struct mount *getmnt();
278 
279 	e_vnodebase = loadvnodes(&numvnodes);
280 	if (totflg) {
281 		printf("%7d vnodes\n", numvnodes);
282 		return;
283 	}
284 	endvnode = e_vnodebase + numvnodes;
285 	printf("%d active vnodes\n", numvnodes);
286 
287 
288 #define ST	mp->mnt_stat
289 	for (evp = e_vnodebase; evp < endvnode; evp++) {
290 		vp = &evp->vnode;
291 		if (vp->v_mount != maddr) {
292 			/*
293 			 * New filesystem
294 			 */
295 			if ((mp = getmnt(vp->v_mount)) == NULL)
296 				continue;
297 			maddr = vp->v_mount;
298 			mount_print(mp);
299 			vnode_header();
300 			switch(ST.f_type) {
301 			case MOUNT_UFS:
302 			case MOUNT_MFS:
303 				ufs_header();
304 				break;
305 			case MOUNT_NFS:
306 				nfs_header();
307 				break;
308 			case MOUNT_NONE:
309 			case MOUNT_PC:
310 			default:
311 				break;
312 			}
313 			printf("\n");
314 		}
315 		vnode_print(evp->avnode, vp);
316 		switch(ST.f_type) {
317 		case MOUNT_UFS:
318 		case MOUNT_MFS:
319 			ufs_print(vp);
320 			break;
321 		case MOUNT_NFS:
322 			nfs_print(vp);
323 			break;
324 		case MOUNT_NONE:
325 		case MOUNT_PC:
326 		default:
327 			break;
328 		}
329 		printf("\n");
330 	}
331 	free(e_vnodebase);
332 }
333 
334 vnode_header()
335 {
336 	printf("ADDR     TYP VFLAG  USE HOLD");
337 }
338 
339 vnode_print(avnode, vp)
340 	struct vnode *avnode;
341 	struct vnode *vp;
342 {
343 	char *type, flags[16];
344 	char *fp = flags;
345 	register flag;
346 
347 	/*
348 	 * set type
349 	 */
350 	switch(vp->v_type) {
351 	case VNON:
352 		type = "non"; break;
353 	case VREG:
354 		type = "reg"; break;
355 	case VDIR:
356 		type = "dir"; break;
357 	case VBLK:
358 		type = "blk"; break;
359 	case VCHR:
360 		type = "chr"; break;
361 	case VLNK:
362 		type = "lnk"; break;
363 	case VSOCK:
364 		type = "soc"; break;
365 	case VFIFO:
366 		type = "fif"; break;
367 	case VBAD:
368 		type = "bad"; break;
369 	default:
370 		type = "unk"; break;
371 	}
372 	/*
373 	 * gather flags
374 	 */
375 	flag = vp->v_flag;
376 	if (flag & VROOT)
377 		*fp++ = 'R';
378 	if (flag & VTEXT)
379 		*fp++ = 'T';
380 	if (flag & VSYSTEM)
381 		*fp++ = 'S';
382 	if (flag & VXLOCK)
383 		*fp++ = 'L';
384 	if (flag & VXWANT)
385 		*fp++ = 'W';
386 	if (flag & VBWAIT)
387 		*fp++ = 'B';
388 	if (flag & VALIASED)
389 		*fp++ = 'A';
390 	if (flag == 0)
391 		*fp++ = '-';
392 	*fp = '\0';
393 	/*
394 	 * print it
395 	 */
396 	printf("%8x %s %5s %4d %4d",
397 		avnode, type, flags, vp->v_usecount, vp->v_holdcnt);
398 }
399 
400 ufs_header()
401 {
402 	printf(" FILEID IFLAG RDEV|SZ");
403 }
404 
405 ufs_print(vp)
406 	struct vnode *vp;
407 {
408 	struct inode *ip = VTOI(vp);
409 	char flagbuf[16], *flags = flagbuf;
410 	register flag;
411 	char *name;
412 	mode_t type;
413 	extern char *devname();
414 
415 	flag = ip->i_flag;
416 	if (flag & ILOCKED)
417 		*flags++ = 'L';
418 	if (flag & IWANT)
419 		*flags++ = 'W';
420 	if (flag & IRENAME)
421 		*flags++ = 'R';
422 	if (flag & IUPD)
423 		*flags++ = 'U';
424 	if (flag & IACC)
425 		*flags++ = 'A';
426 	if (flag & ICHG)
427 		*flags++ = 'C';
428 	if (flag & IMOD)
429 		*flags++ = 'M';
430 	if (flag & ISHLOCK)
431 		*flags++ = 'S';
432 	if (flag & IEXLOCK)
433 		*flags++ = 'E';
434 	if (flag & ILWAIT)
435 		*flags++ = 'Z';
436 	if (flag == 0)
437 		*flags++ = '-';
438 	*flags = '\0';
439 
440 	printf(" %6d %5s", ip->i_number, flagbuf);
441 	type = ip->i_mode & S_IFMT;
442 	if (type == S_IFCHR || type == S_IFBLK)
443 		if (nflg || ((name = devname(ip->i_rdev, type)) == NULL))
444 			printf("   %2d,%-2d",
445 				major(ip->i_rdev), minor(ip->i_rdev));
446 		else
447 			printf(" %7s", name);
448 	else
449 		printf(" %7d", ip->i_size);
450 }
451 
452 nfs_header()
453 {
454 	printf(" FILEID NFLAG RDEV|SZ");
455 }
456 
457 nfs_print(vp)
458 	struct vnode *vp;
459 {
460 	struct nfsnode *np = VTONFS(vp);
461 	char flagbuf[16], *flags = flagbuf;
462 	register flag;
463 	char *name;
464 	mode_t type;
465 	extern char *devname();
466 
467 	flag = np->n_flag;
468 	if (flag & NLOCKED)
469 		*flags++ = 'L';
470 	if (flag & NWANT)
471 		*flags++ = 'W';
472 	if (flag & NMODIFIED)
473 		*flags++ = 'M';
474 	if (flag & NWRITEERR)
475 		*flags++ = 'E';
476 	if (flag == 0)
477 		*flags++ = '-';
478 	*flags = '\0';
479 
480 #define VT	np->n_vattr
481 	printf(" %6d %5s", VT.va_fileid, flagbuf);
482 	type = VT.va_mode & S_IFMT;
483 	if (type == S_IFCHR || type == S_IFBLK)
484 		if (nflg || ((name = devname(VT.va_rdev, type)) == NULL))
485 			printf("   %2d,%-2d",
486 				major(VT.va_rdev), minor(VT.va_rdev));
487 		else
488 			printf(" %7s", name);
489 	else
490 		printf(" %7d", np->n_size);
491 }
492 
493 /*
494  * Given a pointer to a mount structure in kernel space,
495  * read it in and return a usable pointer to it.
496  */
497 struct mount *
498 getmnt(maddr)
499 	struct mount *maddr;
500 {
501 	static struct mtab {
502 		struct mtab *next;
503 		struct mount *maddr;
504 		struct mount mount;
505 	} *mhead = NULL;
506 	register struct mtab *mt;
507 
508 	for (mt = mhead; mt != NULL; mt = mt->next)
509 		if (maddr == mt->maddr)
510 			return (&mt->mount);
511 	if ((mt = (struct mtab *)malloc(sizeof (struct mtab))) == NULL) {
512 		error("out of memory");
513 		exit(1);
514 	}
515 	if (kvm_read(V(maddr), &mt->mount, sizeof(struct mount)) !=
516 	    sizeof(struct mount)) {
517 		error("can't read mount table at %x", maddr);
518 		return (NULL);
519 	}
520 	mt->maddr = maddr;
521 	mt->next = mhead;
522 	mhead = mt;
523 	return (&mt->mount);
524 }
525 
526 mount_print(mp)
527 	struct mount *mp;
528 {
529 	char *type = "unknown";
530 	register flags;
531 
532 #define ST	mp->mnt_stat
533 	printf("*** MOUNT ");
534 	switch (ST.f_type) {
535 	case MOUNT_NONE:
536 		type = "none";
537 		break;
538 	case MOUNT_UFS:
539 		type = "ufs";
540 		break;
541 	case MOUNT_NFS:
542 		type = "nfs";
543 		break;
544 	case MOUNT_MFS:
545 		type = "mfs";
546 		break;
547 	case MOUNT_PC:
548 		type = "pc";
549 		break;
550 	}
551 	printf("%s %s on %s", type, ST.f_mntfromname, ST.f_mntonname);
552 	if (flags = mp->mnt_flag) {
553 		char *comma = "(";
554 
555 		putchar(' ');
556 		/* user visable flags */
557 		if (flags & MNT_RDONLY) {
558 			printf("%srdonly", comma);
559 			flags &= ~MNT_RDONLY;
560 			comma = ",";
561 		}
562 		if (flags & MNT_SYNCHRONOUS) {
563 			printf("%ssynchronous", comma);
564 			flags &= ~MNT_SYNCHRONOUS;
565 			comma = ",";
566 		}
567 		if (flags & MNT_NOEXEC) {
568 			printf("%snoexec", comma);
569 			flags &= ~MNT_NOEXEC;
570 			comma = ",";
571 		}
572 		if (flags & MNT_NOSUID) {
573 			printf("%snosuid", comma);
574 			flags &= ~MNT_NOSUID;
575 			comma = ",";
576 		}
577 		if (flags & MNT_NODEV) {
578 			printf("%snodev", comma);
579 			flags &= ~MNT_NODEV;
580 			comma = ",";
581 		}
582 		if (flags & MNT_EXPORTED) {
583 			printf("%sexport", comma);
584 			flags &= ~MNT_EXPORTED;
585 			comma = ",";
586 		}
587 		if (flags & MNT_EXRDONLY) {
588 			printf("%sexrdonly", comma);
589 			flags &= ~MNT_EXRDONLY;
590 			comma = ",";
591 		}
592 		if (flags & MNT_LOCAL) {
593 			printf("%slocal", comma);
594 			flags &= ~MNT_LOCAL;
595 			comma = ",";
596 		}
597 		if (flags & MNT_QUOTA) {
598 			printf("%squota", comma);
599 			flags &= ~MNT_QUOTA;
600 			comma = ",";
601 		}
602 		/* filesystem control flags */
603 		if (flags & MNT_UPDATE) {
604 			printf("%supdate", comma);
605 			flags &= ~MNT_UPDATE;
606 			comma = ",";
607 		}
608 		if (flags & MNT_MLOCK) {
609 			printf("%slock", comma);
610 			flags &= ~MNT_MLOCK;
611 			comma = ",";
612 		}
613 		if (flags & MNT_MWAIT) {
614 			printf("%swait", comma);
615 			flags &= ~MNT_MWAIT;
616 			comma = ",";
617 		}
618 		if (flags & MNT_MPBUSY) {
619 			printf("%sbusy", comma);
620 			flags &= ~MNT_MPBUSY;
621 			comma = ",";
622 		}
623 		if (flags & MNT_MPWANT) {
624 			printf("%swant", comma);
625 			flags &= ~MNT_MPWANT;
626 			comma = ",";
627 		}
628 		if (flags & MNT_UNMOUNT) {
629 			printf("%sunmount", comma);
630 			flags &= ~MNT_UNMOUNT;
631 			comma = ",";
632 		}
633 		if (flags)
634 			printf("%sunknown_flags:%x", flags);
635 		printf(")");
636 	}
637 	printf("\n");
638 #undef ST
639 }
640 
641 struct e_vnode *
642 loadvnodes(avnodes)
643 	int *avnodes;
644 {
645 	int ret, copysize;
646 	struct e_vnode *vnodebase;
647 	struct e_vnode *kinfo_vnodes();
648 
649 	if (memf != NULL) {
650 		/*
651 		 * do it by hand
652 		 */
653 		return (kinfo_vnodes(avnodes));
654 	}
655 	if ((ret = getkerninfo(KINFO_VNODE, NULL, NULL, 0)) == -1) {
656 		syserror("can't get estimate for kerninfo");
657 		exit(1);
658 	}
659 	copysize = ret;
660 	if ((vnodebase = (struct e_vnode *)malloc(copysize))
661 	     == NULL) {
662 		error("out of memory");
663 		exit(1);
664 	}
665 	if ((ret = getkerninfo(KINFO_VNODE, vnodebase, &copysize, 0))
666 	     == -1) {
667 		syserror("can't get vnode list");
668 		exit(1);
669 	}
670 	if (copysize % sizeof (struct e_vnode)) {
671 		error("vnode size mismatch");
672 		exit(1);
673 	}
674 	*avnodes = copysize / sizeof (struct e_vnode);
675 
676 	return (vnodebase);
677 }
678 
679 /*
680  * simulate what a running kernel does in in kinfo_vnode
681  */
682 struct e_vnode *
683 kinfo_vnodes(avnodes)
684 	int *avnodes;
685 {
686 	struct nlist vnl[] = {
687 #define V_NUMV	0
688 		{ "_numvnodes" },
689 #define V_ROOTFS 1
690 		{ "_rootfs" },
691 		{""}
692 	};
693 	int numvnodes;
694 	struct mount *rootfs, *mp, mount;
695 	char *vbuf, *evbuf, *bp;
696 	struct vnode *vp, vnode;
697 	int num;
698 
699 #define VPTRSZ  sizeof (struct vnode *)
700 #define VNODESZ sizeof (struct vnode)
701 #define NVAL(indx)	vnl[(indx)].n_value
702 
703 	if (kvm_nlist(vnl) != 0) {
704 		error("nlist vnl: %s", kvm_geterr());
705 		exit(1);
706 	}
707 	numvnodes = getword(NVAL(V_NUMV));
708 	if ((vbuf = (char *)malloc((numvnodes + 20) * (VPTRSZ + VNODESZ)))
709 	    == NULL) {
710 		error("out of memory");
711 		exit(1);
712 	}
713 	bp = vbuf;
714 	evbuf = vbuf + (numvnodes + 20) * (VPTRSZ + VNODESZ);
715 	mp = rootfs = (struct mount *)getword(NVAL(V_ROOTFS));
716 	do {
717 		kvm_read(mp, &mount, sizeof(mount));
718 		for (vp = mount.mnt_mounth; vp; vp = vnode.v_mountf) {
719 			kvm_read(vp, &vnode, sizeof (vnode));
720 			if ((bp + VPTRSZ + VNODESZ) > evbuf) {
721 				/* XXX - should realloc */
722 				fprintf(stderr, "pstat: ran out of room for vnodes\n");
723 				exit(1);
724 			}
725 			bcopy(&vp, bp, VPTRSZ);
726 			bp += VPTRSZ;
727 			bcopy(&vnode, bp, VNODESZ);
728 			bp += VNODESZ;
729 			num++;
730 		}
731 		mp = mount.mnt_next;
732 	} while (mp != rootfs);
733 	*avnodes = num;
734 	return ((struct e_vnode *)vbuf);
735 }
736 
737 
738 u_long
739 getword(loc)
740 	int loc;
741 {
742 	u_long word;
743 
744 	kvm_read(V(loc), &word, sizeof (word));
745 	return (word);
746 }
747 
748 putf(v, n)
749 {
750 	if (v)
751 		printf("%c", n);
752 	else
753 		printf(" ");
754 }
755 
756 dotext()
757 {
758 #ifdef NEWVM
759 	printf("no text table in this system\n");
760 #else
761 	register struct text *xp;
762 	int ntext;
763 	struct text *xtext, *atext;
764 	int ntx, ntxca;
765 
766 	ntx = ntxca = 0;
767 	ntext = getword(nl[SNTEXT].n_value);
768 	xtext = (struct text *)calloc(ntext, sizeof (struct text));
769 	atext = (struct text *)getword(nl[STEXT].n_value);
770 	if (ntext < 0 || ntext > 10000) {
771 		fprintf(stderr, "number of texts is preposterous (%d)\n",
772 			ntext);
773 		return;
774 	}
775 	if (xtext == NULL) {
776 		fprintf(stderr, "can't allocate memory for text table\n");
777 		return;
778 	}
779 	kvm_read(atext, xtext, ntext * sizeof (struct text));
780 	for (xp = xtext; xp < &xtext[ntext]; xp++) {
781 		if (xp->x_vptr != NULL)
782 			ntxca++;
783 		if (xp->x_count != 0)
784 			ntx++;
785 	}
786 	if (totflg) {
787 		printf("%3d/%3d texts active, %3d used\n", ntx, ntext, ntxca);
788 		return;
789 	}
790 	printf("%d/%d active texts, %d used\n", ntx, ntext, ntxca);
791 	printf("\
792    LOC   FLAGS DADDR     CADDR  RSS SIZE     VPTR   CNT CCNT      FORW     BACK\n");
793 	for (xp = xtext; xp < &xtext[ntext]; xp++) {
794 		if (xp->x_vptr == NULL)
795 			continue;
796 		printf("%8.1x", atext + (xp - xtext));
797 		printf(" ");
798 		putf(xp->x_flag&XPAGV, 'P');
799 		putf(xp->x_flag&XTRC, 'T');
800 		putf(xp->x_flag&XWRIT, 'W');
801 		putf(xp->x_flag&XLOAD, 'L');
802 		putf(xp->x_flag&XLOCK, 'K');
803 		putf(xp->x_flag&XWANT, 'w');
804 		printf("%5x", xp->x_daddr[0]);
805 		printf("%10x", xp->x_caddr);
806 		printf("%5d", xp->x_rssize);
807 		printf("%5d", xp->x_size);
808 		printf("%10.1x", xp->x_vptr);
809 		printf("%5d", xp->x_count&0377);
810 		printf("%5d", xp->x_ccount);
811 		printf("%10x", xp->x_forw);
812 		printf("%9x", xp->x_back);
813 		printf("\n");
814 	}
815 	free(xtext);
816 #endif
817 }
818 
819 doproc()
820 {
821 	if (!totflg)
822 		printf("pstat: -p no longer supported (use ps)\n");
823 }
824 
825 char mesg[] = "  LINE RAW CAN OUT  HWT LWT     ADDR COL STATE  SESS  PGID DISC\n";
826 int ttyspace = 128;
827 struct tty *tty;
828 
829 dotty()
830 {
831 
832 	if ((tty = (struct tty *)malloc(ttyspace * sizeof(*tty))) == 0) {
833 		printf("pstat: out of memory\n");
834 		return;
835 	}
836 #ifndef hp300
837 	printf("1 cons\n");
838 	kvm_read(V(nl[SCONS].n_value), tty, sizeof(*tty));
839 	printf(mesg);
840 	ttyprt(&tty[0], 0);
841 #endif
842 #ifdef vax
843 	if (nl[SNQD].n_type != 0)
844 		doqdss();
845 	if (nl[SNDZ].n_type != 0)
846 		dottytype("dz", SDZ, SNDZ);
847 	if (nl[SNDH].n_type != 0)
848 		dottytype("dh", SDH, SNDH);
849 	if (nl[SNDMF].n_type != 0)
850 		dottytype("dmf", SDMF, SNDMF);
851 	if (nl[SNDHU].n_type != 0)
852 		dottytype("dhu", SDHU, SNDHU);
853 	if (nl[SNDMZ].n_type != 0)
854 		dottytype("dmz", SDMZ, SNDMZ);
855 #endif
856 #ifdef tahoe
857 	if (nl[SNVX].n_type != 0)
858 		dottytype("vx", SVX, SNVX);
859 	if (nl[SNMP].n_type != 0)
860 		dottytype("mp", SMP, SNMP);
861 #endif
862 #ifdef hp300
863 	if (nl[SNITE].n_type != 0)
864 		dottytype("ite", SITE, SNITE);
865 	if (nl[SNDCA].n_type != 0)
866 		dottytype("dca", SDCA, SNDCA);
867 	if (nl[SNDCM].n_type != 0)
868 		dottytype("dcm", SDCM, SNDCM);
869 	if (nl[SNDCL].n_type != 0)
870 		dottytype("dcl", SDCL, SNDCL);
871 #endif
872 	if (nl[SNPTY].n_type != 0)
873 		dottytype("pty", SPTY, SNPTY);
874 }
875 
876 /*
877  * Special case the qdss: there are 4 ttys per qdss,
878  * but only the first of each is used as a tty.
879  */
880 #ifdef vax
881 doqdss()
882 {
883 	int nqd;
884 	register struct tty *tp;
885 
886 	kvm_read(V(nl[SNQD].n_value), &nqd, sizeof(nqd));
887 	printf("%d qd\n", nqd);
888 	kvm_read(V(nl[SQD].n_value), tty, nqd * sizeof(struct tty) * 4);
889 	printf(mesg);
890 	for (tp = tty; tp < &tty[nqd * 4]; tp += 4)
891 		ttyprt(tp, tp - tty);
892 }
893 #endif
894 
895 dottytype(name, type, number)
896 char *name;
897 {
898 	int ntty;
899 	register struct tty *tp;
900 	extern char *realloc();
901 
902 	if (tty == (struct tty *)0)
903 		return;
904 	kvm_read(V(nl[number].n_value), &ntty, sizeof(ntty));
905 	printf("%d %s %s\n", ntty, name, (ntty == 1) ? "line" :
906 	    "lines");
907 	if (ntty > ttyspace) {
908 		ttyspace = ntty;
909 		if ((tty = (struct tty *)realloc(tty, ttyspace * sizeof(*tty))) == 0) {
910 			printf("pstat: out of memory\n");
911 			return;
912 		}
913 	}
914 	kvm_read(V(nl[type].n_value), tty, ntty * sizeof(struct tty));
915 	printf(mesg);
916 	for (tp = tty; tp < &tty[ntty]; tp++)
917 		ttyprt(tp, tp - tty);
918 }
919 
920 struct {
921 	int flag;
922 	char val;
923 } ttystates[] = {
924 	TS_WOPEN,	'W',
925 	TS_ISOPEN,	'O',
926 	TS_CARR_ON,	'C',
927 	TS_TIMEOUT,	'T',
928 	TS_FLUSH,	'F',
929 	TS_BUSY,	'B',
930 	TS_ASLEEP,	'A',
931 	TS_XCLUDE,	'X',
932 	TS_TTSTOP,	'S',
933 	TS_TBLOCK,	'K',
934 	TS_RCOLL,	'R',
935 	TS_WCOLL,	'I',	/* running short on letters ! */
936 	TS_ASYNC,	'Y',
937 	TS_BKSL,	'D',
938 	TS_ERASE,	'E',
939 	TS_LNCH,	'L',
940 	TS_TYPEN,	'P',
941 	TS_CNTTB,	'N',
942 	0,	0
943 };
944 
945 ttyprt(atp, line)
946 struct tty *atp;
947 {
948 	register struct tty *tp;
949 	char state[20];
950 	register i, j;
951 	char *name;
952 	extern char *devname();
953 	pid_t pgid;
954 
955 	tp = atp;
956 	if (nflg || tp->t_dev == 0 ||
957 	   (name = devname(tp->t_dev, S_IFCHR)) == NULL)
958 		printf("%7d ", line);
959 	else
960 		printf("%7s ", name);
961 	printf("%2d %3d ", tp->t_rawq.c_cc, tp->t_canq.c_cc);
962 	printf("%3d %4d %3d %8x %3d ", tp->t_outq.c_cc,
963 		tp->t_hiwat, tp->t_lowat, tp->t_addr, tp->t_col);
964 	for (i = j = 0; ttystates[i].flag; i++)
965 		if (tp->t_state&ttystates[i].flag)
966 			state[j++] = ttystates[i].val;
967 	if (j == 0)
968 		state[j++] = '-';
969 	state[j] = '\0';
970 	printf("%-4s %6x", state, (u_long)tp->t_session & ~KERNBASE);
971 	if (tp->t_pgrp == NULL || kvm_read(&tp->t_pgrp->pg_id, &pgid,
972 	    sizeof (pid_t)) != sizeof (pid_t))
973 		pgid = 0;
974 	printf("%6d ", pgid);
975 	switch (tp->t_line) {
976 
977 	case TTYDISC:
978 		printf("term\n");
979 		break;
980 
981 	case TABLDISC:
982 		printf("tab\n");
983 		break;
984 
985 	case SLIPDISC:
986 		printf("slip\n");
987 		break;
988 
989 	default:
990 		printf("%d\n", tp->t_line);
991 	}
992 }
993 
994 /*
995  * The user structure is going away.  What's left here won't
996  * be around for long.
997  */
998 dousr()
999 {
1000 #ifdef NEWVM
1001 	printf("nothing left in user structure in this system\n");
1002 #else
1003 	register struct user *up;
1004 	register i, j, *ip;
1005 	register struct nameidata *nd;
1006 	struct proc *p;
1007 	int ret;
1008 
1009 	if ((ret = kvm_getprocs(KINFO_PROC_PID, upid)) != 1) {
1010 		if (ret == -1)
1011 			error("kvm_getproc: %s", kvm_geterr());
1012 		else
1013 			error("can't locate process %d", upid);
1014 		return (1);
1015 	}
1016 	if ((p = kvm_nextproc()) == NULL) {
1017 		error("kvm_nextproc: %s", kvm_geterr());
1018 		return (1);
1019 	}
1020 	if ((up = kvm_getu(p)) == NULL) {
1021 		error("kvm_getu: %s", kvm_geterr());
1022 		return (1);
1023 	}
1024 	nd = &up->u_nd;
1025 	printf("pcb");
1026 	ip = (int *)&up->u_pcb;
1027 	i = 0;
1028 	while (ip < (int *)((char *)&up->u_pcb + sizeof (struct pcb))) {
1029 		if (i%4 == 0)
1030 			putchar('\t');
1031 		printf("%#10x ", *ip++);
1032 		if (i%4 == 3)
1033 			putchar('\n');
1034 		i++;
1035 	}
1036 	if (i%4)
1037 		putchar('\n');
1038 	printf("procp\t%#x\n", up->u_procp);
1039 	printf("ar0\t%#x\n", up->u_ar0);
1040 	printf("sizes\ttext %d data %d stack %d\n",
1041 		up->u_tsize, up->u_dsize, up->u_ssize);
1042 	printf("ssave");
1043 	for (i=0; i<sizeof(label_t)/sizeof(int); i++) {
1044 		if (i%5==0)
1045 			printf("\t");
1046 		printf("%#11x", up->u_ssave.val[i]);
1047 		if (i%5==4)
1048 			printf("\n");
1049 	}
1050 	if (i%5)
1051 		printf("\n");
1052 	printf("odsize\t%#x\n", up->u_odsize);
1053 	printf("ossize\t%#x\n", up->u_ossize);
1054 	printf("outime\t%d\n", up->u_outime);
1055 	printf("mmap\t%#x\n", up->u_mmap);
1056 	printf("sigs");
1057 	for (i=0; i<NSIG; i++) {
1058 		if (i % 8 == 0)
1059 			printf("\t");
1060 		printf("%#x ", up->u_signal[i]);
1061 		if (i % 8 == 7)
1062 			printf("\n");
1063 	}
1064 	if (i % 8)
1065 		printf("\n");
1066 	printf("sigmask");
1067 	for (i=0; i<NSIG; i++) {
1068 		if (i % 8 == 0)
1069 			printf("\t");
1070 		printf("%#x ", up->u_sigmask[i]);
1071 		if (i % 8 == 7)
1072 			printf("\n");
1073 	}
1074 	if (i % 8)
1075 		printf("\n");
1076 	printf("sigonstack\t%#x\n", up->u_sigonstack);
1077 	printf("sigintr\t%#x\n", up->u_sigintr);
1078 	printf("oldmask\t%#x\n", up->u_oldmask);
1079 	printf("sigstack\t%#x %#x\n",
1080 		up->u_sigstack.ss_sp, up->u_sigstack.ss_onstack);
1081 	printf("sig\t%#x\n", up->u_sig);
1082 	printf("code\t%#x\n", up->u_code);
1083 	printf("start\t%ld secs %ld usecs\n",
1084 		up->u_start.tv_sec, up->u_start.tv_usec);
1085 	printf("acflag\t%#x\n", up->u_acflag);
1086 	printf("prof\t%#x %#x %#x %#x\n", up->u_prof.pr_base, up->u_prof.pr_size,
1087 	    up->u_prof.pr_off, up->u_prof.pr_scale);
1088 	printf("ru\t");
1089 	ip = (int *)&up->u_ru;
1090 	for (i = 0; i < sizeof(up->u_ru)/sizeof(int); i++)
1091 		printf("%ld ", ip[i]);
1092 	printf("\n");
1093 	ip = (int *)&up->u_cru;
1094 	printf("cru\t");
1095 	for (i = 0; i < sizeof(up->u_cru)/sizeof(int); i++)
1096 		printf("%ld ", ip[i]);
1097 	printf("\n");
1098 #endif
1099 }
1100 
1101 oatoi(s)
1102 char *s;
1103 {
1104 	register v;
1105 
1106 	v = 0;
1107 	while (*s)
1108 		v = (v<<3) + *s++ - '0';
1109 	return(v);
1110 }
1111 
1112 dofile()
1113 {
1114 	register struct file *fp;
1115 	struct file *addr;
1116 	char *buf;
1117 	int len, maxfile, nfile;
1118 	struct nlist fnl[] = {
1119 #define	FNL_NFILE	0
1120 		{"_nfiles"},
1121 #define FNL_MAXFILE	1
1122 		{"_maxfiles"},
1123 		{""}
1124 	};
1125 	static char *dtypes[] = { "???", "inode", "socket" };
1126 
1127 	if (kvm_nlist(fnl) != 0) {
1128 		error("kvm_nlist: no _nfiles or _maxfiles: %s",
1129 			kvm_geterr());
1130 		return;
1131 	}
1132 	kvm_read(V(fnl[FNL_MAXFILE].n_value), &maxfile,
1133 		sizeof (maxfile));
1134 	if (totflg) {
1135 		kvm_read(V(fnl[FNL_NFILE].n_value), &nfile, sizeof (nfile));
1136 		printf("%3d/%3d files\n", nfile, maxfile);
1137 		return;
1138 	}
1139 	if (getfiles(&buf, &len) == -1)
1140 		return;
1141 	/*
1142 	 * getfiles returns in malloc'd buf a pointer to the first file
1143 	 * structure, and then an array of file structs (whose
1144 	 * addresses are derivable from the previous entry)
1145 	 */
1146 	addr = *((struct file **)buf);
1147 	fp = (struct file *)(buf + sizeof (struct file *));
1148 	nfile = (len - sizeof (struct file *)) / sizeof (struct file);
1149 
1150 	printf("%d/%d open files\n", nfile, maxfile);
1151 	printf("   LOC   TYPE    FLG     CNT  MSG    DATA    OFFSET\n");
1152 	for (; (char *)fp < buf + len; addr = fp->f_filef, fp++) {
1153 		printf("%x ", addr);
1154 		if (fp->f_type <= DTYPE_SOCKET)
1155 			printf("%-8.8s", dtypes[fp->f_type]);
1156 		else
1157 			printf("%8d", fp->f_type);
1158 		putf(fp->f_flag&FREAD, 'R');
1159 		putf(fp->f_flag&FWRITE, 'W');
1160 		putf(fp->f_flag&FAPPEND, 'A');
1161 #ifdef FSHLOCK	/* currently gone */
1162 		putf(fp->f_flag&FSHLOCK, 'S');
1163 		putf(fp->f_flag&FEXLOCK, 'X');
1164 #else
1165 		putf(0, ' ');
1166 		putf(0, ' ');
1167 #endif
1168 		putf(fp->f_flag&FASYNC, 'I');
1169 		printf("  %3d", fp->f_count);
1170 		printf("  %3d", fp->f_msgcount);
1171 		printf("  %8.1x", fp->f_data);
1172 		if (fp->f_offset < 0)
1173 			printf("  %x\n", fp->f_offset);
1174 		else
1175 			printf("  %ld\n", fp->f_offset);
1176 	}
1177 	free(buf);
1178 }
1179 
1180 getfiles(abuf, alen)
1181 	char **abuf;
1182 	int *alen;
1183 {
1184 	char *buf;
1185 	int len;
1186 
1187 	if (memf != NULL) {
1188 		/*
1189 		 * add emulation of KINFO_FILE here
1190 		 */
1191 		error("files on dead kernel, not impl\n");
1192 		exit(1);
1193 	}
1194 	if ((len = getkerninfo(KINFO_FILE, NULL, NULL, 0)) == -1) {
1195 		syserror("getkerninfo estimate");
1196 		return (-1);
1197 	}
1198 	if ((buf = (char *)malloc(len)) == NULL) {
1199 		error("out of memory");
1200 		return (-1);
1201 	}
1202 	if ((len = getkerninfo(KINFO_FILE, buf, &len, 0)) == -1) {
1203 		syserror("getkerninfo");
1204 		return (-1);
1205 	}
1206 	*abuf = buf;
1207 	*alen = len;
1208 	return (0);
1209 }
1210 
1211 
1212 #ifdef NEWVM
1213 doswap()
1214 {
1215 	printf("swap statistics not yet supported in this system\n");
1216 }
1217 
1218 #else /* NEWVM */
1219 int dmmin, dmmax, nswdev;
1220 
1221 doswap()
1222 {
1223 	struct proc *proc;
1224 	int nproc;
1225 	struct text *xtext;
1226 	int ntext;
1227 	struct map *swapmap;
1228 	int nswapmap;
1229 	struct swdevt *swdevt, *sw;
1230 	register struct proc *pp;
1231 	int nswap, used, tused, free, waste;
1232 	int db, sb;
1233 	register struct mapent *me;
1234 	register struct text *xp;
1235 	int i, j;
1236 	long rmalloc();
1237 
1238 	nproc = getword(nl[SNPROC].n_value);
1239 	ntext = getword(nl[SNTEXT].n_value);
1240 	if (nproc < 0 || nproc > 10000 || ntext < 0 || ntext > 10000) {
1241 		fprintf(stderr, "number of procs/texts is preposterous (%d, %d)\n",
1242 			nproc, ntext);
1243 		return;
1244 	}
1245 	proc = (struct proc *)calloc(nproc, sizeof (struct proc));
1246 	if (proc == NULL) {
1247 		fprintf(stderr, "can't allocate memory for proc table\n");
1248 		exit(1);
1249 	}
1250 	xtext = (struct text *)calloc(ntext, sizeof (struct text));
1251 	if (xtext == NULL) {
1252 		fprintf(stderr, "can't allocate memory for text table\n");
1253 		exit(1);
1254 	}
1255 	nswapmap = getword(nl[SNSWAPMAP].n_value);
1256 	swapmap = (struct map *)calloc(nswapmap, sizeof (struct map));
1257 	if (swapmap == NULL) {
1258 		fprintf(stderr, "can't allocate memory for swapmap\n");
1259 		exit(1);
1260 	}
1261 	nswdev = getword(nl[SNSWDEV].n_value);
1262 	swdevt = (struct swdevt *)calloc(nswdev, sizeof (struct swdevt));
1263 	if (swdevt == NULL) {
1264 		fprintf(stderr, "can't allocate memory for swdevt table\n");
1265 		exit(1);
1266 	}
1267 	kvm_read(V(nl[SSWDEVT].n_value), swdevt,
1268 		nswdev * sizeof (struct swdevt));
1269 	kvm_read(V(getword(nl[SPROC].n_value)), proc,
1270 		nproc * sizeof (struct proc));
1271 	kvm_read(V(getword(nl[STEXT].n_value)), xtext,
1272 		ntext * sizeof (struct text));
1273 	kvm_read(V(getword(nl[SWAPMAP].n_value)), swapmap,
1274 		nswapmap * sizeof (struct map));
1275 
1276 	swapmap->m_name = "swap";
1277 	swapmap->m_limit = (struct mapent *)&swapmap[nswapmap];
1278 	dmmin = getword(nl[SDMMIN].n_value);
1279 	dmmax = getword(nl[SDMMAX].n_value);
1280 	nswap = 0;
1281 	for (sw = swdevt; sw < &swdevt[nswdev]; sw++)
1282 		if (sw->sw_freed)
1283 			nswap += sw->sw_nblks;
1284 	free = 0;
1285 	for (me = (struct mapent *)(swapmap+1);
1286 	    me < (struct mapent *)&swapmap[nswapmap]; me++)
1287 		free += me->m_size;
1288 	tused = 0;
1289 	for (xp = xtext; xp < &xtext[ntext]; xp++)
1290 		if (xp->x_vptr!=NULL) {
1291 			tused += ctod(clrnd(xp->x_size));
1292 			if (xp->x_flag & XPAGV)
1293 				tused += ctod(clrnd(ctopt(xp->x_size)));
1294 		}
1295 	used = tused;
1296 	waste = 0;
1297 	for (pp = proc; pp < &proc[nproc]; pp++) {
1298 		if (pp->p_stat == 0 || pp->p_stat == SZOMB)
1299 			continue;
1300 		if (pp->p_flag & SSYS)
1301 			continue;
1302 		db = ctod(pp->p_dsize), sb = up(db);
1303 		used += sb;
1304 		waste += sb - db;
1305 		db = ctod(pp->p_ssize), sb = up(db);
1306 		used += sb;
1307 		waste += sb - db;
1308 		if ((pp->p_flag&SLOAD) == 0)
1309 			used += ctod(vusize(pp));
1310 	}
1311 	if (totflg) {
1312 #define	btok(x)	((x) / (1024 / DEV_BSIZE))
1313 		printf("%3d/%3d 00k swap\n",
1314 		    btok(used/100), btok((used+free)/100));
1315 		return;
1316 	}
1317 	printf("%dk used (%dk text), %dk free, %dk wasted, %dk missing\n",
1318 	    btok(used), btok(tused), btok(free), btok(waste),
1319 /* a dmmax/2 block goes to argmap */
1320 	    btok(nswap - dmmax/2 - (used + free)));
1321 	printf("avail: ");
1322 	for (i = dmmax; i >= dmmin; i /= 2) {
1323 		j = 0;
1324 		while (rmalloc(swapmap, i) != 0)
1325 			j++;
1326 		if (j) printf("%d*%dk ", j, btok(i));
1327 	}
1328 	free = 0;
1329 	for (me = (struct mapent *)(swapmap+1);
1330 	    me < (struct mapent *)&swapmap[nswapmap]; me++)
1331 		free += me->m_size;
1332 	printf("%d*1k\n", btok(free));
1333 }
1334 
1335 up(size)
1336 	register int size;
1337 {
1338 	register int i, block;
1339 
1340 	i = 0;
1341 	block = dmmin;
1342 	while (i < size) {
1343 		i += block;
1344 		if (block < dmmax)
1345 			block *= 2;
1346 	}
1347 	return (i);
1348 }
1349 
1350 /*
1351  * Compute number of pages to be allocated to the u. area
1352  * and data and stack area page tables, which are stored on the
1353  * disk immediately after the u. area.
1354  */
1355 vusize(p)
1356 	register struct proc *p;
1357 {
1358 	register int tsz = p->p_tsize / NPTEPG;
1359 
1360 	/*
1361 	 * We do not need page table space on the disk for page
1362 	 * table pages wholly containing text.
1363 	 */
1364 	return (clrnd(UPAGES +
1365 	    clrnd(ctopt(p->p_tsize+p->p_dsize+p->p_ssize+UPAGES)) - tsz));
1366 }
1367 
1368 /*
1369  * Allocate 'size' units from the given
1370  * map. Return the base of the allocated space.
1371  * In a map, the addresses are increasing and the
1372  * list is terminated by a 0 size.
1373  *
1374  * Algorithm is first-fit.
1375  *
1376  * This routine knows about the interleaving of the swapmap
1377  * and handles that.
1378  */
1379 long
1380 rmalloc(mp, size)
1381 	register struct map *mp;
1382 	long size;
1383 {
1384 	register struct mapent *ep = (struct mapent *)(mp+1);
1385 	register int addr;
1386 	register struct mapent *bp;
1387 	swblk_t first, rest;
1388 
1389 	if (size <= 0 || size > dmmax)
1390 		return (0);
1391 	/*
1392 	 * Search for a piece of the resource map which has enough
1393 	 * free space to accomodate the request.
1394 	 */
1395 	for (bp = ep; bp->m_size; bp++) {
1396 		if (bp->m_size >= size) {
1397 			/*
1398 			 * If allocating from swapmap,
1399 			 * then have to respect interleaving
1400 			 * boundaries.
1401 			 */
1402 			if (nswdev > 1 &&
1403 			    (first = dmmax - bp->m_addr%dmmax) < bp->m_size) {
1404 				if (bp->m_size - first < size)
1405 					continue;
1406 				addr = bp->m_addr + first;
1407 				rest = bp->m_size - first - size;
1408 				bp->m_size = first;
1409 				if (rest)
1410 					rmfree(mp, rest, addr+size);
1411 				return (addr);
1412 			}
1413 			/*
1414 			 * Allocate from the map.
1415 			 * If there is no space left of the piece
1416 			 * we allocated from, move the rest of
1417 			 * the pieces to the left.
1418 			 */
1419 			addr = bp->m_addr;
1420 			bp->m_addr += size;
1421 			if ((bp->m_size -= size) == 0) {
1422 				do {
1423 					bp++;
1424 					(bp-1)->m_addr = bp->m_addr;
1425 				} while ((bp-1)->m_size = bp->m_size);
1426 			}
1427 			if (addr % CLSIZE)
1428 				return (0);
1429 			return (addr);
1430 		}
1431 	}
1432 	return (0);
1433 }
1434 
1435 /*
1436  * Free the previously allocated space at addr
1437  * of size units into the specified map.
1438  * Sort addr into map and combine on
1439  * one or both ends if possible.
1440  */
1441 rmfree(mp, size, addr)
1442 	struct map *mp;
1443 	long size, addr;
1444 {
1445 	struct mapent *firstbp;
1446 	register struct mapent *bp;
1447 	register int t;
1448 
1449 	/*
1450 	 * Both address and size must be
1451 	 * positive, or the protocol has broken down.
1452 	 */
1453 	if (addr <= 0 || size <= 0)
1454 		goto badrmfree;
1455 	/*
1456 	 * Locate the piece of the map which starts after the
1457 	 * returned space (or the end of the map).
1458 	 */
1459 	firstbp = bp = (struct mapent *)(mp + 1);
1460 	for (; bp->m_addr <= addr && bp->m_size != 0; bp++)
1461 		continue;
1462 	/*
1463 	 * If the piece on the left abuts us,
1464 	 * then we should combine with it.
1465 	 */
1466 	if (bp > firstbp && (bp-1)->m_addr+(bp-1)->m_size >= addr) {
1467 		/*
1468 		 * Check no overlap (internal error).
1469 		 */
1470 		if ((bp-1)->m_addr+(bp-1)->m_size > addr)
1471 			goto badrmfree;
1472 		/*
1473 		 * Add into piece on the left by increasing its size.
1474 		 */
1475 		(bp-1)->m_size += size;
1476 		/*
1477 		 * If the combined piece abuts the piece on
1478 		 * the right now, compress it in also,
1479 		 * by shifting the remaining pieces of the map over.
1480 		 */
1481 		if (bp->m_addr && addr+size >= bp->m_addr) {
1482 			if (addr+size > bp->m_addr)
1483 				goto badrmfree;
1484 			(bp-1)->m_size += bp->m_size;
1485 			while (bp->m_size) {
1486 				bp++;
1487 				(bp-1)->m_addr = bp->m_addr;
1488 				(bp-1)->m_size = bp->m_size;
1489 			}
1490 		}
1491 		goto done;
1492 	}
1493 	/*
1494 	 * Don't abut on the left, check for abutting on
1495 	 * the right.
1496 	 */
1497 	if (addr+size >= bp->m_addr && bp->m_size) {
1498 		if (addr+size > bp->m_addr)
1499 			goto badrmfree;
1500 		bp->m_addr -= size;
1501 		bp->m_size += size;
1502 		goto done;
1503 	}
1504 	/*
1505 	 * Don't abut at all.  Make a new entry
1506 	 * and check for map overflow.
1507 	 */
1508 	do {
1509 		t = bp->m_addr;
1510 		bp->m_addr = addr;
1511 		addr = t;
1512 		t = bp->m_size;
1513 		bp->m_size = size;
1514 		bp++;
1515 	} while (size = t);
1516 	/*
1517 	 * Segment at bp is to be the delimiter;
1518 	 * If there is not room for it
1519 	 * then the table is too full
1520 	 * and we must discard something.
1521 	 */
1522 	if (bp+1 > mp->m_limit) {
1523 		/*
1524 		 * Back bp up to last available segment.
1525 		 * which contains a segment already and must
1526 		 * be made into the delimiter.
1527 		 * Discard second to last entry,
1528 		 * since it is presumably smaller than the last
1529 		 * and move the last entry back one.
1530 		 */
1531 		bp--;
1532 		printf("%s: rmap ovflo, lost [%d,%d)\n", mp->m_name,
1533 		    (bp-1)->m_addr, (bp-1)->m_addr+(bp-1)->m_size);
1534 		bp[-1] = bp[0];
1535 		bp[0].m_size = bp[0].m_addr = 0;
1536 	}
1537 done:
1538 	return;
1539 badrmfree:
1540 	printf("bad rmfree\n");
1541 }
1542 #endif /* NEWVM */
1543 
1544 #include <varargs.h>
1545 
1546 error(va_alist)
1547 	va_dcl
1548 {
1549 	char *fmt;
1550 	va_list ap;
1551 	extern errno;
1552 
1553 	fprintf(stderr, "pstat: ");
1554 	va_start(ap);
1555 	fmt = va_arg(ap, char *);
1556 	(void) vfprintf(stderr, fmt, ap);
1557 	va_end(ap);
1558 	fprintf(stderr, "\n");
1559 }
1560 
1561 syserror(va_alist)
1562 	va_dcl
1563 {
1564 	char *fmt;
1565 	va_list ap;
1566 	extern errno;
1567 
1568 	fprintf(stderr, "pstat: ");
1569 	va_start(ap);
1570 	fmt = va_arg(ap, char *);
1571 	(void) vfprintf(stderr, fmt, ap);
1572 	va_end(ap);
1573 	fprintf(stderr, ": %s\n", strerror(errno));
1574 }
1575