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