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