pstat.c revision 1.33 1 /* $NetBSD: pstat.c,v 1.33 1997/10/17 06:34:22 mrg 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. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #ifndef lint
37 static char copyright[] =
38 "@(#) Copyright (c) 1980, 1991, 1993, 1994\n\
39 The Regents of the University of California. All rights reserved.\n";
40 #endif /* not lint */
41
42 #ifndef lint
43 #if 0
44 static char sccsid[] = "@(#)pstat.c 8.16 (Berkeley) 5/9/95";
45 #else
46 static char *rcsid = "$NetBSD: pstat.c,v 1.33 1997/10/17 06:34:22 mrg Exp $";
47 #endif
48 #endif /* not lint */
49
50 #include <sys/param.h>
51 #include <sys/time.h>
52 #include <sys/vnode.h>
53 #include <sys/map.h>
54 #include <sys/ucred.h>
55 #define _KERNEL
56 #include <sys/file.h>
57 #include <ufs/ufs/quota.h>
58 #include <ufs/ufs/inode.h>
59 #define NFS
60 #include <sys/mount.h>
61 #undef NFS
62 #include <sys/uio.h>
63 #include <sys/namei.h>
64 #include <miscfs/union/union.h>
65 #undef _KERNEL
66 #include <sys/stat.h>
67 #include <nfs/nfsproto.h>
68 #include <nfs/rpcv2.h>
69 #include <nfs/nfs.h>
70 #include <nfs/nfsnode.h>
71 #include <sys/ioctl.h>
72 #include <sys/tty.h>
73 #include <sys/conf.h>
74 #include <sys/device.h>
75
76 #include <sys/sysctl.h>
77
78 #include <err.h>
79 #include <kvm.h>
80 #include <limits.h>
81 #include <nlist.h>
82 #include <stdio.h>
83 #include <stdlib.h>
84 #include <string.h>
85 #include <unistd.h>
86
87 #include "swapctl.h"
88
89 struct nlist nl[] = {
90 #define V_MOUNTLIST 0
91 { "_mountlist" }, /* address of head of mount list. */
92 #define V_NUMV 1
93 { "_numvnodes" },
94 #define FNL_NFILE 2
95 {"_nfiles"},
96 #define FNL_MAXFILE 3
97 {"_maxfiles"},
98 #define TTY_NTTY 4
99 {"_tty_count"},
100 #define TTY_TTYLIST 5
101 {"_ttylist"},
102 #define NLMANDATORY TTY_TTYLIST /* names up to here are mandatory */
103 { "" }
104 };
105
106 int usenumflag;
107 int totalflag;
108 int kflag;
109 char *nlistf = NULL;
110 char *memf = NULL;
111 kvm_t *kd;
112
113 struct {
114 int m_flag;
115 const char *m_name;
116 } mnt_flags[] = {
117 { MNT_RDONLY, "rdonly" },
118 { MNT_SYNCHRONOUS, "sync" },
119 { MNT_NOEXEC, "noexec" },
120 { MNT_NOSUID, "nosuid" },
121 { MNT_NODEV, "nodev" },
122 { MNT_UNION, "union" },
123 { MNT_ASYNC, "async" },
124 { MNT_NOCOREDUMP, "nocoredump" },
125 { MNT_EXRDONLY, "exrdonly" },
126 { MNT_EXPORTED, "exported" },
127 { MNT_DEFEXPORTED, "defexported" },
128 { MNT_EXPORTANON, "exportanon" },
129 { MNT_EXKERB, "exkerb" },
130 { MNT_LOCAL, "local" },
131 { MNT_QUOTA, "quota" },
132 { MNT_ROOTFS, "rootfs" },
133 { MNT_UPDATE, "update" },
134 { MNT_DELEXPORT, "delexport" },
135 { MNT_RELOAD, "reload" },
136 { MNT_FORCE, "force" },
137 { MNT_MLOCK, "mlock" },
138 { MNT_WAIT, "wait" },
139 { MNT_MPBUSY, "mpbusy" },
140 { MNT_MPWANT, "mpwant" },
141 { MNT_UNMOUNT, "unmount" },
142 { MNT_WANTRDWR, "wantrdwr" },
143 { 0 }
144 };
145
146
147 #define SVAR(var) __STRING(var) /* to force expansion */
148 #define KGET(idx, var) \
149 KGET1(idx, &var, sizeof(var), SVAR(var))
150 #define KGET1(idx, p, s, msg) \
151 KGET2(nl[idx].n_value, p, s, msg)
152 #define KGET2(addr, p, s, msg) \
153 if (kvm_read(kd, (u_long)(addr), p, s) != s) \
154 warnx("cannot read %s: %s", msg, kvm_geterr(kd))
155 #define KGETRET(addr, p, s, msg) \
156 if (kvm_read(kd, (u_long)(addr), p, s) != s) { \
157 warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \
158 return (0); \
159 }
160
161 void filemode __P((void));
162 int getfiles __P((char **, int *));
163 struct mount *
164 getmnt __P((struct mount *));
165 struct e_vnode *
166 kinfo_vnodes __P((int *));
167 struct e_vnode *
168 loadvnodes __P((int *));
169 void mount_print __P((struct mount *));
170 void nfs_header __P((void));
171 int nfs_print __P((struct vnode *));
172 void ttymode __P((void));
173 void ttyprt __P((struct tty *));
174 void ufs_getflags __P((struct vnode *, struct inode *, char *));
175 void ufs_header __P((void));
176 int ufs_print __P((struct vnode *));
177 int ext2fs_print __P((struct vnode *));
178 void union_header __P((void));
179 int union_print __P((struct vnode *));
180 void usage __P((void));
181 void vnode_header __P((void));
182 void vnode_print __P((struct vnode *, struct vnode *));
183 void vnodemode __P((void));
184
185 int
186 main(argc, argv)
187 int argc;
188 char *argv[];
189 {
190 extern char *optarg;
191 extern int optind;
192 int ch, i, quit, ret;
193 int fileflag, swapflag, ttyflag, vnodeflag;
194 char buf[_POSIX2_LINE_MAX];
195
196 fileflag = swapflag = ttyflag = vnodeflag = 0;
197 while ((ch = getopt(argc, argv, "TM:N:fiknstv")) != -1)
198 switch (ch) {
199 case 'f':
200 fileflag = 1;
201 break;
202 case 'M':
203 memf = optarg;
204 break;
205 case 'N':
206 nlistf = optarg;
207 break;
208 case 'n':
209 usenumflag = 1;
210 break;
211 case 's':
212 swapflag = 1;
213 break;
214 case 'T':
215 totalflag = 1;
216 break;
217 case 't':
218 ttyflag = 1;
219 break;
220 case 'k':
221 kflag = 1;
222 break;
223 case 'v':
224 case 'i': /* Backward compatibility. */
225 vnodeflag = 1;
226 break;
227 default:
228 usage();
229 }
230 argc -= optind;
231 argv += optind;
232
233 /*
234 * Discard setgid privileges if not the running kernel so that bad
235 * guys can't print interesting stuff from kernel memory.
236 */
237 if (nlistf != NULL || memf != NULL)
238 (void)setgid(getgid());
239
240 if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == 0)
241 errx(1, "kvm_openfiles: %s", buf);
242 if ((ret = kvm_nlist(kd, nl)) != 0) {
243 if (ret == -1)
244 errx(1, "kvm_nlist: %s", kvm_geterr(kd));
245 for (i = quit = 0; i <= NLMANDATORY; i++)
246 if (!nl[i].n_value) {
247 quit = 1;
248 warnx("undefined symbol: %s", nl[i].n_name);
249 }
250 if (quit)
251 exit(1);
252 }
253 if (!(fileflag | vnodeflag | ttyflag | swapflag | totalflag))
254 usage();
255 if (fileflag || totalflag)
256 filemode();
257 if (vnodeflag || totalflag)
258 vnodemode();
259 if (ttyflag)
260 ttymode();
261 if (swapflag || totalflag)
262 list_swap(0, kflag, 0, totalflag, 1);
263 exit (0);
264 }
265
266 struct e_vnode {
267 struct vnode *avnode;
268 struct vnode vnode;
269 };
270
271 void
272 vnodemode()
273 {
274 struct e_vnode *e_vnodebase, *endvnode, *evp;
275 struct vnode *vp;
276 struct mount *maddr, *mp;
277 int numvnodes;
278
279 e_vnodebase = loadvnodes(&numvnodes);
280 if (totalflag) {
281 (void)printf("%7d vnodes\n", numvnodes);
282 return;
283 }
284 endvnode = e_vnodebase + numvnodes;
285 (void)printf("%d active vnodes\n", numvnodes);
286
287
288 #define ST mp->mnt_stat
289 maddr = NULL;
290 for (evp = e_vnodebase; evp < endvnode; evp++) {
291 vp = &evp->vnode;
292 if (vp->v_mount != maddr) {
293 /*
294 * New filesystem
295 */
296 if ((mp = getmnt(vp->v_mount)) == NULL)
297 continue;
298 maddr = vp->v_mount;
299 mount_print(mp);
300 vnode_header();
301 if (!strncmp(ST.f_fstypename, MOUNT_FFS, MFSNAMELEN) ||
302 !strncmp(ST.f_fstypename, MOUNT_MFS, MFSNAMELEN))
303 ufs_header();
304 else if (!strncmp(ST.f_fstypename, MOUNT_NFS,
305 MFSNAMELEN))
306 nfs_header();
307 else if (!strncmp(ST.f_fstypename, MOUNT_EXT2FS,
308 MFSNAMELEN))
309 ufs_header();
310 else if (!strcmp(ST.f_fstypename, "union"))
311 union_header();
312 (void)printf("\n");
313 }
314 vnode_print(evp->avnode, vp);
315 if (!strncmp(ST.f_fstypename, MOUNT_FFS, MFSNAMELEN) ||
316 !strncmp(ST.f_fstypename, MOUNT_MFS, MFSNAMELEN)) {
317 ufs_print(vp);
318 } else if (!strncmp(ST.f_fstypename, MOUNT_NFS, MFSNAMELEN)) {
319 nfs_print(vp);
320 } else if (!strncmp(ST.f_fstypename, MOUNT_EXT2FS, MFSNAMELEN)) {
321 ext2fs_print(vp);
322 }
323 (void)printf("\n");
324 }
325 free(e_vnodebase);
326 }
327
328 void
329 vnode_header()
330 {
331 (void)printf("ADDR TYP VFLAG USE HOLD");
332 }
333
334 void
335 vnode_print(avnode, vp)
336 struct vnode *avnode;
337 struct vnode *vp;
338 {
339 char *type, flags[16];
340 char *fp = flags;
341 int flag;
342
343 /*
344 * set type
345 */
346 switch (vp->v_type) {
347 case VNON:
348 type = "non"; break;
349 case VREG:
350 type = "reg"; break;
351 case VDIR:
352 type = "dir"; break;
353 case VBLK:
354 type = "blk"; break;
355 case VCHR:
356 type = "chr"; break;
357 case VLNK:
358 type = "lnk"; break;
359 case VSOCK:
360 type = "soc"; break;
361 case VFIFO:
362 type = "fif"; break;
363 case VBAD:
364 type = "bad"; break;
365 default:
366 type = "unk"; break;
367 }
368 /*
369 * gather flags
370 */
371 flag = vp->v_flag;
372 if (flag & VROOT)
373 *fp++ = 'R';
374 if (flag & VTEXT)
375 *fp++ = 'T';
376 if (flag & VSYSTEM)
377 *fp++ = 'S';
378 if (flag & VISTTY)
379 *fp++ = 'I';
380 if (flag & VXLOCK)
381 *fp++ = 'L';
382 if (flag & VXWANT)
383 *fp++ = 'W';
384 if (flag & VBWAIT)
385 *fp++ = 'B';
386 if (flag & VALIASED)
387 *fp++ = 'A';
388 if (flag & VDIROP)
389 *fp++ = 'D';
390 if (flag == 0)
391 *fp++ = '-';
392 *fp = '\0';
393 (void)printf("%8x %s %5s %4d %4d",
394 avnode, type, flags, vp->v_usecount, vp->v_holdcnt);
395 }
396
397 void
398 ufs_getflags(vp, ip, flags)
399 struct vnode *vp;
400 struct inode *ip;
401 char *flags;
402 {
403 register int flag;
404
405 flag = ip->i_flag;
406 if (flag & IN_LOCKED)
407 *flags++ = 'L';
408 if (flag & IN_WANTED)
409 *flags++ = 'W';
410 if (flag & IN_RENAME)
411 *flags++ = 'R';
412 if (flag & IN_UPDATE)
413 *flags++ = 'U';
414 if (flag & IN_ACCESS)
415 *flags++ = 'A';
416 if (flag & IN_CHANGE)
417 *flags++ = 'C';
418 if (flag & IN_MODIFIED)
419 *flags++ = 'M';
420 if (flag & IN_SHLOCK)
421 *flags++ = 'S';
422 if (flag & IN_EXLOCK)
423 *flags++ = 'E';
424 if (flag & IN_LWAIT)
425 *flags++ = 'Z';
426 if (flag == 0)
427 *flags++ = '-';
428 *flags = '\0';
429
430 }
431
432 void
433 ufs_header()
434 {
435 (void)printf(" FILEID IFLAG RDEV|SZ");
436 }
437
438 int
439 ufs_print(vp)
440 struct vnode *vp;
441 {
442 struct inode inode, *ip = &inode;
443 char flagbuf[16];
444 char *name;
445 mode_t type;
446
447 KGETRET(VTOI(vp), &inode, sizeof(struct inode), "vnode's inode");
448 ufs_getflags(vp, ip, flagbuf);
449 (void)printf(" %6d %5s", ip->i_number, flagbuf);
450 type = ip->i_ffs_mode & S_IFMT;
451 if (S_ISCHR(ip->i_ffs_mode) || S_ISBLK(ip->i_ffs_mode))
452 if (usenumflag || ((name = devname(ip->i_ffs_rdev, type)) == NULL))
453 (void)printf(" %2d,%-2d",
454 major(ip->i_ffs_rdev), minor(ip->i_ffs_rdev));
455 else
456 (void)printf(" %7s", name);
457 else
458 (void)printf(" %7qd", ip->i_ffs_size);
459 return (0);
460 }
461
462 int
463 ext2fs_print(vp)
464 struct vnode *vp;
465 {
466 struct inode inode, *ip = &inode;
467 char flagbuf[16];
468 char *name;
469 mode_t type;
470
471 KGETRET(VTOI(vp), &inode, sizeof(struct inode), "vnode's inode");
472 ufs_getflags(vp, ip, flagbuf);
473 (void)printf(" %6d %5s", ip->i_number, flagbuf);
474 type = ip->i_e2fs_mode & S_IFMT;
475 if (S_ISCHR(ip->i_e2fs_mode) || S_ISBLK(ip->i_e2fs_mode))
476 if (usenumflag || ((name = devname(ip->i_din.e2fs_din.e2di_rdev,
477 type)) == NULL))
478 (void)printf(" %2d,%-2d",
479 major(ip->i_din.e2fs_din.e2di_rdev),
480 minor(ip->i_din.e2fs_din.e2di_rdev));
481 else
482 (void)printf(" %7s", name);
483 else
484 (void)printf(" %7u", (u_int)ip->i_e2fs_size);
485 return (0);
486 }
487
488 void
489 nfs_header()
490 {
491 (void)printf(" FILEID NFLAG RDEV|SZ");
492 }
493
494 int
495 nfs_print(vp)
496 struct vnode *vp;
497 {
498 struct nfsnode nfsnode, *np = &nfsnode;
499 char flagbuf[16], *flags = flagbuf;
500 int flag;
501 char *name;
502 mode_t type;
503
504 KGETRET(VTONFS(vp), &nfsnode, sizeof(nfsnode), "vnode's nfsnode");
505 flag = np->n_flag;
506 if (flag & NFLUSHWANT)
507 *flags++ = 'W';
508 if (flag & NFLUSHINPROG)
509 *flags++ = 'P';
510 if (flag & NMODIFIED)
511 *flags++ = 'M';
512 if (flag & NWRITEERR)
513 *flags++ = 'E';
514 if (flag & NQNFSNONCACHE)
515 *flags++ = 'X';
516 if (flag & NQNFSWRITE)
517 *flags++ = 'O';
518 if (flag & NQNFSEVICTED)
519 *flags++ = 'G';
520 if (flag == 0)
521 *flags++ = '-';
522 *flags = '\0';
523
524 #define VT np->n_vattr
525 (void)printf(" %6d %5s", VT.va_fileid, flagbuf);
526 type = VT.va_mode & S_IFMT;
527 if (S_ISCHR(VT.va_mode) || S_ISBLK(VT.va_mode))
528 if (usenumflag || ((name = devname(VT.va_rdev, type)) == NULL))
529 (void)printf(" %2d,%-2d",
530 major(VT.va_rdev), minor(VT.va_rdev));
531 else
532 (void)printf(" %7s", name);
533 else
534 (void)printf(" %7qd", np->n_size);
535 return (0);
536 }
537
538 void
539 union_header()
540 {
541 (void)printf(" UPPER LOWER");
542 }
543
544 int
545 union_print(vp)
546 struct vnode *vp;
547 {
548 struct union_node unode, *up = &unode;
549
550 KGETRET(VTOUNION(vp), &unode, sizeof(unode), "vnode's unode");
551
552 (void)printf(" %8x %8x", up->un_uppervp, up->un_lowervp);
553 return (0);
554 }
555
556 /*
557 * Given a pointer to a mount structure in kernel space,
558 * read it in and return a usable pointer to it.
559 */
560 struct mount *
561 getmnt(maddr)
562 struct mount *maddr;
563 {
564 static struct mtab {
565 struct mtab *next;
566 struct mount *maddr;
567 struct mount mount;
568 } *mhead = NULL;
569 struct mtab *mt;
570
571 for (mt = mhead; mt != NULL; mt = mt->next)
572 if (maddr == mt->maddr)
573 return (&mt->mount);
574 if ((mt = malloc(sizeof(struct mtab))) == NULL)
575 err(1, NULL);
576 KGETRET(maddr, &mt->mount, sizeof(struct mount), "mount table");
577 mt->maddr = maddr;
578 mt->next = mhead;
579 mhead = mt;
580 return (&mt->mount);
581 }
582
583 void
584 mount_print(mp)
585 struct mount *mp;
586 {
587 int flags;
588 const char *type;
589
590 (void)printf("*** MOUNT %s %s on %s", ST.f_fstypename,
591 ST.f_mntfromname, ST.f_mntonname);
592 if (flags = mp->mnt_flag) {
593 int i;
594 const char *sep = " (";
595
596 for (i = 0; mnt_flags[i].m_flag; i++) {
597 if (flags & mnt_flags[i].m_flag) {
598 (void)printf("%s%s", sep, mnt_flags[i].m_name);
599 flags &= ~mnt_flags[i].m_flag;
600 sep = ",";
601 }
602 }
603 if (flags)
604 (void)printf("%sunknown_flags:%x", sep, flags);
605 (void)printf(")");
606 }
607 (void)printf("\n");
608 }
609
610 struct e_vnode *
611 loadvnodes(avnodes)
612 int *avnodes;
613 {
614 int mib[2];
615 size_t copysize;
616 struct e_vnode *vnodebase;
617
618 if (memf != NULL) {
619 /*
620 * do it by hand
621 */
622 return (kinfo_vnodes(avnodes));
623 }
624 mib[0] = CTL_KERN;
625 mib[1] = KERN_VNODE;
626 if (sysctl(mib, 2, NULL, ©size, NULL, 0) == -1)
627 err(1, "sysctl: KERN_VNODE");
628 if ((vnodebase = malloc(copysize)) == NULL)
629 err(1, NULL);
630 if (sysctl(mib, 2, vnodebase, ©size, NULL, 0) == -1)
631 err(1, "sysctl: KERN_VNODE");
632 if (copysize % sizeof(struct e_vnode))
633 errx(1, "vnode size mismatch");
634 *avnodes = copysize / sizeof(struct e_vnode);
635
636 return (vnodebase);
637 }
638
639 /*
640 * simulate what a running kernel does in in kinfo_vnode
641 */
642 struct e_vnode *
643 kinfo_vnodes(avnodes)
644 int *avnodes;
645 {
646 struct mntlist mountlist;
647 struct mount *mp, mount;
648 struct vnode *vp, vnode;
649 char *vbuf, *evbuf, *bp;
650 int num, numvnodes;
651
652 #define VPTRSZ sizeof(struct vnode *)
653 #define VNODESZ sizeof(struct vnode)
654
655 KGET(V_NUMV, numvnodes);
656 if ((vbuf = malloc((numvnodes + 20) * (VPTRSZ + VNODESZ))) == NULL)
657 err(1, NULL);
658 bp = vbuf;
659 evbuf = vbuf + (numvnodes + 20) * (VPTRSZ + VNODESZ);
660 KGET(V_MOUNTLIST, mountlist);
661 for (num = 0, mp = mountlist.cqh_first; ; mp = mount.mnt_list.cqe_next) {
662 KGET2(mp, &mount, sizeof(mount), "mount entry");
663 for (vp = mount.mnt_vnodelist.lh_first;
664 vp != NULL; vp = vnode.v_mntvnodes.le_next) {
665 KGET2(vp, &vnode, sizeof(vnode), "vnode");
666 if ((bp + VPTRSZ + VNODESZ) > evbuf)
667 /* XXX - should realloc */
668 errx(1, "no more room for vnodes");
669 memmove(bp, &vp, VPTRSZ);
670 bp += VPTRSZ;
671 memmove(bp, &vnode, VNODESZ);
672 bp += VNODESZ;
673 num++;
674 }
675 if (mp == mountlist.cqh_last)
676 break;
677 }
678 *avnodes = num;
679 return ((struct e_vnode *)vbuf);
680 }
681
682 char hdr[]=" LINE RAW CAN OUT HWT LWT COL STATE SESS PGID DISC\n";
683 int ttyspace = 128;
684
685 void
686 ttymode()
687 {
688 int ntty, i;
689 struct ttylist_head tty_head;
690 struct tty *tp, tty;
691
692 KGET(TTY_NTTY, ntty);
693 (void)printf("%d terminal device%s\n", ntty, ntty == 1 ? "" : "s");
694 KGET(TTY_TTYLIST, tty_head);
695 (void)printf(hdr);
696 for (tp = tty_head.tqh_first; tp; tp = tty.tty_link.tqe_next) {
697 KGET2(tp, &tty, sizeof tty, "tty struct");
698 ttyprt(&tty);
699 }
700 }
701
702 struct {
703 int flag;
704 char val;
705 } ttystates[] = {
706 { TS_WOPEN, 'W'},
707 { TS_ISOPEN, 'O'},
708 { TS_CARR_ON, 'C'},
709 { TS_TIMEOUT, 'T'},
710 { TS_FLUSH, 'F'},
711 { TS_BUSY, 'B'},
712 { TS_ASLEEP, 'A'},
713 { TS_XCLUDE, 'X'},
714 { TS_TTSTOP, 'S'},
715 { TS_TBLOCK, 'K'},
716 { TS_ASYNC, 'Y'},
717 { TS_BKSL, 'D'},
718 { TS_ERASE, 'E'},
719 { TS_LNCH, 'L'},
720 { TS_TYPEN, 'P'},
721 { TS_CNTTB, 'N'},
722 { 0, '\0'},
723 };
724
725 void
726 ttyprt(tp)
727 struct tty *tp;
728 {
729 int i, j;
730 pid_t pgid;
731 char *name, state[20];
732
733 if (usenumflag || (name = devname(tp->t_dev, S_IFCHR)) == NULL)
734 (void)printf("0x%3x:%1x ", major(tp->t_dev), minor(tp->t_dev));
735 else
736 (void)printf("%-7s ", name);
737 (void)printf("%2d %3d ", tp->t_rawq.c_cc, tp->t_canq.c_cc);
738 (void)printf("%3d %4d %3d %7d ", tp->t_outq.c_cc,
739 tp->t_hiwat, tp->t_lowat, tp->t_column);
740 for (i = j = 0; ttystates[i].flag; i++)
741 if (tp->t_state&ttystates[i].flag)
742 state[j++] = ttystates[i].val;
743 if (j == 0)
744 state[j++] = '-';
745 state[j] = '\0';
746 (void)printf("%-6s %8x", state, (u_long)tp->t_session);
747 pgid = 0;
748 if (tp->t_pgrp != NULL)
749 KGET2(&tp->t_pgrp->pg_id, &pgid, sizeof(pid_t), "pgid");
750 (void)printf("%6d ", pgid);
751 switch (tp->t_line) {
752 case TTYDISC:
753 (void)printf("term\n");
754 break;
755 case TABLDISC:
756 (void)printf("tab\n");
757 break;
758 case SLIPDISC:
759 (void)printf("slip\n");
760 break;
761 case PPPDISC:
762 (void)printf("ppp\n");
763 break;
764 case STRIPDISC:
765 (void)printf("strip\n");
766 break;
767 default:
768 (void)printf("%d\n", tp->t_line);
769 break;
770 }
771 }
772
773 void
774 filemode()
775 {
776 struct file *fp;
777 struct file *addr;
778 char *buf, flagbuf[16], *fbp;
779 int len, maxfile, nfile;
780 static char *dtypes[] = { "???", "inode", "socket" };
781
782 KGET(FNL_MAXFILE, maxfile);
783 if (totalflag) {
784 KGET(FNL_NFILE, nfile);
785 (void)printf("%3d/%3d files\n", nfile, maxfile);
786 return;
787 }
788 if (getfiles(&buf, &len) == -1)
789 return;
790 /*
791 * Getfiles returns in malloc'd memory a pointer to the first file
792 * structure, and then an array of file structs (whose addresses are
793 * derivable from the previous entry).
794 */
795 addr = ((struct filelist *)buf)->lh_first;
796 fp = (struct file *)(buf + sizeof(struct filelist));
797 nfile = (len - sizeof(struct filelist)) / sizeof(struct file);
798
799 (void)printf("%d/%d open files\n", nfile, maxfile);
800 (void)printf(" LOC TYPE FLG CNT MSG DATA OFFSET\n");
801 for (; (char *)fp < buf + len; addr = fp->f_list.le_next, fp++) {
802 if ((unsigned)fp->f_type > DTYPE_SOCKET)
803 continue;
804 (void)printf("%x ", addr);
805 (void)printf("%-8.8s", dtypes[fp->f_type]);
806 fbp = flagbuf;
807 if (fp->f_flag & FREAD)
808 *fbp++ = 'R';
809 if (fp->f_flag & FWRITE)
810 *fbp++ = 'W';
811 if (fp->f_flag & FAPPEND)
812 *fbp++ = 'A';
813 #ifdef FSHLOCK /* currently gone */
814 if (fp->f_flag & FSHLOCK)
815 *fbp++ = 'S';
816 if (fp->f_flag & FEXLOCK)
817 *fbp++ = 'X';
818 #endif
819 if (fp->f_flag & FASYNC)
820 *fbp++ = 'I';
821 *fbp = '\0';
822 (void)printf("%6s %3d", flagbuf, fp->f_count);
823 (void)printf(" %3d", fp->f_msgcount);
824 (void)printf(" %8.1x", fp->f_data);
825 if (fp->f_offset < 0)
826 (void)printf(" %qx\n", fp->f_offset);
827 else
828 (void)printf(" %qd\n", fp->f_offset);
829 }
830 free(buf);
831 }
832
833 int
834 getfiles(abuf, alen)
835 char **abuf;
836 int *alen;
837 {
838 size_t len;
839 int mib[2];
840 char *buf;
841
842 /*
843 * XXX
844 * Add emulation of KINFO_FILE here.
845 */
846 if (memf != NULL)
847 errx(1, "files on dead kernel, not implemented\n");
848
849 mib[0] = CTL_KERN;
850 mib[1] = KERN_FILE;
851 if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1) {
852 warn("sysctl: KERN_FILE");
853 return (-1);
854 }
855 if ((buf = malloc(len)) == NULL)
856 err(1, NULL);
857 if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) {
858 warn("sysctl: KERN_FILE");
859 return (-1);
860 }
861 *abuf = buf;
862 *alen = len;
863 return (0);
864 }
865
866 void
867 usage()
868 {
869 (void)fprintf(stderr,
870 "usage: pstat [-T|-f|-s|-t|-v] [-kn] [-M core] [-N system]\n");
871 exit(1);
872 }
873