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