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