GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libkvm/kvm_file2.c Lines: 23 493 4.7 %
Date: 2017-11-07 Branches: 5 272 1.8 %

Line Branch Exec Source
1
/*	$OpenBSD: kvm_file2.c,v 1.52 2017/01/21 05:42:04 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
#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
156
	int mib[6], rv;
135
	void *filebase;
136
78
	size_t size;
137
138
78
	if (ISALIVE(kd)) {
139
78
		mib[0] = CTL_KERN;
140
78
		mib[1] = KERN_FILE;
141
78
		mib[2] = op;
142
78
		mib[3] = arg;
143
78
		mib[4] = esize;
144
145
78
		do {
146
78
			mib[5] = 0;
147
148
			/* find size and alloc buffer */
149
78
			rv = sysctl(mib, 6, NULL, &size, NULL, 0);
150
78
			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
78
			size += size / 8; /* add ~10% */
158
159
78
			filebase = _kvm_realloc(kd, kd->filebase, size);
160
78
			if (filebase == NULL)
161
				return (NULL);
162
163
78
			kd->filebase = filebase;
164
165
			/* get actual data */
166
78
			mib[5] = size / esize;
167
78
			rv = sysctl(mib, 6, kd->filebase, &size, NULL, 0);
168

78
			if (rv == -1 && errno != ENOMEM) {
169
				_kvm_syserr(kd, kd->program,
170
				    "kvm_getfiles");
171
				return (NULL);
172
			}
173
78
		} while (rv == -1);
174
175
78
		*cnt = size / esize;
176
78
		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
78
}
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 process *pr, process;
277
	struct ucred ucred;
278
	char *filebuf = NULL;
279
	int i, nfiles;
280
281
	nl[0].n_name = "_filehead";
282
	nl[1].n_name = "_nfiles";
283
	nl[2].n_name = "_allprocess";
284
	nl[3].n_name = 0;
285
286
	if (kvm_nlist(kd, nl) != 0) {
287
		for (np = nl; np->n_type != 0; ++np)
288
			;
289
		_kvm_err(kd, kd->program,
290
			 "%s: no such symbol", np->n_name);
291
		return (NULL);
292
	}
293
	if (KREAD(kd, nl[0].n_value, &filehead)) {
294
		_kvm_err(kd, kd->program, "can't read filehead");
295
		return (NULL);
296
	}
297
	if (KREAD(kd, nl[1].n_value, &nfiles)) {
298
		_kvm_err(kd, kd->program, "can't read nfiles");
299
		return (NULL);
300
	}
301
	if (KREAD(kd, nl[2].n_value, &allprocess)) {
302
		_kvm_err(kd, kd->program, "can't read allprocess");
303
		return (NULL);
304
	}
305
	/* this may be more room than we need but counting is expensive */
306
	where = _kvm_reallocarray(kd, kd->filebase, nfiles + 10, esize);
307
	if (where == NULL)
308
		return (NULL);
309
310
	kd->filebase = (void *)where;
311
	buflen = (nfiles + 10) * esize;
312
313
	if (op != KERN_FILE_BYPID || arg <= 0)
314
		matched = 1;
315
316
	for (pr = LIST_FIRST(&allprocess);
317
	    pr != NULL;
318
	    pr = LIST_NEXT(&process, ps_list)) {
319
		if (KREAD(kd, (u_long)pr, &process)) {
320
			_kvm_err(kd, kd->program, "can't read process at %lx",
321
			    (u_long)pr);
322
			goto cleanup;
323
		}
324
325
		/* skip system, exiting, embryonic and undead processes */
326
		if (process.ps_flags & (PS_SYSTEM | PS_EMBRYO | PS_EXITING))
327
			continue;
328
329
		if (op == KERN_FILE_BYPID) {
330
			/* check if this is the pid we are looking for */
331
			if (arg > 0 && process.ps_pid != (pid_t)arg)
332
				continue;
333
			matched = 1;
334
		}
335
336
		if (KREAD(kd, (u_long)process.ps_ucred, &ucred)) {
337
			_kvm_err(kd, kd->program, "can't read ucred at %lx",
338
			    (u_long)process.ps_ucred);
339
			goto cleanup;
340
		}
341
		process.ps_ucred = &ucred;
342
343
		if (op == KERN_FILE_BYUID && arg >= 0 &&
344
		    process.ps_ucred->cr_uid != (uid_t)arg) {
345
			/* not the uid we are looking for */
346
			continue;
347
		}
348
349
		if (KREAD(kd, (u_long)process.ps_fd, &filed0)) {
350
			_kvm_err(kd, kd->program, "can't read filedesc at %lx",
351
			    (u_long)process.ps_fd);
352
			goto cleanup;
353
		}
354
		if ((char *)process.ps_fd + offsetof(struct filedesc0,fd_dfiles)
355
		    == (char *)filed.fd_ofiles) {
356
			filed.fd_ofiles = filed0.fd_dfiles;
357
			filed.fd_ofileflags = filed0.fd_dfileflags;
358
		} else {
359
			size_t fsize;
360
			char *tmp = reallocarray(filebuf,
361
			    filed.fd_nfiles, OFILESIZE);
362
363
			fsize = filed.fd_nfiles * OFILESIZE;
364
			if (tmp == NULL) {
365
				_kvm_syserr(kd, kd->program, "realloc ofiles");
366
				goto cleanup;
367
			}
368
			filebuf = tmp;
369
			if (kvm_read(kd, (u_long)filed.fd_ofiles, filebuf,
370
			    fsize) != fsize) {
371
				_kvm_err(kd, kd->program,
372
				    "can't read fd_ofiles");
373
				goto cleanup;
374
			}
375
			filed.fd_ofiles = (void *)filebuf;
376
			filed.fd_ofileflags = filebuf +
377
			    (filed.fd_nfiles * sizeof(struct file *));
378
		}
379
		process.ps_fd = &filed;
380
381
		if (process.ps_textvp) {
382
			if (buflen < esize)
383
				goto done;
384
			if (fill_file(kd, &kf, NULL, 0, process.ps_textvp,
385
			    &process, KERN_FILE_TEXT, process.ps_pid) == -1)
386
				goto cleanup;
387
			memcpy(where, &kf, esize);
388
			where += esize;
389
			buflen -= esize;
390
			n++;
391
		}
392
		if (filed.fd_cdir) {
393
			if (buflen < esize)
394
				goto done;
395
			if (fill_file(kd, &kf, NULL, 0, filed.fd_cdir,
396
			    &process, KERN_FILE_CDIR, process.ps_pid) == -1)
397
				goto cleanup;
398
			memcpy(where, &kf, esize);
399
			where += esize;
400
			buflen -= esize;
401
			n++;
402
		}
403
		if (filed.fd_rdir) {
404
			if (buflen < esize)
405
				goto done;
406
			if (fill_file(kd, &kf, NULL, 0, filed.fd_rdir,
407
			    &process, KERN_FILE_RDIR, process.ps_pid) == -1)
408
				goto cleanup;
409
			memcpy(where, &kf, esize);
410
			where += esize;
411
			buflen -= esize;
412
			n++;
413
		}
414
		if (process.ps_tracevp) {
415
			if (buflen < esize)
416
				goto done;
417
			if (fill_file(kd, &kf, NULL, 0, process.ps_tracevp,
418
			    &process, KERN_FILE_TRACE, process.ps_pid) == -1)
419
				goto cleanup;
420
			memcpy(where, &kf, esize);
421
			where += esize;
422
			buflen -= esize;
423
			n++;
424
		}
425
426
		if (filed.fd_nfiles < 0 ||
427
		    filed.fd_lastfile >= filed.fd_nfiles ||
428
		    filed.fd_freefile > filed.fd_lastfile + 1) {
429
			_kvm_err(kd, kd->program,
430
			    "filedesc corrupted at %lx for pid %d",
431
			    (u_long)process.ps_fd, process.ps_pid);
432
			goto cleanup;
433
		}
434
435
		for (i = 0; i < filed.fd_nfiles; i++) {
436
			if (buflen < esize)
437
				goto done;
438
			if ((fp = filed.fd_ofiles[i]) == NULL)
439
				continue;
440
			if (KREAD(kd, (u_long)fp, &file)) {
441
				_kvm_err(kd, kd->program, "can't read file");
442
				goto cleanup;
443
			}
444
			if (fill_file(kd, &kf, &file, (u_long)fp, NULL,
445
			    &process, i, process.ps_pid) == -1)
446
				goto cleanup;
447
			memcpy(where, &kf, esize);
448
			where += esize;
449
			buflen -= esize;
450
			n++;
451
		}
452
	}
453
	if (!matched) {
454
		errno = ESRCH;
455
		goto cleanup;
456
	}
457
done:
458
	*cnt = n;
459
	free(filebuf);
460
	return (kd->filebase);
461
cleanup:
462
	free(filebuf);
463
	return (NULL);
464
}
465
466
static int
467
fill_file(kvm_t *kd, struct kinfo_file *kf, struct file *fp, u_long fpaddr,
468
    struct vnode *vp, struct process *pr, int fd, pid_t pid)
469
{
470
	struct ucred f_cred;
471
472
	memset(kf, 0, sizeof(*kf));
473
474
	kf->fd_fd = fd;		/* might not really be an fd */
475
476
	if (fp != NULL) {
477
		/* Fill in f_cred */
478
		if (KREAD(kd, (u_long)fp->f_cred, &f_cred)) {
479
			_kvm_err(kd, kd->program, "can't read f_cred");
480
			return (-1);
481
		}
482
483
		kf->f_fileaddr = PTRTOINT64(fpaddr);
484
		kf->f_flag = fp->f_flag;
485
		kf->f_iflags = fp->f_iflags;
486
		kf->f_type = fp->f_type;
487
		kf->f_count = fp->f_count;
488
		kf->f_ucred = PTRTOINT64(fp->f_cred);
489
		kf->f_uid = f_cred.cr_uid;
490
		kf->f_gid = f_cred.cr_gid;
491
		kf->f_ops = PTRTOINT64(fp->f_ops);
492
		kf->f_offset = fp->f_offset;
493
		kf->f_data = PTRTOINT64(fp->f_data);
494
		kf->f_usecount = 0;
495
496
		kf->f_rxfer = fp->f_rxfer;
497
		kf->f_rwfer = fp->f_wxfer;
498
		kf->f_seek = fp->f_seek;
499
		kf->f_rbytes = fp->f_rbytes;
500
		kf->f_wbytes = fp->f_wbytes;
501
	} else if (vp != NULL) {
502
		/* fake it */
503
		kf->f_type = DTYPE_VNODE;
504
		kf->f_flag = FREAD;
505
		if (fd == KERN_FILE_TRACE)
506
			kf->f_flag |= FWRITE;
507
		kf->f_data = PTRTOINT64(vp);
508
	}
509
510
	/* information about the object associated with this file */
511
	switch (kf->f_type) {
512
	case DTYPE_VNODE: {
513
		struct vnode vbuf;
514
515
		if (KREAD(kd, (u_long)(fp ? fp->f_data : vp), &vbuf)) {
516
			_kvm_err(kd, kd->program, "can't read vnode");
517
			return (-1);
518
		}
519
		vp = &vbuf;
520
521
		kf->v_un = PTRTOINT64(vp->v_un.vu_socket);
522
		kf->v_type = vp->v_type;
523
		kf->v_tag = vp->v_tag;
524
		kf->v_flag = vp->v_flag;
525
		kf->v_data = PTRTOINT64(vp->v_data);
526
		kf->v_mount = PTRTOINT64(vp->v_mount);
527
528
		if (vp->v_mount != NULL) {
529
			struct mount mount;
530
531
			if (KREAD(kd, (u_long)vp->v_mount, &mount)) {
532
				_kvm_err(kd, kd->program, "can't read v_mount");
533
				return (-1);
534
			}
535
536
			strlcpy(kf->f_mntonname, mount.mnt_stat.f_mntonname,
537
			    sizeof(kf->f_mntonname));
538
		}
539
540
		/* Fill in va_fsid, va_fileid, va_mode, va_size, va_rdev */
541
		filestat(kd, kf, vp);
542
		break;
543
	    }
544
545
	case DTYPE_SOCKET: {
546
		struct socket sock;
547
		struct sosplice ssp;
548
		struct protosw protosw;
549
		struct domain domain;
550
551
		if (KREAD(kd, (u_long)fp->f_data, &sock)) {
552
			_kvm_err(kd, kd->program, "can't read socket");
553
			return (-1);
554
		}
555
556
		kf->so_type = sock.so_type;
557
		kf->so_state = sock.so_state;
558
		kf->so_pcb = PTRTOINT64(sock.so_pcb);
559
		if (KREAD(kd, (u_long)sock.so_proto, &protosw)) {
560
			_kvm_err(kd, kd->program, "can't read protosw");
561
			return (-1);
562
		}
563
		kf->so_protocol = protosw.pr_protocol;
564
		if (KREAD(kd, (u_long)protosw.pr_domain, &domain)) {
565
			_kvm_err(kd, kd->program, "can't read domain");
566
			return (-1);
567
		}
568
		kf->so_family = domain.dom_family;
569
		kf->so_rcv_cc = sock.so_rcv.sb_cc;
570
		kf->so_snd_cc = sock.so_snd.sb_cc;
571
		if (sock.so_sp) {
572
			if (KREAD(kd, (u_long)sock.so_sp, &ssp)) {
573
				_kvm_err(kd, kd->program, "can't read splice");
574
				return (-1);
575
			}
576
			if (ssp.ssp_socket) {
577
				kf->so_splice = PTRTOINT64(ssp.ssp_socket);
578
				kf->so_splicelen = ssp.ssp_len;
579
			} else if (ssp.ssp_soback) {
580
				kf->so_splicelen = -1;
581
			}
582
		}
583
		if (!sock.so_pcb)
584
			break;
585
		switch (kf->so_family) {
586
		case AF_INET: {
587
			struct inpcb inpcb;
588
589
			if (KREAD(kd, (u_long)sock.so_pcb, &inpcb)) {
590
				_kvm_err(kd, kd->program, "can't read inpcb");
591
				return (-1);
592
			}
593
			kf->inp_ppcb = PTRTOINT64(inpcb.inp_ppcb);
594
			kf->inp_lport = inpcb.inp_lport;
595
			kf->inp_laddru[0] = inpcb.inp_laddr.s_addr;
596
			kf->inp_fport = inpcb.inp_fport;
597
			kf->inp_faddru[0] = inpcb.inp_faddr.s_addr;
598
			kf->inp_rtableid = inpcb.inp_rtableid;
599
			if (sock.so_type == SOCK_RAW)
600
				kf->inp_proto = inpcb.inp_ip.ip_p;
601
			if (protosw.pr_protocol == IPPROTO_TCP) {
602
				struct tcpcb tcpcb;
603
				if (KREAD(kd, (u_long)inpcb.inp_ppcb, &tcpcb)) {
604
					_kvm_err(kd, kd->program,
605
					    "can't read tcpcb");
606
					return (-1);
607
				}
608
				kf->t_rcv_wnd = tcpcb.rcv_wnd;
609
				kf->t_snd_wnd = tcpcb.snd_wnd;
610
				kf->t_snd_cwnd = tcpcb.snd_cwnd;
611
				kf->t_state = tcpcb.t_state;
612
			}
613
			break;
614
		    }
615
		case AF_INET6: {
616
			struct inpcb inpcb;
617
#define s6_addr32 __u6_addr.__u6_addr32
618
619
			if (KREAD(kd, (u_long)sock.so_pcb, &inpcb)) {
620
				_kvm_err(kd, kd->program, "can't read inpcb");
621
				return (-1);
622
			}
623
			kf->inp_ppcb = PTRTOINT64(inpcb.inp_ppcb);
624
			kf->inp_lport = inpcb.inp_lport;
625
			kf->inp_laddru[0] = inpcb.inp_laddr6.s6_addr32[0];
626
			kf->inp_laddru[1] = inpcb.inp_laddr6.s6_addr32[1];
627
			kf->inp_laddru[2] = inpcb.inp_laddr6.s6_addr32[2];
628
			kf->inp_laddru[3] = inpcb.inp_laddr6.s6_addr32[3];
629
			kf->inp_fport = inpcb.inp_fport;
630
			kf->inp_faddru[0] = inpcb.inp_laddr6.s6_addr32[0];
631
			kf->inp_faddru[1] = inpcb.inp_faddr6.s6_addr32[1];
632
			kf->inp_faddru[2] = inpcb.inp_faddr6.s6_addr32[2];
633
			kf->inp_faddru[3] = inpcb.inp_faddr6.s6_addr32[3];
634
			kf->inp_rtableid = inpcb.inp_rtableid;
635
			if (sock.so_type == SOCK_RAW)
636
				kf->inp_proto = inpcb.inp_ipv6.ip6_nxt;
637
			if (protosw.pr_protocol == IPPROTO_TCP) {
638
				struct tcpcb tcpcb;
639
				if (KREAD(kd, (u_long)inpcb.inp_ppcb, &tcpcb)) {
640
					_kvm_err(kd, kd->program,
641
					    "can't read tcpcb");
642
					return (-1);
643
				}
644
				kf->t_rcv_wnd = tcpcb.rcv_wnd;
645
				kf->t_snd_wnd = tcpcb.snd_wnd;
646
				kf->t_snd_cwnd = tcpcb.snd_cwnd;
647
				kf->t_state = tcpcb.t_state;
648
			}
649
			break;
650
		    }
651
		case AF_UNIX: {
652
			struct unpcb unpcb;
653
654
			if (KREAD(kd, (u_long)sock.so_pcb, &unpcb)) {
655
				_kvm_err(kd, kd->program, "can't read unpcb");
656
				return (-1);
657
			}
658
			kf->f_msgcount	= unpcb.unp_msgcount;
659
			kf->unp_conn	= PTRTOINT64(unpcb.unp_conn);
660
			kf->unp_refs	= PTRTOINT64(
661
			    SLIST_FIRST(&unpcb.unp_refs));
662
			kf->unp_nextref	= PTRTOINT64(
663
			    SLIST_NEXT(&unpcb, unp_nextref));
664
			kf->v_un	= PTRTOINT64(unpcb.unp_vnode);
665
			if (unpcb.unp_addr != NULL) {
666
				struct mbuf mb;
667
				struct sockaddr_un un;
668
669
				if (KREAD(kd, (u_long)unpcb.unp_addr, &mb)) {
670
					_kvm_err(kd, kd->program,
671
					    "can't read sockaddr_un mbuf");
672
					return (-1);
673
				}
674
				if (KREAD(kd, (u_long)mb.m_data, &un)) {
675
					_kvm_err(kd, kd->program,
676
					    "can't read sockaddr_un");
677
					return (-1);
678
				}
679
680
				kf->unp_addr = PTRTOINT64(unpcb.unp_addr);
681
				memcpy(kf->unp_path, un.sun_path, un.sun_len
682
				    - offsetof(struct sockaddr_un,sun_path));
683
			}
684
685
			break;
686
		    }
687
		}
688
		break;
689
	    }
690
691
	case DTYPE_PIPE: {
692
		struct pipe pipe;
693
694
		if (KREAD(kd, (u_long)fp->f_data, &pipe)) {
695
			_kvm_err(kd, kd->program, "can't read pipe");
696
			return (-1);
697
		}
698
		kf->pipe_peer = PTRTOINT64(pipe.pipe_peer);
699
		kf->pipe_state = pipe.pipe_state;
700
		break;
701
	    }
702
703
	case DTYPE_KQUEUE: {
704
		struct kqueue kqi;
705
706
		if (KREAD(kd, (u_long)fp->f_data, &kqi)) {
707
			_kvm_err(kd, kd->program, "can't read kqi");
708
			return (-1);
709
		}
710
		kf->kq_count = kqi.kq_count;
711
		kf->kq_state = kqi.kq_state;
712
		break;
713
	    }
714
	}
715
716
	/* per-process information for KERN_FILE_BY[PU]ID */
717
	if (pr != NULL) {
718
		kf->p_pid = pid;
719
		kf->p_uid = pr->ps_ucred->cr_uid;
720
		kf->p_gid = pr->ps_ucred->cr_gid;
721
		kf->p_tid = -1;
722
		strlcpy(kf->p_comm, pr->ps_comm, sizeof(kf->p_comm));
723
		if (pr->ps_fd != NULL)
724
			kf->fd_ofileflags = pr->ps_fd->fd_ofileflags[fd];
725
	}
726
727
	return (0);
728
}
729
730
mode_t
731
_kvm_getftype(enum vtype v_type)
732
{
733
	mode_t ftype = 0;
734
735
	switch (v_type) {
736
	case VREG:
737
		ftype = S_IFREG;
738
		break;
739
	case VDIR:
740
		ftype = S_IFDIR;
741
		break;
742
	case VBLK:
743
		ftype = S_IFBLK;
744
		break;
745
	case VCHR:
746
		ftype = S_IFCHR;
747
		break;
748
	case VLNK:
749
		ftype = S_IFLNK;
750
		break;
751
	case VSOCK:
752
		ftype = S_IFSOCK;
753
		break;
754
	case VFIFO:
755
		ftype = S_IFIFO;
756
		break;
757
	case VNON:
758
	case VBAD:
759
		break;
760
	}
761
762
	return (ftype);
763
}
764
765
static int
766
ufs_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
767
{
768
	struct inode inode;
769
	struct ufs1_dinode di1;
770
771
	if (KREAD(kd, (u_long)VTOI(vp), &inode)) {
772
		_kvm_err(kd, kd->program, "can't read inode at %p", VTOI(vp));
773
		return (-1);
774
	}
775
776
	if (KREAD(kd, (u_long)inode.i_din1, &di1)) {
777
		_kvm_err(kd, kd->program, "can't read dinode at %p",
778
		    inode.i_din1);
779
		return (-1);
780
	}
781
782
	inode.i_din1 = &di1;
783
784
	kf->va_fsid = inode.i_dev & 0xffff;
785
	kf->va_fileid = (long)inode.i_number;
786
	kf->va_mode = inode.i_ffs1_mode;
787
	kf->va_size = inode.i_ffs1_size;
788
	kf->va_rdev = inode.i_ffs1_rdev;
789
	kf->va_nlink = inode.i_ffs1_nlink;
790
791
	return (0);
792
}
793
794
static int
795
ext2fs_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
796
{
797
	struct inode inode;
798
	struct ext2fs_dinode e2di;
799
800
	if (KREAD(kd, (u_long)VTOI(vp), &inode)) {
801
		_kvm_err(kd, kd->program, "can't read inode at %p", VTOI(vp));
802
		return (-1);
803
	}
804
805
	if (KREAD(kd, (u_long)inode.i_e2din, &e2di)) {
806
		_kvm_err(kd, kd->program, "can't read dinode at %p",
807
		    inode.i_e2din);
808
		return (-1);
809
	}
810
811
	inode.i_e2din = &e2di;
812
813
	kf->va_fsid = inode.i_dev & 0xffff;
814
	kf->va_fileid = (long)inode.i_number;
815
	kf->va_mode = inode.i_e2fs_mode;
816
	kf->va_size = inode.i_e2fs_size;
817
	kf->va_rdev = 0;	/* XXX */
818
	kf->va_nlink = inode.i_e2fs_nlink;
819
820
	return (0);
821
}
822
823
static int
824
msdos_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
825
{
826
	struct denode de;
827
	struct msdosfsmount mp;
828
829
	if (KREAD(kd, (u_long)VTODE(vp), &de)) {
830
		_kvm_err(kd, kd->program, "can't read denode at %p", VTODE(vp));
831
		return (-1);
832
	}
833
	if (KREAD(kd, (u_long)de.de_pmp, &mp)) {
834
		_kvm_err(kd, kd->program, "can't read mount struct at %p",
835
		    de.de_pmp);
836
		return (-1);
837
	}
838
839
	kf->va_fsid = de.de_dev & 0xffff;
840
	kf->va_fileid = 0; /* XXX see msdosfs_vptofh() for more info */
841
	kf->va_mode = (mp.pm_mask & 0777) | _kvm_getftype(vp->v_type);
842
	kf->va_size = de.de_FileSize;
843
	kf->va_rdev = 0;  /* msdosfs doesn't support device files */
844
	kf->va_nlink = 1;
845
846
	return (0);
847
}
848
849
static int
850
nfs_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
851
{
852
	struct nfsnode nfsnode;
853
854
	if (KREAD(kd, (u_long)VTONFS(vp), &nfsnode)) {
855
		_kvm_err(kd, kd->program, "can't read nfsnode at %p",
856
		    VTONFS(vp));
857
		return (-1);
858
	}
859
	kf->va_fsid = nfsnode.n_vattr.va_fsid;
860
	kf->va_fileid = nfsnode.n_vattr.va_fileid;
861
	kf->va_size = nfsnode.n_size;
862
	kf->va_rdev = nfsnode.n_vattr.va_rdev;
863
	kf->va_mode = (mode_t)nfsnode.n_vattr.va_mode | _kvm_getftype(vp->v_type);
864
	kf->va_nlink = nfsnode.n_vattr.va_nlink;
865
866
	return (0);
867
}
868
869
static int
870
spec_filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
871
{
872
	struct specinfo		specinfo;
873
	struct vnode		parent;
874
875
	if (KREAD(kd, (u_long)vp->v_specinfo, &specinfo)) {
876
		_kvm_err(kd, kd->program, "can't read specinfo at %p",
877
		     vp->v_specinfo);
878
		return (-1);
879
	}
880
881
	vp->v_specinfo = &specinfo;
882
883
	if (KREAD(kd, (u_long)vp->v_specparent, &parent)) {
884
		_kvm_err(kd, kd->program, "can't read parent vnode at %p",
885
		     vp->v_specparent);
886
		return (-1);
887
	}
888
889
	if (ufs_filestat(kd, kf, vp))
890
		return (-1);
891
892
	return (0);
893
}
894
895
static int
896
filestat(kvm_t *kd, struct kinfo_file *kf, struct vnode *vp)
897
{
898
	int ret = 0;
899
900
	if (vp->v_type != VNON && vp->v_type != VBAD) {
901
		switch (vp->v_tag) {
902
		case VT_UFS:
903
		case VT_MFS:
904
			ret = ufs_filestat(kd, kf, vp);
905
			break;
906
		case VT_NFS:
907
			ret = nfs_filestat(kd, kf, vp);
908
			break;
909
		case VT_EXT2FS:
910
			ret = ext2fs_filestat(kd, kf, vp);
911
			break;
912
		case VT_ISOFS:
913
			ret = _kvm_stat_cd9660(kd, kf, vp);
914
			break;
915
		case VT_MSDOSFS:
916
			ret = msdos_filestat(kd, kf, vp);
917
			break;
918
		case VT_UDF:
919
			ret = _kvm_stat_udf(kd, kf, vp);
920
			break;
921
		case VT_NTFS:
922
			ret = _kvm_stat_ntfs(kd, kf, vp);
923
			break;
924
		case VT_NON:
925
			if (vp->v_flag & VCLONE)
926
				ret = spec_filestat(kd, kf, vp);
927
			break;
928
		default:
929
			ret = -1;
930
			break;
931
		}
932
	}
933
	return (ret);
934
}