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