Annotation of src/usr.bin/fstat/fstat.c, Revision 1.38
1.38 ! deraadt 1: /* $OpenBSD: fstat.c,v 1.37 2002/05/18 17:54:15 deraadt Exp $ */
1.2 niklas 2:
1.1 deraadt 3: /*-
4: * Copyright (c) 1988, 1993
5: * The Regents of the University of California. All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by the University of
18: * California, Berkeley and its contributors.
19: * 4. Neither the name of the University nor the names of its contributors
20: * may be used to endorse or promote products derived from this software
21: * without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: */
35:
36: #ifndef lint
37: static char copyright[] =
38: "@(#) Copyright (c) 1988, 1993\n\
39: The Regents of the University of California. All rights reserved.\n";
40: #endif /* not lint */
41:
42: #ifndef lint
43: /*static char sccsid[] = "from: @(#)fstat.c 8.1 (Berkeley) 6/6/93";*/
1.38 ! deraadt 44: static char *rcsid = "$OpenBSD: fstat.c,v 1.37 2002/05/18 17:54:15 deraadt Exp $";
1.1 deraadt 45: #endif /* not lint */
46:
47: #include <sys/param.h>
48: #include <sys/time.h>
49: #include <sys/proc.h>
50: #include <sys/user.h>
51: #include <sys/stat.h>
52: #include <sys/vnode.h>
53: #include <sys/socket.h>
54: #include <sys/socketvar.h>
55: #include <sys/domain.h>
56: #include <sys/protosw.h>
1.37 deraadt 57: #include <sys/event.h>
58: #include <sys/eventvar.h>
1.1 deraadt 59: #include <sys/unpcb.h>
60: #include <sys/sysctl.h>
61: #include <sys/filedesc.h>
1.23 deraadt 62: #include <sys/mount.h>
1.38 ! deraadt 63: #define _KERNEL
1.37 deraadt 64: #include <crypto/cryptodev.h>
1.38 ! deraadt 65: #include <dev/systrace.h>
1.1 deraadt 66: #include <sys/file.h>
67: #include <ufs/ufs/quota.h>
68: #include <ufs/ufs/inode.h>
1.23 deraadt 69: #include <miscfs/nullfs/null.h>
1.1 deraadt 70: #undef _KERNEL
71: #define NFS
1.2 niklas 72: #include <nfs/nfsproto.h>
1.1 deraadt 73: #include <nfs/rpcv2.h>
74: #include <nfs/nfs.h>
75: #include <nfs/nfsnode.h>
76: #undef NFS
77:
1.29 deraadt 78: #include <xfs/xfs_config.h>
1.18 art 79: #include <xfs/xfs_node.h>
80:
1.1 deraadt 81: #include <net/route.h>
82: #include <netinet/in.h>
83: #include <netinet/in_systm.h>
84: #include <netinet/ip.h>
85: #include <netinet/in_pcb.h>
86:
1.26 itojun 87: #ifdef INET6
88: #include <netinet/ip6.h>
89: #include <netinet6/ip6_var.h>
90: #endif
91:
92: #include <netdb.h>
1.5 deraadt 93: #include <arpa/inet.h>
94:
1.22 art 95: #include <sys/pipe.h>
96:
1.1 deraadt 97: #include <ctype.h>
98: #include <errno.h>
99: #include <kvm.h>
1.2 niklas 100: #include <limits.h>
1.1 deraadt 101: #include <nlist.h>
102: #include <paths.h>
103: #include <pwd.h>
104: #include <stdio.h>
105: #include <stdlib.h>
106: #include <string.h>
1.11 millert 107: #include <unistd.h>
1.24 deraadt 108: #include <netdb.h>
1.17 mickey 109: #include <err.h>
1.14 deraadt 110: #include "fstat.h"
1.1 deraadt 111:
112: #define TEXT -1
113: #define CDIR -2
114: #define RDIR -3
115: #define TRACE -4
116:
117: typedef struct devs {
118: struct devs *next;
119: long fsid;
120: ino_t ino;
121: char *name;
122: } DEVS;
123: DEVS *devs;
124:
1.38 ! deraadt 125: int fsflg, /* show files on same filesystem as file(s) argument */
1.1 deraadt 126: pflg, /* show files open by a particular pid */
127: uflg; /* show files open by a particular (effective) user */
1.38 ! deraadt 128: int checkfile; /* true if restricting to particular files or filesystems */
1.1 deraadt 129: int nflg; /* (numerical) display f.s. and rdev as dev_t */
1.28 hugh 130: int oflg; /* display file offset */
1.1 deraadt 131: int vflg; /* display errors in locating kernel data objects etc... */
132:
133: struct file **ofiles; /* buffer of pointers to file structures */
134: int maxfiles;
135: #define ALLOC_OFILES(d) \
136: if ((d) > maxfiles) { \
137: free(ofiles); \
138: ofiles = malloc((d) * sizeof(struct file *)); \
1.17 mickey 139: if (ofiles == NULL) \
140: err(1, "malloc"); \
1.1 deraadt 141: maxfiles = (d); \
142: }
143:
144: /*
1.34 deraadt 145: * a kvm_read that returns true if everything is read
1.1 deraadt 146: */
147: #define KVM_READ(kaddr, paddr, len) \
1.11 millert 148: (kvm_read(kd, (u_long)(kaddr), (void *)(paddr), (len)) == (len))
1.1 deraadt 149:
150: kvm_t *kd;
151:
1.35 millert 152: int ufs_filestat(struct vnode *, struct filestat *);
153: int ext2fs_filestat(struct vnode *, struct filestat *);
154: int isofs_filestat(struct vnode *, struct filestat *);
155: int msdos_filestat(struct vnode *, struct filestat *);
156: int nfs_filestat(struct vnode *, struct filestat *);
157: int xfs_filestat(struct vnode *, struct filestat *);
158: int null_filestat(struct vnode *, struct filestat *);
159: void dofiles(struct kinfo_proc *);
160: void getinetproto(int);
161: void socktrans(struct socket *, int);
162: void usage(void);
163: void vtrans(struct vnode *, int, int, off_t);
164: int getfname(char *);
165: void pipetrans(struct pipe *, int);
1.37 deraadt 166: void kqueuetrans(struct kqueue *, int);
167: void cryptotrans(void *, int i);
1.38 ! deraadt 168: void systracetrans(struct fsystrace *, int i);
1.1 deraadt 169:
1.11 millert 170: int
1.1 deraadt 171: main(argc, argv)
172: int argc;
173: char **argv;
174: {
175: extern char *optarg;
176: extern int optind;
1.32 mpech 177: struct passwd *passwd;
1.1 deraadt 178: struct kinfo_proc *p, *plast;
179: int arg, ch, what;
180: char *memf, *nlistf;
1.2 niklas 181: char buf[_POSIX2_LINE_MAX];
1.1 deraadt 182: int cnt;
183:
184: arg = 0;
185: what = KERN_PROC_ALL;
186: nlistf = memf = NULL;
1.28 hugh 187: oflg = 0;
188: while ((ch = getopt(argc, argv, "fnop:u:vN:M:")) != -1)
1.1 deraadt 189: switch((char)ch) {
190: case 'f':
191: fsflg = 1;
192: break;
193: case 'M':
194: memf = optarg;
195: break;
196: case 'N':
197: nlistf = optarg;
198: break;
199: case 'n':
200: nflg = 1;
201: break;
1.28 hugh 202: case 'o':
203: oflg = 1;
204: break;
1.1 deraadt 205: case 'p':
206: if (pflg++)
207: usage();
208: if (!isdigit(*optarg)) {
1.36 mpech 209: warnx( "-p requires a process id");
1.1 deraadt 210: usage();
211: }
212: what = KERN_PROC_PID;
213: arg = atoi(optarg);
214: break;
215: case 'u':
216: if (uflg++)
217: usage();
1.17 mickey 218: if (!(passwd = getpwnam(optarg)))
1.21 deraadt 219: errx(1, "%s: unknown uid", optarg);
1.1 deraadt 220: what = KERN_PROC_UID;
221: arg = passwd->pw_uid;
222: break;
223: case 'v':
224: vflg = 1;
225: break;
226: default:
227: usage();
228: }
229:
230: if (*(argv += optind)) {
231: for (; *argv; ++argv) {
232: if (getfname(*argv))
233: checkfile = 1;
234: }
1.30 pvalchev 235: if (!checkfile) /* file(s) specified, but none accessible */
1.1 deraadt 236: exit(1);
237: }
238:
239: ALLOC_OFILES(256); /* reserve space for file pointers */
240:
1.34 deraadt 241: if (fsflg && !checkfile) {
1.1 deraadt 242: /* -f with no files means use wd */
243: if (getfname(".") == 0)
244: exit(1);
245: checkfile = 1;
246: }
247:
248: /*
249: * Discard setgid privileges if not the running kernel so that bad
250: * guys can't print interesting stuff from kernel memory.
251: */
1.7 tholo 252: if (nlistf != NULL || memf != NULL) {
253: setegid(getgid());
1.1 deraadt 254: setgid(getgid());
1.7 tholo 255: }
1.1 deraadt 256:
1.17 mickey 257: if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == NULL)
1.21 deraadt 258: errx(1, "%s", buf);
1.16 deraadt 259:
260: setegid(getgid());
261: setgid(getgid());
262:
1.17 mickey 263: if ((p = kvm_getprocs(kd, what, arg, &cnt)) == NULL)
1.21 deraadt 264: errx(1, "%s", kvm_geterr(kd));
1.1 deraadt 265: if (nflg)
266: printf("%s",
1.28 hugh 267: "USER CMD PID FD DEV INUM MODE R/W DV|SZ");
1.1 deraadt 268: else
269: printf("%s",
1.28 hugh 270: "USER CMD PID FD MOUNT INUM MODE R/W DV|SZ");
271: if (oflg)
272: printf("%s", ":OFFSET ");
1.1 deraadt 273: if (checkfile && fsflg == 0)
274: printf(" NAME\n");
275: else
276: putchar('\n');
277:
278: for (plast = &p[cnt]; p < plast; ++p) {
279: if (p->kp_proc.p_stat == SZOMB)
280: continue;
281: dofiles(p);
282: }
283: exit(0);
284: }
285:
286: char *Uname, *Comm;
1.14 deraadt 287: pid_t Pid;
1.1 deraadt 288:
1.34 deraadt 289: #define PREFIX(i) do { \
290: printf("%-8.8s %-10s %5d", Uname, Comm, Pid); \
1.1 deraadt 291: switch(i) { \
292: case TEXT: \
293: printf(" text"); \
294: break; \
295: case CDIR: \
296: printf(" wd"); \
297: break; \
298: case RDIR: \
299: printf(" root"); \
300: break; \
301: case TRACE: \
302: printf(" tr"); \
303: break; \
304: default: \
305: printf(" %4d", i); \
306: break; \
1.34 deraadt 307: } \
308: } while (0)
1.1 deraadt 309:
310: /*
311: * print open files attributed to this process
312: */
313: void
314: dofiles(kp)
315: struct kinfo_proc *kp;
316: {
1.11 millert 317: int i;
1.1 deraadt 318: struct file file;
319: struct filedesc0 filed0;
320: #define filed filed0.fd_fd
321: struct proc *p = &kp->kp_proc;
322: struct eproc *ep = &kp->kp_eproc;
323: extern char *user_from_uid();
324:
325: Uname = user_from_uid(ep->e_ucred.cr_uid, 0);
326: Pid = p->p_pid;
327: Comm = p->p_comm;
328:
329: if (p->p_fd == NULL)
330: return;
331: if (!KVM_READ(p->p_fd, &filed0, sizeof (filed0))) {
1.17 mickey 332: dprintf("can't read filedesc at %p for pid %d", p->p_fd, Pid);
1.1 deraadt 333: return;
334: }
335: if (filed.fd_nfiles < 0 || filed.fd_lastfile >= filed.fd_nfiles ||
336: filed.fd_freefile > filed.fd_lastfile + 1) {
1.17 mickey 337: dprintf("filedesc corrupted at %p for pid %d", p->p_fd, Pid);
1.1 deraadt 338: return;
339: }
340: /*
341: * root directory vnode, if one
342: */
343: if (filed.fd_rdir)
1.28 hugh 344: vtrans(filed.fd_rdir, RDIR, FREAD, 0);
1.1 deraadt 345: /*
346: * current working directory vnode
347: */
1.28 hugh 348: vtrans(filed.fd_cdir, CDIR, FREAD, 0);
1.1 deraadt 349: /*
350: * ktrace vnode, if one
351: */
352: if (p->p_tracep)
1.28 hugh 353: vtrans(p->p_tracep, TRACE, FREAD|FWRITE, 0);
1.1 deraadt 354: /*
355: * open files
356: */
357: #define FPSIZE (sizeof (struct file *))
358: ALLOC_OFILES(filed.fd_lastfile+1);
359: if (filed.fd_nfiles > NDFILE) {
360: if (!KVM_READ(filed.fd_ofiles, ofiles,
361: (filed.fd_lastfile+1) * FPSIZE)) {
1.17 mickey 362: dprintf("can't read file structures at %p for pid %d",
1.1 deraadt 363: filed.fd_ofiles, Pid);
364: return;
365: }
366: } else
367: bcopy(filed0.fd_dfiles, ofiles, (filed.fd_lastfile+1) * FPSIZE);
368: for (i = 0; i <= filed.fd_lastfile; i++) {
369: if (ofiles[i] == NULL)
370: continue;
371: if (!KVM_READ(ofiles[i], &file, sizeof (struct file))) {
1.17 mickey 372: dprintf("can't read file %d at %p for pid %d",
1.1 deraadt 373: i, ofiles[i], Pid);
374: continue;
375: }
376: if (file.f_type == DTYPE_VNODE)
1.38 ! deraadt 377: vtrans((struct vnode *)file.f_data, i, file.f_flag,
! 378: file.f_offset);
1.1 deraadt 379: else if (file.f_type == DTYPE_SOCKET) {
380: if (checkfile == 0)
381: socktrans((struct socket *)file.f_data, i);
1.22 art 382: } else if (file.f_type == DTYPE_PIPE) {
383: if (checkfile == 0)
384: pipetrans((struct pipe *)file.f_data, i);
1.37 deraadt 385: } else if (file.f_type == DTYPE_KQUEUE) {
386: if (checkfile == 0)
387: kqueuetrans((struct kqueue *)file.f_data, i);
388: } else if (file.f_type == DTYPE_CRYPTO) {
389: if (checkfile == 0)
390: cryptotrans(file.f_data, i);
391: } else if (file.f_type == DTYPE_SYSTRACE) {
392: if (checkfile == 0)
1.38 ! deraadt 393: systracetrans((struct fsystrace *)file.f_data, i);
1.22 art 394: } else {
1.17 mickey 395: dprintf("unknown file type %d for file %d of pid %d",
1.1 deraadt 396: file.f_type, i, Pid);
397: }
398: }
399: }
400:
401: void
1.28 hugh 402: vtrans(vp, i, flag, offset)
1.1 deraadt 403: struct vnode *vp;
404: int i;
405: int flag;
1.28 hugh 406: off_t offset;
1.1 deraadt 407: {
408: struct vnode vn;
409: struct filestat fst;
1.12 deraadt 410: char rw[3], mode[17];
1.1 deraadt 411: char *badtype = NULL, *filename, *getmnton();
412:
413: filename = badtype = NULL;
414: if (!KVM_READ(vp, &vn, sizeof (struct vnode))) {
1.17 mickey 415: dprintf("can't read vnode at %p for pid %d", vp, Pid);
1.1 deraadt 416: return;
417: }
418: if (vn.v_type == VNON || vn.v_tag == VT_NON)
419: badtype = "none";
420: else if (vn.v_type == VBAD)
421: badtype = "bad";
422: else
423: switch (vn.v_tag) {
424: case VT_UFS:
425: case VT_MFS:
426: if (!ufs_filestat(&vn, &fst))
427: badtype = "error";
428: break;
429: case VT_NFS:
430: if (!nfs_filestat(&vn, &fst))
431: badtype = "error";
432: break;
1.9 downsj 433: case VT_EXT2FS:
434: if (!ext2fs_filestat(&vn, &fst))
435: badtype = "error";
436: break;
1.14 deraadt 437: case VT_ISOFS:
438: if (!isofs_filestat(&vn, &fst))
439: badtype = "error";
440: break;
441: case VT_MSDOSFS:
442: if (!msdos_filestat(&vn, &fst))
443: badtype = "error";
444: break;
1.18 art 445: case VT_XFS:
446: if (!xfs_filestat(&vn, &fst))
447: badtype = "error";
448: break;
1.23 deraadt 449: case VT_NULL:
450: if (!null_filestat(&vn, &fst))
451: badtype = "error";
1.34 deraadt 452: break;
1.1 deraadt 453: default: {
1.12 deraadt 454: static char unknown[30];
1.34 deraadt 455: snprintf(badtype = unknown, sizeof unknown,
456: "?(%x)", vn.v_tag);
1.10 deraadt 457: break;
1.1 deraadt 458: }
459: }
460: if (checkfile) {
461: int fsmatch = 0;
1.32 mpech 462: DEVS *d;
1.1 deraadt 463:
464: if (badtype)
465: return;
466: for (d = devs; d != NULL; d = d->next)
467: if (d->fsid == fst.fsid) {
468: fsmatch = 1;
469: if (d->ino == fst.fileid) {
470: filename = d->name;
471: break;
472: }
473: }
474: if (fsmatch == 0 || (filename == NULL && fsflg == 0))
475: return;
476: }
477: PREFIX(i);
478: if (badtype) {
479: (void)printf(" - - %10s -\n", badtype);
480: return;
481: }
482: if (nflg)
1.31 deraadt 483: (void)printf(" %2ld,%-2ld", (long)major(fst.fsid),
484: (long)minor(fst.fsid));
1.1 deraadt 485: else
486: (void)printf(" %-8s", getmnton(vn.v_mount));
487: if (nflg)
1.34 deraadt 488: (void)snprintf(mode, sizeof mode, "%o", fst.mode);
1.1 deraadt 489: else
490: strmode(fst.mode, mode);
1.28 hugh 491: (void)printf(" %6ld %11s", fst.fileid, mode);
492: rw[0] = '\0';
493: if (flag & FREAD)
1.34 deraadt 494: strlcat(rw, "r", sizeof rw);
1.28 hugh 495: if (flag & FWRITE)
1.34 deraadt 496: strlcat(rw, "w", sizeof rw);
1.28 hugh 497: printf(" %2s", rw);
1.1 deraadt 498: switch (vn.v_type) {
499: case VBLK:
500: case VCHR: {
501: char *name;
502:
1.34 deraadt 503: if (nflg || ((name = devname(fst.rdev, vn.v_type == VCHR ?
1.1 deraadt 504: S_IFCHR : S_IFBLK)) == NULL))
1.28 hugh 505: printf(" %2d,%-3d", major(fst.rdev), minor(fst.rdev));
1.1 deraadt 506: else
1.28 hugh 507: printf(" %7s", name);
508: if (oflg)
509: printf(" ");
1.1 deraadt 510: break;
511: }
512: default:
1.31 deraadt 513: printf(" %8lld", (long long)fst.size);
1.28 hugh 514: if (oflg)
1.31 deraadt 515: printf(":%-8lld", (long long)offset);
1.1 deraadt 516: }
517: if (filename && !fsflg)
1.28 hugh 518: printf(" %s", filename);
1.1 deraadt 519: putchar('\n');
520: }
521:
522: int
523: ufs_filestat(vp, fsp)
524: struct vnode *vp;
525: struct filestat *fsp;
526: {
527: struct inode inode;
528:
529: if (!KVM_READ(VTOI(vp), &inode, sizeof (inode))) {
1.17 mickey 530: dprintf("can't read inode at %p for pid %d", VTOI(vp), Pid);
1.1 deraadt 531: return 0;
532: }
533: fsp->fsid = inode.i_dev & 0xffff;
534: fsp->fileid = (long)inode.i_number;
1.11 millert 535: fsp->mode = inode.i_ffs_mode;
536: fsp->size = inode.i_ffs_size;
1.9 downsj 537: fsp->rdev = inode.i_ffs_rdev;
538:
539: return 1;
540: }
541:
542: int
543: ext2fs_filestat(vp, fsp)
544: struct vnode *vp;
545: struct filestat *fsp;
546: {
547: struct inode inode;
548:
549: if (!KVM_READ(VTOI(vp), &inode, sizeof (inode))) {
1.17 mickey 550: dprintf("can't read inode at %p for pid %d", VTOI(vp), Pid);
1.9 downsj 551: return 0;
552: }
553: fsp->fsid = inode.i_dev & 0xffff;
554: fsp->fileid = (long)inode.i_number;
1.11 millert 555: fsp->mode = inode.i_e2fs_mode;
556: fsp->size = inode.i_e2fs_size;
1.9 downsj 557: fsp->rdev = 0; /* XXX */
1.14 deraadt 558:
559: return 1;
560: }
561:
562: int
563: msdos_filestat(vp, fsp)
564: struct vnode *vp;
565: struct filestat *fsp;
566: {
567: #if 0
568: struct inode inode;
569:
570: if (!KVM_READ(VTOI(vp), &inode, sizeof (inode))) {
1.17 mickey 571: dprintf("can't read inode at %p for pid %d", VTOI(vp), Pid);
1.14 deraadt 572: return 0;
573: }
574: fsp->fsid = inode.i_dev & 0xffff;
575: fsp->fileid = (long)inode.i_number;
576: fsp->mode = inode.i_e2fs_mode;
577: fsp->size = inode.i_e2fs_size;
578: fsp->rdev = 0; /* XXX */
579: #endif
1.1 deraadt 580:
581: return 1;
582: }
583:
584: int
585: nfs_filestat(vp, fsp)
586: struct vnode *vp;
587: struct filestat *fsp;
588: {
589: struct nfsnode nfsnode;
1.32 mpech 590: mode_t mode;
1.1 deraadt 591:
592: if (!KVM_READ(VTONFS(vp), &nfsnode, sizeof (nfsnode))) {
1.17 mickey 593: dprintf("can't read nfsnode at %p for pid %d", VTONFS(vp), Pid);
1.1 deraadt 594: return 0;
595: }
596: fsp->fsid = nfsnode.n_vattr.va_fsid;
597: fsp->fileid = nfsnode.n_vattr.va_fileid;
598: fsp->size = nfsnode.n_size;
599: fsp->rdev = nfsnode.n_vattr.va_rdev;
600: mode = (mode_t)nfsnode.n_vattr.va_mode;
601: switch (vp->v_type) {
602: case VREG:
603: mode |= S_IFREG;
604: break;
605: case VDIR:
606: mode |= S_IFDIR;
607: break;
608: case VBLK:
609: mode |= S_IFBLK;
610: break;
611: case VCHR:
612: mode |= S_IFCHR;
613: break;
614: case VLNK:
615: mode |= S_IFLNK;
616: break;
617: case VSOCK:
618: mode |= S_IFSOCK;
619: break;
620: case VFIFO:
621: mode |= S_IFIFO;
622: break;
1.17 mickey 623: default:
624: break;
1.34 deraadt 625: }
1.1 deraadt 626: fsp->mode = mode;
627:
628: return 1;
629: }
630:
1.18 art 631: int
632: xfs_filestat(vp, fsp)
633: struct vnode *vp;
634: struct filestat *fsp;
635: {
636: struct xfs_node xfs_node;
637:
638: if (!KVM_READ(VNODE_TO_XNODE(vp), &xfs_node, sizeof (xfs_node))) {
639: dprintf("can't read xfs_node at %p for pid %d", VTOI(vp), Pid);
640: return 0;
641: }
642: fsp->fsid = xfs_node.attr.va_fsid;
643: fsp->fileid = (long)xfs_node.attr.va_fileid;
644: fsp->mode = xfs_node.attr.va_mode;
645: fsp->size = xfs_node.attr.va_size;
646: fsp->rdev = xfs_node.attr.va_rdev;
1.23 deraadt 647:
648: return 1;
649: }
650:
651: int
652: null_filestat(vp, fsp)
653: struct vnode *vp;
654: struct filestat *fsp;
655: {
656: struct null_node node;
657: struct filestat fst;
658: struct vnode vn;
659: int fail = 1;
660:
661: memset(&fst, 0, sizeof fst);
662:
663: if (!KVM_READ(VTONULL(vp), &node, sizeof (node))) {
664: dprintf("can't read node at %p for pid %d", VTONULL(vp), Pid);
665: return 0;
666: }
667:
668: /*
669: * Attempt to find information that might be useful.
670: */
671: if (node.null_lowervp) {
672: if (!KVM_READ(node.null_lowervp, &vn, sizeof (vn))) {
673: dprintf("can't read vnode at %p for pid %d",
674: node.null_lowervp, Pid);
675: return 0;
676: }
677:
678: fail = 0;
679: if (vn.v_type == VNON || vn.v_tag == VT_NON)
680: fail = 1;
681: else if (vn.v_type == VBAD)
682: fail = 1;
683: else
684: switch (vn.v_tag) {
685: case VT_UFS:
686: case VT_MFS:
687: if (!ufs_filestat(&vn, &fst))
688: fail = 1;
689: break;
690: case VT_NFS:
691: if (!nfs_filestat(&vn, &fst))
692: fail = 1;
693: break;
694: case VT_EXT2FS:
695: if (!ext2fs_filestat(&vn, &fst))
696: fail = 1;
697: break;
698: case VT_ISOFS:
699: if (!isofs_filestat(&vn, &fst))
700: fail = 1;
701: break;
702: case VT_MSDOSFS:
703: if (!msdos_filestat(&vn, &fst))
704: fail = 1;
705: break;
706: case VT_XFS:
707: if (!xfs_filestat(&vn, &fst))
708: fail = 1;
709: break;
710: default:
711: break;
712: }
713: }
714:
715: fsp->fsid = (long)node.null_vnode;
716: if (fail)
717: fsp->fileid = (long)node.null_lowervp;
718: else
1.34 deraadt 719: fsp->fileid = fst.fileid;
1.23 deraadt 720: fsp->mode = fst.mode;
721: fsp->size = fst.mode;
722: fsp->rdev = fst.mode;
1.18 art 723:
724: return 1;
725: }
1.1 deraadt 726:
727: char *
728: getmnton(m)
729: struct mount *m;
730: {
731: static struct mount mount;
732: static struct mtab {
733: struct mtab *next;
734: struct mount *m;
735: char mntonname[MNAMELEN];
736: } *mhead = NULL;
1.32 mpech 737: struct mtab *mt;
1.1 deraadt 738:
739: for (mt = mhead; mt != NULL; mt = mt->next)
740: if (m == mt->m)
741: return (mt->mntonname);
742: if (!KVM_READ(m, &mount, sizeof(struct mount))) {
1.17 mickey 743: warn("can't read mount table at %p", m);
1.1 deraadt 744: return (NULL);
745: }
1.17 mickey 746: if ((mt = malloc(sizeof (struct mtab))) == NULL)
747: err(1, "malloc");
1.1 deraadt 748: mt->m = m;
749: bcopy(&mount.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN);
750: mt->next = mhead;
751: mhead = mt;
752: return (mt->mntonname);
1.22 art 753: }
754:
755: void
756: pipetrans(pipe, i)
757: struct pipe *pipe;
758: int i;
759: {
760: struct pipe pi;
761: void *maxaddr;
762:
763: PREFIX(i);
764:
765: printf(" ");
766:
767: /* fill in socket */
768: if (!KVM_READ(pipe, &pi, sizeof(struct pipe))) {
769: dprintf("can't read pipe at %p", pipe);
770: goto bad;
771: }
772:
773: /*
774: * We don't have enough space to fit both peer and own address, so
775: * we select the higher address so both ends of the pipe have the
776: * same visible addr. (it's the higher address because when the other
777: * end closes, it becomes 0)
778: */
779: maxaddr = MAX(pipe, pi.pipe_peer);
780:
1.38 ! deraadt 781: printf("pipe %p state: %s%s%s\n", maxaddr,
1.34 deraadt 782: (pi.pipe_state & PIPE_WANTR) ? "R" : "",
783: (pi.pipe_state & PIPE_WANTW) ? "W" : "",
784: (pi.pipe_state & PIPE_EOF) ? "E" : "");
1.37 deraadt 785: return;
786: bad:
787: printf("* error\n");
788: }
789:
790: void
791: kqueuetrans(kq, i)
792: struct kqueue *kq;
793: int i;
794: {
795: struct kqueue kqi;
796:
797: PREFIX(i);
798:
799: printf(" ");
800:
801: /* fill it in */
802: if (!KVM_READ(kq, &kqi, sizeof(struct kqueue))) {
803: dprintf("can't read kqueue at %p", kq);
804: goto bad;
805: }
806:
1.38 ! deraadt 807: printf("kqueue %p %d state: %s%s\n", kq, kqi.kq_count,
1.37 deraadt 808: (kqi.kq_state & KQ_SEL) ? "S" : "",
809: (kqi.kq_state & KQ_SLEEP) ? "W" : "");
810: return;
811: bad:
812: printf("* error\n");
813: }
814:
815: void
816: cryptotrans(f, i)
817: void *f;
818: int i;
819: {
820: PREFIX(i);
821:
822: printf(" ");
823:
1.38 ! deraadt 824: printf("crypto %p\n", f);
1.37 deraadt 825: return;
826: bad:
827: printf("* error\n");
828: }
829:
830: void
831: systracetrans(f, i)
1.38 ! deraadt 832: struct fsystrace *f;
1.37 deraadt 833: int i;
834: {
1.38 ! deraadt 835: struct fsystrace fi;
! 836:
1.37 deraadt 837: PREFIX(i);
838:
839: printf(" ");
840:
1.38 ! deraadt 841: /* fill it in */
! 842: if (!KVM_READ(f, &fi, sizeof(fi))) {
! 843: dprintf("can't read fsystrace at %p", f);
! 844: goto bad;
! 845: }
1.34 deraadt 846:
1.38 ! deraadt 847: printf("systrace %p npol %d\n", f, fi.npolicies);
1.22 art 848: return;
849: bad:
850: printf("* error\n");
1.1 deraadt 851: }
852:
1.26 itojun 853: #ifdef INET6
854: const char *
855: inet6_addrstr(p)
856: struct in6_addr *p;
857: {
858: struct sockaddr_in6 sin6;
859: static char hbuf[NI_MAXHOST];
860: #ifdef NI_WITHSCOPEID
861: const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;
862: #else
863: const int niflags = NI_NUMERICHOST
864: #endif
865:
866: memset(&sin6, 0, sizeof(sin6));
867: sin6.sin6_family = AF_INET6;
868: sin6.sin6_len = sizeof(struct sockaddr_in6);
869: sin6.sin6_addr = *p;
870: if (IN6_IS_ADDR_LINKLOCAL(p) &&
871: *(u_int16_t *)&sin6.sin6_addr.s6_addr[2] != 0) {
872: sin6.sin6_scope_id =
1.38 ! deraadt 873: ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
1.26 itojun 874: sin6.sin6_addr.s6_addr[2] = sin6.sin6_addr.s6_addr[3] = 0;
875: }
876:
877: if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
1.38 ! deraadt 878: hbuf, sizeof(hbuf), NULL, 0, niflags))
1.26 itojun 879: return "invalid";
880:
881: return hbuf;
882: }
883: #endif
884:
1.1 deraadt 885: void
886: socktrans(sock, i)
887: struct socket *sock;
888: int i;
889: {
890: static char *stypename[] = {
891: "unused", /* 0 */
1.38 ! deraadt 892: "stream", /* 1 */
1.1 deraadt 893: "dgram", /* 2 */
894: "raw", /* 3 */
895: "rdm", /* 4 */
896: "seqpak" /* 5 */
897: };
898: #define STYPEMAX 5
899: struct socket so;
900: struct protosw proto;
901: struct domain dom;
902: struct inpcb inpcb;
903: struct unpcb unpcb;
904: int len;
1.4 deraadt 905: char dname[32];
1.26 itojun 906: #ifdef INET6
907: char xaddrbuf[NI_MAXHOST + 2];
908: #endif
1.1 deraadt 909:
910: PREFIX(i);
911:
912: /* fill in socket */
913: if (!KVM_READ(sock, &so, sizeof(struct socket))) {
1.17 mickey 914: dprintf("can't read sock at %p", sock);
1.1 deraadt 915: goto bad;
916: }
917:
918: /* fill in protosw entry */
919: if (!KVM_READ(so.so_proto, &proto, sizeof(struct protosw))) {
1.17 mickey 920: dprintf("can't read protosw at %p", so.so_proto);
1.1 deraadt 921: goto bad;
922: }
923:
924: /* fill in domain */
925: if (!KVM_READ(proto.pr_domain, &dom, sizeof(struct domain))) {
1.17 mickey 926: dprintf("can't read domain at %p", proto.pr_domain);
1.1 deraadt 927: goto bad;
928: }
929:
930: if ((len = kvm_read(kd, (u_long)dom.dom_name, dname,
1.15 deraadt 931: sizeof(dname) - 1)) != sizeof(dname) -1) {
1.17 mickey 932: dprintf("can't read domain name at %p", dom.dom_name);
1.1 deraadt 933: dname[0] = '\0';
1.38 ! deraadt 934: } else
1.1 deraadt 935: dname[len] = '\0';
936:
937: if ((u_short)so.so_type > STYPEMAX)
938: printf("* %s ?%d", dname, so.so_type);
939: else
940: printf("* %s %s", dname, stypename[so.so_type]);
941:
1.34 deraadt 942: /*
1.1 deraadt 943: * protocol specific formatting
944: *
945: * Try to find interesting things to print. For tcp, the interesting
946: * thing is the address of the tcpcb, for udp and others, just the
947: * inpcb (socket pcb). For unix domain, its the address of the socket
948: * pcb and the address of the connected pcb (if connected). Otherwise
949: * just print the protocol number and address of the socket itself.
950: * The idea is not to duplicate netstat, but to make available enough
951: * information for further analysis.
952: */
953: switch(dom.dom_family) {
954: case AF_INET:
955: getinetproto(proto.pr_protocol);
1.5 deraadt 956: if (proto.pr_protocol == IPPROTO_TCP) {
957: if (so.so_pcb == NULL)
958: break;
959: if (kvm_read(kd, (u_long)so.so_pcb, (char *)&inpcb,
960: sizeof(struct inpcb)) != sizeof(struct inpcb)) {
1.17 mickey 961: dprintf("can't read inpcb at %p", so.so_pcb);
1.5 deraadt 962: goto bad;
963: }
1.11 millert 964: printf(" %p", inpcb.inp_ppcb);
1.5 deraadt 965: printf(" %s:%d",
966: inpcb.inp_laddr.s_addr == INADDR_ANY ? "*" :
967: inet_ntoa(inpcb.inp_laddr),
968: ntohs(inpcb.inp_lport));
1.17 mickey 969: if (inpcb.inp_fport) {
1.13 deraadt 970: if (so.so_state & SS_CONNECTOUT)
971: printf(" --> ");
972: else
973: printf(" <-- ");
974: printf("%s:%d",
1.5 deraadt 975: inpcb.inp_faddr.s_addr == INADDR_ANY ? "*" :
976: inet_ntoa(inpcb.inp_faddr),
977: ntohs(inpcb.inp_fport));
1.17 mickey 978: }
1.5 deraadt 979: } else if (proto.pr_protocol == IPPROTO_UDP) {
980: if (so.so_pcb == NULL)
981: break;
982: if (kvm_read(kd, (u_long)so.so_pcb, (char *)&inpcb,
983: sizeof(struct inpcb)) != sizeof(struct inpcb)) {
1.17 mickey 984: dprintf("can't read inpcb at %p", so.so_pcb);
1.5 deraadt 985: goto bad;
1.1 deraadt 986: }
1.5 deraadt 987: printf(" %s:%d",
988: inpcb.inp_laddr.s_addr == INADDR_ANY ? "*" :
989: inet_ntoa(inpcb.inp_laddr),
990: ntohs(inpcb.inp_lport));
991: if (inpcb.inp_fport)
1.6 deraadt 992: printf(" <-> %s:%d",
1.5 deraadt 993: inpcb.inp_faddr.s_addr == INADDR_ANY ? "*" :
994: inet_ntoa(inpcb.inp_faddr),
995: ntohs(inpcb.inp_fport));
996: } else if (so.so_pcb)
1.11 millert 997: printf(" %p", so.so_pcb);
1.1 deraadt 998: break;
1.26 itojun 999: #ifdef INET6
1000: case AF_INET6:
1001: getinetproto(proto.pr_protocol);
1002: if (proto.pr_protocol == IPPROTO_TCP) {
1003: if (so.so_pcb == NULL)
1004: break;
1005: if (kvm_read(kd, (u_long)so.so_pcb, (char *)&inpcb,
1006: sizeof(struct inpcb)) != sizeof(struct inpcb)) {
1007: dprintf("can't read inpcb at %p", so.so_pcb);
1008: goto bad;
1009: }
1010: printf(" %p", inpcb.inp_ppcb);
1011: snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]",
1012: inet6_addrstr(&inpcb.inp_laddr6));
1013: printf(" %s:%d",
1014: IN6_IS_ADDR_UNSPECIFIED(&inpcb.inp_laddr6) ? "*" :
1015: xaddrbuf,
1016: ntohs(inpcb.inp_lport));
1017: if (inpcb.inp_fport) {
1018: if (so.so_state & SS_CONNECTOUT)
1019: printf(" --> ");
1020: else
1021: printf(" <-- ");
1022: snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]",
1023: inet6_addrstr(&inpcb.inp_faddr6));
1024: printf("%s:%d",
1025: IN6_IS_ADDR_UNSPECIFIED(&inpcb.inp_faddr6) ? "*" :
1026: xaddrbuf,
1027: ntohs(inpcb.inp_fport));
1028: }
1029: } else if (proto.pr_protocol == IPPROTO_UDP) {
1030: if (so.so_pcb == NULL)
1031: break;
1032: if (kvm_read(kd, (u_long)so.so_pcb, (char *)&inpcb,
1033: sizeof(struct inpcb)) != sizeof(struct inpcb)) {
1034: dprintf("can't read inpcb at %p", so.so_pcb);
1035: goto bad;
1036: }
1037: snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]",
1038: inet6_addrstr(&inpcb.inp_laddr6));
1039: printf(" %s:%d",
1040: IN6_IS_ADDR_UNSPECIFIED(&inpcb.inp_laddr6) ? "*" :
1041: xaddrbuf,
1042: ntohs(inpcb.inp_lport));
1.33 itojun 1043: if (inpcb.inp_fport) {
1.26 itojun 1044: snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]",
1045: inet6_addrstr(&inpcb.inp_faddr6));
1046: printf(" <-> %s:%d",
1047: IN6_IS_ADDR_UNSPECIFIED(&inpcb.inp_faddr6) ? "*" :
1048: xaddrbuf,
1049: ntohs(inpcb.inp_fport));
1.33 itojun 1050: }
1.26 itojun 1051: } else if (so.so_pcb)
1052: printf(" %p", so.so_pcb);
1053: break;
1054: #endif
1.1 deraadt 1055: case AF_UNIX:
1056: /* print address of pcb and connected pcb */
1057: if (so.so_pcb) {
1.11 millert 1058: printf(" %p", so.so_pcb);
1.1 deraadt 1059: if (kvm_read(kd, (u_long)so.so_pcb, (char *)&unpcb,
1060: sizeof(struct unpcb)) != sizeof(struct unpcb)){
1.17 mickey 1061: dprintf("can't read unpcb at %p", so.so_pcb);
1.1 deraadt 1062: goto bad;
1063: }
1064: if (unpcb.unp_conn) {
1065: char shoconn[4], *cp;
1066:
1067: cp = shoconn;
1068: if (!(so.so_state & SS_CANTRCVMORE))
1069: *cp++ = '<';
1070: *cp++ = '-';
1071: if (!(so.so_state & SS_CANTSENDMORE))
1072: *cp++ = '>';
1073: *cp = '\0';
1.11 millert 1074: printf(" %s %p", shoconn,
1075: unpcb.unp_conn);
1.1 deraadt 1076: }
1077: }
1078: break;
1079: default:
1080: /* print protocol number and socket address */
1.11 millert 1081: printf(" %d %p", proto.pr_protocol, sock);
1.1 deraadt 1082: }
1083: printf("\n");
1084: return;
1085: bad:
1086: printf("* error\n");
1087: }
1088:
1089: /*
1090: * getinetproto --
1091: * print name of protocol number
1092: */
1093: void
1094: getinetproto(number)
1095: int number;
1096: {
1.24 deraadt 1097: static int isopen;
1.32 mpech 1098: struct protoent *pe;
1.1 deraadt 1099:
1.24 deraadt 1100: if (!isopen)
1101: setprotoent(++isopen);
1102: if ((pe = getprotobynumber(number)) != NULL)
1103: printf(" %s", pe->p_name);
1104: else
1.1 deraadt 1105: printf(" %d", number);
1106: }
1107:
1.11 millert 1108: int
1.1 deraadt 1109: getfname(filename)
1110: char *filename;
1111: {
1112: struct stat statbuf;
1113: DEVS *cur;
1114:
1115: if (stat(filename, &statbuf)) {
1.27 millert 1116: warn("%s", filename);
1.1 deraadt 1117: return(0);
1118: }
1.17 mickey 1119: if ((cur = malloc(sizeof(DEVS))) == NULL)
1120: err(1, "malloc");
1.1 deraadt 1121: cur->next = devs;
1122: devs = cur;
1123:
1124: cur->ino = statbuf.st_ino;
1125: cur->fsid = statbuf.st_dev & 0xffff;
1126: cur->name = filename;
1127: return(1);
1128: }
1129:
1130: void
1131: usage()
1132: {
1.38 ! deraadt 1133: fprintf(stderr, "usage: fstat [-fnv] [-p pid] [-u user] "
! 1134: "[-N system] [-M core] [file ...]\n");
1.1 deraadt 1135: exit(1);
1136: }