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