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