Annotation of src/usr.bin/fstat/fstat.c, Revision 1.19
1.19 ! art 1: /* $OpenBSD: fstat.c,v 1.18 1998/09/06 22:48:46 art 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.19 ! art 44: static char *rcsid = "$OpenBSD: fstat.c,v 1.18 1998/09/06 22:48:46 art 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>
57: #include <sys/unpcb.h>
58: #include <sys/sysctl.h>
59: #include <sys/filedesc.h>
60: #define _KERNEL
61: #include <sys/file.h>
62: #include <ufs/ufs/quota.h>
63: #include <ufs/ufs/inode.h>
64: #undef _KERNEL
65: #define NFS
66: #include <sys/mount.h>
1.2 niklas 67: #include <nfs/nfsproto.h>
1.1 deraadt 68: #include <nfs/rpcv2.h>
69: #include <nfs/nfs.h>
70: #include <nfs/nfsnode.h>
71: #undef NFS
72:
1.18 art 73: #include <xfs/xfs_node.h>
74:
1.1 deraadt 75: #include <net/route.h>
76: #include <netinet/in.h>
77: #include <netinet/in_systm.h>
78: #include <netinet/ip.h>
79: #include <netinet/in_pcb.h>
80:
1.5 deraadt 81: #include <arpa/inet.h>
82:
1.19 ! art 83: #include <sys/pipe.h>
! 84:
1.1 deraadt 85: #include <ctype.h>
86: #include <errno.h>
87: #include <kvm.h>
1.2 niklas 88: #include <limits.h>
1.1 deraadt 89: #include <nlist.h>
90: #include <paths.h>
91: #include <pwd.h>
92: #include <stdio.h>
93: #include <stdlib.h>
94: #include <string.h>
1.11 millert 95: #include <unistd.h>
1.17 mickey 96: #include <err.h>
1.14 deraadt 97: #include "fstat.h"
1.1 deraadt 98:
99: #define TEXT -1
100: #define CDIR -2
101: #define RDIR -3
102: #define TRACE -4
103:
104: typedef struct devs {
105: struct devs *next;
106: long fsid;
107: ino_t ino;
108: char *name;
109: } DEVS;
110: DEVS *devs;
111:
112: int fsflg, /* show files on same filesystem as file(s) argument */
113: pflg, /* show files open by a particular pid */
114: uflg; /* show files open by a particular (effective) user */
115: int checkfile; /* true if restricting to particular files or filesystems */
116: int nflg; /* (numerical) display f.s. and rdev as dev_t */
117: int vflg; /* display errors in locating kernel data objects etc... */
118:
119: struct file **ofiles; /* buffer of pointers to file structures */
120: int maxfiles;
121: #define ALLOC_OFILES(d) \
122: if ((d) > maxfiles) { \
123: free(ofiles); \
124: ofiles = malloc((d) * sizeof(struct file *)); \
1.17 mickey 125: if (ofiles == NULL) \
126: err(1, "malloc"); \
1.1 deraadt 127: maxfiles = (d); \
128: }
129:
130: /*
131: * a kvm_read that returns true if everything is read
132: */
133: #define KVM_READ(kaddr, paddr, len) \
1.11 millert 134: (kvm_read(kd, (u_long)(kaddr), (void *)(paddr), (len)) == (len))
1.1 deraadt 135:
136: kvm_t *kd;
137:
1.11 millert 138: int ufs_filestat __P((struct vnode *, struct filestat *));
139: int ext2fs_filestat __P((struct vnode *, struct filestat *));
1.14 deraadt 140: int isofs_filestat __P((struct vnode *, struct filestat *));
141: int msdos_filestat __P((struct vnode *, struct filestat *));
1.11 millert 142: int nfs_filestat __P((struct vnode *, struct filestat *));
143: void dofiles __P((struct kinfo_proc *));
144: void getinetproto __P((int));
145: void socktrans __P((struct socket *, int));
146: void usage __P((void));
147: void vtrans __P((struct vnode *, int, int));
148: int getfname __P((char *));
1.19 ! art 149: void pipetrans __P((struct pipe *, int));
1.1 deraadt 150:
1.11 millert 151: int
1.1 deraadt 152: main(argc, argv)
153: int argc;
154: char **argv;
155: {
156: extern char *optarg;
157: extern int optind;
158: register struct passwd *passwd;
159: struct kinfo_proc *p, *plast;
160: int arg, ch, what;
161: char *memf, *nlistf;
1.2 niklas 162: char buf[_POSIX2_LINE_MAX];
1.1 deraadt 163: int cnt;
164:
165: arg = 0;
166: what = KERN_PROC_ALL;
167: nlistf = memf = NULL;
1.8 millert 168: while ((ch = getopt(argc, argv, "fnp:u:vN:M:")) != -1)
1.1 deraadt 169: switch((char)ch) {
170: case 'f':
171: fsflg = 1;
172: break;
173: case 'M':
174: memf = optarg;
175: break;
176: case 'N':
177: nlistf = optarg;
178: break;
179: case 'n':
180: nflg = 1;
181: break;
182: case 'p':
183: if (pflg++)
184: usage();
185: if (!isdigit(*optarg)) {
1.17 mickey 186: warnx( "-p requires a process id\n");
1.1 deraadt 187: usage();
188: }
189: what = KERN_PROC_PID;
190: arg = atoi(optarg);
191: break;
192: case 'u':
193: if (uflg++)
194: usage();
1.17 mickey 195: if (!(passwd = getpwnam(optarg)))
196: err(1, "%s: unknown uid", optarg);
1.1 deraadt 197: what = KERN_PROC_UID;
198: arg = passwd->pw_uid;
199: break;
200: case 'v':
201: vflg = 1;
202: break;
203: case '?':
204: default:
205: usage();
206: }
207:
208: if (*(argv += optind)) {
209: for (; *argv; ++argv) {
210: if (getfname(*argv))
211: checkfile = 1;
212: }
213: if (!checkfile) /* file(s) specified, but none accessable */
214: exit(1);
215: }
216:
217: ALLOC_OFILES(256); /* reserve space for file pointers */
218:
219: if (fsflg && !checkfile) {
220: /* -f with no files means use wd */
221: if (getfname(".") == 0)
222: exit(1);
223: checkfile = 1;
224: }
225:
226: /*
227: * Discard setgid privileges if not the running kernel so that bad
228: * guys can't print interesting stuff from kernel memory.
229: */
1.7 tholo 230: if (nlistf != NULL || memf != NULL) {
231: setegid(getgid());
1.1 deraadt 232: setgid(getgid());
1.7 tholo 233: }
1.1 deraadt 234:
1.17 mickey 235: if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == NULL)
236: err(1, buf);
1.16 deraadt 237:
238: setegid(getgid());
239: setgid(getgid());
240:
1.17 mickey 241: if ((p = kvm_getprocs(kd, what, arg, &cnt)) == NULL)
242: err(1, kvm_geterr(kd));
1.1 deraadt 243: if (nflg)
244: printf("%s",
245: "USER CMD PID FD DEV INUM MODE SZ|DV R/W");
246: else
247: printf("%s",
248: "USER CMD PID FD MOUNT INUM MODE SZ|DV R/W");
249: if (checkfile && fsflg == 0)
250: printf(" NAME\n");
251: else
252: putchar('\n');
253:
254: for (plast = &p[cnt]; p < plast; ++p) {
255: if (p->kp_proc.p_stat == SZOMB)
256: continue;
257: dofiles(p);
258: }
259: exit(0);
260: }
261:
262: char *Uname, *Comm;
1.14 deraadt 263: pid_t Pid;
1.1 deraadt 264:
265: #define PREFIX(i) printf("%-8.8s %-10s %5d", Uname, Comm, Pid); \
266: switch(i) { \
267: case TEXT: \
268: printf(" text"); \
269: break; \
270: case CDIR: \
271: printf(" wd"); \
272: break; \
273: case RDIR: \
274: printf(" root"); \
275: break; \
276: case TRACE: \
277: printf(" tr"); \
278: break; \
279: default: \
280: printf(" %4d", i); \
281: break; \
282: }
283:
284: /*
285: * print open files attributed to this process
286: */
287: void
288: dofiles(kp)
289: struct kinfo_proc *kp;
290: {
1.11 millert 291: int i;
1.1 deraadt 292: struct file file;
293: struct filedesc0 filed0;
294: #define filed filed0.fd_fd
295: struct proc *p = &kp->kp_proc;
296: struct eproc *ep = &kp->kp_eproc;
297:
298: extern char *user_from_uid();
299:
300: Uname = user_from_uid(ep->e_ucred.cr_uid, 0);
301: Pid = p->p_pid;
302: Comm = p->p_comm;
303:
304: if (p->p_fd == NULL)
305: return;
306: if (!KVM_READ(p->p_fd, &filed0, sizeof (filed0))) {
1.17 mickey 307: dprintf("can't read filedesc at %p for pid %d", p->p_fd, Pid);
1.1 deraadt 308: return;
309: }
310: if (filed.fd_nfiles < 0 || filed.fd_lastfile >= filed.fd_nfiles ||
311: filed.fd_freefile > filed.fd_lastfile + 1) {
1.17 mickey 312: dprintf("filedesc corrupted at %p for pid %d", p->p_fd, Pid);
1.1 deraadt 313: return;
314: }
315: /*
316: * root directory vnode, if one
317: */
318: if (filed.fd_rdir)
319: vtrans(filed.fd_rdir, RDIR, FREAD);
320: /*
321: * current working directory vnode
322: */
323: vtrans(filed.fd_cdir, CDIR, FREAD);
324: /*
325: * ktrace vnode, if one
326: */
327: if (p->p_tracep)
328: vtrans(p->p_tracep, TRACE, FREAD|FWRITE);
329: /*
330: * open files
331: */
332: #define FPSIZE (sizeof (struct file *))
333: ALLOC_OFILES(filed.fd_lastfile+1);
334: if (filed.fd_nfiles > NDFILE) {
335: if (!KVM_READ(filed.fd_ofiles, ofiles,
336: (filed.fd_lastfile+1) * FPSIZE)) {
1.17 mickey 337: dprintf("can't read file structures at %p for pid %d",
1.1 deraadt 338: filed.fd_ofiles, Pid);
339: return;
340: }
341: } else
342: bcopy(filed0.fd_dfiles, ofiles, (filed.fd_lastfile+1) * FPSIZE);
343: for (i = 0; i <= filed.fd_lastfile; i++) {
344: if (ofiles[i] == NULL)
345: continue;
346: if (!KVM_READ(ofiles[i], &file, sizeof (struct file))) {
1.17 mickey 347: dprintf("can't read file %d at %p for pid %d",
1.1 deraadt 348: i, ofiles[i], Pid);
349: continue;
350: }
351: if (file.f_type == DTYPE_VNODE)
352: vtrans((struct vnode *)file.f_data, i, file.f_flag);
353: else if (file.f_type == DTYPE_SOCKET) {
354: if (checkfile == 0)
355: socktrans((struct socket *)file.f_data, i);
1.19 ! art 356: } else if (file.f_type == DTYPE_PIPE) {
! 357: if (checkfile == 0)
! 358: pipetrans((struct pipe *)file.f_data, i);
! 359: } else {
1.17 mickey 360: dprintf("unknown file type %d for file %d of pid %d",
1.1 deraadt 361: file.f_type, i, Pid);
362: }
363: }
364: }
365:
366: void
367: vtrans(vp, i, flag)
368: struct vnode *vp;
369: int i;
370: int flag;
371: {
372: struct vnode vn;
373: struct filestat fst;
1.12 deraadt 374: char rw[3], mode[17];
1.1 deraadt 375: char *badtype = NULL, *filename, *getmnton();
376:
377: filename = badtype = NULL;
378: if (!KVM_READ(vp, &vn, sizeof (struct vnode))) {
1.17 mickey 379: dprintf("can't read vnode at %p for pid %d", vp, Pid);
1.1 deraadt 380: return;
381: }
382: if (vn.v_type == VNON || vn.v_tag == VT_NON)
383: badtype = "none";
384: else if (vn.v_type == VBAD)
385: badtype = "bad";
386: else
387: switch (vn.v_tag) {
388: case VT_UFS:
389: case VT_MFS:
390: if (!ufs_filestat(&vn, &fst))
391: badtype = "error";
392: break;
393: case VT_NFS:
394: if (!nfs_filestat(&vn, &fst))
395: badtype = "error";
396: break;
1.9 downsj 397: case VT_EXT2FS:
398: if (!ext2fs_filestat(&vn, &fst))
399: badtype = "error";
400: break;
1.14 deraadt 401: case VT_ISOFS:
402: if (!isofs_filestat(&vn, &fst))
403: badtype = "error";
404: break;
405: case VT_MSDOSFS:
406: if (!msdos_filestat(&vn, &fst))
407: badtype = "error";
408: break;
1.18 art 409: case VT_XFS:
410: if (!xfs_filestat(&vn, &fst))
411: badtype = "error";
412: break;
1.1 deraadt 413: default: {
1.12 deraadt 414: static char unknown[30];
1.1 deraadt 415: sprintf(badtype = unknown, "?(%x)", vn.v_tag);
1.10 deraadt 416: break;
1.1 deraadt 417: }
418: }
419: if (checkfile) {
420: int fsmatch = 0;
421: register DEVS *d;
422:
423: if (badtype)
424: return;
425: for (d = devs; d != NULL; d = d->next)
426: if (d->fsid == fst.fsid) {
427: fsmatch = 1;
428: if (d->ino == fst.fileid) {
429: filename = d->name;
430: break;
431: }
432: }
433: if (fsmatch == 0 || (filename == NULL && fsflg == 0))
434: return;
435: }
436: PREFIX(i);
437: if (badtype) {
438: (void)printf(" - - %10s -\n", badtype);
439: return;
440: }
441: if (nflg)
442: (void)printf(" %2d,%-2d", major(fst.fsid), minor(fst.fsid));
443: else
444: (void)printf(" %-8s", getmnton(vn.v_mount));
445: if (nflg)
446: (void)sprintf(mode, "%o", fst.mode);
447: else
448: strmode(fst.mode, mode);
1.11 millert 449: (void)printf(" %6ld %10s", fst.fileid, mode);
1.1 deraadt 450: switch (vn.v_type) {
451: case VBLK:
452: case VCHR: {
453: char *name;
454:
455: if (nflg || ((name = devname(fst.rdev, vn.v_type == VCHR ?
456: S_IFCHR : S_IFBLK)) == NULL))
457: printf(" %2d,%-2d", major(fst.rdev), minor(fst.rdev));
458: else
459: printf(" %6s", name);
460: break;
461: }
462: default:
1.11 millert 463: printf(" %6qd", fst.size);
1.1 deraadt 464: }
465: rw[0] = '\0';
466: if (flag & FREAD)
467: strcat(rw, "r");
468: if (flag & FWRITE)
469: strcat(rw, "w");
470: printf(" %2s", rw);
471: if (filename && !fsflg)
472: printf(" %s", filename);
473: putchar('\n');
474: }
475:
476: int
477: ufs_filestat(vp, fsp)
478: struct vnode *vp;
479: struct filestat *fsp;
480: {
481: struct inode inode;
482:
483: if (!KVM_READ(VTOI(vp), &inode, sizeof (inode))) {
1.17 mickey 484: dprintf("can't read inode at %p for pid %d", VTOI(vp), Pid);
1.1 deraadt 485: return 0;
486: }
487: fsp->fsid = inode.i_dev & 0xffff;
488: fsp->fileid = (long)inode.i_number;
1.11 millert 489: fsp->mode = inode.i_ffs_mode;
490: fsp->size = inode.i_ffs_size;
1.9 downsj 491: fsp->rdev = inode.i_ffs_rdev;
492:
493: return 1;
494: }
495:
496: int
497: ext2fs_filestat(vp, fsp)
498: struct vnode *vp;
499: struct filestat *fsp;
500: {
501: struct inode inode;
502:
503: if (!KVM_READ(VTOI(vp), &inode, sizeof (inode))) {
1.17 mickey 504: dprintf("can't read inode at %p for pid %d", VTOI(vp), Pid);
1.9 downsj 505: return 0;
506: }
507: fsp->fsid = inode.i_dev & 0xffff;
508: fsp->fileid = (long)inode.i_number;
1.11 millert 509: fsp->mode = inode.i_e2fs_mode;
510: fsp->size = inode.i_e2fs_size;
1.9 downsj 511: fsp->rdev = 0; /* XXX */
1.14 deraadt 512:
513: return 1;
514: }
515:
516: int
517: msdos_filestat(vp, fsp)
518: struct vnode *vp;
519: struct filestat *fsp;
520: {
521: #if 0
522: struct inode inode;
523:
524: if (!KVM_READ(VTOI(vp), &inode, sizeof (inode))) {
1.17 mickey 525: dprintf("can't read inode at %p for pid %d", VTOI(vp), Pid);
1.14 deraadt 526: return 0;
527: }
528: fsp->fsid = inode.i_dev & 0xffff;
529: fsp->fileid = (long)inode.i_number;
530: fsp->mode = inode.i_e2fs_mode;
531: fsp->size = inode.i_e2fs_size;
532: fsp->rdev = 0; /* XXX */
533: #endif
1.1 deraadt 534:
535: return 1;
536: }
537:
538: int
539: nfs_filestat(vp, fsp)
540: struct vnode *vp;
541: struct filestat *fsp;
542: {
543: struct nfsnode nfsnode;
544: register mode_t mode;
545:
546: if (!KVM_READ(VTONFS(vp), &nfsnode, sizeof (nfsnode))) {
1.17 mickey 547: dprintf("can't read nfsnode at %p for pid %d", VTONFS(vp), Pid);
1.1 deraadt 548: return 0;
549: }
550: fsp->fsid = nfsnode.n_vattr.va_fsid;
551: fsp->fileid = nfsnode.n_vattr.va_fileid;
552: fsp->size = nfsnode.n_size;
553: fsp->rdev = nfsnode.n_vattr.va_rdev;
554: mode = (mode_t)nfsnode.n_vattr.va_mode;
555: switch (vp->v_type) {
556: case VREG:
557: mode |= S_IFREG;
558: break;
559: case VDIR:
560: mode |= S_IFDIR;
561: break;
562: case VBLK:
563: mode |= S_IFBLK;
564: break;
565: case VCHR:
566: mode |= S_IFCHR;
567: break;
568: case VLNK:
569: mode |= S_IFLNK;
570: break;
571: case VSOCK:
572: mode |= S_IFSOCK;
573: break;
574: case VFIFO:
575: mode |= S_IFIFO;
576: break;
1.17 mickey 577: default:
578: break;
1.1 deraadt 579: };
580: fsp->mode = mode;
581:
582: return 1;
583: }
584:
1.18 art 585: int
586: xfs_filestat(vp, fsp)
587: struct vnode *vp;
588: struct filestat *fsp;
589: {
590: struct xfs_node xfs_node;
591:
592: if (!KVM_READ(VNODE_TO_XNODE(vp), &xfs_node, sizeof (xfs_node))) {
593: dprintf("can't read xfs_node at %p for pid %d", VTOI(vp), Pid);
594: return 0;
595: }
596: fsp->fsid = xfs_node.attr.va_fsid;
597: fsp->fileid = (long)xfs_node.attr.va_fileid;
598: fsp->mode = xfs_node.attr.va_mode;
599: fsp->size = xfs_node.attr.va_size;
600: fsp->rdev = xfs_node.attr.va_rdev;
601:
602: return 1;
603: }
1.1 deraadt 604:
605: char *
606: getmnton(m)
607: struct mount *m;
608: {
609: static struct mount mount;
610: static struct mtab {
611: struct mtab *next;
612: struct mount *m;
613: char mntonname[MNAMELEN];
614: } *mhead = NULL;
615: register struct mtab *mt;
616:
617: for (mt = mhead; mt != NULL; mt = mt->next)
618: if (m == mt->m)
619: return (mt->mntonname);
620: if (!KVM_READ(m, &mount, sizeof(struct mount))) {
1.17 mickey 621: warn("can't read mount table at %p", m);
1.1 deraadt 622: return (NULL);
623: }
1.17 mickey 624: if ((mt = malloc(sizeof (struct mtab))) == NULL)
625: err(1, "malloc");
1.1 deraadt 626: mt->m = m;
627: bcopy(&mount.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN);
628: mt->next = mhead;
629: mhead = mt;
630: return (mt->mntonname);
1.19 ! art 631: }
! 632:
! 633: void
! 634: pipetrans(pipe, i)
! 635: struct pipe *pipe;
! 636: int i;
! 637: {
! 638: struct pipe pi;
! 639: void *maxaddr;
! 640:
! 641: PREFIX(i);
! 642:
! 643: printf(" ");
! 644:
! 645: /* fill in socket */
! 646: if (!KVM_READ(pipe, &pi, sizeof(struct pipe))) {
! 647: dprintf("can't read pipe at %p", pipe);
! 648: goto bad;
! 649: }
! 650:
! 651: /*
! 652: * We don't have enough space to fit both peer and own address, so
! 653: * we select the higher address so both ends of the pipe have the
! 654: * same visible addr. (it's the higher address because when the other
! 655: * end closes, it becomes 0)
! 656: */
! 657: maxaddr = MAX(pipe, pi.pipe_peer);
! 658:
! 659: printf("pipe %p state: %s%s%s", maxaddr,
! 660: (pi.pipe_state & PIPE_WANTR) ? "R" : "",
! 661: (pi.pipe_state & PIPE_WANTW) ? "W" : "",
! 662: (pi.pipe_state & PIPE_EOF) ? "E" : "");
! 663:
! 664: printf("\n");
! 665: return;
! 666: bad:
! 667: printf("* error\n");
1.1 deraadt 668: }
669:
670: void
671: socktrans(sock, i)
672: struct socket *sock;
673: int i;
674: {
675: static char *stypename[] = {
676: "unused", /* 0 */
677: "stream", /* 1 */
678: "dgram", /* 2 */
679: "raw", /* 3 */
680: "rdm", /* 4 */
681: "seqpak" /* 5 */
682: };
683: #define STYPEMAX 5
684: struct socket so;
685: struct protosw proto;
686: struct domain dom;
687: struct inpcb inpcb;
688: struct unpcb unpcb;
689: int len;
1.4 deraadt 690: char dname[32];
1.1 deraadt 691:
692: PREFIX(i);
693:
694: /* fill in socket */
695: if (!KVM_READ(sock, &so, sizeof(struct socket))) {
1.17 mickey 696: dprintf("can't read sock at %p", sock);
1.1 deraadt 697: goto bad;
698: }
699:
700: /* fill in protosw entry */
701: if (!KVM_READ(so.so_proto, &proto, sizeof(struct protosw))) {
1.17 mickey 702: dprintf("can't read protosw at %p", so.so_proto);
1.1 deraadt 703: goto bad;
704: }
705:
706: /* fill in domain */
707: if (!KVM_READ(proto.pr_domain, &dom, sizeof(struct domain))) {
1.17 mickey 708: dprintf("can't read domain at %p", proto.pr_domain);
1.1 deraadt 709: goto bad;
710: }
711:
712: if ((len = kvm_read(kd, (u_long)dom.dom_name, dname,
1.15 deraadt 713: sizeof(dname) - 1)) != sizeof(dname) -1) {
1.17 mickey 714: dprintf("can't read domain name at %p", dom.dom_name);
1.1 deraadt 715: dname[0] = '\0';
716: }
717: else
718: dname[len] = '\0';
719:
720: if ((u_short)so.so_type > STYPEMAX)
721: printf("* %s ?%d", dname, so.so_type);
722: else
723: printf("* %s %s", dname, stypename[so.so_type]);
724:
725: /*
726: * protocol specific formatting
727: *
728: * Try to find interesting things to print. For tcp, the interesting
729: * thing is the address of the tcpcb, for udp and others, just the
730: * inpcb (socket pcb). For unix domain, its the address of the socket
731: * pcb and the address of the connected pcb (if connected). Otherwise
732: * just print the protocol number and address of the socket itself.
733: * The idea is not to duplicate netstat, but to make available enough
734: * information for further analysis.
735: */
736: switch(dom.dom_family) {
737: case AF_INET:
738: getinetproto(proto.pr_protocol);
1.5 deraadt 739: if (proto.pr_protocol == IPPROTO_TCP) {
740: if (so.so_pcb == NULL)
741: break;
742: if (kvm_read(kd, (u_long)so.so_pcb, (char *)&inpcb,
743: sizeof(struct inpcb)) != sizeof(struct inpcb)) {
1.17 mickey 744: dprintf("can't read inpcb at %p", so.so_pcb);
1.5 deraadt 745: goto bad;
746: }
1.11 millert 747: printf(" %p", inpcb.inp_ppcb);
1.5 deraadt 748: printf(" %s:%d",
749: inpcb.inp_laddr.s_addr == INADDR_ANY ? "*" :
750: inet_ntoa(inpcb.inp_laddr),
751: ntohs(inpcb.inp_lport));
1.17 mickey 752: if (inpcb.inp_fport) {
1.13 deraadt 753: if (so.so_state & SS_CONNECTOUT)
754: printf(" --> ");
755: else
756: printf(" <-- ");
757: printf("%s:%d",
1.5 deraadt 758: inpcb.inp_faddr.s_addr == INADDR_ANY ? "*" :
759: inet_ntoa(inpcb.inp_faddr),
760: ntohs(inpcb.inp_fport));
1.17 mickey 761: }
1.5 deraadt 762: } else if (proto.pr_protocol == IPPROTO_UDP) {
763: if (so.so_pcb == NULL)
764: break;
765: if (kvm_read(kd, (u_long)so.so_pcb, (char *)&inpcb,
766: sizeof(struct inpcb)) != sizeof(struct inpcb)) {
1.17 mickey 767: dprintf("can't read inpcb at %p", so.so_pcb);
1.5 deraadt 768: goto bad;
1.1 deraadt 769: }
1.5 deraadt 770: printf(" %s:%d",
771: inpcb.inp_laddr.s_addr == INADDR_ANY ? "*" :
772: inet_ntoa(inpcb.inp_laddr),
773: ntohs(inpcb.inp_lport));
774: if (inpcb.inp_fport)
1.6 deraadt 775: printf(" <-> %s:%d",
1.5 deraadt 776: inpcb.inp_faddr.s_addr == INADDR_ANY ? "*" :
777: inet_ntoa(inpcb.inp_faddr),
778: ntohs(inpcb.inp_fport));
779: } else if (so.so_pcb)
1.11 millert 780: printf(" %p", so.so_pcb);
1.1 deraadt 781: break;
782: case AF_UNIX:
783: /* print address of pcb and connected pcb */
784: if (so.so_pcb) {
1.11 millert 785: printf(" %p", so.so_pcb);
1.1 deraadt 786: if (kvm_read(kd, (u_long)so.so_pcb, (char *)&unpcb,
787: sizeof(struct unpcb)) != sizeof(struct unpcb)){
1.17 mickey 788: dprintf("can't read unpcb at %p", so.so_pcb);
1.1 deraadt 789: goto bad;
790: }
791: if (unpcb.unp_conn) {
792: char shoconn[4], *cp;
793:
794: cp = shoconn;
795: if (!(so.so_state & SS_CANTRCVMORE))
796: *cp++ = '<';
797: *cp++ = '-';
798: if (!(so.so_state & SS_CANTSENDMORE))
799: *cp++ = '>';
800: *cp = '\0';
1.11 millert 801: printf(" %s %p", shoconn,
802: unpcb.unp_conn);
1.1 deraadt 803: }
804: }
805: break;
806: default:
807: /* print protocol number and socket address */
1.11 millert 808: printf(" %d %p", proto.pr_protocol, sock);
1.1 deraadt 809: }
810: printf("\n");
811: return;
812: bad:
813: printf("* error\n");
814: }
815:
816: /*
817: * getinetproto --
818: * print name of protocol number
819: */
820: void
821: getinetproto(number)
822: int number;
823: {
824: char *cp;
825:
826: switch(number) {
827: case IPPROTO_IP:
828: cp = "ip"; break;
829: case IPPROTO_ICMP:
830: cp ="icmp"; break;
831: case IPPROTO_GGP:
832: cp ="ggp"; break;
833: case IPPROTO_TCP:
834: cp ="tcp"; break;
835: case IPPROTO_EGP:
836: cp ="egp"; break;
837: case IPPROTO_PUP:
838: cp ="pup"; break;
839: case IPPROTO_UDP:
840: cp ="udp"; break;
841: case IPPROTO_IDP:
842: cp ="idp"; break;
843: case IPPROTO_RAW:
844: cp ="raw"; break;
845: default:
846: printf(" %d", number);
847: return;
848: }
849: printf(" %s", cp);
850: }
851:
1.11 millert 852: int
1.1 deraadt 853: getfname(filename)
854: char *filename;
855: {
856: struct stat statbuf;
857: DEVS *cur;
858:
859: if (stat(filename, &statbuf)) {
1.17 mickey 860: warn(filename);
1.1 deraadt 861: return(0);
862: }
1.17 mickey 863: if ((cur = malloc(sizeof(DEVS))) == NULL)
864: err(1, "malloc");
1.1 deraadt 865: cur->next = devs;
866: devs = cur;
867:
868: cur->ino = statbuf.st_ino;
869: cur->fsid = statbuf.st_dev & 0xffff;
870: cur->name = filename;
871: return(1);
872: }
873:
874: void
875: usage()
876: {
877: (void)fprintf(stderr,
878: "usage: fstat [-fnv] [-p pid] [-u user] [-N system] [-M core] [file ...]\n");
879: exit(1);
880: }