xref: /original-bsd/usr.sbin/pstat/pstat.c (revision 159d5566)
1 /*-
2  * Copyright (c) 1980, 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1980, 1991 The Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)pstat.c	5.40 (Berkeley) 04/13/93";
16 #endif /* not lint */
17 
18 #include <sys/param.h>
19 #include <sys/user.h>
20 #include <sys/proc.h>
21 #include <sys/time.h>
22 #include <sys/vnode.h>
23 #include <sys/map.h>
24 #define KERNEL
25 #include <sys/file.h>
26 #include <ufs/ufs/quota.h>
27 #include <ufs/ufs/inode.h>
28 #undef KERNEL
29 #define NFS
30 #include <sys/mount.h>
31 #undef NFS
32 #include <sys/stat.h>
33 #include <nfs/nfsnode.h>
34 /* #include <nfs/nfsv2.h> */
35 /* #include <nfs/nfs.h> */
36 #include <sys/ioctl.h>
37 #include <sys/tty.h>
38 #include <sys/conf.h>
39 
40 #include <sys/sysctl.h>
41 
42 #include <nlist.h>
43 #include <kvm.h>
44 #include <stdio.h>
45 #include <limits.h>
46 #include "pathnames.h"
47 
48 #define mask(x)		(x&0377)
49 #define	clear(x)	((int)x &~ KERNBASE)
50 
51 char	*nlistf	= NULL;
52 char	*memf	= NULL;
53 
54 struct nlist nl[] = {
55 #define	SWAPMAP	0
56 	{ "_swapmap" },
57 #define	SNSWAPMAP 1
58 	{ "_nswapmap" },
59 #define	SDMMIN	2
60 	{ "_dmmin" },
61 #define	SDMMAX	3
62 	{ "_dmmax" },
63 #define	SNSWDEV	4
64 	{ "_nswdev" },
65 #define	SSWDEVT	5
66 	{ "_swdevt" },
67 #define NLMANDATORY SSWDEVT	/* names up to here are mandatory */
68 #define	SCONS	NLMANDATORY + 1
69 	{ "_cons" },
70 #define	SPTY	NLMANDATORY + 2
71 	{ "_pt_tty" },
72 #define	SNPTY	NLMANDATORY + 3
73 	{ "_npty" },
74 #ifdef vax
75 #define	SDZ	(SNPTY+1)
76 	{ "_dz_tty" },
77 #define	SNDZ	(SNPTY+2)
78 	{ "_dz_cnt" },
79 #define	SDMF	(SNPTY+3)
80 	{ "_dmf_tty" },
81 #define	SNDMF	(SNPTY+4)
82 	{ "_ndmf" },
83 #define	SDH	(SNPTY+5)
84 	{ "_dh11" },
85 #define	SNDH	(SNPTY+6)
86 	{ "_ndh11" },
87 #define	SDHU	(SNPTY+7)
88 	{ "_dhu_tty" },
89 #define	SNDHU	(SNPTY+8)
90 	{ "_ndhu" },
91 #define	SDMZ	(SNPTY+9)
92 	{ "_dmz_tty" },
93 #define	SNDMZ	(SNPTY+10)
94 	{ "_ndmz" },
95 #define	SQD	(SNPTY+11)
96 	{ "_qd_tty" },
97 #define	SNQD	(SNPTY+12)
98 	{ "_nNQD" },
99 #endif
100 
101 #ifdef tahoe
102 #define	SVX	(SNPTY+1)
103 	{ "_vx_tty" },
104 #define	SNVX	(SNPTY+2)
105 	{ "_nvx" },
106 #define SMP	(SNPTY+3)
107 	{ "_mp_tty" },
108 #define SNMP	(SNPTY+4)
109 	{ "_nmp" },
110 #endif
111 
112 #ifdef hp300
113 #define	SDCA	(SNPTY+1)
114 	{ "_dca_tty" },
115 #define	SNDCA	(SNPTY+2)
116 	{ "_ndca" },
117 #define	SDCM	(SNPTY+3)
118 	{ "_dcm_tty" },
119 #define	SNDCM	(SNPTY+4)
120 	{ "_ndcm" },
121 #define	SDCL	(SNPTY+5)
122 	{ "_dcl_tty" },
123 #define	SNDCL	(SNPTY+6)
124 	{ "_ndcl" },
125 #define	SITE	(SNPTY+7)
126 	{ "_ite_tty" },
127 #define	SNITE	(SNPTY+8)
128 	{ "_nite" },
129 #endif
130 
131 #ifdef mips
132 #define SDC	(SNPTY+1)
133 	{ "_dc_tty" },
134 #define SNDC	(SNPTY+2)
135 	{ "_dc_cnt" },
136 #endif
137 
138 	{ "" }
139 };
140 
141 int	vnof;
142 int	txtf;
143 int	prcf;
144 int	ttyf;
145 int	usrf;
146 int	upid;
147 int	filf;
148 int	swpf;
149 int	totflg;
150 char	partab[1];
151 struct	cdevsw	cdevsw[1];
152 struct	bdevsw	bdevsw[1];
153 int	allflg;
154 int	nflg;
155 u_long	getword();
156 off_t	mkphys();
157 kvm_t	*kd;
158 
159 #define V(x)	(u_long)(x)
160 
161 main(argc, argv)
162 	int argc;
163 	char *argv[];
164 {
165 	extern char *optarg;
166 	extern int optind;
167 	int ch, ret;
168 	char buf[_POSIX2_LINE_MAX];
169 
170 	while ((ch = getopt(argc, argv, "TafvikptU:sxnu")) != EOF)
171 		switch (ch) {
172 		case 'T':
173 			totflg++;
174 			break;
175 		case 'a':
176 			allflg++;
177 			/*FALLTHROUGH*/
178 		case 'p':
179 			prcf++;
180 			break;
181 		case 'f':
182 			filf++;
183 			break;
184 		case 'v':
185 		case 'i':
186 			vnof++;
187 			break;
188 		case 't':
189 			ttyf++;
190 			break;
191 		case 'U':
192 			usrf++;
193 			sscanf(optarg, "%d", &upid);
194 			break;
195 		case 's':
196 			swpf++;
197 			break;
198 		case 'x':
199 			txtf++;
200 			break;
201 		case 'n':
202 			nflg++;
203 			break;
204 		case 'u':
205 			fprintf(stderr, "pstat: use [ -U pid ] for -u\n");
206 			exit(1);
207 		case '?':
208 		default:
209 			usage();
210 		}
211 	argc -= optind;
212 	argv += optind;
213 
214 	if (argc > 1)
215 		memf = argv[1];
216 	if (argc > 0)
217 		nlistf = argv[0];
218 
219 	/*
220 	 * Discard setgid privileges if not the running kernel so that bad
221 	 * guys can't print interesting stuff from kernel memory.
222 	 */
223 	if (nlistf != NULL || memf != NULL)
224 		setgid(getgid());
225 
226 	if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == 0) {
227 		error("kvm_openfiles: %s", buf);
228 		exit(1);
229 	}
230 	if ((ret = kvm_nlist(kd, nl)) != 0) {
231 		int i, quit = 0;
232 
233 		if (ret == -1) {
234 			error("kvm_nlist: %s", kvm_geterr(kd));
235 			exit(1);
236 		}
237 		for (i = 0; i <= NLMANDATORY; i++) {
238 			if (!nl[i].n_value) {
239 				quit = 1;
240 				error("undefined symbol: %s\n",
241 					nl[i].n_name);
242 			}
243 		}
244 		if (quit)
245 			exit(1);
246 	}
247 	if (!(filf | totflg | vnof | prcf | txtf | ttyf | usrf | swpf))
248 		usage();
249 	if (filf||totflg)
250 		dofile();
251 	if (vnof||totflg)
252 		dovnode();
253 	if (prcf||totflg)
254 		doproc();
255 	if (txtf||totflg)
256 		dotext();
257 	if (ttyf)
258 		dotty();
259 	if (usrf)
260 		dousr();
261 	if (swpf||totflg)
262 		doswap();
263 }
264 
265 usage()
266 {
267 
268 	fprintf(stderr,
269 	    "usage: pstat -[Tafiptsx] [-U [pid]] [system] [core]\n");
270 	exit(1);
271 }
272 
273 struct e_vnode {
274 	struct vnode *avnode;
275 	struct vnode vnode;
276 };
277 
278 dovnode()
279 {
280 	register struct e_vnode *e_vnodebase, *endvnode, *evp;
281 	register struct vnode *vp;
282 	register struct mount *maddr = NULL, *mp;
283 	int numvnodes;
284 	struct e_vnode *loadvnodes();
285 	struct mount *getmnt();
286 
287 	e_vnodebase = loadvnodes(&numvnodes);
288 	if (totflg) {
289 		printf("%7d vnodes\n", numvnodes);
290 		return;
291 	}
292 	endvnode = e_vnodebase + numvnodes;
293 	printf("%d active vnodes\n", numvnodes);
294 
295 
296 #define ST	mp->mnt_stat
297 	for (evp = e_vnodebase; evp < endvnode; evp++) {
298 		vp = &evp->vnode;
299 		if (vp->v_mount != maddr) {
300 			/*
301 			 * New filesystem
302 			 */
303 			if ((mp = getmnt(vp->v_mount)) == NULL)
304 				continue;
305 			maddr = vp->v_mount;
306 			mount_print(mp);
307 			vnode_header();
308 			switch(ST.f_type) {
309 			case MOUNT_UFS:
310 			case MOUNT_MFS:
311 				ufs_header();
312 				break;
313 			case MOUNT_NFS:
314 				nfs_header();
315 				break;
316 			case MOUNT_NONE:
317 			case MOUNT_PC:
318 			default:
319 				break;
320 			}
321 			printf("\n");
322 		}
323 		vnode_print(evp->avnode, vp);
324 		switch(ST.f_type) {
325 		case MOUNT_UFS:
326 		case MOUNT_MFS:
327 			ufs_print(vp);
328 			break;
329 		case MOUNT_NFS:
330 			nfs_print(vp);
331 			break;
332 		case MOUNT_NONE:
333 		case MOUNT_PC:
334 		default:
335 			break;
336 		}
337 		printf("\n");
338 	}
339 	free(e_vnodebase);
340 }
341 
342 vnode_header()
343 {
344 	printf("ADDR     TYP VFLAG  USE HOLD");
345 }
346 
347 vnode_print(avnode, vp)
348 	struct vnode *avnode;
349 	struct vnode *vp;
350 {
351 	char *type, flags[16];
352 	char *fp = flags;
353 	register flag;
354 
355 	/*
356 	 * set type
357 	 */
358 	switch(vp->v_type) {
359 	case VNON:
360 		type = "non"; break;
361 	case VREG:
362 		type = "reg"; break;
363 	case VDIR:
364 		type = "dir"; break;
365 	case VBLK:
366 		type = "blk"; break;
367 	case VCHR:
368 		type = "chr"; break;
369 	case VLNK:
370 		type = "lnk"; break;
371 	case VSOCK:
372 		type = "soc"; break;
373 	case VFIFO:
374 		type = "fif"; break;
375 	case VBAD:
376 		type = "bad"; break;
377 	default:
378 		type = "unk"; break;
379 	}
380 	/*
381 	 * gather flags
382 	 */
383 	flag = vp->v_flag;
384 	if (flag & VROOT)
385 		*fp++ = 'R';
386 	if (flag & VTEXT)
387 		*fp++ = 'T';
388 	if (flag & VSYSTEM)
389 		*fp++ = 'S';
390 	if (flag & VXLOCK)
391 		*fp++ = 'L';
392 	if (flag & VXWANT)
393 		*fp++ = 'W';
394 	if (flag & VBWAIT)
395 		*fp++ = 'B';
396 	if (flag & VALIASED)
397 		*fp++ = 'A';
398 	if (flag == 0)
399 		*fp++ = '-';
400 	*fp = '\0';
401 	/*
402 	 * print it
403 	 */
404 	printf("%8x %s %5s %4d %4d",
405 		avnode, type, flags, vp->v_usecount, vp->v_holdcnt);
406 }
407 
408 ufs_header()
409 {
410 	printf(" FILEID IFLAG RDEV|SZ");
411 }
412 
413 ufs_print(vp)
414 	struct vnode *vp;
415 {
416 	struct inode inode, *ip = &inode;
417 	char flagbuf[16], *flags = flagbuf;
418 	register flag;
419 	char *name;
420 	mode_t type;
421 	extern char *devname();
422 
423 	if (kvm_read(kd, V(VTOI(vp)), &inode, sizeof(struct inode)) !=
424 	    sizeof(struct inode)) {
425 		error("can't read inode for %x", vp);
426 		return;
427 	}
428 	flag = ip->i_flag;
429 	if (flag & ILOCKED)
430 		*flags++ = 'L';
431 	if (flag & IWANT)
432 		*flags++ = 'W';
433 	if (flag & IRENAME)
434 		*flags++ = 'R';
435 	if (flag & IUPD)
436 		*flags++ = 'U';
437 	if (flag & IACC)
438 		*flags++ = 'A';
439 	if (flag & ICHG)
440 		*flags++ = 'C';
441 	if (flag & IMOD)
442 		*flags++ = 'M';
443 	if (flag & ISHLOCK)
444 		*flags++ = 'S';
445 	if (flag & IEXLOCK)
446 		*flags++ = 'E';
447 	if (flag & ILWAIT)
448 		*flags++ = 'Z';
449 	if (flag == 0)
450 		*flags++ = '-';
451 	*flags = '\0';
452 
453 	printf(" %6d %5s", ip->i_number, flagbuf);
454 	type = ip->i_mode & S_IFMT;
455 	if (type == S_IFCHR || type == S_IFBLK)
456 		if (nflg || ((name = devname(ip->i_rdev, type)) == NULL))
457 			printf("   %2d,%-2d",
458 				major(ip->i_rdev), minor(ip->i_rdev));
459 		else
460 			printf(" %7s", name);
461 	else
462 		printf(" %7qd", ip->i_size);
463 }
464 
465 nfs_header()
466 {
467 	printf(" FILEID NFLAG RDEV|SZ");
468 }
469 
470 nfs_print(vp)
471 	struct vnode *vp;
472 {
473 	struct nfsnode nfsnode, *np = &nfsnode;
474 	char flagbuf[16], *flags = flagbuf;
475 	register flag;
476 	char *name;
477 	mode_t type;
478 	extern char *devname();
479 
480 	if (kvm_read(kd, V(VTONFS(vp)), &nfsnode, sizeof(struct nfsnode)) !=
481 	    sizeof(struct nfsnode)) {
482 		error("can't read nfsnode for %x", vp);
483 		return;
484 	}
485 	flag = np->n_flag;
486 	if (flag & NFLUSHWANT)
487 		*flags++ = 'W';
488 	if (flag & NFLUSHINPROG)
489 		*flags++ = 'P';
490 	if (flag & NMODIFIED)
491 		*flags++ = 'M';
492 	if (flag & NWRITEERR)
493 		*flags++ = 'E';
494 	if (flag & NQNFSNONCACHE)
495 		*flags++ = 'X';
496 	if (flag & NQNFSWRITE)
497 		*flags++ = 'O';
498 	if (flag & NQNFSEVICTED)
499 		*flags++ = 'G';
500 	if (flag == 0)
501 		*flags++ = '-';
502 	*flags = '\0';
503 
504 #define VT	np->n_vattr
505 	printf(" %6d %5s", VT.va_fileid, flagbuf);
506 	type = VT.va_mode & S_IFMT;
507 	if (type == S_IFCHR || type == S_IFBLK)
508 		if (nflg || ((name = devname(VT.va_rdev, type)) == NULL))
509 			printf("   %2d,%-2d",
510 				major(VT.va_rdev), minor(VT.va_rdev));
511 		else
512 			printf(" %7s", name);
513 	else
514 		printf(" %7qd", np->n_size);
515 }
516 
517 /*
518  * Given a pointer to a mount structure in kernel space,
519  * read it in and return a usable pointer to it.
520  */
521 struct mount *
522 getmnt(maddr)
523 	struct mount *maddr;
524 {
525 	static struct mtab {
526 		struct mtab *next;
527 		struct mount *maddr;
528 		struct mount mount;
529 	} *mhead = NULL;
530 	register struct mtab *mt;
531 
532 	for (mt = mhead; mt != NULL; mt = mt->next)
533 		if (maddr == mt->maddr)
534 			return (&mt->mount);
535 	if ((mt = (struct mtab *)malloc(sizeof (struct mtab))) == NULL) {
536 		error("out of memory");
537 		exit(1);
538 	}
539 	if (kvm_read(kd, V(maddr), &mt->mount, sizeof(struct mount)) !=
540 	    sizeof(struct mount)) {
541 		error("can't read mount table at %x", maddr);
542 		return (NULL);
543 	}
544 	mt->maddr = maddr;
545 	mt->next = mhead;
546 	mhead = mt;
547 	return (&mt->mount);
548 }
549 
550 mount_print(mp)
551 	struct mount *mp;
552 {
553 	char *type = "unknown";
554 	register flags;
555 
556 #define ST	mp->mnt_stat
557 	printf("*** MOUNT ");
558 	switch (ST.f_type) {
559 	case MOUNT_NONE:
560 		type = "none";
561 		break;
562 	case MOUNT_UFS:
563 		type = "ufs";
564 		break;
565 	case MOUNT_NFS:
566 		type = "nfs";
567 		break;
568 	case MOUNT_MFS:
569 		type = "mfs";
570 		break;
571 	case MOUNT_PC:
572 		type = "pc";
573 		break;
574 	}
575 	printf("%s %s on %s", type, ST.f_mntfromname, ST.f_mntonname);
576 	if (flags = mp->mnt_flag) {
577 		char *comma = "(";
578 
579 		putchar(' ');
580 		/* user visable flags */
581 		if (flags & MNT_RDONLY) {
582 			printf("%srdonly", comma);
583 			flags &= ~MNT_RDONLY;
584 			comma = ",";
585 		}
586 		if (flags & MNT_SYNCHRONOUS) {
587 			printf("%ssynchronous", comma);
588 			flags &= ~MNT_SYNCHRONOUS;
589 			comma = ",";
590 		}
591 		if (flags & MNT_NOEXEC) {
592 			printf("%snoexec", comma);
593 			flags &= ~MNT_NOEXEC;
594 			comma = ",";
595 		}
596 		if (flags & MNT_NOSUID) {
597 			printf("%snosuid", comma);
598 			flags &= ~MNT_NOSUID;
599 			comma = ",";
600 		}
601 		if (flags & MNT_NODEV) {
602 			printf("%snodev", comma);
603 			flags &= ~MNT_NODEV;
604 			comma = ",";
605 		}
606 		if (flags & MNT_EXPORTED) {
607 			printf("%sexport", comma);
608 			flags &= ~MNT_EXPORTED;
609 			comma = ",";
610 		}
611 		if (flags & MNT_EXRDONLY) {
612 			printf("%sexrdonly", comma);
613 			flags &= ~MNT_EXRDONLY;
614 			comma = ",";
615 		}
616 		if (flags & MNT_LOCAL) {
617 			printf("%slocal", comma);
618 			flags &= ~MNT_LOCAL;
619 			comma = ",";
620 		}
621 		if (flags & MNT_QUOTA) {
622 			printf("%squota", comma);
623 			flags &= ~MNT_QUOTA;
624 			comma = ",";
625 		}
626 		/* filesystem control flags */
627 		if (flags & MNT_UPDATE) {
628 			printf("%supdate", comma);
629 			flags &= ~MNT_UPDATE;
630 			comma = ",";
631 		}
632 		if (flags & MNT_MLOCK) {
633 			printf("%slock", comma);
634 			flags &= ~MNT_MLOCK;
635 			comma = ",";
636 		}
637 		if (flags & MNT_MWAIT) {
638 			printf("%swait", comma);
639 			flags &= ~MNT_MWAIT;
640 			comma = ",";
641 		}
642 		if (flags & MNT_MPBUSY) {
643 			printf("%sbusy", comma);
644 			flags &= ~MNT_MPBUSY;
645 			comma = ",";
646 		}
647 		if (flags & MNT_MPWANT) {
648 			printf("%swant", comma);
649 			flags &= ~MNT_MPWANT;
650 			comma = ",";
651 		}
652 		if (flags & MNT_UNMOUNT) {
653 			printf("%sunmount", comma);
654 			flags &= ~MNT_UNMOUNT;
655 			comma = ",";
656 		}
657 		if (flags)
658 			printf("%sunknown_flags:%x", flags);
659 		printf(")");
660 	}
661 	printf("\n");
662 #undef ST
663 }
664 
665 struct e_vnode *
666 loadvnodes(avnodes)
667 	int *avnodes;
668 {
669 	int mib[2];
670 	size_t copysize;
671 	struct e_vnode *vnodebase;
672 	struct e_vnode *kinfo_vnodes();
673 
674 	if (memf != NULL) {
675 		/*
676 		 * do it by hand
677 		 */
678 		return (kinfo_vnodes(avnodes));
679 	}
680 	mib[0] = CTL_KERN;
681 	mib[1] = KERN_VNODE;
682 	if (sysctl(mib, 2, NULL, &copysize, NULL, 0) == -1) {
683 		syserror("can't get estimate from sysctl");
684 		exit(1);
685 	}
686 	if ((vnodebase = (struct e_vnode *)malloc(copysize)) == NULL) {
687 		error("out of memory");
688 		exit(1);
689 	}
690 	if (sysctl(mib, 2, vnodebase, &copysize, NULL, 0) == -1) {
691 		syserror("can't get vnode list");
692 		exit(1);
693 	}
694 	if (copysize % sizeof (struct e_vnode)) {
695 		error("vnode size mismatch");
696 		exit(1);
697 	}
698 	*avnodes = copysize / sizeof (struct e_vnode);
699 
700 	return (vnodebase);
701 }
702 
703 /*
704  * simulate what a running kernel does in in kinfo_vnode
705  */
706 struct e_vnode *
707 kinfo_vnodes(avnodes)
708 	int *avnodes;
709 {
710 	struct nlist vnl[] = {
711 #define V_NUMV	0
712 		{ "_numvnodes" },
713 #define V_ROOTFS 1
714 		{ "_rootfs" },
715 		{""}
716 	};
717 	int numvnodes;
718 	struct mount *rootfs, *mp, mount;
719 	char *vbuf, *evbuf, *bp;
720 	struct vnode *vp, vnode;
721 	int num;
722 
723 #define VPTRSZ  sizeof (struct vnode *)
724 #define VNODESZ sizeof (struct vnode)
725 #define NVAL(indx)	vnl[(indx)].n_value
726 
727 	if (kvm_nlist(kd, vnl) != 0) {
728 		error("nlist vnl: %s", kvm_geterr(kd));
729 		exit(1);
730 	}
731 	numvnodes = getword(NVAL(V_NUMV));
732 	if ((vbuf = (char *)malloc((numvnodes + 20) * (VPTRSZ + VNODESZ)))
733 	    == NULL) {
734 		error("out of memory");
735 		exit(1);
736 	}
737 	bp = vbuf;
738 	evbuf = vbuf + (numvnodes + 20) * (VPTRSZ + VNODESZ);
739 	mp = rootfs = (struct mount *)getword(NVAL(V_ROOTFS));
740 	do {
741 		kvm_read(kd, V(mp), &mount, sizeof(mount));
742 		for (vp = mount.mnt_mounth; vp; vp = vnode.v_mountf) {
743 			kvm_read(kd, V(vp), &vnode, sizeof (vnode));
744 			if ((bp + VPTRSZ + VNODESZ) > evbuf) {
745 				/* XXX - should realloc */
746 				fprintf(stderr, "pstat: ran out of room for vnodes\n");
747 				exit(1);
748 			}
749 			bcopy(&vp, bp, VPTRSZ);
750 			bp += VPTRSZ;
751 			bcopy(&vnode, bp, VNODESZ);
752 			bp += VNODESZ;
753 			num++;
754 		}
755 		mp = mount.mnt_next;
756 	} while (mp != rootfs);
757 	*avnodes = num;
758 	return ((struct e_vnode *)vbuf);
759 }
760 
761 
762 u_long
763 getword(loc)
764 	int loc;
765 {
766 	u_long word;
767 
768 	kvm_read(kd, V(loc), &word, sizeof (word));
769 	return (word);
770 }
771 
772 putf(v, n)
773 {
774 	if (v)
775 		printf("%c", n);
776 	else
777 		printf(" ");
778 }
779 
780 dotext()
781 {
782 
783 	printf("no text table in this system\n");
784 }
785 
786 doproc()
787 {
788 	if (!totflg)
789 		printf("pstat: -p no longer supported (use ps)\n");
790 }
791 
792 char mesg[] = "  LINE RAW CAN OUT  HWT LWT     ADDR COL STATE  SESS  PGID DISC\n";
793 int ttyspace = 128;
794 struct tty *tty;
795 
796 dotty()
797 {
798 
799 	if ((tty = (struct tty *)malloc(ttyspace * sizeof(*tty))) == 0) {
800 		printf("pstat: out of memory\n");
801 		return;
802 	}
803 #ifndef hp300
804 	printf("1 cons\n");
805 	kvm_read(kd, V(nl[SCONS].n_value), tty, sizeof(*tty));
806 	printf(mesg);
807 	ttyprt(&tty[0], 0);
808 #endif
809 #ifdef vax
810 	if (nl[SNQD].n_type != 0)
811 		doqdss();
812 	if (nl[SNDZ].n_type != 0)
813 		dottytype("dz", SDZ, SNDZ);
814 	if (nl[SNDH].n_type != 0)
815 		dottytype("dh", SDH, SNDH);
816 	if (nl[SNDMF].n_type != 0)
817 		dottytype("dmf", SDMF, SNDMF);
818 	if (nl[SNDHU].n_type != 0)
819 		dottytype("dhu", SDHU, SNDHU);
820 	if (nl[SNDMZ].n_type != 0)
821 		dottytype("dmz", SDMZ, SNDMZ);
822 #endif
823 #ifdef tahoe
824 	if (nl[SNVX].n_type != 0)
825 		dottytype("vx", SVX, SNVX);
826 	if (nl[SNMP].n_type != 0)
827 		dottytype("mp", SMP, SNMP);
828 #endif
829 #ifdef hp300
830 	if (nl[SNITE].n_type != 0)
831 		dottytype("ite", SITE, SNITE);
832 	if (nl[SNDCA].n_type != 0)
833 		dottytype("dca", SDCA, SNDCA);
834 	if (nl[SNDCM].n_type != 0)
835 		dottytype("dcm", SDCM, SNDCM);
836 	if (nl[SNDCL].n_type != 0)
837 		dottytype("dcl", SDCL, SNDCL);
838 #endif
839 #ifdef mips
840 	if (nl[SNDC].n_type != 0)
841 		dottytype("dc", SDC, SNDC);
842 #endif
843 	if (nl[SNPTY].n_type != 0)
844 		dottytype("pty", SPTY, SNPTY);
845 }
846 
847 /*
848  * Special case the qdss: there are 4 ttys per qdss,
849  * but only the first of each is used as a tty.
850  */
851 #ifdef vax
852 doqdss()
853 {
854 	int nqd;
855 	register struct tty *tp;
856 
857 	kvm_read(kd, V(nl[SNQD].n_value), &nqd, sizeof(nqd));
858 	printf("%d qd\n", nqd);
859 	kvm_read(kd, V(nl[SQD].n_value), tty, nqd * sizeof(struct tty) * 4);
860 	printf(mesg);
861 	for (tp = tty; tp < &tty[nqd * 4]; tp += 4)
862 		ttyprt(tp, tp - tty);
863 }
864 #endif
865 
866 dottytype(name, type, number)
867 char *name;
868 {
869 	int ntty;
870 	register struct tty *tp;
871 	extern char *realloc();
872 
873 	if (tty == (struct tty *)0)
874 		return;
875 	kvm_read(kd, V(nl[number].n_value), &ntty, sizeof(ntty));
876 	printf("%d %s %s\n", ntty, name, (ntty == 1) ? "line" :
877 	    "lines");
878 	if (ntty > ttyspace) {
879 		ttyspace = ntty;
880 		if ((tty = (struct tty *)realloc(tty, ttyspace * sizeof(*tty))) == 0) {
881 			printf("pstat: out of memory\n");
882 			return;
883 		}
884 	}
885 	kvm_read(kd, V(nl[type].n_value), tty, ntty * sizeof(struct tty));
886 	printf(mesg);
887 	for (tp = tty; tp < &tty[ntty]; tp++)
888 		ttyprt(tp, tp - tty);
889 }
890 
891 struct {
892 	int flag;
893 	char val;
894 } ttystates[] = {
895 	TS_WOPEN,	'W',
896 	TS_ISOPEN,	'O',
897 	TS_CARR_ON,	'C',
898 	TS_TIMEOUT,	'T',
899 	TS_FLUSH,	'F',
900 	TS_BUSY,	'B',
901 	TS_ASLEEP,	'A',
902 	TS_XCLUDE,	'X',
903 	TS_TTSTOP,	'S',
904 	TS_TBLOCK,	'K',
905 	TS_ASYNC,	'Y',
906 	TS_BKSL,	'D',
907 	TS_ERASE,	'E',
908 	TS_LNCH,	'L',
909 	TS_TYPEN,	'P',
910 	TS_CNTTB,	'N',
911 	0,	0
912 };
913 
914 ttyprt(atp, line)
915 struct tty *atp;
916 {
917 	register struct tty *tp;
918 	char state[20];
919 	register i, j;
920 	char *name;
921 	extern char *devname();
922 	pid_t pgid;
923 
924 	tp = atp;
925 	if (nflg || tp->t_dev == 0 ||
926 	   (name = devname(tp->t_dev, S_IFCHR)) == NULL)
927 		printf("%7d ", line);
928 	else
929 		printf("%7s ", name);
930 	printf("%2d %3d ", tp->t_rawq.c_cc, tp->t_canq.c_cc);
931 	printf("%3d %4d %3d %8x %3d ", tp->t_outq.c_cc,
932 		tp->t_hiwat, tp->t_lowat, tp->t_addr, tp->t_col);
933 	for (i = j = 0; ttystates[i].flag; i++)
934 		if (tp->t_state&ttystates[i].flag)
935 			state[j++] = ttystates[i].val;
936 	if (j == 0)
937 		state[j++] = '-';
938 	state[j] = '\0';
939 	printf("%-4s %6x", state, (u_long)tp->t_session & ~KERNBASE);
940 	if (tp->t_pgrp == NULL || kvm_read(kd, V(&tp->t_pgrp->pg_id), &pgid,
941 	    sizeof (pid_t)) != sizeof (pid_t))
942 		pgid = 0;
943 	printf("%6d ", pgid);
944 	switch (tp->t_line) {
945 
946 	case TTYDISC:
947 		printf("term\n");
948 		break;
949 
950 	case TABLDISC:
951 		printf("tab\n");
952 		break;
953 
954 	case SLIPDISC:
955 		printf("slip\n");
956 		break;
957 
958 	default:
959 		printf("%d\n", tp->t_line);
960 	}
961 }
962 
963 /*
964  * The user structure is going away.  What's left here won't
965  * be around for long.
966  */
967 dousr()
968 {
969 
970 	printf("nothing left in user structure in this system\n");
971 }
972 
973 oatoi(s)
974 char *s;
975 {
976 	register v;
977 
978 	v = 0;
979 	while (*s)
980 		v = (v<<3) + *s++ - '0';
981 	return(v);
982 }
983 
984 dofile()
985 {
986 	register struct file *fp;
987 	struct file *addr;
988 	char *buf;
989 	int len, maxfile, nfile;
990 	struct nlist fnl[] = {
991 #define	FNL_NFILE	0
992 		{"_nfiles"},
993 #define FNL_MAXFILE	1
994 		{"_maxfiles"},
995 		{""}
996 	};
997 	static char *dtypes[] = { "???", "inode", "socket" };
998 
999 	if (kvm_nlist(kd, fnl) != 0) {
1000 		error("kvm_nlist: no _nfiles or _maxfiles: %s",
1001 			kvm_geterr(kd));
1002 		return;
1003 	}
1004 	kvm_read(kd, V(fnl[FNL_MAXFILE].n_value), &maxfile,
1005 		sizeof (maxfile));
1006 	if (totflg) {
1007 		kvm_read(kd, V(fnl[FNL_NFILE].n_value), &nfile, sizeof (nfile));
1008 		printf("%3d/%3d files\n", nfile, maxfile);
1009 		return;
1010 	}
1011 	if (getfiles(&buf, &len) == -1)
1012 		return;
1013 	/*
1014 	 * getfiles returns in malloc'd buf a pointer to the first file
1015 	 * structure, and then an array of file structs (whose
1016 	 * addresses are derivable from the previous entry)
1017 	 */
1018 	addr = *((struct file **)buf);
1019 	fp = (struct file *)(buf + sizeof (struct file *));
1020 	nfile = (len - sizeof (struct file *)) / sizeof (struct file);
1021 
1022 	printf("%d/%d open files\n", nfile, maxfile);
1023 	printf("   LOC   TYPE    FLG     CNT  MSG    DATA    OFFSET\n");
1024 	for (; (char *)fp < buf + len; addr = fp->f_filef, fp++) {
1025 		if ((unsigned)fp->f_type > DTYPE_SOCKET)
1026 			continue;
1027 		printf("%x ", addr);
1028 		printf("%-8.8s", dtypes[fp->f_type]);
1029 		putf(fp->f_flag&FREAD, 'R');
1030 		putf(fp->f_flag&FWRITE, 'W');
1031 		putf(fp->f_flag&FAPPEND, 'A');
1032 #ifdef FSHLOCK	/* currently gone */
1033 		putf(fp->f_flag&FSHLOCK, 'S');
1034 		putf(fp->f_flag&FEXLOCK, 'X');
1035 #else
1036 		putf(0, ' ');
1037 		putf(0, ' ');
1038 #endif
1039 		putf(fp->f_flag&FASYNC, 'I');
1040 		printf("  %3d", fp->f_count);
1041 		printf("  %3d", fp->f_msgcount);
1042 		printf("  %8.1x", fp->f_data);
1043 		if (fp->f_offset < 0)
1044 			printf("  %x\n", fp->f_offset);
1045 		else
1046 			printf("  %ld\n", fp->f_offset);
1047 	}
1048 	free(buf);
1049 }
1050 
1051 getfiles(abuf, alen)
1052 	char **abuf;
1053 	int *alen;
1054 {
1055 	char *buf;
1056 	int mib[2];
1057 	size_t len;
1058 
1059 	if (memf != NULL) {
1060 		/*
1061 		 * add emulation of KINFO_FILE here
1062 		 */
1063 		error("files on dead kernel, not impl\n");
1064 		exit(1);
1065 	}
1066 	mib[0] = CTL_KERN;
1067 	mib[1] = KERN_FILE;
1068 	if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1) {
1069 		syserror("sysctl size estimate");
1070 		return (-1);
1071 	}
1072 	if ((buf = (char *)malloc(len)) == NULL) {
1073 		error("out of memory");
1074 		return (-1);
1075 	}
1076 	if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) {
1077 		syserror("sysctl");
1078 		return (-1);
1079 	}
1080 	*abuf = buf;
1081 	*alen = len;
1082 	return (0);
1083 }
1084 
1085 
1086 doswap()
1087 {
1088 	printf("swap statistics not yet supported in this system\n");
1089 }
1090 
1091 #include <varargs.h>
1092 
1093 error(va_alist)
1094 	va_dcl
1095 {
1096 	char *fmt;
1097 	va_list ap;
1098 	extern errno;
1099 
1100 	fprintf(stderr, "pstat: ");
1101 	va_start(ap);
1102 	fmt = va_arg(ap, char *);
1103 	(void) vfprintf(stderr, fmt, ap);
1104 	va_end(ap);
1105 	fprintf(stderr, "\n");
1106 }
1107 
1108 syserror(va_alist)
1109 	va_dcl
1110 {
1111 	char *fmt;
1112 	va_list ap;
1113 	extern errno;
1114 
1115 	fprintf(stderr, "pstat: ");
1116 	va_start(ap);
1117 	fmt = va_arg(ap, char *);
1118 	(void) vfprintf(stderr, fmt, ap);
1119 	va_end(ap);
1120 	fprintf(stderr, ": %s\n", strerror(errno));
1121 }
1122