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