libprocstat.c revision 233760
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 233760 2012-04-01 18:22:48Z jhb $");
37
38#include <sys/param.h>
39#include <sys/time.h>
40#include <sys/proc.h>
41#include <sys/user.h>
42#include <sys/stat.h>
43#include <sys/vnode.h>
44#include <sys/socket.h>
45#include <sys/socketvar.h>
46#include <sys/domain.h>
47#include <sys/protosw.h>
48#include <sys/un.h>
49#include <sys/unpcb.h>
50#include <sys/sysctl.h>
51#include <sys/tty.h>
52#include <sys/filedesc.h>
53#include <sys/queue.h>
54#define	_WANT_FILE
55#include <sys/file.h>
56#include <sys/conf.h>
57#include <sys/mman.h>
58#define	_KERNEL
59#include <sys/mount.h>
60#include <sys/pipe.h>
61#include <ufs/ufs/quota.h>
62#include <ufs/ufs/inode.h>
63#include <fs/devfs/devfs.h>
64#include <fs/devfs/devfs_int.h>
65#undef _KERNEL
66#include <nfs/nfsproto.h>
67#include <nfsclient/nfs.h>
68#include <nfsclient/nfsnode.h>
69
70#include <vm/vm.h>
71#include <vm/vm_map.h>
72#include <vm/vm_object.h>
73
74#include <net/route.h>
75#include <netinet/in.h>
76#include <netinet/in_systm.h>
77#include <netinet/ip.h>
78#include <netinet/in_pcb.h>
79
80#include <assert.h>
81#include <ctype.h>
82#include <err.h>
83#include <fcntl.h>
84#include <kvm.h>
85#include <libutil.h>
86#include <limits.h>
87#include <paths.h>
88#include <pwd.h>
89#include <stdio.h>
90#include <stdlib.h>
91#include <stddef.h>
92#include <string.h>
93#include <unistd.h>
94#include <netdb.h>
95
96#include <libprocstat.h>
97#include "libprocstat_internal.h"
98#include "common_kvm.h"
99
100int     statfs(const char *, struct statfs *);	/* XXX */
101
102#define	PROCSTAT_KVM	1
103#define	PROCSTAT_SYSCTL	2
104
105static char	*getmnton(kvm_t *kd, struct mount *m);
106static struct filestat_list	*procstat_getfiles_kvm(
107    struct procstat *procstat, struct kinfo_proc *kp, int mmapped);
108static struct filestat_list	*procstat_getfiles_sysctl(
109    struct procstat *procstat, struct kinfo_proc *kp, int mmapped);
110static int	procstat_get_pipe_info_sysctl(struct filestat *fst,
111    struct pipestat *pipe, char *errbuf);
112static int	procstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst,
113    struct pipestat *pipe, char *errbuf);
114static int	procstat_get_pts_info_sysctl(struct filestat *fst,
115    struct ptsstat *pts, char *errbuf);
116static int	procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst,
117    struct ptsstat *pts, char *errbuf);
118static int	procstat_get_shm_info_sysctl(struct filestat *fst,
119    struct shmstat *shm, char *errbuf);
120static int	procstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst,
121    struct shmstat *shm, char *errbuf);
122static int	procstat_get_socket_info_sysctl(struct filestat *fst,
123    struct sockstat *sock, char *errbuf);
124static int	procstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst,
125    struct sockstat *sock, char *errbuf);
126static int	to_filestat_flags(int flags);
127static int	procstat_get_vnode_info_kvm(kvm_t *kd, struct filestat *fst,
128    struct vnstat *vn, char *errbuf);
129static int	procstat_get_vnode_info_sysctl(struct filestat *fst,
130    struct vnstat *vn, char *errbuf);
131static int	vntype2psfsttype(int type);
132
133void
134procstat_close(struct procstat *procstat)
135{
136
137	assert(procstat);
138	if (procstat->type == PROCSTAT_KVM)
139		kvm_close(procstat->kd);
140	free(procstat);
141}
142
143struct procstat *
144procstat_open_sysctl(void)
145{
146	struct procstat *procstat;
147
148	procstat = calloc(1, sizeof(*procstat));
149	if (procstat == NULL) {
150		warn("malloc()");
151		return (NULL);
152	}
153	procstat->type = PROCSTAT_SYSCTL;
154	return (procstat);
155}
156
157struct procstat *
158procstat_open_kvm(const char *nlistf, const char *memf)
159{
160	struct procstat *procstat;
161	kvm_t *kd;
162	char buf[_POSIX2_LINE_MAX];
163
164	procstat = calloc(1, sizeof(*procstat));
165	if (procstat == NULL) {
166		warn("malloc()");
167		return (NULL);
168	}
169	kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf);
170	if (kd == NULL) {
171		warnx("kvm_openfiles(): %s", buf);
172		free(procstat);
173		return (NULL);
174	}
175	procstat->type = PROCSTAT_KVM;
176	procstat->kd = kd;
177	return (procstat);
178}
179
180struct kinfo_proc *
181procstat_getprocs(struct procstat *procstat, int what, int arg,
182    unsigned int *count)
183{
184	struct kinfo_proc *p0, *p;
185	size_t len;
186	int name[4];
187	int error;
188
189	assert(procstat);
190	assert(count);
191	p = NULL;
192	if (procstat->type == PROCSTAT_KVM) {
193		p0 = kvm_getprocs(procstat->kd, what, arg, count);
194		if (p0 == NULL || count == 0)
195			return (NULL);
196		len = *count * sizeof(*p);
197		p = malloc(len);
198		if (p == NULL) {
199			warnx("malloc(%zu)", len);
200			goto fail;
201		}
202		bcopy(p0, p, len);
203		return (p);
204	} else if (procstat->type == PROCSTAT_SYSCTL) {
205		len = 0;
206		name[0] = CTL_KERN;
207		name[1] = KERN_PROC;
208		name[2] = what;
209		name[3] = arg;
210		error = sysctl(name, 4, NULL, &len, NULL, 0);
211		if (error < 0 && errno != EPERM) {
212			warn("sysctl(kern.proc)");
213			goto fail;
214		}
215		if (len == 0) {
216			warnx("no processes?");
217			goto fail;
218		}
219		p = malloc(len);
220		if (p == NULL) {
221			warnx("malloc(%zu)", len);
222			goto fail;
223		}
224		error = sysctl(name, 4, p, &len, NULL, 0);
225		if (error < 0 && errno != EPERM) {
226			warn("sysctl(kern.proc)");
227			goto fail;
228		}
229		/* Perform simple consistency checks. */
230		if ((len % sizeof(*p)) != 0 || p->ki_structsize != sizeof(*p)) {
231			warnx("kinfo_proc structure size mismatch");
232			goto fail;
233		}
234		*count = len / sizeof(*p);
235		return (p);
236	} else {
237		warnx("unknown access method: %d", procstat->type);
238		return (NULL);
239	}
240fail:
241	if (p)
242		free(p);
243	return (NULL);
244}
245
246void
247procstat_freeprocs(struct procstat *procstat __unused, struct kinfo_proc *p)
248{
249
250	if (p != NULL)
251		free(p);
252	p = NULL;
253}
254
255struct filestat_list *
256procstat_getfiles(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
257{
258
259	if (procstat->type == PROCSTAT_SYSCTL)
260		return (procstat_getfiles_sysctl(procstat, kp, mmapped));
261	else if (procstat->type == PROCSTAT_KVM)
262		return (procstat_getfiles_kvm(procstat, kp, mmapped));
263	else
264		return (NULL);
265}
266
267void
268procstat_freefiles(struct procstat *procstat, struct filestat_list *head)
269{
270	struct filestat *fst, *tmp;
271
272	STAILQ_FOREACH_SAFE(fst, head, next, tmp) {
273		if (fst->fs_path != NULL)
274			free(fst->fs_path);
275		free(fst);
276	}
277	free(head);
278	if (procstat->vmentries != NULL) {
279		free(procstat->vmentries);
280		procstat->vmentries = NULL;
281	}
282	if (procstat->files != NULL) {
283		free(procstat->files);
284		procstat->files = NULL;
285	}
286}
287
288static struct filestat *
289filestat_new_entry(void *typedep, int type, int fd, int fflags, int uflags,
290    int refcount, off_t offset, char *path, cap_rights_t cap_rights)
291{
292	struct filestat *entry;
293
294	entry = calloc(1, sizeof(*entry));
295	if (entry == NULL) {
296		warn("malloc()");
297		return (NULL);
298	}
299	entry->fs_typedep = typedep;
300	entry->fs_fflags = fflags;
301	entry->fs_uflags = uflags;
302	entry->fs_fd = fd;
303	entry->fs_type = type;
304	entry->fs_ref_count = refcount;
305	entry->fs_offset = offset;
306	entry->fs_path = path;
307	entry->fs_cap_rights = cap_rights;
308	return (entry);
309}
310
311static struct vnode *
312getctty(kvm_t *kd, struct kinfo_proc *kp)
313{
314	struct pgrp pgrp;
315	struct proc proc;
316	struct session sess;
317	int error;
318
319	assert(kp);
320	error = kvm_read_all(kd, (unsigned long)kp->ki_paddr, &proc,
321	    sizeof(proc));
322	if (error == 0) {
323		warnx("can't read proc struct at %p for pid %d",
324		    kp->ki_paddr, kp->ki_pid);
325		return (NULL);
326	}
327	if (proc.p_pgrp == NULL)
328		return (NULL);
329	error = kvm_read_all(kd, (unsigned long)proc.p_pgrp, &pgrp,
330	    sizeof(pgrp));
331	if (error == 0) {
332		warnx("can't read pgrp struct at %p for pid %d",
333		    proc.p_pgrp, kp->ki_pid);
334		return (NULL);
335	}
336	error = kvm_read_all(kd, (unsigned long)pgrp.pg_session, &sess,
337	    sizeof(sess));
338	if (error == 0) {
339		warnx("can't read session struct at %p for pid %d",
340		    pgrp.pg_session, kp->ki_pid);
341		return (NULL);
342	}
343	return (sess.s_ttyvp);
344}
345
346static struct filestat_list *
347procstat_getfiles_kvm(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
348{
349	struct file file;
350	struct filedesc filed;
351	struct vm_map_entry vmentry;
352	struct vm_object object;
353	struct vmspace vmspace;
354	vm_map_entry_t entryp;
355	vm_map_t map;
356	vm_object_t objp;
357	struct vnode *vp;
358	struct file **ofiles;
359	struct filestat *entry;
360	struct filestat_list *head;
361	kvm_t *kd;
362	void *data;
363	int i, fflags;
364	int prot, type;
365	unsigned int nfiles;
366
367	assert(procstat);
368	kd = procstat->kd;
369	if (kd == NULL)
370		return (NULL);
371	if (kp->ki_fd == NULL)
372		return (NULL);
373	if (!kvm_read_all(kd, (unsigned long)kp->ki_fd, &filed,
374	    sizeof(filed))) {
375		warnx("can't read filedesc at %p", (void *)kp->ki_fd);
376		return (NULL);
377	}
378
379	/*
380	 * Allocate list head.
381	 */
382	head = malloc(sizeof(*head));
383	if (head == NULL)
384		return (NULL);
385	STAILQ_INIT(head);
386
387	/* root directory vnode, if one. */
388	if (filed.fd_rdir) {
389		entry = filestat_new_entry(filed.fd_rdir, PS_FST_TYPE_VNODE, -1,
390		    PS_FST_FFLAG_READ, PS_FST_UFLAG_RDIR, 0, 0, NULL, 0);
391		if (entry != NULL)
392			STAILQ_INSERT_TAIL(head, entry, next);
393	}
394	/* current working directory vnode. */
395	if (filed.fd_cdir) {
396		entry = filestat_new_entry(filed.fd_cdir, PS_FST_TYPE_VNODE, -1,
397		    PS_FST_FFLAG_READ, PS_FST_UFLAG_CDIR, 0, 0, NULL, 0);
398		if (entry != NULL)
399			STAILQ_INSERT_TAIL(head, entry, next);
400	}
401	/* jail root, if any. */
402	if (filed.fd_jdir) {
403		entry = filestat_new_entry(filed.fd_jdir, PS_FST_TYPE_VNODE, -1,
404		    PS_FST_FFLAG_READ, PS_FST_UFLAG_JAIL, 0, 0, NULL, 0);
405		if (entry != NULL)
406			STAILQ_INSERT_TAIL(head, entry, next);
407	}
408	/* ktrace vnode, if one */
409	if (kp->ki_tracep) {
410		entry = filestat_new_entry(kp->ki_tracep, PS_FST_TYPE_VNODE, -1,
411		    PS_FST_FFLAG_READ | PS_FST_FFLAG_WRITE,
412		    PS_FST_UFLAG_TRACE, 0, 0, NULL, 0);
413		if (entry != NULL)
414			STAILQ_INSERT_TAIL(head, entry, next);
415	}
416	/* text vnode, if one */
417	if (kp->ki_textvp) {
418		entry = filestat_new_entry(kp->ki_textvp, PS_FST_TYPE_VNODE, -1,
419		    PS_FST_FFLAG_READ, PS_FST_UFLAG_TEXT, 0, 0, NULL, 0);
420		if (entry != NULL)
421			STAILQ_INSERT_TAIL(head, entry, next);
422	}
423	/* Controlling terminal. */
424	if ((vp = getctty(kd, kp)) != NULL) {
425		entry = filestat_new_entry(vp, PS_FST_TYPE_VNODE, -1,
426		    PS_FST_FFLAG_READ | PS_FST_FFLAG_WRITE,
427		    PS_FST_UFLAG_CTTY, 0, 0, NULL, 0);
428		if (entry != NULL)
429			STAILQ_INSERT_TAIL(head, entry, next);
430	}
431
432	nfiles = filed.fd_lastfile + 1;
433	ofiles = malloc(nfiles * sizeof(struct file *));
434	if (ofiles == NULL) {
435		warn("malloc(%zu)", nfiles * sizeof(struct file *));
436		goto do_mmapped;
437	}
438	if (!kvm_read_all(kd, (unsigned long)filed.fd_ofiles, ofiles,
439	    nfiles * sizeof(struct file *))) {
440		warnx("cannot read file structures at %p",
441		    (void *)filed.fd_ofiles);
442		free(ofiles);
443		goto do_mmapped;
444	}
445	for (i = 0; i <= filed.fd_lastfile; i++) {
446		if (ofiles[i] == NULL)
447			continue;
448		if (!kvm_read_all(kd, (unsigned long)ofiles[i], &file,
449		    sizeof(struct file))) {
450			warnx("can't read file %d at %p", i,
451			    (void *)ofiles[i]);
452			continue;
453		}
454		switch (file.f_type) {
455		case DTYPE_VNODE:
456			type = PS_FST_TYPE_VNODE;
457			data = file.f_vnode;
458			break;
459		case DTYPE_SOCKET:
460			type = PS_FST_TYPE_SOCKET;
461			data = file.f_data;
462			break;
463		case DTYPE_PIPE:
464			type = PS_FST_TYPE_PIPE;
465			data = file.f_data;
466			break;
467		case DTYPE_FIFO:
468			type = PS_FST_TYPE_FIFO;
469			data = file.f_vnode;
470			break;
471#ifdef DTYPE_PTS
472		case DTYPE_PTS:
473			type = PS_FST_TYPE_PTS;
474			data = file.f_data;
475			break;
476#endif
477		case DTYPE_SHM:
478			type = PS_FST_TYPE_SHM;
479			data = file.f_data;
480			break;
481		default:
482			continue;
483		}
484		/* XXXRW: No capability rights support for kvm yet. */
485		entry = filestat_new_entry(data, type, i,
486		    to_filestat_flags(file.f_flag), 0, 0, 0, NULL, 0);
487		if (entry != NULL)
488			STAILQ_INSERT_TAIL(head, entry, next);
489	}
490	free(ofiles);
491
492do_mmapped:
493
494	/*
495	 * Process mmapped files if requested.
496	 */
497	if (mmapped) {
498		if (!kvm_read_all(kd, (unsigned long)kp->ki_vmspace, &vmspace,
499		    sizeof(vmspace))) {
500			warnx("can't read vmspace at %p",
501			    (void *)kp->ki_vmspace);
502			goto exit;
503		}
504		map = &vmspace.vm_map;
505
506		for (entryp = map->header.next;
507		    entryp != &kp->ki_vmspace->vm_map.header;
508		    entryp = vmentry.next) {
509			if (!kvm_read_all(kd, (unsigned long)entryp, &vmentry,
510			    sizeof(vmentry))) {
511				warnx("can't read vm_map_entry at %p",
512				    (void *)entryp);
513				continue;
514			}
515			if (vmentry.eflags & MAP_ENTRY_IS_SUB_MAP)
516				continue;
517			if ((objp = vmentry.object.vm_object) == NULL)
518				continue;
519			for (; objp; objp = object.backing_object) {
520				if (!kvm_read_all(kd, (unsigned long)objp,
521				    &object, sizeof(object))) {
522					warnx("can't read vm_object at %p",
523					    (void *)objp);
524					break;
525				}
526			}
527
528			/* We want only vnode objects. */
529			if (object.type != OBJT_VNODE)
530				continue;
531
532			prot = vmentry.protection;
533			fflags = 0;
534			if (prot & VM_PROT_READ)
535				fflags = PS_FST_FFLAG_READ;
536			if ((vmentry.eflags & MAP_ENTRY_COW) == 0 &&
537			    prot & VM_PROT_WRITE)
538				fflags |= PS_FST_FFLAG_WRITE;
539
540			/*
541			 * Create filestat entry.
542			 */
543			entry = filestat_new_entry(object.handle,
544			    PS_FST_TYPE_VNODE, -1, fflags,
545			    PS_FST_UFLAG_MMAP, 0, 0, NULL, 0);
546			if (entry != NULL)
547				STAILQ_INSERT_TAIL(head, entry, next);
548		}
549	}
550exit:
551	return (head);
552}
553
554/*
555 * kinfo types to filestat translation.
556 */
557static int
558kinfo_type2fst(int kftype)
559{
560	static struct {
561		int	kf_type;
562		int	fst_type;
563	} kftypes2fst[] = {
564		{ KF_TYPE_CRYPTO, PS_FST_TYPE_CRYPTO },
565		{ KF_TYPE_FIFO, PS_FST_TYPE_FIFO },
566		{ KF_TYPE_KQUEUE, PS_FST_TYPE_KQUEUE },
567		{ KF_TYPE_MQUEUE, PS_FST_TYPE_MQUEUE },
568		{ KF_TYPE_NONE, PS_FST_TYPE_NONE },
569		{ KF_TYPE_PIPE, PS_FST_TYPE_PIPE },
570		{ KF_TYPE_PTS, PS_FST_TYPE_PTS },
571		{ KF_TYPE_SEM, PS_FST_TYPE_SEM },
572		{ KF_TYPE_SHM, PS_FST_TYPE_SHM },
573		{ KF_TYPE_SOCKET, PS_FST_TYPE_SOCKET },
574		{ KF_TYPE_VNODE, PS_FST_TYPE_VNODE },
575		{ KF_TYPE_UNKNOWN, PS_FST_TYPE_UNKNOWN }
576	};
577#define NKFTYPES	(sizeof(kftypes2fst) / sizeof(*kftypes2fst))
578	unsigned int i;
579
580	for (i = 0; i < NKFTYPES; i++)
581		if (kftypes2fst[i].kf_type == kftype)
582			break;
583	if (i == NKFTYPES)
584		return (PS_FST_TYPE_UNKNOWN);
585	return (kftypes2fst[i].fst_type);
586}
587
588/*
589 * kinfo flags to filestat translation.
590 */
591static int
592kinfo_fflags2fst(int kfflags)
593{
594	static struct {
595		int	kf_flag;
596		int	fst_flag;
597	} kfflags2fst[] = {
598		{ KF_FLAG_APPEND, PS_FST_FFLAG_APPEND },
599		{ KF_FLAG_ASYNC, PS_FST_FFLAG_ASYNC },
600		{ KF_FLAG_CAPABILITY, PS_FST_FFLAG_CAPABILITY },
601		{ KF_FLAG_CREAT, PS_FST_FFLAG_CREAT },
602		{ KF_FLAG_DIRECT, PS_FST_FFLAG_DIRECT },
603		{ KF_FLAG_EXCL, PS_FST_FFLAG_EXCL },
604		{ KF_FLAG_EXEC, PS_FST_FFLAG_EXEC },
605		{ KF_FLAG_EXLOCK, PS_FST_FFLAG_EXLOCK },
606		{ KF_FLAG_FSYNC, PS_FST_FFLAG_SYNC },
607		{ KF_FLAG_HASLOCK, PS_FST_FFLAG_HASLOCK },
608		{ KF_FLAG_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW },
609		{ KF_FLAG_NONBLOCK, PS_FST_FFLAG_NONBLOCK },
610		{ KF_FLAG_READ, PS_FST_FFLAG_READ },
611		{ KF_FLAG_SHLOCK, PS_FST_FFLAG_SHLOCK },
612		{ KF_FLAG_TRUNC, PS_FST_FFLAG_TRUNC },
613		{ KF_FLAG_WRITE, PS_FST_FFLAG_WRITE }
614	};
615#define NKFFLAGS	(sizeof(kfflags2fst) / sizeof(*kfflags2fst))
616	unsigned int i;
617	int flags;
618
619	flags = 0;
620	for (i = 0; i < NKFFLAGS; i++)
621		if ((kfflags & kfflags2fst[i].kf_flag) != 0)
622			flags |= kfflags2fst[i].fst_flag;
623	return (flags);
624}
625
626static int
627kinfo_uflags2fst(int fd)
628{
629
630	switch (fd) {
631	case KF_FD_TYPE_CTTY:
632		return (PS_FST_UFLAG_CTTY);
633	case KF_FD_TYPE_CWD:
634		return (PS_FST_UFLAG_CDIR);
635	case KF_FD_TYPE_JAIL:
636		return (PS_FST_UFLAG_JAIL);
637	case KF_FD_TYPE_TEXT:
638		return (PS_FST_UFLAG_TEXT);
639	case KF_FD_TYPE_TRACE:
640		return (PS_FST_UFLAG_TRACE);
641	case KF_FD_TYPE_ROOT:
642		return (PS_FST_UFLAG_RDIR);
643	}
644	return (0);
645}
646
647static struct filestat_list *
648procstat_getfiles_sysctl(struct procstat *procstat, struct kinfo_proc *kp, int mmapped)
649{
650	struct kinfo_file *kif, *files;
651	struct kinfo_vmentry *kve, *vmentries;
652	struct filestat_list *head;
653	struct filestat *entry;
654	char *path;
655	off_t offset;
656	int cnt, fd, fflags;
657	int i, type, uflags;
658	int refcount;
659	cap_rights_t cap_rights;
660
661	assert(kp);
662	if (kp->ki_fd == NULL)
663		return (NULL);
664
665	files = kinfo_getfile(kp->ki_pid, &cnt);
666	if (files == NULL && errno != EPERM) {
667		warn("kinfo_getfile()");
668		return (NULL);
669	}
670	procstat->files = files;
671
672	/*
673	 * Allocate list head.
674	 */
675	head = malloc(sizeof(*head));
676	if (head == NULL)
677		return (NULL);
678	STAILQ_INIT(head);
679	for (i = 0; i < cnt; i++) {
680		kif = &files[i];
681
682		type = kinfo_type2fst(kif->kf_type);
683		fd = kif->kf_fd >= 0 ? kif->kf_fd : -1;
684		fflags = kinfo_fflags2fst(kif->kf_flags);
685		uflags = kinfo_uflags2fst(kif->kf_fd);
686		refcount = kif->kf_ref_count;
687		offset = kif->kf_offset;
688		if (*kif->kf_path != '\0')
689			path = strdup(kif->kf_path);
690		else
691			path = NULL;
692		cap_rights = kif->kf_cap_rights;
693
694		/*
695		 * Create filestat entry.
696		 */
697		entry = filestat_new_entry(kif, type, fd, fflags, uflags,
698		    refcount, offset, path, cap_rights);
699		if (entry != NULL)
700			STAILQ_INSERT_TAIL(head, entry, next);
701	}
702	if (mmapped != 0) {
703		vmentries = kinfo_getvmmap(kp->ki_pid, &cnt);
704		procstat->vmentries = vmentries;
705		if (vmentries == NULL || cnt == 0)
706			goto fail;
707		for (i = 0; i < cnt; i++) {
708			kve = &vmentries[i];
709			if (kve->kve_type != KVME_TYPE_VNODE)
710				continue;
711			fflags = 0;
712			if (kve->kve_protection & KVME_PROT_READ)
713				fflags = PS_FST_FFLAG_READ;
714			if ((kve->kve_flags & KVME_FLAG_COW) == 0 &&
715			    kve->kve_protection & KVME_PROT_WRITE)
716				fflags |= PS_FST_FFLAG_WRITE;
717			offset = kve->kve_offset;
718			refcount = kve->kve_ref_count;
719			if (*kve->kve_path != '\0')
720				path = strdup(kve->kve_path);
721			else
722				path = NULL;
723			entry = filestat_new_entry(kve, PS_FST_TYPE_VNODE, -1,
724			    fflags, PS_FST_UFLAG_MMAP, refcount, offset, path,
725			    0);
726			if (entry != NULL)
727				STAILQ_INSERT_TAIL(head, entry, next);
728		}
729	}
730fail:
731	return (head);
732}
733
734int
735procstat_get_pipe_info(struct procstat *procstat, struct filestat *fst,
736    struct pipestat *ps, char *errbuf)
737{
738
739	assert(ps);
740	if (procstat->type == PROCSTAT_KVM) {
741		return (procstat_get_pipe_info_kvm(procstat->kd, fst, ps,
742		    errbuf));
743	} else if (procstat->type == PROCSTAT_SYSCTL) {
744		return (procstat_get_pipe_info_sysctl(fst, ps, errbuf));
745	} else {
746		warnx("unknown access method: %d", procstat->type);
747		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
748		return (1);
749	}
750}
751
752static int
753procstat_get_pipe_info_kvm(kvm_t *kd, struct filestat *fst,
754    struct pipestat *ps, char *errbuf)
755{
756	struct pipe pi;
757	void *pipep;
758
759	assert(kd);
760	assert(ps);
761	assert(fst);
762	bzero(ps, sizeof(*ps));
763	pipep = fst->fs_typedep;
764	if (pipep == NULL)
765		goto fail;
766	if (!kvm_read_all(kd, (unsigned long)pipep, &pi, sizeof(struct pipe))) {
767		warnx("can't read pipe at %p", (void *)pipep);
768		goto fail;
769	}
770	ps->addr = (uintptr_t)pipep;
771	ps->peer = (uintptr_t)pi.pipe_peer;
772	ps->buffer_cnt = pi.pipe_buffer.cnt;
773	return (0);
774
775fail:
776	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
777	return (1);
778}
779
780static int
781procstat_get_pipe_info_sysctl(struct filestat *fst, struct pipestat *ps,
782    char *errbuf __unused)
783{
784	struct kinfo_file *kif;
785
786	assert(ps);
787	assert(fst);
788	bzero(ps, sizeof(*ps));
789	kif = fst->fs_typedep;
790	if (kif == NULL)
791		return (1);
792	ps->addr = kif->kf_un.kf_pipe.kf_pipe_addr;
793	ps->peer = kif->kf_un.kf_pipe.kf_pipe_peer;
794	ps->buffer_cnt = kif->kf_un.kf_pipe.kf_pipe_buffer_cnt;
795	return (0);
796}
797
798int
799procstat_get_pts_info(struct procstat *procstat, struct filestat *fst,
800    struct ptsstat *pts, char *errbuf)
801{
802
803	assert(pts);
804	if (procstat->type == PROCSTAT_KVM) {
805		return (procstat_get_pts_info_kvm(procstat->kd, fst, pts,
806		    errbuf));
807	} else if (procstat->type == PROCSTAT_SYSCTL) {
808		return (procstat_get_pts_info_sysctl(fst, pts, errbuf));
809	} else {
810		warnx("unknown access method: %d", procstat->type);
811		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
812		return (1);
813	}
814}
815
816static int
817procstat_get_pts_info_kvm(kvm_t *kd, struct filestat *fst,
818    struct ptsstat *pts, char *errbuf)
819{
820	struct tty tty;
821	void *ttyp;
822
823	assert(kd);
824	assert(pts);
825	assert(fst);
826	bzero(pts, sizeof(*pts));
827	ttyp = fst->fs_typedep;
828	if (ttyp == NULL)
829		goto fail;
830	if (!kvm_read_all(kd, (unsigned long)ttyp, &tty, sizeof(struct tty))) {
831		warnx("can't read tty at %p", (void *)ttyp);
832		goto fail;
833	}
834	pts->dev = dev2udev(kd, tty.t_dev);
835	(void)kdevtoname(kd, tty.t_dev, pts->devname);
836	return (0);
837
838fail:
839	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
840	return (1);
841}
842
843static int
844procstat_get_pts_info_sysctl(struct filestat *fst, struct ptsstat *pts,
845    char *errbuf __unused)
846{
847	struct kinfo_file *kif;
848
849	assert(pts);
850	assert(fst);
851	bzero(pts, sizeof(*pts));
852	kif = fst->fs_typedep;
853	if (kif == NULL)
854		return (0);
855	pts->dev = kif->kf_un.kf_pts.kf_pts_dev;
856	strlcpy(pts->devname, kif->kf_path, sizeof(pts->devname));
857	return (0);
858}
859
860int
861procstat_get_shm_info(struct procstat *procstat, struct filestat *fst,
862    struct shmstat *shm, char *errbuf)
863{
864
865	assert(shm);
866	if (procstat->type == PROCSTAT_KVM) {
867		return (procstat_get_shm_info_kvm(procstat->kd, fst, shm,
868		    errbuf));
869	} else if (procstat->type == PROCSTAT_SYSCTL) {
870		return (procstat_get_shm_info_sysctl(fst, shm, errbuf));
871	} else {
872		warnx("unknown access method: %d", procstat->type);
873		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
874		return (1);
875	}
876}
877
878static int
879procstat_get_shm_info_kvm(kvm_t *kd, struct filestat *fst,
880    struct shmstat *shm, char *errbuf)
881{
882	struct shmfd shmfd;
883	void *shmfdp;
884
885	assert(kd);
886	assert(shm);
887	assert(fst);
888	bzero(shm, sizeof(*shm));
889	shmfdp = fst->fs_typedep;
890	if (shmfdp == NULL)
891		goto fail;
892	if (!kvm_read_all(kd, (unsigned long)shmfdp, &shmfd,
893	    sizeof(struct shmfd))) {
894		warnx("can't read shmfd at %p", (void *)shmfdp);
895		goto fail;
896	}
897	shm->mode = S_IFREG | shmfd.shm_mode;
898	shm->size = shmfd.shm_size;
899	return (0);
900
901fail:
902	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
903	return (1);
904}
905
906static int
907procstat_get_shm_info_sysctl(struct filestat *fst, struct shmstat *shm,
908    char *errbuf __unused)
909{
910	struct kinfo_file *kif;
911
912	assert(shm);
913	assert(fst);
914	bzero(shm, sizeof(*shm));
915	kif = fst->fs_typedep;
916	if (kif == NULL)
917		return (0);
918	shm->size = kif->kf_un.kf_file.kf_file_size;
919	shm->mode = kif->kf_un.kf_file.kf_file_mode;
920	return (0);
921}
922
923int
924procstat_get_vnode_info(struct procstat *procstat, struct filestat *fst,
925    struct vnstat *vn, char *errbuf)
926{
927
928	assert(vn);
929	if (procstat->type == PROCSTAT_KVM) {
930		return (procstat_get_vnode_info_kvm(procstat->kd, fst, vn,
931		    errbuf));
932	} else if (procstat->type == PROCSTAT_SYSCTL) {
933		return (procstat_get_vnode_info_sysctl(fst, vn, 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_vnode_info_kvm(kvm_t *kd, struct filestat *fst,
943    struct vnstat *vn, char *errbuf)
944{
945	/* Filesystem specific handlers. */
946	#define FSTYPE(fst)     {#fst, fst##_filestat}
947	struct {
948		const char	*tag;
949		int		(*handler)(kvm_t *kd, struct vnode *vp,
950		    struct vnstat *vn);
951	} fstypes[] = {
952		FSTYPE(devfs),
953		FSTYPE(isofs),
954		FSTYPE(msdosfs),
955		FSTYPE(nfs),
956		FSTYPE(ntfs),
957#ifdef LIBPROCSTAT_NWFS
958		FSTYPE(nwfs),
959#endif
960		FSTYPE(smbfs),
961		FSTYPE(udf),
962		FSTYPE(ufs),
963#ifdef LIBPROCSTAT_ZFS
964		FSTYPE(zfs),
965#endif
966	};
967#define	NTYPES	(sizeof(fstypes) / sizeof(*fstypes))
968	struct vnode vnode;
969	char tagstr[12];
970	void *vp;
971	int error, found;
972	unsigned int i;
973
974	assert(kd);
975	assert(vn);
976	assert(fst);
977	vp = fst->fs_typedep;
978	if (vp == NULL)
979		goto fail;
980	error = kvm_read_all(kd, (unsigned long)vp, &vnode, sizeof(vnode));
981	if (error == 0) {
982		warnx("can't read vnode at %p", (void *)vp);
983		goto fail;
984	}
985	bzero(vn, sizeof(*vn));
986	vn->vn_type = vntype2psfsttype(vnode.v_type);
987	if (vnode.v_type == VNON || vnode.v_type == VBAD)
988		return (0);
989	error = kvm_read_all(kd, (unsigned long)vnode.v_tag, tagstr,
990	    sizeof(tagstr));
991	if (error == 0) {
992		warnx("can't read v_tag at %p", (void *)vp);
993		goto fail;
994	}
995	tagstr[sizeof(tagstr) - 1] = '\0';
996
997	/*
998	 * Find appropriate handler.
999	 */
1000	for (i = 0, found = 0; i < NTYPES; i++)
1001		if (!strcmp(fstypes[i].tag, tagstr)) {
1002			if (fstypes[i].handler(kd, &vnode, vn) != 0) {
1003				goto fail;
1004			}
1005			break;
1006		}
1007	if (i == NTYPES) {
1008		snprintf(errbuf, _POSIX2_LINE_MAX, "?(%s)", tagstr);
1009		return (1);
1010	}
1011	vn->vn_mntdir = getmnton(kd, vnode.v_mount);
1012	if ((vnode.v_type == VBLK || vnode.v_type == VCHR) &&
1013	    vnode.v_rdev != NULL){
1014		vn->vn_dev = dev2udev(kd, vnode.v_rdev);
1015		(void)kdevtoname(kd, vnode.v_rdev, vn->vn_devname);
1016	} else {
1017		vn->vn_dev = -1;
1018	}
1019	return (0);
1020
1021fail:
1022	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1023	return (1);
1024}
1025
1026/*
1027 * kinfo vnode type to filestat translation.
1028 */
1029static int
1030kinfo_vtype2fst(int kfvtype)
1031{
1032	static struct {
1033		int	kf_vtype;
1034		int	fst_vtype;
1035	} kfvtypes2fst[] = {
1036		{ KF_VTYPE_VBAD, PS_FST_VTYPE_VBAD },
1037		{ KF_VTYPE_VBLK, PS_FST_VTYPE_VBLK },
1038		{ KF_VTYPE_VCHR, PS_FST_VTYPE_VCHR },
1039		{ KF_VTYPE_VDIR, PS_FST_VTYPE_VDIR },
1040		{ KF_VTYPE_VFIFO, PS_FST_VTYPE_VFIFO },
1041		{ KF_VTYPE_VLNK, PS_FST_VTYPE_VLNK },
1042		{ KF_VTYPE_VNON, PS_FST_VTYPE_VNON },
1043		{ KF_VTYPE_VREG, PS_FST_VTYPE_VREG },
1044		{ KF_VTYPE_VSOCK, PS_FST_VTYPE_VSOCK }
1045	};
1046#define	NKFVTYPES	(sizeof(kfvtypes2fst) / sizeof(*kfvtypes2fst))
1047	unsigned int i;
1048
1049	for (i = 0; i < NKFVTYPES; i++)
1050		if (kfvtypes2fst[i].kf_vtype == kfvtype)
1051			break;
1052	if (i == NKFVTYPES)
1053		return (PS_FST_VTYPE_UNKNOWN);
1054	return (kfvtypes2fst[i].fst_vtype);
1055}
1056
1057static int
1058procstat_get_vnode_info_sysctl(struct filestat *fst, struct vnstat *vn,
1059    char *errbuf)
1060{
1061	struct statfs stbuf;
1062	struct kinfo_file *kif;
1063	struct kinfo_vmentry *kve;
1064	uint64_t fileid;
1065	uint64_t size;
1066	char *name, *path;
1067	uint32_t fsid;
1068	uint16_t mode;
1069	uint32_t rdev;
1070	int vntype;
1071	int status;
1072
1073	assert(fst);
1074	assert(vn);
1075	bzero(vn, sizeof(*vn));
1076	if (fst->fs_typedep == NULL)
1077		return (1);
1078	if (fst->fs_uflags & PS_FST_UFLAG_MMAP) {
1079		kve = fst->fs_typedep;
1080		fileid = kve->kve_vn_fileid;
1081		fsid = kve->kve_vn_fsid;
1082		mode = kve->kve_vn_mode;
1083		path = kve->kve_path;
1084		rdev = kve->kve_vn_rdev;
1085		size = kve->kve_vn_size;
1086		vntype = kinfo_vtype2fst(kve->kve_vn_type);
1087		status = kve->kve_status;
1088	} else {
1089		kif = fst->fs_typedep;
1090		fileid = kif->kf_un.kf_file.kf_file_fileid;
1091		fsid = kif->kf_un.kf_file.kf_file_fsid;
1092		mode = kif->kf_un.kf_file.kf_file_mode;
1093		path = kif->kf_path;
1094		rdev = kif->kf_un.kf_file.kf_file_rdev;
1095		size = kif->kf_un.kf_file.kf_file_size;
1096		vntype = kinfo_vtype2fst(kif->kf_vnode_type);
1097		status = kif->kf_status;
1098	}
1099	vn->vn_type = vntype;
1100	if (vntype == PS_FST_VTYPE_VNON || vntype == PS_FST_VTYPE_VBAD)
1101		return (0);
1102	if ((status & KF_ATTR_VALID) == 0) {
1103		snprintf(errbuf, _POSIX2_LINE_MAX, "? (no info available)");
1104		return (1);
1105	}
1106	if (path && *path) {
1107		statfs(path, &stbuf);
1108		vn->vn_mntdir = strdup(stbuf.f_mntonname);
1109	} else
1110		vn->vn_mntdir = strdup("-");
1111	vn->vn_dev = rdev;
1112	if (vntype == PS_FST_VTYPE_VBLK) {
1113		name = devname(rdev, S_IFBLK);
1114		if (name != NULL)
1115			strlcpy(vn->vn_devname, name,
1116			    sizeof(vn->vn_devname));
1117	} else if (vntype == PS_FST_VTYPE_VCHR) {
1118		name = devname(vn->vn_dev, S_IFCHR);
1119		if (name != NULL)
1120			strlcpy(vn->vn_devname, name,
1121			    sizeof(vn->vn_devname));
1122	}
1123	vn->vn_fsid = fsid;
1124	vn->vn_fileid = fileid;
1125	vn->vn_size = size;
1126	vn->vn_mode = mode;
1127	return (0);
1128}
1129
1130int
1131procstat_get_socket_info(struct procstat *procstat, struct filestat *fst,
1132    struct sockstat *sock, char *errbuf)
1133{
1134
1135	assert(sock);
1136	if (procstat->type == PROCSTAT_KVM) {
1137		return (procstat_get_socket_info_kvm(procstat->kd, fst, sock,
1138		    errbuf));
1139	} else if (procstat->type == PROCSTAT_SYSCTL) {
1140		return (procstat_get_socket_info_sysctl(fst, sock, errbuf));
1141	} else {
1142		warnx("unknown access method: %d", procstat->type);
1143		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1144		return (1);
1145	}
1146}
1147
1148static int
1149procstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst,
1150    struct sockstat *sock, char *errbuf)
1151{
1152	struct domain dom;
1153	struct inpcb inpcb;
1154	struct protosw proto;
1155	struct socket s;
1156	struct unpcb unpcb;
1157	ssize_t len;
1158	void *so;
1159
1160	assert(kd);
1161	assert(sock);
1162	assert(fst);
1163	bzero(sock, sizeof(*sock));
1164	so = fst->fs_typedep;
1165	if (so == NULL)
1166		goto fail;
1167	sock->so_addr = (uintptr_t)so;
1168	/* fill in socket */
1169	if (!kvm_read_all(kd, (unsigned long)so, &s,
1170	    sizeof(struct socket))) {
1171		warnx("can't read sock at %p", (void *)so);
1172		goto fail;
1173	}
1174	/* fill in protosw entry */
1175	if (!kvm_read_all(kd, (unsigned long)s.so_proto, &proto,
1176	    sizeof(struct protosw))) {
1177		warnx("can't read protosw at %p", (void *)s.so_proto);
1178		goto fail;
1179	}
1180	/* fill in domain */
1181	if (!kvm_read_all(kd, (unsigned long)proto.pr_domain, &dom,
1182	    sizeof(struct domain))) {
1183		warnx("can't read domain at %p",
1184		    (void *)proto.pr_domain);
1185		goto fail;
1186	}
1187	if ((len = kvm_read(kd, (unsigned long)dom.dom_name, sock->dname,
1188	    sizeof(sock->dname) - 1)) < 0) {
1189		warnx("can't read domain name at %p", (void *)dom.dom_name);
1190		sock->dname[0] = '\0';
1191	}
1192	else
1193		sock->dname[len] = '\0';
1194
1195	/*
1196	 * Fill in known data.
1197	 */
1198	sock->type = s.so_type;
1199	sock->proto = proto.pr_protocol;
1200	sock->dom_family = dom.dom_family;
1201	sock->so_pcb = (uintptr_t)s.so_pcb;
1202
1203	/*
1204	 * Protocol specific data.
1205	 */
1206	switch(dom.dom_family) {
1207	case AF_INET:
1208	case AF_INET6:
1209		if (proto.pr_protocol == IPPROTO_TCP) {
1210			if (s.so_pcb) {
1211				if (kvm_read(kd, (u_long)s.so_pcb,
1212				    (char *)&inpcb, sizeof(struct inpcb))
1213				    != sizeof(struct inpcb)) {
1214					warnx("can't read inpcb at %p",
1215					    (void *)s.so_pcb);
1216				} else
1217					sock->inp_ppcb =
1218					    (uintptr_t)inpcb.inp_ppcb;
1219			}
1220		}
1221		break;
1222	case AF_UNIX:
1223		if (s.so_pcb) {
1224			if (kvm_read(kd, (u_long)s.so_pcb, (char *)&unpcb,
1225			    sizeof(struct unpcb)) != sizeof(struct unpcb)){
1226				warnx("can't read unpcb at %p",
1227				    (void *)s.so_pcb);
1228			} else if (unpcb.unp_conn) {
1229				sock->so_rcv_sb_state = s.so_rcv.sb_state;
1230				sock->so_snd_sb_state = s.so_snd.sb_state;
1231				sock->unp_conn = (uintptr_t)unpcb.unp_conn;
1232			}
1233		}
1234		break;
1235	default:
1236		break;
1237	}
1238	return (0);
1239
1240fail:
1241	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1242	return (1);
1243}
1244
1245static int
1246procstat_get_socket_info_sysctl(struct filestat *fst, struct sockstat *sock,
1247    char *errbuf __unused)
1248{
1249	struct kinfo_file *kif;
1250
1251	assert(sock);
1252	assert(fst);
1253	bzero(sock, sizeof(*sock));
1254	kif = fst->fs_typedep;
1255	if (kif == NULL)
1256		return (0);
1257
1258	/*
1259	 * Fill in known data.
1260	 */
1261	sock->type = kif->kf_sock_type;
1262	sock->proto = kif->kf_sock_protocol;
1263	sock->dom_family = kif->kf_sock_domain;
1264	sock->so_pcb = kif->kf_un.kf_sock.kf_sock_pcb;
1265	strlcpy(sock->dname, kif->kf_path, sizeof(sock->dname));
1266	bcopy(&kif->kf_sa_local, &sock->sa_local, kif->kf_sa_local.ss_len);
1267	bcopy(&kif->kf_sa_peer, &sock->sa_peer, kif->kf_sa_peer.ss_len);
1268
1269	/*
1270	 * Protocol specific data.
1271	 */
1272	switch(sock->dom_family) {
1273	case AF_INET:
1274	case AF_INET6:
1275		if (sock->proto == IPPROTO_TCP)
1276			sock->inp_ppcb = kif->kf_un.kf_sock.kf_sock_inpcb;
1277		break;
1278	case AF_UNIX:
1279		if (kif->kf_un.kf_sock.kf_sock_unpconn != 0) {
1280				sock->so_rcv_sb_state =
1281				    kif->kf_un.kf_sock.kf_sock_rcv_sb_state;
1282				sock->so_snd_sb_state =
1283				    kif->kf_un.kf_sock.kf_sock_snd_sb_state;
1284				sock->unp_conn =
1285				    kif->kf_un.kf_sock.kf_sock_unpconn;
1286		}
1287		break;
1288	default:
1289		break;
1290	}
1291	return (0);
1292}
1293
1294/*
1295 * Descriptor flags to filestat translation.
1296 */
1297static int
1298to_filestat_flags(int flags)
1299{
1300	static struct {
1301		int flag;
1302		int fst_flag;
1303	} fstflags[] = {
1304		{ FREAD, PS_FST_FFLAG_READ },
1305		{ FWRITE, PS_FST_FFLAG_WRITE },
1306		{ O_APPEND, PS_FST_FFLAG_APPEND },
1307		{ O_ASYNC, PS_FST_FFLAG_ASYNC },
1308		{ O_CREAT, PS_FST_FFLAG_CREAT },
1309		{ O_DIRECT, PS_FST_FFLAG_DIRECT },
1310		{ O_EXCL, PS_FST_FFLAG_EXCL },
1311		{ O_EXEC, PS_FST_FFLAG_EXEC },
1312		{ O_EXLOCK, PS_FST_FFLAG_EXLOCK },
1313		{ O_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW },
1314		{ O_NONBLOCK, PS_FST_FFLAG_NONBLOCK },
1315		{ O_SHLOCK, PS_FST_FFLAG_SHLOCK },
1316		{ O_SYNC, PS_FST_FFLAG_SYNC },
1317		{ O_TRUNC, PS_FST_FFLAG_TRUNC }
1318	};
1319#define NFSTFLAGS	(sizeof(fstflags) / sizeof(*fstflags))
1320	int fst_flags;
1321	unsigned int i;
1322
1323	fst_flags = 0;
1324	for (i = 0; i < NFSTFLAGS; i++)
1325		if (flags & fstflags[i].flag)
1326			fst_flags |= fstflags[i].fst_flag;
1327	return (fst_flags);
1328}
1329
1330/*
1331 * Vnode type to filestate translation.
1332 */
1333static int
1334vntype2psfsttype(int type)
1335{
1336	static struct {
1337		int	vtype;
1338		int	fst_vtype;
1339	} vt2fst[] = {
1340		{ VBAD, PS_FST_VTYPE_VBAD },
1341		{ VBLK, PS_FST_VTYPE_VBLK },
1342		{ VCHR, PS_FST_VTYPE_VCHR },
1343		{ VDIR, PS_FST_VTYPE_VDIR },
1344		{ VFIFO, PS_FST_VTYPE_VFIFO },
1345		{ VLNK, PS_FST_VTYPE_VLNK },
1346		{ VNON, PS_FST_VTYPE_VNON },
1347		{ VREG, PS_FST_VTYPE_VREG },
1348		{ VSOCK, PS_FST_VTYPE_VSOCK }
1349	};
1350#define	NVFTYPES	(sizeof(vt2fst) / sizeof(*vt2fst))
1351	unsigned int i, fst_type;
1352
1353	fst_type = PS_FST_VTYPE_UNKNOWN;
1354	for (i = 0; i < NVFTYPES; i++) {
1355		if (type == vt2fst[i].vtype) {
1356			fst_type = vt2fst[i].fst_vtype;
1357			break;
1358		}
1359	}
1360	return (fst_type);
1361}
1362
1363static char *
1364getmnton(kvm_t *kd, struct mount *m)
1365{
1366	struct mount mnt;
1367	static struct mtab {
1368		struct mtab *next;
1369		struct mount *m;
1370		char mntonname[MNAMELEN + 1];
1371	} *mhead = NULL;
1372	struct mtab *mt;
1373
1374	for (mt = mhead; mt != NULL; mt = mt->next)
1375		if (m == mt->m)
1376			return (mt->mntonname);
1377	if (!kvm_read_all(kd, (unsigned long)m, &mnt, sizeof(struct mount))) {
1378		warnx("can't read mount table at %p", (void *)m);
1379		return (NULL);
1380	}
1381	if ((mt = malloc(sizeof (struct mtab))) == NULL)
1382		err(1, NULL);
1383	mt->m = m;
1384	bcopy(&mnt.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN);
1385	mt->mntonname[MNAMELEN] = '\0';
1386	mt->next = mhead;
1387	mhead = mt;
1388	return (mt->mntonname);
1389}
1390