xref: /freebsd/lib/libprocstat/libprocstat.c (revision ddd5b8e9b4d8957fce018c520657cdfa4ecffad3)
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 
100 int     statfs(const char *, struct statfs *);	/* XXX */
101 
102 #define	PROCSTAT_KVM	1
103 #define	PROCSTAT_SYSCTL	2
104 
105 static char	*getmnton(kvm_t *kd, struct mount *m);
106 static struct filestat_list	*procstat_getfiles_kvm(
107     struct procstat *procstat, struct kinfo_proc *kp, int mmapped);
108 static struct filestat_list	*procstat_getfiles_sysctl(
109     struct procstat *procstat, struct kinfo_proc *kp, int mmapped);
110 static int	procstat_get_pipe_info_sysctl(struct filestat *fst,
111     struct pipestat *pipe, char *errbuf);
112 static int	procstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst,
113     struct pipestat *pipe, char *errbuf);
114 static int	procstat_get_pts_info_sysctl(struct filestat *fst,
115     struct ptsstat *pts, char *errbuf);
116 static int	procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst,
117     struct ptsstat *pts, char *errbuf);
118 static int	procstat_get_shm_info_sysctl(struct filestat *fst,
119     struct shmstat *shm, char *errbuf);
120 static int	procstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst,
121     struct shmstat *shm, char *errbuf);
122 static int	procstat_get_socket_info_sysctl(struct filestat *fst,
123     struct sockstat *sock, char *errbuf);
124 static int	procstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst,
125     struct sockstat *sock, char *errbuf);
126 static int	to_filestat_flags(int flags);
127 static int	procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst,
128     struct vnstat *vn, char *errbuf);
129 static int	procstat_get_vnode_info_sysctl(struct filestat *fst,
130     struct vnstat *vn, char *errbuf);
131 static int	vntype2psfsttype(int type);
132 
133 void
134 procstat_close(struct procstat *procstat)
135 {
136 
137 	assert(procstat);
138 	if (procstat->type == PROCSTAT_KVM)
139 		kvm_close(procstat->kd);
140 	free(procstat);
141 }
142 
143 struct procstat *
144 procstat_open_sysctl(void)
145 {
146 	struct procstat *procstat;
147 
148 	procstat = calloc(1, sizeof(*procstat));
149 	if (procstat == NULL) {
150 		warn("malloc()");
151 		return (NULL);
152 	}
153 	procstat->type = PROCSTAT_SYSCTL;
154 	return (procstat);
155 }
156 
157 struct procstat *
158 procstat_open_kvm(const char *nlistf, const char *memf)
159 {
160 	struct procstat *procstat;
161 	kvm_t *kd;
162 	char buf[_POSIX2_LINE_MAX];
163 
164 	procstat = calloc(1, sizeof(*procstat));
165 	if (procstat == NULL) {
166 		warn("malloc()");
167 		return (NULL);
168 	}
169 	kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf);
170 	if (kd == NULL) {
171 		warnx("kvm_openfiles(): %s", buf);
172 		free(procstat);
173 		return (NULL);
174 	}
175 	procstat->type = PROCSTAT_KVM;
176 	procstat->kd = kd;
177 	return (procstat);
178 }
179 
180 struct kinfo_proc *
181 procstat_getprocs(struct procstat *procstat, int what, int arg,
182     unsigned int *count)
183 {
184 	struct kinfo_proc *p0, *p;
185 	size_t len;
186 	int name[4];
187 	int cnt;
188 	int error;
189 
190 	assert(procstat);
191 	assert(count);
192 	p = NULL;
193 	if (procstat->type == PROCSTAT_KVM) {
194 		*count = 0;
195 		p0 = kvm_getprocs(procstat->kd, what, arg, &cnt);
196 		if (p0 == NULL || cnt <= 0)
197 			return (NULL);
198 		*count = cnt;
199 		len = *count * sizeof(*p);
200 		p = malloc(len);
201 		if (p == NULL) {
202 			warnx("malloc(%zu)", len);
203 			goto fail;
204 		}
205 		bcopy(p0, p, len);
206 		return (p);
207 	} else if (procstat->type == PROCSTAT_SYSCTL) {
208 		len = 0;
209 		name[0] = CTL_KERN;
210 		name[1] = KERN_PROC;
211 		name[2] = what;
212 		name[3] = arg;
213 		error = sysctl(name, 4, NULL, &len, NULL, 0);
214 		if (error < 0 && errno != EPERM) {
215 			warn("sysctl(kern.proc)");
216 			goto fail;
217 		}
218 		if (len == 0) {
219 			warnx("no processes?");
220 			goto fail;
221 		}
222 		p = malloc(len);
223 		if (p == NULL) {
224 			warnx("malloc(%zu)", len);
225 			goto fail;
226 		}
227 		error = sysctl(name, 4, p, &len, NULL, 0);
228 		if (error < 0 && errno != EPERM) {
229 			warn("sysctl(kern.proc)");
230 			goto fail;
231 		}
232 		/* Perform simple consistency checks. */
233 		if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) {
234 			warnx("kinfo_proc structure size mismatch");
235 			goto fail;
236 		}
237 		*count = len / sizeof(*p);
238 		return (p);
239 	} else {
240 		warnx("unknown access method: %d", procstat->type);
241 		return (NULL);
242 	}
243 fail:
244 	if (p)
245 		free(p);
246 	return (NULL);
247 }
248 
249 void
250 procstat_freeprocs(struct procstat *procstat __unused, struct kinfo_proc *p)
251 {
252 
253 	if (p != NULL)
254 		free(p);
255 	p = NULL;
256 }
257 
258 struct filestat_list *
259 procstat_getfiles(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
260 {
261 
262 	if (procstat->type == PROCSTAT_SYSCTL)
263 		return (procstat_getfiles_sysctl(procstat, kp, mmapped));
264 	else if (procstat->type == PROCSTAT_KVM)
265 		return (procstat_getfiles_kvm(procstat, kp, mmapped));
266 	else
267 		return (NULL);
268 }
269 
270 void
271 procstat_freefiles(struct procstat *procstat, struct filestat_list *head)
272 {
273 	struct filestat *fst, *tmp;
274 
275 	STAILQ_FOREACH_SAFE(fst, head, next, tmp) {
276 		if (fst->fs_path != NULL)
277 			free(fst->fs_path);
278 		free(fst);
279 	}
280 	free(head);
281 	if (procstat->vmentries != NULL) {
282 		free(procstat->vmentries);
283 		procstat->vmentries = NULL;
284 	}
285 	if (procstat->files != NULL) {
286 		free(procstat->files);
287 		procstat->files = NULL;
288 	}
289 }
290 
291 static struct filestat *
292 filestat_new_entry(void *typedep, int type, int fd, int fflags, int uflags,
293     int refcount, off_t offset, char *path, cap_rights_t cap_rights)
294 {
295 	struct filestat *entry;
296 
297 	entry = calloc(1, sizeof(*entry));
298 	if (entry == NULL) {
299 		warn("malloc()");
300 		return (NULL);
301 	}
302 	entry->fs_typedep = typedep;
303 	entry->fs_fflags = fflags;
304 	entry->fs_uflags = uflags;
305 	entry->fs_fd = fd;
306 	entry->fs_type = type;
307 	entry->fs_ref_count = refcount;
308 	entry->fs_offset = offset;
309 	entry->fs_path = path;
310 	entry->fs_cap_rights = cap_rights;
311 	return (entry);
312 }
313 
314 static struct vnode *
315 getctty(kvm_t *kd, struct kinfo_proc *kp)
316 {
317 	struct pgrp pgrp;
318 	struct proc proc;
319 	struct session sess;
320 	int error;
321 
322 	assert(kp);
323 	error = kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc,
324 	    sizeof(proc));
325 	if (error == 0) {
326 		warnx("can't read proc struct at %p for pid %d",
327 		    kp->ki_paddr, kp->ki_pid);
328 		return (NULL);
329 	}
330 	if (proc.p_pgrp == NULL)
331 		return (NULL);
332 	error = kvm_read_all(kd, (unsigned long)proc.p_pgrp, &pgrp,
333 	    sizeof(pgrp));
334 	if (error == 0) {
335 		warnx("can't read pgrp struct at %p for pid %d",
336 		    proc.p_pgrp, kp->ki_pid);
337 		return (NULL);
338 	}
339 	error = kvm_read_all(kd, (unsigned long)pgrp.pg_session, &sess,
340 	    sizeof(sess));
341 	if (error == 0) {
342 		warnx("can't read session struct at %p for pid %d",
343 		    pgrp.pg_session, kp->ki_pid);
344 		return (NULL);
345 	}
346 	return (sess.s_ttyvp);
347 }
348 
349 static struct filestat_list *
350 procstat_getfiles_kvm(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
351 {
352 	struct file file;
353 	struct filedesc filed;
354 	struct vm_map_entry vmentry;
355 	struct vm_object object;
356 	struct vmspace vmspace;
357 	vm_map_entry_t entryp;
358 	vm_map_t map;
359 	vm_object_t objp;
360 	struct vnode *vp;
361 	struct file **ofiles;
362 	struct filestat *entry;
363 	struct filestat_list *head;
364 	kvm_t *kd;
365 	void *data;
366 	int i, fflags;
367 	int prot, type;
368 	unsigned int nfiles;
369 
370 	assert(procstat);
371 	kd = procstat->kd;
372 	if (kd == NULL)
373 		return (NULL);
374 	if (kp->ki_fd == NULL)
375 		return (NULL);
376 	if (!kvm_read_all(kd, (unsigned long)kp->ki_fd, &filed,
377 	    sizeof(filed))) {
378 		warnx("can't read filedesc at %p", (void *)kp->ki_fd);
379 		return (NULL);
380 	}
381 
382 	/*
383 	 * Allocate list head.
384 	 */
385 	head = malloc(sizeof(*head));
386 	if (head == NULL)
387 		return (NULL);
388 	STAILQ_INIT(head);
389 
390 	/* root directory vnode, if one. */
391 	if (filed.fd_rdir) {
392 		entry = filestat_new_entry(filed.fd_rdir, PS_FST_TYPE_VNODE, -1,
393 		    PS_FST_FFLAG_READ, PS_FST_UFLAG_RDIR, 0, 0, NULL, 0);
394 		if (entry != NULL)
395 			STAILQ_INSERT_TAIL(head, entry, next);
396 	}
397 	/* current working directory vnode. */
398 	if (filed.fd_cdir) {
399 		entry = filestat_new_entry(filed.fd_cdir, PS_FST_TYPE_VNODE, -1,
400 		    PS_FST_FFLAG_READ, PS_FST_UFLAG_CDIR, 0, 0, NULL, 0);
401 		if (entry != NULL)
402 			STAILQ_INSERT_TAIL(head, entry, next);
403 	}
404 	/* jail root, if any. */
405 	if (filed.fd_jdir) {
406 		entry = filestat_new_entry(filed.fd_jdir, PS_FST_TYPE_VNODE, -1,
407 		    PS_FST_FFLAG_READ, PS_FST_UFLAG_JAIL, 0, 0, NULL, 0);
408 		if (entry != NULL)
409 			STAILQ_INSERT_TAIL(head, entry, next);
410 	}
411 	/* ktrace vnode, if one */
412 	if (kp->ki_tracep) {
413 		entry = filestat_new_entry(kp->ki_tracep, PS_FST_TYPE_VNODE, -1,
414 		    PS_FST_FFLAG_READ | PS_FST_FFLAG_WRITE,
415 		    PS_FST_UFLAG_TRACE, 0, 0, NULL, 0);
416 		if (entry != NULL)
417 			STAILQ_INSERT_TAIL(head, entry, next);
418 	}
419 	/* text vnode, if one */
420 	if (kp->ki_textvp) {
421 		entry = filestat_new_entry(kp->ki_textvp, PS_FST_TYPE_VNODE, -1,
422 		    PS_FST_FFLAG_READ, PS_FST_UFLAG_TEXT, 0, 0, NULL, 0);
423 		if (entry != NULL)
424 			STAILQ_INSERT_TAIL(head, entry, next);
425 	}
426 	/* Controlling terminal. */
427 	if ((vp = getctty(kd, kp)) != NULL) {
428 		entry = filestat_new_entry(vp, PS_FST_TYPE_VNODE, -1,
429 		    PS_FST_FFLAG_READ | PS_FST_FFLAG_WRITE,
430 		    PS_FST_UFLAG_CTTY, 0, 0, NULL, 0);
431 		if (entry != NULL)
432 			STAILQ_INSERT_TAIL(head, entry, next);
433 	}
434 
435 	nfiles = filed.fd_lastfile + 1;
436 	ofiles = malloc(nfiles * sizeof(struct file *));
437 	if (ofiles == NULL) {
438 		warn("malloc(%zu)", nfiles * sizeof(struct file *));
439 		goto do_mmapped;
440 	}
441 	if (!kvm_read_all(kd, (unsigned long)filed.fd_ofiles, ofiles,
442 	    nfiles * sizeof(struct file *))) {
443 		warnx("cannot read file structures at %p",
444 		    (void *)filed.fd_ofiles);
445 		free(ofiles);
446 		goto do_mmapped;
447 	}
448 	for (i = 0; i <= filed.fd_lastfile; i++) {
449 		if (ofiles[i] == NULL)
450 			continue;
451 		if (!kvm_read_all(kd, (unsigned long)ofiles[i], &file,
452 		    sizeof(struct file))) {
453 			warnx("can't read file %d at %p", i,
454 			    (void *)ofiles[i]);
455 			continue;
456 		}
457 		switch (file.f_type) {
458 		case DTYPE_VNODE:
459 			type = PS_FST_TYPE_VNODE;
460 			data = file.f_vnode;
461 			break;
462 		case DTYPE_SOCKET:
463 			type = PS_FST_TYPE_SOCKET;
464 			data = file.f_data;
465 			break;
466 		case DTYPE_PIPE:
467 			type = PS_FST_TYPE_PIPE;
468 			data = file.f_data;
469 			break;
470 		case DTYPE_FIFO:
471 			type = PS_FST_TYPE_FIFO;
472 			data = file.f_vnode;
473 			break;
474 #ifdef DTYPE_PTS
475 		case DTYPE_PTS:
476 			type = PS_FST_TYPE_PTS;
477 			data = file.f_data;
478 			break;
479 #endif
480 		case DTYPE_SHM:
481 			type = PS_FST_TYPE_SHM;
482 			data = file.f_data;
483 			break;
484 		default:
485 			continue;
486 		}
487 		/* XXXRW: No capability rights support for kvm yet. */
488 		entry = filestat_new_entry(data, type, i,
489 		    to_filestat_flags(file.f_flag), 0, 0, 0, NULL, 0);
490 		if (entry != NULL)
491 			STAILQ_INSERT_TAIL(head, entry, next);
492 	}
493 	free(ofiles);
494 
495 do_mmapped:
496 
497 	/*
498 	 * Process mmapped files if requested.
499 	 */
500 	if (mmapped) {
501 		if (!kvm_read_all(kd, (unsigned long)kp->ki_vmspace, &vmspace,
502 		    sizeof(vmspace))) {
503 			warnx("can't read vmspace at %p",
504 			    (void *)kp->ki_vmspace);
505 			goto exit;
506 		}
507 		map = &vmspace.vm_map;
508 
509 		for (entryp = map->header.next;
510 		    entryp != &kp->ki_vmspace->vm_map.header;
511 		    entryp = vmentry.next) {
512 			if (!kvm_read_all(kd, (unsigned long)entryp, &vmentry,
513 			    sizeof(vmentry))) {
514 				warnx("can't read vm_map_entry at %p",
515 				    (void *)entryp);
516 				continue;
517 			}
518 			if (vmentry.eflags & MAP_ENTRY_IS_SUB_MAP)
519 				continue;
520 			if ((objp = vmentry.object.vm_object) == NULL)
521 				continue;
522 			for (; objp; objp = object.backing_object) {
523 				if (!kvm_read_all(kd, (unsigned long)objp,
524 				    &object, sizeof(object))) {
525 					warnx("can't read vm_object at %p",
526 					    (void *)objp);
527 					break;
528 				}
529 			}
530 
531 			/* We want only vnode objects. */
532 			if (object.type != OBJT_VNODE)
533 				continue;
534 
535 			prot = vmentry.protection;
536 			fflags = 0;
537 			if (prot & VM_PROT_READ)
538 				fflags = PS_FST_FFLAG_READ;
539 			if ((vmentry.eflags & MAP_ENTRY_COW) == 0 &&
540 			    prot & VM_PROT_WRITE)
541 				fflags |= PS_FST_FFLAG_WRITE;
542 
543 			/*
544 			 * Create filestat entry.
545 			 */
546 			entry = filestat_new_entry(object.handle,
547 			    PS_FST_TYPE_VNODE, -1, fflags,
548 			    PS_FST_UFLAG_MMAP, 0, 0, NULL, 0);
549 			if (entry != NULL)
550 				STAILQ_INSERT_TAIL(head, entry, next);
551 		}
552 	}
553 exit:
554 	return (head);
555 }
556 
557 /*
558  * kinfo types to filestat translation.
559  */
560 static int
561 kinfo_type2fst(int kftype)
562 {
563 	static struct {
564 		int	kf_type;
565 		int	fst_type;
566 	} kftypes2fst[] = {
567 		{ KF_TYPE_CRYPTO, PS_FST_TYPE_CRYPTO },
568 		{ KF_TYPE_FIFO, PS_FST_TYPE_FIFO },
569 		{ KF_TYPE_KQUEUE, PS_FST_TYPE_KQUEUE },
570 		{ KF_TYPE_MQUEUE, PS_FST_TYPE_MQUEUE },
571 		{ KF_TYPE_NONE, PS_FST_TYPE_NONE },
572 		{ KF_TYPE_PIPE, PS_FST_TYPE_PIPE },
573 		{ KF_TYPE_PTS, PS_FST_TYPE_PTS },
574 		{ KF_TYPE_SEM, PS_FST_TYPE_SEM },
575 		{ KF_TYPE_SHM, PS_FST_TYPE_SHM },
576 		{ KF_TYPE_SOCKET, PS_FST_TYPE_SOCKET },
577 		{ KF_TYPE_VNODE, PS_FST_TYPE_VNODE },
578 		{ KF_TYPE_UNKNOWN, PS_FST_TYPE_UNKNOWN }
579 	};
580 #define NKFTYPES	(sizeof(kftypes2fst) / sizeof(*kftypes2fst))
581 	unsigned int i;
582 
583 	for (i = 0; i < NKFTYPES; i++)
584 		if (kftypes2fst[i].kf_type == kftype)
585 			break;
586 	if (i == NKFTYPES)
587 		return (PS_FST_TYPE_UNKNOWN);
588 	return (kftypes2fst[i].fst_type);
589 }
590 
591 /*
592  * kinfo flags to filestat translation.
593  */
594 static int
595 kinfo_fflags2fst(int kfflags)
596 {
597 	static struct {
598 		int	kf_flag;
599 		int	fst_flag;
600 	} kfflags2fst[] = {
601 		{ KF_FLAG_APPEND, PS_FST_FFLAG_APPEND },
602 		{ KF_FLAG_ASYNC, PS_FST_FFLAG_ASYNC },
603 		{ KF_FLAG_CREAT, PS_FST_FFLAG_CREAT },
604 		{ KF_FLAG_DIRECT, PS_FST_FFLAG_DIRECT },
605 		{ KF_FLAG_EXCL, PS_FST_FFLAG_EXCL },
606 		{ KF_FLAG_EXEC, PS_FST_FFLAG_EXEC },
607 		{ KF_FLAG_EXLOCK, PS_FST_FFLAG_EXLOCK },
608 		{ KF_FLAG_FSYNC, PS_FST_FFLAG_SYNC },
609 		{ KF_FLAG_HASLOCK, PS_FST_FFLAG_HASLOCK },
610 		{ KF_FLAG_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW },
611 		{ KF_FLAG_NONBLOCK, PS_FST_FFLAG_NONBLOCK },
612 		{ KF_FLAG_READ, PS_FST_FFLAG_READ },
613 		{ KF_FLAG_SHLOCK, PS_FST_FFLAG_SHLOCK },
614 		{ KF_FLAG_TRUNC, PS_FST_FFLAG_TRUNC },
615 		{ KF_FLAG_WRITE, PS_FST_FFLAG_WRITE }
616 	};
617 #define NKFFLAGS	(sizeof(kfflags2fst) / sizeof(*kfflags2fst))
618 	unsigned int i;
619 	int flags;
620 
621 	flags = 0;
622 	for (i = 0; i < NKFFLAGS; i++)
623 		if ((kfflags & kfflags2fst[i].kf_flag) != 0)
624 			flags |= kfflags2fst[i].fst_flag;
625 	return (flags);
626 }
627 
628 static int
629 kinfo_uflags2fst(int fd)
630 {
631 
632 	switch (fd) {
633 	case KF_FD_TYPE_CTTY:
634 		return (PS_FST_UFLAG_CTTY);
635 	case KF_FD_TYPE_CWD:
636 		return (PS_FST_UFLAG_CDIR);
637 	case KF_FD_TYPE_JAIL:
638 		return (PS_FST_UFLAG_JAIL);
639 	case KF_FD_TYPE_TEXT:
640 		return (PS_FST_UFLAG_TEXT);
641 	case KF_FD_TYPE_TRACE:
642 		return (PS_FST_UFLAG_TRACE);
643 	case KF_FD_TYPE_ROOT:
644 		return (PS_FST_UFLAG_RDIR);
645 	}
646 	return (0);
647 }
648 
649 static struct filestat_list *
650 procstat_getfiles_sysctl(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
651 {
652 	struct kinfo_file *kif, *files;
653 	struct kinfo_vmentry *kve, *vmentries;
654 	struct filestat_list *head;
655 	struct filestat *entry;
656 	char *path;
657 	off_t offset;
658 	int cnt, fd, fflags;
659 	int i, type, uflags;
660 	int refcount;
661 	cap_rights_t cap_rights;
662 
663 	assert(kp);
664 	if (kp->ki_fd == NULL)
665 		return (NULL);
666 
667 	files = kinfo_getfile(kp->ki_pid, &cnt);
668 	if (files == NULL && errno != EPERM) {
669 		warn("kinfo_getfile()");
670 		return (NULL);
671 	}
672 	procstat->files = files;
673 
674 	/*
675 	 * Allocate list head.
676 	 */
677 	head = malloc(sizeof(*head));
678 	if (head == NULL)
679 		return (NULL);
680 	STAILQ_INIT(head);
681 	for (i = 0; i < cnt; i++) {
682 		kif = &files[i];
683 
684 		type = kinfo_type2fst(kif->kf_type);
685 		fd = kif->kf_fd >= 0 ? kif->kf_fd : -1;
686 		fflags = kinfo_fflags2fst(kif->kf_flags);
687 		uflags = kinfo_uflags2fst(kif->kf_fd);
688 		refcount = kif->kf_ref_count;
689 		offset = kif->kf_offset;
690 		if (*kif->kf_path != '\0')
691 			path = strdup(kif->kf_path);
692 		else
693 			path = NULL;
694 		cap_rights = kif->kf_cap_rights;
695 
696 		/*
697 		 * Create filestat entry.
698 		 */
699 		entry = filestat_new_entry(kif, type, fd, fflags, uflags,
700 		    refcount, offset, path, cap_rights);
701 		if (entry != NULL)
702 			STAILQ_INSERT_TAIL(head, entry, next);
703 	}
704 	if (mmapped != 0) {
705 		vmentries = kinfo_getvmmap(kp->ki_pid, &cnt);
706 		procstat->vmentries = vmentries;
707 		if (vmentries == NULL || cnt == 0)
708 			goto fail;
709 		for (i = 0; i < cnt; i++) {
710 			kve = &vmentries[i];
711 			if (kve->kve_type != KVME_TYPE_VNODE)
712 				continue;
713 			fflags = 0;
714 			if (kve->kve_protection & KVME_PROT_READ)
715 				fflags = PS_FST_FFLAG_READ;
716 			if ((kve->kve_flags & KVME_FLAG_COW) == 0 &&
717 			    kve->kve_protection & KVME_PROT_WRITE)
718 				fflags |= PS_FST_FFLAG_WRITE;
719 			offset = kve->kve_offset;
720 			refcount = kve->kve_ref_count;
721 			if (*kve->kve_path != '\0')
722 				path = strdup(kve->kve_path);
723 			else
724 				path = NULL;
725 			entry = filestat_new_entry(kve, PS_FST_TYPE_VNODE, -1,
726 			    fflags, PS_FST_UFLAG_MMAP, refcount, offset, path,
727 			    0);
728 			if (entry != NULL)
729 				STAILQ_INSERT_TAIL(head, entry, next);
730 		}
731 	}
732 fail:
733 	return (head);
734 }
735 
736 int
737 procstat_get_pipe_info(struct procstat *procstat, struct filestat *fst,
738     struct pipestat *ps, char *errbuf)
739 {
740 
741 	assert(ps);
742 	if (procstat->type == PROCSTAT_KVM) {
743 		return (procstat_get_pipe_info_kvm(procstat->kd, fst, ps,
744 		    errbuf));
745 	} else if (procstat->type == PROCSTAT_SYSCTL) {
746 		return (procstat_get_pipe_info_sysctl(fst, ps, errbuf));
747 	} else {
748 		warnx("unknown access method: %d", procstat->type);
749 		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
750 		return (1);
751 	}
752 }
753 
754 static int
755 procstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst,
756     struct pipestat *ps, char *errbuf)
757 {
758 	struct pipe pi;
759 	void *pipep;
760 
761 	assert(kd);
762 	assert(ps);
763 	assert(fst);
764 	bzero(ps, sizeof(*ps));
765 	pipep = fst->fs_typedep;
766 	if (pipep == NULL)
767 		goto fail;
768 	if (!kvm_read_all(kd, (unsigned long)pipep, &pi, sizeof(struct pipe))) {
769 		warnx("can't read pipe at %p", (void *)pipep);
770 		goto fail;
771 	}
772 	ps->addr = (uintptr_t)pipep;
773 	ps->peer = (uintptr_t)pi.pipe_peer;
774 	ps->buffer_cnt = pi.pipe_buffer.cnt;
775 	return (0);
776 
777 fail:
778 	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
779 	return (1);
780 }
781 
782 static int
783 procstat_get_pipe_info_sysctl(struct filestat *fst, struct pipestat *ps,
784     char *errbuf __unused)
785 {
786 	struct kinfo_file *kif;
787 
788 	assert(ps);
789 	assert(fst);
790 	bzero(ps, sizeof(*ps));
791 	kif = fst->fs_typedep;
792 	if (kif == NULL)
793 		return (1);
794 	ps->addr = kif->kf_un.kf_pipe.kf_pipe_addr;
795 	ps->peer = kif->kf_un.kf_pipe.kf_pipe_peer;
796 	ps->buffer_cnt = kif->kf_un.kf_pipe.kf_pipe_buffer_cnt;
797 	return (0);
798 }
799 
800 int
801 procstat_get_pts_info(struct procstat *procstat, struct filestat *fst,
802     struct ptsstat *pts, char *errbuf)
803 {
804 
805 	assert(pts);
806 	if (procstat->type == PROCSTAT_KVM) {
807 		return (procstat_get_pts_info_kvm(procstat->kd, fst, pts,
808 		    errbuf));
809 	} else if (procstat->type == PROCSTAT_SYSCTL) {
810 		return (procstat_get_pts_info_sysctl(fst, pts, errbuf));
811 	} else {
812 		warnx("unknown access method: %d", procstat->type);
813 		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
814 		return (1);
815 	}
816 }
817 
818 static int
819 procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst,
820     struct ptsstat *pts, char *errbuf)
821 {
822 	struct tty tty;
823 	void *ttyp;
824 
825 	assert(kd);
826 	assert(pts);
827 	assert(fst);
828 	bzero(pts, sizeof(*pts));
829 	ttyp = fst->fs_typedep;
830 	if (ttyp == NULL)
831 		goto fail;
832 	if (!kvm_read_all(kd, (unsigned long)ttyp, &tty, sizeof(struct tty))) {
833 		warnx("can't read tty at %p", (void *)ttyp);
834 		goto fail;
835 	}
836 	pts->dev = dev2udev(kd, tty.t_dev);
837 	(void)kdevtoname(kd, tty.t_dev, pts->devname);
838 	return (0);
839 
840 fail:
841 	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
842 	return (1);
843 }
844 
845 static int
846 procstat_get_pts_info_sysctl(struct filestat *fst, struct ptsstat *pts,
847     char *errbuf __unused)
848 {
849 	struct kinfo_file *kif;
850 
851 	assert(pts);
852 	assert(fst);
853 	bzero(pts, sizeof(*pts));
854 	kif = fst->fs_typedep;
855 	if (kif == NULL)
856 		return (0);
857 	pts->dev = kif->kf_un.kf_pts.kf_pts_dev;
858 	strlcpy(pts->devname, kif->kf_path, sizeof(pts->devname));
859 	return (0);
860 }
861 
862 int
863 procstat_get_shm_info(struct procstat *procstat, struct filestat *fst,
864     struct shmstat *shm, char *errbuf)
865 {
866 
867 	assert(shm);
868 	if (procstat->type == PROCSTAT_KVM) {
869 		return (procstat_get_shm_info_kvm(procstat->kd, fst, shm,
870 		    errbuf));
871 	} else if (procstat->type == PROCSTAT_SYSCTL) {
872 		return (procstat_get_shm_info_sysctl(fst, shm, errbuf));
873 	} else {
874 		warnx("unknown access method: %d", procstat->type);
875 		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
876 		return (1);
877 	}
878 }
879 
880 static int
881 procstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst,
882     struct shmstat *shm, char *errbuf)
883 {
884 	struct shmfd shmfd;
885 	void *shmfdp;
886 	char *path;
887 	int i;
888 
889 	assert(kd);
890 	assert(shm);
891 	assert(fst);
892 	bzero(shm, sizeof(*shm));
893 	shmfdp = fst->fs_typedep;
894 	if (shmfdp == NULL)
895 		goto fail;
896 	if (!kvm_read_all(kd, (unsigned long)shmfdp, &shmfd,
897 	    sizeof(struct shmfd))) {
898 		warnx("can't read shmfd at %p", (void *)shmfdp);
899 		goto fail;
900 	}
901 	shm->mode = S_IFREG | shmfd.shm_mode;
902 	shm->size = shmfd.shm_size;
903 	if (fst->fs_path == NULL && shmfd.shm_path != NULL) {
904 		path = malloc(MAXPATHLEN);
905 		for (i = 0; i < MAXPATHLEN - 1; i++) {
906 			if (!kvm_read_all(kd, (unsigned long)shmfd.shm_path + i,
907 			    path + i, 1))
908 				break;
909 			if (path[i] == '\0')
910 				break;
911 		}
912 		path[i] = '\0';
913 		if (i == 0)
914 			free(path);
915 		else
916 			fst->fs_path = path;
917 	}
918 	return (0);
919 
920 fail:
921 	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
922 	return (1);
923 }
924 
925 static int
926 procstat_get_shm_info_sysctl(struct filestat *fst, struct shmstat *shm,
927     char *errbuf __unused)
928 {
929 	struct kinfo_file *kif;
930 
931 	assert(shm);
932 	assert(fst);
933 	bzero(shm, sizeof(*shm));
934 	kif = fst->fs_typedep;
935 	if (kif == NULL)
936 		return (0);
937 	shm->size = kif->kf_un.kf_file.kf_file_size;
938 	shm->mode = kif->kf_un.kf_file.kf_file_mode;
939 	return (0);
940 }
941 
942 int
943 procstat_get_vnode_info(struct procstat *procstat, struct filestat *fst,
944     struct vnstat *vn, char *errbuf)
945 {
946 
947 	assert(vn);
948 	if (procstat->type == PROCSTAT_KVM) {
949 		return (procstat_get_vnode_info_kvm(procstat->kd, fst, vn,
950 		    errbuf));
951 	} else if (procstat->type == PROCSTAT_SYSCTL) {
952 		return (procstat_get_vnode_info_sysctl(fst, vn, errbuf));
953 	} else {
954 		warnx("unknown access method: %d", procstat->type);
955 		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
956 		return (1);
957 	}
958 }
959 
960 static int
961 procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst,
962     struct vnstat *vn, char *errbuf)
963 {
964 	/* Filesystem specific handlers. */
965 	#define FSTYPE(fst)     {#fst, fst##_filestat}
966 	struct {
967 		const char	*tag;
968 		int		(*handler)(kvm_t *kd, struct vnode *vp,
969 		    struct vnstat *vn);
970 	} fstypes[] = {
971 		FSTYPE(devfs),
972 		FSTYPE(isofs),
973 		FSTYPE(msdosfs),
974 		FSTYPE(nfs),
975 		FSTYPE(udf),
976 		FSTYPE(ufs),
977 #ifdef LIBPROCSTAT_ZFS
978 		FSTYPE(zfs),
979 #endif
980 	};
981 #define	NTYPES	(sizeof(fstypes) / sizeof(*fstypes))
982 	struct vnode vnode;
983 	char tagstr[12];
984 	void *vp;
985 	int error, found;
986 	unsigned int i;
987 
988 	assert(kd);
989 	assert(vn);
990 	assert(fst);
991 	vp = fst->fs_typedep;
992 	if (vp == NULL)
993 		goto fail;
994 	error = kvm_read_all(kd, (unsigned long)vp, &vnode, sizeof(vnode));
995 	if (error == 0) {
996 		warnx("can't read vnode at %p", (void *)vp);
997 		goto fail;
998 	}
999 	bzero(vn, sizeof(*vn));
1000 	vn->vn_type = vntype2psfsttype(vnode.v_type);
1001 	if (vnode.v_type == VNON || vnode.v_type == VBAD)
1002 		return (0);
1003 	error = kvm_read_all(kd, (unsigned long)vnode.v_tag, tagstr,
1004 	    sizeof(tagstr));
1005 	if (error == 0) {
1006 		warnx("can't read v_tag at %p", (void *)vp);
1007 		goto fail;
1008 	}
1009 	tagstr[sizeof(tagstr) - 1] = '\0';
1010 
1011 	/*
1012 	 * Find appropriate handler.
1013 	 */
1014 	for (i = 0, found = 0; i < NTYPES; i++)
1015 		if (!strcmp(fstypes[i].tag, tagstr)) {
1016 			if (fstypes[i].handler(kd, &vnode, vn) != 0) {
1017 				goto fail;
1018 			}
1019 			break;
1020 		}
1021 	if (i == NTYPES) {
1022 		snprintf(errbuf, _POSIX2_LINE_MAX, "?(%s)", tagstr);
1023 		return (1);
1024 	}
1025 	vn->vn_mntdir = getmnton(kd, vnode.v_mount);
1026 	if ((vnode.v_type == VBLK || vnode.v_type == VCHR) &&
1027 	    vnode.v_rdev != NULL){
1028 		vn->vn_dev = dev2udev(kd, vnode.v_rdev);
1029 		(void)kdevtoname(kd, vnode.v_rdev, vn->vn_devname);
1030 	} else {
1031 		vn->vn_dev = -1;
1032 	}
1033 	return (0);
1034 
1035 fail:
1036 	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1037 	return (1);
1038 }
1039 
1040 /*
1041  * kinfo vnode type to filestat translation.
1042  */
1043 static int
1044 kinfo_vtype2fst(int kfvtype)
1045 {
1046 	static struct {
1047 		int	kf_vtype;
1048 		int	fst_vtype;
1049 	} kfvtypes2fst[] = {
1050 		{ KF_VTYPE_VBAD, PS_FST_VTYPE_VBAD },
1051 		{ KF_VTYPE_VBLK, PS_FST_VTYPE_VBLK },
1052 		{ KF_VTYPE_VCHR, PS_FST_VTYPE_VCHR },
1053 		{ KF_VTYPE_VDIR, PS_FST_VTYPE_VDIR },
1054 		{ KF_VTYPE_VFIFO, PS_FST_VTYPE_VFIFO },
1055 		{ KF_VTYPE_VLNK, PS_FST_VTYPE_VLNK },
1056 		{ KF_VTYPE_VNON, PS_FST_VTYPE_VNON },
1057 		{ KF_VTYPE_VREG, PS_FST_VTYPE_VREG },
1058 		{ KF_VTYPE_VSOCK, PS_FST_VTYPE_VSOCK }
1059 	};
1060 #define	NKFVTYPES	(sizeof(kfvtypes2fst) / sizeof(*kfvtypes2fst))
1061 	unsigned int i;
1062 
1063 	for (i = 0; i < NKFVTYPES; i++)
1064 		if (kfvtypes2fst[i].kf_vtype == kfvtype)
1065 			break;
1066 	if (i == NKFVTYPES)
1067 		return (PS_FST_VTYPE_UNKNOWN);
1068 	return (kfvtypes2fst[i].fst_vtype);
1069 }
1070 
1071 static int
1072 procstat_get_vnode_info_sysctl(struct filestat *fst, struct vnstat *vn,
1073     char *errbuf)
1074 {
1075 	struct statfs stbuf;
1076 	struct kinfo_file *kif;
1077 	struct kinfo_vmentry *kve;
1078 	uint64_t fileid;
1079 	uint64_t size;
1080 	char *name, *path;
1081 	uint32_t fsid;
1082 	uint16_t mode;
1083 	uint32_t rdev;
1084 	int vntype;
1085 	int status;
1086 
1087 	assert(fst);
1088 	assert(vn);
1089 	bzero(vn, sizeof(*vn));
1090 	if (fst->fs_typedep == NULL)
1091 		return (1);
1092 	if (fst->fs_uflags & PS_FST_UFLAG_MMAP) {
1093 		kve = fst->fs_typedep;
1094 		fileid = kve->kve_vn_fileid;
1095 		fsid = kve->kve_vn_fsid;
1096 		mode = kve->kve_vn_mode;
1097 		path = kve->kve_path;
1098 		rdev = kve->kve_vn_rdev;
1099 		size = kve->kve_vn_size;
1100 		vntype = kinfo_vtype2fst(kve->kve_vn_type);
1101 		status = kve->kve_status;
1102 	} else {
1103 		kif = fst->fs_typedep;
1104 		fileid = kif->kf_un.kf_file.kf_file_fileid;
1105 		fsid = kif->kf_un.kf_file.kf_file_fsid;
1106 		mode = kif->kf_un.kf_file.kf_file_mode;
1107 		path = kif->kf_path;
1108 		rdev = kif->kf_un.kf_file.kf_file_rdev;
1109 		size = kif->kf_un.kf_file.kf_file_size;
1110 		vntype = kinfo_vtype2fst(kif->kf_vnode_type);
1111 		status = kif->kf_status;
1112 	}
1113 	vn->vn_type = vntype;
1114 	if (vntype == PS_FST_VTYPE_VNON || vntype == PS_FST_VTYPE_VBAD)
1115 		return (0);
1116 	if ((status & KF_ATTR_VALID) == 0) {
1117 		snprintf(errbuf, _POSIX2_LINE_MAX, "? (no info available)");
1118 		return (1);
1119 	}
1120 	if (path && *path) {
1121 		statfs(path, &stbuf);
1122 		vn->vn_mntdir = strdup(stbuf.f_mntonname);
1123 	} else
1124 		vn->vn_mntdir = strdup("-");
1125 	vn->vn_dev = rdev;
1126 	if (vntype == PS_FST_VTYPE_VBLK) {
1127 		name = devname(rdev, S_IFBLK);
1128 		if (name != NULL)
1129 			strlcpy(vn->vn_devname, name,
1130 			    sizeof(vn->vn_devname));
1131 	} else if (vntype == PS_FST_VTYPE_VCHR) {
1132 		name = devname(vn->vn_dev, S_IFCHR);
1133 		if (name != NULL)
1134 			strlcpy(vn->vn_devname, name,
1135 			    sizeof(vn->vn_devname));
1136 	}
1137 	vn->vn_fsid = fsid;
1138 	vn->vn_fileid = fileid;
1139 	vn->vn_size = size;
1140 	vn->vn_mode = mode;
1141 	return (0);
1142 }
1143 
1144 int
1145 procstat_get_socket_info(struct procstat *procstat, struct filestat *fst,
1146     struct sockstat *sock, char *errbuf)
1147 {
1148 
1149 	assert(sock);
1150 	if (procstat->type == PROCSTAT_KVM) {
1151 		return (procstat_get_socket_info_kvm(procstat->kd, fst, sock,
1152 		    errbuf));
1153 	} else if (procstat->type == PROCSTAT_SYSCTL) {
1154 		return (procstat_get_socket_info_sysctl(fst, sock, errbuf));
1155 	} else {
1156 		warnx("unknown access method: %d", procstat->type);
1157 		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1158 		return (1);
1159 	}
1160 }
1161 
1162 static int
1163 procstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst,
1164     struct sockstat *sock, char *errbuf)
1165 {
1166 	struct domain dom;
1167 	struct inpcb inpcb;
1168 	struct protosw proto;
1169 	struct socket s;
1170 	struct unpcb unpcb;
1171 	ssize_t len;
1172 	void *so;
1173 
1174 	assert(kd);
1175 	assert(sock);
1176 	assert(fst);
1177 	bzero(sock, sizeof(*sock));
1178 	so = fst->fs_typedep;
1179 	if (so == NULL)
1180 		goto fail;
1181 	sock->so_addr = (uintptr_t)so;
1182 	/* fill in socket */
1183 	if (!kvm_read_all(kd, (unsigned long)so, &s,
1184 	    sizeof(struct socket))) {
1185 		warnx("can't read sock at %p", (void *)so);
1186 		goto fail;
1187 	}
1188 	/* fill in protosw entry */
1189 	if (!kvm_read_all(kd, (unsigned long)s.so_proto, &proto,
1190 	    sizeof(struct protosw))) {
1191 		warnx("can't read protosw at %p", (void *)s.so_proto);
1192 		goto fail;
1193 	}
1194 	/* fill in domain */
1195 	if (!kvm_read_all(kd, (unsigned long)proto.pr_domain, &dom,
1196 	    sizeof(struct domain))) {
1197 		warnx("can't read domain at %p",
1198 		    (void *)proto.pr_domain);
1199 		goto fail;
1200 	}
1201 	if ((len = kvm_read(kd, (unsigned long)dom.dom_name, sock->dname,
1202 	    sizeof(sock->dname) - 1)) < 0) {
1203 		warnx("can't read domain name at %p", (void *)dom.dom_name);
1204 		sock->dname[0] = '\0';
1205 	}
1206 	else
1207 		sock->dname[len] = '\0';
1208 
1209 	/*
1210 	 * Fill in known data.
1211 	 */
1212 	sock->type = s.so_type;
1213 	sock->proto = proto.pr_protocol;
1214 	sock->dom_family = dom.dom_family;
1215 	sock->so_pcb = (uintptr_t)s.so_pcb;
1216 
1217 	/*
1218 	 * Protocol specific data.
1219 	 */
1220 	switch(dom.dom_family) {
1221 	case AF_INET:
1222 	case AF_INET6:
1223 		if (proto.pr_protocol == IPPROTO_TCP) {
1224 			if (s.so_pcb) {
1225 				if (kvm_read(kd, (u_long)s.so_pcb,
1226 				    (char *)&inpcb, sizeof(struct inpcb))
1227 				    != sizeof(struct inpcb)) {
1228 					warnx("can't read inpcb at %p",
1229 					    (void *)s.so_pcb);
1230 				} else
1231 					sock->inp_ppcb =
1232 					    (uintptr_t)inpcb.inp_ppcb;
1233 			}
1234 		}
1235 		break;
1236 	case AF_UNIX:
1237 		if (s.so_pcb) {
1238 			if (kvm_read(kd, (u_long)s.so_pcb, (char *)&unpcb,
1239 			    sizeof(struct unpcb)) != sizeof(struct unpcb)){
1240 				warnx("can't read unpcb at %p",
1241 				    (void *)s.so_pcb);
1242 			} else if (unpcb.unp_conn) {
1243 				sock->so_rcv_sb_state = s.so_rcv.sb_state;
1244 				sock->so_snd_sb_state = s.so_snd.sb_state;
1245 				sock->unp_conn = (uintptr_t)unpcb.unp_conn;
1246 			}
1247 		}
1248 		break;
1249 	default:
1250 		break;
1251 	}
1252 	return (0);
1253 
1254 fail:
1255 	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1256 	return (1);
1257 }
1258 
1259 static int
1260 procstat_get_socket_info_sysctl(struct filestat *fst, struct sockstat *sock,
1261     char *errbuf __unused)
1262 {
1263 	struct kinfo_file *kif;
1264 
1265 	assert(sock);
1266 	assert(fst);
1267 	bzero(sock, sizeof(*sock));
1268 	kif = fst->fs_typedep;
1269 	if (kif == NULL)
1270 		return (0);
1271 
1272 	/*
1273 	 * Fill in known data.
1274 	 */
1275 	sock->type = kif->kf_sock_type;
1276 	sock->proto = kif->kf_sock_protocol;
1277 	sock->dom_family = kif->kf_sock_domain;
1278 	sock->so_pcb = kif->kf_un.kf_sock.kf_sock_pcb;
1279 	strlcpy(sock->dname, kif->kf_path, sizeof(sock->dname));
1280 	bcopy(&kif->kf_sa_local, &sock->sa_local, kif->kf_sa_local.ss_len);
1281 	bcopy(&kif->kf_sa_peer, &sock->sa_peer, kif->kf_sa_peer.ss_len);
1282 
1283 	/*
1284 	 * Protocol specific data.
1285 	 */
1286 	switch(sock->dom_family) {
1287 	case AF_INET:
1288 	case AF_INET6:
1289 		if (sock->proto == IPPROTO_TCP)
1290 			sock->inp_ppcb = kif->kf_un.kf_sock.kf_sock_inpcb;
1291 		break;
1292 	case AF_UNIX:
1293 		if (kif->kf_un.kf_sock.kf_sock_unpconn != 0) {
1294 				sock->so_rcv_sb_state =
1295 				    kif->kf_un.kf_sock.kf_sock_rcv_sb_state;
1296 				sock->so_snd_sb_state =
1297 				    kif->kf_un.kf_sock.kf_sock_snd_sb_state;
1298 				sock->unp_conn =
1299 				    kif->kf_un.kf_sock.kf_sock_unpconn;
1300 		}
1301 		break;
1302 	default:
1303 		break;
1304 	}
1305 	return (0);
1306 }
1307 
1308 /*
1309  * Descriptor flags to filestat translation.
1310  */
1311 static int
1312 to_filestat_flags(int flags)
1313 {
1314 	static struct {
1315 		int flag;
1316 		int fst_flag;
1317 	} fstflags[] = {
1318 		{ FREAD, PS_FST_FFLAG_READ },
1319 		{ FWRITE, PS_FST_FFLAG_WRITE },
1320 		{ O_APPEND, PS_FST_FFLAG_APPEND },
1321 		{ O_ASYNC, PS_FST_FFLAG_ASYNC },
1322 		{ O_CREAT, PS_FST_FFLAG_CREAT },
1323 		{ O_DIRECT, PS_FST_FFLAG_DIRECT },
1324 		{ O_EXCL, PS_FST_FFLAG_EXCL },
1325 		{ O_EXEC, PS_FST_FFLAG_EXEC },
1326 		{ O_EXLOCK, PS_FST_FFLAG_EXLOCK },
1327 		{ O_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW },
1328 		{ O_NONBLOCK, PS_FST_FFLAG_NONBLOCK },
1329 		{ O_SHLOCK, PS_FST_FFLAG_SHLOCK },
1330 		{ O_SYNC, PS_FST_FFLAG_SYNC },
1331 		{ O_TRUNC, PS_FST_FFLAG_TRUNC }
1332 	};
1333 #define NFSTFLAGS	(sizeof(fstflags) / sizeof(*fstflags))
1334 	int fst_flags;
1335 	unsigned int i;
1336 
1337 	fst_flags = 0;
1338 	for (i = 0; i < NFSTFLAGS; i++)
1339 		if (flags & fstflags[i].flag)
1340 			fst_flags |= fstflags[i].fst_flag;
1341 	return (fst_flags);
1342 }
1343 
1344 /*
1345  * Vnode type to filestate translation.
1346  */
1347 static int
1348 vntype2psfsttype(int type)
1349 {
1350 	static struct {
1351 		int	vtype;
1352 		int	fst_vtype;
1353 	} vt2fst[] = {
1354 		{ VBAD, PS_FST_VTYPE_VBAD },
1355 		{ VBLK, PS_FST_VTYPE_VBLK },
1356 		{ VCHR, PS_FST_VTYPE_VCHR },
1357 		{ VDIR, PS_FST_VTYPE_VDIR },
1358 		{ VFIFO, PS_FST_VTYPE_VFIFO },
1359 		{ VLNK, PS_FST_VTYPE_VLNK },
1360 		{ VNON, PS_FST_VTYPE_VNON },
1361 		{ VREG, PS_FST_VTYPE_VREG },
1362 		{ VSOCK, PS_FST_VTYPE_VSOCK }
1363 	};
1364 #define	NVFTYPES	(sizeof(vt2fst) / sizeof(*vt2fst))
1365 	unsigned int i, fst_type;
1366 
1367 	fst_type = PS_FST_VTYPE_UNKNOWN;
1368 	for (i = 0; i < NVFTYPES; i++) {
1369 		if (type == vt2fst[i].vtype) {
1370 			fst_type = vt2fst[i].fst_vtype;
1371 			break;
1372 		}
1373 	}
1374 	return (fst_type);
1375 }
1376 
1377 static char *
1378 getmnton(kvm_t *kd, struct mount *m)
1379 {
1380 	struct mount mnt;
1381 	static struct mtab {
1382 		struct mtab *next;
1383 		struct mount *m;
1384 		char mntonname[MNAMELEN + 1];
1385 	} *mhead = NULL;
1386 	struct mtab *mt;
1387 
1388 	for (mt = mhead; mt != NULL; mt = mt->next)
1389 		if (m == mt->m)
1390 			return (mt->mntonname);
1391 	if (!kvm_read_all(kd, (unsigned long)m, &mnt, sizeof(struct mount))) {
1392 		warnx("can't read mount table at %p", (void *)m);
1393 		return (NULL);
1394 	}
1395 	if ((mt = malloc(sizeof (struct mtab))) == NULL)
1396 		err(1, NULL);
1397 	mt->m = m;
1398 	bcopy(&mnt.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN);
1399 	mt->mntonname[MNAMELEN] = '\0';
1400 	mt->next = mhead;
1401 	mhead = mt;
1402 	return (mt->mntonname);
1403 }
1404