1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)vfs_syscalls.c 7.11 (Berkeley) 06/08/89 18 */ 19 20 #include "param.h" 21 #include "systm.h" 22 #include "syscontext.h" 23 #include "kernel.h" 24 #include "file.h" 25 #include "stat.h" 26 #include "vnode.h" 27 #include "../ufs/inode.h" 28 #include "mount.h" 29 #include "proc.h" 30 #include "uio.h" 31 #include "malloc.h" 32 33 /* 34 * Virtual File System System Calls 35 */ 36 37 /* 38 * mount system call 39 */ 40 mount() 41 { 42 register struct a { 43 int type; 44 char *dir; 45 int flags; 46 caddr_t data; 47 } *uap = (struct a *)u.u_ap; 48 register struct nameidata *ndp = &u.u_nd; 49 struct vnode *vp; 50 struct mount *mp; 51 int error; 52 53 /* 54 * Must be super user 55 */ 56 if (error = suser(u.u_cred, &u.u_acflag)) 57 RETURN (error); 58 /* 59 * Get vnode to be covered 60 */ 61 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 62 ndp->ni_segflg = UIO_USERSPACE; 63 ndp->ni_dirp = uap->dir; 64 if (error = namei(ndp)) 65 RETURN (error); 66 vp = ndp->ni_vp; 67 if (vp->v_count != 1) { 68 vput(vp); 69 RETURN (EBUSY); 70 } 71 if (vp->v_type != VDIR) { 72 vput(vp); 73 RETURN (ENOTDIR); 74 } 75 if (uap->type > MOUNT_MAXTYPE || 76 vfssw[uap->type] == (struct vfsops *)0) { 77 vput(vp); 78 RETURN (ENODEV); 79 } 80 81 /* 82 * Mount the filesystem. 83 */ 84 mp = (struct mount *)malloc((u_long)sizeof(struct mount), 85 M_MOUNT, M_WAITOK); 86 mp->m_op = vfssw[uap->type]; 87 mp->m_flag = 0; 88 mp->m_exroot = 0; 89 error = vfs_add(vp, mp, uap->flags); 90 if (!error) 91 error = VFS_MOUNT(mp, uap->dir, uap->data, ndp); 92 cache_purge(vp); 93 VOP_UNLOCK(vp); 94 if (!error) { 95 vfs_unlock(mp); 96 } else { 97 vfs_remove(mp); 98 free((caddr_t)mp, M_MOUNT); 99 vrele(vp); 100 } 101 RETURN (error); 102 } 103 104 /* 105 * Unmount system call. 106 * 107 * Note: unmount takes a path to the vnode mounted on as argument, 108 * not special file (as before). 109 */ 110 unmount() 111 { 112 struct a { 113 char *pathp; 114 int flags; 115 } *uap = (struct a *)u.u_ap; 116 register struct vnode *vp; 117 register struct mount *mp; 118 register struct nameidata *ndp = &u.u_nd; 119 struct vnode *coveredvp; 120 int error; 121 122 /* 123 * Must be super user 124 */ 125 if (error = suser(u.u_cred, &u.u_acflag)) 126 RETURN (error); 127 128 ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 129 ndp->ni_segflg = UIO_USERSPACE; 130 ndp->ni_dirp = uap->pathp; 131 if (error = namei(ndp)) 132 RETURN (error); 133 vp = ndp->ni_vp; 134 /* 135 * Must be the root of the filesystem 136 */ 137 if ((vp->v_flag & VROOT) == 0) { 138 vput(vp); 139 RETURN (EINVAL); 140 } 141 mp = vp->v_mount; 142 vput(vp); 143 /* 144 * Do the unmount. 145 */ 146 coveredvp = mp->m_vnodecovered; 147 if (error = vfs_lock(mp)) 148 RETURN (error); 149 150 xumount(mp); /* remove unused sticky files from text table */ 151 cache_purgevfs(mp); /* remove cache entries for this file sys */ 152 VFS_SYNC(mp, MNT_WAIT); 153 154 error = VFS_UNMOUNT(mp, uap->flags); 155 if (error) { 156 vfs_unlock(mp); 157 } else { 158 vrele(coveredvp); 159 vfs_remove(mp); 160 free((caddr_t)mp, M_MOUNT); 161 } 162 RETURN (error); 163 } 164 165 /* 166 * Sync system call. 167 * Sync each mounted filesystem. 168 */ 169 sync() 170 { 171 register struct mount *mp; 172 173 mp = rootfs; 174 do { 175 if ((mp->m_flag & M_RDONLY) == 0) 176 VFS_SYNC(mp, MNT_NOWAIT); 177 mp = mp->m_next; 178 } while (mp != rootfs); 179 } 180 181 /* 182 * get filesystem statistics 183 */ 184 statfs() 185 { 186 struct a { 187 char *path; 188 struct statfs *buf; 189 } *uap = (struct a *)u.u_ap; 190 register struct vnode *vp; 191 register struct nameidata *ndp = &u.u_nd; 192 struct statfs sb; 193 int error; 194 195 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 196 ndp->ni_segflg = UIO_USERSPACE; 197 ndp->ni_dirp = uap->path; 198 if (error = namei(ndp)) 199 RETURN (error); 200 vp = ndp->ni_vp; 201 if (error = VFS_STATFS(vp->v_mount, &sb)) 202 goto out; 203 error = copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)); 204 out: 205 vput(vp); 206 RETURN (error); 207 } 208 209 fstatfs() 210 { 211 struct a { 212 int fd; 213 struct statfs *buf; 214 } *uap = (struct a *)u.u_ap; 215 struct file *fp; 216 struct statfs sb; 217 int error; 218 219 if (error = getvnode(uap->fd, &fp)) 220 RETURN (error); 221 if (error = VFS_STATFS(((struct vnode *)fp->f_data)->v_mount, &sb)) 222 RETURN (error); 223 RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb))); 224 } 225 226 /* 227 * Change current working directory to a given file descriptor. 228 */ 229 fchdir() 230 { 231 struct a { 232 int fd; 233 } *uap = (struct a *)u.u_ap; 234 register struct vnode *vp; 235 struct file *fp; 236 int error; 237 238 if (error = getvnode(uap->fd, &fp)) 239 RETURN (error); 240 vp = (struct vnode *)fp->f_data; 241 VOP_LOCK(vp); 242 if (vp->v_type != VDIR) 243 error = ENOTDIR; 244 else 245 error = vn_access(vp, VEXEC, u.u_cred); 246 VOP_UNLOCK(vp); 247 vrele(u.u_cdir); 248 u.u_cdir = vp; 249 RETURN (error); 250 } 251 252 /* 253 * Change current working directory (``.''). 254 */ 255 chdir() 256 { 257 struct a { 258 char *fname; 259 } *uap = (struct a *)u.u_ap; 260 register struct nameidata *ndp = &u.u_nd; 261 int error; 262 263 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 264 ndp->ni_segflg = UIO_USERSPACE; 265 ndp->ni_dirp = uap->fname; 266 if (error = chdirec(ndp)) 267 RETURN (error); 268 vrele(u.u_cdir); 269 u.u_cdir = ndp->ni_vp; 270 RETURN (0); 271 } 272 273 /* 274 * Change notion of root (``/'') directory. 275 */ 276 chroot() 277 { 278 struct a { 279 char *fname; 280 } *uap = (struct a *)u.u_ap; 281 register struct nameidata *ndp = &u.u_nd; 282 int error; 283 284 if (error = suser(u.u_cred, &u.u_acflag)) 285 RETURN (error); 286 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 287 ndp->ni_segflg = UIO_USERSPACE; 288 ndp->ni_dirp = uap->fname; 289 if (error = chdirec(ndp)) 290 RETURN (error); 291 vrele(u.u_rdir); 292 u.u_rdir = ndp->ni_vp; 293 RETURN (0); 294 } 295 296 /* 297 * Common routine for chroot and chdir. 298 */ 299 chdirec(ndp) 300 register struct nameidata *ndp; 301 { 302 struct vnode *vp; 303 int error; 304 305 if (error = namei(ndp)) 306 return (error); 307 vp = ndp->ni_vp; 308 if (vp->v_type != VDIR) 309 error = ENOTDIR; 310 else 311 error = vn_access(vp, VEXEC, ndp->ni_cred); 312 VOP_UNLOCK(vp); 313 if (error) 314 vrele(vp); 315 return (error); 316 } 317 318 /* 319 * Open system call. 320 */ 321 open() 322 { 323 struct a { 324 char *fname; 325 int mode; 326 int crtmode; 327 } *uap = (struct a *) u.u_ap; 328 struct nameidata *ndp = &u.u_nd; 329 330 ndp->ni_segflg = UIO_USERSPACE; 331 ndp->ni_dirp = uap->fname; 332 RETURN (copen(uap->mode-FOPEN, uap->crtmode &~ u.u_cmask, ndp, 333 &u.u_r.r_val1)); 334 } 335 336 /* 337 * Creat system call. 338 */ 339 creat() 340 { 341 struct a { 342 char *fname; 343 int fmode; 344 } *uap = (struct a *)u.u_ap; 345 struct nameidata *ndp = &u.u_nd; 346 347 ndp->ni_segflg = UIO_USERSPACE; 348 ndp->ni_dirp = uap->fname; 349 RETURN (copen(FWRITE|FCREAT|FTRUNC, uap->fmode &~ u.u_cmask, ndp, 350 &u.u_r.r_val1)); 351 } 352 353 /* 354 * Common code for open and creat. 355 * Check permissions, allocate an open file structure, 356 * and call the device open routine if any. 357 */ 358 copen(fmode, cmode, ndp, resultfd) 359 int fmode, cmode; 360 struct nameidata *ndp; 361 int *resultfd; 362 { 363 register struct file *fp; 364 struct file *nfp; 365 int indx, error; 366 extern struct fileops vnops; 367 368 if (error = falloc(&nfp, &indx)) 369 return (error); 370 fp = nfp; 371 u.u_r.r_val1 = indx; /* XXX for fdopen() */ 372 if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) { 373 u.u_ofile[indx] = NULL; 374 crfree(fp->f_cred); 375 fp->f_count--; 376 return (error); 377 } 378 fp->f_flag = fmode & FMASK; 379 fp->f_type = DTYPE_VNODE; 380 fp->f_ops = &vnops; 381 fp->f_data = (caddr_t)ndp->ni_vp; 382 if (resultfd) 383 *resultfd = indx; 384 return (0); 385 } 386 387 /* 388 * Mknod system call 389 */ 390 mknod() 391 { 392 register struct a { 393 char *fname; 394 int fmode; 395 int dev; 396 } *uap = (struct a *)u.u_ap; 397 register struct nameidata *ndp = &u.u_nd; 398 register struct vnode *vp; 399 struct vattr vattr; 400 int error; 401 402 if (error = suser(u.u_cred, &u.u_acflag)) 403 RETURN (error); 404 ndp->ni_nameiop = CREATE | LOCKPARENT; 405 ndp->ni_segflg = UIO_USERSPACE; 406 ndp->ni_dirp = uap->fname; 407 if (error = namei(ndp)) 408 RETURN (error); 409 vp = ndp->ni_vp; 410 if (vp != NULL) { 411 error = EEXIST; 412 goto out; 413 } 414 vattr_null(&vattr); 415 switch (uap->fmode & IFMT) { 416 417 case IFMT: /* used by badsect to flag bad sectors */ 418 vattr.va_type = VBAD; 419 break; 420 case IFCHR: 421 vattr.va_type = VCHR; 422 break; 423 case IFBLK: 424 vattr.va_type = VBLK; 425 break; 426 default: 427 error = EINVAL; 428 goto out; 429 } 430 vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask; 431 vattr.va_rdev = uap->dev; 432 out: 433 if (error) 434 VOP_ABORTOP(ndp); 435 else 436 error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 437 RETURN (error); 438 } 439 440 /* 441 * link system call 442 */ 443 link() 444 { 445 register struct a { 446 char *target; 447 char *linkname; 448 } *uap = (struct a *)u.u_ap; 449 register struct nameidata *ndp = &u.u_nd; 450 register struct vnode *vp, *xp; 451 int error; 452 453 ndp->ni_nameiop = LOOKUP | FOLLOW; 454 ndp->ni_segflg = UIO_USERSPACE; 455 ndp->ni_dirp = uap->target; 456 if (error = namei(ndp)) 457 RETURN (error); 458 vp = ndp->ni_vp; 459 if (vp->v_type == VDIR && 460 (error = suser(u.u_cred, &u.u_acflag))) 461 goto out1; 462 ndp->ni_nameiop = CREATE | LOCKPARENT; 463 ndp->ni_dirp = (caddr_t)uap->linkname; 464 if (error = namei(ndp)) 465 goto out1; 466 xp = ndp->ni_vp; 467 if (xp != NULL) { 468 error = EEXIST; 469 goto out; 470 } 471 xp = ndp->ni_dvp; 472 if (vp->v_mount != xp->v_mount) 473 error = EXDEV; 474 out: 475 if (error) 476 VOP_ABORTOP(ndp); 477 else 478 error = VOP_LINK(vp, ndp); 479 out1: 480 vrele(vp); 481 RETURN (error); 482 } 483 484 /* 485 * symlink -- make a symbolic link 486 */ 487 symlink() 488 { 489 struct a { 490 char *target; 491 char *linkname; 492 } *uap = (struct a *)u.u_ap; 493 register struct nameidata *ndp = &u.u_nd; 494 register struct vnode *vp; 495 struct vattr vattr; 496 char *target; 497 int error; 498 499 ndp->ni_segflg = UIO_USERSPACE; 500 ndp->ni_dirp = uap->linkname; 501 MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 502 if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 503 goto out1; 504 ndp->ni_nameiop = CREATE | LOCKPARENT; 505 if (error = namei(ndp)) 506 goto out1; 507 vp = ndp->ni_vp; 508 if (vp) { 509 error = EEXIST; 510 goto out; 511 } 512 vp = ndp->ni_dvp; 513 vattr_null(&vattr); 514 vattr.va_mode = 0777 &~ u.u_cmask; 515 out: 516 if (error) 517 VOP_ABORTOP(ndp); 518 else 519 error = VOP_SYMLINK(ndp, &vattr, target); 520 out1: 521 FREE(target, M_NAMEI); 522 RETURN (error); 523 } 524 525 /* 526 * Unlink system call. 527 * Hard to avoid races here, especially 528 * in unlinking directories. 529 */ 530 unlink() 531 { 532 struct a { 533 char *fname; 534 } *uap = (struct a *)u.u_ap; 535 register struct nameidata *ndp = &u.u_nd; 536 register struct vnode *vp; 537 int error; 538 539 ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 540 ndp->ni_segflg = UIO_USERSPACE; 541 ndp->ni_dirp = uap->fname; 542 if (error = namei(ndp)) 543 RETURN (error); 544 vp = ndp->ni_vp; 545 if (vp->v_type == VDIR && 546 (error = suser(u.u_cred, &u.u_acflag))) 547 goto out; 548 /* 549 * Don't unlink a mounted file. 550 */ 551 if (vp->v_flag & VROOT) { 552 error = EBUSY; 553 goto out; 554 } 555 if (vp->v_flag & VTEXT) 556 xrele(vp); /* try once to free text */ 557 out: 558 if (error) 559 VOP_ABORTOP(ndp); 560 else 561 error = VOP_REMOVE(ndp); 562 RETURN (error); 563 } 564 565 /* 566 * Seek system call 567 */ 568 lseek() 569 { 570 register struct file *fp; 571 register struct a { 572 int fdes; 573 off_t off; 574 int sbase; 575 } *uap = (struct a *)u.u_ap; 576 struct vattr vattr; 577 int error; 578 579 if ((unsigned)uap->fdes >= NOFILE || 580 (fp = u.u_ofile[uap->fdes]) == NULL) 581 RETURN (EBADF); 582 if (fp->f_type != DTYPE_VNODE) 583 RETURN (ESPIPE); 584 switch (uap->sbase) { 585 586 case L_INCR: 587 fp->f_offset += uap->off; 588 break; 589 590 case L_XTND: 591 if (error = VOP_GETATTR((struct vnode *)fp->f_data, 592 &vattr, u.u_cred)) 593 RETURN (error); 594 fp->f_offset = uap->off + vattr.va_size; 595 break; 596 597 case L_SET: 598 fp->f_offset = uap->off; 599 break; 600 601 default: 602 RETURN (EINVAL); 603 } 604 u.u_r.r_off = fp->f_offset; 605 RETURN (0); 606 } 607 608 /* 609 * Access system call 610 */ 611 saccess() 612 { 613 register struct a { 614 char *fname; 615 int fmode; 616 } *uap = (struct a *)u.u_ap; 617 register struct nameidata *ndp = &u.u_nd; 618 register struct vnode *vp; 619 int error, mode, svuid, svgid; 620 621 svuid = u.u_uid; 622 svgid = u.u_gid; 623 u.u_uid = u.u_ruid; 624 u.u_gid = u.u_rgid; 625 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 626 ndp->ni_segflg = UIO_USERSPACE; 627 ndp->ni_dirp = uap->fname; 628 if (error = namei(ndp)) 629 goto out1; 630 vp = ndp->ni_vp; 631 /* 632 * fmode == 0 means only check for exist 633 */ 634 if (uap->fmode) { 635 mode = 0; 636 if (uap->fmode & R_OK) 637 mode |= VREAD; 638 if (uap->fmode & W_OK) 639 mode |= VWRITE; 640 if (uap->fmode & X_OK) 641 mode |= VEXEC; 642 error = vn_access(vp, mode, u.u_cred); 643 } 644 vput(vp); 645 out1: 646 u.u_uid = svuid; 647 u.u_gid = svgid; 648 RETURN (error); 649 } 650 651 /* 652 * Stat system call. This version follows links. 653 */ 654 stat() 655 { 656 657 stat1(FOLLOW); 658 } 659 660 /* 661 * Lstat system call. This version does not follow links. 662 */ 663 lstat() 664 { 665 666 stat1(NOFOLLOW); 667 } 668 669 stat1(follow) 670 int follow; 671 { 672 register struct a { 673 char *fname; 674 struct stat *ub; 675 } *uap = (struct a *)u.u_ap; 676 register struct nameidata *ndp = &u.u_nd; 677 struct stat sb; 678 int error; 679 680 ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow; 681 ndp->ni_segflg = UIO_USERSPACE; 682 ndp->ni_dirp = uap->fname; 683 if (error = namei(ndp)) 684 RETURN (error); 685 error = vn_stat(ndp->ni_vp, &sb); 686 vput(ndp->ni_vp); 687 if (error) 688 RETURN (error); 689 error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 690 RETURN (error); 691 } 692 693 /* 694 * Return target name of a symbolic link 695 */ 696 readlink() 697 { 698 register struct a { 699 char *name; 700 char *buf; 701 int count; 702 } *uap = (struct a *)u.u_ap; 703 register struct nameidata *ndp = &u.u_nd; 704 register struct vnode *vp; 705 struct iovec aiov; 706 struct uio auio; 707 int error; 708 709 ndp->ni_nameiop = LOOKUP | LOCKLEAF; 710 ndp->ni_segflg = UIO_USERSPACE; 711 ndp->ni_dirp = uap->name; 712 if (error = namei(ndp)) 713 RETURN (error); 714 vp = ndp->ni_vp; 715 if (vp->v_type != VLNK) { 716 error = EINVAL; 717 goto out; 718 } 719 aiov.iov_base = uap->buf; 720 aiov.iov_len = uap->count; 721 auio.uio_iov = &aiov; 722 auio.uio_iovcnt = 1; 723 auio.uio_offset = 0; 724 auio.uio_rw = UIO_READ; 725 auio.uio_segflg = UIO_USERSPACE; 726 auio.uio_resid = uap->count; 727 error = VOP_READLINK(vp, &auio, ndp->ni_cred); 728 out: 729 vput(vp); 730 u.u_r.r_val1 = uap->count - auio.uio_resid; 731 RETURN (error); 732 } 733 734 /* 735 * Change flags of a file given path name. 736 */ 737 chflags() 738 { 739 struct a { 740 char *fname; 741 int flags; 742 } *uap = (struct a *)u.u_ap; 743 register struct nameidata *ndp = &u.u_nd; 744 register struct vnode *vp; 745 struct vattr vattr; 746 int error; 747 748 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 749 ndp->ni_segflg = UIO_USERSPACE; 750 ndp->ni_dirp = uap->fname; 751 vattr_null(&vattr); 752 vattr.va_flags = uap->flags; 753 if (error = namei(ndp)) 754 RETURN (error); 755 vp = ndp->ni_vp; 756 if (vp->v_mount->m_flag & M_RDONLY) { 757 error = EROFS; 758 goto out; 759 } 760 error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 761 out: 762 vput(vp); 763 RETURN (error); 764 } 765 766 /* 767 * Change flags of a file given a file descriptor. 768 */ 769 fchflags() 770 { 771 struct a { 772 int fd; 773 int flags; 774 } *uap = (struct a *)u.u_ap; 775 struct vattr vattr; 776 struct vnode *vp; 777 struct file *fp; 778 int error; 779 780 if (error = getvnode(uap->fd, &fp)) 781 RETURN (error); 782 vattr_null(&vattr); 783 vattr.va_flags = uap->flags; 784 vp = (struct vnode *)fp->f_data; 785 VOP_LOCK(vp); 786 if (vp->v_mount->m_flag & M_RDONLY) { 787 error = EROFS; 788 goto out; 789 } 790 error = VOP_SETATTR(vp, &vattr, fp->f_cred); 791 out: 792 VOP_UNLOCK(vp); 793 RETURN (error); 794 } 795 796 /* 797 * Change mode of a file given path name. 798 */ 799 chmod() 800 { 801 struct a { 802 char *fname; 803 int fmode; 804 } *uap = (struct a *)u.u_ap; 805 register struct nameidata *ndp = &u.u_nd; 806 register struct vnode *vp; 807 struct vattr vattr; 808 int error; 809 810 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 811 ndp->ni_segflg = UIO_USERSPACE; 812 ndp->ni_dirp = uap->fname; 813 vattr_null(&vattr); 814 vattr.va_mode = uap->fmode & 07777; 815 if (error = namei(ndp)) 816 RETURN (error); 817 vp = ndp->ni_vp; 818 if (vp->v_mount->m_flag & M_RDONLY) { 819 error = EROFS; 820 goto out; 821 } 822 error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 823 out: 824 vput(vp); 825 RETURN (error); 826 } 827 828 /* 829 * Change mode of a file given a file descriptor. 830 */ 831 fchmod() 832 { 833 struct a { 834 int fd; 835 int fmode; 836 } *uap = (struct a *)u.u_ap; 837 struct vattr vattr; 838 struct vnode *vp; 839 struct file *fp; 840 int error; 841 842 if (error = getvnode(uap->fd, &fp)) 843 RETURN (error); 844 vattr_null(&vattr); 845 vattr.va_mode = uap->fmode & 07777; 846 vp = (struct vnode *)fp->f_data; 847 VOP_LOCK(vp); 848 if (vp->v_mount->m_flag & M_RDONLY) { 849 error = EROFS; 850 goto out; 851 } 852 error = VOP_SETATTR(vp, &vattr, fp->f_cred); 853 out: 854 VOP_UNLOCK(vp); 855 RETURN (error); 856 } 857 858 /* 859 * Set ownership given a path name. 860 */ 861 chown() 862 { 863 struct a { 864 char *fname; 865 int uid; 866 int gid; 867 } *uap = (struct a *)u.u_ap; 868 register struct nameidata *ndp = &u.u_nd; 869 register struct vnode *vp; 870 struct vattr vattr; 871 int error; 872 873 ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 874 ndp->ni_segflg = UIO_USERSPACE; 875 ndp->ni_dirp = uap->fname; 876 vattr_null(&vattr); 877 vattr.va_uid = uap->uid; 878 vattr.va_gid = uap->gid; 879 if (error = namei(ndp)) 880 RETURN (error); 881 vp = ndp->ni_vp; 882 if (vp->v_mount->m_flag & M_RDONLY) { 883 error = EROFS; 884 goto out; 885 } 886 error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 887 out: 888 vput(vp); 889 RETURN (error); 890 } 891 892 /* 893 * Set ownership given a file descriptor. 894 */ 895 fchown() 896 { 897 struct a { 898 int fd; 899 int uid; 900 int gid; 901 } *uap = (struct a *)u.u_ap; 902 struct vattr vattr; 903 struct vnode *vp; 904 struct file *fp; 905 int error; 906 907 if (error = getvnode(uap->fd, &fp)) 908 RETURN (error); 909 vattr_null(&vattr); 910 vattr.va_uid = uap->uid; 911 vattr.va_gid = uap->gid; 912 vp = (struct vnode *)fp->f_data; 913 VOP_LOCK(vp); 914 if (vp->v_mount->m_flag & M_RDONLY) { 915 error = EROFS; 916 goto out; 917 } 918 error = VOP_SETATTR(vp, &vattr, fp->f_cred); 919 out: 920 VOP_UNLOCK(vp); 921 RETURN (error); 922 } 923 924 utimes() 925 { 926 register struct a { 927 char *fname; 928 struct timeval *tptr; 929 } *uap = (struct a *)u.u_ap; 930 register struct nameidata *ndp = &u.u_nd; 931 register struct vnode *vp; 932 struct timeval tv[2]; 933 struct vattr vattr; 934 int error; 935 936 if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 937 RETURN (error); 938 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 939 ndp->ni_segflg = UIO_USERSPACE; 940 ndp->ni_dirp = uap->fname; 941 vattr_null(&vattr); 942 vattr.va_atime = tv[0]; 943 vattr.va_mtime = tv[1]; 944 if (error = namei(ndp)) 945 RETURN (error); 946 vp = ndp->ni_vp; 947 if (vp->v_mount->m_flag & M_RDONLY) { 948 error = EROFS; 949 goto out; 950 } 951 error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 952 out: 953 vput(vp); 954 RETURN (error); 955 } 956 957 /* 958 * Truncate a file given its path name. 959 */ 960 truncate() 961 { 962 struct a { 963 char *fname; 964 off_t length; 965 } *uap = (struct a *)u.u_ap; 966 register struct nameidata *ndp = &u.u_nd; 967 register struct vnode *vp; 968 struct vattr vattr; 969 int error; 970 971 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 972 ndp->ni_segflg = UIO_USERSPACE; 973 ndp->ni_dirp = uap->fname; 974 vattr_null(&vattr); 975 vattr.va_size = uap->length; 976 if (error = namei(ndp)) 977 RETURN (error); 978 vp = ndp->ni_vp; 979 if (vp->v_type == VDIR) { 980 error = EISDIR; 981 goto out; 982 } 983 if (error = vn_access(vp, VWRITE, ndp->ni_cred)) 984 goto out; 985 error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 986 out: 987 vput(vp); 988 RETURN (error); 989 } 990 991 /* 992 * Truncate a file given a file descriptor. 993 */ 994 ftruncate() 995 { 996 struct a { 997 int fd; 998 off_t length; 999 } *uap = (struct a *)u.u_ap; 1000 struct vattr vattr; 1001 struct vnode *vp; 1002 struct file *fp; 1003 int error; 1004 1005 if (error = getvnode(uap->fd, &fp)) 1006 RETURN (error); 1007 if ((fp->f_flag & FWRITE) == 0) 1008 RETURN (EINVAL); 1009 vattr_null(&vattr); 1010 vattr.va_size = uap->length; 1011 vp = (struct vnode *)fp->f_data; 1012 VOP_LOCK(vp); 1013 if (vp->v_type == VDIR) { 1014 error = EISDIR; 1015 goto out; 1016 } 1017 if (error = vn_access(vp, VWRITE, fp->f_cred)) 1018 goto out; 1019 error = VOP_SETATTR(vp, &vattr, fp->f_cred); 1020 out: 1021 VOP_UNLOCK(vp); 1022 RETURN (error); 1023 } 1024 1025 /* 1026 * Synch an open file. 1027 */ 1028 fsync() 1029 { 1030 struct a { 1031 int fd; 1032 } *uap = (struct a *)u.u_ap; 1033 struct file *fp; 1034 int error; 1035 1036 if (error = getvnode(uap->fd, &fp)) 1037 RETURN (error); 1038 error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred); 1039 RETURN (error); 1040 } 1041 1042 /* 1043 * Rename system call. 1044 * 1045 * Source and destination must either both be directories, or both 1046 * not be directories. If target is a directory, it must be empty. 1047 */ 1048 rename() 1049 { 1050 struct a { 1051 char *from; 1052 char *to; 1053 } *uap = (struct a *)u.u_ap; 1054 register struct vnode *tvp, *fvp, *tdvp; 1055 register struct nameidata *ndp = &u.u_nd; 1056 struct nameidata tond; 1057 int error; 1058 1059 ndp->ni_nameiop = DELETE | WANTPARENT; 1060 ndp->ni_segflg = UIO_USERSPACE; 1061 ndp->ni_dirp = uap->from; 1062 if (error = namei(ndp)) 1063 RETURN (error); 1064 fvp = ndp->ni_vp; 1065 nddup(ndp, &tond); 1066 tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 1067 tond.ni_segflg = UIO_USERSPACE; 1068 tond.ni_dirp = uap->to; 1069 error = namei(&tond); 1070 tdvp = tond.ni_dvp; 1071 tvp = tond.ni_vp; 1072 if (tvp != NULL) { 1073 if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 1074 error = EISDIR; 1075 goto out; 1076 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 1077 error = ENOTDIR; 1078 goto out; 1079 } 1080 } 1081 if (error) { 1082 VOP_ABORTOP(ndp); 1083 goto out1; 1084 } 1085 if (fvp->v_mount != tdvp->v_mount) { 1086 error = EXDEV; 1087 goto out; 1088 } 1089 if (fvp == tdvp || fvp == tvp) 1090 error = EINVAL; 1091 out: 1092 if (error) { 1093 VOP_ABORTOP(&tond); 1094 VOP_ABORTOP(ndp); 1095 } else { 1096 error = VOP_RENAME(ndp, &tond); 1097 } 1098 out1: 1099 ndrele(&tond); 1100 RETURN (error); 1101 } 1102 1103 /* 1104 * Mkdir system call 1105 */ 1106 mkdir() 1107 { 1108 struct a { 1109 char *name; 1110 int dmode; 1111 } *uap = (struct a *)u.u_ap; 1112 register struct nameidata *ndp = &u.u_nd; 1113 register struct vnode *vp; 1114 struct vattr vattr; 1115 int error; 1116 1117 ndp->ni_nameiop = CREATE | LOCKPARENT; 1118 ndp->ni_segflg = UIO_USERSPACE; 1119 ndp->ni_dirp = uap->name; 1120 if (error = namei(ndp)) 1121 RETURN (error); 1122 vp = ndp->ni_vp; 1123 if (vp != NULL) { 1124 VOP_ABORTOP(ndp); 1125 RETURN (EEXIST); 1126 } 1127 vattr_null(&vattr); 1128 vattr.va_type = VDIR; 1129 vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask; 1130 error = VOP_MKDIR(ndp, &vattr); 1131 if (!error) 1132 vput(ndp->ni_vp); 1133 RETURN (error); 1134 } 1135 1136 /* 1137 * Rmdir system call. 1138 */ 1139 rmdir() 1140 { 1141 struct a { 1142 char *name; 1143 } *uap = (struct a *)u.u_ap; 1144 register struct nameidata *ndp = &u.u_nd; 1145 register struct vnode *vp; 1146 int error; 1147 1148 ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 1149 ndp->ni_segflg = UIO_USERSPACE; 1150 ndp->ni_dirp = uap->name; 1151 if (error = namei(ndp)) 1152 RETURN (error); 1153 vp = ndp->ni_vp; 1154 if (vp->v_type != VDIR) { 1155 error = ENOTDIR; 1156 goto out; 1157 } 1158 /* 1159 * No rmdir "." please. 1160 */ 1161 if (ndp->ni_dvp == vp) { 1162 error = EINVAL; 1163 goto out; 1164 } 1165 /* 1166 * Don't unlink a mounted file. 1167 */ 1168 if (vp->v_flag & VROOT) 1169 error = EBUSY; 1170 out: 1171 if (error) 1172 VOP_ABORTOP(ndp); 1173 else 1174 error = VOP_RMDIR(ndp); 1175 RETURN (error); 1176 } 1177 1178 /* 1179 * Read a block of directory entries in a file system independent format 1180 */ 1181 getdirentries() 1182 { 1183 register struct a { 1184 int fd; 1185 char *buf; 1186 unsigned count; 1187 long *basep; 1188 } *uap = (struct a *)u.u_ap; 1189 struct file *fp; 1190 struct uio auio; 1191 struct iovec aiov; 1192 off_t off; 1193 int error; 1194 1195 if (error = getvnode(uap->fd, &fp)) 1196 RETURN (error); 1197 if ((fp->f_flag & FREAD) == 0) 1198 RETURN (EBADF); 1199 aiov.iov_base = uap->buf; 1200 aiov.iov_len = uap->count; 1201 auio.uio_iov = &aiov; 1202 auio.uio_iovcnt = 1; 1203 auio.uio_rw = UIO_READ; 1204 auio.uio_segflg = UIO_USERSPACE; 1205 auio.uio_resid = uap->count; 1206 off = fp->f_offset; 1207 if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio, 1208 &(fp->f_offset), fp->f_cred)) 1209 RETURN (error); 1210 error = copyout((caddr_t)&off, (caddr_t)uap->basep, 1211 sizeof(long)); 1212 u.u_r.r_val1 = uap->count - auio.uio_resid; 1213 RETURN (error); 1214 } 1215 1216 /* 1217 * mode mask for creation of files 1218 */ 1219 umask() 1220 { 1221 register struct a { 1222 int mask; 1223 } *uap = (struct a *)u.u_ap; 1224 1225 u.u_r.r_val1 = u.u_cmask; 1226 u.u_cmask = uap->mask & 07777; 1227 RETURN (0); 1228 } 1229 1230 getvnode(fdes, fpp) 1231 struct file **fpp; 1232 int fdes; 1233 { 1234 struct file *fp; 1235 1236 if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL) 1237 return (EBADF); 1238 if (fp->f_type != DTYPE_VNODE) 1239 return (EINVAL); 1240 *fpp = fp; 1241 return (0); 1242 } 1243