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 * %sccs.include.redist.c% 11 * 12 * @(#)vfs_syscalls.c 8.18 (Berkeley) 07/14/94 13 */ 14 15 #include <sys/param.h> 16 #include <sys/systm.h> 17 #include <sys/namei.h> 18 #include <sys/filedesc.h> 19 #include <sys/kernel.h> 20 #include <sys/file.h> 21 #include <sys/stat.h> 22 #include <sys/vnode.h> 23 #include <sys/mount.h> 24 #include <sys/proc.h> 25 #include <sys/uio.h> 26 #include <sys/malloc.h> 27 #include <sys/dirent.h> 28 29 #include <vm/vm.h> 30 #include <sys/sysctl.h> 31 32 static int change_dir __P((struct nameidata *ndp, struct proc *p)); 33 34 /* 35 * Virtual File System System Calls 36 */ 37 38 /* 39 * Mount a file system. 40 */ 41 struct mount_args { 42 int type; 43 char *path; 44 int flags; 45 caddr_t data; 46 }; 47 /* ARGSUSED */ 48 mount(p, uap, retval) 49 struct proc *p; 50 register struct mount_args *uap; 51 int *retval; 52 { 53 register struct vnode *vp; 54 register struct mount *mp; 55 int error, flag; 56 struct vattr va; 57 struct nameidata nd; 58 59 /* 60 * Get vnode to be covered 61 */ 62 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 63 if (error = namei(&nd)) 64 return (error); 65 vp = nd.ni_vp; 66 if (uap->flags & MNT_UPDATE) { 67 if ((vp->v_flag & VROOT) == 0) { 68 vput(vp); 69 return (EINVAL); 70 } 71 mp = vp->v_mount; 72 flag = mp->mnt_flag; 73 /* 74 * We only allow the filesystem to be reloaded if it 75 * is currently mounted read-only. 76 */ 77 if ((uap->flags & MNT_RELOAD) && 78 ((mp->mnt_flag & MNT_RDONLY) == 0)) { 79 vput(vp); 80 return (EOPNOTSUPP); /* Needs translation */ 81 } 82 mp->mnt_flag |= 83 uap->flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); 84 /* 85 * Only root, or the user that did the original mount is 86 * permitted to update it. 87 */ 88 if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid && 89 (error = suser(p->p_ucred, &p->p_acflag))) { 90 vput(vp); 91 return (error); 92 } 93 /* 94 * Do not allow NFS export by non-root users. Silently 95 * enforce MNT_NOSUID and MNT_NODEV for non-root users. 96 */ 97 if (p->p_ucred->cr_uid != 0) { 98 if (uap->flags & MNT_EXPORTED) { 99 vput(vp); 100 return (EPERM); 101 } 102 uap->flags |= MNT_NOSUID | MNT_NODEV; 103 } 104 VOP_UNLOCK(vp); 105 goto update; 106 } 107 /* 108 * If the user is not root, ensure that they own the directory 109 * onto which we are attempting to mount. 110 */ 111 if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) || 112 (va.va_uid != p->p_ucred->cr_uid && 113 (error = suser(p->p_ucred, &p->p_acflag)))) { 114 vput(vp); 115 return (error); 116 } 117 /* 118 * Do not allow NFS export by non-root users. Silently 119 * enforce MNT_NOSUID and MNT_NODEV for non-root users. 120 */ 121 if (p->p_ucred->cr_uid != 0) { 122 if (uap->flags & MNT_EXPORTED) { 123 vput(vp); 124 return (EPERM); 125 } 126 uap->flags |= MNT_NOSUID | MNT_NODEV; 127 } 128 if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) 129 return (error); 130 if (vp->v_type != VDIR) { 131 vput(vp); 132 return (ENOTDIR); 133 } 134 if ((u_long)uap->type > MOUNT_MAXTYPE || vfssw[uap->type] == NULL) { 135 vput(vp); 136 return (ENODEV); 137 } 138 139 /* 140 * Allocate and initialize the file system. 141 */ 142 mp = (struct mount *)malloc((u_long)sizeof(struct mount), 143 M_MOUNT, M_WAITOK); 144 bzero((char *)mp, (u_long)sizeof(struct mount)); 145 mp->mnt_op = vfssw[uap->type]; 146 if (error = vfs_lock(mp)) { 147 free((caddr_t)mp, M_MOUNT); 148 vput(vp); 149 return (error); 150 } 151 if (vp->v_mountedhere != NULL) { 152 vfs_unlock(mp); 153 free((caddr_t)mp, M_MOUNT); 154 vput(vp); 155 return (EBUSY); 156 } 157 vp->v_mountedhere = mp; 158 mp->mnt_vnodecovered = vp; 159 mp->mnt_stat.f_owner = p->p_ucred->cr_uid; 160 update: 161 /* 162 * Set the mount level flags. 163 */ 164 if (uap->flags & MNT_RDONLY) 165 mp->mnt_flag |= MNT_RDONLY; 166 else if (mp->mnt_flag & MNT_RDONLY) 167 mp->mnt_flag |= MNT_WANTRDWR; 168 mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | 169 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); 170 mp->mnt_flag |= uap->flags & (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | 171 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC); 172 /* 173 * Mount the filesystem. 174 */ 175 error = VFS_MOUNT(mp, uap->path, uap->data, &nd, p); 176 if (mp->mnt_flag & MNT_UPDATE) { 177 vrele(vp); 178 if (mp->mnt_flag & MNT_WANTRDWR) 179 mp->mnt_flag &= ~MNT_RDONLY; 180 mp->mnt_flag &=~ 181 (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR); 182 if (error) 183 mp->mnt_flag = flag; 184 return (error); 185 } 186 /* 187 * Put the new filesystem on the mount list after root. 188 */ 189 cache_purge(vp); 190 if (!error) { 191 TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); 192 VOP_UNLOCK(vp); 193 vfs_unlock(mp); 194 error = VFS_START(mp, 0, p); 195 } else { 196 mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 197 vfs_unlock(mp); 198 free((caddr_t)mp, M_MOUNT); 199 vput(vp); 200 } 201 return (error); 202 } 203 204 /* 205 * Unmount a file system. 206 * 207 * Note: unmount takes a path to the vnode mounted on as argument, 208 * not special file (as before). 209 */ 210 struct unmount_args { 211 char *path; 212 int flags; 213 }; 214 /* ARGSUSED */ 215 unmount(p, uap, retval) 216 struct proc *p; 217 register struct unmount_args *uap; 218 int *retval; 219 { 220 register struct vnode *vp; 221 struct mount *mp; 222 int error; 223 struct nameidata nd; 224 225 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 226 if (error = namei(&nd)) 227 return (error); 228 vp = nd.ni_vp; 229 mp = vp->v_mount; 230 231 /* 232 * Only root, or the user that did the original mount is 233 * permitted to unmount this filesystem. 234 */ 235 if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) && 236 (error = suser(p->p_ucred, &p->p_acflag))) { 237 vput(vp); 238 return (error); 239 } 240 241 /* 242 * Must be the root of the filesystem 243 */ 244 if ((vp->v_flag & VROOT) == 0) { 245 vput(vp); 246 return (EINVAL); 247 } 248 vput(vp); 249 return (dounmount(mp, uap->flags, p)); 250 } 251 252 /* 253 * Do the actual file system unmount. 254 */ 255 dounmount(mp, flags, p) 256 register struct mount *mp; 257 int flags; 258 struct proc *p; 259 { 260 struct vnode *coveredvp; 261 int error; 262 263 coveredvp = mp->mnt_vnodecovered; 264 if (vfs_busy(mp)) 265 return (EBUSY); 266 mp->mnt_flag |= MNT_UNMOUNT; 267 if (error = vfs_lock(mp)) 268 return (error); 269 270 mp->mnt_flag &=~ MNT_ASYNC; 271 vnode_pager_umount(mp); /* release cached vnodes */ 272 cache_purgevfs(mp); /* remove cache entries for this file sys */ 273 if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 || 274 (flags & MNT_FORCE)) 275 error = VFS_UNMOUNT(mp, flags, p); 276 mp->mnt_flag &= ~MNT_UNMOUNT; 277 vfs_unbusy(mp); 278 if (error) { 279 vfs_unlock(mp); 280 } else { 281 vrele(coveredvp); 282 TAILQ_REMOVE(&mountlist, mp, mnt_list); 283 mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0; 284 vfs_unlock(mp); 285 if (mp->mnt_vnodelist.lh_first != NULL) 286 panic("unmount: dangling vnode"); 287 free((caddr_t)mp, M_MOUNT); 288 } 289 return (error); 290 } 291 292 /* 293 * Sync each mounted filesystem. 294 */ 295 #ifdef DEBUG 296 int syncprt = 0; 297 struct ctldebug debug0 = { "syncprt", &syncprt }; 298 #endif 299 300 struct sync_args { 301 int dummy; 302 }; 303 /* ARGSUSED */ 304 sync(p, uap, retval) 305 struct proc *p; 306 struct sync_args *uap; 307 int *retval; 308 { 309 register struct mount *mp, *nmp; 310 int asyncflag; 311 312 for (mp = mountlist.tqh_first; mp != NULL; mp = nmp) { 313 nmp = mp->mnt_list.tqe_next; 314 /* 315 * The lock check below is to avoid races with mount 316 * and unmount. 317 */ 318 if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && 319 !vfs_busy(mp)) { 320 asyncflag = mp->mnt_flag & MNT_ASYNC; 321 mp->mnt_flag &= ~MNT_ASYNC; 322 VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p); 323 if (asyncflag) 324 mp->mnt_flag |= MNT_ASYNC; 325 vfs_unbusy(mp); 326 } 327 } 328 #ifdef DIAGNOSTIC 329 if (syncprt) 330 vfs_bufstats(); 331 #endif /* DIAGNOSTIC */ 332 return (0); 333 } 334 335 /* 336 * Change filesystem quotas. 337 */ 338 struct quotactl_args { 339 char *path; 340 int cmd; 341 int uid; 342 caddr_t arg; 343 }; 344 /* ARGSUSED */ 345 quotactl(p, uap, retval) 346 struct proc *p; 347 register struct quotactl_args *uap; 348 int *retval; 349 { 350 register struct mount *mp; 351 int error; 352 struct nameidata nd; 353 354 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 355 if (error = namei(&nd)) 356 return (error); 357 mp = nd.ni_vp->v_mount; 358 vrele(nd.ni_vp); 359 return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p)); 360 } 361 362 /* 363 * Get filesystem statistics. 364 */ 365 struct statfs_args { 366 char *path; 367 struct statfs *buf; 368 }; 369 /* ARGSUSED */ 370 statfs(p, uap, retval) 371 struct proc *p; 372 register struct statfs_args *uap; 373 int *retval; 374 { 375 register struct mount *mp; 376 register struct statfs *sp; 377 int error; 378 struct nameidata nd; 379 380 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 381 if (error = namei(&nd)) 382 return (error); 383 mp = nd.ni_vp->v_mount; 384 sp = &mp->mnt_stat; 385 vrele(nd.ni_vp); 386 if (error = VFS_STATFS(mp, sp, p)) 387 return (error); 388 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 389 return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 390 } 391 392 /* 393 * Get filesystem statistics. 394 */ 395 struct fstatfs_args { 396 int fd; 397 struct statfs *buf; 398 }; 399 /* ARGSUSED */ 400 fstatfs(p, uap, retval) 401 struct proc *p; 402 register struct fstatfs_args *uap; 403 int *retval; 404 { 405 struct file *fp; 406 struct mount *mp; 407 register struct statfs *sp; 408 int error; 409 410 if (error = getvnode(p->p_fd, uap->fd, &fp)) 411 return (error); 412 mp = ((struct vnode *)fp->f_data)->v_mount; 413 sp = &mp->mnt_stat; 414 if (error = VFS_STATFS(mp, sp, p)) 415 return (error); 416 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 417 return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); 418 } 419 420 /* 421 * Get statistics on all filesystems. 422 */ 423 struct getfsstat_args { 424 struct statfs *buf; 425 long bufsize; 426 int flags; 427 }; 428 getfsstat(p, uap, retval) 429 struct proc *p; 430 register struct getfsstat_args *uap; 431 int *retval; 432 { 433 register struct mount *mp, *nmp; 434 register struct statfs *sp; 435 caddr_t sfsp; 436 long count, maxcount, error; 437 438 maxcount = uap->bufsize / sizeof(struct statfs); 439 sfsp = (caddr_t)uap->buf; 440 for (count = 0, mp = mountlist.tqh_first; mp != NULL; mp = nmp) { 441 nmp = mp->mnt_list.tqe_next; 442 if (sfsp && count < maxcount && 443 ((mp->mnt_flag & MNT_MLOCK) == 0)) { 444 sp = &mp->mnt_stat; 445 /* 446 * If MNT_NOWAIT is specified, do not refresh the 447 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. 448 */ 449 if (((uap->flags & MNT_NOWAIT) == 0 || 450 (uap->flags & MNT_WAIT)) && 451 (error = VFS_STATFS(mp, sp, p))) 452 continue; 453 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; 454 if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) 455 return (error); 456 sfsp += sizeof(*sp); 457 } 458 count++; 459 } 460 if (sfsp && count > maxcount) 461 *retval = maxcount; 462 else 463 *retval = count; 464 return (0); 465 } 466 467 /* 468 * Change current working directory to a given file descriptor. 469 */ 470 struct fchdir_args { 471 int fd; 472 }; 473 /* ARGSUSED */ 474 fchdir(p, uap, retval) 475 struct proc *p; 476 struct fchdir_args *uap; 477 int *retval; 478 { 479 register struct filedesc *fdp = p->p_fd; 480 register struct vnode *vp; 481 struct file *fp; 482 int error; 483 484 if (error = getvnode(fdp, uap->fd, &fp)) 485 return (error); 486 vp = (struct vnode *)fp->f_data; 487 VOP_LOCK(vp); 488 if (vp->v_type != VDIR) 489 error = ENOTDIR; 490 else 491 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 492 VOP_UNLOCK(vp); 493 if (error) 494 return (error); 495 VREF(vp); 496 vrele(fdp->fd_cdir); 497 fdp->fd_cdir = vp; 498 return (0); 499 } 500 501 /* 502 * Change current working directory (``.''). 503 */ 504 struct chdir_args { 505 char *path; 506 }; 507 /* ARGSUSED */ 508 chdir(p, uap, retval) 509 struct proc *p; 510 struct chdir_args *uap; 511 int *retval; 512 { 513 register struct filedesc *fdp = p->p_fd; 514 int error; 515 struct nameidata nd; 516 517 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 518 if (error = change_dir(&nd, p)) 519 return (error); 520 vrele(fdp->fd_cdir); 521 fdp->fd_cdir = nd.ni_vp; 522 return (0); 523 } 524 525 /* 526 * Change notion of root (``/'') directory. 527 */ 528 struct chroot_args { 529 char *path; 530 }; 531 /* ARGSUSED */ 532 chroot(p, uap, retval) 533 struct proc *p; 534 struct chroot_args *uap; 535 int *retval; 536 { 537 register struct filedesc *fdp = p->p_fd; 538 int error; 539 struct nameidata nd; 540 541 if (error = suser(p->p_ucred, &p->p_acflag)) 542 return (error); 543 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 544 if (error = change_dir(&nd, p)) 545 return (error); 546 if (fdp->fd_rdir != NULL) 547 vrele(fdp->fd_rdir); 548 fdp->fd_rdir = nd.ni_vp; 549 return (0); 550 } 551 552 /* 553 * Common routine for chroot and chdir. 554 */ 555 static int 556 change_dir(ndp, p) 557 register struct nameidata *ndp; 558 struct proc *p; 559 { 560 struct vnode *vp; 561 int error; 562 563 if (error = namei(ndp)) 564 return (error); 565 vp = ndp->ni_vp; 566 if (vp->v_type != VDIR) 567 error = ENOTDIR; 568 else 569 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 570 VOP_UNLOCK(vp); 571 if (error) 572 vrele(vp); 573 return (error); 574 } 575 576 /* 577 * Check permissions, allocate an open file structure, 578 * and call the device open routine if any. 579 */ 580 struct open_args { 581 char *path; 582 int flags; 583 int mode; 584 }; 585 open(p, uap, retval) 586 struct proc *p; 587 register struct open_args *uap; 588 int *retval; 589 { 590 register struct filedesc *fdp = p->p_fd; 591 register struct file *fp; 592 register struct vnode *vp; 593 int flags, cmode; 594 struct file *nfp; 595 int type, indx, error; 596 struct flock lf; 597 struct nameidata nd; 598 extern struct fileops vnops; 599 600 if (error = falloc(p, &nfp, &indx)) 601 return (error); 602 fp = nfp; 603 flags = FFLAGS(uap->flags); 604 cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; 605 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 606 p->p_dupfd = -indx - 1; /* XXX check for fdopen */ 607 if (error = vn_open(&nd, flags, cmode)) { 608 ffree(fp); 609 if ((error == ENODEV || error == ENXIO) && 610 p->p_dupfd >= 0 && /* XXX from fdopen */ 611 (error = 612 dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) { 613 *retval = indx; 614 return (0); 615 } 616 if (error == ERESTART) 617 error = EINTR; 618 fdp->fd_ofiles[indx] = NULL; 619 return (error); 620 } 621 p->p_dupfd = 0; 622 vp = nd.ni_vp; 623 fp->f_flag = flags & FMASK; 624 fp->f_type = DTYPE_VNODE; 625 fp->f_ops = &vnops; 626 fp->f_data = (caddr_t)vp; 627 if (flags & (O_EXLOCK | O_SHLOCK)) { 628 lf.l_whence = SEEK_SET; 629 lf.l_start = 0; 630 lf.l_len = 0; 631 if (flags & O_EXLOCK) 632 lf.l_type = F_WRLCK; 633 else 634 lf.l_type = F_RDLCK; 635 type = F_FLOCK; 636 if ((flags & FNONBLOCK) == 0) 637 type |= F_WAIT; 638 VOP_UNLOCK(vp); 639 if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) { 640 (void) vn_close(vp, fp->f_flag, fp->f_cred, p); 641 ffree(fp); 642 fdp->fd_ofiles[indx] = NULL; 643 return (error); 644 } 645 VOP_LOCK(vp); 646 fp->f_flag |= FHASLOCK; 647 } 648 VOP_UNLOCK(vp); 649 *retval = indx; 650 return (0); 651 } 652 653 #ifdef COMPAT_43 654 /* 655 * Create a file. 656 */ 657 struct ocreat_args { 658 char *path; 659 int mode; 660 }; 661 ocreat(p, uap, retval) 662 struct proc *p; 663 register struct ocreat_args *uap; 664 int *retval; 665 { 666 struct open_args openuap; 667 668 openuap.path = uap->path; 669 openuap.mode = uap->mode; 670 openuap.flags = O_WRONLY | O_CREAT | O_TRUNC; 671 return (open(p, &openuap, retval)); 672 } 673 #endif /* COMPAT_43 */ 674 675 /* 676 * Create a special file. 677 */ 678 struct mknod_args { 679 char *path; 680 int mode; 681 int dev; 682 }; 683 /* ARGSUSED */ 684 mknod(p, uap, retval) 685 struct proc *p; 686 register struct mknod_args *uap; 687 int *retval; 688 { 689 register struct vnode *vp; 690 struct vattr vattr; 691 int error; 692 struct nameidata nd; 693 694 if (error = suser(p->p_ucred, &p->p_acflag)) 695 return (error); 696 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 697 if (error = namei(&nd)) 698 return (error); 699 vp = nd.ni_vp; 700 if (vp != NULL) 701 error = EEXIST; 702 else { 703 VATTR_NULL(&vattr); 704 vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; 705 vattr.va_rdev = uap->dev; 706 707 switch (uap->mode & S_IFMT) { 708 case S_IFMT: /* used by badsect to flag bad sectors */ 709 vattr.va_type = VBAD; 710 break; 711 case S_IFCHR: 712 vattr.va_type = VCHR; 713 break; 714 case S_IFBLK: 715 vattr.va_type = VBLK; 716 break; 717 default: 718 error = EINVAL; 719 break; 720 } 721 } 722 if (!error) { 723 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 724 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 725 } else { 726 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 727 if (nd.ni_dvp == vp) 728 vrele(nd.ni_dvp); 729 else 730 vput(nd.ni_dvp); 731 if (vp) 732 vrele(vp); 733 } 734 return (error); 735 } 736 737 /* 738 * Create named pipe. 739 */ 740 struct mkfifo_args { 741 char *path; 742 int mode; 743 }; 744 /* ARGSUSED */ 745 mkfifo(p, uap, retval) 746 struct proc *p; 747 register struct mkfifo_args *uap; 748 int *retval; 749 { 750 struct vattr vattr; 751 int error; 752 struct nameidata nd; 753 754 #ifndef FIFO 755 return (EOPNOTSUPP); 756 #else 757 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 758 if (error = namei(&nd)) 759 return (error); 760 if (nd.ni_vp != NULL) { 761 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 762 if (nd.ni_dvp == nd.ni_vp) 763 vrele(nd.ni_dvp); 764 else 765 vput(nd.ni_dvp); 766 vrele(nd.ni_vp); 767 return (EEXIST); 768 } 769 VATTR_NULL(&vattr); 770 vattr.va_type = VFIFO; 771 vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask; 772 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 773 return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)); 774 #endif /* FIFO */ 775 } 776 777 /* 778 * Make a hard file link. 779 */ 780 struct link_args { 781 char *path; 782 char *link; 783 }; 784 /* ARGSUSED */ 785 link(p, uap, retval) 786 struct proc *p; 787 register struct link_args *uap; 788 int *retval; 789 { 790 register struct vnode *vp; 791 struct nameidata nd; 792 int error; 793 794 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 795 if (error = namei(&nd)) 796 return (error); 797 vp = nd.ni_vp; 798 if (vp->v_type != VDIR || 799 (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 800 nd.ni_cnd.cn_nameiop = CREATE; 801 nd.ni_cnd.cn_flags = LOCKPARENT; 802 nd.ni_dirp = uap->link; 803 if ((error = namei(&nd)) == 0) { 804 if (nd.ni_vp != NULL) 805 error = EEXIST; 806 if (!error) { 807 LEASE_CHECK(nd.ni_dvp, 808 p, p->p_ucred, LEASE_WRITE); 809 LEASE_CHECK(vp, 810 p, p->p_ucred, LEASE_WRITE); 811 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 812 } else { 813 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 814 if (nd.ni_dvp == nd.ni_vp) 815 vrele(nd.ni_dvp); 816 else 817 vput(nd.ni_dvp); 818 if (nd.ni_vp) 819 vrele(nd.ni_vp); 820 } 821 } 822 } 823 vrele(vp); 824 return (error); 825 } 826 827 /* 828 * Make a symbolic link. 829 */ 830 struct symlink_args { 831 char *path; 832 char *link; 833 }; 834 /* ARGSUSED */ 835 symlink(p, uap, retval) 836 struct proc *p; 837 register struct symlink_args *uap; 838 int *retval; 839 { 840 struct vattr vattr; 841 char *path; 842 int error; 843 struct nameidata nd; 844 845 MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 846 if (error = copyinstr(uap->path, path, MAXPATHLEN, NULL)) 847 goto out; 848 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p); 849 if (error = namei(&nd)) 850 goto out; 851 if (nd.ni_vp) { 852 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 853 if (nd.ni_dvp == nd.ni_vp) 854 vrele(nd.ni_dvp); 855 else 856 vput(nd.ni_dvp); 857 vrele(nd.ni_vp); 858 error = EEXIST; 859 goto out; 860 } 861 VATTR_NULL(&vattr); 862 vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask; 863 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 864 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path); 865 out: 866 FREE(path, M_NAMEI); 867 return (error); 868 } 869 870 /* 871 * Delete a whiteout from the filesystem. 872 */ 873 struct unwhiteout_args { 874 char *path; 875 }; 876 /* ARGSUSED */ 877 unwhiteout(p, uap, retval) 878 struct proc *p; 879 struct unwhiteout_args *uap; 880 int *retval; 881 { 882 int error; 883 struct nameidata nd; 884 885 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 886 if (error = namei(&nd)) 887 return (error); 888 if (nd.ni_vp || !(nd.ni_cnd.cn_flags & WHITEOUT)) { 889 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 890 if (nd.ni_dvp == nd.ni_vp) 891 vrele(nd.ni_dvp); 892 else 893 vput(nd.ni_dvp); 894 if (nd.ni_vp) 895 vrele(nd.ni_vp); 896 return (EEXIST); 897 } 898 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 899 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE); 900 vput(nd.ni_dvp); 901 return (error); 902 } 903 904 /* 905 * Delete a name from the filesystem. 906 */ 907 struct unlink_args { 908 char *path; 909 }; 910 /* ARGSUSED */ 911 unlink(p, uap, retval) 912 struct proc *p; 913 struct unlink_args *uap; 914 int *retval; 915 { 916 register struct vnode *vp; 917 int error; 918 struct nameidata nd; 919 920 NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 921 if (error = namei(&nd)) 922 return (error); 923 vp = nd.ni_vp; 924 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 925 VOP_LOCK(vp); 926 927 if (vp->v_type != VDIR || 928 (error = suser(p->p_ucred, &p->p_acflag)) == 0) { 929 /* 930 * The root of a mounted filesystem cannot be deleted. 931 */ 932 if (vp->v_flag & VROOT) 933 error = EBUSY; 934 else 935 (void)vnode_pager_uncache(vp); 936 } 937 938 if (!error) { 939 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 940 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 941 } else { 942 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 943 if (nd.ni_dvp == vp) 944 vrele(nd.ni_dvp); 945 else 946 vput(nd.ni_dvp); 947 vput(vp); 948 } 949 return (error); 950 } 951 952 /* 953 * Reposition read/write file offset. 954 */ 955 struct lseek_args { 956 int fd; 957 int pad; 958 off_t offset; 959 int whence; 960 }; 961 lseek(p, uap, retval) 962 struct proc *p; 963 register struct lseek_args *uap; 964 int *retval; 965 { 966 struct ucred *cred = p->p_ucred; 967 register struct filedesc *fdp = p->p_fd; 968 register struct file *fp; 969 struct vattr vattr; 970 int error; 971 972 if ((u_int)uap->fd >= fdp->fd_nfiles || 973 (fp = fdp->fd_ofiles[uap->fd]) == NULL) 974 return (EBADF); 975 if (fp->f_type != DTYPE_VNODE) 976 return (ESPIPE); 977 switch (uap->whence) { 978 case L_INCR: 979 fp->f_offset += uap->offset; 980 break; 981 case L_XTND: 982 if (error = 983 VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p)) 984 return (error); 985 fp->f_offset = uap->offset + vattr.va_size; 986 break; 987 case L_SET: 988 fp->f_offset = uap->offset; 989 break; 990 default: 991 return (EINVAL); 992 } 993 *(off_t *)retval = fp->f_offset; 994 return (0); 995 } 996 997 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 998 /* 999 * Reposition read/write file offset. 1000 */ 1001 struct olseek_args { 1002 int fd; 1003 long offset; 1004 int whence; 1005 }; 1006 olseek(p, uap, retval) 1007 struct proc *p; 1008 register struct olseek_args *uap; 1009 int *retval; 1010 { 1011 struct lseek_args nuap; 1012 off_t qret; 1013 int error; 1014 1015 nuap.fd = uap->fd; 1016 nuap.offset = uap->offset; 1017 nuap.whence = uap->whence; 1018 error = lseek(p, &nuap, &qret); 1019 *(long *)retval = qret; 1020 return (error); 1021 } 1022 #endif /* COMPAT_43 */ 1023 1024 /* 1025 * Check access permissions. 1026 */ 1027 struct access_args { 1028 char *path; 1029 int flags; 1030 }; 1031 access(p, uap, retval) 1032 struct proc *p; 1033 register struct access_args *uap; 1034 int *retval; 1035 { 1036 register struct ucred *cred = p->p_ucred; 1037 register struct vnode *vp; 1038 int error, flags, t_gid, t_uid; 1039 struct nameidata nd; 1040 1041 t_uid = cred->cr_uid; 1042 t_gid = cred->cr_groups[0]; 1043 cred->cr_uid = p->p_cred->p_ruid; 1044 cred->cr_groups[0] = p->p_cred->p_rgid; 1045 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 1046 if (error = namei(&nd)) 1047 goto out1; 1048 vp = nd.ni_vp; 1049 1050 /* Flags == 0 means only check for existence. */ 1051 if (uap->flags) { 1052 flags = 0; 1053 if (uap->flags & R_OK) 1054 flags |= VREAD; 1055 if (uap->flags & W_OK) 1056 flags |= VWRITE; 1057 if (uap->flags & X_OK) 1058 flags |= VEXEC; 1059 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) 1060 error = VOP_ACCESS(vp, flags, cred, p); 1061 } 1062 vput(vp); 1063 out1: 1064 cred->cr_uid = t_uid; 1065 cred->cr_groups[0] = t_gid; 1066 return (error); 1067 } 1068 1069 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1070 /* 1071 * Get file status; this version follows links. 1072 */ 1073 struct ostat_args { 1074 char *path; 1075 struct ostat *ub; 1076 }; 1077 /* ARGSUSED */ 1078 ostat(p, uap, retval) 1079 struct proc *p; 1080 register struct ostat_args *uap; 1081 int *retval; 1082 { 1083 struct stat sb; 1084 struct ostat osb; 1085 int error; 1086 struct nameidata nd; 1087 1088 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 1089 if (error = namei(&nd)) 1090 return (error); 1091 error = vn_stat(nd.ni_vp, &sb, p); 1092 vput(nd.ni_vp); 1093 if (error) 1094 return (error); 1095 cvtstat(&sb, &osb); 1096 error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 1097 return (error); 1098 } 1099 1100 /* 1101 * Get file status; this version does not follow links. 1102 */ 1103 struct olstat_args { 1104 char *path; 1105 struct ostat *ub; 1106 }; 1107 /* ARGSUSED */ 1108 olstat(p, uap, retval) 1109 struct proc *p; 1110 register struct olstat_args *uap; 1111 int *retval; 1112 { 1113 struct stat sb; 1114 struct ostat osb; 1115 int error; 1116 struct nameidata nd; 1117 1118 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 1119 if (error = namei(&nd)) 1120 return (error); 1121 error = vn_stat(nd.ni_vp, &sb, p); 1122 vput(nd.ni_vp); 1123 if (error) 1124 return (error); 1125 cvtstat(&sb, &osb); 1126 error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb)); 1127 return (error); 1128 } 1129 1130 /* 1131 * Convert from an old to a new stat structure. 1132 */ 1133 cvtstat(st, ost) 1134 struct stat *st; 1135 struct ostat *ost; 1136 { 1137 1138 ost->st_dev = st->st_dev; 1139 ost->st_ino = st->st_ino; 1140 ost->st_mode = st->st_mode; 1141 ost->st_nlink = st->st_nlink; 1142 ost->st_uid = st->st_uid; 1143 ost->st_gid = st->st_gid; 1144 ost->st_rdev = st->st_rdev; 1145 if (st->st_size < (quad_t)1 << 32) 1146 ost->st_size = st->st_size; 1147 else 1148 ost->st_size = -2; 1149 ost->st_atime = st->st_atime; 1150 ost->st_mtime = st->st_mtime; 1151 ost->st_ctime = st->st_ctime; 1152 ost->st_blksize = st->st_blksize; 1153 ost->st_blocks = st->st_blocks; 1154 ost->st_flags = st->st_flags; 1155 ost->st_gen = st->st_gen; 1156 } 1157 #endif /* COMPAT_43 || COMPAT_SUNOS */ 1158 1159 /* 1160 * Get file status; this version follows links. 1161 */ 1162 struct stat_args { 1163 char *path; 1164 struct stat *ub; 1165 }; 1166 /* ARGSUSED */ 1167 stat(p, uap, retval) 1168 struct proc *p; 1169 register struct stat_args *uap; 1170 int *retval; 1171 { 1172 struct stat sb; 1173 int error; 1174 struct nameidata nd; 1175 1176 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 1177 if (error = namei(&nd)) 1178 return (error); 1179 error = vn_stat(nd.ni_vp, &sb, p); 1180 vput(nd.ni_vp); 1181 if (error) 1182 return (error); 1183 error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 1184 return (error); 1185 } 1186 1187 /* 1188 * Get file status; this version does not follow links. 1189 */ 1190 struct lstat_args { 1191 char *path; 1192 struct stat *ub; 1193 }; 1194 /* ARGSUSED */ 1195 lstat(p, uap, retval) 1196 struct proc *p; 1197 register struct lstat_args *uap; 1198 int *retval; 1199 { 1200 int error; 1201 struct vnode *vp, *dvp; 1202 struct stat sb, sb1; 1203 struct nameidata nd; 1204 1205 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE, 1206 uap->path, p); 1207 if (error = namei(&nd)) 1208 return (error); 1209 /* 1210 * For symbolic links, always return the attributes of its 1211 * containing directory, except for mode, size, and links. 1212 */ 1213 vp = nd.ni_vp; 1214 dvp = nd.ni_dvp; 1215 if (vp->v_type != VLNK) { 1216 if (dvp == vp) 1217 vrele(dvp); 1218 else 1219 vput(dvp); 1220 error = vn_stat(vp, &sb, p); 1221 vput(vp); 1222 if (error) 1223 return (error); 1224 } else { 1225 error = vn_stat(dvp, &sb, p); 1226 vput(dvp); 1227 if (error) { 1228 vput(vp); 1229 return (error); 1230 } 1231 error = vn_stat(vp, &sb1, p); 1232 vput(vp); 1233 if (error) 1234 return (error); 1235 sb.st_mode &= ~S_IFDIR; 1236 sb.st_mode |= S_IFLNK; 1237 sb.st_nlink = sb1.st_nlink; 1238 sb.st_size = sb1.st_size; 1239 sb.st_blocks = sb1.st_blocks; 1240 } 1241 error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 1242 return (error); 1243 } 1244 1245 /* 1246 * Get configurable pathname variables. 1247 */ 1248 struct pathconf_args { 1249 char *path; 1250 int name; 1251 }; 1252 /* ARGSUSED */ 1253 pathconf(p, uap, retval) 1254 struct proc *p; 1255 register struct pathconf_args *uap; 1256 int *retval; 1257 { 1258 int error; 1259 struct nameidata nd; 1260 1261 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 1262 if (error = namei(&nd)) 1263 return (error); 1264 error = VOP_PATHCONF(nd.ni_vp, uap->name, retval); 1265 vput(nd.ni_vp); 1266 return (error); 1267 } 1268 1269 /* 1270 * Return target name of a symbolic link. 1271 */ 1272 struct readlink_args { 1273 char *path; 1274 char *buf; 1275 int count; 1276 }; 1277 /* ARGSUSED */ 1278 readlink(p, uap, retval) 1279 struct proc *p; 1280 register struct readlink_args *uap; 1281 int *retval; 1282 { 1283 register struct vnode *vp; 1284 struct iovec aiov; 1285 struct uio auio; 1286 int error; 1287 struct nameidata nd; 1288 1289 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p); 1290 if (error = namei(&nd)) 1291 return (error); 1292 vp = nd.ni_vp; 1293 if (vp->v_type != VLNK) 1294 error = EINVAL; 1295 else { 1296 aiov.iov_base = uap->buf; 1297 aiov.iov_len = uap->count; 1298 auio.uio_iov = &aiov; 1299 auio.uio_iovcnt = 1; 1300 auio.uio_offset = 0; 1301 auio.uio_rw = UIO_READ; 1302 auio.uio_segflg = UIO_USERSPACE; 1303 auio.uio_procp = p; 1304 auio.uio_resid = uap->count; 1305 error = VOP_READLINK(vp, &auio, p->p_ucred); 1306 } 1307 vput(vp); 1308 *retval = uap->count - auio.uio_resid; 1309 return (error); 1310 } 1311 1312 /* 1313 * Change flags of a file given a path name. 1314 */ 1315 struct chflags_args { 1316 char *path; 1317 int flags; 1318 }; 1319 /* ARGSUSED */ 1320 chflags(p, uap, retval) 1321 struct proc *p; 1322 register struct chflags_args *uap; 1323 int *retval; 1324 { 1325 register struct vnode *vp; 1326 struct vattr vattr; 1327 int error; 1328 struct nameidata nd; 1329 1330 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 1331 if (error = namei(&nd)) 1332 return (error); 1333 vp = nd.ni_vp; 1334 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1335 VOP_LOCK(vp); 1336 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1337 error = EROFS; 1338 else { 1339 VATTR_NULL(&vattr); 1340 vattr.va_flags = uap->flags; 1341 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1342 } 1343 vput(vp); 1344 return (error); 1345 } 1346 1347 /* 1348 * Change flags of a file given a file descriptor. 1349 */ 1350 struct fchflags_args { 1351 int fd; 1352 int flags; 1353 }; 1354 /* ARGSUSED */ 1355 fchflags(p, uap, retval) 1356 struct proc *p; 1357 register struct fchflags_args *uap; 1358 int *retval; 1359 { 1360 struct vattr vattr; 1361 struct vnode *vp; 1362 struct file *fp; 1363 int error; 1364 1365 if (error = getvnode(p->p_fd, uap->fd, &fp)) 1366 return (error); 1367 vp = (struct vnode *)fp->f_data; 1368 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1369 VOP_LOCK(vp); 1370 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1371 error = EROFS; 1372 else { 1373 VATTR_NULL(&vattr); 1374 vattr.va_flags = uap->flags; 1375 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1376 } 1377 VOP_UNLOCK(vp); 1378 return (error); 1379 } 1380 1381 /* 1382 * Change mode of a file given path name. 1383 */ 1384 struct chmod_args { 1385 char *path; 1386 int mode; 1387 }; 1388 /* ARGSUSED */ 1389 chmod(p, uap, retval) 1390 struct proc *p; 1391 register struct chmod_args *uap; 1392 int *retval; 1393 { 1394 register struct vnode *vp; 1395 struct vattr vattr; 1396 int error; 1397 struct nameidata nd; 1398 1399 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 1400 if (error = namei(&nd)) 1401 return (error); 1402 vp = nd.ni_vp; 1403 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1404 VOP_LOCK(vp); 1405 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1406 error = EROFS; 1407 else { 1408 VATTR_NULL(&vattr); 1409 vattr.va_mode = uap->mode & ALLPERMS; 1410 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1411 } 1412 vput(vp); 1413 return (error); 1414 } 1415 1416 /* 1417 * Change mode of a file given a file descriptor. 1418 */ 1419 struct fchmod_args { 1420 int fd; 1421 int mode; 1422 }; 1423 /* ARGSUSED */ 1424 fchmod(p, uap, retval) 1425 struct proc *p; 1426 register struct fchmod_args *uap; 1427 int *retval; 1428 { 1429 struct vattr vattr; 1430 struct vnode *vp; 1431 struct file *fp; 1432 int error; 1433 1434 if (error = getvnode(p->p_fd, uap->fd, &fp)) 1435 return (error); 1436 vp = (struct vnode *)fp->f_data; 1437 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1438 VOP_LOCK(vp); 1439 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1440 error = EROFS; 1441 else { 1442 VATTR_NULL(&vattr); 1443 vattr.va_mode = uap->mode & ALLPERMS; 1444 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1445 } 1446 VOP_UNLOCK(vp); 1447 return (error); 1448 } 1449 1450 /* 1451 * Set ownership given a path name. 1452 */ 1453 struct chown_args { 1454 char *path; 1455 int uid; 1456 int gid; 1457 }; 1458 /* ARGSUSED */ 1459 chown(p, uap, retval) 1460 struct proc *p; 1461 register struct chown_args *uap; 1462 int *retval; 1463 { 1464 register struct vnode *vp; 1465 struct vattr vattr; 1466 int error; 1467 struct nameidata nd; 1468 1469 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 1470 if (error = namei(&nd)) 1471 return (error); 1472 vp = nd.ni_vp; 1473 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1474 VOP_LOCK(vp); 1475 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1476 error = EROFS; 1477 else { 1478 VATTR_NULL(&vattr); 1479 vattr.va_uid = uap->uid; 1480 vattr.va_gid = uap->gid; 1481 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1482 } 1483 vput(vp); 1484 return (error); 1485 } 1486 1487 /* 1488 * Set ownership given a file descriptor. 1489 */ 1490 struct fchown_args { 1491 int fd; 1492 int uid; 1493 int gid; 1494 }; 1495 /* ARGSUSED */ 1496 fchown(p, uap, retval) 1497 struct proc *p; 1498 register struct fchown_args *uap; 1499 int *retval; 1500 { 1501 struct vattr vattr; 1502 struct vnode *vp; 1503 struct file *fp; 1504 int error; 1505 1506 if (error = getvnode(p->p_fd, uap->fd, &fp)) 1507 return (error); 1508 vp = (struct vnode *)fp->f_data; 1509 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1510 VOP_LOCK(vp); 1511 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1512 error = EROFS; 1513 else { 1514 VATTR_NULL(&vattr); 1515 vattr.va_uid = uap->uid; 1516 vattr.va_gid = uap->gid; 1517 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1518 } 1519 VOP_UNLOCK(vp); 1520 return (error); 1521 } 1522 1523 /* 1524 * Set the access and modification times of a file. 1525 */ 1526 struct utimes_args { 1527 char *path; 1528 struct timeval *tptr; 1529 }; 1530 /* ARGSUSED */ 1531 utimes(p, uap, retval) 1532 struct proc *p; 1533 register struct utimes_args *uap; 1534 int *retval; 1535 { 1536 register struct vnode *vp; 1537 struct timeval tv[2]; 1538 struct vattr vattr; 1539 int error; 1540 struct nameidata nd; 1541 1542 VATTR_NULL(&vattr); 1543 if (uap->tptr == NULL) { 1544 microtime(&tv[0]); 1545 tv[1] = tv[0]; 1546 vattr.va_vaflags |= VA_UTIMES_NULL; 1547 } else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 1548 return (error); 1549 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 1550 if (error = namei(&nd)) 1551 return (error); 1552 vp = nd.ni_vp; 1553 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1554 VOP_LOCK(vp); 1555 if (vp->v_mount->mnt_flag & MNT_RDONLY) 1556 error = EROFS; 1557 else { 1558 vattr.va_atime.ts_sec = tv[0].tv_sec; 1559 vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000; 1560 vattr.va_mtime.ts_sec = tv[1].tv_sec; 1561 vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000; 1562 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1563 } 1564 vput(vp); 1565 return (error); 1566 } 1567 1568 /* 1569 * Truncate a file given its path name. 1570 */ 1571 struct truncate_args { 1572 char *path; 1573 int pad; 1574 off_t length; 1575 }; 1576 /* ARGSUSED */ 1577 truncate(p, uap, retval) 1578 struct proc *p; 1579 register struct truncate_args *uap; 1580 int *retval; 1581 { 1582 register struct vnode *vp; 1583 struct vattr vattr; 1584 int error; 1585 struct nameidata nd; 1586 1587 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 1588 if (error = namei(&nd)) 1589 return (error); 1590 vp = nd.ni_vp; 1591 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1592 VOP_LOCK(vp); 1593 if (vp->v_type == VDIR) 1594 error = EISDIR; 1595 else if ((error = vn_writechk(vp)) == 0 && 1596 (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) { 1597 VATTR_NULL(&vattr); 1598 vattr.va_size = uap->length; 1599 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); 1600 } 1601 vput(vp); 1602 return (error); 1603 } 1604 1605 /* 1606 * Truncate a file given a file descriptor. 1607 */ 1608 struct ftruncate_args { 1609 int fd; 1610 int pad; 1611 off_t length; 1612 }; 1613 /* ARGSUSED */ 1614 ftruncate(p, uap, retval) 1615 struct proc *p; 1616 register struct ftruncate_args *uap; 1617 int *retval; 1618 { 1619 struct vattr vattr; 1620 struct vnode *vp; 1621 struct file *fp; 1622 int error; 1623 1624 if (error = getvnode(p->p_fd, uap->fd, &fp)) 1625 return (error); 1626 if ((fp->f_flag & FWRITE) == 0) 1627 return (EINVAL); 1628 vp = (struct vnode *)fp->f_data; 1629 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1630 VOP_LOCK(vp); 1631 if (vp->v_type == VDIR) 1632 error = EISDIR; 1633 else if ((error = vn_writechk(vp)) == 0) { 1634 VATTR_NULL(&vattr); 1635 vattr.va_size = uap->length; 1636 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p); 1637 } 1638 VOP_UNLOCK(vp); 1639 return (error); 1640 } 1641 1642 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 1643 /* 1644 * Truncate a file given its path name. 1645 */ 1646 struct otruncate_args { 1647 char *path; 1648 long length; 1649 }; 1650 /* ARGSUSED */ 1651 otruncate(p, uap, retval) 1652 struct proc *p; 1653 register struct otruncate_args *uap; 1654 int *retval; 1655 { 1656 struct truncate_args nuap; 1657 1658 nuap.path = uap->path; 1659 nuap.length = uap->length; 1660 return (truncate(p, &nuap, retval)); 1661 } 1662 1663 /* 1664 * Truncate a file given a file descriptor. 1665 */ 1666 struct oftruncate_args { 1667 int fd; 1668 long length; 1669 }; 1670 /* ARGSUSED */ 1671 oftruncate(p, uap, retval) 1672 struct proc *p; 1673 register struct oftruncate_args *uap; 1674 int *retval; 1675 { 1676 struct ftruncate_args nuap; 1677 1678 nuap.fd = uap->fd; 1679 nuap.length = uap->length; 1680 return (ftruncate(p, &nuap, retval)); 1681 } 1682 #endif /* COMPAT_43 || COMPAT_SUNOS */ 1683 1684 /* 1685 * Sync an open file. 1686 */ 1687 struct fsync_args { 1688 int fd; 1689 }; 1690 /* ARGSUSED */ 1691 fsync(p, uap, retval) 1692 struct proc *p; 1693 struct fsync_args *uap; 1694 int *retval; 1695 { 1696 register struct vnode *vp; 1697 struct file *fp; 1698 int error; 1699 1700 if (error = getvnode(p->p_fd, uap->fd, &fp)) 1701 return (error); 1702 vp = (struct vnode *)fp->f_data; 1703 VOP_LOCK(vp); 1704 error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p); 1705 VOP_UNLOCK(vp); 1706 return (error); 1707 } 1708 1709 /* 1710 * Rename files. Source and destination must either both be directories, 1711 * or both not be directories. If target is a directory, it must be empty. 1712 */ 1713 struct rename_args { 1714 char *from; 1715 char *to; 1716 }; 1717 /* ARGSUSED */ 1718 rename(p, uap, retval) 1719 struct proc *p; 1720 register struct rename_args *uap; 1721 int *retval; 1722 { 1723 register struct vnode *tvp, *fvp, *tdvp; 1724 struct nameidata fromnd, tond; 1725 int error; 1726 1727 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE, 1728 uap->from, p); 1729 if (error = namei(&fromnd)) 1730 return (error); 1731 fvp = fromnd.ni_vp; 1732 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART, 1733 UIO_USERSPACE, uap->to, p); 1734 if (error = namei(&tond)) { 1735 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 1736 vrele(fromnd.ni_dvp); 1737 vrele(fvp); 1738 goto out1; 1739 } 1740 tdvp = tond.ni_dvp; 1741 tvp = tond.ni_vp; 1742 if (tvp != NULL) { 1743 if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 1744 error = ENOTDIR; 1745 goto out; 1746 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 1747 error = EISDIR; 1748 goto out; 1749 } 1750 } 1751 if (fvp == tdvp) 1752 error = EINVAL; 1753 /* 1754 * If source is the same as the destination (that is the 1755 * same inode number with the same name in the same directory), 1756 * then there is nothing to do. 1757 */ 1758 if (fvp == tvp && fromnd.ni_dvp == tdvp && 1759 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 1760 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 1761 fromnd.ni_cnd.cn_namelen)) 1762 error = -1; 1763 out: 1764 if (!error) { 1765 LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE); 1766 if (fromnd.ni_dvp != tdvp) 1767 LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1768 if (tvp) 1769 LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE); 1770 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 1771 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 1772 } else { 1773 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 1774 if (tdvp == tvp) 1775 vrele(tdvp); 1776 else 1777 vput(tdvp); 1778 if (tvp) 1779 vput(tvp); 1780 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 1781 vrele(fromnd.ni_dvp); 1782 vrele(fvp); 1783 } 1784 vrele(tond.ni_startdir); 1785 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 1786 out1: 1787 if (fromnd.ni_startdir) 1788 vrele(fromnd.ni_startdir); 1789 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 1790 if (error == -1) 1791 return (0); 1792 return (error); 1793 } 1794 1795 /* 1796 * Make a directory file. 1797 */ 1798 struct mkdir_args { 1799 char *path; 1800 int mode; 1801 }; 1802 /* ARGSUSED */ 1803 mkdir(p, uap, retval) 1804 struct proc *p; 1805 register struct mkdir_args *uap; 1806 int *retval; 1807 { 1808 register struct vnode *vp; 1809 struct vattr vattr; 1810 int error; 1811 struct nameidata nd; 1812 1813 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p); 1814 if (error = namei(&nd)) 1815 return (error); 1816 vp = nd.ni_vp; 1817 if (vp != NULL) { 1818 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1819 if (nd.ni_dvp == vp) 1820 vrele(nd.ni_dvp); 1821 else 1822 vput(nd.ni_dvp); 1823 vrele(vp); 1824 return (EEXIST); 1825 } 1826 VATTR_NULL(&vattr); 1827 vattr.va_type = VDIR; 1828 vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask; 1829 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1830 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 1831 if (!error) 1832 vput(nd.ni_vp); 1833 return (error); 1834 } 1835 1836 /* 1837 * Remove a directory file. 1838 */ 1839 struct rmdir_args { 1840 char *path; 1841 }; 1842 /* ARGSUSED */ 1843 rmdir(p, uap, retval) 1844 struct proc *p; 1845 struct rmdir_args *uap; 1846 int *retval; 1847 { 1848 register struct vnode *vp; 1849 int error; 1850 struct nameidata nd; 1851 1852 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p); 1853 if (error = namei(&nd)) 1854 return (error); 1855 vp = nd.ni_vp; 1856 if (vp->v_type != VDIR) { 1857 error = ENOTDIR; 1858 goto out; 1859 } 1860 /* 1861 * No rmdir "." please. 1862 */ 1863 if (nd.ni_dvp == vp) { 1864 error = EINVAL; 1865 goto out; 1866 } 1867 /* 1868 * The root of a mounted filesystem cannot be deleted. 1869 */ 1870 if (vp->v_flag & VROOT) 1871 error = EBUSY; 1872 out: 1873 if (!error) { 1874 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 1875 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE); 1876 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 1877 } else { 1878 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1879 if (nd.ni_dvp == vp) 1880 vrele(nd.ni_dvp); 1881 else 1882 vput(nd.ni_dvp); 1883 vput(vp); 1884 } 1885 return (error); 1886 } 1887 1888 #ifdef COMPAT_43 1889 /* 1890 * Read a block of directory entries in a file system independent format. 1891 */ 1892 struct ogetdirentries_args { 1893 int fd; 1894 char *buf; 1895 u_int count; 1896 long *basep; 1897 }; 1898 ogetdirentries(p, uap, retval) 1899 struct proc *p; 1900 register struct ogetdirentries_args *uap; 1901 int *retval; 1902 { 1903 register struct vnode *vp; 1904 struct file *fp; 1905 struct uio auio, kuio; 1906 struct iovec aiov, kiov; 1907 struct dirent *dp, *edp; 1908 caddr_t dirbuf; 1909 int error, eofflag, readcnt; 1910 long loff; 1911 1912 if (error = getvnode(p->p_fd, uap->fd, &fp)) 1913 return (error); 1914 if ((fp->f_flag & FREAD) == 0) 1915 return (EBADF); 1916 vp = (struct vnode *)fp->f_data; 1917 unionread: 1918 if (vp->v_type != VDIR) 1919 return (EINVAL); 1920 aiov.iov_base = uap->buf; 1921 aiov.iov_len = uap->count; 1922 auio.uio_iov = &aiov; 1923 auio.uio_iovcnt = 1; 1924 auio.uio_rw = UIO_READ; 1925 auio.uio_segflg = UIO_USERSPACE; 1926 auio.uio_procp = p; 1927 auio.uio_resid = uap->count; 1928 VOP_LOCK(vp); 1929 loff = auio.uio_offset = fp->f_offset; 1930 # if (BYTE_ORDER != LITTLE_ENDIAN) 1931 if (vp->v_mount->mnt_maxsymlinklen <= 0) { 1932 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 1933 (u_long *)0, 0); 1934 fp->f_offset = auio.uio_offset; 1935 } else 1936 # endif 1937 { 1938 kuio = auio; 1939 kuio.uio_iov = &kiov; 1940 kuio.uio_segflg = UIO_SYSSPACE; 1941 kiov.iov_len = uap->count; 1942 MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK); 1943 kiov.iov_base = dirbuf; 1944 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag, 1945 (u_long *)0, 0); 1946 fp->f_offset = kuio.uio_offset; 1947 if (error == 0) { 1948 readcnt = uap->count - kuio.uio_resid; 1949 edp = (struct dirent *)&dirbuf[readcnt]; 1950 for (dp = (struct dirent *)dirbuf; dp < edp; ) { 1951 # if (BYTE_ORDER == LITTLE_ENDIAN) 1952 /* 1953 * The expected low byte of 1954 * dp->d_namlen is our dp->d_type. 1955 * The high MBZ byte of dp->d_namlen 1956 * is our dp->d_namlen. 1957 */ 1958 dp->d_type = dp->d_namlen; 1959 dp->d_namlen = 0; 1960 # else 1961 /* 1962 * The dp->d_type is the high byte 1963 * of the expected dp->d_namlen, 1964 * so must be zero'ed. 1965 */ 1966 dp->d_type = 0; 1967 # endif 1968 if (dp->d_reclen > 0) { 1969 dp = (struct dirent *) 1970 ((char *)dp + dp->d_reclen); 1971 } else { 1972 error = EIO; 1973 break; 1974 } 1975 } 1976 if (dp >= edp) 1977 error = uiomove(dirbuf, readcnt, &auio); 1978 } 1979 FREE(dirbuf, M_TEMP); 1980 } 1981 VOP_UNLOCK(vp); 1982 if (error) 1983 return (error); 1984 1985 #ifdef UNION 1986 { 1987 extern int (**union_vnodeop_p)(); 1988 extern struct vnode *union_lowervp __P((struct vnode *)); 1989 1990 if ((uap->count == auio.uio_resid) && 1991 (vp->v_op == union_vnodeop_p)) { 1992 struct vnode *lvp; 1993 1994 lvp = union_lowervp(vp); 1995 if (lvp != NULLVP) { 1996 VOP_LOCK(lvp); 1997 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 1998 VOP_UNLOCK(lvp); 1999 2000 if (error) { 2001 vrele(lvp); 2002 return (error); 2003 } 2004 fp->f_data = (caddr_t) lvp; 2005 fp->f_offset = 0; 2006 error = vn_close(vp, FREAD, fp->f_cred, p); 2007 if (error) 2008 return (error); 2009 vp = lvp; 2010 goto unionread; 2011 } 2012 } 2013 } 2014 #endif /* UNION */ 2015 2016 if ((uap->count == auio.uio_resid) && 2017 (vp->v_flag & VROOT) && 2018 (vp->v_mount->mnt_flag & MNT_UNION)) { 2019 struct vnode *tvp = vp; 2020 vp = vp->v_mount->mnt_vnodecovered; 2021 VREF(vp); 2022 fp->f_data = (caddr_t) vp; 2023 fp->f_offset = 0; 2024 vrele(tvp); 2025 goto unionread; 2026 } 2027 error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 2028 *retval = uap->count - auio.uio_resid; 2029 return (error); 2030 } 2031 #endif /* COMPAT_43 */ 2032 2033 /* 2034 * Read a block of directory entries in a file system independent format. 2035 */ 2036 struct getdirentries_args { 2037 int fd; 2038 char *buf; 2039 u_int count; 2040 long *basep; 2041 }; 2042 getdirentries(p, uap, retval) 2043 struct proc *p; 2044 register struct getdirentries_args *uap; 2045 int *retval; 2046 { 2047 register struct vnode *vp; 2048 struct file *fp; 2049 struct uio auio; 2050 struct iovec aiov; 2051 long loff; 2052 int error, eofflag; 2053 2054 if (error = getvnode(p->p_fd, uap->fd, &fp)) 2055 return (error); 2056 if ((fp->f_flag & FREAD) == 0) 2057 return (EBADF); 2058 vp = (struct vnode *)fp->f_data; 2059 unionread: 2060 if (vp->v_type != VDIR) 2061 return (EINVAL); 2062 aiov.iov_base = uap->buf; 2063 aiov.iov_len = uap->count; 2064 auio.uio_iov = &aiov; 2065 auio.uio_iovcnt = 1; 2066 auio.uio_rw = UIO_READ; 2067 auio.uio_segflg = UIO_USERSPACE; 2068 auio.uio_procp = p; 2069 auio.uio_resid = uap->count; 2070 VOP_LOCK(vp); 2071 loff = auio.uio_offset = fp->f_offset; 2072 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *)0, 0); 2073 fp->f_offset = auio.uio_offset; 2074 VOP_UNLOCK(vp); 2075 if (error) 2076 return (error); 2077 2078 #ifdef UNION 2079 { 2080 extern int (**union_vnodeop_p)(); 2081 extern struct vnode *union_lowervp __P((struct vnode *)); 2082 2083 if ((uap->count == auio.uio_resid) && 2084 (vp->v_op == union_vnodeop_p)) { 2085 struct vnode *lvp; 2086 2087 lvp = union_lowervp(vp); 2088 if (lvp != NULLVP) { 2089 VOP_LOCK(lvp); 2090 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); 2091 VOP_UNLOCK(lvp); 2092 2093 if (error) { 2094 vrele(lvp); 2095 return (error); 2096 } 2097 fp->f_data = (caddr_t) lvp; 2098 fp->f_offset = 0; 2099 error = vn_close(vp, FREAD, fp->f_cred, p); 2100 if (error) 2101 return (error); 2102 vp = lvp; 2103 goto unionread; 2104 } 2105 } 2106 } 2107 #endif 2108 2109 if ((uap->count == auio.uio_resid) && 2110 (vp->v_flag & VROOT) && 2111 (vp->v_mount->mnt_flag & MNT_UNION)) { 2112 struct vnode *tvp = vp; 2113 vp = vp->v_mount->mnt_vnodecovered; 2114 VREF(vp); 2115 fp->f_data = (caddr_t) vp; 2116 fp->f_offset = 0; 2117 vrele(tvp); 2118 goto unionread; 2119 } 2120 error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)); 2121 *retval = uap->count - auio.uio_resid; 2122 return (error); 2123 } 2124 2125 /* 2126 * Set the mode mask for creation of filesystem nodes. 2127 */ 2128 struct umask_args { 2129 int newmask; 2130 }; 2131 mode_t /* XXX */ 2132 umask(p, uap, retval) 2133 struct proc *p; 2134 struct umask_args *uap; 2135 int *retval; 2136 { 2137 register struct filedesc *fdp; 2138 2139 fdp = p->p_fd; 2140 *retval = fdp->fd_cmask; 2141 fdp->fd_cmask = uap->newmask & ALLPERMS; 2142 return (0); 2143 } 2144 2145 /* 2146 * Void all references to file by ripping underlying filesystem 2147 * away from vnode. 2148 */ 2149 struct revoke_args { 2150 char *path; 2151 }; 2152 /* ARGSUSED */ 2153 revoke(p, uap, retval) 2154 struct proc *p; 2155 register struct revoke_args *uap; 2156 int *retval; 2157 { 2158 register struct vnode *vp; 2159 struct vattr vattr; 2160 int error; 2161 struct nameidata nd; 2162 2163 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); 2164 if (error = namei(&nd)) 2165 return (error); 2166 vp = nd.ni_vp; 2167 if (vp->v_type != VCHR && vp->v_type != VBLK) { 2168 error = EINVAL; 2169 goto out; 2170 } 2171 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) 2172 goto out; 2173 if (p->p_ucred->cr_uid != vattr.va_uid && 2174 (error = suser(p->p_ucred, &p->p_acflag))) 2175 goto out; 2176 if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) 2177 vgoneall(vp); 2178 out: 2179 vrele(vp); 2180 return (error); 2181 } 2182 2183 /* 2184 * Convert a user file descriptor to a kernel file entry. 2185 */ 2186 getvnode(fdp, fd, fpp) 2187 struct filedesc *fdp; 2188 struct file **fpp; 2189 int fd; 2190 { 2191 struct file *fp; 2192 2193 if ((u_int)fd >= fdp->fd_nfiles || 2194 (fp = fdp->fd_ofiles[fd]) == NULL) 2195 return (EBADF); 2196 if (fp->f_type != DTYPE_VNODE) 2197 return (EINVAL); 2198 *fpp = fp; 2199 return (0); 2200 } 2201