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