Deleted Added
full compact
vfs_syscalls.c (84323) vfs_syscalls.c (85339)
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 * $FreeBSD: head/sys/kern/vfs_syscalls.c 84323 2001-10-01 20:01:07Z rwatson $
39 * $FreeBSD: head/sys/kern/vfs_syscalls.c 85339 2001-10-23 01:21:29Z dillon $
40 */
41
42/* For 4.3 integer FS ID compatibility */
43#include "opt_compat.h"
44#include "opt_ffs.h"
45
46#include <sys/param.h>
47#include <sys/systm.h>
48#include <sys/bio.h>
49#include <sys/buf.h>
50#include <sys/sysent.h>
51#include <sys/malloc.h>
52#include <sys/mount.h>
53#include <sys/mutex.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/linker.h>
61#include <sys/stat.h>
62#include <sys/sx.h>
63#include <sys/unistd.h>
64#include <sys/vnode.h>
65#include <sys/proc.h>
66#include <sys/dirent.h>
67#include <sys/extattr.h>
68#include <sys/jail.h>
69#include <sys/sysctl.h>
70
71#include <machine/limits.h>
72
73#include <vm/vm.h>
74#include <vm/vm_object.h>
75#include <vm/vm_zone.h>
76#include <vm/vm_page.h>
77
78static int change_dir __P((struct nameidata *ndp, struct thread *td));
79static void checkdirs __P((struct vnode *olddp, struct vnode *newdp));
80static int chroot_refuse_vdir_fds __P((struct filedesc *fdp));
81static int getutimes __P((const struct timeval *, struct timespec *));
82static int setfown __P((struct thread *td, struct vnode *, uid_t, gid_t));
83static int setfmode __P((struct thread *td, struct vnode *, int));
84static int setfflags __P((struct thread *td, struct vnode *, int));
85static int setutimes __P((struct thread *td, struct vnode *,
86 const struct timespec *, int));
87static int vn_access __P((struct vnode *vp, int user_flags, struct ucred *cred,
88 struct thread *td));
89
90static int usermount = 0; /* if 1, non-root can mount fs. */
91
92int (*union_dircheckp) __P((struct thread *td, struct vnode **, struct file *));
93
94SYSCTL_INT(_vfs, OID_AUTO, usermount, CTLFLAG_RW, &usermount, 0, "");
95
96/*
97 * Virtual File System System Calls
98 */
99
100/*
101 * Mount a file system.
102 */
103#ifndef _SYS_SYSPROTO_H_
104struct mount_args {
105 char *type;
106 char *path;
107 int flags;
108 caddr_t data;
109};
110#endif
111/* ARGSUSED */
112int
113mount(td, uap)
114 struct thread *td;
115 struct mount_args /* {
116 syscallarg(char *) type;
117 syscallarg(char *) path;
118 syscallarg(int) flags;
119 syscallarg(caddr_t) data;
120 } */ *uap;
121{
122 char *fstype;
123 char *fspath;
124 int error;
125
126 fstype = malloc(MFSNAMELEN, M_TEMP, M_WAITOK | M_ZERO);
127 fspath = malloc(MNAMELEN, M_TEMP, M_WAITOK | M_ZERO);
128
129 /*
130 * vfs_mount() actually takes a kernel string for `type' and
131 * `path' now, so extract them.
132 */
133 error = copyinstr(SCARG(uap, type), fstype, MFSNAMELEN, NULL);
134 if (error)
135 goto finish;
136 error = copyinstr(SCARG(uap, path), fspath, MNAMELEN, NULL);
137 if (error)
138 goto finish;
139 error = vfs_mount(td, fstype, fspath, SCARG(uap, flags),
140 SCARG(uap, data));
141finish:
142 free(fstype, M_TEMP);
143 free(fspath, M_TEMP);
144 return (error);
145}
146
147/*
148 * vfs_mount(): actually attempt a filesystem mount.
149 *
150 * This routine is designed to be a "generic" entry point for routines
151 * that wish to mount a filesystem. All parameters except `fsdata' are
152 * pointers into kernel space. `fsdata' is currently still a pointer
153 * into userspace.
154 */
155int
156vfs_mount(td, fstype, fspath, fsflags, fsdata)
157 struct thread *td;
158 const char *fstype;
159 char *fspath;
160 int fsflags;
161 void *fsdata;
162{
163 struct vnode *vp;
164 struct mount *mp;
165 struct vfsconf *vfsp;
166 int error, flag = 0, flag2 = 0;
167 struct vattr va;
168 struct nameidata nd;
169 struct proc *p = td->td_proc;
170
171 /*
172 * Be ultra-paranoid about making sure the type and fspath
173 * variables will fit in our mp buffers, including the
174 * terminating NUL.
175 */
176 if ((strlen(fstype) >= MFSNAMELEN - 1) ||
177 (strlen(fspath) >= MNAMELEN - 1))
178 return (ENAMETOOLONG);
179
180 if (usermount == 0) {
181 error = suser_td(td);
182 if (error)
183 return (error);
184 }
185 /*
186 * Do not allow NFS export by non-root users.
187 */
188 if (fsflags & MNT_EXPORTED) {
189 error = suser_td(td);
190 if (error)
191 return (error);
192 }
193 /*
194 * Silently enforce MNT_NOSUID and MNT_NODEV for non-root users
195 */
196 if (suser_xxx(p->p_ucred, 0, 0))
197 fsflags |= MNT_NOSUID | MNT_NODEV;
198 /*
199 * Get vnode to be covered
200 */
201 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspath, td);
202 if ((error = namei(&nd)) != 0)
203 return (error);
204 NDFREE(&nd, NDF_ONLY_PNBUF);
205 vp = nd.ni_vp;
206 if (fsflags & MNT_UPDATE) {
207 if ((vp->v_flag & VROOT) == 0) {
208 vput(vp);
209 return (EINVAL);
210 }
211 mp = vp->v_mount;
212 flag = mp->mnt_flag;
213 flag2 = mp->mnt_kern_flag;
214 /*
215 * We only allow the filesystem to be reloaded if it
216 * is currently mounted read-only.
217 */
218 if ((fsflags & MNT_RELOAD) &&
219 ((mp->mnt_flag & MNT_RDONLY) == 0)) {
220 vput(vp);
221 return (EOPNOTSUPP); /* Needs translation */
222 }
223 /*
224 * Only root, or the user that did the original mount is
225 * permitted to update it.
226 */
227 if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid) {
228 error = suser_td(td);
229 if (error) {
230 vput(vp);
231 return (error);
232 }
233 }
234 if (vfs_busy(mp, LK_NOWAIT, 0, td)) {
235 vput(vp);
236 return (EBUSY);
237 }
238 mtx_lock(&vp->v_interlock);
239 if ((vp->v_flag & VMOUNT) != 0 ||
240 vp->v_mountedhere != NULL) {
241 mtx_unlock(&vp->v_interlock);
242 vfs_unbusy(mp, td);
243 vput(vp);
244 return (EBUSY);
245 }
246 vp->v_flag |= VMOUNT;
247 mtx_unlock(&vp->v_interlock);
248 mp->mnt_flag |= fsflags &
249 (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_SNAPSHOT);
250 VOP_UNLOCK(vp, 0, td);
251 goto update;
252 }
253 /*
254 * If the user is not root, ensure that they own the directory
255 * onto which we are attempting to mount.
256 */
257 error = VOP_GETATTR(vp, &va, p->p_ucred, td);
258 if (error) {
259 vput(vp);
260 return (error);
261 }
262 if (va.va_uid != p->p_ucred->cr_uid) {
263 error = suser_td(td);
264 if (error) {
265 vput(vp);
266 return (error);
267 }
268 }
269 if ((error = vinvalbuf(vp, V_SAVE, p->p_ucred, td, 0, 0)) != 0) {
270 vput(vp);
271 return (error);
272 }
273 if (vp->v_type != VDIR) {
274 vput(vp);
275 return (ENOTDIR);
276 }
277 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
278 if (!strcmp(vfsp->vfc_name, fstype))
279 break;
280 if (vfsp == NULL) {
281 linker_file_t lf;
282
283 /* Only load modules for root (very important!) */
284 error = suser_td(td);
285 if (error) {
286 vput(vp);
287 return error;
288 }
289 error = linker_load_file(fstype, &lf);
290 if (error || lf == NULL) {
291 vput(vp);
292 if (lf == NULL)
293 error = ENODEV;
294 return error;
295 }
296 lf->userrefs++;
297 /* lookup again, see if the VFS was loaded */
298 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
299 if (!strcmp(vfsp->vfc_name, fstype))
300 break;
301 if (vfsp == NULL) {
302 lf->userrefs--;
303 linker_file_unload(lf);
304 vput(vp);
305 return (ENODEV);
306 }
307 }
308 mtx_lock(&vp->v_interlock);
309 if ((vp->v_flag & VMOUNT) != 0 ||
310 vp->v_mountedhere != NULL) {
311 mtx_unlock(&vp->v_interlock);
312 vput(vp);
313 return (EBUSY);
314 }
315 vp->v_flag |= VMOUNT;
316 mtx_unlock(&vp->v_interlock);
317
318 /*
319 * Allocate and initialize the filesystem.
320 */
321 mp = malloc(sizeof(struct mount), M_MOUNT, M_WAITOK | M_ZERO);
40 */
41
42/* For 4.3 integer FS ID compatibility */
43#include "opt_compat.h"
44#include "opt_ffs.h"
45
46#include <sys/param.h>
47#include <sys/systm.h>
48#include <sys/bio.h>
49#include <sys/buf.h>
50#include <sys/sysent.h>
51#include <sys/malloc.h>
52#include <sys/mount.h>
53#include <sys/mutex.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/linker.h>
61#include <sys/stat.h>
62#include <sys/sx.h>
63#include <sys/unistd.h>
64#include <sys/vnode.h>
65#include <sys/proc.h>
66#include <sys/dirent.h>
67#include <sys/extattr.h>
68#include <sys/jail.h>
69#include <sys/sysctl.h>
70
71#include <machine/limits.h>
72
73#include <vm/vm.h>
74#include <vm/vm_object.h>
75#include <vm/vm_zone.h>
76#include <vm/vm_page.h>
77
78static int change_dir __P((struct nameidata *ndp, struct thread *td));
79static void checkdirs __P((struct vnode *olddp, struct vnode *newdp));
80static int chroot_refuse_vdir_fds __P((struct filedesc *fdp));
81static int getutimes __P((const struct timeval *, struct timespec *));
82static int setfown __P((struct thread *td, struct vnode *, uid_t, gid_t));
83static int setfmode __P((struct thread *td, struct vnode *, int));
84static int setfflags __P((struct thread *td, struct vnode *, int));
85static int setutimes __P((struct thread *td, struct vnode *,
86 const struct timespec *, int));
87static int vn_access __P((struct vnode *vp, int user_flags, struct ucred *cred,
88 struct thread *td));
89
90static int usermount = 0; /* if 1, non-root can mount fs. */
91
92int (*union_dircheckp) __P((struct thread *td, struct vnode **, struct file *));
93
94SYSCTL_INT(_vfs, OID_AUTO, usermount, CTLFLAG_RW, &usermount, 0, "");
95
96/*
97 * Virtual File System System Calls
98 */
99
100/*
101 * Mount a file system.
102 */
103#ifndef _SYS_SYSPROTO_H_
104struct mount_args {
105 char *type;
106 char *path;
107 int flags;
108 caddr_t data;
109};
110#endif
111/* ARGSUSED */
112int
113mount(td, uap)
114 struct thread *td;
115 struct mount_args /* {
116 syscallarg(char *) type;
117 syscallarg(char *) path;
118 syscallarg(int) flags;
119 syscallarg(caddr_t) data;
120 } */ *uap;
121{
122 char *fstype;
123 char *fspath;
124 int error;
125
126 fstype = malloc(MFSNAMELEN, M_TEMP, M_WAITOK | M_ZERO);
127 fspath = malloc(MNAMELEN, M_TEMP, M_WAITOK | M_ZERO);
128
129 /*
130 * vfs_mount() actually takes a kernel string for `type' and
131 * `path' now, so extract them.
132 */
133 error = copyinstr(SCARG(uap, type), fstype, MFSNAMELEN, NULL);
134 if (error)
135 goto finish;
136 error = copyinstr(SCARG(uap, path), fspath, MNAMELEN, NULL);
137 if (error)
138 goto finish;
139 error = vfs_mount(td, fstype, fspath, SCARG(uap, flags),
140 SCARG(uap, data));
141finish:
142 free(fstype, M_TEMP);
143 free(fspath, M_TEMP);
144 return (error);
145}
146
147/*
148 * vfs_mount(): actually attempt a filesystem mount.
149 *
150 * This routine is designed to be a "generic" entry point for routines
151 * that wish to mount a filesystem. All parameters except `fsdata' are
152 * pointers into kernel space. `fsdata' is currently still a pointer
153 * into userspace.
154 */
155int
156vfs_mount(td, fstype, fspath, fsflags, fsdata)
157 struct thread *td;
158 const char *fstype;
159 char *fspath;
160 int fsflags;
161 void *fsdata;
162{
163 struct vnode *vp;
164 struct mount *mp;
165 struct vfsconf *vfsp;
166 int error, flag = 0, flag2 = 0;
167 struct vattr va;
168 struct nameidata nd;
169 struct proc *p = td->td_proc;
170
171 /*
172 * Be ultra-paranoid about making sure the type and fspath
173 * variables will fit in our mp buffers, including the
174 * terminating NUL.
175 */
176 if ((strlen(fstype) >= MFSNAMELEN - 1) ||
177 (strlen(fspath) >= MNAMELEN - 1))
178 return (ENAMETOOLONG);
179
180 if (usermount == 0) {
181 error = suser_td(td);
182 if (error)
183 return (error);
184 }
185 /*
186 * Do not allow NFS export by non-root users.
187 */
188 if (fsflags & MNT_EXPORTED) {
189 error = suser_td(td);
190 if (error)
191 return (error);
192 }
193 /*
194 * Silently enforce MNT_NOSUID and MNT_NODEV for non-root users
195 */
196 if (suser_xxx(p->p_ucred, 0, 0))
197 fsflags |= MNT_NOSUID | MNT_NODEV;
198 /*
199 * Get vnode to be covered
200 */
201 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspath, td);
202 if ((error = namei(&nd)) != 0)
203 return (error);
204 NDFREE(&nd, NDF_ONLY_PNBUF);
205 vp = nd.ni_vp;
206 if (fsflags & MNT_UPDATE) {
207 if ((vp->v_flag & VROOT) == 0) {
208 vput(vp);
209 return (EINVAL);
210 }
211 mp = vp->v_mount;
212 flag = mp->mnt_flag;
213 flag2 = mp->mnt_kern_flag;
214 /*
215 * We only allow the filesystem to be reloaded if it
216 * is currently mounted read-only.
217 */
218 if ((fsflags & MNT_RELOAD) &&
219 ((mp->mnt_flag & MNT_RDONLY) == 0)) {
220 vput(vp);
221 return (EOPNOTSUPP); /* Needs translation */
222 }
223 /*
224 * Only root, or the user that did the original mount is
225 * permitted to update it.
226 */
227 if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid) {
228 error = suser_td(td);
229 if (error) {
230 vput(vp);
231 return (error);
232 }
233 }
234 if (vfs_busy(mp, LK_NOWAIT, 0, td)) {
235 vput(vp);
236 return (EBUSY);
237 }
238 mtx_lock(&vp->v_interlock);
239 if ((vp->v_flag & VMOUNT) != 0 ||
240 vp->v_mountedhere != NULL) {
241 mtx_unlock(&vp->v_interlock);
242 vfs_unbusy(mp, td);
243 vput(vp);
244 return (EBUSY);
245 }
246 vp->v_flag |= VMOUNT;
247 mtx_unlock(&vp->v_interlock);
248 mp->mnt_flag |= fsflags &
249 (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_SNAPSHOT);
250 VOP_UNLOCK(vp, 0, td);
251 goto update;
252 }
253 /*
254 * If the user is not root, ensure that they own the directory
255 * onto which we are attempting to mount.
256 */
257 error = VOP_GETATTR(vp, &va, p->p_ucred, td);
258 if (error) {
259 vput(vp);
260 return (error);
261 }
262 if (va.va_uid != p->p_ucred->cr_uid) {
263 error = suser_td(td);
264 if (error) {
265 vput(vp);
266 return (error);
267 }
268 }
269 if ((error = vinvalbuf(vp, V_SAVE, p->p_ucred, td, 0, 0)) != 0) {
270 vput(vp);
271 return (error);
272 }
273 if (vp->v_type != VDIR) {
274 vput(vp);
275 return (ENOTDIR);
276 }
277 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
278 if (!strcmp(vfsp->vfc_name, fstype))
279 break;
280 if (vfsp == NULL) {
281 linker_file_t lf;
282
283 /* Only load modules for root (very important!) */
284 error = suser_td(td);
285 if (error) {
286 vput(vp);
287 return error;
288 }
289 error = linker_load_file(fstype, &lf);
290 if (error || lf == NULL) {
291 vput(vp);
292 if (lf == NULL)
293 error = ENODEV;
294 return error;
295 }
296 lf->userrefs++;
297 /* lookup again, see if the VFS was loaded */
298 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
299 if (!strcmp(vfsp->vfc_name, fstype))
300 break;
301 if (vfsp == NULL) {
302 lf->userrefs--;
303 linker_file_unload(lf);
304 vput(vp);
305 return (ENODEV);
306 }
307 }
308 mtx_lock(&vp->v_interlock);
309 if ((vp->v_flag & VMOUNT) != 0 ||
310 vp->v_mountedhere != NULL) {
311 mtx_unlock(&vp->v_interlock);
312 vput(vp);
313 return (EBUSY);
314 }
315 vp->v_flag |= VMOUNT;
316 mtx_unlock(&vp->v_interlock);
317
318 /*
319 * Allocate and initialize the filesystem.
320 */
321 mp = malloc(sizeof(struct mount), M_MOUNT, M_WAITOK | M_ZERO);
322 TAILQ_INIT(&mp->mnt_nvnodelist);
322 lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, LK_NOPAUSE);
323 (void)vfs_busy(mp, LK_NOWAIT, 0, td);
324 mp->mnt_op = vfsp->vfc_vfsops;
325 mp->mnt_vfc = vfsp;
326 vfsp->vfc_refcount++;
327 mp->mnt_stat.f_type = vfsp->vfc_typenum;
328 mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
329 strncpy(mp->mnt_stat.f_fstypename, fstype, MFSNAMELEN);
330 mp->mnt_stat.f_fstypename[MFSNAMELEN - 1] = '\0';
331 mp->mnt_vnodecovered = vp;
332 mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
333 strncpy(mp->mnt_stat.f_mntonname, fspath, MNAMELEN);
334 mp->mnt_stat.f_mntonname[MNAMELEN - 1] = '\0';
335 mp->mnt_iosize_max = DFLTPHYS;
336 VOP_UNLOCK(vp, 0, td);
337update:
338 /*
339 * Set the mount level flags.
340 */
341 if (fsflags & MNT_RDONLY)
342 mp->mnt_flag |= MNT_RDONLY;
343 else if (mp->mnt_flag & MNT_RDONLY)
344 mp->mnt_kern_flag |= MNTK_WANTRDWR;
345 mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
346 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOATIME |
347 MNT_NOSYMFOLLOW | MNT_IGNORE |
348 MNT_NOCLUSTERR | MNT_NOCLUSTERW | MNT_SUIDDIR);
349 mp->mnt_flag |= fsflags & (MNT_NOSUID | MNT_NOEXEC |
350 MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_FORCE |
351 MNT_NOSYMFOLLOW | MNT_IGNORE |
352 MNT_NOATIME | MNT_NOCLUSTERR | MNT_NOCLUSTERW | MNT_SUIDDIR);
353 /*
354 * Mount the filesystem.
355 * XXX The final recipients of VFS_MOUNT just overwrite the ndp they
356 * get. No freeing of cn_pnbuf.
357 */
358 error = VFS_MOUNT(mp, fspath, fsdata, &nd, td);
359 if (mp->mnt_flag & MNT_UPDATE) {
360 if (mp->mnt_kern_flag & MNTK_WANTRDWR)
361 mp->mnt_flag &= ~MNT_RDONLY;
362 mp->mnt_flag &=~
363 (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_SNAPSHOT);
364 mp->mnt_kern_flag &=~ MNTK_WANTRDWR;
365 if (error) {
366 mp->mnt_flag = flag;
367 mp->mnt_kern_flag = flag2;
368 }
369 if ((mp->mnt_flag & MNT_RDONLY) == 0) {
370 if (mp->mnt_syncer == NULL)
371 error = vfs_allocate_syncvnode(mp);
372 } else {
373 if (mp->mnt_syncer != NULL)
374 vrele(mp->mnt_syncer);
375 mp->mnt_syncer = NULL;
376 }
377 vfs_unbusy(mp, td);
378 mtx_lock(&vp->v_interlock);
379 vp->v_flag &= ~VMOUNT;
380 mtx_unlock(&vp->v_interlock);
381 vrele(vp);
382 return (error);
383 }
384 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
385 /*
386 * Put the new filesystem on the mount list after root.
387 */
388 cache_purge(vp);
389 if (!error) {
390 struct vnode *newdp;
391
392 mtx_lock(&vp->v_interlock);
393 vp->v_flag &= ~VMOUNT;
394 vp->v_mountedhere = mp;
395 mtx_unlock(&vp->v_interlock);
396 mtx_lock(&mountlist_mtx);
397 TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
398 mtx_unlock(&mountlist_mtx);
399 if (VFS_ROOT(mp, &newdp))
400 panic("mount: lost mount");
401 checkdirs(vp, newdp);
402 vput(newdp);
403 VOP_UNLOCK(vp, 0, td);
404 if ((mp->mnt_flag & MNT_RDONLY) == 0)
405 error = vfs_allocate_syncvnode(mp);
406 vfs_unbusy(mp, td);
407 if ((error = VFS_START(mp, 0, td)) != 0)
408 vrele(vp);
409 } else {
410 mtx_lock(&vp->v_interlock);
411 vp->v_flag &= ~VMOUNT;
412 mtx_unlock(&vp->v_interlock);
413 mp->mnt_vfc->vfc_refcount--;
414 vfs_unbusy(mp, td);
415 free((caddr_t)mp, M_MOUNT);
416 vput(vp);
417 }
418 return (error);
419}
420
421/*
422 * Scan all active processes to see if any of them have a current
423 * or root directory of `olddp'. If so, replace them with the new
424 * mount point.
425 */
426static void
427checkdirs(olddp, newdp)
428 struct vnode *olddp, *newdp;
429{
430 struct filedesc *fdp;
431 struct proc *p;
432
433 if (olddp->v_usecount == 1)
434 return;
435 sx_slock(&allproc_lock);
436 LIST_FOREACH(p, &allproc, p_list) {
437 fdp = p->p_fd;
438 if (fdp == NULL)
439 continue;
440 if (fdp->fd_cdir == olddp) {
441 vrele(fdp->fd_cdir);
442 VREF(newdp);
443 fdp->fd_cdir = newdp;
444 }
445 if (fdp->fd_rdir == olddp) {
446 vrele(fdp->fd_rdir);
447 VREF(newdp);
448 fdp->fd_rdir = newdp;
449 }
450 }
451 sx_sunlock(&allproc_lock);
452 if (rootvnode == olddp) {
453 vrele(rootvnode);
454 VREF(newdp);
455 rootvnode = newdp;
456 }
457}
458
459/*
460 * Unmount a file system.
461 *
462 * Note: unmount takes a path to the vnode mounted on as argument,
463 * not special file (as before).
464 */
465#ifndef _SYS_SYSPROTO_H_
466struct unmount_args {
467 char *path;
468 int flags;
469};
470#endif
471/* ARGSUSED */
472int
473unmount(td, uap)
474 struct thread *td;
475 register struct unmount_args /* {
476 syscallarg(char *) path;
477 syscallarg(int) flags;
478 } */ *uap;
479{
480 register struct vnode *vp;
481 struct mount *mp;
482 int error;
483 struct nameidata nd;
484
485 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
486 SCARG(uap, path), td);
487 if ((error = namei(&nd)) != 0)
488 return (error);
489 vp = nd.ni_vp;
490 NDFREE(&nd, NDF_ONLY_PNBUF);
491 mp = vp->v_mount;
492
493 /*
494 * Only root, or the user that did the original mount is
495 * permitted to unmount this filesystem.
496 */
497 if (mp->mnt_stat.f_owner != td->td_proc->p_ucred->cr_uid) {
498 error = suser_td(td);
499 if (error) {
500 vput(vp);
501 return (error);
502 }
503 }
504
505 /*
506 * Don't allow unmounting the root file system.
507 */
508 if (mp->mnt_flag & MNT_ROOTFS) {
509 vput(vp);
510 return (EINVAL);
511 }
512
513 /*
514 * Must be the root of the filesystem
515 */
516 if ((vp->v_flag & VROOT) == 0) {
517 vput(vp);
518 return (EINVAL);
519 }
520 vput(vp);
521 return (dounmount(mp, SCARG(uap, flags), td));
522}
523
524/*
525 * Do the actual file system unmount.
526 */
527int
528dounmount(mp, flags, td)
529 struct mount *mp;
530 int flags;
531 struct thread *td;
532{
533 struct vnode *coveredvp, *fsrootvp;
534 int error;
535 int async_flag;
536
537 mtx_lock(&mountlist_mtx);
538 mp->mnt_kern_flag |= MNTK_UNMOUNT;
539 lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_mtx, td);
540 vn_start_write(NULL, &mp, V_WAIT);
541
542 if (mp->mnt_flag & MNT_EXPUBLIC)
543 vfs_setpublicfs(NULL, NULL, NULL);
544
545 vfs_msync(mp, MNT_WAIT);
546 async_flag = mp->mnt_flag & MNT_ASYNC;
547 mp->mnt_flag &=~ MNT_ASYNC;
548 cache_purgevfs(mp); /* remove cache entries for this file sys */
549 if (mp->mnt_syncer != NULL)
550 vrele(mp->mnt_syncer);
551 /* Move process cdir/rdir refs on fs root to underlying vnode. */
552 if (VFS_ROOT(mp, &fsrootvp) == 0) {
553 if (mp->mnt_vnodecovered != NULL)
554 checkdirs(fsrootvp, mp->mnt_vnodecovered);
555 if (fsrootvp == rootvnode) {
556 vrele(rootvnode);
557 rootvnode = NULL;
558 }
559 vput(fsrootvp);
560 }
561 if (((mp->mnt_flag & MNT_RDONLY) ||
562 (error = VFS_SYNC(mp, MNT_WAIT, td->td_proc->p_ucred, td)) == 0) ||
563 (flags & MNT_FORCE)) {
564 error = VFS_UNMOUNT(mp, flags, td);
565 }
566 vn_finished_write(mp);
567 if (error) {
568 /* Undo cdir/rdir and rootvnode changes made above. */
569 if (VFS_ROOT(mp, &fsrootvp) == 0) {
570 if (mp->mnt_vnodecovered != NULL)
571 checkdirs(mp->mnt_vnodecovered, fsrootvp);
572 if (rootvnode == NULL) {
573 rootvnode = fsrootvp;
574 vref(rootvnode);
575 }
576 vput(fsrootvp);
577 }
578 if ((mp->mnt_flag & MNT_RDONLY) == 0 && mp->mnt_syncer == NULL)
579 (void) vfs_allocate_syncvnode(mp);
580 mtx_lock(&mountlist_mtx);
581 mp->mnt_kern_flag &= ~MNTK_UNMOUNT;
582 mp->mnt_flag |= async_flag;
583 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK,
584 &mountlist_mtx, td);
585 if (mp->mnt_kern_flag & MNTK_MWAIT)
586 wakeup((caddr_t)mp);
587 return (error);
588 }
589 mtx_lock(&mountlist_mtx);
590 TAILQ_REMOVE(&mountlist, mp, mnt_list);
591 if ((coveredvp = mp->mnt_vnodecovered) != NULL)
592 coveredvp->v_mountedhere = NULL;
593 mp->mnt_vfc->vfc_refcount--;
323 lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, LK_NOPAUSE);
324 (void)vfs_busy(mp, LK_NOWAIT, 0, td);
325 mp->mnt_op = vfsp->vfc_vfsops;
326 mp->mnt_vfc = vfsp;
327 vfsp->vfc_refcount++;
328 mp->mnt_stat.f_type = vfsp->vfc_typenum;
329 mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
330 strncpy(mp->mnt_stat.f_fstypename, fstype, MFSNAMELEN);
331 mp->mnt_stat.f_fstypename[MFSNAMELEN - 1] = '\0';
332 mp->mnt_vnodecovered = vp;
333 mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
334 strncpy(mp->mnt_stat.f_mntonname, fspath, MNAMELEN);
335 mp->mnt_stat.f_mntonname[MNAMELEN - 1] = '\0';
336 mp->mnt_iosize_max = DFLTPHYS;
337 VOP_UNLOCK(vp, 0, td);
338update:
339 /*
340 * Set the mount level flags.
341 */
342 if (fsflags & MNT_RDONLY)
343 mp->mnt_flag |= MNT_RDONLY;
344 else if (mp->mnt_flag & MNT_RDONLY)
345 mp->mnt_kern_flag |= MNTK_WANTRDWR;
346 mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
347 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOATIME |
348 MNT_NOSYMFOLLOW | MNT_IGNORE |
349 MNT_NOCLUSTERR | MNT_NOCLUSTERW | MNT_SUIDDIR);
350 mp->mnt_flag |= fsflags & (MNT_NOSUID | MNT_NOEXEC |
351 MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_FORCE |
352 MNT_NOSYMFOLLOW | MNT_IGNORE |
353 MNT_NOATIME | MNT_NOCLUSTERR | MNT_NOCLUSTERW | MNT_SUIDDIR);
354 /*
355 * Mount the filesystem.
356 * XXX The final recipients of VFS_MOUNT just overwrite the ndp they
357 * get. No freeing of cn_pnbuf.
358 */
359 error = VFS_MOUNT(mp, fspath, fsdata, &nd, td);
360 if (mp->mnt_flag & MNT_UPDATE) {
361 if (mp->mnt_kern_flag & MNTK_WANTRDWR)
362 mp->mnt_flag &= ~MNT_RDONLY;
363 mp->mnt_flag &=~
364 (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_SNAPSHOT);
365 mp->mnt_kern_flag &=~ MNTK_WANTRDWR;
366 if (error) {
367 mp->mnt_flag = flag;
368 mp->mnt_kern_flag = flag2;
369 }
370 if ((mp->mnt_flag & MNT_RDONLY) == 0) {
371 if (mp->mnt_syncer == NULL)
372 error = vfs_allocate_syncvnode(mp);
373 } else {
374 if (mp->mnt_syncer != NULL)
375 vrele(mp->mnt_syncer);
376 mp->mnt_syncer = NULL;
377 }
378 vfs_unbusy(mp, td);
379 mtx_lock(&vp->v_interlock);
380 vp->v_flag &= ~VMOUNT;
381 mtx_unlock(&vp->v_interlock);
382 vrele(vp);
383 return (error);
384 }
385 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
386 /*
387 * Put the new filesystem on the mount list after root.
388 */
389 cache_purge(vp);
390 if (!error) {
391 struct vnode *newdp;
392
393 mtx_lock(&vp->v_interlock);
394 vp->v_flag &= ~VMOUNT;
395 vp->v_mountedhere = mp;
396 mtx_unlock(&vp->v_interlock);
397 mtx_lock(&mountlist_mtx);
398 TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
399 mtx_unlock(&mountlist_mtx);
400 if (VFS_ROOT(mp, &newdp))
401 panic("mount: lost mount");
402 checkdirs(vp, newdp);
403 vput(newdp);
404 VOP_UNLOCK(vp, 0, td);
405 if ((mp->mnt_flag & MNT_RDONLY) == 0)
406 error = vfs_allocate_syncvnode(mp);
407 vfs_unbusy(mp, td);
408 if ((error = VFS_START(mp, 0, td)) != 0)
409 vrele(vp);
410 } else {
411 mtx_lock(&vp->v_interlock);
412 vp->v_flag &= ~VMOUNT;
413 mtx_unlock(&vp->v_interlock);
414 mp->mnt_vfc->vfc_refcount--;
415 vfs_unbusy(mp, td);
416 free((caddr_t)mp, M_MOUNT);
417 vput(vp);
418 }
419 return (error);
420}
421
422/*
423 * Scan all active processes to see if any of them have a current
424 * or root directory of `olddp'. If so, replace them with the new
425 * mount point.
426 */
427static void
428checkdirs(olddp, newdp)
429 struct vnode *olddp, *newdp;
430{
431 struct filedesc *fdp;
432 struct proc *p;
433
434 if (olddp->v_usecount == 1)
435 return;
436 sx_slock(&allproc_lock);
437 LIST_FOREACH(p, &allproc, p_list) {
438 fdp = p->p_fd;
439 if (fdp == NULL)
440 continue;
441 if (fdp->fd_cdir == olddp) {
442 vrele(fdp->fd_cdir);
443 VREF(newdp);
444 fdp->fd_cdir = newdp;
445 }
446 if (fdp->fd_rdir == olddp) {
447 vrele(fdp->fd_rdir);
448 VREF(newdp);
449 fdp->fd_rdir = newdp;
450 }
451 }
452 sx_sunlock(&allproc_lock);
453 if (rootvnode == olddp) {
454 vrele(rootvnode);
455 VREF(newdp);
456 rootvnode = newdp;
457 }
458}
459
460/*
461 * Unmount a file system.
462 *
463 * Note: unmount takes a path to the vnode mounted on as argument,
464 * not special file (as before).
465 */
466#ifndef _SYS_SYSPROTO_H_
467struct unmount_args {
468 char *path;
469 int flags;
470};
471#endif
472/* ARGSUSED */
473int
474unmount(td, uap)
475 struct thread *td;
476 register struct unmount_args /* {
477 syscallarg(char *) path;
478 syscallarg(int) flags;
479 } */ *uap;
480{
481 register struct vnode *vp;
482 struct mount *mp;
483 int error;
484 struct nameidata nd;
485
486 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
487 SCARG(uap, path), td);
488 if ((error = namei(&nd)) != 0)
489 return (error);
490 vp = nd.ni_vp;
491 NDFREE(&nd, NDF_ONLY_PNBUF);
492 mp = vp->v_mount;
493
494 /*
495 * Only root, or the user that did the original mount is
496 * permitted to unmount this filesystem.
497 */
498 if (mp->mnt_stat.f_owner != td->td_proc->p_ucred->cr_uid) {
499 error = suser_td(td);
500 if (error) {
501 vput(vp);
502 return (error);
503 }
504 }
505
506 /*
507 * Don't allow unmounting the root file system.
508 */
509 if (mp->mnt_flag & MNT_ROOTFS) {
510 vput(vp);
511 return (EINVAL);
512 }
513
514 /*
515 * Must be the root of the filesystem
516 */
517 if ((vp->v_flag & VROOT) == 0) {
518 vput(vp);
519 return (EINVAL);
520 }
521 vput(vp);
522 return (dounmount(mp, SCARG(uap, flags), td));
523}
524
525/*
526 * Do the actual file system unmount.
527 */
528int
529dounmount(mp, flags, td)
530 struct mount *mp;
531 int flags;
532 struct thread *td;
533{
534 struct vnode *coveredvp, *fsrootvp;
535 int error;
536 int async_flag;
537
538 mtx_lock(&mountlist_mtx);
539 mp->mnt_kern_flag |= MNTK_UNMOUNT;
540 lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_mtx, td);
541 vn_start_write(NULL, &mp, V_WAIT);
542
543 if (mp->mnt_flag & MNT_EXPUBLIC)
544 vfs_setpublicfs(NULL, NULL, NULL);
545
546 vfs_msync(mp, MNT_WAIT);
547 async_flag = mp->mnt_flag & MNT_ASYNC;
548 mp->mnt_flag &=~ MNT_ASYNC;
549 cache_purgevfs(mp); /* remove cache entries for this file sys */
550 if (mp->mnt_syncer != NULL)
551 vrele(mp->mnt_syncer);
552 /* Move process cdir/rdir refs on fs root to underlying vnode. */
553 if (VFS_ROOT(mp, &fsrootvp) == 0) {
554 if (mp->mnt_vnodecovered != NULL)
555 checkdirs(fsrootvp, mp->mnt_vnodecovered);
556 if (fsrootvp == rootvnode) {
557 vrele(rootvnode);
558 rootvnode = NULL;
559 }
560 vput(fsrootvp);
561 }
562 if (((mp->mnt_flag & MNT_RDONLY) ||
563 (error = VFS_SYNC(mp, MNT_WAIT, td->td_proc->p_ucred, td)) == 0) ||
564 (flags & MNT_FORCE)) {
565 error = VFS_UNMOUNT(mp, flags, td);
566 }
567 vn_finished_write(mp);
568 if (error) {
569 /* Undo cdir/rdir and rootvnode changes made above. */
570 if (VFS_ROOT(mp, &fsrootvp) == 0) {
571 if (mp->mnt_vnodecovered != NULL)
572 checkdirs(mp->mnt_vnodecovered, fsrootvp);
573 if (rootvnode == NULL) {
574 rootvnode = fsrootvp;
575 vref(rootvnode);
576 }
577 vput(fsrootvp);
578 }
579 if ((mp->mnt_flag & MNT_RDONLY) == 0 && mp->mnt_syncer == NULL)
580 (void) vfs_allocate_syncvnode(mp);
581 mtx_lock(&mountlist_mtx);
582 mp->mnt_kern_flag &= ~MNTK_UNMOUNT;
583 mp->mnt_flag |= async_flag;
584 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK,
585 &mountlist_mtx, td);
586 if (mp->mnt_kern_flag & MNTK_MWAIT)
587 wakeup((caddr_t)mp);
588 return (error);
589 }
590 mtx_lock(&mountlist_mtx);
591 TAILQ_REMOVE(&mountlist, mp, mnt_list);
592 if ((coveredvp = mp->mnt_vnodecovered) != NULL)
593 coveredvp->v_mountedhere = NULL;
594 mp->mnt_vfc->vfc_refcount--;
594 if (!LIST_EMPTY(&mp->mnt_vnodelist))
595 if (!TAILQ_EMPTY(&mp->mnt_nvnodelist))
595 panic("unmount: dangling vnode");
596 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_mtx, td);
597 lockdestroy(&mp->mnt_lock);
598 if (coveredvp != NULL)
599 vrele(coveredvp);
600 if (mp->mnt_kern_flag & MNTK_MWAIT)
601 wakeup((caddr_t)mp);
602 free((caddr_t)mp, M_MOUNT);
603 return (0);
604}
605
606/*
607 * Sync each mounted filesystem.
608 */
609#ifndef _SYS_SYSPROTO_H_
610struct sync_args {
611 int dummy;
612};
613#endif
614
615#ifdef DEBUG
616static int syncprt = 0;
617SYSCTL_INT(_debug, OID_AUTO, syncprt, CTLFLAG_RW, &syncprt, 0, "");
618#endif
619
620/* ARGSUSED */
621int
622sync(td, uap)
623 struct thread *td;
624 struct sync_args *uap;
625{
626 struct mount *mp, *nmp;
627 int asyncflag;
628
629 mtx_lock(&mountlist_mtx);
630 for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
631 if (vfs_busy(mp, LK_NOWAIT, &mountlist_mtx, td)) {
632 nmp = TAILQ_NEXT(mp, mnt_list);
633 continue;
634 }
635 if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
636 vn_start_write(NULL, &mp, V_NOWAIT) == 0) {
637 asyncflag = mp->mnt_flag & MNT_ASYNC;
638 mp->mnt_flag &= ~MNT_ASYNC;
639 vfs_msync(mp, MNT_NOWAIT);
640 VFS_SYNC(mp, MNT_NOWAIT,
641 ((td != NULL) ? td->td_proc->p_ucred : NOCRED), td);
642 mp->mnt_flag |= asyncflag;
643 vn_finished_write(mp);
644 }
645 mtx_lock(&mountlist_mtx);
646 nmp = TAILQ_NEXT(mp, mnt_list);
647 vfs_unbusy(mp, td);
648 }
649 mtx_unlock(&mountlist_mtx);
650#if 0
651/*
652 * XXX don't call vfs_bufstats() yet because that routine
653 * was not imported in the Lite2 merge.
654 */
655#ifdef DIAGNOSTIC
656 if (syncprt)
657 vfs_bufstats();
658#endif /* DIAGNOSTIC */
659#endif
660 return (0);
661}
662
663/* XXX PRISON: could be per prison flag */
664static int prison_quotas;
665#if 0
666SYSCTL_INT(_kern_prison, OID_AUTO, quotas, CTLFLAG_RW, &prison_quotas, 0, "");
667#endif
668
669/*
670 * Change filesystem quotas.
671 */
672#ifndef _SYS_SYSPROTO_H_
673struct quotactl_args {
674 char *path;
675 int cmd;
676 int uid;
677 caddr_t arg;
678};
679#endif
680/* ARGSUSED */
681int
682quotactl(td, uap)
683 struct thread *td;
684 register struct quotactl_args /* {
685 syscallarg(char *) path;
686 syscallarg(int) cmd;
687 syscallarg(int) uid;
688 syscallarg(caddr_t) arg;
689 } */ *uap;
690{
691 struct mount *mp;
692 int error;
693 struct nameidata nd;
694
695 if (jailed(td->td_proc->p_ucred) && !prison_quotas)
696 return (EPERM);
697 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
698 if ((error = namei(&nd)) != 0)
699 return (error);
700 NDFREE(&nd, NDF_ONLY_PNBUF);
701 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
702 vrele(nd.ni_vp);
703 if (error)
704 return (error);
705 error = VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
706 SCARG(uap, arg), td);
707 vn_finished_write(mp);
708 return (error);
709}
710
711/*
712 * Get filesystem statistics.
713 */
714#ifndef _SYS_SYSPROTO_H_
715struct statfs_args {
716 char *path;
717 struct statfs *buf;
718};
719#endif
720/* ARGSUSED */
721int
722statfs(td, uap)
723 struct thread *td;
724 register struct statfs_args /* {
725 syscallarg(char *) path;
726 syscallarg(struct statfs *) buf;
727 } */ *uap;
728{
729 register struct mount *mp;
730 register struct statfs *sp;
731 int error;
732 struct nameidata nd;
733 struct statfs sb;
734
735 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
736 if ((error = namei(&nd)) != 0)
737 return (error);
738 mp = nd.ni_vp->v_mount;
739 sp = &mp->mnt_stat;
740 NDFREE(&nd, NDF_ONLY_PNBUF);
741 vrele(nd.ni_vp);
742 error = VFS_STATFS(mp, sp, td);
743 if (error)
744 return (error);
745 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
746 if (suser_xxx(td->td_proc->p_ucred, 0, 0)) {
747 bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb));
748 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
749 sp = &sb;
750 }
751 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
752}
753
754/*
755 * Get filesystem statistics.
756 */
757#ifndef _SYS_SYSPROTO_H_
758struct fstatfs_args {
759 int fd;
760 struct statfs *buf;
761};
762#endif
763/* ARGSUSED */
764int
765fstatfs(td, uap)
766 struct thread *td;
767 register struct fstatfs_args /* {
768 syscallarg(int) fd;
769 syscallarg(struct statfs *) buf;
770 } */ *uap;
771{
772 struct file *fp;
773 struct mount *mp;
774 register struct statfs *sp;
775 int error;
776 struct statfs sb;
777
778 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
779 return (error);
780 mp = ((struct vnode *)fp->f_data)->v_mount;
781 sp = &mp->mnt_stat;
782 error = VFS_STATFS(mp, sp, td);
783 if (error)
784 return (error);
785 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
786 if (suser_xxx(td->td_proc->p_ucred, 0, 0)) {
787 bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb));
788 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
789 sp = &sb;
790 }
791 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
792}
793
794/*
795 * Get statistics on all filesystems.
796 */
797#ifndef _SYS_SYSPROTO_H_
798struct getfsstat_args {
799 struct statfs *buf;
800 long bufsize;
801 int flags;
802};
803#endif
804int
805getfsstat(td, uap)
806 struct thread *td;
807 register struct getfsstat_args /* {
808 syscallarg(struct statfs *) buf;
809 syscallarg(long) bufsize;
810 syscallarg(int) flags;
811 } */ *uap;
812{
813 register struct mount *mp, *nmp;
814 register struct statfs *sp;
815 caddr_t sfsp;
816 long count, maxcount, error;
817
818 maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
819 sfsp = (caddr_t)SCARG(uap, buf);
820 count = 0;
821 mtx_lock(&mountlist_mtx);
822 for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
823 if (vfs_busy(mp, LK_NOWAIT, &mountlist_mtx, td)) {
824 nmp = TAILQ_NEXT(mp, mnt_list);
825 continue;
826 }
827 if (sfsp && count < maxcount) {
828 sp = &mp->mnt_stat;
829 /*
830 * If MNT_NOWAIT or MNT_LAZY is specified, do not
831 * refresh the fsstat cache. MNT_NOWAIT or MNT_LAZY
832 * overrides MNT_WAIT.
833 */
834 if (((SCARG(uap, flags) & (MNT_LAZY|MNT_NOWAIT)) == 0 ||
835 (SCARG(uap, flags) & MNT_WAIT)) &&
836 (error = VFS_STATFS(mp, sp, td))) {
837 mtx_lock(&mountlist_mtx);
838 nmp = TAILQ_NEXT(mp, mnt_list);
839 vfs_unbusy(mp, td);
840 continue;
841 }
842 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
843 error = copyout((caddr_t)sp, sfsp, sizeof(*sp));
844 if (error) {
845 vfs_unbusy(mp, td);
846 return (error);
847 }
848 sfsp += sizeof(*sp);
849 }
850 count++;
851 mtx_lock(&mountlist_mtx);
852 nmp = TAILQ_NEXT(mp, mnt_list);
853 vfs_unbusy(mp, td);
854 }
855 mtx_unlock(&mountlist_mtx);
856 if (sfsp && count > maxcount)
857 td->td_retval[0] = maxcount;
858 else
859 td->td_retval[0] = count;
860 return (0);
861}
862
863/*
864 * Change current working directory to a given file descriptor.
865 */
866#ifndef _SYS_SYSPROTO_H_
867struct fchdir_args {
868 int fd;
869};
870#endif
871/* ARGSUSED */
872int
873fchdir(td, uap)
874 struct thread *td;
875 struct fchdir_args /* {
876 syscallarg(int) fd;
877 } */ *uap;
878{
879 register struct filedesc *fdp = td->td_proc->p_fd;
880 struct vnode *vp, *tdp;
881 struct mount *mp;
882 struct file *fp;
883 int error;
884
885 if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0)
886 return (error);
887 vp = (struct vnode *)fp->f_data;
888 VREF(vp);
889 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
890 if (vp->v_type != VDIR)
891 error = ENOTDIR;
892 else
893 error = VOP_ACCESS(vp, VEXEC, td->td_proc->p_ucred, td);
894 while (!error && (mp = vp->v_mountedhere) != NULL) {
895 if (vfs_busy(mp, 0, 0, td))
896 continue;
897 error = VFS_ROOT(mp, &tdp);
898 vfs_unbusy(mp, td);
899 if (error)
900 break;
901 vput(vp);
902 vp = tdp;
903 }
904 if (error) {
905 vput(vp);
906 return (error);
907 }
908 VOP_UNLOCK(vp, 0, td);
909 vrele(fdp->fd_cdir);
910 fdp->fd_cdir = vp;
911 return (0);
912}
913
914/*
915 * Change current working directory (``.'').
916 */
917#ifndef _SYS_SYSPROTO_H_
918struct chdir_args {
919 char *path;
920};
921#endif
922/* ARGSUSED */
923int
924chdir(td, uap)
925 struct thread *td;
926 struct chdir_args /* {
927 syscallarg(char *) path;
928 } */ *uap;
929{
930 register struct filedesc *fdp = td->td_proc->p_fd;
931 int error;
932 struct nameidata nd;
933
934 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
935 SCARG(uap, path), td);
936 if ((error = change_dir(&nd, td)) != 0)
937 return (error);
938 NDFREE(&nd, NDF_ONLY_PNBUF);
939 vrele(fdp->fd_cdir);
940 fdp->fd_cdir = nd.ni_vp;
941 return (0);
942}
943
944/*
945 * Helper function for raised chroot(2) security function: Refuse if
946 * any filedescriptors are open directories.
947 */
948static int
949chroot_refuse_vdir_fds(fdp)
950 struct filedesc *fdp;
951{
952 struct vnode *vp;
953 struct file *fp;
954 int error;
955 int fd;
956
957 for (fd = 0; fd < fdp->fd_nfiles ; fd++) {
958 error = getvnode(fdp, fd, &fp);
959 if (error)
960 continue;
961 vp = (struct vnode *)fp->f_data;
962 if (vp->v_type != VDIR)
963 continue;
964 return(EPERM);
965 }
966 return (0);
967}
968
969/*
970 * This sysctl determines if we will allow a process to chroot(2) if it
971 * has a directory open:
972 * 0: disallowed for all processes.
973 * 1: allowed for processes that were not already chroot(2)'ed.
974 * 2: allowed for all processes.
975 */
976
977static int chroot_allow_open_directories = 1;
978
979SYSCTL_INT(_kern, OID_AUTO, chroot_allow_open_directories, CTLFLAG_RW,
980 &chroot_allow_open_directories, 0, "");
981
982/*
983 * Change notion of root (``/'') directory.
984 */
985#ifndef _SYS_SYSPROTO_H_
986struct chroot_args {
987 char *path;
988};
989#endif
990/* ARGSUSED */
991int
992chroot(td, uap)
993 struct thread *td;
994 struct chroot_args /* {
995 syscallarg(char *) path;
996 } */ *uap;
997{
998 register struct filedesc *fdp = td->td_proc->p_fd;
999 int error;
1000 struct nameidata nd;
1001
1002 error = suser_xxx(0, td->td_proc, PRISON_ROOT);
1003 if (error)
1004 return (error);
1005 if (chroot_allow_open_directories == 0 ||
1006 (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode))
1007 error = chroot_refuse_vdir_fds(fdp);
1008 if (error)
1009 return (error);
1010 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1011 SCARG(uap, path), td);
1012 if ((error = change_dir(&nd, td)) != 0)
1013 return (error);
1014 NDFREE(&nd, NDF_ONLY_PNBUF);
1015 vrele(fdp->fd_rdir);
1016 fdp->fd_rdir = nd.ni_vp;
1017 if (!fdp->fd_jdir) {
1018 fdp->fd_jdir = nd.ni_vp;
1019 VREF(fdp->fd_jdir);
1020 }
1021 return (0);
1022}
1023
1024/*
1025 * Common routine for chroot and chdir.
1026 */
1027static int
1028change_dir(ndp, td)
1029 register struct nameidata *ndp;
1030 struct thread *td;
1031{
1032 struct vnode *vp;
1033 int error;
1034
1035 error = namei(ndp);
1036 if (error)
1037 return (error);
1038 vp = ndp->ni_vp;
1039 if (vp->v_type != VDIR)
1040 error = ENOTDIR;
1041 else
1042 error = VOP_ACCESS(vp, VEXEC, td->td_proc->p_ucred, td);
1043 if (error)
1044 vput(vp);
1045 else
1046 VOP_UNLOCK(vp, 0, td);
1047 return (error);
1048}
1049
1050/*
1051 * Check permissions, allocate an open file structure,
1052 * and call the device open routine if any.
1053 */
1054#ifndef _SYS_SYSPROTO_H_
1055struct open_args {
1056 char *path;
1057 int flags;
1058 int mode;
1059};
1060#endif
1061int
1062open(td, uap)
1063 struct thread *td;
1064 register struct open_args /* {
1065 syscallarg(char *) path;
1066 syscallarg(int) flags;
1067 syscallarg(int) mode;
1068 } */ *uap;
1069{
1070 struct proc *p = td->td_proc;
1071 struct filedesc *fdp = p->p_fd;
1072 struct file *fp;
1073 struct vnode *vp;
1074 struct vattr vat;
1075 struct mount *mp;
1076 int cmode, flags, oflags;
1077 struct file *nfp;
1078 int type, indx, error;
1079 struct flock lf;
1080 struct nameidata nd;
1081
1082 oflags = SCARG(uap, flags);
1083 if ((oflags & O_ACCMODE) == O_ACCMODE)
1084 return (EINVAL);
1085 flags = FFLAGS(oflags);
1086 error = falloc(td, &nfp, &indx);
1087 if (error)
1088 return (error);
1089 fp = nfp;
1090 cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
1091 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
1092 td->td_dupfd = -indx - 1; /* XXX check for fdopen */
1093 /*
1094 * Bump the ref count to prevent another process from closing
1095 * the descriptor while we are blocked in vn_open()
1096 */
1097 fhold(fp);
1098 error = vn_open(&nd, &flags, cmode);
1099 if (error) {
1100 /*
1101 * release our own reference
1102 */
1103 fdrop(fp, td);
1104
1105 /*
1106 * handle special fdopen() case. bleh. dupfdopen() is
1107 * responsible for dropping the old contents of ofiles[indx]
1108 * if it succeeds.
1109 */
1110 if ((error == ENODEV || error == ENXIO) &&
1111 td->td_dupfd >= 0 && /* XXX from fdopen */
1112 (error =
1113 dupfdopen(td, fdp, indx, td->td_dupfd, flags, error)) == 0) {
1114 td->td_retval[0] = indx;
1115 return (0);
1116 }
1117 /*
1118 * Clean up the descriptor, but only if another thread hadn't
1119 * replaced or closed it.
1120 */
1121 if (fdp->fd_ofiles[indx] == fp) {
1122 fdp->fd_ofiles[indx] = NULL;
1123 fdrop(fp, td);
1124 }
1125
1126 if (error == ERESTART)
1127 error = EINTR;
1128 return (error);
1129 }
1130 td->td_dupfd = 0;
1131 NDFREE(&nd, NDF_ONLY_PNBUF);
1132 vp = nd.ni_vp;
1133
1134 /*
1135 * There should be 2 references on the file, one from the descriptor
1136 * table, and one for us.
1137 *
1138 * Handle the case where someone closed the file (via its file
1139 * descriptor) while we were blocked. The end result should look
1140 * like opening the file succeeded but it was immediately closed.
1141 */
1142 if (fp->f_count == 1) {
1143 KASSERT(fdp->fd_ofiles[indx] != fp,
1144 ("Open file descriptor lost all refs"));
1145 VOP_UNLOCK(vp, 0, td);
1146 vn_close(vp, flags & FMASK, fp->f_cred, td);
1147 fdrop(fp, td);
1148 td->td_retval[0] = indx;
1149 return 0;
1150 }
1151
1152 fp->f_data = (caddr_t)vp;
1153 fp->f_flag = flags & FMASK;
1154 fp->f_ops = &vnops;
1155 fp->f_type = (vp->v_type == VFIFO ? DTYPE_FIFO : DTYPE_VNODE);
1156 VOP_UNLOCK(vp, 0, td);
1157 if (flags & (O_EXLOCK | O_SHLOCK)) {
1158 lf.l_whence = SEEK_SET;
1159 lf.l_start = 0;
1160 lf.l_len = 0;
1161 if (flags & O_EXLOCK)
1162 lf.l_type = F_WRLCK;
1163 else
1164 lf.l_type = F_RDLCK;
1165 type = F_FLOCK;
1166 if ((flags & FNONBLOCK) == 0)
1167 type |= F_WAIT;
1168 if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) != 0)
1169 goto bad;
1170 fp->f_flag |= FHASLOCK;
1171 }
1172 if (flags & O_TRUNC) {
1173 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
1174 goto bad;
1175 VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
1176 VATTR_NULL(&vat);
1177 vat.va_size = 0;
1178 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
1179 error = VOP_SETATTR(vp, &vat, p->p_ucred, td);
1180 VOP_UNLOCK(vp, 0, td);
1181 vn_finished_write(mp);
1182 if (error)
1183 goto bad;
1184 }
1185 /* assert that vn_open created a backing object if one is needed */
1186 KASSERT(!vn_canvmio(vp) || VOP_GETVOBJECT(vp, NULL) == 0,
1187 ("open: vmio vnode has no backing object after vn_open"));
1188 /*
1189 * Release our private reference, leaving the one associated with
1190 * the descriptor table intact.
1191 */
1192 fdrop(fp, td);
1193 td->td_retval[0] = indx;
1194 return (0);
1195bad:
1196 if (fdp->fd_ofiles[indx] == fp) {
1197 fdp->fd_ofiles[indx] = NULL;
1198 fdrop(fp, td);
1199 }
1200 fdrop(fp, td);
1201 return (error);
1202}
1203
1204#ifdef COMPAT_43
1205/*
1206 * Create a file.
1207 */
1208#ifndef _SYS_SYSPROTO_H_
1209struct ocreat_args {
1210 char *path;
1211 int mode;
1212};
1213#endif
1214int
1215ocreat(td, uap)
1216 struct thread *td;
1217 register struct ocreat_args /* {
1218 syscallarg(char *) path;
1219 syscallarg(int) mode;
1220 } */ *uap;
1221{
1222 struct open_args /* {
1223 syscallarg(char *) path;
1224 syscallarg(int) flags;
1225 syscallarg(int) mode;
1226 } */ nuap;
1227
1228 SCARG(&nuap, path) = SCARG(uap, path);
1229 SCARG(&nuap, mode) = SCARG(uap, mode);
1230 SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
1231 return (open(td, &nuap));
1232}
1233#endif /* COMPAT_43 */
1234
1235/*
1236 * Create a special file.
1237 */
1238#ifndef _SYS_SYSPROTO_H_
1239struct mknod_args {
1240 char *path;
1241 int mode;
1242 int dev;
1243};
1244#endif
1245/* ARGSUSED */
1246int
1247mknod(td, uap)
1248 struct thread *td;
1249 register struct mknod_args /* {
1250 syscallarg(char *) path;
1251 syscallarg(int) mode;
1252 syscallarg(int) dev;
1253 } */ *uap;
1254{
1255 struct vnode *vp;
1256 struct mount *mp;
1257 struct vattr vattr;
1258 int error;
1259 int whiteout = 0;
1260 struct nameidata nd;
1261
1262 switch (SCARG(uap, mode) & S_IFMT) {
1263 case S_IFCHR:
1264 case S_IFBLK:
1265 error = suser_td(td);
1266 break;
1267 default:
1268 error = suser_xxx(0, td->td_proc, PRISON_ROOT);
1269 break;
1270 }
1271 if (error)
1272 return (error);
1273restart:
1274 bwillwrite();
1275 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), td);
1276 if ((error = namei(&nd)) != 0)
1277 return (error);
1278 vp = nd.ni_vp;
1279 if (vp != NULL) {
1280 vrele(vp);
1281 error = EEXIST;
1282 } else {
1283 VATTR_NULL(&vattr);
1284 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ td->td_proc->p_fd->fd_cmask;
1285 vattr.va_rdev = SCARG(uap, dev);
1286 whiteout = 0;
1287
1288 switch (SCARG(uap, mode) & S_IFMT) {
1289 case S_IFMT: /* used by badsect to flag bad sectors */
1290 vattr.va_type = VBAD;
1291 break;
1292 case S_IFCHR:
1293 vattr.va_type = VCHR;
1294 break;
1295 case S_IFBLK:
1296 vattr.va_type = VBLK;
1297 break;
1298 case S_IFWHT:
1299 whiteout = 1;
1300 break;
1301 default:
1302 error = EINVAL;
1303 break;
1304 }
1305 }
1306 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1307 NDFREE(&nd, NDF_ONLY_PNBUF);
1308 vput(nd.ni_dvp);
1309 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
1310 return (error);
1311 goto restart;
1312 }
1313 if (!error) {
1314 VOP_LEASE(nd.ni_dvp, td, td->td_proc->p_ucred, LEASE_WRITE);
1315 if (whiteout)
1316 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
1317 else {
1318 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
1319 &nd.ni_cnd, &vattr);
1320 if (error == 0)
1321 vput(nd.ni_vp);
1322 }
1323 }
1324 NDFREE(&nd, NDF_ONLY_PNBUF);
1325 vput(nd.ni_dvp);
1326 vn_finished_write(mp);
1327 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mknod");
1328 ASSERT_VOP_UNLOCKED(nd.ni_vp, "mknod");
1329 return (error);
1330}
1331
1332/*
1333 * Create a named pipe.
1334 */
1335#ifndef _SYS_SYSPROTO_H_
1336struct mkfifo_args {
1337 char *path;
1338 int mode;
1339};
1340#endif
1341/* ARGSUSED */
1342int
1343mkfifo(td, uap)
1344 struct thread *td;
1345 register struct mkfifo_args /* {
1346 syscallarg(char *) path;
1347 syscallarg(int) mode;
1348 } */ *uap;
1349{
1350 struct mount *mp;
1351 struct vattr vattr;
1352 int error;
1353 struct nameidata nd;
1354
1355restart:
1356 bwillwrite();
1357 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), td);
1358 if ((error = namei(&nd)) != 0)
1359 return (error);
1360 if (nd.ni_vp != NULL) {
1361 NDFREE(&nd, NDF_ONLY_PNBUF);
1362 vrele(nd.ni_vp);
1363 vput(nd.ni_dvp);
1364 return (EEXIST);
1365 }
1366 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1367 NDFREE(&nd, NDF_ONLY_PNBUF);
1368 vput(nd.ni_dvp);
1369 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
1370 return (error);
1371 goto restart;
1372 }
1373 VATTR_NULL(&vattr);
1374 vattr.va_type = VFIFO;
1375 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ td->td_proc->p_fd->fd_cmask;
1376 VOP_LEASE(nd.ni_dvp, td, td->td_proc->p_ucred, LEASE_WRITE);
1377 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
1378 if (error == 0)
1379 vput(nd.ni_vp);
1380 NDFREE(&nd, NDF_ONLY_PNBUF);
1381 vput(nd.ni_dvp);
1382 vn_finished_write(mp);
1383 return (error);
1384}
1385
1386/*
1387 * Make a hard file link.
1388 */
1389#ifndef _SYS_SYSPROTO_H_
1390struct link_args {
1391 char *path;
1392 char *link;
1393};
1394#endif
1395/* ARGSUSED */
1396int
1397link(td, uap)
1398 struct thread *td;
1399 register struct link_args /* {
1400 syscallarg(char *) path;
1401 syscallarg(char *) link;
1402 } */ *uap;
1403{
1404 struct vnode *vp;
1405 struct mount *mp;
1406 struct nameidata nd;
1407 int error;
1408
1409 bwillwrite();
1410 NDINIT(&nd, LOOKUP, FOLLOW|NOOBJ, UIO_USERSPACE, SCARG(uap, path), td);
1411 if ((error = namei(&nd)) != 0)
1412 return (error);
1413 NDFREE(&nd, NDF_ONLY_PNBUF);
1414 vp = nd.ni_vp;
1415 if (vp->v_type == VDIR) {
1416 vrele(vp);
1417 return (EPERM); /* POSIX */
1418 }
1419 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
1420 vrele(vp);
1421 return (error);
1422 }
1423 NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), td);
1424 if ((error = namei(&nd)) == 0) {
1425 if (nd.ni_vp != NULL) {
1426 vrele(nd.ni_vp);
1427 error = EEXIST;
1428 } else {
1429 VOP_LEASE(nd.ni_dvp, td, td->td_proc->p_ucred, LEASE_WRITE);
1430 VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE);
1431 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
1432 }
1433 NDFREE(&nd, NDF_ONLY_PNBUF);
1434 vput(nd.ni_dvp);
1435 }
1436 vrele(vp);
1437 vn_finished_write(mp);
1438 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "link");
1439 ASSERT_VOP_UNLOCKED(nd.ni_vp, "link");
1440 return (error);
1441}
1442
1443/*
1444 * Make a symbolic link.
1445 */
1446#ifndef _SYS_SYSPROTO_H_
1447struct symlink_args {
1448 char *path;
1449 char *link;
1450};
1451#endif
1452/* ARGSUSED */
1453int
1454symlink(td, uap)
1455 struct thread *td;
1456 register struct symlink_args /* {
1457 syscallarg(char *) path;
1458 syscallarg(char *) link;
1459 } */ *uap;
1460{
1461 struct mount *mp;
1462 struct vattr vattr;
1463 char *path;
1464 int error;
1465 struct nameidata nd;
1466
1467 path = zalloc(namei_zone);
1468 if ((error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL)) != 0)
1469 goto out;
1470restart:
1471 bwillwrite();
1472 NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), td);
1473 if ((error = namei(&nd)) != 0)
1474 goto out;
1475 if (nd.ni_vp) {
1476 NDFREE(&nd, NDF_ONLY_PNBUF);
1477 vrele(nd.ni_vp);
1478 vput(nd.ni_dvp);
1479 error = EEXIST;
1480 goto out;
1481 }
1482 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1483 NDFREE(&nd, NDF_ONLY_PNBUF);
1484 vput(nd.ni_dvp);
1485 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
1486 return (error);
1487 goto restart;
1488 }
1489 VATTR_NULL(&vattr);
1490 vattr.va_mode = ACCESSPERMS &~ td->td_proc->p_fd->fd_cmask;
1491 VOP_LEASE(nd.ni_dvp, td, td->td_proc->p_ucred, LEASE_WRITE);
1492 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1493 NDFREE(&nd, NDF_ONLY_PNBUF);
1494 if (error == 0)
1495 vput(nd.ni_vp);
1496 vput(nd.ni_dvp);
1497 vn_finished_write(mp);
1498 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "symlink");
1499 ASSERT_VOP_UNLOCKED(nd.ni_vp, "symlink");
1500out:
1501 zfree(namei_zone, path);
1502 return (error);
1503}
1504
1505/*
1506 * Delete a whiteout from the filesystem.
1507 */
1508/* ARGSUSED */
1509int
1510undelete(td, uap)
1511 struct thread *td;
1512 register struct undelete_args /* {
1513 syscallarg(char *) path;
1514 } */ *uap;
1515{
1516 int error;
1517 struct mount *mp;
1518 struct nameidata nd;
1519
1520restart:
1521 bwillwrite();
1522 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
1523 SCARG(uap, path), td);
1524 error = namei(&nd);
1525 if (error)
1526 return (error);
1527
1528 if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
1529 NDFREE(&nd, NDF_ONLY_PNBUF);
1530 if (nd.ni_vp)
1531 vrele(nd.ni_vp);
1532 vput(nd.ni_dvp);
1533 return (EEXIST);
1534 }
1535 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1536 NDFREE(&nd, NDF_ONLY_PNBUF);
1537 vput(nd.ni_dvp);
1538 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
1539 return (error);
1540 goto restart;
1541 }
1542 VOP_LEASE(nd.ni_dvp, td, td->td_proc->p_ucred, LEASE_WRITE);
1543 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE);
1544 NDFREE(&nd, NDF_ONLY_PNBUF);
1545 vput(nd.ni_dvp);
1546 vn_finished_write(mp);
1547 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "undelete");
1548 ASSERT_VOP_UNLOCKED(nd.ni_vp, "undelete");
1549 return (error);
1550}
1551
1552/*
1553 * Delete a name from the filesystem.
1554 */
1555#ifndef _SYS_SYSPROTO_H_
1556struct unlink_args {
1557 char *path;
1558};
1559#endif
1560/* ARGSUSED */
1561int
1562unlink(td, uap)
1563 struct thread *td;
1564 struct unlink_args /* {
1565 syscallarg(char *) path;
1566 } */ *uap;
1567{
1568 struct mount *mp;
1569 struct vnode *vp;
1570 int error;
1571 struct nameidata nd;
1572
1573restart:
1574 bwillwrite();
1575 NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), td);
1576 if ((error = namei(&nd)) != 0)
1577 return (error);
1578 vp = nd.ni_vp;
1579 if (vp->v_type == VDIR)
1580 error = EPERM; /* POSIX */
1581 else {
1582 /*
1583 * The root of a mounted filesystem cannot be deleted.
1584 *
1585 * XXX: can this only be a VDIR case?
1586 */
1587 if (vp->v_flag & VROOT)
1588 error = EBUSY;
1589 }
1590 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1591 NDFREE(&nd, NDF_ONLY_PNBUF);
1592 vrele(vp);
1593 vput(nd.ni_dvp);
1594 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
1595 return (error);
1596 goto restart;
1597 }
1598 VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE);
1599 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
1600 if (!error) {
1601 VOP_LEASE(nd.ni_dvp, td, td->td_proc->p_ucred, LEASE_WRITE);
1602 error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd);
1603 }
1604 NDFREE(&nd, NDF_ONLY_PNBUF);
1605 vput(nd.ni_dvp);
1606 vput(vp);
1607 vn_finished_write(mp);
1608 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "unlink");
1609 ASSERT_VOP_UNLOCKED(nd.ni_vp, "unlink");
1610 return (error);
1611}
1612
1613/*
1614 * Reposition read/write file offset.
1615 */
1616#ifndef _SYS_SYSPROTO_H_
1617struct lseek_args {
1618 int fd;
1619 int pad;
1620 off_t offset;
1621 int whence;
1622};
1623#endif
1624int
1625lseek(td, uap)
1626 struct thread *td;
1627 register struct lseek_args /* {
1628 syscallarg(int) fd;
1629 syscallarg(int) pad;
1630 syscallarg(off_t) offset;
1631 syscallarg(int) whence;
1632 } */ *uap;
1633{
1634 struct ucred *cred = td->td_proc->p_ucred;
1635 register struct filedesc *fdp = td->td_proc->p_fd;
1636 register struct file *fp;
1637 struct vattr vattr;
1638 struct vnode *vp;
1639 off_t offset;
1640 int error, noneg;
1641
1642 if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
1643 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
1644 return (EBADF);
1645 if (fp->f_type != DTYPE_VNODE)
1646 return (ESPIPE);
1647 vp = (struct vnode *)fp->f_data;
1648 noneg = (vp->v_type != VCHR);
1649 offset = SCARG(uap, offset);
1650 switch (SCARG(uap, whence)) {
1651 case L_INCR:
1652 if (noneg &&
1653 (fp->f_offset < 0 ||
1654 (offset > 0 && fp->f_offset > OFF_MAX - offset)))
1655 return (EOVERFLOW);
1656 offset += fp->f_offset;
1657 break;
1658 case L_XTND:
1659 error = VOP_GETATTR(vp, &vattr, cred, td);
1660 if (error)
1661 return (error);
1662 if (noneg &&
1663 (vattr.va_size > OFF_MAX ||
1664 (offset > 0 && vattr.va_size > OFF_MAX - offset)))
1665 return (EOVERFLOW);
1666 offset += vattr.va_size;
1667 break;
1668 case L_SET:
1669 break;
1670 default:
1671 return (EINVAL);
1672 }
1673 if (noneg && offset < 0)
1674 return (EINVAL);
1675 fp->f_offset = offset;
1676 *(off_t *)(td->td_retval) = fp->f_offset;
1677 return (0);
1678}
1679
1680#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1681/*
1682 * Reposition read/write file offset.
1683 */
1684#ifndef _SYS_SYSPROTO_H_
1685struct olseek_args {
1686 int fd;
1687 long offset;
1688 int whence;
1689};
1690#endif
1691int
1692olseek(td, uap)
1693 struct thread *td;
1694 register struct olseek_args /* {
1695 syscallarg(int) fd;
1696 syscallarg(long) offset;
1697 syscallarg(int) whence;
1698 } */ *uap;
1699{
1700 struct lseek_args /* {
1701 syscallarg(int) fd;
1702 syscallarg(int) pad;
1703 syscallarg(off_t) offset;
1704 syscallarg(int) whence;
1705 } */ nuap;
1706 int error;
1707
1708 SCARG(&nuap, fd) = SCARG(uap, fd);
1709 SCARG(&nuap, offset) = SCARG(uap, offset);
1710 SCARG(&nuap, whence) = SCARG(uap, whence);
1711 error = lseek(td, &nuap);
1712 return (error);
1713}
1714#endif /* COMPAT_43 */
1715
1716/*
1717 * Check access permissions using passed credentials.
1718 */
1719static int
1720vn_access(vp, user_flags, cred, td)
1721 struct vnode *vp;
1722 int user_flags;
1723 struct ucred *cred;
1724 struct thread *td;
1725{
1726 int error, flags;
1727
1728 /* Flags == 0 means only check for existence. */
1729 error = 0;
1730 if (user_flags) {
1731 flags = 0;
1732 if (user_flags & R_OK)
1733 flags |= VREAD;
1734 if (user_flags & W_OK)
1735 flags |= VWRITE;
1736 if (user_flags & X_OK)
1737 flags |= VEXEC;
1738 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
1739 error = VOP_ACCESS(vp, flags, cred, td);
1740 }
1741 return (error);
1742}
1743
1744/*
1745 * Check access permissions using "real" credentials.
1746 */
1747#ifndef _SYS_SYSPROTO_H_
1748struct access_args {
1749 char *path;
1750 int flags;
1751};
1752#endif
1753int
1754access(td, uap)
1755 struct thread *td;
1756 register struct access_args /* {
1757 syscallarg(char *) path;
1758 syscallarg(int) flags;
1759 } */ *uap;
1760{
1761 struct ucred *cred, *tmpcred;
1762 register struct vnode *vp;
1763 int error;
1764 struct nameidata nd;
1765
1766 cred = td->td_proc->p_ucred;
1767 /*
1768 * Create and modify a temporary credential instead of one that
1769 * is potentially shared. This could also mess up socket
1770 * buffer accounting which can run in an interrupt context.
1771 *
1772 * XXX - Depending on how "threads" are finally implemented, it
1773 * may be better to explicitly pass the credential to namei()
1774 * rather than to modify the potentially shared process structure.
1775 */
1776 tmpcred = crdup(cred);
1777 tmpcred->cr_uid = cred->cr_ruid;
1778 tmpcred->cr_groups[0] = cred->cr_rgid;
1779 td->td_proc->p_ucred = tmpcred;
1780 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1781 SCARG(uap, path), td);
1782 if ((error = namei(&nd)) != 0)
1783 goto out1;
1784 vp = nd.ni_vp;
1785
1786 error = vn_access(vp, SCARG(uap, flags), tmpcred, td);
1787 NDFREE(&nd, NDF_ONLY_PNBUF);
1788 vput(vp);
1789out1:
1790 td->td_proc->p_ucred = cred;
1791 crfree(tmpcred);
1792 return (error);
1793}
1794
1795/*
1796 * Check access permissions using "effective" credentials.
1797 */
1798#ifndef _SYS_SYSPROTO_H_
1799struct eaccess_args {
1800 char *path;
1801 int flags;
1802};
1803#endif
1804int
1805eaccess(td, uap)
1806 struct thread *td;
1807 register struct eaccess_args /* {
1808 syscallarg(char *) path;
1809 syscallarg(int) flags;
1810 } */ *uap;
1811{
1812 struct nameidata nd;
1813 struct vnode *vp;
1814 int error;
1815
1816 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1817 SCARG(uap, path), td);
1818 if ((error = namei(&nd)) != 0)
1819 return (error);
1820 vp = nd.ni_vp;
1821
1822 error = vn_access(vp, SCARG(uap, flags), td->td_proc->p_ucred, td);
1823 NDFREE(&nd, NDF_ONLY_PNBUF);
1824 vput(vp);
1825 return (error);
1826}
1827
1828#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1829/*
1830 * Get file status; this version follows links.
1831 */
1832#ifndef _SYS_SYSPROTO_H_
1833struct ostat_args {
1834 char *path;
1835 struct ostat *ub;
1836};
1837#endif
1838/* ARGSUSED */
1839int
1840ostat(td, uap)
1841 struct thread *td;
1842 register struct ostat_args /* {
1843 syscallarg(char *) path;
1844 syscallarg(struct ostat *) ub;
1845 } */ *uap;
1846{
1847 struct stat sb;
1848 struct ostat osb;
1849 int error;
1850 struct nameidata nd;
1851
1852 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1853 SCARG(uap, path), td);
1854 if ((error = namei(&nd)) != 0)
1855 return (error);
1856 NDFREE(&nd, NDF_ONLY_PNBUF);
1857 error = vn_stat(nd.ni_vp, &sb, td);
1858 vput(nd.ni_vp);
1859 if (error)
1860 return (error);
1861 cvtstat(&sb, &osb);
1862 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
1863 return (error);
1864}
1865
1866/*
1867 * Get file status; this version does not follow links.
1868 */
1869#ifndef _SYS_SYSPROTO_H_
1870struct olstat_args {
1871 char *path;
1872 struct ostat *ub;
1873};
1874#endif
1875/* ARGSUSED */
1876int
1877olstat(td, uap)
1878 struct thread *td;
1879 register struct olstat_args /* {
1880 syscallarg(char *) path;
1881 syscallarg(struct ostat *) ub;
1882 } */ *uap;
1883{
1884 struct vnode *vp;
1885 struct stat sb;
1886 struct ostat osb;
1887 int error;
1888 struct nameidata nd;
1889
1890 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1891 SCARG(uap, path), td);
1892 if ((error = namei(&nd)) != 0)
1893 return (error);
1894 vp = nd.ni_vp;
1895 error = vn_stat(vp, &sb, td);
1896 NDFREE(&nd, NDF_ONLY_PNBUF);
1897 vput(vp);
1898 if (error)
1899 return (error);
1900 cvtstat(&sb, &osb);
1901 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
1902 return (error);
1903}
1904
1905/*
1906 * Convert from an old to a new stat structure.
1907 */
1908void
1909cvtstat(st, ost)
1910 struct stat *st;
1911 struct ostat *ost;
1912{
1913
1914 ost->st_dev = st->st_dev;
1915 ost->st_ino = st->st_ino;
1916 ost->st_mode = st->st_mode;
1917 ost->st_nlink = st->st_nlink;
1918 ost->st_uid = st->st_uid;
1919 ost->st_gid = st->st_gid;
1920 ost->st_rdev = st->st_rdev;
1921 if (st->st_size < (quad_t)1 << 32)
1922 ost->st_size = st->st_size;
1923 else
1924 ost->st_size = -2;
1925 ost->st_atime = st->st_atime;
1926 ost->st_mtime = st->st_mtime;
1927 ost->st_ctime = st->st_ctime;
1928 ost->st_blksize = st->st_blksize;
1929 ost->st_blocks = st->st_blocks;
1930 ost->st_flags = st->st_flags;
1931 ost->st_gen = st->st_gen;
1932}
1933#endif /* COMPAT_43 || COMPAT_SUNOS */
1934
1935/*
1936 * Get file status; this version follows links.
1937 */
1938#ifndef _SYS_SYSPROTO_H_
1939struct stat_args {
1940 char *path;
1941 struct stat *ub;
1942};
1943#endif
1944/* ARGSUSED */
1945int
1946stat(td, uap)
1947 struct thread *td;
1948 register struct stat_args /* {
1949 syscallarg(char *) path;
1950 syscallarg(struct stat *) ub;
1951 } */ *uap;
1952{
1953 struct stat sb;
1954 int error;
1955 struct nameidata nd;
1956
1957 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1958 SCARG(uap, path), td);
1959 if ((error = namei(&nd)) != 0)
1960 return (error);
1961 error = vn_stat(nd.ni_vp, &sb, td);
1962 NDFREE(&nd, NDF_ONLY_PNBUF);
1963 vput(nd.ni_vp);
1964 if (error)
1965 return (error);
1966 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
1967 return (error);
1968}
1969
1970/*
1971 * Get file status; this version does not follow links.
1972 */
1973#ifndef _SYS_SYSPROTO_H_
1974struct lstat_args {
1975 char *path;
1976 struct stat *ub;
1977};
1978#endif
1979/* ARGSUSED */
1980int
1981lstat(td, uap)
1982 struct thread *td;
1983 register struct lstat_args /* {
1984 syscallarg(char *) path;
1985 syscallarg(struct stat *) ub;
1986 } */ *uap;
1987{
1988 int error;
1989 struct vnode *vp;
1990 struct stat sb;
1991 struct nameidata nd;
1992
1993 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1994 SCARG(uap, path), td);
1995 if ((error = namei(&nd)) != 0)
1996 return (error);
1997 vp = nd.ni_vp;
1998 error = vn_stat(vp, &sb, td);
1999 NDFREE(&nd, NDF_ONLY_PNBUF);
2000 vput(vp);
2001 if (error)
2002 return (error);
2003 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
2004 return (error);
2005}
2006
2007/*
2008 * Implementation of the NetBSD stat() function.
2009 * XXX This should probably be collapsed with the FreeBSD version,
2010 * as the differences are only due to vn_stat() clearing spares at
2011 * the end of the structures. vn_stat could be split to avoid this,
2012 * and thus collapse the following to close to zero code.
2013 */
2014void
2015cvtnstat(sb, nsb)
2016 struct stat *sb;
2017 struct nstat *nsb;
2018{
2019 nsb->st_dev = sb->st_dev;
2020 nsb->st_ino = sb->st_ino;
2021 nsb->st_mode = sb->st_mode;
2022 nsb->st_nlink = sb->st_nlink;
2023 nsb->st_uid = sb->st_uid;
2024 nsb->st_gid = sb->st_gid;
2025 nsb->st_rdev = sb->st_rdev;
2026 nsb->st_atimespec = sb->st_atimespec;
2027 nsb->st_mtimespec = sb->st_mtimespec;
2028 nsb->st_ctimespec = sb->st_ctimespec;
2029 nsb->st_size = sb->st_size;
2030 nsb->st_blocks = sb->st_blocks;
2031 nsb->st_blksize = sb->st_blksize;
2032 nsb->st_flags = sb->st_flags;
2033 nsb->st_gen = sb->st_gen;
2034 nsb->st_qspare[0] = sb->st_qspare[0];
2035 nsb->st_qspare[1] = sb->st_qspare[1];
2036}
2037
2038#ifndef _SYS_SYSPROTO_H_
2039struct nstat_args {
2040 char *path;
2041 struct nstat *ub;
2042};
2043#endif
2044/* ARGSUSED */
2045int
2046nstat(td, uap)
2047 struct thread *td;
2048 register struct nstat_args /* {
2049 syscallarg(char *) path;
2050 syscallarg(struct nstat *) ub;
2051 } */ *uap;
2052{
2053 struct stat sb;
2054 struct nstat nsb;
2055 int error;
2056 struct nameidata nd;
2057
2058 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
2059 SCARG(uap, path), td);
2060 if ((error = namei(&nd)) != 0)
2061 return (error);
2062 NDFREE(&nd, NDF_ONLY_PNBUF);
2063 error = vn_stat(nd.ni_vp, &sb, td);
2064 vput(nd.ni_vp);
2065 if (error)
2066 return (error);
2067 cvtnstat(&sb, &nsb);
2068 error = copyout((caddr_t)&nsb, (caddr_t)SCARG(uap, ub), sizeof (nsb));
2069 return (error);
2070}
2071
2072/*
2073 * NetBSD lstat. Get file status; this version does not follow links.
2074 */
2075#ifndef _SYS_SYSPROTO_H_
2076struct lstat_args {
2077 char *path;
2078 struct stat *ub;
2079};
2080#endif
2081/* ARGSUSED */
2082int
2083nlstat(td, uap)
2084 struct thread *td;
2085 register struct nlstat_args /* {
2086 syscallarg(char *) path;
2087 syscallarg(struct nstat *) ub;
2088 } */ *uap;
2089{
2090 int error;
2091 struct vnode *vp;
2092 struct stat sb;
2093 struct nstat nsb;
2094 struct nameidata nd;
2095
2096 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
2097 SCARG(uap, path), td);
2098 if ((error = namei(&nd)) != 0)
2099 return (error);
2100 vp = nd.ni_vp;
2101 NDFREE(&nd, NDF_ONLY_PNBUF);
2102 error = vn_stat(vp, &sb, td);
2103 vput(vp);
2104 if (error)
2105 return (error);
2106 cvtnstat(&sb, &nsb);
2107 error = copyout((caddr_t)&nsb, (caddr_t)SCARG(uap, ub), sizeof (nsb));
2108 return (error);
2109}
2110
2111/*
2112 * Get configurable pathname variables.
2113 */
2114#ifndef _SYS_SYSPROTO_H_
2115struct pathconf_args {
2116 char *path;
2117 int name;
2118};
2119#endif
2120/* ARGSUSED */
2121int
2122pathconf(td, uap)
2123 struct thread *td;
2124 register struct pathconf_args /* {
2125 syscallarg(char *) path;
2126 syscallarg(int) name;
2127 } */ *uap;
2128{
2129 int error;
2130 struct nameidata nd;
2131
2132 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
2133 SCARG(uap, path), td);
2134 if ((error = namei(&nd)) != 0)
2135 return (error);
2136 NDFREE(&nd, NDF_ONLY_PNBUF);
2137 error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), td->td_retval);
2138 vput(nd.ni_vp);
2139 return (error);
2140}
2141
2142/*
2143 * Return target name of a symbolic link.
2144 */
2145#ifndef _SYS_SYSPROTO_H_
2146struct readlink_args {
2147 char *path;
2148 char *buf;
2149 int count;
2150};
2151#endif
2152/* ARGSUSED */
2153int
2154readlink(td, uap)
2155 struct thread *td;
2156 register struct readlink_args /* {
2157 syscallarg(char *) path;
2158 syscallarg(char *) buf;
2159 syscallarg(int) count;
2160 } */ *uap;
2161{
2162 register struct vnode *vp;
2163 struct iovec aiov;
2164 struct uio auio;
2165 int error;
2166 struct nameidata nd;
2167
2168 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
2169 SCARG(uap, path), td);
2170 if ((error = namei(&nd)) != 0)
2171 return (error);
2172 NDFREE(&nd, NDF_ONLY_PNBUF);
2173 vp = nd.ni_vp;
2174 if (vp->v_type != VLNK)
2175 error = EINVAL;
2176 else {
2177 aiov.iov_base = SCARG(uap, buf);
2178 aiov.iov_len = SCARG(uap, count);
2179 auio.uio_iov = &aiov;
2180 auio.uio_iovcnt = 1;
2181 auio.uio_offset = 0;
2182 auio.uio_rw = UIO_READ;
2183 auio.uio_segflg = UIO_USERSPACE;
2184 auio.uio_td = td;
2185 auio.uio_resid = SCARG(uap, count);
2186 error = VOP_READLINK(vp, &auio, td->td_proc->p_ucred);
2187 }
2188 vput(vp);
2189 td->td_retval[0] = SCARG(uap, count) - auio.uio_resid;
2190 return (error);
2191}
2192
2193/*
2194 * Common implementation code for chflags() and fchflags().
2195 */
2196static int
2197setfflags(td, vp, flags)
2198 struct thread *td;
2199 struct vnode *vp;
2200 int flags;
2201{
2202 int error;
2203 struct mount *mp;
2204 struct vattr vattr;
2205
2206 /*
2207 * Prevent non-root users from setting flags on devices. When
2208 * a device is reused, users can retain ownership of the device
2209 * if they are allowed to set flags and programs assume that
2210 * chown can't fail when done as root.
2211 */
2212 if (vp->v_type == VCHR || vp->v_type == VBLK) {
2213 error = suser_xxx(td->td_proc->p_ucred, td->td_proc,
2214 PRISON_ROOT);
2215 if (error)
2216 return (error);
2217 }
2218
2219 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
2220 return (error);
2221 VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE);
2222 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2223 VATTR_NULL(&vattr);
2224 vattr.va_flags = flags;
2225 error = VOP_SETATTR(vp, &vattr, td->td_proc->p_ucred, td);
2226 VOP_UNLOCK(vp, 0, td);
2227 vn_finished_write(mp);
2228 return (error);
2229}
2230
2231/*
2232 * Change flags of a file given a path name.
2233 */
2234#ifndef _SYS_SYSPROTO_H_
2235struct chflags_args {
2236 char *path;
2237 int flags;
2238};
2239#endif
2240/* ARGSUSED */
2241int
2242chflags(td, uap)
2243 struct thread *td;
2244 register struct chflags_args /* {
2245 syscallarg(char *) path;
2246 syscallarg(int) flags;
2247 } */ *uap;
2248{
2249 int error;
2250 struct nameidata nd;
2251
2252 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2253 if ((error = namei(&nd)) != 0)
2254 return (error);
2255 NDFREE(&nd, NDF_ONLY_PNBUF);
2256 error = setfflags(td, nd.ni_vp, SCARG(uap, flags));
2257 vrele(nd.ni_vp);
2258 return error;
2259}
2260
2261/*
2262 * Change flags of a file given a file descriptor.
2263 */
2264#ifndef _SYS_SYSPROTO_H_
2265struct fchflags_args {
2266 int fd;
2267 int flags;
2268};
2269#endif
2270/* ARGSUSED */
2271int
2272fchflags(td, uap)
2273 struct thread *td;
2274 register struct fchflags_args /* {
2275 syscallarg(int) fd;
2276 syscallarg(int) flags;
2277 } */ *uap;
2278{
2279 struct file *fp;
2280 int error;
2281
2282 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2283 return (error);
2284 return setfflags(td, (struct vnode *) fp->f_data, SCARG(uap, flags));
2285}
2286
2287/*
2288 * Common implementation code for chmod(), lchmod() and fchmod().
2289 */
2290static int
2291setfmode(td, vp, mode)
2292 struct thread *td;
2293 struct vnode *vp;
2294 int mode;
2295{
2296 int error;
2297 struct mount *mp;
2298 struct vattr vattr;
2299
2300 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
2301 return (error);
2302 VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE);
2303 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2304 VATTR_NULL(&vattr);
2305 vattr.va_mode = mode & ALLPERMS;
2306 error = VOP_SETATTR(vp, &vattr, td->td_proc->p_ucred, td);
2307 VOP_UNLOCK(vp, 0, td);
2308 vn_finished_write(mp);
2309 return error;
2310}
2311
2312/*
2313 * Change mode of a file given path name.
2314 */
2315#ifndef _SYS_SYSPROTO_H_
2316struct chmod_args {
2317 char *path;
2318 int mode;
2319};
2320#endif
2321/* ARGSUSED */
2322int
2323chmod(td, uap)
2324 struct thread *td;
2325 register struct chmod_args /* {
2326 syscallarg(char *) path;
2327 syscallarg(int) mode;
2328 } */ *uap;
2329{
2330 int error;
2331 struct nameidata nd;
2332
2333 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2334 if ((error = namei(&nd)) != 0)
2335 return (error);
2336 NDFREE(&nd, NDF_ONLY_PNBUF);
2337 error = setfmode(td, nd.ni_vp, SCARG(uap, mode));
2338 vrele(nd.ni_vp);
2339 return error;
2340}
2341
2342/*
2343 * Change mode of a file given path name (don't follow links.)
2344 */
2345#ifndef _SYS_SYSPROTO_H_
2346struct lchmod_args {
2347 char *path;
2348 int mode;
2349};
2350#endif
2351/* ARGSUSED */
2352int
2353lchmod(td, uap)
2354 struct thread *td;
2355 register struct lchmod_args /* {
2356 syscallarg(char *) path;
2357 syscallarg(int) mode;
2358 } */ *uap;
2359{
2360 int error;
2361 struct nameidata nd;
2362
2363 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2364 if ((error = namei(&nd)) != 0)
2365 return (error);
2366 NDFREE(&nd, NDF_ONLY_PNBUF);
2367 error = setfmode(td, nd.ni_vp, SCARG(uap, mode));
2368 vrele(nd.ni_vp);
2369 return error;
2370}
2371
2372/*
2373 * Change mode of a file given a file descriptor.
2374 */
2375#ifndef _SYS_SYSPROTO_H_
2376struct fchmod_args {
2377 int fd;
2378 int mode;
2379};
2380#endif
2381/* ARGSUSED */
2382int
2383fchmod(td, uap)
2384 struct thread *td;
2385 register struct fchmod_args /* {
2386 syscallarg(int) fd;
2387 syscallarg(int) mode;
2388 } */ *uap;
2389{
2390 struct file *fp;
2391 int error;
2392
2393 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2394 return (error);
2395 return setfmode(td, (struct vnode *)fp->f_data, SCARG(uap, mode));
2396}
2397
2398/*
2399 * Common implementation for chown(), lchown(), and fchown()
2400 */
2401static int
2402setfown(td, vp, uid, gid)
2403 struct thread *td;
2404 struct vnode *vp;
2405 uid_t uid;
2406 gid_t gid;
2407{
2408 int error;
2409 struct mount *mp;
2410 struct vattr vattr;
2411
2412 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
2413 return (error);
2414 VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE);
2415 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2416 VATTR_NULL(&vattr);
2417 vattr.va_uid = uid;
2418 vattr.va_gid = gid;
2419 error = VOP_SETATTR(vp, &vattr, td->td_proc->p_ucred, td);
2420 VOP_UNLOCK(vp, 0, td);
2421 vn_finished_write(mp);
2422 return error;
2423}
2424
2425/*
2426 * Set ownership given a path name.
2427 */
2428#ifndef _SYS_SYSPROTO_H_
2429struct chown_args {
2430 char *path;
2431 int uid;
2432 int gid;
2433};
2434#endif
2435/* ARGSUSED */
2436int
2437chown(td, uap)
2438 struct thread *td;
2439 register struct chown_args /* {
2440 syscallarg(char *) path;
2441 syscallarg(int) uid;
2442 syscallarg(int) gid;
2443 } */ *uap;
2444{
2445 int error;
2446 struct nameidata nd;
2447
2448 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2449 if ((error = namei(&nd)) != 0)
2450 return (error);
2451 NDFREE(&nd, NDF_ONLY_PNBUF);
2452 error = setfown(td, nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid));
2453 vrele(nd.ni_vp);
2454 return (error);
2455}
2456
2457/*
2458 * Set ownership given a path name, do not cross symlinks.
2459 */
2460#ifndef _SYS_SYSPROTO_H_
2461struct lchown_args {
2462 char *path;
2463 int uid;
2464 int gid;
2465};
2466#endif
2467/* ARGSUSED */
2468int
2469lchown(td, uap)
2470 struct thread *td;
2471 register struct lchown_args /* {
2472 syscallarg(char *) path;
2473 syscallarg(int) uid;
2474 syscallarg(int) gid;
2475 } */ *uap;
2476{
2477 int error;
2478 struct nameidata nd;
2479
2480 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2481 if ((error = namei(&nd)) != 0)
2482 return (error);
2483 NDFREE(&nd, NDF_ONLY_PNBUF);
2484 error = setfown(td, nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid));
2485 vrele(nd.ni_vp);
2486 return (error);
2487}
2488
2489/*
2490 * Set ownership given a file descriptor.
2491 */
2492#ifndef _SYS_SYSPROTO_H_
2493struct fchown_args {
2494 int fd;
2495 int uid;
2496 int gid;
2497};
2498#endif
2499/* ARGSUSED */
2500int
2501fchown(td, uap)
2502 struct thread *td;
2503 register struct fchown_args /* {
2504 syscallarg(int) fd;
2505 syscallarg(int) uid;
2506 syscallarg(int) gid;
2507 } */ *uap;
2508{
2509 struct file *fp;
2510 int error;
2511
2512 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2513 return (error);
2514 return setfown(td, (struct vnode *)fp->f_data,
2515 SCARG(uap, uid), SCARG(uap, gid));
2516}
2517
2518/*
2519 * Common implementation code for utimes(), lutimes(), and futimes().
2520 */
2521static int
2522getutimes(usrtvp, tsp)
2523 const struct timeval *usrtvp;
2524 struct timespec *tsp;
2525{
2526 struct timeval tv[2];
2527 int error;
2528
2529 if (usrtvp == NULL) {
2530 microtime(&tv[0]);
2531 TIMEVAL_TO_TIMESPEC(&tv[0], &tsp[0]);
2532 tsp[1] = tsp[0];
2533 } else {
2534 if ((error = copyin(usrtvp, tv, sizeof (tv))) != 0)
2535 return (error);
2536 TIMEVAL_TO_TIMESPEC(&tv[0], &tsp[0]);
2537 TIMEVAL_TO_TIMESPEC(&tv[1], &tsp[1]);
2538 }
2539 return 0;
2540}
2541
2542/*
2543 * Common implementation code for utimes(), lutimes(), and futimes().
2544 */
2545static int
2546setutimes(td, vp, ts, nullflag)
2547 struct thread *td;
2548 struct vnode *vp;
2549 const struct timespec *ts;
2550 int nullflag;
2551{
2552 int error;
2553 struct mount *mp;
2554 struct vattr vattr;
2555
2556 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
2557 return (error);
2558 VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE);
2559 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2560 VATTR_NULL(&vattr);
2561 vattr.va_atime = ts[0];
2562 vattr.va_mtime = ts[1];
2563 if (nullflag)
2564 vattr.va_vaflags |= VA_UTIMES_NULL;
2565 error = VOP_SETATTR(vp, &vattr, td->td_proc->p_ucred, td);
2566 VOP_UNLOCK(vp, 0, td);
2567 vn_finished_write(mp);
2568 return error;
2569}
2570
2571/*
2572 * Set the access and modification times of a file.
2573 */
2574#ifndef _SYS_SYSPROTO_H_
2575struct utimes_args {
2576 char *path;
2577 struct timeval *tptr;
2578};
2579#endif
2580/* ARGSUSED */
2581int
2582utimes(td, uap)
2583 struct thread *td;
2584 register struct utimes_args /* {
2585 syscallarg(char *) path;
2586 syscallarg(struct timeval *) tptr;
2587 } */ *uap;
2588{
2589 struct timespec ts[2];
2590 struct timeval *usrtvp;
2591 int error;
2592 struct nameidata nd;
2593
2594 usrtvp = SCARG(uap, tptr);
2595 if ((error = getutimes(usrtvp, ts)) != 0)
2596 return (error);
2597 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2598 if ((error = namei(&nd)) != 0)
2599 return (error);
2600 NDFREE(&nd, NDF_ONLY_PNBUF);
2601 error = setutimes(td, nd.ni_vp, ts, usrtvp == NULL);
2602 vrele(nd.ni_vp);
2603 return (error);
2604}
2605
2606/*
2607 * Set the access and modification times of a file.
2608 */
2609#ifndef _SYS_SYSPROTO_H_
2610struct lutimes_args {
2611 char *path;
2612 struct timeval *tptr;
2613};
2614#endif
2615/* ARGSUSED */
2616int
2617lutimes(td, uap)
2618 struct thread *td;
2619 register struct lutimes_args /* {
2620 syscallarg(char *) path;
2621 syscallarg(struct timeval *) tptr;
2622 } */ *uap;
2623{
2624 struct timespec ts[2];
2625 struct timeval *usrtvp;
2626 int error;
2627 struct nameidata nd;
2628
2629 usrtvp = SCARG(uap, tptr);
2630 if ((error = getutimes(usrtvp, ts)) != 0)
2631 return (error);
2632 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2633 if ((error = namei(&nd)) != 0)
2634 return (error);
2635 NDFREE(&nd, NDF_ONLY_PNBUF);
2636 error = setutimes(td, nd.ni_vp, ts, usrtvp == NULL);
2637 vrele(nd.ni_vp);
2638 return (error);
2639}
2640
2641/*
2642 * Set the access and modification times of a file.
2643 */
2644#ifndef _SYS_SYSPROTO_H_
2645struct futimes_args {
2646 int fd;
2647 struct timeval *tptr;
2648};
2649#endif
2650/* ARGSUSED */
2651int
2652futimes(td, uap)
2653 struct thread *td;
2654 register struct futimes_args /* {
2655 syscallarg(int ) fd;
2656 syscallarg(struct timeval *) tptr;
2657 } */ *uap;
2658{
2659 struct timespec ts[2];
2660 struct file *fp;
2661 struct timeval *usrtvp;
2662 int error;
2663
2664 usrtvp = SCARG(uap, tptr);
2665 if ((error = getutimes(usrtvp, ts)) != 0)
2666 return (error);
2667 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2668 return (error);
2669 return setutimes(td, (struct vnode *)fp->f_data, ts, usrtvp == NULL);
2670}
2671
2672/*
2673 * Truncate a file given its path name.
2674 */
2675#ifndef _SYS_SYSPROTO_H_
2676struct truncate_args {
2677 char *path;
2678 int pad;
2679 off_t length;
2680};
2681#endif
2682/* ARGSUSED */
2683int
2684truncate(td, uap)
2685 struct thread *td;
2686 register struct truncate_args /* {
2687 syscallarg(char *) path;
2688 syscallarg(int) pad;
2689 syscallarg(off_t) length;
2690 } */ *uap;
2691{
2692 struct mount *mp;
2693 struct vnode *vp;
2694 struct vattr vattr;
2695 int error;
2696 struct nameidata nd;
2697
2698 if (uap->length < 0)
2699 return(EINVAL);
2700 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2701 if ((error = namei(&nd)) != 0)
2702 return (error);
2703 vp = nd.ni_vp;
2704 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
2705 vrele(vp);
2706 return (error);
2707 }
2708 NDFREE(&nd, NDF_ONLY_PNBUF);
2709 VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE);
2710 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2711 if (vp->v_type == VDIR)
2712 error = EISDIR;
2713 else if ((error = vn_writechk(vp)) == 0 &&
2714 (error = VOP_ACCESS(vp, VWRITE, td->td_proc->p_ucred, td)) == 0) {
2715 VATTR_NULL(&vattr);
2716 vattr.va_size = SCARG(uap, length);
2717 error = VOP_SETATTR(vp, &vattr, td->td_proc->p_ucred, td);
2718 }
2719 vput(vp);
2720 vn_finished_write(mp);
2721 return (error);
2722}
2723
2724/*
2725 * Truncate a file given a file descriptor.
2726 */
2727#ifndef _SYS_SYSPROTO_H_
2728struct ftruncate_args {
2729 int fd;
2730 int pad;
2731 off_t length;
2732};
2733#endif
2734/* ARGSUSED */
2735int
2736ftruncate(td, uap)
2737 struct thread *td;
2738 register struct ftruncate_args /* {
2739 syscallarg(int) fd;
2740 syscallarg(int) pad;
2741 syscallarg(off_t) length;
2742 } */ *uap;
2743{
2744 struct mount *mp;
2745 struct vattr vattr;
2746 struct vnode *vp;
2747 struct file *fp;
2748 int error;
2749
2750 if (uap->length < 0)
2751 return(EINVAL);
2752 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2753 return (error);
2754 if ((fp->f_flag & FWRITE) == 0)
2755 return (EINVAL);
2756 vp = (struct vnode *)fp->f_data;
2757 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
2758 return (error);
2759 VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE);
2760 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2761 if (vp->v_type == VDIR)
2762 error = EISDIR;
2763 else if ((error = vn_writechk(vp)) == 0) {
2764 VATTR_NULL(&vattr);
2765 vattr.va_size = SCARG(uap, length);
2766 error = VOP_SETATTR(vp, &vattr, fp->f_cred, td);
2767 }
2768 VOP_UNLOCK(vp, 0, td);
2769 vn_finished_write(mp);
2770 return (error);
2771}
2772
2773#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
2774/*
2775 * Truncate a file given its path name.
2776 */
2777#ifndef _SYS_SYSPROTO_H_
2778struct otruncate_args {
2779 char *path;
2780 long length;
2781};
2782#endif
2783/* ARGSUSED */
2784int
2785otruncate(td, uap)
2786 struct thread *td;
2787 register struct otruncate_args /* {
2788 syscallarg(char *) path;
2789 syscallarg(long) length;
2790 } */ *uap;
2791{
2792 struct truncate_args /* {
2793 syscallarg(char *) path;
2794 syscallarg(int) pad;
2795 syscallarg(off_t) length;
2796 } */ nuap;
2797
2798 SCARG(&nuap, path) = SCARG(uap, path);
2799 SCARG(&nuap, length) = SCARG(uap, length);
2800 return (truncate(td, &nuap));
2801}
2802
2803/*
2804 * Truncate a file given a file descriptor.
2805 */
2806#ifndef _SYS_SYSPROTO_H_
2807struct oftruncate_args {
2808 int fd;
2809 long length;
2810};
2811#endif
2812/* ARGSUSED */
2813int
2814oftruncate(td, uap)
2815 struct thread *td;
2816 register struct oftruncate_args /* {
2817 syscallarg(int) fd;
2818 syscallarg(long) length;
2819 } */ *uap;
2820{
2821 struct ftruncate_args /* {
2822 syscallarg(int) fd;
2823 syscallarg(int) pad;
2824 syscallarg(off_t) length;
2825 } */ nuap;
2826
2827 SCARG(&nuap, fd) = SCARG(uap, fd);
2828 SCARG(&nuap, length) = SCARG(uap, length);
2829 return (ftruncate(td, &nuap));
2830}
2831#endif /* COMPAT_43 || COMPAT_SUNOS */
2832
2833/*
2834 * Sync an open file.
2835 */
2836#ifndef _SYS_SYSPROTO_H_
2837struct fsync_args {
2838 int fd;
2839};
2840#endif
2841/* ARGSUSED */
2842int
2843fsync(td, uap)
2844 struct thread *td;
2845 struct fsync_args /* {
2846 syscallarg(int) fd;
2847 } */ *uap;
2848{
2849 struct vnode *vp;
2850 struct mount *mp;
2851 struct file *fp;
2852 vm_object_t obj;
2853 int error;
2854
2855 GIANT_REQUIRED;
2856
2857 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2858 return (error);
2859 vp = (struct vnode *)fp->f_data;
2860 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
2861 return (error);
2862 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2863 if (VOP_GETVOBJECT(vp, &obj) == 0) {
2864 vm_object_page_clean(obj, 0, 0, 0);
2865 }
2866 error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, td);
2867#ifdef SOFTUPDATES
2868 if (error == 0 && vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP))
2869 error = softdep_fsync(vp);
2870#endif
2871
2872 VOP_UNLOCK(vp, 0, td);
2873 vn_finished_write(mp);
2874 return (error);
2875}
2876
2877/*
2878 * Rename files. Source and destination must either both be directories,
2879 * or both not be directories. If target is a directory, it must be empty.
2880 */
2881#ifndef _SYS_SYSPROTO_H_
2882struct rename_args {
2883 char *from;
2884 char *to;
2885};
2886#endif
2887/* ARGSUSED */
2888int
2889rename(td, uap)
2890 struct thread *td;
2891 register struct rename_args /* {
2892 syscallarg(char *) from;
2893 syscallarg(char *) to;
2894 } */ *uap;
2895{
2896 struct mount *mp;
2897 struct vnode *tvp, *fvp, *tdvp;
2898 struct nameidata fromnd, tond;
2899 int error;
2900
2901 bwillwrite();
2902 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
2903 SCARG(uap, from), td);
2904 if ((error = namei(&fromnd)) != 0)
2905 return (error);
2906 fvp = fromnd.ni_vp;
2907 if ((error = vn_start_write(fvp, &mp, V_WAIT | PCATCH)) != 0) {
2908 NDFREE(&fromnd, NDF_ONLY_PNBUF);
2909 vrele(fromnd.ni_dvp);
2910 vrele(fvp);
2911 goto out1;
2912 }
2913 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | NOOBJ,
2914 UIO_USERSPACE, SCARG(uap, to), td);
2915 if (fromnd.ni_vp->v_type == VDIR)
2916 tond.ni_cnd.cn_flags |= WILLBEDIR;
2917 if ((error = namei(&tond)) != 0) {
2918 /* Translate error code for rename("dir1", "dir2/."). */
2919 if (error == EISDIR && fvp->v_type == VDIR)
2920 error = EINVAL;
2921 NDFREE(&fromnd, NDF_ONLY_PNBUF);
2922 vrele(fromnd.ni_dvp);
2923 vrele(fvp);
2924 goto out1;
2925 }
2926 tdvp = tond.ni_dvp;
2927 tvp = tond.ni_vp;
2928 if (tvp != NULL) {
2929 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
2930 error = ENOTDIR;
2931 goto out;
2932 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
2933 error = EISDIR;
2934 goto out;
2935 }
2936 }
2937 if (fvp == tdvp)
2938 error = EINVAL;
2939 /*
2940 * If source is the same as the destination (that is the
2941 * same inode number with the same name in the same directory),
2942 * then there is nothing to do.
2943 */
2944 if (fvp == tvp && fromnd.ni_dvp == tdvp &&
2945 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
2946 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
2947 fromnd.ni_cnd.cn_namelen))
2948 error = -1;
2949out:
2950 if (!error) {
2951 VOP_LEASE(tdvp, td, td->td_proc->p_ucred, LEASE_WRITE);
2952 if (fromnd.ni_dvp != tdvp) {
2953 VOP_LEASE(fromnd.ni_dvp, td, td->td_proc->p_ucred, LEASE_WRITE);
2954 }
2955 if (tvp) {
2956 VOP_LEASE(tvp, td, td->td_proc->p_ucred, LEASE_WRITE);
2957 }
2958 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
2959 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
2960 NDFREE(&fromnd, NDF_ONLY_PNBUF);
2961 NDFREE(&tond, NDF_ONLY_PNBUF);
2962 } else {
2963 NDFREE(&fromnd, NDF_ONLY_PNBUF);
2964 NDFREE(&tond, NDF_ONLY_PNBUF);
2965 if (tdvp == tvp)
2966 vrele(tdvp);
2967 else
2968 vput(tdvp);
2969 if (tvp)
2970 vput(tvp);
2971 vrele(fromnd.ni_dvp);
2972 vrele(fvp);
2973 }
2974 vrele(tond.ni_startdir);
2975 vn_finished_write(mp);
2976 ASSERT_VOP_UNLOCKED(fromnd.ni_dvp, "rename");
2977 ASSERT_VOP_UNLOCKED(fromnd.ni_vp, "rename");
2978 ASSERT_VOP_UNLOCKED(tond.ni_dvp, "rename");
2979 ASSERT_VOP_UNLOCKED(tond.ni_vp, "rename");
2980out1:
2981 if (fromnd.ni_startdir)
2982 vrele(fromnd.ni_startdir);
2983 if (error == -1)
2984 return (0);
2985 return (error);
2986}
2987
2988/*
2989 * Make a directory file.
2990 */
2991#ifndef _SYS_SYSPROTO_H_
2992struct mkdir_args {
2993 char *path;
2994 int mode;
2995};
2996#endif
2997/* ARGSUSED */
2998int
2999mkdir(td, uap)
3000 struct thread *td;
3001 register struct mkdir_args /* {
3002 syscallarg(char *) path;
3003 syscallarg(int) mode;
3004 } */ *uap;
3005{
3006
3007 return vn_mkdir(uap->path, uap->mode, UIO_USERSPACE, td);
3008}
3009
3010int
3011vn_mkdir(path, mode, segflg, td)
3012 char *path;
3013 int mode;
3014 enum uio_seg segflg;
3015 struct thread *td;
3016{
3017 struct mount *mp;
3018 struct vnode *vp;
3019 struct vattr vattr;
3020 int error;
3021 struct nameidata nd;
3022
3023restart:
3024 bwillwrite();
3025 NDINIT(&nd, CREATE, LOCKPARENT, segflg, path, td);
3026 nd.ni_cnd.cn_flags |= WILLBEDIR;
3027 if ((error = namei(&nd)) != 0)
3028 return (error);
3029 vp = nd.ni_vp;
3030 if (vp != NULL) {
3031 NDFREE(&nd, NDF_ONLY_PNBUF);
3032 vrele(vp);
3033 vput(nd.ni_dvp);
3034 return (EEXIST);
3035 }
3036 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
3037 NDFREE(&nd, NDF_ONLY_PNBUF);
3038 vput(nd.ni_dvp);
3039 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
3040 return (error);
3041 goto restart;
3042 }
3043 VATTR_NULL(&vattr);
3044 vattr.va_type = VDIR;
3045 vattr.va_mode = (mode & ACCESSPERMS) &~ td->td_proc->p_fd->fd_cmask;
3046 VOP_LEASE(nd.ni_dvp, td, td->td_proc->p_ucred, LEASE_WRITE);
3047 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
3048 NDFREE(&nd, NDF_ONLY_PNBUF);
3049 vput(nd.ni_dvp);
3050 if (!error)
3051 vput(nd.ni_vp);
3052 vn_finished_write(mp);
3053 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mkdir");
3054 ASSERT_VOP_UNLOCKED(nd.ni_vp, "mkdir");
3055 return (error);
3056}
3057
3058/*
3059 * Remove a directory file.
3060 */
3061#ifndef _SYS_SYSPROTO_H_
3062struct rmdir_args {
3063 char *path;
3064};
3065#endif
3066/* ARGSUSED */
3067int
3068rmdir(td, uap)
3069 struct thread *td;
3070 struct rmdir_args /* {
3071 syscallarg(char *) path;
3072 } */ *uap;
3073{
3074 struct mount *mp;
3075 struct vnode *vp;
3076 int error;
3077 struct nameidata nd;
3078
3079restart:
3080 bwillwrite();
3081 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
3082 SCARG(uap, path), td);
3083 if ((error = namei(&nd)) != 0)
3084 return (error);
3085 vp = nd.ni_vp;
3086 if (vp->v_type != VDIR) {
3087 error = ENOTDIR;
3088 goto out;
3089 }
3090 /*
3091 * No rmdir "." please.
3092 */
3093 if (nd.ni_dvp == vp) {
3094 error = EINVAL;
3095 goto out;
3096 }
3097 /*
3098 * The root of a mounted filesystem cannot be deleted.
3099 */
3100 if (vp->v_flag & VROOT) {
3101 error = EBUSY;
3102 goto out;
3103 }
3104 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
3105 NDFREE(&nd, NDF_ONLY_PNBUF);
3106 if (nd.ni_dvp == vp)
3107 vrele(nd.ni_dvp);
3108 else
3109 vput(nd.ni_dvp);
3110 vput(vp);
3111 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
3112 return (error);
3113 goto restart;
3114 }
3115 VOP_LEASE(nd.ni_dvp, td, td->td_proc->p_ucred, LEASE_WRITE);
3116 VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE);
3117 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
3118 vn_finished_write(mp);
3119out:
3120 NDFREE(&nd, NDF_ONLY_PNBUF);
3121 if (nd.ni_dvp == vp)
3122 vrele(nd.ni_dvp);
3123 else
3124 vput(nd.ni_dvp);
3125 vput(vp);
3126 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "rmdir");
3127 ASSERT_VOP_UNLOCKED(nd.ni_vp, "rmdir");
3128 return (error);
3129}
3130
3131#ifdef COMPAT_43
3132/*
3133 * Read a block of directory entries in a file system independent format.
3134 */
3135#ifndef _SYS_SYSPROTO_H_
3136struct ogetdirentries_args {
3137 int fd;
3138 char *buf;
3139 u_int count;
3140 long *basep;
3141};
3142#endif
3143int
3144ogetdirentries(td, uap)
3145 struct thread *td;
3146 register struct ogetdirentries_args /* {
3147 syscallarg(int) fd;
3148 syscallarg(char *) buf;
3149 syscallarg(u_int) count;
3150 syscallarg(long *) basep;
3151 } */ *uap;
3152{
3153 struct vnode *vp;
3154 struct file *fp;
3155 struct uio auio, kuio;
3156 struct iovec aiov, kiov;
3157 struct dirent *dp, *edp;
3158 caddr_t dirbuf;
3159 int error, eofflag, readcnt;
3160 long loff;
3161
3162 /* XXX arbitrary sanity limit on `count'. */
3163 if (SCARG(uap, count) > 64 * 1024)
3164 return (EINVAL);
3165 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
3166 return (error);
3167 if ((fp->f_flag & FREAD) == 0)
3168 return (EBADF);
3169 vp = (struct vnode *)fp->f_data;
3170unionread:
3171 if (vp->v_type != VDIR)
3172 return (EINVAL);
3173 aiov.iov_base = SCARG(uap, buf);
3174 aiov.iov_len = SCARG(uap, count);
3175 auio.uio_iov = &aiov;
3176 auio.uio_iovcnt = 1;
3177 auio.uio_rw = UIO_READ;
3178 auio.uio_segflg = UIO_USERSPACE;
3179 auio.uio_td = td;
3180 auio.uio_resid = SCARG(uap, count);
3181 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3182 loff = auio.uio_offset = fp->f_offset;
3183# if (BYTE_ORDER != LITTLE_ENDIAN)
3184 if (vp->v_mount->mnt_maxsymlinklen <= 0) {
3185 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
3186 NULL, NULL);
3187 fp->f_offset = auio.uio_offset;
3188 } else
3189# endif
3190 {
3191 kuio = auio;
3192 kuio.uio_iov = &kiov;
3193 kuio.uio_segflg = UIO_SYSSPACE;
3194 kiov.iov_len = SCARG(uap, count);
3195 MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK);
3196 kiov.iov_base = dirbuf;
3197 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
3198 NULL, NULL);
3199 fp->f_offset = kuio.uio_offset;
3200 if (error == 0) {
3201 readcnt = SCARG(uap, count) - kuio.uio_resid;
3202 edp = (struct dirent *)&dirbuf[readcnt];
3203 for (dp = (struct dirent *)dirbuf; dp < edp; ) {
3204# if (BYTE_ORDER == LITTLE_ENDIAN)
3205 /*
3206 * The expected low byte of
3207 * dp->d_namlen is our dp->d_type.
3208 * The high MBZ byte of dp->d_namlen
3209 * is our dp->d_namlen.
3210 */
3211 dp->d_type = dp->d_namlen;
3212 dp->d_namlen = 0;
3213# else
3214 /*
3215 * The dp->d_type is the high byte
3216 * of the expected dp->d_namlen,
3217 * so must be zero'ed.
3218 */
3219 dp->d_type = 0;
3220# endif
3221 if (dp->d_reclen > 0) {
3222 dp = (struct dirent *)
3223 ((char *)dp + dp->d_reclen);
3224 } else {
3225 error = EIO;
3226 break;
3227 }
3228 }
3229 if (dp >= edp)
3230 error = uiomove(dirbuf, readcnt, &auio);
3231 }
3232 FREE(dirbuf, M_TEMP);
3233 }
3234 VOP_UNLOCK(vp, 0, td);
3235 if (error)
3236 return (error);
3237 if (SCARG(uap, count) == auio.uio_resid) {
3238 if (union_dircheckp) {
3239 error = union_dircheckp(td, &vp, fp);
3240 if (error == -1)
3241 goto unionread;
3242 if (error)
3243 return (error);
3244 }
3245 if ((vp->v_flag & VROOT) &&
3246 (vp->v_mount->mnt_flag & MNT_UNION)) {
3247 struct vnode *tvp = vp;
3248 vp = vp->v_mount->mnt_vnodecovered;
3249 VREF(vp);
3250 fp->f_data = (caddr_t) vp;
3251 fp->f_offset = 0;
3252 vrele(tvp);
3253 goto unionread;
3254 }
3255 }
3256 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
3257 sizeof(long));
3258 td->td_retval[0] = SCARG(uap, count) - auio.uio_resid;
3259 return (error);
3260}
3261#endif /* COMPAT_43 */
3262
3263/*
3264 * Read a block of directory entries in a file system independent format.
3265 */
3266#ifndef _SYS_SYSPROTO_H_
3267struct getdirentries_args {
3268 int fd;
3269 char *buf;
3270 u_int count;
3271 long *basep;
3272};
3273#endif
3274int
3275getdirentries(td, uap)
3276 struct thread *td;
3277 register struct getdirentries_args /* {
3278 syscallarg(int) fd;
3279 syscallarg(char *) buf;
3280 syscallarg(u_int) count;
3281 syscallarg(long *) basep;
3282 } */ *uap;
3283{
3284 struct vnode *vp;
3285 struct file *fp;
3286 struct uio auio;
3287 struct iovec aiov;
3288 long loff;
3289 int error, eofflag;
3290
3291 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
3292 return (error);
3293 if ((fp->f_flag & FREAD) == 0)
3294 return (EBADF);
3295 vp = (struct vnode *)fp->f_data;
3296unionread:
3297 if (vp->v_type != VDIR)
3298 return (EINVAL);
3299 aiov.iov_base = SCARG(uap, buf);
3300 aiov.iov_len = SCARG(uap, count);
3301 auio.uio_iov = &aiov;
3302 auio.uio_iovcnt = 1;
3303 auio.uio_rw = UIO_READ;
3304 auio.uio_segflg = UIO_USERSPACE;
3305 auio.uio_td = td;
3306 auio.uio_resid = SCARG(uap, count);
3307 /* vn_lock(vp, LK_SHARED | LK_RETRY, td); */
3308 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3309 loff = auio.uio_offset = fp->f_offset;
3310 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL, NULL);
3311 fp->f_offset = auio.uio_offset;
3312 VOP_UNLOCK(vp, 0, td);
3313 if (error)
3314 return (error);
3315 if (SCARG(uap, count) == auio.uio_resid) {
3316 if (union_dircheckp) {
3317 error = union_dircheckp(td, &vp, fp);
3318 if (error == -1)
3319 goto unionread;
3320 if (error)
3321 return (error);
3322 }
3323 if ((vp->v_flag & VROOT) &&
3324 (vp->v_mount->mnt_flag & MNT_UNION)) {
3325 struct vnode *tvp = vp;
3326 vp = vp->v_mount->mnt_vnodecovered;
3327 VREF(vp);
3328 fp->f_data = (caddr_t) vp;
3329 fp->f_offset = 0;
3330 vrele(tvp);
3331 goto unionread;
3332 }
3333 }
3334 if (SCARG(uap, basep) != NULL) {
3335 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
3336 sizeof(long));
3337 }
3338 td->td_retval[0] = SCARG(uap, count) - auio.uio_resid;
3339 return (error);
3340}
3341#ifndef _SYS_SYSPROTO_H_
3342struct getdents_args {
3343 int fd;
3344 char *buf;
3345 size_t count;
3346};
3347#endif
3348int
3349getdents(td, uap)
3350 struct thread *td;
3351 register struct getdents_args /* {
3352 syscallarg(int) fd;
3353 syscallarg(char *) buf;
3354 syscallarg(u_int) count;
3355 } */ *uap;
3356{
3357 struct getdirentries_args ap;
3358 ap.fd = uap->fd;
3359 ap.buf = uap->buf;
3360 ap.count = uap->count;
3361 ap.basep = NULL;
3362 return getdirentries(td, &ap);
3363}
3364
3365/*
3366 * Set the mode mask for creation of filesystem nodes.
3367 *
3368 * MP SAFE
3369 */
3370#ifndef _SYS_SYSPROTO_H_
3371struct umask_args {
3372 int newmask;
3373};
3374#endif
3375int
3376umask(td, uap)
3377 struct thread *td;
3378 struct umask_args /* {
3379 syscallarg(int) newmask;
3380 } */ *uap;
3381{
3382 register struct filedesc *fdp;
3383
3384 fdp = td->td_proc->p_fd;
3385 td->td_retval[0] = fdp->fd_cmask;
3386 fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS;
3387 return (0);
3388}
3389
3390/*
3391 * Void all references to file by ripping underlying filesystem
3392 * away from vnode.
3393 */
3394#ifndef _SYS_SYSPROTO_H_
3395struct revoke_args {
3396 char *path;
3397};
3398#endif
3399/* ARGSUSED */
3400int
3401revoke(td, uap)
3402 struct thread *td;
3403 register struct revoke_args /* {
3404 syscallarg(char *) path;
3405 } */ *uap;
3406{
3407 struct mount *mp;
3408 struct vnode *vp;
3409 struct vattr vattr;
3410 int error;
3411 struct nameidata nd;
3412
3413 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
3414 if ((error = namei(&nd)) != 0)
3415 return (error);
3416 vp = nd.ni_vp;
3417 NDFREE(&nd, NDF_ONLY_PNBUF);
3418 if (vp->v_type != VCHR) {
3419 error = EINVAL;
3420 goto out;
3421 }
3422 error = VOP_GETATTR(vp, &vattr, td->td_proc->p_ucred, td);
3423 if (error)
3424 goto out;
3425 if (td->td_proc->p_ucred->cr_uid != vattr.va_uid) {
3426 error = suser_xxx(0, td->td_proc, PRISON_ROOT);
3427 if (error)
3428 goto out;
3429 }
3430 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
3431 goto out;
3432 if (vcount(vp) > 1)
3433 VOP_REVOKE(vp, REVOKEALL);
3434 vn_finished_write(mp);
3435out:
3436 vrele(vp);
3437 return (error);
3438}
3439
3440/*
3441 * Convert a user file descriptor to a kernel file entry.
3442 */
3443int
3444getvnode(fdp, fd, fpp)
3445 struct filedesc *fdp;
3446 int fd;
3447 struct file **fpp;
3448{
3449 struct file *fp;
3450
3451 if ((u_int)fd >= fdp->fd_nfiles ||
3452 (fp = fdp->fd_ofiles[fd]) == NULL)
3453 return (EBADF);
3454 if (fp->f_type != DTYPE_VNODE && fp->f_type != DTYPE_FIFO)
3455 return (EINVAL);
3456 *fpp = fp;
3457 return (0);
3458}
3459/*
3460 * Get (NFS) file handle
3461 */
3462#ifndef _SYS_SYSPROTO_H_
3463struct getfh_args {
3464 char *fname;
3465 fhandle_t *fhp;
3466};
3467#endif
3468int
3469getfh(td, uap)
3470 struct thread *td;
3471 register struct getfh_args *uap;
3472{
3473 struct nameidata nd;
3474 fhandle_t fh;
3475 register struct vnode *vp;
3476 int error;
3477
3478 /*
3479 * Must be super user
3480 */
3481 error = suser_td(td);
3482 if (error)
3483 return (error);
3484 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, td);
3485 error = namei(&nd);
3486 if (error)
3487 return (error);
3488 NDFREE(&nd, NDF_ONLY_PNBUF);
3489 vp = nd.ni_vp;
3490 bzero(&fh, sizeof(fh));
3491 fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
3492 error = VFS_VPTOFH(vp, &fh.fh_fid);
3493 vput(vp);
3494 if (error)
3495 return (error);
3496 error = copyout(&fh, uap->fhp, sizeof (fh));
3497 return (error);
3498}
3499
3500/*
3501 * syscall for the rpc.lockd to use to translate a NFS file handle into
3502 * an open descriptor.
3503 *
3504 * warning: do not remove the suser() call or this becomes one giant
3505 * security hole.
3506 */
3507#ifndef _SYS_SYSPROTO_H_
3508struct fhopen_args {
3509 const struct fhandle *u_fhp;
3510 int flags;
3511};
3512#endif
3513int
3514fhopen(td, uap)
3515 struct thread *td;
3516 struct fhopen_args /* {
3517 syscallarg(const struct fhandle *) u_fhp;
3518 syscallarg(int) flags;
3519 } */ *uap;
3520{
3521 struct proc *p = td->td_proc;
3522 struct mount *mp;
3523 struct vnode *vp;
3524 struct fhandle fhp;
3525 struct vattr vat;
3526 struct vattr *vap = &vat;
3527 struct flock lf;
3528 struct file *fp;
3529 register struct filedesc *fdp = p->p_fd;
3530 int fmode, mode, error, type;
3531 struct file *nfp;
3532 int indx;
3533
3534 /*
3535 * Must be super user
3536 */
3537 error = suser_td(td);
3538 if (error)
3539 return (error);
3540
3541 fmode = FFLAGS(SCARG(uap, flags));
3542 /* why not allow a non-read/write open for our lockd? */
3543 if (((fmode & (FREAD | FWRITE)) == 0) || (fmode & O_CREAT))
3544 return (EINVAL);
3545 error = copyin(SCARG(uap,u_fhp), &fhp, sizeof(fhp));
3546 if (error)
3547 return(error);
3548 /* find the mount point */
3549 mp = vfs_getvfs(&fhp.fh_fsid);
3550 if (mp == NULL)
3551 return (ESTALE);
3552 /* now give me my vnode, it gets returned to me locked */
3553 error = VFS_FHTOVP(mp, &fhp.fh_fid, &vp);
3554 if (error)
3555 return (error);
3556 /*
3557 * from now on we have to make sure not
3558 * to forget about the vnode
3559 * any error that causes an abort must vput(vp)
3560 * just set error = err and 'goto bad;'.
3561 */
3562
3563 /*
3564 * from vn_open
3565 */
3566 if (vp->v_type == VLNK) {
3567 error = EMLINK;
3568 goto bad;
3569 }
3570 if (vp->v_type == VSOCK) {
3571 error = EOPNOTSUPP;
3572 goto bad;
3573 }
3574 mode = 0;
3575 if (fmode & (FWRITE | O_TRUNC)) {
3576 if (vp->v_type == VDIR) {
3577 error = EISDIR;
3578 goto bad;
3579 }
3580 error = vn_writechk(vp);
3581 if (error)
3582 goto bad;
3583 mode |= VWRITE;
3584 }
3585 if (fmode & FREAD)
3586 mode |= VREAD;
3587 if (mode) {
3588 error = VOP_ACCESS(vp, mode, p->p_ucred, td);
3589 if (error)
3590 goto bad;
3591 }
3592 if (fmode & O_TRUNC) {
3593 VOP_UNLOCK(vp, 0, td); /* XXX */
3594 if ((error = vn_start_write(NULL, &mp, V_WAIT | PCATCH)) != 0) {
3595 vrele(vp);
3596 return (error);
3597 }
3598 VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
3599 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); /* XXX */
3600 VATTR_NULL(vap);
3601 vap->va_size = 0;
3602 error = VOP_SETATTR(vp, vap, p->p_ucred, td);
3603 vn_finished_write(mp);
3604 if (error)
3605 goto bad;
3606 }
3607 error = VOP_OPEN(vp, fmode, p->p_ucred, td);
3608 if (error)
3609 goto bad;
3610 /*
3611 * Make sure that a VM object is created for VMIO support.
3612 */
3613 if (vn_canvmio(vp) == TRUE) {
3614 if ((error = vfs_object_create(vp, td, p->p_ucred)) != 0)
3615 goto bad;
3616 }
3617 if (fmode & FWRITE)
3618 vp->v_writecount++;
3619
3620 /*
3621 * end of vn_open code
3622 */
3623
3624 if ((error = falloc(td, &nfp, &indx)) != 0)
3625 goto bad;
3626 fp = nfp;
3627
3628 /*
3629 * Hold an extra reference to avoid having fp ripped out
3630 * from under us while we block in the lock op
3631 */
3632 fhold(fp);
3633 nfp->f_data = (caddr_t)vp;
3634 nfp->f_flag = fmode & FMASK;
3635 nfp->f_ops = &vnops;
3636 nfp->f_type = DTYPE_VNODE;
3637 if (fmode & (O_EXLOCK | O_SHLOCK)) {
3638 lf.l_whence = SEEK_SET;
3639 lf.l_start = 0;
3640 lf.l_len = 0;
3641 if (fmode & O_EXLOCK)
3642 lf.l_type = F_WRLCK;
3643 else
3644 lf.l_type = F_RDLCK;
3645 type = F_FLOCK;
3646 if ((fmode & FNONBLOCK) == 0)
3647 type |= F_WAIT;
3648 VOP_UNLOCK(vp, 0, td);
3649 if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) != 0) {
3650 /*
3651 * The lock request failed. Normally close the
3652 * descriptor but handle the case where someone might
3653 * have dup()d or close()d it when we weren't looking.
3654 */
3655 if (fdp->fd_ofiles[indx] == fp) {
3656 fdp->fd_ofiles[indx] = NULL;
3657 fdrop(fp, td);
3658 }
3659 /*
3660 * release our private reference
3661 */
3662 fdrop(fp, td);
3663 return(error);
3664 }
3665 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3666 fp->f_flag |= FHASLOCK;
3667 }
3668 if ((vp->v_type == VREG) && (VOP_GETVOBJECT(vp, NULL) != 0))
3669 vfs_object_create(vp, td, p->p_ucred);
3670
3671 VOP_UNLOCK(vp, 0, td);
3672 fdrop(fp, td);
3673 td->td_retval[0] = indx;
3674 return (0);
3675
3676bad:
3677 vput(vp);
3678 return (error);
3679}
3680
3681/*
3682 * Stat an (NFS) file handle.
3683 */
3684#ifndef _SYS_SYSPROTO_H_
3685struct fhstat_args {
3686 struct fhandle *u_fhp;
3687 struct stat *sb;
3688};
3689#endif
3690int
3691fhstat(td, uap)
3692 struct thread *td;
3693 register struct fhstat_args /* {
3694 syscallarg(struct fhandle *) u_fhp;
3695 syscallarg(struct stat *) sb;
3696 } */ *uap;
3697{
3698 struct stat sb;
3699 fhandle_t fh;
3700 struct mount *mp;
3701 struct vnode *vp;
3702 int error;
3703
3704 /*
3705 * Must be super user
3706 */
3707 error = suser_td(td);
3708 if (error)
3709 return (error);
3710
3711 error = copyin(SCARG(uap, u_fhp), &fh, sizeof(fhandle_t));
3712 if (error)
3713 return (error);
3714
3715 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
3716 return (ESTALE);
3717 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
3718 return (error);
3719 error = vn_stat(vp, &sb, td);
3720 vput(vp);
3721 if (error)
3722 return (error);
3723 error = copyout(&sb, SCARG(uap, sb), sizeof(sb));
3724 return (error);
3725}
3726
3727/*
3728 * Implement fstatfs() for (NFS) file handles.
3729 */
3730#ifndef _SYS_SYSPROTO_H_
3731struct fhstatfs_args {
3732 struct fhandle *u_fhp;
3733 struct statfs *buf;
3734};
3735#endif
3736int
3737fhstatfs(td, uap)
3738 struct thread *td;
3739 struct fhstatfs_args /* {
3740 syscallarg(struct fhandle) *u_fhp;
3741 syscallarg(struct statfs) *buf;
3742 } */ *uap;
3743{
3744 struct statfs *sp;
3745 struct mount *mp;
3746 struct vnode *vp;
3747 struct statfs sb;
3748 fhandle_t fh;
3749 int error;
3750
3751 /*
3752 * Must be super user
3753 */
3754 error = suser_td(td);
3755 if (error)
3756 return (error);
3757
3758 if ((error = copyin(SCARG(uap, u_fhp), &fh, sizeof(fhandle_t))) != 0)
3759 return (error);
3760
3761 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
3762 return (ESTALE);
3763 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
3764 return (error);
3765 mp = vp->v_mount;
3766 sp = &mp->mnt_stat;
3767 vput(vp);
3768 if ((error = VFS_STATFS(mp, sp, td)) != 0)
3769 return (error);
3770 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
3771 if (suser_xxx(td->td_proc->p_ucred, 0, 0)) {
3772 bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb));
3773 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
3774 sp = &sb;
3775 }
3776 return (copyout(sp, SCARG(uap, buf), sizeof(*sp)));
3777}
3778
3779/*
3780 * Syscall to push extended attribute configuration information into the
3781 * VFS. Accepts a path, which it converts to a mountpoint, as well as
3782 * a command (int cmd), and attribute name and misc data. For now, the
3783 * attribute name is left in userspace for consumption by the VFS_op.
3784 * It will probably be changed to be copied into sysspace by the
3785 * syscall in the future, once issues with various consumers of the
3786 * attribute code have raised their hands.
3787 *
3788 * Currently this is used only by UFS Extended Attributes.
3789 */
3790int
3791extattrctl(td, uap)
3792 struct thread *td;
3793 struct extattrctl_args *uap;
3794{
3795 struct vnode *filename_vp;
3796 struct nameidata nd;
3797 struct mount *mp;
3798 char attrname[EXTATTR_MAXNAMELEN];
3799 int error;
3800
3801 /*
3802 * SCARG(uap, attrname) not always defined. We check again later
3803 * when we invoke the VFS call so as to pass in NULL there if needed.
3804 */
3805 if (SCARG(uap, attrname) != NULL) {
3806 error = copyinstr(SCARG(uap, attrname), attrname,
3807 EXTATTR_MAXNAMELEN, NULL);
3808 if (error)
3809 return (error);
3810 }
3811
3812 /*
3813 * SCARG(uap, filename) not always defined. If it is, grab
3814 * a vnode lock, which VFS_EXTATTRCTL() will later release.
3815 */
3816 filename_vp = NULL;
3817 if (SCARG(uap, filename) != NULL) {
3818 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
3819 SCARG(uap, filename), td);
3820 if ((error = namei(&nd)) != 0)
3821 return (error);
3822 filename_vp = nd.ni_vp;
3823 NDFREE(&nd, NDF_NO_VP_RELE | NDF_NO_VP_UNLOCK);
3824 }
3825
3826 /* SCARG(uap, path) always defined. */
3827 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
3828 if ((error = namei(&nd)) != 0)
3829 return (error);
3830 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
3831 NDFREE(&nd, 0);
3832 if (error) {
3833 if (filename_vp)
3834 vrele(filename_vp);
3835 return (error);
3836 }
3837
3838 if (SCARG(uap, attrname) != NULL) {
3839 error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), filename_vp,
3840 SCARG(uap, attrnamespace), attrname, td);
3841 } else {
3842 error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), filename_vp,
3843 SCARG(uap, attrnamespace), NULL, td);
3844 }
3845
3846 vn_finished_write(mp);
3847 /*
3848 * VFS_EXTATTRCTL will have unlocked, but not de-ref'd,
3849 * filename_vp, so vrele it if it is defined.
3850 */
3851 if (filename_vp != NULL)
3852 vrele(filename_vp);
3853
3854 return (error);
3855}
3856
3857/*
3858 * extattr_set_vp(): Set a named extended attribute on a file or directory
3859 *
3860 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
3861 * kernelspace string pointer "attrname",
3862 * userspace iovec array pointer "iovp", unsigned int iovcnt
3863 * proc "p"
3864 * Returns: 0 on success, an error number otherwise
3865 * Locks: none
3866 * References: vp must be a valid reference for the duration of the call
3867 */
3868static int
3869extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
3870 struct iovec *iovp, unsigned iovcnt, struct thread *td)
3871{
3872 struct mount *mp;
3873 struct uio auio;
3874 struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV];
3875 u_int iovlen, cnt;
3876 int error, i;
3877
3878 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
3879 return (error);
3880 VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE);
3881 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3882
3883 iovlen = iovcnt * sizeof(struct iovec);
3884 if (iovcnt > UIO_SMALLIOV) {
3885 if (iovcnt > UIO_MAXIOV) {
3886 error = EINVAL;
3887 goto done;
3888 }
3889 MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
3890 needfree = iov;
3891 } else
3892 iov = aiov;
3893 auio.uio_iov = iov;
3894 auio.uio_iovcnt = iovcnt;
3895 auio.uio_rw = UIO_WRITE;
3896 auio.uio_segflg = UIO_USERSPACE;
3897 auio.uio_td = td;
3898 auio.uio_offset = 0;
3899 if ((error = copyin((caddr_t)iovp, (caddr_t)iov, iovlen)))
3900 goto done;
3901 auio.uio_resid = 0;
3902 for (i = 0; i < iovcnt; i++) {
3903 if (iov->iov_len > INT_MAX - auio.uio_resid) {
3904 error = EINVAL;
3905 goto done;
3906 }
3907 auio.uio_resid += iov->iov_len;
3908 iov++;
3909 }
3910 cnt = auio.uio_resid;
3911 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
3912 td->td_proc->p_ucred, td);
3913 cnt -= auio.uio_resid;
3914 td->td_retval[0] = cnt;
3915done:
3916 if (needfree)
3917 FREE(needfree, M_IOV);
3918 VOP_UNLOCK(vp, 0, td);
3919 vn_finished_write(mp);
3920 return (error);
3921}
3922
3923int
3924extattr_set_file(td, uap)
3925 struct thread *td;
3926 struct extattr_set_file_args *uap;
3927{
3928 struct nameidata nd;
3929 char attrname[EXTATTR_MAXNAMELEN];
3930 int error;
3931
3932 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
3933 NULL);
3934 if (error)
3935 return (error);
3936
3937 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
3938 if ((error = namei(&nd)) != 0)
3939 return (error);
3940 NDFREE(&nd, NDF_ONLY_PNBUF);
3941
3942 error = extattr_set_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
3943 SCARG(uap, iovp), SCARG(uap, iovcnt), td);
3944
3945 vrele(nd.ni_vp);
3946 return (error);
3947}
3948
3949int
3950extattr_set_fd(td, uap)
3951 struct thread *td;
3952 struct extattr_set_fd_args *uap;
3953{
3954 struct file *fp;
3955 char attrname[EXTATTR_MAXNAMELEN];
3956 int error;
3957
3958 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
3959 NULL);
3960 if (error)
3961 return (error);
3962
3963 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
3964 return (error);
3965
3966 error = extattr_set_vp((struct vnode *)fp->f_data,
3967 SCARG(uap, attrnamespace), attrname, SCARG(uap, iovp),
3968 SCARG(uap, iovcnt), td);
3969
3970 return (error);
3971}
3972
3973/*
3974 * extattr_get_vp(): Get a named extended attribute on a file or directory
3975 *
3976 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
3977 * kernelspace string pointer "attrname",
3978 * userspace iovec array pointer "iovp", unsigned int iovcnt,
3979 * proc "p"
3980 * Returns: 0 on success, an error number otherwise
3981 * Locks: none
3982 * References: vp must be a valid reference for the duration of the call
3983 */
3984static int
3985extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
3986 struct iovec *iovp, unsigned iovcnt, struct thread *td)
3987{
3988 struct uio auio;
3989 struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV];
3990 u_int iovlen, cnt;
3991 int error, i;
3992
3993 VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_READ);
3994 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3995
3996 iovlen = iovcnt * sizeof (struct iovec);
3997 if (iovcnt > UIO_SMALLIOV) {
3998 if (iovcnt > UIO_MAXIOV) {
3999 error = EINVAL;
4000 goto done;
4001 }
4002 MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
4003 needfree = iov;
4004 } else
4005 iov = aiov;
4006 auio.uio_iov = iov;
4007 auio.uio_iovcnt = iovcnt;
4008 auio.uio_rw = UIO_READ;
4009 auio.uio_segflg = UIO_USERSPACE;
4010 auio.uio_td = td;
4011 auio.uio_offset = 0;
4012 if ((error = copyin((caddr_t)iovp, (caddr_t)iov, iovlen)))
4013 goto done;
4014 auio.uio_resid = 0;
4015 for (i = 0; i < iovcnt; i++) {
4016 if (iov->iov_len > INT_MAX - auio.uio_resid) {
4017 error = EINVAL;
4018 goto done;
4019 }
4020 auio.uio_resid += iov->iov_len;
4021 iov++;
4022 }
4023 cnt = auio.uio_resid;
4024 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio,
4025 td->td_proc->p_ucred, td);
4026 cnt -= auio.uio_resid;
4027 td->td_retval[0] = cnt;
4028done:
4029 if (needfree)
4030 FREE(needfree, M_IOV);
4031 VOP_UNLOCK(vp, 0, td);
4032 return (error);
4033}
4034
4035int
4036extattr_get_file(td, uap)
4037 struct thread *td;
4038 struct extattr_get_file_args *uap;
4039{
4040 struct nameidata nd;
4041 char attrname[EXTATTR_MAXNAMELEN];
4042 int error;
4043
4044 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
4045 NULL);
4046 if (error)
4047 return (error);
4048
4049 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
4050 if ((error = namei(&nd)) != 0)
4051 return (error);
4052 NDFREE(&nd, NDF_ONLY_PNBUF);
4053
4054 error = extattr_get_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
4055 SCARG(uap, iovp), SCARG(uap, iovcnt), td);
4056
4057 vrele(nd.ni_vp);
4058 return (error);
4059}
4060
4061int
4062extattr_get_fd(td, uap)
4063 struct thread *td;
4064 struct extattr_get_fd_args *uap;
4065{
4066 struct file *fp;
4067 char attrname[EXTATTR_MAXNAMELEN];
4068 int error;
4069
4070 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
4071 NULL);
4072 if (error)
4073 return (error);
4074
4075 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
4076 return (error);
4077
4078 error = extattr_get_vp((struct vnode *)fp->f_data,
4079 SCARG(uap, attrnamespace), attrname, SCARG(uap, iovp),
4080 SCARG(uap, iovcnt), td);
4081
4082 return (error);
4083}
4084
4085/*
4086 * extattr_delete_vp(): Delete a named extended attribute on a file or
4087 * directory
4088 *
4089 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
4090 * kernelspace string pointer "attrname", proc "p"
4091 * Returns: 0 on success, an error number otherwise
4092 * Locks: none
4093 * References: vp must be a valid reference for the duration of the call
4094 */
4095static int
4096extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
4097 struct thread *td)
4098{
4099 struct mount *mp;
4100 int error;
4101
4102 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
4103 return (error);
4104 VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE);
4105 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
4106
4107 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
4108 td->td_proc->p_ucred, td);
4109
4110 VOP_UNLOCK(vp, 0, td);
4111 vn_finished_write(mp);
4112 return (error);
4113}
4114
4115int
4116extattr_delete_file(td, uap)
4117 struct thread *td;
4118 struct extattr_delete_file_args *uap;
4119{
4120 struct nameidata nd;
4121 char attrname[EXTATTR_MAXNAMELEN];
4122 int error;
4123
4124 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
4125 NULL);
4126 if (error)
4127 return(error);
4128
4129 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
4130 if ((error = namei(&nd)) != 0)
4131 return(error);
4132 NDFREE(&nd, NDF_ONLY_PNBUF);
4133
4134 error = extattr_delete_vp(nd.ni_vp, SCARG(uap, attrnamespace),
4135 attrname, td);
4136
4137 vrele(nd.ni_vp);
4138 return(error);
4139}
4140
4141int
4142extattr_delete_fd(td, uap)
4143 struct thread *td;
4144 struct extattr_delete_fd_args *uap;
4145{
4146 struct file *fp;
4147 char attrname[EXTATTR_MAXNAMELEN];
4148 int error;
4149
4150 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
4151 NULL);
4152 if (error)
4153 return (error);
4154
4155 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
4156 return (error);
4157
4158 error = extattr_delete_vp((struct vnode *)fp->f_data,
4159 SCARG(uap, attrnamespace), attrname, td);
4160
4161 return (error);
4162}
596 panic("unmount: dangling vnode");
597 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_mtx, td);
598 lockdestroy(&mp->mnt_lock);
599 if (coveredvp != NULL)
600 vrele(coveredvp);
601 if (mp->mnt_kern_flag & MNTK_MWAIT)
602 wakeup((caddr_t)mp);
603 free((caddr_t)mp, M_MOUNT);
604 return (0);
605}
606
607/*
608 * Sync each mounted filesystem.
609 */
610#ifndef _SYS_SYSPROTO_H_
611struct sync_args {
612 int dummy;
613};
614#endif
615
616#ifdef DEBUG
617static int syncprt = 0;
618SYSCTL_INT(_debug, OID_AUTO, syncprt, CTLFLAG_RW, &syncprt, 0, "");
619#endif
620
621/* ARGSUSED */
622int
623sync(td, uap)
624 struct thread *td;
625 struct sync_args *uap;
626{
627 struct mount *mp, *nmp;
628 int asyncflag;
629
630 mtx_lock(&mountlist_mtx);
631 for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
632 if (vfs_busy(mp, LK_NOWAIT, &mountlist_mtx, td)) {
633 nmp = TAILQ_NEXT(mp, mnt_list);
634 continue;
635 }
636 if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
637 vn_start_write(NULL, &mp, V_NOWAIT) == 0) {
638 asyncflag = mp->mnt_flag & MNT_ASYNC;
639 mp->mnt_flag &= ~MNT_ASYNC;
640 vfs_msync(mp, MNT_NOWAIT);
641 VFS_SYNC(mp, MNT_NOWAIT,
642 ((td != NULL) ? td->td_proc->p_ucred : NOCRED), td);
643 mp->mnt_flag |= asyncflag;
644 vn_finished_write(mp);
645 }
646 mtx_lock(&mountlist_mtx);
647 nmp = TAILQ_NEXT(mp, mnt_list);
648 vfs_unbusy(mp, td);
649 }
650 mtx_unlock(&mountlist_mtx);
651#if 0
652/*
653 * XXX don't call vfs_bufstats() yet because that routine
654 * was not imported in the Lite2 merge.
655 */
656#ifdef DIAGNOSTIC
657 if (syncprt)
658 vfs_bufstats();
659#endif /* DIAGNOSTIC */
660#endif
661 return (0);
662}
663
664/* XXX PRISON: could be per prison flag */
665static int prison_quotas;
666#if 0
667SYSCTL_INT(_kern_prison, OID_AUTO, quotas, CTLFLAG_RW, &prison_quotas, 0, "");
668#endif
669
670/*
671 * Change filesystem quotas.
672 */
673#ifndef _SYS_SYSPROTO_H_
674struct quotactl_args {
675 char *path;
676 int cmd;
677 int uid;
678 caddr_t arg;
679};
680#endif
681/* ARGSUSED */
682int
683quotactl(td, uap)
684 struct thread *td;
685 register struct quotactl_args /* {
686 syscallarg(char *) path;
687 syscallarg(int) cmd;
688 syscallarg(int) uid;
689 syscallarg(caddr_t) arg;
690 } */ *uap;
691{
692 struct mount *mp;
693 int error;
694 struct nameidata nd;
695
696 if (jailed(td->td_proc->p_ucred) && !prison_quotas)
697 return (EPERM);
698 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
699 if ((error = namei(&nd)) != 0)
700 return (error);
701 NDFREE(&nd, NDF_ONLY_PNBUF);
702 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
703 vrele(nd.ni_vp);
704 if (error)
705 return (error);
706 error = VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
707 SCARG(uap, arg), td);
708 vn_finished_write(mp);
709 return (error);
710}
711
712/*
713 * Get filesystem statistics.
714 */
715#ifndef _SYS_SYSPROTO_H_
716struct statfs_args {
717 char *path;
718 struct statfs *buf;
719};
720#endif
721/* ARGSUSED */
722int
723statfs(td, uap)
724 struct thread *td;
725 register struct statfs_args /* {
726 syscallarg(char *) path;
727 syscallarg(struct statfs *) buf;
728 } */ *uap;
729{
730 register struct mount *mp;
731 register struct statfs *sp;
732 int error;
733 struct nameidata nd;
734 struct statfs sb;
735
736 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
737 if ((error = namei(&nd)) != 0)
738 return (error);
739 mp = nd.ni_vp->v_mount;
740 sp = &mp->mnt_stat;
741 NDFREE(&nd, NDF_ONLY_PNBUF);
742 vrele(nd.ni_vp);
743 error = VFS_STATFS(mp, sp, td);
744 if (error)
745 return (error);
746 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
747 if (suser_xxx(td->td_proc->p_ucred, 0, 0)) {
748 bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb));
749 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
750 sp = &sb;
751 }
752 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
753}
754
755/*
756 * Get filesystem statistics.
757 */
758#ifndef _SYS_SYSPROTO_H_
759struct fstatfs_args {
760 int fd;
761 struct statfs *buf;
762};
763#endif
764/* ARGSUSED */
765int
766fstatfs(td, uap)
767 struct thread *td;
768 register struct fstatfs_args /* {
769 syscallarg(int) fd;
770 syscallarg(struct statfs *) buf;
771 } */ *uap;
772{
773 struct file *fp;
774 struct mount *mp;
775 register struct statfs *sp;
776 int error;
777 struct statfs sb;
778
779 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
780 return (error);
781 mp = ((struct vnode *)fp->f_data)->v_mount;
782 sp = &mp->mnt_stat;
783 error = VFS_STATFS(mp, sp, td);
784 if (error)
785 return (error);
786 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
787 if (suser_xxx(td->td_proc->p_ucred, 0, 0)) {
788 bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb));
789 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
790 sp = &sb;
791 }
792 return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
793}
794
795/*
796 * Get statistics on all filesystems.
797 */
798#ifndef _SYS_SYSPROTO_H_
799struct getfsstat_args {
800 struct statfs *buf;
801 long bufsize;
802 int flags;
803};
804#endif
805int
806getfsstat(td, uap)
807 struct thread *td;
808 register struct getfsstat_args /* {
809 syscallarg(struct statfs *) buf;
810 syscallarg(long) bufsize;
811 syscallarg(int) flags;
812 } */ *uap;
813{
814 register struct mount *mp, *nmp;
815 register struct statfs *sp;
816 caddr_t sfsp;
817 long count, maxcount, error;
818
819 maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
820 sfsp = (caddr_t)SCARG(uap, buf);
821 count = 0;
822 mtx_lock(&mountlist_mtx);
823 for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
824 if (vfs_busy(mp, LK_NOWAIT, &mountlist_mtx, td)) {
825 nmp = TAILQ_NEXT(mp, mnt_list);
826 continue;
827 }
828 if (sfsp && count < maxcount) {
829 sp = &mp->mnt_stat;
830 /*
831 * If MNT_NOWAIT or MNT_LAZY is specified, do not
832 * refresh the fsstat cache. MNT_NOWAIT or MNT_LAZY
833 * overrides MNT_WAIT.
834 */
835 if (((SCARG(uap, flags) & (MNT_LAZY|MNT_NOWAIT)) == 0 ||
836 (SCARG(uap, flags) & MNT_WAIT)) &&
837 (error = VFS_STATFS(mp, sp, td))) {
838 mtx_lock(&mountlist_mtx);
839 nmp = TAILQ_NEXT(mp, mnt_list);
840 vfs_unbusy(mp, td);
841 continue;
842 }
843 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
844 error = copyout((caddr_t)sp, sfsp, sizeof(*sp));
845 if (error) {
846 vfs_unbusy(mp, td);
847 return (error);
848 }
849 sfsp += sizeof(*sp);
850 }
851 count++;
852 mtx_lock(&mountlist_mtx);
853 nmp = TAILQ_NEXT(mp, mnt_list);
854 vfs_unbusy(mp, td);
855 }
856 mtx_unlock(&mountlist_mtx);
857 if (sfsp && count > maxcount)
858 td->td_retval[0] = maxcount;
859 else
860 td->td_retval[0] = count;
861 return (0);
862}
863
864/*
865 * Change current working directory to a given file descriptor.
866 */
867#ifndef _SYS_SYSPROTO_H_
868struct fchdir_args {
869 int fd;
870};
871#endif
872/* ARGSUSED */
873int
874fchdir(td, uap)
875 struct thread *td;
876 struct fchdir_args /* {
877 syscallarg(int) fd;
878 } */ *uap;
879{
880 register struct filedesc *fdp = td->td_proc->p_fd;
881 struct vnode *vp, *tdp;
882 struct mount *mp;
883 struct file *fp;
884 int error;
885
886 if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0)
887 return (error);
888 vp = (struct vnode *)fp->f_data;
889 VREF(vp);
890 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
891 if (vp->v_type != VDIR)
892 error = ENOTDIR;
893 else
894 error = VOP_ACCESS(vp, VEXEC, td->td_proc->p_ucred, td);
895 while (!error && (mp = vp->v_mountedhere) != NULL) {
896 if (vfs_busy(mp, 0, 0, td))
897 continue;
898 error = VFS_ROOT(mp, &tdp);
899 vfs_unbusy(mp, td);
900 if (error)
901 break;
902 vput(vp);
903 vp = tdp;
904 }
905 if (error) {
906 vput(vp);
907 return (error);
908 }
909 VOP_UNLOCK(vp, 0, td);
910 vrele(fdp->fd_cdir);
911 fdp->fd_cdir = vp;
912 return (0);
913}
914
915/*
916 * Change current working directory (``.'').
917 */
918#ifndef _SYS_SYSPROTO_H_
919struct chdir_args {
920 char *path;
921};
922#endif
923/* ARGSUSED */
924int
925chdir(td, uap)
926 struct thread *td;
927 struct chdir_args /* {
928 syscallarg(char *) path;
929 } */ *uap;
930{
931 register struct filedesc *fdp = td->td_proc->p_fd;
932 int error;
933 struct nameidata nd;
934
935 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
936 SCARG(uap, path), td);
937 if ((error = change_dir(&nd, td)) != 0)
938 return (error);
939 NDFREE(&nd, NDF_ONLY_PNBUF);
940 vrele(fdp->fd_cdir);
941 fdp->fd_cdir = nd.ni_vp;
942 return (0);
943}
944
945/*
946 * Helper function for raised chroot(2) security function: Refuse if
947 * any filedescriptors are open directories.
948 */
949static int
950chroot_refuse_vdir_fds(fdp)
951 struct filedesc *fdp;
952{
953 struct vnode *vp;
954 struct file *fp;
955 int error;
956 int fd;
957
958 for (fd = 0; fd < fdp->fd_nfiles ; fd++) {
959 error = getvnode(fdp, fd, &fp);
960 if (error)
961 continue;
962 vp = (struct vnode *)fp->f_data;
963 if (vp->v_type != VDIR)
964 continue;
965 return(EPERM);
966 }
967 return (0);
968}
969
970/*
971 * This sysctl determines if we will allow a process to chroot(2) if it
972 * has a directory open:
973 * 0: disallowed for all processes.
974 * 1: allowed for processes that were not already chroot(2)'ed.
975 * 2: allowed for all processes.
976 */
977
978static int chroot_allow_open_directories = 1;
979
980SYSCTL_INT(_kern, OID_AUTO, chroot_allow_open_directories, CTLFLAG_RW,
981 &chroot_allow_open_directories, 0, "");
982
983/*
984 * Change notion of root (``/'') directory.
985 */
986#ifndef _SYS_SYSPROTO_H_
987struct chroot_args {
988 char *path;
989};
990#endif
991/* ARGSUSED */
992int
993chroot(td, uap)
994 struct thread *td;
995 struct chroot_args /* {
996 syscallarg(char *) path;
997 } */ *uap;
998{
999 register struct filedesc *fdp = td->td_proc->p_fd;
1000 int error;
1001 struct nameidata nd;
1002
1003 error = suser_xxx(0, td->td_proc, PRISON_ROOT);
1004 if (error)
1005 return (error);
1006 if (chroot_allow_open_directories == 0 ||
1007 (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode))
1008 error = chroot_refuse_vdir_fds(fdp);
1009 if (error)
1010 return (error);
1011 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1012 SCARG(uap, path), td);
1013 if ((error = change_dir(&nd, td)) != 0)
1014 return (error);
1015 NDFREE(&nd, NDF_ONLY_PNBUF);
1016 vrele(fdp->fd_rdir);
1017 fdp->fd_rdir = nd.ni_vp;
1018 if (!fdp->fd_jdir) {
1019 fdp->fd_jdir = nd.ni_vp;
1020 VREF(fdp->fd_jdir);
1021 }
1022 return (0);
1023}
1024
1025/*
1026 * Common routine for chroot and chdir.
1027 */
1028static int
1029change_dir(ndp, td)
1030 register struct nameidata *ndp;
1031 struct thread *td;
1032{
1033 struct vnode *vp;
1034 int error;
1035
1036 error = namei(ndp);
1037 if (error)
1038 return (error);
1039 vp = ndp->ni_vp;
1040 if (vp->v_type != VDIR)
1041 error = ENOTDIR;
1042 else
1043 error = VOP_ACCESS(vp, VEXEC, td->td_proc->p_ucred, td);
1044 if (error)
1045 vput(vp);
1046 else
1047 VOP_UNLOCK(vp, 0, td);
1048 return (error);
1049}
1050
1051/*
1052 * Check permissions, allocate an open file structure,
1053 * and call the device open routine if any.
1054 */
1055#ifndef _SYS_SYSPROTO_H_
1056struct open_args {
1057 char *path;
1058 int flags;
1059 int mode;
1060};
1061#endif
1062int
1063open(td, uap)
1064 struct thread *td;
1065 register struct open_args /* {
1066 syscallarg(char *) path;
1067 syscallarg(int) flags;
1068 syscallarg(int) mode;
1069 } */ *uap;
1070{
1071 struct proc *p = td->td_proc;
1072 struct filedesc *fdp = p->p_fd;
1073 struct file *fp;
1074 struct vnode *vp;
1075 struct vattr vat;
1076 struct mount *mp;
1077 int cmode, flags, oflags;
1078 struct file *nfp;
1079 int type, indx, error;
1080 struct flock lf;
1081 struct nameidata nd;
1082
1083 oflags = SCARG(uap, flags);
1084 if ((oflags & O_ACCMODE) == O_ACCMODE)
1085 return (EINVAL);
1086 flags = FFLAGS(oflags);
1087 error = falloc(td, &nfp, &indx);
1088 if (error)
1089 return (error);
1090 fp = nfp;
1091 cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
1092 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
1093 td->td_dupfd = -indx - 1; /* XXX check for fdopen */
1094 /*
1095 * Bump the ref count to prevent another process from closing
1096 * the descriptor while we are blocked in vn_open()
1097 */
1098 fhold(fp);
1099 error = vn_open(&nd, &flags, cmode);
1100 if (error) {
1101 /*
1102 * release our own reference
1103 */
1104 fdrop(fp, td);
1105
1106 /*
1107 * handle special fdopen() case. bleh. dupfdopen() is
1108 * responsible for dropping the old contents of ofiles[indx]
1109 * if it succeeds.
1110 */
1111 if ((error == ENODEV || error == ENXIO) &&
1112 td->td_dupfd >= 0 && /* XXX from fdopen */
1113 (error =
1114 dupfdopen(td, fdp, indx, td->td_dupfd, flags, error)) == 0) {
1115 td->td_retval[0] = indx;
1116 return (0);
1117 }
1118 /*
1119 * Clean up the descriptor, but only if another thread hadn't
1120 * replaced or closed it.
1121 */
1122 if (fdp->fd_ofiles[indx] == fp) {
1123 fdp->fd_ofiles[indx] = NULL;
1124 fdrop(fp, td);
1125 }
1126
1127 if (error == ERESTART)
1128 error = EINTR;
1129 return (error);
1130 }
1131 td->td_dupfd = 0;
1132 NDFREE(&nd, NDF_ONLY_PNBUF);
1133 vp = nd.ni_vp;
1134
1135 /*
1136 * There should be 2 references on the file, one from the descriptor
1137 * table, and one for us.
1138 *
1139 * Handle the case where someone closed the file (via its file
1140 * descriptor) while we were blocked. The end result should look
1141 * like opening the file succeeded but it was immediately closed.
1142 */
1143 if (fp->f_count == 1) {
1144 KASSERT(fdp->fd_ofiles[indx] != fp,
1145 ("Open file descriptor lost all refs"));
1146 VOP_UNLOCK(vp, 0, td);
1147 vn_close(vp, flags & FMASK, fp->f_cred, td);
1148 fdrop(fp, td);
1149 td->td_retval[0] = indx;
1150 return 0;
1151 }
1152
1153 fp->f_data = (caddr_t)vp;
1154 fp->f_flag = flags & FMASK;
1155 fp->f_ops = &vnops;
1156 fp->f_type = (vp->v_type == VFIFO ? DTYPE_FIFO : DTYPE_VNODE);
1157 VOP_UNLOCK(vp, 0, td);
1158 if (flags & (O_EXLOCK | O_SHLOCK)) {
1159 lf.l_whence = SEEK_SET;
1160 lf.l_start = 0;
1161 lf.l_len = 0;
1162 if (flags & O_EXLOCK)
1163 lf.l_type = F_WRLCK;
1164 else
1165 lf.l_type = F_RDLCK;
1166 type = F_FLOCK;
1167 if ((flags & FNONBLOCK) == 0)
1168 type |= F_WAIT;
1169 if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) != 0)
1170 goto bad;
1171 fp->f_flag |= FHASLOCK;
1172 }
1173 if (flags & O_TRUNC) {
1174 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
1175 goto bad;
1176 VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
1177 VATTR_NULL(&vat);
1178 vat.va_size = 0;
1179 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
1180 error = VOP_SETATTR(vp, &vat, p->p_ucred, td);
1181 VOP_UNLOCK(vp, 0, td);
1182 vn_finished_write(mp);
1183 if (error)
1184 goto bad;
1185 }
1186 /* assert that vn_open created a backing object if one is needed */
1187 KASSERT(!vn_canvmio(vp) || VOP_GETVOBJECT(vp, NULL) == 0,
1188 ("open: vmio vnode has no backing object after vn_open"));
1189 /*
1190 * Release our private reference, leaving the one associated with
1191 * the descriptor table intact.
1192 */
1193 fdrop(fp, td);
1194 td->td_retval[0] = indx;
1195 return (0);
1196bad:
1197 if (fdp->fd_ofiles[indx] == fp) {
1198 fdp->fd_ofiles[indx] = NULL;
1199 fdrop(fp, td);
1200 }
1201 fdrop(fp, td);
1202 return (error);
1203}
1204
1205#ifdef COMPAT_43
1206/*
1207 * Create a file.
1208 */
1209#ifndef _SYS_SYSPROTO_H_
1210struct ocreat_args {
1211 char *path;
1212 int mode;
1213};
1214#endif
1215int
1216ocreat(td, uap)
1217 struct thread *td;
1218 register struct ocreat_args /* {
1219 syscallarg(char *) path;
1220 syscallarg(int) mode;
1221 } */ *uap;
1222{
1223 struct open_args /* {
1224 syscallarg(char *) path;
1225 syscallarg(int) flags;
1226 syscallarg(int) mode;
1227 } */ nuap;
1228
1229 SCARG(&nuap, path) = SCARG(uap, path);
1230 SCARG(&nuap, mode) = SCARG(uap, mode);
1231 SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
1232 return (open(td, &nuap));
1233}
1234#endif /* COMPAT_43 */
1235
1236/*
1237 * Create a special file.
1238 */
1239#ifndef _SYS_SYSPROTO_H_
1240struct mknod_args {
1241 char *path;
1242 int mode;
1243 int dev;
1244};
1245#endif
1246/* ARGSUSED */
1247int
1248mknod(td, uap)
1249 struct thread *td;
1250 register struct mknod_args /* {
1251 syscallarg(char *) path;
1252 syscallarg(int) mode;
1253 syscallarg(int) dev;
1254 } */ *uap;
1255{
1256 struct vnode *vp;
1257 struct mount *mp;
1258 struct vattr vattr;
1259 int error;
1260 int whiteout = 0;
1261 struct nameidata nd;
1262
1263 switch (SCARG(uap, mode) & S_IFMT) {
1264 case S_IFCHR:
1265 case S_IFBLK:
1266 error = suser_td(td);
1267 break;
1268 default:
1269 error = suser_xxx(0, td->td_proc, PRISON_ROOT);
1270 break;
1271 }
1272 if (error)
1273 return (error);
1274restart:
1275 bwillwrite();
1276 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), td);
1277 if ((error = namei(&nd)) != 0)
1278 return (error);
1279 vp = nd.ni_vp;
1280 if (vp != NULL) {
1281 vrele(vp);
1282 error = EEXIST;
1283 } else {
1284 VATTR_NULL(&vattr);
1285 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ td->td_proc->p_fd->fd_cmask;
1286 vattr.va_rdev = SCARG(uap, dev);
1287 whiteout = 0;
1288
1289 switch (SCARG(uap, mode) & S_IFMT) {
1290 case S_IFMT: /* used by badsect to flag bad sectors */
1291 vattr.va_type = VBAD;
1292 break;
1293 case S_IFCHR:
1294 vattr.va_type = VCHR;
1295 break;
1296 case S_IFBLK:
1297 vattr.va_type = VBLK;
1298 break;
1299 case S_IFWHT:
1300 whiteout = 1;
1301 break;
1302 default:
1303 error = EINVAL;
1304 break;
1305 }
1306 }
1307 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1308 NDFREE(&nd, NDF_ONLY_PNBUF);
1309 vput(nd.ni_dvp);
1310 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
1311 return (error);
1312 goto restart;
1313 }
1314 if (!error) {
1315 VOP_LEASE(nd.ni_dvp, td, td->td_proc->p_ucred, LEASE_WRITE);
1316 if (whiteout)
1317 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
1318 else {
1319 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
1320 &nd.ni_cnd, &vattr);
1321 if (error == 0)
1322 vput(nd.ni_vp);
1323 }
1324 }
1325 NDFREE(&nd, NDF_ONLY_PNBUF);
1326 vput(nd.ni_dvp);
1327 vn_finished_write(mp);
1328 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mknod");
1329 ASSERT_VOP_UNLOCKED(nd.ni_vp, "mknod");
1330 return (error);
1331}
1332
1333/*
1334 * Create a named pipe.
1335 */
1336#ifndef _SYS_SYSPROTO_H_
1337struct mkfifo_args {
1338 char *path;
1339 int mode;
1340};
1341#endif
1342/* ARGSUSED */
1343int
1344mkfifo(td, uap)
1345 struct thread *td;
1346 register struct mkfifo_args /* {
1347 syscallarg(char *) path;
1348 syscallarg(int) mode;
1349 } */ *uap;
1350{
1351 struct mount *mp;
1352 struct vattr vattr;
1353 int error;
1354 struct nameidata nd;
1355
1356restart:
1357 bwillwrite();
1358 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), td);
1359 if ((error = namei(&nd)) != 0)
1360 return (error);
1361 if (nd.ni_vp != NULL) {
1362 NDFREE(&nd, NDF_ONLY_PNBUF);
1363 vrele(nd.ni_vp);
1364 vput(nd.ni_dvp);
1365 return (EEXIST);
1366 }
1367 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1368 NDFREE(&nd, NDF_ONLY_PNBUF);
1369 vput(nd.ni_dvp);
1370 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
1371 return (error);
1372 goto restart;
1373 }
1374 VATTR_NULL(&vattr);
1375 vattr.va_type = VFIFO;
1376 vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ td->td_proc->p_fd->fd_cmask;
1377 VOP_LEASE(nd.ni_dvp, td, td->td_proc->p_ucred, LEASE_WRITE);
1378 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
1379 if (error == 0)
1380 vput(nd.ni_vp);
1381 NDFREE(&nd, NDF_ONLY_PNBUF);
1382 vput(nd.ni_dvp);
1383 vn_finished_write(mp);
1384 return (error);
1385}
1386
1387/*
1388 * Make a hard file link.
1389 */
1390#ifndef _SYS_SYSPROTO_H_
1391struct link_args {
1392 char *path;
1393 char *link;
1394};
1395#endif
1396/* ARGSUSED */
1397int
1398link(td, uap)
1399 struct thread *td;
1400 register struct link_args /* {
1401 syscallarg(char *) path;
1402 syscallarg(char *) link;
1403 } */ *uap;
1404{
1405 struct vnode *vp;
1406 struct mount *mp;
1407 struct nameidata nd;
1408 int error;
1409
1410 bwillwrite();
1411 NDINIT(&nd, LOOKUP, FOLLOW|NOOBJ, UIO_USERSPACE, SCARG(uap, path), td);
1412 if ((error = namei(&nd)) != 0)
1413 return (error);
1414 NDFREE(&nd, NDF_ONLY_PNBUF);
1415 vp = nd.ni_vp;
1416 if (vp->v_type == VDIR) {
1417 vrele(vp);
1418 return (EPERM); /* POSIX */
1419 }
1420 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
1421 vrele(vp);
1422 return (error);
1423 }
1424 NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), td);
1425 if ((error = namei(&nd)) == 0) {
1426 if (nd.ni_vp != NULL) {
1427 vrele(nd.ni_vp);
1428 error = EEXIST;
1429 } else {
1430 VOP_LEASE(nd.ni_dvp, td, td->td_proc->p_ucred, LEASE_WRITE);
1431 VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE);
1432 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
1433 }
1434 NDFREE(&nd, NDF_ONLY_PNBUF);
1435 vput(nd.ni_dvp);
1436 }
1437 vrele(vp);
1438 vn_finished_write(mp);
1439 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "link");
1440 ASSERT_VOP_UNLOCKED(nd.ni_vp, "link");
1441 return (error);
1442}
1443
1444/*
1445 * Make a symbolic link.
1446 */
1447#ifndef _SYS_SYSPROTO_H_
1448struct symlink_args {
1449 char *path;
1450 char *link;
1451};
1452#endif
1453/* ARGSUSED */
1454int
1455symlink(td, uap)
1456 struct thread *td;
1457 register struct symlink_args /* {
1458 syscallarg(char *) path;
1459 syscallarg(char *) link;
1460 } */ *uap;
1461{
1462 struct mount *mp;
1463 struct vattr vattr;
1464 char *path;
1465 int error;
1466 struct nameidata nd;
1467
1468 path = zalloc(namei_zone);
1469 if ((error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL)) != 0)
1470 goto out;
1471restart:
1472 bwillwrite();
1473 NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), td);
1474 if ((error = namei(&nd)) != 0)
1475 goto out;
1476 if (nd.ni_vp) {
1477 NDFREE(&nd, NDF_ONLY_PNBUF);
1478 vrele(nd.ni_vp);
1479 vput(nd.ni_dvp);
1480 error = EEXIST;
1481 goto out;
1482 }
1483 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1484 NDFREE(&nd, NDF_ONLY_PNBUF);
1485 vput(nd.ni_dvp);
1486 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
1487 return (error);
1488 goto restart;
1489 }
1490 VATTR_NULL(&vattr);
1491 vattr.va_mode = ACCESSPERMS &~ td->td_proc->p_fd->fd_cmask;
1492 VOP_LEASE(nd.ni_dvp, td, td->td_proc->p_ucred, LEASE_WRITE);
1493 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1494 NDFREE(&nd, NDF_ONLY_PNBUF);
1495 if (error == 0)
1496 vput(nd.ni_vp);
1497 vput(nd.ni_dvp);
1498 vn_finished_write(mp);
1499 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "symlink");
1500 ASSERT_VOP_UNLOCKED(nd.ni_vp, "symlink");
1501out:
1502 zfree(namei_zone, path);
1503 return (error);
1504}
1505
1506/*
1507 * Delete a whiteout from the filesystem.
1508 */
1509/* ARGSUSED */
1510int
1511undelete(td, uap)
1512 struct thread *td;
1513 register struct undelete_args /* {
1514 syscallarg(char *) path;
1515 } */ *uap;
1516{
1517 int error;
1518 struct mount *mp;
1519 struct nameidata nd;
1520
1521restart:
1522 bwillwrite();
1523 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
1524 SCARG(uap, path), td);
1525 error = namei(&nd);
1526 if (error)
1527 return (error);
1528
1529 if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
1530 NDFREE(&nd, NDF_ONLY_PNBUF);
1531 if (nd.ni_vp)
1532 vrele(nd.ni_vp);
1533 vput(nd.ni_dvp);
1534 return (EEXIST);
1535 }
1536 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1537 NDFREE(&nd, NDF_ONLY_PNBUF);
1538 vput(nd.ni_dvp);
1539 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
1540 return (error);
1541 goto restart;
1542 }
1543 VOP_LEASE(nd.ni_dvp, td, td->td_proc->p_ucred, LEASE_WRITE);
1544 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE);
1545 NDFREE(&nd, NDF_ONLY_PNBUF);
1546 vput(nd.ni_dvp);
1547 vn_finished_write(mp);
1548 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "undelete");
1549 ASSERT_VOP_UNLOCKED(nd.ni_vp, "undelete");
1550 return (error);
1551}
1552
1553/*
1554 * Delete a name from the filesystem.
1555 */
1556#ifndef _SYS_SYSPROTO_H_
1557struct unlink_args {
1558 char *path;
1559};
1560#endif
1561/* ARGSUSED */
1562int
1563unlink(td, uap)
1564 struct thread *td;
1565 struct unlink_args /* {
1566 syscallarg(char *) path;
1567 } */ *uap;
1568{
1569 struct mount *mp;
1570 struct vnode *vp;
1571 int error;
1572 struct nameidata nd;
1573
1574restart:
1575 bwillwrite();
1576 NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), td);
1577 if ((error = namei(&nd)) != 0)
1578 return (error);
1579 vp = nd.ni_vp;
1580 if (vp->v_type == VDIR)
1581 error = EPERM; /* POSIX */
1582 else {
1583 /*
1584 * The root of a mounted filesystem cannot be deleted.
1585 *
1586 * XXX: can this only be a VDIR case?
1587 */
1588 if (vp->v_flag & VROOT)
1589 error = EBUSY;
1590 }
1591 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1592 NDFREE(&nd, NDF_ONLY_PNBUF);
1593 vrele(vp);
1594 vput(nd.ni_dvp);
1595 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
1596 return (error);
1597 goto restart;
1598 }
1599 VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE);
1600 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
1601 if (!error) {
1602 VOP_LEASE(nd.ni_dvp, td, td->td_proc->p_ucred, LEASE_WRITE);
1603 error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd);
1604 }
1605 NDFREE(&nd, NDF_ONLY_PNBUF);
1606 vput(nd.ni_dvp);
1607 vput(vp);
1608 vn_finished_write(mp);
1609 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "unlink");
1610 ASSERT_VOP_UNLOCKED(nd.ni_vp, "unlink");
1611 return (error);
1612}
1613
1614/*
1615 * Reposition read/write file offset.
1616 */
1617#ifndef _SYS_SYSPROTO_H_
1618struct lseek_args {
1619 int fd;
1620 int pad;
1621 off_t offset;
1622 int whence;
1623};
1624#endif
1625int
1626lseek(td, uap)
1627 struct thread *td;
1628 register struct lseek_args /* {
1629 syscallarg(int) fd;
1630 syscallarg(int) pad;
1631 syscallarg(off_t) offset;
1632 syscallarg(int) whence;
1633 } */ *uap;
1634{
1635 struct ucred *cred = td->td_proc->p_ucred;
1636 register struct filedesc *fdp = td->td_proc->p_fd;
1637 register struct file *fp;
1638 struct vattr vattr;
1639 struct vnode *vp;
1640 off_t offset;
1641 int error, noneg;
1642
1643 if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
1644 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
1645 return (EBADF);
1646 if (fp->f_type != DTYPE_VNODE)
1647 return (ESPIPE);
1648 vp = (struct vnode *)fp->f_data;
1649 noneg = (vp->v_type != VCHR);
1650 offset = SCARG(uap, offset);
1651 switch (SCARG(uap, whence)) {
1652 case L_INCR:
1653 if (noneg &&
1654 (fp->f_offset < 0 ||
1655 (offset > 0 && fp->f_offset > OFF_MAX - offset)))
1656 return (EOVERFLOW);
1657 offset += fp->f_offset;
1658 break;
1659 case L_XTND:
1660 error = VOP_GETATTR(vp, &vattr, cred, td);
1661 if (error)
1662 return (error);
1663 if (noneg &&
1664 (vattr.va_size > OFF_MAX ||
1665 (offset > 0 && vattr.va_size > OFF_MAX - offset)))
1666 return (EOVERFLOW);
1667 offset += vattr.va_size;
1668 break;
1669 case L_SET:
1670 break;
1671 default:
1672 return (EINVAL);
1673 }
1674 if (noneg && offset < 0)
1675 return (EINVAL);
1676 fp->f_offset = offset;
1677 *(off_t *)(td->td_retval) = fp->f_offset;
1678 return (0);
1679}
1680
1681#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1682/*
1683 * Reposition read/write file offset.
1684 */
1685#ifndef _SYS_SYSPROTO_H_
1686struct olseek_args {
1687 int fd;
1688 long offset;
1689 int whence;
1690};
1691#endif
1692int
1693olseek(td, uap)
1694 struct thread *td;
1695 register struct olseek_args /* {
1696 syscallarg(int) fd;
1697 syscallarg(long) offset;
1698 syscallarg(int) whence;
1699 } */ *uap;
1700{
1701 struct lseek_args /* {
1702 syscallarg(int) fd;
1703 syscallarg(int) pad;
1704 syscallarg(off_t) offset;
1705 syscallarg(int) whence;
1706 } */ nuap;
1707 int error;
1708
1709 SCARG(&nuap, fd) = SCARG(uap, fd);
1710 SCARG(&nuap, offset) = SCARG(uap, offset);
1711 SCARG(&nuap, whence) = SCARG(uap, whence);
1712 error = lseek(td, &nuap);
1713 return (error);
1714}
1715#endif /* COMPAT_43 */
1716
1717/*
1718 * Check access permissions using passed credentials.
1719 */
1720static int
1721vn_access(vp, user_flags, cred, td)
1722 struct vnode *vp;
1723 int user_flags;
1724 struct ucred *cred;
1725 struct thread *td;
1726{
1727 int error, flags;
1728
1729 /* Flags == 0 means only check for existence. */
1730 error = 0;
1731 if (user_flags) {
1732 flags = 0;
1733 if (user_flags & R_OK)
1734 flags |= VREAD;
1735 if (user_flags & W_OK)
1736 flags |= VWRITE;
1737 if (user_flags & X_OK)
1738 flags |= VEXEC;
1739 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
1740 error = VOP_ACCESS(vp, flags, cred, td);
1741 }
1742 return (error);
1743}
1744
1745/*
1746 * Check access permissions using "real" credentials.
1747 */
1748#ifndef _SYS_SYSPROTO_H_
1749struct access_args {
1750 char *path;
1751 int flags;
1752};
1753#endif
1754int
1755access(td, uap)
1756 struct thread *td;
1757 register struct access_args /* {
1758 syscallarg(char *) path;
1759 syscallarg(int) flags;
1760 } */ *uap;
1761{
1762 struct ucred *cred, *tmpcred;
1763 register struct vnode *vp;
1764 int error;
1765 struct nameidata nd;
1766
1767 cred = td->td_proc->p_ucred;
1768 /*
1769 * Create and modify a temporary credential instead of one that
1770 * is potentially shared. This could also mess up socket
1771 * buffer accounting which can run in an interrupt context.
1772 *
1773 * XXX - Depending on how "threads" are finally implemented, it
1774 * may be better to explicitly pass the credential to namei()
1775 * rather than to modify the potentially shared process structure.
1776 */
1777 tmpcred = crdup(cred);
1778 tmpcred->cr_uid = cred->cr_ruid;
1779 tmpcred->cr_groups[0] = cred->cr_rgid;
1780 td->td_proc->p_ucred = tmpcred;
1781 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1782 SCARG(uap, path), td);
1783 if ((error = namei(&nd)) != 0)
1784 goto out1;
1785 vp = nd.ni_vp;
1786
1787 error = vn_access(vp, SCARG(uap, flags), tmpcred, td);
1788 NDFREE(&nd, NDF_ONLY_PNBUF);
1789 vput(vp);
1790out1:
1791 td->td_proc->p_ucred = cred;
1792 crfree(tmpcred);
1793 return (error);
1794}
1795
1796/*
1797 * Check access permissions using "effective" credentials.
1798 */
1799#ifndef _SYS_SYSPROTO_H_
1800struct eaccess_args {
1801 char *path;
1802 int flags;
1803};
1804#endif
1805int
1806eaccess(td, uap)
1807 struct thread *td;
1808 register struct eaccess_args /* {
1809 syscallarg(char *) path;
1810 syscallarg(int) flags;
1811 } */ *uap;
1812{
1813 struct nameidata nd;
1814 struct vnode *vp;
1815 int error;
1816
1817 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1818 SCARG(uap, path), td);
1819 if ((error = namei(&nd)) != 0)
1820 return (error);
1821 vp = nd.ni_vp;
1822
1823 error = vn_access(vp, SCARG(uap, flags), td->td_proc->p_ucred, td);
1824 NDFREE(&nd, NDF_ONLY_PNBUF);
1825 vput(vp);
1826 return (error);
1827}
1828
1829#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1830/*
1831 * Get file status; this version follows links.
1832 */
1833#ifndef _SYS_SYSPROTO_H_
1834struct ostat_args {
1835 char *path;
1836 struct ostat *ub;
1837};
1838#endif
1839/* ARGSUSED */
1840int
1841ostat(td, uap)
1842 struct thread *td;
1843 register struct ostat_args /* {
1844 syscallarg(char *) path;
1845 syscallarg(struct ostat *) ub;
1846 } */ *uap;
1847{
1848 struct stat sb;
1849 struct ostat osb;
1850 int error;
1851 struct nameidata nd;
1852
1853 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1854 SCARG(uap, path), td);
1855 if ((error = namei(&nd)) != 0)
1856 return (error);
1857 NDFREE(&nd, NDF_ONLY_PNBUF);
1858 error = vn_stat(nd.ni_vp, &sb, td);
1859 vput(nd.ni_vp);
1860 if (error)
1861 return (error);
1862 cvtstat(&sb, &osb);
1863 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
1864 return (error);
1865}
1866
1867/*
1868 * Get file status; this version does not follow links.
1869 */
1870#ifndef _SYS_SYSPROTO_H_
1871struct olstat_args {
1872 char *path;
1873 struct ostat *ub;
1874};
1875#endif
1876/* ARGSUSED */
1877int
1878olstat(td, uap)
1879 struct thread *td;
1880 register struct olstat_args /* {
1881 syscallarg(char *) path;
1882 syscallarg(struct ostat *) ub;
1883 } */ *uap;
1884{
1885 struct vnode *vp;
1886 struct stat sb;
1887 struct ostat osb;
1888 int error;
1889 struct nameidata nd;
1890
1891 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1892 SCARG(uap, path), td);
1893 if ((error = namei(&nd)) != 0)
1894 return (error);
1895 vp = nd.ni_vp;
1896 error = vn_stat(vp, &sb, td);
1897 NDFREE(&nd, NDF_ONLY_PNBUF);
1898 vput(vp);
1899 if (error)
1900 return (error);
1901 cvtstat(&sb, &osb);
1902 error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
1903 return (error);
1904}
1905
1906/*
1907 * Convert from an old to a new stat structure.
1908 */
1909void
1910cvtstat(st, ost)
1911 struct stat *st;
1912 struct ostat *ost;
1913{
1914
1915 ost->st_dev = st->st_dev;
1916 ost->st_ino = st->st_ino;
1917 ost->st_mode = st->st_mode;
1918 ost->st_nlink = st->st_nlink;
1919 ost->st_uid = st->st_uid;
1920 ost->st_gid = st->st_gid;
1921 ost->st_rdev = st->st_rdev;
1922 if (st->st_size < (quad_t)1 << 32)
1923 ost->st_size = st->st_size;
1924 else
1925 ost->st_size = -2;
1926 ost->st_atime = st->st_atime;
1927 ost->st_mtime = st->st_mtime;
1928 ost->st_ctime = st->st_ctime;
1929 ost->st_blksize = st->st_blksize;
1930 ost->st_blocks = st->st_blocks;
1931 ost->st_flags = st->st_flags;
1932 ost->st_gen = st->st_gen;
1933}
1934#endif /* COMPAT_43 || COMPAT_SUNOS */
1935
1936/*
1937 * Get file status; this version follows links.
1938 */
1939#ifndef _SYS_SYSPROTO_H_
1940struct stat_args {
1941 char *path;
1942 struct stat *ub;
1943};
1944#endif
1945/* ARGSUSED */
1946int
1947stat(td, uap)
1948 struct thread *td;
1949 register struct stat_args /* {
1950 syscallarg(char *) path;
1951 syscallarg(struct stat *) ub;
1952 } */ *uap;
1953{
1954 struct stat sb;
1955 int error;
1956 struct nameidata nd;
1957
1958 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1959 SCARG(uap, path), td);
1960 if ((error = namei(&nd)) != 0)
1961 return (error);
1962 error = vn_stat(nd.ni_vp, &sb, td);
1963 NDFREE(&nd, NDF_ONLY_PNBUF);
1964 vput(nd.ni_vp);
1965 if (error)
1966 return (error);
1967 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
1968 return (error);
1969}
1970
1971/*
1972 * Get file status; this version does not follow links.
1973 */
1974#ifndef _SYS_SYSPROTO_H_
1975struct lstat_args {
1976 char *path;
1977 struct stat *ub;
1978};
1979#endif
1980/* ARGSUSED */
1981int
1982lstat(td, uap)
1983 struct thread *td;
1984 register struct lstat_args /* {
1985 syscallarg(char *) path;
1986 syscallarg(struct stat *) ub;
1987 } */ *uap;
1988{
1989 int error;
1990 struct vnode *vp;
1991 struct stat sb;
1992 struct nameidata nd;
1993
1994 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1995 SCARG(uap, path), td);
1996 if ((error = namei(&nd)) != 0)
1997 return (error);
1998 vp = nd.ni_vp;
1999 error = vn_stat(vp, &sb, td);
2000 NDFREE(&nd, NDF_ONLY_PNBUF);
2001 vput(vp);
2002 if (error)
2003 return (error);
2004 error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
2005 return (error);
2006}
2007
2008/*
2009 * Implementation of the NetBSD stat() function.
2010 * XXX This should probably be collapsed with the FreeBSD version,
2011 * as the differences are only due to vn_stat() clearing spares at
2012 * the end of the structures. vn_stat could be split to avoid this,
2013 * and thus collapse the following to close to zero code.
2014 */
2015void
2016cvtnstat(sb, nsb)
2017 struct stat *sb;
2018 struct nstat *nsb;
2019{
2020 nsb->st_dev = sb->st_dev;
2021 nsb->st_ino = sb->st_ino;
2022 nsb->st_mode = sb->st_mode;
2023 nsb->st_nlink = sb->st_nlink;
2024 nsb->st_uid = sb->st_uid;
2025 nsb->st_gid = sb->st_gid;
2026 nsb->st_rdev = sb->st_rdev;
2027 nsb->st_atimespec = sb->st_atimespec;
2028 nsb->st_mtimespec = sb->st_mtimespec;
2029 nsb->st_ctimespec = sb->st_ctimespec;
2030 nsb->st_size = sb->st_size;
2031 nsb->st_blocks = sb->st_blocks;
2032 nsb->st_blksize = sb->st_blksize;
2033 nsb->st_flags = sb->st_flags;
2034 nsb->st_gen = sb->st_gen;
2035 nsb->st_qspare[0] = sb->st_qspare[0];
2036 nsb->st_qspare[1] = sb->st_qspare[1];
2037}
2038
2039#ifndef _SYS_SYSPROTO_H_
2040struct nstat_args {
2041 char *path;
2042 struct nstat *ub;
2043};
2044#endif
2045/* ARGSUSED */
2046int
2047nstat(td, uap)
2048 struct thread *td;
2049 register struct nstat_args /* {
2050 syscallarg(char *) path;
2051 syscallarg(struct nstat *) ub;
2052 } */ *uap;
2053{
2054 struct stat sb;
2055 struct nstat nsb;
2056 int error;
2057 struct nameidata nd;
2058
2059 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
2060 SCARG(uap, path), td);
2061 if ((error = namei(&nd)) != 0)
2062 return (error);
2063 NDFREE(&nd, NDF_ONLY_PNBUF);
2064 error = vn_stat(nd.ni_vp, &sb, td);
2065 vput(nd.ni_vp);
2066 if (error)
2067 return (error);
2068 cvtnstat(&sb, &nsb);
2069 error = copyout((caddr_t)&nsb, (caddr_t)SCARG(uap, ub), sizeof (nsb));
2070 return (error);
2071}
2072
2073/*
2074 * NetBSD lstat. Get file status; this version does not follow links.
2075 */
2076#ifndef _SYS_SYSPROTO_H_
2077struct lstat_args {
2078 char *path;
2079 struct stat *ub;
2080};
2081#endif
2082/* ARGSUSED */
2083int
2084nlstat(td, uap)
2085 struct thread *td;
2086 register struct nlstat_args /* {
2087 syscallarg(char *) path;
2088 syscallarg(struct nstat *) ub;
2089 } */ *uap;
2090{
2091 int error;
2092 struct vnode *vp;
2093 struct stat sb;
2094 struct nstat nsb;
2095 struct nameidata nd;
2096
2097 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
2098 SCARG(uap, path), td);
2099 if ((error = namei(&nd)) != 0)
2100 return (error);
2101 vp = nd.ni_vp;
2102 NDFREE(&nd, NDF_ONLY_PNBUF);
2103 error = vn_stat(vp, &sb, td);
2104 vput(vp);
2105 if (error)
2106 return (error);
2107 cvtnstat(&sb, &nsb);
2108 error = copyout((caddr_t)&nsb, (caddr_t)SCARG(uap, ub), sizeof (nsb));
2109 return (error);
2110}
2111
2112/*
2113 * Get configurable pathname variables.
2114 */
2115#ifndef _SYS_SYSPROTO_H_
2116struct pathconf_args {
2117 char *path;
2118 int name;
2119};
2120#endif
2121/* ARGSUSED */
2122int
2123pathconf(td, uap)
2124 struct thread *td;
2125 register struct pathconf_args /* {
2126 syscallarg(char *) path;
2127 syscallarg(int) name;
2128 } */ *uap;
2129{
2130 int error;
2131 struct nameidata nd;
2132
2133 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
2134 SCARG(uap, path), td);
2135 if ((error = namei(&nd)) != 0)
2136 return (error);
2137 NDFREE(&nd, NDF_ONLY_PNBUF);
2138 error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), td->td_retval);
2139 vput(nd.ni_vp);
2140 return (error);
2141}
2142
2143/*
2144 * Return target name of a symbolic link.
2145 */
2146#ifndef _SYS_SYSPROTO_H_
2147struct readlink_args {
2148 char *path;
2149 char *buf;
2150 int count;
2151};
2152#endif
2153/* ARGSUSED */
2154int
2155readlink(td, uap)
2156 struct thread *td;
2157 register struct readlink_args /* {
2158 syscallarg(char *) path;
2159 syscallarg(char *) buf;
2160 syscallarg(int) count;
2161 } */ *uap;
2162{
2163 register struct vnode *vp;
2164 struct iovec aiov;
2165 struct uio auio;
2166 int error;
2167 struct nameidata nd;
2168
2169 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
2170 SCARG(uap, path), td);
2171 if ((error = namei(&nd)) != 0)
2172 return (error);
2173 NDFREE(&nd, NDF_ONLY_PNBUF);
2174 vp = nd.ni_vp;
2175 if (vp->v_type != VLNK)
2176 error = EINVAL;
2177 else {
2178 aiov.iov_base = SCARG(uap, buf);
2179 aiov.iov_len = SCARG(uap, count);
2180 auio.uio_iov = &aiov;
2181 auio.uio_iovcnt = 1;
2182 auio.uio_offset = 0;
2183 auio.uio_rw = UIO_READ;
2184 auio.uio_segflg = UIO_USERSPACE;
2185 auio.uio_td = td;
2186 auio.uio_resid = SCARG(uap, count);
2187 error = VOP_READLINK(vp, &auio, td->td_proc->p_ucred);
2188 }
2189 vput(vp);
2190 td->td_retval[0] = SCARG(uap, count) - auio.uio_resid;
2191 return (error);
2192}
2193
2194/*
2195 * Common implementation code for chflags() and fchflags().
2196 */
2197static int
2198setfflags(td, vp, flags)
2199 struct thread *td;
2200 struct vnode *vp;
2201 int flags;
2202{
2203 int error;
2204 struct mount *mp;
2205 struct vattr vattr;
2206
2207 /*
2208 * Prevent non-root users from setting flags on devices. When
2209 * a device is reused, users can retain ownership of the device
2210 * if they are allowed to set flags and programs assume that
2211 * chown can't fail when done as root.
2212 */
2213 if (vp->v_type == VCHR || vp->v_type == VBLK) {
2214 error = suser_xxx(td->td_proc->p_ucred, td->td_proc,
2215 PRISON_ROOT);
2216 if (error)
2217 return (error);
2218 }
2219
2220 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
2221 return (error);
2222 VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE);
2223 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2224 VATTR_NULL(&vattr);
2225 vattr.va_flags = flags;
2226 error = VOP_SETATTR(vp, &vattr, td->td_proc->p_ucred, td);
2227 VOP_UNLOCK(vp, 0, td);
2228 vn_finished_write(mp);
2229 return (error);
2230}
2231
2232/*
2233 * Change flags of a file given a path name.
2234 */
2235#ifndef _SYS_SYSPROTO_H_
2236struct chflags_args {
2237 char *path;
2238 int flags;
2239};
2240#endif
2241/* ARGSUSED */
2242int
2243chflags(td, uap)
2244 struct thread *td;
2245 register struct chflags_args /* {
2246 syscallarg(char *) path;
2247 syscallarg(int) flags;
2248 } */ *uap;
2249{
2250 int error;
2251 struct nameidata nd;
2252
2253 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2254 if ((error = namei(&nd)) != 0)
2255 return (error);
2256 NDFREE(&nd, NDF_ONLY_PNBUF);
2257 error = setfflags(td, nd.ni_vp, SCARG(uap, flags));
2258 vrele(nd.ni_vp);
2259 return error;
2260}
2261
2262/*
2263 * Change flags of a file given a file descriptor.
2264 */
2265#ifndef _SYS_SYSPROTO_H_
2266struct fchflags_args {
2267 int fd;
2268 int flags;
2269};
2270#endif
2271/* ARGSUSED */
2272int
2273fchflags(td, uap)
2274 struct thread *td;
2275 register struct fchflags_args /* {
2276 syscallarg(int) fd;
2277 syscallarg(int) flags;
2278 } */ *uap;
2279{
2280 struct file *fp;
2281 int error;
2282
2283 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2284 return (error);
2285 return setfflags(td, (struct vnode *) fp->f_data, SCARG(uap, flags));
2286}
2287
2288/*
2289 * Common implementation code for chmod(), lchmod() and fchmod().
2290 */
2291static int
2292setfmode(td, vp, mode)
2293 struct thread *td;
2294 struct vnode *vp;
2295 int mode;
2296{
2297 int error;
2298 struct mount *mp;
2299 struct vattr vattr;
2300
2301 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
2302 return (error);
2303 VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE);
2304 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2305 VATTR_NULL(&vattr);
2306 vattr.va_mode = mode & ALLPERMS;
2307 error = VOP_SETATTR(vp, &vattr, td->td_proc->p_ucred, td);
2308 VOP_UNLOCK(vp, 0, td);
2309 vn_finished_write(mp);
2310 return error;
2311}
2312
2313/*
2314 * Change mode of a file given path name.
2315 */
2316#ifndef _SYS_SYSPROTO_H_
2317struct chmod_args {
2318 char *path;
2319 int mode;
2320};
2321#endif
2322/* ARGSUSED */
2323int
2324chmod(td, uap)
2325 struct thread *td;
2326 register struct chmod_args /* {
2327 syscallarg(char *) path;
2328 syscallarg(int) mode;
2329 } */ *uap;
2330{
2331 int error;
2332 struct nameidata nd;
2333
2334 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2335 if ((error = namei(&nd)) != 0)
2336 return (error);
2337 NDFREE(&nd, NDF_ONLY_PNBUF);
2338 error = setfmode(td, nd.ni_vp, SCARG(uap, mode));
2339 vrele(nd.ni_vp);
2340 return error;
2341}
2342
2343/*
2344 * Change mode of a file given path name (don't follow links.)
2345 */
2346#ifndef _SYS_SYSPROTO_H_
2347struct lchmod_args {
2348 char *path;
2349 int mode;
2350};
2351#endif
2352/* ARGSUSED */
2353int
2354lchmod(td, uap)
2355 struct thread *td;
2356 register struct lchmod_args /* {
2357 syscallarg(char *) path;
2358 syscallarg(int) mode;
2359 } */ *uap;
2360{
2361 int error;
2362 struct nameidata nd;
2363
2364 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2365 if ((error = namei(&nd)) != 0)
2366 return (error);
2367 NDFREE(&nd, NDF_ONLY_PNBUF);
2368 error = setfmode(td, nd.ni_vp, SCARG(uap, mode));
2369 vrele(nd.ni_vp);
2370 return error;
2371}
2372
2373/*
2374 * Change mode of a file given a file descriptor.
2375 */
2376#ifndef _SYS_SYSPROTO_H_
2377struct fchmod_args {
2378 int fd;
2379 int mode;
2380};
2381#endif
2382/* ARGSUSED */
2383int
2384fchmod(td, uap)
2385 struct thread *td;
2386 register struct fchmod_args /* {
2387 syscallarg(int) fd;
2388 syscallarg(int) mode;
2389 } */ *uap;
2390{
2391 struct file *fp;
2392 int error;
2393
2394 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2395 return (error);
2396 return setfmode(td, (struct vnode *)fp->f_data, SCARG(uap, mode));
2397}
2398
2399/*
2400 * Common implementation for chown(), lchown(), and fchown()
2401 */
2402static int
2403setfown(td, vp, uid, gid)
2404 struct thread *td;
2405 struct vnode *vp;
2406 uid_t uid;
2407 gid_t gid;
2408{
2409 int error;
2410 struct mount *mp;
2411 struct vattr vattr;
2412
2413 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
2414 return (error);
2415 VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE);
2416 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2417 VATTR_NULL(&vattr);
2418 vattr.va_uid = uid;
2419 vattr.va_gid = gid;
2420 error = VOP_SETATTR(vp, &vattr, td->td_proc->p_ucred, td);
2421 VOP_UNLOCK(vp, 0, td);
2422 vn_finished_write(mp);
2423 return error;
2424}
2425
2426/*
2427 * Set ownership given a path name.
2428 */
2429#ifndef _SYS_SYSPROTO_H_
2430struct chown_args {
2431 char *path;
2432 int uid;
2433 int gid;
2434};
2435#endif
2436/* ARGSUSED */
2437int
2438chown(td, uap)
2439 struct thread *td;
2440 register struct chown_args /* {
2441 syscallarg(char *) path;
2442 syscallarg(int) uid;
2443 syscallarg(int) gid;
2444 } */ *uap;
2445{
2446 int error;
2447 struct nameidata nd;
2448
2449 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2450 if ((error = namei(&nd)) != 0)
2451 return (error);
2452 NDFREE(&nd, NDF_ONLY_PNBUF);
2453 error = setfown(td, nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid));
2454 vrele(nd.ni_vp);
2455 return (error);
2456}
2457
2458/*
2459 * Set ownership given a path name, do not cross symlinks.
2460 */
2461#ifndef _SYS_SYSPROTO_H_
2462struct lchown_args {
2463 char *path;
2464 int uid;
2465 int gid;
2466};
2467#endif
2468/* ARGSUSED */
2469int
2470lchown(td, uap)
2471 struct thread *td;
2472 register struct lchown_args /* {
2473 syscallarg(char *) path;
2474 syscallarg(int) uid;
2475 syscallarg(int) gid;
2476 } */ *uap;
2477{
2478 int error;
2479 struct nameidata nd;
2480
2481 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2482 if ((error = namei(&nd)) != 0)
2483 return (error);
2484 NDFREE(&nd, NDF_ONLY_PNBUF);
2485 error = setfown(td, nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid));
2486 vrele(nd.ni_vp);
2487 return (error);
2488}
2489
2490/*
2491 * Set ownership given a file descriptor.
2492 */
2493#ifndef _SYS_SYSPROTO_H_
2494struct fchown_args {
2495 int fd;
2496 int uid;
2497 int gid;
2498};
2499#endif
2500/* ARGSUSED */
2501int
2502fchown(td, uap)
2503 struct thread *td;
2504 register struct fchown_args /* {
2505 syscallarg(int) fd;
2506 syscallarg(int) uid;
2507 syscallarg(int) gid;
2508 } */ *uap;
2509{
2510 struct file *fp;
2511 int error;
2512
2513 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2514 return (error);
2515 return setfown(td, (struct vnode *)fp->f_data,
2516 SCARG(uap, uid), SCARG(uap, gid));
2517}
2518
2519/*
2520 * Common implementation code for utimes(), lutimes(), and futimes().
2521 */
2522static int
2523getutimes(usrtvp, tsp)
2524 const struct timeval *usrtvp;
2525 struct timespec *tsp;
2526{
2527 struct timeval tv[2];
2528 int error;
2529
2530 if (usrtvp == NULL) {
2531 microtime(&tv[0]);
2532 TIMEVAL_TO_TIMESPEC(&tv[0], &tsp[0]);
2533 tsp[1] = tsp[0];
2534 } else {
2535 if ((error = copyin(usrtvp, tv, sizeof (tv))) != 0)
2536 return (error);
2537 TIMEVAL_TO_TIMESPEC(&tv[0], &tsp[0]);
2538 TIMEVAL_TO_TIMESPEC(&tv[1], &tsp[1]);
2539 }
2540 return 0;
2541}
2542
2543/*
2544 * Common implementation code for utimes(), lutimes(), and futimes().
2545 */
2546static int
2547setutimes(td, vp, ts, nullflag)
2548 struct thread *td;
2549 struct vnode *vp;
2550 const struct timespec *ts;
2551 int nullflag;
2552{
2553 int error;
2554 struct mount *mp;
2555 struct vattr vattr;
2556
2557 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
2558 return (error);
2559 VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE);
2560 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2561 VATTR_NULL(&vattr);
2562 vattr.va_atime = ts[0];
2563 vattr.va_mtime = ts[1];
2564 if (nullflag)
2565 vattr.va_vaflags |= VA_UTIMES_NULL;
2566 error = VOP_SETATTR(vp, &vattr, td->td_proc->p_ucred, td);
2567 VOP_UNLOCK(vp, 0, td);
2568 vn_finished_write(mp);
2569 return error;
2570}
2571
2572/*
2573 * Set the access and modification times of a file.
2574 */
2575#ifndef _SYS_SYSPROTO_H_
2576struct utimes_args {
2577 char *path;
2578 struct timeval *tptr;
2579};
2580#endif
2581/* ARGSUSED */
2582int
2583utimes(td, uap)
2584 struct thread *td;
2585 register struct utimes_args /* {
2586 syscallarg(char *) path;
2587 syscallarg(struct timeval *) tptr;
2588 } */ *uap;
2589{
2590 struct timespec ts[2];
2591 struct timeval *usrtvp;
2592 int error;
2593 struct nameidata nd;
2594
2595 usrtvp = SCARG(uap, tptr);
2596 if ((error = getutimes(usrtvp, ts)) != 0)
2597 return (error);
2598 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2599 if ((error = namei(&nd)) != 0)
2600 return (error);
2601 NDFREE(&nd, NDF_ONLY_PNBUF);
2602 error = setutimes(td, nd.ni_vp, ts, usrtvp == NULL);
2603 vrele(nd.ni_vp);
2604 return (error);
2605}
2606
2607/*
2608 * Set the access and modification times of a file.
2609 */
2610#ifndef _SYS_SYSPROTO_H_
2611struct lutimes_args {
2612 char *path;
2613 struct timeval *tptr;
2614};
2615#endif
2616/* ARGSUSED */
2617int
2618lutimes(td, uap)
2619 struct thread *td;
2620 register struct lutimes_args /* {
2621 syscallarg(char *) path;
2622 syscallarg(struct timeval *) tptr;
2623 } */ *uap;
2624{
2625 struct timespec ts[2];
2626 struct timeval *usrtvp;
2627 int error;
2628 struct nameidata nd;
2629
2630 usrtvp = SCARG(uap, tptr);
2631 if ((error = getutimes(usrtvp, ts)) != 0)
2632 return (error);
2633 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2634 if ((error = namei(&nd)) != 0)
2635 return (error);
2636 NDFREE(&nd, NDF_ONLY_PNBUF);
2637 error = setutimes(td, nd.ni_vp, ts, usrtvp == NULL);
2638 vrele(nd.ni_vp);
2639 return (error);
2640}
2641
2642/*
2643 * Set the access and modification times of a file.
2644 */
2645#ifndef _SYS_SYSPROTO_H_
2646struct futimes_args {
2647 int fd;
2648 struct timeval *tptr;
2649};
2650#endif
2651/* ARGSUSED */
2652int
2653futimes(td, uap)
2654 struct thread *td;
2655 register struct futimes_args /* {
2656 syscallarg(int ) fd;
2657 syscallarg(struct timeval *) tptr;
2658 } */ *uap;
2659{
2660 struct timespec ts[2];
2661 struct file *fp;
2662 struct timeval *usrtvp;
2663 int error;
2664
2665 usrtvp = SCARG(uap, tptr);
2666 if ((error = getutimes(usrtvp, ts)) != 0)
2667 return (error);
2668 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2669 return (error);
2670 return setutimes(td, (struct vnode *)fp->f_data, ts, usrtvp == NULL);
2671}
2672
2673/*
2674 * Truncate a file given its path name.
2675 */
2676#ifndef _SYS_SYSPROTO_H_
2677struct truncate_args {
2678 char *path;
2679 int pad;
2680 off_t length;
2681};
2682#endif
2683/* ARGSUSED */
2684int
2685truncate(td, uap)
2686 struct thread *td;
2687 register struct truncate_args /* {
2688 syscallarg(char *) path;
2689 syscallarg(int) pad;
2690 syscallarg(off_t) length;
2691 } */ *uap;
2692{
2693 struct mount *mp;
2694 struct vnode *vp;
2695 struct vattr vattr;
2696 int error;
2697 struct nameidata nd;
2698
2699 if (uap->length < 0)
2700 return(EINVAL);
2701 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2702 if ((error = namei(&nd)) != 0)
2703 return (error);
2704 vp = nd.ni_vp;
2705 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
2706 vrele(vp);
2707 return (error);
2708 }
2709 NDFREE(&nd, NDF_ONLY_PNBUF);
2710 VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE);
2711 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2712 if (vp->v_type == VDIR)
2713 error = EISDIR;
2714 else if ((error = vn_writechk(vp)) == 0 &&
2715 (error = VOP_ACCESS(vp, VWRITE, td->td_proc->p_ucred, td)) == 0) {
2716 VATTR_NULL(&vattr);
2717 vattr.va_size = SCARG(uap, length);
2718 error = VOP_SETATTR(vp, &vattr, td->td_proc->p_ucred, td);
2719 }
2720 vput(vp);
2721 vn_finished_write(mp);
2722 return (error);
2723}
2724
2725/*
2726 * Truncate a file given a file descriptor.
2727 */
2728#ifndef _SYS_SYSPROTO_H_
2729struct ftruncate_args {
2730 int fd;
2731 int pad;
2732 off_t length;
2733};
2734#endif
2735/* ARGSUSED */
2736int
2737ftruncate(td, uap)
2738 struct thread *td;
2739 register struct ftruncate_args /* {
2740 syscallarg(int) fd;
2741 syscallarg(int) pad;
2742 syscallarg(off_t) length;
2743 } */ *uap;
2744{
2745 struct mount *mp;
2746 struct vattr vattr;
2747 struct vnode *vp;
2748 struct file *fp;
2749 int error;
2750
2751 if (uap->length < 0)
2752 return(EINVAL);
2753 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2754 return (error);
2755 if ((fp->f_flag & FWRITE) == 0)
2756 return (EINVAL);
2757 vp = (struct vnode *)fp->f_data;
2758 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
2759 return (error);
2760 VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE);
2761 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2762 if (vp->v_type == VDIR)
2763 error = EISDIR;
2764 else if ((error = vn_writechk(vp)) == 0) {
2765 VATTR_NULL(&vattr);
2766 vattr.va_size = SCARG(uap, length);
2767 error = VOP_SETATTR(vp, &vattr, fp->f_cred, td);
2768 }
2769 VOP_UNLOCK(vp, 0, td);
2770 vn_finished_write(mp);
2771 return (error);
2772}
2773
2774#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
2775/*
2776 * Truncate a file given its path name.
2777 */
2778#ifndef _SYS_SYSPROTO_H_
2779struct otruncate_args {
2780 char *path;
2781 long length;
2782};
2783#endif
2784/* ARGSUSED */
2785int
2786otruncate(td, uap)
2787 struct thread *td;
2788 register struct otruncate_args /* {
2789 syscallarg(char *) path;
2790 syscallarg(long) length;
2791 } */ *uap;
2792{
2793 struct truncate_args /* {
2794 syscallarg(char *) path;
2795 syscallarg(int) pad;
2796 syscallarg(off_t) length;
2797 } */ nuap;
2798
2799 SCARG(&nuap, path) = SCARG(uap, path);
2800 SCARG(&nuap, length) = SCARG(uap, length);
2801 return (truncate(td, &nuap));
2802}
2803
2804/*
2805 * Truncate a file given a file descriptor.
2806 */
2807#ifndef _SYS_SYSPROTO_H_
2808struct oftruncate_args {
2809 int fd;
2810 long length;
2811};
2812#endif
2813/* ARGSUSED */
2814int
2815oftruncate(td, uap)
2816 struct thread *td;
2817 register struct oftruncate_args /* {
2818 syscallarg(int) fd;
2819 syscallarg(long) length;
2820 } */ *uap;
2821{
2822 struct ftruncate_args /* {
2823 syscallarg(int) fd;
2824 syscallarg(int) pad;
2825 syscallarg(off_t) length;
2826 } */ nuap;
2827
2828 SCARG(&nuap, fd) = SCARG(uap, fd);
2829 SCARG(&nuap, length) = SCARG(uap, length);
2830 return (ftruncate(td, &nuap));
2831}
2832#endif /* COMPAT_43 || COMPAT_SUNOS */
2833
2834/*
2835 * Sync an open file.
2836 */
2837#ifndef _SYS_SYSPROTO_H_
2838struct fsync_args {
2839 int fd;
2840};
2841#endif
2842/* ARGSUSED */
2843int
2844fsync(td, uap)
2845 struct thread *td;
2846 struct fsync_args /* {
2847 syscallarg(int) fd;
2848 } */ *uap;
2849{
2850 struct vnode *vp;
2851 struct mount *mp;
2852 struct file *fp;
2853 vm_object_t obj;
2854 int error;
2855
2856 GIANT_REQUIRED;
2857
2858 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2859 return (error);
2860 vp = (struct vnode *)fp->f_data;
2861 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
2862 return (error);
2863 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2864 if (VOP_GETVOBJECT(vp, &obj) == 0) {
2865 vm_object_page_clean(obj, 0, 0, 0);
2866 }
2867 error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, td);
2868#ifdef SOFTUPDATES
2869 if (error == 0 && vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP))
2870 error = softdep_fsync(vp);
2871#endif
2872
2873 VOP_UNLOCK(vp, 0, td);
2874 vn_finished_write(mp);
2875 return (error);
2876}
2877
2878/*
2879 * Rename files. Source and destination must either both be directories,
2880 * or both not be directories. If target is a directory, it must be empty.
2881 */
2882#ifndef _SYS_SYSPROTO_H_
2883struct rename_args {
2884 char *from;
2885 char *to;
2886};
2887#endif
2888/* ARGSUSED */
2889int
2890rename(td, uap)
2891 struct thread *td;
2892 register struct rename_args /* {
2893 syscallarg(char *) from;
2894 syscallarg(char *) to;
2895 } */ *uap;
2896{
2897 struct mount *mp;
2898 struct vnode *tvp, *fvp, *tdvp;
2899 struct nameidata fromnd, tond;
2900 int error;
2901
2902 bwillwrite();
2903 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
2904 SCARG(uap, from), td);
2905 if ((error = namei(&fromnd)) != 0)
2906 return (error);
2907 fvp = fromnd.ni_vp;
2908 if ((error = vn_start_write(fvp, &mp, V_WAIT | PCATCH)) != 0) {
2909 NDFREE(&fromnd, NDF_ONLY_PNBUF);
2910 vrele(fromnd.ni_dvp);
2911 vrele(fvp);
2912 goto out1;
2913 }
2914 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | NOOBJ,
2915 UIO_USERSPACE, SCARG(uap, to), td);
2916 if (fromnd.ni_vp->v_type == VDIR)
2917 tond.ni_cnd.cn_flags |= WILLBEDIR;
2918 if ((error = namei(&tond)) != 0) {
2919 /* Translate error code for rename("dir1", "dir2/."). */
2920 if (error == EISDIR && fvp->v_type == VDIR)
2921 error = EINVAL;
2922 NDFREE(&fromnd, NDF_ONLY_PNBUF);
2923 vrele(fromnd.ni_dvp);
2924 vrele(fvp);
2925 goto out1;
2926 }
2927 tdvp = tond.ni_dvp;
2928 tvp = tond.ni_vp;
2929 if (tvp != NULL) {
2930 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
2931 error = ENOTDIR;
2932 goto out;
2933 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
2934 error = EISDIR;
2935 goto out;
2936 }
2937 }
2938 if (fvp == tdvp)
2939 error = EINVAL;
2940 /*
2941 * If source is the same as the destination (that is the
2942 * same inode number with the same name in the same directory),
2943 * then there is nothing to do.
2944 */
2945 if (fvp == tvp && fromnd.ni_dvp == tdvp &&
2946 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
2947 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
2948 fromnd.ni_cnd.cn_namelen))
2949 error = -1;
2950out:
2951 if (!error) {
2952 VOP_LEASE(tdvp, td, td->td_proc->p_ucred, LEASE_WRITE);
2953 if (fromnd.ni_dvp != tdvp) {
2954 VOP_LEASE(fromnd.ni_dvp, td, td->td_proc->p_ucred, LEASE_WRITE);
2955 }
2956 if (tvp) {
2957 VOP_LEASE(tvp, td, td->td_proc->p_ucred, LEASE_WRITE);
2958 }
2959 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
2960 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
2961 NDFREE(&fromnd, NDF_ONLY_PNBUF);
2962 NDFREE(&tond, NDF_ONLY_PNBUF);
2963 } else {
2964 NDFREE(&fromnd, NDF_ONLY_PNBUF);
2965 NDFREE(&tond, NDF_ONLY_PNBUF);
2966 if (tdvp == tvp)
2967 vrele(tdvp);
2968 else
2969 vput(tdvp);
2970 if (tvp)
2971 vput(tvp);
2972 vrele(fromnd.ni_dvp);
2973 vrele(fvp);
2974 }
2975 vrele(tond.ni_startdir);
2976 vn_finished_write(mp);
2977 ASSERT_VOP_UNLOCKED(fromnd.ni_dvp, "rename");
2978 ASSERT_VOP_UNLOCKED(fromnd.ni_vp, "rename");
2979 ASSERT_VOP_UNLOCKED(tond.ni_dvp, "rename");
2980 ASSERT_VOP_UNLOCKED(tond.ni_vp, "rename");
2981out1:
2982 if (fromnd.ni_startdir)
2983 vrele(fromnd.ni_startdir);
2984 if (error == -1)
2985 return (0);
2986 return (error);
2987}
2988
2989/*
2990 * Make a directory file.
2991 */
2992#ifndef _SYS_SYSPROTO_H_
2993struct mkdir_args {
2994 char *path;
2995 int mode;
2996};
2997#endif
2998/* ARGSUSED */
2999int
3000mkdir(td, uap)
3001 struct thread *td;
3002 register struct mkdir_args /* {
3003 syscallarg(char *) path;
3004 syscallarg(int) mode;
3005 } */ *uap;
3006{
3007
3008 return vn_mkdir(uap->path, uap->mode, UIO_USERSPACE, td);
3009}
3010
3011int
3012vn_mkdir(path, mode, segflg, td)
3013 char *path;
3014 int mode;
3015 enum uio_seg segflg;
3016 struct thread *td;
3017{
3018 struct mount *mp;
3019 struct vnode *vp;
3020 struct vattr vattr;
3021 int error;
3022 struct nameidata nd;
3023
3024restart:
3025 bwillwrite();
3026 NDINIT(&nd, CREATE, LOCKPARENT, segflg, path, td);
3027 nd.ni_cnd.cn_flags |= WILLBEDIR;
3028 if ((error = namei(&nd)) != 0)
3029 return (error);
3030 vp = nd.ni_vp;
3031 if (vp != NULL) {
3032 NDFREE(&nd, NDF_ONLY_PNBUF);
3033 vrele(vp);
3034 vput(nd.ni_dvp);
3035 return (EEXIST);
3036 }
3037 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
3038 NDFREE(&nd, NDF_ONLY_PNBUF);
3039 vput(nd.ni_dvp);
3040 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
3041 return (error);
3042 goto restart;
3043 }
3044 VATTR_NULL(&vattr);
3045 vattr.va_type = VDIR;
3046 vattr.va_mode = (mode & ACCESSPERMS) &~ td->td_proc->p_fd->fd_cmask;
3047 VOP_LEASE(nd.ni_dvp, td, td->td_proc->p_ucred, LEASE_WRITE);
3048 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
3049 NDFREE(&nd, NDF_ONLY_PNBUF);
3050 vput(nd.ni_dvp);
3051 if (!error)
3052 vput(nd.ni_vp);
3053 vn_finished_write(mp);
3054 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mkdir");
3055 ASSERT_VOP_UNLOCKED(nd.ni_vp, "mkdir");
3056 return (error);
3057}
3058
3059/*
3060 * Remove a directory file.
3061 */
3062#ifndef _SYS_SYSPROTO_H_
3063struct rmdir_args {
3064 char *path;
3065};
3066#endif
3067/* ARGSUSED */
3068int
3069rmdir(td, uap)
3070 struct thread *td;
3071 struct rmdir_args /* {
3072 syscallarg(char *) path;
3073 } */ *uap;
3074{
3075 struct mount *mp;
3076 struct vnode *vp;
3077 int error;
3078 struct nameidata nd;
3079
3080restart:
3081 bwillwrite();
3082 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
3083 SCARG(uap, path), td);
3084 if ((error = namei(&nd)) != 0)
3085 return (error);
3086 vp = nd.ni_vp;
3087 if (vp->v_type != VDIR) {
3088 error = ENOTDIR;
3089 goto out;
3090 }
3091 /*
3092 * No rmdir "." please.
3093 */
3094 if (nd.ni_dvp == vp) {
3095 error = EINVAL;
3096 goto out;
3097 }
3098 /*
3099 * The root of a mounted filesystem cannot be deleted.
3100 */
3101 if (vp->v_flag & VROOT) {
3102 error = EBUSY;
3103 goto out;
3104 }
3105 if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
3106 NDFREE(&nd, NDF_ONLY_PNBUF);
3107 if (nd.ni_dvp == vp)
3108 vrele(nd.ni_dvp);
3109 else
3110 vput(nd.ni_dvp);
3111 vput(vp);
3112 if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
3113 return (error);
3114 goto restart;
3115 }
3116 VOP_LEASE(nd.ni_dvp, td, td->td_proc->p_ucred, LEASE_WRITE);
3117 VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE);
3118 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
3119 vn_finished_write(mp);
3120out:
3121 NDFREE(&nd, NDF_ONLY_PNBUF);
3122 if (nd.ni_dvp == vp)
3123 vrele(nd.ni_dvp);
3124 else
3125 vput(nd.ni_dvp);
3126 vput(vp);
3127 ASSERT_VOP_UNLOCKED(nd.ni_dvp, "rmdir");
3128 ASSERT_VOP_UNLOCKED(nd.ni_vp, "rmdir");
3129 return (error);
3130}
3131
3132#ifdef COMPAT_43
3133/*
3134 * Read a block of directory entries in a file system independent format.
3135 */
3136#ifndef _SYS_SYSPROTO_H_
3137struct ogetdirentries_args {
3138 int fd;
3139 char *buf;
3140 u_int count;
3141 long *basep;
3142};
3143#endif
3144int
3145ogetdirentries(td, uap)
3146 struct thread *td;
3147 register struct ogetdirentries_args /* {
3148 syscallarg(int) fd;
3149 syscallarg(char *) buf;
3150 syscallarg(u_int) count;
3151 syscallarg(long *) basep;
3152 } */ *uap;
3153{
3154 struct vnode *vp;
3155 struct file *fp;
3156 struct uio auio, kuio;
3157 struct iovec aiov, kiov;
3158 struct dirent *dp, *edp;
3159 caddr_t dirbuf;
3160 int error, eofflag, readcnt;
3161 long loff;
3162
3163 /* XXX arbitrary sanity limit on `count'. */
3164 if (SCARG(uap, count) > 64 * 1024)
3165 return (EINVAL);
3166 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
3167 return (error);
3168 if ((fp->f_flag & FREAD) == 0)
3169 return (EBADF);
3170 vp = (struct vnode *)fp->f_data;
3171unionread:
3172 if (vp->v_type != VDIR)
3173 return (EINVAL);
3174 aiov.iov_base = SCARG(uap, buf);
3175 aiov.iov_len = SCARG(uap, count);
3176 auio.uio_iov = &aiov;
3177 auio.uio_iovcnt = 1;
3178 auio.uio_rw = UIO_READ;
3179 auio.uio_segflg = UIO_USERSPACE;
3180 auio.uio_td = td;
3181 auio.uio_resid = SCARG(uap, count);
3182 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3183 loff = auio.uio_offset = fp->f_offset;
3184# if (BYTE_ORDER != LITTLE_ENDIAN)
3185 if (vp->v_mount->mnt_maxsymlinklen <= 0) {
3186 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
3187 NULL, NULL);
3188 fp->f_offset = auio.uio_offset;
3189 } else
3190# endif
3191 {
3192 kuio = auio;
3193 kuio.uio_iov = &kiov;
3194 kuio.uio_segflg = UIO_SYSSPACE;
3195 kiov.iov_len = SCARG(uap, count);
3196 MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK);
3197 kiov.iov_base = dirbuf;
3198 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
3199 NULL, NULL);
3200 fp->f_offset = kuio.uio_offset;
3201 if (error == 0) {
3202 readcnt = SCARG(uap, count) - kuio.uio_resid;
3203 edp = (struct dirent *)&dirbuf[readcnt];
3204 for (dp = (struct dirent *)dirbuf; dp < edp; ) {
3205# if (BYTE_ORDER == LITTLE_ENDIAN)
3206 /*
3207 * The expected low byte of
3208 * dp->d_namlen is our dp->d_type.
3209 * The high MBZ byte of dp->d_namlen
3210 * is our dp->d_namlen.
3211 */
3212 dp->d_type = dp->d_namlen;
3213 dp->d_namlen = 0;
3214# else
3215 /*
3216 * The dp->d_type is the high byte
3217 * of the expected dp->d_namlen,
3218 * so must be zero'ed.
3219 */
3220 dp->d_type = 0;
3221# endif
3222 if (dp->d_reclen > 0) {
3223 dp = (struct dirent *)
3224 ((char *)dp + dp->d_reclen);
3225 } else {
3226 error = EIO;
3227 break;
3228 }
3229 }
3230 if (dp >= edp)
3231 error = uiomove(dirbuf, readcnt, &auio);
3232 }
3233 FREE(dirbuf, M_TEMP);
3234 }
3235 VOP_UNLOCK(vp, 0, td);
3236 if (error)
3237 return (error);
3238 if (SCARG(uap, count) == auio.uio_resid) {
3239 if (union_dircheckp) {
3240 error = union_dircheckp(td, &vp, fp);
3241 if (error == -1)
3242 goto unionread;
3243 if (error)
3244 return (error);
3245 }
3246 if ((vp->v_flag & VROOT) &&
3247 (vp->v_mount->mnt_flag & MNT_UNION)) {
3248 struct vnode *tvp = vp;
3249 vp = vp->v_mount->mnt_vnodecovered;
3250 VREF(vp);
3251 fp->f_data = (caddr_t) vp;
3252 fp->f_offset = 0;
3253 vrele(tvp);
3254 goto unionread;
3255 }
3256 }
3257 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
3258 sizeof(long));
3259 td->td_retval[0] = SCARG(uap, count) - auio.uio_resid;
3260 return (error);
3261}
3262#endif /* COMPAT_43 */
3263
3264/*
3265 * Read a block of directory entries in a file system independent format.
3266 */
3267#ifndef _SYS_SYSPROTO_H_
3268struct getdirentries_args {
3269 int fd;
3270 char *buf;
3271 u_int count;
3272 long *basep;
3273};
3274#endif
3275int
3276getdirentries(td, uap)
3277 struct thread *td;
3278 register struct getdirentries_args /* {
3279 syscallarg(int) fd;
3280 syscallarg(char *) buf;
3281 syscallarg(u_int) count;
3282 syscallarg(long *) basep;
3283 } */ *uap;
3284{
3285 struct vnode *vp;
3286 struct file *fp;
3287 struct uio auio;
3288 struct iovec aiov;
3289 long loff;
3290 int error, eofflag;
3291
3292 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
3293 return (error);
3294 if ((fp->f_flag & FREAD) == 0)
3295 return (EBADF);
3296 vp = (struct vnode *)fp->f_data;
3297unionread:
3298 if (vp->v_type != VDIR)
3299 return (EINVAL);
3300 aiov.iov_base = SCARG(uap, buf);
3301 aiov.iov_len = SCARG(uap, count);
3302 auio.uio_iov = &aiov;
3303 auio.uio_iovcnt = 1;
3304 auio.uio_rw = UIO_READ;
3305 auio.uio_segflg = UIO_USERSPACE;
3306 auio.uio_td = td;
3307 auio.uio_resid = SCARG(uap, count);
3308 /* vn_lock(vp, LK_SHARED | LK_RETRY, td); */
3309 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3310 loff = auio.uio_offset = fp->f_offset;
3311 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL, NULL);
3312 fp->f_offset = auio.uio_offset;
3313 VOP_UNLOCK(vp, 0, td);
3314 if (error)
3315 return (error);
3316 if (SCARG(uap, count) == auio.uio_resid) {
3317 if (union_dircheckp) {
3318 error = union_dircheckp(td, &vp, fp);
3319 if (error == -1)
3320 goto unionread;
3321 if (error)
3322 return (error);
3323 }
3324 if ((vp->v_flag & VROOT) &&
3325 (vp->v_mount->mnt_flag & MNT_UNION)) {
3326 struct vnode *tvp = vp;
3327 vp = vp->v_mount->mnt_vnodecovered;
3328 VREF(vp);
3329 fp->f_data = (caddr_t) vp;
3330 fp->f_offset = 0;
3331 vrele(tvp);
3332 goto unionread;
3333 }
3334 }
3335 if (SCARG(uap, basep) != NULL) {
3336 error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
3337 sizeof(long));
3338 }
3339 td->td_retval[0] = SCARG(uap, count) - auio.uio_resid;
3340 return (error);
3341}
3342#ifndef _SYS_SYSPROTO_H_
3343struct getdents_args {
3344 int fd;
3345 char *buf;
3346 size_t count;
3347};
3348#endif
3349int
3350getdents(td, uap)
3351 struct thread *td;
3352 register struct getdents_args /* {
3353 syscallarg(int) fd;
3354 syscallarg(char *) buf;
3355 syscallarg(u_int) count;
3356 } */ *uap;
3357{
3358 struct getdirentries_args ap;
3359 ap.fd = uap->fd;
3360 ap.buf = uap->buf;
3361 ap.count = uap->count;
3362 ap.basep = NULL;
3363 return getdirentries(td, &ap);
3364}
3365
3366/*
3367 * Set the mode mask for creation of filesystem nodes.
3368 *
3369 * MP SAFE
3370 */
3371#ifndef _SYS_SYSPROTO_H_
3372struct umask_args {
3373 int newmask;
3374};
3375#endif
3376int
3377umask(td, uap)
3378 struct thread *td;
3379 struct umask_args /* {
3380 syscallarg(int) newmask;
3381 } */ *uap;
3382{
3383 register struct filedesc *fdp;
3384
3385 fdp = td->td_proc->p_fd;
3386 td->td_retval[0] = fdp->fd_cmask;
3387 fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS;
3388 return (0);
3389}
3390
3391/*
3392 * Void all references to file by ripping underlying filesystem
3393 * away from vnode.
3394 */
3395#ifndef _SYS_SYSPROTO_H_
3396struct revoke_args {
3397 char *path;
3398};
3399#endif
3400/* ARGSUSED */
3401int
3402revoke(td, uap)
3403 struct thread *td;
3404 register struct revoke_args /* {
3405 syscallarg(char *) path;
3406 } */ *uap;
3407{
3408 struct mount *mp;
3409 struct vnode *vp;
3410 struct vattr vattr;
3411 int error;
3412 struct nameidata nd;
3413
3414 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
3415 if ((error = namei(&nd)) != 0)
3416 return (error);
3417 vp = nd.ni_vp;
3418 NDFREE(&nd, NDF_ONLY_PNBUF);
3419 if (vp->v_type != VCHR) {
3420 error = EINVAL;
3421 goto out;
3422 }
3423 error = VOP_GETATTR(vp, &vattr, td->td_proc->p_ucred, td);
3424 if (error)
3425 goto out;
3426 if (td->td_proc->p_ucred->cr_uid != vattr.va_uid) {
3427 error = suser_xxx(0, td->td_proc, PRISON_ROOT);
3428 if (error)
3429 goto out;
3430 }
3431 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
3432 goto out;
3433 if (vcount(vp) > 1)
3434 VOP_REVOKE(vp, REVOKEALL);
3435 vn_finished_write(mp);
3436out:
3437 vrele(vp);
3438 return (error);
3439}
3440
3441/*
3442 * Convert a user file descriptor to a kernel file entry.
3443 */
3444int
3445getvnode(fdp, fd, fpp)
3446 struct filedesc *fdp;
3447 int fd;
3448 struct file **fpp;
3449{
3450 struct file *fp;
3451
3452 if ((u_int)fd >= fdp->fd_nfiles ||
3453 (fp = fdp->fd_ofiles[fd]) == NULL)
3454 return (EBADF);
3455 if (fp->f_type != DTYPE_VNODE && fp->f_type != DTYPE_FIFO)
3456 return (EINVAL);
3457 *fpp = fp;
3458 return (0);
3459}
3460/*
3461 * Get (NFS) file handle
3462 */
3463#ifndef _SYS_SYSPROTO_H_
3464struct getfh_args {
3465 char *fname;
3466 fhandle_t *fhp;
3467};
3468#endif
3469int
3470getfh(td, uap)
3471 struct thread *td;
3472 register struct getfh_args *uap;
3473{
3474 struct nameidata nd;
3475 fhandle_t fh;
3476 register struct vnode *vp;
3477 int error;
3478
3479 /*
3480 * Must be super user
3481 */
3482 error = suser_td(td);
3483 if (error)
3484 return (error);
3485 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, td);
3486 error = namei(&nd);
3487 if (error)
3488 return (error);
3489 NDFREE(&nd, NDF_ONLY_PNBUF);
3490 vp = nd.ni_vp;
3491 bzero(&fh, sizeof(fh));
3492 fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
3493 error = VFS_VPTOFH(vp, &fh.fh_fid);
3494 vput(vp);
3495 if (error)
3496 return (error);
3497 error = copyout(&fh, uap->fhp, sizeof (fh));
3498 return (error);
3499}
3500
3501/*
3502 * syscall for the rpc.lockd to use to translate a NFS file handle into
3503 * an open descriptor.
3504 *
3505 * warning: do not remove the suser() call or this becomes one giant
3506 * security hole.
3507 */
3508#ifndef _SYS_SYSPROTO_H_
3509struct fhopen_args {
3510 const struct fhandle *u_fhp;
3511 int flags;
3512};
3513#endif
3514int
3515fhopen(td, uap)
3516 struct thread *td;
3517 struct fhopen_args /* {
3518 syscallarg(const struct fhandle *) u_fhp;
3519 syscallarg(int) flags;
3520 } */ *uap;
3521{
3522 struct proc *p = td->td_proc;
3523 struct mount *mp;
3524 struct vnode *vp;
3525 struct fhandle fhp;
3526 struct vattr vat;
3527 struct vattr *vap = &vat;
3528 struct flock lf;
3529 struct file *fp;
3530 register struct filedesc *fdp = p->p_fd;
3531 int fmode, mode, error, type;
3532 struct file *nfp;
3533 int indx;
3534
3535 /*
3536 * Must be super user
3537 */
3538 error = suser_td(td);
3539 if (error)
3540 return (error);
3541
3542 fmode = FFLAGS(SCARG(uap, flags));
3543 /* why not allow a non-read/write open for our lockd? */
3544 if (((fmode & (FREAD | FWRITE)) == 0) || (fmode & O_CREAT))
3545 return (EINVAL);
3546 error = copyin(SCARG(uap,u_fhp), &fhp, sizeof(fhp));
3547 if (error)
3548 return(error);
3549 /* find the mount point */
3550 mp = vfs_getvfs(&fhp.fh_fsid);
3551 if (mp == NULL)
3552 return (ESTALE);
3553 /* now give me my vnode, it gets returned to me locked */
3554 error = VFS_FHTOVP(mp, &fhp.fh_fid, &vp);
3555 if (error)
3556 return (error);
3557 /*
3558 * from now on we have to make sure not
3559 * to forget about the vnode
3560 * any error that causes an abort must vput(vp)
3561 * just set error = err and 'goto bad;'.
3562 */
3563
3564 /*
3565 * from vn_open
3566 */
3567 if (vp->v_type == VLNK) {
3568 error = EMLINK;
3569 goto bad;
3570 }
3571 if (vp->v_type == VSOCK) {
3572 error = EOPNOTSUPP;
3573 goto bad;
3574 }
3575 mode = 0;
3576 if (fmode & (FWRITE | O_TRUNC)) {
3577 if (vp->v_type == VDIR) {
3578 error = EISDIR;
3579 goto bad;
3580 }
3581 error = vn_writechk(vp);
3582 if (error)
3583 goto bad;
3584 mode |= VWRITE;
3585 }
3586 if (fmode & FREAD)
3587 mode |= VREAD;
3588 if (mode) {
3589 error = VOP_ACCESS(vp, mode, p->p_ucred, td);
3590 if (error)
3591 goto bad;
3592 }
3593 if (fmode & O_TRUNC) {
3594 VOP_UNLOCK(vp, 0, td); /* XXX */
3595 if ((error = vn_start_write(NULL, &mp, V_WAIT | PCATCH)) != 0) {
3596 vrele(vp);
3597 return (error);
3598 }
3599 VOP_LEASE(vp, td, p->p_ucred, LEASE_WRITE);
3600 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); /* XXX */
3601 VATTR_NULL(vap);
3602 vap->va_size = 0;
3603 error = VOP_SETATTR(vp, vap, p->p_ucred, td);
3604 vn_finished_write(mp);
3605 if (error)
3606 goto bad;
3607 }
3608 error = VOP_OPEN(vp, fmode, p->p_ucred, td);
3609 if (error)
3610 goto bad;
3611 /*
3612 * Make sure that a VM object is created for VMIO support.
3613 */
3614 if (vn_canvmio(vp) == TRUE) {
3615 if ((error = vfs_object_create(vp, td, p->p_ucred)) != 0)
3616 goto bad;
3617 }
3618 if (fmode & FWRITE)
3619 vp->v_writecount++;
3620
3621 /*
3622 * end of vn_open code
3623 */
3624
3625 if ((error = falloc(td, &nfp, &indx)) != 0)
3626 goto bad;
3627 fp = nfp;
3628
3629 /*
3630 * Hold an extra reference to avoid having fp ripped out
3631 * from under us while we block in the lock op
3632 */
3633 fhold(fp);
3634 nfp->f_data = (caddr_t)vp;
3635 nfp->f_flag = fmode & FMASK;
3636 nfp->f_ops = &vnops;
3637 nfp->f_type = DTYPE_VNODE;
3638 if (fmode & (O_EXLOCK | O_SHLOCK)) {
3639 lf.l_whence = SEEK_SET;
3640 lf.l_start = 0;
3641 lf.l_len = 0;
3642 if (fmode & O_EXLOCK)
3643 lf.l_type = F_WRLCK;
3644 else
3645 lf.l_type = F_RDLCK;
3646 type = F_FLOCK;
3647 if ((fmode & FNONBLOCK) == 0)
3648 type |= F_WAIT;
3649 VOP_UNLOCK(vp, 0, td);
3650 if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) != 0) {
3651 /*
3652 * The lock request failed. Normally close the
3653 * descriptor but handle the case where someone might
3654 * have dup()d or close()d it when we weren't looking.
3655 */
3656 if (fdp->fd_ofiles[indx] == fp) {
3657 fdp->fd_ofiles[indx] = NULL;
3658 fdrop(fp, td);
3659 }
3660 /*
3661 * release our private reference
3662 */
3663 fdrop(fp, td);
3664 return(error);
3665 }
3666 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3667 fp->f_flag |= FHASLOCK;
3668 }
3669 if ((vp->v_type == VREG) && (VOP_GETVOBJECT(vp, NULL) != 0))
3670 vfs_object_create(vp, td, p->p_ucred);
3671
3672 VOP_UNLOCK(vp, 0, td);
3673 fdrop(fp, td);
3674 td->td_retval[0] = indx;
3675 return (0);
3676
3677bad:
3678 vput(vp);
3679 return (error);
3680}
3681
3682/*
3683 * Stat an (NFS) file handle.
3684 */
3685#ifndef _SYS_SYSPROTO_H_
3686struct fhstat_args {
3687 struct fhandle *u_fhp;
3688 struct stat *sb;
3689};
3690#endif
3691int
3692fhstat(td, uap)
3693 struct thread *td;
3694 register struct fhstat_args /* {
3695 syscallarg(struct fhandle *) u_fhp;
3696 syscallarg(struct stat *) sb;
3697 } */ *uap;
3698{
3699 struct stat sb;
3700 fhandle_t fh;
3701 struct mount *mp;
3702 struct vnode *vp;
3703 int error;
3704
3705 /*
3706 * Must be super user
3707 */
3708 error = suser_td(td);
3709 if (error)
3710 return (error);
3711
3712 error = copyin(SCARG(uap, u_fhp), &fh, sizeof(fhandle_t));
3713 if (error)
3714 return (error);
3715
3716 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
3717 return (ESTALE);
3718 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
3719 return (error);
3720 error = vn_stat(vp, &sb, td);
3721 vput(vp);
3722 if (error)
3723 return (error);
3724 error = copyout(&sb, SCARG(uap, sb), sizeof(sb));
3725 return (error);
3726}
3727
3728/*
3729 * Implement fstatfs() for (NFS) file handles.
3730 */
3731#ifndef _SYS_SYSPROTO_H_
3732struct fhstatfs_args {
3733 struct fhandle *u_fhp;
3734 struct statfs *buf;
3735};
3736#endif
3737int
3738fhstatfs(td, uap)
3739 struct thread *td;
3740 struct fhstatfs_args /* {
3741 syscallarg(struct fhandle) *u_fhp;
3742 syscallarg(struct statfs) *buf;
3743 } */ *uap;
3744{
3745 struct statfs *sp;
3746 struct mount *mp;
3747 struct vnode *vp;
3748 struct statfs sb;
3749 fhandle_t fh;
3750 int error;
3751
3752 /*
3753 * Must be super user
3754 */
3755 error = suser_td(td);
3756 if (error)
3757 return (error);
3758
3759 if ((error = copyin(SCARG(uap, u_fhp), &fh, sizeof(fhandle_t))) != 0)
3760 return (error);
3761
3762 if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
3763 return (ESTALE);
3764 if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
3765 return (error);
3766 mp = vp->v_mount;
3767 sp = &mp->mnt_stat;
3768 vput(vp);
3769 if ((error = VFS_STATFS(mp, sp, td)) != 0)
3770 return (error);
3771 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
3772 if (suser_xxx(td->td_proc->p_ucred, 0, 0)) {
3773 bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb));
3774 sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
3775 sp = &sb;
3776 }
3777 return (copyout(sp, SCARG(uap, buf), sizeof(*sp)));
3778}
3779
3780/*
3781 * Syscall to push extended attribute configuration information into the
3782 * VFS. Accepts a path, which it converts to a mountpoint, as well as
3783 * a command (int cmd), and attribute name and misc data. For now, the
3784 * attribute name is left in userspace for consumption by the VFS_op.
3785 * It will probably be changed to be copied into sysspace by the
3786 * syscall in the future, once issues with various consumers of the
3787 * attribute code have raised their hands.
3788 *
3789 * Currently this is used only by UFS Extended Attributes.
3790 */
3791int
3792extattrctl(td, uap)
3793 struct thread *td;
3794 struct extattrctl_args *uap;
3795{
3796 struct vnode *filename_vp;
3797 struct nameidata nd;
3798 struct mount *mp;
3799 char attrname[EXTATTR_MAXNAMELEN];
3800 int error;
3801
3802 /*
3803 * SCARG(uap, attrname) not always defined. We check again later
3804 * when we invoke the VFS call so as to pass in NULL there if needed.
3805 */
3806 if (SCARG(uap, attrname) != NULL) {
3807 error = copyinstr(SCARG(uap, attrname), attrname,
3808 EXTATTR_MAXNAMELEN, NULL);
3809 if (error)
3810 return (error);
3811 }
3812
3813 /*
3814 * SCARG(uap, filename) not always defined. If it is, grab
3815 * a vnode lock, which VFS_EXTATTRCTL() will later release.
3816 */
3817 filename_vp = NULL;
3818 if (SCARG(uap, filename) != NULL) {
3819 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
3820 SCARG(uap, filename), td);
3821 if ((error = namei(&nd)) != 0)
3822 return (error);
3823 filename_vp = nd.ni_vp;
3824 NDFREE(&nd, NDF_NO_VP_RELE | NDF_NO_VP_UNLOCK);
3825 }
3826
3827 /* SCARG(uap, path) always defined. */
3828 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
3829 if ((error = namei(&nd)) != 0)
3830 return (error);
3831 error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
3832 NDFREE(&nd, 0);
3833 if (error) {
3834 if (filename_vp)
3835 vrele(filename_vp);
3836 return (error);
3837 }
3838
3839 if (SCARG(uap, attrname) != NULL) {
3840 error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), filename_vp,
3841 SCARG(uap, attrnamespace), attrname, td);
3842 } else {
3843 error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), filename_vp,
3844 SCARG(uap, attrnamespace), NULL, td);
3845 }
3846
3847 vn_finished_write(mp);
3848 /*
3849 * VFS_EXTATTRCTL will have unlocked, but not de-ref'd,
3850 * filename_vp, so vrele it if it is defined.
3851 */
3852 if (filename_vp != NULL)
3853 vrele(filename_vp);
3854
3855 return (error);
3856}
3857
3858/*
3859 * extattr_set_vp(): Set a named extended attribute on a file or directory
3860 *
3861 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
3862 * kernelspace string pointer "attrname",
3863 * userspace iovec array pointer "iovp", unsigned int iovcnt
3864 * proc "p"
3865 * Returns: 0 on success, an error number otherwise
3866 * Locks: none
3867 * References: vp must be a valid reference for the duration of the call
3868 */
3869static int
3870extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
3871 struct iovec *iovp, unsigned iovcnt, struct thread *td)
3872{
3873 struct mount *mp;
3874 struct uio auio;
3875 struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV];
3876 u_int iovlen, cnt;
3877 int error, i;
3878
3879 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
3880 return (error);
3881 VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE);
3882 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3883
3884 iovlen = iovcnt * sizeof(struct iovec);
3885 if (iovcnt > UIO_SMALLIOV) {
3886 if (iovcnt > UIO_MAXIOV) {
3887 error = EINVAL;
3888 goto done;
3889 }
3890 MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
3891 needfree = iov;
3892 } else
3893 iov = aiov;
3894 auio.uio_iov = iov;
3895 auio.uio_iovcnt = iovcnt;
3896 auio.uio_rw = UIO_WRITE;
3897 auio.uio_segflg = UIO_USERSPACE;
3898 auio.uio_td = td;
3899 auio.uio_offset = 0;
3900 if ((error = copyin((caddr_t)iovp, (caddr_t)iov, iovlen)))
3901 goto done;
3902 auio.uio_resid = 0;
3903 for (i = 0; i < iovcnt; i++) {
3904 if (iov->iov_len > INT_MAX - auio.uio_resid) {
3905 error = EINVAL;
3906 goto done;
3907 }
3908 auio.uio_resid += iov->iov_len;
3909 iov++;
3910 }
3911 cnt = auio.uio_resid;
3912 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
3913 td->td_proc->p_ucred, td);
3914 cnt -= auio.uio_resid;
3915 td->td_retval[0] = cnt;
3916done:
3917 if (needfree)
3918 FREE(needfree, M_IOV);
3919 VOP_UNLOCK(vp, 0, td);
3920 vn_finished_write(mp);
3921 return (error);
3922}
3923
3924int
3925extattr_set_file(td, uap)
3926 struct thread *td;
3927 struct extattr_set_file_args *uap;
3928{
3929 struct nameidata nd;
3930 char attrname[EXTATTR_MAXNAMELEN];
3931 int error;
3932
3933 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
3934 NULL);
3935 if (error)
3936 return (error);
3937
3938 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
3939 if ((error = namei(&nd)) != 0)
3940 return (error);
3941 NDFREE(&nd, NDF_ONLY_PNBUF);
3942
3943 error = extattr_set_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
3944 SCARG(uap, iovp), SCARG(uap, iovcnt), td);
3945
3946 vrele(nd.ni_vp);
3947 return (error);
3948}
3949
3950int
3951extattr_set_fd(td, uap)
3952 struct thread *td;
3953 struct extattr_set_fd_args *uap;
3954{
3955 struct file *fp;
3956 char attrname[EXTATTR_MAXNAMELEN];
3957 int error;
3958
3959 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
3960 NULL);
3961 if (error)
3962 return (error);
3963
3964 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
3965 return (error);
3966
3967 error = extattr_set_vp((struct vnode *)fp->f_data,
3968 SCARG(uap, attrnamespace), attrname, SCARG(uap, iovp),
3969 SCARG(uap, iovcnt), td);
3970
3971 return (error);
3972}
3973
3974/*
3975 * extattr_get_vp(): Get a named extended attribute on a file or directory
3976 *
3977 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
3978 * kernelspace string pointer "attrname",
3979 * userspace iovec array pointer "iovp", unsigned int iovcnt,
3980 * proc "p"
3981 * Returns: 0 on success, an error number otherwise
3982 * Locks: none
3983 * References: vp must be a valid reference for the duration of the call
3984 */
3985static int
3986extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
3987 struct iovec *iovp, unsigned iovcnt, struct thread *td)
3988{
3989 struct uio auio;
3990 struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV];
3991 u_int iovlen, cnt;
3992 int error, i;
3993
3994 VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_READ);
3995 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3996
3997 iovlen = iovcnt * sizeof (struct iovec);
3998 if (iovcnt > UIO_SMALLIOV) {
3999 if (iovcnt > UIO_MAXIOV) {
4000 error = EINVAL;
4001 goto done;
4002 }
4003 MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
4004 needfree = iov;
4005 } else
4006 iov = aiov;
4007 auio.uio_iov = iov;
4008 auio.uio_iovcnt = iovcnt;
4009 auio.uio_rw = UIO_READ;
4010 auio.uio_segflg = UIO_USERSPACE;
4011 auio.uio_td = td;
4012 auio.uio_offset = 0;
4013 if ((error = copyin((caddr_t)iovp, (caddr_t)iov, iovlen)))
4014 goto done;
4015 auio.uio_resid = 0;
4016 for (i = 0; i < iovcnt; i++) {
4017 if (iov->iov_len > INT_MAX - auio.uio_resid) {
4018 error = EINVAL;
4019 goto done;
4020 }
4021 auio.uio_resid += iov->iov_len;
4022 iov++;
4023 }
4024 cnt = auio.uio_resid;
4025 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio,
4026 td->td_proc->p_ucred, td);
4027 cnt -= auio.uio_resid;
4028 td->td_retval[0] = cnt;
4029done:
4030 if (needfree)
4031 FREE(needfree, M_IOV);
4032 VOP_UNLOCK(vp, 0, td);
4033 return (error);
4034}
4035
4036int
4037extattr_get_file(td, uap)
4038 struct thread *td;
4039 struct extattr_get_file_args *uap;
4040{
4041 struct nameidata nd;
4042 char attrname[EXTATTR_MAXNAMELEN];
4043 int error;
4044
4045 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
4046 NULL);
4047 if (error)
4048 return (error);
4049
4050 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
4051 if ((error = namei(&nd)) != 0)
4052 return (error);
4053 NDFREE(&nd, NDF_ONLY_PNBUF);
4054
4055 error = extattr_get_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
4056 SCARG(uap, iovp), SCARG(uap, iovcnt), td);
4057
4058 vrele(nd.ni_vp);
4059 return (error);
4060}
4061
4062int
4063extattr_get_fd(td, uap)
4064 struct thread *td;
4065 struct extattr_get_fd_args *uap;
4066{
4067 struct file *fp;
4068 char attrname[EXTATTR_MAXNAMELEN];
4069 int error;
4070
4071 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
4072 NULL);
4073 if (error)
4074 return (error);
4075
4076 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
4077 return (error);
4078
4079 error = extattr_get_vp((struct vnode *)fp->f_data,
4080 SCARG(uap, attrnamespace), attrname, SCARG(uap, iovp),
4081 SCARG(uap, iovcnt), td);
4082
4083 return (error);
4084}
4085
4086/*
4087 * extattr_delete_vp(): Delete a named extended attribute on a file or
4088 * directory
4089 *
4090 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
4091 * kernelspace string pointer "attrname", proc "p"
4092 * Returns: 0 on success, an error number otherwise
4093 * Locks: none
4094 * References: vp must be a valid reference for the duration of the call
4095 */
4096static int
4097extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
4098 struct thread *td)
4099{
4100 struct mount *mp;
4101 int error;
4102
4103 if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
4104 return (error);
4105 VOP_LEASE(vp, td, td->td_proc->p_ucred, LEASE_WRITE);
4106 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
4107
4108 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
4109 td->td_proc->p_ucred, td);
4110
4111 VOP_UNLOCK(vp, 0, td);
4112 vn_finished_write(mp);
4113 return (error);
4114}
4115
4116int
4117extattr_delete_file(td, uap)
4118 struct thread *td;
4119 struct extattr_delete_file_args *uap;
4120{
4121 struct nameidata nd;
4122 char attrname[EXTATTR_MAXNAMELEN];
4123 int error;
4124
4125 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
4126 NULL);
4127 if (error)
4128 return(error);
4129
4130 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
4131 if ((error = namei(&nd)) != 0)
4132 return(error);
4133 NDFREE(&nd, NDF_ONLY_PNBUF);
4134
4135 error = extattr_delete_vp(nd.ni_vp, SCARG(uap, attrnamespace),
4136 attrname, td);
4137
4138 vrele(nd.ni_vp);
4139 return(error);
4140}
4141
4142int
4143extattr_delete_fd(td, uap)
4144 struct thread *td;
4145 struct extattr_delete_fd_args *uap;
4146{
4147 struct file *fp;
4148 char attrname[EXTATTR_MAXNAMELEN];
4149 int error;
4150
4151 error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
4152 NULL);
4153 if (error)
4154 return (error);
4155
4156 if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
4157 return (error);
4158
4159 error = extattr_delete_vp((struct vnode *)fp->f_data,
4160 SCARG(uap, attrnamespace), attrname, td);
4161
4162 return (error);
4163}