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.13 (Berkeley) 07/03/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 * get statistics on all filesystems 228 */ 229 getfsstat() 230 { 231 struct a { 232 struct statfs *buf; 233 long bufsize; 234 } *uap = (struct a *)u.u_ap; 235 register struct mount *mp; 236 register struct statfs *sfsp; 237 long count, maxcount, error; 238 239 maxcount = uap->bufsize / sizeof(struct statfs); 240 sfsp = uap->buf; 241 mp = rootfs; 242 count = 0; 243 do { 244 count++; 245 if (sfsp && count <= maxcount) { 246 if (error = VFS_STATFS(mp, sfsp)) 247 RETURN (error); 248 sfsp++; 249 } 250 mp = mp->m_prev; 251 } while (mp != rootfs); 252 if (sfsp && count > maxcount) 253 u.u_r.r_val1 = maxcount; 254 else 255 u.u_r.r_val1 = count; 256 RETURN (0); 257 } 258 259 /* 260 * Change current working directory to a given file descriptor. 261 */ 262 fchdir() 263 { 264 struct a { 265 int fd; 266 } *uap = (struct a *)u.u_ap; 267 register struct vnode *vp; 268 struct file *fp; 269 int error; 270 271 if (error = getvnode(uap->fd, &fp)) 272 RETURN (error); 273 vp = (struct vnode *)fp->f_data; 274 VOP_LOCK(vp); 275 if (vp->v_type != VDIR) 276 error = ENOTDIR; 277 else 278 error = VOP_ACCESS(vp, VEXEC, u.u_cred); 279 VOP_UNLOCK(vp); 280 vrele(u.u_cdir); 281 u.u_cdir = vp; 282 RETURN (error); 283 } 284 285 /* 286 * Change current working directory (``.''). 287 */ 288 chdir() 289 { 290 struct a { 291 char *fname; 292 } *uap = (struct a *)u.u_ap; 293 register struct nameidata *ndp = &u.u_nd; 294 int error; 295 296 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 297 ndp->ni_segflg = UIO_USERSPACE; 298 ndp->ni_dirp = uap->fname; 299 if (error = chdirec(ndp)) 300 RETURN (error); 301 vrele(u.u_cdir); 302 u.u_cdir = ndp->ni_vp; 303 RETURN (0); 304 } 305 306 /* 307 * Change notion of root (``/'') directory. 308 */ 309 chroot() 310 { 311 struct a { 312 char *fname; 313 } *uap = (struct a *)u.u_ap; 314 register struct nameidata *ndp = &u.u_nd; 315 int error; 316 317 if (error = suser(u.u_cred, &u.u_acflag)) 318 RETURN (error); 319 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 320 ndp->ni_segflg = UIO_USERSPACE; 321 ndp->ni_dirp = uap->fname; 322 if (error = chdirec(ndp)) 323 RETURN (error); 324 vrele(u.u_rdir); 325 u.u_rdir = ndp->ni_vp; 326 RETURN (0); 327 } 328 329 /* 330 * Common routine for chroot and chdir. 331 */ 332 chdirec(ndp) 333 register struct nameidata *ndp; 334 { 335 struct vnode *vp; 336 int error; 337 338 if (error = namei(ndp)) 339 return (error); 340 vp = ndp->ni_vp; 341 if (vp->v_type != VDIR) 342 error = ENOTDIR; 343 else 344 error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); 345 VOP_UNLOCK(vp); 346 if (error) 347 vrele(vp); 348 return (error); 349 } 350 351 /* 352 * Open system call. 353 */ 354 open() 355 { 356 struct a { 357 char *fname; 358 int mode; 359 int crtmode; 360 } *uap = (struct a *) u.u_ap; 361 struct nameidata *ndp = &u.u_nd; 362 363 ndp->ni_segflg = UIO_USERSPACE; 364 ndp->ni_dirp = uap->fname; 365 RETURN (copen(uap->mode-FOPEN, uap->crtmode &~ u.u_cmask, ndp, 366 &u.u_r.r_val1)); 367 } 368 369 /* 370 * Creat system call. 371 */ 372 creat() 373 { 374 struct a { 375 char *fname; 376 int fmode; 377 } *uap = (struct a *)u.u_ap; 378 struct nameidata *ndp = &u.u_nd; 379 380 ndp->ni_segflg = UIO_USERSPACE; 381 ndp->ni_dirp = uap->fname; 382 RETURN (copen(FWRITE|FCREAT|FTRUNC, uap->fmode &~ u.u_cmask, ndp, 383 &u.u_r.r_val1)); 384 } 385 386 /* 387 * Common code for open and creat. 388 * Check permissions, allocate an open file structure, 389 * and call the device open routine if any. 390 */ 391 copen(fmode, cmode, ndp, resultfd) 392 int fmode, cmode; 393 struct nameidata *ndp; 394 int *resultfd; 395 { 396 register struct file *fp; 397 struct file *nfp; 398 int indx, error; 399 extern struct fileops vnops; 400 401 if (error = falloc(&nfp, &indx)) 402 return (error); 403 fp = nfp; 404 u.u_r.r_val1 = indx; /* XXX for fdopen() */ 405 if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) { 406 u.u_ofile[indx] = NULL; 407 crfree(fp->f_cred); 408 fp->f_count--; 409 return (error); 410 } 411 fp->f_flag = fmode & FMASK; 412 fp->f_type = DTYPE_VNODE; 413 fp->f_ops = &vnops; 414 fp->f_data = (caddr_t)ndp->ni_vp; 415 if (resultfd) 416 *resultfd = indx; 417 return (0); 418 } 419 420 /* 421 * Mknod system call 422 */ 423 mknod() 424 { 425 register struct a { 426 char *fname; 427 int fmode; 428 int dev; 429 } *uap = (struct a *)u.u_ap; 430 register struct nameidata *ndp = &u.u_nd; 431 register struct vnode *vp; 432 struct vattr vattr; 433 int error; 434 435 if (error = suser(u.u_cred, &u.u_acflag)) 436 RETURN (error); 437 ndp->ni_nameiop = CREATE | LOCKPARENT; 438 ndp->ni_segflg = UIO_USERSPACE; 439 ndp->ni_dirp = uap->fname; 440 if (error = namei(ndp)) 441 RETURN (error); 442 vp = ndp->ni_vp; 443 if (vp != NULL) { 444 error = EEXIST; 445 goto out; 446 } 447 vattr_null(&vattr); 448 switch (uap->fmode & IFMT) { 449 450 case IFMT: /* used by badsect to flag bad sectors */ 451 vattr.va_type = VBAD; 452 break; 453 case IFCHR: 454 vattr.va_type = VCHR; 455 break; 456 case IFBLK: 457 vattr.va_type = VBLK; 458 break; 459 default: 460 error = EINVAL; 461 goto out; 462 } 463 vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask; 464 vattr.va_rdev = uap->dev; 465 out: 466 if (error) 467 VOP_ABORTOP(ndp); 468 else 469 error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); 470 RETURN (error); 471 } 472 473 /* 474 * link system call 475 */ 476 link() 477 { 478 register struct a { 479 char *target; 480 char *linkname; 481 } *uap = (struct a *)u.u_ap; 482 register struct nameidata *ndp = &u.u_nd; 483 register struct vnode *vp, *xp; 484 int error; 485 486 ndp->ni_nameiop = LOOKUP | FOLLOW; 487 ndp->ni_segflg = UIO_USERSPACE; 488 ndp->ni_dirp = uap->target; 489 if (error = namei(ndp)) 490 RETURN (error); 491 vp = ndp->ni_vp; 492 if (vp->v_type == VDIR && 493 (error = suser(u.u_cred, &u.u_acflag))) 494 goto out1; 495 ndp->ni_nameiop = CREATE | LOCKPARENT; 496 ndp->ni_dirp = (caddr_t)uap->linkname; 497 if (error = namei(ndp)) 498 goto out1; 499 xp = ndp->ni_vp; 500 if (xp != NULL) { 501 error = EEXIST; 502 goto out; 503 } 504 xp = ndp->ni_dvp; 505 if (vp->v_mount != xp->v_mount) 506 error = EXDEV; 507 out: 508 if (error) 509 VOP_ABORTOP(ndp); 510 else 511 error = VOP_LINK(vp, ndp); 512 out1: 513 vrele(vp); 514 RETURN (error); 515 } 516 517 /* 518 * symlink -- make a symbolic link 519 */ 520 symlink() 521 { 522 struct a { 523 char *target; 524 char *linkname; 525 } *uap = (struct a *)u.u_ap; 526 register struct nameidata *ndp = &u.u_nd; 527 register struct vnode *vp; 528 struct vattr vattr; 529 char *target; 530 int error; 531 532 ndp->ni_segflg = UIO_USERSPACE; 533 ndp->ni_dirp = uap->linkname; 534 MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 535 if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) 536 goto out1; 537 ndp->ni_nameiop = CREATE | LOCKPARENT; 538 if (error = namei(ndp)) 539 goto out1; 540 vp = ndp->ni_vp; 541 if (vp) { 542 error = EEXIST; 543 goto out; 544 } 545 vp = ndp->ni_dvp; 546 vattr_null(&vattr); 547 vattr.va_mode = 0777 &~ u.u_cmask; 548 out: 549 if (error) 550 VOP_ABORTOP(ndp); 551 else 552 error = VOP_SYMLINK(ndp, &vattr, target); 553 out1: 554 FREE(target, M_NAMEI); 555 RETURN (error); 556 } 557 558 /* 559 * Unlink system call. 560 * Hard to avoid races here, especially 561 * in unlinking directories. 562 */ 563 unlink() 564 { 565 struct a { 566 char *fname; 567 } *uap = (struct a *)u.u_ap; 568 register struct nameidata *ndp = &u.u_nd; 569 register struct vnode *vp; 570 int error; 571 572 ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 573 ndp->ni_segflg = UIO_USERSPACE; 574 ndp->ni_dirp = uap->fname; 575 if (error = namei(ndp)) 576 RETURN (error); 577 vp = ndp->ni_vp; 578 if (vp->v_type == VDIR && 579 (error = suser(u.u_cred, &u.u_acflag))) 580 goto out; 581 /* 582 * Don't unlink a mounted file. 583 */ 584 if (vp->v_flag & VROOT) { 585 error = EBUSY; 586 goto out; 587 } 588 if (vp->v_flag & VTEXT) 589 xrele(vp); /* try once to free text */ 590 out: 591 if (error) 592 VOP_ABORTOP(ndp); 593 else 594 error = VOP_REMOVE(ndp); 595 RETURN (error); 596 } 597 598 /* 599 * Seek system call 600 */ 601 lseek() 602 { 603 register struct file *fp; 604 register struct a { 605 int fdes; 606 off_t off; 607 int sbase; 608 } *uap = (struct a *)u.u_ap; 609 struct vattr vattr; 610 int error; 611 612 if ((unsigned)uap->fdes >= NOFILE || 613 (fp = u.u_ofile[uap->fdes]) == NULL) 614 RETURN (EBADF); 615 if (fp->f_type != DTYPE_VNODE) 616 RETURN (ESPIPE); 617 switch (uap->sbase) { 618 619 case L_INCR: 620 fp->f_offset += uap->off; 621 break; 622 623 case L_XTND: 624 if (error = VOP_GETATTR((struct vnode *)fp->f_data, 625 &vattr, u.u_cred)) 626 RETURN (error); 627 fp->f_offset = uap->off + vattr.va_size; 628 break; 629 630 case L_SET: 631 fp->f_offset = uap->off; 632 break; 633 634 default: 635 RETURN (EINVAL); 636 } 637 u.u_r.r_off = fp->f_offset; 638 RETURN (0); 639 } 640 641 /* 642 * Access system call 643 */ 644 saccess() 645 { 646 register struct a { 647 char *fname; 648 int fmode; 649 } *uap = (struct a *)u.u_ap; 650 register struct nameidata *ndp = &u.u_nd; 651 register struct vnode *vp; 652 int error, mode, svuid, svgid; 653 654 svuid = u.u_uid; 655 svgid = u.u_gid; 656 u.u_uid = u.u_ruid; 657 u.u_gid = u.u_rgid; 658 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 659 ndp->ni_segflg = UIO_USERSPACE; 660 ndp->ni_dirp = uap->fname; 661 if (error = namei(ndp)) 662 goto out1; 663 vp = ndp->ni_vp; 664 /* 665 * fmode == 0 means only check for exist 666 */ 667 if (uap->fmode) { 668 mode = 0; 669 if (uap->fmode & R_OK) 670 mode |= VREAD; 671 if (uap->fmode & W_OK) 672 mode |= VWRITE; 673 if (uap->fmode & X_OK) 674 mode |= VEXEC; 675 if ((error = vn_writechk(vp)) == 0) 676 error = VOP_ACCESS(vp, mode, ndp->ni_cred); 677 } 678 vput(vp); 679 out1: 680 u.u_uid = svuid; 681 u.u_gid = svgid; 682 RETURN (error); 683 } 684 685 /* 686 * Stat system call. This version follows links. 687 */ 688 stat() 689 { 690 691 stat1(FOLLOW); 692 } 693 694 /* 695 * Lstat system call. This version does not follow links. 696 */ 697 lstat() 698 { 699 700 stat1(NOFOLLOW); 701 } 702 703 stat1(follow) 704 int follow; 705 { 706 register struct a { 707 char *fname; 708 struct stat *ub; 709 } *uap = (struct a *)u.u_ap; 710 register struct nameidata *ndp = &u.u_nd; 711 struct stat sb; 712 int error; 713 714 ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow; 715 ndp->ni_segflg = UIO_USERSPACE; 716 ndp->ni_dirp = uap->fname; 717 if (error = namei(ndp)) 718 RETURN (error); 719 error = vn_stat(ndp->ni_vp, &sb); 720 vput(ndp->ni_vp); 721 if (error) 722 RETURN (error); 723 error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); 724 RETURN (error); 725 } 726 727 /* 728 * Return target name of a symbolic link 729 */ 730 readlink() 731 { 732 register struct a { 733 char *name; 734 char *buf; 735 int count; 736 } *uap = (struct a *)u.u_ap; 737 register struct nameidata *ndp = &u.u_nd; 738 register struct vnode *vp; 739 struct iovec aiov; 740 struct uio auio; 741 int error; 742 743 ndp->ni_nameiop = LOOKUP | LOCKLEAF; 744 ndp->ni_segflg = UIO_USERSPACE; 745 ndp->ni_dirp = uap->name; 746 if (error = namei(ndp)) 747 RETURN (error); 748 vp = ndp->ni_vp; 749 if (vp->v_type != VLNK) { 750 error = EINVAL; 751 goto out; 752 } 753 aiov.iov_base = uap->buf; 754 aiov.iov_len = uap->count; 755 auio.uio_iov = &aiov; 756 auio.uio_iovcnt = 1; 757 auio.uio_offset = 0; 758 auio.uio_rw = UIO_READ; 759 auio.uio_segflg = UIO_USERSPACE; 760 auio.uio_resid = uap->count; 761 error = VOP_READLINK(vp, &auio, ndp->ni_cred); 762 out: 763 vput(vp); 764 u.u_r.r_val1 = uap->count - auio.uio_resid; 765 RETURN (error); 766 } 767 768 /* 769 * Change flags of a file given path name. 770 */ 771 chflags() 772 { 773 struct a { 774 char *fname; 775 int flags; 776 } *uap = (struct a *)u.u_ap; 777 register struct nameidata *ndp = &u.u_nd; 778 register struct vnode *vp; 779 struct vattr vattr; 780 int error; 781 782 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 783 ndp->ni_segflg = UIO_USERSPACE; 784 ndp->ni_dirp = uap->fname; 785 vattr_null(&vattr); 786 vattr.va_flags = uap->flags; 787 if (error = namei(ndp)) 788 RETURN (error); 789 vp = ndp->ni_vp; 790 if (vp->v_mount->m_flag & M_RDONLY) { 791 error = EROFS; 792 goto out; 793 } 794 error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 795 out: 796 vput(vp); 797 RETURN (error); 798 } 799 800 /* 801 * Change flags of a file given a file descriptor. 802 */ 803 fchflags() 804 { 805 struct a { 806 int fd; 807 int flags; 808 } *uap = (struct a *)u.u_ap; 809 struct vattr vattr; 810 struct vnode *vp; 811 struct file *fp; 812 int error; 813 814 if (error = getvnode(uap->fd, &fp)) 815 RETURN (error); 816 vattr_null(&vattr); 817 vattr.va_flags = uap->flags; 818 vp = (struct vnode *)fp->f_data; 819 VOP_LOCK(vp); 820 if (vp->v_mount->m_flag & M_RDONLY) { 821 error = EROFS; 822 goto out; 823 } 824 error = VOP_SETATTR(vp, &vattr, fp->f_cred); 825 out: 826 VOP_UNLOCK(vp); 827 RETURN (error); 828 } 829 830 /* 831 * Change mode of a file given path name. 832 */ 833 chmod() 834 { 835 struct a { 836 char *fname; 837 int fmode; 838 } *uap = (struct a *)u.u_ap; 839 register struct nameidata *ndp = &u.u_nd; 840 register struct vnode *vp; 841 struct vattr vattr; 842 int error; 843 844 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 845 ndp->ni_segflg = UIO_USERSPACE; 846 ndp->ni_dirp = uap->fname; 847 vattr_null(&vattr); 848 vattr.va_mode = uap->fmode & 07777; 849 if (error = namei(ndp)) 850 RETURN (error); 851 vp = ndp->ni_vp; 852 if (vp->v_mount->m_flag & M_RDONLY) { 853 error = EROFS; 854 goto out; 855 } 856 error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 857 out: 858 vput(vp); 859 RETURN (error); 860 } 861 862 /* 863 * Change mode of a file given a file descriptor. 864 */ 865 fchmod() 866 { 867 struct a { 868 int fd; 869 int fmode; 870 } *uap = (struct a *)u.u_ap; 871 struct vattr vattr; 872 struct vnode *vp; 873 struct file *fp; 874 int error; 875 876 if (error = getvnode(uap->fd, &fp)) 877 RETURN (error); 878 vattr_null(&vattr); 879 vattr.va_mode = uap->fmode & 07777; 880 vp = (struct vnode *)fp->f_data; 881 VOP_LOCK(vp); 882 if (vp->v_mount->m_flag & M_RDONLY) { 883 error = EROFS; 884 goto out; 885 } 886 error = VOP_SETATTR(vp, &vattr, fp->f_cred); 887 out: 888 VOP_UNLOCK(vp); 889 RETURN (error); 890 } 891 892 /* 893 * Set ownership given a path name. 894 */ 895 chown() 896 { 897 struct a { 898 char *fname; 899 int uid; 900 int gid; 901 } *uap = (struct a *)u.u_ap; 902 register struct nameidata *ndp = &u.u_nd; 903 register struct vnode *vp; 904 struct vattr vattr; 905 int error; 906 907 ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; 908 ndp->ni_segflg = UIO_USERSPACE; 909 ndp->ni_dirp = uap->fname; 910 vattr_null(&vattr); 911 vattr.va_uid = uap->uid; 912 vattr.va_gid = uap->gid; 913 if (error = namei(ndp)) 914 RETURN (error); 915 vp = ndp->ni_vp; 916 if (vp->v_mount->m_flag & M_RDONLY) { 917 error = EROFS; 918 goto out; 919 } 920 error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 921 out: 922 vput(vp); 923 RETURN (error); 924 } 925 926 /* 927 * Set ownership given a file descriptor. 928 */ 929 fchown() 930 { 931 struct a { 932 int fd; 933 int uid; 934 int gid; 935 } *uap = (struct a *)u.u_ap; 936 struct vattr vattr; 937 struct vnode *vp; 938 struct file *fp; 939 int error; 940 941 if (error = getvnode(uap->fd, &fp)) 942 RETURN (error); 943 vattr_null(&vattr); 944 vattr.va_uid = uap->uid; 945 vattr.va_gid = uap->gid; 946 vp = (struct vnode *)fp->f_data; 947 VOP_LOCK(vp); 948 if (vp->v_mount->m_flag & M_RDONLY) { 949 error = EROFS; 950 goto out; 951 } 952 error = VOP_SETATTR(vp, &vattr, fp->f_cred); 953 out: 954 VOP_UNLOCK(vp); 955 RETURN (error); 956 } 957 958 utimes() 959 { 960 register struct a { 961 char *fname; 962 struct timeval *tptr; 963 } *uap = (struct a *)u.u_ap; 964 register struct nameidata *ndp = &u.u_nd; 965 register struct vnode *vp; 966 struct timeval tv[2]; 967 struct vattr vattr; 968 int error; 969 970 if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) 971 RETURN (error); 972 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 973 ndp->ni_segflg = UIO_USERSPACE; 974 ndp->ni_dirp = uap->fname; 975 vattr_null(&vattr); 976 vattr.va_atime = tv[0]; 977 vattr.va_mtime = tv[1]; 978 if (error = namei(ndp)) 979 RETURN (error); 980 vp = ndp->ni_vp; 981 if (vp->v_mount->m_flag & M_RDONLY) { 982 error = EROFS; 983 goto out; 984 } 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 its path name. 993 */ 994 truncate() 995 { 996 struct a { 997 char *fname; 998 off_t length; 999 } *uap = (struct a *)u.u_ap; 1000 register struct nameidata *ndp = &u.u_nd; 1001 register struct vnode *vp; 1002 struct vattr vattr; 1003 int error; 1004 1005 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 1006 ndp->ni_segflg = UIO_USERSPACE; 1007 ndp->ni_dirp = uap->fname; 1008 vattr_null(&vattr); 1009 vattr.va_size = uap->length; 1010 if (error = namei(ndp)) 1011 RETURN (error); 1012 vp = ndp->ni_vp; 1013 if (vp->v_type == VDIR) { 1014 error = EISDIR; 1015 goto out; 1016 } 1017 if ((error = vn_writechk(vp)) || 1018 (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) 1019 goto out; 1020 error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); 1021 out: 1022 vput(vp); 1023 RETURN (error); 1024 } 1025 1026 /* 1027 * Truncate a file given a file descriptor. 1028 */ 1029 ftruncate() 1030 { 1031 struct a { 1032 int fd; 1033 off_t length; 1034 } *uap = (struct a *)u.u_ap; 1035 struct vattr vattr; 1036 struct vnode *vp; 1037 struct file *fp; 1038 int error; 1039 1040 if (error = getvnode(uap->fd, &fp)) 1041 RETURN (error); 1042 if ((fp->f_flag & FWRITE) == 0) 1043 RETURN (EINVAL); 1044 vattr_null(&vattr); 1045 vattr.va_size = uap->length; 1046 vp = (struct vnode *)fp->f_data; 1047 VOP_LOCK(vp); 1048 if (vp->v_type == VDIR) { 1049 error = EISDIR; 1050 goto out; 1051 } 1052 if (error = vn_writechk(vp)) 1053 goto out; 1054 error = VOP_SETATTR(vp, &vattr, fp->f_cred); 1055 out: 1056 VOP_UNLOCK(vp); 1057 RETURN (error); 1058 } 1059 1060 /* 1061 * Synch an open file. 1062 */ 1063 fsync() 1064 { 1065 struct a { 1066 int fd; 1067 } *uap = (struct a *)u.u_ap; 1068 struct file *fp; 1069 int error; 1070 1071 if (error = getvnode(uap->fd, &fp)) 1072 RETURN (error); 1073 error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred); 1074 RETURN (error); 1075 } 1076 1077 /* 1078 * Rename system call. 1079 * 1080 * Source and destination must either both be directories, or both 1081 * not be directories. If target is a directory, it must be empty. 1082 */ 1083 rename() 1084 { 1085 struct a { 1086 char *from; 1087 char *to; 1088 } *uap = (struct a *)u.u_ap; 1089 register struct vnode *tvp, *fvp, *tdvp; 1090 register struct nameidata *ndp = &u.u_nd; 1091 struct nameidata tond; 1092 int error; 1093 1094 ndp->ni_nameiop = DELETE | WANTPARENT; 1095 ndp->ni_segflg = UIO_USERSPACE; 1096 ndp->ni_dirp = uap->from; 1097 if (error = namei(ndp)) 1098 RETURN (error); 1099 fvp = ndp->ni_vp; 1100 nddup(ndp, &tond); 1101 tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; 1102 tond.ni_segflg = UIO_USERSPACE; 1103 tond.ni_dirp = uap->to; 1104 error = namei(&tond); 1105 tdvp = tond.ni_dvp; 1106 tvp = tond.ni_vp; 1107 if (tvp != NULL) { 1108 if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 1109 error = EISDIR; 1110 goto out; 1111 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 1112 error = ENOTDIR; 1113 goto out; 1114 } 1115 } 1116 if (error) { 1117 VOP_ABORTOP(ndp); 1118 goto out1; 1119 } 1120 if (fvp->v_mount != tdvp->v_mount) { 1121 error = EXDEV; 1122 goto out; 1123 } 1124 if (fvp == tdvp || fvp == tvp) 1125 error = EINVAL; 1126 out: 1127 if (error) { 1128 VOP_ABORTOP(&tond); 1129 VOP_ABORTOP(ndp); 1130 } else { 1131 error = VOP_RENAME(ndp, &tond); 1132 } 1133 out1: 1134 ndrele(&tond); 1135 RETURN (error); 1136 } 1137 1138 /* 1139 * Mkdir system call 1140 */ 1141 mkdir() 1142 { 1143 struct a { 1144 char *name; 1145 int dmode; 1146 } *uap = (struct a *)u.u_ap; 1147 register struct nameidata *ndp = &u.u_nd; 1148 register struct vnode *vp; 1149 struct vattr vattr; 1150 int error; 1151 1152 ndp->ni_nameiop = CREATE | LOCKPARENT; 1153 ndp->ni_segflg = UIO_USERSPACE; 1154 ndp->ni_dirp = uap->name; 1155 if (error = namei(ndp)) 1156 RETURN (error); 1157 vp = ndp->ni_vp; 1158 if (vp != NULL) { 1159 VOP_ABORTOP(ndp); 1160 RETURN (EEXIST); 1161 } 1162 vattr_null(&vattr); 1163 vattr.va_type = VDIR; 1164 vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask; 1165 error = VOP_MKDIR(ndp, &vattr); 1166 if (!error) 1167 vput(ndp->ni_vp); 1168 RETURN (error); 1169 } 1170 1171 /* 1172 * Rmdir system call. 1173 */ 1174 rmdir() 1175 { 1176 struct a { 1177 char *name; 1178 } *uap = (struct a *)u.u_ap; 1179 register struct nameidata *ndp = &u.u_nd; 1180 register struct vnode *vp; 1181 int error; 1182 1183 ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; 1184 ndp->ni_segflg = UIO_USERSPACE; 1185 ndp->ni_dirp = uap->name; 1186 if (error = namei(ndp)) 1187 RETURN (error); 1188 vp = ndp->ni_vp; 1189 if (vp->v_type != VDIR) { 1190 error = ENOTDIR; 1191 goto out; 1192 } 1193 /* 1194 * No rmdir "." please. 1195 */ 1196 if (ndp->ni_dvp == vp) { 1197 error = EINVAL; 1198 goto out; 1199 } 1200 /* 1201 * Don't unlink a mounted file. 1202 */ 1203 if (vp->v_flag & VROOT) 1204 error = EBUSY; 1205 out: 1206 if (error) 1207 VOP_ABORTOP(ndp); 1208 else 1209 error = VOP_RMDIR(ndp); 1210 RETURN (error); 1211 } 1212 1213 /* 1214 * Read a block of directory entries in a file system independent format 1215 */ 1216 getdirentries() 1217 { 1218 register struct a { 1219 int fd; 1220 char *buf; 1221 unsigned count; 1222 long *basep; 1223 } *uap = (struct a *)u.u_ap; 1224 struct file *fp; 1225 struct uio auio; 1226 struct iovec aiov; 1227 off_t off; 1228 int error; 1229 1230 if (error = getvnode(uap->fd, &fp)) 1231 RETURN (error); 1232 if ((fp->f_flag & FREAD) == 0) 1233 RETURN (EBADF); 1234 aiov.iov_base = uap->buf; 1235 aiov.iov_len = uap->count; 1236 auio.uio_iov = &aiov; 1237 auio.uio_iovcnt = 1; 1238 auio.uio_rw = UIO_READ; 1239 auio.uio_segflg = UIO_USERSPACE; 1240 auio.uio_resid = uap->count; 1241 off = fp->f_offset; 1242 if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio, 1243 &(fp->f_offset), fp->f_cred)) 1244 RETURN (error); 1245 error = copyout((caddr_t)&off, (caddr_t)uap->basep, 1246 sizeof(long)); 1247 u.u_r.r_val1 = uap->count - auio.uio_resid; 1248 RETURN (error); 1249 } 1250 1251 /* 1252 * mode mask for creation of files 1253 */ 1254 umask() 1255 { 1256 register struct a { 1257 int mask; 1258 } *uap = (struct a *)u.u_ap; 1259 1260 u.u_r.r_val1 = u.u_cmask; 1261 u.u_cmask = uap->mask & 07777; 1262 RETURN (0); 1263 } 1264 1265 getvnode(fdes, fpp) 1266 struct file **fpp; 1267 int fdes; 1268 { 1269 struct file *fp; 1270 1271 if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL) 1272 return (EBADF); 1273 if (fp->f_type != DTYPE_VNODE) 1274 return (EINVAL); 1275 *fpp = fp; 1276 return (0); 1277 } 1278