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