1 /* $NetBSD: vfs_syscalls_43.c,v 1.44 2007/12/08 19:29:38 pooka 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.28 (Berkeley) 12/10/94 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: vfs_syscalls_43.c,v 1.44 2007/12/08 19:29:38 pooka Exp $"); 41 42 #if defined(_KERNEL_OPT) 43 #include "fs_union.h" 44 #endif 45 46 #include <sys/param.h> 47 #include <sys/systm.h> 48 #include <sys/filedesc.h> 49 #include <sys/kernel.h> 50 #include <sys/proc.h> 51 #include <sys/file.h> 52 #include <sys/vnode.h> 53 #include <sys/namei.h> 54 #include <sys/dirent.h> 55 #include <sys/socket.h> 56 #include <sys/socketvar.h> 57 #include <sys/stat.h> 58 #include <sys/malloc.h> 59 #include <sys/ioctl.h> 60 #include <sys/fcntl.h> 61 #include <sys/syslog.h> 62 #include <sys/unistd.h> 63 #include <sys/resourcevar.h> 64 #include <sys/sysctl.h> 65 66 #include <sys/mount.h> 67 #include <sys/syscallargs.h> 68 #include <sys/vfs_syscalls.h> 69 70 #include <compat/sys/stat.h> 71 #include <compat/sys/mount.h> 72 73 static void cvtstat(struct stat *, struct stat43 *); 74 75 /* 76 * Convert from an old to a new stat structure. 77 */ 78 static void 79 cvtstat(struct stat *st, struct stat43 *ost) 80 { 81 82 ost->st_dev = st->st_dev; 83 ost->st_ino = st->st_ino; 84 ost->st_mode = st->st_mode & 0xffff; 85 ost->st_nlink = st->st_nlink; 86 ost->st_uid = st->st_uid; 87 ost->st_gid = st->st_gid; 88 ost->st_rdev = st->st_rdev; 89 if (st->st_size < (quad_t)1 << 32) 90 ost->st_size = st->st_size; 91 else 92 ost->st_size = -2; 93 ost->st_atime = st->st_atime; 94 ost->st_mtime = st->st_mtime; 95 ost->st_ctime = st->st_ctime; 96 ost->st_blksize = st->st_blksize; 97 ost->st_blocks = st->st_blocks; 98 ost->st_flags = st->st_flags; 99 ost->st_gen = st->st_gen; 100 } 101 102 /* 103 * Get file status; this version follows links. 104 */ 105 /* ARGSUSED */ 106 int 107 compat_43_sys_stat(struct lwp *l, void *v, register_t *retval) 108 { 109 struct compat_43_sys_stat_args /* { 110 syscallarg(char *) path; 111 syscallarg(struct stat43 *) ub; 112 } */ *uap = v; 113 struct stat sb; 114 struct stat43 osb; 115 int error; 116 117 error = do_sys_stat(l, SCARG(uap, path), FOLLOW, &sb); 118 if (error) 119 return (error); 120 cvtstat(&sb, &osb); 121 error = copyout((void *)&osb, (void *)SCARG(uap, ub), sizeof (osb)); 122 return (error); 123 } 124 125 /* 126 * Get file status; this version does not follow links. 127 */ 128 /* ARGSUSED */ 129 int 130 compat_43_sys_lstat(struct lwp *l, void *v, register_t *retval) 131 { 132 struct compat_43_sys_lstat_args /* { 133 syscallarg(char *) path; 134 syscallarg(struct ostat *) ub; 135 } */ *uap = v; 136 struct vnode *vp, *dvp; 137 struct stat sb, sb1; 138 struct stat43 osb; 139 int error; 140 struct nameidata nd; 141 int ndflags; 142 143 ndflags = NOFOLLOW | LOCKLEAF | LOCKPARENT | TRYEMULROOT; 144 again: 145 NDINIT(&nd, LOOKUP, ndflags, UIO_USERSPACE, SCARG(uap, path)); 146 if ((error = namei(&nd))) { 147 if (error == EISDIR && (ndflags & LOCKPARENT) != 0) { 148 /* 149 * Should only happen on '/'. Retry without LOCKPARENT; 150 * this is safe since the vnode won't be a VLNK. 151 */ 152 ndflags &= ~LOCKPARENT; 153 goto again; 154 } 155 return (error); 156 } 157 /* 158 * For symbolic links, always return the attributes of its 159 * containing directory, except for mode, size, and links. 160 */ 161 vp = nd.ni_vp; 162 dvp = nd.ni_dvp; 163 if (vp->v_type != VLNK) { 164 if ((ndflags & LOCKPARENT) != 0) { 165 if (dvp == vp) 166 vrele(dvp); 167 else 168 vput(dvp); 169 } 170 error = vn_stat(vp, &sb, l); 171 vput(vp); 172 if (error) 173 return (error); 174 } else { 175 error = vn_stat(dvp, &sb, l); 176 vput(dvp); 177 if (error) { 178 vput(vp); 179 return (error); 180 } 181 error = vn_stat(vp, &sb1, l); 182 vput(vp); 183 if (error) 184 return (error); 185 sb.st_mode &= ~S_IFDIR; 186 sb.st_mode |= S_IFLNK; 187 sb.st_nlink = sb1.st_nlink; 188 sb.st_size = sb1.st_size; 189 sb.st_blocks = sb1.st_blocks; 190 } 191 cvtstat(&sb, &osb); 192 error = copyout((void *)&osb, (void *)SCARG(uap, ub), sizeof (osb)); 193 return (error); 194 } 195 196 /* 197 * Return status information about a file descriptor. 198 */ 199 /* ARGSUSED */ 200 int 201 compat_43_sys_fstat(struct lwp *l, void *v, register_t *retval) 202 { 203 struct compat_43_sys_fstat_args /* { 204 syscallarg(int) fd; 205 syscallarg(struct stat43 *) sb; 206 } */ *uap = v; 207 struct proc *p = l->l_proc; 208 int fd = SCARG(uap, fd); 209 struct filedesc *fdp = p->p_fd; 210 struct file *fp; 211 struct stat ub; 212 struct stat43 oub; 213 int error; 214 215 if ((fp = fd_getfile(fdp, fd)) == NULL) 216 return (EBADF); 217 218 FILE_USE(fp); 219 error = (*fp->f_ops->fo_stat)(fp, &ub, l); 220 FILE_UNUSE(fp, l); 221 222 if (error == 0) { 223 cvtstat(&ub, &oub); 224 error = copyout((void *)&oub, (void *)SCARG(uap, sb), 225 sizeof (oub)); 226 } 227 228 229 return (error); 230 } 231 232 233 /* 234 * Truncate a file given a file descriptor. 235 */ 236 /* ARGSUSED */ 237 int 238 compat_43_sys_ftruncate(struct lwp *l, void *v, register_t *retval) 239 { 240 struct compat_43_sys_ftruncate_args /* { 241 syscallarg(int) fd; 242 syscallarg(long) length; 243 } */ *uap = v; 244 struct sys_ftruncate_args /* { 245 syscallarg(int) fd; 246 syscallarg(int) pad; 247 syscallarg(off_t) length; 248 } */ nuap; 249 250 SCARG(&nuap, fd) = SCARG(uap, fd); 251 SCARG(&nuap, length) = SCARG(uap, length); 252 return (sys_ftruncate(l, &nuap, retval)); 253 } 254 255 /* 256 * Truncate a file given its path name. 257 */ 258 /* ARGSUSED */ 259 int 260 compat_43_sys_truncate(struct lwp *l, void *v, register_t *retval) 261 { 262 struct compat_43_sys_truncate_args /* { 263 syscallarg(char *) path; 264 syscallarg(long) length; 265 } */ *uap = v; 266 struct sys_truncate_args /* { 267 syscallarg(char *) path; 268 syscallarg(int) pad; 269 syscallarg(off_t) length; 270 } */ nuap; 271 272 SCARG(&nuap, path) = SCARG(uap, path); 273 SCARG(&nuap, length) = SCARG(uap, length); 274 return (sys_truncate(l, &nuap, retval)); 275 } 276 277 278 /* 279 * Reposition read/write file offset. 280 */ 281 int 282 compat_43_sys_lseek(struct lwp *l, void *v, register_t *retval) 283 { 284 struct compat_43_sys_lseek_args /* { 285 syscallarg(int) fd; 286 syscallarg(long) offset; 287 syscallarg(int) whence; 288 } */ *uap = v; 289 struct sys_lseek_args /* { 290 syscallarg(int) fd; 291 syscallarg(int) pad; 292 syscallarg(off_t) offset; 293 syscallarg(int) whence; 294 } */ nuap; 295 off_t qret; 296 int error; 297 298 SCARG(&nuap, fd) = SCARG(uap, fd); 299 SCARG(&nuap, offset) = SCARG(uap, offset); 300 SCARG(&nuap, whence) = SCARG(uap, whence); 301 error = sys_lseek(l, &nuap, (void *)&qret); 302 *(long *)retval = qret; 303 return (error); 304 } 305 306 307 /* 308 * Create a file. 309 */ 310 int 311 compat_43_sys_creat(struct lwp *l, void *v, register_t *retval) 312 { 313 struct compat_43_sys_creat_args /* { 314 syscallarg(char *) path; 315 syscallarg(int) mode; 316 } */ *uap = v; 317 struct sys_open_args /* { 318 syscallarg(char *) path; 319 syscallarg(int) flags; 320 syscallarg(int) mode; 321 } */ nuap; 322 323 SCARG(&nuap, path) = SCARG(uap, path); 324 SCARG(&nuap, mode) = SCARG(uap, mode); 325 SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC; 326 return (sys_open(l, &nuap, retval)); 327 } 328 329 /*ARGSUSED*/ 330 int 331 compat_43_sys_quota(struct lwp *l, void *v, 332 register_t *retval) 333 { 334 335 return (ENOSYS); 336 } 337 338 339 /* 340 * Read a block of directory entries in a file system independent format. 341 */ 342 int 343 compat_43_sys_getdirentries(struct lwp *l, void *v, register_t *retval) 344 { 345 struct compat_43_sys_getdirentries_args /* { 346 syscallarg(int) fd; 347 syscallarg(char *) buf; 348 syscallarg(u_int) count; 349 syscallarg(long *) basep; 350 } */ *uap = v; 351 struct proc *p = l->l_proc; 352 struct vnode *vp; 353 struct file *fp; 354 struct uio auio, kuio; 355 struct iovec aiov, kiov; 356 struct dirent *dp, *edp; 357 char *dirbuf; 358 size_t count = min(MAXBSIZE, (size_t)SCARG(uap, count)); 359 360 int error, eofflag, readcnt; 361 long loff; 362 363 /* getvnode() will use the descriptor for us */ 364 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 365 return (error); 366 if ((fp->f_flag & FREAD) == 0) { 367 error = EBADF; 368 goto out; 369 } 370 vp = (struct vnode *)fp->f_data; 371 unionread: 372 if (vp->v_type != VDIR) { 373 error = EINVAL; 374 goto out; 375 } 376 aiov.iov_base = SCARG(uap, buf); 377 aiov.iov_len = count; 378 auio.uio_iov = &aiov; 379 auio.uio_iovcnt = 1; 380 auio.uio_rw = UIO_READ; 381 auio.uio_resid = count; 382 KASSERT(l == curlwp); 383 auio.uio_vmspace = l->l_proc->p_vmspace; 384 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 385 loff = auio.uio_offset = fp->f_offset; 386 # if (BYTE_ORDER != LITTLE_ENDIAN) 387 if ((vp->v_mount->mnt_iflag & IMNT_DTYPE) == 0) { 388 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 389 (off_t **)0, (int *)0); 390 fp->f_offset = auio.uio_offset; 391 } else 392 # endif 393 { 394 kuio = auio; 395 kuio.uio_iov = &kiov; 396 kiov.iov_len = count; 397 dirbuf = malloc(count, M_TEMP, M_WAITOK); 398 kiov.iov_base = dirbuf; 399 UIO_SETUP_SYSSPACE(&kuio); 400 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, 401 (off_t **)0, (int *)0); 402 fp->f_offset = kuio.uio_offset; 403 if (error == 0) { 404 readcnt = count - kuio.uio_resid; 405 edp = (struct dirent *)&dirbuf[readcnt]; 406 for (dp = (struct dirent *)dirbuf; dp < edp; ) { 407 # if (BYTE_ORDER == LITTLE_ENDIAN) 408 /* 409 * The expected low byte of 410 * dp->d_namlen is our dp->d_type. 411 * The high MBZ byte of dp->d_namlen 412 * is our dp->d_namlen. 413 */ 414 dp->d_type = dp->d_namlen; 415 dp->d_namlen = 0; 416 # else 417 /* 418 * The dp->d_type is the high byte 419 * of the expected dp->d_namlen, 420 * so must be zero'ed. 421 */ 422 dp->d_type = 0; 423 # endif 424 if (dp->d_reclen > 0) { 425 dp = (struct dirent *) 426 ((char *)dp + dp->d_reclen); 427 } else { 428 error = EIO; 429 break; 430 } 431 } 432 if (dp >= edp) 433 error = uiomove(dirbuf, readcnt, &auio); 434 } 435 free(dirbuf, M_TEMP); 436 } 437 VOP_UNLOCK(vp, 0); 438 if (error) 439 goto out; 440 441 #ifdef UNION 442 { 443 extern int (**union_vnodeop_p)(void *); 444 extern struct vnode *union_dircache(struct vnode *); 445 446 if ((count == auio.uio_resid) && 447 (vp->v_op == union_vnodeop_p)) { 448 struct vnode *lvp; 449 450 lvp = union_dircache(vp); 451 if (lvp != NULLVP) { 452 struct vattr va; 453 454 /* 455 * If the directory is opaque, 456 * then don't show lower entries 457 */ 458 error = VOP_GETATTR(vp, &va, fp->f_cred); 459 if (va.va_flags & OPAQUE) { 460 vput(lvp); 461 lvp = NULL; 462 } 463 } 464 465 if (lvp != NULLVP) { 466 error = VOP_OPEN(lvp, FREAD, fp->f_cred); 467 VOP_UNLOCK(lvp, 0); 468 469 if (error) { 470 vrele(lvp); 471 goto out; 472 } 473 fp->f_data = (void *) lvp; 474 fp->f_offset = 0; 475 error = vn_close(vp, FREAD, fp->f_cred, l); 476 if (error) 477 goto out; 478 vp = lvp; 479 goto unionread; 480 } 481 } 482 } 483 #endif /* UNION */ 484 485 if ((count == auio.uio_resid) && 486 (vp->v_vflag & VV_ROOT) && 487 (vp->v_mount->mnt_flag & MNT_UNION)) { 488 struct vnode *tvp = vp; 489 vp = vp->v_mount->mnt_vnodecovered; 490 VREF(vp); 491 fp->f_data = (void *) vp; 492 fp->f_offset = 0; 493 vrele(tvp); 494 goto unionread; 495 } 496 error = copyout((void *)&loff, (void *)SCARG(uap, basep), 497 sizeof(long)); 498 *retval = count - auio.uio_resid; 499 out: 500 FILE_UNUSE(fp, l); 501 return (error); 502 } 503 504 /* 505 * sysctl helper routine for vfs.generic.conf lookups. 506 */ 507 #if defined(COMPAT_09) || defined(COMPAT_43) || defined(COMPAT_44) 508 static int 509 sysctl_vfs_generic_conf(SYSCTLFN_ARGS) 510 { 511 struct vfsconf vfc; 512 extern const char * const mountcompatnames[]; 513 extern int nmountcompatnames; 514 struct sysctlnode node; 515 struct vfsops *vfsp; 516 u_int vfsnum; 517 518 if (namelen != 1) 519 return (ENOTDIR); 520 vfsnum = name[0]; 521 if (vfsnum >= nmountcompatnames || 522 mountcompatnames[vfsnum] == NULL) 523 return (EOPNOTSUPP); 524 vfsp = vfs_getopsbyname(mountcompatnames[vfsnum]); 525 if (vfsp == NULL) 526 return (EOPNOTSUPP); 527 528 vfc.vfc_vfsops = vfsp; 529 strncpy(vfc.vfc_name, vfsp->vfs_name, sizeof(vfc.vfc_name)); 530 vfc.vfc_typenum = vfsnum; 531 vfc.vfc_refcount = vfsp->vfs_refcount; 532 vfc.vfc_flags = 0; 533 vfc.vfc_mountroot = vfsp->vfs_mountroot; 534 vfc.vfc_next = NULL; 535 vfs_delref(vfsp); 536 537 node = *rnode; 538 node.sysctl_data = &vfc; 539 return (sysctl_lookup(SYSCTLFN_CALL(&node))); 540 } 541 542 /* 543 * Top level filesystem related information gathering. 544 */ 545 SYSCTL_SETUP(compat_sysctl_vfs_setup, "compat sysctl vfs subtree setup") 546 { 547 extern int nmountcompatnames; 548 549 sysctl_createv(clog, 0, NULL, NULL, 550 CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE, 551 CTLTYPE_INT, "maxtypenum", 552 SYSCTL_DESCR("Highest valid filesystem type number"), 553 NULL, nmountcompatnames, NULL, 0, 554 CTL_VFS, VFS_GENERIC, VFS_MAXTYPENUM, CTL_EOL); 555 sysctl_createv(clog, 0, NULL, NULL, 556 CTLFLAG_PERMANENT, 557 CTLTYPE_STRUCT, "conf", 558 SYSCTL_DESCR("Filesystem configuration information"), 559 sysctl_vfs_generic_conf, 0, NULL, 560 sizeof(struct vfsconf), 561 CTL_VFS, VFS_GENERIC, VFS_CONF, CTL_EOL); 562 } 563 #endif 564