123405Smckusick /*
263428Sbostic * Copyright (c) 1989, 1993
363428Sbostic * The Regents of the University of California. All rights reserved.
465771Sbostic * (c) UNIX System Laboratories, Inc.
565771Sbostic * All or some portions of this file are derived from material licensed
665771Sbostic * to the University of California by American Telephone and Telegraph
765771Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with
865771Sbostic * the permission of UNIX System Laboratories, Inc.
923405Smckusick *
1044459Sbostic * %sccs.include.redist.c%
1137741Smckusick *
12*69903Smckusick * @(#)vfs_syscalls.c 8.41 (Berkeley) 06/15/95
1323405Smckusick */
1437Sbill
1556517Sbostic #include <sys/param.h>
1656517Sbostic #include <sys/systm.h>
1756517Sbostic #include <sys/namei.h>
1856517Sbostic #include <sys/filedesc.h>
1956517Sbostic #include <sys/kernel.h>
2056517Sbostic #include <sys/file.h>
2156517Sbostic #include <sys/stat.h>
2256517Sbostic #include <sys/vnode.h>
2356517Sbostic #include <sys/mount.h>
2456517Sbostic #include <sys/proc.h>
2556517Sbostic #include <sys/uio.h>
2656517Sbostic #include <sys/malloc.h>
2756517Sbostic #include <sys/dirent.h>
2856517Sbostic
2968318Scgd #include <sys/syscallargs.h>
3068318Scgd
3153468Smckusick #include <vm/vm.h>
3259875Smckusick #include <sys/sysctl.h>
3337Sbill
3464410Sbostic static int change_dir __P((struct nameidata *ndp, struct proc *p));
3568318Scgd static void checkdirs __P((struct vnode *olddp));
3664410Sbostic
3737741Smckusick /*
3837741Smckusick * Virtual File System System Calls
3937741Smckusick */
4012756Ssam
419167Ssam /*
4264410Sbostic * Mount a file system.
439167Ssam */
4442441Smckusick /* ARGSUSED */
4568318Scgd int
mount(p,uap,retval)4642441Smckusick mount(p, uap, retval)
4745914Smckusick struct proc *p;
4868318Scgd register struct mount_args /* {
4968663Smckusick syscallarg(char *) type;
5068318Scgd syscallarg(char *) path;
5168318Scgd syscallarg(int) flags;
5268318Scgd syscallarg(caddr_t) data;
5368318Scgd } */ *uap;
5468318Scgd register_t *retval;
5542441Smckusick {
5668663Smckusick struct vnode *vp;
5768663Smckusick struct mount *mp;
5868663Smckusick struct vfsconf *vfsp;
5940111Smckusick int error, flag;
6067532Smckusick struct vattr va;
6168663Smckusick u_long fstypenum;
6247540Skarels struct nameidata nd;
6368663Smckusick char fstypename[MFSNAMELEN];
646254Sroot
6537741Smckusick /*
6637741Smckusick * Get vnode to be covered
6737741Smckusick */
6868318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
6968318Scgd SCARG(uap, path), p);
7052322Smckusick if (error = namei(&nd))
7147540Skarels return (error);
7252322Smckusick vp = nd.ni_vp;
7368318Scgd if (SCARG(uap, flags) & MNT_UPDATE) {
7439335Smckusick if ((vp->v_flag & VROOT) == 0) {
7539335Smckusick vput(vp);
7647540Skarels return (EINVAL);
7739335Smckusick }
7839335Smckusick mp = vp->v_mount;
7957047Smckusick flag = mp->mnt_flag;
8039335Smckusick /*
8157047Smckusick * We only allow the filesystem to be reloaded if it
8257047Smckusick * is currently mounted read-only.
8339335Smckusick */
8468318Scgd if ((SCARG(uap, flags) & MNT_RELOAD) &&
8557047Smckusick ((mp->mnt_flag & MNT_RDONLY) == 0)) {
8639335Smckusick vput(vp);
8747540Skarels return (EOPNOTSUPP); /* Needs translation */
8839335Smckusick }
8957047Smckusick mp->mnt_flag |=
9068318Scgd SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
9167532Smckusick /*
9267532Smckusick * Only root, or the user that did the original mount is
9367532Smckusick * permitted to update it.
9467532Smckusick */
9567532Smckusick if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid &&
9667532Smckusick (error = suser(p->p_ucred, &p->p_acflag))) {
9767532Smckusick vput(vp);
9867532Smckusick return (error);
9967532Smckusick }
10067532Smckusick /*
10167532Smckusick * Do not allow NFS export by non-root users. Silently
10267532Smckusick * enforce MNT_NOSUID and MNT_NODEV for non-root users.
10367532Smckusick */
10467532Smckusick if (p->p_ucred->cr_uid != 0) {
10568318Scgd if (SCARG(uap, flags) & MNT_EXPORTED) {
10667532Smckusick vput(vp);
10767532Smckusick return (EPERM);
10867532Smckusick }
10968318Scgd SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
11067532Smckusick }
11169578Smckusick if (vfs_busy(mp, LK_NOWAIT, 0, p)) {
11269578Smckusick vput(vp);
11369578Smckusick return (EBUSY);
11469578Smckusick }
11569409Smckusick VOP_UNLOCK(vp, 0, p);
11639335Smckusick goto update;
11739335Smckusick }
11867532Smckusick /*
11967532Smckusick * If the user is not root, ensure that they own the directory
12067532Smckusick * onto which we are attempting to mount.
12167532Smckusick */
12267532Smckusick if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) ||
12367532Smckusick (va.va_uid != p->p_ucred->cr_uid &&
12467532Smckusick (error = suser(p->p_ucred, &p->p_acflag)))) {
12567532Smckusick vput(vp);
12667532Smckusick return (error);
12767532Smckusick }
12867532Smckusick /*
12967532Smckusick * Do not allow NFS export by non-root users. Silently
13067532Smckusick * enforce MNT_NOSUID and MNT_NODEV for non-root users.
13167532Smckusick */
13267532Smckusick if (p->p_ucred->cr_uid != 0) {
13368318Scgd if (SCARG(uap, flags) & MNT_EXPORTED) {
13467532Smckusick vput(vp);
13567532Smckusick return (EPERM);
13667532Smckusick }
13768318Scgd SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
13867532Smckusick }
13957793Smckusick if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0))
14054441Smckusick return (error);
14137741Smckusick if (vp->v_type != VDIR) {
14237741Smckusick vput(vp);
14347540Skarels return (ENOTDIR);
14437741Smckusick }
14568663Smckusick #ifdef COMPAT_43
14668663Smckusick /*
14768663Smckusick * Historically filesystem types were identified by number. If we
14868663Smckusick * get an integer for the filesystem type instead of a string, we
14968663Smckusick * check to see if it matches one of the historic filesystem types.
15068663Smckusick */
15168663Smckusick fstypenum = (u_long)SCARG(uap, type);
15268663Smckusick if (fstypenum < maxvfsconf) {
15368663Smckusick for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
15468663Smckusick if (vfsp->vfc_typenum == fstypenum)
15568663Smckusick break;
15668663Smckusick if (vfsp == NULL) {
15768663Smckusick vput(vp);
15868663Smckusick return (ENODEV);
15968663Smckusick }
16068663Smckusick strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN);
16168663Smckusick } else
16268663Smckusick #endif /* COMPAT_43 */
16368663Smckusick if (error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL)) {
16437741Smckusick vput(vp);
16568663Smckusick return (error);
16668663Smckusick }
16768663Smckusick for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
16868663Smckusick if (!strcmp(vfsp->vfc_name, fstypename))
16968663Smckusick break;
17068663Smckusick if (vfsp == NULL) {
17168663Smckusick vput(vp);
17247540Skarels return (ENODEV);
17337741Smckusick }
17467969Spendry if (vp->v_mountedhere != NULL) {
17567961Smckusick vput(vp);
17667961Smckusick return (EBUSY);
17767961Smckusick }
17837741Smckusick
17937741Smckusick /*
18068663Smckusick * Allocate and initialize the filesystem.
18137741Smckusick */
18237741Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount),
18337741Smckusick M_MOUNT, M_WAITOK);
18454172Smckusick bzero((char *)mp, (u_long)sizeof(struct mount));
18569578Smckusick lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0);
18669578Smckusick (void)vfs_busy(mp, LK_NOWAIT, 0, p);
18768663Smckusick mp->mnt_op = vfsp->vfc_vfsops;
18868663Smckusick mp->mnt_vfc = vfsp;
18968663Smckusick vfsp->vfc_refcount++;
19068663Smckusick mp->mnt_stat.f_type = vfsp->vfc_typenum;
19168663Smckusick mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
19268663Smckusick strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
19339335Smckusick vp->v_mountedhere = mp;
19441400Smckusick mp->mnt_vnodecovered = vp;
19567532Smckusick mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
19639335Smckusick update:
19739335Smckusick /*
19839335Smckusick * Set the mount level flags.
19939335Smckusick */
20068318Scgd if (SCARG(uap, flags) & MNT_RDONLY)
20141400Smckusick mp->mnt_flag |= MNT_RDONLY;
20257047Smckusick else if (mp->mnt_flag & MNT_RDONLY)
20357047Smckusick mp->mnt_flag |= MNT_WANTRDWR;
20465613Smckusick mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
20565613Smckusick MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC);
20668318Scgd mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC |
20768318Scgd MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC);
20839335Smckusick /*
20939335Smckusick * Mount the filesystem.
21039335Smckusick */
21168318Scgd error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p);
21241400Smckusick if (mp->mnt_flag & MNT_UPDATE) {
21339335Smckusick vrele(vp);
21457047Smckusick if (mp->mnt_flag & MNT_WANTRDWR)
21557047Smckusick mp->mnt_flag &= ~MNT_RDONLY;
21657047Smckusick mp->mnt_flag &=~
21757047Smckusick (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR);
21840111Smckusick if (error)
21941400Smckusick mp->mnt_flag = flag;
22069578Smckusick vfs_unbusy(mp, p);
22147540Skarels return (error);
22239335Smckusick }
22340110Smckusick /*
22440110Smckusick * Put the new filesystem on the mount list after root.
22540110Smckusick */
22637741Smckusick cache_purge(vp);
22737741Smckusick if (!error) {
22869578Smckusick simple_lock(&mountlist_slock);
22969325Smckusick CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
23069578Smckusick simple_unlock(&mountlist_slock);
23167974Smckusick checkdirs(vp);
23269409Smckusick VOP_UNLOCK(vp, 0, p);
23369578Smckusick vfs_unbusy(mp, p);
23469578Smckusick if (error = VFS_START(mp, 0, p))
23569578Smckusick vrele(vp);
23637741Smckusick } else {
23765259Smckusick mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
23868663Smckusick mp->mnt_vfc->vfc_refcount--;
23969578Smckusick vfs_unbusy(mp, p);
24037741Smckusick free((caddr_t)mp, M_MOUNT);
24139335Smckusick vput(vp);
24237741Smckusick }
24347540Skarels return (error);
2446254Sroot }
2456254Sroot
2469167Ssam /*
24767974Smckusick * Scan all active processes to see if any of them have a current
24867974Smckusick * or root directory onto which the new filesystem has just been
24967974Smckusick * mounted. If so, replace them with the new mount point.
25067974Smckusick */
25168318Scgd static void
checkdirs(olddp)25267974Smckusick checkdirs(olddp)
25367974Smckusick struct vnode *olddp;
25467974Smckusick {
25567974Smckusick struct filedesc *fdp;
25667974Smckusick struct vnode *newdp;
25767974Smckusick struct proc *p;
25867974Smckusick
25967974Smckusick if (olddp->v_usecount == 1)
26067974Smckusick return;
26167974Smckusick if (VFS_ROOT(olddp->v_mountedhere, &newdp))
26267974Smckusick panic("mount: lost mount");
26367974Smckusick for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
26467974Smckusick fdp = p->p_fd;
26567974Smckusick if (fdp->fd_cdir == olddp) {
26667974Smckusick vrele(fdp->fd_cdir);
26767974Smckusick VREF(newdp);
26867974Smckusick fdp->fd_cdir = newdp;
26967974Smckusick }
27067974Smckusick if (fdp->fd_rdir == olddp) {
27167974Smckusick vrele(fdp->fd_rdir);
27267974Smckusick VREF(newdp);
27367974Smckusick fdp->fd_rdir = newdp;
27467974Smckusick }
27567974Smckusick }
27667974Smckusick if (rootvnode == olddp) {
27767974Smckusick vrele(rootvnode);
27867974Smckusick VREF(newdp);
27967974Smckusick rootvnode = newdp;
28067974Smckusick }
28167974Smckusick vput(newdp);
28267974Smckusick }
28367974Smckusick
28467974Smckusick /*
28564410Sbostic * Unmount a file system.
28637741Smckusick *
28737741Smckusick * Note: unmount takes a path to the vnode mounted on as argument,
28837741Smckusick * not special file (as before).
2899167Ssam */
29042441Smckusick /* ARGSUSED */
29168318Scgd int
unmount(p,uap,retval)29242441Smckusick unmount(p, uap, retval)
29345914Smckusick struct proc *p;
29468318Scgd register struct unmount_args /* {
29568318Scgd syscallarg(char *) path;
29668318Scgd syscallarg(int) flags;
29768318Scgd } */ *uap;
29868318Scgd register_t *retval;
29942441Smckusick {
30037741Smckusick register struct vnode *vp;
30139356Smckusick struct mount *mp;
30237741Smckusick int error;
30347540Skarels struct nameidata nd;
3046254Sroot
30568318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
30668318Scgd SCARG(uap, path), p);
30752322Smckusick if (error = namei(&nd))
30847540Skarels return (error);
30952322Smckusick vp = nd.ni_vp;
31067532Smckusick mp = vp->v_mount;
31166172Spendry
31237741Smckusick /*
31367532Smckusick * Only root, or the user that did the original mount is
31467532Smckusick * permitted to unmount this filesystem.
31566172Spendry */
31667532Smckusick if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) &&
31766172Spendry (error = suser(p->p_ucred, &p->p_acflag))) {
31866172Spendry vput(vp);
31966172Spendry return (error);
32066172Spendry }
32166172Spendry
32266172Spendry /*
32369334Smckusick * Don't allow unmounting the root file system.
32469334Smckusick */
32569334Smckusick if (mp->mnt_flag & MNT_ROOTFS) {
32669334Smckusick vput(vp);
32769334Smckusick return (EINVAL);
32869334Smckusick }
32969334Smckusick
33069334Smckusick /*
33137741Smckusick * Must be the root of the filesystem
33237741Smckusick */
33337741Smckusick if ((vp->v_flag & VROOT) == 0) {
33437741Smckusick vput(vp);
33547540Skarels return (EINVAL);
33637741Smckusick }
33737741Smckusick vput(vp);
33868318Scgd return (dounmount(mp, SCARG(uap, flags), p));
33939356Smckusick }
34039356Smckusick
34139356Smckusick /*
34264410Sbostic * Do the actual file system unmount.
34339356Smckusick */
34468318Scgd int
dounmount(mp,flags,p)34548026Smckusick dounmount(mp, flags, p)
34639356Smckusick register struct mount *mp;
34739356Smckusick int flags;
34848026Smckusick struct proc *p;
34939356Smckusick {
35039356Smckusick struct vnode *coveredvp;
35139356Smckusick int error;
35239356Smckusick
35369578Smckusick simple_lock(&mountlist_slock);
35441400Smckusick mp->mnt_flag |= MNT_UNMOUNT;
35569578Smckusick lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_slock, p);
35665859Smckusick mp->mnt_flag &=~ MNT_ASYNC;
35745738Smckusick vnode_pager_umount(mp); /* release cached vnodes */
35837741Smckusick cache_purgevfs(mp); /* remove cache entries for this file sys */
35969357Spendry if (((mp->mnt_flag & MNT_RDONLY) ||
36069357Spendry (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) ||
36154441Smckusick (flags & MNT_FORCE))
36248026Smckusick error = VFS_UNMOUNT(mp, flags, p);
36369578Smckusick simple_lock(&mountlist_slock);
36437741Smckusick if (error) {
36569578Smckusick mp->mnt_flag &= ~MNT_UNMOUNT;
36669578Smckusick lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK | LK_REENABLE,
36769578Smckusick &mountlist_slock, p);
36869578Smckusick return (error);
36937741Smckusick }
37069578Smckusick CIRCLEQ_REMOVE(&mountlist, mp, mnt_list);
37169578Smckusick if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) {
37269578Smckusick coveredvp->v_mountedhere = (struct mount *)0;
37369578Smckusick vrele(coveredvp);
37469578Smckusick }
37569578Smckusick mp->mnt_vfc->vfc_refcount--;
37669578Smckusick if (mp->mnt_vnodelist.lh_first != NULL)
37769578Smckusick panic("unmount: dangling vnode");
37869578Smckusick lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock, p);
37969578Smckusick if (mp->mnt_flag & MNT_MWAIT)
38069578Smckusick wakeup((caddr_t)mp);
38169578Smckusick free((caddr_t)mp, M_MOUNT);
38269578Smckusick return (0);
3836254Sroot }
3846254Sroot
3859167Ssam /*
38637741Smckusick * Sync each mounted filesystem.
3879167Ssam */
38867403Smckusick #ifdef DEBUG
38956352Smckusick int syncprt = 0;
39059875Smckusick struct ctldebug debug0 = { "syncprt", &syncprt };
39156352Smckusick #endif
39256352Smckusick
39339491Smckusick /* ARGSUSED */
39468318Scgd int
sync(p,uap,retval)39542441Smckusick sync(p, uap, retval)
39645914Smckusick struct proc *p;
39768318Scgd void *uap;
39868318Scgd register_t *retval;
3996254Sroot {
40065259Smckusick register struct mount *mp, *nmp;
40165859Smckusick int asyncflag;
40237741Smckusick
40369578Smckusick simple_lock(&mountlist_slock);
40469325Smckusick for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
40569578Smckusick if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
40669578Smckusick nmp = mp->mnt_list.cqe_next;
40769578Smckusick continue;
40869578Smckusick }
40969578Smckusick if ((mp->mnt_flag & MNT_RDONLY) == 0) {
41065859Smckusick asyncflag = mp->mnt_flag & MNT_ASYNC;
41165859Smckusick mp->mnt_flag &= ~MNT_ASYNC;
41254441Smckusick VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
41365859Smckusick if (asyncflag)
41465859Smckusick mp->mnt_flag |= MNT_ASYNC;
41565259Smckusick }
41669578Smckusick simple_lock(&mountlist_slock);
41769578Smckusick nmp = mp->mnt_list.cqe_next;
41869578Smckusick vfs_unbusy(mp, p);
41965259Smckusick }
42069578Smckusick simple_unlock(&mountlist_slock);
42156352Smckusick #ifdef DIAGNOSTIC
42256352Smckusick if (syncprt)
42356352Smckusick vfs_bufstats();
42456352Smckusick #endif /* DIAGNOSTIC */
42547688Skarels return (0);
42637741Smckusick }
42737741Smckusick
42837741Smckusick /*
42964410Sbostic * Change filesystem quotas.
43041298Smckusick */
43142441Smckusick /* ARGSUSED */
43268318Scgd int
quotactl(p,uap,retval)43342441Smckusick quotactl(p, uap, retval)
43445914Smckusick struct proc *p;
43568318Scgd register struct quotactl_args /* {
43668318Scgd syscallarg(char *) path;
43768318Scgd syscallarg(int) cmd;
43868318Scgd syscallarg(int) uid;
43968318Scgd syscallarg(caddr_t) arg;
44068318Scgd } */ *uap;
44168318Scgd register_t *retval;
44242441Smckusick {
44341298Smckusick register struct mount *mp;
44441298Smckusick int error;
44547540Skarels struct nameidata nd;
44641298Smckusick
44768318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
44852322Smckusick if (error = namei(&nd))
44947540Skarels return (error);
45052322Smckusick mp = nd.ni_vp->v_mount;
45152322Smckusick vrele(nd.ni_vp);
45268318Scgd return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
45368318Scgd SCARG(uap, arg), p));
45441298Smckusick }
45541298Smckusick
45641298Smckusick /*
45749365Smckusick * Get filesystem statistics.
45837741Smckusick */
45942441Smckusick /* ARGSUSED */
46068318Scgd int
statfs(p,uap,retval)46142441Smckusick statfs(p, uap, retval)
46245914Smckusick struct proc *p;
46368318Scgd register struct statfs_args /* {
46468318Scgd syscallarg(char *) path;
46568318Scgd syscallarg(struct statfs *) buf;
46668318Scgd } */ *uap;
46768318Scgd register_t *retval;
46842441Smckusick {
46939464Smckusick register struct mount *mp;
47040343Smckusick register struct statfs *sp;
47137741Smckusick int error;
47247540Skarels struct nameidata nd;
47337741Smckusick
47468318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
47552322Smckusick if (error = namei(&nd))
47647540Skarels return (error);
47752322Smckusick mp = nd.ni_vp->v_mount;
47841400Smckusick sp = &mp->mnt_stat;
47952322Smckusick vrele(nd.ni_vp);
48048026Smckusick if (error = VFS_STATFS(mp, sp, p))
48147540Skarels return (error);
48241400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
48368318Scgd return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
48437741Smckusick }
48537741Smckusick
48642441Smckusick /*
48749365Smckusick * Get filesystem statistics.
48842441Smckusick */
48942441Smckusick /* ARGSUSED */
49068318Scgd int
fstatfs(p,uap,retval)49142441Smckusick fstatfs(p, uap, retval)
49245914Smckusick struct proc *p;
49368318Scgd register struct fstatfs_args /* {
49468318Scgd syscallarg(int) fd;
49568318Scgd syscallarg(struct statfs *) buf;
49668318Scgd } */ *uap;
49768318Scgd register_t *retval;
49842441Smckusick {
49937741Smckusick struct file *fp;
50039464Smckusick struct mount *mp;
50140343Smckusick register struct statfs *sp;
50237741Smckusick int error;
50337741Smckusick
50468318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
50547540Skarels return (error);
50639464Smckusick mp = ((struct vnode *)fp->f_data)->v_mount;
50741400Smckusick sp = &mp->mnt_stat;
50848026Smckusick if (error = VFS_STATFS(mp, sp, p))
50947540Skarels return (error);
51041400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
51168318Scgd return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
51237741Smckusick }
51337741Smckusick
51437741Smckusick /*
51549365Smckusick * Get statistics on all filesystems.
51638270Smckusick */
51768318Scgd int
getfsstat(p,uap,retval)51842441Smckusick getfsstat(p, uap, retval)
51945914Smckusick struct proc *p;
52068318Scgd register struct getfsstat_args /* {
52168318Scgd syscallarg(struct statfs *) buf;
52268318Scgd syscallarg(long) bufsize;
52368318Scgd syscallarg(int) flags;
52468318Scgd } */ *uap;
52568318Scgd register_t *retval;
52642441Smckusick {
52765259Smckusick register struct mount *mp, *nmp;
52840343Smckusick register struct statfs *sp;
52939606Smckusick caddr_t sfsp;
53038270Smckusick long count, maxcount, error;
53138270Smckusick
53268318Scgd maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
53368318Scgd sfsp = (caddr_t)SCARG(uap, buf);
53469325Smckusick count = 0;
53569578Smckusick simple_lock(&mountlist_slock);
53669325Smckusick for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
53769578Smckusick if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
53869578Smckusick nmp = mp->mnt_list.cqe_next;
53969578Smckusick continue;
54069578Smckusick }
54169578Smckusick if (sfsp && count < maxcount) {
54241400Smckusick sp = &mp->mnt_stat;
54340343Smckusick /*
54440343Smckusick * If MNT_NOWAIT is specified, do not refresh the
54540343Smckusick * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
54640343Smckusick */
54768318Scgd if (((SCARG(uap, flags) & MNT_NOWAIT) == 0 ||
54868318Scgd (SCARG(uap, flags) & MNT_WAIT)) &&
549*69903Smckusick (error = VFS_STATFS(mp, sp, p))) {
550*69903Smckusick simple_lock(&mountlist_slock);
551*69903Smckusick nmp = mp->mnt_list.cqe_next;
552*69903Smckusick vfs_unbusy(mp, p);
55339607Smckusick continue;
554*69903Smckusick }
55541400Smckusick sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
55640343Smckusick if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
55747540Skarels return (error);
55840343Smckusick sfsp += sizeof(*sp);
55938270Smckusick }
56039606Smckusick count++;
56169578Smckusick simple_lock(&mountlist_slock);
56269578Smckusick nmp = mp->mnt_list.cqe_next;
56369578Smckusick vfs_unbusy(mp, p);
56465259Smckusick }
56569578Smckusick simple_unlock(&mountlist_slock);
56638270Smckusick if (sfsp && count > maxcount)
56742441Smckusick *retval = maxcount;
56838270Smckusick else
56942441Smckusick *retval = count;
57047540Skarels return (0);
57138270Smckusick }
57238270Smckusick
57338270Smckusick /*
57438259Smckusick * Change current working directory to a given file descriptor.
57538259Smckusick */
57642441Smckusick /* ARGSUSED */
57768318Scgd int
fchdir(p,uap,retval)57842441Smckusick fchdir(p, uap, retval)
57945914Smckusick struct proc *p;
58068318Scgd struct fchdir_args /* {
58168318Scgd syscallarg(int) fd;
58268318Scgd } */ *uap;
58368318Scgd register_t *retval;
58438259Smckusick {
58545914Smckusick register struct filedesc *fdp = p->p_fd;
58667974Smckusick struct vnode *vp, *tdp;
58767974Smckusick struct mount *mp;
58838259Smckusick struct file *fp;
58938259Smckusick int error;
59038259Smckusick
59168318Scgd if (error = getvnode(fdp, SCARG(uap, fd), &fp))
59247540Skarels return (error);
59338259Smckusick vp = (struct vnode *)fp->f_data;
59467974Smckusick VREF(vp);
59569409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
59638259Smckusick if (vp->v_type != VDIR)
59738259Smckusick error = ENOTDIR;
59838259Smckusick else
59948026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
60067974Smckusick while (!error && (mp = vp->v_mountedhere) != NULL) {
60169578Smckusick if (vfs_busy(mp, 0, 0, p))
60267974Smckusick continue;
60369578Smckusick error = VFS_ROOT(mp, &tdp);
60469578Smckusick vfs_unbusy(mp, p);
60569578Smckusick if (error)
60667974Smckusick break;
60767974Smckusick vput(vp);
60867974Smckusick vp = tdp;
60967974Smckusick }
61067974Smckusick if (error) {
61169547Spendry vput(vp);
61247540Skarels return (error);
61367974Smckusick }
61469547Spendry VOP_UNLOCK(vp, 0, p);
61545914Smckusick vrele(fdp->fd_cdir);
61645914Smckusick fdp->fd_cdir = vp;
61747540Skarels return (0);
61838259Smckusick }
61938259Smckusick
62038259Smckusick /*
62137741Smckusick * Change current working directory (``.'').
62237741Smckusick */
62342441Smckusick /* ARGSUSED */
62468318Scgd int
chdir(p,uap,retval)62542441Smckusick chdir(p, uap, retval)
62645914Smckusick struct proc *p;
62768318Scgd struct chdir_args /* {
62868318Scgd syscallarg(char *) path;
62968318Scgd } */ *uap;
63068318Scgd register_t *retval;
63137741Smckusick {
63245914Smckusick register struct filedesc *fdp = p->p_fd;
63337741Smckusick int error;
63447540Skarels struct nameidata nd;
6356254Sroot
63668318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
63768318Scgd SCARG(uap, path), p);
63864410Sbostic if (error = change_dir(&nd, p))
63947540Skarels return (error);
64045914Smckusick vrele(fdp->fd_cdir);
64152322Smckusick fdp->fd_cdir = nd.ni_vp;
64247540Skarels return (0);
64337741Smckusick }
6446254Sroot
64537741Smckusick /*
64637741Smckusick * Change notion of root (``/'') directory.
64737741Smckusick */
64842441Smckusick /* ARGSUSED */
64968318Scgd int
chroot(p,uap,retval)65042441Smckusick chroot(p, uap, retval)
65145914Smckusick struct proc *p;
65268318Scgd struct chroot_args /* {
65368318Scgd syscallarg(char *) path;
65468318Scgd } */ *uap;
65568318Scgd register_t *retval;
65637741Smckusick {
65745914Smckusick register struct filedesc *fdp = p->p_fd;
65837741Smckusick int error;
65947540Skarels struct nameidata nd;
66037741Smckusick
66147540Skarels if (error = suser(p->p_ucred, &p->p_acflag))
66247540Skarels return (error);
66368318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
66468318Scgd SCARG(uap, path), p);
66564410Sbostic if (error = change_dir(&nd, p))
66647540Skarels return (error);
66745914Smckusick if (fdp->fd_rdir != NULL)
66845914Smckusick vrele(fdp->fd_rdir);
66952322Smckusick fdp->fd_rdir = nd.ni_vp;
67047540Skarels return (0);
6716254Sroot }
6726254Sroot
67337Sbill /*
67437741Smckusick * Common routine for chroot and chdir.
67537741Smckusick */
67664410Sbostic static int
change_dir(ndp,p)67764410Sbostic change_dir(ndp, p)
67852322Smckusick register struct nameidata *ndp;
67947540Skarels struct proc *p;
68037741Smckusick {
68137741Smckusick struct vnode *vp;
68237741Smckusick int error;
68337741Smckusick
68452322Smckusick if (error = namei(ndp))
68537741Smckusick return (error);
68637741Smckusick vp = ndp->ni_vp;
68737741Smckusick if (vp->v_type != VDIR)
68837741Smckusick error = ENOTDIR;
68937741Smckusick else
69048026Smckusick error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
69137741Smckusick if (error)
69269547Spendry vput(vp);
69369547Spendry else
69469547Spendry VOP_UNLOCK(vp, 0, p);
69537741Smckusick return (error);
69637741Smckusick }
69737741Smckusick
69837741Smckusick /*
69942441Smckusick * Check permissions, allocate an open file structure,
70042441Smckusick * and call the device open routine if any.
7016254Sroot */
70268318Scgd int
open(p,uap,retval)70342441Smckusick open(p, uap, retval)
70445914Smckusick struct proc *p;
70568318Scgd register struct open_args /* {
70668318Scgd syscallarg(char *) path;
70768318Scgd syscallarg(int) flags;
70868318Scgd syscallarg(int) mode;
70968318Scgd } */ *uap;
71068318Scgd register_t *retval;
7116254Sroot {
71245914Smckusick register struct filedesc *fdp = p->p_fd;
71342441Smckusick register struct file *fp;
71450111Smckusick register struct vnode *vp;
71564410Sbostic int flags, cmode;
71637741Smckusick struct file *nfp;
71749945Smckusick int type, indx, error;
71849945Smckusick struct flock lf;
71947540Skarels struct nameidata nd;
72037741Smckusick extern struct fileops vnops;
7216254Sroot
72245914Smckusick if (error = falloc(p, &nfp, &indx))
72347540Skarels return (error);
72437741Smckusick fp = nfp;
72568318Scgd flags = FFLAGS(SCARG(uap, flags));
72668318Scgd cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
72768318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
72845202Smckusick p->p_dupfd = -indx - 1; /* XXX check for fdopen */
72964410Sbostic if (error = vn_open(&nd, flags, cmode)) {
73049980Smckusick ffree(fp);
73154723Smckusick if ((error == ENODEV || error == ENXIO) &&
73268318Scgd p->p_dupfd >= 0 && /* XXX from fdopen */
73364410Sbostic (error =
73468318Scgd dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
73542441Smckusick *retval = indx;
73647540Skarels return (0);
73742441Smckusick }
73840884Smckusick if (error == ERESTART)
73940884Smckusick error = EINTR;
74047688Skarels fdp->fd_ofiles[indx] = NULL;
74147540Skarels return (error);
74212756Ssam }
74353828Spendry p->p_dupfd = 0;
74452322Smckusick vp = nd.ni_vp;
74564410Sbostic fp->f_flag = flags & FMASK;
74654348Smckusick fp->f_type = DTYPE_VNODE;
74754348Smckusick fp->f_ops = &vnops;
74854348Smckusick fp->f_data = (caddr_t)vp;
74964410Sbostic if (flags & (O_EXLOCK | O_SHLOCK)) {
75049945Smckusick lf.l_whence = SEEK_SET;
75149945Smckusick lf.l_start = 0;
75249945Smckusick lf.l_len = 0;
75364410Sbostic if (flags & O_EXLOCK)
75449945Smckusick lf.l_type = F_WRLCK;
75549945Smckusick else
75649945Smckusick lf.l_type = F_RDLCK;
75749945Smckusick type = F_FLOCK;
75864410Sbostic if ((flags & FNONBLOCK) == 0)
75949945Smckusick type |= F_WAIT;
76069409Smckusick VOP_UNLOCK(vp, 0, p);
76150111Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
76250111Smckusick (void) vn_close(vp, fp->f_flag, fp->f_cred, p);
76349980Smckusick ffree(fp);
76449945Smckusick fdp->fd_ofiles[indx] = NULL;
76549945Smckusick return (error);
76649945Smckusick }
76769409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
76849949Smckusick fp->f_flag |= FHASLOCK;
76949945Smckusick }
77069409Smckusick VOP_UNLOCK(vp, 0, p);
77142441Smckusick *retval = indx;
77247540Skarels return (0);
7736254Sroot }
7746254Sroot
77542955Smckusick #ifdef COMPAT_43
7766254Sroot /*
77764410Sbostic * Create a file.
7786254Sroot */
77968318Scgd int
compat_43_creat(p,uap,retval)78068318Scgd compat_43_creat(p, uap, retval)
78142441Smckusick struct proc *p;
78268318Scgd register struct compat_43_creat_args /* {
78368318Scgd syscallarg(char *) path;
78468318Scgd syscallarg(int) mode;
78568318Scgd } */ *uap;
78668318Scgd register_t *retval;
7876254Sroot {
78868318Scgd struct open_args /* {
78968318Scgd syscallarg(char *) path;
79068318Scgd syscallarg(int) flags;
79168318Scgd syscallarg(int) mode;
79268318Scgd } */ nuap;
79342441Smckusick
79468318Scgd SCARG(&nuap, path) = SCARG(uap, path);
79568318Scgd SCARG(&nuap, mode) = SCARG(uap, mode);
79668318Scgd SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
79768318Scgd return (open(p, &nuap, retval));
79842441Smckusick }
79942955Smckusick #endif /* COMPAT_43 */
80042441Smckusick
80142441Smckusick /*
80264410Sbostic * Create a special file.
80342441Smckusick */
80442441Smckusick /* ARGSUSED */
80568318Scgd int
mknod(p,uap,retval)80642441Smckusick mknod(p, uap, retval)
80745914Smckusick struct proc *p;
80868318Scgd register struct mknod_args /* {
80968318Scgd syscallarg(char *) path;
81068318Scgd syscallarg(int) mode;
81168318Scgd syscallarg(int) dev;
81268318Scgd } */ *uap;
81368318Scgd register_t *retval;
81442441Smckusick {
81537741Smckusick register struct vnode *vp;
81637741Smckusick struct vattr vattr;
81737741Smckusick int error;
81867575Spendry int whiteout;
81947540Skarels struct nameidata nd;
8206254Sroot
82147540Skarels if (error = suser(p->p_ucred, &p->p_acflag))
82247540Skarels return (error);
82368318Scgd NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
82452322Smckusick if (error = namei(&nd))
82547540Skarels return (error);
82652322Smckusick vp = nd.ni_vp;
82764585Sbostic if (vp != NULL)
82837741Smckusick error = EEXIST;
82964585Sbostic else {
83064585Sbostic VATTR_NULL(&vattr);
83168318Scgd vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
83268318Scgd vattr.va_rdev = SCARG(uap, dev);
83367575Spendry whiteout = 0;
83464585Sbostic
83568318Scgd switch (SCARG(uap, mode) & S_IFMT) {
83664585Sbostic case S_IFMT: /* used by badsect to flag bad sectors */
83764585Sbostic vattr.va_type = VBAD;
83864585Sbostic break;
83964585Sbostic case S_IFCHR:
84064585Sbostic vattr.va_type = VCHR;
84164585Sbostic break;
84264585Sbostic case S_IFBLK:
84364585Sbostic vattr.va_type = VBLK;
84464585Sbostic break;
84567575Spendry case S_IFWHT:
84667575Spendry whiteout = 1;
84767575Spendry break;
84864585Sbostic default:
84964585Sbostic error = EINVAL;
85064585Sbostic break;
85164585Sbostic }
8526254Sroot }
85367747Spendry if (!error) {
85467654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
85567747Spendry if (whiteout) {
85667747Spendry error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
85767747Spendry if (error)
85867747Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
85967747Spendry vput(nd.ni_dvp);
86067747Spendry } else {
86167747Spendry error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
86267747Spendry &nd.ni_cnd, &vattr);
86367747Spendry }
86442465Smckusick } else {
86552322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
86652322Smckusick if (nd.ni_dvp == vp)
86752322Smckusick vrele(nd.ni_dvp);
86843344Smckusick else
86952322Smckusick vput(nd.ni_dvp);
87042465Smckusick if (vp)
87142465Smckusick vrele(vp);
87242465Smckusick }
87347540Skarels return (error);
8746254Sroot }
8756254Sroot
8766254Sroot /*
87768318Scgd * Create a named pipe.
87840285Smckusick */
87942441Smckusick /* ARGSUSED */
88068318Scgd int
mkfifo(p,uap,retval)88142441Smckusick mkfifo(p, uap, retval)
88245914Smckusick struct proc *p;
88368318Scgd register struct mkfifo_args /* {
88468318Scgd syscallarg(char *) path;
88568318Scgd syscallarg(int) mode;
88668318Scgd } */ *uap;
88768318Scgd register_t *retval;
88842441Smckusick {
88940285Smckusick struct vattr vattr;
89040285Smckusick int error;
89147540Skarels struct nameidata nd;
89240285Smckusick
89340285Smckusick #ifndef FIFO
89447540Skarels return (EOPNOTSUPP);
89540285Smckusick #else
89668318Scgd NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
89752322Smckusick if (error = namei(&nd))
89847540Skarels return (error);
89952322Smckusick if (nd.ni_vp != NULL) {
90052322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
90152322Smckusick if (nd.ni_dvp == nd.ni_vp)
90252322Smckusick vrele(nd.ni_dvp);
90343344Smckusick else
90452322Smckusick vput(nd.ni_dvp);
90552322Smckusick vrele(nd.ni_vp);
90647540Skarels return (EEXIST);
90740285Smckusick }
90845785Sbostic VATTR_NULL(&vattr);
90945785Sbostic vattr.va_type = VFIFO;
91068318Scgd vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
91167654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
91252322Smckusick return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
91340285Smckusick #endif /* FIFO */
91440285Smckusick }
91540285Smckusick
91640285Smckusick /*
91764410Sbostic * Make a hard file link.
9186254Sroot */
91942441Smckusick /* ARGSUSED */
92068318Scgd int
link(p,uap,retval)92142441Smckusick link(p, uap, retval)
92245914Smckusick struct proc *p;
92368318Scgd register struct link_args /* {
92468318Scgd syscallarg(char *) path;
92568318Scgd syscallarg(char *) link;
92668318Scgd } */ *uap;
92768318Scgd register_t *retval;
92842441Smckusick {
92964410Sbostic register struct vnode *vp;
93064410Sbostic struct nameidata nd;
93137741Smckusick int error;
9326254Sroot
93368318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
93452322Smckusick if (error = namei(&nd))
93547540Skarels return (error);
93652322Smckusick vp = nd.ni_vp;
93764585Sbostic if (vp->v_type != VDIR ||
93864585Sbostic (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
93964585Sbostic nd.ni_cnd.cn_nameiop = CREATE;
94064585Sbostic nd.ni_cnd.cn_flags = LOCKPARENT;
94168318Scgd nd.ni_dirp = SCARG(uap, link);
94264585Sbostic if ((error = namei(&nd)) == 0) {
94364585Sbostic if (nd.ni_vp != NULL)
94464585Sbostic error = EEXIST;
94564585Sbostic if (!error) {
94667654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred,
94767654Smckusick LEASE_WRITE);
94867654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
94968538Smckusick error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd);
95064585Sbostic } else {
95164585Sbostic VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
95264585Sbostic if (nd.ni_dvp == nd.ni_vp)
95364585Sbostic vrele(nd.ni_dvp);
95464585Sbostic else
95564585Sbostic vput(nd.ni_dvp);
95664585Sbostic if (nd.ni_vp)
95764585Sbostic vrele(nd.ni_vp);
95864585Sbostic }
95964585Sbostic }
96042465Smckusick }
96164585Sbostic vrele(vp);
96247540Skarels return (error);
9636254Sroot }
9646254Sroot
9656254Sroot /*
96649365Smckusick * Make a symbolic link.
9676254Sroot */
96842441Smckusick /* ARGSUSED */
96968318Scgd int
symlink(p,uap,retval)97042441Smckusick symlink(p, uap, retval)
97145914Smckusick struct proc *p;
97268318Scgd register struct symlink_args /* {
97368318Scgd syscallarg(char *) path;
97468318Scgd syscallarg(char *) link;
97568318Scgd } */ *uap;
97668318Scgd register_t *retval;
97742441Smckusick {
97837741Smckusick struct vattr vattr;
97964410Sbostic char *path;
98037741Smckusick int error;
98147540Skarels struct nameidata nd;
9826254Sroot
98364410Sbostic MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
98468318Scgd if (error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL))
98542465Smckusick goto out;
98668318Scgd NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p);
98752322Smckusick if (error = namei(&nd))
98842465Smckusick goto out;
98952322Smckusick if (nd.ni_vp) {
99052322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
99152322Smckusick if (nd.ni_dvp == nd.ni_vp)
99252322Smckusick vrele(nd.ni_dvp);
99343344Smckusick else
99452322Smckusick vput(nd.ni_dvp);
99552322Smckusick vrele(nd.ni_vp);
99637741Smckusick error = EEXIST;
99737741Smckusick goto out;
9986254Sroot }
99941362Smckusick VATTR_NULL(&vattr);
100064410Sbostic vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
100167654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
100264410Sbostic error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
100337741Smckusick out:
100464410Sbostic FREE(path, M_NAMEI);
100547540Skarels return (error);
10066254Sroot }
10076254Sroot
10086254Sroot /*
100967518Spendry * Delete a whiteout from the filesystem.
101067518Spendry */
101167518Spendry /* ARGSUSED */
101268318Scgd int
undelete(p,uap,retval)101367845Smckusick undelete(p, uap, retval)
101467518Spendry struct proc *p;
101568318Scgd register struct undelete_args /* {
101668318Scgd syscallarg(char *) path;
101768318Scgd } */ *uap;
101868318Scgd register_t *retval;
101967518Spendry {
102067518Spendry int error;
102167518Spendry struct nameidata nd;
102267518Spendry
102368318Scgd NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
102468318Scgd SCARG(uap, path), p);
102567575Spendry error = namei(&nd);
102667575Spendry if (error)
102767518Spendry return (error);
102867575Spendry
102967575Spendry if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
103067518Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
103167518Spendry if (nd.ni_dvp == nd.ni_vp)
103267518Spendry vrele(nd.ni_dvp);
103367518Spendry else
103467518Spendry vput(nd.ni_dvp);
103567518Spendry if (nd.ni_vp)
103667518Spendry vrele(nd.ni_vp);
103767518Spendry return (EEXIST);
103867518Spendry }
103967575Spendry
104067654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
104167747Spendry if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE))
104267575Spendry VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
104367518Spendry vput(nd.ni_dvp);
104467518Spendry return (error);
104567518Spendry }
104667518Spendry
104767518Spendry /*
104849365Smckusick * Delete a name from the filesystem.
10496254Sroot */
105042441Smckusick /* ARGSUSED */
105168318Scgd int
unlink(p,uap,retval)105242441Smckusick unlink(p, uap, retval)
105345914Smckusick struct proc *p;
105468318Scgd struct unlink_args /* {
105568318Scgd syscallarg(char *) path;
105668318Scgd } */ *uap;
105768318Scgd register_t *retval;
10586254Sroot {
105937741Smckusick register struct vnode *vp;
106037741Smckusick int error;
106147540Skarels struct nameidata nd;
10626254Sroot
106368318Scgd NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
106452322Smckusick if (error = namei(&nd))
106547540Skarels return (error);
106652322Smckusick vp = nd.ni_vp;
106767654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
106869409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
106964410Sbostic
107064585Sbostic if (vp->v_type != VDIR ||
107164585Sbostic (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
107264585Sbostic /*
107364585Sbostic * The root of a mounted filesystem cannot be deleted.
107464585Sbostic */
107564585Sbostic if (vp->v_flag & VROOT)
107664585Sbostic error = EBUSY;
107764585Sbostic else
107864585Sbostic (void)vnode_pager_uncache(vp);
107964585Sbostic }
108064585Sbostic
108164585Sbostic if (!error) {
108267654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
108352322Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
108442465Smckusick } else {
108552322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
108652322Smckusick if (nd.ni_dvp == vp)
108752322Smckusick vrele(nd.ni_dvp);
108843344Smckusick else
108952322Smckusick vput(nd.ni_dvp);
109067575Spendry if (vp != NULLVP)
109167575Spendry vput(vp);
109242465Smckusick }
109347540Skarels return (error);
10946254Sroot }
10956254Sroot
109664410Sbostic /*
109764410Sbostic * Reposition read/write file offset.
109864410Sbostic */
109968318Scgd int
lseek(p,uap,retval)110060414Smckusick lseek(p, uap, retval)
110153468Smckusick struct proc *p;
110268318Scgd register struct lseek_args /* {
110368318Scgd syscallarg(int) fd;
110468318Scgd syscallarg(int) pad;
110568318Scgd syscallarg(off_t) offset;
110668318Scgd syscallarg(int) whence;
110768318Scgd } */ *uap;
110868318Scgd register_t *retval;
110942441Smckusick {
111047540Skarels struct ucred *cred = p->p_ucred;
111145914Smckusick register struct filedesc *fdp = p->p_fd;
111242441Smckusick register struct file *fp;
111337741Smckusick struct vattr vattr;
111437741Smckusick int error;
11156254Sroot
111668318Scgd if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
111768318Scgd (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
111847540Skarels return (EBADF);
111937741Smckusick if (fp->f_type != DTYPE_VNODE)
112047540Skarels return (ESPIPE);
112168318Scgd switch (SCARG(uap, whence)) {
112213878Ssam case L_INCR:
112368318Scgd fp->f_offset += SCARG(uap, offset);
112413878Ssam break;
112513878Ssam case L_XTND:
112664410Sbostic if (error =
112764410Sbostic VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p))
112847540Skarels return (error);
112968318Scgd fp->f_offset = SCARG(uap, offset) + vattr.va_size;
113013878Ssam break;
113113878Ssam case L_SET:
113268318Scgd fp->f_offset = SCARG(uap, offset);
113313878Ssam break;
113413878Ssam default:
113547540Skarels return (EINVAL);
113613878Ssam }
113754916Storek *(off_t *)retval = fp->f_offset;
113847540Skarels return (0);
11396254Sroot }
11406254Sroot
114160414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
11426254Sroot /*
114364410Sbostic * Reposition read/write file offset.
114460036Smckusick */
114568318Scgd int
compat_43_lseek(p,uap,retval)114668318Scgd compat_43_lseek(p, uap, retval)
114760036Smckusick struct proc *p;
114868318Scgd register struct compat_43_lseek_args /* {
114968318Scgd syscallarg(int) fd;
115068318Scgd syscallarg(long) offset;
115168318Scgd syscallarg(int) whence;
115268318Scgd } */ *uap;
115368318Scgd register_t *retval;
115460036Smckusick {
115568318Scgd struct lseek_args /* {
115668318Scgd syscallarg(int) fd;
115768318Scgd syscallarg(int) pad;
115868318Scgd syscallarg(off_t) offset;
115968318Scgd syscallarg(int) whence;
116068318Scgd } */ nuap;
116160036Smckusick off_t qret;
116260036Smckusick int error;
116360036Smckusick
116468318Scgd SCARG(&nuap, fd) = SCARG(uap, fd);
116568318Scgd SCARG(&nuap, offset) = SCARG(uap, offset);
116668318Scgd SCARG(&nuap, whence) = SCARG(uap, whence);
116760428Smckusick error = lseek(p, &nuap, &qret);
116860036Smckusick *(long *)retval = qret;
116960036Smckusick return (error);
117060036Smckusick }
117160414Smckusick #endif /* COMPAT_43 */
117260036Smckusick
117360036Smckusick /*
117449365Smckusick * Check access permissions.
11756254Sroot */
117668318Scgd int
access(p,uap,retval)117763427Sbostic access(p, uap, retval)
117845914Smckusick struct proc *p;
117968318Scgd register struct access_args /* {
118068318Scgd syscallarg(char *) path;
118168318Scgd syscallarg(int) flags;
118268318Scgd } */ *uap;
118368318Scgd register_t *retval;
118442441Smckusick {
118547540Skarels register struct ucred *cred = p->p_ucred;
118637741Smckusick register struct vnode *vp;
118764585Sbostic int error, flags, t_gid, t_uid;
118847540Skarels struct nameidata nd;
11896254Sroot
119064585Sbostic t_uid = cred->cr_uid;
119164585Sbostic t_gid = cred->cr_groups[0];
119247540Skarels cred->cr_uid = p->p_cred->p_ruid;
119347540Skarels cred->cr_groups[0] = p->p_cred->p_rgid;
119468318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
119568318Scgd SCARG(uap, path), p);
119652322Smckusick if (error = namei(&nd))
119737741Smckusick goto out1;
119852322Smckusick vp = nd.ni_vp;
119964410Sbostic
120064410Sbostic /* Flags == 0 means only check for existence. */
120168318Scgd if (SCARG(uap, flags)) {
120264410Sbostic flags = 0;
120368318Scgd if (SCARG(uap, flags) & R_OK)
120464410Sbostic flags |= VREAD;
120568318Scgd if (SCARG(uap, flags) & W_OK)
120664410Sbostic flags |= VWRITE;
120768318Scgd if (SCARG(uap, flags) & X_OK)
120864410Sbostic flags |= VEXEC;
120964410Sbostic if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
121064410Sbostic error = VOP_ACCESS(vp, flags, cred, p);
12116254Sroot }
121237741Smckusick vput(vp);
121337741Smckusick out1:
121464585Sbostic cred->cr_uid = t_uid;
121564585Sbostic cred->cr_groups[0] = t_gid;
121647540Skarels return (error);
12176254Sroot }
12186254Sroot
121954348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
12206254Sroot /*
122164410Sbostic * Get file status; this version follows links.
122237Sbill */
122342441Smckusick /* ARGSUSED */
122468318Scgd int
compat_43_stat(p,uap,retval)122568318Scgd compat_43_stat(p, uap, retval)
122645914Smckusick struct proc *p;
122768318Scgd register struct compat_43_stat_args /* {
122868318Scgd syscallarg(char *) path;
122968318Scgd syscallarg(struct ostat *) ub;
123068318Scgd } */ *uap;
123168318Scgd register_t *retval;
123253468Smckusick {
123353468Smckusick struct stat sb;
123453468Smckusick struct ostat osb;
123553468Smckusick int error;
123653468Smckusick struct nameidata nd;
123753468Smckusick
123868318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
123968318Scgd SCARG(uap, path), p);
124053468Smckusick if (error = namei(&nd))
124153468Smckusick return (error);
124253468Smckusick error = vn_stat(nd.ni_vp, &sb, p);
124353468Smckusick vput(nd.ni_vp);
124453468Smckusick if (error)
124553468Smckusick return (error);
124653468Smckusick cvtstat(&sb, &osb);
124768318Scgd error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
124853468Smckusick return (error);
124953468Smckusick }
125053468Smckusick
125153468Smckusick /*
125264410Sbostic * Get file status; this version does not follow links.
125353468Smckusick */
125453468Smckusick /* ARGSUSED */
125568318Scgd int
compat_43_lstat(p,uap,retval)125668318Scgd compat_43_lstat(p, uap, retval)
125753468Smckusick struct proc *p;
125868318Scgd register struct compat_43_lstat_args /* {
125968318Scgd syscallarg(char *) path;
126068318Scgd syscallarg(struct ostat *) ub;
126168318Scgd } */ *uap;
126268318Scgd register_t *retval;
126353468Smckusick {
126467748Smckusick struct vnode *vp, *dvp;
126567748Smckusick struct stat sb, sb1;
126653468Smckusick struct ostat osb;
126753468Smckusick int error;
126853468Smckusick struct nameidata nd;
126953468Smckusick
127067748Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
127168318Scgd SCARG(uap, path), p);
127253468Smckusick if (error = namei(&nd))
127353468Smckusick return (error);
127467748Smckusick /*
127567748Smckusick * For symbolic links, always return the attributes of its
127667748Smckusick * containing directory, except for mode, size, and links.
127767748Smckusick */
127867748Smckusick vp = nd.ni_vp;
127967748Smckusick dvp = nd.ni_dvp;
128067748Smckusick if (vp->v_type != VLNK) {
128167748Smckusick if (dvp == vp)
128267748Smckusick vrele(dvp);
128367748Smckusick else
128467748Smckusick vput(dvp);
128567748Smckusick error = vn_stat(vp, &sb, p);
128667748Smckusick vput(vp);
128767748Smckusick if (error)
128867748Smckusick return (error);
128967748Smckusick } else {
129067748Smckusick error = vn_stat(dvp, &sb, p);
129167748Smckusick vput(dvp);
129267748Smckusick if (error) {
129367748Smckusick vput(vp);
129467748Smckusick return (error);
129567748Smckusick }
129667748Smckusick error = vn_stat(vp, &sb1, p);
129767748Smckusick vput(vp);
129867748Smckusick if (error)
129967748Smckusick return (error);
130067748Smckusick sb.st_mode &= ~S_IFDIR;
130167748Smckusick sb.st_mode |= S_IFLNK;
130267748Smckusick sb.st_nlink = sb1.st_nlink;
130367748Smckusick sb.st_size = sb1.st_size;
130467748Smckusick sb.st_blocks = sb1.st_blocks;
130567748Smckusick }
130653468Smckusick cvtstat(&sb, &osb);
130768318Scgd error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
130853468Smckusick return (error);
130953468Smckusick }
131053468Smckusick
131153468Smckusick /*
131264410Sbostic * Convert from an old to a new stat structure.
131353468Smckusick */
131468318Scgd void
cvtstat(st,ost)131553468Smckusick cvtstat(st, ost)
131653468Smckusick struct stat *st;
131753468Smckusick struct ostat *ost;
131853468Smckusick {
131953468Smckusick
132053468Smckusick ost->st_dev = st->st_dev;
132153468Smckusick ost->st_ino = st->st_ino;
132253468Smckusick ost->st_mode = st->st_mode;
132353468Smckusick ost->st_nlink = st->st_nlink;
132453468Smckusick ost->st_uid = st->st_uid;
132553468Smckusick ost->st_gid = st->st_gid;
132653468Smckusick ost->st_rdev = st->st_rdev;
132753468Smckusick if (st->st_size < (quad_t)1 << 32)
132853468Smckusick ost->st_size = st->st_size;
132953468Smckusick else
133053468Smckusick ost->st_size = -2;
133153468Smckusick ost->st_atime = st->st_atime;
133253468Smckusick ost->st_mtime = st->st_mtime;
133353468Smckusick ost->st_ctime = st->st_ctime;
133453468Smckusick ost->st_blksize = st->st_blksize;
133553468Smckusick ost->st_blocks = st->st_blocks;
133653468Smckusick ost->st_flags = st->st_flags;
133753468Smckusick ost->st_gen = st->st_gen;
133853468Smckusick }
133954348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
134053468Smckusick
134153468Smckusick /*
134264410Sbostic * Get file status; this version follows links.
134353468Smckusick */
134453468Smckusick /* ARGSUSED */
134568318Scgd int
stat(p,uap,retval)134653759Smckusick stat(p, uap, retval)
134753468Smckusick struct proc *p;
134868318Scgd register struct stat_args /* {
134968318Scgd syscallarg(char *) path;
135068318Scgd syscallarg(struct stat *) ub;
135168318Scgd } */ *uap;
135268318Scgd register_t *retval;
135337Sbill {
135442441Smckusick struct stat sb;
135542441Smckusick int error;
135647540Skarels struct nameidata nd;
135737Sbill
135868318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
135968318Scgd SCARG(uap, path), p);
136052322Smckusick if (error = namei(&nd))
136147540Skarels return (error);
136252322Smckusick error = vn_stat(nd.ni_vp, &sb, p);
136352322Smckusick vput(nd.ni_vp);
136442441Smckusick if (error)
136547540Skarels return (error);
136668318Scgd error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
136747540Skarels return (error);
136837Sbill }
136937Sbill
137037Sbill /*
137164410Sbostic * Get file status; this version does not follow links.
13725992Swnj */
137342441Smckusick /* ARGSUSED */
137468318Scgd int
lstat(p,uap,retval)137553759Smckusick lstat(p, uap, retval)
137645914Smckusick struct proc *p;
137768318Scgd register struct lstat_args /* {
137868318Scgd syscallarg(char *) path;
137968318Scgd syscallarg(struct stat *) ub;
138068318Scgd } */ *uap;
138168318Scgd register_t *retval;
138242441Smckusick {
138337741Smckusick int error;
138459373Smckusick struct vnode *vp, *dvp;
138559373Smckusick struct stat sb, sb1;
138647540Skarels struct nameidata nd;
13875992Swnj
138859373Smckusick NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
138968318Scgd SCARG(uap, path), p);
139052322Smckusick if (error = namei(&nd))
139147540Skarels return (error);
139259373Smckusick /*
139368579Smckusick * For symbolic links, always return the attributes of its containing
139468579Smckusick * directory, except for mode, size, inode number, and links.
139559373Smckusick */
139659373Smckusick vp = nd.ni_vp;
139759373Smckusick dvp = nd.ni_dvp;
139859373Smckusick if (vp->v_type != VLNK) {
139959373Smckusick if (dvp == vp)
140059373Smckusick vrele(dvp);
140159373Smckusick else
140259373Smckusick vput(dvp);
140359373Smckusick error = vn_stat(vp, &sb, p);
140459373Smckusick vput(vp);
140559373Smckusick if (error)
140659373Smckusick return (error);
140759373Smckusick } else {
140859373Smckusick error = vn_stat(dvp, &sb, p);
140959373Smckusick vput(dvp);
141059373Smckusick if (error) {
141159373Smckusick vput(vp);
141259373Smckusick return (error);
141359373Smckusick }
141459373Smckusick error = vn_stat(vp, &sb1, p);
141559373Smckusick vput(vp);
141659373Smckusick if (error)
141759373Smckusick return (error);
141859373Smckusick sb.st_mode &= ~S_IFDIR;
141959373Smckusick sb.st_mode |= S_IFLNK;
142059373Smckusick sb.st_nlink = sb1.st_nlink;
142159373Smckusick sb.st_size = sb1.st_size;
142259373Smckusick sb.st_blocks = sb1.st_blocks;
142368579Smckusick sb.st_ino = sb1.st_ino;
142459373Smckusick }
142568318Scgd error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
142647540Skarels return (error);
14275992Swnj }
14285992Swnj
14295992Swnj /*
143064410Sbostic * Get configurable pathname variables.
143160414Smckusick */
143260414Smckusick /* ARGSUSED */
143368318Scgd int
pathconf(p,uap,retval)143460414Smckusick pathconf(p, uap, retval)
143560414Smckusick struct proc *p;
143668318Scgd register struct pathconf_args /* {
143768318Scgd syscallarg(char *) path;
143868318Scgd syscallarg(int) name;
143968318Scgd } */ *uap;
144068318Scgd register_t *retval;
144160414Smckusick {
144260414Smckusick int error;
144360414Smckusick struct nameidata nd;
144460414Smckusick
144568318Scgd NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
144668318Scgd SCARG(uap, path), p);
144760414Smckusick if (error = namei(&nd))
144860414Smckusick return (error);
144968318Scgd error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval);
145060414Smckusick vput(nd.ni_vp);
145160414Smckusick return (error);
145260414Smckusick }
145360414Smckusick
145460414Smckusick /*
145549365Smckusick * Return target name of a symbolic link.
145637Sbill */
145742441Smckusick /* ARGSUSED */
145868318Scgd int
readlink(p,uap,retval)145942441Smckusick readlink(p, uap, retval)
146045914Smckusick struct proc *p;
146168318Scgd register struct readlink_args /* {
146268318Scgd syscallarg(char *) path;
146368318Scgd syscallarg(char *) buf;
146468318Scgd syscallarg(int) count;
146568318Scgd } */ *uap;
146668318Scgd register_t *retval;
146742441Smckusick {
146837741Smckusick register struct vnode *vp;
146937741Smckusick struct iovec aiov;
147037741Smckusick struct uio auio;
147137741Smckusick int error;
147247540Skarels struct nameidata nd;
14735992Swnj
147468318Scgd NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
147568318Scgd SCARG(uap, path), p);
147652322Smckusick if (error = namei(&nd))
147747540Skarels return (error);
147852322Smckusick vp = nd.ni_vp;
147964410Sbostic if (vp->v_type != VLNK)
148037741Smckusick error = EINVAL;
148164410Sbostic else {
148268318Scgd aiov.iov_base = SCARG(uap, buf);
148368318Scgd aiov.iov_len = SCARG(uap, count);
148464410Sbostic auio.uio_iov = &aiov;
148564410Sbostic auio.uio_iovcnt = 1;
148664410Sbostic auio.uio_offset = 0;
148764410Sbostic auio.uio_rw = UIO_READ;
148864410Sbostic auio.uio_segflg = UIO_USERSPACE;
148964410Sbostic auio.uio_procp = p;
149068318Scgd auio.uio_resid = SCARG(uap, count);
149164410Sbostic error = VOP_READLINK(vp, &auio, p->p_ucred);
14925992Swnj }
149337741Smckusick vput(vp);
149468318Scgd *retval = SCARG(uap, count) - auio.uio_resid;
149547540Skarels return (error);
14965992Swnj }
14975992Swnj
14989167Ssam /*
149964410Sbostic * Change flags of a file given a path name.
150038259Smckusick */
150142441Smckusick /* ARGSUSED */
150268318Scgd int
chflags(p,uap,retval)150342441Smckusick chflags(p, uap, retval)
150445914Smckusick struct proc *p;
150568318Scgd register struct chflags_args /* {
150668318Scgd syscallarg(char *) path;
150768318Scgd syscallarg(int) flags;
150868318Scgd } */ *uap;
150968318Scgd register_t *retval;
151042441Smckusick {
151138259Smckusick register struct vnode *vp;
151238259Smckusick struct vattr vattr;
151338259Smckusick int error;
151447540Skarels struct nameidata nd;
151538259Smckusick
151668318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
151752322Smckusick if (error = namei(&nd))
151847540Skarels return (error);
151952322Smckusick vp = nd.ni_vp;
152067654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
152169409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
152269738Smckusick VATTR_NULL(&vattr);
152369738Smckusick vattr.va_flags = SCARG(uap, flags);
152469738Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
152538259Smckusick vput(vp);
152647540Skarels return (error);
152738259Smckusick }
152838259Smckusick
152938259Smckusick /*
153038259Smckusick * Change flags of a file given a file descriptor.
153138259Smckusick */
153242441Smckusick /* ARGSUSED */
153368318Scgd int
fchflags(p,uap,retval)153442441Smckusick fchflags(p, uap, retval)
153545914Smckusick struct proc *p;
153668318Scgd register struct fchflags_args /* {
153768318Scgd syscallarg(int) fd;
153868318Scgd syscallarg(int) flags;
153968318Scgd } */ *uap;
154068318Scgd register_t *retval;
154142441Smckusick {
154238259Smckusick struct vattr vattr;
154338259Smckusick struct vnode *vp;
154438259Smckusick struct file *fp;
154538259Smckusick int error;
154638259Smckusick
154768318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
154847540Skarels return (error);
154938259Smckusick vp = (struct vnode *)fp->f_data;
155067654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
155169409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
155269738Smckusick VATTR_NULL(&vattr);
155369738Smckusick vattr.va_flags = SCARG(uap, flags);
155469738Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
155569409Smckusick VOP_UNLOCK(vp, 0, p);
155647540Skarels return (error);
155738259Smckusick }
155838259Smckusick
155938259Smckusick /*
15609167Ssam * Change mode of a file given path name.
15619167Ssam */
156242441Smckusick /* ARGSUSED */
156368318Scgd int
chmod(p,uap,retval)156442441Smckusick chmod(p, uap, retval)
156545914Smckusick struct proc *p;
156668318Scgd register struct chmod_args /* {
156768318Scgd syscallarg(char *) path;
156868318Scgd syscallarg(int) mode;
156968318Scgd } */ *uap;
157068318Scgd register_t *retval;
157142441Smckusick {
157237741Smckusick register struct vnode *vp;
157337741Smckusick struct vattr vattr;
157437741Smckusick int error;
157547540Skarels struct nameidata nd;
15765992Swnj
157768318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
157852322Smckusick if (error = namei(&nd))
157947540Skarels return (error);
158052322Smckusick vp = nd.ni_vp;
158167654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
158269409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
158369738Smckusick VATTR_NULL(&vattr);
158469738Smckusick vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
158569738Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
158637741Smckusick vput(vp);
158747540Skarels return (error);
15887701Ssam }
15897439Sroot
15909167Ssam /*
15919167Ssam * Change mode of a file given a file descriptor.
15929167Ssam */
159342441Smckusick /* ARGSUSED */
159468318Scgd int
fchmod(p,uap,retval)159542441Smckusick fchmod(p, uap, retval)
159645914Smckusick struct proc *p;
159768318Scgd register struct fchmod_args /* {
159868318Scgd syscallarg(int) fd;
159968318Scgd syscallarg(int) mode;
160068318Scgd } */ *uap;
160168318Scgd register_t *retval;
160242441Smckusick {
160337741Smckusick struct vattr vattr;
160437741Smckusick struct vnode *vp;
160537741Smckusick struct file *fp;
160637741Smckusick int error;
16077701Ssam
160868318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
160947540Skarels return (error);
161037741Smckusick vp = (struct vnode *)fp->f_data;
161167654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
161269409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
161369738Smckusick VATTR_NULL(&vattr);
161469738Smckusick vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
161569738Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
161669409Smckusick VOP_UNLOCK(vp, 0, p);
161747540Skarels return (error);
16185992Swnj }
16195992Swnj
16209167Ssam /*
16219167Ssam * Set ownership given a path name.
16229167Ssam */
162342441Smckusick /* ARGSUSED */
162468318Scgd int
chown(p,uap,retval)162542441Smckusick chown(p, uap, retval)
162645914Smckusick struct proc *p;
162768318Scgd register struct chown_args /* {
162868318Scgd syscallarg(char *) path;
162968318Scgd syscallarg(int) uid;
163068318Scgd syscallarg(int) gid;
163168318Scgd } */ *uap;
163268318Scgd register_t *retval;
163342441Smckusick {
163437741Smckusick register struct vnode *vp;
163537741Smckusick struct vattr vattr;
163637741Smckusick int error;
163747540Skarels struct nameidata nd;
163837Sbill
163968318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
164052322Smckusick if (error = namei(&nd))
164147540Skarels return (error);
164252322Smckusick vp = nd.ni_vp;
164367654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
164469409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
164569738Smckusick VATTR_NULL(&vattr);
164669738Smckusick vattr.va_uid = SCARG(uap, uid);
164769738Smckusick vattr.va_gid = SCARG(uap, gid);
164869738Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
164937741Smckusick vput(vp);
165047540Skarels return (error);
16517701Ssam }
16527439Sroot
16539167Ssam /*
16549167Ssam * Set ownership given a file descriptor.
16559167Ssam */
165642441Smckusick /* ARGSUSED */
165768318Scgd int
fchown(p,uap,retval)165842441Smckusick fchown(p, uap, retval)
165945914Smckusick struct proc *p;
166068318Scgd register struct fchown_args /* {
166168318Scgd syscallarg(int) fd;
166268318Scgd syscallarg(int) uid;
166368318Scgd syscallarg(int) gid;
166468318Scgd } */ *uap;
166568318Scgd register_t *retval;
166642441Smckusick {
166737741Smckusick struct vattr vattr;
166837741Smckusick struct vnode *vp;
166937741Smckusick struct file *fp;
167037741Smckusick int error;
16717701Ssam
167268318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
167347540Skarels return (error);
167437741Smckusick vp = (struct vnode *)fp->f_data;
167567654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
167669409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
167769738Smckusick VATTR_NULL(&vattr);
167869738Smckusick vattr.va_uid = SCARG(uap, uid);
167969738Smckusick vattr.va_gid = SCARG(uap, gid);
168069738Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
168169409Smckusick VOP_UNLOCK(vp, 0, p);
168247540Skarels return (error);
16837701Ssam }
16847701Ssam
168542441Smckusick /*
168642441Smckusick * Set the access and modification times of a file.
168742441Smckusick */
168842441Smckusick /* ARGSUSED */
168968318Scgd int
utimes(p,uap,retval)169042441Smckusick utimes(p, uap, retval)
169145914Smckusick struct proc *p;
169268318Scgd register struct utimes_args /* {
169368318Scgd syscallarg(char *) path;
169468318Scgd syscallarg(struct timeval *) tptr;
169568318Scgd } */ *uap;
169668318Scgd register_t *retval;
169742441Smckusick {
169837741Smckusick register struct vnode *vp;
169911811Ssam struct timeval tv[2];
170037741Smckusick struct vattr vattr;
170158840Storek int error;
170247540Skarels struct nameidata nd;
170311811Ssam
170458505Sbostic VATTR_NULL(&vattr);
170568318Scgd if (SCARG(uap, tptr) == NULL) {
170658505Sbostic microtime(&tv[0]);
170758505Sbostic tv[1] = tv[0];
170858548Sbostic vattr.va_vaflags |= VA_UTIMES_NULL;
170968318Scgd } else if (error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv,
171068318Scgd sizeof (tv)))
171158505Sbostic return (error);
171268318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
171352322Smckusick if (error = namei(&nd))
171447540Skarels return (error);
171552322Smckusick vp = nd.ni_vp;
171667654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
171769409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
171869738Smckusick vattr.va_atime.ts_sec = tv[0].tv_sec;
171969738Smckusick vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
172069738Smckusick vattr.va_mtime.ts_sec = tv[1].tv_sec;
172169738Smckusick vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
172269738Smckusick error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
172337741Smckusick vput(vp);
172447540Skarels return (error);
172511811Ssam }
172611811Ssam
172764410Sbostic /*
172864410Sbostic * Truncate a file given its path name.
172964410Sbostic */
173053468Smckusick /* ARGSUSED */
173168318Scgd int
truncate(p,uap,retval)173260414Smckusick truncate(p, uap, retval)
173353468Smckusick struct proc *p;
173468318Scgd register struct truncate_args /* {
173568318Scgd syscallarg(char *) path;
173668318Scgd syscallarg(int) pad;
173768318Scgd syscallarg(off_t) length;
173868318Scgd } */ *uap;
173968318Scgd register_t *retval;
174053468Smckusick {
174137741Smckusick register struct vnode *vp;
174237741Smckusick struct vattr vattr;
174337741Smckusick int error;
174447540Skarels struct nameidata nd;
17457701Ssam
174668318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
174752322Smckusick if (error = namei(&nd))
174847540Skarels return (error);
174952322Smckusick vp = nd.ni_vp;
175067654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
175169409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
175264410Sbostic if (vp->v_type == VDIR)
175337741Smckusick error = EISDIR;
175464410Sbostic else if ((error = vn_writechk(vp)) == 0 &&
175564410Sbostic (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
175664410Sbostic VATTR_NULL(&vattr);
175768318Scgd vattr.va_size = SCARG(uap, length);
175864410Sbostic error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
17597701Ssam }
176037741Smckusick vput(vp);
176147540Skarels return (error);
17627701Ssam }
17637701Ssam
176464410Sbostic /*
176564410Sbostic * Truncate a file given a file descriptor.
176664410Sbostic */
176742441Smckusick /* ARGSUSED */
176868318Scgd int
ftruncate(p,uap,retval)176960414Smckusick ftruncate(p, uap, retval)
177045914Smckusick struct proc *p;
177168318Scgd register struct ftruncate_args /* {
177268318Scgd syscallarg(int) fd;
177368318Scgd syscallarg(int) pad;
177468318Scgd syscallarg(off_t) length;
177568318Scgd } */ *uap;
177668318Scgd register_t *retval;
177742441Smckusick {
177837741Smckusick struct vattr vattr;
177937741Smckusick struct vnode *vp;
17807701Ssam struct file *fp;
178137741Smckusick int error;
17827701Ssam
178368318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
178447540Skarels return (error);
178537741Smckusick if ((fp->f_flag & FWRITE) == 0)
178647540Skarels return (EINVAL);
178737741Smckusick vp = (struct vnode *)fp->f_data;
178867654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
178969409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
179064410Sbostic if (vp->v_type == VDIR)
179137741Smckusick error = EISDIR;
179264410Sbostic else if ((error = vn_writechk(vp)) == 0) {
179364410Sbostic VATTR_NULL(&vattr);
179468318Scgd vattr.va_size = SCARG(uap, length);
179564410Sbostic error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
17967701Ssam }
179769409Smckusick VOP_UNLOCK(vp, 0, p);
179847540Skarels return (error);
17997701Ssam }
18007701Ssam
180154863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
18029167Ssam /*
180354863Storek * Truncate a file given its path name.
180454863Storek */
180554863Storek /* ARGSUSED */
180668318Scgd int
compat_43_truncate(p,uap,retval)180768318Scgd compat_43_truncate(p, uap, retval)
180854863Storek struct proc *p;
180968318Scgd register struct compat_43_truncate_args /* {
181068318Scgd syscallarg(char *) path;
181168318Scgd syscallarg(long) length;
181268318Scgd } */ *uap;
181368318Scgd register_t *retval;
181454863Storek {
181568318Scgd struct truncate_args /* {
181668318Scgd syscallarg(char *) path;
181768318Scgd syscallarg(int) pad;
181868318Scgd syscallarg(off_t) length;
181968318Scgd } */ nuap;
182054863Storek
182168318Scgd SCARG(&nuap, path) = SCARG(uap, path);
182268318Scgd SCARG(&nuap, length) = SCARG(uap, length);
182360428Smckusick return (truncate(p, &nuap, retval));
182454863Storek }
182554863Storek
182654863Storek /*
182754863Storek * Truncate a file given a file descriptor.
182854863Storek */
182954863Storek /* ARGSUSED */
183068318Scgd int
compat_43_ftruncate(p,uap,retval)183168318Scgd compat_43_ftruncate(p, uap, retval)
183254863Storek struct proc *p;
183368318Scgd register struct compat_43_ftruncate_args /* {
183468318Scgd syscallarg(int) fd;
183568318Scgd syscallarg(long) length;
183668318Scgd } */ *uap;
183768318Scgd register_t *retval;
183854863Storek {
183968318Scgd struct ftruncate_args /* {
184068318Scgd syscallarg(int) fd;
184168318Scgd syscallarg(int) pad;
184268318Scgd syscallarg(off_t) length;
184368318Scgd } */ nuap;
184454863Storek
184568318Scgd SCARG(&nuap, fd) = SCARG(uap, fd);
184668318Scgd SCARG(&nuap, length) = SCARG(uap, length);
184760428Smckusick return (ftruncate(p, &nuap, retval));
184854863Storek }
184954863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */
185054863Storek
185154863Storek /*
185264410Sbostic * Sync an open file.
18539167Ssam */
185442441Smckusick /* ARGSUSED */
185568318Scgd int
fsync(p,uap,retval)185642441Smckusick fsync(p, uap, retval)
185745914Smckusick struct proc *p;
185868318Scgd struct fsync_args /* {
185968318Scgd syscallarg(int) fd;
186068318Scgd } */ *uap;
186168318Scgd register_t *retval;
18629167Ssam {
186339592Smckusick register struct vnode *vp;
18649167Ssam struct file *fp;
186537741Smckusick int error;
18669167Ssam
186768318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
186847540Skarels return (error);
186939592Smckusick vp = (struct vnode *)fp->f_data;
187069409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
187154441Smckusick error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
187269409Smckusick VOP_UNLOCK(vp, 0, p);
187347540Skarels return (error);
18749167Ssam }
18759167Ssam
18769167Ssam /*
187764410Sbostic * Rename files. Source and destination must either both be directories,
187864410Sbostic * or both not be directories. If target is a directory, it must be empty.
18799167Ssam */
188042441Smckusick /* ARGSUSED */
188168318Scgd int
rename(p,uap,retval)188242441Smckusick rename(p, uap, retval)
188345914Smckusick struct proc *p;
188468318Scgd register struct rename_args /* {
188568318Scgd syscallarg(char *) from;
188668318Scgd syscallarg(char *) to;
188768318Scgd } */ *uap;
188868318Scgd register_t *retval;
188942441Smckusick {
189037741Smckusick register struct vnode *tvp, *fvp, *tdvp;
189149735Smckusick struct nameidata fromnd, tond;
189237741Smckusick int error;
18937701Ssam
189452322Smckusick NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
189568318Scgd SCARG(uap, from), p);
189652322Smckusick if (error = namei(&fromnd))
189747540Skarels return (error);
189849735Smckusick fvp = fromnd.ni_vp;
189952322Smckusick NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
190068318Scgd UIO_USERSPACE, SCARG(uap, to), p);
190152322Smckusick if (error = namei(&tond)) {
190252230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
190349735Smckusick vrele(fromnd.ni_dvp);
190442465Smckusick vrele(fvp);
190542465Smckusick goto out1;
190642465Smckusick }
190737741Smckusick tdvp = tond.ni_dvp;
190837741Smckusick tvp = tond.ni_vp;
190937741Smckusick if (tvp != NULL) {
191037741Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
191139242Sbostic error = ENOTDIR;
191237741Smckusick goto out;
191337741Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
191439242Sbostic error = EISDIR;
191537741Smckusick goto out;
19169167Ssam }
19179167Ssam }
191839286Smckusick if (fvp == tdvp)
191937741Smckusick error = EINVAL;
192039286Smckusick /*
192149735Smckusick * If source is the same as the destination (that is the
192249735Smckusick * same inode number with the same name in the same directory),
192339286Smckusick * then there is nothing to do.
192439286Smckusick */
192549735Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp &&
192652322Smckusick fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
192752322Smckusick !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
192852322Smckusick fromnd.ni_cnd.cn_namelen))
192939286Smckusick error = -1;
193037741Smckusick out:
193142465Smckusick if (!error) {
193267654Smckusick VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE);
193352192Smckusick if (fromnd.ni_dvp != tdvp)
193467654Smckusick VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
193552192Smckusick if (tvp)
193667654Smckusick VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE);
193752230Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
193852230Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
193942465Smckusick } else {
194052230Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
194143344Smckusick if (tdvp == tvp)
194243344Smckusick vrele(tdvp);
194343344Smckusick else
194443344Smckusick vput(tdvp);
194542465Smckusick if (tvp)
194642465Smckusick vput(tvp);
194752230Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
194849735Smckusick vrele(fromnd.ni_dvp);
194942465Smckusick vrele(fvp);
19509167Ssam }
195149735Smckusick vrele(tond.ni_startdir);
195252322Smckusick FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
195337741Smckusick out1:
195466801Smckusick if (fromnd.ni_startdir)
195566801Smckusick vrele(fromnd.ni_startdir);
195652322Smckusick FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
195739286Smckusick if (error == -1)
195847540Skarels return (0);
195947540Skarels return (error);
19607701Ssam }
19617701Ssam
19627535Sroot /*
196364410Sbostic * Make a directory file.
196412756Ssam */
196542441Smckusick /* ARGSUSED */
196668318Scgd int
mkdir(p,uap,retval)196742441Smckusick mkdir(p, uap, retval)
196845914Smckusick struct proc *p;
196968318Scgd register struct mkdir_args /* {
197068318Scgd syscallarg(char *) path;
197168318Scgd syscallarg(int) mode;
197268318Scgd } */ *uap;
197368318Scgd register_t *retval;
197442441Smckusick {
197537741Smckusick register struct vnode *vp;
197637741Smckusick struct vattr vattr;
197737741Smckusick int error;
197847540Skarels struct nameidata nd;
197912756Ssam
198068318Scgd NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
198152322Smckusick if (error = namei(&nd))
198247540Skarels return (error);
198352322Smckusick vp = nd.ni_vp;
198437741Smckusick if (vp != NULL) {
198552322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
198652322Smckusick if (nd.ni_dvp == vp)
198752322Smckusick vrele(nd.ni_dvp);
198843344Smckusick else
198952322Smckusick vput(nd.ni_dvp);
199042465Smckusick vrele(vp);
199147540Skarels return (EEXIST);
199212756Ssam }
199341362Smckusick VATTR_NULL(&vattr);
199437741Smckusick vattr.va_type = VDIR;
199568318Scgd vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask;
199667654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
199752322Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
199838145Smckusick if (!error)
199952322Smckusick vput(nd.ni_vp);
200047540Skarels return (error);
200112756Ssam }
200212756Ssam
200312756Ssam /*
200464410Sbostic * Remove a directory file.
200512756Ssam */
200642441Smckusick /* ARGSUSED */
200768318Scgd int
rmdir(p,uap,retval)200842441Smckusick rmdir(p, uap, retval)
200945914Smckusick struct proc *p;
201068318Scgd struct rmdir_args /* {
201168318Scgd syscallarg(char *) path;
201268318Scgd } */ *uap;
201368318Scgd register_t *retval;
201412756Ssam {
201537741Smckusick register struct vnode *vp;
201637741Smckusick int error;
201747540Skarels struct nameidata nd;
201812756Ssam
201968318Scgd NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
202068318Scgd SCARG(uap, path), p);
202152322Smckusick if (error = namei(&nd))
202247540Skarels return (error);
202352322Smckusick vp = nd.ni_vp;
202437741Smckusick if (vp->v_type != VDIR) {
202537741Smckusick error = ENOTDIR;
202612756Ssam goto out;
202712756Ssam }
202812756Ssam /*
202937741Smckusick * No rmdir "." please.
203012756Ssam */
203152322Smckusick if (nd.ni_dvp == vp) {
203237741Smckusick error = EINVAL;
203312756Ssam goto out;
203412756Ssam }
203512756Ssam /*
203649365Smckusick * The root of a mounted filesystem cannot be deleted.
203712756Ssam */
203837741Smckusick if (vp->v_flag & VROOT)
203937741Smckusick error = EBUSY;
204012756Ssam out:
204142465Smckusick if (!error) {
204267654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
204367654Smckusick VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
204452322Smckusick error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
204542465Smckusick } else {
204652322Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
204752322Smckusick if (nd.ni_dvp == vp)
204852322Smckusick vrele(nd.ni_dvp);
204943344Smckusick else
205052322Smckusick vput(nd.ni_dvp);
205142465Smckusick vput(vp);
205242465Smckusick }
205347540Skarels return (error);
205412756Ssam }
205512756Ssam
205654620Smckusick #ifdef COMPAT_43
205737741Smckusick /*
205849365Smckusick * Read a block of directory entries in a file system independent format.
205937741Smckusick */
206068318Scgd int
compat_43_getdirentries(p,uap,retval)206168318Scgd compat_43_getdirentries(p, uap, retval)
206254620Smckusick struct proc *p;
206368318Scgd register struct compat_43_getdirentries_args /* {
206468318Scgd syscallarg(int) fd;
206568318Scgd syscallarg(char *) buf;
206668318Scgd syscallarg(u_int) count;
206768318Scgd syscallarg(long *) basep;
206868318Scgd } */ *uap;
206968318Scgd register_t *retval;
207054620Smckusick {
207154620Smckusick register struct vnode *vp;
207254620Smckusick struct file *fp;
207354620Smckusick struct uio auio, kuio;
207454620Smckusick struct iovec aiov, kiov;
207554620Smckusick struct dirent *dp, *edp;
207654620Smckusick caddr_t dirbuf;
207767362Smckusick int error, eofflag, readcnt;
207854969Smckusick long loff;
207954620Smckusick
208068318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
208154620Smckusick return (error);
208254620Smckusick if ((fp->f_flag & FREAD) == 0)
208354620Smckusick return (EBADF);
208454620Smckusick vp = (struct vnode *)fp->f_data;
208567362Smckusick unionread:
208654620Smckusick if (vp->v_type != VDIR)
208754620Smckusick return (EINVAL);
208868318Scgd aiov.iov_base = SCARG(uap, buf);
208968318Scgd aiov.iov_len = SCARG(uap, count);
209054620Smckusick auio.uio_iov = &aiov;
209154620Smckusick auio.uio_iovcnt = 1;
209254620Smckusick auio.uio_rw = UIO_READ;
209354620Smckusick auio.uio_segflg = UIO_USERSPACE;
209454620Smckusick auio.uio_procp = p;
209568318Scgd auio.uio_resid = SCARG(uap, count);
209669409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
209754969Smckusick loff = auio.uio_offset = fp->f_offset;
209854620Smckusick # if (BYTE_ORDER != LITTLE_ENDIAN)
209956339Smckusick if (vp->v_mount->mnt_maxsymlinklen <= 0) {
210067362Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
210168663Smckusick (int *)0, (u_long *)0);
210256339Smckusick fp->f_offset = auio.uio_offset;
210356339Smckusick } else
210454620Smckusick # endif
210554620Smckusick {
210654620Smckusick kuio = auio;
210754620Smckusick kuio.uio_iov = &kiov;
210854620Smckusick kuio.uio_segflg = UIO_SYSSPACE;
210968318Scgd kiov.iov_len = SCARG(uap, count);
211068318Scgd MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK);
211154620Smckusick kiov.iov_base = dirbuf;
211267362Smckusick error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
211368663Smckusick (int *)0, (u_long *)0);
211456339Smckusick fp->f_offset = kuio.uio_offset;
211554620Smckusick if (error == 0) {
211668318Scgd readcnt = SCARG(uap, count) - kuio.uio_resid;
211754620Smckusick edp = (struct dirent *)&dirbuf[readcnt];
211854620Smckusick for (dp = (struct dirent *)dirbuf; dp < edp; ) {
211954620Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN)
212054969Smckusick /*
212155009Smckusick * The expected low byte of
212255009Smckusick * dp->d_namlen is our dp->d_type.
212355009Smckusick * The high MBZ byte of dp->d_namlen
212455009Smckusick * is our dp->d_namlen.
212554969Smckusick */
212655009Smckusick dp->d_type = dp->d_namlen;
212755009Smckusick dp->d_namlen = 0;
212855009Smckusick # else
212955009Smckusick /*
213055009Smckusick * The dp->d_type is the high byte
213155009Smckusick * of the expected dp->d_namlen,
213255009Smckusick * so must be zero'ed.
213355009Smckusick */
213455009Smckusick dp->d_type = 0;
213554620Smckusick # endif
213654620Smckusick if (dp->d_reclen > 0) {
213754620Smckusick dp = (struct dirent *)
213854620Smckusick ((char *)dp + dp->d_reclen);
213954620Smckusick } else {
214054620Smckusick error = EIO;
214154620Smckusick break;
214254620Smckusick }
214354620Smckusick }
214454620Smckusick if (dp >= edp)
214554620Smckusick error = uiomove(dirbuf, readcnt, &auio);
214654620Smckusick }
214754620Smckusick FREE(dirbuf, M_TEMP);
214854620Smckusick }
214969409Smckusick VOP_UNLOCK(vp, 0, p);
215054620Smckusick if (error)
215154620Smckusick return (error);
215267362Smckusick
215367362Smckusick #ifdef UNION
215467362Smckusick {
215567362Smckusick extern int (**union_vnodeop_p)();
215669547Spendry extern struct vnode *union_dircache __P((struct vnode*, struct proc*));
215767362Smckusick
215868318Scgd if ((SCARG(uap, count) == auio.uio_resid) &&
215967362Smckusick (vp->v_op == union_vnodeop_p)) {
216067362Smckusick struct vnode *lvp;
216167362Smckusick
216269547Spendry lvp = union_dircache(vp, p);
216367362Smckusick if (lvp != NULLVP) {
216467575Spendry struct vattr va;
216567575Spendry
216667575Spendry /*
216767575Spendry * If the directory is opaque,
216867575Spendry * then don't show lower entries
216967575Spendry */
217067575Spendry error = VOP_GETATTR(vp, &va, fp->f_cred, p);
217167575Spendry if (va.va_flags & OPAQUE) {
217268079Spendry vput(lvp);
217367575Spendry lvp = NULL;
217467575Spendry }
217567575Spendry }
217667575Spendry
217767575Spendry if (lvp != NULLVP) {
217867362Smckusick error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
217967362Smckusick if (error) {
218069547Spendry vput(lvp);
218167362Smckusick return (error);
218267362Smckusick }
218369547Spendry VOP_UNLOCK(lvp, 0, p);
218467362Smckusick fp->f_data = (caddr_t) lvp;
218567362Smckusick fp->f_offset = 0;
218667362Smckusick error = vn_close(vp, FREAD, fp->f_cred, p);
218767362Smckusick if (error)
218867362Smckusick return (error);
218967362Smckusick vp = lvp;
219067362Smckusick goto unionread;
219167362Smckusick }
219267362Smckusick }
219367362Smckusick }
219467362Smckusick #endif /* UNION */
219567362Smckusick
219668318Scgd if ((SCARG(uap, count) == auio.uio_resid) &&
219767362Smckusick (vp->v_flag & VROOT) &&
219867362Smckusick (vp->v_mount->mnt_flag & MNT_UNION)) {
219967362Smckusick struct vnode *tvp = vp;
220067362Smckusick vp = vp->v_mount->mnt_vnodecovered;
220167362Smckusick VREF(vp);
220267362Smckusick fp->f_data = (caddr_t) vp;
220367362Smckusick fp->f_offset = 0;
220467362Smckusick vrele(tvp);
220567362Smckusick goto unionread;
220667362Smckusick }
220768318Scgd error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
220868318Scgd sizeof(long));
220968318Scgd *retval = SCARG(uap, count) - auio.uio_resid;
221054620Smckusick return (error);
221154620Smckusick }
221267362Smckusick #endif /* COMPAT_43 */
221354620Smckusick
221454620Smckusick /*
221554620Smckusick * Read a block of directory entries in a file system independent format.
221654620Smckusick */
221768318Scgd int
getdirentries(p,uap,retval)221842441Smckusick getdirentries(p, uap, retval)
221945914Smckusick struct proc *p;
222068318Scgd register struct getdirentries_args /* {
222168318Scgd syscallarg(int) fd;
222268318Scgd syscallarg(char *) buf;
222368318Scgd syscallarg(u_int) count;
222468318Scgd syscallarg(long *) basep;
222568318Scgd } */ *uap;
222668318Scgd register_t *retval;
222742441Smckusick {
222839592Smckusick register struct vnode *vp;
222916540Ssam struct file *fp;
223037741Smckusick struct uio auio;
223137741Smckusick struct iovec aiov;
223254969Smckusick long loff;
223367362Smckusick int error, eofflag;
223412756Ssam
223568318Scgd if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
223647540Skarels return (error);
223737741Smckusick if ((fp->f_flag & FREAD) == 0)
223847540Skarels return (EBADF);
223939592Smckusick vp = (struct vnode *)fp->f_data;
224055451Spendry unionread:
224139592Smckusick if (vp->v_type != VDIR)
224247540Skarels return (EINVAL);
224368318Scgd aiov.iov_base = SCARG(uap, buf);
224468318Scgd aiov.iov_len = SCARG(uap, count);
224537741Smckusick auio.uio_iov = &aiov;
224637741Smckusick auio.uio_iovcnt = 1;
224737741Smckusick auio.uio_rw = UIO_READ;
224837741Smckusick auio.uio_segflg = UIO_USERSPACE;
224948026Smckusick auio.uio_procp = p;
225068318Scgd auio.uio_resid = SCARG(uap, count);
225169409Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
225254969Smckusick loff = auio.uio_offset = fp->f_offset;
225368663Smckusick error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
225468663Smckusick (int *)0, (u_long *)0);
225539592Smckusick fp->f_offset = auio.uio_offset;
225669409Smckusick VOP_UNLOCK(vp, 0, p);
225739592Smckusick if (error)
225847540Skarels return (error);
225966095Spendry
226066095Spendry #ifdef UNION
226166095Spendry {
226266095Spendry extern int (**union_vnodeop_p)();
226369547Spendry extern struct vnode *union_dircache __P((struct vnode*, struct proc*));
226466095Spendry
226568318Scgd if ((SCARG(uap, count) == auio.uio_resid) &&
226666095Spendry (vp->v_op == union_vnodeop_p)) {
226767122Spendry struct vnode *lvp;
226866095Spendry
226969547Spendry lvp = union_dircache(vp, p);
227067122Spendry if (lvp != NULLVP) {
227167575Spendry struct vattr va;
227267575Spendry
227367575Spendry /*
227467575Spendry * If the directory is opaque,
227567575Spendry * then don't show lower entries
227667575Spendry */
227767575Spendry error = VOP_GETATTR(vp, &va, fp->f_cred, p);
227867575Spendry if (va.va_flags & OPAQUE) {
227968079Spendry vput(lvp);
228067575Spendry lvp = NULL;
228167575Spendry }
228267575Spendry }
228369547Spendry
228467575Spendry if (lvp != NULLVP) {
228567362Smckusick error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
228666095Spendry if (error) {
228769547Spendry vput(lvp);
228866095Spendry return (error);
228966095Spendry }
229069547Spendry VOP_UNLOCK(lvp, 0, p);
229167122Spendry fp->f_data = (caddr_t) lvp;
229266095Spendry fp->f_offset = 0;
229367122Spendry error = vn_close(vp, FREAD, fp->f_cred, p);
229466095Spendry if (error)
229566095Spendry return (error);
229667122Spendry vp = lvp;
229766095Spendry goto unionread;
229866095Spendry }
229966095Spendry }
230066095Spendry }
230168318Scgd #endif /* UNION */
230266095Spendry
230368318Scgd if ((SCARG(uap, count) == auio.uio_resid) &&
230455451Spendry (vp->v_flag & VROOT) &&
230555451Spendry (vp->v_mount->mnt_flag & MNT_UNION)) {
230655451Spendry struct vnode *tvp = vp;
230755451Spendry vp = vp->v_mount->mnt_vnodecovered;
230855451Spendry VREF(vp);
230955451Spendry fp->f_data = (caddr_t) vp;
231055451Spendry fp->f_offset = 0;
231155451Spendry vrele(tvp);
231255451Spendry goto unionread;
231355451Spendry }
231468318Scgd error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
231568318Scgd sizeof(long));
231668318Scgd *retval = SCARG(uap, count) - auio.uio_resid;
231747540Skarels return (error);
231812756Ssam }
231912756Ssam
232012756Ssam /*
232149365Smckusick * Set the mode mask for creation of filesystem nodes.
232212756Ssam */
232368318Scgd int
umask(p,uap,retval)232442441Smckusick umask(p, uap, retval)
232545914Smckusick struct proc *p;
232668318Scgd struct umask_args /* {
232768318Scgd syscallarg(int) newmask;
232868318Scgd } */ *uap;
232968318Scgd register_t *retval;
233012756Ssam {
233164410Sbostic register struct filedesc *fdp;
233212756Ssam
233364410Sbostic fdp = p->p_fd;
233445914Smckusick *retval = fdp->fd_cmask;
233568318Scgd fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS;
233647540Skarels return (0);
233712756Ssam }
233837741Smckusick
233939566Smarc /*
234039566Smarc * Void all references to file by ripping underlying filesystem
234139566Smarc * away from vnode.
234239566Smarc */
234342441Smckusick /* ARGSUSED */
234468318Scgd int
revoke(p,uap,retval)234542441Smckusick revoke(p, uap, retval)
234645914Smckusick struct proc *p;
234768318Scgd register struct revoke_args /* {
234868318Scgd syscallarg(char *) path;
234968318Scgd } */ *uap;
235068318Scgd register_t *retval;
235142441Smckusick {
235239566Smarc register struct vnode *vp;
235339566Smarc struct vattr vattr;
235439566Smarc int error;
235547540Skarels struct nameidata nd;
235639566Smarc
235768318Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
235852322Smckusick if (error = namei(&nd))
235947540Skarels return (error);
236052322Smckusick vp = nd.ni_vp;
236148026Smckusick if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
236239566Smarc goto out;
236347540Skarels if (p->p_ucred->cr_uid != vattr.va_uid &&
236447540Skarels (error = suser(p->p_ucred, &p->p_acflag)))
236539566Smarc goto out;
236639805Smckusick if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
236768423Smckusick VOP_REVOKE(vp, REVOKEALL);
236839566Smarc out:
236939566Smarc vrele(vp);
237047540Skarels return (error);
237139566Smarc }
237239566Smarc
237349365Smckusick /*
237449365Smckusick * Convert a user file descriptor to a kernel file entry.
237549365Smckusick */
237668318Scgd int
getvnode(fdp,fd,fpp)237764410Sbostic getvnode(fdp, fd, fpp)
237845914Smckusick struct filedesc *fdp;
237937741Smckusick struct file **fpp;
238064410Sbostic int fd;
238137741Smckusick {
238237741Smckusick struct file *fp;
238337741Smckusick
238464410Sbostic if ((u_int)fd >= fdp->fd_nfiles ||
238564410Sbostic (fp = fdp->fd_ofiles[fd]) == NULL)
238637741Smckusick return (EBADF);
238737741Smckusick if (fp->f_type != DTYPE_VNODE)
238837741Smckusick return (EINVAL);
238937741Smckusick *fpp = fp;
239037741Smckusick return (0);
239137741Smckusick }
2392