1221807Sstas/*-
2221807Sstas * Copyright (c) 2009 Stanislav Sedov <stas@FreeBSD.org>
3221807Sstas * Copyright (c) 1988, 1993
4221807Sstas *      The Regents of the University of California.  All rights reserved.
5221807Sstas *
6221807Sstas * Redistribution and use in source and binary forms, with or without
7221807Sstas * modification, are permitted provided that the following conditions
8221807Sstas * are met:
9221807Sstas * 1. Redistributions of source code must retain the above copyright
10221807Sstas *    notice, this list of conditions and the following disclaimer.
11221807Sstas * 2. Redistributions in binary form must reproduce the above copyright
12221807Sstas *    notice, this list of conditions and the following disclaimer in the
13221807Sstas *    documentation and/or other materials provided with the distribution.
14221807Sstas * 3. All advertising materials mentioning features or use of this software
15221807Sstas *    must display the following acknowledgement:
16221807Sstas *      This product includes software developed by the University of
17221807Sstas *      California, Berkeley and its contributors.
18221807Sstas * 4. Neither the name of the University nor the names of its contributors
19221807Sstas *    may be used to endorse or promote products derived from this software
20221807Sstas *    without specific prior written permission.
21221807Sstas *
22221807Sstas * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23221807Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24221807Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25221807Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26221807Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27221807Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28221807Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29221807Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30221807Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31221807Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32221807Sstas * SUCH DAMAGE.
33221807Sstas */
34221807Sstas
35221807Sstas#include <sys/cdefs.h>
36221807Sstas__FBSDID("$FreeBSD: stable/10/lib/libprocstat/libprocstat.c 312036 2017-01-13 08:42:11Z ngie $");
37221807Sstas
38221807Sstas#include <sys/param.h>
39249681Strociny#include <sys/elf.h>
40221807Sstas#include <sys/time.h>
41249674Strociny#include <sys/resourcevar.h>
42250146Strociny#define	_WANT_UCRED
43250146Strociny#include <sys/ucred.h>
44250146Strociny#undef _WANT_UCRED
45221807Sstas#include <sys/proc.h>
46221807Sstas#include <sys/user.h>
47221807Sstas#include <sys/stat.h>
48221807Sstas#include <sys/vnode.h>
49221807Sstas#include <sys/socket.h>
50221807Sstas#include <sys/socketvar.h>
51221807Sstas#include <sys/domain.h>
52221807Sstas#include <sys/protosw.h>
53221807Sstas#include <sys/un.h>
54221807Sstas#include <sys/unpcb.h>
55221807Sstas#include <sys/sysctl.h>
56221807Sstas#include <sys/tty.h>
57221807Sstas#include <sys/filedesc.h>
58221807Sstas#include <sys/queue.h>
59221807Sstas#define	_WANT_FILE
60221807Sstas#include <sys/file.h>
61221807Sstas#include <sys/conf.h>
62250223Sjhb#include <sys/ksem.h>
63233760Sjhb#include <sys/mman.h>
64280250Srwatson#include <sys/capsicum.h>
65221807Sstas#define	_KERNEL
66221807Sstas#include <sys/mount.h>
67221807Sstas#include <sys/pipe.h>
68221807Sstas#include <ufs/ufs/quota.h>
69221807Sstas#include <ufs/ufs/inode.h>
70221807Sstas#include <fs/devfs/devfs.h>
71221807Sstas#include <fs/devfs/devfs_int.h>
72221807Sstas#undef _KERNEL
73221807Sstas#include <nfs/nfsproto.h>
74221807Sstas#include <nfsclient/nfs.h>
75221807Sstas#include <nfsclient/nfsnode.h>
76221807Sstas
77221807Sstas#include <vm/vm.h>
78221807Sstas#include <vm/vm_map.h>
79221807Sstas#include <vm/vm_object.h>
80221807Sstas
81221807Sstas#include <net/route.h>
82221807Sstas#include <netinet/in.h>
83221807Sstas#include <netinet/in_systm.h>
84221807Sstas#include <netinet/ip.h>
85221807Sstas#include <netinet/in_pcb.h>
86221807Sstas
87221807Sstas#include <assert.h>
88221807Sstas#include <ctype.h>
89221807Sstas#include <err.h>
90221807Sstas#include <fcntl.h>
91221807Sstas#include <kvm.h>
92221807Sstas#include <libutil.h>
93221807Sstas#include <limits.h>
94221807Sstas#include <paths.h>
95221807Sstas#include <pwd.h>
96221807Sstas#include <stdio.h>
97221807Sstas#include <stdlib.h>
98221807Sstas#include <stddef.h>
99221807Sstas#include <string.h>
100221807Sstas#include <unistd.h>
101221807Sstas#include <netdb.h>
102221807Sstas
103221807Sstas#include <libprocstat.h>
104221807Sstas#include "libprocstat_internal.h"
105221807Sstas#include "common_kvm.h"
106249666Strociny#include "core.h"
107221807Sstas
108221807Sstasint     statfs(const char *, struct statfs *);	/* XXX */
109221807Sstas
110221807Sstas#define	PROCSTAT_KVM	1
111221807Sstas#define	PROCSTAT_SYSCTL	2
112249666Strociny#define	PROCSTAT_CORE	3
113221807Sstas
114249679Strocinystatic char	**getargv(struct procstat *procstat, struct kinfo_proc *kp,
115249679Strociny    size_t nchr, int env);
116221807Sstasstatic char	*getmnton(kvm_t *kd, struct mount *m);
117249667Strocinystatic struct kinfo_vmentry *	kinfo_getvmmap_core(struct procstat_core *core,
118249667Strociny    int *cntp);
119249681Strocinystatic Elf_Auxinfo	*procstat_getauxv_core(struct procstat_core *core,
120249681Strociny    unsigned int *cntp);
121249681Strocinystatic Elf_Auxinfo	*procstat_getauxv_sysctl(pid_t pid, unsigned int *cntp);
122221807Sstasstatic struct filestat_list	*procstat_getfiles_kvm(
123221807Sstas    struct procstat *procstat, struct kinfo_proc *kp, int mmapped);
124221807Sstasstatic struct filestat_list	*procstat_getfiles_sysctl(
125221807Sstas    struct procstat *procstat, struct kinfo_proc *kp, int mmapped);
126221807Sstasstatic int	procstat_get_pipe_info_sysctl(struct filestat *fst,
127221807Sstas    struct pipestat *pipe, char *errbuf);
128221807Sstasstatic int	procstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst,
129221807Sstas    struct pipestat *pipe, char *errbuf);
130221807Sstasstatic int	procstat_get_pts_info_sysctl(struct filestat *fst,
131221807Sstas    struct ptsstat *pts, char *errbuf);
132221807Sstasstatic int	procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst,
133221807Sstas    struct ptsstat *pts, char *errbuf);
134250223Sjhbstatic int	procstat_get_sem_info_sysctl(struct filestat *fst,
135250223Sjhb    struct semstat *sem, char *errbuf);
136250223Sjhbstatic int	procstat_get_sem_info_kvm(kvm_t *kd, struct filestat *fst,
137250223Sjhb    struct semstat *sem, char *errbuf);
138233760Sjhbstatic int	procstat_get_shm_info_sysctl(struct filestat *fst,
139233760Sjhb    struct shmstat *shm, char *errbuf);
140233760Sjhbstatic int	procstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst,
141233760Sjhb    struct shmstat *shm, char *errbuf);
142221807Sstasstatic int	procstat_get_socket_info_sysctl(struct filestat *fst,
143221807Sstas    struct sockstat *sock, char *errbuf);
144221807Sstasstatic int	procstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst,
145221807Sstas    struct sockstat *sock, char *errbuf);
146221807Sstasstatic int	to_filestat_flags(int flags);
147221807Sstasstatic int	procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst,
148221807Sstas    struct vnstat *vn, char *errbuf);
149221807Sstasstatic int	procstat_get_vnode_info_sysctl(struct filestat *fst,
150221807Sstas    struct vnstat *vn, char *errbuf);
151249670Strocinystatic gid_t	*procstat_getgroups_core(struct procstat_core *core,
152249670Strociny    unsigned int *count);
153250146Strocinystatic gid_t *	procstat_getgroups_kvm(kvm_t *kd, struct kinfo_proc *kp,
154250146Strociny    unsigned int *count);
155249670Strocinystatic gid_t	*procstat_getgroups_sysctl(pid_t pid, unsigned int *count);
156249684Strocinystatic struct kinfo_kstack	*procstat_getkstack_sysctl(pid_t pid,
157249684Strociny    int *cntp);
158250146Strocinystatic int	procstat_getosrel_core(struct procstat_core *core,
159250146Strociny    int *osrelp);
160250146Strocinystatic int	procstat_getosrel_kvm(kvm_t *kd, struct kinfo_proc *kp,
161250146Strociny    int *osrelp);
162250146Strocinystatic int	procstat_getosrel_sysctl(pid_t pid, int *osrelp);
163249676Strocinystatic int	procstat_getpathname_core(struct procstat_core *core,
164249676Strociny    char *pathname, size_t maxlen);
165249676Strocinystatic int	procstat_getpathname_sysctl(pid_t pid, char *pathname,
166249676Strociny    size_t maxlen);
167249674Strocinystatic int	procstat_getrlimit_core(struct procstat_core *core, int which,
168249674Strociny    struct rlimit* rlimit);
169250146Strocinystatic int	procstat_getrlimit_kvm(kvm_t *kd, struct kinfo_proc *kp,
170250146Strociny    int which, struct rlimit* rlimit);
171249674Strocinystatic int	procstat_getrlimit_sysctl(pid_t pid, int which,
172249674Strociny    struct rlimit* rlimit);
173249672Strocinystatic int	procstat_getumask_core(struct procstat_core *core,
174249672Strociny    unsigned short *maskp);
175250146Strocinystatic int	procstat_getumask_kvm(kvm_t *kd, struct kinfo_proc *kp,
176250146Strociny    unsigned short *maskp);
177249672Strocinystatic int	procstat_getumask_sysctl(pid_t pid, unsigned short *maskp);
178221807Sstasstatic int	vntype2psfsttype(int type);
179221807Sstas
180221807Sstasvoid
181221807Sstasprocstat_close(struct procstat *procstat)
182221807Sstas{
183221807Sstas
184221807Sstas	assert(procstat);
185221807Sstas	if (procstat->type == PROCSTAT_KVM)
186221807Sstas		kvm_close(procstat->kd);
187249666Strociny	else if (procstat->type == PROCSTAT_CORE)
188249666Strociny		procstat_core_close(procstat->core);
189249679Strociny	procstat_freeargv(procstat);
190249679Strociny	procstat_freeenvv(procstat);
191222053Spluknet	free(procstat);
192221807Sstas}
193221807Sstas
194221807Sstasstruct procstat *
195221807Sstasprocstat_open_sysctl(void)
196221807Sstas{
197221807Sstas	struct procstat *procstat;
198221807Sstas
199221807Sstas	procstat = calloc(1, sizeof(*procstat));
200221807Sstas	if (procstat == NULL) {
201221807Sstas		warn("malloc()");
202221807Sstas		return (NULL);
203221807Sstas	}
204221807Sstas	procstat->type = PROCSTAT_SYSCTL;
205221807Sstas	return (procstat);
206221807Sstas}
207221807Sstas
208221807Sstasstruct procstat *
209221807Sstasprocstat_open_kvm(const char *nlistf, const char *memf)
210221807Sstas{
211221807Sstas	struct procstat *procstat;
212221807Sstas	kvm_t *kd;
213221807Sstas	char buf[_POSIX2_LINE_MAX];
214221807Sstas
215221807Sstas	procstat = calloc(1, sizeof(*procstat));
216221807Sstas	if (procstat == NULL) {
217221807Sstas		warn("malloc()");
218221807Sstas		return (NULL);
219221807Sstas	}
220221807Sstas	kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf);
221221807Sstas	if (kd == NULL) {
222221807Sstas		warnx("kvm_openfiles(): %s", buf);
223221807Sstas		free(procstat);
224221807Sstas		return (NULL);
225221807Sstas	}
226221807Sstas	procstat->type = PROCSTAT_KVM;
227221807Sstas	procstat->kd = kd;
228221807Sstas	return (procstat);
229221807Sstas}
230221807Sstas
231249666Strocinystruct procstat *
232249666Strocinyprocstat_open_core(const char *filename)
233249666Strociny{
234249666Strociny	struct procstat *procstat;
235249666Strociny	struct procstat_core *core;
236249666Strociny
237249666Strociny	procstat = calloc(1, sizeof(*procstat));
238249666Strociny	if (procstat == NULL) {
239249666Strociny		warn("malloc()");
240249666Strociny		return (NULL);
241249666Strociny	}
242249666Strociny	core = procstat_core_open(filename);
243249666Strociny	if (core == NULL) {
244249666Strociny		free(procstat);
245249666Strociny		return (NULL);
246249666Strociny	}
247249666Strociny	procstat->type = PROCSTAT_CORE;
248249666Strociny	procstat->core = core;
249249666Strociny	return (procstat);
250249666Strociny}
251249666Strociny
252221807Sstasstruct kinfo_proc *
253221807Sstasprocstat_getprocs(struct procstat *procstat, int what, int arg,
254221807Sstas    unsigned int *count)
255221807Sstas{
256221807Sstas	struct kinfo_proc *p0, *p;
257251637Sjhb	size_t len, olen;
258221807Sstas	int name[4];
259241304Savg	int cnt;
260221807Sstas	int error;
261221807Sstas
262221807Sstas	assert(procstat);
263221807Sstas	assert(count);
264221807Sstas	p = NULL;
265221807Sstas	if (procstat->type == PROCSTAT_KVM) {
266241304Savg		*count = 0;
267241304Savg		p0 = kvm_getprocs(procstat->kd, what, arg, &cnt);
268241304Savg		if (p0 == NULL || cnt <= 0)
269221807Sstas			return (NULL);
270241304Savg		*count = cnt;
271221807Sstas		len = *count * sizeof(*p);
272221807Sstas		p = malloc(len);
273221807Sstas		if (p == NULL) {
274223269Sjilles			warnx("malloc(%zu)", len);
275221807Sstas			goto fail;
276221807Sstas		}
277221807Sstas		bcopy(p0, p, len);
278221807Sstas		return (p);
279221807Sstas	} else if (procstat->type == PROCSTAT_SYSCTL) {
280221807Sstas		len = 0;
281221807Sstas		name[0] = CTL_KERN;
282221807Sstas		name[1] = KERN_PROC;
283221807Sstas		name[2] = what;
284221807Sstas		name[3] = arg;
285312036Sngie		error = sysctl(name, nitems(name), NULL, &len, NULL, 0);
286221807Sstas		if (error < 0 && errno != EPERM) {
287221807Sstas			warn("sysctl(kern.proc)");
288221807Sstas			goto fail;
289221807Sstas		}
290221807Sstas		if (len == 0) {
291221807Sstas			warnx("no processes?");
292221807Sstas			goto fail;
293221807Sstas		}
294251637Sjhb		do {
295251637Sjhb			len += len / 10;
296251637Sjhb			p = reallocf(p, len);
297251637Sjhb			if (p == NULL) {
298251637Sjhb				warnx("reallocf(%zu)", len);
299251637Sjhb				goto fail;
300251637Sjhb			}
301251637Sjhb			olen = len;
302312036Sngie			error = sysctl(name, nitems(name), p, &len, NULL, 0);
303251637Sjhb		} while (error < 0 && errno == ENOMEM && olen == len);
304221807Sstas		if (error < 0 && errno != EPERM) {
305221807Sstas			warn("sysctl(kern.proc)");
306221807Sstas			goto fail;
307221807Sstas		}
308221807Sstas		/* Perform simple consistency checks. */
309221807Sstas		if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) {
310249666Strociny			warnx("kinfo_proc structure size mismatch (len = %zu)", len);
311249666Strociny			goto fail;
312249666Strociny		}
313249666Strociny		*count = len / sizeof(*p);
314249666Strociny		return (p);
315249666Strociny	} else if (procstat->type == PROCSTAT_CORE) {
316249666Strociny		p = procstat_core_get(procstat->core, PSC_TYPE_PROC, NULL,
317249666Strociny		    &len);
318249666Strociny		if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) {
319221807Sstas			warnx("kinfo_proc structure size mismatch");
320221807Sstas			goto fail;
321221807Sstas		}
322221807Sstas		*count = len / sizeof(*p);
323221807Sstas		return (p);
324221807Sstas	} else {
325223276Sjilles		warnx("unknown access method: %d", procstat->type);
326221807Sstas		return (NULL);
327221807Sstas	}
328221807Sstasfail:
329221807Sstas	if (p)
330221807Sstas		free(p);
331221807Sstas	return (NULL);
332221807Sstas}
333221807Sstas
334221807Sstasvoid
335221807Sstasprocstat_freeprocs(struct procstat *procstat __unused, struct kinfo_proc *p)
336221807Sstas{
337221807Sstas
338221807Sstas	if (p != NULL)
339221807Sstas		free(p);
340221807Sstas	p = NULL;
341221807Sstas}
342221807Sstas
343221807Sstasstruct filestat_list *
344221807Sstasprocstat_getfiles(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
345221807Sstas{
346249666Strociny
347249666Strociny	switch(procstat->type) {
348249666Strociny	case PROCSTAT_KVM:
349249666Strociny		return (procstat_getfiles_kvm(procstat, kp, mmapped));
350249666Strociny	case PROCSTAT_SYSCTL:
351249666Strociny	case PROCSTAT_CORE:
352221807Sstas		return (procstat_getfiles_sysctl(procstat, kp, mmapped));
353249666Strociny	default:
354249666Strociny		warnx("unknown access method: %d", procstat->type);
355221807Sstas		return (NULL);
356249666Strociny	}
357221807Sstas}
358221807Sstas
359221807Sstasvoid
360221807Sstasprocstat_freefiles(struct procstat *procstat, struct filestat_list *head)
361221807Sstas{
362221807Sstas	struct filestat *fst, *tmp;
363221807Sstas
364221807Sstas	STAILQ_FOREACH_SAFE(fst, head, next, tmp) {
365221807Sstas		if (fst->fs_path != NULL)
366221807Sstas			free(fst->fs_path);
367221807Sstas		free(fst);
368221807Sstas	}
369221807Sstas	free(head);
370221807Sstas	if (procstat->vmentries != NULL) {
371223270Sjilles		free(procstat->vmentries);
372221807Sstas		procstat->vmentries = NULL;
373221807Sstas	}
374221807Sstas	if (procstat->files != NULL) {
375223270Sjilles		free(procstat->files);
376221807Sstas		procstat->files = NULL;
377221807Sstas	}
378221807Sstas}
379221807Sstas
380221807Sstasstatic struct filestat *
381221807Sstasfilestat_new_entry(void *typedep, int type, int fd, int fflags, int uflags,
382255219Spjd    int refcount, off_t offset, char *path, cap_rights_t *cap_rightsp)
383221807Sstas{
384221807Sstas	struct filestat *entry;
385221807Sstas
386221807Sstas	entry = calloc(1, sizeof(*entry));
387221807Sstas	if (entry == NULL) {
388221807Sstas		warn("malloc()");
389221807Sstas		return (NULL);
390221807Sstas	}
391221807Sstas	entry->fs_typedep = typedep;
392221807Sstas	entry->fs_fflags = fflags;
393221807Sstas	entry->fs_uflags = uflags;
394221807Sstas	entry->fs_fd = fd;
395221807Sstas	entry->fs_type = type;
396221807Sstas	entry->fs_ref_count = refcount;
397221807Sstas	entry->fs_offset = offset;
398221807Sstas	entry->fs_path = path;
399256242Spjd	if (cap_rightsp != NULL)
400256242Spjd		entry->fs_cap_rights = *cap_rightsp;
401256242Spjd	else
402256242Spjd		cap_rights_init(&entry->fs_cap_rights);
403221807Sstas	return (entry);
404221807Sstas}
405221807Sstas
406221807Sstasstatic struct vnode *
407221807Sstasgetctty(kvm_t *kd, struct kinfo_proc *kp)
408221807Sstas{
409221807Sstas	struct pgrp pgrp;
410221807Sstas	struct proc proc;
411221807Sstas	struct session sess;
412221807Sstas	int error;
413221807Sstas
414221807Sstas	assert(kp);
415221807Sstas	error = kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc,
416221807Sstas	    sizeof(proc));
417221807Sstas	if (error == 0) {
418221807Sstas		warnx("can't read proc struct at %p for pid %d",
419221807Sstas		    kp->ki_paddr, kp->ki_pid);
420221807Sstas		return (NULL);
421221807Sstas	}
422221807Sstas	if (proc.p_pgrp == NULL)
423221807Sstas		return (NULL);
424221807Sstas	error = kvm_read_all(kd, (unsigned long)proc.p_pgrp, &pgrp,
425221807Sstas	    sizeof(pgrp));
426221807Sstas	if (error == 0) {
427221807Sstas		warnx("can't read pgrp struct at %p for pid %d",
428221807Sstas		    proc.p_pgrp, kp->ki_pid);
429221807Sstas		return (NULL);
430221807Sstas	}
431221807Sstas	error = kvm_read_all(kd, (unsigned long)pgrp.pg_session, &sess,
432221807Sstas	    sizeof(sess));
433221807Sstas	if (error == 0) {
434221807Sstas		warnx("can't read session struct at %p for pid %d",
435221807Sstas		    pgrp.pg_session, kp->ki_pid);
436221807Sstas		return (NULL);
437221807Sstas	}
438221807Sstas	return (sess.s_ttyvp);
439221807Sstas}
440221807Sstas
441221807Sstasstatic struct filestat_list *
442221807Sstasprocstat_getfiles_kvm(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
443221807Sstas{
444221807Sstas	struct file file;
445221807Sstas	struct filedesc filed;
446221807Sstas	struct vm_map_entry vmentry;
447221807Sstas	struct vm_object object;
448221807Sstas	struct vmspace vmspace;
449221807Sstas	vm_map_entry_t entryp;
450221807Sstas	vm_map_t map;
451221807Sstas	vm_object_t objp;
452221807Sstas	struct vnode *vp;
453221807Sstas	struct file **ofiles;
454221807Sstas	struct filestat *entry;
455221807Sstas	struct filestat_list *head;
456221807Sstas	kvm_t *kd;
457221807Sstas	void *data;
458221807Sstas	int i, fflags;
459221807Sstas	int prot, type;
460221807Sstas	unsigned int nfiles;
461221807Sstas
462221807Sstas	assert(procstat);
463221807Sstas	kd = procstat->kd;
464221807Sstas	if (kd == NULL)
465221807Sstas		return (NULL);
466221807Sstas	if (kp->ki_fd == NULL)
467221807Sstas		return (NULL);
468221807Sstas	if (!kvm_read_all(kd, (unsigned long)kp->ki_fd, &filed,
469221807Sstas	    sizeof(filed))) {
470221807Sstas		warnx("can't read filedesc at %p", (void *)kp->ki_fd);
471221807Sstas		return (NULL);
472221807Sstas	}
473221807Sstas
474221807Sstas	/*
475221807Sstas	 * Allocate list head.
476221807Sstas	 */
477221807Sstas	head = malloc(sizeof(*head));
478221807Sstas	if (head == NULL)
479221807Sstas		return (NULL);
480221807Sstas	STAILQ_INIT(head);
481221807Sstas
482221807Sstas	/* root directory vnode, if one. */
483221807Sstas	if (filed.fd_rdir) {
484221807Sstas		entry = filestat_new_entry(filed.fd_rdir, PS_FST_TYPE_VNODE, -1,
485256242Spjd		    PS_FST_FFLAG_READ, PS_FST_UFLAG_RDIR, 0, 0, NULL, NULL);
486221807Sstas		if (entry != NULL)
487221807Sstas			STAILQ_INSERT_TAIL(head, entry, next);
488221807Sstas	}
489221807Sstas	/* current working directory vnode. */
490221807Sstas	if (filed.fd_cdir) {
491221807Sstas		entry = filestat_new_entry(filed.fd_cdir, PS_FST_TYPE_VNODE, -1,
492256242Spjd		    PS_FST_FFLAG_READ, PS_FST_UFLAG_CDIR, 0, 0, NULL, NULL);
493221807Sstas		if (entry != NULL)
494221807Sstas			STAILQ_INSERT_TAIL(head, entry, next);
495221807Sstas	}
496221807Sstas	/* jail root, if any. */
497221807Sstas	if (filed.fd_jdir) {
498221807Sstas		entry = filestat_new_entry(filed.fd_jdir, PS_FST_TYPE_VNODE, -1,
499256242Spjd		    PS_FST_FFLAG_READ, PS_FST_UFLAG_JAIL, 0, 0, NULL, NULL);
500221807Sstas		if (entry != NULL)
501221807Sstas			STAILQ_INSERT_TAIL(head, entry, next);
502221807Sstas	}
503221807Sstas	/* ktrace vnode, if one */
504221807Sstas	if (kp->ki_tracep) {
505221807Sstas		entry = filestat_new_entry(kp->ki_tracep, PS_FST_TYPE_VNODE, -1,
506221807Sstas		    PS_FST_FFLAG_READ | PS_FST_FFLAG_WRITE,
507256242Spjd		    PS_FST_UFLAG_TRACE, 0, 0, NULL, NULL);
508221807Sstas		if (entry != NULL)
509221807Sstas			STAILQ_INSERT_TAIL(head, entry, next);
510221807Sstas	}
511221807Sstas	/* text vnode, if one */
512221807Sstas	if (kp->ki_textvp) {
513221807Sstas		entry = filestat_new_entry(kp->ki_textvp, PS_FST_TYPE_VNODE, -1,
514256242Spjd		    PS_FST_FFLAG_READ, PS_FST_UFLAG_TEXT, 0, 0, NULL, NULL);
515221807Sstas		if (entry != NULL)
516221807Sstas			STAILQ_INSERT_TAIL(head, entry, next);
517221807Sstas	}
518221807Sstas	/* Controlling terminal. */
519221807Sstas	if ((vp = getctty(kd, kp)) != NULL) {
520221807Sstas		entry = filestat_new_entry(vp, PS_FST_TYPE_VNODE, -1,
521221807Sstas		    PS_FST_FFLAG_READ | PS_FST_FFLAG_WRITE,
522256242Spjd		    PS_FST_UFLAG_CTTY, 0, 0, NULL, NULL);
523221807Sstas		if (entry != NULL)
524221807Sstas			STAILQ_INSERT_TAIL(head, entry, next);
525221807Sstas	}
526221807Sstas
527221807Sstas	nfiles = filed.fd_lastfile + 1;
528221807Sstas	ofiles = malloc(nfiles * sizeof(struct file *));
529221807Sstas	if (ofiles == NULL) {
530223269Sjilles		warn("malloc(%zu)", nfiles * sizeof(struct file *));
531221807Sstas		goto do_mmapped;
532221807Sstas	}
533221807Sstas	if (!kvm_read_all(kd, (unsigned long)filed.fd_ofiles, ofiles,
534221807Sstas	    nfiles * sizeof(struct file *))) {
535221807Sstas		warnx("cannot read file structures at %p",
536221807Sstas		    (void *)filed.fd_ofiles);
537221807Sstas		free(ofiles);
538221807Sstas		goto do_mmapped;
539221807Sstas	}
540221807Sstas	for (i = 0; i <= filed.fd_lastfile; i++) {
541221807Sstas		if (ofiles[i] == NULL)
542221807Sstas			continue;
543221807Sstas		if (!kvm_read_all(kd, (unsigned long)ofiles[i], &file,
544221807Sstas		    sizeof(struct file))) {
545221807Sstas			warnx("can't read file %d at %p", i,
546221807Sstas			    (void *)ofiles[i]);
547221807Sstas			continue;
548221807Sstas		}
549221807Sstas		switch (file.f_type) {
550221807Sstas		case DTYPE_VNODE:
551221807Sstas			type = PS_FST_TYPE_VNODE;
552221807Sstas			data = file.f_vnode;
553221807Sstas			break;
554221807Sstas		case DTYPE_SOCKET:
555221807Sstas			type = PS_FST_TYPE_SOCKET;
556221807Sstas			data = file.f_data;
557221807Sstas			break;
558221807Sstas		case DTYPE_PIPE:
559221807Sstas			type = PS_FST_TYPE_PIPE;
560221807Sstas			data = file.f_data;
561221807Sstas			break;
562221807Sstas		case DTYPE_FIFO:
563221807Sstas			type = PS_FST_TYPE_FIFO;
564221807Sstas			data = file.f_vnode;
565221807Sstas			break;
566221807Sstas#ifdef DTYPE_PTS
567221807Sstas		case DTYPE_PTS:
568221807Sstas			type = PS_FST_TYPE_PTS;
569221807Sstas			data = file.f_data;
570221807Sstas			break;
571221807Sstas#endif
572250223Sjhb		case DTYPE_SEM:
573250223Sjhb			type = PS_FST_TYPE_SEM;
574250223Sjhb			data = file.f_data;
575250223Sjhb			break;
576233760Sjhb		case DTYPE_SHM:
577233760Sjhb			type = PS_FST_TYPE_SHM;
578233760Sjhb			data = file.f_data;
579233760Sjhb			break;
580221807Sstas		default:
581221807Sstas			continue;
582221807Sstas		}
583224859Srwatson		/* XXXRW: No capability rights support for kvm yet. */
584221807Sstas		entry = filestat_new_entry(data, type, i,
585256242Spjd		    to_filestat_flags(file.f_flag), 0, 0, 0, NULL, NULL);
586221807Sstas		if (entry != NULL)
587221807Sstas			STAILQ_INSERT_TAIL(head, entry, next);
588221807Sstas	}
589221807Sstas	free(ofiles);
590221807Sstas
591221807Sstasdo_mmapped:
592221807Sstas
593221807Sstas	/*
594221807Sstas	 * Process mmapped files if requested.
595221807Sstas	 */
596221807Sstas	if (mmapped) {
597221807Sstas		if (!kvm_read_all(kd, (unsigned long)kp->ki_vmspace, &vmspace,
598221807Sstas		    sizeof(vmspace))) {
599221807Sstas			warnx("can't read vmspace at %p",
600221807Sstas			    (void *)kp->ki_vmspace);
601221807Sstas			goto exit;
602221807Sstas		}
603221807Sstas		map = &vmspace.vm_map;
604221807Sstas
605221807Sstas		for (entryp = map->header.next;
606221807Sstas		    entryp != &kp->ki_vmspace->vm_map.header;
607221807Sstas		    entryp = vmentry.next) {
608221807Sstas			if (!kvm_read_all(kd, (unsigned long)entryp, &vmentry,
609221807Sstas			    sizeof(vmentry))) {
610221807Sstas				warnx("can't read vm_map_entry at %p",
611221807Sstas				    (void *)entryp);
612221807Sstas				continue;
613221807Sstas			}
614221807Sstas			if (vmentry.eflags & MAP_ENTRY_IS_SUB_MAP)
615221807Sstas				continue;
616221807Sstas			if ((objp = vmentry.object.vm_object) == NULL)
617221807Sstas				continue;
618221807Sstas			for (; objp; objp = object.backing_object) {
619221807Sstas				if (!kvm_read_all(kd, (unsigned long)objp,
620221807Sstas				    &object, sizeof(object))) {
621221807Sstas					warnx("can't read vm_object at %p",
622221807Sstas					    (void *)objp);
623221807Sstas					break;
624221807Sstas				}
625221807Sstas			}
626221807Sstas
627221807Sstas			/* We want only vnode objects. */
628221807Sstas			if (object.type != OBJT_VNODE)
629221807Sstas				continue;
630221807Sstas
631221807Sstas			prot = vmentry.protection;
632221807Sstas			fflags = 0;
633221807Sstas			if (prot & VM_PROT_READ)
634221807Sstas				fflags = PS_FST_FFLAG_READ;
635223279Sjilles			if ((vmentry.eflags & MAP_ENTRY_COW) == 0 &&
636223279Sjilles			    prot & VM_PROT_WRITE)
637221807Sstas				fflags |= PS_FST_FFLAG_WRITE;
638221807Sstas
639221807Sstas			/*
640221807Sstas			 * Create filestat entry.
641221807Sstas			 */
642221807Sstas			entry = filestat_new_entry(object.handle,
643221807Sstas			    PS_FST_TYPE_VNODE, -1, fflags,
644256242Spjd			    PS_FST_UFLAG_MMAP, 0, 0, NULL, NULL);
645221807Sstas			if (entry != NULL)
646221807Sstas				STAILQ_INSERT_TAIL(head, entry, next);
647221807Sstas		}
648221807Sstas	}
649221807Sstasexit:
650221807Sstas	return (head);
651221807Sstas}
652221807Sstas
653221807Sstas/*
654221807Sstas * kinfo types to filestat translation.
655221807Sstas */
656221807Sstasstatic int
657221807Sstaskinfo_type2fst(int kftype)
658221807Sstas{
659221807Sstas	static struct {
660221807Sstas		int	kf_type;
661221807Sstas		int	fst_type;
662221807Sstas	} kftypes2fst[] = {
663221807Sstas		{ KF_TYPE_CRYPTO, PS_FST_TYPE_CRYPTO },
664221807Sstas		{ KF_TYPE_FIFO, PS_FST_TYPE_FIFO },
665221807Sstas		{ KF_TYPE_KQUEUE, PS_FST_TYPE_KQUEUE },
666221807Sstas		{ KF_TYPE_MQUEUE, PS_FST_TYPE_MQUEUE },
667221807Sstas		{ KF_TYPE_NONE, PS_FST_TYPE_NONE },
668221807Sstas		{ KF_TYPE_PIPE, PS_FST_TYPE_PIPE },
669221807Sstas		{ KF_TYPE_PTS, PS_FST_TYPE_PTS },
670221807Sstas		{ KF_TYPE_SEM, PS_FST_TYPE_SEM },
671221807Sstas		{ KF_TYPE_SHM, PS_FST_TYPE_SHM },
672221807Sstas		{ KF_TYPE_SOCKET, PS_FST_TYPE_SOCKET },
673221807Sstas		{ KF_TYPE_VNODE, PS_FST_TYPE_VNODE },
674221807Sstas		{ KF_TYPE_UNKNOWN, PS_FST_TYPE_UNKNOWN }
675221807Sstas	};
676221807Sstas#define NKFTYPES	(sizeof(kftypes2fst) / sizeof(*kftypes2fst))
677221807Sstas	unsigned int i;
678221807Sstas
679221807Sstas	for (i = 0; i < NKFTYPES; i++)
680221807Sstas		if (kftypes2fst[i].kf_type == kftype)
681221807Sstas			break;
682221807Sstas	if (i == NKFTYPES)
683221807Sstas		return (PS_FST_TYPE_UNKNOWN);
684221807Sstas	return (kftypes2fst[i].fst_type);
685221807Sstas}
686221807Sstas
687221807Sstas/*
688221807Sstas * kinfo flags to filestat translation.
689221807Sstas */
690221807Sstasstatic int
691221807Sstaskinfo_fflags2fst(int kfflags)
692221807Sstas{
693221807Sstas	static struct {
694221807Sstas		int	kf_flag;
695221807Sstas		int	fst_flag;
696221807Sstas	} kfflags2fst[] = {
697221807Sstas		{ KF_FLAG_APPEND, PS_FST_FFLAG_APPEND },
698221807Sstas		{ KF_FLAG_ASYNC, PS_FST_FFLAG_ASYNC },
699221807Sstas		{ KF_FLAG_CREAT, PS_FST_FFLAG_CREAT },
700221807Sstas		{ KF_FLAG_DIRECT, PS_FST_FFLAG_DIRECT },
701221807Sstas		{ KF_FLAG_EXCL, PS_FST_FFLAG_EXCL },
702221807Sstas		{ KF_FLAG_EXEC, PS_FST_FFLAG_EXEC },
703221807Sstas		{ KF_FLAG_EXLOCK, PS_FST_FFLAG_EXLOCK },
704221807Sstas		{ KF_FLAG_FSYNC, PS_FST_FFLAG_SYNC },
705221807Sstas		{ KF_FLAG_HASLOCK, PS_FST_FFLAG_HASLOCK },
706221807Sstas		{ KF_FLAG_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW },
707221807Sstas		{ KF_FLAG_NONBLOCK, PS_FST_FFLAG_NONBLOCK },
708221807Sstas		{ KF_FLAG_READ, PS_FST_FFLAG_READ },
709221807Sstas		{ KF_FLAG_SHLOCK, PS_FST_FFLAG_SHLOCK },
710221807Sstas		{ KF_FLAG_TRUNC, PS_FST_FFLAG_TRUNC },
711221807Sstas		{ KF_FLAG_WRITE, PS_FST_FFLAG_WRITE }
712221807Sstas	};
713221807Sstas#define NKFFLAGS	(sizeof(kfflags2fst) / sizeof(*kfflags2fst))
714221807Sstas	unsigned int i;
715221807Sstas	int flags;
716221807Sstas
717221807Sstas	flags = 0;
718221807Sstas	for (i = 0; i < NKFFLAGS; i++)
719221807Sstas		if ((kfflags & kfflags2fst[i].kf_flag) != 0)
720221807Sstas			flags |= kfflags2fst[i].fst_flag;
721221807Sstas	return (flags);
722221807Sstas}
723221807Sstas
724221807Sstasstatic int
725221807Sstaskinfo_uflags2fst(int fd)
726221807Sstas{
727221807Sstas
728221807Sstas	switch (fd) {
729221807Sstas	case KF_FD_TYPE_CTTY:
730221807Sstas		return (PS_FST_UFLAG_CTTY);
731221807Sstas	case KF_FD_TYPE_CWD:
732221807Sstas		return (PS_FST_UFLAG_CDIR);
733221807Sstas	case KF_FD_TYPE_JAIL:
734221807Sstas		return (PS_FST_UFLAG_JAIL);
735221807Sstas	case KF_FD_TYPE_TEXT:
736221807Sstas		return (PS_FST_UFLAG_TEXT);
737221807Sstas	case KF_FD_TYPE_TRACE:
738221807Sstas		return (PS_FST_UFLAG_TRACE);
739221807Sstas	case KF_FD_TYPE_ROOT:
740221807Sstas		return (PS_FST_UFLAG_RDIR);
741221807Sstas	}
742221807Sstas	return (0);
743221807Sstas}
744221807Sstas
745249666Strocinystatic struct kinfo_file *
746249666Strocinykinfo_getfile_core(struct procstat_core *core, int *cntp)
747249666Strociny{
748249666Strociny	int cnt;
749249666Strociny	size_t len;
750249666Strociny	char *buf, *bp, *eb;
751249666Strociny	struct kinfo_file *kif, *kp, *kf;
752249666Strociny
753249666Strociny	buf = procstat_core_get(core, PSC_TYPE_FILES, NULL, &len);
754249666Strociny	if (buf == NULL)
755249666Strociny		return (NULL);
756249666Strociny	/*
757249666Strociny	 * XXXMG: The code below is just copy&past from libutil.
758249666Strociny	 * The code duplication can be avoided if libutil
759249666Strociny	 * is extended to provide something like:
760249666Strociny	 *   struct kinfo_file *kinfo_getfile_from_buf(const char *buf,
761249666Strociny	 *       size_t len, int *cntp);
762249666Strociny	 */
763249666Strociny
764249666Strociny	/* Pass 1: count items */
765249666Strociny	cnt = 0;
766249666Strociny	bp = buf;
767249666Strociny	eb = buf + len;
768249666Strociny	while (bp < eb) {
769249666Strociny		kf = (struct kinfo_file *)(uintptr_t)bp;
770295454Sjhb		if (kf->kf_structsize == 0)
771295454Sjhb			break;
772249666Strociny		bp += kf->kf_structsize;
773249666Strociny		cnt++;
774249666Strociny	}
775249666Strociny
776249666Strociny	kif = calloc(cnt, sizeof(*kif));
777249666Strociny	if (kif == NULL) {
778249666Strociny		free(buf);
779249666Strociny		return (NULL);
780249666Strociny	}
781249666Strociny	bp = buf;
782249666Strociny	eb = buf + len;
783249666Strociny	kp = kif;
784249666Strociny	/* Pass 2: unpack */
785249666Strociny	while (bp < eb) {
786249666Strociny		kf = (struct kinfo_file *)(uintptr_t)bp;
787295454Sjhb		if (kf->kf_structsize == 0)
788295454Sjhb			break;
789249666Strociny		/* Copy/expand into pre-zeroed buffer */
790249666Strociny		memcpy(kp, kf, kf->kf_structsize);
791249666Strociny		/* Advance to next packed record */
792249666Strociny		bp += kf->kf_structsize;
793249666Strociny		/* Set field size to fixed length, advance */
794249666Strociny		kp->kf_structsize = sizeof(*kp);
795249666Strociny		kp++;
796249666Strociny	}
797249666Strociny	free(buf);
798249666Strociny	*cntp = cnt;
799249666Strociny	return (kif);	/* Caller must free() return value */
800249666Strociny}
801249666Strociny
802221807Sstasstatic struct filestat_list *
803249666Strocinyprocstat_getfiles_sysctl(struct procstat *procstat, struct kinfo_proc *kp,
804249666Strociny    int mmapped)
805221807Sstas{
806221807Sstas	struct kinfo_file *kif, *files;
807221807Sstas	struct kinfo_vmentry *kve, *vmentries;
808221807Sstas	struct filestat_list *head;
809221807Sstas	struct filestat *entry;
810221807Sstas	char *path;
811221807Sstas	off_t offset;
812221807Sstas	int cnt, fd, fflags;
813221807Sstas	int i, type, uflags;
814221807Sstas	int refcount;
815224859Srwatson	cap_rights_t cap_rights;
816221807Sstas
817221807Sstas	assert(kp);
818221807Sstas	if (kp->ki_fd == NULL)
819221807Sstas		return (NULL);
820249666Strociny	switch(procstat->type) {
821249666Strociny	case PROCSTAT_SYSCTL:
822249666Strociny		files = kinfo_getfile(kp->ki_pid, &cnt);
823249666Strociny		break;
824249666Strociny	case PROCSTAT_CORE:
825249666Strociny		files = kinfo_getfile_core(procstat->core, &cnt);
826249666Strociny		break;
827249666Strociny	default:
828249666Strociny		assert(!"invalid type");
829249666Strociny	}
830221807Sstas	if (files == NULL && errno != EPERM) {
831221807Sstas		warn("kinfo_getfile()");
832221807Sstas		return (NULL);
833221807Sstas	}
834221807Sstas	procstat->files = files;
835221807Sstas
836221807Sstas	/*
837221807Sstas	 * Allocate list head.
838221807Sstas	 */
839221807Sstas	head = malloc(sizeof(*head));
840221807Sstas	if (head == NULL)
841221807Sstas		return (NULL);
842221807Sstas	STAILQ_INIT(head);
843221807Sstas	for (i = 0; i < cnt; i++) {
844221807Sstas		kif = &files[i];
845221807Sstas
846221807Sstas		type = kinfo_type2fst(kif->kf_type);
847221807Sstas		fd = kif->kf_fd >= 0 ? kif->kf_fd : -1;
848221807Sstas		fflags = kinfo_fflags2fst(kif->kf_flags);
849221807Sstas		uflags = kinfo_uflags2fst(kif->kf_fd);
850221807Sstas		refcount = kif->kf_ref_count;
851221807Sstas		offset = kif->kf_offset;
852221807Sstas		if (*kif->kf_path != '\0')
853221807Sstas			path = strdup(kif->kf_path);
854221807Sstas		else
855221807Sstas			path = NULL;
856224859Srwatson		cap_rights = kif->kf_cap_rights;
857221807Sstas
858221807Sstas		/*
859221807Sstas		 * Create filestat entry.
860221807Sstas		 */
861221807Sstas		entry = filestat_new_entry(kif, type, fd, fflags, uflags,
862255219Spjd		    refcount, offset, path, &cap_rights);
863221807Sstas		if (entry != NULL)
864221807Sstas			STAILQ_INSERT_TAIL(head, entry, next);
865221807Sstas	}
866221807Sstas	if (mmapped != 0) {
867249667Strociny		vmentries = procstat_getvmmap(procstat, kp, &cnt);
868221807Sstas		procstat->vmentries = vmentries;
869221807Sstas		if (vmentries == NULL || cnt == 0)
870221807Sstas			goto fail;
871221807Sstas		for (i = 0; i < cnt; i++) {
872221807Sstas			kve = &vmentries[i];
873221807Sstas			if (kve->kve_type != KVME_TYPE_VNODE)
874221807Sstas				continue;
875221807Sstas			fflags = 0;
876221807Sstas			if (kve->kve_protection & KVME_PROT_READ)
877221807Sstas				fflags = PS_FST_FFLAG_READ;
878223279Sjilles			if ((kve->kve_flags & KVME_FLAG_COW) == 0 &&
879223279Sjilles			    kve->kve_protection & KVME_PROT_WRITE)
880221807Sstas				fflags |= PS_FST_FFLAG_WRITE;
881221807Sstas			offset = kve->kve_offset;
882221807Sstas			refcount = kve->kve_ref_count;
883221807Sstas			if (*kve->kve_path != '\0')
884221807Sstas				path = strdup(kve->kve_path);
885221807Sstas			else
886221807Sstas				path = NULL;
887221807Sstas			entry = filestat_new_entry(kve, PS_FST_TYPE_VNODE, -1,
888224859Srwatson			    fflags, PS_FST_UFLAG_MMAP, refcount, offset, path,
889256242Spjd			    NULL);
890221807Sstas			if (entry != NULL)
891221807Sstas				STAILQ_INSERT_TAIL(head, entry, next);
892221807Sstas		}
893221807Sstas	}
894221807Sstasfail:
895221807Sstas	return (head);
896221807Sstas}
897221807Sstas
898221807Sstasint
899221807Sstasprocstat_get_pipe_info(struct procstat *procstat, struct filestat *fst,
900221807Sstas    struct pipestat *ps, char *errbuf)
901221807Sstas{
902221807Sstas
903221807Sstas	assert(ps);
904221807Sstas	if (procstat->type == PROCSTAT_KVM) {
905221807Sstas		return (procstat_get_pipe_info_kvm(procstat->kd, fst, ps,
906221807Sstas		    errbuf));
907249666Strociny	} else if (procstat->type == PROCSTAT_SYSCTL ||
908249666Strociny		procstat->type == PROCSTAT_CORE) {
909221807Sstas		return (procstat_get_pipe_info_sysctl(fst, ps, errbuf));
910221807Sstas	} else {
911223276Sjilles		warnx("unknown access method: %d", procstat->type);
912250378Strociny		if (errbuf != NULL)
913250378Strociny			snprintf(errbuf, _POSIX2_LINE_MAX, "error");
914221807Sstas		return (1);
915221807Sstas	}
916221807Sstas}
917221807Sstas
918221807Sstasstatic int
919221807Sstasprocstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst,
920221807Sstas    struct pipestat *ps, char *errbuf)
921221807Sstas{
922221807Sstas	struct pipe pi;
923221807Sstas	void *pipep;
924221807Sstas
925221807Sstas	assert(kd);
926221807Sstas	assert(ps);
927221807Sstas	assert(fst);
928221807Sstas	bzero(ps, sizeof(*ps));
929221807Sstas	pipep = fst->fs_typedep;
930221807Sstas	if (pipep == NULL)
931221807Sstas		goto fail;
932221807Sstas	if (!kvm_read_all(kd, (unsigned long)pipep, &pi, sizeof(struct pipe))) {
933221807Sstas		warnx("can't read pipe at %p", (void *)pipep);
934221807Sstas		goto fail;
935221807Sstas	}
936221807Sstas	ps->addr = (uintptr_t)pipep;
937221807Sstas	ps->peer = (uintptr_t)pi.pipe_peer;
938221807Sstas	ps->buffer_cnt = pi.pipe_buffer.cnt;
939221807Sstas	return (0);
940221807Sstas
941221807Sstasfail:
942250378Strociny	if (errbuf != NULL)
943250378Strociny		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
944221807Sstas	return (1);
945221807Sstas}
946221807Sstas
947221807Sstasstatic int
948221807Sstasprocstat_get_pipe_info_sysctl(struct filestat *fst, struct pipestat *ps,
949221807Sstas    char *errbuf __unused)
950221807Sstas{
951221807Sstas	struct kinfo_file *kif;
952221807Sstas
953221807Sstas	assert(ps);
954221807Sstas	assert(fst);
955221807Sstas	bzero(ps, sizeof(*ps));
956221807Sstas	kif = fst->fs_typedep;
957221807Sstas	if (kif == NULL)
958221807Sstas		return (1);
959221807Sstas	ps->addr = kif->kf_un.kf_pipe.kf_pipe_addr;
960221807Sstas	ps->peer = kif->kf_un.kf_pipe.kf_pipe_peer;
961221807Sstas	ps->buffer_cnt = kif->kf_un.kf_pipe.kf_pipe_buffer_cnt;
962221807Sstas	return (0);
963221807Sstas}
964221807Sstas
965221807Sstasint
966221807Sstasprocstat_get_pts_info(struct procstat *procstat, struct filestat *fst,
967221807Sstas    struct ptsstat *pts, char *errbuf)
968221807Sstas{
969221807Sstas
970221807Sstas	assert(pts);
971221807Sstas	if (procstat->type == PROCSTAT_KVM) {
972221807Sstas		return (procstat_get_pts_info_kvm(procstat->kd, fst, pts,
973221807Sstas		    errbuf));
974249666Strociny	} else if (procstat->type == PROCSTAT_SYSCTL ||
975249666Strociny		procstat->type == PROCSTAT_CORE) {
976221807Sstas		return (procstat_get_pts_info_sysctl(fst, pts, errbuf));
977221807Sstas	} else {
978223276Sjilles		warnx("unknown access method: %d", procstat->type);
979250378Strociny		if (errbuf != NULL)
980250378Strociny			snprintf(errbuf, _POSIX2_LINE_MAX, "error");
981221807Sstas		return (1);
982221807Sstas	}
983221807Sstas}
984221807Sstas
985221807Sstasstatic int
986221807Sstasprocstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst,
987221807Sstas    struct ptsstat *pts, char *errbuf)
988221807Sstas{
989221807Sstas	struct tty tty;
990221807Sstas	void *ttyp;
991221807Sstas
992221807Sstas	assert(kd);
993221807Sstas	assert(pts);
994221807Sstas	assert(fst);
995221807Sstas	bzero(pts, sizeof(*pts));
996221807Sstas	ttyp = fst->fs_typedep;
997221807Sstas	if (ttyp == NULL)
998221807Sstas		goto fail;
999221807Sstas	if (!kvm_read_all(kd, (unsigned long)ttyp, &tty, sizeof(struct tty))) {
1000221807Sstas		warnx("can't read tty at %p", (void *)ttyp);
1001221807Sstas		goto fail;
1002221807Sstas	}
1003221807Sstas	pts->dev = dev2udev(kd, tty.t_dev);
1004221807Sstas	(void)kdevtoname(kd, tty.t_dev, pts->devname);
1005221807Sstas	return (0);
1006221807Sstas
1007221807Sstasfail:
1008250378Strociny	if (errbuf != NULL)
1009250378Strociny		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1010221807Sstas	return (1);
1011221807Sstas}
1012221807Sstas
1013221807Sstasstatic int
1014221807Sstasprocstat_get_pts_info_sysctl(struct filestat *fst, struct ptsstat *pts,
1015221807Sstas    char *errbuf __unused)
1016221807Sstas{
1017221807Sstas	struct kinfo_file *kif;
1018221807Sstas
1019221807Sstas	assert(pts);
1020221807Sstas	assert(fst);
1021221807Sstas	bzero(pts, sizeof(*pts));
1022221807Sstas	kif = fst->fs_typedep;
1023221807Sstas	if (kif == NULL)
1024221807Sstas		return (0);
1025221807Sstas	pts->dev = kif->kf_un.kf_pts.kf_pts_dev;
1026221807Sstas	strlcpy(pts->devname, kif->kf_path, sizeof(pts->devname));
1027221807Sstas	return (0);
1028221807Sstas}
1029221807Sstas
1030221807Sstasint
1031250223Sjhbprocstat_get_sem_info(struct procstat *procstat, struct filestat *fst,
1032250223Sjhb    struct semstat *sem, char *errbuf)
1033250223Sjhb{
1034250223Sjhb
1035250223Sjhb	assert(sem);
1036250223Sjhb	if (procstat->type == PROCSTAT_KVM) {
1037250223Sjhb		return (procstat_get_sem_info_kvm(procstat->kd, fst, sem,
1038250223Sjhb		    errbuf));
1039250223Sjhb	} else if (procstat->type == PROCSTAT_SYSCTL ||
1040250223Sjhb	    procstat->type == PROCSTAT_CORE) {
1041250223Sjhb		return (procstat_get_sem_info_sysctl(fst, sem, errbuf));
1042250223Sjhb	} else {
1043250223Sjhb		warnx("unknown access method: %d", procstat->type);
1044250378Strociny		if (errbuf != NULL)
1045250378Strociny			snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1046250223Sjhb		return (1);
1047250223Sjhb	}
1048250223Sjhb}
1049250223Sjhb
1050250223Sjhbstatic int
1051250223Sjhbprocstat_get_sem_info_kvm(kvm_t *kd, struct filestat *fst,
1052250223Sjhb    struct semstat *sem, char *errbuf)
1053250223Sjhb{
1054250223Sjhb	struct ksem ksem;
1055250223Sjhb	void *ksemp;
1056250223Sjhb	char *path;
1057250223Sjhb	int i;
1058250223Sjhb
1059250223Sjhb	assert(kd);
1060250223Sjhb	assert(sem);
1061250223Sjhb	assert(fst);
1062250223Sjhb	bzero(sem, sizeof(*sem));
1063250223Sjhb	ksemp = fst->fs_typedep;
1064250223Sjhb	if (ksemp == NULL)
1065250223Sjhb		goto fail;
1066250223Sjhb	if (!kvm_read_all(kd, (unsigned long)ksemp, &ksem,
1067250223Sjhb	    sizeof(struct ksem))) {
1068250223Sjhb		warnx("can't read ksem at %p", (void *)ksemp);
1069250223Sjhb		goto fail;
1070250223Sjhb	}
1071250223Sjhb	sem->mode = S_IFREG | ksem.ks_mode;
1072250223Sjhb	sem->value = ksem.ks_value;
1073250223Sjhb	if (fst->fs_path == NULL && ksem.ks_path != NULL) {
1074250223Sjhb		path = malloc(MAXPATHLEN);
1075250223Sjhb		for (i = 0; i < MAXPATHLEN - 1; i++) {
1076250223Sjhb			if (!kvm_read_all(kd, (unsigned long)ksem.ks_path + i,
1077250223Sjhb			    path + i, 1))
1078250223Sjhb				break;
1079250223Sjhb			if (path[i] == '\0')
1080250223Sjhb				break;
1081250223Sjhb		}
1082250223Sjhb		path[i] = '\0';
1083250223Sjhb		if (i == 0)
1084250223Sjhb			free(path);
1085250223Sjhb		else
1086250223Sjhb			fst->fs_path = path;
1087250223Sjhb	}
1088250223Sjhb	return (0);
1089250223Sjhb
1090250223Sjhbfail:
1091250378Strociny	if (errbuf != NULL)
1092250378Strociny		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1093250223Sjhb	return (1);
1094250223Sjhb}
1095250223Sjhb
1096250223Sjhbstatic int
1097250223Sjhbprocstat_get_sem_info_sysctl(struct filestat *fst, struct semstat *sem,
1098250223Sjhb    char *errbuf __unused)
1099250223Sjhb{
1100250223Sjhb	struct kinfo_file *kif;
1101250223Sjhb
1102250223Sjhb	assert(sem);
1103250223Sjhb	assert(fst);
1104250223Sjhb	bzero(sem, sizeof(*sem));
1105250223Sjhb	kif = fst->fs_typedep;
1106250223Sjhb	if (kif == NULL)
1107250223Sjhb		return (0);
1108250223Sjhb	sem->value = kif->kf_un.kf_sem.kf_sem_value;
1109250223Sjhb	sem->mode = kif->kf_un.kf_sem.kf_sem_mode;
1110250223Sjhb	return (0);
1111250223Sjhb}
1112250223Sjhb
1113250223Sjhbint
1114233760Sjhbprocstat_get_shm_info(struct procstat *procstat, struct filestat *fst,
1115233760Sjhb    struct shmstat *shm, char *errbuf)
1116233760Sjhb{
1117233760Sjhb
1118233760Sjhb	assert(shm);
1119233760Sjhb	if (procstat->type == PROCSTAT_KVM) {
1120233760Sjhb		return (procstat_get_shm_info_kvm(procstat->kd, fst, shm,
1121233760Sjhb		    errbuf));
1122249666Strociny	} else if (procstat->type == PROCSTAT_SYSCTL ||
1123249666Strociny	    procstat->type == PROCSTAT_CORE) {
1124233760Sjhb		return (procstat_get_shm_info_sysctl(fst, shm, errbuf));
1125233760Sjhb	} else {
1126233760Sjhb		warnx("unknown access method: %d", procstat->type);
1127250378Strociny		if (errbuf != NULL)
1128250378Strociny			snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1129233760Sjhb		return (1);
1130233760Sjhb	}
1131233760Sjhb}
1132233760Sjhb
1133233760Sjhbstatic int
1134233760Sjhbprocstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst,
1135233760Sjhb    struct shmstat *shm, char *errbuf)
1136233760Sjhb{
1137233760Sjhb	struct shmfd shmfd;
1138233760Sjhb	void *shmfdp;
1139236717Sjhb	char *path;
1140236717Sjhb	int i;
1141233760Sjhb
1142233760Sjhb	assert(kd);
1143233760Sjhb	assert(shm);
1144233760Sjhb	assert(fst);
1145233760Sjhb	bzero(shm, sizeof(*shm));
1146233760Sjhb	shmfdp = fst->fs_typedep;
1147233760Sjhb	if (shmfdp == NULL)
1148233760Sjhb		goto fail;
1149233760Sjhb	if (!kvm_read_all(kd, (unsigned long)shmfdp, &shmfd,
1150233760Sjhb	    sizeof(struct shmfd))) {
1151233760Sjhb		warnx("can't read shmfd at %p", (void *)shmfdp);
1152233760Sjhb		goto fail;
1153233760Sjhb	}
1154233760Sjhb	shm->mode = S_IFREG | shmfd.shm_mode;
1155233760Sjhb	shm->size = shmfd.shm_size;
1156236717Sjhb	if (fst->fs_path == NULL && shmfd.shm_path != NULL) {
1157236717Sjhb		path = malloc(MAXPATHLEN);
1158236717Sjhb		for (i = 0; i < MAXPATHLEN - 1; i++) {
1159236717Sjhb			if (!kvm_read_all(kd, (unsigned long)shmfd.shm_path + i,
1160236717Sjhb			    path + i, 1))
1161236717Sjhb				break;
1162236717Sjhb			if (path[i] == '\0')
1163236717Sjhb				break;
1164236717Sjhb		}
1165236717Sjhb		path[i] = '\0';
1166236717Sjhb		if (i == 0)
1167236717Sjhb			free(path);
1168236717Sjhb		else
1169236717Sjhb			fst->fs_path = path;
1170236717Sjhb	}
1171233760Sjhb	return (0);
1172233760Sjhb
1173233760Sjhbfail:
1174250378Strociny	if (errbuf != NULL)
1175250378Strociny		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1176233760Sjhb	return (1);
1177233760Sjhb}
1178233760Sjhb
1179233760Sjhbstatic int
1180233760Sjhbprocstat_get_shm_info_sysctl(struct filestat *fst, struct shmstat *shm,
1181233760Sjhb    char *errbuf __unused)
1182233760Sjhb{
1183233760Sjhb	struct kinfo_file *kif;
1184233760Sjhb
1185233760Sjhb	assert(shm);
1186233760Sjhb	assert(fst);
1187233760Sjhb	bzero(shm, sizeof(*shm));
1188233760Sjhb	kif = fst->fs_typedep;
1189233760Sjhb	if (kif == NULL)
1190233760Sjhb		return (0);
1191233760Sjhb	shm->size = kif->kf_un.kf_file.kf_file_size;
1192233760Sjhb	shm->mode = kif->kf_un.kf_file.kf_file_mode;
1193233760Sjhb	return (0);
1194233760Sjhb}
1195233760Sjhb
1196233760Sjhbint
1197221807Sstasprocstat_get_vnode_info(struct procstat *procstat, struct filestat *fst,
1198221807Sstas    struct vnstat *vn, char *errbuf)
1199221807Sstas{
1200221807Sstas
1201221807Sstas	assert(vn);
1202221807Sstas	if (procstat->type == PROCSTAT_KVM) {
1203221807Sstas		return (procstat_get_vnode_info_kvm(procstat->kd, fst, vn,
1204221807Sstas		    errbuf));
1205249666Strociny	} else if (procstat->type == PROCSTAT_SYSCTL ||
1206249666Strociny		procstat->type == PROCSTAT_CORE) {
1207221807Sstas		return (procstat_get_vnode_info_sysctl(fst, vn, errbuf));
1208221807Sstas	} else {
1209223276Sjilles		warnx("unknown access method: %d", procstat->type);
1210250378Strociny		if (errbuf != NULL)
1211250378Strociny			snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1212221807Sstas		return (1);
1213221807Sstas	}
1214221807Sstas}
1215221807Sstas
1216221807Sstasstatic int
1217221807Sstasprocstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst,
1218221807Sstas    struct vnstat *vn, char *errbuf)
1219221807Sstas{
1220221807Sstas	/* Filesystem specific handlers. */
1221221807Sstas	#define FSTYPE(fst)     {#fst, fst##_filestat}
1222221807Sstas	struct {
1223221807Sstas		const char	*tag;
1224221807Sstas		int		(*handler)(kvm_t *kd, struct vnode *vp,
1225221807Sstas		    struct vnstat *vn);
1226221807Sstas	} fstypes[] = {
1227221807Sstas		FSTYPE(devfs),
1228221807Sstas		FSTYPE(isofs),
1229221807Sstas		FSTYPE(msdosfs),
1230221807Sstas		FSTYPE(nfs),
1231252356Sdavide		FSTYPE(smbfs),
1232221807Sstas		FSTYPE(udf),
1233221807Sstas		FSTYPE(ufs),
1234221824Sstas#ifdef LIBPROCSTAT_ZFS
1235221807Sstas		FSTYPE(zfs),
1236221807Sstas#endif
1237221807Sstas	};
1238221807Sstas#define	NTYPES	(sizeof(fstypes) / sizeof(*fstypes))
1239221807Sstas	struct vnode vnode;
1240221807Sstas	char tagstr[12];
1241221807Sstas	void *vp;
1242221807Sstas	int error, found;
1243221807Sstas	unsigned int i;
1244221807Sstas
1245221807Sstas	assert(kd);
1246221807Sstas	assert(vn);
1247221807Sstas	assert(fst);
1248221807Sstas	vp = fst->fs_typedep;
1249221807Sstas	if (vp == NULL)
1250221807Sstas		goto fail;
1251221807Sstas	error = kvm_read_all(kd, (unsigned long)vp, &vnode, sizeof(vnode));
1252221807Sstas	if (error == 0) {
1253221807Sstas		warnx("can't read vnode at %p", (void *)vp);
1254221807Sstas		goto fail;
1255221807Sstas	}
1256221807Sstas	bzero(vn, sizeof(*vn));
1257221807Sstas	vn->vn_type = vntype2psfsttype(vnode.v_type);
1258221807Sstas	if (vnode.v_type == VNON || vnode.v_type == VBAD)
1259221807Sstas		return (0);
1260221807Sstas	error = kvm_read_all(kd, (unsigned long)vnode.v_tag, tagstr,
1261221807Sstas	    sizeof(tagstr));
1262221807Sstas	if (error == 0) {
1263221807Sstas		warnx("can't read v_tag at %p", (void *)vp);
1264221807Sstas		goto fail;
1265221807Sstas	}
1266221807Sstas	tagstr[sizeof(tagstr) - 1] = '\0';
1267221807Sstas
1268221807Sstas	/*
1269221807Sstas	 * Find appropriate handler.
1270221807Sstas	 */
1271221807Sstas	for (i = 0, found = 0; i < NTYPES; i++)
1272221807Sstas		if (!strcmp(fstypes[i].tag, tagstr)) {
1273221807Sstas			if (fstypes[i].handler(kd, &vnode, vn) != 0) {
1274221807Sstas				goto fail;
1275221807Sstas			}
1276221807Sstas			break;
1277221807Sstas		}
1278221807Sstas	if (i == NTYPES) {
1279250378Strociny		if (errbuf != NULL)
1280250378Strociny			snprintf(errbuf, _POSIX2_LINE_MAX, "?(%s)", tagstr);
1281221807Sstas		return (1);
1282221807Sstas	}
1283221807Sstas	vn->vn_mntdir = getmnton(kd, vnode.v_mount);
1284221807Sstas	if ((vnode.v_type == VBLK || vnode.v_type == VCHR) &&
1285221807Sstas	    vnode.v_rdev != NULL){
1286221807Sstas		vn->vn_dev = dev2udev(kd, vnode.v_rdev);
1287221807Sstas		(void)kdevtoname(kd, vnode.v_rdev, vn->vn_devname);
1288221807Sstas	} else {
1289221807Sstas		vn->vn_dev = -1;
1290221807Sstas	}
1291221807Sstas	return (0);
1292221807Sstas
1293221807Sstasfail:
1294250378Strociny	if (errbuf != NULL)
1295250378Strociny		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1296221807Sstas	return (1);
1297221807Sstas}
1298221807Sstas
1299221807Sstas/*
1300221807Sstas * kinfo vnode type to filestat translation.
1301221807Sstas */
1302221807Sstasstatic int
1303221807Sstaskinfo_vtype2fst(int kfvtype)
1304221807Sstas{
1305221807Sstas	static struct {
1306221807Sstas		int	kf_vtype;
1307221807Sstas		int	fst_vtype;
1308221807Sstas	} kfvtypes2fst[] = {
1309221807Sstas		{ KF_VTYPE_VBAD, PS_FST_VTYPE_VBAD },
1310221807Sstas		{ KF_VTYPE_VBLK, PS_FST_VTYPE_VBLK },
1311221807Sstas		{ KF_VTYPE_VCHR, PS_FST_VTYPE_VCHR },
1312221807Sstas		{ KF_VTYPE_VDIR, PS_FST_VTYPE_VDIR },
1313221807Sstas		{ KF_VTYPE_VFIFO, PS_FST_VTYPE_VFIFO },
1314221807Sstas		{ KF_VTYPE_VLNK, PS_FST_VTYPE_VLNK },
1315221807Sstas		{ KF_VTYPE_VNON, PS_FST_VTYPE_VNON },
1316221807Sstas		{ KF_VTYPE_VREG, PS_FST_VTYPE_VREG },
1317221807Sstas		{ KF_VTYPE_VSOCK, PS_FST_VTYPE_VSOCK }
1318221807Sstas	};
1319221807Sstas#define	NKFVTYPES	(sizeof(kfvtypes2fst) / sizeof(*kfvtypes2fst))
1320221807Sstas	unsigned int i;
1321221807Sstas
1322221807Sstas	for (i = 0; i < NKFVTYPES; i++)
1323221807Sstas		if (kfvtypes2fst[i].kf_vtype == kfvtype)
1324221807Sstas			break;
1325221807Sstas	if (i == NKFVTYPES)
1326221807Sstas		return (PS_FST_VTYPE_UNKNOWN);
1327221807Sstas	return (kfvtypes2fst[i].fst_vtype);
1328221807Sstas}
1329221807Sstas
1330221807Sstasstatic int
1331221807Sstasprocstat_get_vnode_info_sysctl(struct filestat *fst, struct vnstat *vn,
1332221807Sstas    char *errbuf)
1333221807Sstas{
1334221807Sstas	struct statfs stbuf;
1335221807Sstas	struct kinfo_file *kif;
1336221807Sstas	struct kinfo_vmentry *kve;
1337221807Sstas	uint64_t fileid;
1338221807Sstas	uint64_t size;
1339221807Sstas	char *name, *path;
1340221807Sstas	uint32_t fsid;
1341221807Sstas	uint16_t mode;
1342221807Sstas	uint32_t rdev;
1343221807Sstas	int vntype;
1344221807Sstas	int status;
1345221807Sstas
1346221807Sstas	assert(fst);
1347221807Sstas	assert(vn);
1348221807Sstas	bzero(vn, sizeof(*vn));
1349221807Sstas	if (fst->fs_typedep == NULL)
1350221807Sstas		return (1);
1351221807Sstas	if (fst->fs_uflags & PS_FST_UFLAG_MMAP) {
1352221807Sstas		kve = fst->fs_typedep;
1353221807Sstas		fileid = kve->kve_vn_fileid;
1354221807Sstas		fsid = kve->kve_vn_fsid;
1355221807Sstas		mode = kve->kve_vn_mode;
1356221807Sstas		path = kve->kve_path;
1357221807Sstas		rdev = kve->kve_vn_rdev;
1358221807Sstas		size = kve->kve_vn_size;
1359221807Sstas		vntype = kinfo_vtype2fst(kve->kve_vn_type);
1360221807Sstas		status = kve->kve_status;
1361221807Sstas	} else {
1362221807Sstas		kif = fst->fs_typedep;
1363221807Sstas		fileid = kif->kf_un.kf_file.kf_file_fileid;
1364221807Sstas		fsid = kif->kf_un.kf_file.kf_file_fsid;
1365221807Sstas		mode = kif->kf_un.kf_file.kf_file_mode;
1366221807Sstas		path = kif->kf_path;
1367221807Sstas		rdev = kif->kf_un.kf_file.kf_file_rdev;
1368221807Sstas		size = kif->kf_un.kf_file.kf_file_size;
1369221807Sstas		vntype = kinfo_vtype2fst(kif->kf_vnode_type);
1370221807Sstas		status = kif->kf_status;
1371221807Sstas	}
1372221807Sstas	vn->vn_type = vntype;
1373221807Sstas	if (vntype == PS_FST_VTYPE_VNON || vntype == PS_FST_VTYPE_VBAD)
1374221807Sstas		return (0);
1375221807Sstas	if ((status & KF_ATTR_VALID) == 0) {
1376250378Strociny		if (errbuf != NULL) {
1377250378Strociny			snprintf(errbuf, _POSIX2_LINE_MAX,
1378250378Strociny			    "? (no info available)");
1379250378Strociny		}
1380221807Sstas		return (1);
1381221807Sstas	}
1382221807Sstas	if (path && *path) {
1383221807Sstas		statfs(path, &stbuf);
1384221807Sstas		vn->vn_mntdir = strdup(stbuf.f_mntonname);
1385221807Sstas	} else
1386221807Sstas		vn->vn_mntdir = strdup("-");
1387221807Sstas	vn->vn_dev = rdev;
1388221807Sstas	if (vntype == PS_FST_VTYPE_VBLK) {
1389221807Sstas		name = devname(rdev, S_IFBLK);
1390221807Sstas		if (name != NULL)
1391221807Sstas			strlcpy(vn->vn_devname, name,
1392221807Sstas			    sizeof(vn->vn_devname));
1393221807Sstas	} else if (vntype == PS_FST_VTYPE_VCHR) {
1394221807Sstas		name = devname(vn->vn_dev, S_IFCHR);
1395221807Sstas		if (name != NULL)
1396221807Sstas			strlcpy(vn->vn_devname, name,
1397221807Sstas			    sizeof(vn->vn_devname));
1398221807Sstas	}
1399221807Sstas	vn->vn_fsid = fsid;
1400221807Sstas	vn->vn_fileid = fileid;
1401221807Sstas	vn->vn_size = size;
1402221807Sstas	vn->vn_mode = mode;
1403221807Sstas	return (0);
1404221807Sstas}
1405221807Sstas
1406221807Sstasint
1407221807Sstasprocstat_get_socket_info(struct procstat *procstat, struct filestat *fst,
1408221807Sstas    struct sockstat *sock, char *errbuf)
1409221807Sstas{
1410221807Sstas
1411221807Sstas	assert(sock);
1412221807Sstas	if (procstat->type == PROCSTAT_KVM) {
1413221807Sstas		return (procstat_get_socket_info_kvm(procstat->kd, fst, sock,
1414221807Sstas		    errbuf));
1415249666Strociny	} else if (procstat->type == PROCSTAT_SYSCTL ||
1416249666Strociny		procstat->type == PROCSTAT_CORE) {
1417221807Sstas		return (procstat_get_socket_info_sysctl(fst, sock, errbuf));
1418221807Sstas	} else {
1419223276Sjilles		warnx("unknown access method: %d", procstat->type);
1420250378Strociny		if (errbuf != NULL)
1421250378Strociny			snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1422221807Sstas		return (1);
1423221807Sstas	}
1424221807Sstas}
1425221807Sstas
1426221807Sstasstatic int
1427221807Sstasprocstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst,
1428221807Sstas    struct sockstat *sock, char *errbuf)
1429221807Sstas{
1430221807Sstas	struct domain dom;
1431221807Sstas	struct inpcb inpcb;
1432221807Sstas	struct protosw proto;
1433221807Sstas	struct socket s;
1434221807Sstas	struct unpcb unpcb;
1435221807Sstas	ssize_t len;
1436221807Sstas	void *so;
1437221807Sstas
1438221807Sstas	assert(kd);
1439221807Sstas	assert(sock);
1440221807Sstas	assert(fst);
1441221807Sstas	bzero(sock, sizeof(*sock));
1442221807Sstas	so = fst->fs_typedep;
1443221807Sstas	if (so == NULL)
1444221807Sstas		goto fail;
1445221807Sstas	sock->so_addr = (uintptr_t)so;
1446221807Sstas	/* fill in socket */
1447221807Sstas	if (!kvm_read_all(kd, (unsigned long)so, &s,
1448221807Sstas	    sizeof(struct socket))) {
1449221807Sstas		warnx("can't read sock at %p", (void *)so);
1450221807Sstas		goto fail;
1451221807Sstas	}
1452221807Sstas	/* fill in protosw entry */
1453221807Sstas	if (!kvm_read_all(kd, (unsigned long)s.so_proto, &proto,
1454221807Sstas	    sizeof(struct protosw))) {
1455221807Sstas		warnx("can't read protosw at %p", (void *)s.so_proto);
1456221807Sstas		goto fail;
1457221807Sstas	}
1458221807Sstas	/* fill in domain */
1459221807Sstas	if (!kvm_read_all(kd, (unsigned long)proto.pr_domain, &dom,
1460221807Sstas	    sizeof(struct domain))) {
1461221807Sstas		warnx("can't read domain at %p",
1462221807Sstas		    (void *)proto.pr_domain);
1463221807Sstas		goto fail;
1464221807Sstas	}
1465221807Sstas	if ((len = kvm_read(kd, (unsigned long)dom.dom_name, sock->dname,
1466221807Sstas	    sizeof(sock->dname) - 1)) < 0) {
1467221807Sstas		warnx("can't read domain name at %p", (void *)dom.dom_name);
1468221807Sstas		sock->dname[0] = '\0';
1469221807Sstas	}
1470221807Sstas	else
1471221807Sstas		sock->dname[len] = '\0';
1472221807Sstas
1473221807Sstas	/*
1474221807Sstas	 * Fill in known data.
1475221807Sstas	 */
1476221807Sstas	sock->type = s.so_type;
1477221807Sstas	sock->proto = proto.pr_protocol;
1478221807Sstas	sock->dom_family = dom.dom_family;
1479221807Sstas	sock->so_pcb = (uintptr_t)s.so_pcb;
1480221807Sstas
1481221807Sstas	/*
1482221807Sstas	 * Protocol specific data.
1483221807Sstas	 */
1484221807Sstas	switch(dom.dom_family) {
1485221807Sstas	case AF_INET:
1486221807Sstas	case AF_INET6:
1487221807Sstas		if (proto.pr_protocol == IPPROTO_TCP) {
1488221807Sstas			if (s.so_pcb) {
1489221807Sstas				if (kvm_read(kd, (u_long)s.so_pcb,
1490221807Sstas				    (char *)&inpcb, sizeof(struct inpcb))
1491221807Sstas				    != sizeof(struct inpcb)) {
1492221807Sstas					warnx("can't read inpcb at %p",
1493221807Sstas					    (void *)s.so_pcb);
1494221807Sstas				} else
1495221807Sstas					sock->inp_ppcb =
1496221807Sstas					    (uintptr_t)inpcb.inp_ppcb;
1497221807Sstas			}
1498221807Sstas		}
1499221807Sstas		break;
1500221807Sstas	case AF_UNIX:
1501221807Sstas		if (s.so_pcb) {
1502221807Sstas			if (kvm_read(kd, (u_long)s.so_pcb, (char *)&unpcb,
1503221807Sstas			    sizeof(struct unpcb)) != sizeof(struct unpcb)){
1504221807Sstas				warnx("can't read unpcb at %p",
1505221807Sstas				    (void *)s.so_pcb);
1506221807Sstas			} else if (unpcb.unp_conn) {
1507221807Sstas				sock->so_rcv_sb_state = s.so_rcv.sb_state;
1508221807Sstas				sock->so_snd_sb_state = s.so_snd.sb_state;
1509221807Sstas				sock->unp_conn = (uintptr_t)unpcb.unp_conn;
1510221807Sstas			}
1511221807Sstas		}
1512221807Sstas		break;
1513221807Sstas	default:
1514221807Sstas		break;
1515221807Sstas	}
1516221807Sstas	return (0);
1517221807Sstas
1518221807Sstasfail:
1519250378Strociny	if (errbuf != NULL)
1520250378Strociny		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1521221807Sstas	return (1);
1522221807Sstas}
1523221807Sstas
1524221807Sstasstatic int
1525221807Sstasprocstat_get_socket_info_sysctl(struct filestat *fst, struct sockstat *sock,
1526221807Sstas    char *errbuf __unused)
1527221807Sstas{
1528221807Sstas	struct kinfo_file *kif;
1529221807Sstas
1530221807Sstas	assert(sock);
1531221807Sstas	assert(fst);
1532221807Sstas	bzero(sock, sizeof(*sock));
1533221807Sstas	kif = fst->fs_typedep;
1534221807Sstas	if (kif == NULL)
1535221807Sstas		return (0);
1536221807Sstas
1537221807Sstas	/*
1538221807Sstas	 * Fill in known data.
1539221807Sstas	 */
1540221807Sstas	sock->type = kif->kf_sock_type;
1541221807Sstas	sock->proto = kif->kf_sock_protocol;
1542221807Sstas	sock->dom_family = kif->kf_sock_domain;
1543221807Sstas	sock->so_pcb = kif->kf_un.kf_sock.kf_sock_pcb;
1544221807Sstas	strlcpy(sock->dname, kif->kf_path, sizeof(sock->dname));
1545221807Sstas	bcopy(&kif->kf_sa_local, &sock->sa_local, kif->kf_sa_local.ss_len);
1546221807Sstas	bcopy(&kif->kf_sa_peer, &sock->sa_peer, kif->kf_sa_peer.ss_len);
1547221807Sstas
1548221807Sstas	/*
1549221807Sstas	 * Protocol specific data.
1550221807Sstas	 */
1551221807Sstas	switch(sock->dom_family) {
1552221807Sstas	case AF_INET:
1553221807Sstas	case AF_INET6:
1554221807Sstas		if (sock->proto == IPPROTO_TCP)
1555221807Sstas			sock->inp_ppcb = kif->kf_un.kf_sock.kf_sock_inpcb;
1556221807Sstas		break;
1557221807Sstas	case AF_UNIX:
1558221807Sstas		if (kif->kf_un.kf_sock.kf_sock_unpconn != 0) {
1559221807Sstas				sock->so_rcv_sb_state =
1560221807Sstas				    kif->kf_un.kf_sock.kf_sock_rcv_sb_state;
1561221807Sstas				sock->so_snd_sb_state =
1562221807Sstas				    kif->kf_un.kf_sock.kf_sock_snd_sb_state;
1563221807Sstas				sock->unp_conn =
1564221807Sstas				    kif->kf_un.kf_sock.kf_sock_unpconn;
1565221807Sstas		}
1566221807Sstas		break;
1567221807Sstas	default:
1568221807Sstas		break;
1569221807Sstas	}
1570221807Sstas	return (0);
1571221807Sstas}
1572221807Sstas
1573221807Sstas/*
1574221807Sstas * Descriptor flags to filestat translation.
1575221807Sstas */
1576221807Sstasstatic int
1577221807Sstasto_filestat_flags(int flags)
1578221807Sstas{
1579221807Sstas	static struct {
1580221807Sstas		int flag;
1581221807Sstas		int fst_flag;
1582221807Sstas	} fstflags[] = {
1583221807Sstas		{ FREAD, PS_FST_FFLAG_READ },
1584221807Sstas		{ FWRITE, PS_FST_FFLAG_WRITE },
1585221807Sstas		{ O_APPEND, PS_FST_FFLAG_APPEND },
1586221807Sstas		{ O_ASYNC, PS_FST_FFLAG_ASYNC },
1587221807Sstas		{ O_CREAT, PS_FST_FFLAG_CREAT },
1588221807Sstas		{ O_DIRECT, PS_FST_FFLAG_DIRECT },
1589221807Sstas		{ O_EXCL, PS_FST_FFLAG_EXCL },
1590221807Sstas		{ O_EXEC, PS_FST_FFLAG_EXEC },
1591221807Sstas		{ O_EXLOCK, PS_FST_FFLAG_EXLOCK },
1592221807Sstas		{ O_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW },
1593221807Sstas		{ O_NONBLOCK, PS_FST_FFLAG_NONBLOCK },
1594221807Sstas		{ O_SHLOCK, PS_FST_FFLAG_SHLOCK },
1595221807Sstas		{ O_SYNC, PS_FST_FFLAG_SYNC },
1596221807Sstas		{ O_TRUNC, PS_FST_FFLAG_TRUNC }
1597221807Sstas	};
1598221807Sstas#define NFSTFLAGS	(sizeof(fstflags) / sizeof(*fstflags))
1599221807Sstas	int fst_flags;
1600221807Sstas	unsigned int i;
1601221807Sstas
1602221807Sstas	fst_flags = 0;
1603221807Sstas	for (i = 0; i < NFSTFLAGS; i++)
1604221807Sstas		if (flags & fstflags[i].flag)
1605221807Sstas			fst_flags |= fstflags[i].fst_flag;
1606221807Sstas	return (fst_flags);
1607221807Sstas}
1608221807Sstas
1609221807Sstas/*
1610221807Sstas * Vnode type to filestate translation.
1611221807Sstas */
1612221807Sstasstatic int
1613221807Sstasvntype2psfsttype(int type)
1614221807Sstas{
1615221807Sstas	static struct {
1616221807Sstas		int	vtype;
1617221807Sstas		int	fst_vtype;
1618221807Sstas	} vt2fst[] = {
1619221807Sstas		{ VBAD, PS_FST_VTYPE_VBAD },
1620221807Sstas		{ VBLK, PS_FST_VTYPE_VBLK },
1621221807Sstas		{ VCHR, PS_FST_VTYPE_VCHR },
1622221807Sstas		{ VDIR, PS_FST_VTYPE_VDIR },
1623221807Sstas		{ VFIFO, PS_FST_VTYPE_VFIFO },
1624221807Sstas		{ VLNK, PS_FST_VTYPE_VLNK },
1625221807Sstas		{ VNON, PS_FST_VTYPE_VNON },
1626221807Sstas		{ VREG, PS_FST_VTYPE_VREG },
1627221807Sstas		{ VSOCK, PS_FST_VTYPE_VSOCK }
1628221807Sstas	};
1629221807Sstas#define	NVFTYPES	(sizeof(vt2fst) / sizeof(*vt2fst))
1630221807Sstas	unsigned int i, fst_type;
1631221807Sstas
1632221807Sstas	fst_type = PS_FST_VTYPE_UNKNOWN;
1633221807Sstas	for (i = 0; i < NVFTYPES; i++) {
1634221807Sstas		if (type == vt2fst[i].vtype) {
1635221807Sstas			fst_type = vt2fst[i].fst_vtype;
1636221807Sstas			break;
1637221807Sstas		}
1638221807Sstas	}
1639221807Sstas	return (fst_type);
1640221807Sstas}
1641221807Sstas
1642221807Sstasstatic char *
1643221807Sstasgetmnton(kvm_t *kd, struct mount *m)
1644221807Sstas{
1645223262Sbenl	struct mount mnt;
1646221807Sstas	static struct mtab {
1647221807Sstas		struct mtab *next;
1648221807Sstas		struct mount *m;
1649221807Sstas		char mntonname[MNAMELEN + 1];
1650221807Sstas	} *mhead = NULL;
1651221807Sstas	struct mtab *mt;
1652221807Sstas
1653221807Sstas	for (mt = mhead; mt != NULL; mt = mt->next)
1654221807Sstas		if (m == mt->m)
1655221807Sstas			return (mt->mntonname);
1656221807Sstas	if (!kvm_read_all(kd, (unsigned long)m, &mnt, sizeof(struct mount))) {
1657221807Sstas		warnx("can't read mount table at %p", (void *)m);
1658221807Sstas		return (NULL);
1659221807Sstas	}
1660221807Sstas	if ((mt = malloc(sizeof (struct mtab))) == NULL)
1661221807Sstas		err(1, NULL);
1662221807Sstas	mt->m = m;
1663221807Sstas	bcopy(&mnt.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN);
1664223262Sbenl	mt->mntonname[MNAMELEN] = '\0';
1665221807Sstas	mt->next = mhead;
1666221807Sstas	mhead = mt;
1667221807Sstas	return (mt->mntonname);
1668221807Sstas}
1669249666Strociny
1670249679Strociny/*
1671249679Strociny * Auxiliary structures and functions to get process environment or
1672249679Strociny * command line arguments.
1673249679Strociny */
1674249679Strocinystruct argvec {
1675249679Strociny	char	*buf;
1676249679Strociny	size_t	bufsize;
1677249679Strociny	char	**argv;
1678249679Strociny	size_t	argc;
1679249679Strociny};
1680249679Strociny
1681249679Strocinystatic struct argvec *
1682249679Strocinyargvec_alloc(size_t bufsize)
1683249679Strociny{
1684249679Strociny	struct argvec *av;
1685249679Strociny
1686249679Strociny	av = malloc(sizeof(*av));
1687249679Strociny	if (av == NULL)
1688249679Strociny		return (NULL);
1689249679Strociny	av->bufsize = bufsize;
1690249679Strociny	av->buf = malloc(av->bufsize);
1691249679Strociny	if (av->buf == NULL) {
1692249679Strociny		free(av);
1693249679Strociny		return (NULL);
1694249679Strociny	}
1695249679Strociny	av->argc = 32;
1696249679Strociny	av->argv = malloc(sizeof(char *) * av->argc);
1697249679Strociny	if (av->argv == NULL) {
1698249679Strociny		free(av->buf);
1699249679Strociny		free(av);
1700249679Strociny		return (NULL);
1701249679Strociny	}
1702249679Strociny	return av;
1703249679Strociny}
1704249679Strociny
1705249679Strocinystatic void
1706249679Strocinyargvec_free(struct argvec * av)
1707249679Strociny{
1708249679Strociny
1709249679Strociny	free(av->argv);
1710249679Strociny	free(av->buf);
1711249679Strociny	free(av);
1712249679Strociny}
1713249679Strociny
1714249679Strocinystatic char **
1715249679Strocinygetargv(struct procstat *procstat, struct kinfo_proc *kp, size_t nchr, int env)
1716249679Strociny{
1717249679Strociny	int error, name[4], argc, i;
1718249679Strociny	struct argvec *av, **avp;
1719249679Strociny	enum psc_type type;
1720249679Strociny	size_t len;
1721249679Strociny	char *p, **argv;
1722249679Strociny
1723249679Strociny	assert(procstat);
1724249679Strociny	assert(kp);
1725249679Strociny	if (procstat->type == PROCSTAT_KVM) {
1726249679Strociny		warnx("can't use kvm access method");
1727249679Strociny		return (NULL);
1728249679Strociny	}
1729249679Strociny	if (procstat->type != PROCSTAT_SYSCTL &&
1730249679Strociny	    procstat->type != PROCSTAT_CORE) {
1731249679Strociny		warnx("unknown access method: %d", procstat->type);
1732249679Strociny		return (NULL);
1733249679Strociny	}
1734249679Strociny
1735249679Strociny	if (nchr == 0 || nchr > ARG_MAX)
1736249679Strociny		nchr = ARG_MAX;
1737249679Strociny
1738249679Strociny	avp = (struct argvec **)(env ? &procstat->argv : &procstat->envv);
1739249679Strociny	av = *avp;
1740249679Strociny
1741249679Strociny	if (av == NULL)
1742249679Strociny	{
1743249679Strociny		av = argvec_alloc(nchr);
1744249679Strociny		if (av == NULL)
1745249679Strociny		{
1746249679Strociny			warn("malloc(%zu)", nchr);
1747249679Strociny			return (NULL);
1748249679Strociny		}
1749249679Strociny		*avp = av;
1750249679Strociny	} else if (av->bufsize < nchr) {
1751249679Strociny		av->buf = reallocf(av->buf, nchr);
1752249679Strociny		if (av->buf == NULL) {
1753249679Strociny			warn("malloc(%zu)", nchr);
1754249679Strociny			return (NULL);
1755249679Strociny		}
1756249679Strociny	}
1757249679Strociny	if (procstat->type == PROCSTAT_SYSCTL) {
1758249679Strociny		name[0] = CTL_KERN;
1759249679Strociny		name[1] = KERN_PROC;
1760249679Strociny		name[2] = env ? KERN_PROC_ENV : KERN_PROC_ARGS;
1761249679Strociny		name[3] = kp->ki_pid;
1762249679Strociny		len = nchr;
1763312036Sngie		error = sysctl(name, nitems(name), av->buf, &len, NULL, 0);
1764249679Strociny		if (error != 0 && errno != ESRCH && errno != EPERM)
1765249679Strociny			warn("sysctl(kern.proc.%s)", env ? "env" : "args");
1766249679Strociny		if (error != 0 || len == 0)
1767249679Strociny			return (NULL);
1768249679Strociny	} else /* procstat->type == PROCSTAT_CORE */ {
1769249679Strociny		type = env ? PSC_TYPE_ENVV : PSC_TYPE_ARGV;
1770249679Strociny		len = nchr;
1771249679Strociny		if (procstat_core_get(procstat->core, type, av->buf, &len)
1772249679Strociny		    == NULL) {
1773249679Strociny			return (NULL);
1774249679Strociny		}
1775249679Strociny	}
1776249679Strociny
1777249679Strociny	argv = av->argv;
1778249679Strociny	argc = av->argc;
1779249679Strociny	i = 0;
1780249679Strociny	for (p = av->buf; p < av->buf + len; p += strlen(p) + 1) {
1781249679Strociny		argv[i++] = p;
1782249679Strociny		if (i < argc)
1783249679Strociny			continue;
1784249679Strociny		/* Grow argv. */
1785249679Strociny		argc += argc;
1786249679Strociny		argv = realloc(argv, sizeof(char *) * argc);
1787249679Strociny		if (argv == NULL) {
1788249679Strociny			warn("malloc(%zu)", sizeof(char *) * argc);
1789249679Strociny			return (NULL);
1790249679Strociny		}
1791249679Strociny		av->argv = argv;
1792249679Strociny		av->argc = argc;
1793249679Strociny	}
1794249679Strociny	argv[i] = NULL;
1795249679Strociny
1796249679Strociny	return (argv);
1797249679Strociny}
1798249679Strociny
1799249679Strociny/*
1800249679Strociny * Return process command line arguments.
1801249679Strociny */
1802249679Strocinychar **
1803249679Strocinyprocstat_getargv(struct procstat *procstat, struct kinfo_proc *p, size_t nchr)
1804249679Strociny{
1805249679Strociny
1806249679Strociny	return (getargv(procstat, p, nchr, 0));
1807249679Strociny}
1808249679Strociny
1809249679Strociny/*
1810249679Strociny * Free the buffer allocated by procstat_getargv().
1811249679Strociny */
1812249679Strocinyvoid
1813249679Strocinyprocstat_freeargv(struct procstat *procstat)
1814249679Strociny{
1815249679Strociny
1816249679Strociny	if (procstat->argv != NULL) {
1817249679Strociny		argvec_free(procstat->argv);
1818249679Strociny		procstat->argv = NULL;
1819249679Strociny	}
1820249679Strociny}
1821249679Strociny
1822249679Strociny/*
1823249679Strociny * Return process environment.
1824249679Strociny */
1825249679Strocinychar **
1826249679Strocinyprocstat_getenvv(struct procstat *procstat, struct kinfo_proc *p, size_t nchr)
1827249679Strociny{
1828249679Strociny
1829249679Strociny	return (getargv(procstat, p, nchr, 1));
1830249679Strociny}
1831249679Strociny
1832249679Strociny/*
1833249679Strociny * Free the buffer allocated by procstat_getenvv().
1834249679Strociny */
1835249679Strocinyvoid
1836249679Strocinyprocstat_freeenvv(struct procstat *procstat)
1837249679Strociny{
1838249679Strociny	if (procstat->envv != NULL) {
1839249679Strociny		argvec_free(procstat->envv);
1840249679Strociny		procstat->envv = NULL;
1841249679Strociny	}
1842249679Strociny}
1843249679Strociny
1844249667Strocinystatic struct kinfo_vmentry *
1845249667Strocinykinfo_getvmmap_core(struct procstat_core *core, int *cntp)
1846249667Strociny{
1847249667Strociny	int cnt;
1848249667Strociny	size_t len;
1849249667Strociny	char *buf, *bp, *eb;
1850249667Strociny	struct kinfo_vmentry *kiv, *kp, *kv;
1851249667Strociny
1852249667Strociny	buf = procstat_core_get(core, PSC_TYPE_VMMAP, NULL, &len);
1853249667Strociny	if (buf == NULL)
1854249667Strociny		return (NULL);
1855249667Strociny
1856249667Strociny	/*
1857249667Strociny	 * XXXMG: The code below is just copy&past from libutil.
1858249667Strociny	 * The code duplication can be avoided if libutil
1859249667Strociny	 * is extended to provide something like:
1860249667Strociny	 *   struct kinfo_vmentry *kinfo_getvmmap_from_buf(const char *buf,
1861249667Strociny	 *       size_t len, int *cntp);
1862249667Strociny	 */
1863249667Strociny
1864249667Strociny	/* Pass 1: count items */
1865249667Strociny	cnt = 0;
1866249667Strociny	bp = buf;
1867249667Strociny	eb = buf + len;
1868249667Strociny	while (bp < eb) {
1869249667Strociny		kv = (struct kinfo_vmentry *)(uintptr_t)bp;
1870295454Sjhb		if (kv->kve_structsize == 0)
1871295454Sjhb			break;
1872249667Strociny		bp += kv->kve_structsize;
1873249667Strociny		cnt++;
1874249667Strociny	}
1875249667Strociny
1876249667Strociny	kiv = calloc(cnt, sizeof(*kiv));
1877249667Strociny	if (kiv == NULL) {
1878249667Strociny		free(buf);
1879249667Strociny		return (NULL);
1880249667Strociny	}
1881249667Strociny	bp = buf;
1882249667Strociny	eb = buf + len;
1883249667Strociny	kp = kiv;
1884249667Strociny	/* Pass 2: unpack */
1885249667Strociny	while (bp < eb) {
1886249667Strociny		kv = (struct kinfo_vmentry *)(uintptr_t)bp;
1887295454Sjhb		if (kv->kve_structsize == 0)
1888295454Sjhb			break;
1889249667Strociny		/* Copy/expand into pre-zeroed buffer */
1890249667Strociny		memcpy(kp, kv, kv->kve_structsize);
1891249667Strociny		/* Advance to next packed record */
1892249667Strociny		bp += kv->kve_structsize;
1893249667Strociny		/* Set field size to fixed length, advance */
1894249667Strociny		kp->kve_structsize = sizeof(*kp);
1895249667Strociny		kp++;
1896249667Strociny	}
1897249667Strociny	free(buf);
1898249667Strociny	*cntp = cnt;
1899249667Strociny	return (kiv);	/* Caller must free() return value */
1900249667Strociny}
1901249667Strociny
1902249667Strocinystruct kinfo_vmentry *
1903249667Strocinyprocstat_getvmmap(struct procstat *procstat, struct kinfo_proc *kp,
1904249667Strociny    unsigned int *cntp)
1905249667Strociny{
1906249684Strociny
1907249667Strociny	switch(procstat->type) {
1908249667Strociny	case PROCSTAT_KVM:
1909249667Strociny		warnx("kvm method is not supported");
1910249667Strociny		return (NULL);
1911249667Strociny	case PROCSTAT_SYSCTL:
1912249667Strociny		return (kinfo_getvmmap(kp->ki_pid, cntp));
1913249667Strociny	case PROCSTAT_CORE:
1914249667Strociny		return (kinfo_getvmmap_core(procstat->core, cntp));
1915249667Strociny	default:
1916249667Strociny		warnx("unknown access method: %d", procstat->type);
1917249667Strociny		return (NULL);
1918249667Strociny	}
1919249667Strociny}
1920249667Strociny
1921249667Strocinyvoid
1922249667Strocinyprocstat_freevmmap(struct procstat *procstat __unused,
1923249667Strociny    struct kinfo_vmentry *vmmap)
1924249667Strociny{
1925249667Strociny
1926249667Strociny	free(vmmap);
1927249667Strociny}
1928249670Strociny
1929249670Strocinystatic gid_t *
1930250146Strocinyprocstat_getgroups_kvm(kvm_t *kd, struct kinfo_proc *kp, unsigned int *cntp)
1931250146Strociny{
1932250146Strociny	struct proc proc;
1933250146Strociny	struct ucred ucred;
1934250146Strociny	gid_t *groups;
1935250146Strociny	size_t len;
1936250146Strociny
1937250146Strociny	assert(kd != NULL);
1938250146Strociny	assert(kp != NULL);
1939250146Strociny	if (!kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc,
1940250146Strociny	    sizeof(proc))) {
1941250146Strociny		warnx("can't read proc struct at %p for pid %d",
1942250146Strociny		    kp->ki_paddr, kp->ki_pid);
1943250146Strociny		return (NULL);
1944250146Strociny	}
1945250146Strociny	if (proc.p_ucred == NOCRED)
1946250146Strociny		return (NULL);
1947250146Strociny	if (!kvm_read_all(kd, (unsigned long)proc.p_ucred, &ucred,
1948250146Strociny	    sizeof(ucred))) {
1949250146Strociny		warnx("can't read ucred struct at %p for pid %d",
1950250146Strociny		    proc.p_ucred, kp->ki_pid);
1951250146Strociny		return (NULL);
1952250146Strociny	}
1953250146Strociny	len = ucred.cr_ngroups * sizeof(gid_t);
1954250146Strociny	groups = malloc(len);
1955250146Strociny	if (groups == NULL) {
1956250146Strociny		warn("malloc(%zu)", len);
1957250146Strociny		return (NULL);
1958250146Strociny	}
1959250146Strociny	if (!kvm_read_all(kd, (unsigned long)ucred.cr_groups, groups, len)) {
1960250146Strociny		warnx("can't read groups at %p for pid %d",
1961250146Strociny		    ucred.cr_groups, kp->ki_pid);
1962250146Strociny		free(groups);
1963250146Strociny		return (NULL);
1964250146Strociny	}
1965250146Strociny	*cntp = ucred.cr_ngroups;
1966250146Strociny	return (groups);
1967250146Strociny}
1968250146Strociny
1969250146Strocinystatic gid_t *
1970249670Strocinyprocstat_getgroups_sysctl(pid_t pid, unsigned int *cntp)
1971249670Strociny{
1972249670Strociny	int mib[4];
1973249670Strociny	size_t len;
1974249670Strociny	gid_t *groups;
1975249670Strociny
1976249670Strociny	mib[0] = CTL_KERN;
1977249670Strociny	mib[1] = KERN_PROC;
1978249670Strociny	mib[2] = KERN_PROC_GROUPS;
1979249670Strociny	mib[3] = pid;
1980249670Strociny	len = (sysconf(_SC_NGROUPS_MAX) + 1) * sizeof(gid_t);
1981249670Strociny	groups = malloc(len);
1982249670Strociny	if (groups == NULL) {
1983249670Strociny		warn("malloc(%zu)", len);
1984249670Strociny		return (NULL);
1985249670Strociny	}
1986312036Sngie	if (sysctl(mib, nitems(mib), groups, &len, NULL, 0) == -1) {
1987249670Strociny		warn("sysctl: kern.proc.groups: %d", pid);
1988249670Strociny		free(groups);
1989249670Strociny		return (NULL);
1990249670Strociny	}
1991249670Strociny	*cntp = len / sizeof(gid_t);
1992249670Strociny	return (groups);
1993249670Strociny}
1994249670Strociny
1995249670Strocinystatic gid_t *
1996249670Strocinyprocstat_getgroups_core(struct procstat_core *core, unsigned int *cntp)
1997249670Strociny{
1998249670Strociny	size_t len;
1999249670Strociny	gid_t *groups;
2000249670Strociny
2001249670Strociny	groups = procstat_core_get(core, PSC_TYPE_GROUPS, NULL, &len);
2002249670Strociny	if (groups == NULL)
2003249670Strociny		return (NULL);
2004249670Strociny	*cntp = len / sizeof(gid_t);
2005249670Strociny	return (groups);
2006249670Strociny}
2007249670Strociny
2008249670Strocinygid_t *
2009249670Strocinyprocstat_getgroups(struct procstat *procstat, struct kinfo_proc *kp,
2010249670Strociny    unsigned int *cntp)
2011249670Strociny{
2012249670Strociny	switch(procstat->type) {
2013249670Strociny	case PROCSTAT_KVM:
2014250146Strociny		return (procstat_getgroups_kvm(procstat->kd, kp, cntp));
2015249670Strociny	case PROCSTAT_SYSCTL:
2016249670Strociny		return (procstat_getgroups_sysctl(kp->ki_pid, cntp));
2017249670Strociny	case PROCSTAT_CORE:
2018249670Strociny		return (procstat_getgroups_core(procstat->core, cntp));
2019249670Strociny	default:
2020249670Strociny		warnx("unknown access method: %d", procstat->type);
2021249670Strociny		return (NULL);
2022249670Strociny	}
2023249670Strociny}
2024249670Strociny
2025249670Strocinyvoid
2026249670Strocinyprocstat_freegroups(struct procstat *procstat __unused, gid_t *groups)
2027249670Strociny{
2028249670Strociny
2029249670Strociny	free(groups);
2030249670Strociny}
2031249672Strociny
2032249672Strocinystatic int
2033250146Strocinyprocstat_getumask_kvm(kvm_t *kd, struct kinfo_proc *kp, unsigned short *maskp)
2034250146Strociny{
2035250146Strociny	struct filedesc fd;
2036250146Strociny
2037250146Strociny	assert(kd != NULL);
2038250146Strociny	assert(kp != NULL);
2039250146Strociny	if (kp->ki_fd == NULL)
2040250146Strociny		return (-1);
2041250146Strociny	if (!kvm_read_all(kd, (unsigned long)kp->ki_fd, &fd, sizeof(fd))) {
2042250146Strociny		warnx("can't read filedesc at %p for pid %d", kp->ki_fd,
2043250146Strociny		    kp->ki_pid);
2044250146Strociny		return (-1);
2045250146Strociny	}
2046250146Strociny	*maskp = fd.fd_cmask;
2047250146Strociny	return (0);
2048250146Strociny}
2049250146Strociny
2050250146Strocinystatic int
2051249672Strocinyprocstat_getumask_sysctl(pid_t pid, unsigned short *maskp)
2052249672Strociny{
2053249672Strociny	int error;
2054249672Strociny	int mib[4];
2055249672Strociny	size_t len;
2056249672Strociny
2057249672Strociny	mib[0] = CTL_KERN;
2058249672Strociny	mib[1] = KERN_PROC;
2059249672Strociny	mib[2] = KERN_PROC_UMASK;
2060249672Strociny	mib[3] = pid;
2061249672Strociny	len = sizeof(*maskp);
2062312036Sngie	error = sysctl(mib, nitems(mib), maskp, &len, NULL, 0);
2063262947Srwatson	if (error != 0 && errno != ESRCH && errno != EPERM)
2064249672Strociny		warn("sysctl: kern.proc.umask: %d", pid);
2065249672Strociny	return (error);
2066249672Strociny}
2067249672Strociny
2068249672Strocinystatic int
2069249672Strocinyprocstat_getumask_core(struct procstat_core *core, unsigned short *maskp)
2070249672Strociny{
2071249672Strociny	size_t len;
2072249672Strociny	unsigned short *buf;
2073249672Strociny
2074249672Strociny	buf = procstat_core_get(core, PSC_TYPE_UMASK, NULL, &len);
2075249672Strociny	if (buf == NULL)
2076249672Strociny		return (-1);
2077249672Strociny	if (len < sizeof(*maskp)) {
2078249672Strociny		free(buf);
2079249672Strociny		return (-1);
2080249672Strociny	}
2081249672Strociny	*maskp = *buf;
2082249672Strociny	free(buf);
2083249672Strociny	return (0);
2084249672Strociny}
2085249672Strociny
2086249672Strocinyint
2087249672Strocinyprocstat_getumask(struct procstat *procstat, struct kinfo_proc *kp,
2088249672Strociny    unsigned short *maskp)
2089249672Strociny{
2090249672Strociny	switch(procstat->type) {
2091249672Strociny	case PROCSTAT_KVM:
2092250146Strociny		return (procstat_getumask_kvm(procstat->kd, kp, maskp));
2093249672Strociny	case PROCSTAT_SYSCTL:
2094249672Strociny		return (procstat_getumask_sysctl(kp->ki_pid, maskp));
2095249672Strociny	case PROCSTAT_CORE:
2096249672Strociny		return (procstat_getumask_core(procstat->core, maskp));
2097249672Strociny	default:
2098249672Strociny		warnx("unknown access method: %d", procstat->type);
2099249672Strociny		return (-1);
2100249672Strociny	}
2101249672Strociny}
2102249674Strociny
2103249674Strocinystatic int
2104250146Strocinyprocstat_getrlimit_kvm(kvm_t *kd, struct kinfo_proc *kp, int which,
2105250146Strociny    struct rlimit* rlimit)
2106250146Strociny{
2107250146Strociny	struct proc proc;
2108250146Strociny	unsigned long offset;
2109250146Strociny
2110250146Strociny	assert(kd != NULL);
2111250146Strociny	assert(kp != NULL);
2112250146Strociny	assert(which >= 0 && which < RLIM_NLIMITS);
2113250146Strociny	if (!kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc,
2114250146Strociny	    sizeof(proc))) {
2115250146Strociny		warnx("can't read proc struct at %p for pid %d",
2116250146Strociny		    kp->ki_paddr, kp->ki_pid);
2117250146Strociny		return (-1);
2118250146Strociny	}
2119250146Strociny	if (proc.p_limit == NULL)
2120250146Strociny		return (-1);
2121250146Strociny	offset = (unsigned long)proc.p_limit + sizeof(struct rlimit) * which;
2122250146Strociny	if (!kvm_read_all(kd, offset, rlimit, sizeof(*rlimit))) {
2123250146Strociny		warnx("can't read rlimit struct at %p for pid %d",
2124250146Strociny		    (void *)offset, kp->ki_pid);
2125250146Strociny		return (-1);
2126250146Strociny	}
2127250146Strociny	return (0);
2128250146Strociny}
2129250146Strociny
2130250146Strocinystatic int
2131249674Strocinyprocstat_getrlimit_sysctl(pid_t pid, int which, struct rlimit* rlimit)
2132249674Strociny{
2133249674Strociny	int error, name[5];
2134249674Strociny	size_t len;
2135249674Strociny
2136249674Strociny	name[0] = CTL_KERN;
2137249674Strociny	name[1] = KERN_PROC;
2138249674Strociny	name[2] = KERN_PROC_RLIMIT;
2139249674Strociny	name[3] = pid;
2140249674Strociny	name[4] = which;
2141249674Strociny	len = sizeof(struct rlimit);
2142312036Sngie	error = sysctl(name, nitems(name), rlimit, &len, NULL, 0);
2143249674Strociny	if (error < 0 && errno != ESRCH) {
2144249674Strociny		warn("sysctl: kern.proc.rlimit: %d", pid);
2145249674Strociny		return (-1);
2146249674Strociny	}
2147249674Strociny	if (error < 0 || len != sizeof(struct rlimit))
2148249674Strociny		return (-1);
2149249674Strociny	return (0);
2150249674Strociny}
2151249674Strociny
2152249674Strocinystatic int
2153249674Strocinyprocstat_getrlimit_core(struct procstat_core *core, int which,
2154249674Strociny    struct rlimit* rlimit)
2155249674Strociny{
2156249674Strociny	size_t len;
2157249674Strociny	struct rlimit* rlimits;
2158249674Strociny
2159249674Strociny	if (which < 0 || which >= RLIM_NLIMITS) {
2160249674Strociny		errno = EINVAL;
2161249674Strociny		warn("getrlimit: which");
2162249674Strociny		return (-1);
2163249674Strociny	}
2164249674Strociny	rlimits = procstat_core_get(core, PSC_TYPE_RLIMIT, NULL, &len);
2165249674Strociny	if (rlimits == NULL)
2166249674Strociny		return (-1);
2167249674Strociny	if (len < sizeof(struct rlimit) * RLIM_NLIMITS) {
2168249674Strociny		free(rlimits);
2169249674Strociny		return (-1);
2170249674Strociny	}
2171249674Strociny	*rlimit = rlimits[which];
2172249674Strociny	return (0);
2173249674Strociny}
2174249674Strociny
2175249674Strocinyint
2176249674Strocinyprocstat_getrlimit(struct procstat *procstat, struct kinfo_proc *kp, int which,
2177249674Strociny    struct rlimit* rlimit)
2178249674Strociny{
2179249674Strociny	switch(procstat->type) {
2180249674Strociny	case PROCSTAT_KVM:
2181250146Strociny		return (procstat_getrlimit_kvm(procstat->kd, kp, which,
2182250146Strociny		    rlimit));
2183249674Strociny	case PROCSTAT_SYSCTL:
2184249674Strociny		return (procstat_getrlimit_sysctl(kp->ki_pid, which, rlimit));
2185249674Strociny	case PROCSTAT_CORE:
2186249674Strociny		return (procstat_getrlimit_core(procstat->core, which, rlimit));
2187249674Strociny	default:
2188249674Strociny		warnx("unknown access method: %d", procstat->type);
2189249674Strociny		return (-1);
2190249674Strociny	}
2191249674Strociny}
2192249676Strociny
2193249676Strocinystatic int
2194249676Strocinyprocstat_getpathname_sysctl(pid_t pid, char *pathname, size_t maxlen)
2195249676Strociny{
2196249676Strociny	int error, name[4];
2197249676Strociny	size_t len;
2198249676Strociny
2199249676Strociny	name[0] = CTL_KERN;
2200249676Strociny	name[1] = KERN_PROC;
2201249676Strociny	name[2] = KERN_PROC_PATHNAME;
2202249676Strociny	name[3] = pid;
2203249676Strociny	len = maxlen;
2204312036Sngie	error = sysctl(name, nitems(name), pathname, &len, NULL, 0);
2205249676Strociny	if (error != 0 && errno != ESRCH)
2206249676Strociny		warn("sysctl: kern.proc.pathname: %d", pid);
2207249676Strociny	if (len == 0)
2208249676Strociny		pathname[0] = '\0';
2209249676Strociny	return (error);
2210249676Strociny}
2211249676Strociny
2212249676Strocinystatic int
2213249676Strocinyprocstat_getpathname_core(struct procstat_core *core, char *pathname,
2214249676Strociny    size_t maxlen)
2215249676Strociny{
2216249676Strociny	struct kinfo_file *files;
2217249676Strociny	int cnt, i, result;
2218249676Strociny
2219249676Strociny	files = kinfo_getfile_core(core, &cnt);
2220249676Strociny	if (files == NULL)
2221249676Strociny		return (-1);
2222249676Strociny	result = -1;
2223249676Strociny	for (i = 0; i < cnt; i++) {
2224249676Strociny		if (files[i].kf_fd != KF_FD_TYPE_TEXT)
2225249676Strociny			continue;
2226249676Strociny		strncpy(pathname, files[i].kf_path, maxlen);
2227249676Strociny		result = 0;
2228249676Strociny		break;
2229249676Strociny	}
2230249676Strociny	free(files);
2231249676Strociny	return (result);
2232249676Strociny}
2233249676Strociny
2234249676Strocinyint
2235249676Strocinyprocstat_getpathname(struct procstat *procstat, struct kinfo_proc *kp,
2236249676Strociny    char *pathname, size_t maxlen)
2237249676Strociny{
2238249676Strociny	switch(procstat->type) {
2239249676Strociny	case PROCSTAT_KVM:
2240250147Strociny		/* XXX: Return empty string. */
2241250147Strociny		if (maxlen > 0)
2242250147Strociny			pathname[0] = '\0';
2243250147Strociny		return (0);
2244249676Strociny	case PROCSTAT_SYSCTL:
2245249676Strociny		return (procstat_getpathname_sysctl(kp->ki_pid, pathname,
2246249676Strociny		    maxlen));
2247249676Strociny	case PROCSTAT_CORE:
2248249676Strociny		return (procstat_getpathname_core(procstat->core, pathname,
2249249676Strociny		    maxlen));
2250249676Strociny	default:
2251249676Strociny		warnx("unknown access method: %d", procstat->type);
2252249676Strociny		return (-1);
2253249676Strociny	}
2254249676Strociny}
2255249677Strociny
2256249677Strocinystatic int
2257250146Strocinyprocstat_getosrel_kvm(kvm_t *kd, struct kinfo_proc *kp, int *osrelp)
2258250146Strociny{
2259250146Strociny	struct proc proc;
2260250146Strociny
2261250146Strociny	assert(kd != NULL);
2262250146Strociny	assert(kp != NULL);
2263250146Strociny	if (!kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc,
2264250146Strociny	    sizeof(proc))) {
2265250146Strociny		warnx("can't read proc struct at %p for pid %d",
2266250146Strociny		    kp->ki_paddr, kp->ki_pid);
2267250146Strociny		return (-1);
2268250146Strociny	}
2269250146Strociny	*osrelp = proc.p_osrel;
2270250146Strociny	return (0);
2271250146Strociny}
2272250146Strociny
2273250146Strocinystatic int
2274249677Strocinyprocstat_getosrel_sysctl(pid_t pid, int *osrelp)
2275249677Strociny{
2276249677Strociny	int error, name[4];
2277249677Strociny	size_t len;
2278249677Strociny
2279249677Strociny	name[0] = CTL_KERN;
2280249677Strociny	name[1] = KERN_PROC;
2281249677Strociny	name[2] = KERN_PROC_OSREL;
2282249677Strociny	name[3] = pid;
2283249677Strociny	len = sizeof(*osrelp);
2284312036Sngie	error = sysctl(name, nitems(name), osrelp, &len, NULL, 0);
2285249677Strociny	if (error != 0 && errno != ESRCH)
2286249677Strociny		warn("sysctl: kern.proc.osrel: %d", pid);
2287249677Strociny	return (error);
2288249677Strociny}
2289249677Strociny
2290249677Strocinystatic int
2291249677Strocinyprocstat_getosrel_core(struct procstat_core *core, int *osrelp)
2292249677Strociny{
2293249677Strociny	size_t len;
2294249677Strociny	int *buf;
2295249677Strociny
2296249677Strociny	buf = procstat_core_get(core, PSC_TYPE_OSREL, NULL, &len);
2297249677Strociny	if (buf == NULL)
2298249677Strociny		return (-1);
2299249677Strociny	if (len < sizeof(*osrelp)) {
2300249677Strociny		free(buf);
2301249677Strociny		return (-1);
2302249677Strociny	}
2303249677Strociny	*osrelp = *buf;
2304249677Strociny	free(buf);
2305249677Strociny	return (0);
2306249677Strociny}
2307249677Strociny
2308249677Strocinyint
2309249677Strocinyprocstat_getosrel(struct procstat *procstat, struct kinfo_proc *kp, int *osrelp)
2310249677Strociny{
2311249677Strociny	switch(procstat->type) {
2312249677Strociny	case PROCSTAT_KVM:
2313250146Strociny		return (procstat_getosrel_kvm(procstat->kd, kp, osrelp));
2314249677Strociny	case PROCSTAT_SYSCTL:
2315249677Strociny		return (procstat_getosrel_sysctl(kp->ki_pid, osrelp));
2316249677Strociny	case PROCSTAT_CORE:
2317249677Strociny		return (procstat_getosrel_core(procstat->core, osrelp));
2318249677Strociny	default:
2319249677Strociny		warnx("unknown access method: %d", procstat->type);
2320249677Strociny		return (-1);
2321249677Strociny	}
2322249677Strociny}
2323249681Strociny
2324249681Strociny#define PROC_AUXV_MAX	256
2325249681Strociny
2326249681Strociny#if __ELF_WORD_SIZE == 64
2327249681Strocinystatic const char *elf32_sv_names[] = {
2328249681Strociny	"Linux ELF32",
2329249681Strociny	"FreeBSD ELF32",
2330249681Strociny};
2331249681Strociny
2332249681Strocinystatic int
2333249681Strocinyis_elf32_sysctl(pid_t pid)
2334249681Strociny{
2335249681Strociny	int error, name[4];
2336249681Strociny	size_t len, i;
2337249681Strociny	static char sv_name[256];
2338249681Strociny
2339249681Strociny	name[0] = CTL_KERN;
2340249681Strociny	name[1] = KERN_PROC;
2341249681Strociny	name[2] = KERN_PROC_SV_NAME;
2342249681Strociny	name[3] = pid;
2343249681Strociny	len = sizeof(sv_name);
2344312036Sngie	error = sysctl(name, nitems(name), sv_name, &len, NULL, 0);
2345249681Strociny	if (error != 0 || len == 0)
2346249681Strociny		return (0);
2347249681Strociny	for (i = 0; i < sizeof(elf32_sv_names) / sizeof(*elf32_sv_names); i++) {
2348249681Strociny		if (strncmp(sv_name, elf32_sv_names[i], sizeof(sv_name)) == 0)
2349249681Strociny			return (1);
2350249681Strociny	}
2351249681Strociny	return (0);
2352249681Strociny}
2353249681Strociny
2354249681Strocinystatic Elf_Auxinfo *
2355249681Strocinyprocstat_getauxv32_sysctl(pid_t pid, unsigned int *cntp)
2356249681Strociny{
2357249681Strociny	Elf_Auxinfo *auxv;
2358249681Strociny	Elf32_Auxinfo *auxv32;
2359249681Strociny	void *ptr;
2360249681Strociny	size_t len;
2361249681Strociny	unsigned int i, count;
2362249681Strociny	int name[4];
2363249681Strociny
2364249681Strociny	name[0] = CTL_KERN;
2365249681Strociny	name[1] = KERN_PROC;
2366249681Strociny	name[2] = KERN_PROC_AUXV;
2367249681Strociny	name[3] = pid;
2368249681Strociny	len = PROC_AUXV_MAX * sizeof(Elf32_Auxinfo);
2369249681Strociny	auxv = NULL;
2370249681Strociny	auxv32 = malloc(len);
2371249681Strociny	if (auxv32 == NULL) {
2372249681Strociny		warn("malloc(%zu)", len);
2373249681Strociny		goto out;
2374249681Strociny	}
2375312036Sngie	if (sysctl(name, nitems(name), auxv32, &len, NULL, 0) == -1) {
2376249681Strociny		if (errno != ESRCH && errno != EPERM)
2377249681Strociny			warn("sysctl: kern.proc.auxv: %d: %d", pid, errno);
2378249681Strociny		goto out;
2379249681Strociny	}
2380249681Strociny	count = len / sizeof(Elf_Auxinfo);
2381249681Strociny	auxv = malloc(count  * sizeof(Elf_Auxinfo));
2382249681Strociny	if (auxv == NULL) {
2383249681Strociny		warn("malloc(%zu)", count * sizeof(Elf_Auxinfo));
2384249681Strociny		goto out;
2385249681Strociny	}
2386249681Strociny	for (i = 0; i < count; i++) {
2387249681Strociny		/*
2388249681Strociny		 * XXX: We expect that values for a_type on a 32-bit platform
2389249681Strociny		 * are directly mapped to values on 64-bit one, which is not
2390249681Strociny		 * necessarily true.
2391249681Strociny		 */
2392249681Strociny		auxv[i].a_type = auxv32[i].a_type;
2393249681Strociny		ptr = &auxv32[i].a_un;
2394249681Strociny		auxv[i].a_un.a_val = *((uint32_t *)ptr);
2395249681Strociny	}
2396249681Strociny	*cntp = count;
2397249681Strocinyout:
2398249681Strociny	free(auxv32);
2399249681Strociny	return (auxv);
2400249681Strociny}
2401249681Strociny#endif /* __ELF_WORD_SIZE == 64 */
2402249681Strociny
2403249681Strocinystatic Elf_Auxinfo *
2404249681Strocinyprocstat_getauxv_sysctl(pid_t pid, unsigned int *cntp)
2405249681Strociny{
2406249681Strociny	Elf_Auxinfo *auxv;
2407249681Strociny	int name[4];
2408249681Strociny	size_t len;
2409249681Strociny
2410249681Strociny#if __ELF_WORD_SIZE == 64
2411249681Strociny	if (is_elf32_sysctl(pid))
2412249681Strociny		return (procstat_getauxv32_sysctl(pid, cntp));
2413249681Strociny#endif
2414249681Strociny	name[0] = CTL_KERN;
2415249681Strociny	name[1] = KERN_PROC;
2416249681Strociny	name[2] = KERN_PROC_AUXV;
2417249681Strociny	name[3] = pid;
2418249681Strociny	len = PROC_AUXV_MAX * sizeof(Elf_Auxinfo);
2419249681Strociny	auxv = malloc(len);
2420249681Strociny	if (auxv == NULL) {
2421249681Strociny		warn("malloc(%zu)", len);
2422249681Strociny		return (NULL);
2423249681Strociny	}
2424312036Sngie	if (sysctl(name, nitems(name), auxv, &len, NULL, 0) == -1) {
2425249681Strociny		if (errno != ESRCH && errno != EPERM)
2426249681Strociny			warn("sysctl: kern.proc.auxv: %d: %d", pid, errno);
2427249681Strociny		free(auxv);
2428249681Strociny		return (NULL);
2429249681Strociny	}
2430249681Strociny	*cntp = len / sizeof(Elf_Auxinfo);
2431249681Strociny	return (auxv);
2432249681Strociny}
2433249681Strociny
2434249681Strocinystatic Elf_Auxinfo *
2435249681Strocinyprocstat_getauxv_core(struct procstat_core *core, unsigned int *cntp)
2436249681Strociny{
2437249681Strociny	Elf_Auxinfo *auxv;
2438249681Strociny	size_t len;
2439249681Strociny
2440249681Strociny	auxv = procstat_core_get(core, PSC_TYPE_AUXV, NULL, &len);
2441249681Strociny	if (auxv == NULL)
2442249681Strociny		return (NULL);
2443249681Strociny	*cntp = len / sizeof(Elf_Auxinfo);
2444249681Strociny	return (auxv);
2445249681Strociny}
2446249681Strociny
2447249681StrocinyElf_Auxinfo *
2448249681Strocinyprocstat_getauxv(struct procstat *procstat, struct kinfo_proc *kp,
2449249681Strociny    unsigned int *cntp)
2450249681Strociny{
2451249681Strociny	switch(procstat->type) {
2452249681Strociny	case PROCSTAT_KVM:
2453249681Strociny		warnx("kvm method is not supported");
2454249681Strociny		return (NULL);
2455249681Strociny	case PROCSTAT_SYSCTL:
2456249681Strociny		return (procstat_getauxv_sysctl(kp->ki_pid, cntp));
2457249681Strociny	case PROCSTAT_CORE:
2458249681Strociny		return (procstat_getauxv_core(procstat->core, cntp));
2459249681Strociny	default:
2460249681Strociny		warnx("unknown access method: %d", procstat->type);
2461249681Strociny		return (NULL);
2462249681Strociny	}
2463249681Strociny}
2464249681Strociny
2465249681Strocinyvoid
2466249681Strocinyprocstat_freeauxv(struct procstat *procstat __unused, Elf_Auxinfo *auxv)
2467249681Strociny{
2468249681Strociny
2469249681Strociny	free(auxv);
2470249681Strociny}
2471249684Strociny
2472249684Strocinystatic struct kinfo_kstack *
2473249684Strocinyprocstat_getkstack_sysctl(pid_t pid, int *cntp)
2474249684Strociny{
2475249684Strociny	struct kinfo_kstack *kkstp;
2476249684Strociny	int error, name[4];
2477249684Strociny	size_t len;
2478249684Strociny
2479249684Strociny	name[0] = CTL_KERN;
2480249684Strociny	name[1] = KERN_PROC;
2481249684Strociny	name[2] = KERN_PROC_KSTACK;
2482249684Strociny	name[3] = pid;
2483249684Strociny
2484249684Strociny	len = 0;
2485312036Sngie	error = sysctl(name, nitems(name), NULL, &len, NULL, 0);
2486249684Strociny	if (error < 0 && errno != ESRCH && errno != EPERM && errno != ENOENT) {
2487249684Strociny		warn("sysctl: kern.proc.kstack: %d", pid);
2488249684Strociny		return (NULL);
2489249684Strociny	}
2490249684Strociny	if (error == -1 && errno == ENOENT) {
2491249684Strociny		warnx("sysctl: kern.proc.kstack unavailable"
2492249684Strociny		    " (options DDB or options STACK required in kernel)");
2493249684Strociny		return (NULL);
2494249684Strociny	}
2495249684Strociny	if (error == -1)
2496249684Strociny		return (NULL);
2497249684Strociny	kkstp = malloc(len);
2498249684Strociny	if (kkstp == NULL) {
2499249684Strociny		warn("malloc(%zu)", len);
2500249684Strociny		return (NULL);
2501249684Strociny	}
2502312036Sngie	if (sysctl(name, nitems(name), kkstp, &len, NULL, 0) == -1) {
2503249684Strociny		warn("sysctl: kern.proc.pid: %d", pid);
2504249684Strociny		free(kkstp);
2505249684Strociny		return (NULL);
2506249684Strociny	}
2507249684Strociny	*cntp = len / sizeof(*kkstp);
2508249684Strociny
2509249684Strociny	return (kkstp);
2510249684Strociny}
2511249684Strociny
2512249684Strocinystruct kinfo_kstack *
2513249684Strocinyprocstat_getkstack(struct procstat *procstat, struct kinfo_proc *kp,
2514249684Strociny    unsigned int *cntp)
2515249684Strociny{
2516249684Strociny	switch(procstat->type) {
2517249684Strociny	case PROCSTAT_KVM:
2518249684Strociny		warnx("kvm method is not supported");
2519249684Strociny		return (NULL);
2520249684Strociny	case PROCSTAT_SYSCTL:
2521249684Strociny		return (procstat_getkstack_sysctl(kp->ki_pid, cntp));
2522249684Strociny	case PROCSTAT_CORE:
2523249684Strociny		warnx("core method is not supported");
2524249684Strociny		return (NULL);
2525249684Strociny	default:
2526249684Strociny		warnx("unknown access method: %d", procstat->type);
2527249684Strociny		return (NULL);
2528249684Strociny	}
2529249684Strociny}
2530249684Strociny
2531249684Strocinyvoid
2532249684Strocinyprocstat_freekstack(struct procstat *procstat __unused,
2533249684Strociny    struct kinfo_kstack *kkstp)
2534249684Strociny{
2535249684Strociny
2536249684Strociny	free(kkstp);
2537249684Strociny}
2538