pstat.c revision 1.107 1 /* $NetBSD: pstat.c,v 1.107 2008/02/11 15:22:43 ad Exp $ */
2
3 /*-
4 * Copyright (c) 1980, 1991, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __COPYRIGHT("@(#) Copyright (c) 1980, 1991, 1993, 1994\n\
35 The Regents of the University of California. All rights reserved.\n");
36 #endif /* not lint */
37
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "@(#)pstat.c 8.16 (Berkeley) 5/9/95";
41 #else
42 __RCSID("$NetBSD: pstat.c,v 1.107 2008/02/11 15:22:43 ad Exp $");
43 #endif
44 #endif /* not lint */
45
46 #include <sys/param.h>
47 #include <sys/time.h>
48 #include <sys/vnode.h>
49 #include <sys/ucred.h>
50 #include <stdbool.h>
51 #define _KERNEL
52 #include <sys/file.h>
53 #include <ufs/ufs/inode.h>
54 #define NFS
55 #include <sys/mount.h>
56 #undef NFS
57 #include <sys/uio.h>
58 #include <miscfs/genfs/layer.h>
59 #undef _KERNEL
60 #include <sys/stat.h>
61 #include <nfs/nfsproto.h>
62 #include <nfs/rpcv2.h>
63 #include <nfs/nfs.h>
64 #include <nfs/nfsnode.h>
65 #include <sys/ioctl.h>
66 #include <sys/tty.h>
67 #include <sys/conf.h>
68 #include <sys/device.h>
69
70 #include <sys/sysctl.h>
71
72 #include <err.h>
73 #include <kvm.h>
74 #include <limits.h>
75 #include <nlist.h>
76 #include <stdio.h>
77 #include <stdlib.h>
78 #include <string.h>
79 #include <unistd.h>
80
81 #include "swapctl.h"
82
83 struct nlist nl[] = {
84 #define V_MOUNTLIST 0
85 { "_mountlist" }, /* address of head of mount list. */
86 #define V_NUMV 1
87 { "_numvnodes" },
88 #define FNL_NFILE 2
89 { "_nfiles" },
90 #define FNL_MAXFILE 3
91 { "_maxfiles" },
92 #define TTY_NTTY 4
93 { "_tty_count" },
94 #define TTY_TTYLIST 5
95 { "_ttylist" },
96 #define NLMANDATORY TTY_TTYLIST /* names up to here are mandatory */
97 { "" }
98 };
99
100 int usenumflag;
101 int totalflag;
102 int kflag;
103 int hflag;
104 char *nlistf = NULL;
105 char *memf = NULL;
106 kvm_t *kd;
107
108 static const char * const dtypes[] = { DTYPE_NAMES };
109
110
111 static const struct {
112 u_int m_flag;
113 u_int m_visible;
114 const char *m_name;
115 } mnt_flags[] = {
116 __MNT_FLAGS
117 };
118
119 struct flagbit_desc {
120 u_int fd_flags;
121 char fd_mark;
122 };
123
124 #define SVAR(var) __STRING(var) /* to force expansion */
125 #define KGET(idx, var) \
126 KGET1(idx, &var, sizeof(var), SVAR(var))
127 #define KGET1(idx, p, s, msg) \
128 KGET2(nl[idx].n_value, p, s, msg)
129 #define KGET2(addr, p, s, msg) do { \
130 if (kvm_read(kd, (u_long)(addr), p, s) != s) \
131 warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \
132 } while (/* CONSTCOND */0)
133 #define KGETRET(addr, p, s, msg) do { \
134 if (kvm_read(kd, (u_long)(addr), p, s) != s) { \
135 warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \
136 return (0); \
137 } \
138 } while (/* CONSTCOND */0)
139
140 #if 1 /* This is copied from vmstat/vmstat.c */
141 /*
142 * Print single word. `ovflow' is number of characters didn't fit
143 * on the last word. `fmt' is a format string to print this word.
144 * It must contain asterisk for field width. `width' is a width
145 * occupied by this word. `fixed' is a number of constant chars in
146 * `fmt'. `val' is a value to be printed using format string `fmt'.
147 */
148 #define PRWORD(ovflw, fmt, width, fixed, val) do { \
149 (ovflw) += printf((fmt), \
150 (width) - (fixed) - (ovflw) > 0 ? \
151 (width) - (fixed) - (ovflw) : 0, \
152 (val)) - (width); \
153 if ((ovflw) < 0) \
154 (ovflw) = 0; \
155 } while (/* CONSTCOND */0)
156 #endif
157
158 void filemode(void);
159 int getfiles(char **, int *, char **);
160 int getflags(const struct flagbit_desc *, char *, u_int);
161 struct mount *
162 getmnt(struct mount *);
163 char * kinfo_vnodes(int *);
164 void layer_header(void);
165 int layer_print(struct vnode *, int);
166 char * loadvnodes(int *);
167 int main(int, char **);
168 void mount_print(struct mount *);
169 void nfs_header(void);
170 int nfs_print(struct vnode *, int);
171 void ttymode(void);
172 void ttyprt(struct tty *);
173 void ufs_header(void);
174 int ufs_print(struct vnode *, int);
175 int ext2fs_print(struct vnode *, int);
176 void usage(void);
177 void vnode_header(void);
178 int vnode_print(struct vnode *, struct vnode *);
179 void vnodemode(void);
180
181 int
182 main(int argc, char *argv[])
183 {
184 int ch, i, quit, ret, use_sysctl;
185 int fileflag, swapflag, ttyflag, vnodeflag;
186 gid_t egid = getegid();
187 char buf[_POSIX2_LINE_MAX];
188
189 setegid(getgid());
190 fileflag = swapflag = ttyflag = vnodeflag = 0;
191 while ((ch = getopt(argc, argv, "TM:N:fghikmnstv")) != -1)
192 switch (ch) {
193 case 'f':
194 fileflag = 1;
195 break;
196 case 'M':
197 memf = optarg;
198 break;
199 case 'N':
200 nlistf = optarg;
201 break;
202 case 'n':
203 usenumflag = 1;
204 break;
205 case 's':
206 swapflag = 1;
207 break;
208 case 'T':
209 totalflag = 1;
210 break;
211 case 't':
212 ttyflag = 1;
213 break;
214 case 'k':
215 kflag = 1;
216 break;
217 case 'g':
218 kflag = 3; /* 1k ^ 3 */
219 break;
220 case 'h':
221 hflag = 1;
222 break;
223 case 'm':
224 kflag = 2; /* 1k ^ 2 */
225 break;
226 case 'v':
227 case 'i': /* Backward compatibility. */
228 vnodeflag = 1;
229 break;
230 default:
231 usage();
232 }
233 argc -= optind;
234 argv += optind;
235
236 /*
237 * Discard setgid privileges. If not the running kernel, we toss
238 * them away totally so that bad guys can't print interesting stuff
239 * from kernel memory, otherwise switch back to kmem for the
240 * duration of the kvm_openfiles() call.
241 */
242 if (nlistf != NULL || memf != NULL)
243 (void)setgid(getgid());
244 else
245 (void)setegid(egid);
246
247 use_sysctl = (nlistf == NULL && memf == NULL);
248
249 if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == 0)
250 errx(1, "kvm_openfiles: %s", buf);
251
252 /* get rid of it now anyway */
253 if (nlistf == NULL && memf == NULL)
254 (void)setgid(getgid());
255 if ((ret = kvm_nlist(kd, nl)) != 0) {
256 if (ret == -1)
257 errx(1, "kvm_nlist: %s", kvm_geterr(kd));
258 for (i = quit = 0; i <= NLMANDATORY; i++)
259 if (!nl[i].n_value) {
260 quit = 1;
261 warnx("undefined symbol: %s", nl[i].n_name);
262 }
263 if (quit)
264 exit(1);
265 }
266 if (!(fileflag | vnodeflag | ttyflag | swapflag | totalflag))
267 usage();
268 if (fileflag || totalflag)
269 filemode();
270 if (vnodeflag || totalflag)
271 vnodemode();
272 if (ttyflag)
273 ttymode();
274 if (swapflag || totalflag)
275 if (use_sysctl)
276 list_swap(0, kflag, 0, totalflag, 1, hflag);
277 exit(0);
278 }
279
280 #define VPTRSZ sizeof(struct vnode *)
281 #define VNODESZ sizeof(struct vnode)
282 #define PTRSTRWIDTH ((int)sizeof(void *) * 2) /* Width of resulting string
283 when pointer is printed
284 in hexadecimal. */
285
286 void
287 vnodemode(void)
288 {
289 char *e_vnodebase, *endvnode, *evp;
290 struct vnode *vp;
291 struct mount *maddr, *mp;
292 int numvnodes, ovflw;
293 int (*vnode_fsprint) (struct vnode *, int); /* per-fs data printer */
294
295 mp = NULL;
296 e_vnodebase = loadvnodes(&numvnodes);
297 if (totalflag) {
298 (void)printf("%7d vnodes\n", numvnodes);
299 goto out;
300 }
301 endvnode = e_vnodebase + numvnodes * (VPTRSZ + VNODESZ);
302 (void)printf("%d active vnodes\n", numvnodes);
303
304 #define ST mp->mnt_stat
305 #define FSTYPE_IS(mp, name) \
306 (strncmp((mp)->mnt_stat.f_fstypename, (name), \
307 sizeof((mp)->mnt_stat.f_fstypename)) == 0)
308 maddr = NULL;
309 vnode_fsprint = NULL;
310 for (evp = e_vnodebase; evp < endvnode; evp += VPTRSZ + VNODESZ) {
311 vp = (struct vnode *)(evp + VPTRSZ);
312 if (vp->v_mount != maddr) {
313 /*
314 * New filesystem
315 */
316 if ((mp = getmnt(vp->v_mount)) == NULL)
317 continue;
318 maddr = vp->v_mount;
319 mount_print(mp);
320 vnode_header();
321 if (FSTYPE_IS(mp, MOUNT_FFS) ||
322 FSTYPE_IS(mp, MOUNT_MFS)) {
323 ufs_header();
324 vnode_fsprint = ufs_print;
325 } else if (FSTYPE_IS(mp, MOUNT_NFS)) {
326 nfs_header();
327 vnode_fsprint = nfs_print;
328 } else if (FSTYPE_IS(mp, MOUNT_EXT2FS)) {
329 ufs_header();
330 vnode_fsprint = ext2fs_print;
331 } else if (FSTYPE_IS(mp, MOUNT_NULL) ||
332 FSTYPE_IS(mp, MOUNT_OVERLAY) ||
333 FSTYPE_IS(mp, MOUNT_UMAP)) {
334 layer_header();
335 vnode_fsprint = layer_print;
336 } else
337 vnode_fsprint = NULL;
338 (void)printf("\n");
339 }
340 ovflw = vnode_print(*(struct vnode **)evp, vp);
341 if (VTOI(vp) != NULL && vnode_fsprint != NULL)
342 (*vnode_fsprint)(vp, ovflw);
343 (void)printf("\n");
344 }
345
346 out:
347 if (e_vnodebase)
348 free(e_vnodebase);
349 }
350
351 int
352 getflags(const struct flagbit_desc *fd, char *p, u_int flags)
353 {
354 char *q = p;
355
356 if (flags == 0) {
357 *p++ = '-';
358 *p = '\0';
359 return (0);
360 }
361
362 for (; fd->fd_flags != 0; fd++)
363 if ((flags & fd->fd_flags) != 0)
364 *p++ = fd->fd_mark;
365 *p = '\0';
366 return (p - q);
367 }
368
369 const struct flagbit_desc vnode_flags[] = {
370 { VV_ROOT, 'R' },
371 { VI_TEXT, 'T' },
372 { VV_SYSTEM, 'S' },
373 { VV_ISTTY, 'I' },
374 { VI_EXECMAP, 'E' },
375 { VI_XLOCK, 'L' },
376 { VU_DIROP, 'D' },
377 { VI_LAYER, 'Y' },
378 { VI_ONWORKLST, 'O' },
379 { 0, '\0' },
380 };
381
382 void
383 vnode_header(void)
384 {
385
386 (void)printf("%-*s TYP VFLAG USE HOLD TAG NPAGE",
387 PTRSTRWIDTH, "ADDR");
388 }
389
390 int
391 vnode_print(struct vnode *avnode, struct vnode *vp)
392 {
393 char *type, flags[sizeof(vnode_flags) / sizeof(vnode_flags[0])];
394 int ovflw;
395
396 /*
397 * set type
398 */
399 switch (vp->v_type) {
400 case VNON:
401 type = "non"; break;
402 case VREG:
403 type = "reg"; break;
404 case VDIR:
405 type = "dir"; break;
406 case VBLK:
407 type = "blk"; break;
408 case VCHR:
409 type = "chr"; break;
410 case VLNK:
411 type = "lnk"; break;
412 case VSOCK:
413 type = "soc"; break;
414 case VFIFO:
415 type = "fif"; break;
416 case VBAD:
417 type = "bad"; break;
418 default:
419 type = "unk"; break;
420 }
421 /*
422 * gather flags
423 */
424 (void)getflags(vnode_flags, flags,
425 vp->v_uflag | vp->v_iflag | vp->v_vflag);
426
427 ovflw = 0;
428 PRWORD(ovflw, "%*lx", PTRSTRWIDTH, 0, (long)avnode);
429 PRWORD(ovflw, " %*s", 4, 1, type);
430 PRWORD(ovflw, " %*s", 6, 1, flags);
431 PRWORD(ovflw, " %*ld", 5, 1, (long)vp->v_usecount);
432 PRWORD(ovflw, " %*ld", 5, 1, (long)vp->v_holdcnt);
433 PRWORD(ovflw, " %*d", 4, 1, vp->v_tag);
434 PRWORD(ovflw, " %*d", 6, 1, vp->v_uobj.uo_npages);
435 return (ovflw);
436 }
437
438 const struct flagbit_desc ufs_flags[] = {
439 { IN_ACCESS, 'A' },
440 { IN_CHANGE, 'C' },
441 { IN_UPDATE, 'U' },
442 { IN_MODIFIED, 'M' },
443 { IN_ACCESSED, 'a' },
444 { IN_RENAME, 'R' },
445 { IN_SHLOCK, 'S' },
446 { IN_EXLOCK, 'E' },
447 { IN_CLEANING, 'c' },
448 { IN_ADIROP, 'D' },
449 { IN_SPACECOUNTED, 's' },
450 { 0, '\0' },
451 };
452
453 void
454 ufs_header(void)
455 {
456
457 (void)printf(" FILEID IFLAG RDEV|SZ");
458 }
459
460 int
461 ufs_print(struct vnode *vp, int ovflw)
462 {
463 struct inode inode, *ip = &inode;
464 union dinode {
465 struct ufs1_dinode dp1;
466 struct ufs2_dinode dp2;
467 } dip;
468 char flags[sizeof(ufs_flags) / sizeof(ufs_flags[0])];
469 char dev[4 + 1 + 7 + 1]; /* 12bit marjor + 20bit minor */
470 char *name;
471 mode_t type;
472 dev_t rdev;
473
474 KGETRET(VTOI(vp), &inode, sizeof(struct inode), "vnode's inode");
475 KGETRET(ip->i_din.ffs1_din, &dip, sizeof (struct ufs1_dinode),
476 "inode's dinode");
477
478 if (ip->i_size == dip.dp1.di_size)
479 rdev = dip.dp1.di_rdev;
480 else {
481 KGETRET(ip->i_din.ffs1_din, &dip, sizeof (struct ufs2_dinode),
482 "inode's UFS2 dinode");
483 rdev = dip.dp2.di_rdev;
484 }
485
486 /*
487 * XXX need to to locking state.
488 */
489
490 (void)getflags(ufs_flags, flags, ip->i_flag);
491 PRWORD(ovflw, " %*llu", 7, 1, (unsigned long long)ip->i_number);
492 PRWORD(ovflw, " %*s", 6, 1, flags);
493 type = ip->i_mode & S_IFMT;
494 if (S_ISCHR(ip->i_mode) || S_ISBLK(ip->i_mode)) {
495 if (usenumflag ||
496 (name = devname(rdev, type)) == NULL) {
497 snprintf(dev, sizeof(dev), "%d,%d",
498 major(rdev), minor(rdev));
499 name = dev;
500 }
501 PRWORD(ovflw, " %*s", 8, 1, name);
502 } else
503 PRWORD(ovflw, " %*lld", 8, 1, (long long)ip->i_size);
504 return 0;
505 }
506
507 int
508 ext2fs_print(struct vnode *vp, int ovflw)
509 {
510 struct inode inode, *ip = &inode;
511 struct ext2fs_dinode dip;
512 char flags[sizeof(ufs_flags) / sizeof(ufs_flags[0])];
513 char dev[4 + 1 + 7 + 1]; /* 12bit marjor + 20bit minor */
514 char *name;
515 mode_t type;
516
517 KGETRET(VTOI(vp), &inode, sizeof(struct inode), "vnode's inode");
518 KGETRET(ip->i_din.e2fs_din, &dip, sizeof (struct ext2fs_dinode),
519 "inode's dinode");
520
521 /*
522 * XXX need to to locking state.
523 */
524
525 (void)getflags(ufs_flags, flags, ip->i_flag);
526 PRWORD(ovflw, " %*llu", 7, 1, (unsigned long long)ip->i_number);
527 PRWORD(ovflw, " %*s", 6, 1, flags);
528 type = dip.e2di_mode & S_IFMT;
529 if (S_ISCHR(dip.e2di_mode) || S_ISBLK(dip.e2di_mode)) {
530 if (usenumflag ||
531 (name = devname(dip.e2di_rdev, type)) == NULL) {
532 snprintf(dev, sizeof(dev), "%d,%d",
533 major(dip.e2di_rdev), minor(dip.e2di_rdev));
534 name = dev;
535 }
536 PRWORD(ovflw, " %*s", 8, 1, name);
537 } else
538 PRWORD(ovflw, " %*u", 8, 1, (u_int)dip.e2di_size);
539 return (0);
540 }
541
542 const struct flagbit_desc nfs_flags[] = {
543 { NFLUSHWANT, 'W' },
544 { NFLUSHINPROG, 'P' },
545 { NMODIFIED, 'M' },
546 { NWRITEERR, 'E' },
547 { NACC, 'A' },
548 { NUPD, 'U' },
549 { NCHG, 'C' },
550 { 0, '\0' },
551 };
552
553 void
554 nfs_header(void)
555 {
556
557 (void)printf(" FILEID NFLAG RDEV|SZ");
558 }
559
560 int
561 nfs_print(struct vnode *vp, int ovflw)
562 {
563 struct nfsnode nfsnode, *np = &nfsnode;
564 char flags[sizeof(nfs_flags) / sizeof(nfs_flags[0])];
565 char dev[4 + 1 + 7 + 1]; /* 12bit marjor + 20bit minor */
566 struct vattr va;
567 char *name;
568 mode_t type;
569
570 KGETRET(VTONFS(vp), &nfsnode, sizeof(nfsnode), "vnode's nfsnode");
571 (void)getflags(nfs_flags, flags, np->n_flag);
572
573 KGETRET(np->n_vattr, &va, sizeof(va), "vnode attr");
574 PRWORD(ovflw, " %*ld", 7, 1, (long)va.va_fileid);
575 PRWORD(ovflw, " %*s", 6, 1, flags);
576 switch (va.va_type) {
577 case VCHR:
578 type = S_IFCHR;
579 goto device;
580
581 case VBLK:
582 type = S_IFBLK;
583 device:
584 if (usenumflag || (name = devname(va.va_rdev, type)) == NULL) {
585 (void)snprintf(dev, sizeof(dev), "%d,%d",
586 major(va.va_rdev), minor(va.va_rdev));
587 name = dev;
588 }
589 PRWORD(ovflw, " %*s", 8, 1, name);
590 break;
591 default:
592 PRWORD(ovflw, " %*lld", 8, 1, (long long)np->n_size);
593 break;
594 }
595 return (0);
596 }
597
598 void
599 layer_header(void)
600 {
601
602 (void)printf(" %*s", PTRSTRWIDTH, "LOWER");
603 }
604
605 int
606 layer_print(struct vnode *vp, int ovflw)
607 {
608 struct layer_node lnode, *lp = &lnode;
609
610 KGETRET(VTOLAYER(vp), &lnode, sizeof(lnode), "layer vnode");
611
612 PRWORD(ovflw, " %*lx", PTRSTRWIDTH + 1, 1, (long)lp->layer_lowervp);
613 return (0);
614 }
615
616 /*
617 * Given a pointer to a mount structure in kernel space,
618 * read it in and return a usable pointer to it.
619 */
620 struct mount *
621 getmnt(struct mount *maddr)
622 {
623 static struct mtab {
624 struct mtab *next;
625 struct mount *maddr;
626 struct mount mount;
627 } *mhead = NULL;
628 struct mtab *mt;
629 struct mount mb;
630
631 for (mt = mhead; mt != NULL; mt = mt->next)
632 if (maddr == mt->maddr)
633 return (&mt->mount);
634 KGETRET(maddr, &mb, sizeof(struct mount), "mount table");
635 if ((mt = malloc(sizeof(struct mtab))) == NULL)
636 err(1, "malloc");
637 mt->mount = mb;
638 mt->maddr = maddr;
639 mt->next = mhead;
640 mhead = mt;
641 return (&mt->mount);
642 }
643
644 void
645 mount_print(struct mount *mp)
646 {
647 int flags;
648
649 (void)printf("*** MOUNT %s %s on %s", ST.f_fstypename,
650 ST.f_mntfromname, ST.f_mntonname);
651 if ((flags = mp->mnt_flag) != 0) {
652 int i;
653 const char *sep = " (";
654
655 for (i = 0; i < sizeof mnt_flags / sizeof mnt_flags[0]; i++) {
656 if (flags & mnt_flags[i].m_flag) {
657 (void)printf("%s%s", sep, mnt_flags[i].m_name);
658 flags &= ~mnt_flags[i].m_flag;
659 sep = ",";
660 }
661 }
662 if (flags)
663 (void)printf("%sunknown_flags:%x", sep, flags);
664 (void)printf(")");
665 }
666 (void)printf("\n");
667 }
668
669 char *
670 loadvnodes(int *avnodes)
671 {
672 int mib[2];
673 size_t copysize;
674 char *vnodebase;
675
676 if (totalflag) {
677 KGET(V_NUMV, *avnodes);
678 return NULL;
679 }
680 if (memf != NULL) {
681 /*
682 * do it by hand
683 */
684 return (kinfo_vnodes(avnodes));
685 }
686 mib[0] = CTL_KERN;
687 mib[1] = KERN_VNODE;
688 if (sysctl(mib, 2, NULL, ©size, NULL, 0) == -1)
689 err(1, "sysctl: KERN_VNODE");
690 if ((vnodebase = malloc(copysize)) == NULL)
691 err(1, "malloc");
692 if (sysctl(mib, 2, vnodebase, ©size, NULL, 0) == -1)
693 err(1, "sysctl: KERN_VNODE");
694 if (copysize % (VPTRSZ + VNODESZ))
695 errx(1, "vnode size mismatch");
696 *avnodes = copysize / (VPTRSZ + VNODESZ);
697
698 return (vnodebase);
699 }
700
701 /*
702 * simulate what a running kernel does in in kinfo_vnode
703 */
704 char *
705 kinfo_vnodes(int *avnodes)
706 {
707 struct mntlist mountlist;
708 struct mount *mp, mount;
709 struct vnode *vp, vnode;
710 char *beg, *bp, *ep;
711 int numvnodes;
712
713 KGET(V_NUMV, numvnodes);
714 if ((bp = malloc((numvnodes + 20) * (VPTRSZ + VNODESZ))) == NULL)
715 err(1, "malloc");
716 beg = bp;
717 ep = bp + (numvnodes + 20) * (VPTRSZ + VNODESZ);
718 KGET(V_MOUNTLIST, mountlist);
719 for (mp = mountlist.cqh_first;;
720 mp = mount.mnt_list.cqe_next) {
721 KGET2(mp, &mount, sizeof(mount), "mount entry");
722 TAILQ_FOREACH(vp, &mount.mnt_vnodelist, v_mntvnodes) {
723 KGET2(vp, &vnode, sizeof(vnode), "vnode");
724 if (bp + VPTRSZ + VNODESZ > ep)
725 /* XXX - should realloc */
726 errx(1, "no more room for vnodes");
727 memmove(bp, &vp, VPTRSZ);
728 bp += VPTRSZ;
729 memmove(bp, &vnode, VNODESZ);
730 bp += VNODESZ;
731 }
732 if (mp == mountlist.cqh_last)
733 break;
734 }
735 *avnodes = (bp - beg) / (VPTRSZ + VNODESZ);
736 return (beg);
737 }
738
739 void
740 ttymode(void)
741 {
742 int ntty;
743 struct ttylist_head tty_head;
744 struct tty *tp, tty;
745
746 KGET(TTY_NTTY, ntty);
747 (void)printf("%d terminal device%s\n", ntty, ntty == 1 ? "" : "s");
748 KGET(TTY_TTYLIST, tty_head);
749 (void)printf(
750 " LINE RAW CAN OUT HWT LWT COL STATE %-*s PGID DISC\n",
751 PTRSTRWIDTH, "SESS");
752 for (tp = tty_head.tqh_first; tp; tp = tty.tty_link.tqe_next) {
753 KGET2(tp, &tty, sizeof tty, "tty struct");
754 ttyprt(&tty);
755 }
756 }
757
758 static const struct flagbit_desc ttystates[] = {
759 { TS_ISOPEN, 'O'},
760 { TS_DIALOUT, '>'},
761 { TS_CARR_ON, 'C'},
762 { TS_TIMEOUT, 'T'},
763 { TS_FLUSH, 'F'},
764 { TS_BUSY, 'B'},
765 { TS_XCLUDE, 'X'},
766 { TS_TTSTOP, 'S'},
767 { TS_TBLOCK, 'K'},
768 { TS_ASYNC, 'Y'},
769 { TS_BKSL, 'D'},
770 { TS_ERASE, 'E'},
771 { TS_LNCH, 'L'},
772 { TS_TYPEN, 'P'},
773 { TS_CNTTB, 'N'},
774 { 0, '\0'},
775 };
776
777 void
778 ttyprt(struct tty *tp)
779 {
780 char state[sizeof(ttystates) / sizeof(ttystates[0]) + 1];
781 char dev[2 + 3 + 1 + 5 + 1]; /* 12bit major + 20bit minor */
782 struct linesw t_linesw;
783 const char *name;
784 char buffer;
785 pid_t pgid;
786 int n, ovflw;
787
788 if (usenumflag || (name = devname(tp->t_dev, S_IFCHR)) == NULL) {
789 (void)snprintf(dev, sizeof(dev), "0x%3x:%x",
790 major(tp->t_dev), minor(tp->t_dev));
791 name = dev;
792 }
793 ovflw = 0;
794 PRWORD(ovflw, "%-*s", 7, 0, name);
795 PRWORD(ovflw, " %*d", 3, 1, tp->t_rawq.c_cc);
796 PRWORD(ovflw, " %*d", 4, 1, tp->t_canq.c_cc);
797 PRWORD(ovflw, " %*d", 4, 1, tp->t_outq.c_cc);
798 PRWORD(ovflw, " %*d", 5, 1, tp->t_hiwat);
799 PRWORD(ovflw, " %*d", 4, 1, tp->t_lowat);
800 PRWORD(ovflw, " %*d", 8, 1, tp->t_column);
801 n = getflags(ttystates, state, tp->t_state);
802 if (tp->t_wopen) {
803 state[n++] = 'W';
804 state[n] = '\0';
805 }
806 PRWORD(ovflw, " %-*s", 7, 1, state);
807 PRWORD(ovflw, " %*lX", PTRSTRWIDTH + 1, 1, (u_long)tp->t_session);
808 pgid = 0;
809 if (tp->t_pgrp != NULL)
810 KGET2(&tp->t_pgrp->pg_id, &pgid, sizeof(pid_t), "pgid");
811 PRWORD(ovflw, " %*d", 6, 1, pgid);
812 KGET2(tp->t_linesw, &t_linesw, sizeof(t_linesw),
813 "line discipline switch table");
814 name = t_linesw.l_name;
815 (void)putchar(' ');
816 for (;;) {
817 KGET2(name, &buffer, sizeof(buffer), "line discipline name");
818 if (buffer == '\0')
819 break;
820 (void)putchar(buffer);
821 name++;
822 }
823 (void)putchar('\n');
824 }
825
826 static const struct flagbit_desc filemode_flags[] = {
827 { FREAD, 'R' },
828 { FWRITE, 'W' },
829 { FAPPEND, 'A' },
830 #ifdef FSHLOCK /* currently gone */
831 { FSHLOCK, 'S' },
832 { FEXLOCK, 'X' },
833 #endif
834 { FASYNC, 'I' },
835 { 0, '\0' },
836 };
837
838 void
839 filemode(void)
840 {
841 struct file *fp;
842 struct file *addr;
843 char flags[sizeof(filemode_flags) / sizeof(filemode_flags[0])];
844 char *buf, *offset;
845 int len, maxfile, nfile, ovflw;
846
847 KGET(FNL_MAXFILE, maxfile);
848 if (totalflag) {
849 KGET(FNL_NFILE, nfile);
850 (void)printf("%3d/%3d files\n", nfile, maxfile);
851 return;
852 }
853 if (getfiles(&buf, &len, &offset) == -1)
854 return;
855 /*
856 * Getfiles returns in malloc'd memory a pointer to the first file
857 * structure, and then an array of file structs (whose addresses are
858 * derivable from the previous entry).
859 */
860 addr = ((struct filelist *)offset)->lh_first;
861 fp = (struct file *)(offset + sizeof(struct filelist));
862 nfile = (len - sizeof(struct filelist)) / sizeof(struct file);
863
864 (void)printf("%d/%d open files\n", nfile, maxfile);
865 (void)printf("%*s%s%*s TYPE FLG CNT MSG %*s%s%*s IFLG OFFSET\n",
866 (PTRSTRWIDTH - 4) / 2, "", " LOC", (PTRSTRWIDTH - 4) / 2, "",
867 (PTRSTRWIDTH - 4) / 2, "", "DATA", (PTRSTRWIDTH - 4) / 2, "");
868 for (; (char *)fp < offset + len; addr = fp->f_list.le_next, fp++) {
869 if ((unsigned)fp->f_type >= sizeof(dtypes) / sizeof(dtypes[0]))
870 continue;
871 ovflw = 0;
872 (void)getflags(filemode_flags, flags, fp->f_flag);
873 PRWORD(ovflw, "%*lx", PTRSTRWIDTH, 0, (long)addr);
874 PRWORD(ovflw, " %-*s", 9, 1, dtypes[fp->f_type]);
875 PRWORD(ovflw, " %*s", 6, 1, flags);
876 PRWORD(ovflw, " %*d", 5, 1, fp->f_count);
877 PRWORD(ovflw, " %*d", 5, 1, fp->f_msgcount);
878 PRWORD(ovflw, " %*lx", PTRSTRWIDTH + 1, 2, (long)fp->f_data);
879 PRWORD(ovflw, " %*x", 5, 1, fp->f_iflags);
880 if (fp->f_offset < 0)
881 PRWORD(ovflw, " %-*lld\n", PTRSTRWIDTH + 1, 2,
882 (long long)fp->f_offset);
883 else
884 PRWORD(ovflw, " %-*lld\n", PTRSTRWIDTH + 1, 2,
885 (long long)fp->f_offset);
886 }
887 free(buf);
888 }
889
890 int
891 getfiles(char **abuf, int *alen, char **aoffset)
892 {
893 size_t len;
894 int mib[2];
895 char *buf;
896 size_t offset;
897
898 /*
899 * XXX
900 * Add emulation of KINFO_FILE here.
901 */
902 if (memf != NULL)
903 errx(1, "files on dead kernel, not implemented");
904
905 mib[0] = CTL_KERN;
906 mib[1] = KERN_FILE;
907 if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1) {
908 warn("sysctl: KERN_FILE");
909 return (-1);
910 }
911 /* We need to align (struct file *) in the buffer. */
912 offset = len % sizeof(off_t);
913 if ((buf = malloc(len + offset)) == NULL)
914 err(1, "malloc");
915 if (sysctl(mib, 2, buf + offset, &len, NULL, 0) == -1) {
916 warn("sysctl: KERN_FILE");
917 return (-1);
918 }
919 *abuf = buf;
920 *alen = len;
921 *aoffset = (buf + offset);
922 return (0);
923 }
924
925 void
926 usage(void)
927 {
928
929 (void)fprintf(stderr,
930 "usage: %s [-T|-f|-s|-t|-v] [-ghkmn] [-M core] [-N system]\n",
931 getprogname());
932 exit(1);
933 }
934