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