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