xref: /openbsd-src/lib/libkvm/kvm_file2.c (revision b33a8d55775a3013157d6b0e3602c1fe178b48a6)
1 /*	$OpenBSD: kvm_file2.c,v 1.47 2015/09/04 02:58:14 dlg 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/un.h>
74 #include <sys/unpcb.h>
75 #include <sys/filedesc.h>
76 #include <sys/mbuf.h>
77 #include <sys/pipe.h>
78 #include <sys/stat.h>
79 #include <sys/sysctl.h>
80 #include <sys/specdev.h>
81 
82 #define _KERNEL
83 #include <ufs/ufs/quota.h>
84 #include <ufs/ufs/inode.h>
85 #undef _KERNEL
86 
87 #include <nfs/nfsproto.h>
88 #include <nfs/rpcv2.h>
89 #include <nfs/nfs.h>
90 #include <nfs/nfsnode.h>
91 
92 #include <msdosfs/bpb.h>
93 #include <msdosfs/denode.h>
94 #include <msdosfs/msdosfsmount.h>
95 
96 #include <net/route.h>
97 #include <netinet/in.h>
98 #include <netinet/ip.h>
99 #include <netinet/in_pcb.h>
100 #include <netinet/tcp.h>
101 #include <netinet/tcp_timer.h>
102 #include <netinet/tcp_var.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 <stddef.h>
113 #include <stdlib.h>
114 #include <string.h>
115 #include <unistd.h>
116 #include <limits.h>
117 #include <errno.h>
118 
119 #include "kvm_private.h"
120 #include "kvm_file.h"
121 
122 static struct kinfo_file *kvm_deadfile_byfile(kvm_t *, int, int,
123     size_t, int *);
124 static struct kinfo_file *kvm_deadfile_byid(kvm_t *, int, int,
125     size_t, int *);
126 static int fill_file(kvm_t *, struct kinfo_file *, struct file *, u_long,
127     struct vnode *, struct process *, int, pid_t);
128 static int filestat(kvm_t *, struct kinfo_file *, struct vnode *);
129 
130 LIST_HEAD(processlist, process);
131 
132 struct kinfo_file *
133 kvm_getfiles(kvm_t *kd, int op, int arg, size_t esize, int *cnt)
134 {
135 	int mib[6], rv;
136 	void *filebase;
137 	size_t size;
138 
139 	if (ISALIVE(kd)) {
140 		mib[0] = CTL_KERN;
141 		mib[1] = KERN_FILE;
142 		mib[2] = op;
143 		mib[3] = arg;
144 		mib[4] = esize;
145 
146 		do {
147 			mib[5] = 0;
148 
149 			/* find size and alloc buffer */
150 			rv = sysctl(mib, 6, NULL, &size, NULL, 0);
151 			if (rv == -1) {
152 				if (kd->vmfd != -1)
153 					goto deadway;
154 				_kvm_syserr(kd, kd->program, "kvm_getfiles");
155 				return (NULL);
156 			}
157 
158 			size += size / 8; /* add ~10% */
159 
160 			filebase = _kvm_realloc(kd, kd->filebase, size);
161 			if (filebase == NULL)
162 				return (NULL);
163 
164 			kd->filebase = filebase;
165 
166 			/* get actual data */
167 			mib[5] = size / esize;
168 			rv = sysctl(mib, 6, kd->filebase, &size, NULL, 0);
169 			if (rv == -1 && errno != ENOMEM) {
170 				_kvm_syserr(kd, kd->program,
171 				    "kvm_getfiles");
172 				return (NULL);
173 			}
174 		} while (rv == -1);
175 
176 		*cnt = size / esize;
177 		return (kd->filebase);
178 	} else {
179 		if (esize > sizeof(struct kinfo_file)) {
180 			_kvm_syserr(kd, kd->program,
181 			    "kvm_getfiles: unknown fields requested: libkvm out of date?");
182 			return (NULL);
183 		}
184 	    deadway:
185 		switch (op) {
186 		case KERN_FILE_BYFILE:
187 			return (kvm_deadfile_byfile(kd, op, arg, esize, cnt));
188 			break;
189 		case KERN_FILE_BYPID:
190 		case KERN_FILE_BYUID:
191 			return (kvm_deadfile_byid(kd, op, arg, esize, cnt));
192 			break;
193 		default:
194 			return (NULL);
195 		}
196 	}
197 }
198 
199 static struct kinfo_file *
200 kvm_deadfile_byfile(kvm_t *kd, int op, int arg, size_t esize, int *cnt)
201 {
202 	struct nlist nl[3], *p;
203 	size_t buflen;
204 	int n = 0;
205 	char *where;
206 	struct kinfo_file kf;
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 	where = _kvm_reallocarray(kd, kd->filebase, nfiles, esize);
231 	if (where == NULL)
232 		return (NULL);
233 
234 	kd->filebase = (void *)where;
235 	buflen = nfiles * esize;
236 
237 	for (fp = LIST_FIRST(&filehead);
238 	    fp != NULL && esize <= buflen;
239 	    fp = LIST_NEXT(&file, f_list)) {
240 		if (KREAD(kd, (u_long)fp, &file)) {
241 			_kvm_err(kd, kd->program, "can't read kfp");
242 			return (NULL);
243 		}
244 		if (file.f_count == 0)
245 			continue;
246 		if (arg != 0 && file.f_type != arg)
247 			continue;
248 		if (fill_file(kd, &kf, &file, (u_long)fp, NULL, NULL, 0, 0)
249 		    == -1)
250 			return (NULL);
251 		memcpy(where, &kf, esize);
252 		where += esize;
253 		buflen -= esize;
254 		n++;
255 	}
256 	if (n != nfiles) {
257 		_kvm_err(kd, kd->program, "inconsistent nfiles");
258 		return (NULL);
259 	}
260 	*cnt = n;
261 	return (kd->filebase);
262 }
263 
264 static struct kinfo_file *
265 kvm_deadfile_byid(kvm_t *kd, int op, int arg, size_t esize, int *cnt)
266 {
267 	size_t buflen;
268 	struct nlist nl[4], *np;
269 	int n = 0;
270 	char *where;
271 	struct kinfo_file kf;
272 	struct file *fp, file;
273 	struct filelist filehead;
274 	struct filedesc0 filed0;
275 #define filed	filed0.fd_fd
276 	struct processlist allprocess;
277 	struct proc proc;
278 	struct process *pr, process;
279 	struct ucred ucred;
280 	char *filebuf = NULL;
281 	int i, nfiles;
282 
283 	nl[0].n_name = "_filehead";
284 	nl[1].n_name = "_nfiles";
285 	nl[2].n_name = "_allprocess";
286 	nl[3].n_name = 0;
287 
288 	if (kvm_nlist(kd, nl) != 0) {
289 		for (np = nl; np->n_type != 0; ++np)
290 			;
291 		_kvm_err(kd, kd->program,
292 			 "%s: no such symbol", np->n_name);
293 		return (NULL);
294 	}
295 	if (KREAD(kd, nl[0].n_value, &filehead)) {
296 		_kvm_err(kd, kd->program, "can't read filehead");
297 		return (NULL);
298 	}
299 	if (KREAD(kd, nl[1].n_value, &nfiles)) {
300 		_kvm_err(kd, kd->program, "can't read nfiles");
301 		return (NULL);
302 	}
303 	if (KREAD(kd, nl[2].n_value, &allprocess)) {
304 		_kvm_err(kd, kd->program, "can't read allprocess");
305 		return (NULL);
306 	}
307 	/* this may be more room than we need but counting is expensive */
308 	where = _kvm_reallocarray(kd, kd->filebase, nfiles + 10, esize);
309 	if (where == NULL)
310 		return (NULL);
311 
312 	kd->filebase = (void *)where;
313 	buflen = (nfiles + 10) * esize;
314 
315 	for (pr = LIST_FIRST(&allprocess);
316 	    pr != NULL;
317 	    pr = LIST_NEXT(&process, ps_list)) {
318 		if (KREAD(kd, (u_long)pr, &process)) {
319 			_kvm_err(kd, kd->program, "can't read process at %lx",
320 			    (u_long)pr);
321 			goto cleanup;
322 		}
323 
324 		/* skip system, exiting, embryonic and undead processes */
325 		if (process.ps_flags & (PS_SYSTEM | PS_EMBRYO | PS_EXITING))
326 			continue;
327 
328 		if (process.ps_mainproc == NULL)
329 			continue;
330 		if (KREAD(kd, (u_long)process.ps_mainproc, &proc)) {
331 			_kvm_err(kd, kd->program, "can't read proc at %lx",
332 			    (u_long)process.ps_mainproc);
333 			goto cleanup;
334 		}
335 
336 		if (op == KERN_FILE_BYPID && arg > 0 &&
337 		    proc.p_pid != (pid_t)arg) {
338 				/* not the pid we are looking for */
339 				continue;
340 		}
341 
342 		if (KREAD(kd, (u_long)process.ps_ucred, &ucred)) {
343 			_kvm_err(kd, kd->program, "can't read ucred at %lx",
344 			    (u_long)process.ps_ucred);
345 			goto cleanup;
346 		}
347 		process.ps_mainproc = &proc;
348 		proc.p_p = &process;
349 		process.ps_ucred = &ucred;
350 
351 		if (op == KERN_FILE_BYUID && arg >= 0 &&
352 		    process.ps_ucred->cr_uid != (uid_t)arg) {
353 			/* not the uid we are looking for */
354 			continue;
355 		}
356 
357 		if (KREAD(kd, (u_long)process.ps_fd, &filed0)) {
358 			_kvm_err(kd, kd->program, "can't read filedesc at %lx",
359 			    (u_long)process.ps_fd);
360 			goto cleanup;
361 		}
362 		if ((char *)process.ps_fd + offsetof(struct filedesc0,fd_dfiles)
363 		    == (char *)filed.fd_ofiles) {
364 			filed.fd_ofiles = filed0.fd_dfiles;
365 			filed.fd_ofileflags = filed0.fd_dfileflags;
366 		} else {
367 			size_t fsize;
368 			char *tmp = reallocarray(filebuf,
369 			    filed.fd_nfiles, OFILESIZE);
370 
371 			fsize = filed.fd_nfiles * OFILESIZE;
372 			if (tmp == NULL) {
373 				_kvm_syserr(kd, kd->program, "realloc ofiles");
374 				goto cleanup;
375 			}
376 			filebuf = tmp;
377 			if (kvm_read(kd, (u_long)filed.fd_ofiles, filebuf,
378 			    fsize) != fsize) {
379 				_kvm_err(kd, kd->program,
380 				    "can't read fd_ofiles");
381 				goto cleanup;
382 			}
383 			filed.fd_ofiles = (void *)filebuf;
384 			filed.fd_ofileflags = filebuf +
385 			    (filed.fd_nfiles * sizeof(struct file *));
386 		}
387 		process.ps_fd = &filed;
388 
389 		if (process.ps_textvp) {
390 			if (buflen < esize)
391 				goto done;
392 			if (fill_file(kd, &kf, NULL, 0, process.ps_textvp,
393 			    &process, KERN_FILE_TEXT, proc.p_pid) == -1)
394 				goto cleanup;
395 			memcpy(where, &kf, esize);
396 			where += esize;
397 			buflen -= esize;
398 			n++;
399 		}
400 		if (filed.fd_cdir) {
401 			if (buflen < esize)
402 				goto done;
403 			if (fill_file(kd, &kf, NULL, 0, filed.fd_cdir,
404 			    &process, KERN_FILE_CDIR, proc.p_pid) == -1)
405 				goto cleanup;
406 			memcpy(where, &kf, esize);
407 			where += esize;
408 			buflen -= esize;
409 			n++;
410 		}
411 		if (filed.fd_rdir) {
412 			if (buflen < esize)
413 				goto done;
414 			if (fill_file(kd, &kf, NULL, 0, filed.fd_rdir,
415 			    &process, KERN_FILE_RDIR, proc.p_pid) == -1)
416 				goto cleanup;
417 			memcpy(where, &kf, esize);
418 			where += esize;
419 			buflen -= esize;
420 			n++;
421 		}
422 		if (process.ps_tracevp) {
423 			if (buflen < esize)
424 				goto done;
425 			if (fill_file(kd, &kf, NULL, 0, process.ps_tracevp,
426 			    &process, KERN_FILE_TRACE, proc.p_pid) == -1)
427 				goto cleanup;
428 			memcpy(where, &kf, esize);
429 			where += esize;
430 			buflen -= esize;
431 			n++;
432 		}
433 
434 		if (filed.fd_nfiles < 0 ||
435 		    filed.fd_lastfile >= filed.fd_nfiles ||
436 		    filed.fd_freefile > filed.fd_lastfile + 1) {
437 			_kvm_err(kd, kd->program,
438 			    "filedesc corrupted at %lx for pid %d",
439 			    (u_long)process.ps_fd, proc.p_pid);
440 			goto cleanup;
441 		}
442 
443 		for (i = 0; i < filed.fd_nfiles; i++) {
444 			if (buflen < esize)
445 				goto done;
446 			if ((fp = filed.fd_ofiles[i]) == NULL)
447 				continue;
448 			if (KREAD(kd, (u_long)fp, &file)) {
449 				_kvm_err(kd, kd->program, "can't read file");
450 				goto cleanup;
451 			}
452 			if (fill_file(kd, &kf, &file, (u_long)fp, NULL,
453 			    &process, i, proc.p_pid) == -1)
454 				goto cleanup;
455 			memcpy(where, &kf, esize);
456 			where += esize;
457 			buflen -= esize;
458 			n++;
459 		}
460 	}
461 done:
462 	*cnt = n;
463 	free(filebuf);
464 	return (kd->filebase);
465 cleanup:
466 	free(filebuf);
467 	return (NULL);
468 }
469 
470 static int
471 fill_file(kvm_t *kd, struct kinfo_file *kf, struct file *fp, u_long fpaddr,
472     struct vnode *vp, struct process *pr, int fd, pid_t pid)
473 {
474 	struct ucred f_cred;
475 
476 	memset(kf, 0, sizeof(*kf));
477 
478 	kf->fd_fd = fd;		/* might not really be an fd */
479 
480 	if (fp != NULL) {
481 		/* Fill in f_cred */
482 		if (KREAD(kd, (u_long)fp->f_cred, &f_cred)) {
483 			_kvm_err(kd, kd->program, "can't read f_cred");
484 			return (-1);
485 		}
486 
487 		kf->f_fileaddr = PTRTOINT64(fpaddr);
488 		kf->f_flag = fp->f_flag;
489 		kf->f_iflags = fp->f_iflags;
490 		kf->f_type = fp->f_type;
491 		kf->f_count = fp->f_count;
492 		kf->f_ucred = PTRTOINT64(fp->f_cred);
493 		kf->f_uid = f_cred.cr_uid;
494 		kf->f_gid = f_cred.cr_gid;
495 		kf->f_ops = PTRTOINT64(fp->f_ops);
496 		kf->f_offset = fp->f_offset;
497 		kf->f_data = PTRTOINT64(fp->f_data);
498 		kf->f_usecount = 0;
499 
500 		kf->f_rxfer = fp->f_rxfer;
501 		kf->f_rwfer = fp->f_wxfer;
502 		kf->f_seek = fp->f_seek;
503 		kf->f_rbytes = fp->f_rbytes;
504 		kf->f_wbytes = fp->f_wbytes;
505 	} else if (vp != NULL) {
506 		/* fake it */
507 		kf->f_type = DTYPE_VNODE;
508 		kf->f_flag = FREAD;
509 		if (fd == KERN_FILE_TRACE)
510 			kf->f_flag |= FWRITE;
511 		kf->f_data = PTRTOINT64(vp);
512 	}
513 
514 	/* information about the object associated with this file */
515 	switch (kf->f_type) {
516 	case DTYPE_VNODE: {
517 		struct vnode vbuf;
518 
519 		if (KREAD(kd, (u_long)(fp ? fp->f_data : vp), &vbuf)) {
520 			_kvm_err(kd, kd->program, "can't read vnode");
521 			return (-1);
522 		}
523 		vp = &vbuf;
524 
525 		kf->v_un = PTRTOINT64(vp->v_un.vu_socket);
526 		kf->v_type = vp->v_type;
527 		kf->v_tag = vp->v_tag;
528 		kf->v_flag = vp->v_flag;
529 		kf->v_data = PTRTOINT64(vp->v_data);
530 		kf->v_mount = PTRTOINT64(vp->v_mount);
531 
532 		if (vp->v_mount != NULL) {
533 			struct mount mount;
534 
535 			if (KREAD(kd, (u_long)vp->v_mount, &mount)) {
536 				_kvm_err(kd, kd->program, "can't read v_mount");
537 				return (-1);
538 			}
539 
540 			strlcpy(kf->f_mntonname, mount.mnt_stat.f_mntonname,
541 			    sizeof(kf->f_mntonname));
542 		}
543 
544 		/* Fill in va_fsid, va_fileid, va_mode, va_size, va_rdev */
545 		filestat(kd, kf, vp);
546 		break;
547 	    }
548 
549 	case DTYPE_SOCKET: {
550 		struct socket sock;
551 		struct sosplice ssp;
552 		struct protosw protosw;
553 		struct domain domain;
554 
555 		if (KREAD(kd, (u_long)fp->f_data, &sock)) {
556 			_kvm_err(kd, kd->program, "can't read socket");
557 			return (-1);
558 		}
559 
560 		kf->so_type = sock.so_type;
561 		kf->so_state = sock.so_state;
562 		kf->so_pcb = PTRTOINT64(sock.so_pcb);
563 		if (KREAD(kd, (u_long)sock.so_proto, &protosw)) {
564 			_kvm_err(kd, kd->program, "can't read protosw");
565 			return (-1);
566 		}
567 		kf->so_protocol = protosw.pr_protocol;
568 		if (KREAD(kd, (u_long)protosw.pr_domain, &domain)) {
569 			_kvm_err(kd, kd->program, "can't read domain");
570 			return (-1);
571 		}
572 		kf->so_family = domain.dom_family;
573 		kf->so_rcv_cc = sock.so_rcv.sb_cc;
574 		kf->so_snd_cc = sock.so_snd.sb_cc;
575 		if (sock.so_sp) {
576 			if (KREAD(kd, (u_long)sock.so_sp, &ssp)) {
577 				_kvm_err(kd, kd->program, "can't read splice");
578 				return (-1);
579 			}
580 			if (ssp.ssp_socket) {
581 				kf->so_splice = PTRTOINT64(ssp.ssp_socket);
582 				kf->so_splicelen = ssp.ssp_len;
583 			} else if (ssp.ssp_soback) {
584 				kf->so_splicelen = -1;
585 			}
586 		}
587 		if (!sock.so_pcb)
588 			break;
589 		switch (kf->so_family) {
590 		case AF_INET: {
591 			struct inpcb inpcb;
592 
593 			if (KREAD(kd, (u_long)sock.so_pcb, &inpcb)) {
594 				_kvm_err(kd, kd->program, "can't read inpcb");
595 				return (-1);
596 			}
597 			kf->inp_ppcb = PTRTOINT64(inpcb.inp_ppcb);
598 			kf->inp_lport = inpcb.inp_lport;
599 			kf->inp_laddru[0] = inpcb.inp_laddr.s_addr;
600 			kf->inp_fport = inpcb.inp_fport;
601 			kf->inp_faddru[0] = inpcb.inp_faddr.s_addr;
602 			kf->inp_rtableid = inpcb.inp_rtableid;
603 			if (sock.so_type == SOCK_RAW)
604 				kf->inp_proto = inpcb.inp_ip.ip_p;
605 			if (protosw.pr_protocol == IPPROTO_TCP) {
606 				struct tcpcb tcpcb;
607 				if (KREAD(kd, (u_long)inpcb.inp_ppcb, &tcpcb)) {
608 					_kvm_err(kd, kd->program,
609 					    "can't read tcpcb");
610 					return (-1);
611 				}
612 				kf->t_rcv_wnd = tcpcb.rcv_wnd;
613 				kf->t_snd_wnd = tcpcb.snd_wnd;
614 				kf->t_snd_cwnd = tcpcb.snd_cwnd;
615 				kf->t_state = tcpcb.t_state;
616 			}
617 			break;
618 		    }
619 		case AF_INET6: {
620 			struct inpcb inpcb;
621 #define s6_addr32 __u6_addr.__u6_addr32
622 
623 			if (KREAD(kd, (u_long)sock.so_pcb, &inpcb)) {
624 				_kvm_err(kd, kd->program, "can't read inpcb");
625 				return (-1);
626 			}
627 			kf->inp_ppcb = PTRTOINT64(inpcb.inp_ppcb);
628 			kf->inp_lport = inpcb.inp_lport;
629 			kf->inp_laddru[0] = inpcb.inp_laddr6.s6_addr32[0];
630 			kf->inp_laddru[1] = inpcb.inp_laddr6.s6_addr32[1];
631 			kf->inp_laddru[2] = inpcb.inp_laddr6.s6_addr32[2];
632 			kf->inp_laddru[3] = inpcb.inp_laddr6.s6_addr32[3];
633 			kf->inp_fport = inpcb.inp_fport;
634 			kf->inp_faddru[0] = inpcb.inp_laddr6.s6_addr32[0];
635 			kf->inp_faddru[1] = inpcb.inp_faddr6.s6_addr32[1];
636 			kf->inp_faddru[2] = inpcb.inp_faddr6.s6_addr32[2];
637 			kf->inp_faddru[3] = inpcb.inp_faddr6.s6_addr32[3];
638 			kf->inp_rtableid = inpcb.inp_rtableid;
639 			if (sock.so_type == SOCK_RAW)
640 				kf->inp_proto = inpcb.inp_ipv6.ip6_nxt;
641 			if (protosw.pr_protocol == IPPROTO_TCP) {
642 				struct tcpcb tcpcb;
643 				if (KREAD(kd, (u_long)inpcb.inp_ppcb, &tcpcb)) {
644 					_kvm_err(kd, kd->program,
645 					    "can't read tcpcb");
646 					return (-1);
647 				}
648 				kf->t_rcv_wnd = tcpcb.rcv_wnd;
649 				kf->t_snd_wnd = tcpcb.snd_wnd;
650 				kf->t_snd_cwnd = tcpcb.snd_cwnd;
651 				kf->t_state = tcpcb.t_state;
652 			}
653 			break;
654 		    }
655 		case AF_UNIX: {
656 			struct unpcb unpcb;
657 
658 			if (KREAD(kd, (u_long)sock.so_pcb, &unpcb)) {
659 				_kvm_err(kd, kd->program, "can't read unpcb");
660 				return (-1);
661 			}
662 			kf->f_msgcount	= unpcb.unp_msgcount;
663 			kf->unp_conn	= PTRTOINT64(unpcb.unp_conn);
664 			kf->unp_refs	= PTRTOINT64(
665 			    SLIST_FIRST(&unpcb.unp_refs));
666 			kf->unp_nextref	= PTRTOINT64(
667 			    SLIST_NEXT(&unpcb, unp_nextref));
668 			kf->v_un	= PTRTOINT64(unpcb.unp_vnode);
669 			if (unpcb.unp_addr != NULL) {
670 				struct mbuf mb;
671 				struct sockaddr_un un;
672 
673 				if (KREAD(kd, (u_long)unpcb.unp_addr, &mb)) {
674 					_kvm_err(kd, kd->program,
675 					    "can't read sockaddr_un mbuf");
676 					return (-1);
677 				}
678 				if (KREAD(kd, (u_long)mb.m_data, &un)) {
679 					_kvm_err(kd, kd->program,
680 					    "can't read sockaddr_un");
681 					return (-1);
682 				}
683 
684 				kf->unp_addr = PTRTOINT64(unpcb.unp_addr);
685 				memcpy(kf->unp_path, un.sun_path, un.sun_len
686 				    - offsetof(struct sockaddr_un,sun_path));
687 			}
688 
689 			break;
690 		    }
691 		}
692 		break;
693 	    }
694 
695 	case DTYPE_PIPE: {
696 		struct pipe pipe;
697 
698 		if (KREAD(kd, (u_long)fp->f_data, &pipe)) {
699 			_kvm_err(kd, kd->program, "can't read pipe");
700 			return (-1);
701 		}
702 		kf->pipe_peer = PTRTOINT64(pipe.pipe_peer);
703 		kf->pipe_state = pipe.pipe_state;
704 		break;
705 	    }
706 
707 	case DTYPE_KQUEUE: {
708 		struct kqueue kqi;
709 
710 		if (KREAD(kd, (u_long)fp->f_data, &kqi)) {
711 			_kvm_err(kd, kd->program, "can't read kqi");
712 			return (-1);
713 		}
714 		kf->kq_count = kqi.kq_count;
715 		kf->kq_state = kqi.kq_state;
716 		break;
717 	    }
718 	case DTYPE_SYSTRACE: {
719 		struct fsystrace f;
720 
721 		if (KREAD(kd, (u_long)fp->f_data, &f)) {
722 			_kvm_err(kd, kd->program, "can't read fsystrace");
723 			return (-1);
724 		}
725 		kf->str_npolicies = f.npolicies;
726 		break;
727 	    }
728 	}
729 
730 	/* per-process information for KERN_FILE_BY[PU]ID */
731 	if (pr != NULL) {
732 		kf->p_pid = pid;
733 		kf->p_uid = pr->ps_ucred->cr_uid;
734 		kf->p_gid = pr->ps_ucred->cr_gid;
735 		kf->p_tid = -1;
736 		strlcpy(kf->p_comm, pr->ps_mainproc->p_comm,
737 		    sizeof(kf->p_comm));
738 		if (pr->ps_fd != NULL)
739 			kf->fd_ofileflags = pr->ps_fd->fd_ofileflags[fd];
740 	}
741 
742 	return (0);
743 }
744 
745 mode_t
746 _kvm_getftype(enum vtype v_type)
747 {
748 	mode_t ftype = 0;
749 
750 	switch (v_type) {
751 	case VREG:
752 		ftype = S_IFREG;
753 		break;
754 	case VDIR:
755 		ftype = S_IFDIR;
756 		break;
757 	case VBLK:
758 		ftype = S_IFBLK;
759 		break;
760 	case VCHR:
761 		ftype = S_IFCHR;
762 		break;
763 	case VLNK:
764 		ftype = S_IFLNK;
765 		break;
766 	case VSOCK:
767 		ftype = S_IFSOCK;
768 		break;
769 	case VFIFO:
770 		ftype = S_IFIFO;
771 		break;
772 	case VNON:
773 	case VBAD:
774 		break;
775 	}
776 
777 	return (ftype);
778 }
779 
780 static int
781 ufs_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
782 {
783 	struct inode inode;
784 	struct ufs1_dinode di1;
785 
786 	if (KREAD(kd, (u_long)VTOI(vp), &inode)) {
787 		_kvm_err(kd, kd->program, "can't read inode at %p", VTOI(vp));
788 		return (-1);
789 	}
790 
791 	if (KREAD(kd, (u_long)inode.i_din1, &di1)) {
792 		_kvm_err(kd, kd->program, "can't read dinode at %p",
793 		    inode.i_din1);
794 		return (-1);
795 	}
796 
797 	inode.i_din1 = &di1;
798 
799 	kf->va_fsid = inode.i_dev & 0xffff;
800 	kf->va_fileid = (long)inode.i_number;
801 	kf->va_mode = inode.i_ffs1_mode;
802 	kf->va_size = inode.i_ffs1_size;
803 	kf->va_rdev = inode.i_ffs1_rdev;
804 
805 	return (0);
806 }
807 
808 static int
809 ext2fs_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
810 {
811 	struct inode inode;
812 	struct ext2fs_dinode e2di;
813 
814 	if (KREAD(kd, (u_long)VTOI(vp), &inode)) {
815 		_kvm_err(kd, kd->program, "can't read inode at %p", VTOI(vp));
816 		return (-1);
817 	}
818 
819 	if (KREAD(kd, (u_long)inode.i_e2din, &e2di)) {
820 		_kvm_err(kd, kd->program, "can't read dinode at %p",
821 		    inode.i_e2din);
822 		return (-1);
823 	}
824 
825 	inode.i_e2din = &e2di;
826 
827 	kf->va_fsid = inode.i_dev & 0xffff;
828 	kf->va_fileid = (long)inode.i_number;
829 	kf->va_mode = inode.i_e2fs_mode;
830 	kf->va_size = inode.i_e2fs_size;
831 	kf->va_rdev = 0;	/* XXX */
832 
833 	return (0);
834 }
835 
836 static int
837 msdos_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
838 {
839 	struct denode de;
840 	struct msdosfsmount mp;
841 
842 	if (KREAD(kd, (u_long)VTODE(vp), &de)) {
843 		_kvm_err(kd, kd->program, "can't read denode at %p", VTODE(vp));
844 		return (-1);
845 	}
846 	if (KREAD(kd, (u_long)de.de_pmp, &mp)) {
847 		_kvm_err(kd, kd->program, "can't read mount struct at %p",
848 		    de.de_pmp);
849 		return (-1);
850 	}
851 
852 	kf->va_fsid = de.de_dev & 0xffff;
853 	kf->va_fileid = 0; /* XXX see msdosfs_vptofh() for more info */
854 	kf->va_mode = (mp.pm_mask & 0777) | _kvm_getftype(vp->v_type);
855 	kf->va_size = de.de_FileSize;
856 	kf->va_rdev = 0;  /* msdosfs doesn't support device files */
857 
858 	return (0);
859 }
860 
861 static int
862 nfs_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
863 {
864 	struct nfsnode nfsnode;
865 
866 	if (KREAD(kd, (u_long)VTONFS(vp), &nfsnode)) {
867 		_kvm_err(kd, kd->program, "can't read nfsnode at %p",
868 		    VTONFS(vp));
869 		return (-1);
870 	}
871 	kf->va_fsid = nfsnode.n_vattr.va_fsid;
872 	kf->va_fileid = nfsnode.n_vattr.va_fileid;
873 	kf->va_size = nfsnode.n_size;
874 	kf->va_rdev = nfsnode.n_vattr.va_rdev;
875 	kf->va_mode = (mode_t)nfsnode.n_vattr.va_mode | _kvm_getftype(vp->v_type);
876 
877 	return (0);
878 }
879 
880 static int
881 spec_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
882 {
883 	struct specinfo		specinfo;
884 	struct vnode		parent;
885 
886 	if (KREAD(kd, (u_long)vp->v_specinfo, &specinfo)) {
887 		_kvm_err(kd, kd->program, "can't read specinfo at %p",
888 		     vp->v_specinfo);
889 		return (-1);
890 	}
891 
892 	vp->v_specinfo = &specinfo;
893 
894 	if (KREAD(kd, (u_long)vp->v_specparent, &parent)) {
895 		_kvm_err(kd, kd->program, "can't read parent vnode at %p",
896 		     vp->v_specparent);
897 		return (-1);
898 	}
899 
900 	if (ufs_filestat(kd, kf, vp))
901 		return (-1);
902 
903 	return (0);
904 }
905 
906 static int
907 filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
908 {
909 	int ret = 0;
910 
911 	if (vp->v_type != VNON && vp->v_type != VBAD) {
912 		switch (vp->v_tag) {
913 		case VT_UFS:
914 		case VT_MFS:
915 			ret = ufs_filestat(kd, kf, vp);
916 			break;
917 		case VT_NFS:
918 			ret = nfs_filestat(kd, kf, vp);
919 			break;
920 		case VT_EXT2FS:
921 			ret = ext2fs_filestat(kd, kf, vp);
922 			break;
923 		case VT_ISOFS:
924 			ret = _kvm_stat_cd9660(kd, kf, vp);
925 			break;
926 		case VT_MSDOSFS:
927 			ret = msdos_filestat(kd, kf, vp);
928 			break;
929 		case VT_UDF:
930 			ret = _kvm_stat_udf(kd, kf, vp);
931 			break;
932 		case VT_NTFS:
933 			ret = _kvm_stat_ntfs(kd, kf, vp);
934 			break;
935 		case VT_NON:
936 			if (vp->v_flag & VCLONE)
937 				ret = spec_filestat(kd, kf, vp);
938 			break;
939 		default:
940 			ret = -1;
941 			break;
942 		}
943 	}
944 	return (ret);
945 }
946