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