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