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