|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1989 The Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution is only permitted until one year after the first shipment ! 6: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and ! 7: * binary forms are permitted provided that: (1) source distributions retain ! 8: * this entire copyright notice and comment, and (2) distributions including ! 9: * binaries display the following acknowledgement: This product includes ! 10: * software developed by the University of California, Berkeley and its ! 11: * contributors'' in the documentation or other materials provided with the ! 12: * distribution and in all advertising materials mentioning features or use ! 13: * of this software. Neither the name of the University nor the names of ! 14: * its contributors may be used to endorse or promote products derived from ! 15: * this software without specific prior written permission. ! 16: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 19: * ! 20: * @(#)vfs_syscalls.c 7.57 (Berkeley) 7/28/90 ! 21: */ ! 22: ! 23: #include "param.h" ! 24: #include "systm.h" ! 25: #include "user.h" ! 26: #include "kernel.h" ! 27: #include "file.h" ! 28: #include "stat.h" ! 29: #include "vnode.h" ! 30: #include "mount.h" ! 31: #include "proc.h" ! 32: #include "uio.h" ! 33: #include "malloc.h" ! 34: ! 35: #define RETURN(val) {if (u.u_spare[0] != 0) panic("lock count"); return (val);} ! 36: ! 37: /* ! 38: * Virtual File System System Calls ! 39: */ ! 40: ! 41: /* ! 42: * mount system call ! 43: */ ! 44: /* ARGSUSED */ ! 45: mount(p, uap, retval) ! 46: register struct proc *p; ! 47: register struct args { ! 48: int type; ! 49: char *dir; ! 50: int flags; ! 51: caddr_t data; ! 52: } *uap; ! 53: int *retval; ! 54: { ! 55: register struct nameidata *ndp = &u.u_nd; ! 56: register struct vnode *vp; ! 57: register struct mount *mp; ! 58: int error, flag; ! 59: ! 60: /* ! 61: * Must be super user ! 62: */ ! 63: if (error = suser(ndp->ni_cred, &u.u_acflag)) ! 64: RETURN (error); ! 65: /* ! 66: * Get vnode to be covered ! 67: */ ! 68: ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; ! 69: ndp->ni_segflg = UIO_USERSPACE; ! 70: ndp->ni_dirp = uap->dir; ! 71: if (error = namei(ndp)) ! 72: RETURN (error); ! 73: vp = ndp->ni_vp; ! 74: if (uap->flags & MNT_UPDATE) { ! 75: if ((vp->v_flag & VROOT) == 0) { ! 76: vput(vp); ! 77: RETURN (EINVAL); ! 78: } ! 79: mp = vp->v_mount; ! 80: /* ! 81: * We allow going from read-only to read-write, ! 82: * but not from read-write to read-only. ! 83: */ ! 84: if ((mp->mnt_flag & MNT_RDONLY) == 0 && ! 85: (uap->flags & MNT_RDONLY) != 0) { ! 86: vput(vp); ! 87: RETURN (EOPNOTSUPP); /* Needs translation */ ! 88: } ! 89: flag = mp->mnt_flag; ! 90: mp->mnt_flag |= MNT_UPDATE; ! 91: VOP_UNLOCK(vp); ! 92: goto update; ! 93: } ! 94: vinvalbuf(vp, 1); ! 95: if (vp->v_usecount != 1) { ! 96: vput(vp); ! 97: RETURN (EBUSY); ! 98: } ! 99: if (vp->v_type != VDIR) { ! 100: vput(vp); ! 101: RETURN (ENOTDIR); ! 102: } ! 103: if ((unsigned long)uap->type > MOUNT_MAXTYPE || ! 104: vfssw[uap->type] == (struct vfsops *)0) { ! 105: vput(vp); ! 106: RETURN (ENODEV); ! 107: } ! 108: ! 109: /* ! 110: * Allocate and initialize the file system. ! 111: */ ! 112: mp = (struct mount *)malloc((u_long)sizeof(struct mount), ! 113: M_MOUNT, M_WAITOK); ! 114: mp->mnt_op = vfssw[uap->type]; ! 115: mp->mnt_flag = 0; ! 116: mp->mnt_exroot = 0; ! 117: mp->mnt_mounth = NULLVP; ! 118: if (error = vfs_lock(mp)) { ! 119: free((caddr_t)mp, M_MOUNT); ! 120: vput(vp); ! 121: RETURN (error); ! 122: } ! 123: if (vp->v_mountedhere != (struct mount *)0) { ! 124: vfs_unlock(mp); ! 125: free((caddr_t)mp, M_MOUNT); ! 126: vput(vp); ! 127: RETURN (EBUSY); ! 128: } ! 129: vp->v_mountedhere = mp; ! 130: mp->mnt_vnodecovered = vp; ! 131: update: ! 132: /* ! 133: * Set the mount level flags. ! 134: */ ! 135: if (uap->flags & MNT_RDONLY) ! 136: mp->mnt_flag |= MNT_RDONLY; ! 137: else ! 138: mp->mnt_flag &= ~MNT_RDONLY; ! 139: if (uap->flags & MNT_NOSUID) ! 140: mp->mnt_flag |= MNT_NOSUID; ! 141: else ! 142: mp->mnt_flag &= ~MNT_NOSUID; ! 143: if (uap->flags & MNT_NOEXEC) ! 144: mp->mnt_flag |= MNT_NOEXEC; ! 145: else ! 146: mp->mnt_flag &= ~MNT_NOEXEC; ! 147: if (uap->flags & MNT_NODEV) ! 148: mp->mnt_flag |= MNT_NODEV; ! 149: else ! 150: mp->mnt_flag &= ~MNT_NODEV; ! 151: if (uap->flags & MNT_SYNCHRONOUS) ! 152: mp->mnt_flag |= MNT_SYNCHRONOUS; ! 153: else ! 154: mp->mnt_flag &= ~MNT_SYNCHRONOUS; ! 155: /* ! 156: * Mount the filesystem. ! 157: */ ! 158: error = VFS_MOUNT(mp, uap->dir, uap->data, ndp); ! 159: if (mp->mnt_flag & MNT_UPDATE) { ! 160: mp->mnt_flag &= ~MNT_UPDATE; ! 161: vrele(vp); ! 162: if (error) ! 163: mp->mnt_flag = flag; ! 164: RETURN (error); ! 165: } ! 166: /* ! 167: * Put the new filesystem on the mount list after root. ! 168: */ ! 169: mp->mnt_next = rootfs->mnt_next; ! 170: mp->mnt_prev = rootfs; ! 171: rootfs->mnt_next = mp; ! 172: mp->mnt_next->mnt_prev = mp; ! 173: cache_purge(vp); ! 174: if (!error) { ! 175: VOP_UNLOCK(vp); ! 176: vfs_unlock(mp); ! 177: error = VFS_START(mp, 0); ! 178: } else { ! 179: vfs_remove(mp); ! 180: free((caddr_t)mp, M_MOUNT); ! 181: vput(vp); ! 182: } ! 183: RETURN (error); ! 184: } ! 185: ! 186: /* ! 187: * Unmount system call. ! 188: * ! 189: * Note: unmount takes a path to the vnode mounted on as argument, ! 190: * not special file (as before). ! 191: */ ! 192: /* ARGSUSED */ ! 193: unmount(p, uap, retval) ! 194: register struct proc *p; ! 195: register struct args { ! 196: char *pathp; ! 197: int flags; ! 198: } *uap; ! 199: int *retval; ! 200: { ! 201: register struct vnode *vp; ! 202: register struct nameidata *ndp = &u.u_nd; ! 203: struct mount *mp; ! 204: int error; ! 205: ! 206: /* ! 207: * Must be super user ! 208: */ ! 209: if (error = suser(ndp->ni_cred, &u.u_acflag)) ! 210: RETURN (error); ! 211: ! 212: ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; ! 213: ndp->ni_segflg = UIO_USERSPACE; ! 214: ndp->ni_dirp = uap->pathp; ! 215: if (error = namei(ndp)) ! 216: RETURN (error); ! 217: vp = ndp->ni_vp; ! 218: /* ! 219: * Must be the root of the filesystem ! 220: */ ! 221: if ((vp->v_flag & VROOT) == 0) { ! 222: vput(vp); ! 223: RETURN (EINVAL); ! 224: } ! 225: mp = vp->v_mount; ! 226: vput(vp); ! 227: RETURN (dounmount(mp, uap->flags)); ! 228: } ! 229: ! 230: /* ! 231: * Do an unmount. ! 232: */ ! 233: dounmount(mp, flags) ! 234: register struct mount *mp; ! 235: int flags; ! 236: { ! 237: struct vnode *coveredvp; ! 238: int error; ! 239: ! 240: coveredvp = mp->mnt_vnodecovered; ! 241: if (vfs_busy(mp)) ! 242: return (EBUSY); ! 243: mp->mnt_flag |= MNT_UNMOUNT; ! 244: if (error = vfs_lock(mp)) ! 245: return (error); ! 246: ! 247: xumount(mp); /* remove unused sticky files from text table */ ! 248: cache_purgevfs(mp); /* remove cache entries for this file sys */ ! 249: if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE)) ! 250: error = VFS_UNMOUNT(mp, flags); ! 251: mp->mnt_flag &= ~MNT_UNMOUNT; ! 252: vfs_unbusy(mp); ! 253: if (error) { ! 254: vfs_unlock(mp); ! 255: } else { ! 256: vrele(coveredvp); ! 257: vfs_remove(mp); ! 258: free((caddr_t)mp, M_MOUNT); ! 259: } ! 260: return (error); ! 261: } ! 262: ! 263: /* ! 264: * Sync system call. ! 265: * Sync each mounted filesystem. ! 266: */ ! 267: /* ARGSUSED */ ! 268: sync(p, uap, retval) ! 269: register struct proc *p; ! 270: struct args *uap; ! 271: int *retval; ! 272: { ! 273: register struct mount *mp; ! 274: struct mount *omp; ! 275: ! 276: mp = rootfs; ! 277: do { ! 278: /* ! 279: * The lock check below is to avoid races with mount ! 280: * and unmount. ! 281: */ ! 282: if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 && ! 283: !vfs_busy(mp)) { ! 284: VFS_SYNC(mp, MNT_NOWAIT); ! 285: omp = mp; ! 286: mp = mp->mnt_next; ! 287: vfs_unbusy(omp); ! 288: } else ! 289: mp = mp->mnt_next; ! 290: } while (mp != rootfs); ! 291: } ! 292: ! 293: /* ! 294: * operate on filesystem quotas ! 295: */ ! 296: /* ARGSUSED */ ! 297: quotactl(p, uap, retval) ! 298: register struct proc *p; ! 299: register struct args { ! 300: char *path; ! 301: int cmd; ! 302: int uid; ! 303: caddr_t arg; ! 304: } *uap; ! 305: int *retval; ! 306: { ! 307: register struct mount *mp; ! 308: register struct nameidata *ndp = &u.u_nd; ! 309: int error; ! 310: ! 311: ndp->ni_nameiop = LOOKUP | FOLLOW; ! 312: ndp->ni_segflg = UIO_USERSPACE; ! 313: ndp->ni_dirp = uap->path; ! 314: if (error = namei(ndp)) ! 315: RETURN (error); ! 316: mp = ndp->ni_vp->v_mount; ! 317: vrele(ndp->ni_vp); ! 318: RETURN (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg)); ! 319: } ! 320: ! 321: /* ! 322: * get filesystem statistics ! 323: */ ! 324: /* ARGSUSED */ ! 325: statfs(p, uap, retval) ! 326: register struct proc *p; ! 327: register struct args { ! 328: char *path; ! 329: struct statfs *buf; ! 330: } *uap; ! 331: int *retval; ! 332: { ! 333: register struct mount *mp; ! 334: register struct nameidata *ndp = &u.u_nd; ! 335: register struct statfs *sp; ! 336: int error; ! 337: ! 338: ndp->ni_nameiop = LOOKUP | FOLLOW; ! 339: ndp->ni_segflg = UIO_USERSPACE; ! 340: ndp->ni_dirp = uap->path; ! 341: if (error = namei(ndp)) ! 342: RETURN (error); ! 343: mp = ndp->ni_vp->v_mount; ! 344: sp = &mp->mnt_stat; ! 345: vrele(ndp->ni_vp); ! 346: if (error = VFS_STATFS(mp, sp)) ! 347: RETURN (error); ! 348: sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; ! 349: RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); ! 350: } ! 351: ! 352: /* ! 353: * get filesystem statistics ! 354: */ ! 355: /* ARGSUSED */ ! 356: fstatfs(p, uap, retval) ! 357: register struct proc *p; ! 358: register struct args { ! 359: int fd; ! 360: struct statfs *buf; ! 361: } *uap; ! 362: int *retval; ! 363: { ! 364: struct file *fp; ! 365: struct mount *mp; ! 366: register struct statfs *sp; ! 367: int error; ! 368: ! 369: if (error = getvnode(u.u_ofile, uap->fd, &fp)) ! 370: RETURN (error); ! 371: mp = ((struct vnode *)fp->f_data)->v_mount; ! 372: sp = &mp->mnt_stat; ! 373: if (error = VFS_STATFS(mp, sp)) ! 374: RETURN (error); ! 375: sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; ! 376: RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); ! 377: } ! 378: ! 379: /* ! 380: * get statistics on all filesystems ! 381: */ ! 382: getfsstat(p, uap, retval) ! 383: register struct proc *p; ! 384: register struct args { ! 385: struct statfs *buf; ! 386: long bufsize; ! 387: int flags; ! 388: } *uap; ! 389: int *retval; ! 390: { ! 391: register struct mount *mp; ! 392: register struct statfs *sp; ! 393: caddr_t sfsp; ! 394: long count, maxcount, error; ! 395: ! 396: maxcount = uap->bufsize / sizeof(struct statfs); ! 397: sfsp = (caddr_t)uap->buf; ! 398: mp = rootfs; ! 399: count = 0; ! 400: do { ! 401: if (sfsp && count < maxcount && ! 402: ((mp->mnt_flag & MNT_MLOCK) == 0)) { ! 403: sp = &mp->mnt_stat; ! 404: /* ! 405: * If MNT_NOWAIT is specified, do not refresh the ! 406: * fsstat cache. MNT_WAIT overrides MNT_NOWAIT. ! 407: */ ! 408: if (((uap->flags & MNT_NOWAIT) == 0 || ! 409: (uap->flags & MNT_WAIT)) && ! 410: (error = VFS_STATFS(mp, sp))) { ! 411: mp = mp->mnt_prev; ! 412: continue; ! 413: } ! 414: sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; ! 415: if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp))) ! 416: RETURN (error); ! 417: sfsp += sizeof(*sp); ! 418: } ! 419: count++; ! 420: mp = mp->mnt_prev; ! 421: } while (mp != rootfs); ! 422: if (sfsp && count > maxcount) ! 423: *retval = maxcount; ! 424: else ! 425: *retval = count; ! 426: RETURN (0); ! 427: } ! 428: ! 429: /* ! 430: * Change current working directory to a given file descriptor. ! 431: */ ! 432: /* ARGSUSED */ ! 433: fchdir(p, uap, retval) ! 434: register struct proc *p; ! 435: struct args { ! 436: int fd; ! 437: } *uap; ! 438: int *retval; ! 439: { ! 440: register struct nameidata *ndp = &u.u_nd; ! 441: register struct vnode *vp; ! 442: struct file *fp; ! 443: int error; ! 444: ! 445: if (error = getvnode(u.u_ofile, uap->fd, &fp)) ! 446: RETURN (error); ! 447: vp = (struct vnode *)fp->f_data; ! 448: VOP_LOCK(vp); ! 449: if (vp->v_type != VDIR) ! 450: error = ENOTDIR; ! 451: else ! 452: error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); ! 453: VOP_UNLOCK(vp); ! 454: if (error) ! 455: RETURN (error); ! 456: VREF(vp); ! 457: vrele(ndp->ni_cdir); ! 458: ndp->ni_cdir = vp; ! 459: RETURN (0); ! 460: } ! 461: ! 462: /* ! 463: * Change current working directory (``.''). ! 464: */ ! 465: /* ARGSUSED */ ! 466: chdir(p, uap, retval) ! 467: register struct proc *p; ! 468: struct args { ! 469: char *fname; ! 470: } *uap; ! 471: int *retval; ! 472: { ! 473: register struct nameidata *ndp = &u.u_nd; ! 474: int error; ! 475: ! 476: ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; ! 477: ndp->ni_segflg = UIO_USERSPACE; ! 478: ndp->ni_dirp = uap->fname; ! 479: if (error = chdirec(ndp)) ! 480: RETURN (error); ! 481: vrele(ndp->ni_cdir); ! 482: ndp->ni_cdir = ndp->ni_vp; ! 483: RETURN (0); ! 484: } ! 485: ! 486: /* ! 487: * Change notion of root (``/'') directory. ! 488: */ ! 489: /* ARGSUSED */ ! 490: chroot(p, uap, retval) ! 491: register struct proc *p; ! 492: struct args { ! 493: char *fname; ! 494: } *uap; ! 495: int *retval; ! 496: { ! 497: register struct nameidata *ndp = &u.u_nd; ! 498: int error; ! 499: ! 500: if (error = suser(ndp->ni_cred, &u.u_acflag)) ! 501: RETURN (error); ! 502: ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; ! 503: ndp->ni_segflg = UIO_USERSPACE; ! 504: ndp->ni_dirp = uap->fname; ! 505: if (error = chdirec(ndp)) ! 506: RETURN (error); ! 507: if (ndp->ni_rdir != NULL) ! 508: vrele(ndp->ni_rdir); ! 509: ndp->ni_rdir = ndp->ni_vp; ! 510: RETURN (0); ! 511: } ! 512: ! 513: /* ! 514: * Common routine for chroot and chdir. ! 515: */ ! 516: chdirec(ndp) ! 517: register struct nameidata *ndp; ! 518: { ! 519: struct vnode *vp; ! 520: int error; ! 521: ! 522: if (error = namei(ndp)) ! 523: return (error); ! 524: vp = ndp->ni_vp; ! 525: if (vp->v_type != VDIR) ! 526: error = ENOTDIR; ! 527: else ! 528: error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred); ! 529: VOP_UNLOCK(vp); ! 530: if (error) ! 531: vrele(vp); ! 532: return (error); ! 533: } ! 534: ! 535: /* ! 536: * Open system call. ! 537: * Check permissions, allocate an open file structure, ! 538: * and call the device open routine if any. ! 539: */ ! 540: open(p, uap, retval) ! 541: register struct proc *p; ! 542: register struct args { ! 543: char *fname; ! 544: int mode; ! 545: int crtmode; ! 546: } *uap; ! 547: int *retval; ! 548: { ! 549: struct nameidata *ndp = &u.u_nd; ! 550: register struct file *fp; ! 551: int fmode, cmode; ! 552: struct file *nfp; ! 553: int indx, error; ! 554: extern struct fileops vnops; ! 555: ! 556: if (error = falloc(&nfp, &indx)) ! 557: RETURN (error); ! 558: fp = nfp; ! 559: fmode = uap->mode - FOPEN; ! 560: cmode = ((uap->crtmode &~ u.u_cmask) & 07777) &~ S_ISVTX; ! 561: ndp->ni_segflg = UIO_USERSPACE; ! 562: ndp->ni_dirp = uap->fname; ! 563: p->p_dupfd = (u_char)-1; /* XXX check for fdopen */ ! 564: if (error = vn_open(ndp, fmode, cmode)) { ! 565: crfree(fp->f_cred); ! 566: fp->f_count--; ! 567: if (error == ENODEV && /* XXX from fdopen */ ! 568: p->p_dupfd != (u_char)-1 && ! 569: (error = dupfdopen(indx, p->p_dupfd, fmode)) == 0) { ! 570: *retval = indx; ! 571: RETURN (0); ! 572: } ! 573: if (error == ERESTART) ! 574: error = EINTR; ! 575: u.u_ofile[indx] = NULL; ! 576: RETURN (error); ! 577: } ! 578: fp->f_flag = fmode & FMASK; ! 579: fp->f_type = DTYPE_VNODE; ! 580: fp->f_ops = &vnops; ! 581: fp->f_data = (caddr_t)ndp->ni_vp; ! 582: *retval = indx; ! 583: RETURN (0); ! 584: } ! 585: ! 586: #ifdef COMPAT_43 ! 587: /* ! 588: * Creat system call. ! 589: */ ! 590: ocreat(p, uap, retval) ! 591: struct proc *p; ! 592: register struct args { ! 593: char *fname; ! 594: int fmode; ! 595: } *uap; ! 596: int *retval; ! 597: { ! 598: struct args { ! 599: char *fname; ! 600: int mode; ! 601: int crtmode; ! 602: } openuap; ! 603: ! 604: openuap.fname = uap->fname; ! 605: openuap.crtmode = uap->fmode; ! 606: openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; ! 607: RETURN (open(p, &openuap, retval)); ! 608: } ! 609: #endif /* COMPAT_43 */ ! 610: ! 611: /* ! 612: * Mknod system call ! 613: */ ! 614: /* ARGSUSED */ ! 615: mknod(p, uap, retval) ! 616: register struct proc *p; ! 617: register struct args { ! 618: char *fname; ! 619: int fmode; ! 620: int dev; ! 621: } *uap; ! 622: int *retval; ! 623: { ! 624: register struct nameidata *ndp = &u.u_nd; ! 625: register struct vnode *vp; ! 626: struct vattr vattr; ! 627: int error; ! 628: ! 629: if (error = suser(ndp->ni_cred, &u.u_acflag)) ! 630: RETURN (error); ! 631: ndp->ni_nameiop = CREATE | LOCKPARENT; ! 632: ndp->ni_segflg = UIO_USERSPACE; ! 633: ndp->ni_dirp = uap->fname; ! 634: if (error = namei(ndp)) ! 635: RETURN (error); ! 636: vp = ndp->ni_vp; ! 637: if (vp != NULL) { ! 638: error = EEXIST; ! 639: goto out; ! 640: } ! 641: VATTR_NULL(&vattr); ! 642: switch (uap->fmode & S_IFMT) { ! 643: ! 644: case S_IFMT: /* used by badsect to flag bad sectors */ ! 645: vattr.va_type = VBAD; ! 646: break; ! 647: case S_IFCHR: ! 648: vattr.va_type = VCHR; ! 649: break; ! 650: case S_IFBLK: ! 651: vattr.va_type = VBLK; ! 652: break; ! 653: default: ! 654: error = EINVAL; ! 655: goto out; ! 656: } ! 657: vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask; ! 658: vattr.va_rdev = uap->dev; ! 659: out: ! 660: if (!error) { ! 661: error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred); ! 662: } else { ! 663: VOP_ABORTOP(ndp); ! 664: if (ndp->ni_dvp == vp) ! 665: vrele(ndp->ni_dvp); ! 666: else ! 667: vput(ndp->ni_dvp); ! 668: if (vp) ! 669: vrele(vp); ! 670: } ! 671: RETURN (error); ! 672: } ! 673: ! 674: /* ! 675: * Mkfifo system call ! 676: */ ! 677: /* ARGSUSED */ ! 678: mkfifo(p, uap, retval) ! 679: register struct proc *p; ! 680: register struct args { ! 681: char *fname; ! 682: int fmode; ! 683: } *uap; ! 684: int *retval; ! 685: { ! 686: register struct nameidata *ndp = &u.u_nd; ! 687: struct vattr vattr; ! 688: int error; ! 689: ! 690: #ifndef FIFO ! 691: RETURN (EOPNOTSUPP); ! 692: #else ! 693: ndp->ni_nameiop = CREATE | LOCKPARENT; ! 694: ndp->ni_segflg = UIO_USERSPACE; ! 695: ndp->ni_dirp = uap->fname; ! 696: if (error = namei(ndp)) ! 697: RETURN (error); ! 698: if (ndp->ni_vp != NULL) { ! 699: VOP_ABORTOP(ndp); ! 700: if (ndp->ni_dvp == ndp->ni_vp) ! 701: vrele(ndp->ni_dvp); ! 702: else ! 703: vput(ndp->ni_dvp); ! 704: vrele(ndp->ni_vp); ! 705: RETURN (EEXIST); ! 706: } else { ! 707: VATTR_NULL(&vattr); ! 708: vattr.va_type = VFIFO; ! 709: vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask; ! 710: } ! 711: RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred)); ! 712: #endif /* FIFO */ ! 713: } ! 714: ! 715: /* ! 716: * link system call ! 717: */ ! 718: /* ARGSUSED */ ! 719: link(p, uap, retval) ! 720: register struct proc *p; ! 721: register struct args { ! 722: char *target; ! 723: char *linkname; ! 724: } *uap; ! 725: int *retval; ! 726: { ! 727: register struct nameidata *ndp = &u.u_nd; ! 728: register struct vnode *vp, *xp; ! 729: int error; ! 730: ! 731: ndp->ni_nameiop = LOOKUP | FOLLOW; ! 732: ndp->ni_segflg = UIO_USERSPACE; ! 733: ndp->ni_dirp = uap->target; ! 734: if (error = namei(ndp)) ! 735: RETURN (error); ! 736: vp = ndp->ni_vp; ! 737: if (vp->v_type == VDIR && ! 738: (error = suser(ndp->ni_cred, &u.u_acflag))) ! 739: goto out1; ! 740: ndp->ni_nameiop = CREATE | LOCKPARENT; ! 741: ndp->ni_dirp = (caddr_t)uap->linkname; ! 742: if (error = namei(ndp)) ! 743: goto out1; ! 744: xp = ndp->ni_vp; ! 745: if (xp != NULL) { ! 746: error = EEXIST; ! 747: goto out; ! 748: } ! 749: xp = ndp->ni_dvp; ! 750: if (vp->v_mount != xp->v_mount) ! 751: error = EXDEV; ! 752: out: ! 753: if (!error) { ! 754: error = VOP_LINK(vp, ndp); ! 755: } else { ! 756: VOP_ABORTOP(ndp); ! 757: if (ndp->ni_dvp == ndp->ni_vp) ! 758: vrele(ndp->ni_dvp); ! 759: else ! 760: vput(ndp->ni_dvp); ! 761: if (ndp->ni_vp) ! 762: vrele(ndp->ni_vp); ! 763: } ! 764: out1: ! 765: vrele(vp); ! 766: RETURN (error); ! 767: } ! 768: ! 769: /* ! 770: * symlink -- make a symbolic link ! 771: */ ! 772: /* ARGSUSED */ ! 773: symlink(p, uap, retval) ! 774: register struct proc *p; ! 775: register struct args { ! 776: char *target; ! 777: char *linkname; ! 778: } *uap; ! 779: int *retval; ! 780: { ! 781: register struct nameidata *ndp = &u.u_nd; ! 782: struct vattr vattr; ! 783: char *target; ! 784: int error; ! 785: ! 786: ndp->ni_segflg = UIO_USERSPACE; ! 787: ndp->ni_dirp = uap->linkname; ! 788: MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); ! 789: if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0)) ! 790: goto out; ! 791: ndp->ni_nameiop = CREATE | LOCKPARENT; ! 792: if (error = namei(ndp)) ! 793: goto out; ! 794: if (ndp->ni_vp) { ! 795: VOP_ABORTOP(ndp); ! 796: if (ndp->ni_dvp == ndp->ni_vp) ! 797: vrele(ndp->ni_dvp); ! 798: else ! 799: vput(ndp->ni_dvp); ! 800: vrele(ndp->ni_vp); ! 801: error = EEXIST; ! 802: goto out; ! 803: } ! 804: VATTR_NULL(&vattr); ! 805: vattr.va_mode = 0777 &~ u.u_cmask; ! 806: error = VOP_SYMLINK(ndp, &vattr, target); ! 807: out: ! 808: FREE(target, M_NAMEI); ! 809: RETURN (error); ! 810: } ! 811: ! 812: /* ! 813: * Unlink system call. ! 814: * Hard to avoid races here, especially ! 815: * in unlinking directories. ! 816: */ ! 817: /* ARGSUSED */ ! 818: unlink(p, uap, retval) ! 819: register struct proc *p; ! 820: struct args { ! 821: char *fname; ! 822: } *uap; ! 823: int *retval; ! 824: { ! 825: register struct nameidata *ndp = &u.u_nd; ! 826: register struct vnode *vp; ! 827: int error; ! 828: ! 829: ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; ! 830: ndp->ni_segflg = UIO_USERSPACE; ! 831: ndp->ni_dirp = uap->fname; ! 832: if (error = namei(ndp)) ! 833: RETURN (error); ! 834: vp = ndp->ni_vp; ! 835: if (vp->v_type == VDIR && ! 836: (error = suser(ndp->ni_cred, &u.u_acflag))) ! 837: goto out; ! 838: /* ! 839: * Don't unlink a mounted file. ! 840: */ ! 841: if (vp->v_flag & VROOT) { ! 842: error = EBUSY; ! 843: goto out; ! 844: } ! 845: if (vp->v_flag & VTEXT) ! 846: xrele(vp); /* try once to free text */ ! 847: out: ! 848: if (!error) { ! 849: error = VOP_REMOVE(ndp); ! 850: } else { ! 851: VOP_ABORTOP(ndp); ! 852: if (ndp->ni_dvp == vp) ! 853: vrele(ndp->ni_dvp); ! 854: else ! 855: vput(ndp->ni_dvp); ! 856: vput(vp); ! 857: } ! 858: RETURN (error); ! 859: } ! 860: ! 861: /* ! 862: * Seek system call ! 863: */ ! 864: lseek(p, uap, retval) ! 865: register struct proc *p; ! 866: register struct args { ! 867: int fdes; ! 868: off_t off; ! 869: int sbase; ! 870: } *uap; ! 871: off_t *retval; ! 872: { ! 873: struct ucred *cred = u.u_nd.ni_cred; ! 874: register struct file *fp; ! 875: struct vattr vattr; ! 876: int error; ! 877: ! 878: if ((unsigned)uap->fdes >= NOFILE || ! 879: (fp = u.u_ofile[uap->fdes]) == NULL) ! 880: RETURN (EBADF); ! 881: if (fp->f_type != DTYPE_VNODE) ! 882: RETURN (ESPIPE); ! 883: switch (uap->sbase) { ! 884: ! 885: case L_INCR: ! 886: fp->f_offset += uap->off; ! 887: break; ! 888: ! 889: case L_XTND: ! 890: if (error = VOP_GETATTR((struct vnode *)fp->f_data, ! 891: &vattr, cred)) ! 892: RETURN (error); ! 893: fp->f_offset = uap->off + vattr.va_size; ! 894: break; ! 895: ! 896: case L_SET: ! 897: fp->f_offset = uap->off; ! 898: break; ! 899: ! 900: default: ! 901: RETURN (EINVAL); ! 902: } ! 903: *retval = fp->f_offset; ! 904: RETURN (0); ! 905: } ! 906: ! 907: /* ! 908: * Access system call ! 909: */ ! 910: /* ARGSUSED */ ! 911: saccess(p, uap, retval) ! 912: register struct proc *p; ! 913: register struct args { ! 914: char *fname; ! 915: int fmode; ! 916: } *uap; ! 917: int *retval; ! 918: { ! 919: register struct nameidata *ndp = &u.u_nd; ! 920: register struct ucred *cred = ndp->ni_cred; ! 921: register struct vnode *vp; ! 922: int error, mode, svuid, svgid; ! 923: ! 924: svuid = cred->cr_uid; ! 925: svgid = cred->cr_groups[0]; ! 926: cred->cr_uid = p->p_ruid; ! 927: cred->cr_groups[0] = p->p_rgid; ! 928: ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; ! 929: ndp->ni_segflg = UIO_USERSPACE; ! 930: ndp->ni_dirp = uap->fname; ! 931: if (error = namei(ndp)) ! 932: goto out1; ! 933: vp = ndp->ni_vp; ! 934: /* ! 935: * fmode == 0 means only check for exist ! 936: */ ! 937: if (uap->fmode) { ! 938: mode = 0; ! 939: if (uap->fmode & R_OK) ! 940: mode |= VREAD; ! 941: if (uap->fmode & W_OK) ! 942: mode |= VWRITE; ! 943: if (uap->fmode & X_OK) ! 944: mode |= VEXEC; ! 945: if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0) ! 946: error = VOP_ACCESS(vp, mode, ndp->ni_cred); ! 947: } ! 948: vput(vp); ! 949: out1: ! 950: cred->cr_uid = svuid; ! 951: cred->cr_groups[0] = svgid; ! 952: RETURN (error); ! 953: } ! 954: ! 955: /* ! 956: * Stat system call. This version follows links. ! 957: */ ! 958: /* ARGSUSED */ ! 959: stat(p, uap, retval) ! 960: register struct proc *p; ! 961: register struct args { ! 962: char *fname; ! 963: struct stat *ub; ! 964: } *uap; ! 965: int *retval; ! 966: { ! 967: register struct nameidata *ndp = &u.u_nd; ! 968: struct stat sb; ! 969: int error; ! 970: ! 971: ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; ! 972: ndp->ni_segflg = UIO_USERSPACE; ! 973: ndp->ni_dirp = uap->fname; ! 974: if (error = namei(ndp)) ! 975: RETURN (error); ! 976: error = vn_stat(ndp->ni_vp, &sb); ! 977: vput(ndp->ni_vp); ! 978: if (error) ! 979: RETURN (error); ! 980: error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); ! 981: RETURN (error); ! 982: } ! 983: ! 984: /* ! 985: * Lstat system call. This version does not follow links. ! 986: */ ! 987: /* ARGSUSED */ ! 988: lstat(p, uap, retval) ! 989: register struct proc *p; ! 990: register struct args { ! 991: char *fname; ! 992: struct stat *ub; ! 993: } *uap; ! 994: int *retval; ! 995: { ! 996: register struct nameidata *ndp = &u.u_nd; ! 997: struct stat sb; ! 998: int error; ! 999: ! 1000: ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW; ! 1001: ndp->ni_segflg = UIO_USERSPACE; ! 1002: ndp->ni_dirp = uap->fname; ! 1003: if (error = namei(ndp)) ! 1004: RETURN (error); ! 1005: error = vn_stat(ndp->ni_vp, &sb); ! 1006: vput(ndp->ni_vp); ! 1007: if (error) ! 1008: RETURN (error); ! 1009: error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb)); ! 1010: RETURN (error); ! 1011: } ! 1012: ! 1013: /* ! 1014: * Return target name of a symbolic link ! 1015: */ ! 1016: /* ARGSUSED */ ! 1017: readlink(p, uap, retval) ! 1018: register struct proc *p; ! 1019: register struct args { ! 1020: char *name; ! 1021: char *buf; ! 1022: int count; ! 1023: } *uap; ! 1024: int *retval; ! 1025: { ! 1026: register struct nameidata *ndp = &u.u_nd; ! 1027: register struct vnode *vp; ! 1028: struct iovec aiov; ! 1029: struct uio auio; ! 1030: int error; ! 1031: ! 1032: ndp->ni_nameiop = LOOKUP | LOCKLEAF; ! 1033: ndp->ni_segflg = UIO_USERSPACE; ! 1034: ndp->ni_dirp = uap->name; ! 1035: if (error = namei(ndp)) ! 1036: RETURN (error); ! 1037: vp = ndp->ni_vp; ! 1038: if (vp->v_type != VLNK) { ! 1039: error = EINVAL; ! 1040: goto out; ! 1041: } ! 1042: aiov.iov_base = uap->buf; ! 1043: aiov.iov_len = uap->count; ! 1044: auio.uio_iov = &aiov; ! 1045: auio.uio_iovcnt = 1; ! 1046: auio.uio_offset = 0; ! 1047: auio.uio_rw = UIO_READ; ! 1048: auio.uio_segflg = UIO_USERSPACE; ! 1049: auio.uio_resid = uap->count; ! 1050: error = VOP_READLINK(vp, &auio, ndp->ni_cred); ! 1051: out: ! 1052: vput(vp); ! 1053: *retval = uap->count - auio.uio_resid; ! 1054: RETURN (error); ! 1055: } ! 1056: ! 1057: /* ! 1058: * Change flags of a file given path name. ! 1059: */ ! 1060: /* ARGSUSED */ ! 1061: chflags(p, uap, retval) ! 1062: register struct proc *p; ! 1063: register struct args { ! 1064: char *fname; ! 1065: int flags; ! 1066: } *uap; ! 1067: int *retval; ! 1068: { ! 1069: register struct nameidata *ndp = &u.u_nd; ! 1070: register struct vnode *vp; ! 1071: struct vattr vattr; ! 1072: int error; ! 1073: ! 1074: ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; ! 1075: ndp->ni_segflg = UIO_USERSPACE; ! 1076: ndp->ni_dirp = uap->fname; ! 1077: VATTR_NULL(&vattr); ! 1078: vattr.va_flags = uap->flags; ! 1079: if (error = namei(ndp)) ! 1080: RETURN (error); ! 1081: vp = ndp->ni_vp; ! 1082: if (vp->v_mount->mnt_flag & MNT_RDONLY) { ! 1083: error = EROFS; ! 1084: goto out; ! 1085: } ! 1086: error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); ! 1087: out: ! 1088: vput(vp); ! 1089: RETURN (error); ! 1090: } ! 1091: ! 1092: /* ! 1093: * Change flags of a file given a file descriptor. ! 1094: */ ! 1095: /* ARGSUSED */ ! 1096: fchflags(p, uap, retval) ! 1097: register struct proc *p; ! 1098: register struct args { ! 1099: int fd; ! 1100: int flags; ! 1101: } *uap; ! 1102: int *retval; ! 1103: { ! 1104: struct vattr vattr; ! 1105: struct vnode *vp; ! 1106: struct file *fp; ! 1107: int error; ! 1108: ! 1109: if (error = getvnode(u.u_ofile, uap->fd, &fp)) ! 1110: RETURN (error); ! 1111: VATTR_NULL(&vattr); ! 1112: vattr.va_flags = uap->flags; ! 1113: vp = (struct vnode *)fp->f_data; ! 1114: VOP_LOCK(vp); ! 1115: if (vp->v_mount->mnt_flag & MNT_RDONLY) { ! 1116: error = EROFS; ! 1117: goto out; ! 1118: } ! 1119: error = VOP_SETATTR(vp, &vattr, fp->f_cred); ! 1120: out: ! 1121: VOP_UNLOCK(vp); ! 1122: RETURN (error); ! 1123: } ! 1124: ! 1125: /* ! 1126: * Change mode of a file given path name. ! 1127: */ ! 1128: /* ARGSUSED */ ! 1129: chmod(p, uap, retval) ! 1130: register struct proc *p; ! 1131: register struct args { ! 1132: char *fname; ! 1133: int fmode; ! 1134: } *uap; ! 1135: int *retval; ! 1136: { ! 1137: register struct nameidata *ndp = &u.u_nd; ! 1138: register struct vnode *vp; ! 1139: struct vattr vattr; ! 1140: int error; ! 1141: ! 1142: ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; ! 1143: ndp->ni_segflg = UIO_USERSPACE; ! 1144: ndp->ni_dirp = uap->fname; ! 1145: VATTR_NULL(&vattr); ! 1146: vattr.va_mode = uap->fmode & 07777; ! 1147: if (error = namei(ndp)) ! 1148: RETURN (error); ! 1149: vp = ndp->ni_vp; ! 1150: if (vp->v_mount->mnt_flag & MNT_RDONLY) { ! 1151: error = EROFS; ! 1152: goto out; ! 1153: } ! 1154: error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); ! 1155: out: ! 1156: vput(vp); ! 1157: RETURN (error); ! 1158: } ! 1159: ! 1160: /* ! 1161: * Change mode of a file given a file descriptor. ! 1162: */ ! 1163: /* ARGSUSED */ ! 1164: fchmod(p, uap, retval) ! 1165: register struct proc *p; ! 1166: register struct args { ! 1167: int fd; ! 1168: int fmode; ! 1169: } *uap; ! 1170: int *retval; ! 1171: { ! 1172: struct vattr vattr; ! 1173: struct vnode *vp; ! 1174: struct file *fp; ! 1175: int error; ! 1176: ! 1177: if (error = getvnode(u.u_ofile, uap->fd, &fp)) ! 1178: RETURN (error); ! 1179: VATTR_NULL(&vattr); ! 1180: vattr.va_mode = uap->fmode & 07777; ! 1181: vp = (struct vnode *)fp->f_data; ! 1182: VOP_LOCK(vp); ! 1183: if (vp->v_mount->mnt_flag & MNT_RDONLY) { ! 1184: error = EROFS; ! 1185: goto out; ! 1186: } ! 1187: error = VOP_SETATTR(vp, &vattr, fp->f_cred); ! 1188: out: ! 1189: VOP_UNLOCK(vp); ! 1190: RETURN (error); ! 1191: } ! 1192: ! 1193: /* ! 1194: * Set ownership given a path name. ! 1195: */ ! 1196: /* ARGSUSED */ ! 1197: chown(p, uap, retval) ! 1198: register struct proc *p; ! 1199: register struct args { ! 1200: char *fname; ! 1201: int uid; ! 1202: int gid; ! 1203: } *uap; ! 1204: int *retval; ! 1205: { ! 1206: register struct nameidata *ndp = &u.u_nd; ! 1207: register struct vnode *vp; ! 1208: struct vattr vattr; ! 1209: int error; ! 1210: ! 1211: ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF; ! 1212: ndp->ni_segflg = UIO_USERSPACE; ! 1213: ndp->ni_dirp = uap->fname; ! 1214: VATTR_NULL(&vattr); ! 1215: vattr.va_uid = uap->uid; ! 1216: vattr.va_gid = uap->gid; ! 1217: if (error = namei(ndp)) ! 1218: RETURN (error); ! 1219: vp = ndp->ni_vp; ! 1220: if (vp->v_mount->mnt_flag & MNT_RDONLY) { ! 1221: error = EROFS; ! 1222: goto out; ! 1223: } ! 1224: error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); ! 1225: out: ! 1226: vput(vp); ! 1227: RETURN (error); ! 1228: } ! 1229: ! 1230: /* ! 1231: * Set ownership given a file descriptor. ! 1232: */ ! 1233: /* ARGSUSED */ ! 1234: fchown(p, uap, retval) ! 1235: register struct proc *p; ! 1236: register struct args { ! 1237: int fd; ! 1238: int uid; ! 1239: int gid; ! 1240: } *uap; ! 1241: int *retval; ! 1242: { ! 1243: struct vattr vattr; ! 1244: struct vnode *vp; ! 1245: struct file *fp; ! 1246: int error; ! 1247: ! 1248: if (error = getvnode(u.u_ofile, uap->fd, &fp)) ! 1249: RETURN (error); ! 1250: VATTR_NULL(&vattr); ! 1251: vattr.va_uid = uap->uid; ! 1252: vattr.va_gid = uap->gid; ! 1253: vp = (struct vnode *)fp->f_data; ! 1254: VOP_LOCK(vp); ! 1255: if (vp->v_mount->mnt_flag & MNT_RDONLY) { ! 1256: error = EROFS; ! 1257: goto out; ! 1258: } ! 1259: error = VOP_SETATTR(vp, &vattr, fp->f_cred); ! 1260: out: ! 1261: VOP_UNLOCK(vp); ! 1262: RETURN (error); ! 1263: } ! 1264: ! 1265: /* ! 1266: * Set the access and modification times of a file. ! 1267: */ ! 1268: /* ARGSUSED */ ! 1269: utimes(p, uap, retval) ! 1270: register struct proc *p; ! 1271: register struct args { ! 1272: char *fname; ! 1273: struct timeval *tptr; ! 1274: } *uap; ! 1275: int *retval; ! 1276: { ! 1277: register struct nameidata *ndp = &u.u_nd; ! 1278: register struct vnode *vp; ! 1279: struct timeval tv[2]; ! 1280: struct vattr vattr; ! 1281: int error; ! 1282: ! 1283: if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv))) ! 1284: RETURN (error); ! 1285: ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; ! 1286: ndp->ni_segflg = UIO_USERSPACE; ! 1287: ndp->ni_dirp = uap->fname; ! 1288: VATTR_NULL(&vattr); ! 1289: vattr.va_atime = tv[0]; ! 1290: vattr.va_mtime = tv[1]; ! 1291: if (error = namei(ndp)) ! 1292: RETURN (error); ! 1293: vp = ndp->ni_vp; ! 1294: if (vp->v_mount->mnt_flag & MNT_RDONLY) { ! 1295: error = EROFS; ! 1296: goto out; ! 1297: } ! 1298: error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); ! 1299: out: ! 1300: vput(vp); ! 1301: RETURN (error); ! 1302: } ! 1303: ! 1304: /* ! 1305: * Truncate a file given its path name. ! 1306: */ ! 1307: /* ARGSUSED */ ! 1308: truncate(p, uap, retval) ! 1309: register struct proc *p; ! 1310: register struct args { ! 1311: char *fname; ! 1312: off_t length; ! 1313: } *uap; ! 1314: int *retval; ! 1315: { ! 1316: register struct nameidata *ndp = &u.u_nd; ! 1317: register struct vnode *vp; ! 1318: struct vattr vattr; ! 1319: int error; ! 1320: ! 1321: ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; ! 1322: ndp->ni_segflg = UIO_USERSPACE; ! 1323: ndp->ni_dirp = uap->fname; ! 1324: VATTR_NULL(&vattr); ! 1325: vattr.va_size = uap->length; ! 1326: if (error = namei(ndp)) ! 1327: RETURN (error); ! 1328: vp = ndp->ni_vp; ! 1329: if (vp->v_type == VDIR) { ! 1330: error = EISDIR; ! 1331: goto out; ! 1332: } ! 1333: if ((error = vn_writechk(vp)) || ! 1334: (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))) ! 1335: goto out; ! 1336: error = VOP_SETATTR(vp, &vattr, ndp->ni_cred); ! 1337: out: ! 1338: vput(vp); ! 1339: RETURN (error); ! 1340: } ! 1341: ! 1342: /* ! 1343: * Truncate a file given a file descriptor. ! 1344: */ ! 1345: /* ARGSUSED */ ! 1346: ftruncate(p, uap, retval) ! 1347: register struct proc *p; ! 1348: register struct args { ! 1349: int fd; ! 1350: off_t length; ! 1351: } *uap; ! 1352: int *retval; ! 1353: { ! 1354: struct vattr vattr; ! 1355: struct vnode *vp; ! 1356: struct file *fp; ! 1357: int error; ! 1358: ! 1359: if (error = getvnode(u.u_ofile, uap->fd, &fp)) ! 1360: RETURN (error); ! 1361: if ((fp->f_flag & FWRITE) == 0) ! 1362: RETURN (EINVAL); ! 1363: VATTR_NULL(&vattr); ! 1364: vattr.va_size = uap->length; ! 1365: vp = (struct vnode *)fp->f_data; ! 1366: VOP_LOCK(vp); ! 1367: if (vp->v_type == VDIR) { ! 1368: error = EISDIR; ! 1369: goto out; ! 1370: } ! 1371: if (error = vn_writechk(vp)) ! 1372: goto out; ! 1373: error = VOP_SETATTR(vp, &vattr, fp->f_cred); ! 1374: out: ! 1375: VOP_UNLOCK(vp); ! 1376: RETURN (error); ! 1377: } ! 1378: ! 1379: /* ! 1380: * Synch an open file. ! 1381: */ ! 1382: /* ARGSUSED */ ! 1383: fsync(p, uap, retval) ! 1384: register struct proc *p; ! 1385: struct args { ! 1386: int fd; ! 1387: } *uap; ! 1388: int *retval; ! 1389: { ! 1390: register struct vnode *vp; ! 1391: struct file *fp; ! 1392: int error; ! 1393: ! 1394: if (error = getvnode(u.u_ofile, uap->fd, &fp)) ! 1395: RETURN (error); ! 1396: vp = (struct vnode *)fp->f_data; ! 1397: VOP_LOCK(vp); ! 1398: error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT); ! 1399: VOP_UNLOCK(vp); ! 1400: RETURN (error); ! 1401: } ! 1402: ! 1403: /* ! 1404: * Rename system call. ! 1405: * ! 1406: * Source and destination must either both be directories, or both ! 1407: * not be directories. If target is a directory, it must be empty. ! 1408: */ ! 1409: /* ARGSUSED */ ! 1410: rename(p, uap, retval) ! 1411: register struct proc *p; ! 1412: register struct args { ! 1413: char *from; ! 1414: char *to; ! 1415: } *uap; ! 1416: int *retval; ! 1417: { ! 1418: register struct vnode *tvp, *fvp, *tdvp; ! 1419: register struct nameidata *ndp = &u.u_nd; ! 1420: struct nameidata tond; ! 1421: int error; ! 1422: ! 1423: ndp->ni_nameiop = DELETE | WANTPARENT; ! 1424: ndp->ni_segflg = UIO_USERSPACE; ! 1425: ndp->ni_dirp = uap->from; ! 1426: if (error = namei(ndp)) ! 1427: RETURN (error); ! 1428: fvp = ndp->ni_vp; ! 1429: nddup(ndp, &tond); ! 1430: tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE; ! 1431: tond.ni_segflg = UIO_USERSPACE; ! 1432: tond.ni_dirp = uap->to; ! 1433: if (error = namei(&tond)) { ! 1434: VOP_ABORTOP(ndp); ! 1435: vrele(ndp->ni_dvp); ! 1436: vrele(fvp); ! 1437: goto out1; ! 1438: } ! 1439: tdvp = tond.ni_dvp; ! 1440: tvp = tond.ni_vp; ! 1441: if (tvp != NULL) { ! 1442: if (fvp->v_type == VDIR && tvp->v_type != VDIR) { ! 1443: error = ENOTDIR; ! 1444: goto out; ! 1445: } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { ! 1446: error = EISDIR; ! 1447: goto out; ! 1448: } ! 1449: } ! 1450: if (fvp->v_mount != tdvp->v_mount) { ! 1451: error = EXDEV; ! 1452: goto out; ! 1453: } ! 1454: if (fvp == tdvp) ! 1455: error = EINVAL; ! 1456: /* ! 1457: * If source is the same as the destination, ! 1458: * then there is nothing to do. ! 1459: */ ! 1460: if (fvp == tvp) ! 1461: error = -1; ! 1462: out: ! 1463: if (!error) { ! 1464: error = VOP_RENAME(ndp, &tond); ! 1465: } else { ! 1466: VOP_ABORTOP(&tond); ! 1467: if (tdvp == tvp) ! 1468: vrele(tdvp); ! 1469: else ! 1470: vput(tdvp); ! 1471: if (tvp) ! 1472: vput(tvp); ! 1473: VOP_ABORTOP(ndp); ! 1474: vrele(ndp->ni_dvp); ! 1475: vrele(fvp); ! 1476: } ! 1477: out1: ! 1478: ndrele(&tond); ! 1479: if (error == -1) ! 1480: RETURN (0); ! 1481: RETURN (error); ! 1482: } ! 1483: ! 1484: /* ! 1485: * Mkdir system call ! 1486: */ ! 1487: /* ARGSUSED */ ! 1488: mkdir(p, uap, retval) ! 1489: register struct proc *p; ! 1490: register struct args { ! 1491: char *name; ! 1492: int dmode; ! 1493: } *uap; ! 1494: int *retval; ! 1495: { ! 1496: register struct nameidata *ndp = &u.u_nd; ! 1497: register struct vnode *vp; ! 1498: struct vattr vattr; ! 1499: int error; ! 1500: ! 1501: ndp->ni_nameiop = CREATE | LOCKPARENT; ! 1502: ndp->ni_segflg = UIO_USERSPACE; ! 1503: ndp->ni_dirp = uap->name; ! 1504: if (error = namei(ndp)) ! 1505: RETURN (error); ! 1506: vp = ndp->ni_vp; ! 1507: if (vp != NULL) { ! 1508: VOP_ABORTOP(ndp); ! 1509: if (ndp->ni_dvp == vp) ! 1510: vrele(ndp->ni_dvp); ! 1511: else ! 1512: vput(ndp->ni_dvp); ! 1513: vrele(vp); ! 1514: RETURN (EEXIST); ! 1515: } ! 1516: VATTR_NULL(&vattr); ! 1517: vattr.va_type = VDIR; ! 1518: vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask; ! 1519: error = VOP_MKDIR(ndp, &vattr); ! 1520: if (!error) ! 1521: vput(ndp->ni_vp); ! 1522: RETURN (error); ! 1523: } ! 1524: ! 1525: /* ! 1526: * Rmdir system call. ! 1527: */ ! 1528: /* ARGSUSED */ ! 1529: rmdir(p, uap, retval) ! 1530: register struct proc *p; ! 1531: struct args { ! 1532: char *name; ! 1533: } *uap; ! 1534: int *retval; ! 1535: { ! 1536: register struct nameidata *ndp = &u.u_nd; ! 1537: register struct vnode *vp; ! 1538: int error; ! 1539: ! 1540: ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF; ! 1541: ndp->ni_segflg = UIO_USERSPACE; ! 1542: ndp->ni_dirp = uap->name; ! 1543: if (error = namei(ndp)) ! 1544: RETURN (error); ! 1545: vp = ndp->ni_vp; ! 1546: if (vp->v_type != VDIR) { ! 1547: error = ENOTDIR; ! 1548: goto out; ! 1549: } ! 1550: /* ! 1551: * No rmdir "." please. ! 1552: */ ! 1553: if (ndp->ni_dvp == vp) { ! 1554: error = EINVAL; ! 1555: goto out; ! 1556: } ! 1557: /* ! 1558: * Don't unlink a mounted file. ! 1559: */ ! 1560: if (vp->v_flag & VROOT) ! 1561: error = EBUSY; ! 1562: out: ! 1563: if (!error) { ! 1564: error = VOP_RMDIR(ndp); ! 1565: } else { ! 1566: VOP_ABORTOP(ndp); ! 1567: if (ndp->ni_dvp == vp) ! 1568: vrele(ndp->ni_dvp); ! 1569: else ! 1570: vput(ndp->ni_dvp); ! 1571: vput(vp); ! 1572: } ! 1573: RETURN (error); ! 1574: } ! 1575: ! 1576: /* ! 1577: * Read a block of directory entries in a file system independent format ! 1578: */ ! 1579: getdirentries(p, uap, retval) ! 1580: register struct proc *p; ! 1581: register struct args { ! 1582: int fd; ! 1583: char *buf; ! 1584: unsigned count; ! 1585: long *basep; ! 1586: } *uap; ! 1587: int *retval; ! 1588: { ! 1589: register struct vnode *vp; ! 1590: struct file *fp; ! 1591: struct uio auio; ! 1592: struct iovec aiov; ! 1593: off_t off; ! 1594: int error, eofflag; ! 1595: ! 1596: if (error = getvnode(u.u_ofile, uap->fd, &fp)) ! 1597: RETURN (error); ! 1598: if ((fp->f_flag & FREAD) == 0) ! 1599: RETURN (EBADF); ! 1600: vp = (struct vnode *)fp->f_data; ! 1601: if (vp->v_type != VDIR) ! 1602: RETURN (EINVAL); ! 1603: aiov.iov_base = uap->buf; ! 1604: aiov.iov_len = uap->count; ! 1605: auio.uio_iov = &aiov; ! 1606: auio.uio_iovcnt = 1; ! 1607: auio.uio_rw = UIO_READ; ! 1608: auio.uio_segflg = UIO_USERSPACE; ! 1609: auio.uio_resid = uap->count; ! 1610: VOP_LOCK(vp); ! 1611: auio.uio_offset = off = fp->f_offset; ! 1612: error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag); ! 1613: fp->f_offset = auio.uio_offset; ! 1614: VOP_UNLOCK(vp); ! 1615: if (error) ! 1616: RETURN (error); ! 1617: error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long)); ! 1618: *retval = uap->count - auio.uio_resid; ! 1619: RETURN (error); ! 1620: } ! 1621: ! 1622: /* ! 1623: * mode mask for creation of files ! 1624: */ ! 1625: mode_t ! 1626: umask(p, uap, retval) ! 1627: register struct proc *p; ! 1628: struct args { ! 1629: int mask; ! 1630: } *uap; ! 1631: int *retval; ! 1632: { ! 1633: ! 1634: *retval = u.u_cmask; ! 1635: u.u_cmask = uap->mask & 07777; ! 1636: RETURN (0); ! 1637: } ! 1638: ! 1639: /* ! 1640: * Void all references to file by ripping underlying filesystem ! 1641: * away from vnode. ! 1642: */ ! 1643: /* ARGSUSED */ ! 1644: revoke(p, uap, retval) ! 1645: register struct proc *p; ! 1646: register struct args { ! 1647: char *fname; ! 1648: } *uap; ! 1649: int *retval; ! 1650: { ! 1651: register struct nameidata *ndp = &u.u_nd; ! 1652: register struct vnode *vp; ! 1653: struct vattr vattr; ! 1654: int error; ! 1655: ! 1656: ndp->ni_nameiop = LOOKUP | FOLLOW; ! 1657: ndp->ni_segflg = UIO_USERSPACE; ! 1658: ndp->ni_dirp = uap->fname; ! 1659: if (error = namei(ndp)) ! 1660: RETURN (error); ! 1661: vp = ndp->ni_vp; ! 1662: if (vp->v_type != VCHR && vp->v_type != VBLK) { ! 1663: error = EINVAL; ! 1664: goto out; ! 1665: } ! 1666: if (error = VOP_GETATTR(vp, &vattr, ndp->ni_cred)) ! 1667: goto out; ! 1668: if (ndp->ni_cred->cr_uid != vattr.va_uid && ! 1669: (error = suser(ndp->ni_cred, &u.u_acflag))) ! 1670: goto out; ! 1671: if (vp->v_usecount > 1 || (vp->v_flag & VALIASED)) ! 1672: vgoneall(vp); ! 1673: out: ! 1674: vrele(vp); ! 1675: RETURN (error); ! 1676: } ! 1677: ! 1678: getvnode(ofile, fdes, fpp) ! 1679: struct file *ofile[]; ! 1680: struct file **fpp; ! 1681: int fdes; ! 1682: { ! 1683: struct file *fp; ! 1684: ! 1685: if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL) ! 1686: return (EBADF); ! 1687: if (fp->f_type != DTYPE_VNODE) ! 1688: return (EINVAL); ! 1689: *fpp = fp; ! 1690: return (0); ! 1691: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.