]> git.saurik.com Git - apple/xnu.git/blob - bsd/vfs/vfs_syscalls.c
xnu-123.5.tar.gz
[apple/xnu.git] / bsd / vfs / vfs_syscalls.c
1 /*
2 * Copyright (c) 1995-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * Copyright (c) 1989, 1993
24 * The Regents of the University of California. All rights reserved.
25 * (c) UNIX System Laboratories, Inc.
26 * All or some portions of this file are derived from material licensed
27 * to the University of California by American Telephone and Telegraph
28 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
29 * the permission of UNIX System Laboratories, Inc.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. All advertising materials mentioning features or use of this software
40 * must display the following acknowledgement:
41 * This product includes software developed by the University of
42 * California, Berkeley and its contributors.
43 * 4. Neither the name of the University nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * SUCH DAMAGE.
58 *
59 * @(#)vfs_syscalls.c 8.41 (Berkeley) 6/15/95
60 */
61
62 #include <sys/param.h>
63 #include <sys/systm.h>
64 #include <sys/namei.h>
65 #include <sys/filedesc.h>
66 #include <sys/kernel.h>
67 #include <sys/file.h>
68 #include <sys/stat.h>
69 #include <sys/vnode.h>
70 #include <sys/mount.h>
71 #include <sys/proc.h>
72 #include <sys/uio.h>
73 #include <sys/malloc.h>
74 #include <sys/dirent.h>
75 #include <sys/attr.h>
76 #include <sys/sysctl.h>
77 #include <sys/ubc.h>
78 #include <machine/cons.h>
79 #include <miscfs/specfs/specdev.h>
80
81 struct lock__bsd__ exchangelock;
82
83 /*
84 * The currently logged-in user, for ownership of files/directories whose on-disk
85 * permissions are ignored:
86 */
87 uid_t console_user;
88
89 static int change_dir __P((struct nameidata *ndp, struct proc *p));
90 static void checkdirs __P((struct vnode *olddp));
91
92 /* counts number of mount and unmount operations */
93 unsigned int vfs_nummntops=0;
94
95 /*
96 * Virtual File System System Calls
97 */
98
99 /*
100 * Mount a file system.
101 */
102 struct mount_args {
103 char *type;
104 char *path;
105 int flags;
106 caddr_t data;
107 };
108 /* ARGSUSED */
109 int
110 mount(p, uap, retval)
111 struct proc *p;
112 register struct mount_args *uap;
113 register_t *retval;
114 {
115 struct vnode *vp;
116 struct mount *mp;
117 struct vfsconf *vfsp;
118 int error, flag;
119 struct vattr va;
120 u_long fstypenum;
121 struct nameidata nd;
122 char fstypename[MFSNAMELEN];
123 size_t dummy=0;
124 /*
125 * Get vnode to be covered
126 */
127 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
128 uap->path, p);
129 if (error = namei(&nd))
130 return (error);
131 vp = nd.ni_vp;
132
133 if ((vp->v_flag & VROOT) &&
134 (vp->v_mount->mnt_flag & MNT_ROOTFS))
135 uap->flags |= MNT_UPDATE;
136
137 if (uap->flags & MNT_UPDATE) {
138 if ((vp->v_flag & VROOT) == 0) {
139 vput(vp);
140 return (EINVAL);
141 }
142 mp = vp->v_mount;
143 flag = mp->mnt_flag;
144 /*
145 * We only allow the filesystem to be reloaded if it
146 * is currently mounted read-only.
147 */
148 if ((uap->flags & MNT_RELOAD) &&
149 ((mp->mnt_flag & MNT_RDONLY) == 0)) {
150 vput(vp);
151 return (EOPNOTSUPP); /* Needs translation */
152 }
153 mp->mnt_flag |=
154 uap->flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
155 /*
156 * Only root, or the user that did the original mount is
157 * permitted to update it.
158 */
159 if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid &&
160 (error = suser(p->p_ucred, &p->p_acflag))) {
161 vput(vp);
162 return (error);
163 }
164 /*
165 * Do not allow NFS export by non-root users. FOr non-root
166 * users, silently enforce MNT_NOSUID and MNT_NODEV, and
167 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
168 */
169 if (p->p_ucred->cr_uid != 0) {
170 if (uap->flags & MNT_EXPORTED) {
171 vput(vp);
172 return (EPERM);
173 }
174 uap->flags |= MNT_NOSUID | MNT_NODEV;
175 if (flag & MNT_NOEXEC)
176 uap->flags |= MNT_NOEXEC;
177 }
178 if (vfs_busy(mp, LK_NOWAIT, 0, p)) {
179 vput(vp);
180 return (EBUSY);
181 }
182 VOP_UNLOCK(vp, 0, p);
183 goto update;
184 }
185 /*
186 * If the user is not root, ensure that they own the directory
187 * onto which we are attempting to mount.
188 */
189 if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) ||
190 (va.va_uid != p->p_ucred->cr_uid &&
191 (error = suser(p->p_ucred, &p->p_acflag)))) {
192 vput(vp);
193 return (error);
194 }
195 /*
196 * Do not allow NFS export by non-root users. FOr non-root
197 * users, silently enforce MNT_NOSUID and MNT_NODEV, and
198 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
199 */
200 if (p->p_ucred->cr_uid != 0) {
201 if (uap->flags & MNT_EXPORTED) {
202 vput(vp);
203 return (EPERM);
204 }
205 uap->flags |= MNT_NOSUID | MNT_NODEV;
206 if (vp->v_mount->mnt_flag & MNT_NOEXEC)
207 uap->flags |= MNT_NOEXEC;
208 }
209 if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) {
210 vput(vp);
211 return (error);
212 }
213 if (vp->v_type != VDIR) {
214 vput(vp);
215 return (ENOTDIR);
216 }
217 #if COMPAT_43
218 /*
219 * Historically filesystem types were identified by number. If we
220 * get an integer for the filesystem type instead of a string, we
221 * check to see if it matches one of the historic filesystem types.
222 */
223 fstypenum = (u_long)uap->type;
224 if (fstypenum < maxvfsconf) {
225 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
226 if (vfsp->vfc_typenum == fstypenum)
227 break;
228 if (vfsp == NULL) {
229 vput(vp);
230 return (ENODEV);
231 }
232 strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN);
233 } else
234 #endif /* COMPAT_43 */
235 if (error = copyinstr(uap->type, fstypename, MFSNAMELEN, &dummy)) {
236 vput(vp);
237 return (error);
238 }
239 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
240 if (!strcmp(vfsp->vfc_name, fstypename))
241 break;
242 if (vfsp == NULL) {
243 vput(vp);
244 return (ENODEV);
245 }
246 simple_lock(&vp->v_interlock);
247 if (ISSET(vp->v_flag, VMOUNT) && (vp->v_mountedhere != NULL)) {
248 simple_unlock(&vp->v_interlock);
249 vput(vp);
250 return (EBUSY);
251 }
252 SET(vp->v_flag, VMOUNT);
253 simple_unlock(&vp->v_interlock);
254
255 /*
256 * Allocate and initialize the filesystem.
257 */
258 mp = (struct mount *)_MALLOC_ZONE((u_long)sizeof(struct mount),
259 M_MOUNT, M_WAITOK);
260 bzero((char *)mp, (u_long)sizeof(struct mount));
261 lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0);
262 (void)vfs_busy(mp, LK_NOWAIT, 0, p);
263 mp->mnt_op = vfsp->vfc_vfsops;
264 mp->mnt_vfc = vfsp;
265 vfsp->vfc_refcount++;
266 mp->mnt_stat.f_type = vfsp->vfc_typenum;
267 mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
268 strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
269 mp->mnt_vnodecovered = vp;
270 mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
271 VOP_UNLOCK(vp, 0, p);
272
273 update:
274 /*
275 * Set the mount level flags.
276 */
277 if (uap->flags & MNT_RDONLY)
278 mp->mnt_flag |= MNT_RDONLY;
279 else if (mp->mnt_flag & MNT_RDONLY)
280 mp->mnt_kern_flag |= MNTK_WANTRDWR;
281 mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
282 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_UNKNOWNPERMISSIONS);
283 mp->mnt_flag |= uap->flags & (MNT_NOSUID | MNT_NOEXEC |
284 MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_UNKNOWNPERMISSIONS);
285 /*
286 * Mount the filesystem.
287 */
288 error = VFS_MOUNT(mp, uap->path, uap->data, &nd, p);
289 if (mp->mnt_flag & MNT_UPDATE) {
290 vrele(vp);
291 if (mp->mnt_kern_flag & MNTK_WANTRDWR)
292 mp->mnt_flag &= ~MNT_RDONLY;
293 mp->mnt_flag &=~
294 (MNT_UPDATE | MNT_RELOAD | MNT_FORCE);
295 mp->mnt_kern_flag &=~ MNTK_WANTRDWR;
296 if (error)
297 mp->mnt_flag = flag;
298 vfs_unbusy(mp, p);
299 return (error);
300 }
301 /*
302 * Put the new filesystem on the mount list after root.
303 */
304 cache_purge(vp);
305 if (!error) {
306 simple_lock(&vp->v_interlock);
307 CLR(vp->v_flag, VMOUNT);
308 vp->v_mountedhere =mp;
309 simple_unlock(&vp->v_interlock);
310 simple_lock(&mountlist_slock);
311 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
312 simple_unlock(&mountlist_slock);
313 checkdirs(vp);
314 VOP_UNLOCK(vp, 0, p);
315 vfs_unbusy(mp, p);
316 if (error = VFS_START(mp, 0, p))
317 vrele(vp);
318
319 /* increment the operations count */
320 if (!error)
321 vfs_nummntops++;
322 } else {
323 simple_lock(&vp->v_interlock);
324 CLR(vp->v_flag, VMOUNT);
325 simple_unlock(&vp->v_interlock);
326 mp->mnt_vfc->vfc_refcount--;
327 vfs_unbusy(mp, p);
328 _FREE_ZONE((caddr_t)mp, sizeof (struct mount), M_MOUNT);
329 vput(vp);
330 }
331 return (error);
332 }
333
334 /*
335 * Scan all active processes to see if any of them have a current
336 * or root directory onto which the new filesystem has just been
337 * mounted. If so, replace them with the new mount point.
338 */
339 static void
340 checkdirs(olddp)
341 struct vnode *olddp;
342 {
343 struct filedesc *fdp;
344 struct vnode *newdp;
345 struct proc *p;
346
347 if (olddp->v_usecount == 1)
348 return;
349 if (VFS_ROOT(olddp->v_mountedhere, &newdp))
350 panic("mount: lost mount");
351 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
352 fdp = p->p_fd;
353 if (fdp->fd_cdir == olddp) {
354 vrele(fdp->fd_cdir);
355 VREF(newdp);
356 fdp->fd_cdir = newdp;
357 }
358 if (fdp->fd_rdir == olddp) {
359 vrele(fdp->fd_rdir);
360 VREF(newdp);
361 fdp->fd_rdir = newdp;
362 }
363 }
364 if (rootvnode == olddp) {
365 vrele(rootvnode);
366 VREF(newdp);
367 rootvnode = newdp;
368 }
369 vput(newdp);
370 }
371
372 /*
373 * Unmount a file system.
374 *
375 * Note: unmount takes a path to the vnode mounted on as argument,
376 * not special file (as before).
377 */
378 struct unmount_args {
379 char *path;
380 int flags;
381 };
382 /* ARGSUSED */
383 int
384 unmount(p, uap, retval)
385 struct proc *p;
386 register struct unmount_args *uap;
387 register_t *retval;
388 {
389 register struct vnode *vp;
390 struct mount *mp;
391 int error;
392 struct nameidata nd;
393
394 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
395 uap->path, p);
396 if (error = namei(&nd))
397 return (error);
398 vp = nd.ni_vp;
399 mp = vp->v_mount;
400
401 /*
402 * Only root, or the user that did the original mount is
403 * permitted to unmount this filesystem.
404 */
405 if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) &&
406 (error = suser(p->p_ucred, &p->p_acflag))) {
407 vput(vp);
408 return (error);
409 }
410
411 /*
412 * Don't allow unmounting the root file system.
413 */
414 if (mp->mnt_flag & MNT_ROOTFS) {
415 vput(vp);
416 return (EBUSY); /* the root is always busy */
417 }
418
419 /*
420 * Must be the root of the filesystem
421 */
422 if ((vp->v_flag & VROOT) == 0) {
423 vput(vp);
424 return (EINVAL);
425 }
426 vput(vp);
427 return (dounmount(mp, uap->flags, p));
428 }
429
430 /*
431 * Do the actual file system unmount.
432 */
433 int
434 dounmount(mp, flags, p)
435 register struct mount *mp;
436 int flags;
437 struct proc *p;
438 {
439 struct vnode *coveredvp;
440 int error;
441
442 simple_lock(&mountlist_slock);
443 mp->mnt_kern_flag |= MNTK_UNMOUNT;
444 lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_slock, p);
445 mp->mnt_flag &=~ MNT_ASYNC;
446 ubc_umount(mp); /* release cached vnodes */
447 cache_purgevfs(mp); /* remove cache entries for this file sys */
448 if (((mp->mnt_flag & MNT_RDONLY) ||
449 (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) ||
450 (flags & MNT_FORCE))
451 error = VFS_UNMOUNT(mp, flags, p);
452 simple_lock(&mountlist_slock);
453 if (error) {
454 mp->mnt_kern_flag &= ~MNTK_UNMOUNT;
455 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK | LK_REENABLE,
456 &mountlist_slock, p);
457 goto out;
458 }
459
460 /* increment the operations count */
461 if (!error)
462 vfs_nummntops++;
463 CIRCLEQ_REMOVE(&mountlist, mp, mnt_list);
464 if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) {
465 coveredvp->v_mountedhere = (struct mount *)0;
466 simple_unlock(&mountlist_slock);
467 vrele(coveredvp);
468 simple_lock(&mountlist_slock);
469 }
470 mp->mnt_vfc->vfc_refcount--;
471 if (mp->mnt_vnodelist.lh_first != NULL) {
472 panic("unmount: dangling vnode");
473 }
474 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock, p);
475 out:
476 if (mp->mnt_kern_flag & MNTK_MWAIT)
477 wakeup((caddr_t)mp);
478 if (!error)
479 _FREE_ZONE((caddr_t)mp, sizeof (struct mount), M_MOUNT);
480 return (error);
481 }
482
483 /*
484 * Sync each mounted filesystem.
485 */
486 #if DIAGNOSTIC
487 int syncprt = 0;
488 struct ctldebug debug0 = { "syncprt", &syncprt };
489 #endif
490
491 struct sync_args {
492 int dummy;
493 };
494 int print_vmpage_stat=0;
495
496 /* ARGSUSED */
497 int
498 sync(p, uap, retval)
499 struct proc *p;
500 struct sync_args *uap;
501 register_t *retval;
502 {
503 register struct mount *mp, *nmp;
504 int asyncflag;
505
506 simple_lock(&mountlist_slock);
507 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
508 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
509 nmp = mp->mnt_list.cqe_next;
510 continue;
511 }
512 if ((mp->mnt_flag & MNT_RDONLY) == 0) {
513 asyncflag = mp->mnt_flag & MNT_ASYNC;
514 mp->mnt_flag &= ~MNT_ASYNC;
515 VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
516 if (asyncflag)
517 mp->mnt_flag |= MNT_ASYNC;
518 }
519 simple_lock(&mountlist_slock);
520 nmp = mp->mnt_list.cqe_next;
521 vfs_unbusy(mp, p);
522 }
523 simple_unlock(&mountlist_slock);
524
525 {
526 extern void vm_countdirtypages(void);
527 extern unsigned int vp_pagein, vp_pgodirty, vp_pgoclean;
528 extern unsigned int dp_pgins, dp_pgouts;
529 if(print_vmpage_stat) {
530 vm_countdirtypages();
531 printf("VP: %d: %d: %d: %d: %d\n", vp_pgodirty, vp_pgoclean, vp_pagein, dp_pgins, dp_pgouts);
532 }
533 }
534 #if DIAGNOSTIC
535 if (syncprt)
536 vfs_bufstats();
537 #endif /* DIAGNOSTIC */
538 return (0);
539 }
540
541 /*
542 * Change filesystem quotas.
543 */
544 struct quotactl_args {
545 char *path;
546 int cmd;
547 int uid;
548 caddr_t arg;
549 };
550 /* ARGSUSED */
551 int
552 quotactl(p, uap, retval)
553 struct proc *p;
554 register struct quotactl_args *uap;
555 register_t *retval;
556 {
557 register struct mount *mp;
558 int error;
559 struct nameidata nd;
560
561 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
562 if (error = namei(&nd))
563 return (error);
564 mp = nd.ni_vp->v_mount;
565 vrele(nd.ni_vp);
566 return (VFS_QUOTACTL(mp, uap->cmd, uap->uid,
567 uap->arg, p));
568 }
569
570 /*
571 * Get filesystem statistics.
572 */
573 struct statfs_args {
574 char *path;
575 struct statfs *buf;
576 };
577 /* ARGSUSED */
578 int
579 statfs(p, uap, retval)
580 struct proc *p;
581 register struct statfs_args *uap;
582 register_t *retval;
583 {
584 register struct mount *mp;
585 register struct statfs *sp;
586 int error;
587 struct nameidata nd;
588
589 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
590 if (error = namei(&nd))
591 return (error);
592 mp = nd.ni_vp->v_mount;
593 sp = &mp->mnt_stat;
594 vrele(nd.ni_vp);
595 if (error = VFS_STATFS(mp, sp, p))
596 return (error);
597 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
598 /* return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); */
599 return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)-sizeof(sp->f_reserved3)-sizeof(sp->f_reserved4)));
600 }
601
602 /*
603 * Get filesystem statistics.
604 */
605 struct fstatfs_args {
606 int fd;
607 struct statfs *buf;
608 };
609 /* ARGSUSED */
610 int
611 fstatfs(p, uap, retval)
612 struct proc *p;
613 register struct fstatfs_args *uap;
614 register_t *retval;
615 {
616 struct file *fp;
617 struct mount *mp;
618 register struct statfs *sp;
619 int error;
620
621 if (error = getvnode(p, uap->fd, &fp))
622 return (error);
623 mp = ((struct vnode *)fp->f_data)->v_mount;
624 if (!mp)
625 return (EBADF);
626 sp = &mp->mnt_stat;
627 if (error = VFS_STATFS(mp, sp, p))
628 return (error);
629 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
630 /* return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp))); */
631 return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)-sizeof(sp->f_reserved3)-sizeof(sp->f_reserved4)));
632 }
633
634 /*
635 * Get statistics on all filesystems.
636 */
637 struct getfsstat_args {
638 struct statfs *buf;
639 long bufsize;
640 int flags;
641 };
642 int
643 getfsstat(p, uap, retval)
644 struct proc *p;
645 register struct getfsstat_args *uap;
646 register_t *retval;
647 {
648 register struct mount *mp, *nmp;
649 register struct statfs *sp;
650 caddr_t sfsp;
651 long count, maxcount, error;
652
653 maxcount = uap->bufsize / sizeof(struct statfs);
654 sfsp = (caddr_t)uap->buf;
655 count = 0;
656 simple_lock(&mountlist_slock);
657 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
658 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
659 nmp = mp->mnt_list.cqe_next;
660 continue;
661 }
662 if (sfsp && count < maxcount) {
663 sp = &mp->mnt_stat;
664 /*
665 * If MNT_NOWAIT is specified, do not refresh the
666 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
667 */
668 if (((uap->flags & MNT_NOWAIT) == 0 ||
669 (uap->flags & MNT_WAIT)) &&
670 (error = VFS_STATFS(mp, sp, p))) {
671 simple_lock(&mountlist_slock);
672 nmp = mp->mnt_list.cqe_next;
673 vfs_unbusy(mp, p);
674 continue;
675 }
676 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
677 if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
678 return (error);
679 sfsp += sizeof(*sp);
680 }
681 count++;
682 simple_lock(&mountlist_slock);
683 nmp = mp->mnt_list.cqe_next;
684 vfs_unbusy(mp, p);
685 }
686 simple_unlock(&mountlist_slock);
687 if (sfsp && count > maxcount)
688 *retval = maxcount;
689 else
690 *retval = count;
691 return (0);
692 }
693
694 #if COMPAT_GETFSSTAT
695 ogetfsstat(p, uap, retval)
696 struct proc *p;
697 register struct getfsstat_args *uap;
698 register_t *retval;
699 {
700 register struct mount *mp, *nmp;
701 register struct statfs *sp;
702 caddr_t sfsp;
703 long count, maxcount, error;
704
705 maxcount = uap->bufsize / (sizeof(struct statfs) - sizeof(sp->f_reserved4));
706 sfsp = (caddr_t)uap->buf;
707 count = 0;
708 simple_lock(&mountlist_slock);
709 for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
710 if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
711 nmp = mp->mnt_list.cqe_next;
712 continue;
713 }
714 if (sfsp && count < maxcount) {
715 sp = &mp->mnt_stat;
716 /*
717 * If MNT_NOWAIT is specified, do not refresh the
718 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
719 */
720 if (((uap->flags & MNT_NOWAIT) == 0 ||
721 (uap->flags & MNT_WAIT)) &&
722 (error = VFS_STATFS(mp, sp, p))) {
723 simple_lock(&mountlist_slock);
724 nmp = mp->mnt_list.cqe_next;
725 vfs_unbusy(mp, p);
726 continue;
727 }
728 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
729 if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp) - sizeof(sp->f_reserved3) - sizeof(sp->f_reserved4)))
730 return (error);
731 sfsp += sizeof(*sp) - sizeof(sp->f_reserved4);
732 }
733 count++;
734 simple_lock(&mountlist_slock);
735 nmp = mp->mnt_list.cqe_next;
736 vfs_unbusy(mp, p);
737 }
738 simple_unlock(&mountlist_slock);
739 if (sfsp && count > maxcount)
740 *retval = maxcount;
741 else
742 *retval = count;
743 return (0);
744 }
745 #endif
746
747 /*
748 * Change current working directory to a given file descriptor.
749 */
750 struct fchdir_args {
751 int fd;
752 };
753 /* ARGSUSED */
754 int
755 fchdir(p, uap, retval)
756 struct proc *p;
757 struct fchdir_args *uap;
758 register_t *retval;
759 {
760 register struct filedesc *fdp = p->p_fd;
761 struct vnode *vp, *tdp;
762 struct mount *mp;
763 struct file *fp;
764 int error;
765
766 if (error = getvnode(p, uap->fd, &fp))
767 return (error);
768 vp = (struct vnode *)fp->f_data;
769 VREF(vp);
770 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
771 if (vp->v_type != VDIR)
772 error = ENOTDIR;
773 else
774 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
775 while (!error && (mp = vp->v_mountedhere) != NULL) {
776 if (vfs_busy(mp, 0, 0, p))
777 continue;
778 error = VFS_ROOT(mp, &tdp);
779 vfs_unbusy(mp, p);
780 if (error)
781 break;
782 vput(vp);
783 vp = tdp;
784 }
785 if (error) {
786 vput(vp);
787 return (error);
788 }
789 VOP_UNLOCK(vp, 0, p);
790 vrele(fdp->fd_cdir);
791 fdp->fd_cdir = vp;
792 return (0);
793 }
794
795 /*
796 * Change current working directory (``.'').
797 */
798 struct chdir_args {
799 char *path;
800 };
801 /* ARGSUSED */
802 int
803 chdir(p, uap, retval)
804 struct proc *p;
805 struct chdir_args *uap;
806 register_t *retval;
807 {
808 register struct filedesc *fdp = p->p_fd;
809 int error;
810 struct nameidata nd;
811
812 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
813 uap->path, p);
814 if (error = change_dir(&nd, p))
815 return (error);
816 vrele(fdp->fd_cdir);
817 fdp->fd_cdir = nd.ni_vp;
818 return (0);
819 }
820
821 /*
822 * Change notion of root (``/'') directory.
823 */
824 struct chroot_args {
825 char *path;
826 };
827 /* ARGSUSED */
828 int
829 chroot(p, uap, retval)
830 struct proc *p;
831 struct chroot_args *uap;
832 register_t *retval;
833 {
834 register struct filedesc *fdp = p->p_fd;
835 int error;
836 struct nameidata nd;
837
838 if (error = suser(p->p_ucred, &p->p_acflag))
839 return (error);
840
841 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
842 uap->path, p);
843 if (error = change_dir(&nd, p))
844 return (error);
845
846 if(error = clone_system_shared_regions()) {
847 vrele(nd.ni_vp);
848 return (error);
849 }
850
851 if (fdp->fd_rdir != NULL)
852 vrele(fdp->fd_rdir);
853 fdp->fd_rdir = nd.ni_vp;
854 return (0);
855 }
856
857 /*
858 * Common routine for chroot and chdir.
859 */
860 static int
861 change_dir(ndp, p)
862 register struct nameidata *ndp;
863 struct proc *p;
864 {
865 struct vnode *vp;
866 int error;
867
868 if (error = namei(ndp))
869 return (error);
870 vp = ndp->ni_vp;
871 if (vp->v_type != VDIR)
872 error = ENOTDIR;
873 else
874 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
875 if (error)
876 vput(vp);
877 else
878 VOP_UNLOCK(vp, 0, p);
879 return (error);
880 }
881
882 /*
883 * Check permissions, allocate an open file structure,
884 * and call the device open routine if any.
885 */
886 struct open_args {
887 char *path;
888 int flags;
889 int mode;
890 };
891 int
892 open(p, uap, retval)
893 struct proc *p;
894 register struct open_args *uap;
895 register_t *retval;
896 {
897 register struct filedesc *fdp = p->p_fd;
898 register struct file *fp;
899 register struct vnode *vp;
900 int flags, cmode;
901 struct file *nfp;
902 int type, indx, error;
903 struct flock lf;
904 struct nameidata nd;
905 extern struct fileops vnops;
906
907 /* CERT advisory patch applied from FreeBSD */
908 /* Refer to Radar#2262895 A. Ramesh */
909 flags = FFLAGS(uap->flags);
910 if ((flags & (FREAD | FWRITE))==0)
911 return(EINVAL);
912 if (error = falloc(p, &nfp, &indx))
913 return (error);
914 fp = nfp;
915 cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
916 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
917 p->p_dupfd = -indx - 1; /* XXX check for fdopen */
918 if (error = vn_open(&nd, flags, cmode)) {
919 ffree(fp);
920 if ((error == ENODEV || error == ENXIO) &&
921 p->p_dupfd >= 0 && /* XXX from fdopen */
922 (error =
923 dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
924 *retval = indx;
925 return (0);
926 }
927 if (error == ERESTART)
928 error = EINTR;
929 fdrelse(p, indx);
930 return (error);
931 }
932 p->p_dupfd = 0;
933 vp = nd.ni_vp;
934 fp->f_flag = flags & FMASK;
935 fp->f_type = DTYPE_VNODE;
936 fp->f_ops = &vnops;
937 fp->f_data = (caddr_t)vp;
938 if (flags & (O_EXLOCK | O_SHLOCK)) {
939 lf.l_whence = SEEK_SET;
940 lf.l_start = 0;
941 lf.l_len = 0;
942 if (flags & O_EXLOCK)
943 lf.l_type = F_WRLCK;
944 else
945 lf.l_type = F_RDLCK;
946 type = F_FLOCK;
947 if ((flags & FNONBLOCK) == 0)
948 type |= F_WAIT;
949 VOP_UNLOCK(vp, 0, p);
950 if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
951 (void) vn_close(vp, fp->f_flag, fp->f_cred, p);
952 ffree(fp);
953 fdrelse(p, indx);
954 return (error);
955 }
956 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
957 fp->f_flag |= FHASLOCK;
958 }
959 VOP_UNLOCK(vp, 0, p);
960 *fdflags(p, indx) &= ~UF_RESERVED;
961 *retval = indx;
962 return (0);
963 }
964
965 #if COMPAT_43
966 /*
967 * Create a file.
968 */
969 struct ocreat_args {
970 char *path;
971 int mode;
972 };
973 int
974 ocreat(p, uap, retval)
975 struct proc *p;
976 register struct ocreat_args *uap;
977 register_t *retval;
978 {
979 struct open_args nuap;
980
981 nuap.path = uap->path;
982 nuap.mode = uap->mode;
983 nuap.flags = O_WRONLY | O_CREAT | O_TRUNC;
984 return (open(p, &nuap, retval));
985 }
986 #endif /* COMPAT_43 */
987
988 /*
989 * Create a special file.
990 */
991 struct mknod_args {
992 char *path;
993 int mode;
994 int dev;
995 };
996 /* ARGSUSED */
997 int
998 mknod(p, uap, retval)
999 struct proc *p;
1000 register struct mknod_args *uap;
1001 register_t *retval;
1002 {
1003 register struct vnode *vp;
1004 struct vattr vattr;
1005 int error;
1006 int whiteout;
1007 struct nameidata nd;
1008
1009 if (error = suser(p->p_ucred, &p->p_acflag))
1010 return (error);
1011 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
1012 if (error = namei(&nd))
1013 return (error);
1014 vp = nd.ni_vp;
1015 if (vp != NULL)
1016 error = EEXIST;
1017 else {
1018 VATTR_NULL(&vattr);
1019 vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
1020 vattr.va_rdev = uap->dev;
1021 whiteout = 0;
1022
1023 switch (uap->mode & S_IFMT) {
1024 case S_IFMT: /* used by badsect to flag bad sectors */
1025 vattr.va_type = VBAD;
1026 break;
1027 case S_IFCHR:
1028 vattr.va_type = VCHR;
1029 break;
1030 case S_IFBLK:
1031 vattr.va_type = VBLK;
1032 break;
1033 case S_IFWHT:
1034 whiteout = 1;
1035 break;
1036 default:
1037 error = EINVAL;
1038 break;
1039 }
1040 }
1041 if (!error) {
1042 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1043 if (whiteout) {
1044 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
1045 if (error)
1046 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1047 vput(nd.ni_dvp);
1048 } else {
1049 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
1050 &nd.ni_cnd, &vattr);
1051 }
1052 } else {
1053 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1054 if (nd.ni_dvp == vp)
1055 vrele(nd.ni_dvp);
1056 else
1057 vput(nd.ni_dvp);
1058 if (vp)
1059 vrele(vp);
1060 }
1061 return (error);
1062 }
1063
1064 /*
1065 * Create a named pipe.
1066 */
1067 struct mkfifo_args {
1068 char *path;
1069 int mode;
1070 };
1071 /* ARGSUSED */
1072 int
1073 mkfifo(p, uap, retval)
1074 struct proc *p;
1075 register struct mkfifo_args *uap;
1076 register_t *retval;
1077 {
1078 struct vattr vattr;
1079 int error;
1080 struct nameidata nd;
1081
1082 #if !FIFO
1083 return (EOPNOTSUPP);
1084 #else
1085 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
1086 if (error = namei(&nd))
1087 return (error);
1088 if (nd.ni_vp != NULL) {
1089 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1090 if (nd.ni_dvp == nd.ni_vp)
1091 vrele(nd.ni_dvp);
1092 else
1093 vput(nd.ni_dvp);
1094 vrele(nd.ni_vp);
1095 return (EEXIST);
1096 }
1097 VATTR_NULL(&vattr);
1098 vattr.va_type = VFIFO;
1099 vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
1100 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1101 return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
1102 #endif /* FIFO */
1103 }
1104
1105 /*
1106 * Make a hard file link.
1107 */
1108 struct link_args {
1109 char *path;
1110 char *link;
1111 };
1112 /* ARGSUSED */
1113 int
1114 link(p, uap, retval)
1115 struct proc *p;
1116 register struct link_args *uap;
1117 register_t *retval;
1118 {
1119 register struct vnode *vp;
1120 struct nameidata nd;
1121 int error;
1122
1123 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
1124 if (error = namei(&nd))
1125 return (error);
1126 vp = nd.ni_vp;
1127 if (vp->v_type == VDIR)
1128 error = EPERM; /* POSIX */
1129 else {
1130 nd.ni_cnd.cn_nameiop = CREATE;
1131 nd.ni_cnd.cn_flags = LOCKPARENT;
1132 nd.ni_dirp = uap->link;
1133 if ((error = namei(&nd)) == 0) {
1134 if (nd.ni_vp != NULL)
1135 error = EEXIST;
1136 if (!error) {
1137 VOP_LEASE(nd.ni_dvp, p, p->p_ucred,
1138 LEASE_WRITE);
1139 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1140 error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd);
1141 } else {
1142 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1143 if (nd.ni_dvp == nd.ni_vp)
1144 vrele(nd.ni_dvp);
1145 else
1146 vput(nd.ni_dvp);
1147 if (nd.ni_vp)
1148 vrele(nd.ni_vp);
1149 }
1150 }
1151 }
1152 vrele(vp);
1153 return (error);
1154 }
1155
1156 /*
1157 * Make a symbolic link.
1158 */
1159 struct symlink_args {
1160 char *path;
1161 char *link;
1162 };
1163 /* ARGSUSED */
1164 int
1165 symlink(p, uap, retval)
1166 struct proc *p;
1167 register struct symlink_args *uap;
1168 register_t *retval;
1169 {
1170 struct vattr vattr;
1171 char *path;
1172 int error;
1173 struct nameidata nd;
1174 size_t dummy=0;
1175 MALLOC_ZONE(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
1176 if (error = copyinstr(uap->path, path, MAXPATHLEN, &dummy))
1177 goto out;
1178 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p);
1179 if (error = namei(&nd))
1180 goto out;
1181 if (nd.ni_vp) {
1182 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1183 if (nd.ni_dvp == nd.ni_vp)
1184 vrele(nd.ni_dvp);
1185 else
1186 vput(nd.ni_dvp);
1187 vrele(nd.ni_vp);
1188 error = EEXIST;
1189 goto out;
1190 }
1191 VATTR_NULL(&vattr);
1192 vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
1193 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1194 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1195 out:
1196 FREE_ZONE(path, MAXPATHLEN, M_NAMEI);
1197 return (error);
1198 }
1199
1200 /*
1201 * Delete a whiteout from the filesystem.
1202 */
1203 struct undelete_args {
1204 char *path;
1205 };
1206 /* ARGSUSED */
1207 int
1208 undelete(p, uap, retval)
1209 struct proc *p;
1210 register struct undelete_args *uap;
1211 register_t *retval;
1212 {
1213 int error;
1214 struct nameidata nd;
1215
1216 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
1217 uap->path, p);
1218 error = namei(&nd);
1219 if (error)
1220 return (error);
1221
1222 if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
1223 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1224 if (nd.ni_dvp == nd.ni_vp)
1225 vrele(nd.ni_dvp);
1226 else
1227 vput(nd.ni_dvp);
1228 if (nd.ni_vp)
1229 vrele(nd.ni_vp);
1230 return (EEXIST);
1231 }
1232
1233 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1234 if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE))
1235 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1236 vput(nd.ni_dvp);
1237 return (error);
1238 }
1239
1240 /*
1241 * Delete a name from the filesystem.
1242 */
1243 struct unlink_args {
1244 char *path;
1245 };
1246 /* ARGSUSED */
1247 static int
1248 _unlink(p, uap, retval, nodelbusy)
1249 struct proc *p;
1250 struct unlink_args *uap;
1251 register_t *retval;
1252 int nodelbusy;
1253 {
1254 register struct vnode *vp;
1255 int error;
1256 struct nameidata nd;
1257
1258 NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
1259 /* with hfs semantics, busy files cannot be deleted */
1260 if (nodelbusy)
1261 nd.ni_cnd.cn_flags |= NODELETEBUSY;
1262 if (error = namei(&nd))
1263 return (error);
1264 vp = nd.ni_vp;
1265 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1266 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1267
1268 if (vp->v_type == VDIR)
1269 error = EPERM; /* POSIX */
1270 else {
1271 /*
1272 * The root of a mounted filesystem cannot be deleted.
1273 *
1274 * XXX: can this only be a VDIR case?
1275 */
1276 if (vp->v_flag & VROOT)
1277 error = EBUSY;
1278 }
1279
1280 if (!error) {
1281 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1282 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1283 } else {
1284 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1285 if (nd.ni_dvp == vp)
1286 vrele(nd.ni_dvp);
1287 else
1288 vput(nd.ni_dvp);
1289 if (vp != NULLVP)
1290 vput(vp);
1291 }
1292 return (error);
1293 }
1294
1295 /*
1296 * Delete a name from the filesystem using POSIX semantics.
1297 */
1298 int
1299 unlink(p, uap, retval)
1300 struct proc *p;
1301 struct unlink_args *uap;
1302 register_t *retval;
1303 {
1304 return _unlink(p, uap, retval, 0);
1305 }
1306
1307 /*
1308 * Delete a name from the filesystem using HFS semantics.
1309 */
1310 int
1311 delete(p, uap, retval)
1312 struct proc *p;
1313 struct unlink_args *uap;
1314 register_t *retval;
1315 {
1316 return _unlink(p, uap, retval, 1);
1317 }
1318
1319 /*
1320 * Reposition read/write file offset.
1321 */
1322 struct lseek_args {
1323 int fd;
1324 #ifdef DOUBLE_ALIGN_PARAMS
1325 int pad;
1326 #endif
1327 off_t offset;
1328 int whence;
1329 };
1330 int
1331 lseek(p, uap, retval)
1332 struct proc *p;
1333 register struct lseek_args *uap;
1334 register_t *retval;
1335 {
1336 struct ucred *cred = p->p_ucred;
1337 struct file *fp;
1338 struct vattr vattr;
1339 int error;
1340
1341 if (error = fdgetf(p, uap->fd, &fp))
1342 return (error);
1343 if (fp->f_type != DTYPE_VNODE)
1344 return (ESPIPE);
1345 switch (uap->whence) {
1346 case L_INCR:
1347 fp->f_offset += uap->offset;
1348 break;
1349 case L_XTND:
1350 if (error =
1351 VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p))
1352 return (error);
1353 fp->f_offset = uap->offset + vattr.va_size;
1354 break;
1355 case L_SET:
1356 fp->f_offset = uap->offset;
1357 break;
1358 default:
1359 return (EINVAL);
1360 }
1361 *(off_t *)retval = fp->f_offset;
1362 return (0);
1363 }
1364
1365 #if COMPAT_43
1366 /*
1367 * Reposition read/write file offset.
1368 */
1369 struct olseek_args {
1370 int fd;
1371 long offset;
1372 int whence;
1373 };
1374 int
1375 olseek(p, uap, retval)
1376 struct proc *p;
1377 register struct olseek_args *uap;
1378 register_t *retval;
1379 {
1380 struct lseek_args /* {
1381 syscallarg(int) fd;
1382 #ifdef DOUBLE_ALIGN_PARAMS
1383 syscallarg(int) pad;
1384 #endif
1385 syscallarg(off_t) offset;
1386 syscallarg(int) whence;
1387 } */ nuap;
1388 off_t qret;
1389 int error;
1390
1391 nuap.fd = uap->fd;
1392 nuap.offset = uap->offset;
1393 nuap.whence = uap->whence;
1394 error = lseek(p, &nuap, &qret);
1395 *(long *)retval = qret;
1396 return (error);
1397 }
1398 #endif /* COMPAT_43 */
1399
1400 /*
1401 * Check access permissions.
1402 */
1403 struct access_args {
1404 char *path;
1405 int flags;
1406 };
1407 int
1408 access(p, uap, retval)
1409 struct proc *p;
1410 register struct access_args *uap;
1411 register_t *retval;
1412 {
1413 register struct ucred *cred = p->p_ucred;
1414 register struct vnode *vp;
1415 int error, flags, t_gid, t_uid;
1416 struct nameidata nd;
1417
1418 t_uid = cred->cr_uid;
1419 t_gid = cred->cr_groups[0];
1420 cred->cr_uid = p->p_cred->p_ruid;
1421 cred->cr_groups[0] = p->p_cred->p_rgid;
1422 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1423 uap->path, p);
1424 if (error = namei(&nd))
1425 goto out1;
1426 vp = nd.ni_vp;
1427
1428 /* Flags == 0 means only check for existence. */
1429 if (uap->flags) {
1430 flags = 0;
1431 if (uap->flags & R_OK)
1432 flags |= VREAD;
1433 if (uap->flags & W_OK)
1434 flags |= VWRITE;
1435 if (uap->flags & X_OK)
1436 flags |= VEXEC;
1437 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
1438 error = VOP_ACCESS(vp, flags, cred, p);
1439 }
1440 vput(vp);
1441 out1:
1442 cred->cr_uid = t_uid;
1443 cred->cr_groups[0] = t_gid;
1444 return (error);
1445 }
1446
1447 #if COMPAT_43
1448 /*
1449 * Get file status; this version follows links.
1450 */
1451 struct ostat_args {
1452 char *path;
1453 struct ostat *ub;
1454 };
1455 /* ARGSUSED */
1456 int
1457 ostat(p, uap, retval)
1458 struct proc *p;
1459 register struct ostat_args *uap;
1460 register_t *retval;
1461 {
1462 struct stat sb;
1463 struct ostat osb;
1464 int error;
1465 struct nameidata nd;
1466
1467 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1468 uap->path, p);
1469 if (error = namei(&nd))
1470 return (error);
1471 error = vn_stat(nd.ni_vp, &sb, p);
1472 vput(nd.ni_vp);
1473 if (error)
1474 return (error);
1475 cvtstat(&sb, &osb);
1476 error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
1477 return (error);
1478 }
1479
1480 /*
1481 * Get file status; this version does not follow links.
1482 */
1483 struct olstat_args {
1484 char *path;
1485 struct ostat *ub;
1486 };
1487 /* ARGSUSED */
1488 int
1489 olstat(p, uap, retval)
1490 struct proc *p;
1491 register struct olstat_args *uap;
1492 register_t *retval;
1493 {
1494 struct vnode *vp, *dvp;
1495 struct stat sb, sb1;
1496 struct ostat osb;
1497 int error;
1498 struct nameidata nd;
1499
1500 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
1501 uap->path, p);
1502 if (error = namei(&nd))
1503 return (error);
1504 /*
1505 * For symbolic links, always return the attributes of its
1506 * containing directory, except for mode, size, and links.
1507 */
1508 vp = nd.ni_vp;
1509 dvp = nd.ni_dvp;
1510 if (vp->v_type != VLNK) {
1511 if (dvp == vp)
1512 vrele(dvp);
1513 else
1514 vput(dvp);
1515 error = vn_stat(vp, &sb, p);
1516 vput(vp);
1517 if (error)
1518 return (error);
1519 } else {
1520 error = vn_stat(dvp, &sb, p);
1521 vput(dvp);
1522 if (error) {
1523 vput(vp);
1524 return (error);
1525 }
1526 error = vn_stat(vp, &sb1, p);
1527 vput(vp);
1528 if (error)
1529 return (error);
1530 sb.st_mode &= ~S_IFDIR;
1531 sb.st_mode |= S_IFLNK;
1532 sb.st_nlink = sb1.st_nlink;
1533 sb.st_size = sb1.st_size;
1534 sb.st_blocks = sb1.st_blocks;
1535 }
1536 cvtstat(&sb, &osb);
1537 error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
1538 return (error);
1539 }
1540
1541 /*
1542 * Convert from an old to a new stat structure.
1543 */
1544 void
1545 cvtstat(st, ost)
1546 struct stat *st;
1547 struct ostat *ost;
1548 {
1549
1550 ost->st_dev = st->st_dev;
1551 ost->st_ino = st->st_ino;
1552 ost->st_mode = st->st_mode;
1553 ost->st_nlink = st->st_nlink;
1554 ost->st_uid = st->st_uid;
1555 ost->st_gid = st->st_gid;
1556 ost->st_rdev = st->st_rdev;
1557 if (st->st_size < (quad_t)1 << 32)
1558 ost->st_size = st->st_size;
1559 else
1560 ost->st_size = -2;
1561 ost->st_atime = st->st_atime;
1562 ost->st_mtime = st->st_mtime;
1563 ost->st_ctime = st->st_ctime;
1564 ost->st_blksize = st->st_blksize;
1565 ost->st_blocks = st->st_blocks;
1566 ost->st_flags = st->st_flags;
1567 ost->st_gen = st->st_gen;
1568 }
1569 #endif /* COMPAT_43 */
1570
1571 /*
1572 * Get file status; this version follows links.
1573 */
1574 struct stat_args {
1575 char *path;
1576 struct stat *ub;
1577 };
1578 /* ARGSUSED */
1579 int
1580 stat(p, uap, retval)
1581 struct proc *p;
1582 register struct stat_args *uap;
1583 register_t *retval;
1584 {
1585 struct stat sb;
1586 int error;
1587 struct nameidata nd;
1588
1589 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1590 uap->path, p);
1591 if (error = namei(&nd))
1592 return (error);
1593 error = vn_stat(nd.ni_vp, &sb, p);
1594 vput(nd.ni_vp);
1595 if (error)
1596 return (error);
1597 error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
1598 return (error);
1599 }
1600
1601 /*
1602 * Get file status; this version does not follow links.
1603 */
1604 struct lstat_args {
1605 char *path;
1606 struct stat *ub;
1607 };
1608 /* ARGSUSED */
1609 int
1610 lstat(p, uap, retval)
1611 struct proc *p;
1612 register struct lstat_args *uap;
1613 register_t *retval;
1614 {
1615 int error;
1616 struct vnode *vp, *dvp;
1617 struct stat sb, sb1;
1618 struct nameidata nd;
1619
1620 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
1621 uap->path, p);
1622 if (error = namei(&nd))
1623 return (error);
1624 /*
1625 * For symbolic links, always return the attributes of its containing
1626 * directory, except for mode, size, inode number, and links.
1627 */
1628 vp = nd.ni_vp;
1629 dvp = nd.ni_dvp;
1630 if ((vp->v_type != VLNK) || ((vp->v_type == VLNK) && (vp->v_tag == VT_NFS))) {
1631 if (dvp == vp)
1632 vrele(dvp);
1633 else
1634 vput(dvp);
1635 error = vn_stat(vp, &sb, p);
1636 vput(vp);
1637 if (error)
1638 return (error);
1639 if (vp->v_type == VLNK)
1640 sb.st_mode |= S_IFLNK;
1641 } else {
1642 error = vn_stat(dvp, &sb, p);
1643 vput(dvp);
1644 if (error) {
1645 vput(vp);
1646 return (error);
1647 }
1648 error = vn_stat(vp, &sb1, p);
1649 vput(vp);
1650 if (error)
1651 return (error);
1652 sb.st_mode &= ~S_IFDIR;
1653 sb.st_mode |= S_IFLNK;
1654 sb.st_nlink = sb1.st_nlink;
1655 sb.st_size = sb1.st_size;
1656 sb.st_blocks = sb1.st_blocks;
1657 sb.st_ino = sb1.st_ino;
1658 }
1659 error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
1660 return (error);
1661 }
1662
1663 /*
1664 * Get configurable pathname variables.
1665 */
1666 struct pathconf_args {
1667 char *path;
1668 int name;
1669 };
1670 /* ARGSUSED */
1671 int
1672 pathconf(p, uap, retval)
1673 struct proc *p;
1674 register struct pathconf_args *uap;
1675 register_t *retval;
1676 {
1677 int error;
1678 struct nameidata nd;
1679
1680 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1681 uap->path, p);
1682 if (error = namei(&nd))
1683 return (error);
1684 error = VOP_PATHCONF(nd.ni_vp, uap->name, retval);
1685 vput(nd.ni_vp);
1686 return (error);
1687 }
1688
1689 /*
1690 * Return target name of a symbolic link.
1691 */
1692 struct readlink_args {
1693 char *path;
1694 char *buf;
1695 int count;
1696 };
1697 /* ARGSUSED */
1698 int
1699 readlink(p, uap, retval)
1700 struct proc *p;
1701 register struct readlink_args *uap;
1702 register_t *retval;
1703 {
1704 register struct vnode *vp;
1705 struct iovec aiov;
1706 struct uio auio;
1707 int error;
1708 struct nameidata nd;
1709
1710 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
1711 uap->path, p);
1712 if (error = namei(&nd))
1713 return (error);
1714 vp = nd.ni_vp;
1715 if (vp->v_type != VLNK)
1716 error = EINVAL;
1717 else {
1718 aiov.iov_base = uap->buf;
1719 aiov.iov_len = uap->count;
1720 auio.uio_iov = &aiov;
1721 auio.uio_iovcnt = 1;
1722 auio.uio_offset = 0;
1723 auio.uio_rw = UIO_READ;
1724 auio.uio_segflg = UIO_USERSPACE;
1725 auio.uio_procp = p;
1726 auio.uio_resid = uap->count;
1727 error = VOP_READLINK(vp, &auio, p->p_ucred);
1728 }
1729 vput(vp);
1730 *retval = uap->count - auio.uio_resid;
1731 return (error);
1732 }
1733
1734 /*
1735 * Change flags of a file given a path name.
1736 */
1737 struct chflags_args {
1738 char *path;
1739 int flags;
1740 };
1741 /* ARGSUSED */
1742 int
1743 chflags(p, uap, retval)
1744 struct proc *p;
1745 register struct chflags_args *uap;
1746 register_t *retval;
1747 {
1748 register struct vnode *vp;
1749 struct vattr vattr;
1750 int error;
1751 struct nameidata nd;
1752
1753 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
1754 if (error = namei(&nd))
1755 return (error);
1756 vp = nd.ni_vp;
1757 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1758 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1759 VATTR_NULL(&vattr);
1760 vattr.va_flags = uap->flags;
1761 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1762 vput(vp);
1763 return (error);
1764 }
1765
1766 /*
1767 * Change flags of a file given a file descriptor.
1768 */
1769 struct fchflags_args {
1770 int fd;
1771 int flags;
1772 };
1773 /* ARGSUSED */
1774 int
1775 fchflags(p, uap, retval)
1776 struct proc *p;
1777 register struct fchflags_args *uap;
1778 register_t *retval;
1779 {
1780 struct vattr vattr;
1781 struct vnode *vp;
1782 struct file *fp;
1783 int error;
1784
1785 if (error = getvnode(p, uap->fd, &fp))
1786 return (error);
1787 vp = (struct vnode *)fp->f_data;
1788 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1789 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1790 VATTR_NULL(&vattr);
1791 vattr.va_flags = uap->flags;
1792 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1793 VOP_UNLOCK(vp, 0, p);
1794 return (error);
1795 }
1796
1797 /*
1798 * Change mode of a file given path name.
1799 */
1800 struct chmod_args {
1801 char *path;
1802 int mode;
1803 };
1804 /* ARGSUSED */
1805 int
1806 chmod(p, uap, retval)
1807 struct proc *p;
1808 register struct chmod_args *uap;
1809 register_t *retval;
1810 {
1811 register struct vnode *vp;
1812 struct vattr vattr;
1813 int error;
1814 struct nameidata nd;
1815
1816 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
1817 if (error = namei(&nd))
1818 return (error);
1819 vp = nd.ni_vp;
1820 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1821 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1822 VATTR_NULL(&vattr);
1823 vattr.va_mode = uap->mode & ALLPERMS;
1824 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1825 vput(vp);
1826 return (error);
1827 }
1828
1829 /*
1830 * Change mode of a file given a file descriptor.
1831 */
1832 struct fchmod_args {
1833 int fd;
1834 int mode;
1835 };
1836 /* ARGSUSED */
1837 int
1838 fchmod(p, uap, retval)
1839 struct proc *p;
1840 register struct fchmod_args *uap;
1841 register_t *retval;
1842 {
1843 struct vattr vattr;
1844 struct vnode *vp;
1845 struct file *fp;
1846 int error;
1847
1848 if (error = getvnode(p, uap->fd, &fp))
1849 return (error);
1850 vp = (struct vnode *)fp->f_data;
1851 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1852 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1853 VATTR_NULL(&vattr);
1854 vattr.va_mode = uap->mode & ALLPERMS;
1855 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1856 VOP_UNLOCK(vp, 0, p);
1857 return (error);
1858 }
1859
1860 /*
1861 * Set ownership given a path name.
1862 */
1863 struct chown_args {
1864 char *path;
1865 int uid;
1866 int gid;
1867 };
1868 /* ARGSUSED */
1869 int
1870 chown(p, uap, retval)
1871 struct proc *p;
1872 register struct chown_args *uap;
1873 register_t *retval;
1874 {
1875 register struct vnode *vp;
1876 struct vattr vattr;
1877 int error;
1878 struct nameidata nd;
1879
1880 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
1881 if (error = namei(&nd))
1882 return (error);
1883 vp = nd.ni_vp;
1884
1885 /*
1886 XXX A TEMPORARY HACK FOR NOW: Try to track console_user
1887 by looking for chown() calls on /dev/console from a console process:
1888 */
1889 if ((vp) && (vp->v_specinfo) &&
1890 (major(vp->v_specinfo->si_rdev) == CONSMAJOR) &&
1891 (minor(vp->v_specinfo->si_rdev) == 0)) {
1892 console_user = uap->uid;
1893 };
1894
1895 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1896 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1897 VATTR_NULL(&vattr);
1898 vattr.va_uid = uap->uid;
1899 vattr.va_gid = uap->gid;
1900 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1901 vput(vp);
1902 return (error);
1903 }
1904
1905 /*
1906 * Set ownership given a file descriptor.
1907 */
1908 struct fchown_args {
1909 int fd;
1910 int uid;
1911 int gid;
1912 };
1913 /* ARGSUSED */
1914 int
1915 fchown(p, uap, retval)
1916 struct proc *p;
1917 register struct fchown_args *uap;
1918 register_t *retval;
1919 {
1920 struct vattr vattr;
1921 struct vnode *vp;
1922 struct file *fp;
1923 int error;
1924
1925 if (error = getvnode(p, uap->fd, &fp))
1926 return (error);
1927 vp = (struct vnode *)fp->f_data;
1928 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1929 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1930 VATTR_NULL(&vattr);
1931 vattr.va_uid = uap->uid;
1932 vattr.va_gid = uap->gid;
1933 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1934 VOP_UNLOCK(vp, 0, p);
1935 return (error);
1936 }
1937
1938 /*
1939 * Set the access and modification times of a file.
1940 */
1941 struct utimes_args {
1942 char *path;
1943 struct timeval *tptr;
1944 };
1945 /* ARGSUSED */
1946 int
1947 utimes(p, uap, retval)
1948 struct proc *p;
1949 register struct utimes_args *uap;
1950 register_t *retval;
1951 {
1952 register struct vnode *vp;
1953 struct timeval tv[2];
1954 struct vattr vattr;
1955 int error;
1956 struct nameidata nd;
1957
1958 VATTR_NULL(&vattr);
1959 if (uap->tptr == NULL) {
1960 microtime(&tv[0]);
1961 tv[1] = tv[0];
1962 vattr.va_vaflags |= VA_UTIMES_NULL;
1963 } else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv,
1964 sizeof (tv)))
1965 return (error);
1966 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
1967 if (error = namei(&nd))
1968 return (error);
1969 vp = nd.ni_vp;
1970 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1971 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1972 vattr.va_atime.tv_sec = tv[0].tv_sec;
1973 vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000;
1974 vattr.va_mtime.tv_sec = tv[1].tv_sec;
1975 vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000;
1976 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1977 vput(vp);
1978 return (error);
1979 }
1980
1981 /*
1982 * Truncate a file given its path name.
1983 */
1984 struct truncate_args {
1985 char *path;
1986 #ifdef DOUBLE_ALIGN_PARAMS
1987 int pad;
1988 #endif
1989 off_t length;
1990 };
1991 /* ARGSUSED */
1992 int
1993 truncate(p, uap, retval)
1994 struct proc *p;
1995 register struct truncate_args *uap;
1996 register_t *retval;
1997 {
1998 register struct vnode *vp;
1999 struct vattr vattr;
2000 int error;
2001 struct nameidata nd;
2002
2003 if (uap->length < 0)
2004 return(EINVAL);
2005 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
2006 if (error = namei(&nd))
2007 return (error);
2008 vp = nd.ni_vp;
2009 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2010 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2011 if (vp->v_type == VDIR)
2012 error = EISDIR;
2013 else if ((error = vn_writechk(vp)) == 0 &&
2014 (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
2015 VATTR_NULL(&vattr);
2016 vattr.va_size = uap->length;
2017 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2018 }
2019 vput(vp);
2020 return (error);
2021 }
2022
2023 /*
2024 * Truncate a file given a file descriptor.
2025 */
2026 struct ftruncate_args {
2027 int fd;
2028 #ifdef DOUBLE_ALIGN_PARAMS
2029 int pad;
2030 #endif
2031 off_t length;
2032 };
2033 /* ARGSUSED */
2034 int
2035 ftruncate(p, uap, retval)
2036 struct proc *p;
2037 register struct ftruncate_args *uap;
2038 register_t *retval;
2039 {
2040 struct vattr vattr;
2041 struct vnode *vp;
2042 struct file *fp;
2043 int error;
2044
2045 if (uap->length < 0)
2046 return(EINVAL);
2047
2048 if (error = fdgetf(p, uap->fd, &fp))
2049 return (error);
2050
2051 if (fp->f_type == DTYPE_PSXSHM) {
2052 return(pshm_truncate(p, fp, uap->fd, uap->length, retval));
2053 }
2054 if (fp->f_type != DTYPE_VNODE)
2055 return (EINVAL);
2056
2057
2058 if ((fp->f_flag & FWRITE) == 0)
2059 return (EINVAL);
2060 vp = (struct vnode *)fp->f_data;
2061 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2062 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2063 if (vp->v_type == VDIR)
2064 error = EISDIR;
2065 else if ((error = vn_writechk(vp)) == 0) {
2066 VATTR_NULL(&vattr);
2067 vattr.va_size = uap->length;
2068 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
2069 }
2070 VOP_UNLOCK(vp, 0, p);
2071 return (error);
2072 }
2073
2074 #if COMPAT_43
2075 /*
2076 * Truncate a file given its path name.
2077 */
2078 struct otruncate_args {
2079 char *path;
2080 long length;
2081 };
2082 /* ARGSUSED */
2083 int
2084 otruncate(p, uap, retval)
2085 struct proc *p;
2086 register struct otruncate_args *uap;
2087 register_t *retval;
2088 {
2089 struct truncate_args /* {
2090 syscallarg(char *) path;
2091 #ifdef DOUBLE_ALIGN_PARAMS
2092 syscallarg(int) pad;
2093 #endif
2094 syscallarg(off_t) length;
2095 } */ nuap;
2096
2097 nuap.path = uap->path;
2098 nuap.length = uap->length;
2099 return (truncate(p, &nuap, retval));
2100 }
2101
2102 /*
2103 * Truncate a file given a file descriptor.
2104 */
2105 struct oftruncate_args {
2106 int fd;
2107 long length;
2108 };
2109 /* ARGSUSED */
2110 int
2111 oftruncate(p, uap, retval)
2112 struct proc *p;
2113 register struct oftruncate_args *uap;
2114 register_t *retval;
2115 {
2116 struct ftruncate_args /* {
2117 syscallarg(int) fd;
2118 #ifdef DOUBLE_ALIGN_PARAMS
2119 syscallarg(int) pad;
2120 #endif
2121 syscallarg(off_t) length;
2122 } */ nuap;
2123
2124 nuap.fd = uap->fd;
2125 nuap.length = uap->length;
2126 return (ftruncate(p, &nuap, retval));
2127 }
2128 #endif /* COMPAT_43 */
2129
2130 /*
2131 * Sync an open file.
2132 */
2133 struct fsync_args {
2134 int fd;
2135 };
2136 /* ARGSUSED */
2137 int
2138 fsync(p, uap, retval)
2139 struct proc *p;
2140 struct fsync_args *uap;
2141 register_t *retval;
2142 {
2143 register struct vnode *vp;
2144 struct file *fp;
2145 int error;
2146
2147 if (error = getvnode(p, uap->fd, &fp))
2148 return (error);
2149 vp = (struct vnode *)fp->f_data;
2150 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2151 error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
2152 VOP_UNLOCK(vp, 0, p);
2153 return (error);
2154 }
2155
2156 /*
2157 * Duplicate files. Source must be a file, target must be a file or
2158 * must not exist.
2159 */
2160
2161 struct copyfile_args {
2162 char *from;
2163 char *to;
2164 int mode;
2165 int flags;
2166 };
2167 /* ARGSUSED */
2168 int
2169 copyfile(p, uap, retval)
2170 struct proc *p;
2171 register struct copyfile_args *uap;
2172 register_t *retval;
2173 {
2174 register struct vnode *tvp, *fvp, *tdvp;
2175 register struct ucred *cred = p->p_ucred;
2176 struct nameidata fromnd, tond;
2177 int error;
2178
2179 /* Check that the flags are valid.
2180 */
2181
2182 if (uap->flags & ~CPF_MASK) {
2183 return(EINVAL);
2184 }
2185
2186 NDINIT(&fromnd, LOOKUP, SAVESTART, UIO_USERSPACE,
2187 uap->from, p);
2188 if (error = namei(&fromnd))
2189 return (error);
2190 fvp = fromnd.ni_vp;
2191
2192 NDINIT(&tond, CREATE, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
2193 UIO_USERSPACE, uap->to, p);
2194 if (error = namei(&tond)) {
2195 vrele(fvp);
2196 goto out1;
2197 }
2198 tdvp = tond.ni_dvp;
2199 tvp = tond.ni_vp;
2200 if (tvp != NULL) {
2201 if (!(uap->flags & CPF_OVERWRITE)) {
2202 error = EEXIST;
2203 goto out;
2204 }
2205 }
2206
2207 if (fvp->v_type == VDIR || (tvp && tvp->v_type == VDIR)) {
2208 error = EISDIR;
2209 goto out;
2210 }
2211
2212 if (error = VOP_ACCESS(tdvp, VWRITE, cred, p))
2213 goto out;
2214
2215 if (fvp == tdvp)
2216 error = EINVAL;
2217 /*
2218 * If source is the same as the destination (that is the
2219 * same inode number) then there is nothing to do.
2220 * (fixed to have POSIX semantics - CSM 3/2/98)
2221 */
2222 if (fvp == tvp)
2223 error = -1;
2224 out:
2225 if (!error) {
2226 error = VOP_COPYFILE(fvp,tdvp,tvp,&tond.ni_cnd,uap->mode,uap->flags);
2227 } else {
2228 VOP_ABORTOP(tdvp, &tond.ni_cnd);
2229 if (tdvp == tvp)
2230 vrele(tdvp);
2231 else
2232 vput(tdvp);
2233 if (tvp)
2234 vput(tvp);
2235 vrele(fvp);
2236 }
2237 vrele(tond.ni_startdir);
2238 FREE_ZONE(tond.ni_cnd.cn_pnbuf, tond.ni_cnd.cn_pnlen, M_NAMEI);
2239 out1:
2240 if (fromnd.ni_startdir)
2241 vrele(fromnd.ni_startdir);
2242 FREE_ZONE(fromnd.ni_cnd.cn_pnbuf, fromnd.ni_cnd.cn_pnlen, M_NAMEI);
2243 if (error == -1)
2244 return (0);
2245 return (error);
2246 }
2247
2248 /*
2249 * Rename files. Source and destination must either both be directories,
2250 * or both not be directories. If target is a directory, it must be empty.
2251 */
2252 struct rename_args {
2253 char *from;
2254 char *to;
2255 };
2256 /* ARGSUSED */
2257 int
2258 rename(p, uap, retval)
2259 struct proc *p;
2260 register struct rename_args *uap;
2261 register_t *retval;
2262 {
2263 register struct vnode *tvp, *fvp, *tdvp;
2264 struct nameidata fromnd, tond;
2265 int error;
2266 int mntrename;
2267
2268 mntrename = FALSE;
2269
2270 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
2271 uap->from, p);
2272 if (error = namei(&fromnd))
2273 return (error);
2274 fvp = fromnd.ni_vp;
2275
2276 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
2277 UIO_USERSPACE, uap->to, p);
2278 if (error = namei(&tond)) {
2279 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2280 vrele(fromnd.ni_dvp);
2281 vrele(fvp);
2282 goto out2;
2283 }
2284 tdvp = tond.ni_dvp;
2285 tvp = tond.ni_vp;
2286
2287 if (tvp != NULL) {
2288 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
2289 error = ENOTDIR;
2290 goto out;
2291 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
2292 error = EISDIR;
2293 goto out;
2294 }
2295 }
2296 if (fvp == tdvp)
2297 error = EINVAL;
2298 /*
2299 * If source is the same as the destination (that is the
2300 * same inode number) then there is nothing to do.
2301 */
2302 if (fvp == tvp)
2303 error = -1;
2304
2305 /*
2306 * Allow the renaming of mount points.
2307 * - target must not exist
2308 * - target must reside in the same directory as source
2309 * - union mounts cannot be renamed
2310 * - "/" cannot be renamed
2311 */
2312 if ((fvp->v_flag & VROOT) &&
2313 (fvp->v_type == VDIR) &&
2314 (tvp == NULL) &&
2315 (fvp->v_mountedhere == NULL) &&
2316 (fromnd.ni_dvp == tond.ni_dvp) &&
2317 ((fvp->v_mount->mnt_flag & (MNT_UNION | MNT_ROOTFS)) == 0) &&
2318 (fvp->v_mount->mnt_vnodecovered != NULLVP)) {
2319
2320 /* switch fvp to the covered vnode */
2321 fromnd.ni_vp = fvp->v_mount->mnt_vnodecovered;
2322 vrele(fvp);
2323 fvp = fromnd.ni_vp;
2324 VREF(fvp);
2325 mntrename = TRUE;
2326 }
2327 out:
2328 if (!error) {
2329 VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE);
2330 if (fromnd.ni_dvp != tdvp)
2331 VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2332 if (tvp)
2333 VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE);
2334 error = VOP_RENAME(fromnd.ni_dvp, fvp, &fromnd.ni_cnd,
2335 tond.ni_dvp, tvp, &tond.ni_cnd);
2336 if (error)
2337 goto out1;
2338
2339 /*
2340 * update filesystem's mount point data
2341 */
2342 if (mntrename) {
2343 char *cp, *pathend, *mpname;
2344 char * tobuf;
2345 struct mount *mp;
2346 int maxlen;
2347 size_t len = 0;
2348
2349 VREF(fvp);
2350 vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p);
2351 mp = fvp->v_mountedhere;
2352
2353 if (vfs_busy(mp, LK_NOWAIT, 0, p)) {
2354 vput(fvp);
2355 error = EBUSY;
2356 goto out1;
2357 }
2358 VOP_UNLOCK(fvp, 0, p);
2359
2360 MALLOC_ZONE(tobuf, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
2361 error = copyinstr(uap->to, tobuf, MAXPATHLEN, &len);
2362 if (!error) {
2363 /* find current mount point prefix */
2364 pathend = &mp->mnt_stat.f_mntonname[0];
2365 for (cp = pathend; *cp != '\0'; ++cp) {
2366 if (*cp == '/')
2367 pathend = cp + 1;
2368 }
2369 /* find last component of target name */
2370 for (mpname = cp = tobuf; *cp != '\0'; ++cp) {
2371 if (*cp == '/')
2372 mpname = cp + 1;
2373 }
2374 /* append name to prefix */
2375 maxlen = MNAMELEN - (pathend - mp->mnt_stat.f_mntonname);
2376 bzero(pathend, maxlen);
2377 strncpy(pathend, mpname, maxlen - 1);
2378 }
2379 FREE_ZONE(tobuf, MAXPATHLEN, M_NAMEI);
2380
2381 vrele(fvp);
2382 vfs_unbusy(mp, p);
2383 }
2384 } else {
2385 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
2386 if (tdvp == tvp)
2387 vrele(tdvp);
2388 else
2389 vput(tdvp);
2390 if (tvp)
2391 vput(tvp);
2392 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2393 vrele(fromnd.ni_dvp);
2394 vrele(fvp);
2395 }
2396 out1:
2397 vrele(tond.ni_startdir);
2398 FREE_ZONE(tond.ni_cnd.cn_pnbuf, tond.ni_cnd.cn_pnlen, M_NAMEI);
2399 out2:
2400 if (fromnd.ni_startdir)
2401 vrele(fromnd.ni_startdir);
2402 FREE_ZONE(fromnd.ni_cnd.cn_pnbuf, fromnd.ni_cnd.cn_pnlen, M_NAMEI);
2403 if (error == -1)
2404 return (0);
2405 return (error);
2406 }
2407
2408 /*
2409 * Make a directory file.
2410 */
2411 struct mkdir_args {
2412 char *path;
2413 int mode;
2414 };
2415 /* ARGSUSED */
2416 int
2417 mkdir(p, uap, retval)
2418 struct proc *p;
2419 register struct mkdir_args *uap;
2420 register_t *retval;
2421 {
2422 register struct vnode *vp;
2423 struct vattr vattr;
2424 int error;
2425 struct nameidata nd;
2426
2427 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
2428 if (error = namei(&nd))
2429 return (error);
2430 vp = nd.ni_vp;
2431 if (vp != NULL) {
2432 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2433 if (nd.ni_dvp == vp)
2434 vrele(nd.ni_dvp);
2435 else
2436 vput(nd.ni_dvp);
2437 vrele(vp);
2438 return (EEXIST);
2439 }
2440 VATTR_NULL(&vattr);
2441 vattr.va_type = VDIR;
2442 vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask;
2443 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2444 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
2445 if (!error)
2446 vput(nd.ni_vp);
2447 return (error);
2448 }
2449
2450 /*
2451 * Remove a directory file.
2452 */
2453 struct rmdir_args {
2454 char *path;
2455 };
2456 /* ARGSUSED */
2457 int
2458 rmdir(p, uap, retval)
2459 struct proc *p;
2460 struct rmdir_args *uap;
2461 register_t *retval;
2462 {
2463 register struct vnode *vp;
2464 int error;
2465 struct nameidata nd;
2466
2467 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
2468 uap->path, p);
2469 if (error = namei(&nd))
2470 return (error);
2471 vp = nd.ni_vp;
2472 if (vp->v_type != VDIR) {
2473 error = ENOTDIR;
2474 goto out;
2475 }
2476 /*
2477 * No rmdir "." please.
2478 */
2479 if (nd.ni_dvp == vp) {
2480 error = EINVAL;
2481 goto out;
2482 }
2483 /*
2484 * The root of a mounted filesystem cannot be deleted.
2485 */
2486 if (vp->v_flag & VROOT)
2487 error = EBUSY;
2488 out:
2489 if (!error) {
2490 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2491 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2492 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2493 } else {
2494 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2495 if (nd.ni_dvp == vp)
2496 vrele(nd.ni_dvp);
2497 else
2498 vput(nd.ni_dvp);
2499 vput(vp);
2500 }
2501 return (error);
2502 }
2503
2504 #if COMPAT_43
2505 /*
2506 * Read a block of directory entries in a file system independent format.
2507 */
2508 struct ogetdirentries_args {
2509 int fd;
2510 char *buf;
2511 u_int count;
2512 long *basep;
2513 };
2514 int
2515 ogetdirentries(p, uap, retval)
2516 struct proc *p;
2517 register struct ogetdirentries_args *uap;
2518 register_t *retval;
2519 {
2520 register struct vnode *vp;
2521 struct file *fp;
2522 struct uio auio, kuio;
2523 struct iovec aiov, kiov;
2524 struct dirent *dp, *edp;
2525 caddr_t dirbuf;
2526 int error, eofflag, readcnt;
2527 long loff;
2528
2529 if (error = getvnode(p, uap->fd, &fp))
2530 return (error);
2531 if ((fp->f_flag & FREAD) == 0)
2532 return (EBADF);
2533 vp = (struct vnode *)fp->f_data;
2534 unionread:
2535 if (vp->v_type != VDIR)
2536 return (EINVAL);
2537 aiov.iov_base = uap->buf;
2538 aiov.iov_len = uap->count;
2539 auio.uio_iov = &aiov;
2540 auio.uio_iovcnt = 1;
2541 auio.uio_rw = UIO_READ;
2542 auio.uio_segflg = UIO_USERSPACE;
2543 auio.uio_procp = p;
2544 auio.uio_resid = uap->count;
2545 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2546 loff = auio.uio_offset = fp->f_offset;
2547 # if (BYTE_ORDER != LITTLE_ENDIAN)
2548 if (vp->v_mount->mnt_maxsymlinklen <= 0) {
2549 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
2550 (int *)0, (u_long *)0);
2551 fp->f_offset = auio.uio_offset;
2552 } else
2553 # endif
2554 {
2555 kuio = auio;
2556 kuio.uio_iov = &kiov;
2557 kuio.uio_segflg = UIO_SYSSPACE;
2558 kiov.iov_len = uap->count;
2559 MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK);
2560 kiov.iov_base = dirbuf;
2561 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
2562 (int *)0, (u_long *)0);
2563 fp->f_offset = kuio.uio_offset;
2564 if (error == 0) {
2565 readcnt = uap->count - kuio.uio_resid;
2566 edp = (struct dirent *)&dirbuf[readcnt];
2567 for (dp = (struct dirent *)dirbuf; dp < edp; ) {
2568 # if (BYTE_ORDER == LITTLE_ENDIAN)
2569 /*
2570 * The expected low byte of
2571 * dp->d_namlen is our dp->d_type.
2572 * The high MBZ byte of dp->d_namlen
2573 * is our dp->d_namlen.
2574 */
2575 dp->d_type = dp->d_namlen;
2576 dp->d_namlen = 0;
2577 # else
2578 /*
2579 * The dp->d_type is the high byte
2580 * of the expected dp->d_namlen,
2581 * so must be zero'ed.
2582 */
2583 dp->d_type = 0;
2584 # endif
2585 if (dp->d_reclen > 0) {
2586 dp = (struct dirent *)
2587 ((char *)dp + dp->d_reclen);
2588 } else {
2589 error = EIO;
2590 break;
2591 }
2592 }
2593 if (dp >= edp)
2594 error = uiomove(dirbuf, readcnt, &auio);
2595 }
2596 FREE(dirbuf, M_TEMP);
2597 }
2598 VOP_UNLOCK(vp, 0, p);
2599 if (error)
2600 return (error);
2601
2602 #if UNION
2603 {
2604 extern int (**union_vnodeop_p)(void *);
2605 extern struct vnode *union_dircache __P((struct vnode*, struct proc*));
2606
2607 if ((uap->count == auio.uio_resid) &&
2608 (vp->v_op == union_vnodeop_p)) {
2609 struct vnode *lvp;
2610
2611 lvp = union_dircache(vp, p);
2612 if (lvp != NULLVP) {
2613 struct vattr va;
2614
2615 /*
2616 * If the directory is opaque,
2617 * then don't show lower entries
2618 */
2619 error = VOP_GETATTR(vp, &va, fp->f_cred, p);
2620 if (va.va_flags & OPAQUE) {
2621 vput(lvp);
2622 lvp = NULL;
2623 }
2624 }
2625
2626 if (lvp != NULLVP) {
2627 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
2628 if (error) {
2629 vput(lvp);
2630 return (error);
2631 }
2632 VOP_UNLOCK(lvp, 0, p);
2633 fp->f_data = (caddr_t) lvp;
2634 fp->f_offset = 0;
2635 error = vn_close(vp, FREAD, fp->f_cred, p);
2636 if (error)
2637 return (error);
2638 vp = lvp;
2639 goto unionread;
2640 }
2641 }
2642 }
2643 #endif /* UNION */
2644
2645 if ((uap->count == auio.uio_resid) &&
2646 (vp->v_flag & VROOT) &&
2647 (vp->v_mount->mnt_flag & MNT_UNION)) {
2648 struct vnode *tvp = vp;
2649 vp = vp->v_mount->mnt_vnodecovered;
2650 VREF(vp);
2651 fp->f_data = (caddr_t) vp;
2652 fp->f_offset = 0;
2653 vrele(tvp);
2654 goto unionread;
2655 }
2656 error = copyout((caddr_t)&loff, (caddr_t)uap->basep,
2657 sizeof(long));
2658 *retval = uap->count - auio.uio_resid;
2659 return (error);
2660 }
2661 #endif /* COMPAT_43 */
2662
2663 /*
2664 * Read a block of directory entries in a file system independent format.
2665 */
2666 struct getdirentries_args {
2667 int fd;
2668 char *buf;
2669 u_int count;
2670 long *basep;
2671 };
2672 int
2673 getdirentries(p, uap, retval)
2674 struct proc *p;
2675 register struct getdirentries_args *uap;
2676 register_t *retval;
2677 {
2678 register struct vnode *vp;
2679 struct file *fp;
2680 struct uio auio;
2681 struct iovec aiov;
2682 long loff;
2683 int error, eofflag;
2684
2685 if (error = getvnode(p, uap->fd, &fp))
2686 return (error);
2687 if ((fp->f_flag & FREAD) == 0)
2688 return (EBADF);
2689 vp = (struct vnode *)fp->f_data;
2690 unionread:
2691 if (vp->v_type != VDIR)
2692 return (EINVAL);
2693 aiov.iov_base = uap->buf;
2694 aiov.iov_len = uap->count;
2695 auio.uio_iov = &aiov;
2696 auio.uio_iovcnt = 1;
2697 auio.uio_rw = UIO_READ;
2698 auio.uio_segflg = UIO_USERSPACE;
2699 auio.uio_procp = p;
2700 auio.uio_resid = uap->count;
2701 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2702 loff = auio.uio_offset = fp->f_offset;
2703 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
2704 (int *)0, (u_long *)0);
2705 fp->f_offset = auio.uio_offset;
2706 VOP_UNLOCK(vp, 0, p);
2707 if (error)
2708 return (error);
2709
2710 #if UNION
2711 {
2712 extern int (**union_vnodeop_p)(void *);
2713 extern struct vnode *union_dircache __P((struct vnode*, struct proc*));
2714
2715 if ((uap->count == auio.uio_resid) &&
2716 (vp->v_op == union_vnodeop_p)) {
2717 struct vnode *lvp;
2718
2719 lvp = union_dircache(vp, p);
2720 if (lvp != NULLVP) {
2721 struct vattr va;
2722
2723 /*
2724 * If the directory is opaque,
2725 * then don't show lower entries
2726 */
2727 error = VOP_GETATTR(vp, &va, fp->f_cred, p);
2728 if (va.va_flags & OPAQUE) {
2729 vput(lvp);
2730 lvp = NULL;
2731 }
2732 }
2733
2734 if (lvp != NULLVP) {
2735 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
2736 if (error) {
2737 vput(lvp);
2738 return (error);
2739 }
2740 VOP_UNLOCK(lvp, 0, p);
2741 fp->f_data = (caddr_t) lvp;
2742 fp->f_offset = 0;
2743 error = vn_close(vp, FREAD, fp->f_cred, p);
2744 if (error)
2745 return (error);
2746 vp = lvp;
2747 goto unionread;
2748 }
2749 }
2750 }
2751 #endif /* UNION */
2752
2753 if ((uap->count == auio.uio_resid) &&
2754 (vp->v_flag & VROOT) &&
2755 (vp->v_mount->mnt_flag & MNT_UNION)) {
2756 struct vnode *tvp = vp;
2757 vp = vp->v_mount->mnt_vnodecovered;
2758 VREF(vp);
2759 fp->f_data = (caddr_t) vp;
2760 fp->f_offset = 0;
2761 vrele(tvp);
2762 goto unionread;
2763 }
2764 error = copyout((caddr_t)&loff, (caddr_t)uap->basep,
2765 sizeof(long));
2766 *retval = uap->count - auio.uio_resid;
2767 return (error);
2768 }
2769
2770 /*
2771 * Set the mode mask for creation of filesystem nodes.
2772 */
2773 struct umask_args {
2774 int newmask;
2775 };
2776 int
2777 umask(p, uap, retval)
2778 struct proc *p;
2779 struct umask_args *uap;
2780 register_t *retval;
2781 {
2782 register struct filedesc *fdp;
2783
2784 fdp = p->p_fd;
2785 *retval = fdp->fd_cmask;
2786 fdp->fd_cmask = uap->newmask & ALLPERMS;
2787 return (0);
2788 }
2789
2790 /*
2791 * Void all references to file by ripping underlying filesystem
2792 * away from vnode.
2793 */
2794 struct revoke_args {
2795 char *path;
2796 };
2797 /* ARGSUSED */
2798 int
2799 revoke(p, uap, retval)
2800 struct proc *p;
2801 register struct revoke_args *uap;
2802 register_t *retval;
2803 {
2804 register struct vnode *vp;
2805 struct vattr vattr;
2806 int error;
2807 struct nameidata nd;
2808
2809 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
2810 if (error = namei(&nd))
2811 return (error);
2812 vp = nd.ni_vp;
2813 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
2814 goto out;
2815 if (p->p_ucred->cr_uid != vattr.va_uid &&
2816 (error = suser(p->p_ucred, &p->p_acflag)))
2817 goto out;
2818 if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
2819 VOP_REVOKE(vp, REVOKEALL);
2820 out:
2821 vrele(vp);
2822 return (error);
2823 }
2824
2825 /*
2826 * Convert a user file descriptor to a kernel file entry.
2827 */
2828 int
2829 getvnode(p, fd, fpp)
2830 struct proc *p;
2831 int fd;
2832 struct file **fpp;
2833 {
2834 struct file *fp;
2835 int error;
2836
2837 if (error = fdgetf(p, fd, &fp))
2838 return (error);
2839 if (fp->f_type != DTYPE_VNODE)
2840 return (EINVAL);
2841 *fpp = fp;
2842 return (0);
2843 }
2844 /*
2845 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
2846 * The following 10 system calls are designed to support features
2847 * which are specific to the HFS & HFS Plus volume formats
2848 */
2849
2850
2851 /*
2852 * Make a complex file. A complex file is one with multiple forks (data streams)
2853 */
2854 struct mkcomplex_args {
2855 const char *path; /* pathname of the file to be created */
2856 mode_t mode; /* access mode for the newly created file */
2857 u_long type; /* format of the complex file */
2858 };
2859 /* ARGSUSED */
2860 int
2861 mkcomplex(p,uap,retval)
2862 struct proc *p;
2863 register struct mkcomplex_args *uap;
2864 register_t *retval;
2865
2866 {
2867 struct vnode *vp;
2868 struct vattr vattr;
2869 int error;
2870 struct nameidata nd;
2871
2872 /* mkcomplex wants the directory vnode locked so do that here */
2873
2874 NDINIT(&nd, CREATE, FOLLOW | LOCKPARENT, UIO_USERSPACE, (char *)uap->path, p);
2875 if (error = namei(&nd))
2876 return (error);
2877
2878 /* Set the attributes as specified by the user */
2879
2880 VATTR_NULL(&vattr);
2881 vattr.va_mode = (uap->mode & ACCESSPERMS);
2882 error = VOP_MKCOMPLEX(nd.ni_dvp, &vp, &nd.ni_cnd, &vattr, uap->type);
2883
2884 /* The mkcomplex call promises to release the parent vnode pointer
2885 * even an an error case so don't do it here unless the operation
2886 * is not supported. In that case, there isn't anyone to unlock the parent
2887 * The vnode pointer to the file will also be released.
2888 */
2889
2890 if (error)
2891 {
2892 if (error == EOPNOTSUPP)
2893 vput(nd.ni_dvp);
2894 return (error);
2895 }
2896
2897 return (0);
2898
2899 } /* end of mkcomplex system call */
2900
2901
2902
2903 /*
2904 * Extended stat call which returns volumeid and vnodeid as well as other info
2905 */
2906 struct statv_args {
2907 const char *path; /* pathname of the target file */
2908 struct vstat *vsb; /* vstat structure for returned info */
2909 };
2910 /* ARGSUSED */
2911 int
2912 statv(p,uap,retval)
2913 struct proc *p;
2914 register struct statv_args *uap;
2915 register_t *retval;
2916
2917 {
2918 return (EOPNOTSUPP); /* We'll just return an error for now */
2919
2920 } /* end of statv system call */
2921
2922
2923
2924 /*
2925 * Extended lstat call which returns volumeid and vnodeid as well as other info
2926 */
2927 struct lstatv_args {
2928 const char *path; /* pathname of the target file */
2929 struct vstat *vsb; /* vstat structure for returned info */
2930 };
2931 /* ARGSUSED */
2932 int
2933 lstatv(p,uap,retval)
2934 struct proc *p;
2935 register struct lstatv_args *uap;
2936 register_t *retval;
2937
2938 {
2939 return (EOPNOTSUPP); /* We'll just return an error for now */
2940 } /* end of lstatv system call */
2941
2942
2943
2944 /*
2945 * Extended fstat call which returns volumeid and vnodeid as well as other info
2946 */
2947 struct fstatv_args {
2948 int fd; /* file descriptor of the target file */
2949 struct vstat *vsb; /* vstat structure for returned info */
2950 };
2951 /* ARGSUSED */
2952 int
2953 fstatv(p,uap,retval)
2954 struct proc *p;
2955 register struct fstatv_args *uap;
2956 register_t *retval;
2957
2958 {
2959 return (EOPNOTSUPP); /* We'll just return an error for now */
2960 } /* end of fstatv system call */
2961
2962
2963
2964 /*
2965 * Obtain attribute information about a file system object
2966 */
2967
2968 struct getattrlist_args {
2969 const char *path; /* pathname of the target object */
2970 struct attrlist * alist; /* Attributes desired by the user */
2971 void * attributeBuffer; /* buffer to hold returned attributes */
2972 size_t bufferSize; /* size of the return buffer */
2973 unsigned long options; /* options (follow/don't follow) */
2974 };
2975 /* ARGSUSED */
2976 int
2977 getattrlist (p,uap,retval)
2978 struct proc *p;
2979 register struct getattrlist_args *uap;
2980 register_t *retval;
2981
2982 {
2983 int error;
2984 struct nameidata nd;
2985 struct iovec aiov;
2986 struct uio auio;
2987 struct attrlist attributelist;
2988 u_long nameiflags;
2989
2990 /* Get the attributes desire and do our parameter checking */
2991
2992 if (error = copyin((caddr_t)uap->alist, (caddr_t) &attributelist,
2993 sizeof (attributelist)))
2994 {
2995 return(error);
2996 }
2997
2998 if (attributelist.bitmapcount != ATTR_BIT_MAP_COUNT
2999 #if 0
3000 || attributelist.commonattr & ~ATTR_CMN_VALIDMASK ||
3001 attributelist.volattr & ~ATTR_VOL_VALIDMASK ||
3002 attributelist.dirattr & ~ATTR_DIR_VALIDMASK ||
3003 attributelist.fileattr & ~ATTR_FILE_VALIDMASK ||
3004 attributelist.forkattr & ~ATTR_FORK_VALIDMASK
3005 #endif
3006 )
3007 {
3008 return (EINVAL);
3009 }
3010
3011 /* Get the vnode for the file we are getting info on. */
3012 nameiflags = LOCKLEAF;
3013 if ((uap->options & FSOPT_NOFOLLOW) == 0) nameiflags |= FOLLOW;
3014 NDINIT(&nd, LOOKUP, nameiflags, UIO_USERSPACE, (char *)uap->path, p);
3015
3016 if (error = namei(&nd))
3017 return (error);
3018
3019 /* Set up the UIO structure for use by the vfs routine */
3020
3021
3022 aiov.iov_base = uap->attributeBuffer;
3023 aiov.iov_len = uap->bufferSize;
3024 auio.uio_iov = &aiov;
3025 auio.uio_iovcnt = 1;
3026 auio.uio_offset = 0;
3027 auio.uio_rw = UIO_READ;
3028 auio.uio_segflg = UIO_USERSPACE;
3029 auio.uio_procp = p;
3030 auio.uio_resid = uap->bufferSize;
3031
3032
3033 error = VOP_GETATTRLIST(nd.ni_vp, &attributelist, &auio, p->p_ucred, p);
3034
3035 /* Unlock and release the vnode which will have been locked by namei */
3036
3037 vput(nd.ni_vp);
3038
3039 /* return the effort if we got one, otherwise return success */
3040
3041 if (error)
3042 {
3043 return (error);
3044 }
3045
3046 return(0);
3047
3048 } /* end of getattrlist system call */
3049
3050
3051
3052 /*
3053 * Set attribute information about a file system object
3054 */
3055
3056 struct setattrlist_args {
3057 const char *path; /* pathname of the target object */
3058 struct attrlist * alist; /* Attributes being set by the user */
3059 void * attributeBuffer; /* buffer with attribute values to be set */
3060 size_t bufferSize; /* size of the return buffer */
3061 unsigned long options; /* options (follow/don't follow) */
3062 };
3063 /* ARGSUSED */
3064 int
3065 setattrlist (p,uap,retval)
3066 struct proc *p;
3067 register struct setattrlist_args *uap;
3068 register_t *retval;
3069
3070 {
3071 int error;
3072 struct nameidata nd;
3073 struct iovec aiov;
3074 struct uio auio;
3075 struct attrlist alist;
3076 u_long nameiflags;
3077
3078 /* Get the attributes desired and do our parameter checking */
3079
3080 if ((error = copyin((caddr_t)uap->alist, (caddr_t) &alist,
3081 sizeof (alist)))) {
3082 return (error);
3083 }
3084
3085 if (alist.bitmapcount != ATTR_BIT_MAP_COUNT)
3086 return (EINVAL);
3087
3088 /* Get the vnode for the file whose attributes are being set. */
3089 nameiflags = LOCKLEAF;
3090 if ((uap->options & FSOPT_NOFOLLOW) == 0) nameiflags |= FOLLOW;
3091 NDINIT(&nd, LOOKUP, nameiflags, UIO_USERSPACE, (char *)uap->path, p);
3092 if (error = namei(&nd))
3093 return (error);
3094
3095 /* Set up the UIO structure for use by the vfs routine */
3096 aiov.iov_base = uap->attributeBuffer;
3097 aiov.iov_len = uap->bufferSize;
3098 auio.uio_iov = &aiov;
3099 auio.uio_iovcnt = 1;
3100 auio.uio_offset = 0;
3101 auio.uio_rw = UIO_WRITE;
3102 auio.uio_segflg = UIO_USERSPACE;
3103 auio.uio_procp = p;
3104 auio.uio_resid = uap->bufferSize;
3105
3106 error = VOP_SETATTRLIST(nd.ni_vp, &alist, &auio, p->p_ucred, p);
3107
3108 vput(nd.ni_vp);
3109
3110 return (error);
3111
3112 } /* end of setattrlist system call */
3113
3114
3115 /*
3116 * Obtain attribute information on objects in a directory while enumerating
3117 * the directory. This call does not yet support union mounted directories.
3118 * TO DO
3119 * 1.union mounted directories.
3120 */
3121
3122 struct getdirentriesattr_args {
3123 int fd; /* file descriptor */
3124 struct attrlist *alist; /* bit map of requested attributes */
3125 void *buffer; /* buffer to hold returned attribute info */
3126 size_t buffersize; /* size of the return buffer */
3127 u_long *count; /* the count of entries requested/returned */
3128 u_long *basep; /* the offset of where we are leaving off in buffer */
3129 u_long *newstate; /* a flag to inform of changes in directory */
3130 u_long options; /* maybe unused for now */
3131 };
3132 /* ARGSUSED */
3133 int
3134 getdirentriesattr (p,uap,retval)
3135 struct proc *p;
3136 register struct getdirentriesattr_args *uap;
3137 register_t *retval;
3138
3139 {
3140 register struct vnode *vp;
3141 struct file *fp;
3142 struct uio auio;
3143 struct iovec aiov;
3144 u_long actualcount;
3145 u_long newstate;
3146 int error, eofflag;
3147 long loff;
3148 struct attrlist attributelist;
3149
3150 /* Get the attributes into kernel space */
3151 if (error = copyin((caddr_t)uap->alist, (caddr_t) &attributelist, sizeof (attributelist)))
3152 return(error);
3153 if (error = copyin((caddr_t)uap->count, (caddr_t) &actualcount, sizeof (u_long)))
3154 return(error);
3155
3156 if (error = getvnode(p, uap->fd, &fp))
3157 return (error);
3158 if ((fp->f_flag & FREAD) == 0)
3159 return(EBADF);
3160 vp = (struct vnode *)fp->f_data;
3161
3162 if (vp->v_type != VDIR)
3163 return(EINVAL);
3164
3165 /* set up the uio structure which will contain the users return buffer */
3166 aiov.iov_base = uap->buffer;
3167 aiov.iov_len = uap->buffersize;
3168 auio.uio_iov = &aiov;
3169 auio.uio_iovcnt = 1;
3170 auio.uio_rw = UIO_READ;
3171 auio.uio_segflg = UIO_USERSPACE;
3172 auio.uio_procp = p;
3173 auio.uio_resid = uap->buffersize;
3174
3175 loff = auio.uio_offset = fp->f_offset;
3176 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
3177 error = VOP_READDIRATTR (vp, &attributelist, &auio,
3178 actualcount, uap->options, &newstate, &eofflag,
3179 &actualcount, ((u_long **)0), p->p_cred);
3180
3181 VOP_UNLOCK(vp, 0, p);
3182 if (error) return (error);
3183 fp->f_offset = auio.uio_offset; /* should be multiple of dirent, not variable */
3184
3185 if (error = copyout((caddr_t) &actualcount, (caddr_t) uap->count, sizeof(u_long)))
3186 return (error);
3187 if (error = copyout((caddr_t) &newstate, (caddr_t) uap->newstate, sizeof(u_long)))
3188 return (error);
3189 if (error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)))
3190 return (error);
3191
3192 *retval = eofflag; /* similar to getdirentries */
3193 return (0); /* return error earlier, an retval of 0 or 1 now */
3194
3195 } /* end of getdirentryattr system call */
3196
3197 /*
3198 * Exchange data between two files
3199 */
3200
3201 struct exchangedata_args {
3202 const char *path1; /* pathname of the first swapee */
3203 const char *path2; /* pathname of the second swapee */
3204 unsigned long options; /* options */
3205 };
3206 /* ARGSUSED */
3207 int
3208 exchangedata (p,uap,retval)
3209 struct proc *p;
3210 register struct exchangedata_args *uap;
3211 register_t *retval;
3212
3213 {
3214
3215 struct nameidata fnd, snd;
3216 struct vnode *fvp, *svp;
3217 int error;
3218 u_long nameiflags;
3219
3220 nameiflags = 0;
3221 if ((uap->options & FSOPT_NOFOLLOW) == 0) nameiflags |= FOLLOW;
3222
3223 /* Global lock, to prevent race condition, only one exchange at a time */
3224 lockmgr(&exchangelock, LK_EXCLUSIVE , (struct slock *)0, p);
3225
3226 NDINIT(&fnd, LOOKUP, nameiflags, UIO_USERSPACE, (char *) uap->path1, p);
3227
3228 if (error = namei(&fnd))
3229 goto out2;
3230
3231 fvp = fnd.ni_vp;
3232
3233 NDINIT(&snd, LOOKUP, nameiflags, UIO_USERSPACE, (char *)uap->path2, p);
3234
3235 if (error = namei(&snd)) {
3236 vrele(fvp);
3237 goto out2;
3238 }
3239
3240 svp = snd.ni_vp;
3241
3242 /* if the files are the same, return an inval error */
3243 if (svp == fvp) {
3244 vrele(fvp);
3245 vrele(svp);
3246 error = EINVAL;
3247 goto out2;
3248 }
3249
3250 vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p);
3251 vn_lock(svp, LK_EXCLUSIVE | LK_RETRY, p);
3252
3253 error = VOP_ACCESS(fvp, VWRITE, p->p_ucred, p);
3254 if (error) goto out;
3255
3256 error = VOP_ACCESS(svp, VWRITE, p->p_ucred, p);
3257 if (error) goto out;
3258
3259 /* Ok, make the call */
3260 error = VOP_EXCHANGE (fvp, svp, p->p_ucred, p);
3261
3262 out:
3263 vput (svp);
3264 vput (fvp);
3265
3266 out2:
3267 lockmgr(&exchangelock, LK_RELEASE, (struct slock *)0, p);
3268
3269 if (error) {
3270 return (error);
3271 }
3272
3273 return (0);
3274
3275 } /* end of exchangedata system call */
3276
3277 /*
3278 * Check users access to a file
3279 */
3280
3281 struct checkuseraccess_args {
3282 const char *path; /* pathname of the target file */
3283 uid_t userid; /* user for whom we are checking access */
3284 gid_t *groups; /* Group that we are checking for */
3285 int ngroups; /* Number of groups being checked */
3286 int accessrequired; /* needed access to the file */
3287 unsigned long options; /* options */
3288 };
3289
3290 /* ARGSUSED */
3291 int
3292 checkuseraccess (p,uap,retval)
3293 struct proc *p;
3294 register struct checkuseraccess_args *uap;
3295 register_t *retval;
3296
3297 {
3298 register struct vnode *vp;
3299 int error;
3300 struct nameidata nd;
3301 struct ucred cred;
3302 int flags; /*what will actually get passed to access*/
3303 u_long nameiflags;
3304
3305 /* Make sure that the number of groups is correct before we do anything */
3306
3307 if ((uap->ngroups <= 0) || (uap->ngroups > NGROUPS))
3308 return (EINVAL);
3309
3310 /* Verify that the caller is root */
3311
3312 if (error = suser(p->p_ucred, &p->p_acflag))
3313 return(error);
3314
3315 /* Fill in the credential structure */
3316
3317 cred.cr_ref = 0;
3318 cred.cr_uid = uap->userid;
3319 cred.cr_ngroups = uap->ngroups;
3320 if (error = copyin((caddr_t) uap->groups, (caddr_t) &(cred.cr_groups), (sizeof(gid_t))*uap->ngroups))
3321 return (error);
3322
3323 /* Get our hands on the file */
3324
3325 nameiflags = LOCKLEAF;
3326 if ((uap->options & FSOPT_NOFOLLOW) == 0) nameiflags |= FOLLOW;
3327 NDINIT(&nd, LOOKUP, nameiflags, UIO_USERSPACE, (char *)uap->path, p);
3328
3329 if (error = namei(&nd))
3330 return (error);
3331 vp = nd.ni_vp;
3332
3333 /* Flags == 0 means only check for existence. */
3334
3335 flags = 0;
3336
3337 if (uap->accessrequired) {
3338 if (uap->accessrequired & R_OK)
3339 flags |= VREAD;
3340 if (uap->accessrequired & W_OK)
3341 flags |= VWRITE;
3342 if (uap->accessrequired & X_OK)
3343 flags |= VEXEC;
3344 }
3345 error = VOP_ACCESS(vp, flags, &cred, p);
3346
3347 vput(vp);
3348
3349 if (error)
3350 return (error);
3351
3352 return (0);
3353
3354 } /* end of checkuseraccess system call */
3355
3356
3357 struct searchfs_args {
3358 const char *path;
3359 struct fssearchblock *searchblock;
3360 u_long *nummatches;
3361 u_long scriptcode;
3362 u_long options;
3363 struct searchstate *state;
3364 };
3365 /* ARGSUSED */
3366
3367 int
3368 searchfs (p,uap,retval)
3369 struct proc *p;
3370 register struct searchfs_args *uap;
3371 register_t *retval;
3372
3373 {
3374 register struct vnode *vp;
3375 int error=0;
3376 int fserror = 0;
3377 struct nameidata nd;
3378 struct fssearchblock searchblock;
3379 struct searchstate *state;
3380 struct attrlist *returnattrs;
3381 void *searchparams1,*searchparams2;
3382 struct iovec aiov;
3383 struct uio auio;
3384 u_long nummatches;
3385 int mallocsize;
3386 u_long nameiflags;
3387
3388
3389 /* Start by copying in fsearchblock paramater list */
3390
3391 if (error = copyin((caddr_t) uap->searchblock, (caddr_t) &searchblock,sizeof(struct fssearchblock)))
3392 return(error);
3393
3394 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
3395 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
3396 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
3397 /* block. */
3398
3399 mallocsize = searchblock.sizeofsearchparams1+searchblock.sizeofsearchparams2 +
3400 sizeof(struct attrlist) + sizeof(struct searchstate);
3401
3402 MALLOC(searchparams1, void *, mallocsize, M_TEMP, M_WAITOK);
3403
3404 /* Now set up the various pointers to the correct place in our newly allocated memory */
3405
3406 searchparams2 = (void *) (((caddr_t) searchparams1) + searchblock.sizeofsearchparams1);
3407 returnattrs = (struct attrlist *) (((caddr_t) searchparams2) + searchblock.sizeofsearchparams2);
3408 state = (struct searchstate *) (((caddr_t) returnattrs) + sizeof (struct attrlist));
3409
3410 /* Now copy in the stuff given our local variables. */
3411
3412 if (error = copyin((caddr_t) searchblock.searchparams1, searchparams1,searchblock.sizeofsearchparams1))
3413 goto freeandexit;
3414
3415 if (error = copyin((caddr_t) searchblock.searchparams2, searchparams2,searchblock.sizeofsearchparams2))
3416 goto freeandexit;
3417
3418 if (error = copyin((caddr_t) searchblock.returnattrs, (caddr_t) returnattrs, sizeof(struct attrlist)))
3419 goto freeandexit;
3420
3421 if (error = copyin((caddr_t) uap->state, (caddr_t) state, sizeof(struct searchstate)))
3422 goto freeandexit;
3423
3424 /* set up the uio structure which will contain the users return buffer */
3425
3426 aiov.iov_base = searchblock.returnbuffer;
3427 aiov.iov_len = searchblock.returnbuffersize;
3428 auio.uio_iov = &aiov;
3429 auio.uio_iovcnt = 1;
3430 auio.uio_rw = UIO_READ;
3431 auio.uio_segflg = UIO_USERSPACE;
3432 auio.uio_procp = p;
3433 auio.uio_resid = searchblock.returnbuffersize;
3434
3435 nameiflags = LOCKLEAF;
3436 if ((uap->options & FSOPT_NOFOLLOW) == 0) nameiflags |= FOLLOW;
3437 NDINIT(&nd, LOOKUP, nameiflags, UIO_USERSPACE, (char *)uap->path, p);
3438
3439 if (error = namei(&nd))
3440 goto freeandexit;
3441
3442 vp = nd.ni_vp;
3443
3444
3445 /*
3446 * If searchblock.maxmatches == 0, then skip the search. This has happened
3447 * before and sometimes the underlyning code doesnt deal with it well.
3448 */
3449 if (searchblock.maxmatches == 0) {
3450 nummatches = 0;
3451 goto saveandexit;
3452 }
3453
3454 /*
3455 Allright, we have everything we need, so lets make that call.
3456
3457 We keep special track of the return value from the file system:
3458 EAGAIN is an acceptable error condition that shouldn't keep us
3459 from copying out any results...
3460 */
3461
3462 fserror = VOP_SEARCHFS(vp,
3463 searchparams1,
3464 searchparams2,
3465 &searchblock.searchattrs,
3466 searchblock.maxmatches,
3467 &searchblock.timelimit,
3468 returnattrs,
3469 &nummatches,
3470 uap->scriptcode,
3471 uap->options,
3472 &auio,
3473 state);
3474
3475 saveandexit:
3476
3477 vput(vp);
3478
3479 /* Now copy out the stuff that needs copying out. That means the number of matches, the
3480 search state. Everything was already put into he return buffer by the vop call. */
3481
3482 if (error = copyout((caddr_t) state, (caddr_t) uap->state, sizeof(struct searchstate)))
3483 goto freeandexit;
3484
3485 if (error = copyout((caddr_t) &nummatches, (caddr_t) uap->nummatches, sizeof(u_long)))
3486 goto freeandexit;
3487
3488 error = fserror;
3489
3490 freeandexit:
3491
3492 FREE(searchparams1,M_TEMP);
3493
3494 return(error);
3495
3496
3497 } /* end of searchfs system call */
3498
3499
3500 /*
3501 * Make a filesystem-specific control call:
3502 */
3503 struct fsctl_args {
3504 const char *path; /* pathname of the target object */
3505 u_long cmd; /* cmd (also encodes size/direction of arguments a la ioctl) */
3506 caddr_t data; /* pointer to argument buffer */
3507 u_long options; /* options for fsctl processing */
3508 };
3509 /* ARGSUSED */
3510 int
3511 fsctl (p,uap,retval)
3512 struct proc *p;
3513 struct fsctl_args *uap;
3514 register_t *retval;
3515
3516 {
3517 int error;
3518 struct nameidata nd;
3519 u_long nameiflags;
3520 u_long cmd = uap->cmd;
3521 register u_int size;
3522 #define STK_PARAMS 128
3523 char stkbuf[STK_PARAMS];
3524 caddr_t data, memp;
3525
3526 size = IOCPARM_LEN(cmd);
3527 if (size > IOCPARM_MAX) return (EINVAL);
3528
3529 memp = NULL;
3530 if (size > sizeof (stkbuf)) {
3531 if ((memp = (caddr_t)kalloc(size)) == 0) return ENOMEM;
3532 data = memp;
3533 } else {
3534 data = stkbuf;
3535 };
3536
3537 if (cmd & IOC_IN) {
3538 if (size) {
3539 error = copyin(uap->data, data, (u_int)size);
3540 if (error) goto FSCtl_Exit;
3541 } else {
3542 *(caddr_t *)data = uap->data;
3543 };
3544 } else if ((cmd & IOC_OUT) && size) {
3545 /*
3546 * Zero the buffer so the user always
3547 * gets back something deterministic.
3548 */
3549 bzero(data, size);
3550 } else if (cmd & IOC_VOID)
3551 *(caddr_t *)data = uap->data;
3552
3553 /* Get the vnode for the file we are getting info on: */
3554 nameiflags = LOCKLEAF;
3555 if ((uap->options & FSOPT_NOFOLLOW) == 0) nameiflags |= FOLLOW;
3556 NDINIT(&nd, LOOKUP, nameiflags, UIO_USERSPACE, (char *)uap->path, p);
3557 if (error = namei(&nd)) goto FSCtl_Exit;
3558
3559 /* Invoke the filesystem-specific code */
3560 error = VOP_IOCTL(nd.ni_vp, IOCBASECMD(cmd), data, uap->options, p->p_ucred, p);
3561
3562 vput(nd.ni_vp);
3563
3564 /*
3565 * Copy any data to user, size was
3566 * already set and checked above.
3567 */
3568 if (error == 0 && (cmd & IOC_OUT) && size) error = copyout(data, uap->data, (u_int)size);
3569
3570 FSCtl_Exit:
3571 if (memp) kfree(memp, size);
3572
3573 return error;
3574 }
3575 /* end of fsctl system call */