1 /* $NetBSD: vfs_syscalls_30.c,v 1.28 2008/06/24 11:18:15 ad 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.28 2008/06/24 11:18:15 ad 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 ost->st_atimespec = st->st_atimespec; 75 ost->st_mtimespec = st->st_mtimespec; 76 ost->st_ctimespec = st->st_ctimespec; 77 ost->st_birthtimespec = st->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 int fd = SCARG(uap, fd); 184 struct file *fp; 185 struct stat sb; 186 struct stat13 osb; 187 int error; 188 189 if ((fp = fd_getfile(fd)) == NULL) 190 return EBADF; 191 error = (*fp->f_ops->fo_stat)(fp, &sb); 192 fd_putfile(fd); 193 if (error) 194 return error; 195 cvtstat(&osb, &sb); 196 error = copyout(&osb, SCARG(uap, sb), sizeof (osb)); 197 return error; 198 } 199 200 /* 201 * Read a block of directory entries in a file system independent format. 202 */ 203 int 204 compat_30_sys_getdents(struct lwp *l, const struct compat_30_sys_getdents_args *uap, register_t *retval) 205 { 206 /* { 207 syscallarg(int) fd; 208 syscallarg(char *) buf; 209 syscallarg(size_t) count; 210 } */ 211 struct dirent *bdp; 212 struct vnode *vp; 213 char *inp, *tbuf; /* BSD-format */ 214 int len, reclen; /* BSD-format */ 215 char *outp; /* NetBSD-3.0-format */ 216 int resid; 217 struct file *fp; 218 struct uio auio; 219 struct iovec aiov; 220 struct dirent12 idb; 221 off_t off; /* true file offset */ 222 int buflen, error, eofflag; 223 off_t *cookiebuf = NULL, *cookie; 224 int ncookies; 225 226 /* fd_getvnode() will use the descriptor for us */ 227 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) 228 return error; 229 230 if ((fp->f_flag & FREAD) == 0) { 231 error = EBADF; 232 goto out1; 233 } 234 235 vp = fp->f_data; 236 if (vp->v_type != VDIR) { 237 error = EINVAL; 238 goto out1; 239 } 240 241 buflen = min(MAXBSIZE, SCARG(uap, count)); 242 tbuf = malloc(buflen, M_TEMP, M_WAITOK); 243 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 244 off = fp->f_offset; 245 again: 246 aiov.iov_base = tbuf; 247 aiov.iov_len = buflen; 248 auio.uio_iov = &aiov; 249 auio.uio_iovcnt = 1; 250 auio.uio_rw = UIO_READ; 251 auio.uio_resid = buflen; 252 auio.uio_offset = off; 253 UIO_SETUP_SYSSPACE(&auio); 254 /* 255 * First we read into the malloc'ed buffer, then 256 * we massage it into user space, one record at a time. 257 */ 258 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &cookiebuf, 259 &ncookies); 260 if (error) 261 goto out; 262 263 inp = tbuf; 264 outp = SCARG(uap, buf); 265 resid = SCARG(uap, count); 266 if ((len = buflen - auio.uio_resid) == 0) 267 goto eof; 268 269 for (cookie = cookiebuf; len > 0; len -= reclen) { 270 bdp = (struct dirent *)inp; 271 reclen = bdp->d_reclen; 272 if (reclen & _DIRENT_ALIGN(bdp)) 273 panic("netbsd30_getdents: bad reclen %d", reclen); 274 if (cookie) 275 off = *cookie++; /* each entry points to the next */ 276 else 277 off += reclen; 278 if ((off >> 32) != 0) { 279 compat_offseterr(vp, "netbsd30_getdents"); 280 error = EINVAL; 281 goto out; 282 } 283 if (bdp->d_namlen >= sizeof(idb.d_name)) 284 idb.d_namlen = sizeof(idb.d_name) - 1; 285 else 286 idb.d_namlen = bdp->d_namlen; 287 idb.d_reclen = _DIRENT_SIZE(&idb); 288 if (reclen > len || resid < idb.d_reclen) { 289 /* entry too big for buffer, so just stop */ 290 outp++; 291 break; 292 } 293 /* 294 * Massage in place to make a NetBSD-3.0-shaped dirent 295 * (otherwise we have to worry about touching user memory 296 * outside of the copyout() call). 297 */ 298 idb.d_fileno = (u_int32_t)bdp->d_fileno; 299 idb.d_type = bdp->d_type; 300 (void)memcpy(idb.d_name, bdp->d_name, idb.d_namlen); 301 memset(idb.d_name + idb.d_namlen, 0, 302 idb.d_reclen - _DIRENT_NAMEOFF(&idb) - idb.d_namlen); 303 if ((error = copyout(&idb, outp, idb.d_reclen)) != 0) 304 goto out; 305 /* advance past this real entry */ 306 inp += reclen; 307 /* advance output past NetBSD-3.0-shaped entry */ 308 outp += idb.d_reclen; 309 resid -= idb.d_reclen; 310 } 311 312 /* if we squished out the whole block, try again */ 313 if (outp == SCARG(uap, buf)) 314 goto again; 315 fp->f_offset = off; /* update the vnode offset */ 316 317 eof: 318 *retval = SCARG(uap, count) - resid; 319 out: 320 VOP_UNLOCK(vp, 0); 321 if (cookiebuf) 322 free(cookiebuf, M_TEMP); 323 free(tbuf, M_TEMP); 324 out1: 325 fd_putfile(SCARG(uap, fd)); 326 return error; 327 } 328 329 /* 330 * Get file handle system call 331 */ 332 int 333 compat_30_sys_getfh(struct lwp *l, const struct compat_30_sys_getfh_args *uap, register_t *retval) 334 { 335 /* { 336 syscallarg(char *) fname; 337 syscallarg(struct compat_30_fhandle *) fhp; 338 } */ 339 struct vnode *vp; 340 struct compat_30_fhandle fh; 341 int error; 342 struct nameidata nd; 343 size_t sz; 344 345 /* 346 * Must be super user 347 */ 348 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_FILEHANDLE, 349 0, NULL, NULL, NULL); 350 if (error) 351 return (error); 352 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, UIO_USERSPACE, 353 SCARG(uap, fname)); 354 error = namei(&nd); 355 if (error) 356 return (error); 357 vp = nd.ni_vp; 358 sz = sizeof(struct compat_30_fhandle); 359 error = vfs_composefh(vp, (void *)&fh, &sz); 360 vput(vp); 361 if (sz != FHANDLE_SIZE_COMPAT) { 362 error = EINVAL; 363 } 364 if (error) 365 return (error); 366 error = copyout(&fh, SCARG(uap, fhp), sizeof(struct compat_30_fhandle)); 367 return (error); 368 } 369 370 /* 371 * Open a file given a file handle. 372 * 373 * Check permissions, allocate an open file structure, 374 * and call the device open routine if any. 375 */ 376 int 377 compat_30_sys_fhopen(struct lwp *l, const struct compat_30_sys_fhopen_args *uap, register_t *retval) 378 { 379 /* { 380 syscallarg(const fhandle_t *) fhp; 381 syscallarg(int) flags; 382 } */ 383 384 return dofhopen(l, SCARG(uap, fhp), FHANDLE_SIZE_COMPAT, 385 SCARG(uap, flags), retval); 386 } 387 388 /* ARGSUSED */ 389 int 390 compat_30_sys___fhstat30(struct lwp *l, const struct compat_30_sys___fhstat30_args *uap_30, register_t *retval) 391 { 392 /* { 393 syscallarg(const fhandle_t *) fhp; 394 syscallarg(struct stat *) sb; 395 } */ 396 struct sys___fhstat40_args uap; 397 398 SCARG(&uap, fhp) = SCARG(uap_30, fhp); 399 SCARG(&uap, fh_size) = FHANDLE_SIZE_COMPAT; 400 SCARG(&uap, sb) = SCARG(uap_30, sb); 401 402 return sys___fhstat40(l, &uap, retval); 403 } 404 405 /* ARGSUSED */ 406 int 407 compat_30_sys_fhstatvfs1(struct lwp *l, const struct compat_30_sys_fhstatvfs1_args *uap_30, register_t *retval) 408 { 409 /* { 410 syscallarg(const fhandle_t *) fhp; 411 syscallarg(struct statvfs *) buf; 412 syscallarg(int) flags; 413 } */ 414 struct sys___fhstatvfs140_args uap; 415 416 SCARG(&uap, fhp) = SCARG(uap_30, fhp); 417 SCARG(&uap, fh_size) = FHANDLE_SIZE_COMPAT; 418 SCARG(&uap, buf) = SCARG(uap_30, buf); 419 SCARG(&uap, flags) = SCARG(uap_30, flags); 420 421 return sys___fhstatvfs140(l, &uap, retval); 422 } 423