Added David Mills' kernel NTP PLL code. The current version of NTP does
[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
e668648e 34 * $Id: vfs_syscalls.c,v 1.9 1994/01/19 20:27:38 guido 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;
844 if (vp->v_type == VDIR &&
845 (error = suser(p->p_ucred, &p->p_acflag)))
846 goto out1;
847 ndp->ni_nameiop = CREATE | LOCKPARENT;
848 ndp->ni_dirp = (caddr_t)uap->linkname;
849 if (error = namei(ndp, p))
850 goto out1;
851 xp = ndp->ni_vp;
852 if (xp != NULL) {
853 error = EEXIST;
854 goto out;
855 }
856 xp = ndp->ni_dvp;
857 if (vp->v_mount != xp->v_mount)
858 error = EXDEV;
859out:
860 if (!error) {
861 error = VOP_LINK(vp, ndp, p);
862 } else {
863 VOP_ABORTOP(ndp);
864 if (ndp->ni_dvp == ndp->ni_vp)
865 vrele(ndp->ni_dvp);
866 else
867 vput(ndp->ni_dvp);
868 if (ndp->ni_vp)
869 vrele(ndp->ni_vp);
870 }
871out1:
872 vrele(vp);
873 return (error);
874}
875
876/*
877 * Make a symbolic link.
878 */
3c7eb27c
DG
879
880struct symlink_args {
881 char *target;
882 char *linkname;
883};
884
15637ed4 885/* ARGSUSED */
4c45483e 886int
15637ed4
RG
887symlink(p, uap, retval)
888 struct proc *p;
3c7eb27c 889 register struct symlink_args *uap;
15637ed4
RG
890 int *retval;
891{
892 register struct nameidata *ndp;
893 struct vattr vattr;
894 char *target;
895 int error;
896 struct nameidata nd;
897
898 ndp = &nd;
899 ndp->ni_segflg = UIO_USERSPACE;
900 ndp->ni_dirp = uap->linkname;
901 MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
902 if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
903 goto out;
904 ndp->ni_nameiop = CREATE | LOCKPARENT;
905 if (error = namei(ndp, p))
906 goto out;
907 if (ndp->ni_vp) {
908 VOP_ABORTOP(ndp);
909 if (ndp->ni_dvp == ndp->ni_vp)
910 vrele(ndp->ni_dvp);
911 else
912 vput(ndp->ni_dvp);
913 vrele(ndp->ni_vp);
914 error = EEXIST;
915 goto out;
916 }
917 VATTR_NULL(&vattr);
918 vattr.va_mode = 0777 &~ p->p_fd->fd_cmask;
919 error = VOP_SYMLINK(ndp, &vattr, target, p);
920out:
921 FREE(target, M_NAMEI);
922 return (error);
923}
924
925/*
926 * Delete a name from the filesystem.
927 */
3c7eb27c
DG
928
929struct unlink_args {
930 char *fname;
931};
932
15637ed4 933/* ARGSUSED */
4c45483e 934int
15637ed4
RG
935unlink(p, uap, retval)
936 struct proc *p;
3c7eb27c 937 struct unlink_args *uap;
15637ed4
RG
938 int *retval;
939{
940 register struct nameidata *ndp;
941 register struct vnode *vp;
942 int error;
943 struct nameidata nd;
944
945 ndp = &nd;
946 ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
947 ndp->ni_segflg = UIO_USERSPACE;
948 ndp->ni_dirp = uap->fname;
949 if (error = namei(ndp, p))
950 return (error);
951 vp = ndp->ni_vp;
952 if (vp->v_type == VDIR &&
953 (error = suser(p->p_ucred, &p->p_acflag)))
954 goto out;
955 /*
956 * The root of a mounted filesystem cannot be deleted.
957 */
958 if (vp->v_flag & VROOT) {
959 error = EBUSY;
960 goto out;
961 }
962 (void) vnode_pager_uncache(vp);
963out:
964 if (!error) {
965 error = VOP_REMOVE(ndp, p);
966 } else {
967 VOP_ABORTOP(ndp);
968 if (ndp->ni_dvp == vp)
969 vrele(ndp->ni_dvp);
970 else
971 vput(ndp->ni_dvp);
972 vput(vp);
973 }
974 return (error);
975}
976
977/*
978 * Seek system call.
979 */
3c7eb27c
DG
980
981struct lseek_args {
982 int fdes;
983 off_t off;
984 int sbase;
985};
986
4c45483e 987int
15637ed4
RG
988lseek(p, uap, retval)
989 struct proc *p;
3c7eb27c 990 register struct lseek_args *uap;
15637ed4
RG
991 off_t *retval;
992{
993 struct ucred *cred = p->p_ucred;
994 register struct filedesc *fdp = p->p_fd;
995 register struct file *fp;
996 struct vattr vattr;
997 int error;
998
999 if ((unsigned)uap->fdes >= fdp->fd_nfiles ||
1000 (fp = fdp->fd_ofiles[uap->fdes]) == NULL)
1001 return (EBADF);
1002 if (fp->f_type != DTYPE_VNODE)
1003 return (ESPIPE);
1004 switch (uap->sbase) {
1005
1006 case L_INCR:
1007 fp->f_offset += uap->off;
1008 break;
1009
1010 case L_XTND:
1011 if (error = VOP_GETATTR((struct vnode *)fp->f_data,
1012 &vattr, cred, p))
1013 return (error);
1014 fp->f_offset = uap->off + vattr.va_size;
1015 break;
1016
1017 case L_SET:
1018 fp->f_offset = uap->off;
1019 break;
1020
1021 default:
1022 return (EINVAL);
1023 }
1024 *retval = fp->f_offset;
1025 return (0);
1026}
1027
1028/*
1029 * Check access permissions.
1030 */
3c7eb27c
DG
1031
1032struct saccess_args {
1033 char *fname;
1034 int fmode;
1035};
1036
15637ed4 1037/* ARGSUSED */
4c45483e 1038int
15637ed4
RG
1039saccess(p, uap, retval)
1040 struct proc *p;
3c7eb27c 1041 register struct saccess_args *uap;
15637ed4
RG
1042 int *retval;
1043{
1044 register struct nameidata *ndp;
1045 register struct ucred *cred = p->p_ucred;
1046 register struct vnode *vp;
1047 int error, mode, svuid, svgid;
1048 struct nameidata nd;
1049
1050 ndp = &nd;
1051 svuid = cred->cr_uid;
1052 svgid = cred->cr_groups[0];
1053 cred->cr_uid = p->p_cred->p_ruid;
1054 cred->cr_groups[0] = p->p_cred->p_rgid;
1055 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
1056 ndp->ni_segflg = UIO_USERSPACE;
1057 ndp->ni_dirp = uap->fname;
1058 if (error = namei(ndp, p))
1059 goto out1;
1060 vp = ndp->ni_vp;
1061 /*
1062 * fmode == 0 means only check for exist
1063 */
1064 if (uap->fmode) {
1065 mode = 0;
1066 if (uap->fmode & R_OK)
1067 mode |= VREAD;
1068 if (uap->fmode & W_OK)
1069 mode |= VWRITE;
1070 if (uap->fmode & X_OK)
1071 mode |= VEXEC;
1072 if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
1073 error = VOP_ACCESS(vp, mode, cred, p);
1074 }
1075 vput(vp);
1076out1:
1077 cred->cr_uid = svuid;
1078 cred->cr_groups[0] = svgid;
1079 return (error);
1080}
1081
1082/*
1083 * Stat system call.
1084 * This version follows links.
1085 */
3c7eb27c
DG
1086
1087struct stat_args {
1088 char *fname;
1089 struct stat *ub;
1090};
1091
15637ed4 1092/* ARGSUSED */
4c45483e 1093int
15637ed4
RG
1094stat(p, uap, retval)
1095 struct proc *p;
3c7eb27c 1096 register struct stat_args *uap;
15637ed4
RG
1097 int *retval;
1098{
1099 register struct nameidata *ndp;
1100 struct stat sb;
1101 int error;
1102 struct nameidata nd;
1103
1104 ndp = &nd;
1105 ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
1106 ndp->ni_segflg = UIO_USERSPACE;
1107 ndp->ni_dirp = uap->fname;
1108 if (error = namei(ndp, p))
1109 return (error);
1110 error = vn_stat(ndp->ni_vp, &sb, p);
1111 vput(ndp->ni_vp);
1112 if (error)
1113 return (error);
1114 error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
1115 return (error);
1116}
1117
1118/*
1119 * Lstat system call.
1120 * This version does not follow links.
1121 */
3c7eb27c
DG
1122
1123struct lstat_args {
1124 char *fname;
1125 struct stat *ub;
1126};
1127
15637ed4 1128/* ARGSUSED */
4c45483e 1129int
15637ed4
RG
1130lstat(p, uap, retval)
1131 struct proc *p;
3c7eb27c 1132 register struct lstat_args *uap;
15637ed4
RG
1133 int *retval;
1134{
1135 register struct nameidata *ndp;
1136 struct stat sb;
1137 int error;
1138 struct nameidata nd;
1139
1140 ndp = &nd;
1141 ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW;
1142 ndp->ni_segflg = UIO_USERSPACE;
1143 ndp->ni_dirp = uap->fname;
1144 if (error = namei(ndp, p))
1145 return (error);
1146 error = vn_stat(ndp->ni_vp, &sb, p);
1147 vput(ndp->ni_vp);
1148 if (error)
1149 return (error);
1150 error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
1151 return (error);
1152}
1153
1154/*
1155 * Return target name of a symbolic link.
1156 */
3c7eb27c
DG
1157
1158struct readlink_args {
1159 char *name;
1160 char *buf;
1161 int count;
1162};
1163
15637ed4 1164/* ARGSUSED */
4c45483e 1165int
15637ed4
RG
1166readlink(p, uap, retval)
1167 struct proc *p;
3c7eb27c 1168 register struct readlink_args *uap;
15637ed4
RG
1169 int *retval;
1170{
1171 register struct nameidata *ndp;
1172 register struct vnode *vp;
1173 struct iovec aiov;
1174 struct uio auio;
1175 int error;
1176 struct nameidata nd;
1177
1178 ndp = &nd;
1179 ndp->ni_nameiop = LOOKUP | LOCKLEAF;
1180 ndp->ni_segflg = UIO_USERSPACE;
1181 ndp->ni_dirp = uap->name;
1182 if (error = namei(ndp, p))
1183 return (error);
1184 vp = ndp->ni_vp;
1185 if (vp->v_type != VLNK) {
1186 error = EINVAL;
1187 goto out;
1188 }
1189 aiov.iov_base = uap->buf;
1190 aiov.iov_len = uap->count;
1191 auio.uio_iov = &aiov;
1192 auio.uio_iovcnt = 1;
1193 auio.uio_offset = 0;
1194 auio.uio_rw = UIO_READ;
1195 auio.uio_segflg = UIO_USERSPACE;
1196 auio.uio_procp = p;
1197 auio.uio_resid = uap->count;
1198 error = VOP_READLINK(vp, &auio, p->p_ucred);
1199out:
1200 vput(vp);
1201 *retval = uap->count - auio.uio_resid;
1202 return (error);
1203}
1204
1205/*
1206 * Change flags of a file given path name.
1207 */
3c7eb27c
DG
1208
1209struct chflags_args {
1210 char *fname;
1211 int flags;
1212};
1213
15637ed4 1214/* ARGSUSED */
4c45483e 1215int
15637ed4
RG
1216chflags(p, uap, retval)
1217 struct proc *p;
3c7eb27c 1218 register struct chflags_args *uap;
15637ed4
RG
1219 int *retval;
1220{
1221 register struct nameidata *ndp;
1222 register struct vnode *vp;
1223 struct vattr vattr;
1224 int error;
1225 struct nameidata nd;
1226
1227 ndp = &nd;
1228 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
1229 ndp->ni_segflg = UIO_USERSPACE;
1230 ndp->ni_dirp = uap->fname;
1231 if (error = namei(ndp, p))
1232 return (error);
1233 vp = ndp->ni_vp;
1234 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
1235 error = EROFS;
1236 goto out;
1237 }
1238 VATTR_NULL(&vattr);
1239 vattr.va_flags = uap->flags;
1240 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1241out:
1242 vput(vp);
1243 return (error);
1244}
1245
1246/*
1247 * Change flags of a file given a file descriptor.
1248 */
3c7eb27c
DG
1249
1250struct fdchflags_args {
1251 int fd;
1252 int flags;
1253};
1254
15637ed4 1255/* ARGSUSED */
4c45483e 1256int
15637ed4
RG
1257fchflags(p, uap, retval)
1258 struct proc *p;
3c7eb27c 1259 register struct fdchflags_args *uap;
15637ed4
RG
1260 int *retval;
1261{
1262 struct vattr vattr;
1263 struct vnode *vp;
1264 struct file *fp;
1265 int error;
1266
1267 if (error = getvnode(p->p_fd, uap->fd, &fp))
1268 return (error);
1269 vp = (struct vnode *)fp->f_data;
1270 VOP_LOCK(vp);
1271 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
1272 error = EROFS;
1273 goto out;
1274 }
1275 VATTR_NULL(&vattr);
1276 vattr.va_flags = uap->flags;
1277 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1278out:
1279 VOP_UNLOCK(vp);
1280 return (error);
1281}
1282
1283/*
1284 * Change mode of a file given path name.
1285 */
3c7eb27c
DG
1286
1287struct chmod_args {
1288 char *fname;
1289 int fmode;
1290};
1291
15637ed4 1292/* ARGSUSED */
4c45483e 1293int
15637ed4
RG
1294chmod(p, uap, retval)
1295 struct proc *p;
3c7eb27c 1296 register struct chmod_args *uap;
15637ed4
RG
1297 int *retval;
1298{
1299 register struct nameidata *ndp;
1300 register struct vnode *vp;
1301 struct vattr vattr;
1302 int error;
1303 struct nameidata nd;
1304
1305 ndp = &nd;
1306 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
1307 ndp->ni_segflg = UIO_USERSPACE;
1308 ndp->ni_dirp = uap->fname;
1309 if (error = namei(ndp, p))
1310 return (error);
1311 vp = ndp->ni_vp;
1312 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
1313 error = EROFS;
1314 goto out;
1315 }
1316 VATTR_NULL(&vattr);
1317 vattr.va_mode = uap->fmode & 07777;
1318 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1319out:
1320 vput(vp);
1321 return (error);
1322}
1323
1324/*
1325 * Change mode of a file given a file descriptor.
1326 */
3c7eb27c
DG
1327
1328struct fchmod_args {
1329 int fd;
1330 int fmode;
1331};
1332
15637ed4 1333/* ARGSUSED */
4c45483e 1334int
15637ed4
RG
1335fchmod(p, uap, retval)
1336 struct proc *p;
3c7eb27c 1337 register struct fchmod_args *uap;
15637ed4
RG
1338 int *retval;
1339{
1340 struct vattr vattr;
1341 struct vnode *vp;
1342 struct file *fp;
1343 int error;
1344
1345 if (error = getvnode(p->p_fd, uap->fd, &fp))
1346 return (error);
1347 vp = (struct vnode *)fp->f_data;
1348 VOP_LOCK(vp);
1349 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
1350 error = EROFS;
1351 goto out;
1352 }
1353 VATTR_NULL(&vattr);
1354 vattr.va_mode = uap->fmode & 07777;
1355 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1356out:
1357 VOP_UNLOCK(vp);
1358 return (error);
1359}
1360
1361/*
1362 * Set ownership given a path name.
1363 */
3c7eb27c
DG
1364
1365struct chown_args {
1366 char *fname;
1367 int uid;
1368 int gid;
1369};
1370
15637ed4 1371/* ARGSUSED */
4c45483e 1372int
15637ed4
RG
1373chown(p, uap, retval)
1374 struct proc *p;
3c7eb27c 1375 register struct chown_args *uap;
15637ed4
RG
1376 int *retval;
1377{
1378 register struct nameidata *ndp;
1379 register struct vnode *vp;
1380 struct vattr vattr;
1381 int error;
1382 struct nameidata nd;
1383
1384 ndp = &nd;
1385 ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
1386 ndp->ni_segflg = UIO_USERSPACE;
1387 ndp->ni_dirp = uap->fname;
1388 if (error = namei(ndp, p))
1389 return (error);
1390 vp = ndp->ni_vp;
1391 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
1392 error = EROFS;
1393 goto out;
1394 }
1395 VATTR_NULL(&vattr);
1396 vattr.va_uid = uap->uid;
1397 vattr.va_gid = uap->gid;
1398 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1399out:
1400 vput(vp);
1401 return (error);
1402}
1403
1404/*
1405 * Set ownership given a file descriptor.
1406 */
3c7eb27c
DG
1407
1408struct fchown_args {
1409 int fd;
1410 int uid;
1411 int gid;
1412};
1413
15637ed4 1414/* ARGSUSED */
4c45483e 1415int
15637ed4
RG
1416fchown(p, uap, retval)
1417 struct proc *p;
3c7eb27c 1418 register struct fchown_args *uap;
15637ed4
RG
1419 int *retval;
1420{
1421 struct vattr vattr;
1422 struct vnode *vp;
1423 struct file *fp;
1424 int error;
1425
1426 if (error = getvnode(p->p_fd, uap->fd, &fp))
1427 return (error);
1428 vp = (struct vnode *)fp->f_data;
1429 VOP_LOCK(vp);
1430 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
1431 error = EROFS;
1432 goto out;
1433 }
1434 VATTR_NULL(&vattr);
1435 vattr.va_uid = uap->uid;
1436 vattr.va_gid = uap->gid;
1437 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1438out:
1439 VOP_UNLOCK(vp);
1440 return (error);
1441}
1442
1443/*
1444 * Set the access and modification times of a file.
1445 */
3c7eb27c
DG
1446
1447struct utimes_args {
1448 char *fname;
1449 struct timeval *tptr;
1450};
1451
15637ed4 1452/* ARGSUSED */
4c45483e 1453int
15637ed4
RG
1454utimes(p, uap, retval)
1455 struct proc *p;
3c7eb27c 1456 register struct utimes_args *uap;
15637ed4
RG
1457 int *retval;
1458{
1459 register struct nameidata *ndp;
1460 register struct vnode *vp;
1461 struct timeval tv[2];
1462 struct vattr vattr;
1463 int error;
1464 struct nameidata nd;
1465
e668648e 1466 VATTR_NULL(&vattr);
4b8139e5
GR
1467 if ((caddr_t)uap->tptr == NULL) {
1468 microtime(&tv[0]);
1469 tv[1] = tv[0];
e668648e
C
1470 vattr.va_vaflags |= VA_UTIMES_NULL;
1471 } else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
1472 return (error);
15637ed4
RG
1473 ndp = &nd;
1474 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
1475 ndp->ni_segflg = UIO_USERSPACE;
1476 ndp->ni_dirp = uap->fname;
1477 if (error = namei(ndp, p))
1478 return (error);
1479 vp = ndp->ni_vp;
1480 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
1481 error = EROFS;
1482 goto out;
1483 }
15637ed4
RG
1484 vattr.va_atime = tv[0];
1485 vattr.va_mtime = tv[1];
1486 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1487out:
1488 vput(vp);
1489 return (error);
1490}
1491
1492/*
1493 * Truncate a file given its path name.
1494 */
3c7eb27c
DG
1495
1496struct truncate_args {
1497 char *fname;
1498 off_t length;
1499};
1500
15637ed4 1501/* ARGSUSED */
4c45483e 1502int
15637ed4
RG
1503truncate(p, uap, retval)
1504 struct proc *p;
3c7eb27c 1505 register struct truncate_args *uap;
15637ed4
RG
1506 int *retval;
1507{
1508 register struct nameidata *ndp;
1509 register struct vnode *vp;
1510 struct vattr vattr;
1511 int error;
1512 struct nameidata nd;
1513
1514 ndp = &nd;
1515 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
1516 ndp->ni_segflg = UIO_USERSPACE;
1517 ndp->ni_dirp = uap->fname;
1518 if (error = namei(ndp, p))
1519 return (error);
1520 vp = ndp->ni_vp;
1521 if (vp->v_type == VDIR) {
1522 error = EISDIR;
1523 goto out;
1524 }
1525 if ((error = vn_writechk(vp)) ||
1526 (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)))
1527 goto out;
1528 VATTR_NULL(&vattr);
1529 vattr.va_size = uap->length;
1530 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1531out:
1532 vput(vp);
1533 return (error);
1534}
1535
1536/*
1537 * Truncate a file given a file descriptor.
1538 */
3c7eb27c
DG
1539
1540struct ftruncate_args {
1541 int fd;
1542 off_t length;
1543};
1544
15637ed4 1545/* ARGSUSED */
4c45483e 1546int
15637ed4
RG
1547ftruncate(p, uap, retval)
1548 struct proc *p;
3c7eb27c 1549 register struct ftruncate_args *uap;
15637ed4
RG
1550 int *retval;
1551{
1552 struct vattr vattr;
1553 struct vnode *vp;
1554 struct file *fp;
1555 int error;
1556
1557 if (error = getvnode(p->p_fd, uap->fd, &fp))
1558 return (error);
1559 if ((fp->f_flag & FWRITE) == 0)
1560 return (EINVAL);
1561 vp = (struct vnode *)fp->f_data;
1562 VOP_LOCK(vp);
1563 if (vp->v_type == VDIR) {
1564 error = EISDIR;
1565 goto out;
1566 }
1567 if (error = vn_writechk(vp))
1568 goto out;
1569 VATTR_NULL(&vattr);
1570 vattr.va_size = uap->length;
1571 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
1572out:
1573 VOP_UNLOCK(vp);
1574 return (error);
1575}
1576
1577/*
1578 * Synch an open file.
1579 */
3c7eb27c
DG
1580
1581struct fsync_args {
1582 int fd;
1583};
1584
15637ed4 1585/* ARGSUSED */
4c45483e 1586int
15637ed4
RG
1587fsync(p, uap, retval)
1588 struct proc *p;
3c7eb27c 1589 struct fsync_args *uap;
15637ed4
RG
1590 int *retval;
1591{
1592 register struct vnode *vp;
1593 struct file *fp;
1594 int error;
1595
1596 if (error = getvnode(p->p_fd, uap->fd, &fp))
1597 return (error);
1598 vp = (struct vnode *)fp->f_data;
1599 VOP_LOCK(vp);
1600 error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT, p);
1601 VOP_UNLOCK(vp);
1602 return (error);
1603}
1604
1605/*
1606 * Rename system call.
1607 *
1608 * Source and destination must either both be directories, or both
1609 * not be directories. If target is a directory, it must be empty.
1610 */
3c7eb27c
DG
1611
1612struct rename_args {
1613 char *from;
1614 char *to;
1615};
1616
15637ed4 1617/* ARGSUSED */
4c45483e 1618int
15637ed4
RG
1619rename(p, uap, retval)
1620 struct proc *p;
3c7eb27c 1621 register struct rename_args *uap;
15637ed4
RG
1622 int *retval;
1623{
1624 register struct vnode *tvp, *fvp, *tdvp;
1625 struct nameidata fromnd, tond;
1626 int error;
1627
1628 fromnd.ni_nameiop = DELETE | WANTPARENT | SAVESTART;
1629 fromnd.ni_segflg = UIO_USERSPACE;
1630 fromnd.ni_dirp = uap->from;
1631 if (error = namei(&fromnd, p))
1632 return (error);
1633 fvp = fromnd.ni_vp;
1634 tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
1635 tond.ni_segflg = UIO_USERSPACE;
1636 tond.ni_dirp = uap->to;
1637 if (error = namei(&tond, p)) {
1638 VOP_ABORTOP(&fromnd);
1639 vrele(fromnd.ni_dvp);
1640 vrele(fvp);
1641 goto out1;
1642 }
1643 tdvp = tond.ni_dvp;
1644 tvp = tond.ni_vp;
1645 if (tvp != NULL) {
1646 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
1647 error = ENOTDIR;
1648 goto out;
1649 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
1650 error = EISDIR;
1651 goto out;
1652 }
1653 if (fvp->v_mount != tvp->v_mount) {
1654 error = EXDEV;
1655 goto out;
1656 }
1657 }
1658 if (fvp->v_mount != tdvp->v_mount) {
1659 error = EXDEV;
1660 goto out;
1661 }
1662 if (fvp == tdvp)
1663 error = EINVAL;
1664 /*
1665 * If source is the same as the destination (that is the
1666 * same inode number with the same name in the same directory),
1667 * then there is nothing to do.
1668 */
1669 if (fvp == tvp && fromnd.ni_dvp == tdvp &&
1670 fromnd.ni_namelen == tond.ni_namelen &&
1671 !bcmp(fromnd.ni_ptr, tond.ni_ptr, fromnd.ni_namelen))
1672 error = -1;
1673out:
1674 if (!error) {
1675 error = VOP_RENAME(&fromnd, &tond, p);
1676 } else {
1677 VOP_ABORTOP(&tond);
1678 if (tdvp == tvp)
1679 vrele(tdvp);
1680 else
1681 vput(tdvp);
1682 if (tvp)
1683 vput(tvp);
1684 VOP_ABORTOP(&fromnd);
1685 vrele(fromnd.ni_dvp);
1686 vrele(fvp);
1687 }
1688 vrele(tond.ni_startdir);
1689 FREE(tond.ni_pnbuf, M_NAMEI);
1690out1:
b43a13ed
DG
1691 if (fromnd.ni_startdir)
1692 vrele(fromnd.ni_startdir);
15637ed4
RG
1693 FREE(fromnd.ni_pnbuf, M_NAMEI);
1694 if (error == -1)
1695 return (0);
1696 return (error);
1697}
1698
1699/*
1700 * Mkdir system call.
1701 */
3c7eb27c
DG
1702
1703struct mkdir_args {
1704 char *name;
1705 int dmode;
1706};
1707
15637ed4 1708/* ARGSUSED */
4c45483e 1709int
15637ed4
RG
1710mkdir(p, uap, retval)
1711 struct proc *p;
3c7eb27c 1712 register struct mkdir_args *uap;
15637ed4
RG
1713 int *retval;
1714{
1715 register struct nameidata *ndp;
1716 register struct vnode *vp;
1717 struct vattr vattr;
1718 int error;
1719 struct nameidata nd;
1720
1721 ndp = &nd;
1722 ndp->ni_nameiop = CREATE | LOCKPARENT;
1723 ndp->ni_segflg = UIO_USERSPACE;
1724 ndp->ni_dirp = uap->name;
1725 if (error = namei(ndp, p))
1726 return (error);
1727 vp = ndp->ni_vp;
1728 if (vp != NULL) {
1729 VOP_ABORTOP(ndp);
1730 if (ndp->ni_dvp == vp)
1731 vrele(ndp->ni_dvp);
1732 else
1733 vput(ndp->ni_dvp);
1734 vrele(vp);
1735 return (EEXIST);
1736 }
1737 VATTR_NULL(&vattr);
1738 vattr.va_type = VDIR;
1739 vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask;
1740 error = VOP_MKDIR(ndp, &vattr, p);
1741 if (!error)
1742 vput(ndp->ni_vp);
1743 return (error);
1744}
1745
1746/*
1747 * Rmdir system call.
1748 */
3c7eb27c
DG
1749
1750struct rmdir_args {
1751 char *name;
1752};
1753
15637ed4 1754/* ARGSUSED */
4c45483e 1755int
15637ed4
RG
1756rmdir(p, uap, retval)
1757 struct proc *p;
3c7eb27c 1758 struct rmdir_args *uap;
15637ed4
RG
1759 int *retval;
1760{
1761 register struct nameidata *ndp;
1762 register struct vnode *vp;
1763 int error;
1764 struct nameidata nd;
1765
1766 ndp = &nd;
1767 ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
1768 ndp->ni_segflg = UIO_USERSPACE;
1769 ndp->ni_dirp = uap->name;
1770 if (error = namei(ndp, p))
1771 return (error);
1772 vp = ndp->ni_vp;
1773 if (vp->v_type != VDIR) {
1774 error = ENOTDIR;
1775 goto out;
1776 }
1777 /*
1778 * No rmdir "." please.
1779 */
1780 if (ndp->ni_dvp == vp) {
1781 error = EINVAL;
1782 goto out;
1783 }
1784 /*
1785 * The root of a mounted filesystem cannot be deleted.
1786 */
1787 if (vp->v_flag & VROOT)
1788 error = EBUSY;
1789out:
1790 if (!error) {
1791 error = VOP_RMDIR(ndp, p);
1792 } else {
1793 VOP_ABORTOP(ndp);
1794 if (ndp->ni_dvp == vp)
1795 vrele(ndp->ni_dvp);
1796 else
1797 vput(ndp->ni_dvp);
1798 vput(vp);
1799 }
1800 return (error);
1801}
1802
1803/*
1804 * Read a block of directory entries in a file system independent format.
1805 */
3c7eb27c
DG
1806
1807struct getdirentries_args {
1808 int fd;
1809 char *buf;
1810 unsigned count;
1811 long *basep;
1812};
1813
4c45483e 1814int
15637ed4
RG
1815getdirentries(p, uap, retval)
1816 struct proc *p;
3c7eb27c 1817 register struct getdirentries_args *uap;
15637ed4
RG
1818 int *retval;
1819{
1820 register struct vnode *vp;
1821 struct file *fp;
1822 struct uio auio;
1823 struct iovec aiov;
1824 off_t off;
1825 int error, eofflag;
1826
1827 if (error = getvnode(p->p_fd, uap->fd, &fp))
1828 return (error);
1829 if ((fp->f_flag & FREAD) == 0)
1830 return (EBADF);
1831 vp = (struct vnode *)fp->f_data;
1832 if (vp->v_type != VDIR)
1833 return (EINVAL);
1834 aiov.iov_base = uap->buf;
1835 aiov.iov_len = uap->count;
1836 auio.uio_iov = &aiov;
1837 auio.uio_iovcnt = 1;
1838 auio.uio_rw = UIO_READ;
1839 auio.uio_segflg = UIO_USERSPACE;
1840 auio.uio_procp = p;
1841 auio.uio_resid = uap->count;
1842 VOP_LOCK(vp);
1843 auio.uio_offset = off = fp->f_offset;
1844 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag);
1845 fp->f_offset = auio.uio_offset;
1846 VOP_UNLOCK(vp);
1847 if (error)
1848 return (error);
1849 error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
1850 *retval = uap->count - auio.uio_resid;
1851 return (error);
1852}
1853
1854/*
1855 * Set the mode mask for creation of filesystem nodes.
1856 */
3c7eb27c
DG
1857
1858struct umask_args {
1859 int mask;
1860};
1861
15637ed4
RG
1862mode_t
1863umask(p, uap, retval)
1864 struct proc *p;
3c7eb27c 1865 struct umask_args *uap;
15637ed4
RG
1866 int *retval;
1867{
1868 register struct filedesc *fdp = p->p_fd;
1869
1870 *retval = fdp->fd_cmask;
1871 fdp->fd_cmask = uap->mask & 07777;
1872 return (0);
1873}
1874
1875/*
1876 * Void all references to file by ripping underlying filesystem
1877 * away from vnode.
1878 */
3c7eb27c
DG
1879
1880struct revoke_args {
1881 char *fname;
1882};
1883
15637ed4 1884/* ARGSUSED */
4c45483e 1885int
15637ed4
RG
1886revoke(p, uap, retval)
1887 struct proc *p;
3c7eb27c 1888 register struct revoke_args *uap;
15637ed4
RG
1889 int *retval;
1890{
1891 register struct nameidata *ndp;
1892 register struct vnode *vp;
1893 struct vattr vattr;
1894 int error;
1895 struct nameidata nd;
1896
1897 ndp = &nd;
1898 ndp->ni_nameiop = LOOKUP | FOLLOW;
1899 ndp->ni_segflg = UIO_USERSPACE;
1900 ndp->ni_dirp = uap->fname;
1901 if (error = namei(ndp, p))
1902 return (error);
1903 vp = ndp->ni_vp;
1904 if (vp->v_type != VCHR && vp->v_type != VBLK) {
1905 error = EINVAL;
1906 goto out;
1907 }
1908 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
1909 goto out;
1910 if (p->p_ucred->cr_uid != vattr.va_uid &&
1911 (error = suser(p->p_ucred, &p->p_acflag)))
1912 goto out;
1913 if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
1914 vgoneall(vp);
1915out:
1916 vrele(vp);
1917 return (error);
1918}
1919
1920/*
1921 * Convert a user file descriptor to a kernel file entry.
1922 */
fde1aeb2 1923static int
15637ed4
RG
1924getvnode(fdp, fdes, fpp)
1925 struct filedesc *fdp;
15637ed4 1926 int fdes;
fde1aeb2 1927 struct file **fpp;
15637ed4
RG
1928{
1929 struct file *fp;
1930
1931 if ((unsigned)fdes >= fdp->fd_nfiles ||
1932 (fp = fdp->fd_ofiles[fdes]) == NULL)
1933 return (EBADF);
1934 if (fp->f_type != DTYPE_VNODE)
1935 return (EINVAL);
1936 *fpp = fp;
1937 return (0);
1938}