xref: /freebsd/usr.sbin/pstat/pstat.c (revision 5ebc7e6281887681c3a348a5a4c902e262ccd656)
1 /*-
2  * Copyright (c) 1980, 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifndef lint
35 static char copyright[] =
36 "@(#) Copyright (c) 1980, 1991, 1993\n\
37 	The Regents of the University of California.  All rights reserved.\n";
38 #endif /* not lint */
39 
40 #ifndef lint
41 static char sccsid[] = "@(#)pstat.c	8.9 (Berkeley) 2/16/94";
42 #endif /* not lint */
43 
44 #include <sys/param.h>
45 #include <sys/time.h>
46 #include <sys/vnode.h>
47 #include <sys/ucred.h>
48 #define KERNEL
49 #include <sys/file.h>
50 #include <ufs/ufs/quota.h>
51 #include <ufs/ufs/inode.h>
52 #define NFS
53 #include <sys/mount.h>
54 #undef NFS
55 #undef KERNEL
56 #include <sys/stat.h>
57 #include <nfs/nfsnode.h>
58 #include <sys/ioctl.h>
59 #include <sys/ioctl_compat.h>	/* XXX NTTYDISC is too well hidden */
60 #include <sys/tty.h>
61 #include <sys/conf.h>
62 #include <sys/rlist.h>
63 
64 #include <sys/sysctl.h>
65 
66 #include <err.h>
67 #include <kvm.h>
68 #include <limits.h>
69 #include <nlist.h>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <unistd.h>
74 
75 struct nlist nl[] = {
76 #define VM_SWAPLIST	0
77 	{ "_swaplist" },/* list of free swap areas */
78 #define VM_SWDEVT	1
79 	{ "_swdevt" },	/* list of swap devices and sizes */
80 #define VM_NSWAP	2
81 	{ "_nswap" },	/* size of largest swap device */
82 #define VM_NSWDEV	3
83 	{ "_nswdev" },	/* number of swap devices */
84 #define VM_DMMAX	4
85 	{ "_dmmax" },	/* maximum size of a swap block */
86 #define	V_MOUNTLIST	5
87 	{ "_mountlist" },	/* address of head of mount list. */
88 #define V_NUMV		6
89 	{ "_numvnodes" },
90 #define	FNL_NFILE	7
91 	{"_nfiles"},
92 #define FNL_MAXFILE	8
93 	{"_maxfiles"},
94 #define NLMANDATORY FNL_MAXFILE	/* names up to here are mandatory */
95 #define	SCONS		NLMANDATORY + 1
96 	{ "_cons" },
97 #define	SPTY		NLMANDATORY + 2
98 	{ "_pt_tty" },
99 #define	SNPTY		NLMANDATORY + 3
100 	{ "_npty" },
101 
102 #ifdef hp300
103 #define	SDCA	(SNPTY+1)
104 	{ "_dca_tty" },
105 #define	SNDCA	(SNPTY+2)
106 	{ "_ndca" },
107 #define	SDCM	(SNPTY+3)
108 	{ "_dcm_tty" },
109 #define	SNDCM	(SNPTY+4)
110 	{ "_ndcm" },
111 #define	SDCL	(SNPTY+5)
112 	{ "_dcl_tty" },
113 #define	SNDCL	(SNPTY+6)
114 	{ "_ndcl" },
115 #define	SITE	(SNPTY+7)
116 	{ "_ite_tty" },
117 #define	SNITE	(SNPTY+8)
118 	{ "_nite" },
119 #endif
120 
121 #ifdef mips
122 #define SDC	(SNPTY+1)
123 	{ "_dc_tty" },
124 #define SNDC	(SNPTY+2)
125 	{ "_dc_cnt" },
126 #endif
127 
128 #ifdef __FreeBSD__
129 #define SCCONS	(SNPTY+1)
130 	{ "_sccons" },
131 #define NSCCONS	(SNPTY+2)
132 	{ "_nsccons" },
133 #define SIO  (SNPTY+3)
134 	{ "_sio_tty" },
135 #define NSIO (SNPTY+4)
136 	{ "_nsio_tty" },
137 #define RC  (SNPTY+5)
138 	{ "_rc_tty" },
139 #define NRC (SNPTY+6)
140 	{ "_nrc_tty" },
141 #endif
142 	{ "" }
143 };
144 
145 int	usenumflag;
146 int	totalflag;
147 char	*nlistf	= NULL;
148 char	*memf	= NULL;
149 kvm_t	*kd;
150 
151 char	*usage;
152 
153 #define	SVAR(var) __STRING(var)	/* to force expansion */
154 #define	KGET(idx, var)							\
155 	KGET1(idx, &var, sizeof(var), SVAR(var))
156 #define	KGET1(idx, p, s, msg)						\
157 	KGET2(nl[idx].n_value, p, s, msg)
158 #define	KGET2(addr, p, s, msg)						\
159 	if (kvm_read(kd, (u_long)(addr), p, s) != s)			\
160 		warnx("cannot read %s: %s", msg, kvm_geterr(kd))
161 #define	KGETRET(addr, p, s, msg)					\
162 	if (kvm_read(kd, (u_long)(addr), p, s) != s) {			\
163 		warnx("cannot read %s: %s", msg, kvm_geterr(kd));	\
164 		return (0);						\
165 	}
166 
167 void	filemode __P((void));
168 int	getfiles __P((char **, int *));
169 struct mount *
170 	getmnt __P((struct mount *));
171 struct e_vnode *
172 	kinfo_vnodes __P((int *));
173 struct e_vnode *
174 	loadvnodes __P((int *));
175 void	mount_print __P((struct mount *));
176 void	nfs_header __P((void));
177 int	nfs_print __P((struct vnode *));
178 void	swapmode __P((void));
179 void	ttymode __P((void));
180 void	ttyprt __P((struct tty *, int));
181 void	ttytype __P((struct tty *, char *, int, int));
182 void	ufs_header __P((void));
183 int	ufs_print __P((struct vnode *));
184 void	vnode_header __P((void));
185 void	vnode_print __P((struct vnode *, struct vnode *));
186 void	vnodemode __P((void));
187 
188 int
189 main(argc, argv)
190 	int argc;
191 	char *argv[];
192 {
193 	extern char *optarg;
194 	extern int optind;
195 	int ch, i, quit, ret;
196 	int fileflag, swapflag, ttyflag, vnodeflag;
197 	char buf[_POSIX2_LINE_MAX],*opts;
198 
199 	fileflag = swapflag = ttyflag = vnodeflag = 0;
200 
201 	/* We will behave like good old swapinfo if thus invoked */
202 	opts = strrchr(argv[0],'/');
203 	if (opts)
204 		opts++;
205 	else
206 		opts = argv[0];
207 	if (!strcmp(opts,"swapinfo")) {
208 		swapflag = 1;
209 		opts = "k";
210 		usage = "usage: swapinfo [-k] [-M core] [-N system]\n";
211 	} else {
212 		opts = "TM:N:fiknstv";
213 		usage = "usage: pstat [-Tfknstv] [-M core] [-N system]\n";
214 	}
215 
216 	while ((ch = getopt(argc, argv, opts)) != EOF)
217 		switch (ch) {
218 		case 'f':
219 			fileflag = 1;
220 			break;
221 		case 'k':
222 			putenv("BLOCKSIZE=1K");
223 			break;
224 		case 'M':
225 			memf = optarg;
226 			break;
227 		case 'N':
228 			nlistf = optarg;
229 			break;
230 		case 'n':
231 			usenumflag = 1;
232 			break;
233 		case 's':
234 			swapflag = 1;
235 			break;
236 		case 'T':
237 			totalflag = 1;
238 			break;
239 		case 't':
240 			ttyflag = 1;
241 			break;
242 		case 'v':
243 		case 'i':		/* Backward compatibility. */
244 			vnodeflag = 1;
245 			break;
246 		default:
247 			(void)fprintf(stderr, usage);
248 			exit(1);
249 		}
250 	argc -= optind;
251 	argv += optind;
252 
253 	/*
254 	 * Discard setgid privileges if not the running kernel so that bad
255 	 * guys can't print interesting stuff from kernel memory.
256 	 */
257 	if (nlistf != NULL || memf != NULL)
258 		(void)setgid(getgid());
259 
260 	if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == 0)
261 		errx(1, "kvm_openfiles: %s", buf);
262 	if ((ret = kvm_nlist(kd, nl)) != 0) {
263 		if (ret == -1)
264 			errx(1, "kvm_nlist: %s", kvm_geterr(kd));
265 		for (i = quit = 0; i <= NLMANDATORY; i++)
266 			if (!nl[i].n_value) {
267 				quit = 1;
268 				warnx("undefined symbol: %s\n", nl[i].n_name);
269 			}
270 		if (quit)
271 			exit(1);
272 	}
273 	if (!(fileflag | vnodeflag | ttyflag | swapflag | totalflag)) {
274 		(void)fprintf(stderr, usage);
275 		exit(1);
276 	}
277 	if (fileflag || totalflag)
278 		filemode();
279 	if (vnodeflag || totalflag)
280 		vnodemode();
281 	if (ttyflag)
282 		ttymode();
283 	if (swapflag || totalflag)
284 		swapmode();
285 	exit (0);
286 }
287 
288 struct e_vnode {
289 	struct vnode *avnode;
290 	struct vnode vnode;
291 };
292 
293 void
294 vnodemode()
295 {
296 	register struct e_vnode *e_vnodebase, *endvnode, *evp;
297 	register struct vnode *vp;
298 	register struct mount *maddr, *mp;
299 	int numvnodes;
300 
301 	e_vnodebase = loadvnodes(&numvnodes);
302 	if (totalflag) {
303 		(void)printf("%7d vnodes\n", numvnodes);
304 		return;
305 	}
306 	endvnode = e_vnodebase + numvnodes;
307 	(void)printf("%d active vnodes\n", numvnodes);
308 
309 
310 #define ST	mp->mnt_stat
311 	maddr = NULL;
312 	for (evp = e_vnodebase; evp < endvnode; evp++) {
313 		vp = &evp->vnode;
314 		if (vp->v_mount != maddr) {
315 			/*
316 			 * New filesystem
317 			 */
318 			if ((mp = getmnt(vp->v_mount)) == NULL)
319 				continue;
320 			maddr = vp->v_mount;
321 			mount_print(mp);
322 			vnode_header();
323 			switch(ST.f_type) {
324 			case MOUNT_UFS:
325 			case MOUNT_MFS:
326 				ufs_header();
327 				break;
328 			case MOUNT_NFS:
329 				nfs_header();
330 				break;
331 			case MOUNT_NONE:
332 			case MOUNT_MSDOS:
333 			default:
334 				break;
335 			}
336 			(void)printf("\n");
337 		}
338 		vnode_print(evp->avnode, vp);
339 		switch(ST.f_type) {
340 		case MOUNT_UFS:
341 		case MOUNT_MFS:
342 			ufs_print(vp);
343 			break;
344 		case MOUNT_NFS:
345 			nfs_print(vp);
346 			break;
347 		case MOUNT_NONE:
348 		case MOUNT_MSDOS:
349 		default:
350 			break;
351 		}
352 		(void)printf("\n");
353 	}
354 	free(e_vnodebase);
355 }
356 
357 void
358 vnode_header()
359 {
360 	(void)printf("ADDR     TYP VFLAG  USE HOLD");
361 }
362 
363 void
364 vnode_print(avnode, vp)
365 	struct vnode *avnode;
366 	struct vnode *vp;
367 {
368 	char *type, flags[16];
369 	char *fp = flags;
370 	register int flag;
371 
372 	/*
373 	 * set type
374 	 */
375 	switch(vp->v_type) {
376 	case VNON:
377 		type = "non"; break;
378 	case VREG:
379 		type = "reg"; break;
380 	case VDIR:
381 		type = "dir"; break;
382 	case VBLK:
383 		type = "blk"; break;
384 	case VCHR:
385 		type = "chr"; break;
386 	case VLNK:
387 		type = "lnk"; break;
388 	case VSOCK:
389 		type = "soc"; break;
390 	case VFIFO:
391 		type = "fif"; break;
392 	case VBAD:
393 		type = "bad"; break;
394 	default:
395 		type = "unk"; break;
396 	}
397 	/*
398 	 * gather flags
399 	 */
400 	flag = vp->v_flag;
401 	if (flag & VROOT)
402 		*fp++ = 'R';
403 	if (flag & VTEXT)
404 		*fp++ = 'T';
405 	if (flag & VSYSTEM)
406 		*fp++ = 'S';
407 	if (flag & VXLOCK)
408 		*fp++ = 'L';
409 	if (flag & VXWANT)
410 		*fp++ = 'W';
411 	if (flag & VBWAIT)
412 		*fp++ = 'B';
413 	if (flag & VALIASED)
414 		*fp++ = 'A';
415 	if (flag == 0)
416 		*fp++ = '-';
417 	*fp = '\0';
418 	(void)printf("%8x %s %5s %4d %4d",
419 	    avnode, type, flags, vp->v_usecount, vp->v_holdcnt);
420 }
421 
422 void
423 ufs_header()
424 {
425 	(void)printf(" FILEID IFLAG RDEV|SZ");
426 }
427 
428 int
429 ufs_print(vp)
430 	struct vnode *vp;
431 {
432 	register int flag;
433 	struct inode inode, *ip = &inode;
434 	char flagbuf[16], *flags = flagbuf;
435 	char *name;
436 	mode_t type;
437 
438 	KGETRET(VTOI(vp), &inode, sizeof(struct inode), "vnode's inode");
439 	flag = ip->i_flag;
440 	if (flag & IN_LOCKED)
441 		*flags++ = 'L';
442 	if (flag & IN_WANTED)
443 		*flags++ = 'W';
444 	if (flag & IN_RENAME)
445 		*flags++ = 'R';
446 	if (flag & IN_UPDATE)
447 		*flags++ = 'U';
448 	if (flag & IN_ACCESS)
449 		*flags++ = 'A';
450 	if (flag & IN_CHANGE)
451 		*flags++ = 'C';
452 	if (flag & IN_MODIFIED)
453 		*flags++ = 'M';
454 	if (flag & IN_SHLOCK)
455 		*flags++ = 'S';
456 	if (flag & IN_EXLOCK)
457 		*flags++ = 'E';
458 	if (flag & IN_LWAIT)
459 		*flags++ = 'Z';
460 	if (flag == 0)
461 		*flags++ = '-';
462 	*flags = '\0';
463 
464 	(void)printf(" %6d %5s", ip->i_number, flagbuf);
465 	type = ip->i_mode & S_IFMT;
466 	if (S_ISCHR(ip->i_mode) || S_ISBLK(ip->i_mode))
467 		if (usenumflag || ((name = devname(ip->i_rdev, type)) == NULL))
468 			(void)printf("   %2d,%-2d",
469 			    major(ip->i_rdev), minor(ip->i_rdev));
470 		else
471 			(void)printf(" %7s", name);
472 	else
473 		(void)printf(" %7qd", ip->i_size);
474 	return (0);
475 }
476 
477 void
478 nfs_header()
479 {
480 	(void)printf(" FILEID NFLAG RDEV|SZ");
481 }
482 
483 int
484 nfs_print(vp)
485 	struct vnode *vp;
486 {
487 	struct nfsnode nfsnode, *np = &nfsnode;
488 	char flagbuf[16], *flags = flagbuf;
489 	register int flag;
490 	char *name;
491 	mode_t type;
492 
493 	KGETRET(VTONFS(vp), &nfsnode, sizeof(nfsnode), "vnode's nfsnode");
494 	flag = np->n_flag;
495 	if (flag & NFLUSHWANT)
496 		*flags++ = 'W';
497 	if (flag & NFLUSHINPROG)
498 		*flags++ = 'P';
499 	if (flag & NMODIFIED)
500 		*flags++ = 'M';
501 	if (flag & NWRITEERR)
502 		*flags++ = 'E';
503 	if (flag & NQNFSNONCACHE)
504 		*flags++ = 'X';
505 	if (flag & NQNFSWRITE)
506 		*flags++ = 'O';
507 	if (flag & NQNFSEVICTED)
508 		*flags++ = 'G';
509 	if (flag == 0)
510 		*flags++ = '-';
511 	*flags = '\0';
512 
513 #define VT	np->n_vattr
514 	(void)printf(" %6d %5s", VT.va_fileid, flagbuf);
515 	type = VT.va_mode & S_IFMT;
516 	if (S_ISCHR(VT.va_mode) || S_ISBLK(VT.va_mode))
517 		if (usenumflag || ((name = devname(VT.va_rdev, type)) == NULL))
518 			(void)printf("   %2d,%-2d",
519 			    major(VT.va_rdev), minor(VT.va_rdev));
520 		else
521 			(void)printf(" %7s", name);
522 	else
523 		(void)printf(" %7qd", np->n_size);
524 	return (0);
525 }
526 
527 /*
528  * Given a pointer to a mount structure in kernel space,
529  * read it in and return a usable pointer to it.
530  */
531 struct mount *
532 getmnt(maddr)
533 	struct mount *maddr;
534 {
535 	static struct mtab {
536 		struct mtab *next;
537 		struct mount *maddr;
538 		struct mount mount;
539 	} *mhead = NULL;
540 	register struct mtab *mt;
541 
542 	for (mt = mhead; mt != NULL; mt = mt->next)
543 		if (maddr == mt->maddr)
544 			return (&mt->mount);
545 	if ((mt = malloc(sizeof(struct mtab))) == NULL)
546 		err(1, NULL);
547 	KGETRET(maddr, &mt->mount, sizeof(struct mount), "mount table");
548 	mt->maddr = maddr;
549 	mt->next = mhead;
550 	mhead = mt;
551 	return (&mt->mount);
552 }
553 
554 void
555 mount_print(mp)
556 	struct mount *mp;
557 {
558 	register int flags;
559 	char *type;
560 
561 #define ST	mp->mnt_stat
562 	(void)printf("*** MOUNT ");
563 	switch (ST.f_type) {
564 	case MOUNT_NONE:
565 		type = "none";
566 		break;
567 	case MOUNT_UFS:
568 		type = "ufs";
569 		break;
570 	case MOUNT_NFS:
571 		type = "nfs";
572 		break;
573 	case MOUNT_MFS:
574 		type = "mfs";
575 		break;
576 	case MOUNT_MSDOS:
577 		type = "pc";
578 		break;
579 	default:
580 		type = "unknown";
581 		break;
582 	}
583 	(void)printf("%s %s on %s", type, ST.f_mntfromname, ST.f_mntonname);
584 	if (flags = mp->mnt_flag) {
585 		char *comma = "(";
586 
587 		putchar(' ');
588 		/* user visable flags */
589 		if (flags & MNT_RDONLY) {
590 			(void)printf("%srdonly", comma);
591 			flags &= ~MNT_RDONLY;
592 			comma = ",";
593 		}
594 		if (flags & MNT_SYNCHRONOUS) {
595 			(void)printf("%ssynchronous", comma);
596 			flags &= ~MNT_SYNCHRONOUS;
597 			comma = ",";
598 		}
599 		if (flags & MNT_NOEXEC) {
600 			(void)printf("%snoexec", comma);
601 			flags &= ~MNT_NOEXEC;
602 			comma = ",";
603 		}
604 		if (flags & MNT_NOSUID) {
605 			(void)printf("%snosuid", comma);
606 			flags &= ~MNT_NOSUID;
607 			comma = ",";
608 		}
609 		if (flags & MNT_NODEV) {
610 			(void)printf("%snodev", comma);
611 			flags &= ~MNT_NODEV;
612 			comma = ",";
613 		}
614 		if (flags & MNT_EXPORTED) {
615 			(void)printf("%sexport", comma);
616 			flags &= ~MNT_EXPORTED;
617 			comma = ",";
618 		}
619 		if (flags & MNT_EXRDONLY) {
620 			(void)printf("%sexrdonly", comma);
621 			flags &= ~MNT_EXRDONLY;
622 			comma = ",";
623 		}
624 		if (flags & MNT_LOCAL) {
625 			(void)printf("%slocal", comma);
626 			flags &= ~MNT_LOCAL;
627 			comma = ",";
628 		}
629 		if (flags & MNT_QUOTA) {
630 			(void)printf("%squota", comma);
631 			flags &= ~MNT_QUOTA;
632 			comma = ",";
633 		}
634 		/* filesystem control flags */
635 		if (flags & MNT_UPDATE) {
636 			(void)printf("%supdate", comma);
637 			flags &= ~MNT_UPDATE;
638 			comma = ",";
639 		}
640 		if (flags & MNT_MLOCK) {
641 			(void)printf("%slock", comma);
642 			flags &= ~MNT_MLOCK;
643 			comma = ",";
644 		}
645 		if (flags & MNT_MWAIT) {
646 			(void)printf("%swait", comma);
647 			flags &= ~MNT_MWAIT;
648 			comma = ",";
649 		}
650 		if (flags & MNT_MPBUSY) {
651 			(void)printf("%sbusy", comma);
652 			flags &= ~MNT_MPBUSY;
653 			comma = ",";
654 		}
655 		if (flags & MNT_MPWANT) {
656 			(void)printf("%swant", comma);
657 			flags &= ~MNT_MPWANT;
658 			comma = ",";
659 		}
660 		if (flags & MNT_UNMOUNT) {
661 			(void)printf("%sunmount", comma);
662 			flags &= ~MNT_UNMOUNT;
663 			comma = ",";
664 		}
665 		if (flags)
666 			(void)printf("%sunknown_flags:%x", comma, flags);
667 		(void)printf(")");
668 	}
669 	(void)printf("\n");
670 #undef ST
671 }
672 
673 struct e_vnode *
674 loadvnodes(avnodes)
675 	int *avnodes;
676 {
677 	int mib[2];
678 	size_t copysize;
679 	struct e_vnode *vnodebase;
680 
681 	if (memf != NULL) {
682 		/*
683 		 * do it by hand
684 		 */
685 		return (kinfo_vnodes(avnodes));
686 	}
687 	mib[0] = CTL_KERN;
688 	mib[1] = KERN_VNODE;
689 	if (sysctl(mib, 2, NULL, &copysize, NULL, 0) == -1)
690 		err(1, "sysctl: KERN_VNODE");
691 	if ((vnodebase = malloc(copysize)) == NULL)
692 		err(1, NULL);
693 	if (sysctl(mib, 2, vnodebase, &copysize, NULL, 0) == -1)
694 		err(1, "sysctl: KERN_VNODE");
695 	if (copysize % sizeof(struct e_vnode))
696 		errx(1, "vnode size mismatch");
697 	*avnodes = copysize / sizeof(struct e_vnode);
698 
699 	return (vnodebase);
700 }
701 
702 /*
703  * simulate what a running kernel does in in kinfo_vnode
704  */
705 struct e_vnode *
706 kinfo_vnodes(avnodes)
707 	int *avnodes;
708 {
709 	struct mntlist mountlist;
710 	struct mount *mp, mount;
711 	struct vnode *vp, vnode;
712 	char *vbuf, *evbuf, *bp;
713 	int num, numvnodes;
714 
715 #define VPTRSZ  sizeof(struct vnode *)
716 #define VNODESZ sizeof(struct vnode)
717 
718 	KGET(V_NUMV, numvnodes);
719 	if ((vbuf = malloc((numvnodes + 20) * (VPTRSZ + VNODESZ))) == NULL)
720 		err(1, NULL);
721 	bp = vbuf;
722 	evbuf = vbuf + (numvnodes + 20) * (VPTRSZ + VNODESZ);
723 	KGET(V_MOUNTLIST, mountlist);
724 	for (num = 0, mp = mountlist.tqh_first;
725 	    mp != NULL; mp = mp->mnt_list.tqe_next) {
726 		KGET2(mp, &mount, sizeof(mount), "mount entry");
727 		for (vp = mount.mnt_vnodelist.lh_first;
728 		    vp != NULL; vp = vp->v_mntvnodes.le_next) {
729 			KGET2(vp, &vnode, sizeof(vnode), "vnode");
730 			if ((bp + VPTRSZ + VNODESZ) > evbuf)
731 				/* XXX - should realloc */
732 				errx(1, "no more room for vnodes");
733 			memmove(bp, &vp, VPTRSZ);
734 			bp += VPTRSZ;
735 			memmove(bp, &vnode, VNODESZ);
736 			bp += VNODESZ;
737 			num++;
738 		}
739 	}
740 	*avnodes = num;
741 	return ((struct e_vnode *)vbuf);
742 }
743 
744 char hdr[]="  LINE RAW CAN OUT  HWT LWT     COL STATE  SESS  PGID DISC\n";
745 int ttyspace = 128;
746 
747 void
748 ttymode()
749 {
750 	struct tty *tty;
751 
752 	if ((tty = malloc(ttyspace * sizeof(*tty))) == NULL)
753 		err(1, NULL);
754 #ifndef hp300
755 	if (nl[SCONS].n_type != 0) {
756 		(void)printf("1 console\n");
757 		KGET(SCONS, *tty);
758 		(void)printf(hdr);
759 		ttyprt(&tty[0], 0);
760 	}
761 #endif
762 #ifdef vax
763 	if (nl[SNQD].n_type != 0)
764 		qdss();
765 	if (nl[SNDZ].n_type != 0)
766 		ttytype(tty, "dz", SDZ, SNDZ);
767 	if (nl[SNDH].n_type != 0)
768 		ttytype(tty, "dh", SDH, SNDH);
769 	if (nl[SNDMF].n_type != 0)
770 		ttytype(tty, "dmf", SDMF, SNDMF);
771 	if (nl[SNDHU].n_type != 0)
772 		ttytype(tty, "dhu", SDHU, SNDHU);
773 	if (nl[SNDMZ].n_type != 0)
774 		ttytype(tty, "dmz", SDMZ, SNDMZ);
775 #endif
776 #ifdef tahoe
777 	if (nl[SNVX].n_type != 0)
778 		ttytype(tty, "vx", SVX, SNVX);
779 	if (nl[SNMP].n_type != 0)
780 		ttytype(tty, "mp", SMP, SNMP);
781 #endif
782 #ifdef hp300
783 	if (nl[SNITE].n_type != 0)
784 		ttytype(tty, "ite", SITE, SNITE);
785 	if (nl[SNDCA].n_type != 0)
786 		ttytype(tty, "dca", SDCA, SNDCA);
787 	if (nl[SNDCM].n_type != 0)
788 		ttytype(tty, "dcm", SDCM, SNDCM);
789 	if (nl[SNDCL].n_type != 0)
790 		ttytype(tty, "dcl", SDCL, SNDCL);
791 #endif
792 #ifdef mips
793 	if (nl[SNDC].n_type != 0)
794 		ttytype(tty, "dc", SDC, SNDC);
795 #endif
796 #ifdef __FreeBSD__
797 	if (nl[NSCCONS].n_type != 0)
798 		ttytype(tty, "vty", SCCONS, NSCCONS);
799 	if (nl[NSIO].n_type != 0)
800 		ttytype(tty, "sio", SIO, NSIO);
801 	if (nl[NRC].n_type != 0)
802 		ttytype(tty, "rc", RC, NRC);
803 #endif
804 	if (nl[SNPTY].n_type != 0)
805 		ttytype(tty, "pty", SPTY, SNPTY);
806 }
807 
808 void
809 ttytype(tty, name, type, number)
810 	register struct tty *tty;
811 	char *name;
812 	int type, number;
813 {
814 	register struct tty *tp;
815 	int ntty;
816 
817 	if (tty == NULL)
818 		return;
819 	KGET(number, ntty);
820 	(void)printf("%d %s %s\n", ntty, name, (ntty == 1) ? "line" : "lines");
821 	if (ntty > ttyspace) {
822 		ttyspace = ntty;
823 		if ((tty = realloc(tty, ttyspace * sizeof(*tty))) == 0)
824 			err(1, NULL);
825 	}
826 	KGET1(type, tty, ntty * sizeof(struct tty), "tty structs");
827 	(void)printf(hdr);
828 	for (tp = tty; tp < &tty[ntty]; tp++)
829 		ttyprt(tp, tp - tty);
830 }
831 
832 struct {
833 	int flag;
834 	char val;
835 } ttystates[] = {
836 	{ TS_WOPEN,	'W'},
837 	{ TS_ISOPEN,	'O'},
838 	{ TS_CARR_ON,	'C'},
839 	{ TS_TIMEOUT,	'T'},
840 	{ TS_FLUSH,	'F'},
841 	{ TS_BUSY,	'B'},
842 	{ TS_ASLEEP,	'A'},
843 	{ TS_XCLUDE,	'X'},
844 	{ TS_TTSTOP,	'S'},
845 	{ TS_TBLOCK,	'K'},
846 	{ TS_ASYNC,	'Y'},
847 	{ TS_BKSL,	'D'},
848 	{ TS_ERASE,	'E'},
849 	{ TS_LNCH,	'L'},
850 	{ TS_TYPEN,	'P'},
851 	{ TS_CNTTB,	'N'},
852 #ifdef __FreeBSD__
853 	{ TS_SNOOP,     's'},
854 	{ TS_CAN_BYPASS_L_RINT, 'l'},
855 #endif
856 	{ 0,	       '\0'},
857 };
858 
859 void
860 ttyprt(tp, line)
861 	register struct tty *tp;
862 	int line;
863 {
864 	register int i, j;
865 	pid_t pgid;
866 	char *name, state[20];
867 
868 	if (usenumflag || tp->t_dev == 0 ||
869 	   (name = devname(tp->t_dev, S_IFCHR)) == NULL)
870 		(void)printf("%7d ", line);
871 	else
872 		(void)printf("%7s ", name);
873 	(void)printf("%2d %3d ", tp->t_rawq.c_cc, tp->t_canq.c_cc);
874 	(void)printf("%3d %4d %3d %7d ", tp->t_outq.c_cc,
875 		tp->t_hiwat, tp->t_lowat, tp->t_column);
876 	for (i = j = 0; ttystates[i].flag; i++)
877 		if (tp->t_state&ttystates[i].flag)
878 			state[j++] = ttystates[i].val;
879 	if (j == 0)
880 		state[j++] = '-';
881 	state[j] = '\0';
882 	(void)printf("%-4s %6x", state, (u_long)tp->t_session & ~KERNBASE);
883 	pgid = 0;
884 	if (tp->t_pgrp != NULL)
885 		KGET2(&tp->t_pgrp->pg_id, &pgid, sizeof(pid_t), "pgid");
886 	(void)printf("%6d ", pgid);
887 	switch (tp->t_line) {
888 	case TTYDISC:
889 		(void)printf("term\n");
890 		break;
891 	case NTTYDISC:
892 		(void)printf("ntty\n");
893 		break;
894 	case TABLDISC:
895 		(void)printf("tab\n");
896 		break;
897 	case SLIPDISC:
898 		(void)printf("slip\n");
899 		break;
900 	case PPPDISC:
901 		(void)printf("ppp\n");
902 		break;
903 	default:
904 		(void)printf("%d\n", tp->t_line);
905 		break;
906 	}
907 }
908 
909 void
910 filemode()
911 {
912 	register struct file *fp;
913 	struct file *addr;
914 	char *buf, flagbuf[16], *fbp;
915 	int len, maxfile, nfile;
916 	static char *dtypes[] = { "???", "inode", "socket" };
917 
918 	KGET(FNL_MAXFILE, maxfile);
919 	if (totalflag) {
920 		KGET(FNL_NFILE, nfile);
921 		(void)printf("%3d/%3d files\n", nfile, maxfile);
922 		return;
923 	}
924 	if (getfiles(&buf, &len) == -1)
925 		return;
926 	/*
927 	 * Getfiles returns in malloc'd memory a pointer to the first file
928 	 * structure, and then an array of file structs (whose addresses are
929 	 * derivable from the previous entry).
930 	 */
931 	addr = *((struct file **)buf);
932 	fp = (struct file *)(buf + sizeof(struct file *));
933 	nfile = (len - sizeof(struct file *)) / sizeof(struct file);
934 
935 	(void)printf("%d/%d open files\n", nfile, maxfile);
936 	(void)printf("   LOC   TYPE    FLG     CNT  MSG    DATA    OFFSET\n");
937 	for (; (char *)fp < buf + len; addr = fp->f_filef, fp++) {
938 		if ((unsigned)fp->f_type > DTYPE_SOCKET)
939 			continue;
940 		(void)printf("%x ", addr);
941 		(void)printf("%-8.8s", dtypes[fp->f_type]);
942 		fbp = flagbuf;
943 		if (fp->f_flag & FREAD)
944 			*fbp++ = 'R';
945 		if (fp->f_flag & FWRITE)
946 			*fbp++ = 'W';
947 		if (fp->f_flag & FAPPEND)
948 			*fbp++ = 'A';
949 #ifdef FSHLOCK	/* currently gone */
950 		if (fp->f_flag & FSHLOCK)
951 			*fbp++ = 'S';
952 		if (fp->f_flag & FEXLOCK)
953 			*fbp++ = 'X';
954 #endif
955 		if (fp->f_flag & FASYNC)
956 			*fbp++ = 'I';
957 		*fbp = '\0';
958 		(void)printf("%6s  %3d", flagbuf, fp->f_count);
959 		(void)printf("  %3d", fp->f_msgcount);
960 		(void)printf("  %8.1x", fp->f_data);
961 		if (fp->f_offset < 0)
962 			(void)printf("  %qx\n", fp->f_offset);
963 		else
964 			(void)printf("  %qd\n", fp->f_offset);
965 	}
966 	free(buf);
967 }
968 
969 int
970 getfiles(abuf, alen)
971 	char **abuf;
972 	int *alen;
973 {
974 	size_t len;
975 	int mib[2];
976 	char *buf;
977 
978 	/*
979 	 * XXX
980 	 * Add emulation of KINFO_FILE here.
981 	 */
982 	if (memf != NULL)
983 		errx(1, "files on dead kernel, not implemented\n");
984 
985 	mib[0] = CTL_KERN;
986 	mib[1] = KERN_FILE;
987 	if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1) {
988 		warn("sysctl: KERN_FILE");
989 		return (-1);
990 	}
991 	if ((buf = malloc(len)) == NULL)
992 		err(1, NULL);
993 	if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) {
994 		warn("sysctl: KERN_FILE");
995 		return (-1);
996 	}
997 	*abuf = buf;
998 	*alen = len;
999 	return (0);
1000 }
1001 
1002 /*
1003  * swapmode is based on a program called swapinfo written
1004  * by Kevin Lahey <kml@rokkaku.atl.ga.us>.
1005  */
1006 void
1007 swapmode()
1008 {
1009 	char *header;
1010 	int hlen, nswap, nswdev, dmmax;
1011 	int i, div, avail, nfree, npfree, used;
1012 	struct swdevt *sw;
1013 	long blocksize, *perdev;
1014 	struct rlist head;
1015 	struct rlist *swaplist;
1016 	u_long ptr;
1017 
1018 	KGET(VM_NSWAP, nswap);
1019 	KGET(VM_NSWDEV, nswdev);
1020 	KGET(VM_DMMAX, dmmax);
1021 	KGET(VM_SWAPLIST, swaplist);
1022 	if ((sw = malloc(nswdev * sizeof(*sw))) == NULL ||
1023 	    (perdev = malloc(nswdev * sizeof(*perdev))) == NULL)
1024 		err(1, "malloc");
1025 	KGET1(VM_SWDEVT, &ptr, sizeof ptr, "swdevt");
1026 	KGET2(ptr, sw, nswdev * sizeof(*sw), "*swdevt");
1027 
1028 	/* Count up swap space. */
1029 	nfree = 0;
1030 	memset(perdev, 0, nswdev * sizeof(*perdev));
1031 	while (swaplist) {
1032 		int	top, bottom, next_block;
1033 
1034 		KGET2(swaplist, &head, sizeof(struct rlist), "swaplist");
1035 
1036 		top = head.rl_end;
1037 		bottom = head.rl_start;
1038 
1039 		nfree += top - bottom + 1;
1040 
1041 		/*
1042 		 * Swap space is split up among the configured disks.
1043 		 *
1044 		 * For interleaved swap devices, the first dmmax blocks
1045 		 * of swap space some from the first disk, the next dmmax
1046 		 * blocks from the next, and so on up to nswap blocks.
1047 		 *
1048 		 * The list of free space joins adjacent free blocks,
1049 		 * ignoring device boundries.  If we want to keep track
1050 		 * of this information per device, we'll just have to
1051 		 * extract it ourselves.
1052 		 */
1053 		while (top / dmmax != bottom / dmmax) {
1054 			next_block = ((bottom + dmmax) / dmmax);
1055 			perdev[(bottom / dmmax) % nswdev] +=
1056 				next_block * dmmax - bottom;
1057 			bottom = next_block * dmmax;
1058 		}
1059 		perdev[(bottom / dmmax) % nswdev] +=
1060 			top - bottom + 1;
1061 
1062 		swaplist = head.rl_next;
1063 	}
1064 
1065 	header = getbsize(&hlen, &blocksize);
1066 	if (!totalflag)
1067 		(void)printf("%-11s %*s %8s %8s %8s  %s\n",
1068 		    "Device", hlen, header,
1069 		    "Used", "Avail", "Capacity", "Type");
1070 	div = blocksize / 512;
1071 	avail = npfree = 0;
1072 	for (i = 0; i < nswdev; i++) {
1073 		int xsize, xfree;
1074 
1075 		/*
1076 		 * Don't report statistics for partitions which have not
1077 		 * yet been activated via swapon(8).
1078 		 */
1079 		if (!(sw[i].sw_flags & SW_FREED))
1080 			continue;
1081 
1082 		if (!totalflag)
1083 			(void)printf("/dev/%-6s %*d ",
1084 			    devname(sw[i].sw_dev, S_IFBLK),
1085 			    hlen, sw[i].sw_nblks / div);
1086 
1087 		/* The first dmmax is never allocated to avoid trashing of
1088 		 * disklabels
1089 		 */
1090 		xsize = sw[i].sw_nblks - dmmax;
1091 		xfree = perdev[i];
1092 		used = xsize - xfree;
1093 		npfree++;
1094 		avail += xsize;
1095 		if (totalflag)
1096 			continue;
1097 		(void)printf("%8d %8d %5.0f%%    %s\n",
1098 		    used / div, xfree / div,
1099 		    (double)used / (double)xsize * 100.0,
1100 		    (sw[i].sw_flags & SW_SEQUENTIAL) ?
1101 			     "Sequential" : "Interleaved");
1102 	}
1103 
1104 	/*
1105 	 * If only one partition has been set up via swapon(8), we don't
1106 	 * need to bother with totals.
1107 	 */
1108 	used = avail - nfree;
1109 	if (totalflag) {
1110 		(void)printf("%dM/%dM swap space\n", used / 2048, avail / 2048);
1111 		return;
1112 	}
1113 	if (npfree > 1) {
1114 		(void)printf("%-11s %*d %8d %8d %5.0f%%\n",
1115 		    "Total", hlen, avail / div, used / div, nfree / div,
1116 		    (double)used / (double)avail * 100.0);
1117 	}
1118 }
1119