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