1 /* $NetBSD: vfs_syscalls_20.c,v 1.41 2019/01/27 02:08:39 pgoyette 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.41 2019/01/27 02:08:39 pgoyette 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/syscall.h> 61 #include <sys/syscallvar.h> 62 #include <sys/syscallargs.h> 63 #include <sys/kauth.h> 64 65 #include <compat/common/compat_mod.h> 66 67 #include <compat/sys/mount.h> 68 69 #define MOUNTNO_NONE 0 70 #define MOUNTNO_UFS 1 /* UNIX "Fast" Filesystem */ 71 #define MOUNTNO_NFS 2 /* Network Filesystem */ 72 #define MOUNTNO_MFS 3 /* Memory Filesystem */ 73 #define MOUNTNO_MSDOS 4 /* MSDOS Filesystem */ 74 #define MOUNTNO_CD9660 5 /* iso9660 cdrom */ 75 #define MOUNTNO_FDESC 6 /* /dev/fd filesystem */ 76 #define MOUNTNO_KERNFS 7 /* kernel variable filesystem */ 77 #define MOUNTNO_DEVFS 8 /* device node filesystem */ 78 #define MOUNTNO_AFS 9 /* AFS 3.x */ 79 static const struct { 80 const char *name; 81 const int value; 82 } nv[] = { 83 { MOUNT_UFS, MOUNTNO_UFS }, 84 { MOUNT_NFS, MOUNTNO_NFS }, 85 { MOUNT_MFS, MOUNTNO_MFS }, 86 { MOUNT_MSDOS, MOUNTNO_MSDOS }, 87 { MOUNT_CD9660, MOUNTNO_CD9660 }, 88 { MOUNT_FDESC, MOUNTNO_FDESC }, 89 { MOUNT_KERNFS, MOUNTNO_KERNFS }, 90 { MOUNT_AFS, MOUNTNO_AFS }, 91 }; 92 93 static const struct syscall_package vfs_syscalls_20_syscalls[] = { 94 { SYS_compat_20_fhstatfs, 0, (sy_call_t *)compat_20_sys_fhstatfs }, 95 { SYS_compat_20_fstatfs, 0, (sy_call_t *)compat_20_sys_fstatfs }, 96 { SYS_compat_20_getfsstat, 0, (sy_call_t *)compat_20_sys_getfsstat }, 97 { SYS_compat_20_statfs, 0, (sy_call_t *)compat_20_sys_statfs }, 98 { 0, 0, NULL } 99 }; 100 101 static int 102 vfs2fs(struct statfs12 *bfs, const struct statvfs *fs) 103 { 104 struct statfs12 ofs; 105 int i; 106 ofs.f_type = 0; 107 ofs.f_oflags = (short)fs->f_flag; 108 109 for (i = 0; i < sizeof(nv) / sizeof(nv[0]); i++) { 110 if (strcmp(nv[i].name, fs->f_fstypename) == 0) { 111 ofs.f_type = nv[i].value; 112 break; 113 } 114 } 115 #define CLAMP(a) (long)(((a) & ~LONG_MAX) ? LONG_MAX : (a)) 116 ofs.f_bsize = CLAMP(fs->f_frsize); 117 ofs.f_iosize = CLAMP(fs->f_iosize); 118 ofs.f_blocks = CLAMP(fs->f_blocks); 119 ofs.f_bfree = CLAMP(fs->f_bfree); 120 if (fs->f_bfree > fs->f_bresvd) 121 ofs.f_bavail = CLAMP(fs->f_bfree - fs->f_bresvd); 122 else 123 ofs.f_bavail = -CLAMP(fs->f_bresvd - fs->f_bfree); 124 ofs.f_files = CLAMP(fs->f_files); 125 ofs.f_ffree = CLAMP(fs->f_ffree); 126 ofs.f_fsid = fs->f_fsidx; 127 ofs.f_owner = fs->f_owner; 128 ofs.f_flags = (long)fs->f_flag; 129 ofs.f_syncwrites = CLAMP(fs->f_syncwrites); 130 ofs.f_asyncwrites = CLAMP(fs->f_asyncwrites); 131 (void)strncpy(ofs.f_fstypename, fs->f_fstypename, 132 sizeof(ofs.f_fstypename)); 133 (void)strncpy(ofs.f_mntonname, fs->f_mntonname, 134 sizeof(ofs.f_mntonname)); 135 (void)strncpy(ofs.f_mntfromname, fs->f_mntfromname, 136 sizeof(ofs.f_mntfromname)); 137 138 return copyout(&ofs, bfs, sizeof(ofs)); 139 } 140 141 /* 142 * Get filesystem statistics. 143 */ 144 /* ARGSUSED */ 145 int 146 compat_20_sys_statfs(struct lwp *l, const struct compat_20_sys_statfs_args *uap, register_t *retval) 147 { 148 /* { 149 syscallarg(const char *) path; 150 syscallarg(struct statfs12 *) buf; 151 } */ 152 struct mount *mp; 153 struct statvfs *sbuf; 154 int error; 155 struct vnode *vp; 156 157 error = namei_simple_user(SCARG(uap, path), 158 NSM_FOLLOW_TRYEMULROOT, &vp); 159 if (error != 0) 160 return error; 161 162 mp = vp->v_mount; 163 164 sbuf = malloc(sizeof(*sbuf), M_TEMP, M_WAITOK); 165 if ((error = dostatvfs(mp, sbuf, l, 0, 1)) != 0) 166 goto done; 167 168 error = vfs2fs(SCARG(uap, buf), sbuf); 169 done: 170 vrele(vp); 171 free(sbuf, M_TEMP); 172 return error; 173 } 174 175 /* 176 * Get filesystem statistics. 177 */ 178 /* ARGSUSED */ 179 int 180 compat_20_sys_fstatfs(struct lwp *l, const struct compat_20_sys_fstatfs_args *uap, register_t *retval) 181 { 182 /* { 183 syscallarg(int) fd; 184 syscallarg(struct statfs12 *) buf; 185 } */ 186 struct file *fp; 187 struct mount *mp; 188 struct statvfs *sbuf; 189 int error; 190 191 /* fd_getvnode() will use the descriptor for us */ 192 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) 193 return (error); 194 mp = fp->f_vnode->v_mount; 195 sbuf = malloc(sizeof(*sbuf), M_TEMP, M_WAITOK); 196 if ((error = dostatvfs(mp, sbuf, l, 0, 1)) != 0) 197 goto out; 198 error = vfs2fs(SCARG(uap, buf), sbuf); 199 out: 200 fd_putfile(SCARG(uap, fd)); 201 free(sbuf, M_TEMP); 202 return error; 203 } 204 205 206 /* 207 * Get statistics on all filesystems. 208 */ 209 int 210 compat_20_sys_getfsstat(struct lwp *l, const struct compat_20_sys_getfsstat_args *uap, register_t *retval) 211 { 212 /* { 213 syscallarg(struct statfs12 *) buf; 214 syscallarg(long) bufsize; 215 syscallarg(int) flags; 216 } */ 217 int root = 0; 218 mount_iterator_t *iter; 219 struct mount *mp; 220 struct statvfs *sbuf; 221 struct statfs12 *sfsp; 222 size_t count, maxcount; 223 int error = 0; 224 225 sbuf = malloc(sizeof(*sbuf), M_TEMP, M_WAITOK); 226 maxcount = (size_t)SCARG(uap, bufsize) / sizeof(struct statfs12); 227 sfsp = SCARG(uap, buf); 228 count = 0; 229 mountlist_iterator_init(&iter); 230 while ((mp = mountlist_iterator_next(iter)) != NULL) { 231 if (sfsp && count < maxcount) { 232 error = dostatvfs(mp, sbuf, l, SCARG(uap, flags), 0); 233 if (error) 234 continue; 235 error = vfs2fs(sfsp, sbuf); 236 if (error) 237 goto out; 238 sfsp++; 239 root |= strcmp(sbuf->f_mntonname, "/") == 0; 240 } 241 count++; 242 } 243 if (root == 0 && l->l_proc->p_cwdi->cwdi_rdir) { 244 /* 245 * fake a root entry 246 */ 247 if ((error = dostatvfs(l->l_proc->p_cwdi->cwdi_rdir->v_mount, 248 sbuf, l, SCARG(uap, flags), 1)) != 0) 249 goto out; 250 if (sfsp) 251 error = vfs2fs(sfsp, sbuf); 252 count++; 253 } 254 if (sfsp && count > maxcount) 255 *retval = maxcount; 256 else 257 *retval = count; 258 out: 259 mountlist_iterator_destroy(iter); 260 free(sbuf, M_TEMP); 261 return error; 262 } 263 264 int 265 compat_20_sys_fhstatfs(struct lwp *l, const struct compat_20_sys_fhstatfs_args *uap, register_t *retval) 266 { 267 /* { 268 syscallarg(const struct compat_30_fhandle *) fhp; 269 syscallarg(struct statfs12 *) buf; 270 } */ 271 struct statvfs *sbuf; 272 struct compat_30_fhandle fh; 273 struct mount *mp; 274 struct vnode *vp; 275 int error; 276 277 /* 278 * Must be super user 279 */ 280 if ((error = kauth_authorize_system(l->l_cred, 281 KAUTH_SYSTEM_FILEHANDLE, 0, NULL, NULL, NULL))) 282 return (error); 283 284 if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fh))) != 0) 285 return (error); 286 287 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) 288 return (ESTALE); 289 if ((error = VFS_FHTOVP(mp, (struct fid*)&fh.fh_fid, &vp))) 290 return (error); 291 mp = vp->v_mount; 292 VOP_UNLOCK(vp); 293 sbuf = malloc(sizeof(*sbuf), M_TEMP, M_WAITOK); 294 if ((error = VFS_STATVFS(mp, sbuf)) != 0) 295 goto out; 296 error = vfs2fs(SCARG(uap, buf), sbuf); 297 out: 298 vrele(vp); 299 free(sbuf, M_TEMP); 300 return error; 301 } 302 303 int 304 vfs_syscalls_20_init(void) 305 { 306 307 return syscall_establish(NULL, vfs_syscalls_20_syscalls); 308 } 309 310 int 311 vfs_syscalls_20_fini(void) 312 { 313 314 return syscall_disestablish(NULL, vfs_syscalls_20_syscalls); 315 } 316