libprocstat.c revision 249667
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: head/lib/libprocstat/libprocstat.c 249667 2013-04-20 07:49:35Z trociny $");
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
101int     statfs(const char *, struct statfs *);	/* XXX */
102
103#define	PROCSTAT_KVM	1
104#define	PROCSTAT_SYSCTL	2
105#define	PROCSTAT_CORE	3
106
107static char	*getmnton(kvm_t *kd, struct mount *m);
108static struct kinfo_vmentry *	kinfo_getvmmap_core(struct procstat_core *core,
109    int *cntp);
110static struct filestat_list	*procstat_getfiles_kvm(
111    struct procstat *procstat, struct kinfo_proc *kp, int mmapped);
112static struct filestat_list	*procstat_getfiles_sysctl(
113    struct procstat *procstat, struct kinfo_proc *kp, int mmapped);
114static int	procstat_get_pipe_info_sysctl(struct filestat *fst,
115    struct pipestat *pipe, char *errbuf);
116static int	procstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst,
117    struct pipestat *pipe, char *errbuf);
118static int	procstat_get_pts_info_sysctl(struct filestat *fst,
119    struct ptsstat *pts, char *errbuf);
120static int	procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst,
121    struct ptsstat *pts, char *errbuf);
122static int	procstat_get_shm_info_sysctl(struct filestat *fst,
123    struct shmstat *shm, char *errbuf);
124static int	procstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst,
125    struct shmstat *shm, char *errbuf);
126static int	procstat_get_socket_info_sysctl(struct filestat *fst,
127    struct sockstat *sock, char *errbuf);
128static int	procstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst,
129    struct sockstat *sock, char *errbuf);
130static int	to_filestat_flags(int flags);
131static int	procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst,
132    struct vnstat *vn, char *errbuf);
133static int	procstat_get_vnode_info_sysctl(struct filestat *fst,
134    struct vnstat *vn, char *errbuf);
135static int	vntype2psfsttype(int type);
136
137void
138procstat_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
149struct procstat *
150procstat_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
163struct procstat *
164procstat_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
186struct procstat *
187procstat_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
207struct kinfo_proc *
208procstat_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	}
279fail:
280	if (p)
281		free(p);
282	return (NULL);
283}
284
285void
286procstat_freeprocs(struct procstat *procstat __unused, struct kinfo_proc *p)
287{
288
289	if (p != NULL)
290		free(p);
291	p = NULL;
292}
293
294struct filestat_list *
295procstat_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
310void
311procstat_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
331static struct filestat *
332filestat_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
354static struct vnode *
355getctty(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
389static struct filestat_list *
390procstat_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
535do_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	}
593exit:
594	return (head);
595}
596
597/*
598 * kinfo types to filestat translation.
599 */
600static int
601kinfo_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 */
634static int
635kinfo_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
668static int
669kinfo_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
689static struct kinfo_file *
690kinfo_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
742static struct filestat_list *
743procstat_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	}
834fail:
835	return (head);
836}
837
838int
839procstat_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
857static int
858procstat_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
880fail:
881	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
882	return (1);
883}
884
885static int
886procstat_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
903int
904procstat_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
922static int
923procstat_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
944fail:
945	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
946	return (1);
947}
948
949static int
950procstat_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
966int
967procstat_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
985static int
986procstat_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
1025fail:
1026	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1027	return (1);
1028}
1029
1030static int
1031procstat_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
1047int
1048procstat_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
1066static int
1067procstat_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
1141fail:
1142	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1143	return (1);
1144}
1145
1146/*
1147 * kinfo vnode type to filestat translation.
1148 */
1149static int
1150kinfo_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
1177static int
1178procstat_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
1250int
1251procstat_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
1269static int
1270procstat_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
1361fail:
1362	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1363	return (1);
1364}
1365
1366static int
1367procstat_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 */
1418static int
1419to_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 */
1454static int
1455vntype2psfsttype(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
1484static char *
1485getmnton(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
1512static struct kinfo_vmentry *
1513kinfo_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
1566struct kinfo_vmentry *
1567procstat_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
1584void
1585procstat_freevmmap(struct procstat *procstat __unused,
1586    struct kinfo_vmentry *vmmap)
1587{
1588
1589	free(vmmap);
1590}
1591