xref: /openbsd/lib/libkvm/kvm_file2.c (revision 3d8817e4)
1 /*	$OpenBSD: kvm_file2.c,v 1.16 2010/07/17 19:27:07 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 #include <msdosfs/denode.h>
94 #include <msdosfs/msdosfsmount.h>
95 
96 #include <miscfs/specfs/specdev.h>
97 
98 #include <net/route.h>
99 #include <netinet/in.h>
100 #include <netinet/in_systm.h>
101 #include <netinet/ip.h>
102 #include <netinet/in_pcb.h>
103 
104 #ifdef INET6
105 #include <netinet/ip6.h>
106 #include <netinet6/ip6_var.h>
107 #endif
108 
109 #include <nlist.h>
110 #include <kvm.h>
111 #include <db.h>
112 #include <stdlib.h>
113 #include <string.h>
114 #include <unistd.h>
115 
116 #include "kvm_private.h"
117 
118 static struct kinfo_file2 *kvm_deadfile2_byfile(kvm_t *, int, int,
119     size_t, int *);
120 static struct kinfo_file2 *kvm_deadfile2_byid(kvm_t *, int, int,
121     size_t, int *);
122 static int fill_file2(kvm_t *, struct kinfo_file2 *, struct file *,
123     struct vnode *, struct proc *, int);
124 static int filestat(kvm_t *, struct kinfo_file2 *, struct vnode *);
125 
126 LIST_HEAD(proclist, proc);
127 
128 struct kinfo_file2 *
129 kvm_getfile2(kvm_t *kd, int op, int arg, size_t esize, int *cnt)
130 {
131 	int mib[6], rv;
132 	size_t size;
133 
134 	if (kd->filebase != NULL) {
135 		free(kd->filebase);
136 		/*
137 		 * Clear this pointer in case this call fails.  Otherwise,
138 		 * kvm_close() will free it again.
139 		 */
140 		kd->filebase = 0;
141 	}
142 
143 	if (ISALIVE(kd)) {
144 		mib[0] = CTL_KERN;
145 		mib[1] = KERN_FILE2;
146 		mib[2] = op;
147 		mib[3] = arg;
148 		mib[4] = esize;
149 		mib[5] = 0;
150 
151 		/* find size and alloc buffer */
152 		rv = sysctl(mib, 6, NULL, &size, NULL, 0);
153 		if (rv == -1) {
154 			if (kd->vmfd != -1)
155 				goto deadway;
156 			_kvm_syserr(kd, kd->program, "kvm_getfile2");
157 			return (NULL);
158 		}
159 		kd->filebase = _kvm_malloc(kd, size);
160 		if (kd->filebase == NULL)
161 			return (NULL);
162 
163 		/* get actual data */
164 		mib[5] = size / esize;
165 		rv = sysctl(mib, 6, kd->filebase, &size, NULL, 0);
166 		if (rv == -1) {
167 			_kvm_syserr(kd, kd->program, "kvm_getfile2");
168 			return (NULL);
169 		}
170 		*cnt = size / esize;
171 		return ((struct kinfo_file2 *)kd->filebase);
172 	} else {
173 		if (esize > sizeof(struct kinfo_file2)) {
174 			_kvm_syserr(kd, kd->program,
175 			    "kvm_getfile2: unknown fields requested: libkvm out of date?");
176 			return (NULL);
177 		}
178 	    deadway:
179 		switch (op) {
180 		case KERN_FILE_BYFILE:
181 			if (arg != 0) {
182 				_kvm_err(kd, kd->program,
183 				    "%s: invalid argument");
184 				return (NULL);
185 			}
186 			return (kvm_deadfile2_byfile(kd, op, arg, esize, cnt));
187 			break;
188 		case KERN_FILE_BYPID:
189 		case KERN_FILE_BYUID:
190 			return (kvm_deadfile2_byid(kd, op, arg, esize, cnt));
191 			break;
192 		default:
193 			return (NULL);
194 		}
195 	}
196 }
197 
198 static struct kinfo_file2 *
199 kvm_deadfile2_byfile(kvm_t *kd, int op, int arg, size_t esize, int *cnt)
200 {
201 	size_t size;
202 	struct nlist nl[3], *p;
203 	int buflen = kd->arglen, n = 0;
204 	char *where = kd->argspc;
205 	struct kinfo_file2 *kf = NULL;
206 	struct file *fp, file;
207 	struct filelist filehead;
208 	int nfiles;
209 
210 	nl[0].n_name = "_filehead";
211 	nl[1].n_name = "_nfiles";
212 	nl[2].n_name = 0;
213 
214 	if (kvm_nlist(kd, nl) != 0) {
215 		for (p = nl; p->n_type != 0; ++p)
216 			;
217 		_kvm_err(kd, kd->program,
218 			 "%s: no such symbol", p->n_name);
219 		return (NULL);
220 	}
221 	if (KREAD(kd, nl[0].n_value, &filehead)) {
222 		_kvm_err(kd, kd->program, "can't read filehead");
223 		return (NULL);
224 	}
225 	if (KREAD(kd, nl[1].n_value, &nfiles)) {
226 		_kvm_err(kd, kd->program, "can't read nfiles");
227 		return (NULL);
228 	}
229 	size = (nfiles + 10) * sizeof(struct kinfo_file2);
230 	kd->filebase = _kvm_malloc(kd, size);
231 	if (kd->filebase == NULL)
232 		return (NULL);
233 
234 	LIST_FOREACH(fp, &filehead, f_list) {
235 		if (buflen < sizeof(struct kinfo_file2))
236 			break;
237 
238 		if (KREAD(kd, (long)fp, &file)) {
239 			_kvm_err(kd, kd->program, "can't read kfp");
240 			return (NULL);
241 		}
242 		kf = (struct kinfo_file2 *)where;
243 		where += sizeof(struct kinfo_file2);
244 		buflen -= sizeof(struct kinfo_file2);
245 		n++;
246 		if (fill_file2(kd, kf, fp, NULL, NULL, 0) == -1)
247 			return (NULL);
248 	}
249 	if (n != nfiles) {
250 		_kvm_err(kd, kd->program, "inconsistent nfiles");
251 		return (NULL);
252 	}
253 	*cnt = n;
254 	return (kf);
255 }
256 
257 static struct kinfo_file2 *
258 kvm_deadfile2_byid(kvm_t *kd, int op, int arg, size_t esize, int *cnt)
259 {
260 	size_t size;
261 	struct nlist nl[5], *np;
262 	int buflen = kd->arglen, n = 0;
263 	char *where = kd->argspc;
264 	struct kinfo_file2 *kf = NULL;
265 	struct file *fp, file;
266 	struct filelist filehead;
267 	struct filedesc0 filed0;
268 #define filed	filed0.fd_fd
269 	struct proclist allproc;
270 	struct proc *p, proc;
271 	struct process process;
272 	struct pcred pcred;
273 	struct ucred ucred;
274 	int i, nfiles, nprocs;
275 
276 	nl[0].n_name = "_filehead";
277 	nl[1].n_name = "_nfiles";
278 	nl[2].n_name = "_nprocs";
279 	nl[3].n_name = "_allproc";
280 	nl[4].n_name = 0;
281 
282 	if (kvm_nlist(kd, nl) != 0) {
283 		for (np = nl; np->n_type != 0; ++np)
284 			;
285 		_kvm_err(kd, kd->program,
286 			 "%s: no such symbol", np->n_name);
287 		return (NULL);
288 	}
289 	if (KREAD(kd, nl[0].n_value, &filehead)) {
290 		_kvm_err(kd, kd->program, "can't read filehead");
291 		return (NULL);
292 	}
293 	if (KREAD(kd, nl[1].n_value, &nfiles)) {
294 		_kvm_err(kd, kd->program, "can't read nfiles");
295 		return (NULL);
296 	}
297 	if (KREAD(kd, nl[2].n_value, &nprocs)) {
298 		_kvm_err(kd, kd->program, "can't read nprocs");
299 		return (NULL);
300 	}
301 	if (KREAD(kd, nl[3].n_value, &allproc)) {
302 		_kvm_err(kd, kd->program, "can't read allproc");
303 		return (NULL);
304 	}
305 	/* this may be more room than we need but counting is expensive */
306 	size = (nfiles + 10) * sizeof(struct kinfo_file2);
307 	kd->filebase = _kvm_malloc(kd, size);
308 	if (kd->filebase == NULL)
309 		return (NULL);
310 
311 	LIST_FOREACH(p, &allproc, p_list) {
312 		if (buflen < sizeof(struct kinfo_file2))
313 			break;
314 
315 		if (KREAD(kd, (u_long)p, &proc)) {
316 			_kvm_err(kd, kd->program, "can't read proc at %x", p);
317 			return (NULL);
318 		}
319 
320 		/* skip system, embryonic and undead processes */
321 		if ((proc.p_flag & P_SYSTEM) ||
322 		    proc.p_stat == SIDL || proc.p_stat == SZOMB)
323 			continue;
324 		if (op == KERN_FILE_BYPID) {
325 			if (arg > 0 && proc.p_pid != (pid_t)arg) {
326 				/* not the pid we are looking for */
327 				continue;
328 			}
329 		} else /* if (op == KERN_FILE_BYUID) */ {
330 			if (arg > 0 && proc.p_ucred->cr_uid != (uid_t)arg) {
331 				/* not the uid we are looking for */
332 				continue;
333 			}
334 		}
335 
336 		if (proc.p_fd == NULL || proc.p_p == NULL)
337 			continue;
338 
339 		if (KREAD(kd, (u_long)proc.p_p, &process)) {
340 			_kvm_err(kd, kd->program, "can't read process at %x",
341 			    proc.p_p);
342 			return (NULL);
343 		}
344 		proc.p_p = &process;
345 
346 		if (KREAD(kd, (u_long)process.ps_cred, &pcred) == 0)
347 			KREAD(kd, (u_long)pcred.pc_ucred, &ucred);
348 		process.ps_cred = &pcred;
349 		pcred.pc_ucred = &ucred;
350 
351 		if (KREAD(kd, (u_long)proc.p_fd, &filed0)) {
352 			_kvm_err(kd, kd->program, "can't read filedesc at %x",
353 			    proc.p_fd);
354 			return (NULL);
355 		}
356 		proc.p_fd = &filed;
357 
358 		if (proc.p_textvp) {
359 			if (buflen < sizeof(struct kinfo_file2))
360 				goto done;
361 			kf = (struct kinfo_file2 *)where;
362 			where += sizeof(struct kinfo_file2);
363 			buflen -= sizeof(struct kinfo_file2);
364 			n++;
365 			if (fill_file2(kd, kf, NULL, proc.p_textvp, &proc,
366 			    KERN_FILE_TEXT) == -1)
367 				return (NULL);
368 		}
369 		if (filed.fd_cdir) {
370 			if (buflen < sizeof(struct kinfo_file2))
371 				goto done;
372 			kf = (struct kinfo_file2 *)where;
373 			where += sizeof(struct kinfo_file2);
374 			buflen -= sizeof(struct kinfo_file2);
375 			n++;
376 			if (fill_file2(kd, kf, NULL, filed.fd_cdir, &proc,
377 			    KERN_FILE_CDIR) == -1)
378 				return (NULL);
379 		}
380 		if (filed.fd_rdir) {
381 			if (buflen < sizeof(struct kinfo_file2))
382 				goto done;
383 			kf = (struct kinfo_file2 *)where;
384 			where += sizeof(struct kinfo_file2);
385 			buflen -= sizeof(struct kinfo_file2);
386 			n++;
387 			if (fill_file2(kd, kf, NULL, filed.fd_rdir, &proc,
388 			    KERN_FILE_RDIR) == -1)
389 				return (NULL);
390 		}
391 		if (proc.p_tracep) {
392 			if (buflen < sizeof(struct kinfo_file2))
393 				goto done;
394 			kf = (struct kinfo_file2 *)where;
395 			where += sizeof(struct kinfo_file2);
396 			buflen -= sizeof(struct kinfo_file2);
397 			n++;
398 			if (fill_file2(kd, kf, NULL, proc.p_tracep, &proc,
399 			    KERN_FILE_TRACE) == -1)
400 				return (NULL);
401 		}
402 
403 		if (filed.fd_nfiles < 0 ||
404 		    filed.fd_lastfile >= filed.fd_nfiles ||
405 		    filed.fd_freefile > filed.fd_lastfile + 1) {
406 			_kvm_err(kd, kd->program,
407 			    "filedesc corrupted at %x for pid %d",
408 			    proc.p_fd, proc.p_pid);
409 			return (NULL);
410 		}
411 
412 		for (i = 0; i < filed.fd_nfiles; i++) {
413 			if (buflen < sizeof(struct kinfo_file2))
414 				goto done;
415 			if ((fp = filed.fd_ofiles[i]) == NULL)
416 				continue;
417 			if (KREAD(kd, (u_long)fp, &file)) {
418 				_kvm_err(kd, kd->program, "can't read file");
419 				return (NULL);
420 			}
421 			kf = (struct kinfo_file2 *)where;
422 			where += sizeof(struct kinfo_file2);
423 			buflen -= sizeof(struct kinfo_file2);
424 			n++;
425 			if (fill_file2(kd, kf, &file, NULL, &proc, i) == -1)
426 				return (NULL);
427 		}
428 	}
429 done:
430 	*cnt = n;
431 	return (kf);
432 }
433 
434 static int
435 fill_file2(kvm_t *kd, struct kinfo_file2 *kf, struct file *fp, struct vnode *vp,
436     struct proc *p, int fd)
437 {
438 	struct ucred f_cred;
439 
440 	memset(kf, 0, sizeof(*kf));
441 
442 	kf->fd_fd = fd;		/* might not really be an fd */
443 
444 	if (fp != NULL) {
445 		/* Fill in f_cred */
446 		if (KREAD(kd, (u_long)fp->f_cred, &f_cred)) {
447 			_kvm_err(kd, kd->program, "can't read f_cred");
448 			return (-1);
449 		}
450 		fp->f_cred = &f_cred;
451 
452 		kf->f_fileaddr = PTRTOINT64(fp);
453 		kf->f_flag = fp->f_flag;
454 		kf->f_iflags = fp->f_iflags;
455 		kf->f_type = fp->f_type;
456 		kf->f_count = fp->f_count;
457 		kf->f_msgcount = fp->f_msgcount;
458 		kf->f_ucred = PTRTOINT64(fp->f_cred);
459 		kf->f_uid = fp->f_cred->cr_uid;
460 		kf->f_gid = fp->f_cred->cr_gid;
461 		kf->f_ops = PTRTOINT64(fp->f_ops);
462 		kf->f_offset = fp->f_offset;
463 		kf->f_data = PTRTOINT64(fp->f_data);
464 		kf->f_usecount = fp->f_usecount;
465 
466 		if (getuid() == 0 || p->p_ucred->cr_uid == fp->f_cred->cr_uid) {
467 			kf->f_rxfer = fp->f_rxfer;
468 			kf->f_rwfer = fp->f_wxfer;
469 			kf->f_seek = fp->f_seek;
470 			kf->f_rbytes = fp->f_rbytes;
471 			kf->f_wbytes = fp->f_rbytes;
472 		}
473 	} else if (vp != NULL) {
474 		/* fake it */
475 		kf->f_type = DTYPE_VNODE;
476 		kf->f_flag = FREAD;
477 		if (fd == KERN_FILE_TRACE)
478 			kf->f_flag |= FWRITE;
479 	}
480 
481 	/* information about the object associated with this file */
482 	switch (kf->f_type) {
483 	case DTYPE_VNODE: {
484 		struct vnode vbuf;
485 		struct mount mount;
486 
487 		if (KREAD(kd, (u_long)(fp ? fp->f_data : vp), &vbuf)) {
488 			_kvm_err(kd, kd->program, "can't read vnode");
489 			return (-1);
490 		}
491 		vp = &vbuf;
492 
493 		if (KREAD(kd, (u_long)vp->v_mount, &mount)) {
494 			_kvm_err(kd, kd->program, "can't read v_mount");
495 			return (-1);
496 		}
497 		vp->v_mount = &mount;
498 
499 		kf->v_un = PTRTOINT64(vp->v_un.vu_socket);
500 		kf->v_type = vp->v_type;
501 		kf->v_tag = vp->v_tag;
502 		kf->v_flag = vp->v_flag;
503 		kf->v_data = PTRTOINT64(vp->v_data);
504 		kf->v_mount = PTRTOINT64(vp->v_mount);
505 		strlcpy(kf->f_mntonname, vp->v_mount->mnt_stat.f_mntonname,
506 		    sizeof(kf->f_mntonname));
507 
508 		/* Fill in va_fsid, va_fileid, va_mode, va_size, va_rdev */
509 		filestat(kd, kf, vp);
510 		break;
511 	    }
512 
513 	case DTYPE_SOCKET: {
514 		struct socket sock;
515 		struct protosw protosw;
516 		struct domain domain;
517 
518 		if (KREAD(kd, (u_long)fp->f_data, &sock)) {
519 			_kvm_err(kd, kd->program, "can't read socket");
520 			return (-1);
521 		}
522 
523 		kf->so_type = sock.so_type;
524 		kf->so_state = sock.so_state;
525 		kf->so_pcb = PTRTOINT64(sock.so_pcb);
526 		if (KREAD(kd, (u_long)sock.so_proto, &protosw)) {
527 			_kvm_err(kd, kd->program, "can't read protosw");
528 			return (-1);
529 		}
530 		kf->so_protocol = protosw.pr_protocol;
531 		if (KREAD(kd, (u_long)protosw.pr_domain, &domain)) {
532 			_kvm_err(kd, kd->program, "can't read domain");
533 			return (-1);
534 		}
535 		kf->so_family = domain.dom_family;
536 		if (!sock.so_pcb)
537 			break;
538 		switch (kf->so_family) {
539 		case AF_INET: {
540 			struct inpcb inpcb;
541 
542 			if (KREAD(kd, (u_long)sock.so_pcb, &inpcb)) {
543 				_kvm_err(kd, kd->program, "can't read inpcb");
544 				return (-1);
545 			}
546 			kf->inp_ppcb = PTRTOINT64(inpcb.inp_ppcb);
547 			kf->inp_lport = inpcb.inp_lport;
548 			kf->inp_laddru[0] = inpcb.inp_laddr.s_addr;
549 			kf->inp_fport = inpcb.inp_fport;
550 			kf->inp_faddru[0] = inpcb.inp_faddr.s_addr;
551 			break;
552 		    }
553 		case AF_INET6: {
554 			struct inpcb inpcb;
555 #define s6_addr32 __u6_addr.__u6_addr32
556 
557 			if (KREAD(kd, (u_long)sock.so_pcb, &inpcb)) {
558 				_kvm_err(kd, kd->program, "can't read inpcb");
559 				return (-1);
560 			}
561 			kf->inp_ppcb = PTRTOINT64(inpcb.inp_ppcb);
562 			kf->inp_lport = inpcb.inp_lport;
563 			kf->inp_laddru[0] = inpcb.inp_laddr6.s6_addr32[0];
564 			kf->inp_laddru[1] = inpcb.inp_laddr6.s6_addr32[1];
565 			kf->inp_laddru[2] = inpcb.inp_laddr6.s6_addr32[2];
566 			kf->inp_laddru[3] = inpcb.inp_laddr6.s6_addr32[3];
567 			kf->inp_fport = inpcb.inp_fport;
568 			kf->inp_faddru[0] = inpcb.inp_laddr6.s6_addr32[0];
569 			kf->inp_faddru[1] = inpcb.inp_faddr6.s6_addr32[1];
570 			kf->inp_faddru[2] = inpcb.inp_faddr6.s6_addr32[2];
571 			kf->inp_faddru[3] = inpcb.inp_faddr6.s6_addr32[3];
572 			break;
573 		    }
574 		case AF_UNIX: {
575 			struct unpcb unpcb;
576 
577 			if (KREAD(kd, (u_long)sock.so_pcb, &unpcb)) {
578 				_kvm_err(kd, kd->program, "can't read unpcb");
579 				return (-1);
580 			}
581 			kf->unp_conn = PTRTOINT64(unpcb.unp_conn);
582 			break;
583 		    }
584 		}
585 		break;
586 	    }
587 
588 	case DTYPE_PIPE: {
589 		struct pipe pipe;
590 
591 		if (KREAD(kd, (u_long)fp->f_data, &pipe)) {
592 			_kvm_err(kd, kd->program, "can't read pipe");
593 			return (-1);
594 		}
595 		kf->pipe_peer = PTRTOINT64(pipe.pipe_peer);
596 		kf->pipe_state = pipe.pipe_state;
597 		break;
598 	    }
599 
600 	case DTYPE_KQUEUE: {
601 		struct kqueue kqi;
602 
603 		if (KREAD(kd, (u_long)fp->f_data, &kqi)) {
604 			_kvm_err(kd, kd->program, "can't read kqi");
605 			return (-1);
606 		}
607 		kf->kq_count = kqi.kq_count;
608 		kf->kq_state = kqi.kq_state;
609 		break;
610 	    }
611 	case DTYPE_SYSTRACE: {
612 		struct fsystrace f;
613 
614 		if (KREAD(kd, (u_long)fp->f_data, &f)) {
615 			_kvm_err(kd, kd->program, "can't read fsystrace");
616 			return (-1);
617 		}
618 		kf->str_npolicies = f.npolicies;
619 		break;
620 	    }
621 	}
622 
623 	/* per-process information for KERN_FILE_BY[PU]ID */
624 	if (p != NULL) {
625 		kf->p_pid = p->p_pid;
626 		kf->p_uid = p->p_ucred->cr_uid;
627 		kf->p_gid = p->p_ucred->cr_gid;
628 		strlcpy(kf->p_comm, p->p_comm, sizeof(kf->p_comm));
629 		if (p->p_fd != NULL)
630 			kf->fd_ofileflags = p->p_fd->fd_ofileflags[fd];
631 	}
632 
633 	return (0);
634 }
635 
636 mode_t
637 _kvm_getftype(enum vtype v_type)
638 {
639 	mode_t ftype = 0;
640 
641 	switch (v_type) {
642 	case VREG:
643 		ftype = S_IFREG;
644 		break;
645 	case VDIR:
646 		ftype = S_IFDIR;
647 		break;
648 	case VBLK:
649 		ftype = S_IFBLK;
650 		break;
651 	case VCHR:
652 		ftype = S_IFCHR;
653 		break;
654 	case VLNK:
655 		ftype = S_IFLNK;
656 		break;
657 	case VSOCK:
658 		ftype = S_IFSOCK;
659 		break;
660 	case VFIFO:
661 		ftype = S_IFIFO;
662 		break;
663 	case VNON:
664 	case VBAD:
665 		break;
666 	}
667 
668 	return (ftype);
669 }
670 
671 static int
672 ufs_filestat(kvm_t *kd, struct kinfo_file2 *kf, struct vnode *vp)
673 {
674 	struct inode inode;
675 	struct ufs1_dinode di1;
676 
677 	if (KREAD(kd, (u_long)VTOI(vp), &inode)) {
678 		_kvm_err(kd, kd->program, "can't read inode at %p", VTOI(vp));
679 		return (-1);
680 	}
681 
682 	if (KREAD(kd, (u_long)inode.i_din1, &di1)) {
683 		_kvm_err(kd, kd->program, "can't read dinode at %p",
684 		    inode.i_din1);
685 		return (-1);
686 	}
687 
688 	inode.i_din1 = &di1;
689 
690 	kf->va_fsid = inode.i_dev & 0xffff;
691 	kf->va_fileid = (long)inode.i_number;
692 	kf->va_mode = inode.i_ffs1_mode;
693 	kf->va_size = inode.i_ffs1_size;
694 	kf->va_rdev = inode.i_ffs1_rdev;
695 
696 	return (0);
697 }
698 
699 static int
700 ext2fs_filestat(kvm_t *kd, struct kinfo_file2 *kf, struct vnode *vp)
701 {
702 	struct inode inode;
703 	struct ext2fs_dinode e2di;
704 
705 	if (KREAD(kd, (u_long)VTOI(vp), &inode)) {
706 		_kvm_err(kd, kd->program, "can't read inode at %p", VTOI(vp));
707 		return (-1);
708 	}
709 
710 	if (KREAD(kd, (u_long)inode.i_e2din, &e2di)) {
711 		_kvm_err(kd, kd->program, "can't read dinode at %p",
712 		    inode.i_e2din);
713 		return (-1);
714 	}
715 
716 	inode.i_e2din = &e2di;
717 
718 	kf->va_fsid = inode.i_dev & 0xffff;
719 	kf->va_fileid = (long)inode.i_number;
720 	kf->va_mode = inode.i_e2fs_mode;
721 	kf->va_size = inode.i_e2fs_size;
722 	kf->va_rdev = 0;	/* XXX */
723 
724 	return (0);
725 }
726 
727 static int
728 msdos_filestat(kvm_t *kd, struct kinfo_file2 *kf, struct vnode *vp)
729 {
730 	struct denode de;
731 	struct msdosfsmount mp;
732 
733 	if (KREAD(kd, (u_long)VTODE(vp), &de)) {
734 		_kvm_err(kd, kd->program, "can't read denode at %p", VTODE(vp));
735 		return (-1);
736 	}
737 	if (KREAD(kd, (u_long)de.de_pmp, &mp)) {
738 		_kvm_err(kd, kd->program, "can't read mount struct at %p",
739 		    de.de_pmp);
740 		return (-1);
741 	}
742 
743 	kf->va_fsid = de.de_dev & 0xffff;
744 	kf->va_fileid = 0; /* XXX see msdosfs_vptofh() for more info */
745 	kf->va_mode = (mp.pm_mask & 0777) | _kvm_getftype(vp->v_type);
746 	kf->va_size = de.de_FileSize;
747 	kf->va_rdev = 0;  /* msdosfs doesn't support device files */
748 
749 	return (0);
750 }
751 
752 static int
753 nfs_filestat(kvm_t *kd, struct kinfo_file2 *kf, struct vnode *vp)
754 {
755 	struct nfsnode nfsnode;
756 
757 	if (KREAD(kd, (u_long)VTONFS(vp), &nfsnode)) {
758 		_kvm_err(kd, kd->program, "can't read nfsnode at %p",
759 		    VTONFS(vp));
760 		return (-1);
761 	}
762 	kf->va_fsid = nfsnode.n_vattr.va_fsid;
763 	kf->va_fileid = nfsnode.n_vattr.va_fileid;
764 	kf->va_size = nfsnode.n_size;
765 	kf->va_rdev = nfsnode.n_vattr.va_rdev;
766 	kf->va_mode = (mode_t)nfsnode.n_vattr.va_mode | _kvm_getftype(vp->v_type);
767 
768 	return (0);
769 }
770 
771 static int
772 nnpfs_filestat(kvm_t *kd, struct kinfo_file2 *kf, struct vnode *vp)
773 {
774 	struct nnpfs_node nnpfs_node;
775 
776 	if (KREAD(kd, (u_long)VNODE_TO_XNODE(vp), &nnpfs_node)) {
777 		_kvm_err(kd, kd->program, "can't read nnpfs_node at %p",
778 		    VTOI(vp));
779 		return (-1);
780 	}
781 	kf->va_fsid = nnpfs_node.attr.va_fsid;
782 	kf->va_fileid = (long)nnpfs_node.attr.va_fileid;
783 	kf->va_mode = nnpfs_node.attr.va_mode;
784 	kf->va_size = nnpfs_node.attr.va_size;
785 	kf->va_rdev = nnpfs_node.attr.va_rdev;
786 
787 	return (0);
788 }
789 
790 static int
791 spec_filestat(kvm_t *kd, struct kinfo_file2 *kf, struct vnode *vp)
792 {
793 	struct specinfo		specinfo;
794 	struct vnode		parent;
795 
796 	if (KREAD(kd, (u_long)vp->v_specinfo, &specinfo)) {
797 		_kvm_err(kd, kd->program, "can't read specinfo at %p",
798 		     vp->v_specinfo);
799 		return (-1);
800 	}
801 
802 	vp->v_specinfo = &specinfo;
803 
804 	if (KREAD(kd, (u_long)vp->v_specparent, &parent)) {
805 		_kvm_err(kd, kd->program, "can't read parent vnode at %p",
806 		     vp->v_specparent);
807 		return (-1);
808 	}
809 
810 	if (ufs_filestat(kd, kf, vp))
811 		return (-1);
812 
813 	return (0);
814 }
815 
816 static int
817 filestat(kvm_t *kd, struct kinfo_file2 *kf, struct vnode *vp)
818 {
819 	int ret = 0;
820 
821 	if (vp->v_type != VNON && vp->v_type != VBAD) {
822 		switch (vp->v_tag) {
823 		case VT_UFS:
824 		case VT_MFS:
825 			ret = ufs_filestat(kd, kf, vp);
826 			break;
827 		case VT_NFS:
828 			ret = nfs_filestat(kd, kf, vp);
829 			break;
830 		case VT_EXT2FS:
831 			ret = ext2fs_filestat(kd, kf, vp);
832 			break;
833 		case VT_ISOFS:
834 			ret = _kvm_stat_cd9660(kd, kf, vp);
835 			break;
836 		case VT_MSDOSFS:
837 			ret = msdos_filestat(kd, kf, vp);
838 			break;
839 		case VT_NNPFS:
840 			ret = nnpfs_filestat(kd, kf, vp);
841 			break;
842 		case VT_UDF:
843 			ret = _kvm_stat_udf(kd, kf, vp);
844 			break;
845 		case VT_NTFS:
846 			ret = _kvm_stat_ntfs(kd, kf, vp);
847 			break;
848 		case VT_NON:
849 			if (vp->v_flag & VCLONE)
850 				ret = spec_filestat(kd, kf, vp);
851 			break;
852 		}
853 	}
854 	return (ret);
855 }
856