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