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