|
|
1.1 root 1: /*-
2: * Copyright (c) 1988 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted provided
6: * that: (1) source distributions retain this entire copyright notice and
7: * comment, and (2) distributions including binaries display the following
8: * acknowledgement: ``This product includes software developed by the
9: * University of California, Berkeley and its contributors'' in the
10: * documentation or other materials provided with the distribution and in
11: * all advertising materials mentioning features or use of this software.
12: * Neither the name of the University nor the names of its contributors may
13: * be used to endorse or promote products derived from this software without
14: * specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #ifndef lint
21: char copyright[] =
22: "@(#) Copyright (c) 1988 The Regents of the University of California.\n\
23: All rights reserved.\n";
24: #endif /* not lint */
25:
26: #ifndef lint
27: static char sccsid[] = "@(#)fstat.c 5.25 (Berkeley) 6/29/90";
28: #endif /* not lint */
29:
30: /*
31: * fstat
32: */
33: #include <machine/pte.h>
34:
35: #include <sys/param.h>
36: #include <sys/user.h>
37: #include <sys/proc.h>
38: #include <sys/text.h>
39: #include <sys/stat.h>
40: #include <sys/time.h>
41: #include <sys/vnode.h>
42: #include <sys/socket.h>
43: #include <sys/socketvar.h>
44: #include <sys/domain.h>
45: #include <sys/protosw.h>
46: #include <sys/unpcb.h>
47: #include <sys/vmmac.h>
48: #define KERNEL
49: #define NFS
50: #include <sys/file.h>
51: #include <sys/mount.h>
52: #include <ufs/quota.h>
53: #include <ufs/inode.h>
54: #include <nfs/nfsv2.h>
55: #include <nfs/nfs.h>
56: #include <nfs/nfsnode.h>
57: #undef KERNEL
58:
59: #include <net/route.h>
60: #include <netinet/in.h>
61: #include <netinet/in_systm.h>
62: #include <netinet/ip.h>
63: #include <netinet/in_pcb.h>
64:
65: #include <kvm.h>
66: #include <paths.h>
67: #include <ctype.h>
68: #include <nlist.h>
69: #include <pwd.h>
70: #include <string.h>
71: #include <stdio.h>
72:
73: #define TEXT -1
74: #define CDIR -2
75: #define RDIR -3
76: #define TRACE -4
77:
78: typedef struct devs {
79: struct devs *next;
80: long fsid;
81: ino_t ino;
82: char *name;
83: } DEVS;
84: DEVS *devs;
85:
86: struct filestat {
87: long fsid;
88: long fileid;
89: mode_t mode;
90: u_long size;
91: dev_t rdev;
92: };
93:
94: #ifdef notdef
95: struct nlist nl[] = {
96: { "" },
97: };
98: #endif
99:
100: int fsflg, /* show files on same filesystem as file(s) argument */
101: pflg, /* show files open by a particular pid */
102: uflg; /* show files open by a particular (effective) user */
103: int checkfile; /* true if restricting to particular files or filesystems */
104: int nflg; /* (numerical) display f.s. and rdev as dev_t */
105: int vflg; /* display errors in locating kernel data objects etc... */
106:
107: #define dprintf if (vflg) fprintf
108:
109: extern int errno;
110: off_t lseek();
111:
112: main(argc, argv)
113: int argc;
114: char **argv;
115: {
116: register struct passwd *passwd;
117: int what = KINFO_PROC_ALL, arg = 0;
118: struct passwd *getpwnam(), *getpwuid();
119: struct proc *p;
120: extern char *optarg;
121: extern int optind;
122: int ch;
123: char *malloc();
124:
125:
126: while ((ch = getopt(argc, argv, "p:u:fnv")) != EOF)
127: switch((char)ch) {
128: case 'p':
129: if (pflg++)
130: usage();
131: if (!isdigit(*optarg)) {
132: fputs("fstat: -p option requires a process id.\n", stderr);
133: usage();
134: }
135: what = KINFO_PROC_PID;
136: arg = atoi(optarg);
137: break;
138: case 'u':
139: if (uflg++)
140: usage();
141: if (!(passwd = getpwnam(optarg))) {
142: fprintf(stderr, "%s: unknown uid\n",
143: optarg);
144: exit(1);
145: }
146: what = KINFO_PROC_UID;
147: arg = passwd->pw_uid;
148: break;
149: case 'f':
150: fsflg++;
151: break;
152: case 'n':
153: nflg++;
154: break;
155: case 'v':
156: vflg++;
157: break;
158: case '?':
159: default:
160: usage();
161: }
162:
163: if (*(argv += optind)) {
164: for (; *argv; ++argv) {
165: if (getfname(*argv))
166: checkfile = 1;
167: }
168: if (!checkfile) /* file(s) specified, but none accessable */
169: exit(1);
170: }
171: if (fsflg && !checkfile) {
172: /* -f with no files means use wd */
173: if (getfname(".") == 0)
174: exit(1);
175: checkfile = 1;
176: }
177:
178: /* modify the following to make work on dead kernels */
179: if (kvm_openfiles(NULL, NULL, NULL) == -1) {
180: fprintf(stderr, "fstat: %s\n", kvm_geterr());
181: exit(1);
182: }
183: #ifdef notdef
184: if (kvm_nlist(nl) != 0) {
185: fprintf(stderr, "fstat: no namelist: %s\n", kvm_geterr());
186: exit(1);
187: }
188: #endif
189: if (kvm_getprocs(what, arg) == -1) {
190: fprintf(stderr, "fstat: %s\n", kvm_geterr());
191: exit(1);
192: }
193: if (nflg)
194: fputs("USER CMD PID FD DEV INUM MODE SZ|DV", stdout);
195: else
196: fputs("USER CMD PID FD MOUNT INUM MODE SZ|DV", stdout);
197: if (checkfile && fsflg == 0)
198: fputs(" NAME\n", stdout);
199: else
200: putchar('\n');
201:
202: while ((p = kvm_nextproc()) != NULL) {
203: if (p->p_stat == SZOMB)
204: continue;
205: dofiles(p);
206: }
207: exit(0);
208: }
209:
210: char *Uname, *Comm;
211: int Pid;
212:
213: #define PREFIX(i) printf("%-8.8s %-8.8s %5d", Uname, Comm, Pid); \
214: switch(i) { \
215: case TEXT: \
216: fputs(" text", stdout); \
217: break; \
218: case CDIR: \
219: fputs(" wd", stdout); \
220: break; \
221: case RDIR: \
222: fputs(" root", stdout); \
223: break; \
224: case TRACE: \
225: fputs(" tr", stdout); \
226: break; \
227: default: \
228: printf(" %4d", i); \
229: break; \
230: }
231:
232: /*
233: * print open files attributed to this process
234: */
235: dofiles(p)
236: struct proc *p;
237: {
238: int i;
239: struct file file;
240: struct user *up = kvm_getu(p);
241: struct vnode *xvptr;
242: extern char *user_from_uid();
243:
244: Uname = user_from_uid(p->p_uid, 0);
245: Pid = p->p_pid;
246: Comm = p->p_comm;
247:
248: if (up == NULL) {
249: dprintf(stderr, "can't read u for pid %d\n", Pid);
250: return;
251: }
252: /*
253: * root directory vnode, if one
254: */
255: if (up->u_rdir)
256: vtrans(up->u_rdir, RDIR);
257: /*
258: * text vnode
259: */
260: if (p->p_textp &&
261: kvm_read(&(p->p_textp->x_vptr), &xvptr,
262: sizeof (struct vnode *)) == sizeof (struct vnode *) &&
263: xvptr != NULL)
264: vtrans(xvptr, TEXT);
265: /*
266: * current working directory vnode
267: */
268: vtrans(up->u_cdir, CDIR);
269: /*
270: * ktrace vnode, if one
271: */
272: if (p->p_tracep)
273: vtrans(p->p_tracep, TRACE);
274: /*
275: * open files
276: */
277: for (i = 0; i <= up->u_lastfile; i++) {
278: if (up->u_ofile[i] == 0)
279: continue;
280: if (kvm_read(up->u_ofile[i], &file, sizeof (struct file)) !=
281: sizeof (struct file)) {
282: dprintf(stderr, "can't read file %d for pid %d\n",
283: i, Pid);
284: continue;
285: }
286: if (file.f_type == DTYPE_VNODE)
287: vtrans((struct vnode *)file.f_data, i);
288: else if (file.f_type == DTYPE_SOCKET && checkfile == 0)
289: socktrans((struct socket *)file.f_data, i);
290: else {
291: dprintf(stderr,
292: "unknown file type %d for file %d of pid %d\n",
293: file.f_type, i, Pid);
294: }
295: }
296: }
297:
298: vtrans(vp, i)
299: struct vnode *vp;
300: {
301: struct vnode vn;
302: struct filestat fst;
303: char *filename = NULL;
304: char *badtype = NULL;
305: char *getmnton();
306: extern char *devname();
307: char mode[15];
308:
309: if (kvm_read((off_t)vp, &vn, sizeof (struct vnode)) !=
310: sizeof (struct vnode)) {
311: dprintf(stderr, "can't read vnode at %x for pid %d\n",
312: vp, Pid);
313: return;
314: }
315: if (vn.v_type == VNON || vn.v_tag == VT_NON)
316: badtype = "none";
317: else if (vn.v_type == VBAD)
318: badtype = "bad";
319: else
320: switch (vn.v_tag) {
321: case VT_UFS:
322: ufs_filestat(&vn, &fst);
323: break;
324: case VT_MFS:
325: ufs_filestat(&vn, &fst);
326: break;
327: case VT_NFS:
328: nfs_filestat(&vn, &fst);
329: break;
330: default: {
331: static char unknown[10];
332: sprintf(badtype = unknown, "?(%x)", vn.v_tag);
333: break;;
334: }
335: }
336: if (checkfile) {
337: int fsmatch = 0;
338: register DEVS *d;
339:
340: if (badtype)
341: return;
342: for (d = devs; d != NULL; d = d->next)
343: if (d->fsid == fst.fsid) {
344: fsmatch = 1;
345: if (d->ino == fst.fileid) {
346: filename = d->name;
347: break;
348: }
349: }
350: if (fsmatch == 0 || (filename == NULL && fsflg == 0))
351: return;
352: }
353: PREFIX(i);
354: if (badtype) {
355: (void)printf(" - - %10s -\n", badtype);
356: return;
357: }
358: if (nflg)
359: (void)printf(" %2d,%-2d", major(fst.fsid), minor(fst.fsid));
360: else
361: (void)printf(" %-8s", getmnton(vn.v_mount));
362: if (nflg)
363: (void)sprintf(mode, "%o", fst.mode);
364: else
365: strmode(fst.mode, mode);
366: (void)printf(" %6d %10s", fst.fileid, mode);
367: switch (vn.v_type) {
368: case VBLK:
369: case VCHR: {
370: char *name;
371:
372: if (nflg || ((name = devname(fst.rdev, vn.v_type == VCHR ?
373: S_IFCHR : S_IFBLK)) == NULL))
374: printf(" %2d,%-2d", major(fst.rdev), minor(fst.rdev));
375: else
376: printf(" %6s", name);
377: break;
378: }
379: default:
380: printf(" %6d", fst.size);
381: }
382: if (filename && !fsflg)
383: printf(" %s", filename);
384:
385: putchar('\n');
386: }
387:
388: ufs_filestat(vp, fsp)
389: struct vnode *vp;
390: struct filestat *fsp;
391: {
392: struct inode *ip = VTOI(vp);
393:
394: fsp->fsid = ip->i_dev & 0xffff;
395: fsp->fileid = (long)ip->i_number;
396: fsp->mode = (mode_t)ip->i_mode;
397: fsp->size = (u_long)ip->i_size;
398: fsp->rdev = ip->i_rdev;
399: }
400:
401: nfs_filestat(vp, fsp)
402: struct vnode *vp;
403: struct filestat *fsp;
404: {
405: register struct nfsnode *np = VTONFS(vp);
406: register mode_t mode;
407:
408: fsp->fsid = np->n_vattr.va_fsid;
409: fsp->fileid = np->n_vattr.va_fileid;
410: fsp->size = np->n_size;
411: fsp->rdev = np->n_vattr.va_rdev;
412: mode = (mode_t)np->n_vattr.va_mode;
413: switch (vp->v_type) {
414: case VREG:
415: mode |= S_IFREG;
416: break;
417: case VDIR:
418: mode |= S_IFDIR;
419: break;
420: case VBLK:
421: mode |= S_IFBLK;
422: break;
423: case VCHR:
424: mode |= S_IFCHR;
425: break;
426: case VLNK:
427: mode |= S_IFLNK;
428: break;
429: case VSOCK:
430: mode |= S_IFSOCK;
431: break;
432: case VFIFO:
433: mode |= S_IFIFO;
434: break;
435: };
436: fsp->mode = mode;
437: }
438:
439:
440: char *
441: getmnton(m)
442: struct mount *m;
443: {
444: static struct mount mount;
445: static struct mtab {
446: struct mtab *next;
447: struct mount *m;
448: char mntonname[MNAMELEN];
449: } *mhead = NULL;
450: register struct mtab *mt;
451:
452: for (mt = mhead; mt != NULL; mt = mt->next)
453: if (m == mt->m)
454: return (mt->mntonname);
455: if (kvm_read((off_t)m, &mount, sizeof(struct mount)) !=
456: sizeof(struct mount)) {
457: fprintf(stderr, "can't read mount table at %x\n", m);
458: return (NULL);
459: }
460: if ((mt = (struct mtab *)malloc(sizeof (struct mtab))) == NULL) {
461: fprintf(stderr, "out of memory\n");
462: exit(1);
463: }
464: mt->m = m;
465: bcopy(&mount.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN);
466: mt->next = mhead;
467: mhead = mt;
468: return (mt->mntonname);
469: }
470:
471: socktrans(sock, i)
472: struct socket *sock;
473: {
474: static char *stypename[] = {
475: "unused", /* 0 */
476: "stream", /* 1 */
477: "dgram", /* 2 */
478: "raw", /* 3 */
479: "rdm", /* 4 */
480: "seqpak" /* 5 */
481: };
482: #define STYPEMAX 5
483: struct socket so;
484: struct protosw proto;
485: struct domain dom;
486: struct inpcb inpcb;
487: struct unpcb unpcb;
488: int len;
489: char dname[32], *strcpy();
490:
491: PREFIX(i);
492:
493: /* fill in socket */
494: if (kvm_read((off_t)sock, (char *)&so, sizeof(struct socket))
495: != sizeof(struct socket)) {
496: dprintf(stderr, "can't read sock at %x\n", sock);
497: goto bad;
498: }
499:
500: /* fill in protosw entry */
501: if (kvm_read((off_t)so.so_proto, (char *)&proto, sizeof(struct protosw))
502: != sizeof(struct protosw)) {
503: dprintf(stderr, "can't read protosw at %x", so.so_proto);
504: goto bad;
505: }
506:
507: /* fill in domain */
508: if (kvm_read((off_t)proto.pr_domain, (char *)&dom, sizeof(struct domain))
509: != sizeof(struct domain)) {
510: dprintf(stderr, "can't read domain at %x\n", proto.pr_domain);
511: goto bad;
512: }
513:
514: /*
515: * grab domain name
516: * kludge "internet" --> "inet" for brevity
517: */
518: if (dom.dom_family == AF_INET)
519: strcpy(dname, "inet");
520: else {
521: if ((len = kvm_read((off_t)dom.dom_name, dname, sizeof(dname) - 1)) < 0) {
522: dprintf(stderr, "can't read domain name at %x\n",
523: dom.dom_name);
524: dname[0] = '\0';
525: }
526: else
527: dname[len] = '\0';
528: }
529:
530: if ((u_short)so.so_type > STYPEMAX)
531: printf("* %s ?%d", dname, so.so_type);
532: else
533: printf("* %s %s", dname, stypename[so.so_type]);
534:
535: /*
536: * protocol specific formatting
537: *
538: * Try to find interesting things to print. For tcp, the interesting
539: * thing is the address of the tcpcb, for udp and others, just the
540: * inpcb (socket pcb). For unix domain, its the address of the socket
541: * pcb and the address of the connected pcb (if connected). Otherwise
542: * just print the protocol number and address of the socket itself.
543: * The idea is not to duplicate netstat, but to make available enough
544: * information for further analysis.
545: */
546: switch(dom.dom_family) {
547: case AF_INET:
548: getinetproto(proto.pr_protocol);
549: if (proto.pr_protocol == IPPROTO_TCP ) {
550: if (so.so_pcb) {
551: if (kvm_read((off_t)so.so_pcb, (char *)&inpcb, sizeof(struct inpcb))
552: != sizeof(struct inpcb)){
553: dprintf(stderr,
554: "can't read inpcb at %x\n", so.so_pcb);
555: goto bad;
556: }
557: printf(" %x", (int)inpcb.inp_ppcb);
558: }
559: }
560: else if (so.so_pcb)
561: printf(" %x", (int)so.so_pcb);
562: break;
563: case AF_UNIX:
564: /* print address of pcb and connected pcb */
565: if (so.so_pcb) {
566: printf(" %x", (int)so.so_pcb);
567: if (kvm_read((off_t)so.so_pcb, (char *)&unpcb, sizeof(struct unpcb))
568: != sizeof(struct unpcb)){
569: dprintf(stderr, "can't read unpcb at %x\n",
570: so.so_pcb);
571: goto bad;
572: }
573: if (unpcb.unp_conn) {
574: char shoconn[4], *cp;
575:
576: cp = shoconn;
577: if (!(so.so_state & SS_CANTRCVMORE))
578: *cp++ = '<';
579: *cp++ = '-';
580: if (!(so.so_state & SS_CANTSENDMORE))
581: *cp++ = '>';
582: *cp = '\0';
583: printf(" %s %x", shoconn,
584: (int)unpcb.unp_conn);
585: }
586: }
587: break;
588: default:
589: /* print protocol number and socket address */
590: printf(" %d %x", proto.pr_protocol, (int)sock);
591: }
592: printf("\n");
593: return;
594: bad:
595: printf("* error\n");
596: }
597:
598: /*
599: * getinetproto --
600: * print name of protocol number
601: */
602: getinetproto(number)
603: int number;
604: {
605: char *cp;
606:
607: switch(number) {
608: case IPPROTO_IP:
609: cp = "ip"; break;
610: case IPPROTO_ICMP:
611: cp ="icmp"; break;
612: case IPPROTO_GGP:
613: cp ="ggp"; break;
614: case IPPROTO_TCP:
615: cp ="tcp"; break;
616: case IPPROTO_EGP:
617: cp ="egp"; break;
618: case IPPROTO_PUP:
619: cp ="pup"; break;
620: case IPPROTO_UDP:
621: cp ="udp"; break;
622: case IPPROTO_IDP:
623: cp ="idp"; break;
624: case IPPROTO_RAW:
625: cp ="raw"; break;
626: default:
627: printf(" %d", number);
628: return;
629: }
630: printf(" %s", cp);
631: }
632:
633: getfname(filename)
634: char *filename;
635: {
636: struct stat statbuf;
637: DEVS *cur;
638: char *malloc();
639:
640: if (stat(filename, &statbuf)) {
641: fprintf(stderr, "fstat: %s: %s\n", strerror(errno),
642: 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: cur->ino = statbuf.st_ino;
653: cur->fsid = statbuf.st_dev & 0xffff;
654: cur->name = filename;
655: return(1);
656: }
657:
658: usage()
659: {
660: (void)fprintf(stderr,
661: "usage: fstat [-u user] [-p pid] [filename ...]\n");
662: exit(1);
663: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.