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