xref: /openbsd/lib/libkvm/kvm_file2.c (revision 6c2b9309)
1*6c2b9309Sbluhm /*	$OpenBSD: kvm_file2.c,v 1.58 2024/02/11 21:29:12 bluhm Exp $	*/
29dc8fca8Smillert 
39dc8fca8Smillert /*
4bf198cc6Smillert  * Copyright (c) 2009 Todd C. Miller <millert@openbsd.org>
59dc8fca8Smillert  *
69dc8fca8Smillert  * Permission to use, copy, modify, and distribute this software for any
79dc8fca8Smillert  * purpose with or without fee is hereby granted, provided that the above
89dc8fca8Smillert  * copyright notice and this permission notice appear in all copies.
99dc8fca8Smillert  *
109dc8fca8Smillert  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
119dc8fca8Smillert  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
129dc8fca8Smillert  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
139dc8fca8Smillert  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
149dc8fca8Smillert  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
159dc8fca8Smillert  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
169dc8fca8Smillert  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
179dc8fca8Smillert  */
189dc8fca8Smillert 
199dc8fca8Smillert /*-
209dc8fca8Smillert  * Copyright (c) 1989, 1992, 1993
219dc8fca8Smillert  *	The Regents of the University of California.  All rights reserved.
229dc8fca8Smillert  *
239dc8fca8Smillert  * Redistribution and use in source and binary forms, with or without
249dc8fca8Smillert  * modification, are permitted provided that the following conditions
259dc8fca8Smillert  * are met:
269dc8fca8Smillert  * 1. Redistributions of source code must retain the above copyright
279dc8fca8Smillert  *    notice, this list of conditions and the following disclaimer.
289dc8fca8Smillert  * 2. Redistributions in binary form must reproduce the above copyright
299dc8fca8Smillert  *    notice, this list of conditions and the following disclaimer in the
309dc8fca8Smillert  *    documentation and/or other materials provided with the distribution.
319dc8fca8Smillert  * 3. Neither the name of the University nor the names of its contributors
329dc8fca8Smillert  *    may be used to endorse or promote products derived from this software
339dc8fca8Smillert  *    without specific prior written permission.
349dc8fca8Smillert  *
359dc8fca8Smillert  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
369dc8fca8Smillert  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
379dc8fca8Smillert  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
389dc8fca8Smillert  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
399dc8fca8Smillert  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
409dc8fca8Smillert  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
419dc8fca8Smillert  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
429dc8fca8Smillert  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
439dc8fca8Smillert  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
449dc8fca8Smillert  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
459dc8fca8Smillert  * SUCH DAMAGE.
469dc8fca8Smillert  */
479dc8fca8Smillert 
489dc8fca8Smillert /*
499dc8fca8Smillert  * Extended file list interface for kvm.  pstat, fstat and netstat are
509dc8fca8Smillert  * users of this code, so we've factored it out into a separate module.
519dc8fca8Smillert  * Thus, we keep this grunge out of the other kvm applications (i.e.,
529dc8fca8Smillert  * most other applications are interested only in open/close/read/nlist).
539dc8fca8Smillert  */
549dc8fca8Smillert 
55c6fa9a04Smillert #define __need_process
56c6fa9a04Smillert 
570b082c0eSderaadt #include <sys/types.h>
580b082c0eSderaadt #include <sys/signal.h>
59c6fa9a04Smillert #include <sys/uio.h>
609dc8fca8Smillert #include <sys/ucred.h>
61c6fa9a04Smillert #include <sys/proc.h>
62c6fa9a04Smillert #define _KERNEL
639dc8fca8Smillert #include <sys/file.h>
649dc8fca8Smillert #include <sys/mount.h>
659dc8fca8Smillert #undef _KERNEL
669dc8fca8Smillert #include <sys/vnode.h>
679dc8fca8Smillert #include <sys/socket.h>
689dc8fca8Smillert #include <sys/socketvar.h>
699dc8fca8Smillert #include <sys/domain.h>
709dc8fca8Smillert #include <sys/protosw.h>
719dc8fca8Smillert #include <sys/event.h>
729dc8fca8Smillert #include <sys/eventvar.h>
73cef0bbe1Sguenther #include <sys/un.h>
749dc8fca8Smillert #include <sys/unpcb.h>
759dc8fca8Smillert #include <sys/filedesc.h>
76cef0bbe1Sguenther #include <sys/mbuf.h>
779dc8fca8Smillert #include <sys/pipe.h>
789dc8fca8Smillert #include <sys/stat.h>
799dc8fca8Smillert #include <sys/sysctl.h>
80544451c3Sderaadt #include <sys/specdev.h>
819dc8fca8Smillert 
829dc8fca8Smillert #define _KERNEL
839dc8fca8Smillert #include <ufs/ufs/quota.h>
849dc8fca8Smillert #include <ufs/ufs/inode.h>
859dc8fca8Smillert #undef _KERNEL
869dc8fca8Smillert 
879dc8fca8Smillert #include <nfs/nfsproto.h>
889dc8fca8Smillert #include <nfs/rpcv2.h>
899dc8fca8Smillert #include <nfs/nfs.h>
909dc8fca8Smillert #include <nfs/nfsnode.h>
919dc8fca8Smillert 
923814b7daSmillert #include <msdosfs/bpb.h>
933814b7daSmillert #include <msdosfs/denode.h>
943814b7daSmillert #include <msdosfs/msdosfsmount.h>
953814b7daSmillert 
969dc8fca8Smillert #include <net/route.h>
979dc8fca8Smillert #include <netinet/in.h>
989dc8fca8Smillert #include <netinet/ip.h>
999dc8fca8Smillert #include <netinet/in_pcb.h>
100991eda1fSclaudio #include <netinet/tcp.h>
101991eda1fSclaudio #include <netinet/tcp_timer.h>
102991eda1fSclaudio #include <netinet/tcp_var.h>
1039dc8fca8Smillert 
1049dc8fca8Smillert #ifdef INET6
1059dc8fca8Smillert #include <netinet/ip6.h>
1069dc8fca8Smillert #endif
1079dc8fca8Smillert 
1084b1f64dcSguenther #include <fcntl.h>
1099dc8fca8Smillert #include <nlist.h>
1109dc8fca8Smillert #include <kvm.h>
1119dc8fca8Smillert #include <db.h>
112cef0bbe1Sguenther #include <stddef.h>
113659225e1Schl #include <stdlib.h>
114659225e1Schl #include <string.h>
115659225e1Schl #include <unistd.h>
116aea60beeSderaadt #include <limits.h>
117a6b19e38Sdlg #include <errno.h>
1189dc8fca8Smillert 
1199dc8fca8Smillert #include "kvm_private.h"
12026de9129Sguenther #include "kvm_file.h"
1219dc8fca8Smillert 
122cef0bbe1Sguenther static struct kinfo_file *kvm_deadfile_byfile(kvm_t *, int, int,
1239dc8fca8Smillert     size_t, int *);
124cef0bbe1Sguenther static struct kinfo_file *kvm_deadfile_byid(kvm_t *, int, int,
1259dc8fca8Smillert     size_t, int *);
126cef0bbe1Sguenther static int fill_file(kvm_t *, struct kinfo_file *, struct file *, u_long,
127644b4788Sguenther     struct vnode *, struct process *, int, pid_t);
128cef0bbe1Sguenther static int filestat(kvm_t *, struct kinfo_file *, struct vnode *);
1299dc8fca8Smillert 
130712e2ef1Sguenther LIST_HEAD(processlist, process);
131c6fa9a04Smillert 
132cef0bbe1Sguenther struct kinfo_file *
kvm_getfiles(kvm_t * kd,int op,int arg,size_t esize,int * cnt)133cef0bbe1Sguenther kvm_getfiles(kvm_t *kd, int op, int arg, size_t esize, int *cnt)
1349dc8fca8Smillert {
1359dc8fca8Smillert 	int mib[6], rv;
136a6b19e38Sdlg 	void *filebase;
1379dc8fca8Smillert 	size_t size;
1389dc8fca8Smillert 
1399dc8fca8Smillert 	if (ISALIVE(kd)) {
1409dc8fca8Smillert 		mib[0] = CTL_KERN;
141cef0bbe1Sguenther 		mib[1] = KERN_FILE;
1429dc8fca8Smillert 		mib[2] = op;
1439dc8fca8Smillert 		mib[3] = arg;
1449dc8fca8Smillert 		mib[4] = esize;
145a6b19e38Sdlg 
146a6b19e38Sdlg 		do {
1479dc8fca8Smillert 			mib[5] = 0;
1489dc8fca8Smillert 
1499dc8fca8Smillert 			/* find size and alloc buffer */
1509dc8fca8Smillert 			rv = sysctl(mib, 6, NULL, &size, NULL, 0);
1519dc8fca8Smillert 			if (rv == -1) {
1528493a6f2Szhuk 				if (errno != ESRCH && kd->vmfd != -1)
1539dc8fca8Smillert 					goto deadway;
154cef0bbe1Sguenther 				_kvm_syserr(kd, kd->program, "kvm_getfiles");
1559dc8fca8Smillert 				return (NULL);
1569dc8fca8Smillert 			}
157a6b19e38Sdlg 
158a6b19e38Sdlg 			size += size / 8; /* add ~10% */
159a6b19e38Sdlg 
160a6b19e38Sdlg 			filebase = _kvm_realloc(kd, kd->filebase, size);
161a6b19e38Sdlg 			if (filebase == NULL)
1629dc8fca8Smillert 				return (NULL);
1639dc8fca8Smillert 
164a6b19e38Sdlg 			kd->filebase = filebase;
165a6b19e38Sdlg 
1669dc8fca8Smillert 			/* get actual data */
1679dc8fca8Smillert 			mib[5] = size / esize;
1689dc8fca8Smillert 			rv = sysctl(mib, 6, kd->filebase, &size, NULL, 0);
169a6b19e38Sdlg 			if (rv == -1 && errno != ENOMEM) {
170a6b19e38Sdlg 				_kvm_syserr(kd, kd->program,
171a6b19e38Sdlg 				    "kvm_getfiles");
1729dc8fca8Smillert 				return (NULL);
1739dc8fca8Smillert 			}
174a6b19e38Sdlg 		} while (rv == -1);
175a6b19e38Sdlg 
1769dc8fca8Smillert 		*cnt = size / esize;
177ce4c48cfSguenther 		return (kd->filebase);
1789dc8fca8Smillert 	} else {
179cef0bbe1Sguenther 		if (esize > sizeof(struct kinfo_file)) {
180d8035eb3Sguenther 			_kvm_syserr(kd, kd->program,
181cef0bbe1Sguenther 			    "kvm_getfiles: unknown fields requested: libkvm out of date?");
182d8035eb3Sguenther 			return (NULL);
183d8035eb3Sguenther 		}
1849dc8fca8Smillert 	    deadway:
1859dc8fca8Smillert 		switch (op) {
1869dc8fca8Smillert 		case KERN_FILE_BYFILE:
187cef0bbe1Sguenther 			return (kvm_deadfile_byfile(kd, op, arg, esize, cnt));
1889dc8fca8Smillert 			break;
1899dc8fca8Smillert 		case KERN_FILE_BYPID:
1909dc8fca8Smillert 		case KERN_FILE_BYUID:
191cef0bbe1Sguenther 			return (kvm_deadfile_byid(kd, op, arg, esize, cnt));
1929dc8fca8Smillert 			break;
1939dc8fca8Smillert 		default:
1949dc8fca8Smillert 			return (NULL);
1959dc8fca8Smillert 		}
1969dc8fca8Smillert 	}
1979dc8fca8Smillert }
1989dc8fca8Smillert 
199cef0bbe1Sguenther static struct kinfo_file *
kvm_deadfile_byfile(kvm_t * kd,int op,int arg,size_t esize,int * cnt)200cef0bbe1Sguenther kvm_deadfile_byfile(kvm_t *kd, int op, int arg, size_t esize, int *cnt)
2019dc8fca8Smillert {
2029dc8fca8Smillert 	struct nlist nl[3], *p;
2031be4f2c3Sguenther 	size_t buflen;
2041be4f2c3Sguenther 	int n = 0;
2051be4f2c3Sguenther 	char *where;
206cef0bbe1Sguenther 	struct kinfo_file kf;
2079dc8fca8Smillert 	struct file *fp, file;
2089dc8fca8Smillert 	struct filelist filehead;
2099dc8fca8Smillert 	int nfiles;
2109dc8fca8Smillert 
2119dc8fca8Smillert 	nl[0].n_name = "_filehead";
212d9ca134eSyasuoka 	nl[1].n_name = "_numfiles";
2139dc8fca8Smillert 	nl[2].n_name = 0;
2149dc8fca8Smillert 
2159dc8fca8Smillert 	if (kvm_nlist(kd, nl) != 0) {
2169dc8fca8Smillert 		for (p = nl; p->n_type != 0; ++p)
2179dc8fca8Smillert 			;
2189dc8fca8Smillert 		_kvm_err(kd, kd->program,
2199dc8fca8Smillert 			 "%s: no such symbol", p->n_name);
2209dc8fca8Smillert 		return (NULL);
2219dc8fca8Smillert 	}
2229dc8fca8Smillert 	if (KREAD(kd, nl[0].n_value, &filehead)) {
2239dc8fca8Smillert 		_kvm_err(kd, kd->program, "can't read filehead");
2249dc8fca8Smillert 		return (NULL);
2259dc8fca8Smillert 	}
2269dc8fca8Smillert 	if (KREAD(kd, nl[1].n_value, &nfiles)) {
2279dc8fca8Smillert 		_kvm_err(kd, kd->program, "can't read nfiles");
2289dc8fca8Smillert 		return (NULL);
2299dc8fca8Smillert 	}
230a6b19e38Sdlg 	where = _kvm_reallocarray(kd, kd->filebase, nfiles, esize);
231a6b19e38Sdlg 	if (where == NULL)
2329dc8fca8Smillert 		return (NULL);
233a6b19e38Sdlg 
234a6b19e38Sdlg 	kd->filebase = (void *)where;
235f4ccacb3Sderaadt 	buflen = nfiles * esize;
2369dc8fca8Smillert 
2371be4f2c3Sguenther 	for (fp = LIST_FIRST(&filehead);
2381be4f2c3Sguenther 	    fp != NULL && esize <= buflen;
2391be4f2c3Sguenther 	    fp = LIST_NEXT(&file, f_list)) {
2401be4f2c3Sguenther 		if (KREAD(kd, (u_long)fp, &file)) {
2419dc8fca8Smillert 			_kvm_err(kd, kd->program, "can't read kfp");
2429dc8fca8Smillert 			return (NULL);
2439dc8fca8Smillert 		}
2444aba674dSguenther 		if (file.f_count == 0)
2454aba674dSguenther 			continue;
2464d545055Sguenther 		if (arg != 0 && file.f_type != arg)
2474aba674dSguenther 			continue;
248cef0bbe1Sguenther 		if (fill_file(kd, &kf, &file, (u_long)fp, NULL, NULL, 0, 0)
2491be4f2c3Sguenther 		    == -1)
2509dc8fca8Smillert 			return (NULL);
2511be4f2c3Sguenther 		memcpy(where, &kf, esize);
2521be4f2c3Sguenther 		where += esize;
2531be4f2c3Sguenther 		buflen -= esize;
2541be4f2c3Sguenther 		n++;
2559dc8fca8Smillert 	}
2569dc8fca8Smillert 	if (n != nfiles) {
2579dc8fca8Smillert 		_kvm_err(kd, kd->program, "inconsistent nfiles");
2589dc8fca8Smillert 		return (NULL);
2599dc8fca8Smillert 	}
2609dc8fca8Smillert 	*cnt = n;
261ce4c48cfSguenther 	return (kd->filebase);
2629dc8fca8Smillert }
2639dc8fca8Smillert 
264cef0bbe1Sguenther static struct kinfo_file *
kvm_deadfile_byid(kvm_t * kd,int op,int arg,size_t esize,int * cnt)265cef0bbe1Sguenther kvm_deadfile_byid(kvm_t *kd, int op, int arg, size_t esize, int *cnt)
2669dc8fca8Smillert {
2671be4f2c3Sguenther 	size_t buflen;
268e916a790Sguenther 	struct nlist nl[4], *np;
2698493a6f2Szhuk 	int n = 0, matched = 0;
2701be4f2c3Sguenther 	char *where;
271cef0bbe1Sguenther 	struct kinfo_file kf;
2729dc8fca8Smillert 	struct file *fp, file;
2739dc8fca8Smillert 	struct filelist filehead;
2749dc8fca8Smillert 	struct filedesc0 filed0;
2759dc8fca8Smillert #define filed	filed0.fd_fd
276712e2ef1Sguenther 	struct processlist allprocess;
277712e2ef1Sguenther 	struct process *pr, process;
2789dc8fca8Smillert 	struct ucred ucred;
279e916a790Sguenther 	char *filebuf = NULL;
2801be4f2c3Sguenther 	int i, nfiles;
2819dc8fca8Smillert 
2829dc8fca8Smillert 	nl[0].n_name = "_filehead";
283d9ca134eSyasuoka 	nl[1].n_name = "_numfiles";
284712e2ef1Sguenther 	nl[2].n_name = "_allprocess";
2851be4f2c3Sguenther 	nl[3].n_name = 0;
2869dc8fca8Smillert 
2879dc8fca8Smillert 	if (kvm_nlist(kd, nl) != 0) {
2889dc8fca8Smillert 		for (np = nl; np->n_type != 0; ++np)
2899dc8fca8Smillert 			;
2909dc8fca8Smillert 		_kvm_err(kd, kd->program,
2919dc8fca8Smillert 			 "%s: no such symbol", np->n_name);
2929dc8fca8Smillert 		return (NULL);
2939dc8fca8Smillert 	}
2949dc8fca8Smillert 	if (KREAD(kd, nl[0].n_value, &filehead)) {
2959dc8fca8Smillert 		_kvm_err(kd, kd->program, "can't read filehead");
2969dc8fca8Smillert 		return (NULL);
2979dc8fca8Smillert 	}
2989dc8fca8Smillert 	if (KREAD(kd, nl[1].n_value, &nfiles)) {
2999dc8fca8Smillert 		_kvm_err(kd, kd->program, "can't read nfiles");
3009dc8fca8Smillert 		return (NULL);
3019dc8fca8Smillert 	}
302712e2ef1Sguenther 	if (KREAD(kd, nl[2].n_value, &allprocess)) {
303712e2ef1Sguenther 		_kvm_err(kd, kd->program, "can't read allprocess");
3049dc8fca8Smillert 		return (NULL);
3059dc8fca8Smillert 	}
3069dc8fca8Smillert 	/* this may be more room than we need but counting is expensive */
307a6b19e38Sdlg 	where = _kvm_reallocarray(kd, kd->filebase, nfiles + 10, esize);
308a6b19e38Sdlg 	if (where == NULL)
3099dc8fca8Smillert 		return (NULL);
310a6b19e38Sdlg 
311a6b19e38Sdlg 	kd->filebase = (void *)where;
312f4ccacb3Sderaadt 	buflen = (nfiles + 10) * esize;
3139dc8fca8Smillert 
3148493a6f2Szhuk 	if (op != KERN_FILE_BYPID || arg <= 0)
3158493a6f2Szhuk 		matched = 1;
3168493a6f2Szhuk 
317712e2ef1Sguenther 	for (pr = LIST_FIRST(&allprocess);
318712e2ef1Sguenther 	    pr != NULL;
319712e2ef1Sguenther 	    pr = LIST_NEXT(&process, ps_list)) {
320712e2ef1Sguenther 		if (KREAD(kd, (u_long)pr, &process)) {
321b3c702ccSguenther 			_kvm_err(kd, kd->program, "can't read process at %lx",
322712e2ef1Sguenther 			    (u_long)pr);
323e916a790Sguenther 			goto cleanup;
3249dc8fca8Smillert 		}
325712e2ef1Sguenther 
326644b4788Sguenther 		/* skip system, exiting, embryonic and undead processes */
327644b4788Sguenther 		if (process.ps_flags & (PS_SYSTEM | PS_EMBRYO | PS_EXITING))
328644b4788Sguenther 			continue;
329644b4788Sguenther 
3308493a6f2Szhuk 		if (op == KERN_FILE_BYPID) {
3318493a6f2Szhuk 			/* check if this is the pid we are looking for */
3323b7181b7Sguenther 			if (arg > 0 && process.ps_pid != (pid_t)arg)
333712e2ef1Sguenther 				continue;
3348493a6f2Szhuk 			matched = 1;
335a60854cdSguenther 		}
3369dc8fca8Smillert 
337d559b8cbSguenther 		if (KREAD(kd, (u_long)process.ps_ucred, &ucred)) {
338b3c702ccSguenther 			_kvm_err(kd, kd->program, "can't read ucred at %lx",
339d559b8cbSguenther 			    (u_long)process.ps_ucred);
340b3c702ccSguenther 			goto cleanup;
341b3c702ccSguenther 		}
342d559b8cbSguenther 		process.ps_ucred = &ucred;
3439dc8fca8Smillert 
344712e2ef1Sguenther 		if (op == KERN_FILE_BYUID && arg >= 0 &&
345644b4788Sguenther 		    process.ps_ucred->cr_uid != (uid_t)arg) {
346712e2ef1Sguenther 			/* not the uid we are looking for */
347712e2ef1Sguenther 			continue;
348712e2ef1Sguenther 		}
349712e2ef1Sguenther 
350644b4788Sguenther 		if (KREAD(kd, (u_long)process.ps_fd, &filed0)) {
351b3c702ccSguenther 			_kvm_err(kd, kd->program, "can't read filedesc at %lx",
352644b4788Sguenther 			    (u_long)process.ps_fd);
353e916a790Sguenther 			goto cleanup;
354e916a790Sguenther 		}
355644b4788Sguenther 		if ((char *)process.ps_fd + offsetof(struct filedesc0,fd_dfiles)
356e916a790Sguenther 		    == (char *)filed.fd_ofiles) {
357e916a790Sguenther 			filed.fd_ofiles = filed0.fd_dfiles;
358e916a790Sguenther 			filed.fd_ofileflags = filed0.fd_dfileflags;
359e916a790Sguenther 		} else {
360f4ccacb3Sderaadt 			size_t fsize;
361f4ccacb3Sderaadt 			char *tmp = reallocarray(filebuf,
362f4ccacb3Sderaadt 			    filed.fd_nfiles, OFILESIZE);
363e916a790Sguenther 
364f4ccacb3Sderaadt 			fsize = filed.fd_nfiles * OFILESIZE;
365e916a790Sguenther 			if (tmp == NULL) {
366e916a790Sguenther 				_kvm_syserr(kd, kd->program, "realloc ofiles");
367e916a790Sguenther 				goto cleanup;
368e916a790Sguenther 			}
369e916a790Sguenther 			filebuf = tmp;
370e916a790Sguenther 			if (kvm_read(kd, (u_long)filed.fd_ofiles, filebuf,
371e916a790Sguenther 			    fsize) != fsize) {
372e916a790Sguenther 				_kvm_err(kd, kd->program,
373e916a790Sguenther 				    "can't read fd_ofiles");
374e916a790Sguenther 				goto cleanup;
375e916a790Sguenther 			}
376e916a790Sguenther 			filed.fd_ofiles = (void *)filebuf;
377e916a790Sguenther 			filed.fd_ofileflags = filebuf +
378e916a790Sguenther 			    (filed.fd_nfiles * sizeof(struct file *));
3799dc8fca8Smillert 		}
380644b4788Sguenther 		process.ps_fd = &filed;
3819dc8fca8Smillert 
382a0a1a1a1Sguenther 		if (process.ps_textvp) {
3831be4f2c3Sguenther 			if (buflen < esize)
384d360b1b6Smillert 				goto done;
385a0a1a1a1Sguenther 			if (fill_file(kd, &kf, NULL, 0, process.ps_textvp,
3863b7181b7Sguenther 			    &process, KERN_FILE_TEXT, process.ps_pid) == -1)
387e916a790Sguenther 				goto cleanup;
3881be4f2c3Sguenther 			memcpy(where, &kf, esize);
3891be4f2c3Sguenther 			where += esize;
3901be4f2c3Sguenther 			buflen -= esize;
3911be4f2c3Sguenther 			n++;
392d360b1b6Smillert 		}
3939dc8fca8Smillert 		if (filed.fd_cdir) {
3941be4f2c3Sguenther 			if (buflen < esize)
3959dc8fca8Smillert 				goto done;
396644b4788Sguenther 			if (fill_file(kd, &kf, NULL, 0, filed.fd_cdir,
3973b7181b7Sguenther 			    &process, KERN_FILE_CDIR, process.ps_pid) == -1)
398e916a790Sguenther 				goto cleanup;
3991be4f2c3Sguenther 			memcpy(where, &kf, esize);
4001be4f2c3Sguenther 			where += esize;
4011be4f2c3Sguenther 			buflen -= esize;
4021be4f2c3Sguenther 			n++;
4039dc8fca8Smillert 		}
4049dc8fca8Smillert 		if (filed.fd_rdir) {
4051be4f2c3Sguenther 			if (buflen < esize)
4069dc8fca8Smillert 				goto done;
407644b4788Sguenther 			if (fill_file(kd, &kf, NULL, 0, filed.fd_rdir,
4083b7181b7Sguenther 			    &process, KERN_FILE_RDIR, process.ps_pid) == -1)
409e916a790Sguenther 				goto cleanup;
4101be4f2c3Sguenther 			memcpy(where, &kf, esize);
4111be4f2c3Sguenther 			where += esize;
4121be4f2c3Sguenther 			buflen -= esize;
4131be4f2c3Sguenther 			n++;
4149dc8fca8Smillert 		}
415c5b5e7dfSguenther 		if (process.ps_tracevp) {
4161be4f2c3Sguenther 			if (buflen < esize)
4179dc8fca8Smillert 				goto done;
418cef0bbe1Sguenther 			if (fill_file(kd, &kf, NULL, 0, process.ps_tracevp,
4193b7181b7Sguenther 			    &process, KERN_FILE_TRACE, process.ps_pid) == -1)
420e916a790Sguenther 				goto cleanup;
4211be4f2c3Sguenther 			memcpy(where, &kf, esize);
4221be4f2c3Sguenther 			where += esize;
4231be4f2c3Sguenther 			buflen -= esize;
4241be4f2c3Sguenther 			n++;
4259dc8fca8Smillert 		}
4269dc8fca8Smillert 
4279dc8fca8Smillert 		if (filed.fd_nfiles < 0 ||
4289dc8fca8Smillert 		    filed.fd_lastfile >= filed.fd_nfiles ||
4299dc8fca8Smillert 		    filed.fd_freefile > filed.fd_lastfile + 1) {
4309dc8fca8Smillert 			_kvm_err(kd, kd->program,
431b3c702ccSguenther 			    "filedesc corrupted at %lx for pid %d",
4323b7181b7Sguenther 			    (u_long)process.ps_fd, process.ps_pid);
433e916a790Sguenther 			goto cleanup;
4349dc8fca8Smillert 		}
4359dc8fca8Smillert 
4369dc8fca8Smillert 		for (i = 0; i < filed.fd_nfiles; i++) {
4371be4f2c3Sguenther 			if (buflen < esize)
4389dc8fca8Smillert 				goto done;
4399dc8fca8Smillert 			if ((fp = filed.fd_ofiles[i]) == NULL)
4409dc8fca8Smillert 				continue;
4419dc8fca8Smillert 			if (KREAD(kd, (u_long)fp, &file)) {
4429dc8fca8Smillert 				_kvm_err(kd, kd->program, "can't read file");
443e916a790Sguenther 				goto cleanup;
4449dc8fca8Smillert 			}
445cef0bbe1Sguenther 			if (fill_file(kd, &kf, &file, (u_long)fp, NULL,
4463b7181b7Sguenther 			    &process, i, process.ps_pid) == -1)
447e916a790Sguenther 				goto cleanup;
4481be4f2c3Sguenther 			memcpy(where, &kf, esize);
4491be4f2c3Sguenther 			where += esize;
4501be4f2c3Sguenther 			buflen -= esize;
4511be4f2c3Sguenther 			n++;
4529dc8fca8Smillert 		}
4539dc8fca8Smillert 	}
4548493a6f2Szhuk 	if (!matched) {
4558493a6f2Szhuk 		errno = ESRCH;
4568493a6f2Szhuk 		goto cleanup;
4578493a6f2Szhuk 	}
4589dc8fca8Smillert done:
4599dc8fca8Smillert 	*cnt = n;
460e916a790Sguenther 	free(filebuf);
461ce4c48cfSguenther 	return (kd->filebase);
462e916a790Sguenther cleanup:
463e916a790Sguenther 	free(filebuf);
464e916a790Sguenther 	return (NULL);
4659dc8fca8Smillert }
4669dc8fca8Smillert 
4679dc8fca8Smillert static int
fill_file(kvm_t * kd,struct kinfo_file * kf,struct file * fp,u_long fpaddr,struct vnode * vp,struct process * pr,int fd,pid_t pid)468644b4788Sguenther fill_file(kvm_t *kd, struct kinfo_file *kf, struct file *fp, u_long fpaddr,
469644b4788Sguenther     struct vnode *vp, struct process *pr, int fd, pid_t pid)
4709dc8fca8Smillert {
4719dc8fca8Smillert 	struct ucred f_cred;
4729dc8fca8Smillert 
4739dc8fca8Smillert 	memset(kf, 0, sizeof(*kf));
4749dc8fca8Smillert 
4759dc8fca8Smillert 	kf->fd_fd = fd;		/* might not really be an fd */
4769dc8fca8Smillert 
4779dc8fca8Smillert 	if (fp != NULL) {
4789dc8fca8Smillert 		/* Fill in f_cred */
4799dc8fca8Smillert 		if (KREAD(kd, (u_long)fp->f_cred, &f_cred)) {
4809dc8fca8Smillert 			_kvm_err(kd, kd->program, "can't read f_cred");
4819dc8fca8Smillert 			return (-1);
4829dc8fca8Smillert 		}
4839dc8fca8Smillert 
4841be4f2c3Sguenther 		kf->f_fileaddr = PTRTOINT64(fpaddr);
4859dc8fca8Smillert 		kf->f_flag = fp->f_flag;
4869dc8fca8Smillert 		kf->f_iflags = fp->f_iflags;
4879dc8fca8Smillert 		kf->f_type = fp->f_type;
4889dc8fca8Smillert 		kf->f_count = fp->f_count;
4899dc8fca8Smillert 		kf->f_ucred = PTRTOINT64(fp->f_cred);
4901be4f2c3Sguenther 		kf->f_uid = f_cred.cr_uid;
4911be4f2c3Sguenther 		kf->f_gid = f_cred.cr_gid;
4929dc8fca8Smillert 		kf->f_ops = PTRTOINT64(fp->f_ops);
4939dc8fca8Smillert 		kf->f_offset = fp->f_offset;
4949dc8fca8Smillert 		kf->f_data = PTRTOINT64(fp->f_data);
49550902bb7Sguenther 		kf->f_usecount = 0;
4969dc8fca8Smillert 
4979dc8fca8Smillert 		kf->f_rxfer = fp->f_rxfer;
4989dc8fca8Smillert 		kf->f_rwfer = fp->f_wxfer;
4999dc8fca8Smillert 		kf->f_seek = fp->f_seek;
5009dc8fca8Smillert 		kf->f_rbytes = fp->f_rbytes;
5015990d487Sguenther 		kf->f_wbytes = fp->f_wbytes;
5029dc8fca8Smillert 	} else if (vp != NULL) {
5039dc8fca8Smillert 		/* fake it */
5049dc8fca8Smillert 		kf->f_type = DTYPE_VNODE;
5059dc8fca8Smillert 		kf->f_flag = FREAD;
5069dc8fca8Smillert 		if (fd == KERN_FILE_TRACE)
5079dc8fca8Smillert 			kf->f_flag |= FWRITE;
5081be4f2c3Sguenther 		kf->f_data = PTRTOINT64(vp);
5099dc8fca8Smillert 	}
5109dc8fca8Smillert 
5119dc8fca8Smillert 	/* information about the object associated with this file */
5129dc8fca8Smillert 	switch (kf->f_type) {
5139dc8fca8Smillert 	case DTYPE_VNODE: {
5149dc8fca8Smillert 		struct vnode vbuf;
5159dc8fca8Smillert 
5169dc8fca8Smillert 		if (KREAD(kd, (u_long)(fp ? fp->f_data : vp), &vbuf)) {
5179dc8fca8Smillert 			_kvm_err(kd, kd->program, "can't read vnode");
5189dc8fca8Smillert 			return (-1);
5199dc8fca8Smillert 		}
5209dc8fca8Smillert 		vp = &vbuf;
5219dc8fca8Smillert 
5229dc8fca8Smillert 		kf->v_un = PTRTOINT64(vp->v_un.vu_socket);
5239dc8fca8Smillert 		kf->v_type = vp->v_type;
5249dc8fca8Smillert 		kf->v_tag = vp->v_tag;
5259dc8fca8Smillert 		kf->v_flag = vp->v_flag;
5269dc8fca8Smillert 		kf->v_data = PTRTOINT64(vp->v_data);
5279dc8fca8Smillert 		kf->v_mount = PTRTOINT64(vp->v_mount);
5281be4f2c3Sguenther 
5291be4f2c3Sguenther 		if (vp->v_mount != NULL) {
5301be4f2c3Sguenther 			struct mount mount;
5311be4f2c3Sguenther 
5321be4f2c3Sguenther 			if (KREAD(kd, (u_long)vp->v_mount, &mount)) {
5331be4f2c3Sguenther 				_kvm_err(kd, kd->program, "can't read v_mount");
5341be4f2c3Sguenther 				return (-1);
5351be4f2c3Sguenther 			}
5361be4f2c3Sguenther 
5371be4f2c3Sguenther 			strlcpy(kf->f_mntonname, mount.mnt_stat.f_mntonname,
5389dc8fca8Smillert 			    sizeof(kf->f_mntonname));
5391be4f2c3Sguenther 		}
5409dc8fca8Smillert 
5419dc8fca8Smillert 		/* Fill in va_fsid, va_fileid, va_mode, va_size, va_rdev */
5429dc8fca8Smillert 		filestat(kd, kf, vp);
5439dc8fca8Smillert 		break;
5449dc8fca8Smillert 	    }
5459dc8fca8Smillert 
5469dc8fca8Smillert 	case DTYPE_SOCKET: {
5479dc8fca8Smillert 		struct socket sock;
54868d360c0Sbluhm 		struct sosplice ssp;
5499dc8fca8Smillert 		struct protosw protosw;
5509dc8fca8Smillert 		struct domain domain;
5519dc8fca8Smillert 
5529dc8fca8Smillert 		if (KREAD(kd, (u_long)fp->f_data, &sock)) {
5539dc8fca8Smillert 			_kvm_err(kd, kd->program, "can't read socket");
5549dc8fca8Smillert 			return (-1);
5559dc8fca8Smillert 		}
5569dc8fca8Smillert 
5579dc8fca8Smillert 		kf->so_type = sock.so_type;
5589dc8fca8Smillert 		kf->so_state = sock.so_state;
5599dc8fca8Smillert 		kf->so_pcb = PTRTOINT64(sock.so_pcb);
5609dc8fca8Smillert 		if (KREAD(kd, (u_long)sock.so_proto, &protosw)) {
5619dc8fca8Smillert 			_kvm_err(kd, kd->program, "can't read protosw");
5629dc8fca8Smillert 			return (-1);
5639dc8fca8Smillert 		}
5649dc8fca8Smillert 		kf->so_protocol = protosw.pr_protocol;
5659dc8fca8Smillert 		if (KREAD(kd, (u_long)protosw.pr_domain, &domain)) {
5669dc8fca8Smillert 			_kvm_err(kd, kd->program, "can't read domain");
5679dc8fca8Smillert 			return (-1);
5689dc8fca8Smillert 		}
5699dc8fca8Smillert 		kf->so_family = domain.dom_family;
570cef0bbe1Sguenther 		kf->so_rcv_cc = sock.so_rcv.sb_cc;
571cef0bbe1Sguenther 		kf->so_snd_cc = sock.so_snd.sb_cc;
57268d360c0Sbluhm 		if (sock.so_sp) {
57368d360c0Sbluhm 			if (KREAD(kd, (u_long)sock.so_sp, &ssp)) {
57468d360c0Sbluhm 				_kvm_err(kd, kd->program, "can't read splice");
57568d360c0Sbluhm 				return (-1);
57668d360c0Sbluhm 			}
57768d360c0Sbluhm 			if (ssp.ssp_socket) {
57868d360c0Sbluhm 				kf->so_splice = PTRTOINT64(ssp.ssp_socket);
57968d360c0Sbluhm 				kf->so_splicelen = ssp.ssp_len;
58068d360c0Sbluhm 			} else if (ssp.ssp_soback) {
581a60854cdSguenther 				kf->so_splicelen = -1;
58268d360c0Sbluhm 			}
58368d360c0Sbluhm 		}
58499e53febSmillert 		if (!sock.so_pcb)
58599e53febSmillert 			break;
5869dc8fca8Smillert 		switch (kf->so_family) {
5879dc8fca8Smillert 		case AF_INET: {
5889dc8fca8Smillert 			struct inpcb inpcb;
5899dc8fca8Smillert 
5909dc8fca8Smillert 			if (KREAD(kd, (u_long)sock.so_pcb, &inpcb)) {
5919dc8fca8Smillert 				_kvm_err(kd, kd->program, "can't read inpcb");
5929dc8fca8Smillert 				return (-1);
5939dc8fca8Smillert 			}
5949dc8fca8Smillert 			kf->inp_ppcb = PTRTOINT64(inpcb.inp_ppcb);
5959dc8fca8Smillert 			kf->inp_lport = inpcb.inp_lport;
5969dc8fca8Smillert 			kf->inp_laddru[0] = inpcb.inp_laddr.s_addr;
5979dc8fca8Smillert 			kf->inp_fport = inpcb.inp_fport;
5989dc8fca8Smillert 			kf->inp_faddru[0] = inpcb.inp_faddr.s_addr;
599a60854cdSguenther 			kf->inp_rtableid = inpcb.inp_rtableid;
600991eda1fSclaudio 			if (sock.so_type == SOCK_RAW)
601991eda1fSclaudio 				kf->inp_proto = inpcb.inp_ip.ip_p;
602991eda1fSclaudio 			if (protosw.pr_protocol == IPPROTO_TCP) {
603991eda1fSclaudio 				struct tcpcb tcpcb;
604991eda1fSclaudio 				if (KREAD(kd, (u_long)inpcb.inp_ppcb, &tcpcb)) {
605991eda1fSclaudio 					_kvm_err(kd, kd->program,
606991eda1fSclaudio 					    "can't read tcpcb");
607991eda1fSclaudio 					return (-1);
608991eda1fSclaudio 				}
609991eda1fSclaudio 				kf->t_rcv_wnd = tcpcb.rcv_wnd;
610991eda1fSclaudio 				kf->t_snd_wnd = tcpcb.snd_wnd;
611991eda1fSclaudio 				kf->t_snd_cwnd = tcpcb.snd_cwnd;
612991eda1fSclaudio 				kf->t_state = tcpcb.t_state;
613991eda1fSclaudio 			}
6149dc8fca8Smillert 			break;
6159dc8fca8Smillert 		    }
6169dc8fca8Smillert 		case AF_INET6: {
6179dc8fca8Smillert 			struct inpcb inpcb;
6189dc8fca8Smillert #define s6_addr32 __u6_addr.__u6_addr32
6199dc8fca8Smillert 
6209dc8fca8Smillert 			if (KREAD(kd, (u_long)sock.so_pcb, &inpcb)) {
6219dc8fca8Smillert 				_kvm_err(kd, kd->program, "can't read inpcb");
6229dc8fca8Smillert 				return (-1);
6239dc8fca8Smillert 			}
6249dc8fca8Smillert 			kf->inp_ppcb = PTRTOINT64(inpcb.inp_ppcb);
6259dc8fca8Smillert 			kf->inp_lport = inpcb.inp_lport;
6269dc8fca8Smillert 			kf->inp_laddru[0] = inpcb.inp_laddr6.s6_addr32[0];
6279dc8fca8Smillert 			kf->inp_laddru[1] = inpcb.inp_laddr6.s6_addr32[1];
6289dc8fca8Smillert 			kf->inp_laddru[2] = inpcb.inp_laddr6.s6_addr32[2];
6299dc8fca8Smillert 			kf->inp_laddru[3] = inpcb.inp_laddr6.s6_addr32[3];
6309dc8fca8Smillert 			kf->inp_fport = inpcb.inp_fport;
6319dc8fca8Smillert 			kf->inp_faddru[0] = inpcb.inp_laddr6.s6_addr32[0];
6329dc8fca8Smillert 			kf->inp_faddru[1] = inpcb.inp_faddr6.s6_addr32[1];
6339dc8fca8Smillert 			kf->inp_faddru[2] = inpcb.inp_faddr6.s6_addr32[2];
6349dc8fca8Smillert 			kf->inp_faddru[3] = inpcb.inp_faddr6.s6_addr32[3];
635a60854cdSguenther 			kf->inp_rtableid = inpcb.inp_rtableid;
636991eda1fSclaudio 			if (sock.so_type == SOCK_RAW)
637991eda1fSclaudio 				kf->inp_proto = inpcb.inp_ipv6.ip6_nxt;
638991eda1fSclaudio 			if (protosw.pr_protocol == IPPROTO_TCP) {
639991eda1fSclaudio 				struct tcpcb tcpcb;
640991eda1fSclaudio 				if (KREAD(kd, (u_long)inpcb.inp_ppcb, &tcpcb)) {
641991eda1fSclaudio 					_kvm_err(kd, kd->program,
642991eda1fSclaudio 					    "can't read tcpcb");
643991eda1fSclaudio 					return (-1);
644991eda1fSclaudio 				}
645991eda1fSclaudio 				kf->t_rcv_wnd = tcpcb.rcv_wnd;
646991eda1fSclaudio 				kf->t_snd_wnd = tcpcb.snd_wnd;
647991eda1fSclaudio 				kf->t_snd_cwnd = tcpcb.snd_cwnd;
648991eda1fSclaudio 				kf->t_state = tcpcb.t_state;
649991eda1fSclaudio 			}
6509dc8fca8Smillert 			break;
6519dc8fca8Smillert 		    }
6529dc8fca8Smillert 		case AF_UNIX: {
6539dc8fca8Smillert 			struct unpcb unpcb;
6549dc8fca8Smillert 
6559dc8fca8Smillert 			if (KREAD(kd, (u_long)sock.so_pcb, &unpcb)) {
6569dc8fca8Smillert 				_kvm_err(kd, kd->program, "can't read unpcb");
6579dc8fca8Smillert 				return (-1);
6589dc8fca8Smillert 			}
659171fc181Sguenther 			kf->f_msgcount	= unpcb.unp_msgcount;
6609dc8fca8Smillert 			kf->unp_conn	= PTRTOINT64(unpcb.unp_conn);
661efbf5d25Sbluhm 			kf->unp_refs	= PTRTOINT64(
662efbf5d25Sbluhm 			    SLIST_FIRST(&unpcb.unp_refs));
663efbf5d25Sbluhm 			kf->unp_nextref	= PTRTOINT64(
664efbf5d25Sbluhm 			    SLIST_NEXT(&unpcb, unp_nextref));
665cef0bbe1Sguenther 			kf->v_un	= PTRTOINT64(unpcb.unp_vnode);
666cef0bbe1Sguenther 			if (unpcb.unp_addr != NULL) {
667cef0bbe1Sguenther 				struct mbuf mb;
668cef0bbe1Sguenther 				struct sockaddr_un un;
669cef0bbe1Sguenther 
670cef0bbe1Sguenther 				if (KREAD(kd, (u_long)unpcb.unp_addr, &mb)) {
671cef0bbe1Sguenther 					_kvm_err(kd, kd->program,
672cef0bbe1Sguenther 					    "can't read sockaddr_un mbuf");
673cef0bbe1Sguenther 					return (-1);
674cef0bbe1Sguenther 				}
675cef0bbe1Sguenther 				if (KREAD(kd, (u_long)mb.m_data, &un)) {
676cef0bbe1Sguenther 					_kvm_err(kd, kd->program,
677cef0bbe1Sguenther 					    "can't read sockaddr_un");
678cef0bbe1Sguenther 					return (-1);
679cef0bbe1Sguenther 				}
680cef0bbe1Sguenther 
681cef0bbe1Sguenther 				kf->unp_addr = PTRTOINT64(unpcb.unp_addr);
682cef0bbe1Sguenther 				memcpy(kf->unp_path, un.sun_path, un.sun_len
683cef0bbe1Sguenther 				    - offsetof(struct sockaddr_un,sun_path));
684cef0bbe1Sguenther 			}
685cef0bbe1Sguenther 
6869dc8fca8Smillert 			break;
6879dc8fca8Smillert 		    }
6889dc8fca8Smillert 		}
6899dc8fca8Smillert 		break;
6909dc8fca8Smillert 	    }
6919dc8fca8Smillert 
6929dc8fca8Smillert 	case DTYPE_PIPE: {
6939dc8fca8Smillert 		struct pipe pipe;
6949dc8fca8Smillert 
6959dc8fca8Smillert 		if (KREAD(kd, (u_long)fp->f_data, &pipe)) {
6969dc8fca8Smillert 			_kvm_err(kd, kd->program, "can't read pipe");
6979dc8fca8Smillert 			return (-1);
6989dc8fca8Smillert 		}
6999dc8fca8Smillert 		kf->pipe_peer = PTRTOINT64(pipe.pipe_peer);
7009dc8fca8Smillert 		kf->pipe_state = pipe.pipe_state;
7019dc8fca8Smillert 		break;
7029dc8fca8Smillert 	    }
7039dc8fca8Smillert 
7049dc8fca8Smillert 	case DTYPE_KQUEUE: {
7059dc8fca8Smillert 		struct kqueue kqi;
7069dc8fca8Smillert 
7079dc8fca8Smillert 		if (KREAD(kd, (u_long)fp->f_data, &kqi)) {
7089dc8fca8Smillert 			_kvm_err(kd, kd->program, "can't read kqi");
7099dc8fca8Smillert 			return (-1);
7109dc8fca8Smillert 		}
7119dc8fca8Smillert 		kf->kq_count = kqi.kq_count;
7129dc8fca8Smillert 		kf->kq_state = kqi.kq_state;
7139dc8fca8Smillert 		break;
7149dc8fca8Smillert 	    }
7159dc8fca8Smillert 	}
7169dc8fca8Smillert 
7179dc8fca8Smillert 	/* per-process information for KERN_FILE_BY[PU]ID */
718644b4788Sguenther 	if (pr != NULL) {
719a60854cdSguenther 		kf->p_pid = pid;
720644b4788Sguenther 		kf->p_uid = pr->ps_ucred->cr_uid;
721644b4788Sguenther 		kf->p_gid = pr->ps_ucred->cr_gid;
722644b4788Sguenther 		kf->p_tid = -1;
7238fda72b7Sguenther 		strlcpy(kf->p_comm, pr->ps_comm, sizeof(kf->p_comm));
724644b4788Sguenther 		if (pr->ps_fd != NULL)
725644b4788Sguenther 			kf->fd_ofileflags = pr->ps_fd->fd_ofileflags[fd];
7269dc8fca8Smillert 	}
7279dc8fca8Smillert 
7289dc8fca8Smillert 	return (0);
7299dc8fca8Smillert }
7309dc8fca8Smillert 
7319938c243Smillert mode_t
_kvm_getftype(enum vtype v_type)7329938c243Smillert _kvm_getftype(enum vtype v_type)
7333814b7daSmillert {
7343814b7daSmillert 	mode_t ftype = 0;
7353814b7daSmillert 
7363814b7daSmillert 	switch (v_type) {
7373814b7daSmillert 	case VREG:
7383814b7daSmillert 		ftype = S_IFREG;
7393814b7daSmillert 		break;
7403814b7daSmillert 	case VDIR:
7413814b7daSmillert 		ftype = S_IFDIR;
7423814b7daSmillert 		break;
7433814b7daSmillert 	case VBLK:
7443814b7daSmillert 		ftype = S_IFBLK;
7453814b7daSmillert 		break;
7463814b7daSmillert 	case VCHR:
7473814b7daSmillert 		ftype = S_IFCHR;
7483814b7daSmillert 		break;
7493814b7daSmillert 	case VLNK:
7503814b7daSmillert 		ftype = S_IFLNK;
7513814b7daSmillert 		break;
7523814b7daSmillert 	case VSOCK:
7533814b7daSmillert 		ftype = S_IFSOCK;
7543814b7daSmillert 		break;
7553814b7daSmillert 	case VFIFO:
7563814b7daSmillert 		ftype = S_IFIFO;
7573814b7daSmillert 		break;
7583814b7daSmillert 	case VNON:
7593814b7daSmillert 	case VBAD:
7603814b7daSmillert 		break;
7613814b7daSmillert 	}
7623814b7daSmillert 
7633814b7daSmillert 	return (ftype);
7643814b7daSmillert }
7653814b7daSmillert 
7669dc8fca8Smillert static int
ufs_filestat(kvm_t * kd,struct kinfo_file * kf,struct vnode * vp)767cef0bbe1Sguenther ufs_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
7689dc8fca8Smillert {
7699dc8fca8Smillert 	struct inode inode;
7709dc8fca8Smillert 	struct ufs1_dinode di1;
7719dc8fca8Smillert 
7729dc8fca8Smillert 	if (KREAD(kd, (u_long)VTOI(vp), &inode)) {
7739dc8fca8Smillert 		_kvm_err(kd, kd->program, "can't read inode at %p", VTOI(vp));
7749dc8fca8Smillert 		return (-1);
7759dc8fca8Smillert 	}
7769dc8fca8Smillert 
7779dc8fca8Smillert 	if (KREAD(kd, (u_long)inode.i_din1, &di1)) {
7789dc8fca8Smillert 		_kvm_err(kd, kd->program, "can't read dinode at %p",
7799dc8fca8Smillert 		    inode.i_din1);
7809dc8fca8Smillert 		return (-1);
7819dc8fca8Smillert 	}
7829dc8fca8Smillert 
7839dc8fca8Smillert 	inode.i_din1 = &di1;
7849dc8fca8Smillert 
7859dc8fca8Smillert 	kf->va_fsid = inode.i_dev & 0xffff;
7869dc8fca8Smillert 	kf->va_fileid = (long)inode.i_number;
7879dc8fca8Smillert 	kf->va_mode = inode.i_ffs1_mode;
7889dc8fca8Smillert 	kf->va_size = inode.i_ffs1_size;
7899dc8fca8Smillert 	kf->va_rdev = inode.i_ffs1_rdev;
7908cdd1cc4Sguenther 	kf->va_nlink = inode.i_ffs1_nlink;
7919dc8fca8Smillert 
7929dc8fca8Smillert 	return (0);
7939dc8fca8Smillert }
7949dc8fca8Smillert 
7959dc8fca8Smillert static int
ext2fs_filestat(kvm_t * kd,struct kinfo_file * kf,struct vnode * vp)796cef0bbe1Sguenther ext2fs_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
7979dc8fca8Smillert {
7989dc8fca8Smillert 	struct inode inode;
7999dc8fca8Smillert 	struct ext2fs_dinode e2di;
8009dc8fca8Smillert 
8019dc8fca8Smillert 	if (KREAD(kd, (u_long)VTOI(vp), &inode)) {
8029dc8fca8Smillert 		_kvm_err(kd, kd->program, "can't read inode at %p", VTOI(vp));
8039dc8fca8Smillert 		return (-1);
8049dc8fca8Smillert 	}
8059dc8fca8Smillert 
8069dc8fca8Smillert 	if (KREAD(kd, (u_long)inode.i_e2din, &e2di)) {
8079dc8fca8Smillert 		_kvm_err(kd, kd->program, "can't read dinode at %p",
8089dc8fca8Smillert 		    inode.i_e2din);
8099dc8fca8Smillert 		return (-1);
8109dc8fca8Smillert 	}
8119dc8fca8Smillert 
8129dc8fca8Smillert 	inode.i_e2din = &e2di;
8139dc8fca8Smillert 
8149dc8fca8Smillert 	kf->va_fsid = inode.i_dev & 0xffff;
8159dc8fca8Smillert 	kf->va_fileid = (long)inode.i_number;
8169dc8fca8Smillert 	kf->va_mode = inode.i_e2fs_mode;
8179dc8fca8Smillert 	kf->va_size = inode.i_e2fs_size;
8189dc8fca8Smillert 	kf->va_rdev = 0;	/* XXX */
8198cdd1cc4Sguenther 	kf->va_nlink = inode.i_e2fs_nlink;
8209dc8fca8Smillert 
8219dc8fca8Smillert 	return (0);
8229dc8fca8Smillert }
8239dc8fca8Smillert 
8249dc8fca8Smillert static int
msdos_filestat(kvm_t * kd,struct kinfo_file * kf,struct vnode * vp)825cef0bbe1Sguenther msdos_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
8269dc8fca8Smillert {
8273814b7daSmillert 	struct denode de;
8283814b7daSmillert 	struct msdosfsmount mp;
8299dc8fca8Smillert 
8303814b7daSmillert 	if (KREAD(kd, (u_long)VTODE(vp), &de)) {
8313814b7daSmillert 		_kvm_err(kd, kd->program, "can't read denode at %p", VTODE(vp));
8329dc8fca8Smillert 		return (-1);
8339dc8fca8Smillert 	}
8343814b7daSmillert 	if (KREAD(kd, (u_long)de.de_pmp, &mp)) {
8353814b7daSmillert 		_kvm_err(kd, kd->program, "can't read mount struct at %p",
8363814b7daSmillert 		    de.de_pmp);
8373814b7daSmillert 		return (-1);
8383814b7daSmillert 	}
8393814b7daSmillert 
8403814b7daSmillert 	kf->va_fsid = de.de_dev & 0xffff;
8413814b7daSmillert 	kf->va_fileid = 0; /* XXX see msdosfs_vptofh() for more info */
8429938c243Smillert 	kf->va_mode = (mp.pm_mask & 0777) | _kvm_getftype(vp->v_type);
8433814b7daSmillert 	kf->va_size = de.de_FileSize;
8443814b7daSmillert 	kf->va_rdev = 0;  /* msdosfs doesn't support device files */
8458cdd1cc4Sguenther 	kf->va_nlink = 1;
8469dc8fca8Smillert 
8479dc8fca8Smillert 	return (0);
8489dc8fca8Smillert }
8499dc8fca8Smillert 
8509dc8fca8Smillert static int
nfs_filestat(kvm_t * kd,struct kinfo_file * kf,struct vnode * vp)851cef0bbe1Sguenther nfs_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
8529dc8fca8Smillert {
8539dc8fca8Smillert 	struct nfsnode nfsnode;
8549dc8fca8Smillert 
8559dc8fca8Smillert 	if (KREAD(kd, (u_long)VTONFS(vp), &nfsnode)) {
8569dc8fca8Smillert 		_kvm_err(kd, kd->program, "can't read nfsnode at %p",
8579dc8fca8Smillert 		    VTONFS(vp));
8589dc8fca8Smillert 		return (-1);
8599dc8fca8Smillert 	}
8609dc8fca8Smillert 	kf->va_fsid = nfsnode.n_vattr.va_fsid;
8619dc8fca8Smillert 	kf->va_fileid = nfsnode.n_vattr.va_fileid;
8629dc8fca8Smillert 	kf->va_size = nfsnode.n_size;
8639dc8fca8Smillert 	kf->va_rdev = nfsnode.n_vattr.va_rdev;
8649938c243Smillert 	kf->va_mode = (mode_t)nfsnode.n_vattr.va_mode | _kvm_getftype(vp->v_type);
8658cdd1cc4Sguenther 	kf->va_nlink = nfsnode.n_vattr.va_nlink;
8669dc8fca8Smillert 
8679dc8fca8Smillert 	return (0);
8689dc8fca8Smillert }
8699dc8fca8Smillert 
8709dc8fca8Smillert static int
spec_filestat(kvm_t * kd,struct kinfo_file * kf,struct vnode * vp)871cef0bbe1Sguenther spec_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
8729dc8fca8Smillert {
8739dc8fca8Smillert 	struct specinfo		specinfo;
8749dc8fca8Smillert 	struct vnode		parent;
8759dc8fca8Smillert 
8769dc8fca8Smillert 	if (KREAD(kd, (u_long)vp->v_specinfo, &specinfo)) {
8779dc8fca8Smillert 		_kvm_err(kd, kd->program, "can't read specinfo at %p",
8789dc8fca8Smillert 		     vp->v_specinfo);
8799dc8fca8Smillert 		return (-1);
8809dc8fca8Smillert 	}
8819dc8fca8Smillert 
8829dc8fca8Smillert 	vp->v_specinfo = &specinfo;
8839dc8fca8Smillert 
8849dc8fca8Smillert 	if (KREAD(kd, (u_long)vp->v_specparent, &parent)) {
8859dc8fca8Smillert 		_kvm_err(kd, kd->program, "can't read parent vnode at %p",
8869dc8fca8Smillert 		     vp->v_specparent);
8879dc8fca8Smillert 		return (-1);
8889dc8fca8Smillert 	}
8899dc8fca8Smillert 
8909dc8fca8Smillert 	if (ufs_filestat(kd, kf, vp))
8919dc8fca8Smillert 		return (-1);
8929dc8fca8Smillert 
8939dc8fca8Smillert 	return (0);
8949dc8fca8Smillert }
8959dc8fca8Smillert 
8969dc8fca8Smillert static int
filestat(kvm_t * kd,struct kinfo_file * kf,struct vnode * vp)897cef0bbe1Sguenther filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
8989dc8fca8Smillert {
8999dc8fca8Smillert 	int ret = 0;
9009dc8fca8Smillert 
9019dc8fca8Smillert 	if (vp->v_type != VNON && vp->v_type != VBAD) {
9029dc8fca8Smillert 		switch (vp->v_tag) {
9039dc8fca8Smillert 		case VT_UFS:
9049dc8fca8Smillert 		case VT_MFS:
9059dc8fca8Smillert 			ret = ufs_filestat(kd, kf, vp);
9069dc8fca8Smillert 			break;
9079dc8fca8Smillert 		case VT_NFS:
9089dc8fca8Smillert 			ret = nfs_filestat(kd, kf, vp);
9099dc8fca8Smillert 			break;
9109dc8fca8Smillert 		case VT_EXT2FS:
9119dc8fca8Smillert 			ret = ext2fs_filestat(kd, kf, vp);
9129dc8fca8Smillert 			break;
9139dc8fca8Smillert 		case VT_ISOFS:
914de71b0ceSmillert 			ret = _kvm_stat_cd9660(kd, kf, vp);
9159dc8fca8Smillert 			break;
9169dc8fca8Smillert 		case VT_MSDOSFS:
9179dc8fca8Smillert 			ret = msdos_filestat(kd, kf, vp);
9189dc8fca8Smillert 			break;
919de71b0ceSmillert 		case VT_UDF:
920de71b0ceSmillert 			ret = _kvm_stat_udf(kd, kf, vp);
921de71b0ceSmillert 			break;
9229938c243Smillert 		case VT_NTFS:
9239938c243Smillert 			ret = _kvm_stat_ntfs(kd, kf, vp);
9249938c243Smillert 			break;
9259dc8fca8Smillert 		case VT_NON:
9269dc8fca8Smillert 			if (vp->v_flag & VCLONE)
9279dc8fca8Smillert 				ret = spec_filestat(kd, kf, vp);
9289dc8fca8Smillert 			break;
929c416fe4bSderaadt 		default:
930c416fe4bSderaadt 			ret = -1;
931c416fe4bSderaadt 			break;
9329dc8fca8Smillert 		}
9339dc8fca8Smillert 	}
9349dc8fca8Smillert 	return (ret);
9359dc8fca8Smillert }
936