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