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