libprocstat.c revision 221936
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 221936 2011-05-15 00:46:25Z 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#ifdef LIBPROCSTAT_NWFS
877		FSTYPE(nwfs),
878#endif
879		FSTYPE(smbfs),
880		FSTYPE(udf),
881		FSTYPE(ufs),
882#ifdef LIBPROCSTAT_ZFS
883		FSTYPE(zfs),
884#endif
885	};
886#define	NTYPES	(sizeof(fstypes) / sizeof(*fstypes))
887	struct vnode vnode;
888	char tagstr[12];
889	void *vp;
890	int error, found;
891	unsigned int i;
892
893	assert(kd);
894	assert(vn);
895	assert(fst);
896	vp = fst->fs_typedep;
897	if (vp == NULL)
898		goto fail;
899	error = kvm_read_all(kd, (unsigned long)vp, &vnode, sizeof(vnode));
900	if (error == 0) {
901		warnx("can't read vnode at %p", (void *)vp);
902		goto fail;
903	}
904	bzero(vn, sizeof(*vn));
905	vn->vn_type = vntype2psfsttype(vnode.v_type);
906	if (vnode.v_type == VNON || vnode.v_type == VBAD)
907		return (0);
908	error = kvm_read_all(kd, (unsigned long)vnode.v_tag, tagstr,
909	    sizeof(tagstr));
910	if (error == 0) {
911		warnx("can't read v_tag at %p", (void *)vp);
912		goto fail;
913	}
914	tagstr[sizeof(tagstr) - 1] = '\0';
915
916	/*
917	 * Find appropriate handler.
918	 */
919	for (i = 0, found = 0; i < NTYPES; i++)
920		if (!strcmp(fstypes[i].tag, tagstr)) {
921			if (fstypes[i].handler(kd, &vnode, vn) != 0) {
922				goto fail;
923			}
924			break;
925		}
926	if (i == NTYPES) {
927		snprintf(errbuf, _POSIX2_LINE_MAX, "?(%s)", tagstr);
928		return (1);
929	}
930	vn->vn_mntdir = getmnton(kd, vnode.v_mount);
931	if ((vnode.v_type == VBLK || vnode.v_type == VCHR) &&
932	    vnode.v_rdev != NULL){
933		vn->vn_dev = dev2udev(kd, vnode.v_rdev);
934		(void)kdevtoname(kd, vnode.v_rdev, vn->vn_devname);
935	} else {
936		vn->vn_dev = -1;
937	}
938	return (0);
939
940fail:
941	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
942	return (1);
943}
944
945/*
946 * kinfo vnode type to filestat translation.
947 */
948static int
949kinfo_vtype2fst(int kfvtype)
950{
951	static struct {
952		int	kf_vtype;
953		int	fst_vtype;
954	} kfvtypes2fst[] = {
955		{ KF_VTYPE_VBAD, PS_FST_VTYPE_VBAD },
956		{ KF_VTYPE_VBLK, PS_FST_VTYPE_VBLK },
957		{ KF_VTYPE_VCHR, PS_FST_VTYPE_VCHR },
958		{ KF_VTYPE_VDIR, PS_FST_VTYPE_VDIR },
959		{ KF_VTYPE_VFIFO, PS_FST_VTYPE_VFIFO },
960		{ KF_VTYPE_VLNK, PS_FST_VTYPE_VLNK },
961		{ KF_VTYPE_VNON, PS_FST_VTYPE_VNON },
962		{ KF_VTYPE_VREG, PS_FST_VTYPE_VREG },
963		{ KF_VTYPE_VSOCK, PS_FST_VTYPE_VSOCK }
964	};
965#define	NKFVTYPES	(sizeof(kfvtypes2fst) / sizeof(*kfvtypes2fst))
966	unsigned int i;
967
968	for (i = 0; i < NKFVTYPES; i++)
969		if (kfvtypes2fst[i].kf_vtype == kfvtype)
970			break;
971	if (i == NKFVTYPES)
972		return (PS_FST_VTYPE_UNKNOWN);
973	return (kfvtypes2fst[i].fst_vtype);
974}
975
976static int
977procstat_get_vnode_info_sysctl(struct filestat *fst, struct vnstat *vn,
978    char *errbuf)
979{
980	struct statfs stbuf;
981	struct kinfo_file *kif;
982	struct kinfo_vmentry *kve;
983	uint64_t fileid;
984	uint64_t size;
985	char *name, *path;
986	uint32_t fsid;
987	uint16_t mode;
988	uint32_t rdev;
989	int vntype;
990	int status;
991
992	assert(fst);
993	assert(vn);
994	bzero(vn, sizeof(*vn));
995	if (fst->fs_typedep == NULL)
996		return (1);
997	if (fst->fs_uflags & PS_FST_UFLAG_MMAP) {
998		kve = fst->fs_typedep;
999		fileid = kve->kve_vn_fileid;
1000		fsid = kve->kve_vn_fsid;
1001		mode = kve->kve_vn_mode;
1002		path = kve->kve_path;
1003		rdev = kve->kve_vn_rdev;
1004		size = kve->kve_vn_size;
1005		vntype = kinfo_vtype2fst(kve->kve_vn_type);
1006		status = kve->kve_status;
1007	} else {
1008		kif = fst->fs_typedep;
1009		fileid = kif->kf_un.kf_file.kf_file_fileid;
1010		fsid = kif->kf_un.kf_file.kf_file_fsid;
1011		mode = kif->kf_un.kf_file.kf_file_mode;
1012		path = kif->kf_path;
1013		rdev = kif->kf_un.kf_file.kf_file_rdev;
1014		size = kif->kf_un.kf_file.kf_file_size;
1015		vntype = kinfo_vtype2fst(kif->kf_vnode_type);
1016		status = kif->kf_status;
1017	}
1018	vn->vn_type = vntype;
1019	if (vntype == PS_FST_VTYPE_VNON || vntype == PS_FST_VTYPE_VBAD)
1020		return (0);
1021	if ((status & KF_ATTR_VALID) == 0) {
1022		snprintf(errbuf, _POSIX2_LINE_MAX, "? (no info available)");
1023		return (1);
1024	}
1025	if (path && *path) {
1026		statfs(path, &stbuf);
1027		vn->vn_mntdir = strdup(stbuf.f_mntonname);
1028	} else
1029		vn->vn_mntdir = strdup("-");
1030	vn->vn_dev = rdev;
1031	if (vntype == PS_FST_VTYPE_VBLK) {
1032		name = devname(rdev, S_IFBLK);
1033		if (name != NULL)
1034			strlcpy(vn->vn_devname, name,
1035			    sizeof(vn->vn_devname));
1036	} else if (vntype == PS_FST_VTYPE_VCHR) {
1037		name = devname(vn->vn_dev, S_IFCHR);
1038		if (name != NULL)
1039			strlcpy(vn->vn_devname, name,
1040			    sizeof(vn->vn_devname));
1041	}
1042	vn->vn_fsid = fsid;
1043	vn->vn_fileid = fileid;
1044	vn->vn_size = size;
1045	vn->vn_mode = mode;
1046	return (0);
1047}
1048
1049int
1050procstat_get_socket_info(struct procstat *procstat, struct filestat *fst,
1051    struct sockstat *sock, char *errbuf)
1052{
1053
1054	assert(sock);
1055	if (procstat->type == PROCSTAT_KVM) {
1056		return (procstat_get_socket_info_kvm(procstat->kd, fst, sock,
1057		    errbuf));
1058	} else if (procstat->type == PROCSTAT_SYSCTL) {
1059		return (procstat_get_socket_info_sysctl(fst, sock, errbuf));
1060	} else {
1061		warnx("unknow access method: %d", procstat->type);
1062		snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1063		return (1);
1064	}
1065}
1066
1067static int
1068procstat_get_socket_info_kvm(kvm_t *kd, struct filestat *fst,
1069    struct sockstat *sock, char *errbuf)
1070{
1071	struct domain dom;
1072	struct inpcb inpcb;
1073	struct protosw proto;
1074	struct socket s;
1075	struct unpcb unpcb;
1076	ssize_t len;
1077	void *so;
1078
1079	assert(kd);
1080	assert(sock);
1081	assert(fst);
1082	bzero(sock, sizeof(*sock));
1083	so = fst->fs_typedep;
1084	if (so == NULL)
1085		goto fail;
1086	sock->so_addr = (uintptr_t)so;
1087	/* fill in socket */
1088	if (!kvm_read_all(kd, (unsigned long)so, &s,
1089	    sizeof(struct socket))) {
1090		warnx("can't read sock at %p", (void *)so);
1091		goto fail;
1092	}
1093	/* fill in protosw entry */
1094	if (!kvm_read_all(kd, (unsigned long)s.so_proto, &proto,
1095	    sizeof(struct protosw))) {
1096		warnx("can't read protosw at %p", (void *)s.so_proto);
1097		goto fail;
1098	}
1099	/* fill in domain */
1100	if (!kvm_read_all(kd, (unsigned long)proto.pr_domain, &dom,
1101	    sizeof(struct domain))) {
1102		warnx("can't read domain at %p",
1103		    (void *)proto.pr_domain);
1104		goto fail;
1105	}
1106	if ((len = kvm_read(kd, (unsigned long)dom.dom_name, sock->dname,
1107	    sizeof(sock->dname) - 1)) < 0) {
1108		warnx("can't read domain name at %p", (void *)dom.dom_name);
1109		sock->dname[0] = '\0';
1110	}
1111	else
1112		sock->dname[len] = '\0';
1113
1114	/*
1115	 * Fill in known data.
1116	 */
1117	sock->type = s.so_type;
1118	sock->proto = proto.pr_protocol;
1119	sock->dom_family = dom.dom_family;
1120	sock->so_pcb = (uintptr_t)s.so_pcb;
1121
1122	/*
1123	 * Protocol specific data.
1124	 */
1125	switch(dom.dom_family) {
1126	case AF_INET:
1127	case AF_INET6:
1128		if (proto.pr_protocol == IPPROTO_TCP) {
1129			if (s.so_pcb) {
1130				if (kvm_read(kd, (u_long)s.so_pcb,
1131				    (char *)&inpcb, sizeof(struct inpcb))
1132				    != sizeof(struct inpcb)) {
1133					warnx("can't read inpcb at %p",
1134					    (void *)s.so_pcb);
1135				} else
1136					sock->inp_ppcb =
1137					    (uintptr_t)inpcb.inp_ppcb;
1138			}
1139		}
1140		break;
1141	case AF_UNIX:
1142		if (s.so_pcb) {
1143			if (kvm_read(kd, (u_long)s.so_pcb, (char *)&unpcb,
1144			    sizeof(struct unpcb)) != sizeof(struct unpcb)){
1145				warnx("can't read unpcb at %p",
1146				    (void *)s.so_pcb);
1147			} else if (unpcb.unp_conn) {
1148				sock->so_rcv_sb_state = s.so_rcv.sb_state;
1149				sock->so_snd_sb_state = s.so_snd.sb_state;
1150				sock->unp_conn = (uintptr_t)unpcb.unp_conn;
1151			}
1152		}
1153		break;
1154	default:
1155		break;
1156	}
1157	return (0);
1158
1159fail:
1160	snprintf(errbuf, _POSIX2_LINE_MAX, "error");
1161	return (1);
1162}
1163
1164static int
1165procstat_get_socket_info_sysctl(struct filestat *fst, struct sockstat *sock,
1166    char *errbuf __unused)
1167{
1168	struct kinfo_file *kif;
1169
1170	assert(sock);
1171	assert(fst);
1172	bzero(sock, sizeof(*sock));
1173	kif = fst->fs_typedep;
1174	if (kif == NULL)
1175		return (0);
1176
1177	/*
1178	 * Fill in known data.
1179	 */
1180	sock->type = kif->kf_sock_type;
1181	sock->proto = kif->kf_sock_protocol;
1182	sock->dom_family = kif->kf_sock_domain;
1183	sock->so_pcb = kif->kf_un.kf_sock.kf_sock_pcb;
1184	strlcpy(sock->dname, kif->kf_path, sizeof(sock->dname));
1185	bcopy(&kif->kf_sa_local, &sock->sa_local, kif->kf_sa_local.ss_len);
1186	bcopy(&kif->kf_sa_peer, &sock->sa_peer, kif->kf_sa_peer.ss_len);
1187
1188	/*
1189	 * Protocol specific data.
1190	 */
1191	switch(sock->dom_family) {
1192	case AF_INET:
1193	case AF_INET6:
1194		if (sock->proto == IPPROTO_TCP)
1195			sock->inp_ppcb = kif->kf_un.kf_sock.kf_sock_inpcb;
1196		break;
1197	case AF_UNIX:
1198		if (kif->kf_un.kf_sock.kf_sock_unpconn != 0) {
1199				sock->so_rcv_sb_state =
1200				    kif->kf_un.kf_sock.kf_sock_rcv_sb_state;
1201				sock->so_snd_sb_state =
1202				    kif->kf_un.kf_sock.kf_sock_snd_sb_state;
1203				sock->unp_conn =
1204				    kif->kf_un.kf_sock.kf_sock_unpconn;
1205		}
1206		break;
1207	default:
1208		break;
1209	}
1210	return (0);
1211}
1212
1213/*
1214 * Descriptor flags to filestat translation.
1215 */
1216static int
1217to_filestat_flags(int flags)
1218{
1219	static struct {
1220		int flag;
1221		int fst_flag;
1222	} fstflags[] = {
1223		{ FREAD, PS_FST_FFLAG_READ },
1224		{ FWRITE, PS_FST_FFLAG_WRITE },
1225		{ O_APPEND, PS_FST_FFLAG_APPEND },
1226		{ O_ASYNC, PS_FST_FFLAG_ASYNC },
1227		{ O_CREAT, PS_FST_FFLAG_CREAT },
1228		{ O_DIRECT, PS_FST_FFLAG_DIRECT },
1229		{ O_EXCL, PS_FST_FFLAG_EXCL },
1230		{ O_EXEC, PS_FST_FFLAG_EXEC },
1231		{ O_EXLOCK, PS_FST_FFLAG_EXLOCK },
1232		{ O_NOFOLLOW, PS_FST_FFLAG_NOFOLLOW },
1233		{ O_NONBLOCK, PS_FST_FFLAG_NONBLOCK },
1234		{ O_SHLOCK, PS_FST_FFLAG_SHLOCK },
1235		{ O_SYNC, PS_FST_FFLAG_SYNC },
1236		{ O_TRUNC, PS_FST_FFLAG_TRUNC }
1237	};
1238#define NFSTFLAGS	(sizeof(fstflags) / sizeof(*fstflags))
1239	int fst_flags;
1240	unsigned int i;
1241
1242	fst_flags = 0;
1243	for (i = 0; i < NFSTFLAGS; i++)
1244		if (flags & fstflags[i].flag)
1245			fst_flags |= fstflags[i].fst_flag;
1246	return (fst_flags);
1247}
1248
1249/*
1250 * Vnode type to filestate translation.
1251 */
1252static int
1253vntype2psfsttype(int type)
1254{
1255	static struct {
1256		int	vtype;
1257		int	fst_vtype;
1258	} vt2fst[] = {
1259		{ VBAD, PS_FST_VTYPE_VBAD },
1260		{ VBLK, PS_FST_VTYPE_VBLK },
1261		{ VCHR, PS_FST_VTYPE_VCHR },
1262		{ VDIR, PS_FST_VTYPE_VDIR },
1263		{ VFIFO, PS_FST_VTYPE_VFIFO },
1264		{ VLNK, PS_FST_VTYPE_VLNK },
1265		{ VNON, PS_FST_VTYPE_VNON },
1266		{ VREG, PS_FST_VTYPE_VREG },
1267		{ VSOCK, PS_FST_VTYPE_VSOCK }
1268	};
1269#define	NVFTYPES	(sizeof(vt2fst) / sizeof(*vt2fst))
1270	unsigned int i, fst_type;
1271
1272	fst_type = PS_FST_VTYPE_UNKNOWN;
1273	for (i = 0; i < NVFTYPES; i++) {
1274		if (type == vt2fst[i].vtype) {
1275			fst_type = vt2fst[i].fst_vtype;
1276			break;
1277		}
1278	}
1279	return (fst_type);
1280}
1281
1282static char *
1283getmnton(kvm_t *kd, struct mount *m)
1284{
1285	static struct mount mnt;
1286	static struct mtab {
1287		struct mtab *next;
1288		struct mount *m;
1289		char mntonname[MNAMELEN + 1];
1290	} *mhead = NULL;
1291	struct mtab *mt;
1292
1293	for (mt = mhead; mt != NULL; mt = mt->next)
1294		if (m == mt->m)
1295			return (mt->mntonname);
1296	if (!kvm_read_all(kd, (unsigned long)m, &mnt, sizeof(struct mount))) {
1297		warnx("can't read mount table at %p", (void *)m);
1298		return (NULL);
1299	}
1300	if ((mt = malloc(sizeof (struct mtab))) == NULL)
1301		err(1, NULL);
1302	mt->m = m;
1303	bcopy(&mnt.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN);
1304	mnt.mnt_stat.f_mntonname[MNAMELEN] = '\0';
1305	mt->next = mhead;
1306	mhead = mt;
1307	return (mt->mntonname);
1308}
1309