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