1 /* $NetBSD: vfs_syscalls_43.c,v 1.22 2003/01/18 07:28:34 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 #include <sys/cdefs.h> 44 __KERNEL_RCSID(0, "$NetBSD: vfs_syscalls_43.c,v 1.22 2003/01/18 07:28:34 thorpej Exp $"); 45 46 #if defined(_KERNEL_OPT) 47 #include "fs_union.h" 48 #endif 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/filedesc.h> 53 #include <sys/kernel.h> 54 #include <sys/proc.h> 55 #include <sys/file.h> 56 #include <sys/vnode.h> 57 #include <sys/namei.h> 58 #include <sys/dirent.h> 59 #include <sys/socket.h> 60 #include <sys/socketvar.h> 61 #include <sys/stat.h> 62 #include <sys/ioctl.h> 63 #include <sys/fcntl.h> 64 #include <sys/malloc.h> 65 #include <sys/syslog.h> 66 #include <sys/unistd.h> 67 #include <sys/resourcevar.h> 68 69 #include <sys/mount.h> 70 #include <sys/sa.h> 71 #include <sys/syscallargs.h> 72 73 static void cvtstat __P((struct stat *, struct stat43 *)); 74 75 /* 76 * Convert from an old to a new stat structure. 77 */ 78 static void 79 cvtstat(st, ost) 80 struct stat *st; 81 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, void *v, register_t *retval) 110 { 111 struct compat_43_sys_stat_args /* { 112 syscallarg(char *) path; 113 syscallarg(struct stat43 *) ub; 114 } */ *uap = v; 115 struct proc *p = l->l_proc; 116 struct stat sb; 117 struct stat43 osb; 118 int error; 119 struct nameidata nd; 120 121 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 122 SCARG(uap, path), p); 123 if ((error = namei(&nd)) != 0) 124 return (error); 125 error = vn_stat(nd.ni_vp, &sb, p); 126 vput(nd.ni_vp); 127 if (error) 128 return (error); 129 cvtstat(&sb, &osb); 130 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 131 return (error); 132 } 133 134 /* 135 * Get file status; this version does not follow links. 136 */ 137 /* ARGSUSED */ 138 int 139 compat_43_sys_lstat(struct lwp *l, void *v, register_t *retval) 140 { 141 struct compat_43_sys_lstat_args /* { 142 syscallarg(char *) path; 143 syscallarg(struct ostat *) ub; 144 } */ *uap = v; 145 struct proc *p = l->l_proc; 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(struct lwp *l, void *v, register_t *retval) 212 { 213 struct compat_43_sys_fstat_args /* { 214 syscallarg(int) fd; 215 syscallarg(struct stat43 *) sb; 216 } */ *uap = v; 217 struct proc *p = l->l_proc; 218 int fd = SCARG(uap, fd); 219 struct filedesc *fdp = p->p_fd; 220 struct file *fp; 221 struct stat ub; 222 struct stat43 oub; 223 int error; 224 225 if ((fp = fd_getfile(fdp, fd)) == NULL) 226 return (EBADF); 227 228 FILE_USE(fp); 229 error = (*fp->f_ops->fo_stat)(fp, &ub, p); 230 FILE_UNUSE(fp, p); 231 232 if (error == 0) { 233 cvtstat(&ub, &oub); 234 error = copyout((caddr_t)&oub, (caddr_t)SCARG(uap, sb), 235 sizeof (oub)); 236 } 237 238 239 return (error); 240 } 241 242 243 /* 244 * Truncate a file given a file descriptor. 245 */ 246 /* ARGSUSED */ 247 int 248 compat_43_sys_ftruncate(struct lwp *l, void *v, register_t *retval) 249 { 250 struct compat_43_sys_ftruncate_args /* { 251 syscallarg(int) fd; 252 syscallarg(long) length; 253 } */ *uap = v; 254 struct sys_ftruncate_args /* { 255 syscallarg(int) fd; 256 syscallarg(int) pad; 257 syscallarg(off_t) length; 258 } */ nuap; 259 260 SCARG(&nuap, fd) = SCARG(uap, fd); 261 SCARG(&nuap, length) = SCARG(uap, length); 262 return (sys_ftruncate(l, &nuap, retval)); 263 } 264 265 /* 266 * Truncate a file given its path name. 267 */ 268 /* ARGSUSED */ 269 int 270 compat_43_sys_truncate(struct lwp *l, void *v, register_t *retval) 271 { 272 struct compat_43_sys_truncate_args /* { 273 syscallarg(char *) path; 274 syscallarg(long) length; 275 } */ *uap = v; 276 struct sys_truncate_args /* { 277 syscallarg(char *) path; 278 syscallarg(int) pad; 279 syscallarg(off_t) length; 280 } */ nuap; 281 282 SCARG(&nuap, path) = SCARG(uap, path); 283 SCARG(&nuap, length) = SCARG(uap, length); 284 return (sys_truncate(l, &nuap, retval)); 285 } 286 287 288 /* 289 * Reposition read/write file offset. 290 */ 291 int 292 compat_43_sys_lseek(struct lwp *l, void *v, register_t *retval) 293 { 294 struct compat_43_sys_lseek_args /* { 295 syscallarg(int) fd; 296 syscallarg(long) offset; 297 syscallarg(int) whence; 298 } */ *uap = v; 299 struct sys_lseek_args /* { 300 syscallarg(int) fd; 301 syscallarg(int) pad; 302 syscallarg(off_t) offset; 303 syscallarg(int) whence; 304 } */ nuap; 305 off_t qret; 306 int error; 307 308 SCARG(&nuap, fd) = SCARG(uap, fd); 309 SCARG(&nuap, offset) = SCARG(uap, offset); 310 SCARG(&nuap, whence) = SCARG(uap, whence); 311 error = sys_lseek(l, &nuap, (void *)&qret); 312 *(long *)retval = qret; 313 return (error); 314 } 315 316 317 /* 318 * Create a file. 319 */ 320 int 321 compat_43_sys_creat(struct lwp *l, void *v, register_t *retval) 322 { 323 struct compat_43_sys_creat_args /* { 324 syscallarg(char *) path; 325 syscallarg(int) mode; 326 } */ *uap = v; 327 struct sys_open_args /* { 328 syscallarg(char *) path; 329 syscallarg(int) flags; 330 syscallarg(int) mode; 331 } */ nuap; 332 333 SCARG(&nuap, path) = SCARG(uap, path); 334 SCARG(&nuap, mode) = SCARG(uap, mode); 335 SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC; 336 return (sys_open(l, &nuap, retval)); 337 } 338 339 /*ARGSUSED*/ 340 int 341 compat_43_sys_quota(struct lwp *l, void *v, register_t *retval) 342 { 343 344 return (ENOSYS); 345 } 346 347 348 /* 349 * Read a block of directory entries in a file system independent format. 350 */ 351 int 352 compat_43_sys_getdirentries(struct lwp *l, void *v, register_t *retval) 353 { 354 struct compat_43_sys_getdirentries_args /* { 355 syscallarg(int) fd; 356 syscallarg(char *) buf; 357 syscallarg(u_int) count; 358 syscallarg(long *) basep; 359 } */ *uap = v; 360 struct proc *p = l->l_proc; 361 struct vnode *vp; 362 struct file *fp; 363 struct uio auio, kuio; 364 struct iovec aiov, kiov; 365 struct dirent *dp, *edp; 366 caddr_t dirbuf; 367 int error, eofflag, readcnt; 368 long loff; 369 370 /* getvnode() will use the descriptor for us */ 371 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0) 372 return (error); 373 if ((fp->f_flag & FREAD) == 0) { 374 error = EBADF; 375 goto out; 376 } 377 vp = (struct vnode *)fp->f_data; 378 unionread: 379 if (vp->v_type != VDIR) { 380 error = EINVAL; 381 goto out; 382 } 383 aiov.iov_base = SCARG(uap, buf); 384 aiov.iov_len = SCARG(uap, count); 385 auio.uio_iov = &aiov; 386 auio.uio_iovcnt = 1; 387 auio.uio_rw = UIO_READ; 388 auio.uio_segflg = UIO_USERSPACE; 389 auio.uio_procp = p; 390 auio.uio_resid = SCARG(uap, count); 391 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 392 loff = auio.uio_offset = fp->f_offset; 393 # if (BYTE_ORDER != LITTLE_ENDIAN) 394 if (vp->v_mount->mnt_maxsymlinklen <= 0) { 395 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 396 (off_t **)0, (int *)0); 397 fp->f_offset = auio.uio_offset; 398 } else 399 # endif 400 { 401 kuio = auio; 402 kuio.uio_iov = &kiov; 403 kuio.uio_segflg = UIO_SYSSPACE; 404 kiov.iov_len = SCARG(uap, count); 405 MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK); 406 kiov.iov_base = dirbuf; 407 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, 408 (off_t **)0, (int *)0); 409 fp->f_offset = kuio.uio_offset; 410 if (error == 0) { 411 readcnt = SCARG(uap, count) - kuio.uio_resid; 412 edp = (struct dirent *)&dirbuf[readcnt]; 413 for (dp = (struct dirent *)dirbuf; dp < edp; ) { 414 # if (BYTE_ORDER == LITTLE_ENDIAN) 415 /* 416 * The expected low byte of 417 * dp->d_namlen is our dp->d_type. 418 * The high MBZ byte of dp->d_namlen 419 * is our dp->d_namlen. 420 */ 421 dp->d_type = dp->d_namlen; 422 dp->d_namlen = 0; 423 # else 424 /* 425 * The dp->d_type is the high byte 426 * of the expected dp->d_namlen, 427 * so must be zero'ed. 428 */ 429 dp->d_type = 0; 430 # endif 431 if (dp->d_reclen > 0) { 432 dp = (struct dirent *) 433 ((char *)dp + dp->d_reclen); 434 } else { 435 error = EIO; 436 break; 437 } 438 } 439 if (dp >= edp) 440 error = uiomove(dirbuf, readcnt, &auio); 441 } 442 FREE(dirbuf, M_TEMP); 443 } 444 VOP_UNLOCK(vp, 0); 445 if (error) 446 goto out; 447 448 #ifdef UNION 449 { 450 extern int (**union_vnodeop_p) __P((void *)); 451 extern struct vnode *union_dircache __P((struct vnode *)); 452 453 if ((SCARG(uap, count) == auio.uio_resid) && 454 (vp->v_op == union_vnodeop_p)) { 455 struct vnode *lvp; 456 457 lvp = union_dircache(vp); 458 if (lvp != NULLVP) { 459 struct vattr va; 460 461 /* 462 * If the directory is opaque, 463 * then don't show lower entries 464 */ 465 error = VOP_GETATTR(vp, &va, fp->f_cred, p); 466 if (va.va_flags & OPAQUE) { 467 vput(lvp); 468 lvp = NULL; 469 } 470 } 471 472 if (lvp != NULLVP) { 473 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 474 VOP_UNLOCK(lvp, 0); 475 476 if (error) { 477 vrele(lvp); 478 goto out; 479 } 480 fp->f_data = (caddr_t) lvp; 481 fp->f_offset = 0; 482 error = vn_close(vp, FREAD, fp->f_cred, p); 483 if (error) 484 goto out; 485 vp = lvp; 486 goto unionread; 487 } 488 } 489 } 490 #endif /* UNION */ 491 492 if ((SCARG(uap, count) == auio.uio_resid) && 493 (vp->v_flag & VROOT) && 494 (vp->v_mount->mnt_flag & MNT_UNION)) { 495 struct vnode *tvp = vp; 496 vp = vp->v_mount->mnt_vnodecovered; 497 VREF(vp); 498 fp->f_data = (caddr_t) vp; 499 fp->f_offset = 0; 500 vrele(tvp); 501 goto unionread; 502 } 503 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 504 sizeof(long)); 505 *retval = SCARG(uap, count) - auio.uio_resid; 506 out: 507 FILE_UNUSE(fp, p); 508 return (error); 509 } 510