Deleted Added
full compact
1/*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)vfs_syscalls.c 8.13 (Berkeley) 4/15/94
39 * $FreeBSD: head/sys/kern/vfs_syscalls.c 22578 1997-02-12 06:46:11Z mpp $
39 * $FreeBSD: head/sys/kern/vfs_syscalls.c 22582 1997-02-12 07:54:22Z mpp $
40 */
41
42/*
43 * XXX - The following is required because of some magic done
44 * in getdirentries() below which is only done if the translucent
45 * filesystem `UNION' is compiled into the kernel. This is broken,
46 * but I don't have time to study the code deeply enough to understand
47 * what's going on and determine an appropriate fix. -GAW
48 */
49#include "opt_union.h"
50
51#include <sys/param.h>
52#include <sys/systm.h>
53#include <sys/sysent.h>
54#include <sys/sysproto.h>
55#include <sys/namei.h>
56#include <sys/filedesc.h>
57#include <sys/kernel.h>
58#include <sys/file.h>
59#include <sys/stat.h>
60#include <sys/unistd.h>
61#include <sys/vnode.h>
62#include <sys/mount.h>
63#include <sys/proc.h>
64#include <sys/uio.h>
65#include <sys/malloc.h>
66#include <sys/dirent.h>
67
68/* see if this is needed XXX JH
68#ifdef UNION
69#include <miscfs/union/union.h>
70#endif
72*/
71
72#include <vm/vm.h>
73#include <vm/vm_param.h>
74#include <vm/vm_object.h>
75#include <vm/vm_extern.h>
76#include <sys/sysctl.h>
77
78static int change_dir __P((struct nameidata *ndp, struct proc *p));
79static void checkdirs __P((struct vnode *olddp));
80
81/*
82 * Virtual File System System Calls
83 */
84
85/*
86 * Mount a file system.
87 */
88#ifndef _SYS_SYSPROTO_H_
89struct mount_args {
90 char *type;
91 char *path;
92 int flags;
93 caddr_t data;
94};
95#endif
96/* ARGSUSED */
97int
98mount(p, uap, retval)
99 struct proc *p;
100 register struct mount_args /* {
101 syscallarg(char *) type;
102 syscallarg(char *) path;
103 syscallarg(int) flags;
104 syscallarg(caddr_t) data;
105 } */ *uap;
106 register_t *retval;
107{
108 struct vnode *vp;
109 struct mount *mp;
110 struct vfsconf *vfsp;
111 int error, flag = 0;
112 struct vattr va;
113 u_long fstypenum;
114 struct nameidata nd;
115 char fstypename[MFSNAMELEN];
116
117 /*
118 * Get vnode to be covered
119 */
120 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
121 SCARG(uap, path), p);
122 if (error = namei(&nd))
123 return (error);
124 vp = nd.ni_vp;
125 if (SCARG(uap, flags) & MNT_UPDATE) {
126 if ((vp->v_flag & VROOT) == 0) {
127 vput(vp);
128 return (EINVAL);
129 }
130 mp = vp->v_mount;
131 flag = mp->mnt_flag;
132 /*
133 * We only allow the filesystem to be reloaded if it
134 * is currently mounted read-only.
135 */
136 if ((SCARG(uap, flags) & MNT_RELOAD) &&
137 ((mp->mnt_flag & MNT_RDONLY) == 0)) {
138 vput(vp);
139 return (EOPNOTSUPP); /* Needs translation */
140 }
141 mp->mnt_flag |=
142 SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
143 /*
144 * Only root, or the user that did the original mount is
145 * permitted to update it.
146 */
147 if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid &&
148 (error = suser(p->p_ucred, &p->p_acflag))) {
149 vput(vp);
150 return (error);
151 }
152 /*
153 * Do not allow NFS export by non-root users. Silently
154 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
155 */
156 if (p->p_ucred->cr_uid != 0) {
157 if (SCARG(uap, flags) & MNT_EXPORTED) {
158 vput(vp);
159 return (EPERM);
160 }
161 SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
162 }
163 if (vfs_busy(mp, LK_NOWAIT, 0, p)) {
164 vput(vp);
165 return (EBUSY);
166 }
167 VOP_UNLOCK(vp, 0, p);
168 goto update;
169 }
170 /*
171 * If the user is not root, ensure that they own the directory
172 * onto which we are attempting to mount.
173 */
174 if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) ||
175 (va.va_uid != p->p_ucred->cr_uid &&
176 (error = suser(p->p_ucred, &p->p_acflag)))) {
177 vput(vp);
178 return (error);
179 }
180 /*
181 * Do not allow NFS export by non-root users. Silently
182 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
183 */
184 if (p->p_ucred->cr_uid != 0) {
185 if (SCARG(uap, flags) & MNT_EXPORTED) {
186 vput(vp);
187 return (EPERM);
188 }
189 SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
190 }
191 if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0))
192 return (error);
193 if (vp->v_type != VDIR) {
194 vput(vp);
195 return (ENOTDIR);
196 }
197#ifdef COMPAT_43
198 /*
199 * Historically filesystem types were identified by number. If we
200 * get an integer for the filesystem type instead of a string, we
201 * check to see if it matches one of the historic filesystem types.
202 */
203 fstypenum = (u_long)SCARG(uap, type);
204 if (fstypenum < maxvfsconf) {
205 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
206 if (vfsp->vfc_typenum == fstypenum)
207 break;
208 if (vfsp == NULL) {
209 vput(vp);
210 return (ENODEV);
211 }
212 strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN);
213 } else
214#endif /* COMPAT_43 */
215 if (error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL)) {
216 vput(vp);
217 return (error);
218 }
219 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
220 if (!strcmp(vfsp->vfc_name, fstypename))
221 break;
222 if (vfsp == NULL) {
223 vput(vp);
224 return (ENODEV);
225 }
226 if (vp->v_mountedhere != NULL) {
227 vput(vp);
228 return (EBUSY);
229 }
230
231 /*
232 * Allocate and initialize the filesystem.
233 */
234 mp = (struct mount *)malloc((u_long)sizeof(struct mount),
235 M_MOUNT, M_WAITOK);
236 bzero((char *)mp, (u_long)sizeof(struct mount));
237 lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0);
238 (void)vfs_busy(mp, LK_NOWAIT, 0, p);
239 mp->mnt_op = vfsp->vfc_vfsops;
240 mp->mnt_vfc = vfsp;
241 vfsp->vfc_refcount++;
242 mp->mnt_stat.f_type = vfsp->vfc_typenum;
243 mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
244 strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
245 vp->v_mountedhere = mp;
246 mp->mnt_vnodecovered = vp;
247 mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
248update:
249 /*
250 * Set the mount level flags.
251 */
252 if (SCARG(uap, flags) & MNT_RDONLY)
253 mp->mnt_flag |= MNT_RDONLY;
254 else if (mp->mnt_flag & MNT_RDONLY)
255 mp->mnt_flag |= MNT_WANTRDWR;
256 mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
257 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOATIME);
258 mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC |
259 MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_FORCE |
260 MNT_NOATIME);
261 /*
262 * Mount the filesystem.
263 */
264 error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p);
265 if (mp->mnt_flag & MNT_UPDATE) {
266 vrele(vp);
267 if (mp->mnt_flag & MNT_WANTRDWR)
268 mp->mnt_flag &= ~MNT_RDONLY;
269 mp->mnt_flag &=~
270 (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR);
271 if (error)
272 mp->mnt_flag = flag;
273 vfs_unbusy(mp, p);
274 return (error);
275 }
276 /*
277 * Put the new filesystem on the mount list after root.
278 */
279 cache_purge(vp);
280 if (!error) {
281 simple_lock(&mountlist_slock);
282 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
283 simple_unlock(&mountlist_slock);
284 checkdirs(vp);
285 VOP_UNLOCK(vp, 0, p);
286 vfs_unbusy(mp, p);
287 if (error = VFS_START(mp, 0, p))
288 vrele(vp);
289 } else {
290 mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
291 mp->mnt_vfc->vfc_refcount--;
292 vfs_unbusy(mp, p);
293 free((caddr_t)mp, M_MOUNT);
294 vput(vp);
295 }
296 return (error);
297}
298
299/*
300 * Scan all active processes to see if any of them have a current
301 * or root directory onto which the new filesystem has just been
302 * mounted. If so, replace them with the new mount point.
303 */
304static void
305checkdirs(olddp)
306 struct vnode *olddp;
307{
308 struct filedesc *fdp;
309 struct vnode *newdp;
310 struct proc *p;
311
312 if (olddp->v_usecount == 1)
313 return;
314 if (VFS_ROOT(olddp->v_mountedhere, &newdp))
315 panic("mount: lost mount");
316 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
317 fdp = p->p_fd;
318 if (fdp->fd_cdir == olddp) {
319 vrele(fdp->fd_cdir);
320 VREF(newdp);
321 fdp->fd_cdir = newdp;
322 }
323 if (fdp->fd_rdir == olddp) {
324 vrele(fdp->fd_rdir);
325 VREF(newdp);
326 fdp->fd_rdir = newdp;
327 }
328 }
329 if (rootvnode == olddp) {
330 vrele(rootvnode);
331 VREF(newdp);
332 rootvnode = newdp;
333 }
334 vput(newdp);
335}
336
337/*
338 * Unmount a file system.
339 *
340 * Note: unmount takes a path to the vnode mounted on as argument,
341 * not special file (as before).
342 */
343#ifndef _SYS_SYSPROTO_H_
344struct unmount_args {
345 char *path;
346 int flags;
347};
348#endif
349/* ARGSUSED */
350int
351unmount(p, uap, retval)
352 struct proc *p;
353 register struct unmount_args /* {
354 syscallarg(char *) path;
355 syscallarg(int) flags;
356 } */ *uap;
357 register_t *retval;
358{
359 register struct vnode *vp;
360 struct mount *mp;
361 int error;
362 struct nameidata nd;
363
364 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
365 SCARG(uap, path), p);
366 if (error = namei(&nd))
367 return (error);
368 vp = nd.ni_vp;
369 mp = vp->v_mount;
370
371 /*
372 * Only root, or the user that did the original mount is
373 * permitted to unmount this filesystem.
374 */
375 if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) &&
376 (error = suser(p->p_ucred, &p->p_acflag))) {
377 vput(vp);
378 return (error);
379 }
380
381 /*
382 * Don't allow unmounting the root file system.
383 */
384 if (mp->mnt_flag & MNT_ROOTFS) {
385 vput(vp);
386 return (EINVAL);
387 }
388
389 /*
390 * Must be the root of the filesystem
391 */
392 if ((vp->v_flag & VROOT) == 0) {
393 vput(vp);
394 return (EINVAL);
395 }
396 vput(vp);
397 return (dounmount(mp, SCARG(uap, flags), p));
398}
399
400/*
401 * Do the actual file system unmount.
402 */
403int
404dounmount(mp, flags, p)
405 register struct mount *mp;
406 int flags;
407 struct proc *p;
408{
409 struct vnode *coveredvp;
410 int error;
411
412 simple_lock(&mountlist_slock);
413 mp->mnt_flag |= MNT_UNMOUNT;
414 lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_slock, p);
415 mp->mnt_flag &=~ MNT_ASYNC;
416 vfs_msync(mp, MNT_NOWAIT);
417 vnode_pager_umount(mp); /* release cached vnodes */
418 cache_purgevfs(mp); /* remove cache entries for this file sys */
419 if (((mp->mnt_flag & MNT_RDONLY) ||
420 (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) ||
421 (flags & MNT_FORCE))
422 error = VFS_UNMOUNT(mp, flags, p);
423 simple_lock(&mountlist_slock);
424 if (error) {
425 mp->mnt_flag &= ~MNT_UNMOUNT;
426 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK | LK_REENABLE,
427 &mountlist_slock, p);
428 return (error);
429 }
430 CIRCLEQ_REMOVE(&mountlist, mp, mnt_list);
431 if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) {
432 coveredvp->v_mountedhere = (struct mount *)0;
433 vrele(coveredvp);
434 }
435 mp->mnt_vfc->vfc_refcount--;
436 if (mp->mnt_vnodelist.lh_first != NULL)
437 panic("unmount: dangling vnode");
438 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock, p);
439 if (mp->mnt_flag & MNT_MWAIT)
440 wakeup((caddr_t)mp);
441 free((caddr_t)mp, M_MOUNT);
442 return (0);
443}
444
445/*
446 * Sync each mounted filesystem.
447 */
448#ifndef _SYS_SYSPROTO_H_
449struct sync_args {
450 int dummy;
451};
452#endif
453
454#ifdef DEBUG
455int syncprt = 0;
456SYSCTL_INT(_debug, 0, syncprt, CTLFLAG_RW, &syncprt, 0, "");
457#endif
458
459/* ARGSUSED */
460int
461sync(p, uap, retval)
462 struct proc *p;
463 struct sync_args *uap;
464 register_t *retval;
465{
466 register struct mount *mp, *nmp;
467 int asyncflag;
468
469 simple_lock(&mountlist_slock);
470 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
471 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
472 nmp = mp->mnt_list.cqe_next;
473 continue;
474 }
475 if ((mp->mnt_flag & MNT_RDONLY) == 0) {
476 asyncflag = mp->mnt_flag & MNT_ASYNC;
477 mp->mnt_flag &= ~MNT_ASYNC;
478 vfs_msync(mp, MNT_NOWAIT);
479 VFS_SYNC(mp, MNT_NOWAIT, p != NULL ? p->p_ucred : NOCRED, p);
480 if (asyncflag)
481 mp->mnt_flag |= MNT_ASYNC;
482 }
483 simple_lock(&mountlist_slock);
484 nmp = mp->mnt_list.cqe_next;
485 vfs_unbusy(mp, p);
486 }
487 simple_unlock(&mountlist_slock);
488#if 0
489/*
490 * XXX don't call vfs_bufstats() yet because that routine
491 * was not imported in the Lite2 merge.
492 */
493#ifdef DIAGNOSTIC
494 if (syncprt)
495 vfs_bufstats();
496#endif /* DIAGNOSTIC */
497#endif
498 return (0);
499}
500
501/*
502 * Change filesystem quotas.
503 */
504#ifndef _SYS_SYSPROTO_H_
505struct quotactl_args {
506 char *path;
507 int cmd;
508 int uid;
509 caddr_t arg;
510};
511#endif
512/* ARGSUSED */
513int
514quotactl(p, uap, retval)
515 struct proc *p;
516 register struct quotactl_args /* {
517 syscallarg(char *) path;
518 syscallarg(int) cmd;
519 syscallarg(int) uid;
520 syscallarg(caddr_t) arg;
521 } */ *uap;
522 register_t *retval;
523{
524 register struct mount *mp;
525 int error;
526 struct nameidata nd;
527
528 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
529 if (error = namei(&nd))
530 return (error);
531 mp = nd.ni_vp->v_mount;
532 vrele(nd.ni_vp);
533 return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
534 SCARG(uap, arg), p));
535}
536
537/*
538 * Get filesystem statistics.
539 */
540#ifndef _SYS_SYSPROTO_H_
541struct statfs_args {
542 char *path;
543 struct statfs *buf;
544};
545#endif
546/* ARGSUSED */
547int
548statfs(p, uap, retval)
549 struct proc *p;
550 register struct statfs_args /* {
551 syscallarg(char *) path;
552 syscallarg(struct statfs *) buf;
553 } */ *uap;
554 register_t *retval;
555{
556 register struct mount *mp;
557 register struct statfs *sp;
558 int error;
559 struct nameidata nd;
560
561 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
562 if (error = namei(&nd))
563 return (error);
564 mp = nd.ni_vp->v_mount;
565 sp = &mp->mnt_stat;
566 vrele(nd.ni_vp);
567 error = VFS_STATFS(mp, sp, p);
568 if (error)
569 return (error);
570 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
571 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
572}
573
574/*
575 * Get filesystem statistics.
576 */
577#ifndef _SYS_SYSPROTO_H_
578struct fstatfs_args {
579 int fd;
580 struct statfs *buf;
581};
582#endif
583/* ARGSUSED */
584int
585fstatfs(p, uap, retval)
586 struct proc *p;
587 register struct fstatfs_args /* {
588 syscallarg(int) fd;
589 syscallarg(struct statfs *) buf;
590 } */ *uap;
591 register_t *retval;
592{
593 struct file *fp;
594 struct mount *mp;
595 register struct statfs *sp;
596 int error;
597
598 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
599 return (error);
600 mp = ((struct vnode *)fp->f_data)->v_mount;
601 sp = &mp->mnt_stat;
602 error = VFS_STATFS(mp, sp, p);
603 if (error)
604 return (error);
605 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
606 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
607}
608
609/*
610 * Get statistics on all filesystems.
611 */
612#ifndef _SYS_SYSPROTO_H_
613struct getfsstat_args {
614 struct statfs *buf;
615 long bufsize;
616 int flags;
617};
618#endif
619int
620getfsstat(p, uap, retval)
621 struct proc *p;
622 register struct getfsstat_args /* {
623 syscallarg(struct statfs *) buf;
624 syscallarg(long) bufsize;
625 syscallarg(int) flags;
626 } */ *uap;
627 register_t *retval;
628{
629 register struct mount *mp, *nmp;
630 register struct statfs *sp;
631 caddr_t sfsp;
632 long count, maxcount, error;
633
634 maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
635 sfsp = (caddr_t)SCARG(uap, buf);
636 count = 0;
637 simple_lock(&mountlist_slock);
638 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
639 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
640 nmp = mp->mnt_list.cqe_next;
641 continue;
642 }
643 if (sfsp && count < maxcount) {
644 sp = &mp->mnt_stat;
645 /*
646 * If MNT_NOWAIT is specified, do not refresh the
647 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
648 */
649 if (((SCARG(uap, flags) & MNT_NOWAIT) == 0 ||
650 (SCARG(uap, flags) & MNT_WAIT)) &&
651 (error = VFS_STATFS(mp, sp, p))) {
652 simple_lock(&mountlist_slock);
653 nmp = mp->mnt_list.cqe_next;
654 vfs_unbusy(mp, p);
655 continue;
656 }
657 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
658 error = copyout((caddr_t)sp, sfsp, sizeof(*sp));
659 if (error) {
660 vfs_unbusy(mp, p);
661 return (error);
662 }
663 sfsp += sizeof(*sp);
664 }
665 count++;
666 simple_lock(&mountlist_slock);
667 nmp = mp->mnt_list.cqe_next;
668 vfs_unbusy(mp, p);
669 }
670 simple_unlock(&mountlist_slock);
671 if (sfsp && count > maxcount)
672 *retval = maxcount;
673 else
674 *retval = count;
675 return (0);
676}
677
678/*
679 * Change current working directory to a given file descriptor.
680 */
681#ifndef _SYS_SYSPROTO_H_
682struct fchdir_args {
683 int fd;
684};
685#endif
686/* ARGSUSED */
687int
688fchdir(p, uap, retval)
689 struct proc *p;
690 struct fchdir_args /* {
691 syscallarg(int) fd;
692 } */ *uap;
693 register_t *retval;
694{
695 register struct filedesc *fdp = p->p_fd;
696 struct vnode *vp, *tdp;
697 struct mount *mp;
698 struct file *fp;
699 int error;
700
701 if (error = getvnode(fdp, SCARG(uap, fd), &fp))
702 return (error);
703 vp = (struct vnode *)fp->f_data;
704 VREF(vp);
705 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
706 if (vp->v_type != VDIR)
707 error = ENOTDIR;
708 else
709 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
710 while (!error && (mp = vp->v_mountedhere) != NULL) {
711 if (vfs_busy(mp, 0, 0, p))
712 continue;
713 error = VFS_ROOT(mp, &tdp);
714 vfs_unbusy(mp, p);
715 if (error)
716 break;
717 vput(vp);
718 vp = tdp;
719 }
720 if (error) {
721 vput(vp);
722 return (error);
723 }
724 VOP_UNLOCK(vp, 0, p);
725 vrele(fdp->fd_cdir);
726 fdp->fd_cdir = vp;
727 return (0);
728}
729
730/*
731 * Change current working directory (``.'').
732 */
733#ifndef _SYS_SYSPROTO_H_
734struct chdir_args {
735 char *path;
736};
737#endif
738/* ARGSUSED */
739int
740chdir(p, uap, retval)
741 struct proc *p;
742 struct chdir_args /* {
743 syscallarg(char *) path;
744 } */ *uap;
745 register_t *retval;
746{
747 register struct filedesc *fdp = p->p_fd;
748 int error;
749 struct nameidata nd;
750
751 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
752 SCARG(uap, path), p);
753 if (error = change_dir(&nd, p))
754 return (error);
755 vrele(fdp->fd_cdir);
756 fdp->fd_cdir = nd.ni_vp;
757 return (0);
758}
759
760/*
761 * Change notion of root (``/'') directory.
762 */
763#ifndef _SYS_SYSPROTO_H_
764struct chroot_args {
765 char *path;
766};
767#endif
768/* ARGSUSED */
769int
770chroot(p, uap, retval)
771 struct proc *p;
772 struct chroot_args /* {
773 syscallarg(char *) path;
774 } */ *uap;
775 register_t *retval;
776{
777 register struct filedesc *fdp = p->p_fd;
778 int error;
779 struct nameidata nd;
780
781 error = suser(p->p_ucred, &p->p_acflag);
782 if (error)
783 return (error);
784 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
785 SCARG(uap, path), p);
786 if (error = change_dir(&nd, p))
787 return (error);
788 if (fdp->fd_rdir != NULL)
789 vrele(fdp->fd_rdir);
790 fdp->fd_rdir = nd.ni_vp;
791 return (0);
792}
793
794/*
795 * Common routine for chroot and chdir.
796 */
797static int
798change_dir(ndp, p)
799 register struct nameidata *ndp;
800 struct proc *p;
801{
802 struct vnode *vp;
803 int error;
804
805 error = namei(ndp);
806 if (error)
807 return (error);
808 vp = ndp->ni_vp;
809 if (vp->v_type != VDIR)
810 error = ENOTDIR;
811 else
812 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
813 if (error)
814 vput(vp);
815 else
816 VOP_UNLOCK(vp, 0, p);
817 return (error);
818}
819
820/*
821 * Check permissions, allocate an open file structure,
822 * and call the device open routine if any.
823 */
824#ifndef _SYS_SYSPROTO_H_
825struct open_args {
826 char *path;
827 int flags;
828 int mode;
829};
830#endif
831int
832open(p, uap, retval)
833 struct proc *p;
834 register struct open_args /* {
835 syscallarg(char *) path;
836 syscallarg(int) flags;
837 syscallarg(int) mode;
838 } */ *uap;
839 register_t *retval;
840{
841 register struct filedesc *fdp = p->p_fd;
842 register struct file *fp;
843 register struct vnode *vp;
844 int flags, cmode;
845 struct file *nfp;
846 int type, indx, error;
847 struct flock lf;
848 struct nameidata nd;
849
850 error = falloc(p, &nfp, &indx);
851 if (error)
852 return (error);
853 fp = nfp;
854 flags = FFLAGS(SCARG(uap, flags));
855 cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
856 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
857 p->p_dupfd = -indx - 1; /* XXX check for fdopen */
858 error = vn_open(&nd, flags, cmode);
859 if (error) {
860 ffree(fp);
861 if ((error == ENODEV || error == ENXIO) &&
862 p->p_dupfd >= 0 && /* XXX from fdopen */
863 (error =
864 dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
865 *retval = indx;
866 return (0);
867 }
868 if (error == ERESTART)
869 error = EINTR;
870 fdp->fd_ofiles[indx] = NULL;
871 return (error);
872 }
873 p->p_dupfd = 0;
874 vp = nd.ni_vp;
875
876 fp->f_flag = flags & FMASK;
877 fp->f_type = (vp->v_type == VFIFO ? DTYPE_FIFO : DTYPE_VNODE);
878 fp->f_ops = &vnops;
879 fp->f_data = (caddr_t)vp;
880 if (flags & (O_EXLOCK | O_SHLOCK)) {
881 lf.l_whence = SEEK_SET;
882 lf.l_start = 0;
883 lf.l_len = 0;
884 if (flags & O_EXLOCK)
885 lf.l_type = F_WRLCK;
886 else
887 lf.l_type = F_RDLCK;
888 type = F_FLOCK;
889 if ((flags & FNONBLOCK) == 0)
890 type |= F_WAIT;
891 VOP_UNLOCK(vp, 0, p);
892 if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
893 (void) vn_close(vp, fp->f_flag, fp->f_cred, p);
894 ffree(fp);
895 fdp->fd_ofiles[indx] = NULL;
896 return (error);
897 }
898 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
899 fp->f_flag |= FHASLOCK;
900 }
901 VOP_UNLOCK(vp, 0, p);
902 *retval = indx;
903 return (0);
904}
905
906#ifdef COMPAT_43
907/*
908 * Create a file.
909 */
910#ifndef _SYS_SYSPROTO_H_
911struct ocreat_args {
912 char *path;
913 int mode;
914};
915#endif
916int
917ocreat(p, uap, retval)
918 struct proc *p;
919 register struct ocreat_args /* {
920 syscallarg(char *) path;
921 syscallarg(int) mode;
922 } */ *uap;
923 register_t *retval;
924{
925 struct open_args /* {
926 syscallarg(char *) path;
927 syscallarg(int) flags;
928 syscallarg(int) mode;
929 } */ nuap;
930
931 SCARG(&nuap, path) = SCARG(uap, path);
932 SCARG(&nuap, mode) = SCARG(uap, mode);
933 SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
934 return (open(p, &nuap, retval));
935}
936#endif /* COMPAT_43 */
937
938/*
939 * Create a special file.
940 */
941#ifndef _SYS_SYSPROTO_H_
942struct mknod_args {
943 char *path;
944 int mode;
945 int dev;
946};
947#endif
948/* ARGSUSED */
949int
950mknod(p, uap, retval)
951 struct proc *p;
952 register struct mknod_args /* {
953 syscallarg(char *) path;
954 syscallarg(int) mode;
955 syscallarg(int) dev;
956 } */ *uap;
957 register_t *retval;
958{
959 register struct vnode *vp;
960 struct vattr vattr;
961 int error;
962 int whiteout;
963 struct nameidata nd;
964
965 error = suser(p->p_ucred, &p->p_acflag);
966 if (error)
967 return (error);
968 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
969 if (error = namei(&nd))
970 return (error);
971 vp = nd.ni_vp;
972 if (vp != NULL)
973 error = EEXIST;
974 else {
975 VATTR_NULL(&vattr);
976 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
977 vattr.va_rdev = SCARG(uap, dev);
978 whiteout = 0;
979
980 switch (SCARG(uap, mode) & S_IFMT) {
981 case S_IFMT: /* used by badsect to flag bad sectors */
982 vattr.va_type = VBAD;
983 break;
984 case S_IFCHR:
985 vattr.va_type = VCHR;
986 break;
987 case S_IFBLK:
988 vattr.va_type = VBLK;
989 break;
990 case S_IFWHT:
991 whiteout = 1;
992 break;
993 default:
994 error = EINVAL;
995 break;
996 }
997 }
998 if (!error) {
999 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1000 if (whiteout) {
1001 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
1002 if (error)
1003 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1004 vput(nd.ni_dvp);
1005 } else {
1006 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
1007 &nd.ni_cnd, &vattr);
1008 }
1009 } else {
1010 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1011 if (nd.ni_dvp == vp)
1012 vrele(nd.ni_dvp);
1013 else
1014 vput(nd.ni_dvp);
1015 if (vp)
1016 vrele(vp);
1017 }
1018 return (error);
1019}
1020
1021/*
1022 * Create a named pipe.
1023 */
1024#ifndef _SYS_SYSPROTO_H_
1025struct mkfifo_args {
1026 char *path;
1027 int mode;
1028};
1029#endif
1030/* ARGSUSED */
1031int
1032mkfifo(p, uap, retval)
1033 struct proc *p;
1034 register struct mkfifo_args /* {
1035 syscallarg(char *) path;
1036 syscallarg(int) mode;
1037 } */ *uap;
1038 register_t *retval;
1039{
1040#ifndef FIFO
1041 return (EOPNOTSUPP);
1042#else
1043 struct vattr vattr;
1044 int error;
1045 struct nameidata nd;
1046
1047 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
1048 if (error = namei(&nd))
1049 return (error);
1050 if (nd.ni_vp != NULL) {
1051 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1052 if (nd.ni_dvp == nd.ni_vp)
1053 vrele(nd.ni_dvp);
1054 else
1055 vput(nd.ni_dvp);
1056 vrele(nd.ni_vp);
1057 return (EEXIST);
1058 }
1059 VATTR_NULL(&vattr);
1060 vattr.va_type = VFIFO;
1061 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
1062 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1063 return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
1064#endif /* FIFO */
1065}
1066
1067/*
1068 * Make a hard file link.
1069 */
1070#ifndef _SYS_SYSPROTO_H_
1071struct link_args {
1072 char *path;
1073 char *link;
1074};
1075#endif
1076/* ARGSUSED */
1077int
1078link(p, uap, retval)
1079 struct proc *p;
1080 register struct link_args /* {
1081 syscallarg(char *) path;
1082 syscallarg(char *) link;
1083 } */ *uap;
1084 register_t *retval;
1085{
1086 register struct vnode *vp;
1087 struct nameidata nd;
1088 int error;
1089
1090 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1091 if (error = namei(&nd))
1092 return (error);
1093 vp = nd.ni_vp;
1094 if (vp->v_type == VDIR)
1095 error = EPERM; /* POSIX */
1096 else {
1097 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p);
1098 error = namei(&nd);
1099 if (!error) {
1100 if (nd.ni_vp != NULL) {
1101 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1102 if (nd.ni_dvp == nd.ni_vp)
1103 vrele(nd.ni_dvp);
1104 else
1105 vput(nd.ni_dvp);
1106 if (nd.ni_vp)
1107 vrele(nd.ni_vp);
1108 error = EEXIST;
1109 } else {
1110 VOP_LEASE(nd.ni_dvp, p, p->p_ucred,
1111 LEASE_WRITE);
1112 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1113 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
1114 }
1115 }
1116 }
1117 vrele(vp);
1118 return (error);
1119}
1120
1121/*
1122 * Make a symbolic link.
1123 */
1124#ifndef _SYS_SYSPROTO_H_
1125struct symlink_args {
1126 char *path;
1127 char *link;
1128};
1129#endif
1130/* ARGSUSED */
1131int
1132symlink(p, uap, retval)
1133 struct proc *p;
1134 register struct symlink_args /* {
1135 syscallarg(char *) path;
1136 syscallarg(char *) link;
1137 } */ *uap;
1138 register_t *retval;
1139{
1140 struct vattr vattr;
1141 char *path;
1142 int error;
1143 struct nameidata nd;
1144
1145 MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
1146 if (error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL))
1147 goto out;
1148 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p);
1149 if (error = namei(&nd))
1150 goto out;
1151 if (nd.ni_vp) {
1152 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1153 if (nd.ni_dvp == nd.ni_vp)
1154 vrele(nd.ni_dvp);
1155 else
1156 vput(nd.ni_dvp);
1157 vrele(nd.ni_vp);
1158 error = EEXIST;
1159 goto out;
1160 }
1161 VATTR_NULL(&vattr);
1162 vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
1163 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1164 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1165out:
1166 FREE(path, M_NAMEI);
1167 return (error);
1168}
1169
1170/*
1171 * Delete a whiteout from the filesystem.
1172 */
1173/* ARGSUSED */
1174int
1175undelete(p, uap, retval)
1176 struct proc *p;
1177 register struct undelete_args /* {
1178 syscallarg(char *) path;
1179 } */ *uap;
1180 register_t *retval;
1181{
1182 int error;
1183 struct nameidata nd;
1184
1185 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
1186 SCARG(uap, path), p);
1187 error = namei(&nd);
1188 if (error)
1189 return (error);
1190
1191 if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
1192 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1193 if (nd.ni_dvp == nd.ni_vp)
1194 vrele(nd.ni_dvp);
1195 else
1196 vput(nd.ni_dvp);
1197 if (nd.ni_vp)
1198 vrele(nd.ni_vp);
1199 return (EEXIST);
1200 }
1201
1202 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1203 if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE))
1204 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1205 vput(nd.ni_dvp);
1206 return (error);
1207}
1208
1209/*
1210 * Delete a name from the filesystem.
1211 */
1212#ifndef _SYS_SYSPROTO_H_
1213struct unlink_args {
1214 char *path;
1215};
1216#endif
1217/* ARGSUSED */
1218int
1219unlink(p, uap, retval)
1220 struct proc *p;
1221 struct unlink_args /* {
1222 syscallarg(char *) path;
1223 } */ *uap;
1224 register_t *retval;
1225{
1226 register struct vnode *vp;
1227 int error;
1228 struct nameidata nd;
1229
1230 NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
1231 if (error = namei(&nd))
1232 return (error);
1233 vp = nd.ni_vp;
1234 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1235 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1236
1237 if (vp->v_type == VDIR)
1238 error = EPERM; /* POSIX */
1239 else {
1240 /*
1241 * The root of a mounted filesystem cannot be deleted.
1242 *
1243 * XXX: can this only be a VDIR case?
1244 */
1245 if (vp->v_flag & VROOT)
1246 error = EBUSY;
1247 else
1248 (void) vnode_pager_uncache(vp, p);
1249 }
1250
1251 if (!error) {
1252 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1253 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1254 } else {
1255 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1256 if (nd.ni_dvp == vp)
1257 vrele(nd.ni_dvp);
1258 else
1259 vput(nd.ni_dvp);
1260 if (vp != NULLVP)
1261 vput(vp);
1262 }
1263 return (error);
1264}
1265
1266/*
1267 * Reposition read/write file offset.
1268 */
1269#ifndef _SYS_SYSPROTO_H_
1270struct lseek_args {
1271 int fd;
1272 int pad;
1273 off_t offset;
1274 int whence;
1275};
1276#endif
1277int
1278lseek(p, uap, retval)
1279 struct proc *p;
1280 register struct lseek_args /* {
1281 syscallarg(int) fd;
1282 syscallarg(int) pad;
1283 syscallarg(off_t) offset;
1284 syscallarg(int) whence;
1285 } */ *uap;
1286 register_t *retval; /* XXX */
1287{
1288 struct ucred *cred = p->p_ucred;
1289 register struct filedesc *fdp = p->p_fd;
1290 register struct file *fp;
1291 struct vattr vattr;
1292 int error;
1293
1294 if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
1295 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
1296 return (EBADF);
1297 if (fp->f_type != DTYPE_VNODE)
1298 return (ESPIPE);
1299 switch (SCARG(uap, whence)) {
1300 case L_INCR:
1301 fp->f_offset += SCARG(uap, offset);
1302 break;
1303 case L_XTND:
1304 error=VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p);
1305 if (error)
1306 return (error);
1307 fp->f_offset = SCARG(uap, offset) + vattr.va_size;
1308 break;
1309 case L_SET:
1310 fp->f_offset = SCARG(uap, offset);
1311 break;
1312 default:
1313 return (EINVAL);
1314 }
1315 *(off_t *)retval = fp->f_offset;
1316 return (0);
1317}
1318
1319#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1320/*
1321 * Reposition read/write file offset.
1322 */
1323#ifndef _SYS_SYSPROTO_H_
1324struct olseek_args {
1325 int fd;
1326 long offset;
1327 int whence;
1328};
1329#endif
1330int
1331olseek(p, uap, retval)
1332 struct proc *p;
1333 register struct olseek_args /* {
1334 syscallarg(int) fd;
1335 syscallarg(long) offset;
1336 syscallarg(int) whence;
1337 } */ *uap;
1338 register_t *retval;
1339{
1340 struct lseek_args /* {
1341 syscallarg(int) fd;
1342 syscallarg(int) pad;
1343 syscallarg(off_t) offset;
1344 syscallarg(int) whence;
1345 } */ nuap;
1346 off_t qret;
1347 int error;
1348
1349 SCARG(&nuap, fd) = SCARG(uap, fd);
1350 SCARG(&nuap, offset) = SCARG(uap, offset);
1351 SCARG(&nuap, whence) = SCARG(uap, whence);
1352 error = lseek(p, &nuap, (register_t *) &qret);
1353 *(long *)retval = qret;
1354 return (error);
1355}
1356#endif /* COMPAT_43 */
1357
1358/*
1359 * Check access permissions.
1360 */
1361#ifndef _SYS_SYSPROTO_H_
1362struct access_args {
1363 char *path;
1364 int flags;
1365};
1366#endif
1367int
1368access(p, uap, retval)
1369 struct proc *p;
1370 register struct access_args /* {
1371 syscallarg(char *) path;
1372 syscallarg(int) flags;
1373 } */ *uap;
1374 register_t *retval;
1375{
1376 register struct ucred *cred = p->p_ucred;
1377 register struct vnode *vp;
1378 int error, flags, t_gid, t_uid;
1379 struct nameidata nd;
1380
1381 t_uid = cred->cr_uid;
1382 t_gid = cred->cr_groups[0];
1383 cred->cr_uid = p->p_cred->p_ruid;
1384 cred->cr_groups[0] = p->p_cred->p_rgid;
1385 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1386 SCARG(uap, path), p);
1387 if (error = namei(&nd))
1388 goto out1;
1389 vp = nd.ni_vp;
1390
1391 /* Flags == 0 means only check for existence. */
1392 if (SCARG(uap, flags)) {
1393 flags = 0;
1394 if (SCARG(uap, flags) & R_OK)
1395 flags |= VREAD;
1396 if (SCARG(uap, flags) & W_OK)
1397 flags |= VWRITE;
1398 if (SCARG(uap, flags) & X_OK)
1399 flags |= VEXEC;
1400 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
1401 error = VOP_ACCESS(vp, flags, cred, p);
1402 }
1403 vput(vp);
1404out1:
1405 cred->cr_uid = t_uid;
1406 cred->cr_groups[0] = t_gid;
1407 return (error);
1408}
1409
1410#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1411/*
1412 * Get file status; this version follows links.
1413 */
1414#ifndef _SYS_SYSPROTO_H_
1415struct ostat_args {
1416 char *path;
1417 struct ostat *ub;
1418};
1419#endif
1420/* ARGSUSED */
1421int
1422ostat(p, uap, retval)
1423 struct proc *p;
1424 register struct ostat_args /* {
1425 syscallarg(char *) path;
1426 syscallarg(struct ostat *) ub;
1427 } */ *uap;
1428 register_t *retval;
1429{
1430 struct stat sb;
1431 struct ostat osb;
1432 int error;
1433 struct nameidata nd;
1434
1435 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1436 SCARG(uap, path), p);
1437 if (error = namei(&nd))
1438 return (error);
1439 error = vn_stat(nd.ni_vp, &sb, p);
1440 vput(nd.ni_vp);
1441 if (error)
1442 return (error);
1443 cvtstat(&sb, &osb);
1444 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
1445 return (error);
1446}
1447
1448/*
1449 * Get file status; this version does not follow links.
1450 */
1451#ifndef _SYS_SYSPROTO_H_
1452struct olstat_args {
1453 char *path;
1454 struct ostat *ub;
1455};
1456#endif
1457/* ARGSUSED */
1458int
1459olstat(p, uap, retval)
1460 struct proc *p;
1461 register struct olstat_args /* {
1462 syscallarg(char *) path;
1463 syscallarg(struct ostat *) ub;
1464 } */ *uap;
1465 register_t *retval;
1466{
1467 struct vnode *vp, *dvp;
1468 struct stat sb, sb1;
1469 struct ostat osb;
1470 int error;
1471 struct nameidata nd;
1472
1473 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
1474 SCARG(uap, path), p);
1475 if (error = namei(&nd))
1476 return (error);
1477 /*
1478 * For symbolic links, always return the attributes of its
1479 * containing directory, except for mode, size, and links.
1480 */
1481 vp = nd.ni_vp;
1482 dvp = nd.ni_dvp;
1483 if (vp->v_type != VLNK) {
1484 if (dvp == vp)
1485 vrele(dvp);
1486 else
1487 vput(dvp);
1488 error = vn_stat(vp, &sb, p);
1489 vput(vp);
1490 if (error)
1491 return (error);
1492 } else {
1493 error = vn_stat(dvp, &sb, p);
1494 vput(dvp);
1495 if (error) {
1496 vput(vp);
1497 return (error);
1498 }
1499 error = vn_stat(vp, &sb1, p);
1500 vput(vp);
1501 if (error)
1502 return (error);
1503 sb.st_mode &= ~S_IFDIR;
1504 sb.st_mode |= S_IFLNK;
1505 sb.st_nlink = sb1.st_nlink;
1506 sb.st_size = sb1.st_size;
1507 sb.st_blocks = sb1.st_blocks;
1508 }
1509 cvtstat(&sb, &osb);
1510 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
1511 return (error);
1512}
1513
1514/*
1515 * Convert from an old to a new stat structure.
1516 */
1517void
1518cvtstat(st, ost)
1519 struct stat *st;
1520 struct ostat *ost;
1521{
1522
1523 ost->st_dev = st->st_dev;
1524 ost->st_ino = st->st_ino;
1525 ost->st_mode = st->st_mode;
1526 ost->st_nlink = st->st_nlink;
1527 ost->st_uid = st->st_uid;
1528 ost->st_gid = st->st_gid;
1529 ost->st_rdev = st->st_rdev;
1530 if (st->st_size < (quad_t)1 << 32)
1531 ost->st_size = st->st_size;
1532 else
1533 ost->st_size = -2;
1534 ost->st_atime = st->st_atime;
1535 ost->st_mtime = st->st_mtime;
1536 ost->st_ctime = st->st_ctime;
1537 ost->st_blksize = st->st_blksize;
1538 ost->st_blocks = st->st_blocks;
1539 ost->st_flags = st->st_flags;
1540 ost->st_gen = st->st_gen;
1541}
1542#endif /* COMPAT_43 || COMPAT_SUNOS */
1543
1544/*
1545 * Get file status; this version follows links.
1546 */
1547#ifndef _SYS_SYSPROTO_H_
1548struct stat_args {
1549 char *path;
1550 struct stat *ub;
1551};
1552#endif
1553/* ARGSUSED */
1554int
1555stat(p, uap, retval)
1556 struct proc *p;
1557 register struct stat_args /* {
1558 syscallarg(char *) path;
1559 syscallarg(struct stat *) ub;
1560 } */ *uap;
1561 register_t *retval;
1562{
1563 struct stat sb;
1564 int error;
1565 struct nameidata nd;
1566
1567 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1568 SCARG(uap, path), p);
1569 if (error = namei(&nd))
1570 return (error);
1571 error = vn_stat(nd.ni_vp, &sb, p);
1572 vput(nd.ni_vp);
1573 if (error)
1574 return (error);
1575 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
1576 return (error);
1577}
1578
1579/*
1580 * Get file status; this version does not follow links.
1581 */
1582#ifndef _SYS_SYSPROTO_H_
1583struct lstat_args {
1584 char *path;
1585 struct stat *ub;
1586};
1587#endif
1588/* ARGSUSED */
1589int
1590lstat(p, uap, retval)
1591 struct proc *p;
1592 register struct lstat_args /* {
1593 syscallarg(char *) path;
1594 syscallarg(struct stat *) ub;
1595 } */ *uap;
1596 register_t *retval;
1597{
1598 int error;
1599 struct vnode *vp, *dvp;
1600 struct stat sb, sb1;
1601 struct nameidata nd;
1602
1603 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
1604 SCARG(uap, path), p);
1605 if (error = namei(&nd))
1606 return (error);
1607 /*
1608 * For symbolic links, always return the attributes of its containing
1609 * directory, except for mode, size, inode number, and links.
1610 */
1611 vp = nd.ni_vp;
1612 dvp = nd.ni_dvp;
1613 if (vp->v_type != VLNK) {
1614 if (dvp == vp)
1615 vrele(dvp);
1616 else
1617 vput(dvp);
1618 error = vn_stat(vp, &sb, p);
1619 vput(vp);
1620 if (error)
1621 return (error);
1622 } else {
1623 error = vn_stat(dvp, &sb, p);
1624 vput(dvp);
1625 if (error) {
1626 vput(vp);
1627 return (error);
1628 }
1629 error = vn_stat(vp, &sb1, p);
1630 vput(vp);
1631 if (error)
1632 return (error);
1633 sb.st_mode &= ~S_IFDIR;
1634 sb.st_mode |= S_IFLNK;
1635 sb.st_nlink = sb1.st_nlink;
1636 sb.st_size = sb1.st_size;
1637 sb.st_blocks = sb1.st_blocks;
1638 sb.st_ino = sb1.st_ino;
1639 }
1640 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
1641 return (error);
1642}
1643
1644/*
1645 * Get configurable pathname variables.
1646 */
1647#ifndef _SYS_SYSPROTO_H_
1648struct pathconf_args {
1649 char *path;
1650 int name;
1651};
1652#endif
1653/* ARGSUSED */
1654int
1655pathconf(p, uap, retval)
1656 struct proc *p;
1657 register struct pathconf_args /* {
1658 syscallarg(char *) path;
1659 syscallarg(int) name;
1660 } */ *uap;
1661 register_t *retval;
1662{
1663 int error;
1664 struct nameidata nd;
1665
1666 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1667 SCARG(uap, path), p);
1668 if (error = namei(&nd))
1669 return (error);
1670 error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval);
1671 vput(nd.ni_vp);
1672 return (error);
1673}
1674
1675/*
1676 * Return target name of a symbolic link.
1677 */
1678#ifndef _SYS_SYSPROTO_H_
1679struct readlink_args {
1680 char *path;
1681 char *buf;
1682 int count;
1683};
1684#endif
1685/* ARGSUSED */
1686int
1687readlink(p, uap, retval)
1688 struct proc *p;
1689 register struct readlink_args /* {
1690 syscallarg(char *) path;
1691 syscallarg(char *) buf;
1692 syscallarg(int) count;
1693 } */ *uap;
1694 register_t *retval;
1695{
1696 register struct vnode *vp;
1697 struct iovec aiov;
1698 struct uio auio;
1699 int error;
1700 struct nameidata nd;
1701
1702 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
1703 SCARG(uap, path), p);
1704 if (error = namei(&nd))
1705 return (error);
1706 vp = nd.ni_vp;
1707 if (vp->v_type != VLNK)
1708 error = EINVAL;
1709 else {
1710 aiov.iov_base = SCARG(uap, buf);
1711 aiov.iov_len = SCARG(uap, count);
1712 auio.uio_iov = &aiov;
1713 auio.uio_iovcnt = 1;
1714 auio.uio_offset = 0;
1715 auio.uio_rw = UIO_READ;
1716 auio.uio_segflg = UIO_USERSPACE;
1717 auio.uio_procp = p;
1718 auio.uio_resid = SCARG(uap, count);
1719 error = VOP_READLINK(vp, &auio, p->p_ucred);
1720 }
1721 vput(vp);
1722 *retval = SCARG(uap, count) - auio.uio_resid;
1723 return (error);
1724}
1725
1726/*
1727 * Change flags of a file given a path name.
1728 */
1729#ifndef _SYS_SYSPROTO_H_
1730struct chflags_args {
1731 char *path;
1732 int flags;
1733};
1734#endif
1735/* ARGSUSED */
1736int
1737chflags(p, uap, retval)
1738 struct proc *p;
1739 register struct chflags_args /* {
1740 syscallarg(char *) path;
1741 syscallarg(int) flags;
1742 } */ *uap;
1743 register_t *retval;
1744{
1745 register struct vnode *vp;
1746 struct vattr vattr;
1747 int error;
1748 struct nameidata nd;
1749
1750 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1751 if (error = namei(&nd))
1752 return (error);
1753 vp = nd.ni_vp;
1754 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1755 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1756 VATTR_NULL(&vattr);
1757 vattr.va_flags = SCARG(uap, flags);
1758 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1759 vput(vp);
1760 return (error);
1761}
1762
1763/*
1764 * Change flags of a file given a file descriptor.
1765 */
1766#ifndef _SYS_SYSPROTO_H_
1767struct fchflags_args {
1768 int fd;
1769 int flags;
1770};
1771#endif
1772/* ARGSUSED */
1773int
1774fchflags(p, uap, retval)
1775 struct proc *p;
1776 register struct fchflags_args /* {
1777 syscallarg(int) fd;
1778 syscallarg(int) flags;
1779 } */ *uap;
1780 register_t *retval;
1781{
1782 struct vattr vattr;
1783 struct vnode *vp;
1784 struct file *fp;
1785 int error;
1786
1787 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
1788 return (error);
1789 vp = (struct vnode *)fp->f_data;
1790 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1791 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1792 VATTR_NULL(&vattr);
1793 vattr.va_flags = SCARG(uap, flags);
1794 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1795 VOP_UNLOCK(vp, 0, p);
1796 return (error);
1797}
1798
1799/*
1800 * Change mode of a file given path name.
1801 */
1802#ifndef _SYS_SYSPROTO_H_
1803struct chmod_args {
1804 char *path;
1805 int mode;
1806};
1807#endif
1808/* ARGSUSED */
1809int
1810chmod(p, uap, retval)
1811 struct proc *p;
1812 register struct chmod_args /* {
1813 syscallarg(char *) path;
1814 syscallarg(int) mode;
1815 } */ *uap;
1816 register_t *retval;
1817{
1818 register struct vnode *vp;
1819 struct vattr vattr;
1820 int error;
1821 struct nameidata nd;
1822
1823 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1824 if (error = namei(&nd))
1825 return (error);
1826 vp = nd.ni_vp;
1827 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1828 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1829 VATTR_NULL(&vattr);
1830 vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
1831 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1832 vput(vp);
1833 return (error);
1834}
1835
1836/*
1837 * Change mode of a file given a file descriptor.
1838 */
1839#ifndef _SYS_SYSPROTO_H_
1840struct fchmod_args {
1841 int fd;
1842 int mode;
1843};
1844#endif
1845/* ARGSUSED */
1846int
1847fchmod(p, uap, retval)
1848 struct proc *p;
1849 register struct fchmod_args /* {
1850 syscallarg(int) fd;
1851 syscallarg(int) mode;
1852 } */ *uap;
1853 register_t *retval;
1854{
1855 struct vattr vattr;
1856 struct vnode *vp;
1857 struct file *fp;
1858 int error;
1859
1860 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
1861 return (error);
1862 vp = (struct vnode *)fp->f_data;
1863 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1864 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1865 VATTR_NULL(&vattr);
1866 vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
1867 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1868 VOP_UNLOCK(vp, 0, p);
1869 return (error);
1870}
1871
1872/*
1873 * Set ownership given a path name.
1874 */
1875#ifndef _SYS_SYSPROTO_H_
1876struct chown_args {
1877 char *path;
1878 int uid;
1879 int gid;
1880};
1881#endif
1882/* ARGSUSED */
1883int
1884chown(p, uap, retval)
1885 struct proc *p;
1886 register struct chown_args /* {
1887 syscallarg(char *) path;
1888 syscallarg(int) uid;
1889 syscallarg(int) gid;
1890 } */ *uap;
1891 register_t *retval;
1892{
1893 register struct vnode *vp;
1894 struct vattr vattr;
1895 int error;
1896 struct nameidata nd;
1897
1898 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1899 if (error = namei(&nd))
1900 return (error);
1901 vp = nd.ni_vp;
1902 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1903 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1904 VATTR_NULL(&vattr);
1905 vattr.va_uid = SCARG(uap, uid);
1906 vattr.va_gid = SCARG(uap, gid);
1907 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1908 vput(vp);
1909 return (error);
1910}
1911
1912/*
1913 * Set ownership given a file descriptor.
1914 */
1915#ifndef _SYS_SYSPROTO_H_
1916struct fchown_args {
1917 int fd;
1918 int uid;
1919 int gid;
1920};
1921#endif
1922/* ARGSUSED */
1923int
1924fchown(p, uap, retval)
1925 struct proc *p;
1926 register struct fchown_args /* {
1927 syscallarg(int) fd;
1928 syscallarg(int) uid;
1929 syscallarg(int) gid;
1930 } */ *uap;
1931 register_t *retval;
1932{
1933 struct vattr vattr;
1934 struct vnode *vp;
1935 struct file *fp;
1936 int error;
1937
1938 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
1939 return (error);
1940 vp = (struct vnode *)fp->f_data;
1941 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1942 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1943 VATTR_NULL(&vattr);
1944 vattr.va_uid = SCARG(uap, uid);
1945 vattr.va_gid = SCARG(uap, gid);
1946 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1947 VOP_UNLOCK(vp, 0, p);
1948 return (error);
1949}
1950
1951/*
1952 * Set the access and modification times of a file.
1953 */
1954#ifndef _SYS_SYSPROTO_H_
1955struct utimes_args {
1956 char *path;
1957 struct timeval *tptr;
1958};
1959#endif
1960/* ARGSUSED */
1961int
1962utimes(p, uap, retval)
1963 struct proc *p;
1964 register struct utimes_args /* {
1965 syscallarg(char *) path;
1966 syscallarg(struct timeval *) tptr;
1967 } */ *uap;
1968 register_t *retval;
1969{
1970 register struct vnode *vp;
1971 struct timeval tv[2];
1972 struct vattr vattr;
1973 int error;
1974 struct nameidata nd;
1975
1976 VATTR_NULL(&vattr);
1977 if (SCARG(uap, tptr) == NULL) {
1978 microtime(&tv[0]);
1979 tv[1] = tv[0];
1980 vattr.va_vaflags |= VA_UTIMES_NULL;
1981 } else if (error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv,
1982 sizeof (tv)))
1983 return (error);
1984 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1985 if (error = namei(&nd))
1986 return (error);
1987 vp = nd.ni_vp;
1988 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1989 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1990 vattr.va_atime.tv_sec = tv[0].tv_sec;
1991 vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000;
1992 vattr.va_mtime.tv_sec = tv[1].tv_sec;
1993 vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000;
1994 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1995 vput(vp);
1996 return (error);
1997}
1998
1999/*
2000 * Truncate a file given its path name.
2001 */
2002#ifndef _SYS_SYSPROTO_H_
2003struct truncate_args {
2004 char *path;
2005 int pad;
2006 off_t length;
2007};
2008#endif
2009/* ARGSUSED */
2010int
2011truncate(p, uap, retval)
2012 struct proc *p;
2013 register struct truncate_args /* {
2014 syscallarg(char *) path;
2015 syscallarg(int) pad;
2016 syscallarg(off_t) length;
2017 } */ *uap;
2018 register_t *retval;
2019{
2020 register struct vnode *vp;
2021 struct vattr vattr;
2022 int error;
2023 struct nameidata nd;
2024
2025 if (uap->length < 0)
2026 return(EINVAL);
2027 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2028 if (error = namei(&nd))
2029 return (error);
2030 vp = nd.ni_vp;
2031 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2032 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2033 if (vp->v_type == VDIR)
2034 error = EISDIR;
2035 else if ((error = vn_writechk(vp)) == 0 &&
2036 (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
2037 VATTR_NULL(&vattr);
2038 vattr.va_size = SCARG(uap, length);
2039 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2040 }
2041 vput(vp);
2042 return (error);
2043}
2044
2045/*
2046 * Truncate a file given a file descriptor.
2047 */
2048#ifndef _SYS_SYSPROTO_H_
2049struct ftruncate_args {
2050 int fd;
2051 int pad;
2052 off_t length;
2053};
2054#endif
2055/* ARGSUSED */
2056int
2057ftruncate(p, uap, retval)
2058 struct proc *p;
2059 register struct ftruncate_args /* {
2060 syscallarg(int) fd;
2061 syscallarg(int) pad;
2062 syscallarg(off_t) length;
2063 } */ *uap;
2064 register_t *retval;
2065{
2066 struct vattr vattr;
2067 struct vnode *vp;
2068 struct file *fp;
2069 int error;
2070
2071 if (uap->length < 0)
2072 return(EINVAL);
2073 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
2074 return (error);
2075 if ((fp->f_flag & FWRITE) == 0)
2076 return (EINVAL);
2077 vp = (struct vnode *)fp->f_data;
2078 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2079 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2080 if (vp->v_type == VDIR)
2081 error = EISDIR;
2082 else if ((error = vn_writechk(vp)) == 0) {
2083 VATTR_NULL(&vattr);
2084 vattr.va_size = SCARG(uap, length);
2085 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
2086 }
2087 VOP_UNLOCK(vp, 0, p);
2088 return (error);
2089}
2090
2091#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
2092/*
2093 * Truncate a file given its path name.
2094 */
2095#ifndef _SYS_SYSPROTO_H_
2096struct otruncate_args {
2097 char *path;
2098 long length;
2099};
2100#endif
2101/* ARGSUSED */
2102int
2103otruncate(p, uap, retval)
2104 struct proc *p;
2105 register struct otruncate_args /* {
2106 syscallarg(char *) path;
2107 syscallarg(long) length;
2108 } */ *uap;
2109 register_t *retval;
2110{
2111 struct truncate_args /* {
2112 syscallarg(char *) path;
2113 syscallarg(int) pad;
2114 syscallarg(off_t) length;
2115 } */ nuap;
2116
2117 SCARG(&nuap, path) = SCARG(uap, path);
2118 SCARG(&nuap, length) = SCARG(uap, length);
2119 return (truncate(p, &nuap, retval));
2120}
2121
2122/*
2123 * Truncate a file given a file descriptor.
2124 */
2125#ifndef _SYS_SYSPROTO_H_
2126struct oftruncate_args {
2127 int fd;
2128 long length;
2129};
2130#endif
2131/* ARGSUSED */
2132int
2133oftruncate(p, uap, retval)
2134 struct proc *p;
2135 register struct oftruncate_args /* {
2136 syscallarg(int) fd;
2137 syscallarg(long) length;
2138 } */ *uap;
2139 register_t *retval;
2140{
2141 struct ftruncate_args /* {
2142 syscallarg(int) fd;
2143 syscallarg(int) pad;
2144 syscallarg(off_t) length;
2145 } */ nuap;
2146
2147 SCARG(&nuap, fd) = SCARG(uap, fd);
2148 SCARG(&nuap, length) = SCARG(uap, length);
2149 return (ftruncate(p, &nuap, retval));
2150}
2151#endif /* COMPAT_43 || COMPAT_SUNOS */
2152
2153/*
2154 * Sync an open file.
2155 */
2156#ifndef _SYS_SYSPROTO_H_
2157struct fsync_args {
2158 int fd;
2159};
2160#endif
2161/* ARGSUSED */
2162int
2163fsync(p, uap, retval)
2164 struct proc *p;
2165 struct fsync_args /* {
2166 syscallarg(int) fd;
2167 } */ *uap;
2168 register_t *retval;
2169{
2170 register struct vnode *vp;
2171 struct file *fp;
2172 int error;
2173
2174 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
2175 return (error);
2176 vp = (struct vnode *)fp->f_data;
2177 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2178 if (vp->v_object) {
2179 vm_object_page_clean(vp->v_object, 0, 0 ,0, FALSE);
2180 }
2181 error = VOP_FSYNC(vp, fp->f_cred,
2182 (vp->v_mount->mnt_flag & MNT_ASYNC) ? MNT_NOWAIT : MNT_WAIT, p);
2183 VOP_UNLOCK(vp, 0, p);
2184 return (error);
2185}
2186
2187/*
2188 * Rename files. Source and destination must either both be directories,
2189 * or both not be directories. If target is a directory, it must be empty.
2190 */
2191#ifndef _SYS_SYSPROTO_H_
2192struct rename_args {
2193 char *from;
2194 char *to;
2195};
2196#endif
2197/* ARGSUSED */
2198int
2199rename(p, uap, retval)
2200 struct proc *p;
2201 register struct rename_args /* {
2202 syscallarg(char *) from;
2203 syscallarg(char *) to;
2204 } */ *uap;
2205 register_t *retval;
2206{
2207 register struct vnode *tvp, *fvp, *tdvp;
2208 struct nameidata fromnd, tond;
2209 int error;
2210
2211 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
2212 SCARG(uap, from), p);
2213 if (error = namei(&fromnd))
2214 return (error);
2215 fvp = fromnd.ni_vp;
2216 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
2217 UIO_USERSPACE, SCARG(uap, to), p);
2218 if (fromnd.ni_vp->v_type == VDIR)
2219 tond.ni_cnd.cn_flags |= WILLBEDIR;
2220 if (error = namei(&tond)) {
2221 /* Translate error code for rename("dir1", "dir2/."). */
2222 if (error == EISDIR && fvp->v_type == VDIR)
2223 error = EINVAL;
2224 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2225 vrele(fromnd.ni_dvp);
2226 vrele(fvp);
2227 goto out1;
2228 }
2229 tdvp = tond.ni_dvp;
2230 tvp = tond.ni_vp;
2231 if (tvp != NULL) {
2232 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
2233 error = ENOTDIR;
2234 goto out;
2235 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
2236 error = EISDIR;
2237 goto out;
2238 }
2239 }
2240 if (fvp == tdvp)
2241 error = EINVAL;
2242 /*
2243 * If source is the same as the destination (that is the
2244 * same inode number with the same name in the same directory),
2245 * then there is nothing to do.
2246 */
2247 if (fvp == tvp && fromnd.ni_dvp == tdvp &&
2248 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
2249 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
2250 fromnd.ni_cnd.cn_namelen))
2251 error = -1;
2252out:
2253 if (!error) {
2254 VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE);
2255 if (fromnd.ni_dvp != tdvp)
2256 VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2257 if (tvp) {
2258 VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE);
2259 (void) vnode_pager_uncache(tvp, p);
2260 }
2261 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
2262 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
2263 } else {
2264 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
2265 if (tdvp == tvp)
2266 vrele(tdvp);
2267 else
2268 vput(tdvp);
2269 if (tvp)
2270 vput(tvp);
2271 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2272 vrele(fromnd.ni_dvp);
2273 vrele(fvp);
2274 }
2275 vrele(tond.ni_startdir);
2276 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
2277out1:
2278 if (fromnd.ni_startdir)
2279 vrele(fromnd.ni_startdir);
2280 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
2281 if (error == -1)
2282 return (0);
2283 return (error);
2284}
2285
2286/*
2287 * Make a directory file.
2288 */
2289#ifndef _SYS_SYSPROTO_H_
2290struct mkdir_args {
2291 char *path;
2292 int mode;
2293};
2294#endif
2295/* ARGSUSED */
2296int
2297mkdir(p, uap, retval)
2298 struct proc *p;
2299 register struct mkdir_args /* {
2300 syscallarg(char *) path;
2301 syscallarg(int) mode;
2302 } */ *uap;
2303 register_t *retval;
2304{
2305 register struct vnode *vp;
2306 struct vattr vattr;
2307 int error;
2308 struct nameidata nd;
2309
2310 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
2311 nd.ni_cnd.cn_flags |= WILLBEDIR;
2312 if (error = namei(&nd))
2313 return (error);
2314 vp = nd.ni_vp;
2315 if (vp != NULL) {
2316 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2317 if (nd.ni_dvp == vp)
2318 vrele(nd.ni_dvp);
2319 else
2320 vput(nd.ni_dvp);
2321 vrele(vp);
2322 return (EEXIST);
2323 }
2324 VATTR_NULL(&vattr);
2325 vattr.va_type = VDIR;
2326 vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask;
2327 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2328 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
2329 if (!error)
2330 vput(nd.ni_vp);
2331 return (error);
2332}
2333
2334/*
2335 * Remove a directory file.
2336 */
2337#ifndef _SYS_SYSPROTO_H_
2338struct rmdir_args {
2339 char *path;
2340};
2341#endif
2342/* ARGSUSED */
2343int
2344rmdir(p, uap, retval)
2345 struct proc *p;
2346 struct rmdir_args /* {
2347 syscallarg(char *) path;
2348 } */ *uap;
2349 register_t *retval;
2350{
2351 register struct vnode *vp;
2352 int error;
2353 struct nameidata nd;
2354
2355 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
2356 SCARG(uap, path), p);
2357 if (error = namei(&nd))
2358 return (error);
2359 vp = nd.ni_vp;
2360 if (vp->v_type != VDIR) {
2361 error = ENOTDIR;
2362 goto out;
2363 }
2364 /*
2365 * No rmdir "." please.
2366 */
2367 if (nd.ni_dvp == vp) {
2368 error = EINVAL;
2369 goto out;
2370 }
2371 /*
2372 * The root of a mounted filesystem cannot be deleted.
2373 */
2374 if (vp->v_flag & VROOT)
2375 error = EBUSY;
2376out:
2377 if (!error) {
2378 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2379 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2380 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2381 } else {
2382 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2383 if (nd.ni_dvp == vp)
2384 vrele(nd.ni_dvp);
2385 else
2386 vput(nd.ni_dvp);
2387 vput(vp);
2388 }
2389 return (error);
2390}
2391
2392#ifdef COMPAT_43
2393/*
2394 * Read a block of directory entries in a file system independent format.
2395 */
2396#ifndef _SYS_SYSPROTO_H_
2397struct ogetdirentries_args {
2398 int fd;
2399 char *buf;
2400 u_int count;
2401 long *basep;
2402};
2403#endif
2404int
2405ogetdirentries(p, uap, retval)
2406 struct proc *p;
2407 register struct ogetdirentries_args /* {
2408 syscallarg(int) fd;
2409 syscallarg(char *) buf;
2410 syscallarg(u_int) count;
2411 syscallarg(long *) basep;
2412 } */ *uap;
2413 register_t *retval;
2414{
2415 register struct vnode *vp;
2416 struct file *fp;
2417 struct uio auio, kuio;
2418 struct iovec aiov, kiov;
2419 struct dirent *dp, *edp;
2420 caddr_t dirbuf;
2421 int error, eofflag, readcnt;
2422 long loff;
2423
2424 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
2425 return (error);
2426 if ((fp->f_flag & FREAD) == 0)
2427 return (EBADF);
2428 vp = (struct vnode *)fp->f_data;
2429unionread:
2430 if (vp->v_type != VDIR)
2431 return (EINVAL);
2432 aiov.iov_base = SCARG(uap, buf);
2433 aiov.iov_len = SCARG(uap, count);
2434 auio.uio_iov = &aiov;
2435 auio.uio_iovcnt = 1;
2436 auio.uio_rw = UIO_READ;
2437 auio.uio_segflg = UIO_USERSPACE;
2438 auio.uio_procp = p;
2439 auio.uio_resid = SCARG(uap, count);
2440 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2441 loff = auio.uio_offset = fp->f_offset;
2442# if (BYTE_ORDER != LITTLE_ENDIAN)
2443 if (vp->v_mount->mnt_maxsymlinklen <= 0) {
2444 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
2445 NULL, NULL);
2446 fp->f_offset = auio.uio_offset;
2447 } else
2448# endif
2449 {
2450 kuio = auio;
2451 kuio.uio_iov = &kiov;
2452 kuio.uio_segflg = UIO_SYSSPACE;
2453 kiov.iov_len = SCARG(uap, count);
2454 MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK);
2455 kiov.iov_base = dirbuf;
2456 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
2457 NULL, NULL);
2458 fp->f_offset = kuio.uio_offset;
2459 if (error == 0) {
2460 readcnt = SCARG(uap, count) - kuio.uio_resid;
2461 edp = (struct dirent *)&dirbuf[readcnt];
2462 for (dp = (struct dirent *)dirbuf; dp < edp; ) {
2463# if (BYTE_ORDER == LITTLE_ENDIAN)
2464 /*
2465 * The expected low byte of
2466 * dp->d_namlen is our dp->d_type.
2467 * The high MBZ byte of dp->d_namlen
2468 * is our dp->d_namlen.
2469 */
2470 dp->d_type = dp->d_namlen;
2471 dp->d_namlen = 0;
2472# else
2473 /*
2474 * The dp->d_type is the high byte
2475 * of the expected dp->d_namlen,
2476 * so must be zero'ed.
2477 */
2478 dp->d_type = 0;
2479# endif
2480 if (dp->d_reclen > 0) {
2481 dp = (struct dirent *)
2482 ((char *)dp + dp->d_reclen);
2483 } else {
2484 error = EIO;
2485 break;
2486 }
2487 }
2488 if (dp >= edp)
2489 error = uiomove(dirbuf, readcnt, &auio);
2490 }
2491 FREE(dirbuf, M_TEMP);
2492 }
2493 VOP_UNLOCK(vp, 0, p);
2494 if (error)
2495 return (error);
2496
2497#ifdef UNION
2498{
2501 extern int (**union_vnodeop_p)();
2502 extern struct vnode *union_dircache __P((struct vnode*, struct proc*));
2503
2499 if ((SCARG(uap, count) == auio.uio_resid) &&
2500 (vp->v_op == union_vnodeop_p)) {
2501 struct vnode *lvp;
2502
2503 lvp = union_dircache(vp, p);
2504 if (lvp != NULLVP) {
2505 struct vattr va;
2506
2507 /*
2508 * If the directory is opaque,
2509 * then don't show lower entries
2510 */
2511 error = VOP_GETATTR(vp, &va, fp->f_cred, p);
2512 if (va.va_flags & OPAQUE) {
2513 vput(lvp);
2514 lvp = NULL;
2515 }
2516 }
2517
2518 if (lvp != NULLVP) {
2519 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
2520 if (error) {
2521 vput(lvp);
2522 return (error);
2523 }
2524 VOP_UNLOCK(lvp, 0, p);
2525 fp->f_data = (caddr_t) lvp;
2526 fp->f_offset = 0;
2527 error = vn_close(vp, FREAD, fp->f_cred, p);
2528 if (error)
2529 return (error);
2530 vp = lvp;
2531 goto unionread;
2532 }
2533 }
2534}
2535#endif /* UNION */
2536
2537 if ((SCARG(uap, count) == auio.uio_resid) &&
2538 (vp->v_flag & VROOT) &&
2539 (vp->v_mount->mnt_flag & MNT_UNION)) {
2540 struct vnode *tvp = vp;
2541 vp = vp->v_mount->mnt_vnodecovered;
2542 VREF(vp);
2543 fp->f_data = (caddr_t) vp;
2544 fp->f_offset = 0;
2545 vrele(tvp);
2546 goto unionread;
2547 }
2548 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
2549 sizeof(long));
2550 *retval = SCARG(uap, count) - auio.uio_resid;
2551 return (error);
2552}
2553#endif /* COMPAT_43 */
2554
2555/*
2556 * Read a block of directory entries in a file system independent format.
2557 */
2558#ifndef _SYS_SYSPROTO_H_
2559struct getdirentries_args {
2560 int fd;
2561 char *buf;
2562 u_int count;
2563 long *basep;
2564};
2565#endif
2566int
2567getdirentries(p, uap, retval)
2568 struct proc *p;
2569 register struct getdirentries_args /* {
2570 syscallarg(int) fd;
2571 syscallarg(char *) buf;
2572 syscallarg(u_int) count;
2573 syscallarg(long *) basep;
2574 } */ *uap;
2575 register_t *retval;
2576{
2577 register struct vnode *vp;
2578 struct file *fp;
2579 struct uio auio;
2580 struct iovec aiov;
2581 long loff;
2582 int error, eofflag;
2583
2584 if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
2585 return (error);
2586 if ((fp->f_flag & FREAD) == 0)
2587 return (EBADF);
2588 vp = (struct vnode *)fp->f_data;
2589unionread:
2590 if (vp->v_type != VDIR)
2591 return (EINVAL);
2592 aiov.iov_base = SCARG(uap, buf);
2593 aiov.iov_len = SCARG(uap, count);
2594 auio.uio_iov = &aiov;
2595 auio.uio_iovcnt = 1;
2596 auio.uio_rw = UIO_READ;
2597 auio.uio_segflg = UIO_USERSPACE;
2598 auio.uio_procp = p;
2599 auio.uio_resid = SCARG(uap, count);
2600 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2601 loff = auio.uio_offset = fp->f_offset;
2602 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL, NULL);
2603 fp->f_offset = auio.uio_offset;
2604 VOP_UNLOCK(vp, 0, p);
2605 if (error)
2606 return (error);
2607
2608#ifdef UNION
2609{
2615 extern int (**union_vnodeop_p)();
2616 extern struct vnode *union_dircache __P((struct vnode*, struct proc*));
2617
2610 if ((SCARG(uap, count) == auio.uio_resid) &&
2611 (vp->v_op == union_vnodeop_p)) {
2612 struct vnode *lvp;
2613
2614 lvp = union_dircache(vp, p);
2615 if (lvp != NULLVP) {
2616 struct vattr va;
2617
2618 /*
2619 * If the directory is opaque,
2620 * then don't show lower entries
2621 */
2622 error = VOP_GETATTR(vp, &va, fp->f_cred, p);
2623 if (va.va_flags & OPAQUE) {
2624 vput(lvp);
2625 lvp = NULL;
2626 }
2627 }
2628
2629 if (lvp != NULLVP) {
2630 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
2631 if (error) {
2632 vput(lvp);
2633 return (error);
2634 }
2635 VOP_UNLOCK(lvp, 0, p);
2636 fp->f_data = (caddr_t) lvp;
2637 fp->f_offset = 0;
2638 error = vn_close(vp, FREAD, fp->f_cred, p);
2639 if (error)
2640 return (error);
2641 vp = lvp;
2642 goto unionread;
2643 }
2644 }
2645}
2646#endif /* UNION */
2647
2648 if ((SCARG(uap, count) == auio.uio_resid) &&
2649 (vp->v_flag & VROOT) &&
2650 (vp->v_mount->mnt_flag & MNT_UNION)) {
2651 struct vnode *tvp = vp;
2652 vp = vp->v_mount->mnt_vnodecovered;
2653 VREF(vp);
2654 fp->f_data = (caddr_t) vp;
2655 fp->f_offset = 0;
2656 vrele(tvp);
2657 goto unionread;
2658 }
2659 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
2660 sizeof(long));
2661 *retval = SCARG(uap, count) - auio.uio_resid;
2662 return (error);
2663}
2664
2665/*
2666 * Set the mode mask for creation of filesystem nodes.
2667 */
2668#ifndef _SYS_SYSPROTO_H_
2669struct umask_args {
2670 int newmask;
2671};
2672#endif
2673int
2674umask(p, uap, retval)
2675 struct proc *p;
2676 struct umask_args /* {
2677 syscallarg(int) newmask;
2678 } */ *uap;
2679 int *retval; /* XXX */
2680{
2681 register struct filedesc *fdp;
2682
2683 fdp = p->p_fd;
2684 *retval = fdp->fd_cmask;
2685 fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS;
2686 return (0);
2687}
2688
2689/*
2690 * Void all references to file by ripping underlying filesystem
2691 * away from vnode.
2692 */
2693#ifndef _SYS_SYSPROTO_H_
2694struct revoke_args {
2695 char *path;
2696};
2697#endif
2698/* ARGSUSED */
2699int
2700revoke(p, uap, retval)
2701 struct proc *p;
2702 register struct revoke_args /* {
2703 syscallarg(char *) path;
2704 } */ *uap;
2705 register_t *retval;
2706{
2707 register struct vnode *vp;
2708 struct vattr vattr;
2709 int error;
2710 struct nameidata nd;
2711
2712 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2713 if (error = namei(&nd))
2714 return (error);
2715 vp = nd.ni_vp;
2716 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
2717 goto out;
2718 if (p->p_ucred->cr_uid != vattr.va_uid &&
2719 (error = suser(p->p_ucred, &p->p_acflag)))
2720 goto out;
2721 if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
2722 VOP_REVOKE(vp, REVOKEALL);
2723out:
2724 vrele(vp);
2725 return (error);
2726}
2727
2728/*
2729 * Convert a user file descriptor to a kernel file entry.
2730 */
2731int
2732getvnode(fdp, fd, fpp)
2733 struct filedesc *fdp;
2734 int fd;
2735 struct file **fpp;
2736{
2737 struct file *fp;
2738
2739 if ((u_int)fd >= fdp->fd_nfiles ||
2740 (fp = fdp->fd_ofiles[fd]) == NULL)
2741 return (EBADF);
2742 if (fp->f_type != DTYPE_VNODE && fp->f_type != DTYPE_FIFO)
2743 return (EINVAL);
2744 *fpp = fp;
2745 return (0);
2746}