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$");
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>
64256242Spjd#include <sys/capability.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;
285221807Sstas		error = sysctl(name, 4, 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;
302251637Sjhb			error = sysctl(name, 4, 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;
770249666Strociny		bp += kf->kf_structsize;
771249666Strociny		cnt++;
772249666Strociny	}
773249666Strociny
774249666Strociny	kif = calloc(cnt, sizeof(*kif));
775249666Strociny	if (kif == NULL) {
776249666Strociny		free(buf);
777249666Strociny		return (NULL);
778249666Strociny	}
779249666Strociny	bp = buf;
780249666Strociny	eb = buf + len;
781249666Strociny	kp = kif;
782249666Strociny	/* Pass 2: unpack */
783249666Strociny	while (bp < eb) {
784249666Strociny		kf = (struct kinfo_file *)(uintptr_t)bp;
785249666Strociny		/* Copy/expand into pre-zeroed buffer */
786249666Strociny		memcpy(kp, kf, kf->kf_structsize);
787249666Strociny		/* Advance to next packed record */
788249666Strociny		bp += kf->kf_structsize;
789249666Strociny		/* Set field size to fixed length, advance */
790249666Strociny		kp->kf_structsize = sizeof(*kp);
791249666Strociny		kp++;
792249666Strociny	}
793249666Strociny	free(buf);
794249666Strociny	*cntp = cnt;
795249666Strociny	return (kif);	/* Caller must free() return value */
796249666Strociny}
797249666Strociny
798221807Sstasstatic struct filestat_list *
799249666Strocinyprocstat_getfiles_sysctl(struct procstat *procstat, struct kinfo_proc *kp,
800249666Strociny    int mmapped)
801221807Sstas{
802221807Sstas	struct kinfo_file *kif, *files;
803221807Sstas	struct kinfo_vmentry *kve, *vmentries;
804221807Sstas	struct filestat_list *head;
805221807Sstas	struct filestat *entry;
806221807Sstas	char *path;
807221807Sstas	off_t offset;
808221807Sstas	int cnt, fd, fflags;
809221807Sstas	int i, type, uflags;
810221807Sstas	int refcount;
811224859Srwatson	cap_rights_t cap_rights;
812221807Sstas
813221807Sstas	assert(kp);
814221807Sstas	if (kp->ki_fd == NULL)
815221807Sstas		return (NULL);
816249666Strociny	switch(procstat->type) {
817249666Strociny	case PROCSTAT_SYSCTL:
818249666Strociny		files = kinfo_getfile(kp->ki_pid, &cnt);
819249666Strociny		break;
820249666Strociny	case PROCSTAT_CORE:
821249666Strociny		files = kinfo_getfile_core(procstat->core, &cnt);
822249666Strociny		break;
823249666Strociny	default:
824249666Strociny		assert(!"invalid type");
825249666Strociny	}
826221807Sstas	if (files == NULL && errno != EPERM) {
827221807Sstas		warn("kinfo_getfile()");
828221807Sstas		return (NULL);
829221807Sstas	}
830221807Sstas	procstat->files = files;
831221807Sstas
832221807Sstas	/*
833221807Sstas	 * Allocate list head.
834221807Sstas	 */
835221807Sstas	head = malloc(sizeof(*head));
836221807Sstas	if (head == NULL)
837221807Sstas		return (NULL);
838221807Sstas	STAILQ_INIT(head);
839221807Sstas	for (i = 0; i < cnt; i++) {
840221807Sstas		kif = &files[i];
841221807Sstas
842221807Sstas		type = kinfo_type2fst(kif->kf_type);
843221807Sstas		fd = kif->kf_fd >= 0 ? kif->kf_fd : -1;
844221807Sstas		fflags = kinfo_fflags2fst(kif->kf_flags);
845221807Sstas		uflags = kinfo_uflags2fst(kif->kf_fd);
846221807Sstas		refcount = kif->kf_ref_count;
847221807Sstas		offset = kif->kf_offset;
848221807Sstas		if (*kif->kf_path != '\0')
849221807Sstas			path = strdup(kif->kf_path);
850221807Sstas		else
851221807Sstas			path = NULL;
852224859Srwatson		cap_rights = kif->kf_cap_rights;
853221807Sstas
854221807Sstas		/*
855221807Sstas		 * Create filestat entry.
856221807Sstas		 */
857221807Sstas		entry = filestat_new_entry(kif, type, fd, fflags, uflags,
858255219Spjd		    refcount, offset, path, &cap_rights);
859221807Sstas		if (entry != NULL)
860221807Sstas			STAILQ_INSERT_TAIL(head, entry, next);
861221807Sstas	}
862221807Sstas	if (mmapped != 0) {
863249667Strociny		vmentries = procstat_getvmmap(procstat, kp, &cnt);
864221807Sstas		procstat->vmentries = vmentries;
865221807Sstas		if (vmentries == NULL || cnt == 0)
866221807Sstas			goto fail;
867221807Sstas		for (i = 0; i < cnt; i++) {
868221807Sstas			kve = &vmentries[i];
869221807Sstas			if (kve->kve_type != KVME_TYPE_VNODE)
870221807Sstas				continue;
871221807Sstas			fflags = 0;
872221807Sstas			if (kve->kve_protection & KVME_PROT_READ)
873221807Sstas				fflags = PS_FST_FFLAG_READ;
874223279Sjilles			if ((kve->kve_flags & KVME_FLAG_COW) == 0 &&
875223279Sjilles			    kve->kve_protection & KVME_PROT_WRITE)
876221807Sstas				fflags |= PS_FST_FFLAG_WRITE;
877221807Sstas			offset = kve->kve_offset;
878221807Sstas			refcount = kve->kve_ref_count;
879221807Sstas			if (*kve->kve_path != '\0')
880221807Sstas				path = strdup(kve->kve_path);
881221807Sstas			else
882221807Sstas				path = NULL;
883221807Sstas			entry = filestat_new_entry(kve, PS_FST_TYPE_VNODE, -1,
884224859Srwatson			    fflags, PS_FST_UFLAG_MMAP, refcount, offset, path,
885256242Spjd			    NULL);
886221807Sstas			if (entry != NULL)
887221807Sstas				STAILQ_INSERT_TAIL(head, entry, next);
888221807Sstas		}
889221807Sstas	}
890221807Sstasfail:
891221807Sstas	return (head);
892221807Sstas}
893221807Sstas
894221807Sstasint
895221807Sstasprocstat_get_pipe_info(struct procstat *procstat, struct filestat *fst,
896221807Sstas    struct pipestat *ps, char *errbuf)
897221807Sstas{
898221807Sstas
899221807Sstas	assert(ps);
900221807Sstas	if (procstat->type == PROCSTAT_KVM) {
901221807Sstas		return (procstat_get_pipe_info_kvm(procstat->kd, fst, ps,
902221807Sstas		    errbuf));
903249666Strociny	} else if (procstat->type == PROCSTAT_SYSCTL ||
904249666Strociny		procstat->type == PROCSTAT_CORE) {
905221807Sstas		return (procstat_get_pipe_info_sysctl(fst, ps, errbuf));
906221807Sstas	} else {
907223276Sjilles		warnx("unknown access method: %d", procstat->type);
908250378Strociny		if (errbuf != NULL)
909250378Strociny			snprintf(errbuf, _POSIX2_LINE_MAX, "error");
910221807Sstas		return (1);
911221807Sstas	}
912221807Sstas}
913221807Sstas
914221807Sstasstatic int
915221807Sstasprocstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst,
916221807Sstas    struct pipestat *ps, char *errbuf)
917221807Sstas{
918221807Sstas	struct pipe pi;
919221807Sstas	void *pipep;
920221807Sstas
921221807Sstas	assert(kd);
922221807Sstas	assert(ps);
923221807Sstas	assert(fst);
924221807Sstas	bzero(ps, sizeof(*ps));
925221807Sstas	pipep = fst->fs_typedep;
926221807Sstas	if (pipep == NULL)
927221807Sstas		goto fail;
928221807Sstas	if (!kvm_read_all(kd, (unsigned long)pipep, &pi, sizeof(struct pipe))) {
929221807Sstas		warnx("can't read pipe at %p", (void *)pipep);
930221807Sstas		goto fail;
931221807Sstas	}
932221807Sstas	ps->addr = (uintptr_t)pipep;
933221807Sstas	ps->peer = (uintptr_t)pi.pipe_peer;
934221807Sstas	ps->buffer_cnt = pi.pipe_buffer.cnt;
935221807Sstas	return (0);
936221807Sstas
937221807Sstasfail:
938250378Strociny	if (errbuf != NULL)
939250378Strociny		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
940221807Sstas	return (1);
941221807Sstas}
942221807Sstas
943221807Sstasstatic int
944221807Sstasprocstat_get_pipe_info_sysctl(struct filestat *fst, struct pipestat *ps,
945221807Sstas    char *errbuf __unused)
946221807Sstas{
947221807Sstas	struct kinfo_file *kif;
948221807Sstas
949221807Sstas	assert(ps);
950221807Sstas	assert(fst);
951221807Sstas	bzero(ps, sizeof(*ps));
952221807Sstas	kif = fst->fs_typedep;
953221807Sstas	if (kif == NULL)
954221807Sstas		return (1);
955221807Sstas	ps->addr = kif->kf_un.kf_pipe.kf_pipe_addr;
956221807Sstas	ps->peer = kif->kf_un.kf_pipe.kf_pipe_peer;
957221807Sstas	ps->buffer_cnt = kif->kf_un.kf_pipe.kf_pipe_buffer_cnt;
958221807Sstas	return (0);
959221807Sstas}
960221807Sstas
961221807Sstasint
962221807Sstasprocstat_get_pts_info(struct procstat *procstat, struct filestat *fst,
963221807Sstas    struct ptsstat *pts, char *errbuf)
964221807Sstas{
965221807Sstas
966221807Sstas	assert(pts);
967221807Sstas	if (procstat->type == PROCSTAT_KVM) {
968221807Sstas		return (procstat_get_pts_info_kvm(procstat->kd, fst, pts,
969221807Sstas		    errbuf));
970249666Strociny	} else if (procstat->type == PROCSTAT_SYSCTL ||
971249666Strociny		procstat->type == PROCSTAT_CORE) {
972221807Sstas		return (procstat_get_pts_info_sysctl(fst, pts, errbuf));
973221807Sstas	} else {
974223276Sjilles		warnx("unknown access method: %d", procstat->type);
975250378Strociny		if (errbuf != NULL)
976250378Strociny			snprintf(errbuf, _POSIX2_LINE_MAX, "error");
977221807Sstas		return (1);
978221807Sstas	}
979221807Sstas}
980221807Sstas
981221807Sstasstatic int
982221807Sstasprocstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst,
983221807Sstas    struct ptsstat *pts, char *errbuf)
984221807Sstas{
985221807Sstas	struct tty tty;
986221807Sstas	void *ttyp;
987221807Sstas
988221807Sstas	assert(kd);
989221807Sstas	assert(pts);
990221807Sstas	assert(fst);
991221807Sstas	bzero(pts, sizeof(*pts));
992221807Sstas	ttyp = fst->fs_typedep;
993221807Sstas	if (ttyp == NULL)
994221807Sstas		goto fail;
995221807Sstas	if (!kvm_read_all(kd, (unsigned long)ttyp, &tty, sizeof(struct tty))) {
996221807Sstas		warnx("can't read tty at %p", (void *)ttyp);
997221807Sstas		goto fail;
998221807Sstas	}
999221807Sstas	pts->dev = dev2udev(kd, tty.t_dev);
1000221807Sstas	(void)kdevtoname(kd, tty.t_dev, pts->devname);
1001221807Sstas	return (0);
1002221807Sstas
1003221807Sstasfail:
1004250378Strociny	if (errbuf != NULL)
1005250378Strociny		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1006221807Sstas	return (1);
1007221807Sstas}
1008221807Sstas
1009221807Sstasstatic int
1010221807Sstasprocstat_get_pts_info_sysctl(struct filestat *fst, struct ptsstat *pts,
1011221807Sstas    char *errbuf __unused)
1012221807Sstas{
1013221807Sstas	struct kinfo_file *kif;
1014221807Sstas
1015221807Sstas	assert(pts);
1016221807Sstas	assert(fst);
1017221807Sstas	bzero(pts, sizeof(*pts));
1018221807Sstas	kif = fst->fs_typedep;
1019221807Sstas	if (kif == NULL)
1020221807Sstas		return (0);
1021221807Sstas	pts->dev = kif->kf_un.kf_pts.kf_pts_dev;
1022221807Sstas	strlcpy(pts->devname, kif->kf_path, sizeof(pts->devname));
1023221807Sstas	return (0);
1024221807Sstas}
1025221807Sstas
1026221807Sstasint
1027250223Sjhbprocstat_get_sem_info(struct procstat *procstat, struct filestat *fst,
1028250223Sjhb    struct semstat *sem, char *errbuf)
1029250223Sjhb{
1030250223Sjhb
1031250223Sjhb	assert(sem);
1032250223Sjhb	if (procstat->type == PROCSTAT_KVM) {
1033250223Sjhb		return (procstat_get_sem_info_kvm(procstat->kd, fst, sem,
1034250223Sjhb		    errbuf));
1035250223Sjhb	} else if (procstat->type == PROCSTAT_SYSCTL ||
1036250223Sjhb	    procstat->type == PROCSTAT_CORE) {
1037250223Sjhb		return (procstat_get_sem_info_sysctl(fst, sem, errbuf));
1038250223Sjhb	} else {
1039250223Sjhb		warnx("unknown access method: %d", procstat->type);
1040250378Strociny		if (errbuf != NULL)
1041250378Strociny			snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1042250223Sjhb		return (1);
1043250223Sjhb	}
1044250223Sjhb}
1045250223Sjhb
1046250223Sjhbstatic int
1047250223Sjhbprocstat_get_sem_info_kvm(kvm_t *kd, struct filestat *fst,
1048250223Sjhb    struct semstat *sem, char *errbuf)
1049250223Sjhb{
1050250223Sjhb	struct ksem ksem;
1051250223Sjhb	void *ksemp;
1052250223Sjhb	char *path;
1053250223Sjhb	int i;
1054250223Sjhb
1055250223Sjhb	assert(kd);
1056250223Sjhb	assert(sem);
1057250223Sjhb	assert(fst);
1058250223Sjhb	bzero(sem, sizeof(*sem));
1059250223Sjhb	ksemp = fst->fs_typedep;
1060250223Sjhb	if (ksemp == NULL)
1061250223Sjhb		goto fail;
1062250223Sjhb	if (!kvm_read_all(kd, (unsigned long)ksemp, &ksem,
1063250223Sjhb	    sizeof(struct ksem))) {
1064250223Sjhb		warnx("can't read ksem at %p", (void *)ksemp);
1065250223Sjhb		goto fail;
1066250223Sjhb	}
1067250223Sjhb	sem->mode = S_IFREG | ksem.ks_mode;
1068250223Sjhb	sem->value = ksem.ks_value;
1069250223Sjhb	if (fst->fs_path == NULL && ksem.ks_path != NULL) {
1070250223Sjhb		path = malloc(MAXPATHLEN);
1071250223Sjhb		for (i = 0; i < MAXPATHLEN - 1; i++) {
1072250223Sjhb			if (!kvm_read_all(kd, (unsigned long)ksem.ks_path + i,
1073250223Sjhb			    path + i, 1))
1074250223Sjhb				break;
1075250223Sjhb			if (path[i] == '\0')
1076250223Sjhb				break;
1077250223Sjhb		}
1078250223Sjhb		path[i] = '\0';
1079250223Sjhb		if (i == 0)
1080250223Sjhb			free(path);
1081250223Sjhb		else
1082250223Sjhb			fst->fs_path = path;
1083250223Sjhb	}
1084250223Sjhb	return (0);
1085250223Sjhb
1086250223Sjhbfail:
1087250378Strociny	if (errbuf != NULL)
1088250378Strociny		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1089250223Sjhb	return (1);
1090250223Sjhb}
1091250223Sjhb
1092250223Sjhbstatic int
1093250223Sjhbprocstat_get_sem_info_sysctl(struct filestat *fst, struct semstat *sem,
1094250223Sjhb    char *errbuf __unused)
1095250223Sjhb{
1096250223Sjhb	struct kinfo_file *kif;
1097250223Sjhb
1098250223Sjhb	assert(sem);
1099250223Sjhb	assert(fst);
1100250223Sjhb	bzero(sem, sizeof(*sem));
1101250223Sjhb	kif = fst->fs_typedep;
1102250223Sjhb	if (kif == NULL)
1103250223Sjhb		return (0);
1104250223Sjhb	sem->value = kif->kf_un.kf_sem.kf_sem_value;
1105250223Sjhb	sem->mode = kif->kf_un.kf_sem.kf_sem_mode;
1106250223Sjhb	return (0);
1107250223Sjhb}
1108250223Sjhb
1109250223Sjhbint
1110233760Sjhbprocstat_get_shm_info(struct procstat *procstat, struct filestat *fst,
1111233760Sjhb    struct shmstat *shm, char *errbuf)
1112233760Sjhb{
1113233760Sjhb
1114233760Sjhb	assert(shm);
1115233760Sjhb	if (procstat->type == PROCSTAT_KVM) {
1116233760Sjhb		return (procstat_get_shm_info_kvm(procstat->kd, fst, shm,
1117233760Sjhb		    errbuf));
1118249666Strociny	} else if (procstat->type == PROCSTAT_SYSCTL ||
1119249666Strociny	    procstat->type == PROCSTAT_CORE) {
1120233760Sjhb		return (procstat_get_shm_info_sysctl(fst, shm, errbuf));
1121233760Sjhb	} else {
1122233760Sjhb		warnx("unknown access method: %d", procstat->type);
1123250378Strociny		if (errbuf != NULL)
1124250378Strociny			snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1125233760Sjhb		return (1);
1126233760Sjhb	}
1127233760Sjhb}
1128233760Sjhb
1129233760Sjhbstatic int
1130233760Sjhbprocstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst,
1131233760Sjhb    struct shmstat *shm, char *errbuf)
1132233760Sjhb{
1133233760Sjhb	struct shmfd shmfd;
1134233760Sjhb	void *shmfdp;
1135236717Sjhb	char *path;
1136236717Sjhb	int i;
1137233760Sjhb
1138233760Sjhb	assert(kd);
1139233760Sjhb	assert(shm);
1140233760Sjhb	assert(fst);
1141233760Sjhb	bzero(shm, sizeof(*shm));
1142233760Sjhb	shmfdp = fst->fs_typedep;
1143233760Sjhb	if (shmfdp == NULL)
1144233760Sjhb		goto fail;
1145233760Sjhb	if (!kvm_read_all(kd, (unsigned long)shmfdp, &shmfd,
1146233760Sjhb	    sizeof(struct shmfd))) {
1147233760Sjhb		warnx("can't read shmfd at %p", (void *)shmfdp);
1148233760Sjhb		goto fail;
1149233760Sjhb	}
1150233760Sjhb	shm->mode = S_IFREG | shmfd.shm_mode;
1151233760Sjhb	shm->size = shmfd.shm_size;
1152236717Sjhb	if (fst->fs_path == NULL && shmfd.shm_path != NULL) {
1153236717Sjhb		path = malloc(MAXPATHLEN);
1154236717Sjhb		for (i = 0; i < MAXPATHLEN - 1; i++) {
1155236717Sjhb			if (!kvm_read_all(kd, (unsigned long)shmfd.shm_path + i,
1156236717Sjhb			    path + i, 1))
1157236717Sjhb				break;
1158236717Sjhb			if (path[i] == '\0')
1159236717Sjhb				break;
1160236717Sjhb		}
1161236717Sjhb		path[i] = '\0';
1162236717Sjhb		if (i == 0)
1163236717Sjhb			free(path);
1164236717Sjhb		else
1165236717Sjhb			fst->fs_path = path;
1166236717Sjhb	}
1167233760Sjhb	return (0);
1168233760Sjhb
1169233760Sjhbfail:
1170250378Strociny	if (errbuf != NULL)
1171250378Strociny		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1172233760Sjhb	return (1);
1173233760Sjhb}
1174233760Sjhb
1175233760Sjhbstatic int
1176233760Sjhbprocstat_get_shm_info_sysctl(struct filestat *fst, struct shmstat *shm,
1177233760Sjhb    char *errbuf __unused)
1178233760Sjhb{
1179233760Sjhb	struct kinfo_file *kif;
1180233760Sjhb
1181233760Sjhb	assert(shm);
1182233760Sjhb	assert(fst);
1183233760Sjhb	bzero(shm, sizeof(*shm));
1184233760Sjhb	kif = fst->fs_typedep;
1185233760Sjhb	if (kif == NULL)
1186233760Sjhb		return (0);
1187233760Sjhb	shm->size = kif->kf_un.kf_file.kf_file_size;
1188233760Sjhb	shm->mode = kif->kf_un.kf_file.kf_file_mode;
1189233760Sjhb	return (0);
1190233760Sjhb}
1191233760Sjhb
1192233760Sjhbint
1193221807Sstasprocstat_get_vnode_info(struct procstat *procstat, struct filestat *fst,
1194221807Sstas    struct vnstat *vn, char *errbuf)
1195221807Sstas{
1196221807Sstas
1197221807Sstas	assert(vn);
1198221807Sstas	if (procstat->type == PROCSTAT_KVM) {
1199221807Sstas		return (procstat_get_vnode_info_kvm(procstat->kd, fst, vn,
1200221807Sstas		    errbuf));
1201249666Strociny	} else if (procstat->type == PROCSTAT_SYSCTL ||
1202249666Strociny		procstat->type == PROCSTAT_CORE) {
1203221807Sstas		return (procstat_get_vnode_info_sysctl(fst, vn, errbuf));
1204221807Sstas	} else {
1205223276Sjilles		warnx("unknown access method: %d", procstat->type);
1206250378Strociny		if (errbuf != NULL)
1207250378Strociny			snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1208221807Sstas		return (1);
1209221807Sstas	}
1210221807Sstas}
1211221807Sstas
1212221807Sstasstatic int
1213221807Sstasprocstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst,
1214221807Sstas    struct vnstat *vn, char *errbuf)
1215221807Sstas{
1216221807Sstas	/* Filesystem specific handlers. */
1217221807Sstas	#define FSTYPE(fst)     {#fst, fst##_filestat}
1218221807Sstas	struct {
1219221807Sstas		const char	*tag;
1220221807Sstas		int		(*handler)(kvm_t *kd, struct vnode *vp,
1221221807Sstas		    struct vnstat *vn);
1222221807Sstas	} fstypes[] = {
1223221807Sstas		FSTYPE(devfs),
1224221807Sstas		FSTYPE(isofs),
1225221807Sstas		FSTYPE(msdosfs),
1226221807Sstas		FSTYPE(nfs),
1227252356Sdavide		FSTYPE(smbfs),
1228221807Sstas		FSTYPE(udf),
1229221807Sstas		FSTYPE(ufs),
1230221824Sstas#ifdef LIBPROCSTAT_ZFS
1231221807Sstas		FSTYPE(zfs),
1232221807Sstas#endif
1233221807Sstas	};
1234221807Sstas#define	NTYPES	(sizeof(fstypes) / sizeof(*fstypes))
1235221807Sstas	struct vnode vnode;
1236221807Sstas	char tagstr[12];
1237221807Sstas	void *vp;
1238221807Sstas	int error, found;
1239221807Sstas	unsigned int i;
1240221807Sstas
1241221807Sstas	assert(kd);
1242221807Sstas	assert(vn);
1243221807Sstas	assert(fst);
1244221807Sstas	vp = fst->fs_typedep;
1245221807Sstas	if (vp == NULL)
1246221807Sstas		goto fail;
1247221807Sstas	error = kvm_read_all(kd, (unsigned long)vp, &vnode, sizeof(vnode));
1248221807Sstas	if (error == 0) {
1249221807Sstas		warnx("can't read vnode at %p", (void *)vp);
1250221807Sstas		goto fail;
1251221807Sstas	}
1252221807Sstas	bzero(vn, sizeof(*vn));
1253221807Sstas	vn->vn_type = vntype2psfsttype(vnode.v_type);
1254221807Sstas	if (vnode.v_type == VNON || vnode.v_type == VBAD)
1255221807Sstas		return (0);
1256221807Sstas	error = kvm_read_all(kd, (unsigned long)vnode.v_tag, tagstr,
1257221807Sstas	    sizeof(tagstr));
1258221807Sstas	if (error == 0) {
1259221807Sstas		warnx("can't read v_tag at %p", (void *)vp);
1260221807Sstas		goto fail;
1261221807Sstas	}
1262221807Sstas	tagstr[sizeof(tagstr) - 1] = '\0';
1263221807Sstas
1264221807Sstas	/*
1265221807Sstas	 * Find appropriate handler.
1266221807Sstas	 */
1267221807Sstas	for (i = 0, found = 0; i < NTYPES; i++)
1268221807Sstas		if (!strcmp(fstypes[i].tag, tagstr)) {
1269221807Sstas			if (fstypes[i].handler(kd, &vnode, vn) != 0) {
1270221807Sstas				goto fail;
1271221807Sstas			}
1272221807Sstas			break;
1273221807Sstas		}
1274221807Sstas	if (i == NTYPES) {
1275250378Strociny		if (errbuf != NULL)
1276250378Strociny			snprintf(errbuf, _POSIX2_LINE_MAX, "?(%s)", tagstr);
1277221807Sstas		return (1);
1278221807Sstas	}
1279221807Sstas	vn->vn_mntdir = getmnton(kd, vnode.v_mount);
1280221807Sstas	if ((vnode.v_type == VBLK || vnode.v_type == VCHR) &&
1281221807Sstas	    vnode.v_rdev != NULL){
1282221807Sstas		vn->vn_dev = dev2udev(kd, vnode.v_rdev);
1283221807Sstas		(void)kdevtoname(kd, vnode.v_rdev, vn->vn_devname);
1284221807Sstas	} else {
1285221807Sstas		vn->vn_dev = -1;
1286221807Sstas	}
1287221807Sstas	return (0);
1288221807Sstas
1289221807Sstasfail:
1290250378Strociny	if (errbuf != NULL)
1291250378Strociny		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1292221807Sstas	return (1);
1293221807Sstas}
1294221807Sstas
1295221807Sstas/*
1296221807Sstas * kinfo vnode type to filestat translation.
1297221807Sstas */
1298221807Sstasstatic int
1299221807Sstaskinfo_vtype2fst(int kfvtype)
1300221807Sstas{
1301221807Sstas	static struct {
1302221807Sstas		int	kf_vtype;
1303221807Sstas		int	fst_vtype;
1304221807Sstas	} kfvtypes2fst[] = {
1305221807Sstas		{ KF_VTYPE_VBAD, PS_FST_VTYPE_VBAD },
1306221807Sstas		{ KF_VTYPE_VBLK, PS_FST_VTYPE_VBLK },
1307221807Sstas		{ KF_VTYPE_VCHR, PS_FST_VTYPE_VCHR },
1308221807Sstas		{ KF_VTYPE_VDIR, PS_FST_VTYPE_VDIR },
1309221807Sstas		{ KF_VTYPE_VFIFO, PS_FST_VTYPE_VFIFO },
1310221807Sstas		{ KF_VTYPE_VLNK, PS_FST_VTYPE_VLNK },
1311221807Sstas		{ KF_VTYPE_VNON, PS_FST_VTYPE_VNON },
1312221807Sstas		{ KF_VTYPE_VREG, PS_FST_VTYPE_VREG },
1313221807Sstas		{ KF_VTYPE_VSOCK, PS_FST_VTYPE_VSOCK }
1314221807Sstas	};
1315221807Sstas#define	NKFVTYPES	(sizeof(kfvtypes2fst) / sizeof(*kfvtypes2fst))
1316221807Sstas	unsigned int i;
1317221807Sstas
1318221807Sstas	for (i = 0; i < NKFVTYPES; i++)
1319221807Sstas		if (kfvtypes2fst[i].kf_vtype == kfvtype)
1320221807Sstas			break;
1321221807Sstas	if (i == NKFVTYPES)
1322221807Sstas		return (PS_FST_VTYPE_UNKNOWN);
1323221807Sstas	return (kfvtypes2fst[i].fst_vtype);
1324221807Sstas}
1325221807Sstas
1326221807Sstasstatic int
1327221807Sstasprocstat_get_vnode_info_sysctl(struct filestat *fst, struct vnstat *vn,
1328221807Sstas    char *errbuf)
1329221807Sstas{
1330221807Sstas	struct statfs stbuf;
1331221807Sstas	struct kinfo_file *kif;
1332221807Sstas	struct kinfo_vmentry *kve;
1333221807Sstas	uint64_t fileid;
1334221807Sstas	uint64_t size;
1335221807Sstas	char *name, *path;
1336221807Sstas	uint32_t fsid;
1337221807Sstas	uint16_t mode;
1338221807Sstas	uint32_t rdev;
1339221807Sstas	int vntype;
1340221807Sstas	int status;
1341221807Sstas
1342221807Sstas	assert(fst);
1343221807Sstas	assert(vn);
1344221807Sstas	bzero(vn, sizeof(*vn));
1345221807Sstas	if (fst->fs_typedep == NULL)
1346221807Sstas		return (1);
1347221807Sstas	if (fst->fs_uflags & PS_FST_UFLAG_MMAP) {
1348221807Sstas		kve = fst->fs_typedep;
1349221807Sstas		fileid = kve->kve_vn_fileid;
1350221807Sstas		fsid = kve->kve_vn_fsid;
1351221807Sstas		mode = kve->kve_vn_mode;
1352221807Sstas		path = kve->kve_path;
1353221807Sstas		rdev = kve->kve_vn_rdev;
1354221807Sstas		size = kve->kve_vn_size;
1355221807Sstas		vntype = kinfo_vtype2fst(kve->kve_vn_type);
1356221807Sstas		status = kve->kve_status;
1357221807Sstas	} else {
1358221807Sstas		kif = fst->fs_typedep;
1359221807Sstas		fileid = kif->kf_un.kf_file.kf_file_fileid;
1360221807Sstas		fsid = kif->kf_un.kf_file.kf_file_fsid;
1361221807Sstas		mode = kif->kf_un.kf_file.kf_file_mode;
1362221807Sstas		path = kif->kf_path;
1363221807Sstas		rdev = kif->kf_un.kf_file.kf_file_rdev;
1364221807Sstas		size = kif->kf_un.kf_file.kf_file_size;
1365221807Sstas		vntype = kinfo_vtype2fst(kif->kf_vnode_type);
1366221807Sstas		status = kif->kf_status;
1367221807Sstas	}
1368221807Sstas	vn->vn_type = vntype;
1369221807Sstas	if (vntype == PS_FST_VTYPE_VNON || vntype == PS_FST_VTYPE_VBAD)
1370221807Sstas		return (0);
1371221807Sstas	if ((status & KF_ATTR_VALID) == 0) {
1372250378Strociny		if (errbuf != NULL) {
1373250378Strociny			snprintf(errbuf, _POSIX2_LINE_MAX,
1374250378Strociny			    "? (no info available)");
1375250378Strociny		}
1376221807Sstas		return (1);
1377221807Sstas	}
1378221807Sstas	if (path && *path) {
1379221807Sstas		statfs(path, &stbuf);
1380221807Sstas		vn->vn_mntdir = strdup(stbuf.f_mntonname);
1381221807Sstas	} else
1382221807Sstas		vn->vn_mntdir = strdup("-");
1383221807Sstas	vn->vn_dev = rdev;
1384221807Sstas	if (vntype == PS_FST_VTYPE_VBLK) {
1385221807Sstas		name = devname(rdev, S_IFBLK);
1386221807Sstas		if (name != NULL)
1387221807Sstas			strlcpy(vn->vn_devname, name,
1388221807Sstas			    sizeof(vn->vn_devname));
1389221807Sstas	} else if (vntype == PS_FST_VTYPE_VCHR) {
1390221807Sstas		name = devname(vn->vn_dev, S_IFCHR);
1391221807Sstas		if (name != NULL)
1392221807Sstas			strlcpy(vn->vn_devname, name,
1393221807Sstas			    sizeof(vn->vn_devname));
1394221807Sstas	}
1395221807Sstas	vn->vn_fsid = fsid;
1396221807Sstas	vn->vn_fileid = fileid;
1397221807Sstas	vn->vn_size = size;
1398221807Sstas	vn->vn_mode = mode;
1399221807Sstas	return (0);
1400221807Sstas}
1401221807Sstas
1402221807Sstasint
1403221807Sstasprocstat_get_socket_info(struct procstat *procstat, struct filestat *fst,
1404221807Sstas    struct sockstat *sock, char *errbuf)
1405221807Sstas{
1406221807Sstas
1407221807Sstas	assert(sock);
1408221807Sstas	if (procstat->type == PROCSTAT_KVM) {
1409221807Sstas		return (procstat_get_socket_info_kvm(procstat->kd, fst, sock,
1410221807Sstas		    errbuf));
1411249666Strociny	} else if (procstat->type == PROCSTAT_SYSCTL ||
1412249666Strociny		procstat->type == PROCSTAT_CORE) {
1413221807Sstas		return (procstat_get_socket_info_sysctl(fst, sock, errbuf));
1414221807Sstas	} else {
1415223276Sjilles		warnx("unknown access method: %d", procstat->type);
1416250378Strociny		if (errbuf != NULL)
1417250378Strociny			snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1418221807Sstas		return (1);
1419221807Sstas	}
1420221807Sstas}
1421221807Sstas
1422221807Sstasstatic int
1423221807Sstasprocstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst,
1424221807Sstas    struct sockstat *sock, char *errbuf)
1425221807Sstas{
1426221807Sstas	struct domain dom;
1427221807Sstas	struct inpcb inpcb;
1428221807Sstas	struct protosw proto;
1429221807Sstas	struct socket s;
1430221807Sstas	struct unpcb unpcb;
1431221807Sstas	ssize_t len;
1432221807Sstas	void *so;
1433221807Sstas
1434221807Sstas	assert(kd);
1435221807Sstas	assert(sock);
1436221807Sstas	assert(fst);
1437221807Sstas	bzero(sock, sizeof(*sock));
1438221807Sstas	so = fst->fs_typedep;
1439221807Sstas	if (so == NULL)
1440221807Sstas		goto fail;
1441221807Sstas	sock->so_addr = (uintptr_t)so;
1442221807Sstas	/* fill in socket */
1443221807Sstas	if (!kvm_read_all(kd, (unsigned long)so, &s,
1444221807Sstas	    sizeof(struct socket))) {
1445221807Sstas		warnx("can't read sock at %p", (void *)so);
1446221807Sstas		goto fail;
1447221807Sstas	}
1448221807Sstas	/* fill in protosw entry */
1449221807Sstas	if (!kvm_read_all(kd, (unsigned long)s.so_proto, &proto,
1450221807Sstas	    sizeof(struct protosw))) {
1451221807Sstas		warnx("can't read protosw at %p", (void *)s.so_proto);
1452221807Sstas		goto fail;
1453221807Sstas	}
1454221807Sstas	/* fill in domain */
1455221807Sstas	if (!kvm_read_all(kd, (unsigned long)proto.pr_domain, &dom,
1456221807Sstas	    sizeof(struct domain))) {
1457221807Sstas		warnx("can't read domain at %p",
1458221807Sstas		    (void *)proto.pr_domain);
1459221807Sstas		goto fail;
1460221807Sstas	}
1461221807Sstas	if ((len = kvm_read(kd, (unsigned long)dom.dom_name, sock->dname,
1462221807Sstas	    sizeof(sock->dname) - 1)) < 0) {
1463221807Sstas		warnx("can't read domain name at %p", (void *)dom.dom_name);
1464221807Sstas		sock->dname[0] = '\0';
1465221807Sstas	}
1466221807Sstas	else
1467221807Sstas		sock->dname[len] = '\0';
1468221807Sstas
1469221807Sstas	/*
1470221807Sstas	 * Fill in known data.
1471221807Sstas	 */
1472221807Sstas	sock->type = s.so_type;
1473221807Sstas	sock->proto = proto.pr_protocol;
1474221807Sstas	sock->dom_family = dom.dom_family;
1475221807Sstas	sock->so_pcb = (uintptr_t)s.so_pcb;
1476221807Sstas
1477221807Sstas	/*
1478221807Sstas	 * Protocol specific data.
1479221807Sstas	 */
1480221807Sstas	switch(dom.dom_family) {
1481221807Sstas	case AF_INET:
1482221807Sstas	case AF_INET6:
1483221807Sstas		if (proto.pr_protocol == IPPROTO_TCP) {
1484221807Sstas			if (s.so_pcb) {
1485221807Sstas				if (kvm_read(kd, (u_long)s.so_pcb,
1486221807Sstas				    (char *)&inpcb, sizeof(struct inpcb))
1487221807Sstas				    != sizeof(struct inpcb)) {
1488221807Sstas					warnx("can't read inpcb at %p",
1489221807Sstas					    (void *)s.so_pcb);
1490221807Sstas				} else
1491221807Sstas					sock->inp_ppcb =
1492221807Sstas					    (uintptr_t)inpcb.inp_ppcb;
1493221807Sstas			}
1494221807Sstas		}
1495221807Sstas		break;
1496221807Sstas	case AF_UNIX:
1497221807Sstas		if (s.so_pcb) {
1498221807Sstas			if (kvm_read(kd, (u_long)s.so_pcb, (char *)&unpcb,
1499221807Sstas			    sizeof(struct unpcb)) != sizeof(struct unpcb)){
1500221807Sstas				warnx("can't read unpcb at %p",
1501221807Sstas				    (void *)s.so_pcb);
1502221807Sstas			} else if (unpcb.unp_conn) {
1503221807Sstas				sock->so_rcv_sb_state = s.so_rcv.sb_state;
1504221807Sstas				sock->so_snd_sb_state = s.so_snd.sb_state;
1505221807Sstas				sock->unp_conn = (uintptr_t)unpcb.unp_conn;
1506221807Sstas			}
1507221807Sstas		}
1508221807Sstas		break;
1509221807Sstas	default:
1510221807Sstas		break;
1511221807Sstas	}
1512221807Sstas	return (0);
1513221807Sstas
1514221807Sstasfail:
1515250378Strociny	if (errbuf != NULL)
1516250378Strociny		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1517221807Sstas	return (1);
1518221807Sstas}
1519221807Sstas
1520221807Sstasstatic int
1521221807Sstasprocstat_get_socket_info_sysctl(struct filestat *fst, struct sockstat *sock,
1522221807Sstas    char *errbuf __unused)
1523221807Sstas{
1524221807Sstas	struct kinfo_file *kif;
1525221807Sstas
1526221807Sstas	assert(sock);
1527221807Sstas	assert(fst);
1528221807Sstas	bzero(sock, sizeof(*sock));
1529221807Sstas	kif = fst->fs_typedep;
1530221807Sstas	if (kif == NULL)
1531221807Sstas		return (0);
1532221807Sstas
1533221807Sstas	/*
1534221807Sstas	 * Fill in known data.
1535221807Sstas	 */
1536221807Sstas	sock->type = kif->kf_sock_type;
1537221807Sstas	sock->proto = kif->kf_sock_protocol;
1538221807Sstas	sock->dom_family = kif->kf_sock_domain;
1539221807Sstas	sock->so_pcb = kif->kf_un.kf_sock.kf_sock_pcb;
1540221807Sstas	strlcpy(sock->dname, kif->kf_path, sizeof(sock->dname));
1541221807Sstas	bcopy(&kif->kf_sa_local, &sock->sa_local, kif->kf_sa_local.ss_len);
1542221807Sstas	bcopy(&kif->kf_sa_peer, &sock->sa_peer, kif->kf_sa_peer.ss_len);
1543221807Sstas
1544221807Sstas	/*
1545221807Sstas	 * Protocol specific data.
1546221807Sstas	 */
1547221807Sstas	switch(sock->dom_family) {
1548221807Sstas	case AF_INET:
1549221807Sstas	case AF_INET6:
1550221807Sstas		if (sock->proto == IPPROTO_TCP)
1551221807Sstas			sock->inp_ppcb = kif->kf_un.kf_sock.kf_sock_inpcb;
1552221807Sstas		break;
1553221807Sstas	case AF_UNIX:
1554221807Sstas		if (kif->kf_un.kf_sock.kf_sock_unpconn != 0) {
1555221807Sstas				sock->so_rcv_sb_state =
1556221807Sstas				    kif->kf_un.kf_sock.kf_sock_rcv_sb_state;
1557221807Sstas				sock->so_snd_sb_state =
1558221807Sstas				    kif->kf_un.kf_sock.kf_sock_snd_sb_state;
1559221807Sstas				sock->unp_conn =
1560221807Sstas				    kif->kf_un.kf_sock.kf_sock_unpconn;
1561221807Sstas		}
1562221807Sstas		break;
1563221807Sstas	default:
1564221807Sstas		break;
1565221807Sstas	}
1566221807Sstas	return (0);
1567221807Sstas}
1568221807Sstas
1569221807Sstas/*
1570221807Sstas * Descriptor flags to filestat translation.
1571221807Sstas */
1572221807Sstasstatic int
1573221807Sstasto_filestat_flags(int flags)
1574221807Sstas{
1575221807Sstas	static struct {
1576221807Sstas		int flag;
1577221807Sstas		int fst_flag;
1578221807Sstas	} fstflags[] = {
1579221807Sstas		{ FREAD, PS_FST_FFLAG_READ },
1580221807Sstas		{ FWRITE, PS_FST_FFLAG_WRITE },
1581221807Sstas		{ O_APPEND, PS_FST_FFLAG_APPEND },
1582221807Sstas		{ O_ASYNC, PS_FST_FFLAG_ASYNC },
1583221807Sstas		{ O_CREAT, PS_FST_FFLAG_CREAT },
1584221807Sstas		{ O_DIRECT, PS_FST_FFLAG_DIRECT },
1585221807Sstas		{ O_EXCL, PS_FST_FFLAG_EXCL },
1586221807Sstas		{ O_EXEC, PS_FST_FFLAG_EXEC },
1587221807Sstas		{ O_EXLOCK, PS_FST_FFLAG_EXLOCK },
1588221807Sstas		{ O_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW },
1589221807Sstas		{ O_NONBLOCK, PS_FST_FFLAG_NONBLOCK },
1590221807Sstas		{ O_SHLOCK, PS_FST_FFLAG_SHLOCK },
1591221807Sstas		{ O_SYNC, PS_FST_FFLAG_SYNC },
1592221807Sstas		{ O_TRUNC, PS_FST_FFLAG_TRUNC }
1593221807Sstas	};
1594221807Sstas#define NFSTFLAGS	(sizeof(fstflags) / sizeof(*fstflags))
1595221807Sstas	int fst_flags;
1596221807Sstas	unsigned int i;
1597221807Sstas
1598221807Sstas	fst_flags = 0;
1599221807Sstas	for (i = 0; i < NFSTFLAGS; i++)
1600221807Sstas		if (flags & fstflags[i].flag)
1601221807Sstas			fst_flags |= fstflags[i].fst_flag;
1602221807Sstas	return (fst_flags);
1603221807Sstas}
1604221807Sstas
1605221807Sstas/*
1606221807Sstas * Vnode type to filestate translation.
1607221807Sstas */
1608221807Sstasstatic int
1609221807Sstasvntype2psfsttype(int type)
1610221807Sstas{
1611221807Sstas	static struct {
1612221807Sstas		int	vtype;
1613221807Sstas		int	fst_vtype;
1614221807Sstas	} vt2fst[] = {
1615221807Sstas		{ VBAD, PS_FST_VTYPE_VBAD },
1616221807Sstas		{ VBLK, PS_FST_VTYPE_VBLK },
1617221807Sstas		{ VCHR, PS_FST_VTYPE_VCHR },
1618221807Sstas		{ VDIR, PS_FST_VTYPE_VDIR },
1619221807Sstas		{ VFIFO, PS_FST_VTYPE_VFIFO },
1620221807Sstas		{ VLNK, PS_FST_VTYPE_VLNK },
1621221807Sstas		{ VNON, PS_FST_VTYPE_VNON },
1622221807Sstas		{ VREG, PS_FST_VTYPE_VREG },
1623221807Sstas		{ VSOCK, PS_FST_VTYPE_VSOCK }
1624221807Sstas	};
1625221807Sstas#define	NVFTYPES	(sizeof(vt2fst) / sizeof(*vt2fst))
1626221807Sstas	unsigned int i, fst_type;
1627221807Sstas
1628221807Sstas	fst_type = PS_FST_VTYPE_UNKNOWN;
1629221807Sstas	for (i = 0; i < NVFTYPES; i++) {
1630221807Sstas		if (type == vt2fst[i].vtype) {
1631221807Sstas			fst_type = vt2fst[i].fst_vtype;
1632221807Sstas			break;
1633221807Sstas		}
1634221807Sstas	}
1635221807Sstas	return (fst_type);
1636221807Sstas}
1637221807Sstas
1638221807Sstasstatic char *
1639221807Sstasgetmnton(kvm_t *kd, struct mount *m)
1640221807Sstas{
1641223262Sbenl	struct mount mnt;
1642221807Sstas	static struct mtab {
1643221807Sstas		struct mtab *next;
1644221807Sstas		struct mount *m;
1645221807Sstas		char mntonname[MNAMELEN + 1];
1646221807Sstas	} *mhead = NULL;
1647221807Sstas	struct mtab *mt;
1648221807Sstas
1649221807Sstas	for (mt = mhead; mt != NULL; mt = mt->next)
1650221807Sstas		if (m == mt->m)
1651221807Sstas			return (mt->mntonname);
1652221807Sstas	if (!kvm_read_all(kd, (unsigned long)m, &mnt, sizeof(struct mount))) {
1653221807Sstas		warnx("can't read mount table at %p", (void *)m);
1654221807Sstas		return (NULL);
1655221807Sstas	}
1656221807Sstas	if ((mt = malloc(sizeof (struct mtab))) == NULL)
1657221807Sstas		err(1, NULL);
1658221807Sstas	mt->m = m;
1659221807Sstas	bcopy(&mnt.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN);
1660223262Sbenl	mt->mntonname[MNAMELEN] = '\0';
1661221807Sstas	mt->next = mhead;
1662221807Sstas	mhead = mt;
1663221807Sstas	return (mt->mntonname);
1664221807Sstas}
1665249666Strociny
1666249679Strociny/*
1667249679Strociny * Auxiliary structures and functions to get process environment or
1668249679Strociny * command line arguments.
1669249679Strociny */
1670249679Strocinystruct argvec {
1671249679Strociny	char	*buf;
1672249679Strociny	size_t	bufsize;
1673249679Strociny	char	**argv;
1674249679Strociny	size_t	argc;
1675249679Strociny};
1676249679Strociny
1677249679Strocinystatic struct argvec *
1678249679Strocinyargvec_alloc(size_t bufsize)
1679249679Strociny{
1680249679Strociny	struct argvec *av;
1681249679Strociny
1682249679Strociny	av = malloc(sizeof(*av));
1683249679Strociny	if (av == NULL)
1684249679Strociny		return (NULL);
1685249679Strociny	av->bufsize = bufsize;
1686249679Strociny	av->buf = malloc(av->bufsize);
1687249679Strociny	if (av->buf == NULL) {
1688249679Strociny		free(av);
1689249679Strociny		return (NULL);
1690249679Strociny	}
1691249679Strociny	av->argc = 32;
1692249679Strociny	av->argv = malloc(sizeof(char *) * av->argc);
1693249679Strociny	if (av->argv == NULL) {
1694249679Strociny		free(av->buf);
1695249679Strociny		free(av);
1696249679Strociny		return (NULL);
1697249679Strociny	}
1698249679Strociny	return av;
1699249679Strociny}
1700249679Strociny
1701249679Strocinystatic void
1702249679Strocinyargvec_free(struct argvec * av)
1703249679Strociny{
1704249679Strociny
1705249679Strociny	free(av->argv);
1706249679Strociny	free(av->buf);
1707249679Strociny	free(av);
1708249679Strociny}
1709249679Strociny
1710249679Strocinystatic char **
1711249679Strocinygetargv(struct procstat *procstat, struct kinfo_proc *kp, size_t nchr, int env)
1712249679Strociny{
1713249679Strociny	int error, name[4], argc, i;
1714249679Strociny	struct argvec *av, **avp;
1715249679Strociny	enum psc_type type;
1716249679Strociny	size_t len;
1717249679Strociny	char *p, **argv;
1718249679Strociny
1719249679Strociny	assert(procstat);
1720249679Strociny	assert(kp);
1721249679Strociny	if (procstat->type == PROCSTAT_KVM) {
1722249679Strociny		warnx("can't use kvm access method");
1723249679Strociny		return (NULL);
1724249679Strociny	}
1725249679Strociny	if (procstat->type != PROCSTAT_SYSCTL &&
1726249679Strociny	    procstat->type != PROCSTAT_CORE) {
1727249679Strociny		warnx("unknown access method: %d", procstat->type);
1728249679Strociny		return (NULL);
1729249679Strociny	}
1730249679Strociny
1731249679Strociny	if (nchr == 0 || nchr > ARG_MAX)
1732249679Strociny		nchr = ARG_MAX;
1733249679Strociny
1734249679Strociny	avp = (struct argvec **)(env ? &procstat->argv : &procstat->envv);
1735249679Strociny	av = *avp;
1736249679Strociny
1737249679Strociny	if (av == NULL)
1738249679Strociny	{
1739249679Strociny		av = argvec_alloc(nchr);
1740249679Strociny		if (av == NULL)
1741249679Strociny		{
1742249679Strociny			warn("malloc(%zu)", nchr);
1743249679Strociny			return (NULL);
1744249679Strociny		}
1745249679Strociny		*avp = av;
1746249679Strociny	} else if (av->bufsize < nchr) {
1747249679Strociny		av->buf = reallocf(av->buf, nchr);
1748249679Strociny		if (av->buf == NULL) {
1749249679Strociny			warn("malloc(%zu)", nchr);
1750249679Strociny			return (NULL);
1751249679Strociny		}
1752249679Strociny	}
1753249679Strociny	if (procstat->type == PROCSTAT_SYSCTL) {
1754249679Strociny		name[0] = CTL_KERN;
1755249679Strociny		name[1] = KERN_PROC;
1756249679Strociny		name[2] = env ? KERN_PROC_ENV : KERN_PROC_ARGS;
1757249679Strociny		name[3] = kp->ki_pid;
1758249679Strociny		len = nchr;
1759249679Strociny		error = sysctl(name, 4, av->buf, &len, NULL, 0);
1760249679Strociny		if (error != 0 && errno != ESRCH && errno != EPERM)
1761249679Strociny			warn("sysctl(kern.proc.%s)", env ? "env" : "args");
1762249679Strociny		if (error != 0 || len == 0)
1763249679Strociny			return (NULL);
1764249679Strociny	} else /* procstat->type == PROCSTAT_CORE */ {
1765249679Strociny		type = env ? PSC_TYPE_ENVV : PSC_TYPE_ARGV;
1766249679Strociny		len = nchr;
1767249679Strociny		if (procstat_core_get(procstat->core, type, av->buf, &len)
1768249679Strociny		    == NULL) {
1769249679Strociny			return (NULL);
1770249679Strociny		}
1771249679Strociny	}
1772249679Strociny
1773249679Strociny	argv = av->argv;
1774249679Strociny	argc = av->argc;
1775249679Strociny	i = 0;
1776249679Strociny	for (p = av->buf; p < av->buf + len; p += strlen(p) + 1) {
1777249679Strociny		argv[i++] = p;
1778249679Strociny		if (i < argc)
1779249679Strociny			continue;
1780249679Strociny		/* Grow argv. */
1781249679Strociny		argc += argc;
1782249679Strociny		argv = realloc(argv, sizeof(char *) * argc);
1783249679Strociny		if (argv == NULL) {
1784249679Strociny			warn("malloc(%zu)", sizeof(char *) * argc);
1785249679Strociny			return (NULL);
1786249679Strociny		}
1787249679Strociny		av->argv = argv;
1788249679Strociny		av->argc = argc;
1789249679Strociny	}
1790249679Strociny	argv[i] = NULL;
1791249679Strociny
1792249679Strociny	return (argv);
1793249679Strociny}
1794249679Strociny
1795249679Strociny/*
1796249679Strociny * Return process command line arguments.
1797249679Strociny */
1798249679Strocinychar **
1799249679Strocinyprocstat_getargv(struct procstat *procstat, struct kinfo_proc *p, size_t nchr)
1800249679Strociny{
1801249679Strociny
1802249679Strociny	return (getargv(procstat, p, nchr, 0));
1803249679Strociny}
1804249679Strociny
1805249679Strociny/*
1806249679Strociny * Free the buffer allocated by procstat_getargv().
1807249679Strociny */
1808249679Strocinyvoid
1809249679Strocinyprocstat_freeargv(struct procstat *procstat)
1810249679Strociny{
1811249679Strociny
1812249679Strociny	if (procstat->argv != NULL) {
1813249679Strociny		argvec_free(procstat->argv);
1814249679Strociny		procstat->argv = NULL;
1815249679Strociny	}
1816249679Strociny}
1817249679Strociny
1818249679Strociny/*
1819249679Strociny * Return process environment.
1820249679Strociny */
1821249679Strocinychar **
1822249679Strocinyprocstat_getenvv(struct procstat *procstat, struct kinfo_proc *p, size_t nchr)
1823249679Strociny{
1824249679Strociny
1825249679Strociny	return (getargv(procstat, p, nchr, 1));
1826249679Strociny}
1827249679Strociny
1828249679Strociny/*
1829249679Strociny * Free the buffer allocated by procstat_getenvv().
1830249679Strociny */
1831249679Strocinyvoid
1832249679Strocinyprocstat_freeenvv(struct procstat *procstat)
1833249679Strociny{
1834249679Strociny	if (procstat->envv != NULL) {
1835249679Strociny		argvec_free(procstat->envv);
1836249679Strociny		procstat->envv = NULL;
1837249679Strociny	}
1838249679Strociny}
1839249679Strociny
1840249667Strocinystatic struct kinfo_vmentry *
1841249667Strocinykinfo_getvmmap_core(struct procstat_core *core, int *cntp)
1842249667Strociny{
1843249667Strociny	int cnt;
1844249667Strociny	size_t len;
1845249667Strociny	char *buf, *bp, *eb;
1846249667Strociny	struct kinfo_vmentry *kiv, *kp, *kv;
1847249667Strociny
1848249667Strociny	buf = procstat_core_get(core, PSC_TYPE_VMMAP, NULL, &len);
1849249667Strociny	if (buf == NULL)
1850249667Strociny		return (NULL);
1851249667Strociny
1852249667Strociny	/*
1853249667Strociny	 * XXXMG: The code below is just copy&past from libutil.
1854249667Strociny	 * The code duplication can be avoided if libutil
1855249667Strociny	 * is extended to provide something like:
1856249667Strociny	 *   struct kinfo_vmentry *kinfo_getvmmap_from_buf(const char *buf,
1857249667Strociny	 *       size_t len, int *cntp);
1858249667Strociny	 */
1859249667Strociny
1860249667Strociny	/* Pass 1: count items */
1861249667Strociny	cnt = 0;
1862249667Strociny	bp = buf;
1863249667Strociny	eb = buf + len;
1864249667Strociny	while (bp < eb) {
1865249667Strociny		kv = (struct kinfo_vmentry *)(uintptr_t)bp;
1866249667Strociny		bp += kv->kve_structsize;
1867249667Strociny		cnt++;
1868249667Strociny	}
1869249667Strociny
1870249667Strociny	kiv = calloc(cnt, sizeof(*kiv));
1871249667Strociny	if (kiv == NULL) {
1872249667Strociny		free(buf);
1873249667Strociny		return (NULL);
1874249667Strociny	}
1875249667Strociny	bp = buf;
1876249667Strociny	eb = buf + len;
1877249667Strociny	kp = kiv;
1878249667Strociny	/* Pass 2: unpack */
1879249667Strociny	while (bp < eb) {
1880249667Strociny		kv = (struct kinfo_vmentry *)(uintptr_t)bp;
1881249667Strociny		/* Copy/expand into pre-zeroed buffer */
1882249667Strociny		memcpy(kp, kv, kv->kve_structsize);
1883249667Strociny		/* Advance to next packed record */
1884249667Strociny		bp += kv->kve_structsize;
1885249667Strociny		/* Set field size to fixed length, advance */
1886249667Strociny		kp->kve_structsize = sizeof(*kp);
1887249667Strociny		kp++;
1888249667Strociny	}
1889249667Strociny	free(buf);
1890249667Strociny	*cntp = cnt;
1891249667Strociny	return (kiv);	/* Caller must free() return value */
1892249667Strociny}
1893249667Strociny
1894249667Strocinystruct kinfo_vmentry *
1895249667Strocinyprocstat_getvmmap(struct procstat *procstat, struct kinfo_proc *kp,
1896249667Strociny    unsigned int *cntp)
1897249667Strociny{
1898249684Strociny
1899249667Strociny	switch(procstat->type) {
1900249667Strociny	case PROCSTAT_KVM:
1901249667Strociny		warnx("kvm method is not supported");
1902249667Strociny		return (NULL);
1903249667Strociny	case PROCSTAT_SYSCTL:
1904249667Strociny		return (kinfo_getvmmap(kp->ki_pid, cntp));
1905249667Strociny	case PROCSTAT_CORE:
1906249667Strociny		return (kinfo_getvmmap_core(procstat->core, cntp));
1907249667Strociny	default:
1908249667Strociny		warnx("unknown access method: %d", procstat->type);
1909249667Strociny		return (NULL);
1910249667Strociny	}
1911249667Strociny}
1912249667Strociny
1913249667Strocinyvoid
1914249667Strocinyprocstat_freevmmap(struct procstat *procstat __unused,
1915249667Strociny    struct kinfo_vmentry *vmmap)
1916249667Strociny{
1917249667Strociny
1918249667Strociny	free(vmmap);
1919249667Strociny}
1920249670Strociny
1921249670Strocinystatic gid_t *
1922250146Strocinyprocstat_getgroups_kvm(kvm_t *kd, struct kinfo_proc *kp, unsigned int *cntp)
1923250146Strociny{
1924250146Strociny	struct proc proc;
1925250146Strociny	struct ucred ucred;
1926250146Strociny	gid_t *groups;
1927250146Strociny	size_t len;
1928250146Strociny
1929250146Strociny	assert(kd != NULL);
1930250146Strociny	assert(kp != NULL);
1931250146Strociny	if (!kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc,
1932250146Strociny	    sizeof(proc))) {
1933250146Strociny		warnx("can't read proc struct at %p for pid %d",
1934250146Strociny		    kp->ki_paddr, kp->ki_pid);
1935250146Strociny		return (NULL);
1936250146Strociny	}
1937250146Strociny	if (proc.p_ucred == NOCRED)
1938250146Strociny		return (NULL);
1939250146Strociny	if (!kvm_read_all(kd, (unsigned long)proc.p_ucred, &ucred,
1940250146Strociny	    sizeof(ucred))) {
1941250146Strociny		warnx("can't read ucred struct at %p for pid %d",
1942250146Strociny		    proc.p_ucred, kp->ki_pid);
1943250146Strociny		return (NULL);
1944250146Strociny	}
1945250146Strociny	len = ucred.cr_ngroups * sizeof(gid_t);
1946250146Strociny	groups = malloc(len);
1947250146Strociny	if (groups == NULL) {
1948250146Strociny		warn("malloc(%zu)", len);
1949250146Strociny		return (NULL);
1950250146Strociny	}
1951250146Strociny	if (!kvm_read_all(kd, (unsigned long)ucred.cr_groups, groups, len)) {
1952250146Strociny		warnx("can't read groups at %p for pid %d",
1953250146Strociny		    ucred.cr_groups, kp->ki_pid);
1954250146Strociny		free(groups);
1955250146Strociny		return (NULL);
1956250146Strociny	}
1957250146Strociny	*cntp = ucred.cr_ngroups;
1958250146Strociny	return (groups);
1959250146Strociny}
1960250146Strociny
1961250146Strocinystatic gid_t *
1962249670Strocinyprocstat_getgroups_sysctl(pid_t pid, unsigned int *cntp)
1963249670Strociny{
1964249670Strociny	int mib[4];
1965249670Strociny	size_t len;
1966249670Strociny	gid_t *groups;
1967249670Strociny
1968249670Strociny	mib[0] = CTL_KERN;
1969249670Strociny	mib[1] = KERN_PROC;
1970249670Strociny	mib[2] = KERN_PROC_GROUPS;
1971249670Strociny	mib[3] = pid;
1972249670Strociny	len = (sysconf(_SC_NGROUPS_MAX) + 1) * sizeof(gid_t);
1973249670Strociny	groups = malloc(len);
1974249670Strociny	if (groups == NULL) {
1975249670Strociny		warn("malloc(%zu)", len);
1976249670Strociny		return (NULL);
1977249670Strociny	}
1978249670Strociny	if (sysctl(mib, 4, groups, &len, NULL, 0) == -1) {
1979249670Strociny		warn("sysctl: kern.proc.groups: %d", pid);
1980249670Strociny		free(groups);
1981249670Strociny		return (NULL);
1982249670Strociny	}
1983249670Strociny	*cntp = len / sizeof(gid_t);
1984249670Strociny	return (groups);
1985249670Strociny}
1986249670Strociny
1987249670Strocinystatic gid_t *
1988249670Strocinyprocstat_getgroups_core(struct procstat_core *core, unsigned int *cntp)
1989249670Strociny{
1990249670Strociny	size_t len;
1991249670Strociny	gid_t *groups;
1992249670Strociny
1993249670Strociny	groups = procstat_core_get(core, PSC_TYPE_GROUPS, NULL, &len);
1994249670Strociny	if (groups == NULL)
1995249670Strociny		return (NULL);
1996249670Strociny	*cntp = len / sizeof(gid_t);
1997249670Strociny	return (groups);
1998249670Strociny}
1999249670Strociny
2000249670Strocinygid_t *
2001249670Strocinyprocstat_getgroups(struct procstat *procstat, struct kinfo_proc *kp,
2002249670Strociny    unsigned int *cntp)
2003249670Strociny{
2004249670Strociny	switch(procstat->type) {
2005249670Strociny	case PROCSTAT_KVM:
2006250146Strociny		return (procstat_getgroups_kvm(procstat->kd, kp, cntp));
2007249670Strociny	case PROCSTAT_SYSCTL:
2008249670Strociny		return (procstat_getgroups_sysctl(kp->ki_pid, cntp));
2009249670Strociny	case PROCSTAT_CORE:
2010249670Strociny		return (procstat_getgroups_core(procstat->core, cntp));
2011249670Strociny	default:
2012249670Strociny		warnx("unknown access method: %d", procstat->type);
2013249670Strociny		return (NULL);
2014249670Strociny	}
2015249670Strociny}
2016249670Strociny
2017249670Strocinyvoid
2018249670Strocinyprocstat_freegroups(struct procstat *procstat __unused, gid_t *groups)
2019249670Strociny{
2020249670Strociny
2021249670Strociny	free(groups);
2022249670Strociny}
2023249672Strociny
2024249672Strocinystatic int
2025250146Strocinyprocstat_getumask_kvm(kvm_t *kd, struct kinfo_proc *kp, unsigned short *maskp)
2026250146Strociny{
2027250146Strociny	struct filedesc fd;
2028250146Strociny
2029250146Strociny	assert(kd != NULL);
2030250146Strociny	assert(kp != NULL);
2031250146Strociny	if (kp->ki_fd == NULL)
2032250146Strociny		return (-1);
2033250146Strociny	if (!kvm_read_all(kd, (unsigned long)kp->ki_fd, &fd, sizeof(fd))) {
2034250146Strociny		warnx("can't read filedesc at %p for pid %d", kp->ki_fd,
2035250146Strociny		    kp->ki_pid);
2036250146Strociny		return (-1);
2037250146Strociny	}
2038250146Strociny	*maskp = fd.fd_cmask;
2039250146Strociny	return (0);
2040250146Strociny}
2041250146Strociny
2042250146Strocinystatic int
2043249672Strocinyprocstat_getumask_sysctl(pid_t pid, unsigned short *maskp)
2044249672Strociny{
2045249672Strociny	int error;
2046249672Strociny	int mib[4];
2047249672Strociny	size_t len;
2048249672Strociny
2049249672Strociny	mib[0] = CTL_KERN;
2050249672Strociny	mib[1] = KERN_PROC;
2051249672Strociny	mib[2] = KERN_PROC_UMASK;
2052249672Strociny	mib[3] = pid;
2053249672Strociny	len = sizeof(*maskp);
2054249672Strociny	error = sysctl(mib, 4, maskp, &len, NULL, 0);
2055262947Srwatson	if (error != 0 && errno != ESRCH && errno != EPERM)
2056249672Strociny		warn("sysctl: kern.proc.umask: %d", pid);
2057249672Strociny	return (error);
2058249672Strociny}
2059249672Strociny
2060249672Strocinystatic int
2061249672Strocinyprocstat_getumask_core(struct procstat_core *core, unsigned short *maskp)
2062249672Strociny{
2063249672Strociny	size_t len;
2064249672Strociny	unsigned short *buf;
2065249672Strociny
2066249672Strociny	buf = procstat_core_get(core, PSC_TYPE_UMASK, NULL, &len);
2067249672Strociny	if (buf == NULL)
2068249672Strociny		return (-1);
2069249672Strociny	if (len < sizeof(*maskp)) {
2070249672Strociny		free(buf);
2071249672Strociny		return (-1);
2072249672Strociny	}
2073249672Strociny	*maskp = *buf;
2074249672Strociny	free(buf);
2075249672Strociny	return (0);
2076249672Strociny}
2077249672Strociny
2078249672Strocinyint
2079249672Strocinyprocstat_getumask(struct procstat *procstat, struct kinfo_proc *kp,
2080249672Strociny    unsigned short *maskp)
2081249672Strociny{
2082249672Strociny	switch(procstat->type) {
2083249672Strociny	case PROCSTAT_KVM:
2084250146Strociny		return (procstat_getumask_kvm(procstat->kd, kp, maskp));
2085249672Strociny	case PROCSTAT_SYSCTL:
2086249672Strociny		return (procstat_getumask_sysctl(kp->ki_pid, maskp));
2087249672Strociny	case PROCSTAT_CORE:
2088249672Strociny		return (procstat_getumask_core(procstat->core, maskp));
2089249672Strociny	default:
2090249672Strociny		warnx("unknown access method: %d", procstat->type);
2091249672Strociny		return (-1);
2092249672Strociny	}
2093249672Strociny}
2094249674Strociny
2095249674Strocinystatic int
2096250146Strocinyprocstat_getrlimit_kvm(kvm_t *kd, struct kinfo_proc *kp, int which,
2097250146Strociny    struct rlimit* rlimit)
2098250146Strociny{
2099250146Strociny	struct proc proc;
2100250146Strociny	unsigned long offset;
2101250146Strociny
2102250146Strociny	assert(kd != NULL);
2103250146Strociny	assert(kp != NULL);
2104250146Strociny	assert(which >= 0 && which < RLIM_NLIMITS);
2105250146Strociny	if (!kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc,
2106250146Strociny	    sizeof(proc))) {
2107250146Strociny		warnx("can't read proc struct at %p for pid %d",
2108250146Strociny		    kp->ki_paddr, kp->ki_pid);
2109250146Strociny		return (-1);
2110250146Strociny	}
2111250146Strociny	if (proc.p_limit == NULL)
2112250146Strociny		return (-1);
2113250146Strociny	offset = (unsigned long)proc.p_limit + sizeof(struct rlimit) * which;
2114250146Strociny	if (!kvm_read_all(kd, offset, rlimit, sizeof(*rlimit))) {
2115250146Strociny		warnx("can't read rlimit struct at %p for pid %d",
2116250146Strociny		    (void *)offset, kp->ki_pid);
2117250146Strociny		return (-1);
2118250146Strociny	}
2119250146Strociny	return (0);
2120250146Strociny}
2121250146Strociny
2122250146Strocinystatic int
2123249674Strocinyprocstat_getrlimit_sysctl(pid_t pid, int which, struct rlimit* rlimit)
2124249674Strociny{
2125249674Strociny	int error, name[5];
2126249674Strociny	size_t len;
2127249674Strociny
2128249674Strociny	name[0] = CTL_KERN;
2129249674Strociny	name[1] = KERN_PROC;
2130249674Strociny	name[2] = KERN_PROC_RLIMIT;
2131249674Strociny	name[3] = pid;
2132249674Strociny	name[4] = which;
2133249674Strociny	len = sizeof(struct rlimit);
2134249674Strociny	error = sysctl(name, 5, rlimit, &len, NULL, 0);
2135249674Strociny	if (error < 0 && errno != ESRCH) {
2136249674Strociny		warn("sysctl: kern.proc.rlimit: %d", pid);
2137249674Strociny		return (-1);
2138249674Strociny	}
2139249674Strociny	if (error < 0 || len != sizeof(struct rlimit))
2140249674Strociny		return (-1);
2141249674Strociny	return (0);
2142249674Strociny}
2143249674Strociny
2144249674Strocinystatic int
2145249674Strocinyprocstat_getrlimit_core(struct procstat_core *core, int which,
2146249674Strociny    struct rlimit* rlimit)
2147249674Strociny{
2148249674Strociny	size_t len;
2149249674Strociny	struct rlimit* rlimits;
2150249674Strociny
2151249674Strociny	if (which < 0 || which >= RLIM_NLIMITS) {
2152249674Strociny		errno = EINVAL;
2153249674Strociny		warn("getrlimit: which");
2154249674Strociny		return (-1);
2155249674Strociny	}
2156249674Strociny	rlimits = procstat_core_get(core, PSC_TYPE_RLIMIT, NULL, &len);
2157249674Strociny	if (rlimits == NULL)
2158249674Strociny		return (-1);
2159249674Strociny	if (len < sizeof(struct rlimit) * RLIM_NLIMITS) {
2160249674Strociny		free(rlimits);
2161249674Strociny		return (-1);
2162249674Strociny	}
2163249674Strociny	*rlimit = rlimits[which];
2164249674Strociny	return (0);
2165249674Strociny}
2166249674Strociny
2167249674Strocinyint
2168249674Strocinyprocstat_getrlimit(struct procstat *procstat, struct kinfo_proc *kp, int which,
2169249674Strociny    struct rlimit* rlimit)
2170249674Strociny{
2171249674Strociny	switch(procstat->type) {
2172249674Strociny	case PROCSTAT_KVM:
2173250146Strociny		return (procstat_getrlimit_kvm(procstat->kd, kp, which,
2174250146Strociny		    rlimit));
2175249674Strociny	case PROCSTAT_SYSCTL:
2176249674Strociny		return (procstat_getrlimit_sysctl(kp->ki_pid, which, rlimit));
2177249674Strociny	case PROCSTAT_CORE:
2178249674Strociny		return (procstat_getrlimit_core(procstat->core, which, rlimit));
2179249674Strociny	default:
2180249674Strociny		warnx("unknown access method: %d", procstat->type);
2181249674Strociny		return (-1);
2182249674Strociny	}
2183249674Strociny}
2184249676Strociny
2185249676Strocinystatic int
2186249676Strocinyprocstat_getpathname_sysctl(pid_t pid, char *pathname, size_t maxlen)
2187249676Strociny{
2188249676Strociny	int error, name[4];
2189249676Strociny	size_t len;
2190249676Strociny
2191249676Strociny	name[0] = CTL_KERN;
2192249676Strociny	name[1] = KERN_PROC;
2193249676Strociny	name[2] = KERN_PROC_PATHNAME;
2194249676Strociny	name[3] = pid;
2195249676Strociny	len = maxlen;
2196249676Strociny	error = sysctl(name, 4, pathname, &len, NULL, 0);
2197249676Strociny	if (error != 0 && errno != ESRCH)
2198249676Strociny		warn("sysctl: kern.proc.pathname: %d", pid);
2199249676Strociny	if (len == 0)
2200249676Strociny		pathname[0] = '\0';
2201249676Strociny	return (error);
2202249676Strociny}
2203249676Strociny
2204249676Strocinystatic int
2205249676Strocinyprocstat_getpathname_core(struct procstat_core *core, char *pathname,
2206249676Strociny    size_t maxlen)
2207249676Strociny{
2208249676Strociny	struct kinfo_file *files;
2209249676Strociny	int cnt, i, result;
2210249676Strociny
2211249676Strociny	files = kinfo_getfile_core(core, &cnt);
2212249676Strociny	if (files == NULL)
2213249676Strociny		return (-1);
2214249676Strociny	result = -1;
2215249676Strociny	for (i = 0; i < cnt; i++) {
2216249676Strociny		if (files[i].kf_fd != KF_FD_TYPE_TEXT)
2217249676Strociny			continue;
2218249676Strociny		strncpy(pathname, files[i].kf_path, maxlen);
2219249676Strociny		result = 0;
2220249676Strociny		break;
2221249676Strociny	}
2222249676Strociny	free(files);
2223249676Strociny	return (result);
2224249676Strociny}
2225249676Strociny
2226249676Strocinyint
2227249676Strocinyprocstat_getpathname(struct procstat *procstat, struct kinfo_proc *kp,
2228249676Strociny    char *pathname, size_t maxlen)
2229249676Strociny{
2230249676Strociny	switch(procstat->type) {
2231249676Strociny	case PROCSTAT_KVM:
2232250147Strociny		/* XXX: Return empty string. */
2233250147Strociny		if (maxlen > 0)
2234250147Strociny			pathname[0] = '\0';
2235250147Strociny		return (0);
2236249676Strociny	case PROCSTAT_SYSCTL:
2237249676Strociny		return (procstat_getpathname_sysctl(kp->ki_pid, pathname,
2238249676Strociny		    maxlen));
2239249676Strociny	case PROCSTAT_CORE:
2240249676Strociny		return (procstat_getpathname_core(procstat->core, pathname,
2241249676Strociny		    maxlen));
2242249676Strociny	default:
2243249676Strociny		warnx("unknown access method: %d", procstat->type);
2244249676Strociny		return (-1);
2245249676Strociny	}
2246249676Strociny}
2247249677Strociny
2248249677Strocinystatic int
2249250146Strocinyprocstat_getosrel_kvm(kvm_t *kd, struct kinfo_proc *kp, int *osrelp)
2250250146Strociny{
2251250146Strociny	struct proc proc;
2252250146Strociny
2253250146Strociny	assert(kd != NULL);
2254250146Strociny	assert(kp != NULL);
2255250146Strociny	if (!kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc,
2256250146Strociny	    sizeof(proc))) {
2257250146Strociny		warnx("can't read proc struct at %p for pid %d",
2258250146Strociny		    kp->ki_paddr, kp->ki_pid);
2259250146Strociny		return (-1);
2260250146Strociny	}
2261250146Strociny	*osrelp = proc.p_osrel;
2262250146Strociny	return (0);
2263250146Strociny}
2264250146Strociny
2265250146Strocinystatic int
2266249677Strocinyprocstat_getosrel_sysctl(pid_t pid, int *osrelp)
2267249677Strociny{
2268249677Strociny	int error, name[4];
2269249677Strociny	size_t len;
2270249677Strociny
2271249677Strociny	name[0] = CTL_KERN;
2272249677Strociny	name[1] = KERN_PROC;
2273249677Strociny	name[2] = KERN_PROC_OSREL;
2274249677Strociny	name[3] = pid;
2275249677Strociny	len = sizeof(*osrelp);
2276249677Strociny	error = sysctl(name, 4, osrelp, &len, NULL, 0);
2277249677Strociny	if (error != 0 && errno != ESRCH)
2278249677Strociny		warn("sysctl: kern.proc.osrel: %d", pid);
2279249677Strociny	return (error);
2280249677Strociny}
2281249677Strociny
2282249677Strocinystatic int
2283249677Strocinyprocstat_getosrel_core(struct procstat_core *core, int *osrelp)
2284249677Strociny{
2285249677Strociny	size_t len;
2286249677Strociny	int *buf;
2287249677Strociny
2288249677Strociny	buf = procstat_core_get(core, PSC_TYPE_OSREL, NULL, &len);
2289249677Strociny	if (buf == NULL)
2290249677Strociny		return (-1);
2291249677Strociny	if (len < sizeof(*osrelp)) {
2292249677Strociny		free(buf);
2293249677Strociny		return (-1);
2294249677Strociny	}
2295249677Strociny	*osrelp = *buf;
2296249677Strociny	free(buf);
2297249677Strociny	return (0);
2298249677Strociny}
2299249677Strociny
2300249677Strocinyint
2301249677Strocinyprocstat_getosrel(struct procstat *procstat, struct kinfo_proc *kp, int *osrelp)
2302249677Strociny{
2303249677Strociny	switch(procstat->type) {
2304249677Strociny	case PROCSTAT_KVM:
2305250146Strociny		return (procstat_getosrel_kvm(procstat->kd, kp, osrelp));
2306249677Strociny	case PROCSTAT_SYSCTL:
2307249677Strociny		return (procstat_getosrel_sysctl(kp->ki_pid, osrelp));
2308249677Strociny	case PROCSTAT_CORE:
2309249677Strociny		return (procstat_getosrel_core(procstat->core, osrelp));
2310249677Strociny	default:
2311249677Strociny		warnx("unknown access method: %d", procstat->type);
2312249677Strociny		return (-1);
2313249677Strociny	}
2314249677Strociny}
2315249681Strociny
2316249681Strociny#define PROC_AUXV_MAX	256
2317249681Strociny
2318249681Strociny#if __ELF_WORD_SIZE == 64
2319249681Strocinystatic const char *elf32_sv_names[] = {
2320249681Strociny	"Linux ELF32",
2321249681Strociny	"FreeBSD ELF32",
2322249681Strociny};
2323249681Strociny
2324249681Strocinystatic int
2325249681Strocinyis_elf32_sysctl(pid_t pid)
2326249681Strociny{
2327249681Strociny	int error, name[4];
2328249681Strociny	size_t len, i;
2329249681Strociny	static char sv_name[256];
2330249681Strociny
2331249681Strociny	name[0] = CTL_KERN;
2332249681Strociny	name[1] = KERN_PROC;
2333249681Strociny	name[2] = KERN_PROC_SV_NAME;
2334249681Strociny	name[3] = pid;
2335249681Strociny	len = sizeof(sv_name);
2336249681Strociny	error = sysctl(name, 4, sv_name, &len, NULL, 0);
2337249681Strociny	if (error != 0 || len == 0)
2338249681Strociny		return (0);
2339249681Strociny	for (i = 0; i < sizeof(elf32_sv_names) / sizeof(*elf32_sv_names); i++) {
2340249681Strociny		if (strncmp(sv_name, elf32_sv_names[i], sizeof(sv_name)) == 0)
2341249681Strociny			return (1);
2342249681Strociny	}
2343249681Strociny	return (0);
2344249681Strociny}
2345249681Strociny
2346249681Strocinystatic Elf_Auxinfo *
2347249681Strocinyprocstat_getauxv32_sysctl(pid_t pid, unsigned int *cntp)
2348249681Strociny{
2349249681Strociny	Elf_Auxinfo *auxv;
2350249681Strociny	Elf32_Auxinfo *auxv32;
2351249681Strociny	void *ptr;
2352249681Strociny	size_t len;
2353249681Strociny	unsigned int i, count;
2354249681Strociny	int name[4];
2355249681Strociny
2356249681Strociny	name[0] = CTL_KERN;
2357249681Strociny	name[1] = KERN_PROC;
2358249681Strociny	name[2] = KERN_PROC_AUXV;
2359249681Strociny	name[3] = pid;
2360249681Strociny	len = PROC_AUXV_MAX * sizeof(Elf32_Auxinfo);
2361249681Strociny	auxv = NULL;
2362249681Strociny	auxv32 = malloc(len);
2363249681Strociny	if (auxv32 == NULL) {
2364249681Strociny		warn("malloc(%zu)", len);
2365249681Strociny		goto out;
2366249681Strociny	}
2367249681Strociny	if (sysctl(name, 4, auxv32, &len, NULL, 0) == -1) {
2368249681Strociny		if (errno != ESRCH && errno != EPERM)
2369249681Strociny			warn("sysctl: kern.proc.auxv: %d: %d", pid, errno);
2370249681Strociny		goto out;
2371249681Strociny	}
2372249681Strociny	count = len / sizeof(Elf_Auxinfo);
2373249681Strociny	auxv = malloc(count  * sizeof(Elf_Auxinfo));
2374249681Strociny	if (auxv == NULL) {
2375249681Strociny		warn("malloc(%zu)", count * sizeof(Elf_Auxinfo));
2376249681Strociny		goto out;
2377249681Strociny	}
2378249681Strociny	for (i = 0; i < count; i++) {
2379249681Strociny		/*
2380249681Strociny		 * XXX: We expect that values for a_type on a 32-bit platform
2381249681Strociny		 * are directly mapped to values on 64-bit one, which is not
2382249681Strociny		 * necessarily true.
2383249681Strociny		 */
2384249681Strociny		auxv[i].a_type = auxv32[i].a_type;
2385249681Strociny		ptr = &auxv32[i].a_un;
2386249681Strociny		auxv[i].a_un.a_val = *((uint32_t *)ptr);
2387249681Strociny	}
2388249681Strociny	*cntp = count;
2389249681Strocinyout:
2390249681Strociny	free(auxv32);
2391249681Strociny	return (auxv);
2392249681Strociny}
2393249681Strociny#endif /* __ELF_WORD_SIZE == 64 */
2394249681Strociny
2395249681Strocinystatic Elf_Auxinfo *
2396249681Strocinyprocstat_getauxv_sysctl(pid_t pid, unsigned int *cntp)
2397249681Strociny{
2398249681Strociny	Elf_Auxinfo *auxv;
2399249681Strociny	int name[4];
2400249681Strociny	size_t len;
2401249681Strociny
2402249681Strociny#if __ELF_WORD_SIZE == 64
2403249681Strociny	if (is_elf32_sysctl(pid))
2404249681Strociny		return (procstat_getauxv32_sysctl(pid, cntp));
2405249681Strociny#endif
2406249681Strociny	name[0] = CTL_KERN;
2407249681Strociny	name[1] = KERN_PROC;
2408249681Strociny	name[2] = KERN_PROC_AUXV;
2409249681Strociny	name[3] = pid;
2410249681Strociny	len = PROC_AUXV_MAX * sizeof(Elf_Auxinfo);
2411249681Strociny	auxv = malloc(len);
2412249681Strociny	if (auxv == NULL) {
2413249681Strociny		warn("malloc(%zu)", len);
2414249681Strociny		return (NULL);
2415249681Strociny	}
2416249681Strociny	if (sysctl(name, 4, auxv, &len, NULL, 0) == -1) {
2417249681Strociny		if (errno != ESRCH && errno != EPERM)
2418249681Strociny			warn("sysctl: kern.proc.auxv: %d: %d", pid, errno);
2419249681Strociny		free(auxv);
2420249681Strociny		return (NULL);
2421249681Strociny	}
2422249681Strociny	*cntp = len / sizeof(Elf_Auxinfo);
2423249681Strociny	return (auxv);
2424249681Strociny}
2425249681Strociny
2426249681Strocinystatic Elf_Auxinfo *
2427249681Strocinyprocstat_getauxv_core(struct procstat_core *core, unsigned int *cntp)
2428249681Strociny{
2429249681Strociny	Elf_Auxinfo *auxv;
2430249681Strociny	size_t len;
2431249681Strociny
2432249681Strociny	auxv = procstat_core_get(core, PSC_TYPE_AUXV, NULL, &len);
2433249681Strociny	if (auxv == NULL)
2434249681Strociny		return (NULL);
2435249681Strociny	*cntp = len / sizeof(Elf_Auxinfo);
2436249681Strociny	return (auxv);
2437249681Strociny}
2438249681Strociny
2439249681StrocinyElf_Auxinfo *
2440249681Strocinyprocstat_getauxv(struct procstat *procstat, struct kinfo_proc *kp,
2441249681Strociny    unsigned int *cntp)
2442249681Strociny{
2443249681Strociny	switch(procstat->type) {
2444249681Strociny	case PROCSTAT_KVM:
2445249681Strociny		warnx("kvm method is not supported");
2446249681Strociny		return (NULL);
2447249681Strociny	case PROCSTAT_SYSCTL:
2448249681Strociny		return (procstat_getauxv_sysctl(kp->ki_pid, cntp));
2449249681Strociny	case PROCSTAT_CORE:
2450249681Strociny		return (procstat_getauxv_core(procstat->core, cntp));
2451249681Strociny	default:
2452249681Strociny		warnx("unknown access method: %d", procstat->type);
2453249681Strociny		return (NULL);
2454249681Strociny	}
2455249681Strociny}
2456249681Strociny
2457249681Strocinyvoid
2458249681Strocinyprocstat_freeauxv(struct procstat *procstat __unused, Elf_Auxinfo *auxv)
2459249681Strociny{
2460249681Strociny
2461249681Strociny	free(auxv);
2462249681Strociny}
2463249684Strociny
2464249684Strocinystatic struct kinfo_kstack *
2465249684Strocinyprocstat_getkstack_sysctl(pid_t pid, int *cntp)
2466249684Strociny{
2467249684Strociny	struct kinfo_kstack *kkstp;
2468249684Strociny	int error, name[4];
2469249684Strociny	size_t len;
2470249684Strociny
2471249684Strociny	name[0] = CTL_KERN;
2472249684Strociny	name[1] = KERN_PROC;
2473249684Strociny	name[2] = KERN_PROC_KSTACK;
2474249684Strociny	name[3] = pid;
2475249684Strociny
2476249684Strociny	len = 0;
2477249684Strociny	error = sysctl(name, 4, NULL, &len, NULL, 0);
2478249684Strociny	if (error < 0 && errno != ESRCH && errno != EPERM && errno != ENOENT) {
2479249684Strociny		warn("sysctl: kern.proc.kstack: %d", pid);
2480249684Strociny		return (NULL);
2481249684Strociny	}
2482249684Strociny	if (error == -1 && errno == ENOENT) {
2483249684Strociny		warnx("sysctl: kern.proc.kstack unavailable"
2484249684Strociny		    " (options DDB or options STACK required in kernel)");
2485249684Strociny		return (NULL);
2486249684Strociny	}
2487249684Strociny	if (error == -1)
2488249684Strociny		return (NULL);
2489249684Strociny	kkstp = malloc(len);
2490249684Strociny	if (kkstp == NULL) {
2491249684Strociny		warn("malloc(%zu)", len);
2492249684Strociny		return (NULL);
2493249684Strociny	}
2494249684Strociny	if (sysctl(name, 4, kkstp, &len, NULL, 0) == -1) {
2495249684Strociny		warn("sysctl: kern.proc.pid: %d", pid);
2496249684Strociny		free(kkstp);
2497249684Strociny		return (NULL);
2498249684Strociny	}
2499249684Strociny	*cntp = len / sizeof(*kkstp);
2500249684Strociny
2501249684Strociny	return (kkstp);
2502249684Strociny}
2503249684Strociny
2504249684Strocinystruct kinfo_kstack *
2505249684Strocinyprocstat_getkstack(struct procstat *procstat, struct kinfo_proc *kp,
2506249684Strociny    unsigned int *cntp)
2507249684Strociny{
2508249684Strociny	switch(procstat->type) {
2509249684Strociny	case PROCSTAT_KVM:
2510249684Strociny		warnx("kvm method is not supported");
2511249684Strociny		return (NULL);
2512249684Strociny	case PROCSTAT_SYSCTL:
2513249684Strociny		return (procstat_getkstack_sysctl(kp->ki_pid, cntp));
2514249684Strociny	case PROCSTAT_CORE:
2515249684Strociny		warnx("core method is not supported");
2516249684Strociny		return (NULL);
2517249684Strociny	default:
2518249684Strociny		warnx("unknown access method: %d", procstat->type);
2519249684Strociny		return (NULL);
2520249684Strociny	}
2521249684Strociny}
2522249684Strociny
2523249684Strocinyvoid
2524249684Strocinyprocstat_freekstack(struct procstat *procstat __unused,
2525249684Strociny    struct kinfo_kstack *kkstp)
2526249684Strociny{
2527249684Strociny
2528249684Strociny	free(kkstp);
2529249684Strociny}
2530