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