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