|
|
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.