xref: /freebsd/lib/libprocstat/libprocstat.c (revision 39680c7b)
1 /*-
2  * Copyright (c) 2009 Stanislav Sedov <stas@FreeBSD.org>
3  * Copyright (c) 1988, 1993
4  *      The Regents of the University of California.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by the University of
17  *      California, Berkeley and its contributors.
18  * 4. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37 
38 #include <sys/param.h>
39 #include <sys/time.h>
40 #include <sys/proc.h>
41 #include <sys/user.h>
42 #include <sys/stat.h>
43 #include <sys/vnode.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 #include <sys/domain.h>
47 #include <sys/protosw.h>
48 #include <sys/un.h>
49 #include <sys/unpcb.h>
50 #include <sys/sysctl.h>
51 #include <sys/tty.h>
52 #include <sys/filedesc.h>
53 #include <sys/queue.h>
54 #define	_WANT_FILE
55 #include <sys/file.h>
56 #include <sys/conf.h>
57 #include <sys/mman.h>
58 #define	_KERNEL
59 #include <sys/mount.h>
60 #include <sys/pipe.h>
61 #include <ufs/ufs/quota.h>
62 #include <ufs/ufs/inode.h>
63 #include <fs/devfs/devfs.h>
64 #include <fs/devfs/devfs_int.h>
65 #undef _KERNEL
66 #include <nfs/nfsproto.h>
67 #include <nfsclient/nfs.h>
68 #include <nfsclient/nfsnode.h>
69 
70 #include <vm/vm.h>
71 #include <vm/vm_map.h>
72 #include <vm/vm_object.h>
73 
74 #include <net/route.h>
75 #include <netinet/in.h>
76 #include <netinet/in_systm.h>
77 #include <netinet/ip.h>
78 #include <netinet/in_pcb.h>
79 
80 #include <assert.h>
81 #include <ctype.h>
82 #include <err.h>
83 #include <fcntl.h>
84 #include <kvm.h>
85 #include <libutil.h>
86 #include <limits.h>
87 #include <paths.h>
88 #include <pwd.h>
89 #include <stdio.h>
90 #include <stdlib.h>
91 #include <stddef.h>
92 #include <string.h>
93 #include <unistd.h>
94 #include <netdb.h>
95 
96 #include <libprocstat.h>
97 #include "libprocstat_internal.h"
98 #include "common_kvm.h"
99 #include "core.h"
100 
101 int     statfs(const char *, struct statfs *);	/* XXX */
102 
103 #define	PROCSTAT_KVM	1
104 #define	PROCSTAT_SYSCTL	2
105 #define	PROCSTAT_CORE	3
106 
107 static char	*getmnton(kvm_t *kd, struct mount *m);
108 static struct kinfo_vmentry *	kinfo_getvmmap_core(struct procstat_core *core,
109     int *cntp);
110 static struct filestat_list	*procstat_getfiles_kvm(
111     struct procstat *procstat, struct kinfo_proc *kp, int mmapped);
112 static struct filestat_list	*procstat_getfiles_sysctl(
113     struct procstat *procstat, struct kinfo_proc *kp, int mmapped);
114 static int	procstat_get_pipe_info_sysctl(struct filestat *fst,
115     struct pipestat *pipe, char *errbuf);
116 static int	procstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst,
117     struct pipestat *pipe, char *errbuf);
118 static int	procstat_get_pts_info_sysctl(struct filestat *fst,
119     struct ptsstat *pts, char *errbuf);
120 static int	procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst,
121     struct ptsstat *pts, char *errbuf);
122 static int	procstat_get_shm_info_sysctl(struct filestat *fst,
123     struct shmstat *shm, char *errbuf);
124 static int	procstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst,
125     struct shmstat *shm, char *errbuf);
126 static int	procstat_get_socket_info_sysctl(struct filestat *fst,
127     struct sockstat *sock, char *errbuf);
128 static int	procstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst,
129     struct sockstat *sock, char *errbuf);
130 static int	to_filestat_flags(int flags);
131 static int	procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst,
132     struct vnstat *vn, char *errbuf);
133 static int	procstat_get_vnode_info_sysctl(struct filestat *fst,
134     struct vnstat *vn, char *errbuf);
135 static int	vntype2psfsttype(int type);
136 
137 void
138 procstat_close(struct procstat *procstat)
139 {
140 
141 	assert(procstat);
142 	if (procstat->type == PROCSTAT_KVM)
143 		kvm_close(procstat->kd);
144 	else if (procstat->type == PROCSTAT_CORE)
145 		procstat_core_close(procstat->core);
146 	free(procstat);
147 }
148 
149 struct procstat *
150 procstat_open_sysctl(void)
151 {
152 	struct procstat *procstat;
153 
154 	procstat = calloc(1, sizeof(*procstat));
155 	if (procstat == NULL) {
156 		warn("malloc()");
157 		return (NULL);
158 	}
159 	procstat->type = PROCSTAT_SYSCTL;
160 	return (procstat);
161 }
162 
163 struct procstat *
164 procstat_open_kvm(const char *nlistf, const char *memf)
165 {
166 	struct procstat *procstat;
167 	kvm_t *kd;
168 	char buf[_POSIX2_LINE_MAX];
169 
170 	procstat = calloc(1, sizeof(*procstat));
171 	if (procstat == NULL) {
172 		warn("malloc()");
173 		return (NULL);
174 	}
175 	kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf);
176 	if (kd == NULL) {
177 		warnx("kvm_openfiles(): %s", buf);
178 		free(procstat);
179 		return (NULL);
180 	}
181 	procstat->type = PROCSTAT_KVM;
182 	procstat->kd = kd;
183 	return (procstat);
184 }
185 
186 struct procstat *
187 procstat_open_core(const char *filename)
188 {
189 	struct procstat *procstat;
190 	struct procstat_core *core;
191 
192 	procstat = calloc(1, sizeof(*procstat));
193 	if (procstat == NULL) {
194 		warn("malloc()");
195 		return (NULL);
196 	}
197 	core = procstat_core_open(filename);
198 	if (core == NULL) {
199 		free(procstat);
200 		return (NULL);
201 	}
202 	procstat->type = PROCSTAT_CORE;
203 	procstat->core = core;
204 	return (procstat);
205 }
206 
207 struct kinfo_proc *
208 procstat_getprocs(struct procstat *procstat, int what, int arg,
209     unsigned int *count)
210 {
211 	struct kinfo_proc *p0, *p;
212 	size_t len;
213 	int name[4];
214 	int cnt;
215 	int error;
216 
217 	assert(procstat);
218 	assert(count);
219 	p = NULL;
220 	if (procstat->type == PROCSTAT_KVM) {
221 		*count = 0;
222 		p0 = kvm_getprocs(procstat->kd, what, arg, &cnt);
223 		if (p0 == NULL || cnt <= 0)
224 			return (NULL);
225 		*count = cnt;
226 		len = *count * sizeof(*p);
227 		p = malloc(len);
228 		if (p == NULL) {
229 			warnx("malloc(%zu)", len);
230 			goto fail;
231 		}
232 		bcopy(p0, p, len);
233 		return (p);
234 	} else if (procstat->type == PROCSTAT_SYSCTL) {
235 		len = 0;
236 		name[0] = CTL_KERN;
237 		name[1] = KERN_PROC;
238 		name[2] = what;
239 		name[3] = arg;
240 		error = sysctl(name, 4, NULL, &len, NULL, 0);
241 		if (error < 0 && errno != EPERM) {
242 			warn("sysctl(kern.proc)");
243 			goto fail;
244 		}
245 		if (len == 0) {
246 			warnx("no processes?");
247 			goto fail;
248 		}
249 		p = malloc(len);
250 		if (p == NULL) {
251 			warnx("malloc(%zu)", len);
252 			goto fail;
253 		}
254 		error = sysctl(name, 4, p, &len, NULL, 0);
255 		if (error < 0 && errno != EPERM) {
256 			warn("sysctl(kern.proc)");
257 			goto fail;
258 		}
259 		/* Perform simple consistency checks. */
260 		if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) {
261 			warnx("kinfo_proc structure size mismatch (len = %zu)", len);
262 			goto fail;
263 		}
264 		*count = len / sizeof(*p);
265 		return (p);
266 	} else if (procstat->type == PROCSTAT_CORE) {
267 		p = procstat_core_get(procstat->core, PSC_TYPE_PROC, NULL,
268 		    &len);
269 		if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) {
270 			warnx("kinfo_proc structure size mismatch");
271 			goto fail;
272 		}
273 		*count = len / sizeof(*p);
274 		return (p);
275 	} else {
276 		warnx("unknown access method: %d", procstat->type);
277 		return (NULL);
278 	}
279 fail:
280 	if (p)
281 		free(p);
282 	return (NULL);
283 }
284 
285 void
286 procstat_freeprocs(struct procstat *procstat __unused, struct kinfo_proc *p)
287 {
288 
289 	if (p != NULL)
290 		free(p);
291 	p = NULL;
292 }
293 
294 struct filestat_list *
295 procstat_getfiles(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
296 {
297 
298 	switch(procstat->type) {
299 	case PROCSTAT_KVM:
300 		return (procstat_getfiles_kvm(procstat, kp, mmapped));
301 	case PROCSTAT_SYSCTL:
302 	case PROCSTAT_CORE:
303 		return (procstat_getfiles_sysctl(procstat, kp, mmapped));
304 	default:
305 		warnx("unknown access method: %d", procstat->type);
306 		return (NULL);
307 	}
308 }
309 
310 void
311 procstat_freefiles(struct procstat *procstat, struct filestat_list *head)
312 {
313 	struct filestat *fst, *tmp;
314 
315 	STAILQ_FOREACH_SAFE(fst, head, next, tmp) {
316 		if (fst->fs_path != NULL)
317 			free(fst->fs_path);
318 		free(fst);
319 	}
320 	free(head);
321 	if (procstat->vmentries != NULL) {
322 		free(procstat->vmentries);
323 		procstat->vmentries = NULL;
324 	}
325 	if (procstat->files != NULL) {
326 		free(procstat->files);
327 		procstat->files = NULL;
328 	}
329 }
330 
331 static struct filestat *
332 filestat_new_entry(void *typedep, int type, int fd, int fflags, int uflags,
333     int refcount, off_t offset, char *path, cap_rights_t cap_rights)
334 {
335 	struct filestat *entry;
336 
337 	entry = calloc(1, sizeof(*entry));
338 	if (entry == NULL) {
339 		warn("malloc()");
340 		return (NULL);
341 	}
342 	entry->fs_typedep = typedep;
343 	entry->fs_fflags = fflags;
344 	entry->fs_uflags = uflags;
345 	entry->fs_fd = fd;
346 	entry->fs_type = type;
347 	entry->fs_ref_count = refcount;
348 	entry->fs_offset = offset;
349 	entry->fs_path = path;
350 	entry->fs_cap_rights = cap_rights;
351 	return (entry);
352 }
353 
354 static struct vnode *
355 getctty(kvm_t *kd, struct kinfo_proc *kp)
356 {
357 	struct pgrp pgrp;
358 	struct proc proc;
359 	struct session sess;
360 	int error;
361 
362 	assert(kp);
363 	error = kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc,
364 	    sizeof(proc));
365 	if (error == 0) {
366 		warnx("can't read proc struct at %p for pid %d",
367 		    kp->ki_paddr, kp->ki_pid);
368 		return (NULL);
369 	}
370 	if (proc.p_pgrp == NULL)
371 		return (NULL);
372 	error = kvm_read_all(kd, (unsigned long)proc.p_pgrp, &pgrp,
373 	    sizeof(pgrp));
374 	if (error == 0) {
375 		warnx("can't read pgrp struct at %p for pid %d",
376 		    proc.p_pgrp, kp->ki_pid);
377 		return (NULL);
378 	}
379 	error = kvm_read_all(kd, (unsigned long)pgrp.pg_session, &sess,
380 	    sizeof(sess));
381 	if (error == 0) {
382 		warnx("can't read session struct at %p for pid %d",
383 		    pgrp.pg_session, kp->ki_pid);
384 		return (NULL);
385 	}
386 	return (sess.s_ttyvp);
387 }
388 
389 static struct filestat_list *
390 procstat_getfiles_kvm(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
391 {
392 	struct file file;
393 	struct filedesc filed;
394 	struct vm_map_entry vmentry;
395 	struct vm_object object;
396 	struct vmspace vmspace;
397 	vm_map_entry_t entryp;
398 	vm_map_t map;
399 	vm_object_t objp;
400 	struct vnode *vp;
401 	struct file **ofiles;
402 	struct filestat *entry;
403 	struct filestat_list *head;
404 	kvm_t *kd;
405 	void *data;
406 	int i, fflags;
407 	int prot, type;
408 	unsigned int nfiles;
409 
410 	assert(procstat);
411 	kd = procstat->kd;
412 	if (kd == NULL)
413 		return (NULL);
414 	if (kp->ki_fd == NULL)
415 		return (NULL);
416 	if (!kvm_read_all(kd, (unsigned long)kp->ki_fd, &filed,
417 	    sizeof(filed))) {
418 		warnx("can't read filedesc at %p", (void *)kp->ki_fd);
419 		return (NULL);
420 	}
421 
422 	/*
423 	 * Allocate list head.
424 	 */
425 	head = malloc(sizeof(*head));
426 	if (head == NULL)
427 		return (NULL);
428 	STAILQ_INIT(head);
429 
430 	/* root directory vnode, if one. */
431 	if (filed.fd_rdir) {
432 		entry = filestat_new_entry(filed.fd_rdir, PS_FST_TYPE_VNODE, -1,
433 		    PS_FST_FFLAG_READ, PS_FST_UFLAG_RDIR, 0, 0, NULL, 0);
434 		if (entry != NULL)
435 			STAILQ_INSERT_TAIL(head, entry, next);
436 	}
437 	/* current working directory vnode. */
438 	if (filed.fd_cdir) {
439 		entry = filestat_new_entry(filed.fd_cdir, PS_FST_TYPE_VNODE, -1,
440 		    PS_FST_FFLAG_READ, PS_FST_UFLAG_CDIR, 0, 0, NULL, 0);
441 		if (entry != NULL)
442 			STAILQ_INSERT_TAIL(head, entry, next);
443 	}
444 	/* jail root, if any. */
445 	if (filed.fd_jdir) {
446 		entry = filestat_new_entry(filed.fd_jdir, PS_FST_TYPE_VNODE, -1,
447 		    PS_FST_FFLAG_READ, PS_FST_UFLAG_JAIL, 0, 0, NULL, 0);
448 		if (entry != NULL)
449 			STAILQ_INSERT_TAIL(head, entry, next);
450 	}
451 	/* ktrace vnode, if one */
452 	if (kp->ki_tracep) {
453 		entry = filestat_new_entry(kp->ki_tracep, PS_FST_TYPE_VNODE, -1,
454 		    PS_FST_FFLAG_READ | PS_FST_FFLAG_WRITE,
455 		    PS_FST_UFLAG_TRACE, 0, 0, NULL, 0);
456 		if (entry != NULL)
457 			STAILQ_INSERT_TAIL(head, entry, next);
458 	}
459 	/* text vnode, if one */
460 	if (kp->ki_textvp) {
461 		entry = filestat_new_entry(kp->ki_textvp, PS_FST_TYPE_VNODE, -1,
462 		    PS_FST_FFLAG_READ, PS_FST_UFLAG_TEXT, 0, 0, NULL, 0);
463 		if (entry != NULL)
464 			STAILQ_INSERT_TAIL(head, entry, next);
465 	}
466 	/* Controlling terminal. */
467 	if ((vp = getctty(kd, kp)) != NULL) {
468 		entry = filestat_new_entry(vp, PS_FST_TYPE_VNODE, -1,
469 		    PS_FST_FFLAG_READ | PS_FST_FFLAG_WRITE,
470 		    PS_FST_UFLAG_CTTY, 0, 0, NULL, 0);
471 		if (entry != NULL)
472 			STAILQ_INSERT_TAIL(head, entry, next);
473 	}
474 
475 	nfiles = filed.fd_lastfile + 1;
476 	ofiles = malloc(nfiles * sizeof(struct file *));
477 	if (ofiles == NULL) {
478 		warn("malloc(%zu)", nfiles * sizeof(struct file *));
479 		goto do_mmapped;
480 	}
481 	if (!kvm_read_all(kd, (unsigned long)filed.fd_ofiles, ofiles,
482 	    nfiles * sizeof(struct file *))) {
483 		warnx("cannot read file structures at %p",
484 		    (void *)filed.fd_ofiles);
485 		free(ofiles);
486 		goto do_mmapped;
487 	}
488 	for (i = 0; i <= filed.fd_lastfile; i++) {
489 		if (ofiles[i] == NULL)
490 			continue;
491 		if (!kvm_read_all(kd, (unsigned long)ofiles[i], &file,
492 		    sizeof(struct file))) {
493 			warnx("can't read file %d at %p", i,
494 			    (void *)ofiles[i]);
495 			continue;
496 		}
497 		switch (file.f_type) {
498 		case DTYPE_VNODE:
499 			type = PS_FST_TYPE_VNODE;
500 			data = file.f_vnode;
501 			break;
502 		case DTYPE_SOCKET:
503 			type = PS_FST_TYPE_SOCKET;
504 			data = file.f_data;
505 			break;
506 		case DTYPE_PIPE:
507 			type = PS_FST_TYPE_PIPE;
508 			data = file.f_data;
509 			break;
510 		case DTYPE_FIFO:
511 			type = PS_FST_TYPE_FIFO;
512 			data = file.f_vnode;
513 			break;
514 #ifdef DTYPE_PTS
515 		case DTYPE_PTS:
516 			type = PS_FST_TYPE_PTS;
517 			data = file.f_data;
518 			break;
519 #endif
520 		case DTYPE_SHM:
521 			type = PS_FST_TYPE_SHM;
522 			data = file.f_data;
523 			break;
524 		default:
525 			continue;
526 		}
527 		/* XXXRW: No capability rights support for kvm yet. */
528 		entry = filestat_new_entry(data, type, i,
529 		    to_filestat_flags(file.f_flag), 0, 0, 0, NULL, 0);
530 		if (entry != NULL)
531 			STAILQ_INSERT_TAIL(head, entry, next);
532 	}
533 	free(ofiles);
534 
535 do_mmapped:
536 
537 	/*
538 	 * Process mmapped files if requested.
539 	 */
540 	if (mmapped) {
541 		if (!kvm_read_all(kd, (unsigned long)kp->ki_vmspace, &vmspace,
542 		    sizeof(vmspace))) {
543 			warnx("can't read vmspace at %p",
544 			    (void *)kp->ki_vmspace);
545 			goto exit;
546 		}
547 		map = &vmspace.vm_map;
548 
549 		for (entryp = map->header.next;
550 		    entryp != &kp->ki_vmspace->vm_map.header;
551 		    entryp = vmentry.next) {
552 			if (!kvm_read_all(kd, (unsigned long)entryp, &vmentry,
553 			    sizeof(vmentry))) {
554 				warnx("can't read vm_map_entry at %p",
555 				    (void *)entryp);
556 				continue;
557 			}
558 			if (vmentry.eflags & MAP_ENTRY_IS_SUB_MAP)
559 				continue;
560 			if ((objp = vmentry.object.vm_object) == NULL)
561 				continue;
562 			for (; objp; objp = object.backing_object) {
563 				if (!kvm_read_all(kd, (unsigned long)objp,
564 				    &object, sizeof(object))) {
565 					warnx("can't read vm_object at %p",
566 					    (void *)objp);
567 					break;
568 				}
569 			}
570 
571 			/* We want only vnode objects. */
572 			if (object.type != OBJT_VNODE)
573 				continue;
574 
575 			prot = vmentry.protection;
576 			fflags = 0;
577 			if (prot & VM_PROT_READ)
578 				fflags = PS_FST_FFLAG_READ;
579 			if ((vmentry.eflags & MAP_ENTRY_COW) == 0 &&
580 			    prot & VM_PROT_WRITE)
581 				fflags |= PS_FST_FFLAG_WRITE;
582 
583 			/*
584 			 * Create filestat entry.
585 			 */
586 			entry = filestat_new_entry(object.handle,
587 			    PS_FST_TYPE_VNODE, -1, fflags,
588 			    PS_FST_UFLAG_MMAP, 0, 0, NULL, 0);
589 			if (entry != NULL)
590 				STAILQ_INSERT_TAIL(head, entry, next);
591 		}
592 	}
593 exit:
594 	return (head);
595 }
596 
597 /*
598  * kinfo types to filestat translation.
599  */
600 static int
601 kinfo_type2fst(int kftype)
602 {
603 	static struct {
604 		int	kf_type;
605 		int	fst_type;
606 	} kftypes2fst[] = {
607 		{ KF_TYPE_CRYPTO, PS_FST_TYPE_CRYPTO },
608 		{ KF_TYPE_FIFO, PS_FST_TYPE_FIFO },
609 		{ KF_TYPE_KQUEUE, PS_FST_TYPE_KQUEUE },
610 		{ KF_TYPE_MQUEUE, PS_FST_TYPE_MQUEUE },
611 		{ KF_TYPE_NONE, PS_FST_TYPE_NONE },
612 		{ KF_TYPE_PIPE, PS_FST_TYPE_PIPE },
613 		{ KF_TYPE_PTS, PS_FST_TYPE_PTS },
614 		{ KF_TYPE_SEM, PS_FST_TYPE_SEM },
615 		{ KF_TYPE_SHM, PS_FST_TYPE_SHM },
616 		{ KF_TYPE_SOCKET, PS_FST_TYPE_SOCKET },
617 		{ KF_TYPE_VNODE, PS_FST_TYPE_VNODE },
618 		{ KF_TYPE_UNKNOWN, PS_FST_TYPE_UNKNOWN }
619 	};
620 #define NKFTYPES	(sizeof(kftypes2fst) / sizeof(*kftypes2fst))
621 	unsigned int i;
622 
623 	for (i = 0; i < NKFTYPES; i++)
624 		if (kftypes2fst[i].kf_type == kftype)
625 			break;
626 	if (i == NKFTYPES)
627 		return (PS_FST_TYPE_UNKNOWN);
628 	return (kftypes2fst[i].fst_type);
629 }
630 
631 /*
632  * kinfo flags to filestat translation.
633  */
634 static int
635 kinfo_fflags2fst(int kfflags)
636 {
637 	static struct {
638 		int	kf_flag;
639 		int	fst_flag;
640 	} kfflags2fst[] = {
641 		{ KF_FLAG_APPEND, PS_FST_FFLAG_APPEND },
642 		{ KF_FLAG_ASYNC, PS_FST_FFLAG_ASYNC },
643 		{ KF_FLAG_CREAT, PS_FST_FFLAG_CREAT },
644 		{ KF_FLAG_DIRECT, PS_FST_FFLAG_DIRECT },
645 		{ KF_FLAG_EXCL, PS_FST_FFLAG_EXCL },
646 		{ KF_FLAG_EXEC, PS_FST_FFLAG_EXEC },
647 		{ KF_FLAG_EXLOCK, PS_FST_FFLAG_EXLOCK },
648 		{ KF_FLAG_FSYNC, PS_FST_FFLAG_SYNC },
649 		{ KF_FLAG_HASLOCK, PS_FST_FFLAG_HASLOCK },
650 		{ KF_FLAG_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW },
651 		{ KF_FLAG_NONBLOCK, PS_FST_FFLAG_NONBLOCK },
652 		{ KF_FLAG_READ, PS_FST_FFLAG_READ },
653 		{ KF_FLAG_SHLOCK, PS_FST_FFLAG_SHLOCK },
654 		{ KF_FLAG_TRUNC, PS_FST_FFLAG_TRUNC },
655 		{ KF_FLAG_WRITE, PS_FST_FFLAG_WRITE }
656 	};
657 #define NKFFLAGS	(sizeof(kfflags2fst) / sizeof(*kfflags2fst))
658 	unsigned int i;
659 	int flags;
660 
661 	flags = 0;
662 	for (i = 0; i < NKFFLAGS; i++)
663 		if ((kfflags & kfflags2fst[i].kf_flag) != 0)
664 			flags |= kfflags2fst[i].fst_flag;
665 	return (flags);
666 }
667 
668 static int
669 kinfo_uflags2fst(int fd)
670 {
671 
672 	switch (fd) {
673 	case KF_FD_TYPE_CTTY:
674 		return (PS_FST_UFLAG_CTTY);
675 	case KF_FD_TYPE_CWD:
676 		return (PS_FST_UFLAG_CDIR);
677 	case KF_FD_TYPE_JAIL:
678 		return (PS_FST_UFLAG_JAIL);
679 	case KF_FD_TYPE_TEXT:
680 		return (PS_FST_UFLAG_TEXT);
681 	case KF_FD_TYPE_TRACE:
682 		return (PS_FST_UFLAG_TRACE);
683 	case KF_FD_TYPE_ROOT:
684 		return (PS_FST_UFLAG_RDIR);
685 	}
686 	return (0);
687 }
688 
689 static struct kinfo_file *
690 kinfo_getfile_core(struct procstat_core *core, int *cntp)
691 {
692 	int cnt;
693 	size_t len;
694 	char *buf, *bp, *eb;
695 	struct kinfo_file *kif, *kp, *kf;
696 
697 	buf = procstat_core_get(core, PSC_TYPE_FILES, NULL, &len);
698 	if (buf == NULL)
699 		return (NULL);
700 	/*
701 	 * XXXMG: The code below is just copy&past from libutil.
702 	 * The code duplication can be avoided if libutil
703 	 * is extended to provide something like:
704 	 *   struct kinfo_file *kinfo_getfile_from_buf(const char *buf,
705 	 *       size_t len, int *cntp);
706 	 */
707 
708 	/* Pass 1: count items */
709 	cnt = 0;
710 	bp = buf;
711 	eb = buf + len;
712 	while (bp < eb) {
713 		kf = (struct kinfo_file *)(uintptr_t)bp;
714 		bp += kf->kf_structsize;
715 		cnt++;
716 	}
717 
718 	kif = calloc(cnt, sizeof(*kif));
719 	if (kif == NULL) {
720 		free(buf);
721 		return (NULL);
722 	}
723 	bp = buf;
724 	eb = buf + len;
725 	kp = kif;
726 	/* Pass 2: unpack */
727 	while (bp < eb) {
728 		kf = (struct kinfo_file *)(uintptr_t)bp;
729 		/* Copy/expand into pre-zeroed buffer */
730 		memcpy(kp, kf, kf->kf_structsize);
731 		/* Advance to next packed record */
732 		bp += kf->kf_structsize;
733 		/* Set field size to fixed length, advance */
734 		kp->kf_structsize = sizeof(*kp);
735 		kp++;
736 	}
737 	free(buf);
738 	*cntp = cnt;
739 	return (kif);	/* Caller must free() return value */
740 }
741 
742 static struct filestat_list *
743 procstat_getfiles_sysctl(struct procstat *procstat, struct kinfo_proc *kp,
744     int mmapped)
745 {
746 	struct kinfo_file *kif, *files;
747 	struct kinfo_vmentry *kve, *vmentries;
748 	struct filestat_list *head;
749 	struct filestat *entry;
750 	char *path;
751 	off_t offset;
752 	int cnt, fd, fflags;
753 	int i, type, uflags;
754 	int refcount;
755 	cap_rights_t cap_rights;
756 
757 	assert(kp);
758 	if (kp->ki_fd == NULL)
759 		return (NULL);
760 	switch(procstat->type) {
761 	case PROCSTAT_SYSCTL:
762 		files = kinfo_getfile(kp->ki_pid, &cnt);
763 		break;
764 	case PROCSTAT_CORE:
765 		files = kinfo_getfile_core(procstat->core, &cnt);
766 		break;
767 	default:
768 		assert(!"invalid type");
769 	}
770 	if (files == NULL && errno != EPERM) {
771 		warn("kinfo_getfile()");
772 		return (NULL);
773 	}
774 	procstat->files = files;
775 
776 	/*
777 	 * Allocate list head.
778 	 */
779 	head = malloc(sizeof(*head));
780 	if (head == NULL)
781 		return (NULL);
782 	STAILQ_INIT(head);
783 	for (i = 0; i < cnt; i++) {
784 		kif = &files[i];
785 
786 		type = kinfo_type2fst(kif->kf_type);
787 		fd = kif->kf_fd >= 0 ? kif->kf_fd : -1;
788 		fflags = kinfo_fflags2fst(kif->kf_flags);
789 		uflags = kinfo_uflags2fst(kif->kf_fd);
790 		refcount = kif->kf_ref_count;
791 		offset = kif->kf_offset;
792 		if (*kif->kf_path != '\0')
793 			path = strdup(kif->kf_path);
794 		else
795 			path = NULL;
796 		cap_rights = kif->kf_cap_rights;
797 
798 		/*
799 		 * Create filestat entry.
800 		 */
801 		entry = filestat_new_entry(kif, type, fd, fflags, uflags,
802 		    refcount, offset, path, cap_rights);
803 		if (entry != NULL)
804 			STAILQ_INSERT_TAIL(head, entry, next);
805 	}
806 	if (mmapped != 0) {
807 		vmentries = procstat_getvmmap(procstat, kp, &cnt);
808 		procstat->vmentries = vmentries;
809 		if (vmentries == NULL || cnt == 0)
810 			goto fail;
811 		for (i = 0; i < cnt; i++) {
812 			kve = &vmentries[i];
813 			if (kve->kve_type != KVME_TYPE_VNODE)
814 				continue;
815 			fflags = 0;
816 			if (kve->kve_protection & KVME_PROT_READ)
817 				fflags = PS_FST_FFLAG_READ;
818 			if ((kve->kve_flags & KVME_FLAG_COW) == 0 &&
819 			    kve->kve_protection & KVME_PROT_WRITE)
820 				fflags |= PS_FST_FFLAG_WRITE;
821 			offset = kve->kve_offset;
822 			refcount = kve->kve_ref_count;
823 			if (*kve->kve_path != '\0')
824 				path = strdup(kve->kve_path);
825 			else
826 				path = NULL;
827 			entry = filestat_new_entry(kve, PS_FST_TYPE_VNODE, -1,
828 			    fflags, PS_FST_UFLAG_MMAP, refcount, offset, path,
829 			    0);
830 			if (entry != NULL)
831 				STAILQ_INSERT_TAIL(head, entry, next);
832 		}
833 	}
834 fail:
835 	return (head);
836 }
837 
838 int
839 procstat_get_pipe_info(struct procstat *procstat, struct filestat *fst,
840     struct pipestat *ps, char *errbuf)
841 {
842 
843 	assert(ps);
844 	if (procstat->type == PROCSTAT_KVM) {
845 		return (procstat_get_pipe_info_kvm(procstat->kd, fst, ps,
846 		    errbuf));
847 	} else if (procstat->type == PROCSTAT_SYSCTL ||
848 		procstat->type == PROCSTAT_CORE) {
849 		return (procstat_get_pipe_info_sysctl(fst, ps, errbuf));
850 	} else {
851 		warnx("unknown access method: %d", procstat->type);
852 		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
853 		return (1);
854 	}
855 }
856 
857 static int
858 procstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst,
859     struct pipestat *ps, char *errbuf)
860 {
861 	struct pipe pi;
862 	void *pipep;
863 
864 	assert(kd);
865 	assert(ps);
866 	assert(fst);
867 	bzero(ps, sizeof(*ps));
868 	pipep = fst->fs_typedep;
869 	if (pipep == NULL)
870 		goto fail;
871 	if (!kvm_read_all(kd, (unsigned long)pipep, &pi, sizeof(struct pipe))) {
872 		warnx("can't read pipe at %p", (void *)pipep);
873 		goto fail;
874 	}
875 	ps->addr = (uintptr_t)pipep;
876 	ps->peer = (uintptr_t)pi.pipe_peer;
877 	ps->buffer_cnt = pi.pipe_buffer.cnt;
878 	return (0);
879 
880 fail:
881 	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
882 	return (1);
883 }
884 
885 static int
886 procstat_get_pipe_info_sysctl(struct filestat *fst, struct pipestat *ps,
887     char *errbuf __unused)
888 {
889 	struct kinfo_file *kif;
890 
891 	assert(ps);
892 	assert(fst);
893 	bzero(ps, sizeof(*ps));
894 	kif = fst->fs_typedep;
895 	if (kif == NULL)
896 		return (1);
897 	ps->addr = kif->kf_un.kf_pipe.kf_pipe_addr;
898 	ps->peer = kif->kf_un.kf_pipe.kf_pipe_peer;
899 	ps->buffer_cnt = kif->kf_un.kf_pipe.kf_pipe_buffer_cnt;
900 	return (0);
901 }
902 
903 int
904 procstat_get_pts_info(struct procstat *procstat, struct filestat *fst,
905     struct ptsstat *pts, char *errbuf)
906 {
907 
908 	assert(pts);
909 	if (procstat->type == PROCSTAT_KVM) {
910 		return (procstat_get_pts_info_kvm(procstat->kd, fst, pts,
911 		    errbuf));
912 	} else if (procstat->type == PROCSTAT_SYSCTL ||
913 		procstat->type == PROCSTAT_CORE) {
914 		return (procstat_get_pts_info_sysctl(fst, pts, errbuf));
915 	} else {
916 		warnx("unknown access method: %d", procstat->type);
917 		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
918 		return (1);
919 	}
920 }
921 
922 static int
923 procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst,
924     struct ptsstat *pts, char *errbuf)
925 {
926 	struct tty tty;
927 	void *ttyp;
928 
929 	assert(kd);
930 	assert(pts);
931 	assert(fst);
932 	bzero(pts, sizeof(*pts));
933 	ttyp = fst->fs_typedep;
934 	if (ttyp == NULL)
935 		goto fail;
936 	if (!kvm_read_all(kd, (unsigned long)ttyp, &tty, sizeof(struct tty))) {
937 		warnx("can't read tty at %p", (void *)ttyp);
938 		goto fail;
939 	}
940 	pts->dev = dev2udev(kd, tty.t_dev);
941 	(void)kdevtoname(kd, tty.t_dev, pts->devname);
942 	return (0);
943 
944 fail:
945 	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
946 	return (1);
947 }
948 
949 static int
950 procstat_get_pts_info_sysctl(struct filestat *fst, struct ptsstat *pts,
951     char *errbuf __unused)
952 {
953 	struct kinfo_file *kif;
954 
955 	assert(pts);
956 	assert(fst);
957 	bzero(pts, sizeof(*pts));
958 	kif = fst->fs_typedep;
959 	if (kif == NULL)
960 		return (0);
961 	pts->dev = kif->kf_un.kf_pts.kf_pts_dev;
962 	strlcpy(pts->devname, kif->kf_path, sizeof(pts->devname));
963 	return (0);
964 }
965 
966 int
967 procstat_get_shm_info(struct procstat *procstat, struct filestat *fst,
968     struct shmstat *shm, char *errbuf)
969 {
970 
971 	assert(shm);
972 	if (procstat->type == PROCSTAT_KVM) {
973 		return (procstat_get_shm_info_kvm(procstat->kd, fst, shm,
974 		    errbuf));
975 	} else if (procstat->type == PROCSTAT_SYSCTL ||
976 	    procstat->type == PROCSTAT_CORE) {
977 		return (procstat_get_shm_info_sysctl(fst, shm, errbuf));
978 	} else {
979 		warnx("unknown access method: %d", procstat->type);
980 		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
981 		return (1);
982 	}
983 }
984 
985 static int
986 procstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst,
987     struct shmstat *shm, char *errbuf)
988 {
989 	struct shmfd shmfd;
990 	void *shmfdp;
991 	char *path;
992 	int i;
993 
994 	assert(kd);
995 	assert(shm);
996 	assert(fst);
997 	bzero(shm, sizeof(*shm));
998 	shmfdp = fst->fs_typedep;
999 	if (shmfdp == NULL)
1000 		goto fail;
1001 	if (!kvm_read_all(kd, (unsigned long)shmfdp, &shmfd,
1002 	    sizeof(struct shmfd))) {
1003 		warnx("can't read shmfd at %p", (void *)shmfdp);
1004 		goto fail;
1005 	}
1006 	shm->mode = S_IFREG | shmfd.shm_mode;
1007 	shm->size = shmfd.shm_size;
1008 	if (fst->fs_path == NULL && shmfd.shm_path != NULL) {
1009 		path = malloc(MAXPATHLEN);
1010 		for (i = 0; i < MAXPATHLEN - 1; i++) {
1011 			if (!kvm_read_all(kd, (unsigned long)shmfd.shm_path + i,
1012 			    path + i, 1))
1013 				break;
1014 			if (path[i] == '\0')
1015 				break;
1016 		}
1017 		path[i] = '\0';
1018 		if (i == 0)
1019 			free(path);
1020 		else
1021 			fst->fs_path = path;
1022 	}
1023 	return (0);
1024 
1025 fail:
1026 	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1027 	return (1);
1028 }
1029 
1030 static int
1031 procstat_get_shm_info_sysctl(struct filestat *fst, struct shmstat *shm,
1032     char *errbuf __unused)
1033 {
1034 	struct kinfo_file *kif;
1035 
1036 	assert(shm);
1037 	assert(fst);
1038 	bzero(shm, sizeof(*shm));
1039 	kif = fst->fs_typedep;
1040 	if (kif == NULL)
1041 		return (0);
1042 	shm->size = kif->kf_un.kf_file.kf_file_size;
1043 	shm->mode = kif->kf_un.kf_file.kf_file_mode;
1044 	return (0);
1045 }
1046 
1047 int
1048 procstat_get_vnode_info(struct procstat *procstat, struct filestat *fst,
1049     struct vnstat *vn, char *errbuf)
1050 {
1051 
1052 	assert(vn);
1053 	if (procstat->type == PROCSTAT_KVM) {
1054 		return (procstat_get_vnode_info_kvm(procstat->kd, fst, vn,
1055 		    errbuf));
1056 	} else if (procstat->type == PROCSTAT_SYSCTL ||
1057 		procstat->type == PROCSTAT_CORE) {
1058 		return (procstat_get_vnode_info_sysctl(fst, vn, errbuf));
1059 	} else {
1060 		warnx("unknown access method: %d", procstat->type);
1061 		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1062 		return (1);
1063 	}
1064 }
1065 
1066 static int
1067 procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst,
1068     struct vnstat *vn, char *errbuf)
1069 {
1070 	/* Filesystem specific handlers. */
1071 	#define FSTYPE(fst)     {#fst, fst##_filestat}
1072 	struct {
1073 		const char	*tag;
1074 		int		(*handler)(kvm_t *kd, struct vnode *vp,
1075 		    struct vnstat *vn);
1076 	} fstypes[] = {
1077 		FSTYPE(devfs),
1078 		FSTYPE(isofs),
1079 		FSTYPE(msdosfs),
1080 		FSTYPE(nfs),
1081 		FSTYPE(udf),
1082 		FSTYPE(ufs),
1083 #ifdef LIBPROCSTAT_ZFS
1084 		FSTYPE(zfs),
1085 #endif
1086 	};
1087 #define	NTYPES	(sizeof(fstypes) / sizeof(*fstypes))
1088 	struct vnode vnode;
1089 	char tagstr[12];
1090 	void *vp;
1091 	int error, found;
1092 	unsigned int i;
1093 
1094 	assert(kd);
1095 	assert(vn);
1096 	assert(fst);
1097 	vp = fst->fs_typedep;
1098 	if (vp == NULL)
1099 		goto fail;
1100 	error = kvm_read_all(kd, (unsigned long)vp, &vnode, sizeof(vnode));
1101 	if (error == 0) {
1102 		warnx("can't read vnode at %p", (void *)vp);
1103 		goto fail;
1104 	}
1105 	bzero(vn, sizeof(*vn));
1106 	vn->vn_type = vntype2psfsttype(vnode.v_type);
1107 	if (vnode.v_type == VNON || vnode.v_type == VBAD)
1108 		return (0);
1109 	error = kvm_read_all(kd, (unsigned long)vnode.v_tag, tagstr,
1110 	    sizeof(tagstr));
1111 	if (error == 0) {
1112 		warnx("can't read v_tag at %p", (void *)vp);
1113 		goto fail;
1114 	}
1115 	tagstr[sizeof(tagstr) - 1] = '\0';
1116 
1117 	/*
1118 	 * Find appropriate handler.
1119 	 */
1120 	for (i = 0, found = 0; i < NTYPES; i++)
1121 		if (!strcmp(fstypes[i].tag, tagstr)) {
1122 			if (fstypes[i].handler(kd, &vnode, vn) != 0) {
1123 				goto fail;
1124 			}
1125 			break;
1126 		}
1127 	if (i == NTYPES) {
1128 		snprintf(errbuf, _POSIX2_LINE_MAX, "?(%s)", tagstr);
1129 		return (1);
1130 	}
1131 	vn->vn_mntdir = getmnton(kd, vnode.v_mount);
1132 	if ((vnode.v_type == VBLK || vnode.v_type == VCHR) &&
1133 	    vnode.v_rdev != NULL){
1134 		vn->vn_dev = dev2udev(kd, vnode.v_rdev);
1135 		(void)kdevtoname(kd, vnode.v_rdev, vn->vn_devname);
1136 	} else {
1137 		vn->vn_dev = -1;
1138 	}
1139 	return (0);
1140 
1141 fail:
1142 	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1143 	return (1);
1144 }
1145 
1146 /*
1147  * kinfo vnode type to filestat translation.
1148  */
1149 static int
1150 kinfo_vtype2fst(int kfvtype)
1151 {
1152 	static struct {
1153 		int	kf_vtype;
1154 		int	fst_vtype;
1155 	} kfvtypes2fst[] = {
1156 		{ KF_VTYPE_VBAD, PS_FST_VTYPE_VBAD },
1157 		{ KF_VTYPE_VBLK, PS_FST_VTYPE_VBLK },
1158 		{ KF_VTYPE_VCHR, PS_FST_VTYPE_VCHR },
1159 		{ KF_VTYPE_VDIR, PS_FST_VTYPE_VDIR },
1160 		{ KF_VTYPE_VFIFO, PS_FST_VTYPE_VFIFO },
1161 		{ KF_VTYPE_VLNK, PS_FST_VTYPE_VLNK },
1162 		{ KF_VTYPE_VNON, PS_FST_VTYPE_VNON },
1163 		{ KF_VTYPE_VREG, PS_FST_VTYPE_VREG },
1164 		{ KF_VTYPE_VSOCK, PS_FST_VTYPE_VSOCK }
1165 	};
1166 #define	NKFVTYPES	(sizeof(kfvtypes2fst) / sizeof(*kfvtypes2fst))
1167 	unsigned int i;
1168 
1169 	for (i = 0; i < NKFVTYPES; i++)
1170 		if (kfvtypes2fst[i].kf_vtype == kfvtype)
1171 			break;
1172 	if (i == NKFVTYPES)
1173 		return (PS_FST_VTYPE_UNKNOWN);
1174 	return (kfvtypes2fst[i].fst_vtype);
1175 }
1176 
1177 static int
1178 procstat_get_vnode_info_sysctl(struct filestat *fst, struct vnstat *vn,
1179     char *errbuf)
1180 {
1181 	struct statfs stbuf;
1182 	struct kinfo_file *kif;
1183 	struct kinfo_vmentry *kve;
1184 	uint64_t fileid;
1185 	uint64_t size;
1186 	char *name, *path;
1187 	uint32_t fsid;
1188 	uint16_t mode;
1189 	uint32_t rdev;
1190 	int vntype;
1191 	int status;
1192 
1193 	assert(fst);
1194 	assert(vn);
1195 	bzero(vn, sizeof(*vn));
1196 	if (fst->fs_typedep == NULL)
1197 		return (1);
1198 	if (fst->fs_uflags & PS_FST_UFLAG_MMAP) {
1199 		kve = fst->fs_typedep;
1200 		fileid = kve->kve_vn_fileid;
1201 		fsid = kve->kve_vn_fsid;
1202 		mode = kve->kve_vn_mode;
1203 		path = kve->kve_path;
1204 		rdev = kve->kve_vn_rdev;
1205 		size = kve->kve_vn_size;
1206 		vntype = kinfo_vtype2fst(kve->kve_vn_type);
1207 		status = kve->kve_status;
1208 	} else {
1209 		kif = fst->fs_typedep;
1210 		fileid = kif->kf_un.kf_file.kf_file_fileid;
1211 		fsid = kif->kf_un.kf_file.kf_file_fsid;
1212 		mode = kif->kf_un.kf_file.kf_file_mode;
1213 		path = kif->kf_path;
1214 		rdev = kif->kf_un.kf_file.kf_file_rdev;
1215 		size = kif->kf_un.kf_file.kf_file_size;
1216 		vntype = kinfo_vtype2fst(kif->kf_vnode_type);
1217 		status = kif->kf_status;
1218 	}
1219 	vn->vn_type = vntype;
1220 	if (vntype == PS_FST_VTYPE_VNON || vntype == PS_FST_VTYPE_VBAD)
1221 		return (0);
1222 	if ((status & KF_ATTR_VALID) == 0) {
1223 		snprintf(errbuf, _POSIX2_LINE_MAX, "? (no info available)");
1224 		return (1);
1225 	}
1226 	if (path && *path) {
1227 		statfs(path, &stbuf);
1228 		vn->vn_mntdir = strdup(stbuf.f_mntonname);
1229 	} else
1230 		vn->vn_mntdir = strdup("-");
1231 	vn->vn_dev = rdev;
1232 	if (vntype == PS_FST_VTYPE_VBLK) {
1233 		name = devname(rdev, S_IFBLK);
1234 		if (name != NULL)
1235 			strlcpy(vn->vn_devname, name,
1236 			    sizeof(vn->vn_devname));
1237 	} else if (vntype == PS_FST_VTYPE_VCHR) {
1238 		name = devname(vn->vn_dev, S_IFCHR);
1239 		if (name != NULL)
1240 			strlcpy(vn->vn_devname, name,
1241 			    sizeof(vn->vn_devname));
1242 	}
1243 	vn->vn_fsid = fsid;
1244 	vn->vn_fileid = fileid;
1245 	vn->vn_size = size;
1246 	vn->vn_mode = mode;
1247 	return (0);
1248 }
1249 
1250 int
1251 procstat_get_socket_info(struct procstat *procstat, struct filestat *fst,
1252     struct sockstat *sock, char *errbuf)
1253 {
1254 
1255 	assert(sock);
1256 	if (procstat->type == PROCSTAT_KVM) {
1257 		return (procstat_get_socket_info_kvm(procstat->kd, fst, sock,
1258 		    errbuf));
1259 	} else if (procstat->type == PROCSTAT_SYSCTL ||
1260 		procstat->type == PROCSTAT_CORE) {
1261 		return (procstat_get_socket_info_sysctl(fst, sock, errbuf));
1262 	} else {
1263 		warnx("unknown access method: %d", procstat->type);
1264 		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1265 		return (1);
1266 	}
1267 }
1268 
1269 static int
1270 procstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst,
1271     struct sockstat *sock, char *errbuf)
1272 {
1273 	struct domain dom;
1274 	struct inpcb inpcb;
1275 	struct protosw proto;
1276 	struct socket s;
1277 	struct unpcb unpcb;
1278 	ssize_t len;
1279 	void *so;
1280 
1281 	assert(kd);
1282 	assert(sock);
1283 	assert(fst);
1284 	bzero(sock, sizeof(*sock));
1285 	so = fst->fs_typedep;
1286 	if (so == NULL)
1287 		goto fail;
1288 	sock->so_addr = (uintptr_t)so;
1289 	/* fill in socket */
1290 	if (!kvm_read_all(kd, (unsigned long)so, &s,
1291 	    sizeof(struct socket))) {
1292 		warnx("can't read sock at %p", (void *)so);
1293 		goto fail;
1294 	}
1295 	/* fill in protosw entry */
1296 	if (!kvm_read_all(kd, (unsigned long)s.so_proto, &proto,
1297 	    sizeof(struct protosw))) {
1298 		warnx("can't read protosw at %p", (void *)s.so_proto);
1299 		goto fail;
1300 	}
1301 	/* fill in domain */
1302 	if (!kvm_read_all(kd, (unsigned long)proto.pr_domain, &dom,
1303 	    sizeof(struct domain))) {
1304 		warnx("can't read domain at %p",
1305 		    (void *)proto.pr_domain);
1306 		goto fail;
1307 	}
1308 	if ((len = kvm_read(kd, (unsigned long)dom.dom_name, sock->dname,
1309 	    sizeof(sock->dname) - 1)) < 0) {
1310 		warnx("can't read domain name at %p", (void *)dom.dom_name);
1311 		sock->dname[0] = '\0';
1312 	}
1313 	else
1314 		sock->dname[len] = '\0';
1315 
1316 	/*
1317 	 * Fill in known data.
1318 	 */
1319 	sock->type = s.so_type;
1320 	sock->proto = proto.pr_protocol;
1321 	sock->dom_family = dom.dom_family;
1322 	sock->so_pcb = (uintptr_t)s.so_pcb;
1323 
1324 	/*
1325 	 * Protocol specific data.
1326 	 */
1327 	switch(dom.dom_family) {
1328 	case AF_INET:
1329 	case AF_INET6:
1330 		if (proto.pr_protocol == IPPROTO_TCP) {
1331 			if (s.so_pcb) {
1332 				if (kvm_read(kd, (u_long)s.so_pcb,
1333 				    (char *)&inpcb, sizeof(struct inpcb))
1334 				    != sizeof(struct inpcb)) {
1335 					warnx("can't read inpcb at %p",
1336 					    (void *)s.so_pcb);
1337 				} else
1338 					sock->inp_ppcb =
1339 					    (uintptr_t)inpcb.inp_ppcb;
1340 			}
1341 		}
1342 		break;
1343 	case AF_UNIX:
1344 		if (s.so_pcb) {
1345 			if (kvm_read(kd, (u_long)s.so_pcb, (char *)&unpcb,
1346 			    sizeof(struct unpcb)) != sizeof(struct unpcb)){
1347 				warnx("can't read unpcb at %p",
1348 				    (void *)s.so_pcb);
1349 			} else if (unpcb.unp_conn) {
1350 				sock->so_rcv_sb_state = s.so_rcv.sb_state;
1351 				sock->so_snd_sb_state = s.so_snd.sb_state;
1352 				sock->unp_conn = (uintptr_t)unpcb.unp_conn;
1353 			}
1354 		}
1355 		break;
1356 	default:
1357 		break;
1358 	}
1359 	return (0);
1360 
1361 fail:
1362 	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1363 	return (1);
1364 }
1365 
1366 static int
1367 procstat_get_socket_info_sysctl(struct filestat *fst, struct sockstat *sock,
1368     char *errbuf __unused)
1369 {
1370 	struct kinfo_file *kif;
1371 
1372 	assert(sock);
1373 	assert(fst);
1374 	bzero(sock, sizeof(*sock));
1375 	kif = fst->fs_typedep;
1376 	if (kif == NULL)
1377 		return (0);
1378 
1379 	/*
1380 	 * Fill in known data.
1381 	 */
1382 	sock->type = kif->kf_sock_type;
1383 	sock->proto = kif->kf_sock_protocol;
1384 	sock->dom_family = kif->kf_sock_domain;
1385 	sock->so_pcb = kif->kf_un.kf_sock.kf_sock_pcb;
1386 	strlcpy(sock->dname, kif->kf_path, sizeof(sock->dname));
1387 	bcopy(&kif->kf_sa_local, &sock->sa_local, kif->kf_sa_local.ss_len);
1388 	bcopy(&kif->kf_sa_peer, &sock->sa_peer, kif->kf_sa_peer.ss_len);
1389 
1390 	/*
1391 	 * Protocol specific data.
1392 	 */
1393 	switch(sock->dom_family) {
1394 	case AF_INET:
1395 	case AF_INET6:
1396 		if (sock->proto == IPPROTO_TCP)
1397 			sock->inp_ppcb = kif->kf_un.kf_sock.kf_sock_inpcb;
1398 		break;
1399 	case AF_UNIX:
1400 		if (kif->kf_un.kf_sock.kf_sock_unpconn != 0) {
1401 				sock->so_rcv_sb_state =
1402 				    kif->kf_un.kf_sock.kf_sock_rcv_sb_state;
1403 				sock->so_snd_sb_state =
1404 				    kif->kf_un.kf_sock.kf_sock_snd_sb_state;
1405 				sock->unp_conn =
1406 				    kif->kf_un.kf_sock.kf_sock_unpconn;
1407 		}
1408 		break;
1409 	default:
1410 		break;
1411 	}
1412 	return (0);
1413 }
1414 
1415 /*
1416  * Descriptor flags to filestat translation.
1417  */
1418 static int
1419 to_filestat_flags(int flags)
1420 {
1421 	static struct {
1422 		int flag;
1423 		int fst_flag;
1424 	} fstflags[] = {
1425 		{ FREAD, PS_FST_FFLAG_READ },
1426 		{ FWRITE, PS_FST_FFLAG_WRITE },
1427 		{ O_APPEND, PS_FST_FFLAG_APPEND },
1428 		{ O_ASYNC, PS_FST_FFLAG_ASYNC },
1429 		{ O_CREAT, PS_FST_FFLAG_CREAT },
1430 		{ O_DIRECT, PS_FST_FFLAG_DIRECT },
1431 		{ O_EXCL, PS_FST_FFLAG_EXCL },
1432 		{ O_EXEC, PS_FST_FFLAG_EXEC },
1433 		{ O_EXLOCK, PS_FST_FFLAG_EXLOCK },
1434 		{ O_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW },
1435 		{ O_NONBLOCK, PS_FST_FFLAG_NONBLOCK },
1436 		{ O_SHLOCK, PS_FST_FFLAG_SHLOCK },
1437 		{ O_SYNC, PS_FST_FFLAG_SYNC },
1438 		{ O_TRUNC, PS_FST_FFLAG_TRUNC }
1439 	};
1440 #define NFSTFLAGS	(sizeof(fstflags) / sizeof(*fstflags))
1441 	int fst_flags;
1442 	unsigned int i;
1443 
1444 	fst_flags = 0;
1445 	for (i = 0; i < NFSTFLAGS; i++)
1446 		if (flags & fstflags[i].flag)
1447 			fst_flags |= fstflags[i].fst_flag;
1448 	return (fst_flags);
1449 }
1450 
1451 /*
1452  * Vnode type to filestate translation.
1453  */
1454 static int
1455 vntype2psfsttype(int type)
1456 {
1457 	static struct {
1458 		int	vtype;
1459 		int	fst_vtype;
1460 	} vt2fst[] = {
1461 		{ VBAD, PS_FST_VTYPE_VBAD },
1462 		{ VBLK, PS_FST_VTYPE_VBLK },
1463 		{ VCHR, PS_FST_VTYPE_VCHR },
1464 		{ VDIR, PS_FST_VTYPE_VDIR },
1465 		{ VFIFO, PS_FST_VTYPE_VFIFO },
1466 		{ VLNK, PS_FST_VTYPE_VLNK },
1467 		{ VNON, PS_FST_VTYPE_VNON },
1468 		{ VREG, PS_FST_VTYPE_VREG },
1469 		{ VSOCK, PS_FST_VTYPE_VSOCK }
1470 	};
1471 #define	NVFTYPES	(sizeof(vt2fst) / sizeof(*vt2fst))
1472 	unsigned int i, fst_type;
1473 
1474 	fst_type = PS_FST_VTYPE_UNKNOWN;
1475 	for (i = 0; i < NVFTYPES; i++) {
1476 		if (type == vt2fst[i].vtype) {
1477 			fst_type = vt2fst[i].fst_vtype;
1478 			break;
1479 		}
1480 	}
1481 	return (fst_type);
1482 }
1483 
1484 static char *
1485 getmnton(kvm_t *kd, struct mount *m)
1486 {
1487 	struct mount mnt;
1488 	static struct mtab {
1489 		struct mtab *next;
1490 		struct mount *m;
1491 		char mntonname[MNAMELEN + 1];
1492 	} *mhead = NULL;
1493 	struct mtab *mt;
1494 
1495 	for (mt = mhead; mt != NULL; mt = mt->next)
1496 		if (m == mt->m)
1497 			return (mt->mntonname);
1498 	if (!kvm_read_all(kd, (unsigned long)m, &mnt, sizeof(struct mount))) {
1499 		warnx("can't read mount table at %p", (void *)m);
1500 		return (NULL);
1501 	}
1502 	if ((mt = malloc(sizeof (struct mtab))) == NULL)
1503 		err(1, NULL);
1504 	mt->m = m;
1505 	bcopy(&mnt.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN);
1506 	mt->mntonname[MNAMELEN] = '\0';
1507 	mt->next = mhead;
1508 	mhead = mt;
1509 	return (mt->mntonname);
1510 }
1511 
1512 static struct kinfo_vmentry *
1513 kinfo_getvmmap_core(struct procstat_core *core, int *cntp)
1514 {
1515 	int cnt;
1516 	size_t len;
1517 	char *buf, *bp, *eb;
1518 	struct kinfo_vmentry *kiv, *kp, *kv;
1519 
1520 	buf = procstat_core_get(core, PSC_TYPE_VMMAP, NULL, &len);
1521 	if (buf == NULL)
1522 		return (NULL);
1523 
1524 	/*
1525 	 * XXXMG: The code below is just copy&past from libutil.
1526 	 * The code duplication can be avoided if libutil
1527 	 * is extended to provide something like:
1528 	 *   struct kinfo_vmentry *kinfo_getvmmap_from_buf(const char *buf,
1529 	 *       size_t len, int *cntp);
1530 	 */
1531 
1532 	/* Pass 1: count items */
1533 	cnt = 0;
1534 	bp = buf;
1535 	eb = buf + len;
1536 	while (bp < eb) {
1537 		kv = (struct kinfo_vmentry *)(uintptr_t)bp;
1538 		bp += kv->kve_structsize;
1539 		cnt++;
1540 	}
1541 
1542 	kiv = calloc(cnt, sizeof(*kiv));
1543 	if (kiv == NULL) {
1544 		free(buf);
1545 		return (NULL);
1546 	}
1547 	bp = buf;
1548 	eb = buf + len;
1549 	kp = kiv;
1550 	/* Pass 2: unpack */
1551 	while (bp < eb) {
1552 		kv = (struct kinfo_vmentry *)(uintptr_t)bp;
1553 		/* Copy/expand into pre-zeroed buffer */
1554 		memcpy(kp, kv, kv->kve_structsize);
1555 		/* Advance to next packed record */
1556 		bp += kv->kve_structsize;
1557 		/* Set field size to fixed length, advance */
1558 		kp->kve_structsize = sizeof(*kp);
1559 		kp++;
1560 	}
1561 	free(buf);
1562 	*cntp = cnt;
1563 	return (kiv);	/* Caller must free() return value */
1564 }
1565 
1566 struct kinfo_vmentry *
1567 procstat_getvmmap(struct procstat *procstat, struct kinfo_proc *kp,
1568     unsigned int *cntp)
1569 {
1570 	switch(procstat->type) {
1571 	case PROCSTAT_KVM:
1572 		warnx("kvm method is not supported");
1573 		return (NULL);
1574 	case PROCSTAT_SYSCTL:
1575 		return (kinfo_getvmmap(kp->ki_pid, cntp));
1576 	case PROCSTAT_CORE:
1577 		return (kinfo_getvmmap_core(procstat->core, cntp));
1578 	default:
1579 		warnx("unknown access method: %d", procstat->type);
1580 		return (NULL);
1581 	}
1582 }
1583 
1584 void
1585 procstat_freevmmap(struct procstat *procstat __unused,
1586     struct kinfo_vmentry *vmmap)
1587 {
1588 
1589 	free(vmmap);
1590 }
1591