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