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