libprocstat.c revision 241636
11590Srgrimes/*-
21590Srgrimes * Copyright (c) 2009 Stanislav Sedov <stas@FreeBSD.org>
31590Srgrimes * Copyright (c) 1988, 1993
41590Srgrimes *      The Regents of the University of California.  All rights reserved.
51590Srgrimes *
61590Srgrimes * Redistribution and use in source and binary forms, with or without
71590Srgrimes * modification, are permitted provided that the following conditions
81590Srgrimes * are met:
91590Srgrimes * 1. Redistributions of source code must retain the above copyright
101590Srgrimes *    notice, this list of conditions and the following disclaimer.
111590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
121590Srgrimes *    notice, this list of conditions and the following disclaimer in the
131590Srgrimes *    documentation and/or other materials provided with the distribution.
141590Srgrimes * 3. All advertising materials mentioning features or use of this software
151590Srgrimes *    must display the following acknowledgement:
161590Srgrimes *      This product includes software developed by the University of
171590Srgrimes *      California, Berkeley and its contributors.
181590Srgrimes * 4. Neither the name of the University nor the names of its contributors
191590Srgrimes *    may be used to endorse or promote products derived from this software
201590Srgrimes *    without specific prior written permission.
211590Srgrimes *
221590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
231590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
241590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
251590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
261590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
271590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
281590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
291590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3087675Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3187675Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3287675Smarkm * SUCH DAMAGE.
3387675Smarkm */
341590Srgrimes
3528695Scharnier#include <sys/cdefs.h>
361590Srgrimes__FBSDID("$FreeBSD: head/lib/libprocstat/libprocstat.c 241636 2012-10-17 11:30:00Z attilio $");
371590Srgrimes
3887675Smarkm#include <sys/param.h>
391590Srgrimes#include <sys/time.h>
401590Srgrimes#include <sys/proc.h>
4187675Smarkm#include <sys/user.h>
4228695Scharnier#include <sys/stat.h>
431590Srgrimes#include <sys/vnode.h>
441590Srgrimes#include <sys/socket.h>
451590Srgrimes#include <sys/socketvar.h>
461590Srgrimes#include <sys/domain.h>
471590Srgrimes#include <sys/protosw.h>
481590Srgrimes#include <sys/un.h>
491590Srgrimes#include <sys/unpcb.h>
501590Srgrimes#include <sys/sysctl.h>
511590Srgrimes#include <sys/tty.h>
521590Srgrimes#include <sys/filedesc.h>
5328695Scharnier#include <sys/queue.h>
5428695Scharnier#define	_WANT_FILE
5573255Simp#include <sys/file.h>
5625777Sache#include <sys/conf.h>
571590Srgrimes#include <sys/mman.h>
581590Srgrimes#define	_KERNEL
591590Srgrimes#include <sys/mount.h>
601590Srgrimes#include <sys/pipe.h>
611590Srgrimes#include <ufs/ufs/quota.h>
6229434Sache#include <ufs/ufs/inode.h>
631590Srgrimes#include <fs/devfs/devfs.h>
64202200Sed#include <fs/devfs/devfs_int.h>
65233269Sglebius#undef _KERNEL
66233269Sglebius#include <nfs/nfsproto.h>
671590Srgrimes#include <nfsclient/nfs.h>
6883242Sdd#include <nfsclient/nfsnode.h>
6983242Sdd
7073255Simp#include <vm/vm.h>
7173255Simp#include <vm/vm_map.h>
721590Srgrimes#include <vm/vm_object.h>
73227200Sed
7473255Simp#include <net/route.h>
7573255Simp#include <netinet/in.h>
7673255Simp#include <netinet/in_systm.h>
7773255Simp#include <netinet/ip.h>
78227200Sed#include <netinet/in_pcb.h>
79227200Sed
80227200Sed#include <assert.h>
811590Srgrimes#include <ctype.h>
82155875Scognet#include <err.h>
83200156Sed#include <fcntl.h>
84155875Scognet#include <kvm.h>
85155875Scognet#include <libutil.h>
86155875Scognet#include <limits.h>
87155875Scognet#include <paths.h>
88200156Sed#include <pwd.h>
89155875Scognet#include <stdio.h>
90155875Scognet#include <stdlib.h>
91155875Scognet#include <stddef.h>
92155875Scognet#include <string.h>
93155875Scognet#include <unistd.h>
94155875Scognet#include <netdb.h>
951590Srgrimes
9673255Simp#include <libprocstat.h>
971590Srgrimes#include "libprocstat_internal.h"
981590Srgrimes#include "common_kvm.h"
99200156Sed
10073255Simpint     statfs(const char *, struct statfs *);	/* XXX */
10183082Sru
10273255Simp#define	PROCSTAT_KVM	1
10373255Simp#define	PROCSTAT_SYSCTL	2
10483242Sdd
10583242Sddstatic char	*getmnton(kvm_t *kd, struct mount *m);
10673255Simpstatic struct filestat_list	*procstat_getfiles_kvm(
1071590Srgrimes    struct procstat *procstat, struct kinfo_proc *kp, int mmapped);
10825777Sachestatic struct filestat_list	*procstat_getfiles_sysctl(
10925777Sache    struct procstat *procstat, struct kinfo_proc *kp, int mmapped);
11073255Simpstatic int	procstat_get_pipe_info_sysctl(struct filestat *fst,
1111590Srgrimes    struct pipestat *pipe, char *errbuf);
1121590Srgrimesstatic int	procstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst,
1131590Srgrimes    struct pipestat *pipe, char *errbuf);
1141590Srgrimesstatic int	procstat_get_pts_info_sysctl(struct filestat *fst,
1151590Srgrimes    struct ptsstat *pts, char *errbuf);
1161590Srgrimesstatic int	procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst,
11773255Simp    struct ptsstat *pts, char *errbuf);
11873255Simpstatic int	procstat_get_shm_info_sysctl(struct filestat *fst,
11973255Simp    struct shmstat *shm, char *errbuf);
12073255Simpstatic int	procstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst,
12173255Simp    struct shmstat *shm, char *errbuf);
12273255Simpstatic int	procstat_get_socket_info_sysctl(struct filestat *fst,
12373255Simp    struct sockstat *sock, char *errbuf);
1241590Srgrimesstatic int	procstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst,
1251590Srgrimes    struct sockstat *sock, char *errbuf);
12628695Scharnierstatic int	to_filestat_flags(int flags);
1271590Srgrimesstatic int	procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst,
1281590Srgrimes    struct vnstat *vn, char *errbuf);
1291590Srgrimesstatic int	procstat_get_vnode_info_sysctl(struct filestat *fst,
1301590Srgrimes    struct vnstat *vn, char *errbuf);
13128695Scharnierstatic int	vntype2psfsttype(int type);
1321590Srgrimes
13373255Simpvoid
13473255Simpprocstat_close(struct procstat *procstat)
13573320Simp{
13673255Simp
13773320Simp	assert(procstat);
13873320Simp	if (procstat->type == PROCSTAT_KVM)
13973255Simp		kvm_close(procstat->kd);
14073255Simp	free(procstat);
1411590Srgrimes}
1421590Srgrimes
1431590Srgrimesstruct procstat *
1441590Srgrimesprocstat_open_sysctl(void)
1451590Srgrimes{
146200156Sed	struct procstat *procstat;
147200156Sed
1481590Srgrimes	procstat = calloc(1, sizeof(*procstat));
149200156Sed	if (procstat == NULL) {
150155875Scognet		warn("malloc()");
15173255Simp		return (NULL);
15283082Sru	}
153200156Sed	procstat->type = PROCSTAT_SYSCTL;
15473255Simp	return (procstat);
15573255Simp}
15673255Simp
15787675Smarkmstruct procstat *
15873255Simpprocstat_open_kvm(const char *nlistf, const char *memf)
15973255Simp{
16073255Simp	struct procstat *procstat;
16183082Sru	kvm_t *kd;
16283082Sru	char buf[_POSIX2_LINE_MAX];
163200156Sed
16483082Sru	procstat = calloc(1, sizeof(*procstat));
16583082Sru	if (procstat == NULL) {
16683082Sru		warn("malloc()");
16783082Sru		return (NULL);
16883082Sru	}
16973255Simp	kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf);
17073255Simp	if (kd == NULL) {
17173255Simp		warnx("kvm_openfiles(): %s", buf);
17273255Simp		free(procstat);
173200156Sed		return (NULL);
17428695Scharnier	}
1751590Srgrimes	procstat->type = PROCSTAT_KVM;
1761590Srgrimes	procstat->kd = kd;
1771590Srgrimes	return (procstat);
1781590Srgrimes}
17928695Scharnier
180201224Sedstruct kinfo_proc *
18128695Scharnierprocstat_getprocs(struct procstat *procstat, int what, int arg,
18273320Simp    unsigned int *count)
18328695Scharnier{
18428695Scharnier	struct kinfo_proc *p0, *p;
18528695Scharnier	size_t len;
1861590Srgrimes	int name[4];
18773255Simp	int cnt;
1881590Srgrimes	int error;
18973255Simp
190233269Sglebius	assert(procstat);
1911590Srgrimes	assert(count);
1921590Srgrimes	p = NULL;
1931590Srgrimes	if (procstat->type == PROCSTAT_KVM) {
19429434Sache		*count = 0;
1951590Srgrimes		p0 = kvm_getprocs(procstat->kd, what, arg, &cnt);
1961590Srgrimes		if (p0 == NULL || cnt <= 0)
197233269Sglebius			return (NULL);
198233269Sglebius		*count = cnt;
19987675Smarkm		len = *count * sizeof(*p);
20069231Skris		p = malloc(len);
20176367Skris		if (p == NULL) {
2021590Srgrimes			warnx("malloc(%zu)", len);
20369231Skris			goto fail;
20469231Skris		}
20569231Skris		bcopy(p0, p, len);
2061590Srgrimes		return (p);
2071590Srgrimes	} else if (procstat->type == PROCSTAT_SYSCTL) {
2081590Srgrimes		len = 0;
20969231Skris		name[0] = CTL_KERN;
21069231Skris		name[1] = KERN_PROC;
21166557Sn_hibma		name[2] = what;
21266557Sn_hibma		name[3] = arg;
2131590Srgrimes		error = sysctl(name, 4, NULL, &len, NULL, 0);
2141590Srgrimes		if (error < 0 && errno != EPERM) {
2151590Srgrimes			warn("sysctl(kern.proc)");
2161590Srgrimes			goto fail;
2171590Srgrimes		}
2181590Srgrimes		if (len == 0) {
2191590Srgrimes			warnx("no processes?");
2201590Srgrimes			goto fail;
2211590Srgrimes		}
2221590Srgrimes		p = malloc(len);
2231590Srgrimes		if (p == NULL) {
2241590Srgrimes			warnx("malloc(%zu)", len);
2251590Srgrimes			goto fail;
226233269Sglebius		}
227233269Sglebius		error = sysctl(name, 4, p, &len, NULL, 0);
228233269Sglebius		if (error < 0 && errno != EPERM) {
2291590Srgrimes			warn("sysctl(kern.proc)");
230233269Sglebius			goto fail;
231233269Sglebius		}
232233269Sglebius		/* Perform simple consistency checks. */
23363909Sasmodai		if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) {
234233269Sglebius			warnx("kinfo_proc structure size mismatch");
2351590Srgrimes			goto fail;
236233269Sglebius		}
2371590Srgrimes		*count = len / sizeof(*p);
23876367Skris		return (p);
23976367Skris	} else {
24076367Skris		warnx("unknown access method: %d", procstat->type);
241233269Sglebius		return (NULL);
24276367Skris	}
243241848Seadlerfail:
244241848Seadler	if (p)
24576367Skris		free(p);
246223940Sobrien	return (NULL);
247233269Sglebius}
248233269Sglebius
249233269Sglebiusvoid
250233269Sglebiusprocstat_freeprocs(struct procstat *procstat __unused, struct kinfo_proc *p)
25150776Sdbaker{
252175346Sdas
253233269Sglebius	if (p != NULL)
2541590Srgrimes		free(p);
255233269Sglebius	p = NULL;
256233269Sglebius}
257233269Sglebius
258175346Sdasstruct filestat_list *
259175346Sdasprocstat_getfiles(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
260175346Sdas{
261233269Sglebius
262233269Sglebius	if (procstat->type == PROCSTAT_SYSCTL)
2631590Srgrimes		return (procstat_getfiles_sysctl(procstat, kp, mmapped));
264175346Sdas	else if (procstat->type == PROCSTAT_KVM)
265233269Sglebius		return (procstat_getfiles_kvm(procstat, kp, mmapped));
266233269Sglebius	else
267233269Sglebius		return (NULL);
268233269Sglebius}
269233269Sglebius
270233269Sglebiusvoid
27129434Sacheprocstat_freefiles(struct procstat *procstat, struct filestat_list *head)
272233269Sglebius{
273233269Sglebius	struct filestat *fst, *tmp;
27429434Sache
27529434Sache	STAILQ_FOREACH_SAFE(fst, head, next, tmp) {
27624729Sache		if (fst->fs_path != NULL)
277233269Sglebius			free(fst->fs_path);
27829434Sache		free(fst);
2791590Srgrimes	}
280175346Sdas	free(head);
281233269Sglebius	if (procstat->vmentries != NULL) {
2821590Srgrimes		free(procstat->vmentries);
2831590Srgrimes		procstat->vmentries = NULL;
28428695Scharnier	}
28569231Skris	if (procstat->files != NULL) {
2861590Srgrimes		free(procstat->files);
28728695Scharnier		procstat->files = NULL;
28869231Skris	}
28987675Smarkm}
29069231Skris
2911590Srgrimesstatic struct filestat *
2921590Srgrimesfilestat_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
314static struct vnode *
315getctty(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
349static struct filestat_list *
350procstat_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
495do_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	}
553exit:
554	return (head);
555}
556
557/*
558 * kinfo types to filestat translation.
559 */
560static int
561kinfo_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 */
594static int
595kinfo_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_CAPABILITY, PS_FST_FFLAG_CAPABILITY },
604		{ KF_FLAG_CREAT, PS_FST_FFLAG_CREAT },
605		{ KF_FLAG_DIRECT, PS_FST_FFLAG_DIRECT },
606		{ KF_FLAG_EXCL, PS_FST_FFLAG_EXCL },
607		{ KF_FLAG_EXEC, PS_FST_FFLAG_EXEC },
608		{ KF_FLAG_EXLOCK, PS_FST_FFLAG_EXLOCK },
609		{ KF_FLAG_FSYNC, PS_FST_FFLAG_SYNC },
610		{ KF_FLAG_HASLOCK, PS_FST_FFLAG_HASLOCK },
611		{ KF_FLAG_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW },
612		{ KF_FLAG_NONBLOCK, PS_FST_FFLAG_NONBLOCK },
613		{ KF_FLAG_READ, PS_FST_FFLAG_READ },
614		{ KF_FLAG_SHLOCK, PS_FST_FFLAG_SHLOCK },
615		{ KF_FLAG_TRUNC, PS_FST_FFLAG_TRUNC },
616		{ KF_FLAG_WRITE, PS_FST_FFLAG_WRITE }
617	};
618#define NKFFLAGS	(sizeof(kfflags2fst) / sizeof(*kfflags2fst))
619	unsigned int i;
620	int flags;
621
622	flags = 0;
623	for (i = 0; i < NKFFLAGS; i++)
624		if ((kfflags & kfflags2fst[i].kf_flag) != 0)
625			flags |= kfflags2fst[i].fst_flag;
626	return (flags);
627}
628
629static int
630kinfo_uflags2fst(int fd)
631{
632
633	switch (fd) {
634	case KF_FD_TYPE_CTTY:
635		return (PS_FST_UFLAG_CTTY);
636	case KF_FD_TYPE_CWD:
637		return (PS_FST_UFLAG_CDIR);
638	case KF_FD_TYPE_JAIL:
639		return (PS_FST_UFLAG_JAIL);
640	case KF_FD_TYPE_TEXT:
641		return (PS_FST_UFLAG_TEXT);
642	case KF_FD_TYPE_TRACE:
643		return (PS_FST_UFLAG_TRACE);
644	case KF_FD_TYPE_ROOT:
645		return (PS_FST_UFLAG_RDIR);
646	}
647	return (0);
648}
649
650static struct filestat_list *
651procstat_getfiles_sysctl(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
652{
653	struct kinfo_file *kif, *files;
654	struct kinfo_vmentry *kve, *vmentries;
655	struct filestat_list *head;
656	struct filestat *entry;
657	char *path;
658	off_t offset;
659	int cnt, fd, fflags;
660	int i, type, uflags;
661	int refcount;
662	cap_rights_t cap_rights;
663
664	assert(kp);
665	if (kp->ki_fd == NULL)
666		return (NULL);
667
668	files = kinfo_getfile(kp->ki_pid, &cnt);
669	if (files == NULL && errno != EPERM) {
670		warn("kinfo_getfile()");
671		return (NULL);
672	}
673	procstat->files = files;
674
675	/*
676	 * Allocate list head.
677	 */
678	head = malloc(sizeof(*head));
679	if (head == NULL)
680		return (NULL);
681	STAILQ_INIT(head);
682	for (i = 0; i < cnt; i++) {
683		kif = &files[i];
684
685		type = kinfo_type2fst(kif->kf_type);
686		fd = kif->kf_fd >= 0 ? kif->kf_fd : -1;
687		fflags = kinfo_fflags2fst(kif->kf_flags);
688		uflags = kinfo_uflags2fst(kif->kf_fd);
689		refcount = kif->kf_ref_count;
690		offset = kif->kf_offset;
691		if (*kif->kf_path != '\0')
692			path = strdup(kif->kf_path);
693		else
694			path = NULL;
695		cap_rights = kif->kf_cap_rights;
696
697		/*
698		 * Create filestat entry.
699		 */
700		entry = filestat_new_entry(kif, type, fd, fflags, uflags,
701		    refcount, offset, path, cap_rights);
702		if (entry != NULL)
703			STAILQ_INSERT_TAIL(head, entry, next);
704	}
705	if (mmapped != 0) {
706		vmentries = kinfo_getvmmap(kp->ki_pid, &cnt);
707		procstat->vmentries = vmentries;
708		if (vmentries == NULL || cnt == 0)
709			goto fail;
710		for (i = 0; i < cnt; i++) {
711			kve = &vmentries[i];
712			if (kve->kve_type != KVME_TYPE_VNODE)
713				continue;
714			fflags = 0;
715			if (kve->kve_protection & KVME_PROT_READ)
716				fflags = PS_FST_FFLAG_READ;
717			if ((kve->kve_flags & KVME_FLAG_COW) == 0 &&
718			    kve->kve_protection & KVME_PROT_WRITE)
719				fflags |= PS_FST_FFLAG_WRITE;
720			offset = kve->kve_offset;
721			refcount = kve->kve_ref_count;
722			if (*kve->kve_path != '\0')
723				path = strdup(kve->kve_path);
724			else
725				path = NULL;
726			entry = filestat_new_entry(kve, PS_FST_TYPE_VNODE, -1,
727			    fflags, PS_FST_UFLAG_MMAP, refcount, offset, path,
728			    0);
729			if (entry != NULL)
730				STAILQ_INSERT_TAIL(head, entry, next);
731		}
732	}
733fail:
734	return (head);
735}
736
737int
738procstat_get_pipe_info(struct procstat *procstat, struct filestat *fst,
739    struct pipestat *ps, char *errbuf)
740{
741
742	assert(ps);
743	if (procstat->type == PROCSTAT_KVM) {
744		return (procstat_get_pipe_info_kvm(procstat->kd, fst, ps,
745		    errbuf));
746	} else if (procstat->type == PROCSTAT_SYSCTL) {
747		return (procstat_get_pipe_info_sysctl(fst, ps, errbuf));
748	} else {
749		warnx("unknown access method: %d", procstat->type);
750		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
751		return (1);
752	}
753}
754
755static int
756procstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst,
757    struct pipestat *ps, char *errbuf)
758{
759	struct pipe pi;
760	void *pipep;
761
762	assert(kd);
763	assert(ps);
764	assert(fst);
765	bzero(ps, sizeof(*ps));
766	pipep = fst->fs_typedep;
767	if (pipep == NULL)
768		goto fail;
769	if (!kvm_read_all(kd, (unsigned long)pipep, &pi, sizeof(struct pipe))) {
770		warnx("can't read pipe at %p", (void *)pipep);
771		goto fail;
772	}
773	ps->addr = (uintptr_t)pipep;
774	ps->peer = (uintptr_t)pi.pipe_peer;
775	ps->buffer_cnt = pi.pipe_buffer.cnt;
776	return (0);
777
778fail:
779	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
780	return (1);
781}
782
783static int
784procstat_get_pipe_info_sysctl(struct filestat *fst, struct pipestat *ps,
785    char *errbuf __unused)
786{
787	struct kinfo_file *kif;
788
789	assert(ps);
790	assert(fst);
791	bzero(ps, sizeof(*ps));
792	kif = fst->fs_typedep;
793	if (kif == NULL)
794		return (1);
795	ps->addr = kif->kf_un.kf_pipe.kf_pipe_addr;
796	ps->peer = kif->kf_un.kf_pipe.kf_pipe_peer;
797	ps->buffer_cnt = kif->kf_un.kf_pipe.kf_pipe_buffer_cnt;
798	return (0);
799}
800
801int
802procstat_get_pts_info(struct procstat *procstat, struct filestat *fst,
803    struct ptsstat *pts, char *errbuf)
804{
805
806	assert(pts);
807	if (procstat->type == PROCSTAT_KVM) {
808		return (procstat_get_pts_info_kvm(procstat->kd, fst, pts,
809		    errbuf));
810	} else if (procstat->type == PROCSTAT_SYSCTL) {
811		return (procstat_get_pts_info_sysctl(fst, pts, errbuf));
812	} else {
813		warnx("unknown access method: %d", procstat->type);
814		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
815		return (1);
816	}
817}
818
819static int
820procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst,
821    struct ptsstat *pts, char *errbuf)
822{
823	struct tty tty;
824	void *ttyp;
825
826	assert(kd);
827	assert(pts);
828	assert(fst);
829	bzero(pts, sizeof(*pts));
830	ttyp = fst->fs_typedep;
831	if (ttyp == NULL)
832		goto fail;
833	if (!kvm_read_all(kd, (unsigned long)ttyp, &tty, sizeof(struct tty))) {
834		warnx("can't read tty at %p", (void *)ttyp);
835		goto fail;
836	}
837	pts->dev = dev2udev(kd, tty.t_dev);
838	(void)kdevtoname(kd, tty.t_dev, pts->devname);
839	return (0);
840
841fail:
842	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
843	return (1);
844}
845
846static int
847procstat_get_pts_info_sysctl(struct filestat *fst, struct ptsstat *pts,
848    char *errbuf __unused)
849{
850	struct kinfo_file *kif;
851
852	assert(pts);
853	assert(fst);
854	bzero(pts, sizeof(*pts));
855	kif = fst->fs_typedep;
856	if (kif == NULL)
857		return (0);
858	pts->dev = kif->kf_un.kf_pts.kf_pts_dev;
859	strlcpy(pts->devname, kif->kf_path, sizeof(pts->devname));
860	return (0);
861}
862
863int
864procstat_get_shm_info(struct procstat *procstat, struct filestat *fst,
865    struct shmstat *shm, char *errbuf)
866{
867
868	assert(shm);
869	if (procstat->type == PROCSTAT_KVM) {
870		return (procstat_get_shm_info_kvm(procstat->kd, fst, shm,
871		    errbuf));
872	} else if (procstat->type == PROCSTAT_SYSCTL) {
873		return (procstat_get_shm_info_sysctl(fst, shm, errbuf));
874	} else {
875		warnx("unknown access method: %d", procstat->type);
876		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
877		return (1);
878	}
879}
880
881static int
882procstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst,
883    struct shmstat *shm, char *errbuf)
884{
885	struct shmfd shmfd;
886	void *shmfdp;
887	char *path;
888	int i;
889
890	assert(kd);
891	assert(shm);
892	assert(fst);
893	bzero(shm, sizeof(*shm));
894	shmfdp = fst->fs_typedep;
895	if (shmfdp == NULL)
896		goto fail;
897	if (!kvm_read_all(kd, (unsigned long)shmfdp, &shmfd,
898	    sizeof(struct shmfd))) {
899		warnx("can't read shmfd at %p", (void *)shmfdp);
900		goto fail;
901	}
902	shm->mode = S_IFREG | shmfd.shm_mode;
903	shm->size = shmfd.shm_size;
904	if (fst->fs_path == NULL && shmfd.shm_path != NULL) {
905		path = malloc(MAXPATHLEN);
906		for (i = 0; i < MAXPATHLEN - 1; i++) {
907			if (!kvm_read_all(kd, (unsigned long)shmfd.shm_path + i,
908			    path + i, 1))
909				break;
910			if (path[i] == '\0')
911				break;
912		}
913		path[i] = '\0';
914		if (i == 0)
915			free(path);
916		else
917			fst->fs_path = path;
918	}
919	return (0);
920
921fail:
922	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
923	return (1);
924}
925
926static int
927procstat_get_shm_info_sysctl(struct filestat *fst, struct shmstat *shm,
928    char *errbuf __unused)
929{
930	struct kinfo_file *kif;
931
932	assert(shm);
933	assert(fst);
934	bzero(shm, sizeof(*shm));
935	kif = fst->fs_typedep;
936	if (kif == NULL)
937		return (0);
938	shm->size = kif->kf_un.kf_file.kf_file_size;
939	shm->mode = kif->kf_un.kf_file.kf_file_mode;
940	return (0);
941}
942
943int
944procstat_get_vnode_info(struct procstat *procstat, struct filestat *fst,
945    struct vnstat *vn, char *errbuf)
946{
947
948	assert(vn);
949	if (procstat->type == PROCSTAT_KVM) {
950		return (procstat_get_vnode_info_kvm(procstat->kd, fst, vn,
951		    errbuf));
952	} else if (procstat->type == PROCSTAT_SYSCTL) {
953		return (procstat_get_vnode_info_sysctl(fst, vn, errbuf));
954	} else {
955		warnx("unknown access method: %d", procstat->type);
956		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
957		return (1);
958	}
959}
960
961static int
962procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst,
963    struct vnstat *vn, char *errbuf)
964{
965	/* Filesystem specific handlers. */
966	#define FSTYPE(fst)     {#fst, fst##_filestat}
967	struct {
968		const char	*tag;
969		int		(*handler)(kvm_t *kd, struct vnode *vp,
970		    struct vnstat *vn);
971	} fstypes[] = {
972		FSTYPE(devfs),
973		FSTYPE(isofs),
974		FSTYPE(msdosfs),
975		FSTYPE(nfs),
976		FSTYPE(smbfs),
977		FSTYPE(udf),
978		FSTYPE(ufs),
979#ifdef LIBPROCSTAT_ZFS
980		FSTYPE(zfs),
981#endif
982	};
983#define	NTYPES	(sizeof(fstypes) / sizeof(*fstypes))
984	struct vnode vnode;
985	char tagstr[12];
986	void *vp;
987	int error, found;
988	unsigned int i;
989
990	assert(kd);
991	assert(vn);
992	assert(fst);
993	vp = fst->fs_typedep;
994	if (vp == NULL)
995		goto fail;
996	error = kvm_read_all(kd, (unsigned long)vp, &vnode, sizeof(vnode));
997	if (error == 0) {
998		warnx("can't read vnode at %p", (void *)vp);
999		goto fail;
1000	}
1001	bzero(vn, sizeof(*vn));
1002	vn->vn_type = vntype2psfsttype(vnode.v_type);
1003	if (vnode.v_type == VNON || vnode.v_type == VBAD)
1004		return (0);
1005	error = kvm_read_all(kd, (unsigned long)vnode.v_tag, tagstr,
1006	    sizeof(tagstr));
1007	if (error == 0) {
1008		warnx("can't read v_tag at %p", (void *)vp);
1009		goto fail;
1010	}
1011	tagstr[sizeof(tagstr) - 1] = '\0';
1012
1013	/*
1014	 * Find appropriate handler.
1015	 */
1016	for (i = 0, found = 0; i < NTYPES; i++)
1017		if (!strcmp(fstypes[i].tag, tagstr)) {
1018			if (fstypes[i].handler(kd, &vnode, vn) != 0) {
1019				goto fail;
1020			}
1021			break;
1022		}
1023	if (i == NTYPES) {
1024		snprintf(errbuf, _POSIX2_LINE_MAX, "?(%s)", tagstr);
1025		return (1);
1026	}
1027	vn->vn_mntdir = getmnton(kd, vnode.v_mount);
1028	if ((vnode.v_type == VBLK || vnode.v_type == VCHR) &&
1029	    vnode.v_rdev != NULL){
1030		vn->vn_dev = dev2udev(kd, vnode.v_rdev);
1031		(void)kdevtoname(kd, vnode.v_rdev, vn->vn_devname);
1032	} else {
1033		vn->vn_dev = -1;
1034	}
1035	return (0);
1036
1037fail:
1038	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1039	return (1);
1040}
1041
1042/*
1043 * kinfo vnode type to filestat translation.
1044 */
1045static int
1046kinfo_vtype2fst(int kfvtype)
1047{
1048	static struct {
1049		int	kf_vtype;
1050		int	fst_vtype;
1051	} kfvtypes2fst[] = {
1052		{ KF_VTYPE_VBAD, PS_FST_VTYPE_VBAD },
1053		{ KF_VTYPE_VBLK, PS_FST_VTYPE_VBLK },
1054		{ KF_VTYPE_VCHR, PS_FST_VTYPE_VCHR },
1055		{ KF_VTYPE_VDIR, PS_FST_VTYPE_VDIR },
1056		{ KF_VTYPE_VFIFO, PS_FST_VTYPE_VFIFO },
1057		{ KF_VTYPE_VLNK, PS_FST_VTYPE_VLNK },
1058		{ KF_VTYPE_VNON, PS_FST_VTYPE_VNON },
1059		{ KF_VTYPE_VREG, PS_FST_VTYPE_VREG },
1060		{ KF_VTYPE_VSOCK, PS_FST_VTYPE_VSOCK }
1061	};
1062#define	NKFVTYPES	(sizeof(kfvtypes2fst) / sizeof(*kfvtypes2fst))
1063	unsigned int i;
1064
1065	for (i = 0; i < NKFVTYPES; i++)
1066		if (kfvtypes2fst[i].kf_vtype == kfvtype)
1067			break;
1068	if (i == NKFVTYPES)
1069		return (PS_FST_VTYPE_UNKNOWN);
1070	return (kfvtypes2fst[i].fst_vtype);
1071}
1072
1073static int
1074procstat_get_vnode_info_sysctl(struct filestat *fst, struct vnstat *vn,
1075    char *errbuf)
1076{
1077	struct statfs stbuf;
1078	struct kinfo_file *kif;
1079	struct kinfo_vmentry *kve;
1080	uint64_t fileid;
1081	uint64_t size;
1082	char *name, *path;
1083	uint32_t fsid;
1084	uint16_t mode;
1085	uint32_t rdev;
1086	int vntype;
1087	int status;
1088
1089	assert(fst);
1090	assert(vn);
1091	bzero(vn, sizeof(*vn));
1092	if (fst->fs_typedep == NULL)
1093		return (1);
1094	if (fst->fs_uflags & PS_FST_UFLAG_MMAP) {
1095		kve = fst->fs_typedep;
1096		fileid = kve->kve_vn_fileid;
1097		fsid = kve->kve_vn_fsid;
1098		mode = kve->kve_vn_mode;
1099		path = kve->kve_path;
1100		rdev = kve->kve_vn_rdev;
1101		size = kve->kve_vn_size;
1102		vntype = kinfo_vtype2fst(kve->kve_vn_type);
1103		status = kve->kve_status;
1104	} else {
1105		kif = fst->fs_typedep;
1106		fileid = kif->kf_un.kf_file.kf_file_fileid;
1107		fsid = kif->kf_un.kf_file.kf_file_fsid;
1108		mode = kif->kf_un.kf_file.kf_file_mode;
1109		path = kif->kf_path;
1110		rdev = kif->kf_un.kf_file.kf_file_rdev;
1111		size = kif->kf_un.kf_file.kf_file_size;
1112		vntype = kinfo_vtype2fst(kif->kf_vnode_type);
1113		status = kif->kf_status;
1114	}
1115	vn->vn_type = vntype;
1116	if (vntype == PS_FST_VTYPE_VNON || vntype == PS_FST_VTYPE_VBAD)
1117		return (0);
1118	if ((status & KF_ATTR_VALID) == 0) {
1119		snprintf(errbuf, _POSIX2_LINE_MAX, "? (no info available)");
1120		return (1);
1121	}
1122	if (path && *path) {
1123		statfs(path, &stbuf);
1124		vn->vn_mntdir = strdup(stbuf.f_mntonname);
1125	} else
1126		vn->vn_mntdir = strdup("-");
1127	vn->vn_dev = rdev;
1128	if (vntype == PS_FST_VTYPE_VBLK) {
1129		name = devname(rdev, S_IFBLK);
1130		if (name != NULL)
1131			strlcpy(vn->vn_devname, name,
1132			    sizeof(vn->vn_devname));
1133	} else if (vntype == PS_FST_VTYPE_VCHR) {
1134		name = devname(vn->vn_dev, S_IFCHR);
1135		if (name != NULL)
1136			strlcpy(vn->vn_devname, name,
1137			    sizeof(vn->vn_devname));
1138	}
1139	vn->vn_fsid = fsid;
1140	vn->vn_fileid = fileid;
1141	vn->vn_size = size;
1142	vn->vn_mode = mode;
1143	return (0);
1144}
1145
1146int
1147procstat_get_socket_info(struct procstat *procstat, struct filestat *fst,
1148    struct sockstat *sock, char *errbuf)
1149{
1150
1151	assert(sock);
1152	if (procstat->type == PROCSTAT_KVM) {
1153		return (procstat_get_socket_info_kvm(procstat->kd, fst, sock,
1154		    errbuf));
1155	} else if (procstat->type == PROCSTAT_SYSCTL) {
1156		return (procstat_get_socket_info_sysctl(fst, sock, errbuf));
1157	} else {
1158		warnx("unknown access method: %d", procstat->type);
1159		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1160		return (1);
1161	}
1162}
1163
1164static int
1165procstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst,
1166    struct sockstat *sock, char *errbuf)
1167{
1168	struct domain dom;
1169	struct inpcb inpcb;
1170	struct protosw proto;
1171	struct socket s;
1172	struct unpcb unpcb;
1173	ssize_t len;
1174	void *so;
1175
1176	assert(kd);
1177	assert(sock);
1178	assert(fst);
1179	bzero(sock, sizeof(*sock));
1180	so = fst->fs_typedep;
1181	if (so == NULL)
1182		goto fail;
1183	sock->so_addr = (uintptr_t)so;
1184	/* fill in socket */
1185	if (!kvm_read_all(kd, (unsigned long)so, &s,
1186	    sizeof(struct socket))) {
1187		warnx("can't read sock at %p", (void *)so);
1188		goto fail;
1189	}
1190	/* fill in protosw entry */
1191	if (!kvm_read_all(kd, (unsigned long)s.so_proto, &proto,
1192	    sizeof(struct protosw))) {
1193		warnx("can't read protosw at %p", (void *)s.so_proto);
1194		goto fail;
1195	}
1196	/* fill in domain */
1197	if (!kvm_read_all(kd, (unsigned long)proto.pr_domain, &dom,
1198	    sizeof(struct domain))) {
1199		warnx("can't read domain at %p",
1200		    (void *)proto.pr_domain);
1201		goto fail;
1202	}
1203	if ((len = kvm_read(kd, (unsigned long)dom.dom_name, sock->dname,
1204	    sizeof(sock->dname) - 1)) < 0) {
1205		warnx("can't read domain name at %p", (void *)dom.dom_name);
1206		sock->dname[0] = '\0';
1207	}
1208	else
1209		sock->dname[len] = '\0';
1210
1211	/*
1212	 * Fill in known data.
1213	 */
1214	sock->type = s.so_type;
1215	sock->proto = proto.pr_protocol;
1216	sock->dom_family = dom.dom_family;
1217	sock->so_pcb = (uintptr_t)s.so_pcb;
1218
1219	/*
1220	 * Protocol specific data.
1221	 */
1222	switch(dom.dom_family) {
1223	case AF_INET:
1224	case AF_INET6:
1225		if (proto.pr_protocol == IPPROTO_TCP) {
1226			if (s.so_pcb) {
1227				if (kvm_read(kd, (u_long)s.so_pcb,
1228				    (char *)&inpcb, sizeof(struct inpcb))
1229				    != sizeof(struct inpcb)) {
1230					warnx("can't read inpcb at %p",
1231					    (void *)s.so_pcb);
1232				} else
1233					sock->inp_ppcb =
1234					    (uintptr_t)inpcb.inp_ppcb;
1235			}
1236		}
1237		break;
1238	case AF_UNIX:
1239		if (s.so_pcb) {
1240			if (kvm_read(kd, (u_long)s.so_pcb, (char *)&unpcb,
1241			    sizeof(struct unpcb)) != sizeof(struct unpcb)){
1242				warnx("can't read unpcb at %p",
1243				    (void *)s.so_pcb);
1244			} else if (unpcb.unp_conn) {
1245				sock->so_rcv_sb_state = s.so_rcv.sb_state;
1246				sock->so_snd_sb_state = s.so_snd.sb_state;
1247				sock->unp_conn = (uintptr_t)unpcb.unp_conn;
1248			}
1249		}
1250		break;
1251	default:
1252		break;
1253	}
1254	return (0);
1255
1256fail:
1257	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1258	return (1);
1259}
1260
1261static int
1262procstat_get_socket_info_sysctl(struct filestat *fst, struct sockstat *sock,
1263    char *errbuf __unused)
1264{
1265	struct kinfo_file *kif;
1266
1267	assert(sock);
1268	assert(fst);
1269	bzero(sock, sizeof(*sock));
1270	kif = fst->fs_typedep;
1271	if (kif == NULL)
1272		return (0);
1273
1274	/*
1275	 * Fill in known data.
1276	 */
1277	sock->type = kif->kf_sock_type;
1278	sock->proto = kif->kf_sock_protocol;
1279	sock->dom_family = kif->kf_sock_domain;
1280	sock->so_pcb = kif->kf_un.kf_sock.kf_sock_pcb;
1281	strlcpy(sock->dname, kif->kf_path, sizeof(sock->dname));
1282	bcopy(&kif->kf_sa_local, &sock->sa_local, kif->kf_sa_local.ss_len);
1283	bcopy(&kif->kf_sa_peer, &sock->sa_peer, kif->kf_sa_peer.ss_len);
1284
1285	/*
1286	 * Protocol specific data.
1287	 */
1288	switch(sock->dom_family) {
1289	case AF_INET:
1290	case AF_INET6:
1291		if (sock->proto == IPPROTO_TCP)
1292			sock->inp_ppcb = kif->kf_un.kf_sock.kf_sock_inpcb;
1293		break;
1294	case AF_UNIX:
1295		if (kif->kf_un.kf_sock.kf_sock_unpconn != 0) {
1296				sock->so_rcv_sb_state =
1297				    kif->kf_un.kf_sock.kf_sock_rcv_sb_state;
1298				sock->so_snd_sb_state =
1299				    kif->kf_un.kf_sock.kf_sock_snd_sb_state;
1300				sock->unp_conn =
1301				    kif->kf_un.kf_sock.kf_sock_unpconn;
1302		}
1303		break;
1304	default:
1305		break;
1306	}
1307	return (0);
1308}
1309
1310/*
1311 * Descriptor flags to filestat translation.
1312 */
1313static int
1314to_filestat_flags(int flags)
1315{
1316	static struct {
1317		int flag;
1318		int fst_flag;
1319	} fstflags[] = {
1320		{ FREAD, PS_FST_FFLAG_READ },
1321		{ FWRITE, PS_FST_FFLAG_WRITE },
1322		{ O_APPEND, PS_FST_FFLAG_APPEND },
1323		{ O_ASYNC, PS_FST_FFLAG_ASYNC },
1324		{ O_CREAT, PS_FST_FFLAG_CREAT },
1325		{ O_DIRECT, PS_FST_FFLAG_DIRECT },
1326		{ O_EXCL, PS_FST_FFLAG_EXCL },
1327		{ O_EXEC, PS_FST_FFLAG_EXEC },
1328		{ O_EXLOCK, PS_FST_FFLAG_EXLOCK },
1329		{ O_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW },
1330		{ O_NONBLOCK, PS_FST_FFLAG_NONBLOCK },
1331		{ O_SHLOCK, PS_FST_FFLAG_SHLOCK },
1332		{ O_SYNC, PS_FST_FFLAG_SYNC },
1333		{ O_TRUNC, PS_FST_FFLAG_TRUNC }
1334	};
1335#define NFSTFLAGS	(sizeof(fstflags) / sizeof(*fstflags))
1336	int fst_flags;
1337	unsigned int i;
1338
1339	fst_flags = 0;
1340	for (i = 0; i < NFSTFLAGS; i++)
1341		if (flags & fstflags[i].flag)
1342			fst_flags |= fstflags[i].fst_flag;
1343	return (fst_flags);
1344}
1345
1346/*
1347 * Vnode type to filestate translation.
1348 */
1349static int
1350vntype2psfsttype(int type)
1351{
1352	static struct {
1353		int	vtype;
1354		int	fst_vtype;
1355	} vt2fst[] = {
1356		{ VBAD, PS_FST_VTYPE_VBAD },
1357		{ VBLK, PS_FST_VTYPE_VBLK },
1358		{ VCHR, PS_FST_VTYPE_VCHR },
1359		{ VDIR, PS_FST_VTYPE_VDIR },
1360		{ VFIFO, PS_FST_VTYPE_VFIFO },
1361		{ VLNK, PS_FST_VTYPE_VLNK },
1362		{ VNON, PS_FST_VTYPE_VNON },
1363		{ VREG, PS_FST_VTYPE_VREG },
1364		{ VSOCK, PS_FST_VTYPE_VSOCK }
1365	};
1366#define	NVFTYPES	(sizeof(vt2fst) / sizeof(*vt2fst))
1367	unsigned int i, fst_type;
1368
1369	fst_type = PS_FST_VTYPE_UNKNOWN;
1370	for (i = 0; i < NVFTYPES; i++) {
1371		if (type == vt2fst[i].vtype) {
1372			fst_type = vt2fst[i].fst_vtype;
1373			break;
1374		}
1375	}
1376	return (fst_type);
1377}
1378
1379static char *
1380getmnton(kvm_t *kd, struct mount *m)
1381{
1382	struct mount mnt;
1383	static struct mtab {
1384		struct mtab *next;
1385		struct mount *m;
1386		char mntonname[MNAMELEN + 1];
1387	} *mhead = NULL;
1388	struct mtab *mt;
1389
1390	for (mt = mhead; mt != NULL; mt = mt->next)
1391		if (m == mt->m)
1392			return (mt->mntonname);
1393	if (!kvm_read_all(kd, (unsigned long)m, &mnt, sizeof(struct mount))) {
1394		warnx("can't read mount table at %p", (void *)m);
1395		return (NULL);
1396	}
1397	if ((mt = malloc(sizeof (struct mtab))) == NULL)
1398		err(1, NULL);
1399	mt->m = m;
1400	bcopy(&mnt.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN);
1401	mt->mntonname[MNAMELEN] = '\0';
1402	mt->next = mhead;
1403	mhead = mt;
1404	return (mt->mntonname);
1405}
1406