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