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