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