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$");
37
38#include <sys/param.h>
39#include <sys/user.h>
40#include <sys/stat.h>
41#include <sys/vnode.h>
42#include <sys/conf.h>
43#define	_KERNEL
44#include <sys/pipe.h>
45#include <sys/mount.h>
46#include <ufs/ufs/quota.h>
47#include <ufs/ufs/inode.h>
48#include <fs/devfs/devfs.h>
49#include <fs/devfs/devfs_int.h>
50#undef _KERNEL
51#include <nfs/nfsproto.h>
52#include <nfsclient/nfs.h>
53#include <nfsclient/nfsnode.h>
54
55#include <assert.h>
56#include <err.h>
57#include <kvm.h>
58#include <stddef.h>
59#include <string.h>
60
61#include <libprocstat.h>
62#include "common_kvm.h"
63
64int
65kvm_read_all(kvm_t *kd, unsigned long addr, void *buf, size_t nbytes)
66{
67	ssize_t error;
68
69	if (nbytes >= SSIZE_MAX)
70		return (0);
71	error = kvm_read(kd, addr, buf, nbytes);
72	return (error == (ssize_t)(nbytes));
73}
74
75int
76kdevtoname(kvm_t *kd, struct cdev *dev, char *buf)
77{
78	struct cdev si;
79
80	assert(buf);
81	if (!kvm_read_all(kd, (unsigned long)dev, &si, sizeof(si)))
82		return (1);
83	strlcpy(buf, si.si_name, SPECNAMELEN + 1);
84	return (0);
85}
86
87int
88ufs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn)
89{
90	struct inode inode;
91
92	if (!kvm_read_all(kd, (unsigned long)VTOI(vp), &inode, sizeof(inode))) {
93		warnx("can't read inode at %p", (void *)VTOI(vp));
94		return (1);
95	}
96	/*
97	 * The st_dev from stat(2) is a dev_t. These kernel structures
98	 * contain cdev pointers. We need to convert to dev_t to make
99	 * comparisons
100	 */
101	vn->vn_fsid = dev2udev(kd, inode.i_dev);
102	vn->vn_fileid = inode.i_number;
103	vn->vn_mode = (mode_t)inode.i_mode;
104	vn->vn_size = inode.i_size;
105	return (0);
106}
107
108int
109devfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn)
110{
111	struct devfs_dirent devfs_dirent;
112	struct mount mount;
113
114	if (!kvm_read_all(kd, (unsigned long)getvnodedata(vp), &devfs_dirent,
115	    sizeof(devfs_dirent))) {
116		warnx("can't read devfs_dirent at %p",
117		    (void *)vp->v_data);
118		return (1);
119	}
120	if (!kvm_read_all(kd, (unsigned long)getvnodemount(vp), &mount,
121	    sizeof(mount))) {
122		warnx("can't read mount at %p",
123		    (void *)getvnodemount(vp));
124		return (1);
125	}
126	vn->vn_fsid = mount.mnt_stat.f_fsid.val[0];
127	vn->vn_fileid = devfs_dirent.de_inode;
128	vn->vn_mode = (devfs_dirent.de_mode & ~S_IFMT) | S_IFCHR;
129	vn->vn_size = 0;
130	return (0);
131}
132
133int
134nfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn)
135{
136	struct nfsnode nfsnode;
137	mode_t mode;
138
139	if (!kvm_read_all(kd, (unsigned long)VTONFS(vp), &nfsnode,
140	    sizeof(nfsnode))) {
141		warnx("can't read nfsnode at %p",
142		    (void *)VTONFS(vp));
143		return (1);
144	}
145	vn->vn_fsid = nfsnode.n_vattr.va_fsid;
146	vn->vn_fileid = nfsnode.n_vattr.va_fileid;
147	vn->vn_size = nfsnode.n_size;
148	mode = (mode_t)nfsnode.n_vattr.va_mode;
149	switch (vp->v_type) {
150	case VREG:
151		mode |= S_IFREG;
152		break;
153	case VDIR:
154		mode |= S_IFDIR;
155		break;
156	case VBLK:
157		mode |= S_IFBLK;
158		break;
159	case VCHR:
160		mode |= S_IFCHR;
161		break;
162	case VLNK:
163		mode |= S_IFLNK;
164		break;
165	case VSOCK:
166		mode |= S_IFSOCK;
167		break;
168	case VFIFO:
169		mode |= S_IFIFO;
170		break;
171	default:
172		break;
173	};
174	vn->vn_mode = mode;
175	return (0);
176}
177
178/*
179 * Read the cdev structure in the kernel in order to work out the
180 * associated dev_t
181 */
182dev_t
183dev2udev(kvm_t *kd, struct cdev *dev)
184{
185	struct cdev_priv priv;
186
187	assert(kd);
188	if (kvm_read_all(kd, (unsigned long)cdev2priv(dev), &priv,
189	    sizeof(priv))) {
190		return ((dev_t)priv.cdp_inode);
191	} else {
192		warnx("can't convert cdev *%p to a dev_t\n", dev);
193		return (-1);
194	}
195}
196
197void *
198getvnodedata(struct vnode *vp)
199{
200	return (vp->v_data);
201}
202
203struct mount *
204getvnodemount(struct vnode *vp)
205{
206	return (vp->v_mount);
207}
208