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