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