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