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