| 1 | /* $NetBSD: vfs_syscalls_20.c,v 1.39 2015/07/24 13:02:52 maxv Exp $ */ |
| 2 | |
| 3 | /* |
| 4 | * Copyright (c) 1989, 1993 |
| 5 | * The Regents of the University of California. All rights reserved. |
| 6 | * (c) UNIX System Laboratories, Inc. |
| 7 | * All or some portions of this file are derived from material licensed |
| 8 | * to the University of California by American Telephone and Telegraph |
| 9 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with |
| 10 | * the permission of UNIX System Laboratories, Inc. |
| 11 | * |
| 12 | * Redistribution and use in source and binary forms, with or without |
| 13 | * modification, are permitted provided that the following conditions |
| 14 | * are met: |
| 15 | * 1. Redistributions of source code must retain the above copyright |
| 16 | * notice, this list of conditions and the following disclaimer. |
| 17 | * 2. Redistributions in binary form must reproduce the above copyright |
| 18 | * notice, this list of conditions and the following disclaimer in the |
| 19 | * documentation and/or other materials provided with the distribution. |
| 20 | * 3. 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 | * @(#)vfs_syscalls.c 8.42 (Berkeley) 7/31/95 |
| 37 | */ |
| 38 | |
| 39 | #include <sys/cdefs.h> |
| 40 | __KERNEL_RCSID(0, "$NetBSD: vfs_syscalls_20.c,v 1.39 2015/07/24 13:02:52 maxv Exp $" ); |
| 41 | |
| 42 | #ifdef _KERNEL_OPT |
| 43 | #include "opt_compat_netbsd.h" |
| 44 | #endif |
| 45 | |
| 46 | #include <sys/param.h> |
| 47 | #include <sys/systm.h> |
| 48 | #include <sys/namei.h> |
| 49 | #include <sys/filedesc.h> |
| 50 | #include <sys/kernel.h> |
| 51 | #include <sys/file.h> |
| 52 | #include <sys/stat.h> |
| 53 | #include <sys/vnode.h> |
| 54 | #include <sys/mount.h> |
| 55 | #include <sys/proc.h> |
| 56 | #include <sys/uio.h> |
| 57 | #include <sys/malloc.h> |
| 58 | #include <sys/dirent.h> |
| 59 | #include <sys/sysctl.h> |
| 60 | #include <sys/syscallargs.h> |
| 61 | #include <sys/kauth.h> |
| 62 | |
| 63 | #include <compat/sys/mount.h> |
| 64 | |
| 65 | #define MOUNTNO_NONE 0 |
| 66 | #define MOUNTNO_UFS 1 /* UNIX "Fast" Filesystem */ |
| 67 | #define MOUNTNO_NFS 2 /* Network Filesystem */ |
| 68 | #define MOUNTNO_MFS 3 /* Memory Filesystem */ |
| 69 | #define MOUNTNO_MSDOS 4 /* MSDOS Filesystem */ |
| 70 | #define MOUNTNO_CD9660 5 /* iso9660 cdrom */ |
| 71 | #define MOUNTNO_FDESC 6 /* /dev/fd filesystem */ |
| 72 | #define MOUNTNO_KERNFS 7 /* kernel variable filesystem */ |
| 73 | #define MOUNTNO_DEVFS 8 /* device node filesystem */ |
| 74 | #define MOUNTNO_AFS 9 /* AFS 3.x */ |
| 75 | static const struct { |
| 76 | const char *name; |
| 77 | const int value; |
| 78 | } nv[] = { |
| 79 | { MOUNT_UFS, MOUNTNO_UFS }, |
| 80 | { MOUNT_NFS, MOUNTNO_NFS }, |
| 81 | { MOUNT_MFS, MOUNTNO_MFS }, |
| 82 | { MOUNT_MSDOS, MOUNTNO_MSDOS }, |
| 83 | { MOUNT_CD9660, MOUNTNO_CD9660 }, |
| 84 | { MOUNT_FDESC, MOUNTNO_FDESC }, |
| 85 | { MOUNT_KERNFS, MOUNTNO_KERNFS }, |
| 86 | { MOUNT_AFS, MOUNTNO_AFS }, |
| 87 | }; |
| 88 | |
| 89 | static int |
| 90 | vfs2fs(struct statfs12 *bfs, const struct statvfs *fs) |
| 91 | { |
| 92 | struct statfs12 ofs; |
| 93 | int i; |
| 94 | ofs.f_type = 0; |
| 95 | ofs.f_oflags = (short)fs->f_flag; |
| 96 | |
| 97 | for (i = 0; i < sizeof(nv) / sizeof(nv[0]); i++) { |
| 98 | if (strcmp(nv[i].name, fs->f_fstypename) == 0) { |
| 99 | ofs.f_type = nv[i].value; |
| 100 | break; |
| 101 | } |
| 102 | } |
| 103 | #define CLAMP(a) (long)(((a) & ~LONG_MAX) ? LONG_MAX : (a)) |
| 104 | ofs.f_bsize = CLAMP(fs->f_frsize); |
| 105 | ofs.f_iosize = CLAMP(fs->f_iosize); |
| 106 | ofs.f_blocks = CLAMP(fs->f_blocks); |
| 107 | ofs.f_bfree = CLAMP(fs->f_bfree); |
| 108 | if (fs->f_bfree > fs->f_bresvd) |
| 109 | ofs.f_bavail = CLAMP(fs->f_bfree - fs->f_bresvd); |
| 110 | else |
| 111 | ofs.f_bavail = -CLAMP(fs->f_bresvd - fs->f_bfree); |
| 112 | ofs.f_files = CLAMP(fs->f_files); |
| 113 | ofs.f_ffree = CLAMP(fs->f_ffree); |
| 114 | ofs.f_fsid = fs->f_fsidx; |
| 115 | ofs.f_owner = fs->f_owner; |
| 116 | ofs.f_flags = (long)fs->f_flag; |
| 117 | ofs.f_syncwrites = CLAMP(fs->f_syncwrites); |
| 118 | ofs.f_asyncwrites = CLAMP(fs->f_asyncwrites); |
| 119 | (void)strncpy(ofs.f_fstypename, fs->f_fstypename, |
| 120 | sizeof(ofs.f_fstypename)); |
| 121 | (void)strncpy(ofs.f_mntonname, fs->f_mntonname, |
| 122 | sizeof(ofs.f_mntonname)); |
| 123 | (void)strncpy(ofs.f_mntfromname, fs->f_mntfromname, |
| 124 | sizeof(ofs.f_mntfromname)); |
| 125 | |
| 126 | return copyout(&ofs, bfs, sizeof(ofs)); |
| 127 | } |
| 128 | |
| 129 | /* |
| 130 | * Get filesystem statistics. |
| 131 | */ |
| 132 | /* ARGSUSED */ |
| 133 | int |
| 134 | compat_20_sys_statfs(struct lwp *l, const struct compat_20_sys_statfs_args *uap, register_t *retval) |
| 135 | { |
| 136 | /* { |
| 137 | syscallarg(const char *) path; |
| 138 | syscallarg(struct statfs12 *) buf; |
| 139 | } */ |
| 140 | struct mount *mp; |
| 141 | struct statvfs *sbuf; |
| 142 | int error; |
| 143 | struct vnode *vp; |
| 144 | |
| 145 | error = namei_simple_user(SCARG(uap, path), |
| 146 | NSM_FOLLOW_TRYEMULROOT, &vp); |
| 147 | if (error != 0) |
| 148 | return error; |
| 149 | |
| 150 | mp = vp->v_mount; |
| 151 | |
| 152 | sbuf = malloc(sizeof(*sbuf), M_TEMP, M_WAITOK); |
| 153 | if ((error = dostatvfs(mp, sbuf, l, 0, 1)) != 0) |
| 154 | goto done; |
| 155 | |
| 156 | error = vfs2fs(SCARG(uap, buf), sbuf); |
| 157 | done: |
| 158 | vrele(vp); |
| 159 | free(sbuf, M_TEMP); |
| 160 | return error; |
| 161 | } |
| 162 | |
| 163 | /* |
| 164 | * Get filesystem statistics. |
| 165 | */ |
| 166 | /* ARGSUSED */ |
| 167 | int |
| 168 | compat_20_sys_fstatfs(struct lwp *l, const struct compat_20_sys_fstatfs_args *uap, register_t *retval) |
| 169 | { |
| 170 | /* { |
| 171 | syscallarg(int) fd; |
| 172 | syscallarg(struct statfs12 *) buf; |
| 173 | } */ |
| 174 | struct file *fp; |
| 175 | struct mount *mp; |
| 176 | struct statvfs *sbuf; |
| 177 | int error; |
| 178 | |
| 179 | /* fd_getvnode() will use the descriptor for us */ |
| 180 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) |
| 181 | return (error); |
| 182 | mp = fp->f_vnode->v_mount; |
| 183 | sbuf = malloc(sizeof(*sbuf), M_TEMP, M_WAITOK); |
| 184 | if ((error = dostatvfs(mp, sbuf, l, 0, 1)) != 0) |
| 185 | goto out; |
| 186 | error = vfs2fs(SCARG(uap, buf), sbuf); |
| 187 | out: |
| 188 | fd_putfile(SCARG(uap, fd)); |
| 189 | free(sbuf, M_TEMP); |
| 190 | return error; |
| 191 | } |
| 192 | |
| 193 | |
| 194 | /* |
| 195 | * Get statistics on all filesystems. |
| 196 | */ |
| 197 | int |
| 198 | compat_20_sys_getfsstat(struct lwp *l, const struct compat_20_sys_getfsstat_args *uap, register_t *retval) |
| 199 | { |
| 200 | /* { |
| 201 | syscallarg(struct statfs12 *) buf; |
| 202 | syscallarg(long) bufsize; |
| 203 | syscallarg(int) flags; |
| 204 | } */ |
| 205 | int root = 0; |
| 206 | struct mount *mp, *nmp; |
| 207 | struct statvfs *sbuf; |
| 208 | struct statfs12 *sfsp; |
| 209 | size_t count, maxcount; |
| 210 | int error = 0; |
| 211 | |
| 212 | sbuf = malloc(sizeof(*sbuf), M_TEMP, M_WAITOK); |
| 213 | maxcount = (size_t)SCARG(uap, bufsize) / sizeof(struct statfs12); |
| 214 | sfsp = SCARG(uap, buf); |
| 215 | mutex_enter(&mountlist_lock); |
| 216 | count = 0; |
| 217 | for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { |
| 218 | if (vfs_busy(mp, &nmp)) { |
| 219 | continue; |
| 220 | } |
| 221 | if (sfsp && count < maxcount) { |
| 222 | error = dostatvfs(mp, sbuf, l, SCARG(uap, flags), 0); |
| 223 | if (error) { |
| 224 | vfs_unbusy(mp, false, &nmp); |
| 225 | continue; |
| 226 | } |
| 227 | error = vfs2fs(sfsp, sbuf); |
| 228 | if (error) { |
| 229 | vfs_unbusy(mp, false, NULL); |
| 230 | goto out; |
| 231 | } |
| 232 | sfsp++; |
| 233 | root |= strcmp(sbuf->f_mntonname, "/" ) == 0; |
| 234 | } |
| 235 | count++; |
| 236 | vfs_unbusy(mp, false, &nmp); |
| 237 | } |
| 238 | mutex_exit(&mountlist_lock); |
| 239 | if (root == 0 && l->l_proc->p_cwdi->cwdi_rdir) { |
| 240 | /* |
| 241 | * fake a root entry |
| 242 | */ |
| 243 | if ((error = dostatvfs(l->l_proc->p_cwdi->cwdi_rdir->v_mount, |
| 244 | sbuf, l, SCARG(uap, flags), 1)) != 0) |
| 245 | goto out; |
| 246 | if (sfsp) |
| 247 | error = vfs2fs(sfsp, sbuf); |
| 248 | count++; |
| 249 | } |
| 250 | if (sfsp && count > maxcount) |
| 251 | *retval = maxcount; |
| 252 | else |
| 253 | *retval = count; |
| 254 | out: |
| 255 | free(sbuf, M_TEMP); |
| 256 | return error; |
| 257 | } |
| 258 | |
| 259 | int |
| 260 | compat_20_sys_fhstatfs(struct lwp *l, const struct compat_20_sys_fhstatfs_args *uap, register_t *retval) |
| 261 | { |
| 262 | /* { |
| 263 | syscallarg(const struct compat_30_fhandle *) fhp; |
| 264 | syscallarg(struct statfs12 *) buf; |
| 265 | } */ |
| 266 | struct statvfs *sbuf; |
| 267 | struct compat_30_fhandle fh; |
| 268 | struct mount *mp; |
| 269 | struct vnode *vp; |
| 270 | int error; |
| 271 | |
| 272 | /* |
| 273 | * Must be super user |
| 274 | */ |
| 275 | if ((error = kauth_authorize_system(l->l_cred, |
| 276 | KAUTH_SYSTEM_FILEHANDLE, 0, NULL, NULL, NULL))) |
| 277 | return (error); |
| 278 | |
| 279 | if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fh))) != 0) |
| 280 | return (error); |
| 281 | |
| 282 | if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) |
| 283 | return (ESTALE); |
| 284 | if ((error = VFS_FHTOVP(mp, (struct fid*)&fh.fh_fid, &vp))) |
| 285 | return (error); |
| 286 | mp = vp->v_mount; |
| 287 | VOP_UNLOCK(vp); |
| 288 | sbuf = malloc(sizeof(*sbuf), M_TEMP, M_WAITOK); |
| 289 | if ((error = VFS_STATVFS(mp, sbuf)) != 0) |
| 290 | goto out; |
| 291 | error = vfs2fs(SCARG(uap, buf), sbuf); |
| 292 | out: |
| 293 | vrele(vp); |
| 294 | free(sbuf, M_TEMP); |
| 295 | return error; |
| 296 | } |
| 297 | |