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