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