1: /* 2: * Copyright (c) 1987 Regents of the University of California. 3: * All rights reserved. 4: * 5: * Redistribution and use in source and binary forms are permitted 6: * provided that this notice is preserved and that due credit is given 7: * to the University of California at Berkeley. The name of the University 8: * may not be used to endorse or promote products derived from this 9: * software without specific prior written permission. This software 10: * is provided ``as is'' without express or implied warranty. 11: */ 12: 13: #if defined(DOSCCS) && !defined(lint) 14: char copyright[] = 15: "@(#) Copyright (c) 1987 Regents of the University of California.\n\ 16: All rights reserved.\n"; 17: 18: static char sccsid[] = "@(#)fstat.c 5.11.1 (2.11BSD GTE) 12/31/93"; 19: #endif 20: 21: /* 22: * fstat 23: */ 24: #include <sys/param.h> 25: #include <sys/user.h> 26: #include <sys/proc.h> 27: #include <sys/text.h> 28: #include <sys/stat.h> 29: #include <sys/inode.h> 30: #include <sys/socket.h> 31: #include <sys/socketvar.h> 32: #include <sys/domain.h> 33: #include <sys/protosw.h> 34: #include <sys/unpcb.h> 35: #include <sys/vmmac.h> 36: #define KERNEL 37: #include <sys/file.h> 38: #undef KERNEL 39: #include <net/route.h> 40: #include <netinet/in.h> 41: #include <netinet/in_pcb.h> 42: #include <stdio.h> 43: #include <ctype.h> 44: #include <nlist.h> 45: #include <pwd.h> 46: 47: #ifdef ULTRIX 48: /* UFS -> GFS */ 49: # define inode gnode 50: # define x_iptr x_gptr 51: # define i_dev g_dev 52: # define i_number g_number 53: # define i_mode g_mode 54: # define i_size g_size 55: #endif 56: 57: #define N_KMEM "/dev/kmem" 58: #define N_MEM "/dev/mem" 59: #define N_SWAP "/dev/drum" 60: #define N_UNIX "/vmunix" 61: 62: #define TEXT -2 63: #define WD -1 64: 65: typedef struct devs { 66: struct devs *next; 67: dev_t dev; 68: int inum; 69: char *name; 70: } DEVS; 71: DEVS *devs; 72: 73: #ifdef pdp11 74: static struct nlist nl[] = { 75: { "_proc" }, 76: #define X_PROC 0 77: { "_nproc" }, 78: #define X_NPROC 1 79: { "_netdata" }, 80: #define X_NETDATA 2 81: { "" }, 82: }; 83: #else 84: static struct nlist nl[] = { 85: { "_proc" }, 86: #define X_PROC 0 87: { "_Usrptmap" }, 88: #define X_USRPTMA 1 89: { "_nproc" }, 90: #define X_NPROC 2 91: { "_usrpt" }, 92: #define X_USRPT 3 93: { "" }, 94: }; 95: #endif 96: 97: struct proc *mproc; 98: #ifndef pdp11 99: struct pte *Usrptma, *usrpt; 100: #endif 101: 102: union { 103: struct user user; 104: #ifdef pdp11 105: char upages[ctob(USIZE)]; 106: #else 107: char upages[UPAGES][NBPG]; 108: #endif 109: } user; 110: 111: extern int errno; 112: static int fflg, vflg; 113: static int kmem, mem, nproc, swap; 114: static char *uname; 115: #ifdef pdp11 116: static off_t netdata; 117: long lgetw(); 118: #endif 119: 120: off_t lseek(); 121: 122: main(argc, argv) 123: int argc; 124: char **argv; 125: { 126: extern char *optarg; 127: extern int optind; 128: register struct passwd *passwd; 129: register int pflg, pid, uflg, uid; 130: int ch, size; 131: struct passwd *getpwnam(), *getpwuid(); 132: long lgetw(); 133: char *malloc(); 134: 135: pflg = uflg = 0; 136: while ((ch = getopt(argc, argv, "p:u:v")) != EOF) 137: switch((char)ch) { 138: case 'p': 139: if (pflg++) 140: usage(); 141: if (!isdigit(*optarg)) { 142: fputs("fstat: -p option requires a process id.\n", stderr); 143: usage(); 144: } 145: pid = atoi(optarg); 146: break; 147: case 'u': 148: if (uflg++) 149: usage(); 150: if (!(passwd = getpwnam(optarg))) { 151: fprintf(stderr, "%s: unknown uid\n", optarg); 152: exit(1); 153: } 154: uid = passwd->pw_uid; 155: uname = passwd->pw_name; 156: break; 157: case 'v': /* undocumented: print read error messages */ 158: vflg++; 159: break; 160: case '?': 161: default: 162: usage(); 163: } 164: 165: if (*(argv += optind)) { 166: for (; *argv; ++argv) { 167: if (getfname(*argv)) 168: fflg = 1; 169: } 170: if (!fflg) /* file(s) specified, but none accessable */ 171: exit(1); 172: } 173: 174: openfiles(); 175: 176: if (nlist(N_UNIX, nl) == -1 || !nl[0].n_type) { 177: fprintf(stderr, "%s: No namelist\n", N_UNIX); 178: exit(1); 179: } 180: #ifdef pdp11 181: if (nl[X_NETDATA].n_type) { 182: netdata = lgetw((off_t)nl[X_NETDATA].n_value); 183: netdata = ctob(netdata); 184: } 185: #else 186: Usrptma = (struct pte *)nl[X_USRPTMA].n_value; 187: usrpt = (struct pte *) nl[X_USRPT].n_value; 188: #endif 189: nproc = (int)lgetw((off_t)nl[X_NPROC].n_value); 190: 191: #ifdef pdp11 192: (void)lseek(kmem, (off_t)nl[X_PROC].n_value, L_SET); 193: #else 194: (void)lseek(kmem, lgetw((off_t)nl[X_PROC].n_value), L_SET); 195: #endif 196: size = nproc * sizeof(struct proc); 197: if ((mproc = (struct proc *)malloc((u_int)size)) == NULL) { 198: fprintf(stderr, "fstat: out of space.\n"); 199: exit(1); 200: } 201: if (read(kmem, (char *)mproc, size) != size) 202: rerr1("proc table", N_KMEM); 203: 204: printf("USER\t CMD\t PID FD\tDEVICE\tINODE\t SIZE TYPE%s\n", 205: fflg ? " NAME" : ""); 206: for (; nproc--; ++mproc) { 207: if (mproc->p_stat == 0) 208: continue; 209: if (pflg && mproc->p_pid != pid) 210: continue; 211: if (uflg) { 212: if (mproc->p_uid != uid) 213: continue; 214: } 215: else 216: uname = (passwd = getpwuid(mproc->p_uid)) ? 217: passwd->pw_name : "unknown"; 218: if (mproc->p_stat != SZOMB && getu() == 0) 219: continue; 220: dotext(); 221: readf(); 222: } 223: exit(0); 224: } 225: 226: #ifndef pdp11 227: static 228: getu() 229: { 230: struct pte *pteaddr, apte; 231: struct pte arguutl[UPAGES+CLSIZE]; 232: register int i; 233: int ncl; 234: 235: if ((mproc->p_flag & SLOAD) == 0) { 236: if (swap < 0) 237: return(0); 238: (void)lseek(swap, (off_t)dtob(mproc->p_swaddr), L_SET); 239: if (read(swap, (char *)&user.user, sizeof(struct user)) 240: != sizeof(struct user)) { 241: fprintf(stderr, "fstat: can't read u for pid %d from %s\n", mproc->p_pid, N_SWAP); 242: return(0); 243: } 244: return(1); 245: } 246: pteaddr = &Usrptma[btokmx(mproc->p_p0br) + mproc->p_szpt - 1]; 247: (void)lseek(kmem, (off_t)pteaddr, L_SET); 248: if (read(kmem, (char *)&apte, sizeof(apte)) != sizeof(apte)) { 249: printf("fstat: can't read indir pte to get u for pid %d from %s\n", mproc->p_pid, N_SWAP); 250: return(0); 251: } 252: (void)lseek(mem, (off_t)ctob(apte.pg_pfnum+1) - (UPAGES+CLSIZE) 253: * sizeof(struct pte), L_SET); 254: if (read(mem, (char *)arguutl, sizeof(arguutl)) != sizeof(arguutl)) { 255: printf("fstat: can't read page table for u of pid %d from %s\n", mproc->p_pid, N_KMEM); 256: return(0); 257: } 258: ncl = (sizeof(struct user) + NBPG*CLSIZE - 1) / (NBPG*CLSIZE); 259: while (--ncl >= 0) { 260: i = ncl * CLSIZE; 261: (void)lseek(mem, (off_t)ctob(arguutl[CLSIZE+i].pg_pfnum), L_SET); 262: if (read(mem, user.upages[i], CLSIZE*NBPG) != CLSIZE*NBPG) { 263: printf("fstat: can't read page %u of u of pid %d from %s\n", arguutl[CLSIZE+i].pg_pfnum, mproc->p_pid, N_MEM); 264: return(0); 265: } 266: } 267: return(1); 268: } 269: #else 270: static 271: getu() 272: { 273: 274: if ((mproc->p_flag & SLOAD) == 0) { 275: if (swap < 0) 276: return(0); 277: (void)lseek(swap, (off_t)(mproc->p_addr)<<9, L_SET); 278: if (read(swap, (char *)&user.user, sizeof(struct user)) 279: != sizeof(struct user)) { 280: fprintf(stderr, "fstat: can't read u for pid %d from %s\n", mproc->p_pid, N_SWAP); 281: return(0); 282: } 283: return(1); 284: } 285: (void)lseek(mem, (off_t)ctob((off_t)mproc->p_addr), L_SET); 286: if (read(mem, &user.user, sizeof(user.user))!=sizeof(user.user)) { 287: printf("fstat: can't read page table for u of pid %d from %s\n", mproc->p_pid, N_MEM); 288: return(0); 289: } 290: return(1); 291: } 292: #endif 293: 294: static 295: dotext() 296: { 297: struct text text; 298: 299: #ifdef pdp11 300: if (!mproc->p_textp) 301: return; 302: #endif 303: (void)lseek(kmem, (off_t)mproc->p_textp, L_SET); 304: if (read(kmem, (char *) &text, sizeof(text)) != sizeof(text)) { 305: rerr1("text table", N_KMEM); 306: return; 307: } 308: if (text.x_flag) 309: itrans(DTYPE_INODE, text.x_iptr, TEXT); 310: } 311: 312: static 313: itrans(ftype, g, fno) 314: int ftype, fno; 315: struct inode *g; /* if ftype is inode */ 316: { 317: struct inode inode; 318: dev_t idev; 319: char *comm, *itype(); 320: char *name = (char *)NULL; /* set by devmatch() on a match */ 321: 322: if (g || fflg) { 323: (void)lseek(kmem, (off_t)g, L_SET); 324: if (read(kmem, (char *)&inode, sizeof(inode)) != sizeof(inode)) { 325: rerr2(errno, (int)g, "inode"); 326: return; 327: } 328: idev = inode.i_dev; 329: if (fflg && !devmatch(idev, inode.i_number, &name)) 330: return; 331: } 332: if (mproc->p_pid == 0) 333: comm = "swapper"; 334: #ifndef pdp11 335: else if (mproc->p_pid == 2) 336: comm = "pagedaemon"; 337: #endif 338: else 339: comm = user.user.u_comm; 340: printf("%-8.8s %-10.10s %5d ", uname, comm, mproc->p_pid); 341: 342: switch(fno) { 343: case WD: 344: printf(" wd"); break; 345: case TEXT: 346: printf("text"); break; 347: default: 348: printf("%4d", fno); 349: } 350: 351: if (g == 0) { 352: printf("* (deallocated)\n"); 353: return; 354: } 355: 356: switch(ftype) { 357: case DTYPE_INODE: 358: #ifdef pdp11 359: case DTYPE_PIPE: 360: #endif 361: printf("\t%2d, %2d\t%5lu\t%6ld\t%3s %s\n", major(inode.i_dev), 362: minor(inode.i_dev), (long)inode.i_number, 363: inode.i_mode == IFSOCK ? 0L : inode.i_size, 364: #ifdef pdp11 365: ftype == DTYPE_PIPE ? "pip" : 366: #endif 367: itype(inode.i_mode), name ? name : ""); 368: break; 369: case DTYPE_SOCKET: 370: socktrans((struct socket *)g); 371: break; 372: #ifdef DTYPE_PORT 373: case DTYPE_PORT: 374: printf("* (fifo / named pipe)\n"); 375: break; 376: #endif 377: default: 378: printf("* (unknown file type)\n"); 379: } 380: } 381: 382: static char * 383: itype(mode) 384: u_short mode; 385: { 386: switch(mode & IFMT) { 387: case IFCHR: 388: return("chr"); 389: case IFDIR: 390: return("dir"); 391: case IFBLK: 392: return("blk"); 393: case IFREG: 394: return("reg"); 395: case IFLNK: 396: return("lnk"); 397: case IFSOCK: 398: return("soc"); 399: default: 400: return("unk"); 401: } 402: /*NOTREACHED*/ 403: } 404: 405: static 406: socktrans(sock) 407: struct socket *sock; 408: { 409: static char *stypename[] = { 410: "unused", /* 0 */ 411: "stream", /* 1 */ 412: "dgram", /* 2 */ 413: "raw", /* 3 */ 414: "rdm", /* 4 */ 415: "seqpak" /* 5 */ 416: }; 417: #define STYPEMAX 5 418: struct socket so; 419: struct protosw proto; 420: struct domain dom; 421: struct inpcb inpcb; 422: struct unpcb unpcb; 423: int len; 424: char dname[32], *strcpy(); 425: 426: /* fill in socket */ 427: #ifdef pdp11 428: (void)lseek(mem, (off_t)sock + netdata, L_SET); 429: if (read(mem, (char *)&so, sizeof(struct socket)) 430: #else 431: (void)lseek(kmem, (off_t)sock, L_SET); 432: if (read(kmem, (char *)&so, sizeof(struct socket)) 433: #endif 434: != sizeof(struct socket)) { 435: rerr2(errno, (int)sock, "socket"); 436: return; 437: } 438: 439: /* fill in protosw entry */ 440: #ifdef pdp11 441: (void)lseek(mem, (off_t)so.so_proto + netdata, L_SET); 442: if (read(mem, (char *)&proto, sizeof(struct protosw)) 443: #else 444: (void)lseek(kmem, (off_t)so.so_proto, L_SET); 445: if (read(kmem, (char *)&proto, sizeof(struct protosw)) 446: #endif 447: != sizeof(struct protosw)) { 448: rerr2(errno, (int)so.so_proto, "protosw"); 449: return; 450: } 451: 452: /* fill in domain */ 453: #ifdef pdp11 454: (void)lseek(mem, (off_t)proto.pr_domain + netdata, L_SET); 455: if (read(mem, (char *)&dom, sizeof(struct domain)) 456: #else 457: (void)lseek(kmem, (off_t)proto.pr_domain, L_SET); 458: if (read(kmem, (char *)&dom, sizeof(struct domain)) 459: #endif 460: != sizeof(struct domain)) { 461: rerr2(errno, (int)proto.pr_domain, "domain"); 462: return; 463: } 464: 465: /* 466: * grab domain name 467: * kludge "internet" --> "inet" for brevity 468: */ 469: if (dom.dom_family == AF_INET) 470: (void)strcpy(dname, "inet"); 471: else { 472: #ifdef pdp11 473: (void)lseek(mem, (off_t)dom.dom_name + netdata, L_SET); 474: if ((len = read(mem, dname, sizeof(dname) - 1)) < 0) { 475: #else 476: (void)lseek(kmem, (off_t)dom.dom_name, L_SET); 477: if ((len = read(kmem, dname, sizeof(dname) - 1)) < 0) { 478: #endif 479: rerr2(errno, (int)dom.dom_name, "char"); 480: dname[0] = '\0'; 481: } 482: else 483: dname[len] = '\0'; 484: } 485: 486: if ((u_short)so.so_type > STYPEMAX) 487: printf("* (%s unk%d %x", dname, so.so_type, so.so_state); 488: else 489: printf("* (%s %s %x", dname, stypename[so.so_type], 490: so.so_state); 491: 492: /* 493: * protocol specific formatting 494: * 495: * Try to find interesting things to print. For tcp, the interesting 496: * thing is the address of the tcpcb, for udp and others, just the 497: * inpcb (socket pcb). For unix domain, its the address of the socket 498: * pcb and the address of the connected pcb (if connected). Otherwise 499: * just print the protocol number and address of the socket itself. 500: * The idea is not to duplicate netstat, but to make available enough 501: * information for further analysis. 502: */ 503: switch(dom.dom_family) { 504: case AF_INET: 505: getinetproto(proto.pr_protocol); 506: if (proto.pr_protocol == IPPROTO_TCP ) { 507: if (so.so_pcb) { 508: #ifdef pdp11 509: (void)lseek(mem,(off_t)so.so_pcb+netdata,L_SET); 510: if (read(mem, &inpcb, sizeof(struct inpcb)) 511: #else 512: (void)lseek(kmem, (off_t)so.so_pcb, L_SET); 513: if (read(kmem, (char *)&inpcb, sizeof(struct inpcb)) 514: #endif 515: != sizeof(struct inpcb)){ 516: rerr2(errno, (int)so.so_pcb, "inpcb"); 517: return; 518: } 519: printf(" %x", (int)inpcb.inp_ppcb); 520: } 521: } 522: else if (so.so_pcb) 523: printf(" %x", (int)so.so_pcb); 524: break; 525: case AF_UNIX: 526: /* print address of pcb and connected pcb */ 527: if (so.so_pcb) { 528: printf(" %x", (int)so.so_pcb); 529: #ifdef pdp11 530: (void)lseek(mem, (off_t)so.so_pcb + netdata, L_SET); 531: if (read(mem, (char *)&unpcb, sizeof(struct unpcb)) 532: #else 533: (void)lseek(kmem, (off_t)so.so_pcb, L_SET); 534: if (read(kmem, (char *)&unpcb, sizeof(struct unpcb)) 535: #endif 536: != sizeof(struct unpcb)){ 537: rerr2(errno, (int)so.so_pcb, "unpcb"); 538: return; 539: } 540: if (unpcb.unp_conn) { 541: char shoconn[4], *cp; 542: 543: cp = shoconn; 544: if (!(so.so_state & SS_CANTRCVMORE)) 545: *cp++ = '<'; 546: *cp++ = '-'; 547: if (!(so.so_state & SS_CANTSENDMORE)) 548: *cp++ = '>'; 549: *cp = '\0'; 550: printf(" %s %x", shoconn, (int)unpcb.unp_conn); 551: } 552: } 553: break; 554: default: 555: /* print protocol number and socket address */ 556: printf(" %d %x", proto.pr_protocol, (int)sock); 557: } 558: printf(")\n"); 559: } 560: 561: /* 562: * getinetproto -- 563: * print name of protocol number 564: */ 565: static 566: getinetproto(number) 567: int number; 568: { 569: char *cp; 570: 571: switch(number) { 572: case IPPROTO_IP: 573: cp = "ip"; break; 574: case IPPROTO_ICMP: 575: cp ="icmp"; break; 576: case IPPROTO_GGP: 577: cp ="ggp"; break; 578: case IPPROTO_TCP: 579: cp ="tcp"; break; 580: case IPPROTO_EGP: 581: cp ="egp"; break; 582: case IPPROTO_PUP: 583: cp ="pup"; break; 584: case IPPROTO_UDP: 585: cp ="udp"; break; 586: case IPPROTO_IDP: 587: cp ="idp"; break; 588: case IPPROTO_RAW: 589: cp ="raw"; break; 590: default: 591: printf(" %d", number); 592: return; 593: } 594: printf(" %s", cp); 595: } 596: 597: static 598: readf() 599: { 600: struct file lfile; 601: int i; 602: 603: itrans(DTYPE_INODE, user.user.u_cdir, WD); 604: for (i = 0; i < NOFILE; i++) { 605: if (user.user.u_ofile[i] == 0) 606: continue; 607: (void)lseek(kmem, (off_t)user.user.u_ofile[i], L_SET); 608: if (read(kmem, (char *)&lfile, sizeof(lfile)) 609: != sizeof(lfile)) { 610: rerr1("file", N_KMEM); 611: continue; 612: } 613: itrans(lfile.f_type, (struct inode *)lfile.f_data, i); 614: } 615: } 616: 617: static 618: devmatch(idev, inum, name) 619: dev_t idev; 620: ino_t inum; 621: char **name; 622: { 623: register DEVS *d; 624: 625: for (d = devs; d; d = d->next) 626: if (d->dev == idev && (d->inum == 0 || d->inum == inum)) { 627: *name = d->name; 628: return(1); 629: } 630: return(0); 631: } 632: 633: static 634: getfname(filename) 635: char *filename; 636: { 637: struct stat statbuf; 638: DEVS *cur; 639: char *malloc(); 640: 641: if (stat(filename, &statbuf)) { 642: perror(filename); 643: return(0); 644: } 645: if ((cur = (DEVS *)malloc(sizeof(DEVS))) == NULL) { 646: fprintf(stderr, "fstat: out of space.\n"); 647: exit(1); 648: } 649: cur->next = devs; 650: devs = cur; 651: 652: /* if file is block special, look for open files on it */ 653: if ((statbuf.st_mode & S_IFMT) != S_IFBLK) { 654: cur->inum = statbuf.st_ino; 655: cur->dev = statbuf.st_dev; 656: } 657: else { 658: cur->inum = 0; 659: cur->dev = statbuf.st_rdev; 660: } 661: cur->name = filename; 662: return(1); 663: } 664: 665: static 666: openfiles() 667: { 668: if ((kmem = open(N_KMEM, O_RDONLY, 0)) < 0) { 669: perror(N_KMEM); 670: exit(1); 671: } 672: if ((mem = open(N_MEM, O_RDONLY, 0)) < 0) { 673: perror(N_MEM); 674: exit(1); 675: } 676: if ((swap = open(N_SWAP, O_RDONLY, 0)) < 0) { 677: perror(N_SWAP); 678: exit(1); 679: } 680: } 681: 682: static 683: rerr1(what, fromwhat) 684: char *what, *fromwhat; 685: { 686: if (vflg) 687: printf("fstat: error reading %s from %s", what, fromwhat); 688: } 689: 690: static 691: rerr2(err, address, what) 692: int err, address; 693: char *what; 694: { 695: if (vflg) 696: printf("error %d reading %s at %x from kmem\n", errno, what, address); 697: } 698: 699: static long 700: lgetw(loc) 701: off_t loc; 702: { 703: #ifdef pdp11 704: u_short word; 705: #else 706: long word; 707: #endif 708: 709: (void)lseek(kmem, (off_t)loc, L_SET); 710: if (read(kmem, (char *)&word, sizeof(word)) != sizeof(word)) 711: rerr2(errno, (int)loc, "word"); 712: return((long)word); 713: } 714: 715: static 716: usage() 717: { 718: fputs("usage: fstat [-v] [-u user] [-p pid] [filename ...]\n", stderr); 719: exit(1); 720: }