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