1 /* $NetBSD: vfs_syscalls_43.c,v 1.19 2001/06/14 20:32:41 thorpej 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. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * @(#)vfs_syscalls.c 8.28 (Berkeley) 12/10/94 41 */ 42 43 #if defined(_KERNEL_OPT) 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/ioctl.h> 60 #include <sys/fcntl.h> 61 #include <sys/malloc.h> 62 #include <sys/syslog.h> 63 #include <sys/unistd.h> 64 #include <sys/resourcevar.h> 65 66 #include <sys/mount.h> 67 #include <sys/syscallargs.h> 68 69 static void cvtstat __P((struct stat *, struct stat43 *)); 70 71 /* 72 * Convert from an old to a new stat structure. 73 */ 74 static void 75 cvtstat(st, ost) 76 struct stat *st; 77 struct stat43 *ost; 78 { 79 80 ost->st_dev = st->st_dev; 81 ost->st_ino = st->st_ino; 82 ost->st_mode = st->st_mode & 0xffff; 83 ost->st_nlink = st->st_nlink; 84 ost->st_uid = st->st_uid; 85 ost->st_gid = st->st_gid; 86 ost->st_rdev = st->st_rdev; 87 if (st->st_size < (quad_t)1 << 32) 88 ost->st_size = st->st_size; 89 else 90 ost->st_size = -2; 91 ost->st_atime = st->st_atime; 92 ost->st_mtime = st->st_mtime; 93 ost->st_ctime = st->st_ctime; 94 ost->st_blksize = st->st_blksize; 95 ost->st_blocks = st->st_blocks; 96 ost->st_flags = st->st_flags; 97 ost->st_gen = st->st_gen; 98 } 99 100 /* 101 * Get file status; this version follows links. 102 */ 103 /* ARGSUSED */ 104 int 105 compat_43_sys_stat(p, v, retval) 106 struct proc *p; 107 void *v; 108 register_t *retval; 109 { 110 struct compat_43_sys_stat_args /* { 111 syscallarg(char *) path; 112 syscallarg(struct stat43 *) ub; 113 } */ *uap = v; 114 struct stat sb; 115 struct stat43 osb; 116 int error; 117 struct nameidata nd; 118 119 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 120 SCARG(uap, path), p); 121 if ((error = namei(&nd)) != 0) 122 return (error); 123 error = vn_stat(nd.ni_vp, &sb, p); 124 vput(nd.ni_vp); 125 if (error) 126 return (error); 127 cvtstat(&sb, &osb); 128 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 129 return (error); 130 } 131 132 /* 133 * Get file status; this version does not follow links. 134 */ 135 /* ARGSUSED */ 136 int 137 compat_43_sys_lstat(p, v, retval) 138 struct proc *p; 139 void *v; 140 register_t *retval; 141 { 142 struct compat_43_sys_lstat_args /* { 143 syscallarg(char *) path; 144 syscallarg(struct ostat *) ub; 145 } */ *uap = v; 146 struct vnode *vp, *dvp; 147 struct stat sb, sb1; 148 struct stat43 osb; 149 int error; 150 struct nameidata nd; 151 int ndflags; 152 153 ndflags = NOFOLLOW | LOCKLEAF | LOCKPARENT; 154 again: 155 NDINIT(&nd, LOOKUP, ndflags, UIO_USERSPACE, SCARG(uap, path), p); 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 return (error); 166 } 167 /* 168 * For symbolic links, always return the attributes of its 169 * containing directory, except for mode, size, and links. 170 */ 171 vp = nd.ni_vp; 172 dvp = nd.ni_dvp; 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, p); 181 vput(vp); 182 if (error) 183 return (error); 184 } else { 185 error = vn_stat(dvp, &sb, p); 186 vput(dvp); 187 if (error) { 188 vput(vp); 189 return (error); 190 } 191 error = vn_stat(vp, &sb1, p); 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((caddr_t)&osb, (caddr_t)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(p, v, retval) 212 struct proc *p; 213 void *v; 214 register_t *retval; 215 { 216 struct compat_43_sys_fstat_args /* { 217 syscallarg(int) fd; 218 syscallarg(struct stat43 *) sb; 219 } */ *uap = v; 220 int fd = SCARG(uap, fd); 221 struct filedesc *fdp = p->p_fd; 222 struct file *fp; 223 struct stat ub; 224 struct stat43 oub; 225 int error; 226 227 if ((fp = fd_getfile(fdp, fd)) == NULL) 228 return (EBADF); 229 230 FILE_USE(fp); 231 error = (*fp->f_ops->fo_stat)(fp, &ub, p); 232 FILE_UNUSE(fp, p); 233 234 if (error == 0) { 235 cvtstat(&ub, &oub); 236 error = copyout((caddr_t)&oub, (caddr_t)SCARG(uap, sb), 237 sizeof (oub)); 238 } 239 240 241 return (error); 242 } 243 244 245 /* 246 * Truncate a file given a file descriptor. 247 */ 248 /* ARGSUSED */ 249 int 250 compat_43_sys_ftruncate(p, v, retval) 251 struct proc *p; 252 void *v; 253 register_t *retval; 254 { 255 struct compat_43_sys_ftruncate_args /* { 256 syscallarg(int) fd; 257 syscallarg(long) length; 258 } */ *uap = v; 259 struct sys_ftruncate_args /* { 260 syscallarg(int) fd; 261 syscallarg(int) pad; 262 syscallarg(off_t) length; 263 } */ nuap; 264 265 SCARG(&nuap, fd) = SCARG(uap, fd); 266 SCARG(&nuap, length) = SCARG(uap, length); 267 return (sys_ftruncate(p, &nuap, retval)); 268 } 269 270 /* 271 * Truncate a file given its path name. 272 */ 273 /* ARGSUSED */ 274 int 275 compat_43_sys_truncate(p, v, retval) 276 struct proc *p; 277 void *v; 278 register_t *retval; 279 { 280 struct compat_43_sys_truncate_args /* { 281 syscallarg(char *) path; 282 syscallarg(long) length; 283 } */ *uap = v; 284 struct sys_truncate_args /* { 285 syscallarg(char *) path; 286 syscallarg(int) pad; 287 syscallarg(off_t) length; 288 } */ nuap; 289 290 SCARG(&nuap, path) = SCARG(uap, path); 291 SCARG(&nuap, length) = SCARG(uap, length); 292 return (sys_truncate(p, &nuap, retval)); 293 } 294 295 296 /* 297 * Reposition read/write file offset. 298 */ 299 int 300 compat_43_sys_lseek(p, v, retval) 301 struct proc *p; 302 void *v; 303 register_t *retval; 304 { 305 struct compat_43_sys_lseek_args /* { 306 syscallarg(int) fd; 307 syscallarg(long) offset; 308 syscallarg(int) whence; 309 } */ *uap = v; 310 struct sys_lseek_args /* { 311 syscallarg(int) fd; 312 syscallarg(int) pad; 313 syscallarg(off_t) offset; 314 syscallarg(int) whence; 315 } */ nuap; 316 off_t qret; 317 int error; 318 319 SCARG(&nuap, fd) = SCARG(uap, fd); 320 SCARG(&nuap, offset) = SCARG(uap, offset); 321 SCARG(&nuap, whence) = SCARG(uap, whence); 322 error = sys_lseek(p, &nuap, (register_t *)&qret); 323 *(long *)retval = qret; 324 return (error); 325 } 326 327 328 /* 329 * Create a file. 330 */ 331 int 332 compat_43_sys_creat(p, v, retval) 333 struct proc *p; 334 void *v; 335 register_t *retval; 336 { 337 struct compat_43_sys_creat_args /* { 338 syscallarg(char *) path; 339 syscallarg(int) mode; 340 } */ *uap = v; 341 struct sys_open_args /* { 342 syscallarg(char *) path; 343 syscallarg(int) flags; 344 syscallarg(int) mode; 345 } */ nuap; 346 347 SCARG(&nuap, path) = SCARG(uap, path); 348 SCARG(&nuap, mode) = SCARG(uap, mode); 349 SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC; 350 return (sys_open(p, &nuap, retval)); 351 } 352 353 /*ARGSUSED*/ 354 int 355 compat_43_sys_quota(p, v, retval) 356 struct proc *p; 357 void *v; 358 register_t *retval; 359 { 360 361 return (ENOSYS); 362 } 363 364 365 /* 366 * Read a block of directory entries in a file system independent format. 367 */ 368 int 369 compat_43_sys_getdirentries(p, v, retval) 370 struct proc *p; 371 void *v; 372 register_t *retval; 373 { 374 struct compat_43_sys_getdirentries_args /* { 375 syscallarg(int) fd; 376 syscallarg(char *) buf; 377 syscallarg(u_int) count; 378 syscallarg(long *) basep; 379 } */ *uap = v; 380 struct vnode *vp; 381 struct file *fp; 382 struct uio auio, kuio; 383 struct iovec aiov, kiov; 384 struct dirent *dp, *edp; 385 caddr_t dirbuf; 386 int error, eofflag, readcnt; 387 long loff; 388 389 /* getvnode() will use the descriptor for us */ 390 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 391 return (error); 392 if ((fp->f_flag & FREAD) == 0) { 393 error = EBADF; 394 goto out; 395 } 396 vp = (struct vnode *)fp->f_data; 397 unionread: 398 if (vp->v_type != VDIR) { 399 error = EINVAL; 400 goto out; 401 } 402 aiov.iov_base = SCARG(uap, buf); 403 aiov.iov_len = SCARG(uap, count); 404 auio.uio_iov = &aiov; 405 auio.uio_iovcnt = 1; 406 auio.uio_rw = UIO_READ; 407 auio.uio_segflg = UIO_USERSPACE; 408 auio.uio_procp = p; 409 auio.uio_resid = SCARG(uap, count); 410 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 411 loff = auio.uio_offset = fp->f_offset; 412 # if (BYTE_ORDER != LITTLE_ENDIAN) 413 if (vp->v_mount->mnt_maxsymlinklen <= 0) { 414 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 415 (off_t **)0, (int *)0); 416 fp->f_offset = auio.uio_offset; 417 } else 418 # endif 419 { 420 kuio = auio; 421 kuio.uio_iov = &kiov; 422 kuio.uio_segflg = UIO_SYSSPACE; 423 kiov.iov_len = SCARG(uap, count); 424 MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK); 425 kiov.iov_base = dirbuf; 426 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, 427 (off_t **)0, (int *)0); 428 fp->f_offset = kuio.uio_offset; 429 if (error == 0) { 430 readcnt = SCARG(uap, count) - kuio.uio_resid; 431 edp = (struct dirent *)&dirbuf[readcnt]; 432 for (dp = (struct dirent *)dirbuf; dp < edp; ) { 433 # if (BYTE_ORDER == LITTLE_ENDIAN) 434 /* 435 * The expected low byte of 436 * dp->d_namlen is our dp->d_type. 437 * The high MBZ byte of dp->d_namlen 438 * is our dp->d_namlen. 439 */ 440 dp->d_type = dp->d_namlen; 441 dp->d_namlen = 0; 442 # else 443 /* 444 * The dp->d_type is the high byte 445 * of the expected dp->d_namlen, 446 * so must be zero'ed. 447 */ 448 dp->d_type = 0; 449 # endif 450 if (dp->d_reclen > 0) { 451 dp = (struct dirent *) 452 ((char *)dp + dp->d_reclen); 453 } else { 454 error = EIO; 455 break; 456 } 457 } 458 if (dp >= edp) 459 error = uiomove(dirbuf, readcnt, &auio); 460 } 461 FREE(dirbuf, M_TEMP); 462 } 463 VOP_UNLOCK(vp, 0); 464 if (error) 465 goto out; 466 467 #ifdef UNION 468 { 469 extern int (**union_vnodeop_p) __P((void *)); 470 extern struct vnode *union_dircache __P((struct vnode *)); 471 472 if ((SCARG(uap, count) == auio.uio_resid) && 473 (vp->v_op == union_vnodeop_p)) { 474 struct vnode *lvp; 475 476 lvp = union_dircache(vp); 477 if (lvp != NULLVP) { 478 struct vattr va; 479 480 /* 481 * If the directory is opaque, 482 * then don't show lower entries 483 */ 484 error = VOP_GETATTR(vp, &va, fp->f_cred, p); 485 if (va.va_flags & OPAQUE) { 486 vput(lvp); 487 lvp = NULL; 488 } 489 } 490 491 if (lvp != NULLVP) { 492 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 493 VOP_UNLOCK(lvp, 0); 494 495 if (error) { 496 vrele(lvp); 497 goto out; 498 } 499 fp->f_data = (caddr_t) lvp; 500 fp->f_offset = 0; 501 error = vn_close(vp, FREAD, fp->f_cred, p); 502 if (error) 503 goto out; 504 vp = lvp; 505 goto unionread; 506 } 507 } 508 } 509 #endif /* UNION */ 510 511 if ((SCARG(uap, count) == auio.uio_resid) && 512 (vp->v_flag & VROOT) && 513 (vp->v_mount->mnt_flag & MNT_UNION)) { 514 struct vnode *tvp = vp; 515 vp = vp->v_mount->mnt_vnodecovered; 516 VREF(vp); 517 fp->f_data = (caddr_t) vp; 518 fp->f_offset = 0; 519 vrele(tvp); 520 goto unionread; 521 } 522 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 523 sizeof(long)); 524 *retval = SCARG(uap, count) - auio.uio_resid; 525 out: 526 FILE_UNUSE(fp, p); 527 return (error); 528 } 529