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