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