1 /*- 2 * SPDX-License-Identifier: BSD-4-Clause 3 * 4 * Copyright (c) 2009 Stanislav Sedov <stas@FreeBSD.org> 5 * Copyright (c) 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #include <sys/cdefs.h> 38 __FBSDID("$FreeBSD$"); 39 40 #include <sys/param.h> 41 #include <sys/user.h> 42 #include <sys/stat.h> 43 #include <sys/vnode.h> 44 #include <sys/conf.h> 45 #define _KERNEL 46 #include <sys/pipe.h> 47 #include <sys/mount.h> 48 #include <ufs/ufs/quota.h> 49 #include <ufs/ufs/inode.h> 50 #include <ufs/ufs/extattr.h> 51 #include <ufs/ufs/ufsmount.h> 52 #include <fs/devfs/devfs.h> 53 #include <fs/devfs/devfs_int.h> 54 #undef _KERNEL 55 #include <nfs/nfsproto.h> 56 #include <nfsclient/nfs.h> 57 #include <nfsclient/nfsnode.h> 58 59 #include <assert.h> 60 #include <err.h> 61 #include <kvm.h> 62 #include <stddef.h> 63 #include <string.h> 64 65 #include <libprocstat.h> 66 #include "common_kvm.h" 67 68 int 69 kvm_read_all(kvm_t *kd, unsigned long addr, void *buf, size_t nbytes) 70 { 71 ssize_t error; 72 73 if (nbytes >= SSIZE_MAX) 74 return (0); 75 error = kvm_read(kd, addr, buf, nbytes); 76 return (error == (ssize_t)(nbytes)); 77 } 78 79 int 80 kdevtoname(kvm_t *kd, struct cdev *dev, char *buf) 81 { 82 struct cdev si; 83 84 assert(buf); 85 if (!kvm_read_all(kd, (unsigned long)dev, &si, sizeof(si))) 86 return (1); 87 strlcpy(buf, si.si_name, SPECNAMELEN + 1); 88 return (0); 89 } 90 91 int 92 ufs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn) 93 { 94 struct inode inode; 95 struct ufsmount um; 96 97 if (!kvm_read_all(kd, (unsigned long)VTOI(vp), &inode, sizeof(inode))) { 98 warnx("can't read inode at %p", (void *)VTOI(vp)); 99 return (1); 100 } 101 if (!kvm_read_all(kd, (unsigned long)inode.i_ump, &um, sizeof(um))) { 102 warnx("can't read ufsmount at %p", (void *)inode.i_ump); 103 return (1); 104 } 105 /* 106 * The st_dev from stat(2) is a dev_t. These kernel structures 107 * contain cdev pointers. We need to convert to dev_t to make 108 * comparisons 109 */ 110 vn->vn_fsid = dev2udev(kd, um.um_dev); 111 vn->vn_fileid = inode.i_number; 112 vn->vn_mode = (mode_t)inode.i_mode; 113 vn->vn_size = inode.i_size; 114 return (0); 115 } 116 117 int 118 devfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn) 119 { 120 struct devfs_dirent devfs_dirent; 121 struct mount mount; 122 123 if (!kvm_read_all(kd, (unsigned long)getvnodedata(vp), &devfs_dirent, 124 sizeof(devfs_dirent))) { 125 warnx("can't read devfs_dirent at %p", 126 (void *)vp->v_data); 127 return (1); 128 } 129 if (!kvm_read_all(kd, (unsigned long)getvnodemount(vp), &mount, 130 sizeof(mount))) { 131 warnx("can't read mount at %p", 132 (void *)getvnodemount(vp)); 133 return (1); 134 } 135 vn->vn_fsid = mount.mnt_stat.f_fsid.val[0]; 136 vn->vn_fileid = devfs_dirent.de_inode; 137 vn->vn_mode = (devfs_dirent.de_mode & ~S_IFMT) | S_IFCHR; 138 vn->vn_size = 0; 139 return (0); 140 } 141 142 int 143 nfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn) 144 { 145 struct nfsnode nfsnode; 146 mode_t mode; 147 148 if (!kvm_read_all(kd, (unsigned long)VTONFS(vp), &nfsnode, 149 sizeof(nfsnode))) { 150 warnx("can't read nfsnode at %p", 151 (void *)VTONFS(vp)); 152 return (1); 153 } 154 vn->vn_fsid = nfsnode.n_vattr.va_fsid; 155 vn->vn_fileid = nfsnode.n_vattr.va_fileid; 156 vn->vn_size = nfsnode.n_size; 157 mode = (mode_t)nfsnode.n_vattr.va_mode; 158 switch (vp->v_type) { 159 case VREG: 160 mode |= S_IFREG; 161 break; 162 case VDIR: 163 mode |= S_IFDIR; 164 break; 165 case VBLK: 166 mode |= S_IFBLK; 167 break; 168 case VCHR: 169 mode |= S_IFCHR; 170 break; 171 case VLNK: 172 mode |= S_IFLNK; 173 break; 174 case VSOCK: 175 mode |= S_IFSOCK; 176 break; 177 case VFIFO: 178 mode |= S_IFIFO; 179 break; 180 default: 181 break; 182 }; 183 vn->vn_mode = mode; 184 return (0); 185 } 186 187 /* 188 * Read the cdev structure in the kernel in order to work out the 189 * associated dev_t 190 */ 191 dev_t 192 dev2udev(kvm_t *kd, struct cdev *dev) 193 { 194 struct cdev_priv priv; 195 196 assert(kd); 197 if (kvm_read_all(kd, (unsigned long)cdev2priv(dev), &priv, 198 sizeof(priv))) { 199 return ((dev_t)priv.cdp_inode); 200 } else { 201 warnx("can't convert cdev *%p to a dev_t\n", dev); 202 return (-1); 203 } 204 } 205 206 void * 207 getvnodedata(struct vnode *vp) 208 { 209 return (vp->v_data); 210 } 211 212 struct mount * 213 getvnodemount(struct vnode *vp) 214 { 215 return (vp->v_mount); 216 } 217