1 /* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)vfs_syscalls.c 8.13 (Berkeley) 4/15/94 39 * $Id: vfs_syscalls.c,v 1.64 1997/04/04 17:46:19 dfr Exp $ 40 */ 41 42 /* 43 * XXX - The following is required because of some magic done 44 * in getdirentries() below which is only done if the translucent 45 * filesystem `UNION' is compiled into the kernel. This is broken, 46 * but I don't have time to study the code deeply enough to understand 47 * what's going on and determine an appropriate fix. -GAW 48 */ 49 #include "opt_union.h" 50 51 #include <sys/param.h> 52 #include <sys/systm.h> 53 #include <sys/sysent.h> 54 #include <sys/sysproto.h> 55 #include <sys/namei.h> 56 #include <sys/filedesc.h> 57 #include <sys/kernel.h> 58 #include <sys/fcntl.h> 59 #include <sys/file.h> 60 #include <sys/stat.h> 61 #include <sys/unistd.h> 62 #include <sys/vnode.h> 63 #include <sys/mount.h> 64 #include <sys/proc.h> 65 #include <sys/uio.h> 66 #include <sys/malloc.h> 67 #include <sys/dirent.h> 68 69 #ifdef UNION 70 #include <miscfs/union/union.h> 71 #endif 72 73 #include <vm/vm.h> 74 #include <vm/vm_param.h> 75 #include <vm/vm_object.h> 76 #include <vm/vm_extern.h> 77 #include <sys/sysctl.h> 78 79 static int change_dir __P((struct nameidata *ndp, struct proc *p)); 80 static void checkdirs __P((struct vnode *olddp)); 81 82 /* 83 * Virtual File System System Calls 84 */ 85 86 /* 87 * Mount a file system. 88 */ 89 #ifndef _SYS_SYSPROTO_H_ 90 struct mount_args { 91 char *type; 92 char *path; 93 int flags; 94 caddr_t data; 95 }; 96 #endif 97 /* ARGSUSED */ 98 int 99 mount(p, uap, retval) 100 struct proc *p; 101 register struct mount_args /* { 102 syscallarg(char *) type; 103 syscallarg(char *) path; 104 syscallarg(int) flags; 105 syscallarg(caddr_t) data; 106 } */ *uap; 107 register_t *retval; 108 { 109 struct vnode *vp; 110 struct mount *mp; 111 struct vfsconf *vfsp; 112 int error, flag = 0; 113 struct vattr va; 114 u_long fstypenum; 115 struct nameidata nd; 116 char fstypename[MFSNAMELEN]; 117 118 /* 119 * Get vnode to be covered 120 */ 121 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 122 SCARG(uap, path), p); 123 if (error = namei(&nd)) 124 return (error); 125 vp = nd.ni_vp; 126 if (SCARG(uap, flags) & MNT_UPDATE) { 127 if ((vp->v_flag & VROOT) == 0) { 128 vput(vp); 129 return (EINVAL); 130 } 131 mp = vp->v_mount; 132 flag = mp->mnt_flag; 133 /* 134 * We only allow the filesystem to be reloaded if it 135 * is currently mounted read-only. 136 */ 137 if ((SCARG(uap, flags) & MNT_RELOAD) && 138 ((mp->mnt_flag & MNT_RDONLY) == 0)) { 139 vput(vp); 140 return (EOPNOTSUPP); /* Needs translation */ 141 } 142 mp->mnt_flag |= 143 SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); 144 /* 145 * Only root, or the user that did the original mount is 146 * permitted to update it. 147 */ 148 if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid && 149 (error = suser(p->p_ucred, &p->p_acflag))) { 150 vput(vp); 151 return (error); 152 } 153 /* 154 * Do not allow NFS export by non-root users. Silently 155 * enforce MNT_NOSUID and MNT_NODEV for non-root users. 156 */ 157 if (p->p_ucred->cr_uid != 0) { 158 if (SCARG(uap, flags) & MNT_EXPORTED) { 159 vput(vp); 160 return (EPERM); 161 } 162 SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; 163 } 164 if (vfs_busy(mp, LK_NOWAIT, 0, p)) { 165 vput(vp); 166 return (EBUSY); 167 } 168 VOP_UNLOCK(vp, 0, p); 169 goto update; 170 } 171 /* 172 * If the user is not root, ensure that they own the directory 173 * onto which we are attempting to mount. 174 */ 175 if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) || 176 (va.va_uid != p->p_ucred->cr_uid && 177 (error = suser(p->p_ucred, &p->p_acflag)))) { 178 vput(vp); 179 return (error); 180 } 181 /* 182 * Do not allow NFS export by non-root users. Silently 183 * enforce MNT_NOSUID and MNT_NODEV for non-root users. 184 */ 185 if (p->p_ucred->cr_uid != 0) { 186 if (SCARG(uap, flags) & MNT_EXPORTED) { 187 vput(vp); 188 return (EPERM); 189 } 190 SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; 191 } 192 if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) 193 return (error); 194 if (vp->v_type != VDIR) { 195 vput(vp); 196 return (ENOTDIR); 197 } 198 #ifdef COMPAT_43 199 /* 200 * Historically filesystem types were identified by number. If we 201 * get an integer for the filesystem type instead of a string, we 202 * check to see if it matches one of the historic filesystem types. 203 */ 204 fstypenum = (u_long)SCARG(uap, type); 205 if (fstypenum < maxvfsconf) { 206 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) 207 if (vfsp->vfc_typenum == fstypenum) 208 break; 209 if (vfsp == NULL) { 210 vput(vp); 211 return (ENODEV); 212 } 213 strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN); 214 } else 215 #endif /* COMPAT_43 */ 216 if (error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL)) { 217 vput(vp); 218 return (error); 219 } 220 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) 221 if (!strcmp(vfsp->vfc_name, fstypename)) 222 break; 223 if (vfsp == NULL) { 224 vput(vp); 225 return (ENODEV); 226 } 227 if (vp->v_mountedhere != NULL) { 228 vput(vp); 229 return (EBUSY); 230 } 231 232 /* 233 * Allocate and initialize the filesystem. 234 */ 235 mp = (struct mount *)malloc((u_long)sizeof(struct mount), 236 M_MOUNT, M_WAITOK); 237 bzero((char *)mp, (u_long)sizeof(struct mount)); 238 lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0); 239 (void)vfs_busy(mp, LK_NOWAIT, 0, p); 240 mp->mnt_op = vfsp->vfc_vfsops; 241 mp->mnt_vfc = vfsp; 242 vfsp->vfc_refcount++; 243 mp->mnt_stat.f_type = vfsp->vfc_typenum; 244 mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; 245 strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); 246 vp->v_mountedhere = mp; 247 mp->mnt_vnodecovered = vp; 248 mp->mnt_stat.f_owner = p->p_ucred->cr_uid; 249 update: 250 /* 251 * Set the mount level flags. 252 */ 253 if (SCARG(uap, flags) & MNT_RDONLY) 254 mp->mnt_flag |= MNT_RDONLY; 255 else if (mp->mnt_flag & MNT_RDONLY) 256 mp->mnt_flag |= MNT_WANTRDWR; 257 mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | 258 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOATIME); 259 mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC | 260 MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_FORCE | 261 MNT_NOATIME); 262 /* 263 * Mount the filesystem. 264 */ 265 error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p); 266 if (mp->mnt_flag & MNT_UPDATE) { 267 vrele(vp); 268 if (mp->mnt_flag & MNT_WANTRDWR) 269 mp->mnt_flag &= ~MNT_RDONLY; 270 mp->mnt_flag &=~ 271 (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR); 272 if (error) 273 mp->mnt_flag = flag; 274 vfs_unbusy(mp, p); 275 return (error); 276 } 277 /* 278 * Put the new filesystem on the mount list after root. 279 */ 280 cache_purge(vp); 281 if (!error) { 282 simple_lock(&mountlist_slock); 283 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); 284 simple_unlock(&mountlist_slock); 285 checkdirs(vp); 286 VOP_UNLOCK(vp, 0, p); 287 vfs_unbusy(mp, p); 288 if (error = VFS_START(mp, 0, p)) 289 vrele(vp); 290 } else { 291 mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 292 mp->mnt_vfc->vfc_refcount--; 293 vfs_unbusy(mp, p); 294 free((caddr_t)mp, M_MOUNT); 295 vput(vp); 296 } 297 return (error); 298 } 299 300 /* 301 * Scan all active processes to see if any of them have a current 302 * or root directory onto which the new filesystem has just been 303 * mounted. If so, replace them with the new mount point. 304 */ 305 static void 306 checkdirs(olddp) 307 struct vnode *olddp; 308 { 309 struct filedesc *fdp; 310 struct vnode *newdp; 311 struct proc *p; 312 313 if (olddp->v_usecount == 1) 314 return; 315 if (VFS_ROOT(olddp->v_mountedhere, &newdp)) 316 panic("mount: lost mount"); 317 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { 318 fdp = p->p_fd; 319 if (fdp->fd_cdir == olddp) { 320 vrele(fdp->fd_cdir); 321 VREF(newdp); 322 fdp->fd_cdir = newdp; 323 } 324 if (fdp->fd_rdir == olddp) { 325 vrele(fdp->fd_rdir); 326 VREF(newdp); 327 fdp->fd_rdir = newdp; 328 } 329 } 330 if (rootvnode == olddp) { 331 vrele(rootvnode); 332 VREF(newdp); 333 rootvnode = newdp; 334 } 335 vput(newdp); 336 } 337 338 /* 339 * Unmount a file system. 340 * 341 * Note: unmount takes a path to the vnode mounted on as argument, 342 * not special file (as before). 343 */ 344 #ifndef _SYS_SYSPROTO_H_ 345 struct unmount_args { 346 char *path; 347 int flags; 348 }; 349 #endif 350 /* ARGSUSED */ 351 int 352 unmount(p, uap, retval) 353 struct proc *p; 354 register struct unmount_args /* { 355 syscallarg(char *) path; 356 syscallarg(int) flags; 357 } */ *uap; 358 register_t *retval; 359 { 360 register struct vnode *vp; 361 struct mount *mp; 362 int error; 363 struct nameidata nd; 364 365 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 366 SCARG(uap, path), p); 367 if (error = namei(&nd)) 368 return (error); 369 vp = nd.ni_vp; 370 mp = vp->v_mount; 371 372 /* 373 * Only root, or the user that did the original mount is 374 * permitted to unmount this filesystem. 375 */ 376 if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) && 377 (error = suser(p->p_ucred, &p->p_acflag))) { 378 vput(vp); 379 return (error); 380 } 381 382 /* 383 * Don't allow unmounting the root file system. 384 */ 385 if (mp->mnt_flag & MNT_ROOTFS) { 386 vput(vp); 387 return (EINVAL); 388 } 389 390 /* 391 * Must be the root of the filesystem 392 */ 393 if ((vp->v_flag & VROOT) == 0) { 394 vput(vp); 395 return (EINVAL); 396 } 397 vput(vp); 398 return (dounmount(mp, SCARG(uap, flags), p)); 399 } 400 401 /* 402 * Do the actual file system unmount. 403 */ 404 int 405 dounmount(mp, flags, p) 406 register struct mount *mp; 407 int flags; 408 struct proc *p; 409 { 410 struct vnode *coveredvp; 411 int error; 412 413 simple_lock(&mountlist_slock); 414 mp->mnt_flag |= MNT_UNMOUNT; 415 lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_slock, p); 416 mp->mnt_flag &=~ MNT_ASYNC; 417 vfs_msync(mp, MNT_NOWAIT); 418 vnode_pager_umount(mp); /* release cached vnodes */ 419 cache_purgevfs(mp); /* remove cache entries for this file sys */ 420 if (((mp->mnt_flag & MNT_RDONLY) || 421 (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) || 422 (flags & MNT_FORCE)) 423 error = VFS_UNMOUNT(mp, flags, p); 424 simple_lock(&mountlist_slock); 425 if (error) { 426 mp->mnt_flag &= ~MNT_UNMOUNT; 427 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK | LK_REENABLE, 428 &mountlist_slock, p); 429 return (error); 430 } 431 CIRCLEQ_REMOVE(&mountlist, mp, mnt_list); 432 if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) { 433 coveredvp->v_mountedhere = (struct mount *)0; 434 vrele(coveredvp); 435 } 436 mp->mnt_vfc->vfc_refcount--; 437 if (mp->mnt_vnodelist.lh_first != NULL) 438 panic("unmount: dangling vnode"); 439 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock, p); 440 if (mp->mnt_flag & MNT_MWAIT) 441 wakeup((caddr_t)mp); 442 free((caddr_t)mp, M_MOUNT); 443 return (0); 444 } 445 446 /* 447 * Sync each mounted filesystem. 448 */ 449 #ifndef _SYS_SYSPROTO_H_ 450 struct sync_args { 451 int dummy; 452 }; 453 #endif 454 455 #ifdef DEBUG 456 int syncprt = 0; 457 SYSCTL_INT(_debug, 0, syncprt, CTLFLAG_RW, &syncprt, 0, ""); 458 #endif 459 460 /* ARGSUSED */ 461 int 462 sync(p, uap, retval) 463 struct proc *p; 464 struct sync_args *uap; 465 register_t *retval; 466 { 467 register struct mount *mp, *nmp; 468 int asyncflag; 469 470 simple_lock(&mountlist_slock); 471 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { 472 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { 473 nmp = mp->mnt_list.cqe_next; 474 continue; 475 } 476 if ((mp->mnt_flag & MNT_RDONLY) == 0) { 477 asyncflag = mp->mnt_flag & MNT_ASYNC; 478 mp->mnt_flag &= ~MNT_ASYNC; 479 vfs_msync(mp, MNT_NOWAIT); 480 VFS_SYNC(mp, MNT_NOWAIT, p != NULL ? p->p_ucred : NOCRED, p); 481 if (asyncflag) 482 mp->mnt_flag |= MNT_ASYNC; 483 } 484 simple_lock(&mountlist_slock); 485 nmp = mp->mnt_list.cqe_next; 486 vfs_unbusy(mp, p); 487 } 488 simple_unlock(&mountlist_slock); 489 #if 0 490 /* 491 * XXX don't call vfs_bufstats() yet because that routine 492 * was not imported in the Lite2 merge. 493 */ 494 #ifdef DIAGNOSTIC 495 if (syncprt) 496 vfs_bufstats(); 497 #endif /* DIAGNOSTIC */ 498 #endif 499 return (0); 500 } 501 502 /* 503 * Change filesystem quotas. 504 */ 505 #ifndef _SYS_SYSPROTO_H_ 506 struct quotactl_args { 507 char *path; 508 int cmd; 509 int uid; 510 caddr_t arg; 511 }; 512 #endif 513 /* ARGSUSED */ 514 int 515 quotactl(p, uap, retval) 516 struct proc *p; 517 register struct quotactl_args /* { 518 syscallarg(char *) path; 519 syscallarg(int) cmd; 520 syscallarg(int) uid; 521 syscallarg(caddr_t) arg; 522 } */ *uap; 523 register_t *retval; 524 { 525 register struct mount *mp; 526 int error; 527 struct nameidata nd; 528 529 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 530 if (error = namei(&nd)) 531 return (error); 532 mp = nd.ni_vp->v_mount; 533 vrele(nd.ni_vp); 534 return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid), 535 SCARG(uap, arg), p)); 536 } 537 538 /* 539 * Get filesystem statistics. 540 */ 541 #ifndef _SYS_SYSPROTO_H_ 542 struct statfs_args { 543 char *path; 544 struct statfs *buf; 545 }; 546 #endif 547 /* ARGSUSED */ 548 int 549 statfs(p, uap, retval) 550 struct proc *p; 551 register struct statfs_args /* { 552 syscallarg(char *) path; 553 syscallarg(struct statfs *) buf; 554 } */ *uap; 555 register_t *retval; 556 { 557 register struct mount *mp; 558 register struct statfs *sp; 559 int error; 560 struct nameidata nd; 561 struct statfs sb; 562 563 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 564 if (error = namei(&nd)) 565 return (error); 566 mp = nd.ni_vp->v_mount; 567 sp = &mp->mnt_stat; 568 vrele(nd.ni_vp); 569 error = VFS_STATFS(mp, sp, p); 570 if (error) 571 return (error); 572 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 573 if (p->p_ucred->cr_uid != 0) { 574 bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); 575 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; 576 sp = &sb; 577 } 578 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 579 } 580 581 /* 582 * Get filesystem statistics. 583 */ 584 #ifndef _SYS_SYSPROTO_H_ 585 struct fstatfs_args { 586 int fd; 587 struct statfs *buf; 588 }; 589 #endif 590 /* ARGSUSED */ 591 int 592 fstatfs(p, uap, retval) 593 struct proc *p; 594 register struct fstatfs_args /* { 595 syscallarg(int) fd; 596 syscallarg(struct statfs *) buf; 597 } */ *uap; 598 register_t *retval; 599 { 600 struct file *fp; 601 struct mount *mp; 602 register struct statfs *sp; 603 int error; 604 struct statfs sb; 605 606 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 607 return (error); 608 mp = ((struct vnode *)fp->f_data)->v_mount; 609 sp = &mp->mnt_stat; 610 error = VFS_STATFS(mp, sp, p); 611 if (error) 612 return (error); 613 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 614 if (p->p_ucred->cr_uid != 0) { 615 bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); 616 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; 617 sp = &sb; 618 } 619 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); 620 } 621 622 /* 623 * Get statistics on all filesystems. 624 */ 625 #ifndef _SYS_SYSPROTO_H_ 626 struct getfsstat_args { 627 struct statfs *buf; 628 long bufsize; 629 int flags; 630 }; 631 #endif 632 int 633 getfsstat(p, uap, retval) 634 struct proc *p; 635 register struct getfsstat_args /* { 636 syscallarg(struct statfs *) buf; 637 syscallarg(long) bufsize; 638 syscallarg(int) flags; 639 } */ *uap; 640 register_t *retval; 641 { 642 register struct mount *mp, *nmp; 643 register struct statfs *sp; 644 caddr_t sfsp; 645 long count, maxcount, error; 646 647 maxcount = SCARG(uap, bufsize) / sizeof(struct statfs); 648 sfsp = (caddr_t)SCARG(uap, buf); 649 count = 0; 650 simple_lock(&mountlist_slock); 651 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) { 652 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { 653 nmp = mp->mnt_list.cqe_next; 654 continue; 655 } 656 if (sfsp && count < maxcount) { 657 sp = &mp->mnt_stat; 658 /* 659 * If MNT_NOWAIT is specified, do not refresh the 660 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 661 */ 662 if (((SCARG(uap, flags) & MNT_NOWAIT) == 0 || 663 (SCARG(uap, flags) & MNT_WAIT)) && 664 (error = VFS_STATFS(mp, sp, p))) { 665 simple_lock(&mountlist_slock); 666 nmp = mp->mnt_list.cqe_next; 667 vfs_unbusy(mp, p); 668 continue; 669 } 670 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 671 error = copyout((caddr_t)sp, sfsp, sizeof(*sp)); 672 if (error) { 673 vfs_unbusy(mp, p); 674 return (error); 675 } 676 sfsp += sizeof(*sp); 677 } 678 count++; 679 simple_lock(&mountlist_slock); 680 nmp = mp->mnt_list.cqe_next; 681 vfs_unbusy(mp, p); 682 } 683 simple_unlock(&mountlist_slock); 684 if (sfsp && count > maxcount) 685 *retval = maxcount; 686 else 687 *retval = count; 688 return (0); 689 } 690 691 /* 692 * Change current working directory to a given file descriptor. 693 */ 694 #ifndef _SYS_SYSPROTO_H_ 695 struct fchdir_args { 696 int fd; 697 }; 698 #endif 699 /* ARGSUSED */ 700 int 701 fchdir(p, uap, retval) 702 struct proc *p; 703 struct fchdir_args /* { 704 syscallarg(int) fd; 705 } */ *uap; 706 register_t *retval; 707 { 708 register struct filedesc *fdp = p->p_fd; 709 struct vnode *vp, *tdp; 710 struct mount *mp; 711 struct file *fp; 712 int error; 713 714 if (error = getvnode(fdp, SCARG(uap, fd), &fp)) 715 return (error); 716 vp = (struct vnode *)fp->f_data; 717 VREF(vp); 718 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 719 if (vp->v_type != VDIR) 720 error = ENOTDIR; 721 else 722 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 723 while (!error && (mp = vp->v_mountedhere) != NULL) { 724 if (vfs_busy(mp, 0, 0, p)) 725 continue; 726 error = VFS_ROOT(mp, &tdp); 727 vfs_unbusy(mp, p); 728 if (error) 729 break; 730 vput(vp); 731 vp = tdp; 732 } 733 if (error) { 734 vput(vp); 735 return (error); 736 } 737 VOP_UNLOCK(vp, 0, p); 738 vrele(fdp->fd_cdir); 739 fdp->fd_cdir = vp; 740 return (0); 741 } 742 743 /* 744 * Change current working directory (``.''). 745 */ 746 #ifndef _SYS_SYSPROTO_H_ 747 struct chdir_args { 748 char *path; 749 }; 750 #endif 751 /* ARGSUSED */ 752 int 753 chdir(p, uap, retval) 754 struct proc *p; 755 struct chdir_args /* { 756 syscallarg(char *) path; 757 } */ *uap; 758 register_t *retval; 759 { 760 register struct filedesc *fdp = p->p_fd; 761 int error; 762 struct nameidata nd; 763 764 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 765 SCARG(uap, path), p); 766 if (error = change_dir(&nd, p)) 767 return (error); 768 vrele(fdp->fd_cdir); 769 fdp->fd_cdir = nd.ni_vp; 770 return (0); 771 } 772 773 /* 774 * Change notion of root (``/'') directory. 775 */ 776 #ifndef _SYS_SYSPROTO_H_ 777 struct chroot_args { 778 char *path; 779 }; 780 #endif 781 /* ARGSUSED */ 782 int 783 chroot(p, uap, retval) 784 struct proc *p; 785 struct chroot_args /* { 786 syscallarg(char *) path; 787 } */ *uap; 788 register_t *retval; 789 { 790 register struct filedesc *fdp = p->p_fd; 791 int error; 792 struct nameidata nd; 793 794 error = suser(p->p_ucred, &p->p_acflag); 795 if (error) 796 return (error); 797 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 798 SCARG(uap, path), p); 799 if (error = change_dir(&nd, p)) 800 return (error); 801 if (fdp->fd_rdir != NULL) 802 vrele(fdp->fd_rdir); 803 fdp->fd_rdir = nd.ni_vp; 804 return (0); 805 } 806 807 /* 808 * Common routine for chroot and chdir. 809 */ 810 static int 811 change_dir(ndp, p) 812 register struct nameidata *ndp; 813 struct proc *p; 814 { 815 struct vnode *vp; 816 int error; 817 818 error = namei(ndp); 819 if (error) 820 return (error); 821 vp = ndp->ni_vp; 822 if (vp->v_type != VDIR) 823 error = ENOTDIR; 824 else 825 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 826 if (error) 827 vput(vp); 828 else 829 VOP_UNLOCK(vp, 0, p); 830 return (error); 831 } 832 833 /* 834 * Check permissions, allocate an open file structure, 835 * and call the device open routine if any. 836 */ 837 #ifndef _SYS_SYSPROTO_H_ 838 struct open_args { 839 char *path; 840 int flags; 841 int mode; 842 }; 843 #endif 844 int 845 open(p, uap, retval) 846 struct proc *p; 847 register struct open_args /* { 848 syscallarg(char *) path; 849 syscallarg(int) flags; 850 syscallarg(int) mode; 851 } */ *uap; 852 register_t *retval; 853 { 854 register struct filedesc *fdp = p->p_fd; 855 register struct file *fp; 856 register struct vnode *vp; 857 int flags, cmode; 858 struct file *nfp; 859 int type, indx, error; 860 struct flock lf; 861 struct nameidata nd; 862 863 error = falloc(p, &nfp, &indx); 864 if (error) 865 return (error); 866 fp = nfp; 867 flags = FFLAGS(SCARG(uap, flags)); 868 cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; 869 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 870 p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 871 error = vn_open(&nd, flags, cmode); 872 if (error) { 873 ffree(fp); 874 if ((error == ENODEV || error == ENXIO) && 875 p->p_dupfd >= 0 && /* XXX from fdopen */ 876 (error = 877 dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { 878 *retval = indx; 879 return (0); 880 } 881 if (error == ERESTART) 882 error = EINTR; 883 fdp->fd_ofiles[indx] = NULL; 884 return (error); 885 } 886 p->p_dupfd = 0; 887 vp = nd.ni_vp; 888 889 fp->f_flag = flags & FMASK; 890 fp->f_type = (vp->v_type == VFIFO ? DTYPE_FIFO : DTYPE_VNODE); 891 fp->f_ops = &vnops; 892 fp->f_data = (caddr_t)vp; 893 if (flags & (O_EXLOCK | O_SHLOCK)) { 894 lf.l_whence = SEEK_SET; 895 lf.l_start = 0; 896 lf.l_len = 0; 897 if (flags & O_EXLOCK) 898 lf.l_type = F_WRLCK; 899 else 900 lf.l_type = F_RDLCK; 901 type = F_FLOCK; 902 if ((flags & FNONBLOCK) == 0) 903 type |= F_WAIT; 904 VOP_UNLOCK(vp, 0, p); 905 if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 906 (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 907 ffree(fp); 908 fdp->fd_ofiles[indx] = NULL; 909 return (error); 910 } 911 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 912 fp->f_flag |= FHASLOCK; 913 } 914 VOP_UNLOCK(vp, 0, p); 915 *retval = indx; 916 return (0); 917 } 918 919 #ifdef COMPAT_43 920 /* 921 * Create a file. 922 */ 923 #ifndef _SYS_SYSPROTO_H_ 924 struct ocreat_args { 925 char *path; 926 int mode; 927 }; 928 #endif 929 int 930 ocreat(p, uap, retval) 931 struct proc *p; 932 register struct ocreat_args /* { 933 syscallarg(char *) path; 934 syscallarg(int) mode; 935 } */ *uap; 936 register_t *retval; 937 { 938 struct open_args /* { 939 syscallarg(char *) path; 940 syscallarg(int) flags; 941 syscallarg(int) mode; 942 } */ nuap; 943 944 SCARG(&nuap, path) = SCARG(uap, path); 945 SCARG(&nuap, mode) = SCARG(uap, mode); 946 SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC; 947 return (open(p, &nuap, retval)); 948 } 949 #endif /* COMPAT_43 */ 950 951 /* 952 * Create a special file. 953 */ 954 #ifndef _SYS_SYSPROTO_H_ 955 struct mknod_args { 956 char *path; 957 int mode; 958 int dev; 959 }; 960 #endif 961 /* ARGSUSED */ 962 int 963 mknod(p, uap, retval) 964 struct proc *p; 965 register struct mknod_args /* { 966 syscallarg(char *) path; 967 syscallarg(int) mode; 968 syscallarg(int) dev; 969 } */ *uap; 970 register_t *retval; 971 { 972 register struct vnode *vp; 973 struct vattr vattr; 974 int error; 975 int whiteout; 976 struct nameidata nd; 977 978 error = suser(p->p_ucred, &p->p_acflag); 979 if (error) 980 return (error); 981 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 982 if (error = namei(&nd)) 983 return (error); 984 vp = nd.ni_vp; 985 if (vp != NULL) 986 error = EEXIST; 987 else { 988 VATTR_NULL(&vattr); 989 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 990 vattr.va_rdev = SCARG(uap, dev); 991 whiteout = 0; 992 993 switch (SCARG(uap, mode) & S_IFMT) { 994 case S_IFMT: /* used by badsect to flag bad sectors */ 995 vattr.va_type = VBAD; 996 break; 997 case S_IFCHR: 998 vattr.va_type = VCHR; 999 break; 1000 case S_IFBLK: 1001 vattr.va_type = VBLK; 1002 break; 1003 case S_IFWHT: 1004 whiteout = 1; 1005 break; 1006 default: 1007 error = EINVAL; 1008 break; 1009 } 1010 } 1011 if (!error) { 1012 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1013 if (whiteout) { 1014 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE); 1015 if (error) 1016 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1017 vput(nd.ni_dvp); 1018 } else { 1019 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, 1020 &nd.ni_cnd, &vattr); 1021 } 1022 } else { 1023 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1024 if (nd.ni_dvp == vp) 1025 vrele(nd.ni_dvp); 1026 else 1027 vput(nd.ni_dvp); 1028 if (vp) 1029 vrele(vp); 1030 } 1031 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mknod"); 1032 ASSERT_VOP_UNLOCKED(nd.ni_vp, "mknod"); 1033 return (error); 1034 } 1035 1036 /* 1037 * Create a named pipe. 1038 */ 1039 #ifndef _SYS_SYSPROTO_H_ 1040 struct mkfifo_args { 1041 char *path; 1042 int mode; 1043 }; 1044 #endif 1045 /* ARGSUSED */ 1046 int 1047 mkfifo(p, uap, retval) 1048 struct proc *p; 1049 register struct mkfifo_args /* { 1050 syscallarg(char *) path; 1051 syscallarg(int) mode; 1052 } */ *uap; 1053 register_t *retval; 1054 { 1055 struct vattr vattr; 1056 int error; 1057 struct nameidata nd; 1058 1059 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 1060 if (error = namei(&nd)) 1061 return (error); 1062 if (nd.ni_vp != NULL) { 1063 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1064 if (nd.ni_dvp == nd.ni_vp) 1065 vrele(nd.ni_dvp); 1066 else 1067 vput(nd.ni_dvp); 1068 vrele(nd.ni_vp); 1069 return (EEXIST); 1070 } 1071 VATTR_NULL(&vattr); 1072 vattr.va_type = VFIFO; 1073 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask; 1074 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1075 return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 1076 } 1077 1078 /* 1079 * Make a hard file link. 1080 */ 1081 #ifndef _SYS_SYSPROTO_H_ 1082 struct link_args { 1083 char *path; 1084 char *link; 1085 }; 1086 #endif 1087 /* ARGSUSED */ 1088 int 1089 link(p, uap, retval) 1090 struct proc *p; 1091 register struct link_args /* { 1092 syscallarg(char *) path; 1093 syscallarg(char *) link; 1094 } */ *uap; 1095 register_t *retval; 1096 { 1097 register struct vnode *vp; 1098 struct nameidata nd; 1099 int error; 1100 1101 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1102 if (error = namei(&nd)) 1103 return (error); 1104 vp = nd.ni_vp; 1105 if (vp->v_type == VDIR) 1106 error = EPERM; /* POSIX */ 1107 else { 1108 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p); 1109 error = namei(&nd); 1110 if (!error) { 1111 if (nd.ni_vp != NULL) { 1112 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1113 if (nd.ni_dvp == nd.ni_vp) 1114 vrele(nd.ni_dvp); 1115 else 1116 vput(nd.ni_dvp); 1117 if (nd.ni_vp) 1118 vrele(nd.ni_vp); 1119 error = EEXIST; 1120 } else { 1121 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, 1122 LEASE_WRITE); 1123 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1124 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 1125 } 1126 } 1127 } 1128 vrele(vp); 1129 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "link"); 1130 ASSERT_VOP_UNLOCKED(nd.ni_vp, "link"); 1131 return (error); 1132 } 1133 1134 /* 1135 * Make a symbolic link. 1136 */ 1137 #ifndef _SYS_SYSPROTO_H_ 1138 struct symlink_args { 1139 char *path; 1140 char *link; 1141 }; 1142 #endif 1143 /* ARGSUSED */ 1144 int 1145 symlink(p, uap, retval) 1146 struct proc *p; 1147 register struct symlink_args /* { 1148 syscallarg(char *) path; 1149 syscallarg(char *) link; 1150 } */ *uap; 1151 register_t *retval; 1152 { 1153 struct vattr vattr; 1154 char *path; 1155 int error; 1156 struct nameidata nd; 1157 1158 MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 1159 if (error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL)) 1160 goto out; 1161 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p); 1162 if (error = namei(&nd)) 1163 goto out; 1164 if (nd.ni_vp) { 1165 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1166 if (nd.ni_dvp == nd.ni_vp) 1167 vrele(nd.ni_dvp); 1168 else 1169 vput(nd.ni_dvp); 1170 vrele(nd.ni_vp); 1171 error = EEXIST; 1172 goto out; 1173 } 1174 VATTR_NULL(&vattr); 1175 vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; 1176 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1177 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 1178 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "symlink"); 1179 ASSERT_VOP_UNLOCKED(nd.ni_vp, "symlink"); 1180 out: 1181 FREE(path, M_NAMEI); 1182 return (error); 1183 } 1184 1185 /* 1186 * Delete a whiteout from the filesystem. 1187 */ 1188 /* ARGSUSED */ 1189 int 1190 undelete(p, uap, retval) 1191 struct proc *p; 1192 register struct undelete_args /* { 1193 syscallarg(char *) path; 1194 } */ *uap; 1195 register_t *retval; 1196 { 1197 int error; 1198 struct nameidata nd; 1199 1200 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, 1201 SCARG(uap, path), p); 1202 error = namei(&nd); 1203 if (error) 1204 return (error); 1205 1206 if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) { 1207 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1208 if (nd.ni_dvp == nd.ni_vp) 1209 vrele(nd.ni_dvp); 1210 else 1211 vput(nd.ni_dvp); 1212 if (nd.ni_vp) 1213 vrele(nd.ni_vp); 1214 return (EEXIST); 1215 } 1216 1217 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1218 if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) 1219 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1220 vput(nd.ni_dvp); 1221 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "undelete"); 1222 ASSERT_VOP_UNLOCKED(nd.ni_vp, "undelete"); 1223 return (error); 1224 } 1225 1226 /* 1227 * Delete a name from the filesystem. 1228 */ 1229 #ifndef _SYS_SYSPROTO_H_ 1230 struct unlink_args { 1231 char *path; 1232 }; 1233 #endif 1234 /* ARGSUSED */ 1235 int 1236 unlink(p, uap, retval) 1237 struct proc *p; 1238 struct unlink_args /* { 1239 syscallarg(char *) path; 1240 } */ *uap; 1241 register_t *retval; 1242 { 1243 register struct vnode *vp; 1244 int error; 1245 struct nameidata nd; 1246 1247 NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 1248 if (error = namei(&nd)) 1249 return (error); 1250 vp = nd.ni_vp; 1251 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1252 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1253 1254 if (vp->v_type == VDIR) 1255 error = EPERM; /* POSIX */ 1256 else { 1257 /* 1258 * The root of a mounted filesystem cannot be deleted. 1259 * 1260 * XXX: can this only be a VDIR case? 1261 */ 1262 if (vp->v_flag & VROOT) 1263 error = EBUSY; 1264 else 1265 (void) vnode_pager_uncache(vp, p); 1266 } 1267 1268 if (!error) { 1269 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1270 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 1271 } else { 1272 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1273 if (nd.ni_dvp == vp) 1274 vrele(nd.ni_dvp); 1275 else 1276 vput(nd.ni_dvp); 1277 if (vp != NULLVP) 1278 vput(vp); 1279 } 1280 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "unlink"); 1281 ASSERT_VOP_UNLOCKED(nd.ni_vp, "unlink"); 1282 return (error); 1283 } 1284 1285 /* 1286 * Reposition read/write file offset. 1287 */ 1288 #ifndef _SYS_SYSPROTO_H_ 1289 struct lseek_args { 1290 int fd; 1291 int pad; 1292 off_t offset; 1293 int whence; 1294 }; 1295 #endif 1296 int 1297 lseek(p, uap, retval) 1298 struct proc *p; 1299 register struct lseek_args /* { 1300 syscallarg(int) fd; 1301 syscallarg(int) pad; 1302 syscallarg(off_t) offset; 1303 syscallarg(int) whence; 1304 } */ *uap; 1305 register_t *retval; /* XXX */ 1306 { 1307 struct ucred *cred = p->p_ucred; 1308 register struct filedesc *fdp = p->p_fd; 1309 register struct file *fp; 1310 struct vattr vattr; 1311 int error; 1312 1313 if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles || 1314 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL) 1315 return (EBADF); 1316 if (fp->f_type != DTYPE_VNODE) 1317 return (ESPIPE); 1318 switch (SCARG(uap, whence)) { 1319 case L_INCR: 1320 fp->f_offset += SCARG(uap, offset); 1321 break; 1322 case L_XTND: 1323 error=VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p); 1324 if (error) 1325 return (error); 1326 fp->f_offset = SCARG(uap, offset) + vattr.va_size; 1327 break; 1328 case L_SET: 1329 fp->f_offset = SCARG(uap, offset); 1330 break; 1331 default: 1332 return (EINVAL); 1333 } 1334 *(off_t *)retval = fp->f_offset; 1335 return (0); 1336 } 1337 1338 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1339 /* 1340 * Reposition read/write file offset. 1341 */ 1342 #ifndef _SYS_SYSPROTO_H_ 1343 struct olseek_args { 1344 int fd; 1345 long offset; 1346 int whence; 1347 }; 1348 #endif 1349 int 1350 olseek(p, uap, retval) 1351 struct proc *p; 1352 register struct olseek_args /* { 1353 syscallarg(int) fd; 1354 syscallarg(long) offset; 1355 syscallarg(int) whence; 1356 } */ *uap; 1357 register_t *retval; 1358 { 1359 struct lseek_args /* { 1360 syscallarg(int) fd; 1361 syscallarg(int) pad; 1362 syscallarg(off_t) offset; 1363 syscallarg(int) whence; 1364 } */ nuap; 1365 off_t qret; 1366 int error; 1367 1368 SCARG(&nuap, fd) = SCARG(uap, fd); 1369 SCARG(&nuap, offset) = SCARG(uap, offset); 1370 SCARG(&nuap, whence) = SCARG(uap, whence); 1371 error = lseek(p, &nuap, (register_t *) &qret); 1372 *(long *)retval = qret; 1373 return (error); 1374 } 1375 #endif /* COMPAT_43 */ 1376 1377 /* 1378 * Check access permissions. 1379 */ 1380 #ifndef _SYS_SYSPROTO_H_ 1381 struct access_args { 1382 char *path; 1383 int flags; 1384 }; 1385 #endif 1386 int 1387 access(p, uap, retval) 1388 struct proc *p; 1389 register struct access_args /* { 1390 syscallarg(char *) path; 1391 syscallarg(int) flags; 1392 } */ *uap; 1393 register_t *retval; 1394 { 1395 register struct ucred *cred = p->p_ucred; 1396 register struct vnode *vp; 1397 int error, flags, t_gid, t_uid; 1398 struct nameidata nd; 1399 1400 t_uid = cred->cr_uid; 1401 t_gid = cred->cr_groups[0]; 1402 cred->cr_uid = p->p_cred->p_ruid; 1403 cred->cr_groups[0] = p->p_cred->p_rgid; 1404 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1405 SCARG(uap, path), p); 1406 if (error = namei(&nd)) 1407 goto out1; 1408 vp = nd.ni_vp; 1409 1410 /* Flags == 0 means only check for existence. */ 1411 if (SCARG(uap, flags)) { 1412 flags = 0; 1413 if (SCARG(uap, flags) & R_OK) 1414 flags |= VREAD; 1415 if (SCARG(uap, flags) & W_OK) 1416 flags |= VWRITE; 1417 if (SCARG(uap, flags) & X_OK) 1418 flags |= VEXEC; 1419 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 1420 error = VOP_ACCESS(vp, flags, cred, p); 1421 } 1422 vput(vp); 1423 out1: 1424 cred->cr_uid = t_uid; 1425 cred->cr_groups[0] = t_gid; 1426 return (error); 1427 } 1428 1429 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1430 /* 1431 * Get file status; this version follows links. 1432 */ 1433 #ifndef _SYS_SYSPROTO_H_ 1434 struct ostat_args { 1435 char *path; 1436 struct ostat *ub; 1437 }; 1438 #endif 1439 /* ARGSUSED */ 1440 int 1441 ostat(p, uap, retval) 1442 struct proc *p; 1443 register struct ostat_args /* { 1444 syscallarg(char *) path; 1445 syscallarg(struct ostat *) ub; 1446 } */ *uap; 1447 register_t *retval; 1448 { 1449 struct stat sb; 1450 struct ostat osb; 1451 int error; 1452 struct nameidata nd; 1453 1454 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1455 SCARG(uap, path), p); 1456 if (error = namei(&nd)) 1457 return (error); 1458 error = vn_stat(nd.ni_vp, &sb, p); 1459 vput(nd.ni_vp); 1460 if (error) 1461 return (error); 1462 cvtstat(&sb, &osb); 1463 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 1464 return (error); 1465 } 1466 1467 /* 1468 * Get file status; this version does not follow links. 1469 */ 1470 #ifndef _SYS_SYSPROTO_H_ 1471 struct olstat_args { 1472 char *path; 1473 struct ostat *ub; 1474 }; 1475 #endif 1476 /* ARGSUSED */ 1477 int 1478 olstat(p, uap, retval) 1479 struct proc *p; 1480 register struct olstat_args /* { 1481 syscallarg(char *) path; 1482 syscallarg(struct ostat *) ub; 1483 } */ *uap; 1484 register_t *retval; 1485 { 1486 struct vnode *vp; 1487 struct stat sb; 1488 struct ostat osb; 1489 int error; 1490 struct nameidata nd; 1491 1492 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, 1493 SCARG(uap, path), p); 1494 if (error = namei(&nd)) 1495 return (error); 1496 vp = nd.ni_vp; 1497 error = vn_stat(vp, &sb, p); 1498 if (vp->v_type == VLNK) 1499 sb.st_mode |= S_IFLNK | ACCESSPERMS; /* 0777 */ 1500 vput(vp); 1501 if (error) 1502 return (error); 1503 cvtstat(&sb, &osb); 1504 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb)); 1505 return (error); 1506 } 1507 1508 /* 1509 * Convert from an old to a new stat structure. 1510 */ 1511 void 1512 cvtstat(st, ost) 1513 struct stat *st; 1514 struct ostat *ost; 1515 { 1516 1517 ost->st_dev = st->st_dev; 1518 ost->st_ino = st->st_ino; 1519 ost->st_mode = st->st_mode; 1520 ost->st_nlink = st->st_nlink; 1521 ost->st_uid = st->st_uid; 1522 ost->st_gid = st->st_gid; 1523 ost->st_rdev = st->st_rdev; 1524 if (st->st_size < (quad_t)1 << 32) 1525 ost->st_size = st->st_size; 1526 else 1527 ost->st_size = -2; 1528 ost->st_atime = st->st_atime; 1529 ost->st_mtime = st->st_mtime; 1530 ost->st_ctime = st->st_ctime; 1531 ost->st_blksize = st->st_blksize; 1532 ost->st_blocks = st->st_blocks; 1533 ost->st_flags = st->st_flags; 1534 ost->st_gen = st->st_gen; 1535 } 1536 #endif /* COMPAT_43 || COMPAT_SUNOS */ 1537 1538 /* 1539 * Get file status; this version follows links. 1540 */ 1541 #ifndef _SYS_SYSPROTO_H_ 1542 struct stat_args { 1543 char *path; 1544 struct stat *ub; 1545 }; 1546 #endif 1547 /* ARGSUSED */ 1548 int 1549 stat(p, uap, retval) 1550 struct proc *p; 1551 register struct stat_args /* { 1552 syscallarg(char *) path; 1553 syscallarg(struct stat *) ub; 1554 } */ *uap; 1555 register_t *retval; 1556 { 1557 struct stat sb; 1558 int error; 1559 struct nameidata nd; 1560 1561 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1562 SCARG(uap, path), p); 1563 if (error = namei(&nd)) 1564 return (error); 1565 error = vn_stat(nd.ni_vp, &sb, p); 1566 vput(nd.ni_vp); 1567 if (error) 1568 return (error); 1569 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 1570 return (error); 1571 } 1572 1573 /* 1574 * Get file status; this version does not follow links. 1575 */ 1576 #ifndef _SYS_SYSPROTO_H_ 1577 struct lstat_args { 1578 char *path; 1579 struct stat *ub; 1580 }; 1581 #endif 1582 /* ARGSUSED */ 1583 int 1584 lstat(p, uap, retval) 1585 struct proc *p; 1586 register struct lstat_args /* { 1587 syscallarg(char *) path; 1588 syscallarg(struct stat *) ub; 1589 } */ *uap; 1590 register_t *retval; 1591 { 1592 int error; 1593 struct vnode *vp; 1594 struct stat sb; 1595 struct nameidata nd; 1596 1597 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, 1598 SCARG(uap, path), p); 1599 if (error = namei(&nd)) 1600 return (error); 1601 vp = nd.ni_vp; 1602 error = vn_stat(vp, &sb, p); 1603 if (vp->v_type == VLNK) 1604 sb.st_mode |= S_IFLNK | ACCESSPERMS; /* 0777 */ 1605 vput(vp); 1606 if (error) 1607 return (error); 1608 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb)); 1609 return (error); 1610 } 1611 1612 /* 1613 * Get configurable pathname variables. 1614 */ 1615 #ifndef _SYS_SYSPROTO_H_ 1616 struct pathconf_args { 1617 char *path; 1618 int name; 1619 }; 1620 #endif 1621 /* ARGSUSED */ 1622 int 1623 pathconf(p, uap, retval) 1624 struct proc *p; 1625 register struct pathconf_args /* { 1626 syscallarg(char *) path; 1627 syscallarg(int) name; 1628 } */ *uap; 1629 register_t *retval; 1630 { 1631 int error; 1632 struct nameidata nd; 1633 1634 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, 1635 SCARG(uap, path), p); 1636 if (error = namei(&nd)) 1637 return (error); 1638 error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval); 1639 vput(nd.ni_vp); 1640 return (error); 1641 } 1642 1643 /* 1644 * Return target name of a symbolic link. 1645 */ 1646 #ifndef _SYS_SYSPROTO_H_ 1647 struct readlink_args { 1648 char *path; 1649 char *buf; 1650 int count; 1651 }; 1652 #endif 1653 /* ARGSUSED */ 1654 int 1655 readlink(p, uap, retval) 1656 struct proc *p; 1657 register struct readlink_args /* { 1658 syscallarg(char *) path; 1659 syscallarg(char *) buf; 1660 syscallarg(int) count; 1661 } */ *uap; 1662 register_t *retval; 1663 { 1664 register struct vnode *vp; 1665 struct iovec aiov; 1666 struct uio auio; 1667 int error; 1668 struct nameidata nd; 1669 1670 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, 1671 SCARG(uap, path), p); 1672 if (error = namei(&nd)) 1673 return (error); 1674 vp = nd.ni_vp; 1675 if (vp->v_type != VLNK) 1676 error = EINVAL; 1677 else { 1678 aiov.iov_base = SCARG(uap, buf); 1679 aiov.iov_len = SCARG(uap, count); 1680 auio.uio_iov = &aiov; 1681 auio.uio_iovcnt = 1; 1682 auio.uio_offset = 0; 1683 auio.uio_rw = UIO_READ; 1684 auio.uio_segflg = UIO_USERSPACE; 1685 auio.uio_procp = p; 1686 auio.uio_resid = SCARG(uap, count); 1687 error = VOP_READLINK(vp, &auio, p->p_ucred); 1688 } 1689 vput(vp); 1690 *retval = SCARG(uap, count) - auio.uio_resid; 1691 return (error); 1692 } 1693 1694 /* 1695 * Change flags of a file given a path name. 1696 */ 1697 #ifndef _SYS_SYSPROTO_H_ 1698 struct chflags_args { 1699 char *path; 1700 int flags; 1701 }; 1702 #endif 1703 /* ARGSUSED */ 1704 int 1705 chflags(p, uap, retval) 1706 struct proc *p; 1707 register struct chflags_args /* { 1708 syscallarg(char *) path; 1709 syscallarg(int) flags; 1710 } */ *uap; 1711 register_t *retval; 1712 { 1713 register struct vnode *vp; 1714 struct vattr vattr; 1715 int error; 1716 struct nameidata nd; 1717 1718 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1719 if (error = namei(&nd)) 1720 return (error); 1721 vp = nd.ni_vp; 1722 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1723 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1724 VATTR_NULL(&vattr); 1725 vattr.va_flags = SCARG(uap, flags); 1726 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1727 vput(vp); 1728 return (error); 1729 } 1730 1731 /* 1732 * Change flags of a file given a file descriptor. 1733 */ 1734 #ifndef _SYS_SYSPROTO_H_ 1735 struct fchflags_args { 1736 int fd; 1737 int flags; 1738 }; 1739 #endif 1740 /* ARGSUSED */ 1741 int 1742 fchflags(p, uap, retval) 1743 struct proc *p; 1744 register struct fchflags_args /* { 1745 syscallarg(int) fd; 1746 syscallarg(int) flags; 1747 } */ *uap; 1748 register_t *retval; 1749 { 1750 struct vattr vattr; 1751 struct vnode *vp; 1752 struct file *fp; 1753 int error; 1754 1755 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1756 return (error); 1757 vp = (struct vnode *)fp->f_data; 1758 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1759 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1760 VATTR_NULL(&vattr); 1761 vattr.va_flags = SCARG(uap, flags); 1762 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1763 VOP_UNLOCK(vp, 0, p); 1764 return (error); 1765 } 1766 1767 /* 1768 * Change mode of a file given path name. 1769 */ 1770 #ifndef _SYS_SYSPROTO_H_ 1771 struct chmod_args { 1772 char *path; 1773 int mode; 1774 }; 1775 #endif 1776 /* ARGSUSED */ 1777 int 1778 chmod(p, uap, retval) 1779 struct proc *p; 1780 register struct chmod_args /* { 1781 syscallarg(char *) path; 1782 syscallarg(int) mode; 1783 } */ *uap; 1784 register_t *retval; 1785 { 1786 register struct vnode *vp; 1787 struct vattr vattr; 1788 int error; 1789 struct nameidata nd; 1790 1791 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1792 if (error = namei(&nd)) 1793 return (error); 1794 vp = nd.ni_vp; 1795 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1796 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1797 VATTR_NULL(&vattr); 1798 vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 1799 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1800 vput(vp); 1801 return (error); 1802 } 1803 1804 /* 1805 * Change mode of a file given a file descriptor. 1806 */ 1807 #ifndef _SYS_SYSPROTO_H_ 1808 struct fchmod_args { 1809 int fd; 1810 int mode; 1811 }; 1812 #endif 1813 /* ARGSUSED */ 1814 int 1815 fchmod(p, uap, retval) 1816 struct proc *p; 1817 register struct fchmod_args /* { 1818 syscallarg(int) fd; 1819 syscallarg(int) mode; 1820 } */ *uap; 1821 register_t *retval; 1822 { 1823 struct vattr vattr; 1824 struct vnode *vp; 1825 struct file *fp; 1826 int error; 1827 1828 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1829 return (error); 1830 vp = (struct vnode *)fp->f_data; 1831 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1832 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1833 VATTR_NULL(&vattr); 1834 vattr.va_mode = SCARG(uap, mode) & ALLPERMS; 1835 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1836 VOP_UNLOCK(vp, 0, p); 1837 return (error); 1838 } 1839 1840 /* 1841 * Set ownership given a path name. 1842 */ 1843 #ifndef _SYS_SYSPROTO_H_ 1844 struct chown_args { 1845 char *path; 1846 int uid; 1847 int gid; 1848 }; 1849 #endif 1850 /* ARGSUSED */ 1851 int 1852 chown(p, uap, retval) 1853 struct proc *p; 1854 register struct chown_args /* { 1855 syscallarg(char *) path; 1856 syscallarg(int) uid; 1857 syscallarg(int) gid; 1858 } */ *uap; 1859 register_t *retval; 1860 { 1861 register struct vnode *vp; 1862 struct vattr vattr; 1863 int error; 1864 struct nameidata nd; 1865 1866 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1867 if (error = namei(&nd)) 1868 return (error); 1869 vp = nd.ni_vp; 1870 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1871 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1872 VATTR_NULL(&vattr); 1873 vattr.va_uid = SCARG(uap, uid); 1874 vattr.va_gid = SCARG(uap, gid); 1875 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1876 vput(vp); 1877 return (error); 1878 } 1879 1880 /* 1881 * Set ownership given a path name, do not cross symlinks. 1882 */ 1883 #ifndef _SYS_SYSPROTO_H_ 1884 struct lchown_args { 1885 char *path; 1886 int uid; 1887 int gid; 1888 }; 1889 #endif 1890 /* ARGSUSED */ 1891 int 1892 lchown(p, uap, retval) 1893 struct proc *p; 1894 register struct lchown_args /* { 1895 syscallarg(char *) path; 1896 syscallarg(int) uid; 1897 syscallarg(int) gid; 1898 } */ *uap; 1899 register_t *retval; 1900 { 1901 register struct vnode *vp; 1902 struct vattr vattr; 1903 int error; 1904 struct nameidata nd; 1905 1906 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1907 if (error = namei(&nd)) 1908 return (error); 1909 vp = nd.ni_vp; 1910 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1911 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1912 VATTR_NULL(&vattr); 1913 vattr.va_uid = SCARG(uap, uid); 1914 vattr.va_gid = SCARG(uap, gid); 1915 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1916 vput(vp); 1917 return (error); 1918 } 1919 1920 /* 1921 * Set ownership given a file descriptor. 1922 */ 1923 #ifndef _SYS_SYSPROTO_H_ 1924 struct fchown_args { 1925 int fd; 1926 int uid; 1927 int gid; 1928 }; 1929 #endif 1930 /* ARGSUSED */ 1931 int 1932 fchown(p, uap, retval) 1933 struct proc *p; 1934 register struct fchown_args /* { 1935 syscallarg(int) fd; 1936 syscallarg(int) uid; 1937 syscallarg(int) gid; 1938 } */ *uap; 1939 register_t *retval; 1940 { 1941 struct vattr vattr; 1942 struct vnode *vp; 1943 struct file *fp; 1944 int error; 1945 1946 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 1947 return (error); 1948 vp = (struct vnode *)fp->f_data; 1949 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1950 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1951 VATTR_NULL(&vattr); 1952 vattr.va_uid = SCARG(uap, uid); 1953 vattr.va_gid = SCARG(uap, gid); 1954 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1955 VOP_UNLOCK(vp, 0, p); 1956 return (error); 1957 } 1958 1959 /* 1960 * Set the access and modification times of a file. 1961 */ 1962 #ifndef _SYS_SYSPROTO_H_ 1963 struct utimes_args { 1964 char *path; 1965 struct timeval *tptr; 1966 }; 1967 #endif 1968 /* ARGSUSED */ 1969 int 1970 utimes(p, uap, retval) 1971 struct proc *p; 1972 register struct utimes_args /* { 1973 syscallarg(char *) path; 1974 syscallarg(struct timeval *) tptr; 1975 } */ *uap; 1976 register_t *retval; 1977 { 1978 register struct vnode *vp; 1979 struct timeval tv[2]; 1980 struct vattr vattr; 1981 int error; 1982 struct nameidata nd; 1983 1984 VATTR_NULL(&vattr); 1985 if (SCARG(uap, tptr) == NULL) { 1986 microtime(&tv[0]); 1987 tv[1] = tv[0]; 1988 vattr.va_vaflags |= VA_UTIMES_NULL; 1989 } else if (error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv, 1990 sizeof (tv))) 1991 return (error); 1992 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 1993 if (error = namei(&nd)) 1994 return (error); 1995 vp = nd.ni_vp; 1996 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 1997 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 1998 vattr.va_atime.tv_sec = tv[0].tv_sec; 1999 vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000; 2000 vattr.va_mtime.tv_sec = tv[1].tv_sec; 2001 vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000; 2002 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2003 vput(vp); 2004 return (error); 2005 } 2006 2007 /* 2008 * Truncate a file given its path name. 2009 */ 2010 #ifndef _SYS_SYSPROTO_H_ 2011 struct truncate_args { 2012 char *path; 2013 int pad; 2014 off_t length; 2015 }; 2016 #endif 2017 /* ARGSUSED */ 2018 int 2019 truncate(p, uap, retval) 2020 struct proc *p; 2021 register struct truncate_args /* { 2022 syscallarg(char *) path; 2023 syscallarg(int) pad; 2024 syscallarg(off_t) length; 2025 } */ *uap; 2026 register_t *retval; 2027 { 2028 register struct vnode *vp; 2029 struct vattr vattr; 2030 int error; 2031 struct nameidata nd; 2032 2033 if (uap->length < 0) 2034 return(EINVAL); 2035 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2036 if (error = namei(&nd)) 2037 return (error); 2038 vp = nd.ni_vp; 2039 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2040 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2041 if (vp->v_type == VDIR) 2042 error = EISDIR; 2043 else if ((error = vn_writechk(vp)) == 0 && 2044 (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { 2045 VATTR_NULL(&vattr); 2046 vattr.va_size = SCARG(uap, length); 2047 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 2048 } 2049 vput(vp); 2050 return (error); 2051 } 2052 2053 /* 2054 * Truncate a file given a file descriptor. 2055 */ 2056 #ifndef _SYS_SYSPROTO_H_ 2057 struct ftruncate_args { 2058 int fd; 2059 int pad; 2060 off_t length; 2061 }; 2062 #endif 2063 /* ARGSUSED */ 2064 int 2065 ftruncate(p, uap, retval) 2066 struct proc *p; 2067 register struct ftruncate_args /* { 2068 syscallarg(int) fd; 2069 syscallarg(int) pad; 2070 syscallarg(off_t) length; 2071 } */ *uap; 2072 register_t *retval; 2073 { 2074 struct vattr vattr; 2075 struct vnode *vp; 2076 struct file *fp; 2077 int error; 2078 2079 if (uap->length < 0) 2080 return(EINVAL); 2081 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 2082 return (error); 2083 if ((fp->f_flag & FWRITE) == 0) 2084 return (EINVAL); 2085 vp = (struct vnode *)fp->f_data; 2086 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2087 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2088 if (vp->v_type == VDIR) 2089 error = EISDIR; 2090 else if ((error = vn_writechk(vp)) == 0) { 2091 VATTR_NULL(&vattr); 2092 vattr.va_size = SCARG(uap, length); 2093 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 2094 } 2095 VOP_UNLOCK(vp, 0, p); 2096 return (error); 2097 } 2098 2099 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 2100 /* 2101 * Truncate a file given its path name. 2102 */ 2103 #ifndef _SYS_SYSPROTO_H_ 2104 struct otruncate_args { 2105 char *path; 2106 long length; 2107 }; 2108 #endif 2109 /* ARGSUSED */ 2110 int 2111 otruncate(p, uap, retval) 2112 struct proc *p; 2113 register struct otruncate_args /* { 2114 syscallarg(char *) path; 2115 syscallarg(long) length; 2116 } */ *uap; 2117 register_t *retval; 2118 { 2119 struct truncate_args /* { 2120 syscallarg(char *) path; 2121 syscallarg(int) pad; 2122 syscallarg(off_t) length; 2123 } */ nuap; 2124 2125 SCARG(&nuap, path) = SCARG(uap, path); 2126 SCARG(&nuap, length) = SCARG(uap, length); 2127 return (truncate(p, &nuap, retval)); 2128 } 2129 2130 /* 2131 * Truncate a file given a file descriptor. 2132 */ 2133 #ifndef _SYS_SYSPROTO_H_ 2134 struct oftruncate_args { 2135 int fd; 2136 long length; 2137 }; 2138 #endif 2139 /* ARGSUSED */ 2140 int 2141 oftruncate(p, uap, retval) 2142 struct proc *p; 2143 register struct oftruncate_args /* { 2144 syscallarg(int) fd; 2145 syscallarg(long) length; 2146 } */ *uap; 2147 register_t *retval; 2148 { 2149 struct ftruncate_args /* { 2150 syscallarg(int) fd; 2151 syscallarg(int) pad; 2152 syscallarg(off_t) length; 2153 } */ nuap; 2154 2155 SCARG(&nuap, fd) = SCARG(uap, fd); 2156 SCARG(&nuap, length) = SCARG(uap, length); 2157 return (ftruncate(p, &nuap, retval)); 2158 } 2159 #endif /* COMPAT_43 || COMPAT_SUNOS */ 2160 2161 /* 2162 * Sync an open file. 2163 */ 2164 #ifndef _SYS_SYSPROTO_H_ 2165 struct fsync_args { 2166 int fd; 2167 }; 2168 #endif 2169 /* ARGSUSED */ 2170 int 2171 fsync(p, uap, retval) 2172 struct proc *p; 2173 struct fsync_args /* { 2174 syscallarg(int) fd; 2175 } */ *uap; 2176 register_t *retval; 2177 { 2178 register struct vnode *vp; 2179 struct file *fp; 2180 int error; 2181 2182 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 2183 return (error); 2184 vp = (struct vnode *)fp->f_data; 2185 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2186 if (vp->v_object) { 2187 vm_object_page_clean(vp->v_object, 0, 0 ,0, FALSE); 2188 } 2189 error = VOP_FSYNC(vp, fp->f_cred, 2190 (vp->v_mount && (vp->v_mount->mnt_flag & MNT_ASYNC)) ? 2191 MNT_NOWAIT : MNT_WAIT, p); 2192 VOP_UNLOCK(vp, 0, p); 2193 return (error); 2194 } 2195 2196 /* 2197 * Rename files. Source and destination must either both be directories, 2198 * or both not be directories. If target is a directory, it must be empty. 2199 */ 2200 #ifndef _SYS_SYSPROTO_H_ 2201 struct rename_args { 2202 char *from; 2203 char *to; 2204 }; 2205 #endif 2206 /* ARGSUSED */ 2207 int 2208 rename(p, uap, retval) 2209 struct proc *p; 2210 register struct rename_args /* { 2211 syscallarg(char *) from; 2212 syscallarg(char *) to; 2213 } */ *uap; 2214 register_t *retval; 2215 { 2216 register struct vnode *tvp, *fvp, *tdvp; 2217 struct nameidata fromnd, tond; 2218 int error; 2219 2220 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 2221 SCARG(uap, from), p); 2222 if (error = namei(&fromnd)) 2223 return (error); 2224 fvp = fromnd.ni_vp; 2225 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 2226 UIO_USERSPACE, SCARG(uap, to), p); 2227 if (fromnd.ni_vp->v_type == VDIR) 2228 tond.ni_cnd.cn_flags |= WILLBEDIR; 2229 if (error = namei(&tond)) { 2230 /* Translate error code for rename("dir1", "dir2/."). */ 2231 if (error == EISDIR && fvp->v_type == VDIR) 2232 error = EINVAL; 2233 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 2234 vrele(fromnd.ni_dvp); 2235 vrele(fvp); 2236 goto out1; 2237 } 2238 tdvp = tond.ni_dvp; 2239 tvp = tond.ni_vp; 2240 if (tvp != NULL) { 2241 if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 2242 error = ENOTDIR; 2243 goto out; 2244 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 2245 error = EISDIR; 2246 goto out; 2247 } 2248 } 2249 if (fvp == tdvp) 2250 error = EINVAL; 2251 /* 2252 * If source is the same as the destination (that is the 2253 * same inode number with the same name in the same directory), 2254 * then there is nothing to do. 2255 */ 2256 if (fvp == tvp && fromnd.ni_dvp == tdvp && 2257 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 2258 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 2259 fromnd.ni_cnd.cn_namelen)) 2260 error = -1; 2261 out: 2262 if (!error) { 2263 VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE); 2264 if (fromnd.ni_dvp != tdvp) 2265 VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2266 if (tvp) { 2267 VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE); 2268 (void) vnode_pager_uncache(tvp, p); 2269 } 2270 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 2271 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 2272 } else { 2273 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 2274 if (tdvp == tvp) 2275 vrele(tdvp); 2276 else 2277 vput(tdvp); 2278 if (tvp) 2279 vput(tvp); 2280 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 2281 vrele(fromnd.ni_dvp); 2282 vrele(fvp); 2283 } 2284 vrele(tond.ni_startdir); 2285 ASSERT_VOP_UNLOCKED(fromnd.ni_dvp, "rename"); 2286 ASSERT_VOP_UNLOCKED(fromnd.ni_vp, "rename"); 2287 ASSERT_VOP_UNLOCKED(tond.ni_dvp, "rename"); 2288 ASSERT_VOP_UNLOCKED(tond.ni_vp, "rename"); 2289 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 2290 out1: 2291 if (fromnd.ni_startdir) 2292 vrele(fromnd.ni_startdir); 2293 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 2294 if (error == -1) 2295 return (0); 2296 return (error); 2297 } 2298 2299 /* 2300 * Make a directory file. 2301 */ 2302 #ifndef _SYS_SYSPROTO_H_ 2303 struct mkdir_args { 2304 char *path; 2305 int mode; 2306 }; 2307 #endif 2308 /* ARGSUSED */ 2309 int 2310 mkdir(p, uap, retval) 2311 struct proc *p; 2312 register struct mkdir_args /* { 2313 syscallarg(char *) path; 2314 syscallarg(int) mode; 2315 } */ *uap; 2316 register_t *retval; 2317 { 2318 register struct vnode *vp; 2319 struct vattr vattr; 2320 int error; 2321 struct nameidata nd; 2322 2323 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p); 2324 nd.ni_cnd.cn_flags |= WILLBEDIR; 2325 if (error = namei(&nd)) 2326 return (error); 2327 vp = nd.ni_vp; 2328 if (vp != NULL) { 2329 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2330 if (nd.ni_dvp == vp) 2331 vrele(nd.ni_dvp); 2332 else 2333 vput(nd.ni_dvp); 2334 vrele(vp); 2335 return (EEXIST); 2336 } 2337 VATTR_NULL(&vattr); 2338 vattr.va_type = VDIR; 2339 vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask; 2340 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2341 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 2342 if (!error) 2343 vput(nd.ni_vp); 2344 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mkdir"); 2345 ASSERT_VOP_UNLOCKED(nd.ni_vp, "mkdir"); 2346 return (error); 2347 } 2348 2349 /* 2350 * Remove a directory file. 2351 */ 2352 #ifndef _SYS_SYSPROTO_H_ 2353 struct rmdir_args { 2354 char *path; 2355 }; 2356 #endif 2357 /* ARGSUSED */ 2358 int 2359 rmdir(p, uap, retval) 2360 struct proc *p; 2361 struct rmdir_args /* { 2362 syscallarg(char *) path; 2363 } */ *uap; 2364 register_t *retval; 2365 { 2366 register struct vnode *vp; 2367 int error; 2368 struct nameidata nd; 2369 2370 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, 2371 SCARG(uap, path), p); 2372 if (error = namei(&nd)) 2373 return (error); 2374 vp = nd.ni_vp; 2375 if (vp->v_type != VDIR) { 2376 error = ENOTDIR; 2377 goto out; 2378 } 2379 /* 2380 * No rmdir "." please. 2381 */ 2382 if (nd.ni_dvp == vp) { 2383 error = EINVAL; 2384 goto out; 2385 } 2386 /* 2387 * The root of a mounted filesystem cannot be deleted. 2388 */ 2389 if (vp->v_flag & VROOT) 2390 error = EBUSY; 2391 out: 2392 if (!error) { 2393 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 2394 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 2395 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 2396 } else { 2397 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2398 if (nd.ni_dvp == vp) 2399 vrele(nd.ni_dvp); 2400 else 2401 vput(nd.ni_dvp); 2402 vput(vp); 2403 } 2404 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "rmdir"); 2405 ASSERT_VOP_UNLOCKED(nd.ni_vp, "rmdir"); 2406 return (error); 2407 } 2408 2409 #ifdef COMPAT_43 2410 /* 2411 * Read a block of directory entries in a file system independent format. 2412 */ 2413 #ifndef _SYS_SYSPROTO_H_ 2414 struct ogetdirentries_args { 2415 int fd; 2416 char *buf; 2417 u_int count; 2418 long *basep; 2419 }; 2420 #endif 2421 int 2422 ogetdirentries(p, uap, retval) 2423 struct proc *p; 2424 register struct ogetdirentries_args /* { 2425 syscallarg(int) fd; 2426 syscallarg(char *) buf; 2427 syscallarg(u_int) count; 2428 syscallarg(long *) basep; 2429 } */ *uap; 2430 register_t *retval; 2431 { 2432 register struct vnode *vp; 2433 struct file *fp; 2434 struct uio auio, kuio; 2435 struct iovec aiov, kiov; 2436 struct dirent *dp, *edp; 2437 caddr_t dirbuf; 2438 int error, eofflag, readcnt; 2439 long loff; 2440 2441 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 2442 return (error); 2443 if ((fp->f_flag & FREAD) == 0) 2444 return (EBADF); 2445 vp = (struct vnode *)fp->f_data; 2446 unionread: 2447 if (vp->v_type != VDIR) 2448 return (EINVAL); 2449 aiov.iov_base = SCARG(uap, buf); 2450 aiov.iov_len = SCARG(uap, count); 2451 auio.uio_iov = &aiov; 2452 auio.uio_iovcnt = 1; 2453 auio.uio_rw = UIO_READ; 2454 auio.uio_segflg = UIO_USERSPACE; 2455 auio.uio_procp = p; 2456 auio.uio_resid = SCARG(uap, count); 2457 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2458 loff = auio.uio_offset = fp->f_offset; 2459 # if (BYTE_ORDER != LITTLE_ENDIAN) 2460 if (vp->v_mount->mnt_maxsymlinklen <= 0) { 2461 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 2462 NULL, NULL); 2463 fp->f_offset = auio.uio_offset; 2464 } else 2465 # endif 2466 { 2467 kuio = auio; 2468 kuio.uio_iov = &kiov; 2469 kuio.uio_segflg = UIO_SYSSPACE; 2470 kiov.iov_len = SCARG(uap, count); 2471 MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK); 2472 kiov.iov_base = dirbuf; 2473 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, 2474 NULL, NULL); 2475 fp->f_offset = kuio.uio_offset; 2476 if (error == 0) { 2477 readcnt = SCARG(uap, count) - kuio.uio_resid; 2478 edp = (struct dirent *)&dirbuf[readcnt]; 2479 for (dp = (struct dirent *)dirbuf; dp < edp; ) { 2480 # if (BYTE_ORDER == LITTLE_ENDIAN) 2481 /* 2482 * The expected low byte of 2483 * dp->d_namlen is our dp->d_type. 2484 * The high MBZ byte of dp->d_namlen 2485 * is our dp->d_namlen. 2486 */ 2487 dp->d_type = dp->d_namlen; 2488 dp->d_namlen = 0; 2489 # else 2490 /* 2491 * The dp->d_type is the high byte 2492 * of the expected dp->d_namlen, 2493 * so must be zero'ed. 2494 */ 2495 dp->d_type = 0; 2496 # endif 2497 if (dp->d_reclen > 0) { 2498 dp = (struct dirent *) 2499 ((char *)dp + dp->d_reclen); 2500 } else { 2501 error = EIO; 2502 break; 2503 } 2504 } 2505 if (dp >= edp) 2506 error = uiomove(dirbuf, readcnt, &auio); 2507 } 2508 FREE(dirbuf, M_TEMP); 2509 } 2510 VOP_UNLOCK(vp, 0, p); 2511 if (error) 2512 return (error); 2513 2514 #ifdef UNION 2515 { 2516 if ((SCARG(uap, count) == auio.uio_resid) && 2517 (vp->v_op == union_vnodeop_p)) { 2518 struct vnode *lvp; 2519 2520 lvp = union_dircache(vp, p); 2521 if (lvp != NULLVP) { 2522 struct vattr va; 2523 2524 /* 2525 * If the directory is opaque, 2526 * then don't show lower entries 2527 */ 2528 error = VOP_GETATTR(vp, &va, fp->f_cred, p); 2529 if (va.va_flags & OPAQUE) { 2530 vput(lvp); 2531 lvp = NULL; 2532 } 2533 } 2534 2535 if (lvp != NULLVP) { 2536 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 2537 if (error) { 2538 vput(lvp); 2539 return (error); 2540 } 2541 VOP_UNLOCK(lvp, 0, p); 2542 fp->f_data = (caddr_t) lvp; 2543 fp->f_offset = 0; 2544 error = vn_close(vp, FREAD, fp->f_cred, p); 2545 if (error) 2546 return (error); 2547 vp = lvp; 2548 goto unionread; 2549 } 2550 } 2551 } 2552 #endif /* UNION */ 2553 2554 if ((SCARG(uap, count) == auio.uio_resid) && 2555 (vp->v_flag & VROOT) && 2556 (vp->v_mount->mnt_flag & MNT_UNION)) { 2557 struct vnode *tvp = vp; 2558 vp = vp->v_mount->mnt_vnodecovered; 2559 VREF(vp); 2560 fp->f_data = (caddr_t) vp; 2561 fp->f_offset = 0; 2562 vrele(tvp); 2563 goto unionread; 2564 } 2565 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 2566 sizeof(long)); 2567 *retval = SCARG(uap, count) - auio.uio_resid; 2568 return (error); 2569 } 2570 #endif /* COMPAT_43 */ 2571 2572 /* 2573 * Read a block of directory entries in a file system independent format. 2574 */ 2575 #ifndef _SYS_SYSPROTO_H_ 2576 struct getdirentries_args { 2577 int fd; 2578 char *buf; 2579 u_int count; 2580 long *basep; 2581 }; 2582 #endif 2583 int 2584 getdirentries(p, uap, retval) 2585 struct proc *p; 2586 register struct getdirentries_args /* { 2587 syscallarg(int) fd; 2588 syscallarg(char *) buf; 2589 syscallarg(u_int) count; 2590 syscallarg(long *) basep; 2591 } */ *uap; 2592 register_t *retval; 2593 { 2594 register struct vnode *vp; 2595 struct file *fp; 2596 struct uio auio; 2597 struct iovec aiov; 2598 long loff; 2599 int error, eofflag; 2600 2601 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) 2602 return (error); 2603 if ((fp->f_flag & FREAD) == 0) 2604 return (EBADF); 2605 vp = (struct vnode *)fp->f_data; 2606 unionread: 2607 if (vp->v_type != VDIR) 2608 return (EINVAL); 2609 aiov.iov_base = SCARG(uap, buf); 2610 aiov.iov_len = SCARG(uap, count); 2611 auio.uio_iov = &aiov; 2612 auio.uio_iovcnt = 1; 2613 auio.uio_rw = UIO_READ; 2614 auio.uio_segflg = UIO_USERSPACE; 2615 auio.uio_procp = p; 2616 auio.uio_resid = SCARG(uap, count); 2617 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 2618 loff = auio.uio_offset = fp->f_offset; 2619 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL, NULL); 2620 fp->f_offset = auio.uio_offset; 2621 VOP_UNLOCK(vp, 0, p); 2622 if (error) 2623 return (error); 2624 2625 #ifdef UNION 2626 { 2627 if ((SCARG(uap, count) == auio.uio_resid) && 2628 (vp->v_op == union_vnodeop_p)) { 2629 struct vnode *lvp; 2630 2631 lvp = union_dircache(vp, p); 2632 if (lvp != NULLVP) { 2633 struct vattr va; 2634 2635 /* 2636 * If the directory is opaque, 2637 * then don't show lower entries 2638 */ 2639 error = VOP_GETATTR(vp, &va, fp->f_cred, p); 2640 if (va.va_flags & OPAQUE) { 2641 vput(lvp); 2642 lvp = NULL; 2643 } 2644 } 2645 2646 if (lvp != NULLVP) { 2647 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 2648 if (error) { 2649 vput(lvp); 2650 return (error); 2651 } 2652 VOP_UNLOCK(lvp, 0, p); 2653 fp->f_data = (caddr_t) lvp; 2654 fp->f_offset = 0; 2655 error = vn_close(vp, FREAD, fp->f_cred, p); 2656 if (error) 2657 return (error); 2658 vp = lvp; 2659 goto unionread; 2660 } 2661 } 2662 } 2663 #endif /* UNION */ 2664 2665 if ((SCARG(uap, count) == auio.uio_resid) && 2666 (vp->v_flag & VROOT) && 2667 (vp->v_mount->mnt_flag & MNT_UNION)) { 2668 struct vnode *tvp = vp; 2669 vp = vp->v_mount->mnt_vnodecovered; 2670 VREF(vp); 2671 fp->f_data = (caddr_t) vp; 2672 fp->f_offset = 0; 2673 vrele(tvp); 2674 goto unionread; 2675 } 2676 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep), 2677 sizeof(long)); 2678 *retval = SCARG(uap, count) - auio.uio_resid; 2679 return (error); 2680 } 2681 2682 /* 2683 * Set the mode mask for creation of filesystem nodes. 2684 */ 2685 #ifndef _SYS_SYSPROTO_H_ 2686 struct umask_args { 2687 int newmask; 2688 }; 2689 #endif 2690 int 2691 umask(p, uap, retval) 2692 struct proc *p; 2693 struct umask_args /* { 2694 syscallarg(int) newmask; 2695 } */ *uap; 2696 int *retval; /* XXX */ 2697 { 2698 register struct filedesc *fdp; 2699 2700 fdp = p->p_fd; 2701 *retval = fdp->fd_cmask; 2702 fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS; 2703 return (0); 2704 } 2705 2706 /* 2707 * Void all references to file by ripping underlying filesystem 2708 * away from vnode. 2709 */ 2710 #ifndef _SYS_SYSPROTO_H_ 2711 struct revoke_args { 2712 char *path; 2713 }; 2714 #endif 2715 /* ARGSUSED */ 2716 int 2717 revoke(p, uap, retval) 2718 struct proc *p; 2719 register struct revoke_args /* { 2720 syscallarg(char *) path; 2721 } */ *uap; 2722 register_t *retval; 2723 { 2724 register struct vnode *vp; 2725 struct vattr vattr; 2726 int error; 2727 struct nameidata nd; 2728 2729 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p); 2730 if (error = namei(&nd)) 2731 return (error); 2732 vp = nd.ni_vp; 2733 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 2734 goto out; 2735 if (p->p_ucred->cr_uid != vattr.va_uid && 2736 (error = suser(p->p_ucred, &p->p_acflag))) 2737 goto out; 2738 if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 2739 VOP_REVOKE(vp, REVOKEALL); 2740 out: 2741 vrele(vp); 2742 return (error); 2743 } 2744 2745 /* 2746 * Convert a user file descriptor to a kernel file entry. 2747 */ 2748 int 2749 getvnode(fdp, fd, fpp) 2750 struct filedesc *fdp; 2751 int fd; 2752 struct file **fpp; 2753 { 2754 struct file *fp; 2755 2756 if ((u_int)fd >= fdp->fd_nfiles || 2757 (fp = fdp->fd_ofiles[fd]) == NULL) 2758 return (EBADF); 2759 if (fp->f_type != DTYPE_VNODE && fp->f_type != DTYPE_FIFO) 2760 return (EINVAL); 2761 *fpp = fp; 2762 return (0); 2763 } 2764