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