xref: /openbsd-src/lib/libkvm/kvm_file2.c (revision cd1eb269cafb12c415be1749cd4a4b5422710415)
1 /*	$OpenBSD: kvm_file2.c,v 1.14 2010/01/10 03:37:50 guenther Exp $	*/
2 
3 /*
4  * Copyright (c) 2009 Todd C. Miller <Todd.Miller@courtesan.com>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*-
20  * Copyright (c) 1989, 1992, 1993
21  *	The Regents of the University of California.  All rights reserved.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the above copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  * 3. Neither the name of the University nor the names of its contributors
32  *    may be used to endorse or promote products derived from this software
33  *    without specific prior written permission.
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
36  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
39  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45  * SUCH DAMAGE.
46  */
47 
48 /*
49  * Extended file list interface for kvm.  pstat, fstat and netstat are
50  * users of this code, so we've factored it out into a separate module.
51  * Thus, we keep this grunge out of the other kvm applications (i.e.,
52  * most other applications are interested only in open/close/read/nlist).
53  */
54 
55 #define __need_process
56 
57 #include <sys/param.h>
58 #include <sys/uio.h>
59 #include <sys/ucred.h>
60 #include <sys/proc.h>
61 #define _KERNEL
62 #include <sys/file.h>
63 #include <sys/mount.h>
64 #include <dev/systrace.h>
65 #undef _KERNEL
66 #include <sys/vnode.h>
67 #include <sys/socket.h>
68 #include <sys/socketvar.h>
69 #include <sys/domain.h>
70 #include <sys/protosw.h>
71 #include <sys/event.h>
72 #include <sys/eventvar.h>
73 #include <sys/unpcb.h>
74 #include <sys/filedesc.h>
75 #include <sys/pipe.h>
76 #include <sys/stat.h>
77 #include <sys/sysctl.h>
78 
79 #define _KERNEL
80 #include <ufs/ufs/quota.h>
81 #include <ufs/ufs/inode.h>
82 #undef _KERNEL
83 
84 #include <nfs/nfsproto.h>
85 #include <nfs/rpcv2.h>
86 #include <nfs/nfs.h>
87 #include <nfs/nfsnode.h>
88 
89 #include <nnpfs/nnpfs_config.h>
90 #include <nnpfs/nnpfs_node.h>
91 
92 #include <msdosfs/bpb.h>
93 #define _KERNEL
94 #include <msdosfs/denode.h>
95 #undef _KERNEL
96 #include <msdosfs/msdosfsmount.h>
97 
98 #include <miscfs/specfs/specdev.h>
99 
100 #include <net/route.h>
101 #include <netinet/in.h>
102 #include <netinet/in_systm.h>
103 #include <netinet/ip.h>
104 #include <netinet/in_pcb.h>
105 
106 #ifdef INET6
107 #include <netinet/ip6.h>
108 #include <netinet6/ip6_var.h>
109 #endif
110 
111 #include <nlist.h>
112 #include <kvm.h>
113 #include <db.h>
114 #include <stdlib.h>
115 #include <string.h>
116 #include <unistd.h>
117 
118 #include "kvm_private.h"
119 
120 static struct kinfo_file2 *kvm_deadfile2_byfile(kvm_t *, int, int,
121     size_t, int *);
122 static struct kinfo_file2 *kvm_deadfile2_byid(kvm_t *, int, int,
123     size_t, int *);
124 static int fill_file2(kvm_t *, struct kinfo_file2 *, struct file *,
125     struct vnode *, struct proc *, int);
126 static int filestat(kvm_t *, struct kinfo_file2 *, struct vnode *);
127 
128 LIST_HEAD(proclist, proc);
129 
130 struct kinfo_file2 *
131 kvm_getfile2(kvm_t *kd, int op, int arg, size_t esize, int *cnt)
132 {
133 	int mib[6], rv;
134 	size_t size;
135 
136 	if (kd->filebase != NULL) {
137 		free(kd->filebase);
138 		/*
139 		 * Clear this pointer in case this call fails.  Otherwise,
140 		 * kvm_close() will free it again.
141 		 */
142 		kd->filebase = 0;
143 	}
144 
145 	if (ISALIVE(kd)) {
146 		mib[0] = CTL_KERN;
147 		mib[1] = KERN_FILE2;
148 		mib[2] = op;
149 		mib[3] = arg;
150 		mib[4] = esize;
151 		mib[5] = 0;
152 
153 		/* find size and alloc buffer */
154 		rv = sysctl(mib, 6, NULL, &size, NULL, 0);
155 		if (rv == -1) {
156 			if (kd->vmfd != -1)
157 				goto deadway;
158 			_kvm_syserr(kd, kd->program, "kvm_getfile2");
159 			return (NULL);
160 		}
161 		kd->filebase = _kvm_malloc(kd, size);
162 		if (kd->filebase == NULL)
163 			return (NULL);
164 
165 		/* get actual data */
166 		mib[5] = size / esize;
167 		rv = sysctl(mib, 6, kd->filebase, &size, NULL, 0);
168 		if (rv == -1) {
169 			_kvm_syserr(kd, kd->program, "kvm_getfile2");
170 			return (NULL);
171 		}
172 		*cnt = size / esize;
173 		return ((struct kinfo_file2 *)kd->filebase);
174 	} else {
175 	    deadway:
176 		switch (op) {
177 		case KERN_FILE_BYFILE:
178 			if (arg != 0) {
179 				_kvm_err(kd, kd->program,
180 				    "%s: invalid argument");
181 				return (NULL);
182 			}
183 			return (kvm_deadfile2_byfile(kd, op, arg, esize, cnt));
184 			break;
185 		case KERN_FILE_BYPID:
186 		case KERN_FILE_BYUID:
187 			return (kvm_deadfile2_byid(kd, op, arg, esize, cnt));
188 			break;
189 		default:
190 			return (NULL);
191 		}
192 	}
193 }
194 
195 static struct kinfo_file2 *
196 kvm_deadfile2_byfile(kvm_t *kd, int op, int arg, size_t esize, int *cnt)
197 {
198 	size_t size;
199 	struct nlist nl[3], *p;
200 	int buflen = kd->arglen, n = 0;
201 	char *where = kd->argspc;
202 	struct kinfo_file2 *kf = NULL;
203 	struct file *fp, file;
204 	struct filelist filehead;
205 	int nfiles;
206 
207 	nl[0].n_name = "_filehead";
208 	nl[1].n_name = "_nfiles";
209 	nl[2].n_name = 0;
210 
211 	if (kvm_nlist(kd, nl) != 0) {
212 		for (p = nl; p->n_type != 0; ++p)
213 			;
214 		_kvm_err(kd, kd->program,
215 			 "%s: no such symbol", p->n_name);
216 		return (NULL);
217 	}
218 	if (KREAD(kd, nl[0].n_value, &filehead)) {
219 		_kvm_err(kd, kd->program, "can't read filehead");
220 		return (NULL);
221 	}
222 	if (KREAD(kd, nl[1].n_value, &nfiles)) {
223 		_kvm_err(kd, kd->program, "can't read nfiles");
224 		return (NULL);
225 	}
226 	size = (nfiles + 10) * sizeof(struct kinfo_file2);
227 	kd->filebase = _kvm_malloc(kd, size);
228 	if (kd->filebase == NULL)
229 		return (NULL);
230 
231 	LIST_FOREACH(fp, &filehead, f_list) {
232 		if (buflen < sizeof(struct kinfo_file2))
233 			break;
234 
235 		if (KREAD(kd, (long)fp, &file)) {
236 			_kvm_err(kd, kd->program, "can't read kfp");
237 			return (NULL);
238 		}
239 		kf = (struct kinfo_file2 *)where;
240 		where += sizeof(struct kinfo_file2);
241 		buflen -= sizeof(struct kinfo_file2);
242 		n++;
243 		if (fill_file2(kd, kf, fp, NULL, NULL, 0) == -1)
244 			return (NULL);
245 	}
246 	if (n != nfiles) {
247 		_kvm_err(kd, kd->program, "inconsistent nfiles");
248 		return (NULL);
249 	}
250 	*cnt = n;
251 	return (kf);
252 }
253 
254 static struct kinfo_file2 *
255 kvm_deadfile2_byid(kvm_t *kd, int op, int arg, size_t esize, int *cnt)
256 {
257 	size_t size;
258 	struct nlist nl[5], *np;
259 	int buflen = kd->arglen, n = 0;
260 	char *where = kd->argspc;
261 	struct kinfo_file2 *kf = NULL;
262 	struct file *fp, file;
263 	struct filelist filehead;
264 	struct filedesc0 filed0;
265 #define filed	filed0.fd_fd
266 	struct proclist allproc;
267 	struct proc *p, proc;
268 	struct process process;
269 	struct pcred pcred;
270 	struct ucred ucred;
271 	int i, nfiles, nprocs;
272 
273 	nl[0].n_name = "_filehead";
274 	nl[1].n_name = "_nfiles";
275 	nl[2].n_name = "_nprocs";
276 	nl[3].n_name = "_allproc";
277 	nl[4].n_name = 0;
278 
279 	if (kvm_nlist(kd, nl) != 0) {
280 		for (np = nl; np->n_type != 0; ++np)
281 			;
282 		_kvm_err(kd, kd->program,
283 			 "%s: no such symbol", np->n_name);
284 		return (NULL);
285 	}
286 	if (KREAD(kd, nl[0].n_value, &filehead)) {
287 		_kvm_err(kd, kd->program, "can't read filehead");
288 		return (NULL);
289 	}
290 	if (KREAD(kd, nl[1].n_value, &nfiles)) {
291 		_kvm_err(kd, kd->program, "can't read nfiles");
292 		return (NULL);
293 	}
294 	if (KREAD(kd, nl[2].n_value, &nprocs)) {
295 		_kvm_err(kd, kd->program, "can't read nprocs");
296 		return (NULL);
297 	}
298 	if (KREAD(kd, nl[3].n_value, &allproc)) {
299 		_kvm_err(kd, kd->program, "can't read allproc");
300 		return (NULL);
301 	}
302 	/* this may be more room than we need but counting is expensive */
303 	size = (nfiles + 10) * sizeof(struct kinfo_file2);
304 	kd->filebase = _kvm_malloc(kd, size);
305 	if (kd->filebase == NULL)
306 		return (NULL);
307 
308 	LIST_FOREACH(p, &allproc, p_list) {
309 		if (buflen < sizeof(struct kinfo_file2))
310 			break;
311 
312 		if (KREAD(kd, (u_long)p, &proc)) {
313 			_kvm_err(kd, kd->program, "can't read proc at %x", p);
314 			return (NULL);
315 		}
316 
317 		/* skip system, embryonic and undead processes */
318 		if ((proc.p_flag & P_SYSTEM) ||
319 		    proc.p_stat == SIDL || proc.p_stat == SZOMB)
320 			continue;
321 		if (op == KERN_FILE_BYPID) {
322 			if (arg > 0 && proc.p_pid != (pid_t)arg) {
323 				/* not the pid we are looking for */
324 				continue;
325 			}
326 		} else /* if (op == KERN_FILE_BYUID) */ {
327 			if (arg > 0 && proc.p_ucred->cr_uid != (uid_t)arg) {
328 				/* not the uid we are looking for */
329 				continue;
330 			}
331 		}
332 
333 		if (proc.p_fd == NULL || proc.p_p == NULL)
334 			continue;
335 
336 		if (KREAD(kd, (u_long)proc.p_p, &process)) {
337 			_kvm_err(kd, kd->program, "can't read process at %x",
338 			    proc.p_p);
339 			return (NULL);
340 		}
341 		proc.p_p = &process;
342 
343 		if (KREAD(kd, (u_long)process.ps_cred, &pcred) == 0)
344 			KREAD(kd, (u_long)pcred.pc_ucred, &ucred);
345 		process.ps_cred = &pcred;
346 		pcred.pc_ucred = &ucred;
347 
348 		if (KREAD(kd, (u_long)proc.p_fd, &filed0)) {
349 			_kvm_err(kd, kd->program, "can't read filedesc at %x",
350 			    proc.p_fd);
351 			return (NULL);
352 		}
353 		proc.p_fd = &filed;
354 
355 		if (proc.p_textvp) {
356 			if (buflen < sizeof(struct kinfo_file2))
357 				goto done;
358 			kf = (struct kinfo_file2 *)where;
359 			where += sizeof(struct kinfo_file2);
360 			buflen -= sizeof(struct kinfo_file2);
361 			n++;
362 			if (fill_file2(kd, kf, NULL, proc.p_textvp, &proc,
363 			    KERN_FILE_TEXT) == -1)
364 				return (NULL);
365 		}
366 		if (filed.fd_cdir) {
367 			if (buflen < sizeof(struct kinfo_file2))
368 				goto done;
369 			kf = (struct kinfo_file2 *)where;
370 			where += sizeof(struct kinfo_file2);
371 			buflen -= sizeof(struct kinfo_file2);
372 			n++;
373 			if (fill_file2(kd, kf, NULL, filed.fd_cdir, &proc,
374 			    KERN_FILE_CDIR) == -1)
375 				return (NULL);
376 		}
377 		if (filed.fd_rdir) {
378 			if (buflen < sizeof(struct kinfo_file2))
379 				goto done;
380 			kf = (struct kinfo_file2 *)where;
381 			where += sizeof(struct kinfo_file2);
382 			buflen -= sizeof(struct kinfo_file2);
383 			n++;
384 			if (fill_file2(kd, kf, NULL, filed.fd_rdir, &proc,
385 			    KERN_FILE_RDIR) == -1)
386 				return (NULL);
387 		}
388 		if (proc.p_tracep) {
389 			if (buflen < sizeof(struct kinfo_file2))
390 				goto done;
391 			kf = (struct kinfo_file2 *)where;
392 			where += sizeof(struct kinfo_file2);
393 			buflen -= sizeof(struct kinfo_file2);
394 			n++;
395 			if (fill_file2(kd, kf, NULL, proc.p_tracep, &proc,
396 			    KERN_FILE_TRACE) == -1)
397 				return (NULL);
398 		}
399 
400 		if (filed.fd_nfiles < 0 ||
401 		    filed.fd_lastfile >= filed.fd_nfiles ||
402 		    filed.fd_freefile > filed.fd_lastfile + 1) {
403 			_kvm_err(kd, kd->program,
404 			    "filedesc corrupted at %x for pid %d",
405 			    proc.p_fd, proc.p_pid);
406 			return (NULL);
407 		}
408 
409 		for (i = 0; i < filed.fd_nfiles; i++) {
410 			if (buflen < sizeof(struct kinfo_file2))
411 				goto done;
412 			if ((fp = filed.fd_ofiles[i]) == NULL)
413 				continue;
414 			if (KREAD(kd, (u_long)fp, &file)) {
415 				_kvm_err(kd, kd->program, "can't read file");
416 				return (NULL);
417 			}
418 			kf = (struct kinfo_file2 *)where;
419 			where += sizeof(struct kinfo_file2);
420 			buflen -= sizeof(struct kinfo_file2);
421 			n++;
422 			if (fill_file2(kd, kf, &file, NULL, &proc, i) == -1)
423 				return (NULL);
424 		}
425 	}
426 done:
427 	*cnt = n;
428 	return (kf);
429 }
430 
431 static int
432 fill_file2(kvm_t *kd, struct kinfo_file2 *kf, struct file *fp, struct vnode *vp,
433     struct proc *p, int fd)
434 {
435 	struct ucred f_cred;
436 
437 	memset(kf, 0, sizeof(*kf));
438 
439 	kf->fd_fd = fd;		/* might not really be an fd */
440 
441 	if (fp != NULL) {
442 		/* Fill in f_cred */
443 		if (KREAD(kd, (u_long)fp->f_cred, &f_cred)) {
444 			_kvm_err(kd, kd->program, "can't read f_cred");
445 			return (-1);
446 		}
447 		fp->f_cred = &f_cred;
448 
449 		kf->f_fileaddr = PTRTOINT64(fp);
450 		kf->f_flag = fp->f_flag;
451 		kf->f_iflags = fp->f_iflags;
452 		kf->f_type = fp->f_type;
453 		kf->f_count = fp->f_count;
454 		kf->f_msgcount = fp->f_msgcount;
455 		kf->f_ucred = PTRTOINT64(fp->f_cred);
456 		kf->f_uid = fp->f_cred->cr_uid;
457 		kf->f_gid = fp->f_cred->cr_gid;
458 		kf->f_ops = PTRTOINT64(fp->f_ops);
459 		kf->f_offset = fp->f_offset;
460 		kf->f_data = PTRTOINT64(fp->f_data);
461 		kf->f_usecount = fp->f_usecount;
462 
463 		if (getuid() == 0 || p->p_ucred->cr_uid == fp->f_cred->cr_uid) {
464 			kf->f_rxfer = fp->f_rxfer;
465 			kf->f_rwfer = fp->f_wxfer;
466 			kf->f_seek = fp->f_seek;
467 			kf->f_rbytes = fp->f_rbytes;
468 			kf->f_wbytes = fp->f_rbytes;
469 		}
470 	} else if (vp != NULL) {
471 		/* fake it */
472 		kf->f_type = DTYPE_VNODE;
473 		kf->f_flag = FREAD;
474 		if (fd == KERN_FILE_TRACE)
475 			kf->f_flag |= FWRITE;
476 	}
477 
478 	/* information about the object associated with this file */
479 	switch (kf->f_type) {
480 	case DTYPE_VNODE: {
481 		struct vnode vbuf;
482 		struct mount mount;
483 
484 		if (KREAD(kd, (u_long)(fp ? fp->f_data : vp), &vbuf)) {
485 			_kvm_err(kd, kd->program, "can't read vnode");
486 			return (-1);
487 		}
488 		vp = &vbuf;
489 
490 		if (KREAD(kd, (u_long)vp->v_mount, &mount)) {
491 			_kvm_err(kd, kd->program, "can't read v_mount");
492 			return (-1);
493 		}
494 		vp->v_mount = &mount;
495 
496 		kf->v_un = PTRTOINT64(vp->v_un.vu_socket);
497 		kf->v_type = vp->v_type;
498 		kf->v_tag = vp->v_tag;
499 		kf->v_flag = vp->v_flag;
500 		kf->v_data = PTRTOINT64(vp->v_data);
501 		kf->v_mount = PTRTOINT64(vp->v_mount);
502 		strlcpy(kf->f_mntonname, vp->v_mount->mnt_stat.f_mntonname,
503 		    sizeof(kf->f_mntonname));
504 
505 		/* Fill in va_fsid, va_fileid, va_mode, va_size, va_rdev */
506 		filestat(kd, kf, vp);
507 		break;
508 	    }
509 
510 	case DTYPE_SOCKET: {
511 		struct socket sock;
512 		struct protosw protosw;
513 		struct domain domain;
514 
515 		if (KREAD(kd, (u_long)fp->f_data, &sock)) {
516 			_kvm_err(kd, kd->program, "can't read socket");
517 			return (-1);
518 		}
519 
520 		kf->so_type = sock.so_type;
521 		kf->so_state = sock.so_state;
522 		kf->so_pcb = PTRTOINT64(sock.so_pcb);
523 		if (KREAD(kd, (u_long)sock.so_proto, &protosw)) {
524 			_kvm_err(kd, kd->program, "can't read protosw");
525 			return (-1);
526 		}
527 		kf->so_protocol = protosw.pr_protocol;
528 		if (KREAD(kd, (u_long)protosw.pr_domain, &domain)) {
529 			_kvm_err(kd, kd->program, "can't read domain");
530 			return (-1);
531 		}
532 		kf->so_family = domain.dom_family;
533 		if (!sock.so_pcb)
534 			break;
535 		switch (kf->so_family) {
536 		case AF_INET: {
537 			struct inpcb inpcb;
538 
539 			if (KREAD(kd, (u_long)sock.so_pcb, &inpcb)) {
540 				_kvm_err(kd, kd->program, "can't read inpcb");
541 				return (-1);
542 			}
543 			kf->inp_ppcb = PTRTOINT64(inpcb.inp_ppcb);
544 			kf->inp_lport = inpcb.inp_lport;
545 			kf->inp_laddru[0] = inpcb.inp_laddr.s_addr;
546 			kf->inp_fport = inpcb.inp_fport;
547 			kf->inp_faddru[0] = inpcb.inp_faddr.s_addr;
548 			break;
549 		    }
550 		case AF_INET6: {
551 			struct inpcb inpcb;
552 #define s6_addr32 __u6_addr.__u6_addr32
553 
554 			if (KREAD(kd, (u_long)sock.so_pcb, &inpcb)) {
555 				_kvm_err(kd, kd->program, "can't read inpcb");
556 				return (-1);
557 			}
558 			kf->inp_ppcb = PTRTOINT64(inpcb.inp_ppcb);
559 			kf->inp_lport = inpcb.inp_lport;
560 			kf->inp_laddru[0] = inpcb.inp_laddr6.s6_addr32[0];
561 			kf->inp_laddru[1] = inpcb.inp_laddr6.s6_addr32[1];
562 			kf->inp_laddru[2] = inpcb.inp_laddr6.s6_addr32[2];
563 			kf->inp_laddru[3] = inpcb.inp_laddr6.s6_addr32[3];
564 			kf->inp_fport = inpcb.inp_fport;
565 			kf->inp_faddru[0] = inpcb.inp_laddr6.s6_addr32[0];
566 			kf->inp_faddru[1] = inpcb.inp_faddr6.s6_addr32[1];
567 			kf->inp_faddru[2] = inpcb.inp_faddr6.s6_addr32[2];
568 			kf->inp_faddru[3] = inpcb.inp_faddr6.s6_addr32[3];
569 			break;
570 		    }
571 		case AF_UNIX: {
572 			struct unpcb unpcb;
573 
574 			if (KREAD(kd, (u_long)sock.so_pcb, &unpcb)) {
575 				_kvm_err(kd, kd->program, "can't read unpcb");
576 				return (-1);
577 			}
578 			kf->unp_conn = PTRTOINT64(unpcb.unp_conn);
579 			break;
580 		    }
581 		}
582 		break;
583 	    }
584 
585 	case DTYPE_PIPE: {
586 		struct pipe pipe;
587 
588 		if (KREAD(kd, (u_long)fp->f_data, &pipe)) {
589 			_kvm_err(kd, kd->program, "can't read pipe");
590 			return (-1);
591 		}
592 		kf->pipe_peer = PTRTOINT64(pipe.pipe_peer);
593 		kf->pipe_state = pipe.pipe_state;
594 		break;
595 	    }
596 
597 	case DTYPE_KQUEUE: {
598 		struct kqueue kqi;
599 
600 		if (KREAD(kd, (u_long)fp->f_data, &kqi)) {
601 			_kvm_err(kd, kd->program, "can't read kqi");
602 			return (-1);
603 		}
604 		kf->kq_count = kqi.kq_count;
605 		kf->kq_state = kqi.kq_state;
606 		break;
607 	    }
608 	case DTYPE_SYSTRACE: {
609 		struct fsystrace f;
610 
611 		if (KREAD(kd, (u_long)fp->f_data, &f)) {
612 			_kvm_err(kd, kd->program, "can't read fsystrace");
613 			return (-1);
614 		}
615 		kf->str_npolicies = f.npolicies;
616 		break;
617 	    }
618 	}
619 
620 	/* per-process information for KERN_FILE_BY[PU]ID */
621 	if (p != NULL) {
622 		kf->p_pid = p->p_pid;
623 		kf->p_uid = p->p_ucred->cr_uid;
624 		kf->p_gid = p->p_ucred->cr_gid;
625 		strlcpy(kf->p_comm, p->p_comm, sizeof(kf->p_comm));
626 		if (p->p_fd != NULL)
627 			kf->fd_ofileflags = p->p_fd->fd_ofileflags[fd];
628 	}
629 
630 	return (0);
631 }
632 
633 mode_t
634 _kvm_getftype(enum vtype v_type)
635 {
636 	mode_t ftype = 0;
637 
638 	switch (v_type) {
639 	case VREG:
640 		ftype = S_IFREG;
641 		break;
642 	case VDIR:
643 		ftype = S_IFDIR;
644 		break;
645 	case VBLK:
646 		ftype = S_IFBLK;
647 		break;
648 	case VCHR:
649 		ftype = S_IFCHR;
650 		break;
651 	case VLNK:
652 		ftype = S_IFLNK;
653 		break;
654 	case VSOCK:
655 		ftype = S_IFSOCK;
656 		break;
657 	case VFIFO:
658 		ftype = S_IFIFO;
659 		break;
660 	case VNON:
661 	case VBAD:
662 		break;
663 	}
664 
665 	return (ftype);
666 }
667 
668 static int
669 ufs_filestat(kvm_t *kd, struct kinfo_file2 *kf, struct vnode *vp)
670 {
671 	struct inode inode;
672 	struct ufs1_dinode di1;
673 
674 	if (KREAD(kd, (u_long)VTOI(vp), &inode)) {
675 		_kvm_err(kd, kd->program, "can't read inode at %p", VTOI(vp));
676 		return (-1);
677 	}
678 
679 	if (KREAD(kd, (u_long)inode.i_din1, &di1)) {
680 		_kvm_err(kd, kd->program, "can't read dinode at %p",
681 		    inode.i_din1);
682 		return (-1);
683 	}
684 
685 	inode.i_din1 = &di1;
686 
687 	kf->va_fsid = inode.i_dev & 0xffff;
688 	kf->va_fileid = (long)inode.i_number;
689 	kf->va_mode = inode.i_ffs1_mode;
690 	kf->va_size = inode.i_ffs1_size;
691 	kf->va_rdev = inode.i_ffs1_rdev;
692 
693 	return (0);
694 }
695 
696 static int
697 ext2fs_filestat(kvm_t *kd, struct kinfo_file2 *kf, struct vnode *vp)
698 {
699 	struct inode inode;
700 	struct ext2fs_dinode e2di;
701 
702 	if (KREAD(kd, (u_long)VTOI(vp), &inode)) {
703 		_kvm_err(kd, kd->program, "can't read inode at %p", VTOI(vp));
704 		return (-1);
705 	}
706 
707 	if (KREAD(kd, (u_long)inode.i_e2din, &e2di)) {
708 		_kvm_err(kd, kd->program, "can't read dinode at %p",
709 		    inode.i_e2din);
710 		return (-1);
711 	}
712 
713 	inode.i_e2din = &e2di;
714 
715 	kf->va_fsid = inode.i_dev & 0xffff;
716 	kf->va_fileid = (long)inode.i_number;
717 	kf->va_mode = inode.i_e2fs_mode;
718 	kf->va_size = inode.i_e2fs_size;
719 	kf->va_rdev = 0;	/* XXX */
720 
721 	return (0);
722 }
723 
724 static int
725 msdos_filestat(kvm_t *kd, struct kinfo_file2 *kf, struct vnode *vp)
726 {
727 	struct denode de;
728 	struct msdosfsmount mp;
729 
730 	if (KREAD(kd, (u_long)VTODE(vp), &de)) {
731 		_kvm_err(kd, kd->program, "can't read denode at %p", VTODE(vp));
732 		return (-1);
733 	}
734 	if (KREAD(kd, (u_long)de.de_pmp, &mp)) {
735 		_kvm_err(kd, kd->program, "can't read mount struct at %p",
736 		    de.de_pmp);
737 		return (-1);
738 	}
739 
740 	kf->va_fsid = de.de_dev & 0xffff;
741 	kf->va_fileid = 0; /* XXX see msdosfs_vptofh() for more info */
742 	kf->va_mode = (mp.pm_mask & 0777) | _kvm_getftype(vp->v_type);
743 	kf->va_size = de.de_FileSize;
744 	kf->va_rdev = 0;  /* msdosfs doesn't support device files */
745 
746 	return (0);
747 }
748 
749 static int
750 nfs_filestat(kvm_t *kd, struct kinfo_file2 *kf, struct vnode *vp)
751 {
752 	struct nfsnode nfsnode;
753 
754 	if (KREAD(kd, (u_long)VTONFS(vp), &nfsnode)) {
755 		_kvm_err(kd, kd->program, "can't read nfsnode at %p",
756 		    VTONFS(vp));
757 		return (-1);
758 	}
759 	kf->va_fsid = nfsnode.n_vattr.va_fsid;
760 	kf->va_fileid = nfsnode.n_vattr.va_fileid;
761 	kf->va_size = nfsnode.n_size;
762 	kf->va_rdev = nfsnode.n_vattr.va_rdev;
763 	kf->va_mode = (mode_t)nfsnode.n_vattr.va_mode | _kvm_getftype(vp->v_type);
764 
765 	return (0);
766 }
767 
768 static int
769 nnpfs_filestat(kvm_t *kd, struct kinfo_file2 *kf, struct vnode *vp)
770 {
771 	struct nnpfs_node nnpfs_node;
772 
773 	if (KREAD(kd, (u_long)VNODE_TO_XNODE(vp), &nnpfs_node)) {
774 		_kvm_err(kd, kd->program, "can't read nnpfs_node at %p",
775 		    VTOI(vp));
776 		return (-1);
777 	}
778 	kf->va_fsid = nnpfs_node.attr.va_fsid;
779 	kf->va_fileid = (long)nnpfs_node.attr.va_fileid;
780 	kf->va_mode = nnpfs_node.attr.va_mode;
781 	kf->va_size = nnpfs_node.attr.va_size;
782 	kf->va_rdev = nnpfs_node.attr.va_rdev;
783 
784 	return (0);
785 }
786 
787 static int
788 spec_filestat(kvm_t *kd, struct kinfo_file2 *kf, struct vnode *vp)
789 {
790 	struct specinfo		specinfo;
791 	struct vnode		parent;
792 
793 	if (KREAD(kd, (u_long)vp->v_specinfo, &specinfo)) {
794 		_kvm_err(kd, kd->program, "can't read specinfo at %p",
795 		     vp->v_specinfo);
796 		return (-1);
797 	}
798 
799 	vp->v_specinfo = &specinfo;
800 
801 	if (KREAD(kd, (u_long)vp->v_specparent, &parent)) {
802 		_kvm_err(kd, kd->program, "can't read parent vnode at %p",
803 		     vp->v_specparent);
804 		return (-1);
805 	}
806 
807 	if (ufs_filestat(kd, kf, vp))
808 		return (-1);
809 
810 	return (0);
811 }
812 
813 static int
814 filestat(kvm_t *kd, struct kinfo_file2 *kf, struct vnode *vp)
815 {
816 	int ret = 0;
817 
818 	if (vp->v_type != VNON && vp->v_type != VBAD) {
819 		switch (vp->v_tag) {
820 		case VT_UFS:
821 		case VT_MFS:
822 			ret = ufs_filestat(kd, kf, vp);
823 			break;
824 		case VT_NFS:
825 			ret = nfs_filestat(kd, kf, vp);
826 			break;
827 		case VT_EXT2FS:
828 			ret = ext2fs_filestat(kd, kf, vp);
829 			break;
830 		case VT_ISOFS:
831 			ret = _kvm_stat_cd9660(kd, kf, vp);
832 			break;
833 		case VT_MSDOSFS:
834 			ret = msdos_filestat(kd, kf, vp);
835 			break;
836 		case VT_NNPFS:
837 			ret = nnpfs_filestat(kd, kf, vp);
838 			break;
839 		case VT_UDF:
840 			ret = _kvm_stat_udf(kd, kf, vp);
841 			break;
842 		case VT_NTFS:
843 			ret = _kvm_stat_ntfs(kd, kf, vp);
844 			break;
845 		case VT_NON:
846 			if (vp->v_flag & VCLONE)
847 				ret = spec_filestat(kd, kf, vp);
848 			break;
849 		}
850 	}
851 	return (ret);
852 }
853