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