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