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