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