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