Deleted Added
full compact
pstat.c (50479) pstat.c (53452)
1/*-
2 * Copyright (c) 1980, 1991, 1993, 1994
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
35static const char copyright[] =
36"@(#) Copyright (c) 1980, 1991, 1993, 1994\n\
37 The Regents of the University of California. All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41#if 0
42static char sccsid[] = "@(#)pstat.c 8.16 (Berkeley) 5/9/95";
43#endif
44static const char rcsid[] =
1/*-
2 * Copyright (c) 1980, 1991, 1993, 1994
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
35static const char copyright[] =
36"@(#) Copyright (c) 1980, 1991, 1993, 1994\n\
37 The Regents of the University of California. All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41#if 0
42static char sccsid[] = "@(#)pstat.c 8.16 (Berkeley) 5/9/95";
43#endif
44static const char rcsid[] =
45 "$FreeBSD: head/usr.sbin/pstat/pstat.c 50479 1999-08-28 01:35:59Z peter $";
45 "$FreeBSD: head/usr.sbin/pstat/pstat.c 53452 1999-11-20 10:00:46Z phk $";
46#endif /* not lint */
47
48#include <sys/param.h>
49#include <sys/time.h>
50#include <sys/vnode.h>
51#include <sys/ucred.h>
52#define KERNEL
53#include <sys/file.h>
54#include <ufs/ufs/quota.h>
55#include <ufs/ufs/inode.h>
56#include <sys/mount.h>
57#include <sys/uio.h>
58#include <sys/namei.h>
59#include <miscfs/union/union.h>
60#undef KERNEL
61#include <sys/stat.h>
62#include <nfs/rpcv2.h>
63#include <nfs/nfsproto.h>
64#include <nfs/nfs.h>
65#include <nfs/nfsnode.h>
66#include <sys/ioctl.h>
67#include <sys/ioctl_compat.h> /* XXX NTTYDISC is too well hidden */
68#include <sys/tty.h>
69#include <sys/conf.h>
70#include <sys/blist.h>
71
72#include <sys/user.h>
73#include <sys/sysctl.h>
74
75#include <err.h>
76#include <fcntl.h>
77#include <kvm.h>
78#include <limits.h>
79#include <nlist.h>
80#include <stdio.h>
81#include <stdlib.h>
82#include <string.h>
83#include <unistd.h>
84
85struct nlist nl[] = {
86#define NLMANDATORYBEG 0
87#define V_MOUNTLIST 0
88 { "_mountlist" }, /* address of head of mount list. */
89#define V_NUMV 1
90 { "_numvnodes" },
91#define FNL_NFILE 2
92 {"_nfiles"},
93#define FNL_MAXFILE 3
94 {"_maxfiles"},
95#define NLMANDATORYEND FNL_MAXFILE /* names up to here are mandatory */
96#define SCONS NLMANDATORYEND + 1
97 { "_cons" },
98#define SPTY NLMANDATORYEND + 2
99 { "_pt_tty" },
100#define SNPTY NLMANDATORYEND + 3
101 { "_npty" },
102
103
104
105#ifdef __FreeBSD__
106#define SCCONS (SNPTY+1)
107 { "_sccons" },
108#define NSCCONS (SNPTY+2)
109 { "_nsccons" },
110#define SIO (SNPTY+3)
111 { "_sio_tty" },
112#define NSIO (SNPTY+4)
113 { "_nsio_tty" },
114#define RC (SNPTY+5)
115 { "_rc_tty" },
116#define NRC (SNPTY+6)
117 { "_nrc_tty" },
118#define CY (SNPTY+7)
119 { "_cy_tty" },
120#define NCY (SNPTY+8)
121 { "_ncy_tty" },
122#define SI (SNPTY+9)
123 { "_si_tty" },
124#define NSI (SNPTY+10)
125 { "_si_Nports" },
126#endif
127 { "" }
128};
129
130int usenumflag;
131int totalflag;
132int swapflag;
133char *nlistf = NULL;
134char *memf = NULL;
135kvm_t *kd;
136
137char *usagestr;
138
139struct {
140 int m_flag;
141 const char *m_name;
142} mnt_flags[] = {
143 { MNT_RDONLY, "rdonly" },
144 { MNT_SYNCHRONOUS, "sync" },
145 { MNT_NOEXEC, "noexec" },
146 { MNT_NOSUID, "nosuid" },
147 { MNT_NODEV, "nodev" },
148 { MNT_UNION, "union" },
149 { MNT_ASYNC, "async" },
150 { MNT_NOATIME, "noatime" },
151 { MNT_EXRDONLY, "exrdonly" },
152 { MNT_EXPORTED, "exported" },
153 { MNT_DEFEXPORTED, "defexported" },
154 { MNT_EXPORTANON, "exportanon" },
155 { MNT_EXKERB, "exkerb" },
156 { MNT_LOCAL, "local" },
157 { MNT_QUOTA, "quota" },
158 { MNT_ROOTFS, "rootfs" },
159 { MNT_USER, "user" },
160 { MNT_UPDATE, "update" },
161 { MNT_DELEXPORT },
162 { MNT_UPDATE, "update" },
163 { MNT_DELEXPORT, "delexport" },
164 { MNT_RELOAD, "reload" },
165 { MNT_FORCE, "force" },
166#if 0
167 { MNT_UNMOUNT, "unmount" },
168 { MNT_MWAIT, "mwait" },
169 { MNT_WANTRDWR, "wantrdwr" },
170#endif
171 { 0 }
172};
173
174
175#define SVAR(var) __STRING(var) /* to force expansion */
176#define KGET(idx, var) \
177 KGET1(idx, &var, sizeof(var), SVAR(var))
178#define KGET1(idx, p, s, msg) \
179 KGET2(nl[idx].n_value, p, s, msg)
180#define KGET2(addr, p, s, msg) \
181 if (kvm_read(kd, (u_long)(addr), p, s) != s) \
182 warnx("cannot read %s: %s", msg, kvm_geterr(kd))
183#define KGETN(idx, var) \
184 KGET1N(idx, &var, sizeof(var), SVAR(var))
185#define KGET1N(idx, p, s, msg) \
186 KGET2N(nl[idx].n_value, p, s, msg)
187#define KGET2N(addr, p, s, msg) \
188 ((kvm_read(kd, (u_long)(addr), p, s) == s) ? 1 : 0)
189#define KGETRET(addr, p, s, msg) \
190 if (kvm_read(kd, (u_long)(addr), p, s) != s) { \
191 warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \
192 return (0); \
193 }
194
195void filemode __P((void));
196int getfiles __P((char **, int *));
197struct mount *
198 getmnt __P((struct mount *));
199struct e_vnode *
200 kinfo_vnodes __P((int *));
201struct e_vnode *
202 loadvnodes __P((int *));
203void mount_print __P((struct mount *));
204void nfs_header __P((void));
205int nfs_print __P((struct vnode *));
206void swapmode __P((void));
207void ttymode __P((void));
208void ttyprt __P((struct tty *, int));
209void ttytype __P((struct tty *, char *, int, int, int));
210void ufs_header __P((void));
211int ufs_print __P((struct vnode *));
212void union_header __P((void));
213int union_print __P((struct vnode *));
214static void usage __P((void));
215void vnode_header __P((void));
216void vnode_print __P((struct vnode *, struct vnode *));
217void vnodemode __P((void));
218
219int
220main(argc, argv)
221 int argc;
222 char *argv[];
223{
224 int ch, i, quit, ret;
225 int fileflag, ttyflag, vnodeflag;
226 char buf[_POSIX2_LINE_MAX],*opts;
227
228 fileflag = swapflag = ttyflag = vnodeflag = 0;
229
230 /* We will behave like good old swapinfo if thus invoked */
231 opts = strrchr(argv[0],'/');
232 if (opts)
233 opts++;
234 else
235 opts = argv[0];
236 if (!strcmp(opts,"swapinfo")) {
237 swapflag = 1;
238 opts = "kM:N:";
239 usagestr = "swapinfo [-k] [-M core] [-N system]";
240 } else {
241 opts = "TM:N:fiknstv";
242 usagestr = "pstat [-Tfknstv] [-M core] [-N system]";
243 }
244
245 while ((ch = getopt(argc, argv, opts)) != -1)
246 switch (ch) {
247 case 'f':
248 fileflag = 1;
249 break;
250 case 'k':
251 putenv("BLOCKSIZE=1K");
252 break;
253 case 'M':
254 memf = optarg;
255 break;
256 case 'N':
257 nlistf = optarg;
258 break;
259 case 'n':
260 usenumflag = 1;
261 break;
262 case 's':
263 ++swapflag;
264 break;
265 case 'T':
266 totalflag = 1;
267 break;
268 case 't':
269 ttyflag = 1;
270 break;
271 case 'v':
272 case 'i': /* Backward compatibility. */
273 fprintf(stderr, "vnode mode not supported\n");
274 exit(1);
275#if 0
276 vnodeflag = 1;
277 break;
278#endif
279 default:
280 usage();
281 }
282 argc -= optind;
283 argv += optind;
284
285 /*
286 * Discard setgid privileges if not the running kernel so that bad
287 * guys can't print interesting stuff from kernel memory.
288 */
289 if (nlistf != NULL || memf != NULL)
290 (void)setgid(getgid());
291
292 if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == 0)
293 errx(1, "kvm_openfiles: %s", buf);
294 if ((ret = kvm_nlist(kd, nl)) != 0) {
295 if (ret == -1)
296 errx(1, "kvm_nlist: %s", kvm_geterr(kd));
297 for (i = NLMANDATORYBEG, quit = 0; i <= NLMANDATORYEND; i++)
298 if (!nl[i].n_value) {
299 quit = 1;
300 warnx("undefined symbol: %s", nl[i].n_name);
301 }
302 if (quit)
303 exit(1);
304 }
305 if (!(fileflag | vnodeflag | ttyflag | swapflag | totalflag))
306 usage();
307 if (fileflag || totalflag)
308 filemode();
309 if (vnodeflag)
310 vnodemode();
311 if (ttyflag)
312 ttymode();
313 if (swapflag || totalflag)
314 swapmode();
315 exit (0);
316}
317
318static void
319usage()
320{
321 fprintf(stderr, "usage: %s\n", usagestr);
322 exit (1);
323}
324
325struct e_vnode {
326 struct vnode *avnode;
327 struct vnode vnode;
328};
329
330void
331vnodemode()
332{
333 struct e_vnode *e_vnodebase, *endvnode, *evp;
334 struct vnode *vp;
335 struct mount *maddr, *mp;
336 int numvnodes;
337
338 e_vnodebase = loadvnodes(&numvnodes);
339 if (totalflag) {
340 (void)printf("%7d vnodes\n", numvnodes);
341 return;
342 }
343 endvnode = e_vnodebase + numvnodes;
344 (void)printf("%d active vnodes\n", numvnodes);
345
346
347#define ST mp->mnt_stat
348 maddr = NULL;
349 for (evp = e_vnodebase; evp < endvnode; evp++) {
350 vp = &evp->vnode;
351 if (vp->v_mount != maddr) {
352 /*
353 * New filesystem
354 */
355 if ((mp = getmnt(vp->v_mount)) == NULL)
356 continue;
357 maddr = vp->v_mount;
358 mount_print(mp);
359 vnode_header();
360 if (!strcmp(ST.f_fstypename, "ufs") ||
361 !strcmp(ST.f_fstypename, "mfs"))
362 ufs_header();
363 else if (!strcmp(ST.f_fstypename, "nfs"))
364 nfs_header();
365 else if (!strcmp(ST.f_fstypename, "union"))
366 union_header();
367 (void)printf("\n");
368 }
369 vnode_print(evp->avnode, vp);
370 if (!strcmp(ST.f_fstypename, "ufs") ||
371 !strcmp(ST.f_fstypename, "mfs"))
372 ufs_print(vp);
373 else if (!strcmp(ST.f_fstypename, "nfs"))
374 nfs_print(vp);
375 else if (!strcmp(ST.f_fstypename, "union"))
376 union_print(vp);
377 (void)printf("\n");
378 }
379 free(e_vnodebase);
380}
381
382void
383vnode_header()
384{
385 (void)printf("ADDR TYP VFLAG USE HOLD");
386}
387
388void
389vnode_print(avnode, vp)
390 struct vnode *avnode;
391 struct vnode *vp;
392{
393 char *type, flags[16];
394 char *fp = flags;
395 int flag;
396
397 /*
398 * set type
399 */
400 switch (vp->v_type) {
401 case VNON:
402 type = "non"; break;
403 case VREG:
404 type = "reg"; break;
405 case VDIR:
406 type = "dir"; break;
407 case VBLK:
408 type = "blk"; break;
409 case VCHR:
410 type = "chr"; break;
411 case VLNK:
412 type = "lnk"; break;
413 case VSOCK:
414 type = "soc"; break;
415 case VFIFO:
416 type = "fif"; break;
417 case VBAD:
418 type = "bad"; break;
419 default:
420 type = "unk"; break;
421 }
422 /*
423 * gather flags
424 */
425 flag = vp->v_flag;
426 if (flag & VROOT)
427 *fp++ = 'R';
428 if (flag & VTEXT)
429 *fp++ = 'T';
430 if (flag & VSYSTEM)
431 *fp++ = 'S';
432 if (flag & VISTTY)
433 *fp++ = 't';
434 if (flag & VXLOCK)
435 *fp++ = 'L';
436 if (flag & VXWANT)
437 *fp++ = 'W';
438 if (flag & VBWAIT)
439 *fp++ = 'B';
440 if (flag & VOBJBUF)
441 *fp++ = 'V';
442 if (flag & VAGE)
443 *fp++ = 'a';
444 if (flag & VOLOCK)
445 *fp++ = 'l';
446 if (flag & VOWANT)
447 *fp++ = 'w';
448 if (flag == 0)
449 *fp++ = '-';
450 *fp = '\0';
451 (void)printf("%8lx %s %5s %4d %4d",
452 (u_long)(void *)avnode, type, flags, vp->v_usecount, vp->v_holdcnt);
453}
454
455void
456ufs_header()
457{
458 (void)printf(" FILEID IFLAG RDEV|SZ");
459}
460
461int
462ufs_print(vp)
463 struct vnode *vp;
464{
465 int flag;
466 struct inode inode, *ip = &inode;
467 char flagbuf[16], *flags = flagbuf;
468 char *name;
469 mode_t type;
470
471 KGETRET(VTOI(vp), &inode, sizeof(struct inode), "vnode's inode");
472 flag = ip->i_flag;
473 if (flag & IN_RENAME)
474 *flags++ = 'R';
475 if (flag & IN_UPDATE)
476 *flags++ = 'U';
477 if (flag & IN_ACCESS)
478 *flags++ = 'A';
479 if (flag & IN_CHANGE)
480 *flags++ = 'C';
481 if (flag & IN_MODIFIED)
482 *flags++ = 'M';
483 if (flag & IN_SHLOCK)
484 *flags++ = 'S';
485 if (flag & IN_EXLOCK)
486 *flags++ = 'E';
487 if (flag == 0)
488 *flags++ = '-';
489 *flags = '\0';
490
491 (void)printf(" %6d %5s", ip->i_number, flagbuf);
492 type = ip->i_mode & S_IFMT;
493 if (S_ISCHR(ip->i_mode) || S_ISBLK(ip->i_mode))
494 if (usenumflag || ((name = devname(ip->i_rdev, type)) == NULL))
495 (void)printf(" %2d,%-2d",
496 major(ip->i_rdev), minor(ip->i_rdev));
497 else
498 (void)printf(" %7s", name);
499 else
500 (void)printf(" %7qd", ip->i_size);
501 return (0);
502}
503
504void
505nfs_header()
506{
507 (void)printf(" FILEID NFLAG RDEV|SZ");
508}
509
510int
511nfs_print(vp)
512 struct vnode *vp;
513{
514 struct nfsnode nfsnode, *np = &nfsnode;
515 char flagbuf[16], *flags = flagbuf;
516 int flag;
517 char *name;
518 mode_t type;
519
520 KGETRET(VTONFS(vp), &nfsnode, sizeof(nfsnode), "vnode's nfsnode");
521 flag = np->n_flag;
522 if (flag & NFLUSHWANT)
523 *flags++ = 'W';
524 if (flag & NFLUSHINPROG)
525 *flags++ = 'P';
526 if (flag & NMODIFIED)
527 *flags++ = 'M';
528 if (flag & NWRITEERR)
529 *flags++ = 'E';
530 if (flag & NQNFSNONCACHE)
531 *flags++ = 'X';
532 if (flag & NQNFSWRITE)
533 *flags++ = 'O';
534 if (flag & NQNFSEVICTED)
535 *flags++ = 'G';
536 if (flag == 0)
537 *flags++ = '-';
538 *flags = '\0';
539
540#define VT np->n_vattr
541 (void)printf(" %6ld %5s", VT.va_fileid, flagbuf);
542 type = VT.va_mode & S_IFMT;
543 if (S_ISCHR(VT.va_mode) || S_ISBLK(VT.va_mode))
544 if (usenumflag || ((name = devname(VT.va_rdev, type)) == NULL))
545 (void)printf(" %2d,%-2d",
546 major(VT.va_rdev), minor(VT.va_rdev));
547 else
548 (void)printf(" %7s", name);
549 else
550 (void)printf(" %7qd", np->n_size);
551 return (0);
552}
553
554void
555union_header()
556{
557 (void)printf(" UPPER LOWER");
558}
559
560int
561union_print(vp)
562 struct vnode *vp;
563{
564 struct union_node unode, *up = &unode;
565
566 KGETRET(VTOUNION(vp), &unode, sizeof(unode), "vnode's unode");
567
568 (void)printf(" %8lx %8lx", (u_long)(void *)up->un_uppervp,
569 (u_long)(void *)up->un_lowervp);
570 return (0);
571}
572
573/*
574 * Given a pointer to a mount structure in kernel space,
575 * read it in and return a usable pointer to it.
576 */
577struct mount *
578getmnt(maddr)
579 struct mount *maddr;
580{
581 static struct mtab {
582 struct mtab *next;
583 struct mount *maddr;
584 struct mount mount;
585 } *mhead = NULL;
586 struct mtab *mt;
587
588 for (mt = mhead; mt != NULL; mt = mt->next)
589 if (maddr == mt->maddr)
590 return (&mt->mount);
591 if ((mt = malloc(sizeof(struct mtab))) == NULL)
592 errx(1, "malloc");
593 KGETRET(maddr, &mt->mount, sizeof(struct mount), "mount table");
594 mt->maddr = maddr;
595 mt->next = mhead;
596 mhead = mt;
597 return (&mt->mount);
598}
599
600void
601mount_print(mp)
602 struct mount *mp;
603{
604 int flags;
605 const char *type;
606
607#define ST mp->mnt_stat
608 (void)printf("*** MOUNT %s %s on %s", ST.f_fstypename,
609 ST.f_mntfromname, ST.f_mntonname);
610 if ((flags = mp->mnt_flag)) {
611 int i;
612 const char *sep = " (";
613
614 for (i = 0; mnt_flags[i].m_flag; i++) {
615 if (flags & mnt_flags[i].m_flag) {
616 (void)printf("%s%s", sep, mnt_flags[i].m_name);
617 flags &= ~mnt_flags[i].m_flag;
618 sep = ",";
619 }
620 }
621 if (flags)
622 (void)printf("%sunknown_flags:%x", sep, flags);
623 (void)printf(")");
624 }
625 (void)printf("\n");
626#undef ST
627}
628
629struct e_vnode *
630loadvnodes(avnodes)
631 int *avnodes;
632{
633 int mib[2];
634 size_t copysize;
635 struct e_vnode *vnodebase;
636
637 if (memf != NULL) {
638 /*
639 * do it by hand
640 */
641 return (kinfo_vnodes(avnodes));
642 }
643 mib[0] = CTL_KERN;
644 mib[1] = KERN_VNODE;
645 if (sysctl(mib, 2, NULL, &copysize, NULL, 0) == -1)
646 err(1, "sysctl: KERN_VNODE");
647 if ((vnodebase = malloc(copysize)) == NULL)
648 errx(1, "malloc");
649 if (sysctl(mib, 2, vnodebase, &copysize, NULL, 0) == -1)
650 err(1, "sysctl: KERN_VNODE");
651 if (copysize % sizeof(struct e_vnode))
652 errx(1, "vnode size mismatch");
653 *avnodes = copysize / sizeof(struct e_vnode);
654
655 return (vnodebase);
656}
657
658/*
659 * simulate what a running kernel does in in kinfo_vnode
660 */
661struct e_vnode *
662kinfo_vnodes(avnodes)
663 int *avnodes;
664{
665 struct mntlist mountlist;
666 struct mount *mp, mount, *mp_next;
667 struct vnode *vp, vnode, *vp_next;
668 char *vbuf, *evbuf, *bp;
669 int num, numvnodes;
670
671#define VPTRSZ sizeof(struct vnode *)
672#define VNODESZ sizeof(struct vnode)
673
674 KGET(V_NUMV, numvnodes);
675 if ((vbuf = malloc((numvnodes + 20) * (VPTRSZ + VNODESZ))) == NULL)
676 errx(1, "malloc");
677 bp = vbuf;
678 evbuf = vbuf + (numvnodes + 20) * (VPTRSZ + VNODESZ);
679 KGET(V_MOUNTLIST, mountlist);
46#endif /* not lint */
47
48#include <sys/param.h>
49#include <sys/time.h>
50#include <sys/vnode.h>
51#include <sys/ucred.h>
52#define KERNEL
53#include <sys/file.h>
54#include <ufs/ufs/quota.h>
55#include <ufs/ufs/inode.h>
56#include <sys/mount.h>
57#include <sys/uio.h>
58#include <sys/namei.h>
59#include <miscfs/union/union.h>
60#undef KERNEL
61#include <sys/stat.h>
62#include <nfs/rpcv2.h>
63#include <nfs/nfsproto.h>
64#include <nfs/nfs.h>
65#include <nfs/nfsnode.h>
66#include <sys/ioctl.h>
67#include <sys/ioctl_compat.h> /* XXX NTTYDISC is too well hidden */
68#include <sys/tty.h>
69#include <sys/conf.h>
70#include <sys/blist.h>
71
72#include <sys/user.h>
73#include <sys/sysctl.h>
74
75#include <err.h>
76#include <fcntl.h>
77#include <kvm.h>
78#include <limits.h>
79#include <nlist.h>
80#include <stdio.h>
81#include <stdlib.h>
82#include <string.h>
83#include <unistd.h>
84
85struct nlist nl[] = {
86#define NLMANDATORYBEG 0
87#define V_MOUNTLIST 0
88 { "_mountlist" }, /* address of head of mount list. */
89#define V_NUMV 1
90 { "_numvnodes" },
91#define FNL_NFILE 2
92 {"_nfiles"},
93#define FNL_MAXFILE 3
94 {"_maxfiles"},
95#define NLMANDATORYEND FNL_MAXFILE /* names up to here are mandatory */
96#define SCONS NLMANDATORYEND + 1
97 { "_cons" },
98#define SPTY NLMANDATORYEND + 2
99 { "_pt_tty" },
100#define SNPTY NLMANDATORYEND + 3
101 { "_npty" },
102
103
104
105#ifdef __FreeBSD__
106#define SCCONS (SNPTY+1)
107 { "_sccons" },
108#define NSCCONS (SNPTY+2)
109 { "_nsccons" },
110#define SIO (SNPTY+3)
111 { "_sio_tty" },
112#define NSIO (SNPTY+4)
113 { "_nsio_tty" },
114#define RC (SNPTY+5)
115 { "_rc_tty" },
116#define NRC (SNPTY+6)
117 { "_nrc_tty" },
118#define CY (SNPTY+7)
119 { "_cy_tty" },
120#define NCY (SNPTY+8)
121 { "_ncy_tty" },
122#define SI (SNPTY+9)
123 { "_si_tty" },
124#define NSI (SNPTY+10)
125 { "_si_Nports" },
126#endif
127 { "" }
128};
129
130int usenumflag;
131int totalflag;
132int swapflag;
133char *nlistf = NULL;
134char *memf = NULL;
135kvm_t *kd;
136
137char *usagestr;
138
139struct {
140 int m_flag;
141 const char *m_name;
142} mnt_flags[] = {
143 { MNT_RDONLY, "rdonly" },
144 { MNT_SYNCHRONOUS, "sync" },
145 { MNT_NOEXEC, "noexec" },
146 { MNT_NOSUID, "nosuid" },
147 { MNT_NODEV, "nodev" },
148 { MNT_UNION, "union" },
149 { MNT_ASYNC, "async" },
150 { MNT_NOATIME, "noatime" },
151 { MNT_EXRDONLY, "exrdonly" },
152 { MNT_EXPORTED, "exported" },
153 { MNT_DEFEXPORTED, "defexported" },
154 { MNT_EXPORTANON, "exportanon" },
155 { MNT_EXKERB, "exkerb" },
156 { MNT_LOCAL, "local" },
157 { MNT_QUOTA, "quota" },
158 { MNT_ROOTFS, "rootfs" },
159 { MNT_USER, "user" },
160 { MNT_UPDATE, "update" },
161 { MNT_DELEXPORT },
162 { MNT_UPDATE, "update" },
163 { MNT_DELEXPORT, "delexport" },
164 { MNT_RELOAD, "reload" },
165 { MNT_FORCE, "force" },
166#if 0
167 { MNT_UNMOUNT, "unmount" },
168 { MNT_MWAIT, "mwait" },
169 { MNT_WANTRDWR, "wantrdwr" },
170#endif
171 { 0 }
172};
173
174
175#define SVAR(var) __STRING(var) /* to force expansion */
176#define KGET(idx, var) \
177 KGET1(idx, &var, sizeof(var), SVAR(var))
178#define KGET1(idx, p, s, msg) \
179 KGET2(nl[idx].n_value, p, s, msg)
180#define KGET2(addr, p, s, msg) \
181 if (kvm_read(kd, (u_long)(addr), p, s) != s) \
182 warnx("cannot read %s: %s", msg, kvm_geterr(kd))
183#define KGETN(idx, var) \
184 KGET1N(idx, &var, sizeof(var), SVAR(var))
185#define KGET1N(idx, p, s, msg) \
186 KGET2N(nl[idx].n_value, p, s, msg)
187#define KGET2N(addr, p, s, msg) \
188 ((kvm_read(kd, (u_long)(addr), p, s) == s) ? 1 : 0)
189#define KGETRET(addr, p, s, msg) \
190 if (kvm_read(kd, (u_long)(addr), p, s) != s) { \
191 warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \
192 return (0); \
193 }
194
195void filemode __P((void));
196int getfiles __P((char **, int *));
197struct mount *
198 getmnt __P((struct mount *));
199struct e_vnode *
200 kinfo_vnodes __P((int *));
201struct e_vnode *
202 loadvnodes __P((int *));
203void mount_print __P((struct mount *));
204void nfs_header __P((void));
205int nfs_print __P((struct vnode *));
206void swapmode __P((void));
207void ttymode __P((void));
208void ttyprt __P((struct tty *, int));
209void ttytype __P((struct tty *, char *, int, int, int));
210void ufs_header __P((void));
211int ufs_print __P((struct vnode *));
212void union_header __P((void));
213int union_print __P((struct vnode *));
214static void usage __P((void));
215void vnode_header __P((void));
216void vnode_print __P((struct vnode *, struct vnode *));
217void vnodemode __P((void));
218
219int
220main(argc, argv)
221 int argc;
222 char *argv[];
223{
224 int ch, i, quit, ret;
225 int fileflag, ttyflag, vnodeflag;
226 char buf[_POSIX2_LINE_MAX],*opts;
227
228 fileflag = swapflag = ttyflag = vnodeflag = 0;
229
230 /* We will behave like good old swapinfo if thus invoked */
231 opts = strrchr(argv[0],'/');
232 if (opts)
233 opts++;
234 else
235 opts = argv[0];
236 if (!strcmp(opts,"swapinfo")) {
237 swapflag = 1;
238 opts = "kM:N:";
239 usagestr = "swapinfo [-k] [-M core] [-N system]";
240 } else {
241 opts = "TM:N:fiknstv";
242 usagestr = "pstat [-Tfknstv] [-M core] [-N system]";
243 }
244
245 while ((ch = getopt(argc, argv, opts)) != -1)
246 switch (ch) {
247 case 'f':
248 fileflag = 1;
249 break;
250 case 'k':
251 putenv("BLOCKSIZE=1K");
252 break;
253 case 'M':
254 memf = optarg;
255 break;
256 case 'N':
257 nlistf = optarg;
258 break;
259 case 'n':
260 usenumflag = 1;
261 break;
262 case 's':
263 ++swapflag;
264 break;
265 case 'T':
266 totalflag = 1;
267 break;
268 case 't':
269 ttyflag = 1;
270 break;
271 case 'v':
272 case 'i': /* Backward compatibility. */
273 fprintf(stderr, "vnode mode not supported\n");
274 exit(1);
275#if 0
276 vnodeflag = 1;
277 break;
278#endif
279 default:
280 usage();
281 }
282 argc -= optind;
283 argv += optind;
284
285 /*
286 * Discard setgid privileges if not the running kernel so that bad
287 * guys can't print interesting stuff from kernel memory.
288 */
289 if (nlistf != NULL || memf != NULL)
290 (void)setgid(getgid());
291
292 if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == 0)
293 errx(1, "kvm_openfiles: %s", buf);
294 if ((ret = kvm_nlist(kd, nl)) != 0) {
295 if (ret == -1)
296 errx(1, "kvm_nlist: %s", kvm_geterr(kd));
297 for (i = NLMANDATORYBEG, quit = 0; i <= NLMANDATORYEND; i++)
298 if (!nl[i].n_value) {
299 quit = 1;
300 warnx("undefined symbol: %s", nl[i].n_name);
301 }
302 if (quit)
303 exit(1);
304 }
305 if (!(fileflag | vnodeflag | ttyflag | swapflag | totalflag))
306 usage();
307 if (fileflag || totalflag)
308 filemode();
309 if (vnodeflag)
310 vnodemode();
311 if (ttyflag)
312 ttymode();
313 if (swapflag || totalflag)
314 swapmode();
315 exit (0);
316}
317
318static void
319usage()
320{
321 fprintf(stderr, "usage: %s\n", usagestr);
322 exit (1);
323}
324
325struct e_vnode {
326 struct vnode *avnode;
327 struct vnode vnode;
328};
329
330void
331vnodemode()
332{
333 struct e_vnode *e_vnodebase, *endvnode, *evp;
334 struct vnode *vp;
335 struct mount *maddr, *mp;
336 int numvnodes;
337
338 e_vnodebase = loadvnodes(&numvnodes);
339 if (totalflag) {
340 (void)printf("%7d vnodes\n", numvnodes);
341 return;
342 }
343 endvnode = e_vnodebase + numvnodes;
344 (void)printf("%d active vnodes\n", numvnodes);
345
346
347#define ST mp->mnt_stat
348 maddr = NULL;
349 for (evp = e_vnodebase; evp < endvnode; evp++) {
350 vp = &evp->vnode;
351 if (vp->v_mount != maddr) {
352 /*
353 * New filesystem
354 */
355 if ((mp = getmnt(vp->v_mount)) == NULL)
356 continue;
357 maddr = vp->v_mount;
358 mount_print(mp);
359 vnode_header();
360 if (!strcmp(ST.f_fstypename, "ufs") ||
361 !strcmp(ST.f_fstypename, "mfs"))
362 ufs_header();
363 else if (!strcmp(ST.f_fstypename, "nfs"))
364 nfs_header();
365 else if (!strcmp(ST.f_fstypename, "union"))
366 union_header();
367 (void)printf("\n");
368 }
369 vnode_print(evp->avnode, vp);
370 if (!strcmp(ST.f_fstypename, "ufs") ||
371 !strcmp(ST.f_fstypename, "mfs"))
372 ufs_print(vp);
373 else if (!strcmp(ST.f_fstypename, "nfs"))
374 nfs_print(vp);
375 else if (!strcmp(ST.f_fstypename, "union"))
376 union_print(vp);
377 (void)printf("\n");
378 }
379 free(e_vnodebase);
380}
381
382void
383vnode_header()
384{
385 (void)printf("ADDR TYP VFLAG USE HOLD");
386}
387
388void
389vnode_print(avnode, vp)
390 struct vnode *avnode;
391 struct vnode *vp;
392{
393 char *type, flags[16];
394 char *fp = flags;
395 int flag;
396
397 /*
398 * set type
399 */
400 switch (vp->v_type) {
401 case VNON:
402 type = "non"; break;
403 case VREG:
404 type = "reg"; break;
405 case VDIR:
406 type = "dir"; break;
407 case VBLK:
408 type = "blk"; break;
409 case VCHR:
410 type = "chr"; break;
411 case VLNK:
412 type = "lnk"; break;
413 case VSOCK:
414 type = "soc"; break;
415 case VFIFO:
416 type = "fif"; break;
417 case VBAD:
418 type = "bad"; break;
419 default:
420 type = "unk"; break;
421 }
422 /*
423 * gather flags
424 */
425 flag = vp->v_flag;
426 if (flag & VROOT)
427 *fp++ = 'R';
428 if (flag & VTEXT)
429 *fp++ = 'T';
430 if (flag & VSYSTEM)
431 *fp++ = 'S';
432 if (flag & VISTTY)
433 *fp++ = 't';
434 if (flag & VXLOCK)
435 *fp++ = 'L';
436 if (flag & VXWANT)
437 *fp++ = 'W';
438 if (flag & VBWAIT)
439 *fp++ = 'B';
440 if (flag & VOBJBUF)
441 *fp++ = 'V';
442 if (flag & VAGE)
443 *fp++ = 'a';
444 if (flag & VOLOCK)
445 *fp++ = 'l';
446 if (flag & VOWANT)
447 *fp++ = 'w';
448 if (flag == 0)
449 *fp++ = '-';
450 *fp = '\0';
451 (void)printf("%8lx %s %5s %4d %4d",
452 (u_long)(void *)avnode, type, flags, vp->v_usecount, vp->v_holdcnt);
453}
454
455void
456ufs_header()
457{
458 (void)printf(" FILEID IFLAG RDEV|SZ");
459}
460
461int
462ufs_print(vp)
463 struct vnode *vp;
464{
465 int flag;
466 struct inode inode, *ip = &inode;
467 char flagbuf[16], *flags = flagbuf;
468 char *name;
469 mode_t type;
470
471 KGETRET(VTOI(vp), &inode, sizeof(struct inode), "vnode's inode");
472 flag = ip->i_flag;
473 if (flag & IN_RENAME)
474 *flags++ = 'R';
475 if (flag & IN_UPDATE)
476 *flags++ = 'U';
477 if (flag & IN_ACCESS)
478 *flags++ = 'A';
479 if (flag & IN_CHANGE)
480 *flags++ = 'C';
481 if (flag & IN_MODIFIED)
482 *flags++ = 'M';
483 if (flag & IN_SHLOCK)
484 *flags++ = 'S';
485 if (flag & IN_EXLOCK)
486 *flags++ = 'E';
487 if (flag == 0)
488 *flags++ = '-';
489 *flags = '\0';
490
491 (void)printf(" %6d %5s", ip->i_number, flagbuf);
492 type = ip->i_mode & S_IFMT;
493 if (S_ISCHR(ip->i_mode) || S_ISBLK(ip->i_mode))
494 if (usenumflag || ((name = devname(ip->i_rdev, type)) == NULL))
495 (void)printf(" %2d,%-2d",
496 major(ip->i_rdev), minor(ip->i_rdev));
497 else
498 (void)printf(" %7s", name);
499 else
500 (void)printf(" %7qd", ip->i_size);
501 return (0);
502}
503
504void
505nfs_header()
506{
507 (void)printf(" FILEID NFLAG RDEV|SZ");
508}
509
510int
511nfs_print(vp)
512 struct vnode *vp;
513{
514 struct nfsnode nfsnode, *np = &nfsnode;
515 char flagbuf[16], *flags = flagbuf;
516 int flag;
517 char *name;
518 mode_t type;
519
520 KGETRET(VTONFS(vp), &nfsnode, sizeof(nfsnode), "vnode's nfsnode");
521 flag = np->n_flag;
522 if (flag & NFLUSHWANT)
523 *flags++ = 'W';
524 if (flag & NFLUSHINPROG)
525 *flags++ = 'P';
526 if (flag & NMODIFIED)
527 *flags++ = 'M';
528 if (flag & NWRITEERR)
529 *flags++ = 'E';
530 if (flag & NQNFSNONCACHE)
531 *flags++ = 'X';
532 if (flag & NQNFSWRITE)
533 *flags++ = 'O';
534 if (flag & NQNFSEVICTED)
535 *flags++ = 'G';
536 if (flag == 0)
537 *flags++ = '-';
538 *flags = '\0';
539
540#define VT np->n_vattr
541 (void)printf(" %6ld %5s", VT.va_fileid, flagbuf);
542 type = VT.va_mode & S_IFMT;
543 if (S_ISCHR(VT.va_mode) || S_ISBLK(VT.va_mode))
544 if (usenumflag || ((name = devname(VT.va_rdev, type)) == NULL))
545 (void)printf(" %2d,%-2d",
546 major(VT.va_rdev), minor(VT.va_rdev));
547 else
548 (void)printf(" %7s", name);
549 else
550 (void)printf(" %7qd", np->n_size);
551 return (0);
552}
553
554void
555union_header()
556{
557 (void)printf(" UPPER LOWER");
558}
559
560int
561union_print(vp)
562 struct vnode *vp;
563{
564 struct union_node unode, *up = &unode;
565
566 KGETRET(VTOUNION(vp), &unode, sizeof(unode), "vnode's unode");
567
568 (void)printf(" %8lx %8lx", (u_long)(void *)up->un_uppervp,
569 (u_long)(void *)up->un_lowervp);
570 return (0);
571}
572
573/*
574 * Given a pointer to a mount structure in kernel space,
575 * read it in and return a usable pointer to it.
576 */
577struct mount *
578getmnt(maddr)
579 struct mount *maddr;
580{
581 static struct mtab {
582 struct mtab *next;
583 struct mount *maddr;
584 struct mount mount;
585 } *mhead = NULL;
586 struct mtab *mt;
587
588 for (mt = mhead; mt != NULL; mt = mt->next)
589 if (maddr == mt->maddr)
590 return (&mt->mount);
591 if ((mt = malloc(sizeof(struct mtab))) == NULL)
592 errx(1, "malloc");
593 KGETRET(maddr, &mt->mount, sizeof(struct mount), "mount table");
594 mt->maddr = maddr;
595 mt->next = mhead;
596 mhead = mt;
597 return (&mt->mount);
598}
599
600void
601mount_print(mp)
602 struct mount *mp;
603{
604 int flags;
605 const char *type;
606
607#define ST mp->mnt_stat
608 (void)printf("*** MOUNT %s %s on %s", ST.f_fstypename,
609 ST.f_mntfromname, ST.f_mntonname);
610 if ((flags = mp->mnt_flag)) {
611 int i;
612 const char *sep = " (";
613
614 for (i = 0; mnt_flags[i].m_flag; i++) {
615 if (flags & mnt_flags[i].m_flag) {
616 (void)printf("%s%s", sep, mnt_flags[i].m_name);
617 flags &= ~mnt_flags[i].m_flag;
618 sep = ",";
619 }
620 }
621 if (flags)
622 (void)printf("%sunknown_flags:%x", sep, flags);
623 (void)printf(")");
624 }
625 (void)printf("\n");
626#undef ST
627}
628
629struct e_vnode *
630loadvnodes(avnodes)
631 int *avnodes;
632{
633 int mib[2];
634 size_t copysize;
635 struct e_vnode *vnodebase;
636
637 if (memf != NULL) {
638 /*
639 * do it by hand
640 */
641 return (kinfo_vnodes(avnodes));
642 }
643 mib[0] = CTL_KERN;
644 mib[1] = KERN_VNODE;
645 if (sysctl(mib, 2, NULL, &copysize, NULL, 0) == -1)
646 err(1, "sysctl: KERN_VNODE");
647 if ((vnodebase = malloc(copysize)) == NULL)
648 errx(1, "malloc");
649 if (sysctl(mib, 2, vnodebase, &copysize, NULL, 0) == -1)
650 err(1, "sysctl: KERN_VNODE");
651 if (copysize % sizeof(struct e_vnode))
652 errx(1, "vnode size mismatch");
653 *avnodes = copysize / sizeof(struct e_vnode);
654
655 return (vnodebase);
656}
657
658/*
659 * simulate what a running kernel does in in kinfo_vnode
660 */
661struct e_vnode *
662kinfo_vnodes(avnodes)
663 int *avnodes;
664{
665 struct mntlist mountlist;
666 struct mount *mp, mount, *mp_next;
667 struct vnode *vp, vnode, *vp_next;
668 char *vbuf, *evbuf, *bp;
669 int num, numvnodes;
670
671#define VPTRSZ sizeof(struct vnode *)
672#define VNODESZ sizeof(struct vnode)
673
674 KGET(V_NUMV, numvnodes);
675 if ((vbuf = malloc((numvnodes + 20) * (VPTRSZ + VNODESZ))) == NULL)
676 errx(1, "malloc");
677 bp = vbuf;
678 evbuf = vbuf + (numvnodes + 20) * (VPTRSZ + VNODESZ);
679 KGET(V_MOUNTLIST, mountlist);
680 for (num = 0, mp = mountlist.cqh_first; ; mp = mp_next) {
680 for (num = 0, mp = TAILQ_FIRST(&mountlist); ; mp = mp_next) {
681 KGET2(mp, &mount, sizeof(mount), "mount entry");
681 KGET2(mp, &mount, sizeof(mount), "mount entry");
682 mp_next = mount.mnt_list.cqe_next;
682 mp_next = TAILQ_NEXT(&mount, mnt_list);
683 for (vp = mount.mnt_vnodelist.lh_first;
684 vp != NULL; vp = vp_next) {
685 KGET2(vp, &vnode, sizeof(vnode), "vnode");
686 vp_next = vnode.v_mntvnodes.le_next;
687 if ((bp + VPTRSZ + VNODESZ) > evbuf)
688 /* XXX - should realloc */
689 errx(1, "no more room for vnodes");
690 memmove(bp, &vp, VPTRSZ);
691 bp += VPTRSZ;
692 memmove(bp, &vnode, VNODESZ);
693 bp += VNODESZ;
694 num++;
695 }
683 for (vp = mount.mnt_vnodelist.lh_first;
684 vp != NULL; vp = vp_next) {
685 KGET2(vp, &vnode, sizeof(vnode), "vnode");
686 vp_next = vnode.v_mntvnodes.le_next;
687 if ((bp + VPTRSZ + VNODESZ) > evbuf)
688 /* XXX - should realloc */
689 errx(1, "no more room for vnodes");
690 memmove(bp, &vp, VPTRSZ);
691 bp += VPTRSZ;
692 memmove(bp, &vnode, VNODESZ);
693 bp += VNODESZ;
694 num++;
695 }
696 if (mp == mountlist.cqh_last)
696 if (mp == TAILQ_LAST(&mountlist, mntlist))
697 break;
698 }
699 *avnodes = num;
700 return ((struct e_vnode *)vbuf);
701}
702
703char hdr[] =
704" LINE RAW CAN OUT IHIWT ILOWT OHWT LWT COL STATE SESS PGID DISC\n";
705int ttyspace = 128;
706
707void
708ttymode()
709{
710 struct tty *tty;
711 struct tty ttyb[1000];
712 int error, len, i;
713
714 (void)printf(hdr);
715 len = sizeof(ttyb);
716 error = sysctlbyname("kern.ttys", &ttyb, &len, 0, 0);
717 if (!error) {
718 len /= sizeof(ttyb[0]);
719 for (i = 0; i < len; i++) {
720 ttyprt(&ttyb[i], 0);
721 }
722 }
723 if ((tty = malloc(ttyspace * sizeof(*tty))) == NULL)
724 errx(1, "malloc");
725 if (nl[SCONS].n_type != 0) {
726 (void)printf("1 console\n");
727 KGET(SCONS, *tty);
728 ttyprt(&tty[0], 0);
729 }
730#ifdef __FreeBSD__
731 if (nl[NSCCONS].n_type != 0)
732 ttytype(tty, "vty", SCCONS, NSCCONS, 0);
733 if (nl[NSIO].n_type != 0)
734 ttytype(tty, "sio", SIO, NSIO, 0);
735 if (nl[NRC].n_type != 0)
736 ttytype(tty, "rc", RC, NRC, 0);
737 if (nl[NCY].n_type != 0)
738 ttytype(tty, "cy", CY, NCY, 0);
739 if (nl[NSI].n_type != 0)
740 ttytype(tty, "si", SI, NSI, 1);
741#endif
742 if (nl[SNPTY].n_type != 0)
743 ttytype(tty, "pty", SPTY, SNPTY, 0);
744}
745
746void
747ttytype(tty, name, type, number, indir)
748 struct tty *tty;
749 char *name;
750 int type, number, indir;
751{
752 struct tty *tp;
753 int ntty;
754 struct tty **ttyaddr;
755
756 if (tty == NULL)
757 return;
758 KGET(number, ntty);
759 (void)printf("%d %s %s\n", ntty, name, (ntty == 1) ? "line" : "lines");
760 if (ntty > ttyspace) {
761 ttyspace = ntty;
762 if ((tty = realloc(tty, ttyspace * sizeof(*tty))) == 0)
763 errx(1, "realloc");
764 }
765 if (indir) {
766 KGET(type, ttyaddr);
767 KGET2(ttyaddr, tty, ntty * sizeof(struct tty), "tty structs");
768 } else {
769 KGET1(type, tty, ntty * sizeof(struct tty), "tty structs");
770 }
771 (void)printf(hdr);
772 for (tp = tty; tp < &tty[ntty]; tp++)
773 ttyprt(tp, tp - tty);
774}
775
776struct {
777 int flag;
778 char val;
779} ttystates[] = {
780#ifdef TS_WOPEN
781 { TS_WOPEN, 'W'},
782#endif
783 { TS_ISOPEN, 'O'},
784 { TS_CARR_ON, 'C'},
785#ifdef TS_CONNECTED
786 { TS_CONNECTED, 'c'},
787#endif
788 { TS_TIMEOUT, 'T'},
789 { TS_FLUSH, 'F'},
790 { TS_BUSY, 'B'},
791#ifdef TS_ASLEEP
792 { TS_ASLEEP, 'A'},
793#endif
794#ifdef TS_SO_OLOWAT
795 { TS_SO_OLOWAT, 'A'},
796#endif
797#ifdef TS_SO_OCOMPLETE
798 { TS_SO_OCOMPLETE, 'a'},
799#endif
800 { TS_XCLUDE, 'X'},
801 { TS_TTSTOP, 'S'},
802#ifdef TS_CAR_OFLOW
803 { TS_CAR_OFLOW, 'm'},
804#endif
805#ifdef TS_CTS_OFLOW
806 { TS_CTS_OFLOW, 'o'},
807#endif
808#ifdef TS_DSR_OFLOW
809 { TS_DSR_OFLOW, 'd'},
810#endif
811 { TS_TBLOCK, 'K'},
812 { TS_ASYNC, 'Y'},
813 { TS_BKSL, 'D'},
814 { TS_ERASE, 'E'},
815 { TS_LNCH, 'L'},
816 { TS_TYPEN, 'P'},
817 { TS_CNTTB, 'N'},
818#ifdef TS_CAN_BYPASS_L_RINT
819 { TS_CAN_BYPASS_L_RINT, 'l'},
820#endif
821#ifdef TS_SNOOP
822 { TS_SNOOP, 's'},
823#endif
824#ifdef TS_ZOMBIE
825 { TS_ZOMBIE, 'Z'},
826#endif
827 { 0, '\0'},
828};
829
830void
831ttyprt(tp, line)
832 struct tty *tp;
833 int line;
834{
835 int i, j;
836 pid_t pgid;
837 char *name, state[20];
838
839 if (usenumflag || tp->t_dev == 0 ||
840 (name = devname(tp->t_dev, S_IFCHR)) == NULL)
841 (void)printf("%7d ", line);
842 else
843 (void)printf("%7s ", name);
844 (void)printf("%2d %3d ", tp->t_rawq.c_cc, tp->t_canq.c_cc);
845 (void)printf("%3d %5d %5d %4d %3d %7d ", tp->t_outq.c_cc,
846 tp->t_ihiwat, tp->t_ilowat, tp->t_ohiwat, tp->t_olowat,
847 tp->t_column);
848 for (i = j = 0; ttystates[i].flag; i++)
849 if (tp->t_state&ttystates[i].flag)
850 state[j++] = ttystates[i].val;
851 if (j == 0)
852 state[j++] = '-';
853 state[j] = '\0';
854 (void)printf("%-6s %8lx", state, (u_long)(void *)tp->t_session);
855 pgid = 0;
856 if (tp->t_pgrp != NULL)
857 KGET2(&tp->t_pgrp->pg_id, &pgid, sizeof(pid_t), "pgid");
858 (void)printf("%6d ", pgid);
859 switch (tp->t_line) {
860 case TTYDISC:
861 (void)printf("term\n");
862 break;
863 case NTTYDISC:
864 (void)printf("ntty\n");
865 break;
866 case TABLDISC:
867 (void)printf("tab\n");
868 break;
869 case SLIPDISC:
870 (void)printf("slip\n");
871 break;
872 case PPPDISC:
873 (void)printf("ppp\n");
874 break;
875 default:
876 (void)printf("%d\n", tp->t_line);
877 break;
878 }
879}
880
881void
882filemode()
883{
884 struct file *fp;
885 struct file *addr;
886 char *buf, flagbuf[16], *fbp;
887 int len, maxfile, nfile;
888 static char *dtypes[] = { "???", "inode", "socket" };
889
890 KGET(FNL_MAXFILE, maxfile);
891 if (totalflag) {
892 KGET(FNL_NFILE, nfile);
893 (void)printf("%3d/%3d files\n", nfile, maxfile);
894 return;
895 }
896 if (getfiles(&buf, &len) == -1)
897 return;
898 /*
899 * Getfiles returns in malloc'd memory a pointer to the first file
900 * structure, and then an array of file structs (whose addresses are
901 * derivable from the previous entry).
902 */
903 addr = ((struct filelist *)buf)->lh_first;
904 fp = (struct file *)(buf + sizeof(struct filelist));
905 nfile = (len - sizeof(struct filelist)) / sizeof(struct file);
906
907 (void)printf("%d/%d open files\n", nfile, maxfile);
908 (void)printf(" LOC TYPE FLG CNT MSG DATA OFFSET\n");
909 for (; (char *)fp < buf + len; addr = fp->f_list.le_next, fp++) {
910 if ((unsigned)fp->f_type > DTYPE_SOCKET)
911 continue;
912 (void)printf("%8lx ", (u_long)(void *)addr);
913 (void)printf("%-8.8s", dtypes[fp->f_type]);
914 fbp = flagbuf;
915 if (fp->f_flag & FREAD)
916 *fbp++ = 'R';
917 if (fp->f_flag & FWRITE)
918 *fbp++ = 'W';
919 if (fp->f_flag & FAPPEND)
920 *fbp++ = 'A';
921#ifdef FSHLOCK /* currently gone */
922 if (fp->f_flag & FSHLOCK)
923 *fbp++ = 'S';
924 if (fp->f_flag & FEXLOCK)
925 *fbp++ = 'X';
926#endif
927 if (fp->f_flag & FASYNC)
928 *fbp++ = 'I';
929 *fbp = '\0';
930 (void)printf("%6s %3d", flagbuf, fp->f_count);
931 (void)printf(" %3d", fp->f_msgcount);
932 (void)printf(" %8lx", (u_long)(void *)fp->f_data);
933 if (fp->f_offset < 0)
934 (void)printf(" %qx\n", fp->f_offset);
935 else
936 (void)printf(" %qd\n", fp->f_offset);
937 }
938 free(buf);
939}
940
941int
942getfiles(abuf, alen)
943 char **abuf;
944 int *alen;
945{
946 size_t len;
947 int mib[2];
948 char *buf;
949
950 /*
951 * XXX
952 * Add emulation of KINFO_FILE here.
953 */
954 if (memf != NULL)
955 errx(1, "files on dead kernel, not implemented");
956
957 mib[0] = CTL_KERN;
958 mib[1] = KERN_FILE;
959 if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1) {
960 warn("sysctl: KERN_FILE");
961 return (-1);
962 }
963 if ((buf = malloc(len)) == NULL)
964 errx(1, "malloc");
965 if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) {
966 warn("sysctl: KERN_FILE");
967 return (-1);
968 }
969 *abuf = buf;
970 *alen = len;
971 return (0);
972}
973
974/*
975 * swapmode is based on a program called swapinfo written
976 * by Kevin Lahey <kml@rokkaku.atl.ga.us>.
977 */
978void
979swapmode(void)
980{
981 struct kvm_swap kswap[16];
982 int i;
983 int n;
984 int pagesize = getpagesize();
985 const char *header;
986 int hlen;
987 long blocksize;
988
989 n = kvm_getswapinfo(
990 kd,
991 kswap,
992 sizeof(kswap)/sizeof(kswap[0]),
993 ((swapflag > 1) ? SWIF_DUMP_TREE : 0) | SWIF_DEV_PREFIX
994 );
995
996#define CONVERT(v) ((int)((quad_t)(v) * pagesize / blocksize))
997
998 header = getbsize(&hlen, &blocksize);
999 if (totalflag == 0) {
1000 (void)printf("%-11s %*s %8s %8s %8s %s\n",
1001 "Device", hlen, header,
1002 "Used", "Avail", "Capacity", "Type");
1003
1004 for (i = 0; i < n; ++i) {
1005 (void)printf(
1006 "%-11s %*d ",
1007 kswap[i].ksw_devname,
1008 hlen,
1009 CONVERT(kswap[i].ksw_total)
1010 );
1011 (void)printf(
1012 "%8d %8d %5.0f%% %s\n",
1013 CONVERT(kswap[i].ksw_used),
1014 CONVERT(kswap[i].ksw_total - kswap[i].ksw_used),
1015 (double)kswap[i].ksw_used * 100.0 /
1016 (double)kswap[i].ksw_total,
1017 (kswap[i].ksw_flags & SW_SEQUENTIAL) ?
1018 "Sequential" : "Interleaved"
1019 );
1020 }
1021 }
1022
1023 if (totalflag) {
1024 blocksize = 1024 * 1024;
1025
1026 (void)printf(
1027 "%dM/%dM swap space\n",
1028 CONVERT(kswap[n].ksw_used),
1029 CONVERT(kswap[n].ksw_total)
1030 );
1031 } else if (n > 1) {
1032 (void)printf(
1033 "%-11s %*d %8d %8d %5.0f%%\n",
1034 "Total",
1035 hlen,
1036 CONVERT(kswap[n].ksw_total),
1037 CONVERT(kswap[n].ksw_used),
1038 CONVERT(kswap[n].ksw_total - kswap[n].ksw_used),
1039 (double)kswap[n].ksw_used * 100.0 /
1040 (double)kswap[n].ksw_total
1041 );
1042 }
1043}
697 break;
698 }
699 *avnodes = num;
700 return ((struct e_vnode *)vbuf);
701}
702
703char hdr[] =
704" LINE RAW CAN OUT IHIWT ILOWT OHWT LWT COL STATE SESS PGID DISC\n";
705int ttyspace = 128;
706
707void
708ttymode()
709{
710 struct tty *tty;
711 struct tty ttyb[1000];
712 int error, len, i;
713
714 (void)printf(hdr);
715 len = sizeof(ttyb);
716 error = sysctlbyname("kern.ttys", &ttyb, &len, 0, 0);
717 if (!error) {
718 len /= sizeof(ttyb[0]);
719 for (i = 0; i < len; i++) {
720 ttyprt(&ttyb[i], 0);
721 }
722 }
723 if ((tty = malloc(ttyspace * sizeof(*tty))) == NULL)
724 errx(1, "malloc");
725 if (nl[SCONS].n_type != 0) {
726 (void)printf("1 console\n");
727 KGET(SCONS, *tty);
728 ttyprt(&tty[0], 0);
729 }
730#ifdef __FreeBSD__
731 if (nl[NSCCONS].n_type != 0)
732 ttytype(tty, "vty", SCCONS, NSCCONS, 0);
733 if (nl[NSIO].n_type != 0)
734 ttytype(tty, "sio", SIO, NSIO, 0);
735 if (nl[NRC].n_type != 0)
736 ttytype(tty, "rc", RC, NRC, 0);
737 if (nl[NCY].n_type != 0)
738 ttytype(tty, "cy", CY, NCY, 0);
739 if (nl[NSI].n_type != 0)
740 ttytype(tty, "si", SI, NSI, 1);
741#endif
742 if (nl[SNPTY].n_type != 0)
743 ttytype(tty, "pty", SPTY, SNPTY, 0);
744}
745
746void
747ttytype(tty, name, type, number, indir)
748 struct tty *tty;
749 char *name;
750 int type, number, indir;
751{
752 struct tty *tp;
753 int ntty;
754 struct tty **ttyaddr;
755
756 if (tty == NULL)
757 return;
758 KGET(number, ntty);
759 (void)printf("%d %s %s\n", ntty, name, (ntty == 1) ? "line" : "lines");
760 if (ntty > ttyspace) {
761 ttyspace = ntty;
762 if ((tty = realloc(tty, ttyspace * sizeof(*tty))) == 0)
763 errx(1, "realloc");
764 }
765 if (indir) {
766 KGET(type, ttyaddr);
767 KGET2(ttyaddr, tty, ntty * sizeof(struct tty), "tty structs");
768 } else {
769 KGET1(type, tty, ntty * sizeof(struct tty), "tty structs");
770 }
771 (void)printf(hdr);
772 for (tp = tty; tp < &tty[ntty]; tp++)
773 ttyprt(tp, tp - tty);
774}
775
776struct {
777 int flag;
778 char val;
779} ttystates[] = {
780#ifdef TS_WOPEN
781 { TS_WOPEN, 'W'},
782#endif
783 { TS_ISOPEN, 'O'},
784 { TS_CARR_ON, 'C'},
785#ifdef TS_CONNECTED
786 { TS_CONNECTED, 'c'},
787#endif
788 { TS_TIMEOUT, 'T'},
789 { TS_FLUSH, 'F'},
790 { TS_BUSY, 'B'},
791#ifdef TS_ASLEEP
792 { TS_ASLEEP, 'A'},
793#endif
794#ifdef TS_SO_OLOWAT
795 { TS_SO_OLOWAT, 'A'},
796#endif
797#ifdef TS_SO_OCOMPLETE
798 { TS_SO_OCOMPLETE, 'a'},
799#endif
800 { TS_XCLUDE, 'X'},
801 { TS_TTSTOP, 'S'},
802#ifdef TS_CAR_OFLOW
803 { TS_CAR_OFLOW, 'm'},
804#endif
805#ifdef TS_CTS_OFLOW
806 { TS_CTS_OFLOW, 'o'},
807#endif
808#ifdef TS_DSR_OFLOW
809 { TS_DSR_OFLOW, 'd'},
810#endif
811 { TS_TBLOCK, 'K'},
812 { TS_ASYNC, 'Y'},
813 { TS_BKSL, 'D'},
814 { TS_ERASE, 'E'},
815 { TS_LNCH, 'L'},
816 { TS_TYPEN, 'P'},
817 { TS_CNTTB, 'N'},
818#ifdef TS_CAN_BYPASS_L_RINT
819 { TS_CAN_BYPASS_L_RINT, 'l'},
820#endif
821#ifdef TS_SNOOP
822 { TS_SNOOP, 's'},
823#endif
824#ifdef TS_ZOMBIE
825 { TS_ZOMBIE, 'Z'},
826#endif
827 { 0, '\0'},
828};
829
830void
831ttyprt(tp, line)
832 struct tty *tp;
833 int line;
834{
835 int i, j;
836 pid_t pgid;
837 char *name, state[20];
838
839 if (usenumflag || tp->t_dev == 0 ||
840 (name = devname(tp->t_dev, S_IFCHR)) == NULL)
841 (void)printf("%7d ", line);
842 else
843 (void)printf("%7s ", name);
844 (void)printf("%2d %3d ", tp->t_rawq.c_cc, tp->t_canq.c_cc);
845 (void)printf("%3d %5d %5d %4d %3d %7d ", tp->t_outq.c_cc,
846 tp->t_ihiwat, tp->t_ilowat, tp->t_ohiwat, tp->t_olowat,
847 tp->t_column);
848 for (i = j = 0; ttystates[i].flag; i++)
849 if (tp->t_state&ttystates[i].flag)
850 state[j++] = ttystates[i].val;
851 if (j == 0)
852 state[j++] = '-';
853 state[j] = '\0';
854 (void)printf("%-6s %8lx", state, (u_long)(void *)tp->t_session);
855 pgid = 0;
856 if (tp->t_pgrp != NULL)
857 KGET2(&tp->t_pgrp->pg_id, &pgid, sizeof(pid_t), "pgid");
858 (void)printf("%6d ", pgid);
859 switch (tp->t_line) {
860 case TTYDISC:
861 (void)printf("term\n");
862 break;
863 case NTTYDISC:
864 (void)printf("ntty\n");
865 break;
866 case TABLDISC:
867 (void)printf("tab\n");
868 break;
869 case SLIPDISC:
870 (void)printf("slip\n");
871 break;
872 case PPPDISC:
873 (void)printf("ppp\n");
874 break;
875 default:
876 (void)printf("%d\n", tp->t_line);
877 break;
878 }
879}
880
881void
882filemode()
883{
884 struct file *fp;
885 struct file *addr;
886 char *buf, flagbuf[16], *fbp;
887 int len, maxfile, nfile;
888 static char *dtypes[] = { "???", "inode", "socket" };
889
890 KGET(FNL_MAXFILE, maxfile);
891 if (totalflag) {
892 KGET(FNL_NFILE, nfile);
893 (void)printf("%3d/%3d files\n", nfile, maxfile);
894 return;
895 }
896 if (getfiles(&buf, &len) == -1)
897 return;
898 /*
899 * Getfiles returns in malloc'd memory a pointer to the first file
900 * structure, and then an array of file structs (whose addresses are
901 * derivable from the previous entry).
902 */
903 addr = ((struct filelist *)buf)->lh_first;
904 fp = (struct file *)(buf + sizeof(struct filelist));
905 nfile = (len - sizeof(struct filelist)) / sizeof(struct file);
906
907 (void)printf("%d/%d open files\n", nfile, maxfile);
908 (void)printf(" LOC TYPE FLG CNT MSG DATA OFFSET\n");
909 for (; (char *)fp < buf + len; addr = fp->f_list.le_next, fp++) {
910 if ((unsigned)fp->f_type > DTYPE_SOCKET)
911 continue;
912 (void)printf("%8lx ", (u_long)(void *)addr);
913 (void)printf("%-8.8s", dtypes[fp->f_type]);
914 fbp = flagbuf;
915 if (fp->f_flag & FREAD)
916 *fbp++ = 'R';
917 if (fp->f_flag & FWRITE)
918 *fbp++ = 'W';
919 if (fp->f_flag & FAPPEND)
920 *fbp++ = 'A';
921#ifdef FSHLOCK /* currently gone */
922 if (fp->f_flag & FSHLOCK)
923 *fbp++ = 'S';
924 if (fp->f_flag & FEXLOCK)
925 *fbp++ = 'X';
926#endif
927 if (fp->f_flag & FASYNC)
928 *fbp++ = 'I';
929 *fbp = '\0';
930 (void)printf("%6s %3d", flagbuf, fp->f_count);
931 (void)printf(" %3d", fp->f_msgcount);
932 (void)printf(" %8lx", (u_long)(void *)fp->f_data);
933 if (fp->f_offset < 0)
934 (void)printf(" %qx\n", fp->f_offset);
935 else
936 (void)printf(" %qd\n", fp->f_offset);
937 }
938 free(buf);
939}
940
941int
942getfiles(abuf, alen)
943 char **abuf;
944 int *alen;
945{
946 size_t len;
947 int mib[2];
948 char *buf;
949
950 /*
951 * XXX
952 * Add emulation of KINFO_FILE here.
953 */
954 if (memf != NULL)
955 errx(1, "files on dead kernel, not implemented");
956
957 mib[0] = CTL_KERN;
958 mib[1] = KERN_FILE;
959 if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1) {
960 warn("sysctl: KERN_FILE");
961 return (-1);
962 }
963 if ((buf = malloc(len)) == NULL)
964 errx(1, "malloc");
965 if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) {
966 warn("sysctl: KERN_FILE");
967 return (-1);
968 }
969 *abuf = buf;
970 *alen = len;
971 return (0);
972}
973
974/*
975 * swapmode is based on a program called swapinfo written
976 * by Kevin Lahey <kml@rokkaku.atl.ga.us>.
977 */
978void
979swapmode(void)
980{
981 struct kvm_swap kswap[16];
982 int i;
983 int n;
984 int pagesize = getpagesize();
985 const char *header;
986 int hlen;
987 long blocksize;
988
989 n = kvm_getswapinfo(
990 kd,
991 kswap,
992 sizeof(kswap)/sizeof(kswap[0]),
993 ((swapflag > 1) ? SWIF_DUMP_TREE : 0) | SWIF_DEV_PREFIX
994 );
995
996#define CONVERT(v) ((int)((quad_t)(v) * pagesize / blocksize))
997
998 header = getbsize(&hlen, &blocksize);
999 if (totalflag == 0) {
1000 (void)printf("%-11s %*s %8s %8s %8s %s\n",
1001 "Device", hlen, header,
1002 "Used", "Avail", "Capacity", "Type");
1003
1004 for (i = 0; i < n; ++i) {
1005 (void)printf(
1006 "%-11s %*d ",
1007 kswap[i].ksw_devname,
1008 hlen,
1009 CONVERT(kswap[i].ksw_total)
1010 );
1011 (void)printf(
1012 "%8d %8d %5.0f%% %s\n",
1013 CONVERT(kswap[i].ksw_used),
1014 CONVERT(kswap[i].ksw_total - kswap[i].ksw_used),
1015 (double)kswap[i].ksw_used * 100.0 /
1016 (double)kswap[i].ksw_total,
1017 (kswap[i].ksw_flags & SW_SEQUENTIAL) ?
1018 "Sequential" : "Interleaved"
1019 );
1020 }
1021 }
1022
1023 if (totalflag) {
1024 blocksize = 1024 * 1024;
1025
1026 (void)printf(
1027 "%dM/%dM swap space\n",
1028 CONVERT(kswap[n].ksw_used),
1029 CONVERT(kswap[n].ksw_total)
1030 );
1031 } else if (n > 1) {
1032 (void)printf(
1033 "%-11s %*d %8d %8d %5.0f%%\n",
1034 "Total",
1035 hlen,
1036 CONVERT(kswap[n].ksw_total),
1037 CONVERT(kswap[n].ksw_used),
1038 CONVERT(kswap[n].ksw_total - kswap[n].ksw_used),
1039 (double)kswap[n].ksw_used * 100.0 /
1040 (double)kswap[n].ksw_total
1041 );
1042 }
1043}