1 /* $NetBSD: vfs_syscalls_30.c,v 1.30 2009/01/26 13:00:04 njoly Exp $ */ 2 3 /*- 4 * Copyright (c) 2005, 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: vfs_syscalls_30.c,v 1.30 2009/01/26 13:00:04 njoly Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/namei.h> 37 #include <sys/filedesc.h> 38 #include <sys/kernel.h> 39 #include <sys/file.h> 40 #include <sys/stat.h> 41 #include <sys/socketvar.h> 42 #include <sys/vnode.h> 43 #include <sys/mount.h> 44 #include <sys/proc.h> 45 #include <sys/uio.h> 46 #include <sys/dirent.h> 47 #include <sys/malloc.h> 48 #include <sys/kauth.h> 49 #include <sys/vfs_syscalls.h> 50 51 #include <sys/syscallargs.h> 52 53 #include <compat/common/compat_util.h> 54 #include <compat/sys/stat.h> 55 #include <compat/sys/dirent.h> 56 #include <compat/sys/mount.h> 57 58 static void cvtstat(struct stat13 *, const struct stat *); 59 60 /* 61 * Convert from a new to an old stat structure. 62 */ 63 static void 64 cvtstat(struct stat13 *ost, const struct stat *st) 65 { 66 67 ost->st_dev = st->st_dev; 68 ost->st_ino = (uint32_t)st->st_ino; 69 ost->st_mode = st->st_mode; 70 ost->st_nlink = st->st_nlink; 71 ost->st_uid = st->st_uid; 72 ost->st_gid = st->st_gid; 73 ost->st_rdev = st->st_rdev; 74 timespec_to_timespec50(&st->st_atimespec, &ost->st_atimespec); 75 timespec_to_timespec50(&st->st_mtimespec, &ost->st_mtimespec); 76 timespec_to_timespec50(&st->st_ctimespec, &ost->st_ctimespec); 77 timespec_to_timespec50(&st->st_birthtimespec, &ost->st_birthtimespec); 78 ost->st_size = st->st_size; 79 ost->st_blocks = st->st_blocks; 80 ost->st_blksize = st->st_blksize; 81 ost->st_flags = st->st_flags; 82 ost->st_gen = st->st_gen; 83 } 84 85 /* 86 * Get file status; this version follows links. 87 */ 88 /* ARGSUSED */ 89 int 90 compat_30_sys___stat13(struct lwp *l, const struct compat_30_sys___stat13_args *uap, register_t *retval) 91 { 92 /* { 93 syscallarg(const char *) path; 94 syscallarg(struct stat13 *) ub; 95 } */ 96 struct stat sb; 97 struct stat13 osb; 98 int error; 99 100 error = do_sys_stat(SCARG(uap, path), FOLLOW, &sb); 101 if (error) 102 return error; 103 cvtstat(&osb, &sb); 104 error = copyout(&osb, SCARG(uap, ub), sizeof (osb)); 105 return error; 106 } 107 108 109 /* 110 * Get file status; this version does not follow links. 111 */ 112 /* ARGSUSED */ 113 int 114 compat_30_sys___lstat13(struct lwp *l, const struct compat_30_sys___lstat13_args *uap, register_t *retval) 115 { 116 /* { 117 syscallarg(const char *) path; 118 syscallarg(struct stat13 *) ub; 119 } */ 120 struct stat sb; 121 struct stat13 osb; 122 int error; 123 124 error = do_sys_stat(SCARG(uap, path), NOFOLLOW, &sb); 125 if (error) 126 return error; 127 cvtstat(&osb, &sb); 128 error = copyout(&osb, SCARG(uap, ub), sizeof (osb)); 129 return error; 130 } 131 132 /* ARGSUSED */ 133 int 134 compat_30_sys_fhstat(struct lwp *l, const struct compat_30_sys_fhstat_args *uap, register_t *retval) 135 { 136 /* { 137 syscallarg(const struct compat_30_fhandle *) fhp; 138 syscallarg(struct stat13 *) sb; 139 } */ 140 struct stat sb; 141 struct stat13 osb; 142 int error; 143 struct compat_30_fhandle fh; 144 struct mount *mp; 145 struct vnode *vp; 146 147 /* 148 * Must be super user 149 */ 150 if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE, 151 0, NULL, NULL, NULL))) 152 return (error); 153 154 if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fh))) != 0) 155 return (error); 156 157 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) 158 return (ESTALE); 159 if (mp->mnt_op->vfs_fhtovp == NULL) 160 return EOPNOTSUPP; 161 if ((error = VFS_FHTOVP(mp, (struct fid*)&fh.fh_fid, &vp))) 162 return (error); 163 error = vn_stat(vp, &sb); 164 vput(vp); 165 if (error) 166 return (error); 167 cvtstat(&osb, &sb); 168 error = copyout(&osb, SCARG(uap, sb), sizeof(sb)); 169 return (error); 170 } 171 172 /* 173 * Return status information about a file descriptor. 174 */ 175 /* ARGSUSED */ 176 int 177 compat_30_sys___fstat13(struct lwp *l, const struct compat_30_sys___fstat13_args *uap, register_t *retval) 178 { 179 /* { 180 syscallarg(int) fd; 181 syscallarg(struct stat13 *) sb; 182 } */ 183 struct stat sb; 184 struct stat13 osb; 185 int error; 186 187 error = do_sys_fstat(SCARG(uap, fd), &sb); 188 if (error) 189 return error; 190 cvtstat(&osb, &sb); 191 error = copyout(&osb, SCARG(uap, sb), sizeof (osb)); 192 return error; 193 } 194 195 /* 196 * Read a block of directory entries in a file system independent format. 197 */ 198 int 199 compat_30_sys_getdents(struct lwp *l, const struct compat_30_sys_getdents_args *uap, register_t *retval) 200 { 201 /* { 202 syscallarg(int) fd; 203 syscallarg(char *) buf; 204 syscallarg(size_t) count; 205 } */ 206 struct dirent *bdp; 207 struct vnode *vp; 208 char *inp, *tbuf; /* BSD-format */ 209 int len, reclen; /* BSD-format */ 210 char *outp; /* NetBSD-3.0-format */ 211 int resid; 212 struct file *fp; 213 struct uio auio; 214 struct iovec aiov; 215 struct dirent12 idb; 216 off_t off; /* true file offset */ 217 int buflen, error, eofflag; 218 off_t *cookiebuf = NULL, *cookie; 219 int ncookies; 220 221 /* fd_getvnode() will use the descriptor for us */ 222 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) 223 return error; 224 225 if ((fp->f_flag & FREAD) == 0) { 226 error = EBADF; 227 goto out1; 228 } 229 230 vp = fp->f_data; 231 if (vp->v_type != VDIR) { 232 error = EINVAL; 233 goto out1; 234 } 235 236 buflen = min(MAXBSIZE, SCARG(uap, count)); 237 tbuf = malloc(buflen, M_TEMP, M_WAITOK); 238 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 239 off = fp->f_offset; 240 again: 241 aiov.iov_base = tbuf; 242 aiov.iov_len = buflen; 243 auio.uio_iov = &aiov; 244 auio.uio_iovcnt = 1; 245 auio.uio_rw = UIO_READ; 246 auio.uio_resid = buflen; 247 auio.uio_offset = off; 248 UIO_SETUP_SYSSPACE(&auio); 249 /* 250 * First we read into the malloc'ed buffer, then 251 * we massage it into user space, one record at a time. 252 */ 253 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &cookiebuf, 254 &ncookies); 255 if (error) 256 goto out; 257 258 inp = tbuf; 259 outp = SCARG(uap, buf); 260 resid = SCARG(uap, count); 261 if ((len = buflen - auio.uio_resid) == 0) 262 goto eof; 263 264 for (cookie = cookiebuf; len > 0; len -= reclen) { 265 bdp = (struct dirent *)inp; 266 reclen = bdp->d_reclen; 267 if (reclen & _DIRENT_ALIGN(bdp)) 268 panic("netbsd30_getdents: bad reclen %d", reclen); 269 if (cookie) 270 off = *cookie++; /* each entry points to the next */ 271 else 272 off += reclen; 273 if ((off >> 32) != 0) { 274 compat_offseterr(vp, "netbsd30_getdents"); 275 error = EINVAL; 276 goto out; 277 } 278 if (bdp->d_namlen >= sizeof(idb.d_name)) 279 idb.d_namlen = sizeof(idb.d_name) - 1; 280 else 281 idb.d_namlen = bdp->d_namlen; 282 idb.d_reclen = _DIRENT_SIZE(&idb); 283 if (reclen > len || resid < idb.d_reclen) { 284 /* entry too big for buffer, so just stop */ 285 outp++; 286 break; 287 } 288 /* 289 * Massage in place to make a NetBSD-3.0-shaped dirent 290 * (otherwise we have to worry about touching user memory 291 * outside of the copyout() call). 292 */ 293 idb.d_fileno = (u_int32_t)bdp->d_fileno; 294 idb.d_type = bdp->d_type; 295 (void)memcpy(idb.d_name, bdp->d_name, idb.d_namlen); 296 memset(idb.d_name + idb.d_namlen, 0, 297 idb.d_reclen - _DIRENT_NAMEOFF(&idb) - idb.d_namlen); 298 if ((error = copyout(&idb, outp, idb.d_reclen)) != 0) 299 goto out; 300 /* advance past this real entry */ 301 inp += reclen; 302 /* advance output past NetBSD-3.0-shaped entry */ 303 outp += idb.d_reclen; 304 resid -= idb.d_reclen; 305 } 306 307 /* if we squished out the whole block, try again */ 308 if (outp == SCARG(uap, buf)) 309 goto again; 310 fp->f_offset = off; /* update the vnode offset */ 311 312 eof: 313 *retval = SCARG(uap, count) - resid; 314 out: 315 VOP_UNLOCK(vp, 0); 316 if (cookiebuf) 317 free(cookiebuf, M_TEMP); 318 free(tbuf, M_TEMP); 319 out1: 320 fd_putfile(SCARG(uap, fd)); 321 return error; 322 } 323 324 /* 325 * Get file handle system call 326 */ 327 int 328 compat_30_sys_getfh(struct lwp *l, const struct compat_30_sys_getfh_args *uap, register_t *retval) 329 { 330 /* { 331 syscallarg(char *) fname; 332 syscallarg(struct compat_30_fhandle *) fhp; 333 } */ 334 struct vnode *vp; 335 struct compat_30_fhandle fh; 336 int error; 337 struct nameidata nd; 338 size_t sz; 339 340 /* 341 * Must be super user 342 */ 343 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE, 344 0, NULL, NULL, NULL); 345 if (error) 346 return (error); 347 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, UIO_USERSPACE, 348 SCARG(uap, fname)); 349 error = namei(&nd); 350 if (error) 351 return (error); 352 vp = nd.ni_vp; 353 sz = sizeof(struct compat_30_fhandle); 354 error = vfs_composefh(vp, (void *)&fh, &sz); 355 vput(vp); 356 if (sz != FHANDLE_SIZE_COMPAT) { 357 error = EINVAL; 358 } 359 if (error) 360 return (error); 361 error = copyout(&fh, SCARG(uap, fhp), sizeof(struct compat_30_fhandle)); 362 return (error); 363 } 364 365 /* 366 * Open a file given a file handle. 367 * 368 * Check permissions, allocate an open file structure, 369 * and call the device open routine if any. 370 */ 371 int 372 compat_30_sys_fhopen(struct lwp *l, const struct compat_30_sys_fhopen_args *uap, register_t *retval) 373 { 374 /* { 375 syscallarg(const fhandle_t *) fhp; 376 syscallarg(int) flags; 377 } */ 378 379 return dofhopen(l, SCARG(uap, fhp), FHANDLE_SIZE_COMPAT, 380 SCARG(uap, flags), retval); 381 } 382 383 /* ARGSUSED */ 384 int 385 compat_30_sys___fhstat30(struct lwp *l, const struct compat_30_sys___fhstat30_args *uap_30, register_t *retval) 386 { 387 /* { 388 syscallarg(const fhandle_t *) fhp; 389 syscallarg(struct stat30 *) sb; 390 } */ 391 struct stat sb; 392 struct stat13 osb; 393 int error; 394 395 error = do_fhstat(l, SCARG(uap_30, fhp), FHANDLE_SIZE_COMPAT, &sb); 396 if (error) 397 return error; 398 cvtstat(&osb, &sb); 399 error = copyout(&osb, SCARG(uap_30, sb), sizeof (osb)); 400 return error; 401 } 402 403 /* ARGSUSED */ 404 int 405 compat_30_sys_fhstatvfs1(struct lwp *l, const struct compat_30_sys_fhstatvfs1_args *uap_30, register_t *retval) 406 { 407 /* { 408 syscallarg(const fhandle_t *) fhp; 409 syscallarg(struct statvfs *) buf; 410 syscallarg(int) flags; 411 } */ 412 struct sys___fhstatvfs140_args uap; 413 414 SCARG(&uap, fhp) = SCARG(uap_30, fhp); 415 SCARG(&uap, fh_size) = FHANDLE_SIZE_COMPAT; 416 SCARG(&uap, buf) = SCARG(uap_30, buf); 417 SCARG(&uap, flags) = SCARG(uap_30, flags); 418 419 return sys___fhstatvfs140(l, &uap, retval); 420 } 421