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