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