xref: /openbsd-src/usr.bin/fstat/fstat.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpenBSD: fstat.c,v 1.47 2003/07/02 21:04:10 deraadt Exp $	*/
2 
3 /*-
4  * Copyright (c) 1988, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #ifndef lint
33 static char copyright[] =
34 "@(#) Copyright (c) 1988, 1993\n\
35 	The Regents of the University of California.  All rights reserved.\n";
36 #endif /* not lint */
37 
38 #ifndef lint
39 /*static char sccsid[] = "from: @(#)fstat.c	8.1 (Berkeley) 6/6/93";*/
40 static char *rcsid = "$OpenBSD: fstat.c,v 1.47 2003/07/02 21:04:10 deraadt Exp $";
41 #endif /* not lint */
42 
43 #include <sys/param.h>
44 #include <sys/time.h>
45 #include <sys/proc.h>
46 #include <sys/user.h>
47 #include <sys/stat.h>
48 #include <sys/vnode.h>
49 #include <sys/socket.h>
50 #include <sys/socketvar.h>
51 #include <sys/domain.h>
52 #include <sys/protosw.h>
53 #include <sys/event.h>
54 #include <sys/eventvar.h>
55 #include <sys/unpcb.h>
56 #include <sys/sysctl.h>
57 #include <sys/filedesc.h>
58 #define	_KERNEL
59 #include <sys/mount.h>
60 #include <crypto/cryptodev.h>
61 #include <dev/systrace.h>
62 #include <sys/file.h>
63 #include <ufs/ufs/quota.h>
64 #include <ufs/ufs/inode.h>
65 #include <miscfs/nullfs/null.h>
66 #undef _KERNEL
67 #define NFS
68 #include <nfs/nfsproto.h>
69 #include <nfs/rpcv2.h>
70 #include <nfs/nfs.h>
71 #include <nfs/nfsnode.h>
72 #undef NFS
73 
74 #include <xfs/xfs_config.h>
75 #include <xfs/xfs_node.h>
76 
77 #include <net/route.h>
78 #include <netinet/in.h>
79 #include <netinet/in_systm.h>
80 #include <netinet/ip.h>
81 #include <netinet/in_pcb.h>
82 
83 #ifdef INET6
84 #include <netinet/ip6.h>
85 #include <netinet6/ip6_var.h>
86 #endif
87 
88 #include <netdb.h>
89 #include <arpa/inet.h>
90 
91 #include <sys/pipe.h>
92 
93 #include <ctype.h>
94 #include <errno.h>
95 #include <kvm.h>
96 #include <limits.h>
97 #include <nlist.h>
98 #include <paths.h>
99 #include <pwd.h>
100 #include <stdio.h>
101 #include <stdlib.h>
102 #include <string.h>
103 #include <unistd.h>
104 #include <netdb.h>
105 #include <err.h>
106 #include "fstat.h"
107 
108 #define	TEXT	-1
109 #define	CDIR	-2
110 #define	RDIR	-3
111 #define	TRACE	-4
112 
113 typedef struct devs {
114 	struct	devs *next;
115 	long	fsid;
116 	ino_t	ino;
117 	char	*name;
118 } DEVS;
119 DEVS *devs;
120 
121 int	fsflg;	/* show files on same filesystem as file(s) argument */
122 int	pflg;	/* show files open by a particular pid */
123 int	uflg;	/* show files open by a particular (effective) user */
124 int	checkfile; /* true if restricting to particular files or filesystems */
125 int	nflg;	/* (numerical) display f.s. and rdev as dev_t */
126 int	oflg;	/* display file offset */
127 int	vflg;	/* display errors in locating kernel data objects etc... */
128 
129 struct file **ofiles;	/* buffer of pointers to file structures */
130 int maxfiles;
131 #define ALLOC_OFILES(d)	\
132 	if ((d) > maxfiles) { \
133 		free(ofiles); \
134 		ofiles = malloc((d) * sizeof(struct file *)); \
135 		if (ofiles == NULL) \
136 			err(1, "malloc"); \
137 		maxfiles = (d); \
138 	}
139 
140 /*
141  * a kvm_read that returns true if everything is read
142  */
143 #define KVM_READ(kaddr, paddr, len) \
144 	(kvm_read(kd, (u_long)(kaddr), (void *)(paddr), (len)) == (len))
145 
146 kvm_t *kd;
147 
148 int ufs_filestat(struct vnode *, struct filestat *);
149 int ext2fs_filestat(struct vnode *, struct filestat *);
150 int isofs_filestat(struct vnode *, struct filestat *);
151 int msdos_filestat(struct vnode *, struct filestat *);
152 int nfs_filestat(struct vnode *, struct filestat *);
153 int xfs_filestat(struct vnode *, struct filestat *);
154 int null_filestat(struct vnode *, struct filestat *);
155 void dofiles(struct kinfo_proc *);
156 void getinetproto(int);
157 void socktrans(struct socket *, int);
158 void usage(void);
159 void vtrans(struct vnode *, int, int, off_t);
160 int getfname(char *);
161 void pipetrans(struct pipe *, int);
162 void kqueuetrans(struct kqueue *, int);
163 void cryptotrans(void *, int);
164 void systracetrans(struct fsystrace *, int);
165 char *getmnton(struct mount *);
166 const char *inet6_addrstr(struct in6_addr *);
167 
168 int
169 main(int argc, char *argv[])
170 {
171 	extern char *optarg;
172 	extern int optind;
173 	struct passwd *passwd;
174 	struct kinfo_proc *p, *plast;
175 	int arg, ch, what;
176 	char *memf, *nlistf;
177 	char buf[_POSIX2_LINE_MAX];
178 	int cnt;
179 
180 	arg = 0;
181 	what = KERN_PROC_ALL;
182 	nlistf = memf = NULL;
183 	oflg = 0;
184 	while ((ch = getopt(argc, argv, "fnop:u:vN:M:")) != -1)
185 		switch((char)ch) {
186 		case 'f':
187 			fsflg = 1;
188 			break;
189 		case 'M':
190 			memf = optarg;
191 			break;
192 		case 'N':
193 			nlistf = optarg;
194 			break;
195 		case 'n':
196 			nflg = 1;
197 			break;
198 		case 'o':
199 			oflg = 1;
200 			break;
201 		case 'p':
202 			if (pflg++)
203 				usage();
204 			if (!isdigit(*optarg)) {
205 				warnx( "-p requires a process id");
206 				usage();
207 			}
208 			what = KERN_PROC_PID;
209 			arg = atoi(optarg);
210 			break;
211 		case 'u':
212 			if (uflg++)
213 				usage();
214 			if (!(passwd = getpwnam(optarg)))
215 				errx(1, "%s: unknown uid", optarg);
216 			what = KERN_PROC_UID;
217 			arg = passwd->pw_uid;
218 			break;
219 		case 'v':
220 			vflg = 1;
221 			break;
222 		default:
223 			usage();
224 		}
225 
226 	/*
227 	 * Discard setgid privileges if not the running kernel so that bad
228 	 * guys can't print interesting stuff from kernel memory.
229 	 */
230 	if (nlistf != NULL || memf != NULL) {
231 		setegid(getgid());
232 		setgid(getgid());
233 	}
234 
235 	if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == NULL)
236 		errx(1, "%s", buf);
237 
238 	setegid(getgid());
239 	setgid(getgid());
240 
241 	if (*(argv += optind)) {
242 		for (; *argv; ++argv) {
243 			if (getfname(*argv))
244 				checkfile = 1;
245 		}
246 		if (!checkfile)	/* file(s) specified, but none accessible */
247 			exit(1);
248 	}
249 
250 	ALLOC_OFILES(256);	/* reserve space for file pointers */
251 
252 	if (fsflg && !checkfile) {
253 		/* -f with no files means use wd */
254 		if (getfname(".") == 0)
255 			exit(1);
256 		checkfile = 1;
257 	}
258 
259 	if ((p = kvm_getprocs(kd, what, arg, &cnt)) == NULL)
260 		errx(1, "%s", kvm_geterr(kd));
261 	if (nflg)
262 		printf("%s",
263 "USER     CMD          PID   FD  DEV    INUM       MODE R/W    DV|SZ");
264 	else
265 		printf("%s",
266 "USER     CMD          PID   FD MOUNT      INUM MODE       R/W    DV|SZ");
267 	if (oflg)
268 		printf("%s", ":OFFSET  ");
269 	if (checkfile && fsflg == 0)
270 		printf(" NAME\n");
271 	else
272 		putchar('\n');
273 
274 	for (plast = &p[cnt]; p < plast; ++p) {
275 		if (p->kp_proc.p_stat == SZOMB)
276 			continue;
277 		dofiles(p);
278 	}
279 	exit(0);
280 }
281 
282 char	*Uname, *Comm;
283 pid_t	Pid;
284 
285 #define PREFIX(i) do { \
286 	printf("%-8.8s %-10s %5ld", Uname, Comm, (long)Pid); \
287 	switch(i) { \
288 	case TEXT: \
289 		printf(" text"); \
290 		break; \
291 	case CDIR: \
292 		printf("   wd"); \
293 		break; \
294 	case RDIR: \
295 		printf(" root"); \
296 		break; \
297 	case TRACE: \
298 		printf("   tr"); \
299 		break; \
300 	default: \
301 		printf(" %4d", i); \
302 		break; \
303 	} \
304 } while (0)
305 
306 /*
307  * print open files attributed to this process
308  */
309 void
310 dofiles(struct kinfo_proc *kp)
311 {
312 	int i;
313 	struct file file;
314 	struct filedesc0 filed0;
315 #define	filed	filed0.fd_fd
316 	struct proc *p = &kp->kp_proc;
317 	struct eproc *ep = &kp->kp_eproc;
318 
319 	Uname = user_from_uid(ep->e_ucred.cr_uid, 0);
320 	Pid = p->p_pid;
321 	Comm = p->p_comm;
322 
323 	if (p->p_fd == NULL)
324 		return;
325 	if (!KVM_READ(p->p_fd, &filed0, sizeof (filed0))) {
326 		dprintf("can't read filedesc at %p for pid %ld",
327 		    p->p_fd, (long)Pid);
328 		return;
329 	}
330 	if (filed.fd_nfiles < 0 || filed.fd_lastfile >= filed.fd_nfiles ||
331 	    filed.fd_freefile > filed.fd_lastfile + 1) {
332 		dprintf("filedesc corrupted at %p for pid %ld",
333 		    p->p_fd, (long)Pid);
334 		return;
335 	}
336 	/*
337 	 * root directory vnode, if one
338 	 */
339 	if (filed.fd_rdir)
340 		vtrans(filed.fd_rdir, RDIR, FREAD, 0);
341 	/*
342 	 * current working directory vnode
343 	 */
344 	vtrans(filed.fd_cdir, CDIR, FREAD, 0);
345 	/*
346 	 * ktrace vnode, if one
347 	 */
348 	if (p->p_tracep)
349 		vtrans(p->p_tracep, TRACE, FREAD|FWRITE, 0);
350 	/*
351 	 * open files
352 	 */
353 #define FPSIZE	(sizeof (struct file *))
354 	ALLOC_OFILES(filed.fd_lastfile+1);
355 	if (filed.fd_nfiles > NDFILE) {
356 		if (!KVM_READ(filed.fd_ofiles, ofiles,
357 		    (filed.fd_lastfile+1) * FPSIZE)) {
358 			dprintf("can't read file structures at %p for pid %ld",
359 			    filed.fd_ofiles, (long)Pid);
360 			return;
361 		}
362 	} else
363 		bcopy(filed0.fd_dfiles, ofiles, (filed.fd_lastfile+1) * FPSIZE);
364 	for (i = 0; i <= filed.fd_lastfile; i++) {
365 		if (ofiles[i] == NULL)
366 			continue;
367 		if (!KVM_READ(ofiles[i], &file, sizeof (struct file))) {
368 			dprintf("can't read file %d at %p for pid %ld",
369 				i, ofiles[i], (long)Pid);
370 			continue;
371 		}
372 		if (file.f_type == DTYPE_VNODE)
373 			vtrans((struct vnode *)file.f_data, i, file.f_flag,
374 			    file.f_offset);
375 		else if (file.f_type == DTYPE_SOCKET) {
376 			if (checkfile == 0)
377 				socktrans((struct socket *)file.f_data, i);
378 		} else if (file.f_type == DTYPE_PIPE) {
379 			if (checkfile == 0)
380 				pipetrans((struct pipe *)file.f_data, i);
381 		} else if (file.f_type == DTYPE_KQUEUE) {
382 			if (checkfile == 0)
383 				kqueuetrans((struct kqueue *)file.f_data, i);
384 		} else if (file.f_type == DTYPE_CRYPTO) {
385 			if (checkfile == 0)
386 				cryptotrans(file.f_data, i);
387 		} else if (file.f_type == DTYPE_SYSTRACE) {
388 			if (checkfile == 0)
389 				systracetrans((struct fsystrace *)file.f_data, i);
390 		} else {
391 			dprintf("unknown file type %d for file %d of pid %ld",
392 				file.f_type, i, (long)Pid);
393 		}
394 	}
395 }
396 
397 void
398 vtrans(struct vnode *vp, int i, int flag, off_t offset)
399 {
400 	struct vnode vn;
401 	struct filestat fst;
402 	char rw[3], mode[17];
403 	char *badtype = NULL, *filename;
404 
405 	filename = badtype = NULL;
406 	if (!KVM_READ(vp, &vn, sizeof (struct vnode))) {
407 		dprintf("can't read vnode at %p for pid %ld", vp, (long)Pid);
408 		return;
409 	}
410 	if (vn.v_type == VNON || vn.v_tag == VT_NON)
411 		badtype = "none";
412 	else if (vn.v_type == VBAD)
413 		badtype = "bad";
414 	else
415 		switch (vn.v_tag) {
416 		case VT_UFS:
417 		case VT_MFS:
418 			if (!ufs_filestat(&vn, &fst))
419 				badtype = "error";
420 			break;
421 		case VT_NFS:
422 			if (!nfs_filestat(&vn, &fst))
423 				badtype = "error";
424 			break;
425 		case VT_EXT2FS:
426 			if (!ext2fs_filestat(&vn, &fst))
427 				badtype = "error";
428 			break;
429 		case VT_ISOFS:
430 			if (!isofs_filestat(&vn, &fst))
431 				badtype = "error";
432 			break;
433 		case VT_MSDOSFS:
434 			if (!msdos_filestat(&vn, &fst))
435 				badtype = "error";
436 			break;
437 		case VT_XFS:
438 			if (!xfs_filestat(&vn, &fst))
439 				badtype = "error";
440 			break;
441 		case VT_NULL:
442 			if (!null_filestat(&vn, &fst))
443 				badtype = "error";
444 			break;
445 		default: {
446 			static char unknown[30];
447 			snprintf(badtype = unknown, sizeof unknown,
448 			    "?(%x)", vn.v_tag);
449 			break;
450 		}
451 	}
452 	if (checkfile) {
453 		int fsmatch = 0;
454 		DEVS *d;
455 
456 		if (badtype)
457 			return;
458 		for (d = devs; d != NULL; d = d->next)
459 			if (d->fsid == fst.fsid) {
460 				fsmatch = 1;
461 				if (d->ino == fst.fileid) {
462 					filename = d->name;
463 					break;
464 				}
465 			}
466 		if (fsmatch == 0 || (filename == NULL && fsflg == 0))
467 			return;
468 	}
469 	PREFIX(i);
470 	if (badtype) {
471 		(void)printf(" -         -  %10s    -\n", badtype);
472 		return;
473 	}
474 	if (nflg)
475 		(void)printf(" %2ld,%-2ld", (long)major(fst.fsid),
476 		    (long)minor(fst.fsid));
477 	else
478 		(void)printf(" %-8s", getmnton(vn.v_mount));
479 	if (nflg)
480 		(void)snprintf(mode, sizeof mode, "%o", fst.mode);
481 	else
482 		strmode(fst.mode, mode);
483 	(void)printf(" %6ld %11s", fst.fileid, mode);
484 	rw[0] = '\0';
485 	if (flag & FREAD)
486 		strlcat(rw, "r", sizeof rw);
487 	if (flag & FWRITE)
488 		strlcat(rw, "w", sizeof rw);
489 	printf(" %2s", rw);
490 	switch (vn.v_type) {
491 	case VBLK:
492 	case VCHR: {
493 		char *name;
494 
495 		if (nflg || ((name = devname(fst.rdev, vn.v_type == VCHR ?
496 		    S_IFCHR : S_IFBLK)) == NULL))
497 			printf("   %2d,%-3d", major(fst.rdev), minor(fst.rdev));
498 		else
499 			printf("  %7s", name);
500 		if (oflg)
501 			printf("         ");
502 		break;
503 	}
504 	default:
505 		printf(" %8lld", (long long)fst.size);
506 		if (oflg)
507 			printf(":%-8lld", (long long)offset);
508 	}
509 	if (filename && !fsflg)
510 		printf(" %s", filename);
511 	putchar('\n');
512 }
513 
514 int
515 ufs_filestat(struct vnode *vp, struct filestat *fsp)
516 {
517 	struct inode inode;
518 
519 	if (!KVM_READ(VTOI(vp), &inode, sizeof (inode))) {
520 		dprintf("can't read inode at %p for pid %ld",
521 		    VTOI(vp), (long)Pid);
522 		return 0;
523 	}
524 	fsp->fsid = inode.i_dev & 0xffff;
525 	fsp->fileid = (long)inode.i_number;
526 	fsp->mode = inode.i_ffs_mode;
527 	fsp->size = inode.i_ffs_size;
528 	fsp->rdev = inode.i_ffs_rdev;
529 
530 	return 1;
531 }
532 
533 int
534 ext2fs_filestat(struct vnode *vp, struct filestat *fsp)
535 {
536 	struct inode inode;
537 
538 	if (!KVM_READ(VTOI(vp), &inode, sizeof (inode))) {
539 		dprintf("can't read inode at %p for pid %ld",
540 		    VTOI(vp), (long)Pid);
541 		return 0;
542 	}
543 	fsp->fsid = inode.i_dev & 0xffff;
544 	fsp->fileid = (long)inode.i_number;
545 	fsp->mode = inode.i_e2fs_mode;
546 	fsp->size = inode.i_e2fs_size;
547 	fsp->rdev = 0;	/* XXX */
548 
549 	return 1;
550 }
551 
552 int
553 msdos_filestat(struct vnode *vp, struct filestat *fsp)
554 {
555 #if 0
556 	struct inode inode;
557 
558 	if (!KVM_READ(VTOI(vp), &inode, sizeof (inode))) {
559 		dprintf("can't read inode at %p for pid %ld",
560 		    VTOI(vp), (long)Pid);
561 		return 0;
562 	}
563 	fsp->fsid = inode.i_dev & 0xffff;
564 	fsp->fileid = (long)inode.i_number;
565 	fsp->mode = inode.i_e2fs_mode;
566 	fsp->size = inode.i_e2fs_size;
567 	fsp->rdev = 0;	/* XXX */
568 #endif
569 
570 	return 1;
571 }
572 
573 int
574 nfs_filestat(struct vnode *vp, struct filestat *fsp)
575 {
576 	struct nfsnode nfsnode;
577 	mode_t mode;
578 
579 	if (!KVM_READ(VTONFS(vp), &nfsnode, sizeof (nfsnode))) {
580 		dprintf("can't read nfsnode at %p for pid %ld",
581 		    VTONFS(vp), (long)Pid);
582 		return 0;
583 	}
584 	fsp->fsid = nfsnode.n_vattr.va_fsid;
585 	fsp->fileid = nfsnode.n_vattr.va_fileid;
586 	fsp->size = nfsnode.n_size;
587 	fsp->rdev = nfsnode.n_vattr.va_rdev;
588 	mode = (mode_t)nfsnode.n_vattr.va_mode;
589 	switch (vp->v_type) {
590 	case VREG:
591 		mode |= S_IFREG;
592 		break;
593 	case VDIR:
594 		mode |= S_IFDIR;
595 		break;
596 	case VBLK:
597 		mode |= S_IFBLK;
598 		break;
599 	case VCHR:
600 		mode |= S_IFCHR;
601 		break;
602 	case VLNK:
603 		mode |= S_IFLNK;
604 		break;
605 	case VSOCK:
606 		mode |= S_IFSOCK;
607 		break;
608 	case VFIFO:
609 		mode |= S_IFIFO;
610 		break;
611 	default:
612 		break;
613 	}
614 	fsp->mode = mode;
615 
616 	return 1;
617 }
618 
619 int
620 xfs_filestat(struct vnode *vp, struct filestat *fsp)
621 {
622 	struct xfs_node xfs_node;
623 
624 	if (!KVM_READ(VNODE_TO_XNODE(vp), &xfs_node, sizeof (xfs_node))) {
625 		dprintf("can't read xfs_node at %p for pid %ld",
626 		    VTOI(vp), (long)Pid);
627 		return 0;
628 	}
629 	fsp->fsid = xfs_node.attr.va_fsid;
630 	fsp->fileid = (long)xfs_node.attr.va_fileid;
631 	fsp->mode = xfs_node.attr.va_mode;
632 	fsp->size = xfs_node.attr.va_size;
633 	fsp->rdev = xfs_node.attr.va_rdev;
634 
635 	return 1;
636 }
637 
638 int
639 null_filestat(struct vnode *vp, struct filestat *fsp)
640 {
641 	struct null_node node;
642 	struct filestat fst;
643 	struct vnode vn;
644 	int fail = 1;
645 
646 	memset(&fst, 0, sizeof fst);
647 
648 	if (!KVM_READ(VTONULL(vp), &node, sizeof (node))) {
649 		dprintf("can't read node at %p for pid %ld",
650 		    VTONULL(vp), (long)Pid);
651 		return 0;
652 	}
653 
654 	/*
655 	 * Attempt to find information that might be useful.
656 	 */
657 	if (node.null_lowervp) {
658 		if (!KVM_READ(node.null_lowervp, &vn, sizeof (vn))) {
659 			dprintf("can't read vnode at %p for pid %ld",
660 			    node.null_lowervp, (long)Pid);
661 			return 0;
662 		}
663 
664 		fail = 0;
665 		if (vn.v_type == VNON || vn.v_tag == VT_NON)
666 			fail = 1;
667 		else if (vn.v_type == VBAD)
668 			fail = 1;
669 		else
670 			switch (vn.v_tag) {
671 			case VT_UFS:
672 			case VT_MFS:
673 				if (!ufs_filestat(&vn, &fst))
674 					fail = 1;
675 				break;
676 			case VT_NFS:
677 				if (!nfs_filestat(&vn, &fst))
678 					fail = 1;
679 				break;
680 			case VT_EXT2FS:
681 				if (!ext2fs_filestat(&vn, &fst))
682 					fail = 1;
683 				break;
684 			case VT_ISOFS:
685 				if (!isofs_filestat(&vn, &fst))
686 					fail = 1;
687 				break;
688 			case VT_MSDOSFS:
689 				if (!msdos_filestat(&vn, &fst))
690 					fail = 1;
691 				break;
692 			case VT_XFS:
693 				if (!xfs_filestat(&vn, &fst))
694 					fail = 1;
695 				break;
696 			default:
697 				break;
698 			}
699 	}
700 
701 	fsp->fsid = (long)node.null_vnode;
702 	if (fail)
703 		fsp->fileid = (long)node.null_lowervp;
704 	else
705 		fsp->fileid = fst.fileid;
706 	fsp->mode = fst.mode;
707 	fsp->size = fst.mode;
708 	fsp->rdev = fst.mode;
709 
710 	return 1;
711 }
712 
713 char *
714 getmnton(struct mount *m)
715 {
716 	static struct mount mount;
717 	static struct mtab {
718 		struct mtab *next;
719 		struct mount *m;
720 		char mntonname[MNAMELEN];
721 	} *mhead = NULL;
722 	struct mtab *mt;
723 
724 	for (mt = mhead; mt != NULL; mt = mt->next)
725 		if (m == mt->m)
726 			return (mt->mntonname);
727 	if (!KVM_READ(m, &mount, sizeof(struct mount))) {
728 		warn("can't read mount table at %p", m);
729 		return (NULL);
730 	}
731 	if ((mt = malloc(sizeof (struct mtab))) == NULL)
732 		err(1, "malloc");
733 	mt->m = m;
734 	bcopy(&mount.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN);
735 	mt->next = mhead;
736 	mhead = mt;
737 	return (mt->mntonname);
738 }
739 
740 void
741 pipetrans(struct pipe *pipe, int i)
742 {
743 	struct pipe pi;
744 	void *maxaddr;
745 
746 	PREFIX(i);
747 
748 	printf(" ");
749 
750 	/* fill in socket */
751 	if (!KVM_READ(pipe, &pi, sizeof(struct pipe))) {
752 		dprintf("can't read pipe at %p", pipe);
753 		goto bad;
754 	}
755 
756 	/*
757 	 * We don't have enough space to fit both peer and own address, so
758 	 * we select the higher address so both ends of the pipe have the
759 	 * same visible addr. (it's the higher address because when the other
760 	 * end closes, it becomes 0)
761 	 */
762 	maxaddr = MAX(pipe, pi.pipe_peer);
763 
764 	printf("pipe %p state: %s%s%s\n", maxaddr,
765 	    (pi.pipe_state & PIPE_WANTR) ? "R" : "",
766 	    (pi.pipe_state & PIPE_WANTW) ? "W" : "",
767 	    (pi.pipe_state & PIPE_EOF) ? "E" : "");
768 	return;
769 bad:
770 	printf("* error\n");
771 }
772 
773 void
774 kqueuetrans(struct kqueue *kq, int i)
775 {
776 	struct kqueue kqi;
777 
778 	PREFIX(i);
779 
780 	printf(" ");
781 
782 	/* fill it in */
783 	if (!KVM_READ(kq, &kqi, sizeof(struct kqueue))) {
784 		dprintf("can't read kqueue at %p", kq);
785 		goto bad;
786 	}
787 
788 	printf("kqueue %p %d state: %s%s\n", kq, kqi.kq_count,
789 	    (kqi.kq_state & KQ_SEL) ? "S" : "",
790 	    (kqi.kq_state & KQ_SLEEP) ? "W" : "");
791 	return;
792 bad:
793 	printf("* error\n");
794 }
795 
796 void
797 cryptotrans(void *f, int i)
798 {
799 	PREFIX(i);
800 
801 	printf(" ");
802 
803 	printf("crypto %p\n", f);
804 }
805 
806 void
807 systracetrans(struct fsystrace *f, int i)
808 {
809 	struct fsystrace fi;
810 
811 	PREFIX(i);
812 
813 	printf(" ");
814 
815 	/* fill it in */
816 	if (!KVM_READ(f, &fi, sizeof(fi))) {
817 		dprintf("can't read fsystrace at %p", f);
818 		goto bad;
819 	}
820 
821 	printf("systrace %p npol %d\n", f, fi.npolicies);
822 	return;
823 bad:
824 	printf("* error\n");
825 }
826 
827 #ifdef INET6
828 const char *
829 inet6_addrstr(struct in6_addr *p)
830 {
831 	struct sockaddr_in6 sin6;
832 	static char hbuf[NI_MAXHOST];
833 #ifdef NI_WITHSCOPEID
834 	const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;
835 #else
836 	const int niflags = NI_NUMERICHOST
837 #endif
838 
839 	memset(&sin6, 0, sizeof(sin6));
840 	sin6.sin6_family = AF_INET6;
841 	sin6.sin6_len = sizeof(struct sockaddr_in6);
842 	sin6.sin6_addr = *p;
843 	if (IN6_IS_ADDR_LINKLOCAL(p) &&
844 	    *(u_int16_t *)&sin6.sin6_addr.s6_addr[2] != 0) {
845 		sin6.sin6_scope_id =
846 		    ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
847 		sin6.sin6_addr.s6_addr[2] = sin6.sin6_addr.s6_addr[3] = 0;
848 	}
849 
850 	if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
851 	    hbuf, sizeof(hbuf), NULL, 0, niflags))
852 		return "invalid";
853 
854 	return hbuf;
855 }
856 #endif
857 
858 void
859 socktrans(struct socket *sock, int i)
860 {
861 	static char *stypename[] = {
862 		"unused",	/* 0 */
863 		"stream",	/* 1 */
864 		"dgram",	/* 2 */
865 		"raw",		/* 3 */
866 		"rdm",		/* 4 */
867 		"seqpak"	/* 5 */
868 	};
869 #define	STYPEMAX 5
870 	struct socket	so;
871 	struct protosw	proto;
872 	struct domain	dom;
873 	struct inpcb	inpcb;
874 	struct unpcb	unpcb;
875 	int len;
876 	char dname[32];
877 #ifdef INET6
878 	char xaddrbuf[NI_MAXHOST + 2];
879 #endif
880 
881 	PREFIX(i);
882 
883 	/* fill in socket */
884 	if (!KVM_READ(sock, &so, sizeof(struct socket))) {
885 		dprintf("can't read sock at %p", sock);
886 		goto bad;
887 	}
888 
889 	/* fill in protosw entry */
890 	if (!KVM_READ(so.so_proto, &proto, sizeof(struct protosw))) {
891 		dprintf("can't read protosw at %p", so.so_proto);
892 		goto bad;
893 	}
894 
895 	/* fill in domain */
896 	if (!KVM_READ(proto.pr_domain, &dom, sizeof(struct domain))) {
897 		dprintf("can't read domain at %p", proto.pr_domain);
898 		goto bad;
899 	}
900 
901 	if ((len = kvm_read(kd, (u_long)dom.dom_name, dname,
902 	    sizeof(dname) - 1)) != sizeof(dname) -1) {
903 		dprintf("can't read domain name at %p", dom.dom_name);
904 		dname[0] = '\0';
905 	} else
906 		dname[len] = '\0';
907 
908 	if ((u_short)so.so_type > STYPEMAX)
909 		printf("* %s ?%d", dname, so.so_type);
910 	else
911 		printf("* %s %s", dname, stypename[so.so_type]);
912 
913 	/*
914 	 * protocol specific formatting
915 	 *
916 	 * Try to find interesting things to print.  For tcp, the interesting
917 	 * thing is the address of the tcpcb, for udp and others, just the
918 	 * inpcb (socket pcb).  For unix domain, its the address of the socket
919 	 * pcb and the address of the connected pcb (if connected).  Otherwise
920 	 * just print the protocol number and address of the socket itself.
921 	 * The idea is not to duplicate netstat, but to make available enough
922 	 * information for further analysis.
923 	 */
924 	switch(dom.dom_family) {
925 	case AF_INET:
926 		getinetproto(proto.pr_protocol);
927 		if (proto.pr_protocol == IPPROTO_TCP) {
928 			if (so.so_pcb == NULL)
929 				break;
930 			if (kvm_read(kd, (u_long)so.so_pcb, (char *)&inpcb,
931 			    sizeof(struct inpcb)) != sizeof(struct inpcb)) {
932 				dprintf("can't read inpcb at %p", so.so_pcb);
933 				goto bad;
934 			}
935 			printf(" %p", inpcb.inp_ppcb);
936 			printf(" %s:%d",
937 			    inpcb.inp_laddr.s_addr == INADDR_ANY ? "*" :
938 			    inet_ntoa(inpcb.inp_laddr),
939 			    ntohs(inpcb.inp_lport));
940 			if (inpcb.inp_fport) {
941 				if (so.so_state & SS_CONNECTOUT)
942 					printf(" --> ");
943 				else
944 					printf(" <-- ");
945 				printf("%s:%d",
946 				    inpcb.inp_faddr.s_addr == INADDR_ANY ? "*" :
947 				    inet_ntoa(inpcb.inp_faddr),
948 				    ntohs(inpcb.inp_fport));
949 			}
950 		} else if (proto.pr_protocol == IPPROTO_UDP) {
951 			if (so.so_pcb == NULL)
952 				break;
953 			if (kvm_read(kd, (u_long)so.so_pcb, (char *)&inpcb,
954 			    sizeof(struct inpcb)) != sizeof(struct inpcb)) {
955 				dprintf("can't read inpcb at %p", so.so_pcb);
956 				goto bad;
957 			}
958 			printf(" %s:%d",
959 			    inpcb.inp_laddr.s_addr == INADDR_ANY ? "*" :
960 			    inet_ntoa(inpcb.inp_laddr),
961 			    ntohs(inpcb.inp_lport));
962 			if (inpcb.inp_fport)
963 				printf(" <-> %s:%d",
964 				    inpcb.inp_faddr.s_addr == INADDR_ANY ? "*" :
965 				    inet_ntoa(inpcb.inp_faddr),
966 				    ntohs(inpcb.inp_fport));
967 		} else if (so.so_pcb)
968 			printf(" %p", so.so_pcb);
969 		break;
970 #ifdef INET6
971 	case AF_INET6:
972 		getinetproto(proto.pr_protocol);
973 		if (proto.pr_protocol == IPPROTO_TCP) {
974 			if (so.so_pcb == NULL)
975 				break;
976 			if (kvm_read(kd, (u_long)so.so_pcb, (char *)&inpcb,
977 			    sizeof(struct inpcb)) != sizeof(struct inpcb)) {
978 				dprintf("can't read inpcb at %p", so.so_pcb);
979 				goto bad;
980 			}
981 			printf(" %p", inpcb.inp_ppcb);
982 			snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]",
983 			    inet6_addrstr(&inpcb.inp_laddr6));
984 			printf(" %s:%d",
985 			    IN6_IS_ADDR_UNSPECIFIED(&inpcb.inp_laddr6) ? "*" :
986 			    xaddrbuf,
987 			    ntohs(inpcb.inp_lport));
988 			if (inpcb.inp_fport) {
989 				if (so.so_state & SS_CONNECTOUT)
990 					printf(" --> ");
991 				else
992 					printf(" <-- ");
993 				snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]",
994 				    inet6_addrstr(&inpcb.inp_faddr6));
995 				printf("%s:%d",
996 				    IN6_IS_ADDR_UNSPECIFIED(&inpcb.inp_faddr6) ? "*" :
997 				    xaddrbuf,
998 				    ntohs(inpcb.inp_fport));
999 			}
1000 		} else if (proto.pr_protocol == IPPROTO_UDP) {
1001 			if (so.so_pcb == NULL)
1002 				break;
1003 			if (kvm_read(kd, (u_long)so.so_pcb, (char *)&inpcb,
1004 			    sizeof(struct inpcb)) != sizeof(struct inpcb)) {
1005 				dprintf("can't read inpcb at %p", so.so_pcb);
1006 				goto bad;
1007 			}
1008 			snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]",
1009 			    inet6_addrstr(&inpcb.inp_laddr6));
1010 			printf(" %s:%d",
1011 			    IN6_IS_ADDR_UNSPECIFIED(&inpcb.inp_laddr6) ? "*" :
1012 			    xaddrbuf,
1013 			    ntohs(inpcb.inp_lport));
1014 			if (inpcb.inp_fport) {
1015 				snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]",
1016 				    inet6_addrstr(&inpcb.inp_faddr6));
1017 				printf(" <-> %s:%d",
1018 				    IN6_IS_ADDR_UNSPECIFIED(&inpcb.inp_faddr6) ? "*" :
1019 				    xaddrbuf,
1020 				    ntohs(inpcb.inp_fport));
1021 			}
1022 		} else if (so.so_pcb)
1023 			printf(" %p", so.so_pcb);
1024 		break;
1025 #endif
1026 	case AF_UNIX:
1027 		/* print address of pcb and connected pcb */
1028 		if (so.so_pcb) {
1029 			printf(" %p", so.so_pcb);
1030 			if (kvm_read(kd, (u_long)so.so_pcb, (char *)&unpcb,
1031 			    sizeof(struct unpcb)) != sizeof(struct unpcb)){
1032 				dprintf("can't read unpcb at %p", so.so_pcb);
1033 				goto bad;
1034 			}
1035 			if (unpcb.unp_conn) {
1036 				char shoconn[4], *cp;
1037 
1038 				cp = shoconn;
1039 				if (!(so.so_state & SS_CANTRCVMORE))
1040 					*cp++ = '<';
1041 				*cp++ = '-';
1042 				if (!(so.so_state & SS_CANTSENDMORE))
1043 					*cp++ = '>';
1044 				*cp = '\0';
1045 				printf(" %s %p", shoconn,
1046 				    unpcb.unp_conn);
1047 			}
1048 		}
1049 		break;
1050 	default:
1051 		/* print protocol number and socket address */
1052 		printf(" %d %p", proto.pr_protocol, sock);
1053 	}
1054 	printf("\n");
1055 	return;
1056 bad:
1057 	printf("* error\n");
1058 }
1059 
1060 /*
1061  * getinetproto --
1062  *	print name of protocol number
1063  */
1064 void
1065 getinetproto(number)
1066 	int number;
1067 {
1068 	static int isopen;
1069 	struct protoent *pe;
1070 
1071 	if (!isopen)
1072 		setprotoent(++isopen);
1073 	if ((pe = getprotobynumber(number)) != NULL)
1074 		printf(" %s", pe->p_name);
1075 	else
1076 		printf(" %d", number);
1077 }
1078 
1079 int
1080 getfname(char *filename)
1081 {
1082 	struct stat statbuf;
1083 	DEVS *cur;
1084 
1085 	if (stat(filename, &statbuf)) {
1086 		warn("%s", filename);
1087 		return(0);
1088 	}
1089 	if ((cur = malloc(sizeof(DEVS))) == NULL)
1090 		err(1, "malloc");
1091 	cur->next = devs;
1092 	devs = cur;
1093 
1094 	cur->ino = statbuf.st_ino;
1095 	cur->fsid = statbuf.st_dev & 0xffff;
1096 	cur->name = filename;
1097 	return(1);
1098 }
1099 
1100 void
1101 usage(void)
1102 {
1103 	fprintf(stderr, "usage: fstat [-fnv] [-p pid] [-u user] "
1104 	    "[-N system] [-M core] [file ...]\n");
1105 	exit(1);
1106 }
1107