fstat.c revision 146466
1179055Sjfv/*-
2171384Sjfv * Copyright (c) 1988, 1993
3320897Serj *	The Regents of the University of California.  All rights reserved.
4171384Sjfv *
5320897Serj * Redistribution and use in source and binary forms, with or without
6320897Serj * modification, are permitted provided that the following conditions
7171384Sjfv * are met:
8320897Serj * 1. Redistributions of source code must retain the above copyright
9320897Serj *    notice, this list of conditions and the following disclaimer.
10171384Sjfv * 2. Redistributions in binary form must reproduce the above copyright
11320897Serj *    notice, this list of conditions and the following disclaimer in the
12320897Serj *    documentation and/or other materials provided with the distribution.
13320897Serj * 3. All advertising materials mentioning features or use of this software
14171384Sjfv *    must display the following acknowledgement:
15320897Serj *	This product includes software developed by the University of
16320897Serj *	California, Berkeley and its contributors.
17320897Serj * 4. Neither the name of the University nor the names of its contributors
18171384Sjfv *    may be used to endorse or promote products derived from this software
19320897Serj *    without specific prior written permission.
20171384Sjfv *
21320897Serj * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22320897Serj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23320897Serj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24320897Serj * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25320897Serj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26320897Serj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27320897Serj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28320897Serj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29171384Sjfv * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30171384Sjfv * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31171384Sjfv * SUCH DAMAGE.
32179055Sjfv */
33179055Sjfv
34171384Sjfv#ifndef lint
35171384Sjfvstatic const char copyright[] =
36171384Sjfv"@(#) Copyright (c) 1988, 1993\n\
37171384Sjfv	The Regents of the University of California.  All rights reserved.\n";
38292674Ssbruno#endif /* not lint */
39292674Ssbruno
40282289Serj#ifndef lint
41292674Ssbruno#if 0
42282289Serjstatic char sccsid[] = "@(#)fstat.c	8.3 (Berkeley) 5/2/95";
43282289Serj#endif
44282289Serj#endif /* not lint */
45282289Serj#include <sys/cdefs.h>
46282289Serj__FBSDID("$FreeBSD: head/usr.bin/fstat/fstat.c 146466 2005-05-21 09:55:10Z ru $");
47282289Serj
48282289Serj#include <sys/param.h>
49282289Serj#include <sys/time.h>
50282289Serj#include <sys/proc.h>
51282289Serj#include <sys/user.h>
52282289Serj#include <sys/stat.h>
53282289Serj#include <sys/vnode.h>
54282289Serj#include <sys/socket.h>
55282289Serj#include <sys/socketvar.h>
56320897Serj#include <sys/domain.h>
57320897Serj#include <sys/protosw.h>
58320897Serj#include <sys/un.h>
59320897Serj#include <sys/unpcb.h>
60171384Sjfv#include <sys/sysctl.h>
61251964Sjfv#include <sys/filedesc.h>
62251964Sjfv#include <sys/queue.h>
63251964Sjfv#define	_KERNEL
64251964Sjfv#include <sys/pipe.h>
65251964Sjfv#include <sys/conf.h>
66251964Sjfv#include <sys/file.h>
67251964Sjfv#include <sys/mount.h>
68251964Sjfv#include <ufs/ufs/quota.h>
69251964Sjfv#include <ufs/ufs/inode.h>
70251964Sjfv#include <fs/devfs/devfs.h>
71251964Sjfv#undef _KERNEL
72251964Sjfv#include <nfs/nfsproto.h>
73251964Sjfv#include <nfs/rpcv2.h>
74171384Sjfv#include <nfsclient/nfs.h>
75171384Sjfv#include <nfsclient/nfsnode.h>
76171384Sjfv
77171384Sjfv
78171384Sjfv#include <vm/vm.h>
79171384Sjfv#include <vm/vm_map.h>
80171384Sjfv#include <vm/vm_object.h>
81171384Sjfv
82171384Sjfv#include <net/route.h>
83185352Sjfv#include <netinet/in.h>
84171384Sjfv#include <netinet/in_systm.h>
85171384Sjfv#include <netinet/ip.h>
86171384Sjfv#include <netinet/in_pcb.h>
87172043Sjfv
88171384Sjfv#include <ctype.h>
89200239Sjfv#include <err.h>
90200239Sjfv#include <fcntl.h>
91171384Sjfv#include <kvm.h>
92172043Sjfv#include <limits.h>
93172043Sjfv#include <nlist.h>
94172043Sjfv#include <paths.h>
95172043Sjfv#include <pwd.h>
96172043Sjfv#include <stdio.h>
97172043Sjfv#include <stdlib.h>
98179055Sjfv#include <string.h>
99172043Sjfv#include <unistd.h>
100190873Sjfv#include <netdb.h>
101190873Sjfv
102190873Sjfv#include "fstat.h"
103280182Sjfv
104280182Sjfv#define	TEXT	-1
105280182Sjfv#define	CDIR	-2
106280182Sjfv#define	RDIR	-3
107280182Sjfv#define	TRACE	-4
108280182Sjfv#define	MMAP	-5
109280182Sjfv#define	JDIR	-6
110320897Serj
111280182SjfvDEVS *devs;
112320897Serj
113320897Serj#ifdef notdef
114215911Sjfvstruct nlist nl[] = {
115172043Sjfv	{ "" },
116172043Sjfv};
117172043Sjfv#endif
118172043Sjfv
119292674Ssbrunoint 	fsflg,	/* show files on same filesystem as file(s) argument */
120172043Sjfv	pflg,	/* show files open by a particular pid */
121172043Sjfv	uflg;	/* show files open by a particular (effective) user */
122172043Sjfvint 	checkfile; /* true if restricting to particular files or filesystems */
123172043Sjfvint	nflg;	/* (numerical) display f.s. and rdev as dev_t */
124172043Sjfvint	vflg;	/* display errors in locating kernel data objects etc... */
125172043Sjfvint	mflg;	/* include memory-mapped files */
126172043Sjfv
127172043Sjfv
128172043Sjfvstruct file **ofiles;	/* buffer of pointers to file structures */
129172043Sjfvint maxfiles;
130172043Sjfv#define ALLOC_OFILES(d)	\
131172043Sjfv	if ((d) > maxfiles) { \
132172043Sjfv		free(ofiles); \
133172043Sjfv		ofiles = malloc((d) * sizeof(struct file *)); \
134172043Sjfv		if (ofiles == NULL) { \
135179055Sjfv			err(1, NULL); \
136172043Sjfv		} \
137251964Sjfv		maxfiles = (d); \
138251964Sjfv	}
139251964Sjfv
140251964Sjfvchar *memf, *nlistf;
141251964Sjfvkvm_t *kd;
142251964Sjfv
143282289Serjstatic void fstat_kvm(int, int);
144282289Serjstatic void fstat_sysctl(int, int);
145247822Sjfvvoid dofiles(struct kinfo_proc *kp);
146247822Sjfvvoid dommap(struct kinfo_proc *kp);
147247822Sjfvvoid vtrans(struct vnode *vp, int i, int flag);
148247822Sjfvint  ufs_filestat(struct vnode *vp, struct filestat *fsp);
149247822Sjfvint  nfs_filestat(struct vnode *vp, struct filestat *fsp);
150247822Sjfvint  devfs_filestat(struct vnode *vp, struct filestat *fsp);
151247822Sjfvchar *getmnton(struct mount *m);
152247822Sjfvvoid pipetrans(struct pipe *pi, int i, int flag);
153247822Sjfvvoid socktrans(struct socket *sock, int i);
154247822Sjfvvoid getinetproto(int number);
155247822Sjfvint  getfname(const char *filename);
156247822Sjfvvoid usage(void);
157247822Sjfv
158247822Sjfv
159247822Sjfvint
160247822Sjfvmain(int argc, char **argv)
161247822Sjfv{
162247822Sjfv	struct passwd *passwd;
163247822Sjfv	int arg, ch, what;
164247822Sjfv
165247822Sjfv	arg = 0;
166247822Sjfv	what = KERN_PROC_ALL;
167247822Sjfv	nlistf = memf = NULL;
168247822Sjfv	while ((ch = getopt(argc, argv, "fmnp:u:vN:M:")) != -1)
169247822Sjfv		switch((char)ch) {
170247822Sjfv		case 'f':
171280182Sjfv			fsflg = 1;
172247822Sjfv			break;
173247822Sjfv		case 'M':
174247822Sjfv			memf = optarg;
175247822Sjfv			break;
176247822Sjfv		case 'N':
177247822Sjfv			nlistf = optarg;
178247822Sjfv			break;
179280182Sjfv		case 'm':
180247822Sjfv			mflg = 1;
181247822Sjfv			break;
182282289Serj		case 'n':
183247822Sjfv			nflg = 1;
184280182Sjfv			break;
185292674Ssbruno		case 'p':
186280182Sjfv			if (pflg++)
187282289Serj				usage();
188280182Sjfv			if (!isdigit(*optarg)) {
189280182Sjfv				warnx("-p requires a process id");
190280182Sjfv				usage();
191280182Sjfv			}
192280182Sjfv			what = KERN_PROC_PID;
193280182Sjfv			arg = atoi(optarg);
194320897Serj			break;
195280182Sjfv		case 'u':
196282289Serj			if (uflg++)
197280182Sjfv				usage();
198320897Serj			if (!(passwd = getpwnam(optarg)))
199320897Serj				errx(1, "%s: unknown uid", optarg);
200320897Serj			what = KERN_PROC_UID;
201320897Serj			arg = passwd->pw_uid;
202320897Serj			break;
203320897Serj		case 'v':
204320897Serj			vflg = 1;
205320897Serj			break;
206320897Serj		case '?':
207320897Serj		default:
208320897Serj			usage();
209320897Serj		}
210320897Serj
211280182Sjfv	if (*(argv += optind)) {
212247822Sjfv		for (; *argv; ++argv) {
213172043Sjfv			if (getfname(*argv))
214251964Sjfv				checkfile = 1;
215251964Sjfv		}
216251964Sjfv		if (!checkfile)	/* file(s) specified, but none accessable */
217247822Sjfv			exit(1);
218171384Sjfv	}
219171384Sjfv
220179055Sjfv	if (fsflg && !checkfile) {
221230775Sjfv		/* -f with no files means use wd */
222172043Sjfv		if (getfname(".") == 0)
223171384Sjfv			exit(1);
224171384Sjfv		checkfile = 1;
225171384Sjfv	}
226171384Sjfv
227171384Sjfv	if (memf != NULL)
228171384Sjfv		fstat_kvm(what, arg);
229171384Sjfv	else
230171384Sjfv		fstat_sysctl(what, arg);
231171384Sjfv	exit(0);
232171384Sjfv}
233179055Sjfv
234230775Sjfvstatic void
235171384Sjfvprint_header(void)
236171384Sjfv{
237171384Sjfv
238171384Sjfv	if (nflg)
239171384Sjfv		printf("%s",
240171384Sjfv"USER     CMD          PID   FD  DEV    INUM       MODE SZ|DV R/W");
241171384Sjfv	else
242171384Sjfv		printf("%s",
243171384Sjfv"USER     CMD          PID   FD MOUNT      INUM MODE         SZ|DV R/W");
244171384Sjfv	if (checkfile && fsflg == 0)
245171384Sjfv		printf(" NAME\n");
246179055Sjfv	else
247230775Sjfv		putchar('\n');
248171384Sjfv}
249171384Sjfv
250171384Sjfvstatic void
251179055Sjfvfstat_kvm(int what, int arg)
252171384Sjfv{
253171384Sjfv	struct kinfo_proc *p, *plast;
254171384Sjfv	char buf[_POSIX2_LINE_MAX];
255171384Sjfv	int cnt;
256171384Sjfv
257171384Sjfv	ALLOC_OFILES(256);	/* reserve space for file pointers */
258171384Sjfv
259171384Sjfv	/*
260171384Sjfv	 * Discard setgid privileges if not the running kernel so that bad
261171384Sjfv	 * guys can't print interesting stuff from kernel memory.
262179055Sjfv	 */
263230775Sjfv	if (nlistf != NULL || memf != NULL)
264171384Sjfv		setgid(getgid());
265171384Sjfv
266171384Sjfv	if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == NULL)
267205720Sjfv		errx(1, "%s", buf);
268205720Sjfv	setgid(getgid());
269205720Sjfv#ifdef notdef
270205720Sjfv	if (kvm_nlist(kd, nl) != 0)
271205720Sjfv		errx(1, "no namelist: %s", kvm_geterr(kd));
272205720Sjfv#endif
273205720Sjfv	if ((p = kvm_getprocs(kd, what, arg, &cnt)) == NULL)
274205720Sjfv		errx(1, "%s", kvm_geterr(kd));
275205720Sjfv	print_header();
276205720Sjfv	for (plast = &p[cnt]; p < plast; ++p) {
277205720Sjfv		if (p->ki_stat == SZOMB)
278205720Sjfv			continue;
279205720Sjfv		dofiles(p);
280205720Sjfv		if (mflg)
281171384Sjfv			dommap(p);
282171384Sjfv	}
283171384Sjfv}
284171384Sjfv
285171384Sjfvstatic void
286171384Sjfvfstat_sysctl(int what, int arg)
287171384Sjfv{
288171384Sjfv
289179055Sjfv	/* not yet implemented */
290230775Sjfv	fstat_kvm(what, arg);
291171384Sjfv}
292171384Sjfv
293171384Sjfvconst char	*Uname, *Comm;
294171384Sjfvint	Pid;
295171384Sjfv
296171384Sjfv#define PREFIX(i) printf("%-8.8s %-10s %5d", Uname, Comm, Pid); \
297171384Sjfv	switch(i) { \
298171384Sjfv	case TEXT: \
299171384Sjfv		printf(" text"); \
300171384Sjfv		break; \
301179055Sjfv	case CDIR: \
302230775Sjfv		printf("   wd"); \
303171384Sjfv		break; \
304171384Sjfv	case RDIR: \
305171384Sjfv		printf(" root"); \
306171384Sjfv		break; \
307171384Sjfv	case TRACE: \
308171384Sjfv		printf("   tr"); \
309171384Sjfv		break; \
310171384Sjfv	case MMAP: \
311179055Sjfv		printf(" mmap"); \
312179055Sjfv		break; \
313179055Sjfv	case JDIR: \
314171384Sjfv		printf(" jail"); \
315171384Sjfv		break; \
316171384Sjfv	default: \
317179055Sjfv		printf(" %4d", i); \
318230775Sjfv		break; \
319171384Sjfv	}
320171384Sjfv
321171384Sjfv/*
322190873Sjfv * print open files attributed to this process
323190873Sjfv */
324190873Sjfvvoid
325190873Sjfvdofiles(struct kinfo_proc *kp)
326190873Sjfv{
327190873Sjfv	int i;
328190873Sjfv	struct file file;
329190873Sjfv	struct filedesc filed;
330190873Sjfv
331190873Sjfv	Uname = user_from_uid(kp->ki_uid, 0);
332230775Sjfv	Pid = kp->ki_pid;
333190873Sjfv	Comm = kp->ki_comm;
334190873Sjfv
335190873Sjfv	if (kp->ki_fd == NULL)
336190873Sjfv		return;
337190873Sjfv	if (!KVM_READ(kp->ki_fd, &filed, sizeof (filed))) {
338190873Sjfv		dprintf(stderr, "can't read filedesc at %p for pid %d\n",
339190873Sjfv		    (void *)kp->ki_fd, Pid);
340190873Sjfv		return;
341190873Sjfv	}
342190873Sjfv	/*
343190873Sjfv	 * root directory vnode, if one
344190873Sjfv	 */
345230775Sjfv	if (filed.fd_rdir)
346190873Sjfv		vtrans(filed.fd_rdir, RDIR, FREAD);
347190873Sjfv	/*
348190873Sjfv	 * current working directory vnode
349190873Sjfv	 */
350190873Sjfv	vtrans(filed.fd_cdir, CDIR, FREAD);
351190873Sjfv	/*
352190873Sjfv	 * jail root, if any.
353190873Sjfv	 */
354190873Sjfv	if (filed.fd_jdir)
355190873Sjfv		vtrans(filed.fd_jdir, JDIR, FREAD);
356190873Sjfv	/*
357190873Sjfv	 * ktrace vnode, if one
358230775Sjfv	 */
359190873Sjfv	if (kp->ki_tracep)
360190873Sjfv		vtrans(kp->ki_tracep, TRACE, FREAD|FWRITE);
361190873Sjfv	/*
362200239Sjfv	 * text vnode, if one
363200239Sjfv	 */
364200239Sjfv	if (kp->ki_textvp)
365200239Sjfv		vtrans(kp->ki_textvp, TEXT, FREAD);
366200239Sjfv	/*
367200239Sjfv	 * open files
368200239Sjfv	 */
369200239Sjfv#define FPSIZE	(sizeof (struct file *))
370200239Sjfv#define MAX_LASTFILE	(0x1000000)
371230775Sjfv
372200239Sjfv	/* Sanity check on filed.fd_lastfile */
373200239Sjfv	if (filed.fd_lastfile <= -1 || filed.fd_lastfile > MAX_LASTFILE)
374230775Sjfv		return;
375230775Sjfv
376200239Sjfv	ALLOC_OFILES(filed.fd_lastfile+1);
377200239Sjfv	if (!KVM_READ(filed.fd_ofiles, ofiles,
378200239Sjfv	    (filed.fd_lastfile+1) * FPSIZE)) {
379215911Sjfv		dprintf(stderr,
380215911Sjfv		    "can't read file structures at %p for pid %d\n",
381215911Sjfv		    (void *)filed.fd_ofiles, Pid);
382215911Sjfv		return;
383215911Sjfv	}
384215911Sjfv	for (i = 0; i <= filed.fd_lastfile; i++) {
385215911Sjfv		if (ofiles[i] == NULL)
386215911Sjfv			continue;
387215911Sjfv		if (!KVM_READ(ofiles[i], &file, sizeof (struct file))) {
388230775Sjfv			dprintf(stderr, "can't read file %d at %p for pid %d\n",
389230775Sjfv			    i, (void *)ofiles[i], Pid);
390215911Sjfv			continue;
391215911Sjfv		}
392215911Sjfv		if (file.f_type == DTYPE_VNODE)
393171384Sjfv			vtrans(file.f_vnode, i, file.f_flag);
394171384Sjfv		else if (file.f_type == DTYPE_SOCKET) {
395171384Sjfv			if (checkfile == 0)
396171384Sjfv				socktrans(file.f_data, i);
397171384Sjfv		}
398171384Sjfv#ifdef DTYPE_PIPE
399171384Sjfv		else if (file.f_type == DTYPE_PIPE) {
400179055Sjfv			if (checkfile == 0)
401230775Sjfv				pipetrans(file.f_data, i, file.f_flag);
402171384Sjfv		}
403171384Sjfv#endif
404171384Sjfv#ifdef DTYPE_FIFO
405179055Sjfv		else if (file.f_type == DTYPE_FIFO) {
406171384Sjfv			if (checkfile == 0)
407171384Sjfv				vtrans(file.f_vnode, i, file.f_flag);
408171384Sjfv		}
409171384Sjfv#endif
410171384Sjfv		else {
411171384Sjfv			dprintf(stderr,
412179055Sjfv			    "unknown file type %d for file %d of pid %d\n",
413171384Sjfv			    file.f_type, i, Pid);
414171384Sjfv		}
415171384Sjfv	}
416179055Sjfv}
417171384Sjfv
418171384Sjfvvoid
419171384Sjfvdommap(struct kinfo_proc *kp)
420171384Sjfv{
421171384Sjfv	vm_map_t map;
422171384Sjfv	struct vmspace vmspace;
423179055Sjfv	struct vm_map_entry entry;
424171384Sjfv	vm_map_entry_t entryp;
425171384Sjfv	struct vm_object object;
426171384Sjfv	vm_object_t objp;
427179055Sjfv	int prot, fflags;
428171384Sjfv
429171384Sjfv	if (!KVM_READ(kp->ki_vmspace, &vmspace, sizeof(vmspace))) {
430171384Sjfv		dprintf(stderr,
431171384Sjfv		    "can't read vmspace at %p for pid %d\n",
432171384Sjfv		    (void *)kp->ki_vmspace, Pid);
433171384Sjfv		return;
434171384Sjfv	}
435171384Sjfv	map = &vmspace.vm_map;
436171384Sjfv
437179055Sjfv	for (entryp = map->header.next;
438230775Sjfv	    entryp != &kp->ki_vmspace->vm_map.header; entryp = entry.next) {
439171384Sjfv		if (!KVM_READ(entryp, &entry, sizeof(entry))) {
440171384Sjfv			dprintf(stderr,
441171384Sjfv			    "can't read vm_map_entry at %p for pid %d\n",
442215911Sjfv			    (void *)entryp, Pid);
443215911Sjfv			return;
444215911Sjfv		}
445215911Sjfv
446215911Sjfv		if (entry.eflags & MAP_ENTRY_IS_SUB_MAP)
447215911Sjfv			continue;
448215911Sjfv
449215911Sjfv		if ((objp = entry.object.vm_object) == NULL)
450215911Sjfv			continue;
451215911Sjfv
452215911Sjfv		for (; objp; objp = object.backing_object) {
453215911Sjfv			if (!KVM_READ(objp, &object, sizeof(object))) {
454215911Sjfv				dprintf(stderr,
455179055Sjfv				    "can't read vm_object at %p for pid %d\n",
456179055Sjfv				    (void *)objp, Pid);
457179055Sjfv				return;
458179055Sjfv			}
459179055Sjfv		}
460179055Sjfv
461179055Sjfv		prot = entry.protection;
462179055Sjfv		fflags = (prot & VM_PROT_READ ? FREAD : 0) |
463179055Sjfv		    (prot & VM_PROT_WRITE ? FWRITE : 0);
464179055Sjfv
465179055Sjfv		switch (object.type) {
466179055Sjfv		case OBJT_VNODE:
467171384Sjfv			vtrans((struct vnode *)object.handle, MMAP, fflags);
468171384Sjfv			break;
469171384Sjfv		default:
470171384Sjfv			break;
471171384Sjfv		}
472171384Sjfv	}
473171384Sjfv}
474171384Sjfv
475171384Sjfvvoid
476171384Sjfvvtrans(struct vnode *vp, int i, int flag)
477215911Sjfv{
478230775Sjfv	struct vnode vn;
479171384Sjfv	struct filestat fst;
480171384Sjfv	char rw[3], mode[15], tagstr[12], *tagptr;
481171384Sjfv	const char *badtype, *filename;
482171384Sjfv
483171384Sjfv	filename = badtype = NULL;
484171384Sjfv	if (!KVM_READ(vp, &vn, sizeof (struct vnode))) {
485171384Sjfv		dprintf(stderr, "can't read vnode at %p for pid %d\n",
486171384Sjfv		    (void *)vp, Pid);
487171384Sjfv		return;
488171384Sjfv	}
489171384Sjfv	if (!KVM_READ(&vp->v_tag, &tagptr, sizeof tagptr) ||
490171384Sjfv	    !KVM_READ(tagptr, tagstr, sizeof tagstr)) {
491171384Sjfv		dprintf(stderr, "can't read v_tag at %p for pid %d\n",
492171384Sjfv		    (void *)vp, Pid);
493185352Sjfv		return;
494185352Sjfv	}
495171384Sjfv	tagstr[sizeof(tagstr) - 1] = '\0';
496171384Sjfv	if (vn.v_type == VNON)
497171384Sjfv		badtype = "none";
498179055Sjfv	else if (vn.v_type == VBAD)
499230775Sjfv		badtype = "bad";
500171384Sjfv	else {
501171384Sjfv		if (!strcmp("ufs", tagstr)) {
502171384Sjfv			if (!ufs_filestat(&vn, &fst))
503171384Sjfv				badtype = "error";
504171384Sjfv		} else if (!strcmp("devfs", tagstr)) {
505179055Sjfv			if (!devfs_filestat(&vn, &fst))
506179055Sjfv				badtype = "error";
507179055Sjfv		} else if (!strcmp("nfs", tagstr)) {
508179055Sjfv			if (!nfs_filestat(&vn, &fst))
509179055Sjfv				badtype = "error";
510179055Sjfv		} else if (!strcmp("msdosfs", tagstr)) {
511179055Sjfv			if (!msdosfs_filestat(&vn, &fst))
512179055Sjfv				badtype = "error";
513179055Sjfv		} else if (!strcmp("isofs", tagstr)) {
514230775Sjfv			if (!isofs_filestat(&vn, &fst))
515230775Sjfv				badtype = "error";
516179055Sjfv		} else {
517179055Sjfv			static char unknown[32];
518179055Sjfv			snprintf(unknown, sizeof unknown, "?(%s)", tagstr);
519179055Sjfv			badtype = unknown;
520171384Sjfv		}
521171384Sjfv	}
522171384Sjfv	if (checkfile) {
523171384Sjfv		int fsmatch = 0;
524171384Sjfv		DEVS *d;
525171384Sjfv
526171384Sjfv		if (badtype)
527171384Sjfv			return;
528230775Sjfv		for (d = devs; d != NULL; d = d->next)
529171384Sjfv			if (d->fsid == fst.fsid) {
530190873Sjfv				fsmatch = 1;
531190873Sjfv				if (d->ino == fst.fileid) {
532190873Sjfv					filename = d->name;
533179055Sjfv					break;
534230775Sjfv				}
535171384Sjfv			}
536171384Sjfv		if (fsmatch == 0 || (filename == NULL && fsflg == 0))
537171384Sjfv			return;
538171384Sjfv	}
539171384Sjfv	PREFIX(i);
540171384Sjfv	if (badtype) {
541171384Sjfv		(void)printf(" -         -  %10s    -\n", badtype);
542171384Sjfv		return;
543171384Sjfv	}
544171384Sjfv	if (nflg)
545171384Sjfv		(void)printf(" %2d,%-2d", major(fst.fsid), minor(fst.fsid));
546230775Sjfv	else
547171384Sjfv		(void)printf(" %-8s", getmnton(vn.v_mount));
548190873Sjfv	if (nflg)
549190873Sjfv		(void)sprintf(mode, "%o", fst.mode);
550190873Sjfv	else
551179055Sjfv		strmode(fst.mode, mode);
552230775Sjfv	(void)printf(" %6ld %10s", fst.fileid, mode);
553179055Sjfv	switch (vn.v_type) {
554171384Sjfv	case VBLK:
555179055Sjfv	case VCHR: {
556179055Sjfv		char *name;
557179055Sjfv
558179055Sjfv		if (nflg || ((name = devname(fst.rdev, vn.v_type == VCHR ?
559179055Sjfv		    S_IFCHR : S_IFBLK)) == NULL))
560179055Sjfv			printf("  %2d,%-2d", major(fst.rdev), minor(fst.rdev));
561179055Sjfv		else
562179055Sjfv			printf(" %6s", name);
563179055Sjfv		break;
564230775Sjfv	}
565179055Sjfv	default:
566171384Sjfv		printf(" %6lu", fst.size);
567179055Sjfv	}
568280182Sjfv	rw[0] = '\0';
569280182Sjfv	if (flag & FREAD)
570280182Sjfv		strcat(rw, "r");
571280182Sjfv	if (flag & FWRITE)
572280182Sjfv		strcat(rw, "w");
573280182Sjfv	printf(" %2s", rw);
574280182Sjfv	if (filename && !fsflg)
575280182Sjfv		printf("  %s", filename);
576280182Sjfv	putchar('\n');
577280182Sjfv}
578280182Sjfv
579280182Sjfvint
580280182Sjfvufs_filestat(struct vnode *vp, struct filestat *fsp)
581280182Sjfv{
582179055Sjfv	struct inode inode;
583179055Sjfv
584179055Sjfv	if (!KVM_READ(VTOI(vp), &inode, sizeof (inode))) {
585179055Sjfv		dprintf(stderr, "can't read inode at %p for pid %d\n",
586179055Sjfv		    (void *)VTOI(vp), Pid);
587179055Sjfv		return 0;
588179055Sjfv	}
589230775Sjfv	/*
590179055Sjfv	 * The st_dev from stat(2) is a dev_t. These kernel structures
591179055Sjfv	 * contain cdev pointers. We need to convert to dev_t to make
592230775Sjfv	 * comparisons
593171384Sjfv	 */
594171384Sjfv	fsp->fsid = dev2udev(inode.i_dev);
595171384Sjfv	fsp->fileid = (long)inode.i_number;
596179055Sjfv	fsp->mode = (mode_t)inode.i_mode;
597179055Sjfv	fsp->size = (u_long)inode.i_size;
598179055Sjfv#if should_be_but_is_hard
599179055Sjfv	/* XXX - need to load i_ump and i_din[12] from kernel memory */
600179055Sjfv	if (inode.i_ump->um_fstype == UFS1)
601179055Sjfv		fsp->rdev = inode.i_din1->di_rdev;
602179055Sjfv	else
603230775Sjfv		fsp->rdev = inode.i_din2->di_rdev;
604179055Sjfv#else
605179055Sjfv	fsp->rdev = 0;
606247822Sjfv#endif
607230775Sjfv
608179055Sjfv	return 1;
609179055Sjfv}
610179055Sjfv
611280182Sjfvint
612280182Sjfvdevfs_filestat(struct vnode *vp, struct filestat *fsp)
613280182Sjfv{
614280182Sjfv	struct devfs_dirent devfs_dirent;
615280182Sjfv	struct mount mount;
616280182Sjfv	struct vnode vnode;
617280182Sjfv
618280182Sjfv	if (!KVM_READ(vp->v_data, &devfs_dirent, sizeof (devfs_dirent))) {
619280182Sjfv		dprintf(stderr, "can't read devfs_dirent at %p for pid %d\n",
620280182Sjfv		    (void *)vp->v_data, Pid);
621280182Sjfv		return 0;
622171384Sjfv	}
623171384Sjfv	if (!KVM_READ(vp->v_mount, &mount, sizeof (mount))) {
624171384Sjfv		dprintf(stderr, "can't read mount at %p for pid %d\n",
625171384Sjfv		    (void *)vp->v_mount, Pid);
626171384Sjfv		return 0;
627171384Sjfv	}
628230775Sjfv	if (!KVM_READ(devfs_dirent.de_vnode, &vnode, sizeof (vnode))) {
629171384Sjfv		dprintf(stderr, "can't read vnode at %p for pid %d\n",
630179055Sjfv		    (void *)devfs_dirent.de_vnode, Pid);
631230775Sjfv		return 0;
632230775Sjfv	}
633171384Sjfv	fsp->fsid = (long)mount.mnt_stat.f_fsid.val[0];
634171384Sjfv	fsp->fileid = devfs_dirent.de_inode;
635171384Sjfv	fsp->mode = (devfs_dirent.de_mode & ~S_IFMT) | S_IFCHR;
636215911Sjfv	fsp->size = 0;
637215911Sjfv	fsp->rdev = dev2udev(vnode.v_rdev);
638215911Sjfv
639215911Sjfv	return 1;
640215911Sjfv}
641215911Sjfv
642215911Sjfvint
643215911Sjfvnfs_filestat(struct vnode *vp, struct filestat *fsp)
644215911Sjfv{
645215911Sjfv	struct nfsnode nfsnode;
646215911Sjfv	mode_t mode;
647215911Sjfv
648215911Sjfv	if (!KVM_READ(VTONFS(vp), &nfsnode, sizeof (nfsnode))) {
649215911Sjfv		dprintf(stderr, "can't read nfsnode at %p for pid %d\n",
650215911Sjfv		    (void *)VTONFS(vp), Pid);
651215911Sjfv		return 0;
652215911Sjfv	}
653215911Sjfv	fsp->fsid = nfsnode.n_vattr.va_fsid;
654215911Sjfv	fsp->fileid = nfsnode.n_vattr.va_fileid;
655215911Sjfv	fsp->size = nfsnode.n_size;
656215911Sjfv	fsp->rdev = nfsnode.n_vattr.va_rdev;
657215911Sjfv	mode = (mode_t)nfsnode.n_vattr.va_mode;
658215911Sjfv	switch (vp->v_type) {
659215911Sjfv	case VREG:
660215911Sjfv		mode |= S_IFREG;
661215911Sjfv		break;
662215911Sjfv	case VDIR:
663215911Sjfv		mode |= S_IFDIR;
664215911Sjfv		break;
665215911Sjfv	case VBLK:
666215911Sjfv		mode |= S_IFBLK;
667215911Sjfv		break;
668215911Sjfv	case VCHR:
669215911Sjfv		mode |= S_IFCHR;
670215911Sjfv		break;
671215911Sjfv	case VLNK:
672215911Sjfv		mode |= S_IFLNK;
673215911Sjfv		break;
674200239Sjfv	case VSOCK:
675171384Sjfv		mode |= S_IFSOCK;
676171384Sjfv		break;
677171384Sjfv	case VFIFO:
678200239Sjfv		mode |= S_IFIFO;
679200239Sjfv		break;
680171384Sjfv	case VNON:
681200239Sjfv	case VBAD:
682230775Sjfv		return 0;
683171384Sjfv	};
684200239Sjfv	fsp->mode = mode;
685247822Sjfv
686230775Sjfv	return 1;
687171384Sjfv}
688171384Sjfv
689171384Sjfv
690280182Sjfvchar *
691280182Sjfvgetmnton(struct mount *m)
692280182Sjfv{
693280182Sjfv	static struct mount mount;
694280182Sjfv	static struct mtab {
695280182Sjfv		struct mtab *next;
696280182Sjfv		struct mount *m;
697280182Sjfv		char mntonname[MNAMELEN];
698280182Sjfv	} *mhead = NULL;
699280182Sjfv	struct mtab *mt;
700280182Sjfv
701280182Sjfv	for (mt = mhead; mt != NULL; mt = mt->next)
702280182Sjfv		if (m == mt->m)
703280182Sjfv			return (mt->mntonname);
704280182Sjfv	if (!KVM_READ(m, &mount, sizeof(struct mount))) {
705280182Sjfv		warnx("can't read mount table at %p", (void *)m);
706179055Sjfv		return (NULL);
707171384Sjfv	}
708171384Sjfv	if ((mt = malloc(sizeof (struct mtab))) == NULL)
709179055Sjfv		err(1, NULL);
710171384Sjfv	mt->m = m;
711179055Sjfv	bcopy(&mount.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN);
712230775Sjfv	mt->next = mhead;
713171384Sjfv	mhead = mt;
714179055Sjfv	return (mt->mntonname);
715230775Sjfv}
716171384Sjfv
717171384Sjfvvoid
718171384Sjfvpipetrans(struct pipe *pi, int i, int flag)
719179055Sjfv{
720171384Sjfv	struct pipe pip;
721171384Sjfv	char rw[3];
722171384Sjfv
723171384Sjfv	PREFIX(i);
724171384Sjfv
725171384Sjfv	/* fill in socket */
726171384Sjfv	if (!KVM_READ(pi, &pip, sizeof(struct pipe))) {
727179055Sjfv		dprintf(stderr, "can't read pipe at %p\n", (void *)pi);
728230775Sjfv		goto bad;
729171384Sjfv	}
730171384Sjfv
731171384Sjfv	printf("* pipe %8lx <-> %8lx", (u_long)pi, (u_long)pip.pipe_peer);
732179055Sjfv	printf(" %6d", (int)pip.pipe_buffer.cnt);
733171384Sjfv	rw[0] = '\0';
734171384Sjfv	if (flag & FREAD)
735171384Sjfv		strcat(rw, "r");
736171384Sjfv	if (flag & FWRITE)
737171384Sjfv		strcat(rw, "w");
738171384Sjfv	printf(" %2s", rw);
739171384Sjfv	putchar('\n');
740179055Sjfv	return;
741230775Sjfv
742171384Sjfvbad:
743171384Sjfv	printf("* error\n");
744171384Sjfv}
745179055Sjfv
746171384Sjfvvoid
747171384Sjfvsocktrans(struct socket *sock, int i)
748171384Sjfv{
749171384Sjfv	static const char *stypename[] = {
750171384Sjfv		"unused",	/* 0 */
751171384Sjfv		"stream", 	/* 1 */
752171384Sjfv		"dgram",	/* 2 */
753179055Sjfv		"raw",		/* 3 */
754230775Sjfv		"rdm",		/* 4 */
755171384Sjfv		"seqpak"	/* 5 */
756171384Sjfv	};
757171384Sjfv#define	STYPEMAX 5
758179055Sjfv	struct socket	so;
759171384Sjfv	struct protosw	proto;
760171384Sjfv	struct domain	dom;
761171384Sjfv	struct inpcb	inpcb;
762171384Sjfv	struct unpcb	unpcb;
763171384Sjfv	int len;
764171384Sjfv	char dname[32];
765179055Sjfv
766230775Sjfv	PREFIX(i);
767171384Sjfv
768171384Sjfv	/* fill in socket */
769171384Sjfv	if (!KVM_READ(sock, &so, sizeof(struct socket))) {
770179055Sjfv		dprintf(stderr, "can't read sock at %p\n", (void *)sock);
771171384Sjfv		goto bad;
772171384Sjfv	}
773171384Sjfv
774171384Sjfv	/* fill in protosw entry */
775171384Sjfv	if (!KVM_READ(so.so_proto, &proto, sizeof(struct protosw))) {
776171384Sjfv		dprintf(stderr, "can't read protosw at %p",
777171384Sjfv		    (void *)so.so_proto);
778179055Sjfv		goto bad;
779230775Sjfv	}
780171384Sjfv
781171384Sjfv	/* fill in domain */
782171384Sjfv	if (!KVM_READ(proto.pr_domain, &dom, sizeof(struct domain))) {
783171384Sjfv		dprintf(stderr, "can't read domain at %p\n",
784171384Sjfv		    (void *)proto.pr_domain);
785171384Sjfv		goto bad;
786171384Sjfv	}
787171384Sjfv
788171384Sjfv	if ((len = kvm_read(kd, (u_long)dom.dom_name, dname,
789171384Sjfv	    sizeof(dname) - 1)) < 0) {
790171384Sjfv		dprintf(stderr, "can't read domain name at %p\n",
791171384Sjfv		    (void *)dom.dom_name);
792171384Sjfv		dname[0] = '\0';
793171384Sjfv	}
794171384Sjfv	else
795179055Sjfv		dname[len] = '\0';
796230775Sjfv
797171384Sjfv	if ((u_short)so.so_type > STYPEMAX)
798171384Sjfv		printf("* %s ?%d", dname, so.so_type);
799171384Sjfv	else
800230775Sjfv		printf("* %s %s", dname, stypename[so.so_type]);
801230775Sjfv
802230775Sjfv	/*
803230775Sjfv	 * protocol specific formatting
804230775Sjfv	 *
805230775Sjfv	 * Try to find interesting things to print.  For tcp, the interesting
806230775Sjfv	 * thing is the address of the tcpcb, for udp and others, just the
807230775Sjfv	 * inpcb (socket pcb).  For unix domain, its the address of the socket
808230775Sjfv	 * pcb and the address of the connected pcb (if connected).  Otherwise
809230775Sjfv	 * just print the protocol number and address of the socket itself.
810230775Sjfv	 * The idea is not to duplicate netstat, but to make available enough
811230775Sjfv	 * information for further analysis.
812230775Sjfv	 */
813230775Sjfv	switch(dom.dom_family) {
814230775Sjfv	case AF_INET:
815230775Sjfv	case AF_INET6:
816230775Sjfv		getinetproto(proto.pr_protocol);
817230775Sjfv		if (proto.pr_protocol == IPPROTO_TCP ) {
818230775Sjfv			if (so.so_pcb) {
819171384Sjfv				if (kvm_read(kd, (u_long)so.so_pcb,
820171384Sjfv				    (char *)&inpcb, sizeof(struct inpcb))
821171384Sjfv				    != sizeof(struct inpcb)) {
822171384Sjfv					dprintf(stderr,
823171384Sjfv					    "can't read inpcb at %p\n",
824171384Sjfv					    (void *)so.so_pcb);
825171384Sjfv					goto bad;
826171384Sjfv				}
827171384Sjfv				printf(" %lx", (u_long)inpcb.inp_ppcb);
828179055Sjfv			}
829230775Sjfv		}
830171384Sjfv		else if (so.so_pcb)
831171384Sjfv			printf(" %lx", (u_long)so.so_pcb);
832171384Sjfv		break;
833230775Sjfv	case AF_UNIX:
834230775Sjfv		/* print address of pcb and connected pcb */
835230775Sjfv		if (so.so_pcb) {
836230775Sjfv			printf(" %lx", (u_long)so.so_pcb);
837230775Sjfv			if (kvm_read(kd, (u_long)so.so_pcb, (char *)&unpcb,
838230775Sjfv			    sizeof(struct unpcb)) != sizeof(struct unpcb)){
839230775Sjfv				dprintf(stderr, "can't read unpcb at %p\n",
840230775Sjfv				    (void *)so.so_pcb);
841230775Sjfv				goto bad;
842230775Sjfv			}
843230775Sjfv			if (unpcb.unp_conn) {
844230775Sjfv				char shoconn[4], *cp;
845230775Sjfv
846230775Sjfv				cp = shoconn;
847230775Sjfv				if (!(so.so_rcv.sb_state & SBS_CANTRCVMORE))
848230775Sjfv					*cp++ = '<';
849230775Sjfv				*cp++ = '-';
850171384Sjfv				if (!(so.so_snd.sb_state & SBS_CANTSENDMORE))
851171384Sjfv					*cp++ = '>';
852171384Sjfv				*cp = '\0';
853171384Sjfv				printf(" %s %lx", shoconn,
854171384Sjfv				    (u_long)unpcb.unp_conn);
855171384Sjfv			}
856171384Sjfv		}
857171384Sjfv		break;
858179055Sjfv	default:
859230775Sjfv		/* print protocol number and socket address */
860171384Sjfv		printf(" %d %lx", proto.pr_protocol, (u_long)sock);
861171384Sjfv	}
862171384Sjfv	printf("\n");
863171384Sjfv	return;
864171384Sjfvbad:
865171384Sjfv	printf("* error\n");
866171384Sjfv}
867171384Sjfv
868179055Sjfv
869230775Sjfv/*
870171384Sjfv * Read the cdev structure in the kernel in order to work out the
871171384Sjfv * associated dev_t
872171384Sjfv */
873190873Sjfvdev_t
874190873Sjfvdev2udev(struct cdev *dev)
875190873Sjfv{
876190873Sjfv	struct cdev si;
877190873Sjfv
878190873Sjfv	if (KVM_READ(dev, &si, sizeof si)) {
879299200Spfg		/* XXX: FIXME! */
880190873Sjfv		return 0;
881190873Sjfv	} else {
882190873Sjfv		dprintf(stderr, "can't convert cdev *%p to a dev_t\n", dev);
883190873Sjfv		return -1;
884230775Sjfv	}
885190873Sjfv}
886190873Sjfv
887190873Sjfv/*
888190873Sjfv * getinetproto --
889179055Sjfv *	print name of protocol number
890171384Sjfv */
891179055Sjfvvoid
892171384Sjfvgetinetproto(int number)
893179055Sjfv{
894171384Sjfv	static int isopen;
895171384Sjfv	struct protoent *pe;
896171384Sjfv
897171384Sjfv	if (!isopen)
898179055Sjfv		setprotoent(++isopen);
899230775Sjfv	if ((pe = getprotobynumber(number)) != NULL)
900171384Sjfv		printf(" %s", pe->p_name);
901179055Sjfv	else
902230775Sjfv		printf(" %d", number);
903171384Sjfv}
904171384Sjfv
905171384Sjfvint
906181003Sjfvgetfname(const char *filename)
907181003Sjfv{
908181003Sjfv	struct stat statbuf;
909181003Sjfv	DEVS *cur;
910181003Sjfv
911181003Sjfv	if (stat(filename, &statbuf)) {
912181003Sjfv		warn("%s", filename);
913181003Sjfv		return(0);
914181003Sjfv	}
915230775Sjfv	if ((cur = malloc(sizeof(DEVS))) == NULL)
916181003Sjfv		err(1, NULL);
917181003Sjfv	cur->next = devs;
918181003Sjfv	devs = cur;
919179055Sjfv
920179055Sjfv	cur->ino = statbuf.st_ino;
921179055Sjfv	cur->fsid = statbuf.st_dev;
922179055Sjfv	cur->name = filename;
923179055Sjfv	return(1);
924179055Sjfv}
925179055Sjfv
926179055Sjfvvoid
927230775Sjfvusage(void)
928238149Sjfv{
929179055Sjfv	(void)fprintf(stderr,
930179055Sjfv "usage: fstat [-fmnv] [-M core] [-N system] [-p pid] [-u user] [file ...]\n");
931179055Sjfv	exit(1);
932238149Sjfv}
933238149Sjfv