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