world - Fix fstat and gcore
[dragonfly.git] / usr.bin / fstat / fstat.c
1 /*-
2  * Copyright (c) 1988, 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. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * @(#) Copyright (c) 1988, 1993 The Regents of the University of California.  All rights reserved.
30  * @(#)fstat.c  8.3 (Berkeley) 5/2/95
31  * $FreeBSD: src/usr.bin/fstat/fstat.c,v 1.21.2.7 2001/11/21 10:49:37 dwmalone Exp $
32  */
33
34 #include <sys/user.h>
35 #include <sys/param.h>
36 #include <sys/time.h>
37 #include <sys/stat.h>
38 #include <sys/vnode.h>
39 #include <sys/socket.h>
40 #include <sys/socketvar.h>
41 #include <sys/domain.h>
42 #include <sys/protosw.h>
43 #include <sys/un.h>
44 #include <sys/unpcb.h>
45 #include <sys/sysctl.h>
46 #include <sys/filedesc.h>
47 #include <sys/queue.h>
48 #include <sys/pipe.h>
49 #include <sys/conf.h>
50 #include <sys/file.h>
51 #include <sys/ktrace.h>
52 #include <vfs/ufs/quota.h>
53 #include <vfs/ufs/inode.h>
54 #include <sys/mount.h>
55 #include <sys/namecache.h>
56 #include <nfs/nfsproto.h>
57 #include <nfs/rpcv2.h>
58 #include <nfs/nfs.h>
59 #include <nfs/nfsnode.h>
60 #include <sys/devfs.h>
61
62 #include <vm/vm.h>
63 #include <vm/vm_map.h>
64 #include <vm/vm_object.h>
65
66 #include <net/route.h>
67 #include <netinet/in.h>
68 #include <netinet/in_systm.h>
69 #include <netinet/ip.h>
70 #include <netinet/in_pcb.h>
71
72 #include <ctype.h>
73 #include <err.h>
74 #include <fcntl.h>
75 #include <kvm.h>
76 #include <limits.h>
77 #include <nlist.h>
78 #include <paths.h>
79 #include <pwd.h>
80 #include <stdio.h>
81 #include <stdlib.h>
82 #include <string.h>
83 #include <unistd.h>
84 #include <netdb.h>
85
86 #include "fstat.h"
87
88 #define TEXT    -1
89 #define CDIR    -2
90 #define RDIR    -3
91 #define TRACE   -4
92 #define MMAP    -5
93
94 DEVS *devs;
95
96 static void make_printable(char *buf, int len);
97 static int kreadent(const void *kaddr, vm_map_entry_t copy);
98
99 #ifdef notdef
100 struct nlist nl[] = {
101         { "" },
102 };
103 #endif
104
105 int     fsflg,  /* show files on same filesystem as file(s) argument */
106         pflg,   /* show files open by a particular pid */
107         uflg;   /* show files open by a particular (effective) user */
108 int     checkfile; /* true if restricting to particular files or filesystems */
109 int     nflg;   /* (numerical) display f.s. and rdev as dev_t */
110 int     vflg;   /* display errors in locating kernel data objects etc... */
111 int     mflg;   /* include memory-mapped files */
112 int     wflg_mnt = 16;
113 int     wflg_cmd = 10;
114 int     pid_width = 5;
115 int     ino_width = 6;
116
117 const char *Uname;
118 char    *Comm;
119 int     Pid;
120
121
122 struct fdnode *ofiles;  /* buffer of pointers to file structures */
123 int maxfiles;
124
125 #define ALLOC_OFILES(d) \
126         if ((d) > maxfiles) { \
127                 free(ofiles); \
128                 ofiles = malloc((d) * sizeof(struct fdnode)); \
129                 if (ofiles == NULL) { \
130                         err(1, NULL); \
131                 } \
132                 maxfiles = (d); \
133         }
134
135 kvm_t *kd;
136
137 static void dofiles(struct kinfo_proc *, struct proc *);
138 static void dommap(struct proc *);
139 static void vtrans(struct vnode *, struct nchandle *, int, int, off_t);
140 static int  ufs_filestat(struct vnode *, struct filestat *);
141 static int  nfs_filestat(struct vnode *, struct filestat *);
142 static int  devfs_filestat(struct vnode *, struct filestat *);
143 static char *getmnton(struct mount *, struct namecache_list *, struct nchandle *);
144 static void pipetrans(struct pipe *, int, int);
145 static void socktrans(struct socket *, int);
146 static void getinetproto(int);
147 static int  getfname(const char *);
148 static void usage(void) __dead2;
149
150
151 int
152 main(int argc, char **argv)
153 {
154         struct passwd *passwd;
155         struct kinfo_proc *p, *plast;
156         struct proc proc;
157         int arg, ch, what;
158         char *memf, *nlistf;
159         char buf[_POSIX2_LINE_MAX];
160         int cnt;
161
162         arg = 0;
163         what = KERN_PROC_ALL;
164         nlistf = memf = NULL;
165         while ((ch = getopt(argc, argv, "fmnp:u:vwN:M:")) != -1)
166                 switch((char)ch) {
167                 case 'f':
168                         fsflg = 1;
169                         break;
170                 case 'M':
171                         memf = optarg;
172                         break;
173                 case 'N':
174                         nlistf = optarg;
175                         break;
176                 case 'm':
177                         mflg = 1;
178                         break;
179                 case 'n':
180                         nflg = 1;
181                         break;
182                 case 'p':
183                         if (pflg++)
184                                 usage();
185                         if (!isdigit(*optarg)) {
186                                 warnx("-p requires a process id");
187                                 usage();
188                         }
189                         what = KERN_PROC_PID;
190                         arg = atoi(optarg);
191                         break;
192                 case 'u':
193                         if (uflg++)
194                                 usage();
195                         if (!(passwd = getpwnam(optarg)))
196                                 errx(1, "%s: unknown uid", optarg);
197                         what = KERN_PROC_UID;
198                         arg = passwd->pw_uid;
199                         break;
200                 case 'v':
201                         vflg = 1;
202                         break;
203                 case 'w':
204                         wflg_mnt = 40;
205                         wflg_cmd = 16;
206                         break;
207                 case '?':
208                 default:
209                         usage();
210                 }
211
212         if (*(argv += optind)) {
213                 for (; *argv; ++argv) {
214                         if (getfname(*argv))
215                                 checkfile = 1;
216                 }
217                 if (!checkfile) /* file(s) specified, but none accessable */
218                         exit(1);
219         }
220
221         ALLOC_OFILES(256);      /* reserve space for file pointers */
222
223         if (fsflg && !checkfile) {
224                 /* -f with no files means use wd */
225                 if (getfname(".") == 0)
226                         exit(1);
227                 checkfile = 1;
228         }
229
230         /*
231          * Discard setgid privileges if not the running kernel so that bad
232          * guys can't print interesting stuff from kernel memory.
233          */
234         if (nlistf != NULL || memf != NULL)
235                 setgid(getgid());
236
237         if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == NULL)
238                 errx(1, "%s", buf);
239 #ifdef notdef
240         if (kvm_nlist(kd, nl) != 0)
241                 errx(1, "no namelist: %s", kvm_geterr(kd));
242 #endif
243         if ((p = kvm_getprocs(kd, what, arg, &cnt)) == NULL)
244                 errx(1, "%s", kvm_geterr(kd));
245         if (nflg)
246                 printf("USER     %-*.*s %*.*s   FD DEV              %*.*s MODE   SZ|DV R/W", 
247                         wflg_cmd, wflg_cmd, "CMD",
248                         pid_width, pid_width, "PID",
249                         ino_width, ino_width, "INUM");
250         else
251                 printf("USER     %-*.*s %*.*s   FD %-*.*s %*.*s MODE           SZ|DV R/W", 
252                         wflg_cmd, wflg_cmd, "CMD", 
253                         pid_width, pid_width, "PID",
254                         wflg_mnt, wflg_mnt, "PATH",
255                         ino_width, ino_width, "INUM");
256         if (checkfile && fsflg == 0)
257                 printf(" NAME\n");
258         else
259                 putchar('\n');
260
261         for (plast = &p[cnt]; p < plast; ++p) {
262                 if (p->kp_stat == SZOMB)
263                         continue;
264                 if (!kread((void *)p->kp_paddr, &proc, sizeof(proc))) {
265                         dprintf(stderr, "can't read proc at %p for pid %d\n",
266                             (void *)p->kp_paddr, Pid);
267                         continue;
268                 }
269                 dofiles(p, &proc);
270                 if (mflg)
271                         dommap(&proc);
272         }
273         exit(0);
274 }
275
276 #define PREFIX(i) \
277         printf("%-8.8s %-*s %*d", Uname, wflg_cmd, Comm, pid_width, Pid); \
278         switch(i) { \
279         case TEXT: \
280                 printf(" text"); \
281                 break; \
282         case CDIR: \
283                 printf("   wd"); \
284                 break; \
285         case RDIR: \
286                 printf(" root"); \
287                 break; \
288         case TRACE: \
289                 printf("   tr"); \
290                 break; \
291         case MMAP: \
292                 printf(" mmap"); \
293                 break; \
294         default: \
295                 printf(" %4d", i); \
296                 break; \
297         }
298
299 /*
300  * print open files attributed to this process
301  */
302 static void
303 dofiles(struct kinfo_proc *kp, struct proc *p)
304 {
305         int i;
306         struct file file;
307         struct filedesc filed;
308         struct ktrace_node ktrace_node;
309
310         Uname = user_from_uid(kp->kp_uid, 0);
311         Pid = kp->kp_pid;
312         Comm = kp->kp_comm;
313         make_printable(Comm, strlen(Comm));
314
315         if (p->p_fd == NULL)
316                 return;
317         if (!kread(p->p_fd, &filed, sizeof (filed))) {
318                 dprintf(stderr, "can't read filedesc at %p for pid %d\n",
319                     (void *)p->p_fd, Pid);
320                 return;
321         }
322         /*
323          * root directory vnode, if one
324          */
325         if (filed.fd_rdir)
326                 vtrans(filed.fd_rdir, &filed.fd_nrdir, RDIR, FREAD, 0);
327         /*
328          * current working directory vnode
329          */
330         vtrans(filed.fd_cdir, &filed.fd_ncdir, CDIR, FREAD, 0);
331         /*
332          * ktrace vnode, if one
333          */
334         if (p->p_tracenode) {
335                 if (kread(p->p_tracenode, &ktrace_node, sizeof (ktrace_node)))
336                         vtrans(ktrace_node.kn_vp, NULL, TRACE, FREAD|FWRITE, 0);
337         }
338         /*
339          * text vnode, if one
340          */
341         if (p->p_textvp)
342                 vtrans(p->p_textvp, NULL, TEXT, FREAD, 0);
343         /*
344          * open files
345          */
346         ALLOC_OFILES(filed.fd_lastfile+1);
347         if (!kread(filed.fd_files, ofiles,
348             (filed.fd_lastfile+1) * sizeof(struct fdnode))) {
349                 dprintf(stderr,
350                     "can't read file structures at %p for pid %d\n",
351                     (void *)filed.fd_files, Pid);
352                 return;
353         }
354         for (i = 0; i <= filed.fd_lastfile; i++) {
355                 if (ofiles[i].fp == NULL)
356                         continue;
357                 if (!kread(ofiles[i].fp, &file, sizeof (struct file))) {
358                         dprintf(stderr, "can't read file %d at %p for pid %d\n",
359                             i, (void *)ofiles[i].fp, Pid);
360                         continue;
361                 }
362                 if (file.f_type == DTYPE_VNODE) {
363                         vtrans((struct vnode *)file.f_data, &file.f_nchandle,
364                                 i, file.f_flag, file.f_offset);
365                 } else if (file.f_type == DTYPE_SOCKET) {
366                         if (checkfile == 0)
367                                 socktrans((struct socket *)file.f_data, i);
368                 }
369 #ifdef DTYPE_PIPE
370                 else if (file.f_type == DTYPE_PIPE) {
371                         if (checkfile == 0)
372                                 pipetrans((struct pipe *)file.f_data, i,
373                                     file.f_flag);
374                 }
375 #endif
376 #ifdef DTYPE_FIFO
377                 else if (file.f_type == DTYPE_FIFO) {
378                         if (checkfile == 0)
379                                 vtrans((struct vnode *)file.f_data,
380                                         &file.f_nchandle,
381                                         i, file.f_flag, file.f_offset);
382                 }
383 #endif
384                 else {
385                         dprintf(stderr,
386                             "unknown file type %d for file %d of pid %d\n",
387                             file.f_type, i, Pid);
388                 }
389         }
390 }
391
392 static
393 vm_map_entry_t
394 kinfo_vm_map_entry_first(vm_map_t map, vm_map_entry_t copy)
395 {
396         vm_map_entry_t ken;
397
398         ken = map->rb_root.rbh_root;
399         if (ken == NULL)
400                 return NULL;
401         if (!kreadent(ken, copy))
402                 return NULL;
403         while (copy->rb_entry.rbe_left) {
404                 ken = copy->rb_entry.rbe_left;
405                 if (!kreadent(ken, copy))
406                         return NULL;
407         }
408         return ken;
409 }
410
411 static
412 vm_map_entry_t
413 kinfo_vm_map_entry_next(vm_map_entry_t ken, vm_map_entry_t copy)
414 {
415         vm_map_entry_t ken2;
416
417         if (copy->rb_entry.rbe_right) {
418                 ken = copy->rb_entry.rbe_right;
419                 if (!kreadent(ken, copy))
420                         return NULL;
421                 while (copy->rb_entry.rbe_left) {
422                         ken = copy->rb_entry.rbe_left;
423                         if (!kreadent(ken, copy))
424                                 return NULL;
425                 }
426         } else {
427                 if ((ken2 = copy->rb_entry.rbe_parent) == NULL)
428                         return NULL;
429                 if (!kreadent(ken2, copy))
430                         return NULL;
431                 if (ken == copy->rb_entry.rbe_left) {
432                         ken = ken2;
433                 } else {
434                         while (ken == copy->rb_entry.rbe_right) {
435                                 ken = ken2;
436                                 ken2 = copy->rb_entry.rbe_parent;
437                                 if (!kreadent(ken2, copy))
438                                         return NULL;
439                         }
440                         ken = ken2;
441                 }
442         }
443         return ken;
444 }
445
446 static void
447 dommap(struct proc *p)
448 {
449         struct vmspace vmspace;
450         vm_map_t map;
451         struct vm_map_entry entry;
452         vm_map_entry_t ken;
453         struct vm_object object;
454         vm_object_t objp;
455         int prot, fflags;
456
457         if (!kread(p->p_vmspace, &vmspace, sizeof(vmspace))) {
458                 dprintf(stderr, "can't read vmspace at %p for pid %d\n",
459                     (void *)p->p_vmspace, Pid);
460                 return;
461         }
462
463         map = &vmspace.vm_map;
464         for (ken = kinfo_vm_map_entry_first(map, &entry);
465              ken;
466              ken = kinfo_vm_map_entry_next(ken, &entry)) {
467                 if (entry.maptype == VM_MAPTYPE_SUBMAP)
468                         continue;
469
470                 if ((objp = entry.object.vm_object) == NULL)
471                         continue;
472
473                 for (; objp; objp = object.backing_object) {
474                         if (!kread(objp, &object, sizeof(object))) {
475                                 dprintf(stderr,
476                                     "can't read vm_object at %p for pid %d\n",
477                                     (void *)objp, Pid);
478                                 return;
479                         }
480                 }
481
482                 prot = entry.protection;
483                 fflags = (prot & VM_PROT_READ ? FREAD : 0) |
484                     (prot & VM_PROT_WRITE ? FWRITE : 0);
485
486                 switch (object.type) {
487                 case OBJT_VNODE:
488                         vtrans((struct vnode *)object.handle, NULL, 
489                                 MMAP, fflags, 0);
490                         break;
491                 default:
492                         break;
493                 }
494         }
495 }
496
497 static void
498 vtrans(struct vnode *vp, struct nchandle *ncr, int i, int flag, off_t off)
499 {
500         struct vnode vn;
501         struct filestat fst;
502         char rw[3], mode[15];
503         const char *badtype = NULL, *filename;
504         char *name;
505
506         fst.offset = off;
507         filename = badtype = NULL;
508         if (!kread(vp, &vn, sizeof (struct vnode))) {
509                 dprintf(stderr, "can't read vnode at %p for pid %d\n",
510                     (void *)vp, Pid);
511                 return;
512         }
513         if (vn.v_type == VNON || vn.v_tag == VT_NON)
514                 badtype = "none";
515         else if (vn.v_type == VBAD)
516                 badtype = "bad";
517         else
518                 switch (vn.v_tag) {
519                 case VT_HAMMER:
520                         if (!hammer_filestat(&vn, &fst))
521                                 badtype = "error";
522                         break;
523                 case VT_HAMMER2:
524                         if (!hammer2_filestat(&vn, &fst))
525                                 badtype = "error";
526                         break;
527                 case VT_TMPFS:
528                         if (!tmpfs_filestat(&vn, &fst))
529                                 badtype = "error";
530                         break;
531                 case VT_UFS:
532                         if (!ufs_filestat(&vn, &fst))
533                                 badtype = "error";
534                         break;
535                 case VT_MFS:
536                         if (!ufs_filestat(&vn, &fst))
537                                 badtype = "error";
538                         break;
539                 case VT_NFS:
540                         if (!nfs_filestat(&vn, &fst))
541                                 badtype = "error";
542                         break;
543                 case VT_NTFS:
544                         if (!ntfs_filestat(&vn, &fst))
545                                 badtype = "error";
546                         break;
547                 case VT_EXT2FS:
548                         if (!ext2fs_filestat(&vn, &fst))
549                                 badtype = "error";
550                         break;
551
552                 case VT_MSDOSFS:
553                         if (!msdosfs_filestat(&vn, &fst))
554                                 badtype = "error";
555                         break;
556
557                 case VT_ISOFS:
558                         if (!isofs_filestat(&vn, &fst))
559                                 badtype = "error";
560                         break;
561
562                 case VT_DEVFS:
563                         if (!devfs_filestat(&vn, &fst))
564                                 badtype = "error";
565                         break;
566
567                 default: {
568                         static char unknown[10];
569                         sprintf(unknown, "?(%x)", vn.v_tag);
570                         badtype=unknown;
571                         break;
572                 }
573         }
574         if (checkfile) {
575                 int fsmatch = 0;
576                 DEVS *d;
577
578                 if (badtype)
579                         return;
580                 for (d = devs; d != NULL; d = d->next)
581                         if (d->fsid == fst.fsid) {
582                                 fsmatch = 1;
583                                 if (d->ino == (ino_t)fst.fileid) {
584                                         filename = d->name;
585                                         break;
586                                 }
587                         }
588                 if (fsmatch == 0 || (filename == NULL && fsflg == 0))
589                         return;
590         }
591         PREFIX(i);
592         if (badtype) {
593                 (void)printf(" %-*s  %10s    %jd\n",
594                              wflg_mnt,
595                              getmnton(vn.v_mount, &vn.v_namecache, ncr),
596                              badtype,
597                              (intmax_t)off);
598                 return;
599         }
600         if (nflg)
601                 printf(" %3u,%-9u   ",
602                        major(fst.fsid), minor(fst.fsid));
603         else
604                 printf(" %-*s",
605                        wflg_mnt, getmnton(vn.v_mount, &vn.v_namecache, ncr));
606         if (nflg)
607                 sprintf(mode, "%o", fst.mode);
608         else
609                 strmode(fst.mode, mode);
610
611         printf(" %*ld %10s", ino_width, fst.fileid, mode);
612
613         switch (vn.v_type) {
614         case VBLK:
615         case VCHR:
616                 if (nflg || ((name = devname(fst.rdev, vn.v_type == VCHR ?
617                     S_IFCHR : S_IFBLK)) == NULL))
618                         printf(" %3u,%-4u", major(fst.rdev), minor(fst.rdev));
619                 else
620                         printf(" %8s", name);
621                 break;
622         case VREG:
623                 printf(" %jd", (intmax_t)fst.offset);
624                 break;
625         default:
626                 printf(" %8ju", (uintmax_t)fst.size);
627         }
628         rw[0] = '\0';
629         if (flag & FREAD)
630                 strcat(rw, "r");
631         if (flag & FWRITE)
632                 strcat(rw, "w");
633         printf(" %2s", rw);
634         if (filename && !fsflg)
635                 printf("  %s", filename);
636         putchar('\n');
637 }
638
639 static int
640 ufs_filestat(struct vnode *vp, struct filestat *fsp)
641 {
642         struct inode inode;
643
644         if (!kread(VTOI(vp), &inode, sizeof (inode))) {
645                 dprintf(stderr, "can't read inode at %p for pid %d\n",
646                     (void *)VTOI(vp), Pid);
647                 return 0;
648         }
649         /*
650          * The st_dev from stat(2) is a udev_t. These kernel structures
651          * contain dev_t structures. We need to convert to udev to make
652          * comparisons
653          */
654         fsp->fsid = dev2udev(inode.i_dev);
655         fsp->fileid = (long)inode.i_number;
656         fsp->mode = (mode_t)inode.i_mode;
657         fsp->size = inode.i_size;
658         fsp->rdev = inode.i_rdev;
659
660         return 1;
661 }
662
663 static int
664 nfs_filestat(struct vnode *vp, struct filestat *fsp)
665 {
666         struct nfsnode nfsnode;
667
668         if (!kread(VTONFS(vp), &nfsnode, sizeof (nfsnode))) {
669                 dprintf(stderr, "can't read nfsnode at %p for pid %d\n",
670                     (void *)VTONFS(vp), Pid);
671                 return 0;
672         }
673         fsp->fsid = nfsnode.n_vattr.va_fsid;
674         fsp->fileid = nfsnode.n_vattr.va_fileid;
675         fsp->size = nfsnode.n_size;
676         fsp->rdev = makeudev(nfsnode.n_vattr.va_rmajor,
677                              nfsnode.n_vattr.va_rminor);
678         fsp->mode = nfsnode.n_vattr.va_mode | mtrans(vp->v_type);
679
680         return 1;
681 }
682
683 static int
684 devfs_filestat(struct vnode *vp, struct filestat *fsp)
685 {
686         struct devfs_node devfs_node;
687
688         if (!kread(vp->v_data, &devfs_node, sizeof (devfs_node))) {
689                 dprintf(stderr, "can't read devfs_node at %p for pid %d\n",
690                     (void *)vp->v_data, Pid);
691                 return 0;
692         }
693         fsp->fsid = fsp->rdev = dev2udev(vp->v_rdev);
694         fsp->fileid = devfs_node.d_dir.d_ino;
695         fsp->mode = (devfs_node.mode & ~S_IFMT) | S_IFCHR;
696         fsp->size = 0;
697
698         return 1;
699 }
700
701 static char *
702 getmnton(struct mount *m, struct namecache_list *ncplist, struct nchandle *ncr)
703 {
704         static struct mount mount_l;
705         static struct mtab {
706                 struct mtab *next;
707                 struct mount *m;
708                 char mntonname[MNAMELEN];
709         } *mhead = NULL;
710         struct mtab *mt;
711         struct namecache *ncp;
712         struct namecache ncp_copy;
713         static char path[1024];
714         int i;
715
716         /*
717          * If no ncp is passed try to find one via ncplist.  Make sure
718          * we are using the correct mount pointer or the matching code
719          * will not know how to transition mount points properly.
720          */
721         if (ncr == NULL || ncr->ncp == NULL) {
722                 ncp = ncplist->tqh_first;
723         } else {
724                 ncp = ncr->ncp;
725                 if (ncr->mount)
726                         m = ncr->mount;
727         }
728
729         /*
730          * If we have an ncp, traceback the path.  This is a kvm pointer.
731          */
732         if (ncp) {
733                 if (!kread(m, &mount_l, sizeof(struct mount))) {
734                         warnx("can't read mount table at %p", (void *)m);
735                         return (NULL);
736                 }
737                 i = sizeof(path) - 1;
738                 path[i] = 0;
739                 while (ncp) {
740                         /*
741                          * If this is the root of the mount then traverse
742                          * to the parent mount.
743                          */
744                         if (ncp == mount_l.mnt_ncmountpt.ncp) {
745                                 ncp = mount_l.mnt_ncmounton.ncp;
746                                 if (ncp == NULL)
747                                         break;
748                                 m = mount_l.mnt_ncmounton.mount;
749                                 if (!kread(m, &mount_l, sizeof(struct mount))) {
750                                         warnx("can't read mount table at %p", (void *)m);
751                                         return (NULL);
752                                 }
753                         }
754
755                         /*
756                          * Ok, pull out the ncp and extract the name
757                          */
758                         if (!kread(ncp, &ncp_copy, sizeof(ncp_copy))) {
759                                 warnx("can't read ncp at %p", ncp);
760                                 return (NULL);
761                         }
762                         if (i <= ncp_copy.nc_nlen)
763                                 break;
764                         i -= ncp_copy.nc_nlen;
765                         if (!kread(ncp_copy.nc_name, path + i, ncp_copy.nc_nlen)) {
766                                 warnx("can't read ncp %p path component at %p", ncp, ncp_copy.nc_name);
767                                 return (NULL);
768                         }
769                         make_printable(path + i, ncp_copy.nc_nlen);
770                         path[--i] = '/';
771                         ncp = ncp_copy.nc_parent;
772                 }
773                 if (i == sizeof(path) - 1)
774                         path[--i] = '/';
775                 return(path + i);
776         }
777
778         /*
779          * If all else fails print out the mount point path
780          */
781         for (mt = mhead; mt != NULL; mt = mt->next) {
782                 if (m == mt->m)
783                         return (mt->mntonname);
784         }
785         if (!kread(m, &mount_l, sizeof(struct mount))) {
786                 warnx("can't read mount table at %p", (void *)m);
787                 return (NULL);
788         }
789         if ((mt = malloc(sizeof (struct mtab))) == NULL)
790                 err(1, NULL);
791         mt->m = m;
792         bcopy(&mount_l.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN);
793         mt->next = mhead;
794         mhead = mt;
795         return (mt->mntonname);
796 }
797
798 static void
799 pipetrans(struct pipe *pi, int i, int flag)
800 {
801         struct pipe pip;
802         struct pipebuf *b1;
803         struct pipebuf *b2;
804         char rw[3];
805         char side1;
806         char side2;
807
808         PREFIX(i);
809         if ((intptr_t)pi & 1) {
810                 side1 = 'B';
811                 side2 = 'A';
812                 b1 = &pip.bufferB;
813                 b2 = &pip.bufferA;
814         } else {
815                 side1 = 'A';
816                 side2 = 'B';
817                 b1 = &pip.bufferA;
818                 b2 = &pip.bufferB;
819         }
820         pi = (void *)((intptr_t)pi & ~(intptr_t)1);
821
822         /* fill in socket */
823         if (!kread(pi, &pip, sizeof(struct pipe))) {
824                 dprintf(stderr, "can't read pipe at %p\n", (void *)pi);
825                 goto bad;
826         }
827
828         printf("* pipe %8lx (%c<->%c)", (u_long)pi, side1, side2);
829         printf(" ravail %-zd wavail %-zd",
830                b1->windex - b1->rindex,
831                b2->windex - b2->rindex);
832         rw[0] = '\0';
833         if (flag & FREAD)
834                 strcat(rw, "r");
835         if (flag & FWRITE)
836                 strcat(rw, "w");
837         printf(" %2s", rw);
838         putchar('\n');
839         return;
840
841 bad:
842         printf("* error\n");
843 }
844
845 static void
846 socktrans(struct socket *sock, int i)
847 {
848         static const char *stypename[] = {
849                 "unused",       /* 0 */
850                 "stream",       /* 1 */
851                 "dgram",        /* 2 */
852                 "raw",          /* 3 */
853                 "rdm",          /* 4 */
854                 "seqpak"        /* 5 */
855         };
856 #define STYPEMAX 5
857         struct socket   so;
858         struct protosw  proto;
859         struct domain   dom;
860         struct inpcb    inpcb;
861         struct unpcb    unpcb;
862         int len;
863         char dname[32];
864
865         PREFIX(i);
866
867         /* fill in socket */
868         if (!kread(sock, &so, sizeof(struct socket))) {
869                 dprintf(stderr, "can't read sock at %p\n", (void *)sock);
870                 goto bad;
871         }
872
873         /* fill in protosw entry */
874         if (!kread(so.so_proto, &proto, sizeof(struct protosw))) {
875                 dprintf(stderr, "can't read protosw at %p",
876                     (void *)so.so_proto);
877                 goto bad;
878         }
879
880         /* fill in domain */
881         if (!kread(proto.pr_domain, &dom, sizeof(struct domain))) {
882                 dprintf(stderr, "can't read domain at %p\n",
883                     (const void *)proto.pr_domain);
884                 goto bad;
885         }
886
887         if ((len = kvm_read(kd, (u_long)dom.dom_name, dname,
888             sizeof(dname) - 1)) < 0) {
889                 dprintf(stderr, "can't read domain name at %p\n",
890                     (void *)dom.dom_name);
891                 dname[0] = '\0';
892         }
893         else
894                 dname[len] = '\0';
895
896         if ((u_short)so.so_type > STYPEMAX)
897                 printf("* %s ?%d", dname, so.so_type);
898         else
899                 printf("* %s %s", dname, stypename[so.so_type]);
900
901         /*
902          * protocol specific formatting
903          *
904          * Try to find interesting things to print.  For tcp, the interesting
905          * thing is the address of the tcpcb, for udp and others, just the
906          * inpcb (socket pcb).  For unix domain, its the address of the socket
907          * pcb and the address of the connected pcb (if connected).  Otherwise
908          * just print the protocol number and address of the socket itself.
909          * The idea is not to duplicate netstat, but to make available enough
910          * information for further analysis.
911          */
912         switch(dom.dom_family) {
913         case AF_INET:
914         case AF_INET6:
915                 getinetproto(proto.pr_protocol);
916                 if (proto.pr_protocol == IPPROTO_TCP ) {
917                         if (so.so_pcb) {
918                                 if (kvm_read(kd, (u_long)so.so_pcb,
919                                     (char *)&inpcb, sizeof(struct inpcb))
920                                     != sizeof(struct inpcb)) {
921                                         dprintf(stderr,
922                                             "can't read inpcb at %p\n",
923                                             (void *)so.so_pcb);
924                                         goto bad;
925                                 }
926                                 printf(" %lx", (u_long)inpcb.inp_ppcb);
927                         }
928                 }
929                 else if (so.so_pcb)
930                         printf(" %lx", (u_long)so.so_pcb);
931                 break;
932         case AF_UNIX:
933                 /* print address of pcb and connected pcb */
934                 if (so.so_pcb) {
935                         printf(" %lx", (u_long)so.so_pcb);
936                         if (kvm_read(kd, (u_long)so.so_pcb, (char *)&unpcb,
937                             sizeof(struct unpcb)) != sizeof(struct unpcb)){
938                                 dprintf(stderr, "can't read unpcb at %p\n",
939                                     (void *)so.so_pcb);
940                                 goto bad;
941                         }
942                         if (unpcb.unp_conn) {
943                                 char shoconn[4], *cp;
944
945                                 cp = shoconn;
946                                 if (!(so.so_state & SS_CANTRCVMORE))
947                                         *cp++ = '<';
948                                 *cp++ = '-';
949                                 if (!(so.so_state & SS_CANTSENDMORE))
950                                         *cp++ = '>';
951                                 *cp = '\0';
952                                 printf(" %s %lx", shoconn,
953                                     (u_long)unpcb.unp_conn);
954                         }
955                 }
956                 break;
957         default:
958                 /* print protocol number and socket address */
959                 printf(" %d %lx", proto.pr_protocol, (u_long)sock);
960         }
961         printf("\n");
962         return;
963 bad:
964         printf("* error\n");
965 }
966
967
968 /*
969  * Read the cdev structure in the kernel (as pointed to by a dev_t)
970  * in order to work out the associated udev_t
971  */
972 udev_t
973 dev2udev(void *dev)
974 {
975         struct cdev si;
976
977         if (kread(dev, &si, sizeof si)) {
978                 if ((si.si_umajor & 0xffffff00) ||
979                     (si.si_uminor & 0x0000ff00)) {
980                         return NOUDEV;
981                 }
982                 return((si.si_umajor << 8) | si.si_uminor);
983         } else {
984                 dprintf(stderr, "can't convert dev_t %p to a udev_t\n", dev);
985                 return NOUDEV;
986         }
987 }
988
989 udev_t
990 makeudev(int x, int y)
991 {
992         if ((x & 0xffffff00) || (y & 0x0000ff00))
993                 return NOUDEV;
994         return ((x << 8) | y);
995 }
996
997 /*
998  * getinetproto --
999  *      print name of protocol number
1000  */
1001 static void
1002 getinetproto(int number)
1003 {
1004         static int isopen;
1005         struct protoent *pe;
1006
1007         if (!isopen)
1008                 setprotoent(++isopen);
1009         if ((pe = getprotobynumber(number)) != NULL)
1010                 printf(" %s", pe->p_name);
1011         else
1012                 printf(" %d", number);
1013 }
1014
1015 static int
1016 getfname(const char *filename)
1017 {
1018         struct stat statbuf;
1019         DEVS *cur;
1020
1021         if (stat(filename, &statbuf)) {
1022                 warn("%s", filename);
1023                 return(0);
1024         }
1025         if ((cur = malloc(sizeof(DEVS))) == NULL)
1026                 err(1, NULL);
1027         cur->next = devs;
1028         devs = cur;
1029
1030         cur->ino = statbuf.st_ino;
1031         cur->fsid = statbuf.st_dev;
1032         cur->name = filename;
1033         return(1);
1034 }
1035
1036 static void
1037 usage(void)
1038 {
1039         (void)fprintf(stderr,
1040  "usage: fstat [-fmnv] [-p pid] [-u user] [-N system] [-M core] [file ...]\n");
1041         exit(1);
1042 }
1043
1044 static 
1045 void
1046 make_printable(char *buf, int len)
1047 {
1048     while (len > 0) {
1049         if (!isprint(*buf)) 
1050                 *buf = '?';
1051         ++buf;
1052         --len;
1053     }
1054 }
1055
1056 ssize_t
1057 kread(const void *kaddr, void *uaddr, size_t nbytes)
1058 {
1059     if (nbytes > 0x10000000)
1060         return(0);
1061
1062     if (kvm_read(kd, (u_long)kaddr, (char *)uaddr, nbytes) == (ssize_t)nbytes)
1063         return(1);
1064     else
1065         return(0);
1066 }
1067
1068 static
1069 int
1070 kreadent(const void *kaddr, vm_map_entry_t copy)
1071 {
1072         if (kread(kaddr, copy, sizeof(*copy)))
1073                 return 1;
1074         dprintf(stderr, "can't read vm_map_entry at %p for pid %d\n",
1075                 kaddr, Pid);
1076         return 0;
1077 }