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