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