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