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