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