]> git.saurik.com Git - apple/xnu.git/blob - bsd/vfs/vfs_syscalls.c
xnu-517.9.5.tar.gz
[apple/xnu.git] / bsd / vfs / vfs_syscalls.c
1 /*
2 * Copyright (c) 1995-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * Copyright (c) 1989, 1993
24 * The Regents of the University of California. All rights reserved.
25 * (c) UNIX System Laboratories, Inc.
26 * All or some portions of this file are derived from material licensed
27 * to the University of California by American Telephone and Telegraph
28 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
29 * the permission of UNIX System Laboratories, Inc.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. All advertising materials mentioning features or use of this software
40 * must display the following acknowledgement:
41 * This product includes software developed by the University of
42 * California, Berkeley and its contributors.
43 * 4. Neither the name of the University nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * SUCH DAMAGE.
58 *
59 * @(#)vfs_syscalls.c 8.41 (Berkeley) 6/15/95
60 */
61
62 #include <sys/param.h>
63 #include <sys/systm.h>
64 #include <sys/namei.h>
65 #include <sys/filedesc.h>
66 #include <sys/kernel.h>
67 #include <sys/file.h>
68 #include <sys/stat.h>
69 #include <sys/vnode.h>
70 #include <sys/mount.h>
71 #include <sys/proc.h>
72 #include <sys/uio.h>
73 #include <sys/malloc.h>
74 #include <sys/dirent.h>
75 #include <sys/attr.h>
76 #include <sys/sysctl.h>
77 #include <sys/ubc.h>
78 #include <sys/quota.h>
79
80 #include <bsm/audit_kernel.h>
81 #include <bsm/audit_kevents.h>
82
83 #include <machine/cons.h>
84 #include <miscfs/specfs/specdev.h>
85
86 #include <architecture/byte_order.h>
87
88 struct lock__bsd__ exchangelock;
89
90 /*
91 * The currently logged-in user, for ownership of files/directories whose on-disk
92 * permissions are ignored:
93 */
94 uid_t console_user;
95
96 static int change_dir __P((struct nameidata *ndp, struct proc *p));
97 static void checkdirs __P((struct vnode *olddp));
98 static void enablequotas __P((struct proc *p, struct mount *mp));
99 void notify_filemod_watchers(struct vnode *vp, struct proc *p);
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 flags = FFLAGS(uap->flags);
1070
1071 AUDIT_ARG(fflags, oflags);
1072 AUDIT_ARG(mode, uap->mode);
1073
1074 cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
1075
1076 if ((oflags & O_ACCMODE) == O_ACCMODE)
1077 return(EINVAL);
1078 if (error = falloc(p, &nfp, &indx))
1079 return (error);
1080 fp = nfp;
1081 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1, UIO_USERSPACE, uap->path, p);
1082 p->p_dupfd = -indx - 1; /* XXX check for fdopen */
1083 if (error = vn_open_modflags(&nd, &flags, cmode)) {
1084 ffree(fp);
1085 if ((error == ENODEV || error == ENXIO) &&
1086 p->p_dupfd >= 0 && /* XXX from fdopen */
1087 (error =
1088 dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
1089 *retval = indx;
1090 return (0);
1091 }
1092 if (error == ERESTART)
1093 error = EINTR;
1094 fdrelse(p, indx);
1095 return (error);
1096 }
1097 p->p_dupfd = 0;
1098 vp = nd.ni_vp;
1099 fp->f_flag = flags & FMASK;
1100 fp->f_type = DTYPE_VNODE;
1101 fp->f_ops = &vnops;
1102 fp->f_data = (caddr_t)vp;
1103
1104 VOP_UNLOCK(vp, 0, p);
1105 if (flags & (O_EXLOCK | O_SHLOCK)) {
1106 lf.l_whence = SEEK_SET;
1107 lf.l_start = 0;
1108 lf.l_len = 0;
1109 if (flags & O_EXLOCK)
1110 lf.l_type = F_WRLCK;
1111 else
1112 lf.l_type = F_RDLCK;
1113 type = F_FLOCK;
1114 if ((flags & FNONBLOCK) == 0)
1115 type |= F_WAIT;
1116 if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type))
1117 goto bad;
1118 fp->f_flag |= FHASLOCK;
1119 }
1120
1121 if (flags & O_TRUNC) {
1122 struct vattr vat;
1123 struct vattr *vap = &vat;
1124
1125 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1126 (void)vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */
1127 VATTR_NULL(vap);
1128 vap->va_size = 0;
1129 /* try to truncate by setting the size attribute */
1130 error = VOP_SETATTR(vp, vap, p->p_ucred, p);
1131 VOP_UNLOCK(vp, 0, p); /* XXX */
1132 if (error)
1133 goto bad;
1134 }
1135
1136 *fdflags(p, indx) &= ~UF_RESERVED;
1137 *retval = indx;
1138 return (0);
1139 bad:
1140 vn_close(vp, fp->f_flag, fp->f_cred, p);
1141 ffree(fp);
1142 fdrelse(p, indx);
1143 return (error);
1144 }
1145
1146 #if COMPAT_43
1147 /*
1148 * Create a file.
1149 */
1150 struct ocreat_args {
1151 char *path;
1152 int mode;
1153 };
1154 int
1155 ocreat(p, uap, retval)
1156 struct proc *p;
1157 register struct ocreat_args *uap;
1158 register_t *retval;
1159 {
1160 struct open_args nuap;
1161
1162 nuap.path = uap->path;
1163 nuap.mode = uap->mode;
1164 nuap.flags = O_WRONLY | O_CREAT | O_TRUNC;
1165 return (open(p, &nuap, retval));
1166 }
1167 #endif /* COMPAT_43 */
1168
1169 /*
1170 * Create a special file.
1171 */
1172 struct mknod_args {
1173 char *path;
1174 int mode;
1175 int dev;
1176 };
1177 /* ARGSUSED */
1178 int
1179 mknod(p, uap, retval)
1180 struct proc *p;
1181 register struct mknod_args *uap;
1182 register_t *retval;
1183 {
1184 register struct vnode *vp;
1185 struct vattr vattr;
1186 int cmode, error;
1187 int whiteout;
1188 struct nameidata nd;
1189
1190 AUDIT_ARG(mode, uap->mode);
1191 AUDIT_ARG(dev, uap->dev);
1192 cmode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
1193 if (error = suser(p->p_ucred, &p->p_acflag))
1194 return (error);
1195 bwillwrite();
1196 NDINIT(&nd, CREATE, LOCKPARENT | AUDITVNPATH1, UIO_USERSPACE, uap->path, p);
1197 error = namei(&nd);
1198 if (error)
1199 return (error);
1200 vp = nd.ni_vp;
1201 if (vp != NULL)
1202 error = EEXIST;
1203 else {
1204 VATTR_NULL(&vattr);
1205 vattr.va_mode = cmode;
1206 vattr.va_rdev = uap->dev;
1207 whiteout = 0;
1208
1209 switch (uap->mode & S_IFMT) {
1210 case S_IFMT: /* used by badsect to flag bad sectors */
1211 vattr.va_type = VBAD;
1212 break;
1213 case S_IFCHR:
1214 vattr.va_type = VCHR;
1215 break;
1216 case S_IFBLK:
1217 vattr.va_type = VBLK;
1218 break;
1219 case S_IFWHT:
1220 whiteout = 1;
1221 break;
1222 default:
1223 error = EINVAL;
1224 break;
1225 }
1226 }
1227 if (!error) {
1228 char *nameptr;
1229 nameptr = add_name(nd.ni_cnd.cn_nameptr, nd.ni_cnd.cn_namelen, nd.ni_cnd.cn_hash, 0);
1230 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1231 if (whiteout) {
1232 error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
1233 if (error)
1234 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1235 vput(nd.ni_dvp);
1236 } else {
1237 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
1238 &nd.ni_cnd, &vattr);
1239 }
1240
1241 if (error == 0 && nd.ni_vp) {
1242 if (VNAME(nd.ni_vp) == NULL) {
1243 VNAME(nd.ni_vp) = nameptr;
1244 nameptr = NULL;
1245 }
1246 if (VPARENT(nd.ni_vp) == NULL) {
1247 if (vget(nd.ni_dvp, 0, p) == 0) {
1248 VPARENT(nd.ni_vp) = nd.ni_dvp;
1249 }
1250 }
1251 }
1252 if (nameptr) {
1253 remove_name(nameptr);
1254 nameptr = NULL;
1255 }
1256 } else {
1257 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1258 if (nd.ni_dvp == vp)
1259 vrele(nd.ni_dvp);
1260 else
1261 vput(nd.ni_dvp);
1262 if (vp)
1263 vrele(vp);
1264 }
1265 return (error);
1266 }
1267
1268 /*
1269 * Create a named pipe.
1270 */
1271 struct mkfifo_args {
1272 char *path;
1273 int mode;
1274 };
1275 /* ARGSUSED */
1276 int
1277 mkfifo(p, uap, retval)
1278 struct proc *p;
1279 register struct mkfifo_args *uap;
1280 register_t *retval;
1281 {
1282 struct vattr vattr;
1283 int error;
1284 struct nameidata nd;
1285 char *nameptr=NULL;
1286
1287
1288 #if !FIFO
1289 return (EOPNOTSUPP);
1290 #else
1291 bwillwrite();
1292 NDINIT(&nd, CREATE, LOCKPARENT | AUDITVNPATH1, UIO_USERSPACE, uap->path, p);
1293 error = namei(&nd);
1294 if (error)
1295 return (error);
1296 if (nd.ni_vp != NULL) {
1297 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1298 if (nd.ni_dvp == nd.ni_vp)
1299 vrele(nd.ni_dvp);
1300 else
1301 vput(nd.ni_dvp);
1302 vrele(nd.ni_vp);
1303 return (EEXIST);
1304 }
1305
1306 nameptr = add_name(nd.ni_cnd.cn_nameptr,
1307 nd.ni_cnd.cn_namelen,
1308 nd.ni_cnd.cn_hash, 0);
1309 VATTR_NULL(&vattr);
1310 vattr.va_type = VFIFO;
1311 vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
1312 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1313 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
1314
1315 if (error == 0 && nd.ni_vp && nd.ni_vp->v_type == VFIFO) {
1316 int vpid = nd.ni_vp->v_id;
1317 if (vget(nd.ni_vp, 0, p) == 0) {
1318 if (vpid == nd.ni_vp->v_id && nd.ni_vp->v_type == VFIFO) {
1319 VNAME(nd.ni_vp) = nameptr;
1320 nameptr = NULL;
1321
1322 if (VPARENT(nd.ni_vp) == NULL) {
1323 if (vget(nd.ni_dvp, 0, p) == 0) {
1324 VPARENT(nd.ni_vp) = nd.ni_dvp;
1325 }
1326 }
1327 }
1328 }
1329 }
1330 if (nameptr) {
1331 remove_name(nameptr);
1332 }
1333 return error;
1334 #endif /* FIFO */
1335 }
1336
1337 /*
1338 * Make a hard file link.
1339 */
1340 struct link_args {
1341 char *path;
1342 char *link;
1343 };
1344 /* ARGSUSED */
1345 int
1346 link(p, uap, retval)
1347 struct proc *p;
1348 register struct link_args *uap;
1349 register_t *retval;
1350 {
1351 register struct vnode *vp;
1352 struct nameidata nd;
1353 int error;
1354
1355 bwillwrite();
1356 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1, UIO_USERSPACE, uap->path, p);
1357 error = namei(&nd);
1358 if (error)
1359 return (error);
1360 vp = nd.ni_vp;
1361 if (vp->v_type == VDIR)
1362 error = EPERM; /* POSIX */
1363 else {
1364 nd.ni_cnd.cn_nameiop = CREATE;
1365 nd.ni_cnd.cn_flags = LOCKPARENT | AUDITVNPATH2;
1366 nd.ni_dirp = uap->link;
1367 error = namei(&nd);
1368 if (error == 0) {
1369 if (nd.ni_vp != NULL)
1370 error = EEXIST;
1371 if (!error) {
1372 VOP_LEASE(nd.ni_dvp, p, p->p_ucred,
1373 LEASE_WRITE);
1374 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1375 error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd);
1376 } else {
1377 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1378 if (nd.ni_dvp == nd.ni_vp)
1379 vrele(nd.ni_dvp);
1380 else
1381 vput(nd.ni_dvp);
1382 if (nd.ni_vp)
1383 vrele(nd.ni_vp);
1384 }
1385 }
1386 }
1387 vrele(vp);
1388 return (error);
1389 }
1390
1391 /*
1392 * Make a symbolic link.
1393 */
1394 struct symlink_args {
1395 char *path;
1396 char *link;
1397 };
1398 /* ARGSUSED */
1399 int
1400 symlink(p, uap, retval)
1401 struct proc *p;
1402 register struct symlink_args *uap;
1403 register_t *retval;
1404 {
1405 struct vattr vattr;
1406 char *path, *nameptr;
1407 int error;
1408 struct nameidata nd;
1409 size_t dummy=0;
1410 u_long vpid;
1411
1412 MALLOC_ZONE(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
1413 if (error = copyinstr(uap->path, path, MAXPATHLEN, &dummy))
1414 goto out;
1415 AUDIT_ARG(text, path); /* This is the link string */
1416 bwillwrite();
1417 NDINIT(&nd, CREATE, LOCKPARENT | AUDITVNPATH1, UIO_USERSPACE, uap->link, p);
1418 error = namei(&nd);
1419 if (error)
1420 goto out;
1421 if (nd.ni_vp) {
1422 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1423 if (nd.ni_dvp == nd.ni_vp)
1424 vrele(nd.ni_dvp);
1425 else
1426 vput(nd.ni_dvp);
1427 vrele(nd.ni_vp);
1428 error = EEXIST;
1429 goto out;
1430 }
1431 VATTR_NULL(&vattr);
1432 vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
1433 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1434
1435 nameptr = add_name(nd.ni_cnd.cn_nameptr, nd.ni_cnd.cn_namelen, nd.ni_cnd.cn_hash, 0);
1436
1437 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1438
1439 // have to do this little dance because nd.ni_vp is not locked
1440 // on return from the VOP_SYMLINK() call.
1441 //
1442 if (error == 0 && nd.ni_vp && nd.ni_vp->v_type == VLNK) {
1443 vpid = nd.ni_vp->v_id;
1444 if (vget(nd.ni_vp, 0, p) == 0) {
1445 if (vpid == nd.ni_vp->v_id && nd.ni_vp->v_type == VLNK) {
1446 VNAME(nd.ni_vp) = nameptr;
1447 nameptr = NULL;
1448
1449 if (VPARENT(nd.ni_vp) == NULL && vget(nd.ni_dvp, 0, p) == 0) {
1450 VPARENT(nd.ni_vp) = nd.ni_dvp;
1451 }
1452 }
1453 vrele(nd.ni_vp);
1454 }
1455 }
1456 if (nameptr) { // only true if we didn't add it to the vnode
1457 remove_name(nameptr);
1458 }
1459 out:
1460 FREE_ZONE(path, MAXPATHLEN, M_NAMEI);
1461 return (error);
1462 }
1463
1464 /*
1465 * Delete a whiteout from the filesystem.
1466 */
1467 struct undelete_args {
1468 char *path;
1469 };
1470 /* ARGSUSED */
1471 int
1472 undelete(p, uap, retval)
1473 struct proc *p;
1474 register struct undelete_args *uap;
1475 register_t *retval;
1476 {
1477 int error;
1478 struct nameidata nd;
1479
1480 bwillwrite();
1481 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT|AUDITVNPATH1, UIO_USERSPACE,
1482 uap->path, p);
1483 error = namei(&nd);
1484 if (error)
1485 return (error);
1486
1487 if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
1488 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1489 if (nd.ni_dvp == nd.ni_vp)
1490 vrele(nd.ni_dvp);
1491 else
1492 vput(nd.ni_dvp);
1493 if (nd.ni_vp)
1494 vrele(nd.ni_vp);
1495 return (EEXIST);
1496 }
1497
1498 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1499 if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE))
1500 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1501 vput(nd.ni_dvp);
1502 return (error);
1503 }
1504
1505 /*
1506 * Delete a name from the filesystem.
1507 */
1508 struct unlink_args {
1509 char *path;
1510 };
1511 /* ARGSUSED */
1512 static int
1513 _unlink(p, uap, retval, nodelbusy)
1514 struct proc *p;
1515 struct unlink_args *uap;
1516 register_t *retval;
1517 int nodelbusy;
1518 {
1519 register struct vnode *vp;
1520 int error;
1521 struct nameidata nd;
1522
1523 bwillwrite();
1524 NDINIT(&nd, DELETE, LOCKPARENT | AUDITVNPATH1, UIO_USERSPACE, uap->path, p);
1525 /* with Carbon semantics, busy files cannot be deleted */
1526 if (nodelbusy)
1527 nd.ni_cnd.cn_flags |= NODELETEBUSY;
1528 error = namei(&nd);
1529 if (error)
1530 return (error);
1531
1532 vp = nd.ni_vp;
1533 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1534 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1535
1536 if (vp->v_type == VDIR)
1537 error = EPERM; /* POSIX */
1538 else {
1539 /*
1540 * The root of a mounted filesystem cannot be deleted.
1541 *
1542 * XXX: can this only be a VDIR case?
1543 */
1544 if (vp->v_flag & VROOT)
1545 error = EBUSY;
1546 }
1547
1548 if (!error) {
1549 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1550 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1551 } else {
1552 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1553 if (nd.ni_dvp == vp)
1554 vrele(nd.ni_dvp);
1555 else
1556 vput(nd.ni_dvp);
1557 if (vp != NULLVP)
1558 vput(vp);
1559 }
1560 return (error);
1561 }
1562
1563 /*
1564 * Delete a name from the filesystem using POSIX semantics.
1565 */
1566 int
1567 unlink(p, uap, retval)
1568 struct proc *p;
1569 struct unlink_args *uap;
1570 register_t *retval;
1571 {
1572 return _unlink(p, uap, retval, 0);
1573 }
1574
1575 /*
1576 * Delete a name from the filesystem using Carbon semantics.
1577 */
1578 int
1579 delete(p, uap, retval)
1580 struct proc *p;
1581 struct unlink_args *uap;
1582 register_t *retval;
1583 {
1584 return _unlink(p, uap, retval, 1);
1585 }
1586
1587 /*
1588 * Reposition read/write file offset.
1589 */
1590 struct lseek_args {
1591 int fd;
1592 #ifdef DOUBLE_ALIGN_PARAMS
1593 int pad;
1594 #endif
1595 off_t offset;
1596 int whence;
1597 };
1598 int
1599 lseek(p, uap, retval)
1600 struct proc *p;
1601 register struct lseek_args *uap;
1602 register_t *retval;
1603 {
1604 struct ucred *cred = p->p_ucred;
1605 struct file *fp;
1606 struct vnode *vp;
1607 struct vattr vattr;
1608 off_t offset = uap->offset;
1609 int error;
1610
1611 if (error = fdgetf(p, uap->fd, &fp))
1612 return (error);
1613 if (fref(fp) == -1)
1614 return (EBADF);
1615 if (fp->f_type != DTYPE_VNODE) {
1616 frele(fp);
1617 return (ESPIPE);
1618 }
1619 vp = (struct vnode *)fp->f_data;
1620 switch (uap->whence) {
1621 case L_INCR:
1622 offset += fp->f_offset;
1623 break;
1624 case L_XTND:
1625 if (error = VOP_GETATTR(vp, &vattr, cred, p))
1626 break;
1627 offset += vattr.va_size;
1628 break;
1629 case L_SET:
1630 break;
1631 default:
1632 error = EINVAL;
1633 }
1634 if (error == 0) {
1635 if (uap->offset > 0 && offset < 0) {
1636 /* Incremented/relative move past max size */
1637 error = EOVERFLOW;
1638 } else {
1639 /*
1640 * Allow negative offsets on character devices, per
1641 * POSIX 1003.1-2001. Most likely for writing disk
1642 * labels.
1643 */
1644 if (offset < 0 && vp->v_type != VCHR) {
1645 /* Decremented/relative move before start */
1646 error = EINVAL;
1647 } else {
1648 /* Success */
1649 fp->f_offset = offset;
1650 *(off_t *)retval = fp->f_offset;
1651 }
1652 }
1653 }
1654 frele(fp);
1655 return (error);
1656 }
1657
1658 #if COMPAT_43
1659 /*
1660 * Reposition read/write file offset.
1661 */
1662 struct olseek_args {
1663 int fd;
1664 long offset;
1665 int whence;
1666 };
1667 int
1668 olseek(p, uap, retval)
1669 struct proc *p;
1670 register struct olseek_args *uap;
1671 register_t *retval;
1672 {
1673 struct lseek_args /* {
1674 syscallarg(int) fd;
1675 #ifdef DOUBLE_ALIGN_PARAMS
1676 syscallarg(int) pad;
1677 #endif
1678 syscallarg(off_t) offset;
1679 syscallarg(int) whence;
1680 } */ nuap;
1681 off_t qret;
1682 int error;
1683
1684 nuap.fd = uap->fd;
1685 nuap.offset = uap->offset;
1686 nuap.whence = uap->whence;
1687 error = lseek(p, &nuap, &qret);
1688 *(long *)retval = qret;
1689 return (error);
1690 }
1691 #endif /* COMPAT_43 */
1692
1693 /*
1694 * Check access permissions.
1695 */
1696 struct access_args {
1697 char *path;
1698 int flags;
1699 };
1700 int
1701 access(p, uap, retval)
1702 struct proc *p;
1703 register struct access_args *uap;
1704 register_t *retval;
1705 {
1706 register struct ucred *cred = p->p_ucred;
1707 register struct vnode *vp;
1708 int error, flags, t_gid, t_uid;
1709 struct nameidata nd;
1710
1711 t_uid = cred->cr_uid;
1712 t_gid = cred->cr_groups[0];
1713 cred->cr_uid = p->p_cred->p_ruid;
1714 cred->cr_groups[0] = p->p_cred->p_rgid;
1715 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1, UIO_USERSPACE,
1716 uap->path, p);
1717 error = namei(&nd);
1718 if (error)
1719 goto out1;
1720 vp = nd.ni_vp;
1721
1722 /* Flags == 0 means only check for existence. */
1723 if (uap->flags) {
1724 flags = 0;
1725 if (uap->flags & R_OK)
1726 flags |= VREAD;
1727 if (uap->flags & W_OK)
1728 flags |= VWRITE;
1729 if (uap->flags & X_OK)
1730 flags |= VEXEC;
1731 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
1732 error = VOP_ACCESS(vp, flags, cred, p);
1733 }
1734 vput(vp);
1735 out1:
1736 cred->cr_uid = t_uid;
1737 cred->cr_groups[0] = t_gid;
1738 return (error);
1739 }
1740
1741 #if COMPAT_43
1742 /*
1743 * Get file status; this version follows links.
1744 */
1745 struct ostat_args {
1746 char *path;
1747 struct ostat *ub;
1748 };
1749 /* ARGSUSED */
1750 int
1751 ostat(p, uap, retval)
1752 struct proc *p;
1753 register struct ostat_args *uap;
1754 register_t *retval;
1755 {
1756 struct stat sb;
1757 struct ostat osb;
1758 int error;
1759 struct nameidata nd;
1760
1761 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1, UIO_USERSPACE,
1762 uap->path, p);
1763 if (error = namei(&nd))
1764 return (error);
1765 error = vn_stat(nd.ni_vp, &sb, p);
1766 vput(nd.ni_vp);
1767 if (error)
1768 return (error);
1769 cvtstat(&sb, &osb);
1770 error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
1771 return (error);
1772 }
1773
1774 /*
1775 * Get file status; this version does not follow links.
1776 */
1777 struct olstat_args {
1778 char *path;
1779 struct ostat *ub;
1780 };
1781 /* ARGSUSED */
1782 int
1783 olstat(p, uap, retval)
1784 struct proc *p;
1785 register struct olstat_args *uap;
1786 register_t *retval;
1787 {
1788 struct vnode *vp, *dvp;
1789 struct stat sb, sb1;
1790 struct ostat osb;
1791 int error;
1792 struct nameidata nd;
1793
1794 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT | AUDITVNPATH1,
1795 UIO_USERSPACE, uap->path, p);
1796 if (error = namei(&nd))
1797 return (error);
1798 /*
1799 * For symbolic links, always return the attributes of its
1800 * containing directory, except for mode, size, and links.
1801 */
1802 vp = nd.ni_vp;
1803 dvp = nd.ni_dvp;
1804 if (vp->v_type != VLNK) {
1805 if (dvp == vp)
1806 vrele(dvp);
1807 else
1808 vput(dvp);
1809 error = vn_stat(vp, &sb, p);
1810 vput(vp);
1811 if (error)
1812 return (error);
1813 } else {
1814 error = vn_stat(dvp, &sb, p);
1815 vput(dvp);
1816 if (error) {
1817 vput(vp);
1818 return (error);
1819 }
1820 error = vn_stat(vp, &sb1, p);
1821 vput(vp);
1822 if (error)
1823 return (error);
1824 sb.st_mode &= ~S_IFDIR;
1825 sb.st_mode |= S_IFLNK;
1826 sb.st_nlink = sb1.st_nlink;
1827 sb.st_size = sb1.st_size;
1828 sb.st_blocks = sb1.st_blocks;
1829 }
1830 cvtstat(&sb, &osb);
1831 error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
1832 return (error);
1833 }
1834
1835 /*
1836 * Convert from an old to a new stat structure.
1837 */
1838 void
1839 cvtstat(st, ost)
1840 struct stat *st;
1841 struct ostat *ost;
1842 {
1843
1844 ost->st_dev = st->st_dev;
1845 ost->st_ino = st->st_ino;
1846 ost->st_mode = st->st_mode;
1847 ost->st_nlink = st->st_nlink;
1848 ost->st_uid = st->st_uid;
1849 ost->st_gid = st->st_gid;
1850 ost->st_rdev = st->st_rdev;
1851 if (st->st_size < (quad_t)1 << 32)
1852 ost->st_size = st->st_size;
1853 else
1854 ost->st_size = -2;
1855 ost->st_atime = st->st_atime;
1856 ost->st_mtime = st->st_mtime;
1857 ost->st_ctime = st->st_ctime;
1858 ost->st_blksize = st->st_blksize;
1859 ost->st_blocks = st->st_blocks;
1860 ost->st_flags = st->st_flags;
1861 ost->st_gen = st->st_gen;
1862 }
1863 #endif /* COMPAT_43 */
1864
1865 /*
1866 * The stat buffer spare fields are uninitialized
1867 * so don't include them in the copyout.
1868 */
1869 #define STATBUFSIZE \
1870 (sizeof(struct stat) - sizeof(int32_t) - 2 * sizeof(int64_t))
1871 /*
1872 * Get file status; this version follows links.
1873 */
1874 struct stat_args {
1875 char *path;
1876 struct stat *ub;
1877 };
1878 /* ARGSUSED */
1879 int
1880 stat(p, uap, retval)
1881 struct proc *p;
1882 register struct stat_args *uap;
1883 register_t *retval;
1884 {
1885 struct stat sb;
1886 int error;
1887 struct nameidata nd;
1888
1889 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | SHAREDLEAF | AUDITVNPATH1,
1890 UIO_USERSPACE, uap->path, p);
1891 error = namei(&nd);
1892 if (error)
1893 return (error);
1894 error = vn_stat(nd.ni_vp, &sb, p);
1895 vput(nd.ni_vp);
1896 if (error)
1897 return (error);
1898 error = copyout((caddr_t)&sb, (caddr_t)uap->ub, STATBUFSIZE);
1899 return (error);
1900 }
1901
1902 /*
1903 * Get file status; this version does not follow links.
1904 */
1905 struct lstat_args {
1906 char *path;
1907 struct stat *ub;
1908 };
1909 /* ARGSUSED */
1910 int
1911 lstat(p, uap, retval)
1912 struct proc *p;
1913 register struct lstat_args *uap;
1914 register_t *retval;
1915 {
1916 int error;
1917 struct vnode *vp;
1918 struct stat sb;
1919 struct nameidata nd;
1920
1921 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | AUDITVNPATH1, UIO_USERSPACE,
1922 uap->path, p);
1923 error = namei(&nd);
1924 if (error)
1925 return (error);
1926 vp = nd.ni_vp;
1927 error = vn_stat(vp, &sb, p);
1928 vput(vp);
1929 if (error)
1930 return (error);
1931 error = copyout((caddr_t)&sb, (caddr_t)uap->ub, STATBUFSIZE);
1932 return (error);
1933 }
1934
1935 /*
1936 * Get configurable pathname variables.
1937 */
1938 struct pathconf_args {
1939 char *path;
1940 int name;
1941 };
1942 /* ARGSUSED */
1943 int
1944 pathconf(p, uap, retval)
1945 struct proc *p;
1946 register struct pathconf_args *uap;
1947 register_t *retval;
1948 {
1949 int error;
1950 struct nameidata nd;
1951
1952 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1, UIO_USERSPACE,
1953 uap->path, p);
1954 error = namei(&nd);
1955 if (error)
1956 return (error);
1957 error = VOP_PATHCONF(nd.ni_vp, uap->name, retval);
1958 vput(nd.ni_vp);
1959 return (error);
1960 }
1961
1962 /*
1963 * Return target name of a symbolic link.
1964 */
1965 struct readlink_args {
1966 char *path;
1967 char *buf;
1968 int count;
1969 };
1970 /* ARGSUSED */
1971 int
1972 readlink(p, uap, retval)
1973 struct proc *p;
1974 register struct readlink_args *uap;
1975 register_t *retval;
1976 {
1977 register struct vnode *vp;
1978 struct iovec aiov;
1979 struct uio auio;
1980 int error;
1981 struct nameidata nd;
1982
1983 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | AUDITVNPATH1, UIO_USERSPACE,
1984 uap->path, p);
1985 error = namei(&nd);
1986 if (error)
1987 return (error);
1988 vp = nd.ni_vp;
1989 if (vp->v_type != VLNK)
1990 error = EINVAL;
1991 else {
1992 aiov.iov_base = uap->buf;
1993 aiov.iov_len = uap->count;
1994 auio.uio_iov = &aiov;
1995 auio.uio_iovcnt = 1;
1996 auio.uio_offset = 0;
1997 auio.uio_rw = UIO_READ;
1998 auio.uio_segflg = UIO_USERSPACE;
1999 auio.uio_procp = p;
2000 auio.uio_resid = uap->count;
2001 error = VOP_READLINK(vp, &auio, p->p_ucred);
2002 }
2003 vput(vp);
2004 *retval = uap->count - auio.uio_resid;
2005 return (error);
2006 }
2007
2008 /*
2009 * Change flags of a file given a path name.
2010 */
2011 struct chflags_args {
2012 char *path;
2013 int flags;
2014 };
2015 /* ARGSUSED */
2016 int
2017 chflags(p, uap, retval)
2018 struct proc *p;
2019 register struct chflags_args *uap;
2020 register_t *retval;
2021 {
2022 register struct vnode *vp;
2023 struct vattr vattr;
2024 int error;
2025 struct nameidata nd;
2026
2027 AUDIT_ARG(fflags, uap->flags);
2028 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1, UIO_USERSPACE, uap->path, p);
2029 error = namei(&nd);
2030 if (error)
2031 return (error);
2032 vp = nd.ni_vp;
2033 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2034 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2035 VATTR_NULL(&vattr);
2036 vattr.va_flags = uap->flags;
2037 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2038 vput(vp);
2039 return (error);
2040 }
2041
2042 /*
2043 * Change flags of a file given a file descriptor.
2044 */
2045 struct fchflags_args {
2046 int fd;
2047 int flags;
2048 };
2049 /* ARGSUSED */
2050 int
2051 fchflags(p, uap, retval)
2052 struct proc *p;
2053 register struct fchflags_args *uap;
2054 register_t *retval;
2055 {
2056 struct vattr vattr;
2057 struct vnode *vp;
2058 struct file *fp;
2059 int error;
2060
2061 AUDIT_ARG(fd, uap->fd);
2062 AUDIT_ARG(fflags, uap->flags);
2063 if (error = getvnode(p, uap->fd, &fp))
2064 return (error);
2065
2066 vp = (struct vnode *)fp->f_data;
2067
2068 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2069 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2070
2071 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
2072
2073 VATTR_NULL(&vattr);
2074 vattr.va_flags = uap->flags;
2075 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2076 VOP_UNLOCK(vp, 0, p);
2077 return (error);
2078 }
2079
2080 /*
2081 * Change mode of a file given path name.
2082 */
2083 struct chmod_args {
2084 char *path;
2085 int mode;
2086 };
2087 /* ARGSUSED */
2088 int
2089 chmod(p, uap, retval)
2090 struct proc *p;
2091 register struct chmod_args *uap;
2092 register_t *retval;
2093 {
2094 register struct vnode *vp;
2095 struct vattr vattr;
2096 int error;
2097 struct nameidata nd;
2098
2099 AUDIT_ARG(mode, (mode_t)uap->mode);
2100
2101 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1, UIO_USERSPACE, uap->path, p);
2102 error = namei(&nd);
2103 if (error)
2104 return (error);
2105 vp = nd.ni_vp;
2106 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2107 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2108 VATTR_NULL(&vattr);
2109 vattr.va_mode = uap->mode & ALLPERMS;
2110 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2111
2112 vput(vp);
2113 return (error);
2114 }
2115
2116 /*
2117 * Change mode of a file given a file descriptor.
2118 */
2119 struct fchmod_args {
2120 int fd;
2121 int mode;
2122 };
2123 /* ARGSUSED */
2124 int
2125 fchmod(p, uap, retval)
2126 struct proc *p;
2127 register struct fchmod_args *uap;
2128 register_t *retval;
2129 {
2130 struct vattr vattr;
2131 struct vnode *vp;
2132 struct file *fp;
2133 int error;
2134
2135 AUDIT_ARG(fd, uap->fd);
2136 AUDIT_ARG(mode, (mode_t)uap->mode);
2137 if (error = getvnode(p, uap->fd, &fp))
2138 return (error);
2139
2140 vp = (struct vnode *)fp->f_data;
2141 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2142 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2143
2144 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
2145
2146 VATTR_NULL(&vattr);
2147 vattr.va_mode = uap->mode & ALLPERMS;
2148 AUDIT_ARG(mode, (mode_t)vattr.va_mode);
2149 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2150
2151 VOP_UNLOCK(vp, 0, p);
2152
2153 return (error);
2154 }
2155
2156 /*
2157 * Set ownership given a path name.
2158 */
2159 struct chown_args {
2160 char *path;
2161 int uid;
2162 int gid;
2163 };
2164 /* ARGSUSED */
2165 int
2166 chown(p, uap, retval)
2167 struct proc *p;
2168 register struct chown_args *uap;
2169 register_t *retval;
2170 {
2171 register struct vnode *vp;
2172 struct vattr vattr;
2173 int error;
2174 struct nameidata nd;
2175
2176 AUDIT_ARG(owner, uap->uid, uap->gid);
2177
2178 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1, UIO_USERSPACE, uap->path, p);
2179 error = namei(&nd);
2180 if (error)
2181 return (error);
2182 vp = nd.ni_vp;
2183
2184 /*
2185 * XXX A TEMPORARY HACK FOR NOW: Try to track console_user
2186 * by looking for chown() calls on /dev/console from a console process.
2187 */
2188 if ((vp) && (vp->v_type == VBLK || vp->v_type == VCHR) && (vp->v_specinfo) &&
2189 (major(vp->v_specinfo->si_rdev) == CONSMAJOR) &&
2190 (minor(vp->v_specinfo->si_rdev) == 0)) {
2191 console_user = uap->uid;
2192 };
2193
2194 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2195 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2196 VATTR_NULL(&vattr);
2197 vattr.va_uid = uap->uid;
2198 vattr.va_gid = uap->gid;
2199 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2200
2201 vput(vp);
2202 return (error);
2203 }
2204
2205 /*
2206 * Set ownership given a file descriptor.
2207 */
2208 struct fchown_args {
2209 int fd;
2210 int uid;
2211 int gid;
2212 };
2213 /* ARGSUSED */
2214 int
2215 fchown(p, uap, retval)
2216 struct proc *p;
2217 register struct fchown_args *uap;
2218 register_t *retval;
2219 {
2220 struct vattr vattr;
2221 struct vnode *vp;
2222 struct file *fp;
2223 int error;
2224
2225 AUDIT_ARG(owner, uap->uid, uap->gid);
2226 AUDIT_ARG(fd, uap->fd);
2227
2228 if (error = getvnode(p, uap->fd, &fp))
2229 return (error);
2230
2231 vp = (struct vnode *)fp->f_data;
2232 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2233 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2234
2235 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
2236
2237 VATTR_NULL(&vattr);
2238 vattr.va_uid = uap->uid;
2239 vattr.va_gid = uap->gid;
2240 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2241
2242 VOP_UNLOCK(vp, 0, p);
2243 return (error);
2244 }
2245
2246 static int
2247 getutimes(usrtvp, tsp)
2248 const struct timeval *usrtvp;
2249 struct timespec *tsp;
2250 {
2251 struct timeval tv[2];
2252 int error;
2253
2254 if (usrtvp == NULL) {
2255 microtime(&tv[0]);
2256 TIMEVAL_TO_TIMESPEC(&tv[0], &tsp[0]);
2257 tsp[1] = tsp[0];
2258 } else {
2259 if ((error = copyin((void *)usrtvp, (void *)tv, sizeof (tv))) != 0)
2260 return (error);
2261 TIMEVAL_TO_TIMESPEC(&tv[0], &tsp[0]);
2262 TIMEVAL_TO_TIMESPEC(&tv[1], &tsp[1]);
2263 }
2264 return 0;
2265 }
2266
2267 static int
2268 setutimes(p, vp, ts, nullflag)
2269 struct proc *p;
2270 struct vnode *vp;
2271 const struct timespec *ts;
2272 int nullflag;
2273 {
2274 int error;
2275 struct vattr vattr;
2276
2277 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2278 error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2279 if (error)
2280 goto out;
2281
2282 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
2283
2284 VATTR_NULL(&vattr);
2285 vattr.va_atime = ts[0];
2286 vattr.va_mtime = ts[1];
2287 if (nullflag)
2288 vattr.va_vaflags |= VA_UTIMES_NULL;
2289 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2290
2291 VOP_UNLOCK(vp, 0, p);
2292 out:
2293 return error;
2294 }
2295
2296 /*
2297 * Set the access and modification times of a file.
2298 */
2299 struct utimes_args {
2300 char *path;
2301 struct timeval *tptr;
2302 };
2303 /* ARGSUSED */
2304 int
2305 utimes(p, uap, retval)
2306 struct proc *p;
2307 register struct utimes_args *uap;
2308 register_t *retval;
2309 {
2310 struct timespec ts[2];
2311 struct timeval *usrtvp;
2312 int error;
2313 struct nameidata nd;
2314
2315 /* AUDIT: Needed to change the order of operations to do the
2316 * name lookup first because auditing wants the path.
2317 */
2318 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1, UIO_USERSPACE, uap->path, p);
2319 error = namei(&nd);
2320 if (error)
2321 return (error);
2322
2323 usrtvp = uap->tptr;
2324 if ((error = getutimes(usrtvp, ts)) != 0) {
2325 vrele(nd.ni_vp);
2326 return (error);
2327 }
2328 error = setutimes(p, nd.ni_vp, ts, usrtvp == NULL);
2329 vrele(nd.ni_vp);
2330 return (error);
2331 }
2332
2333 /*
2334 * Set the access and modification times of a file.
2335 */
2336 struct futimes_args {
2337 int fd;
2338 struct timeval *tptr;
2339 };
2340 /* ARGSUSED */
2341 int
2342 futimes(p, uap, retval)
2343 struct proc *p;
2344 register struct futimes_args *uap;
2345 register_t *retval;
2346 {
2347 struct timespec ts[2];
2348 struct file *fp;
2349 struct timeval *usrtvp;
2350 int error;
2351
2352 AUDIT_ARG(fd, uap->fd);
2353 usrtvp = uap->tptr;
2354 if ((error = getutimes(usrtvp, ts)) != 0)
2355 return (error);
2356 if ((error = getvnode(p, uap->fd, &fp)) != 0)
2357 return (error);
2358
2359 return setutimes(p, (struct vnode *)fp->f_data, ts, usrtvp == NULL);
2360 }
2361
2362 /*
2363 * Truncate a file given its path name.
2364 */
2365 struct truncate_args {
2366 char *path;
2367 #ifdef DOUBLE_ALIGN_PARAMS
2368 int pad;
2369 #endif
2370 off_t length;
2371 };
2372 /* ARGSUSED */
2373 int
2374 truncate(p, uap, retval)
2375 struct proc *p;
2376 register struct truncate_args *uap;
2377 register_t *retval;
2378 {
2379 register struct vnode *vp;
2380 struct vattr vattr;
2381 int error;
2382 struct nameidata nd;
2383
2384 if (uap->length < 0)
2385 return(EINVAL);
2386 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1, UIO_USERSPACE, uap->path, p);
2387 if (error = namei(&nd))
2388 return (error);
2389 vp = nd.ni_vp;
2390 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2391 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2392 if (vp->v_type == VDIR)
2393 error = EISDIR;
2394 else if ((error = vn_writechk(vp)) == 0 &&
2395 (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
2396 VATTR_NULL(&vattr);
2397 vattr.va_size = uap->length;
2398 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2399 }
2400 vput(vp);
2401 return (error);
2402 }
2403
2404 /*
2405 * Truncate a file given a file descriptor.
2406 */
2407 struct ftruncate_args {
2408 int fd;
2409 #ifdef DOUBLE_ALIGN_PARAMS
2410 int pad;
2411 #endif
2412 off_t length;
2413 };
2414 /* ARGSUSED */
2415 int
2416 ftruncate(p, uap, retval)
2417 struct proc *p;
2418 register struct ftruncate_args *uap;
2419 register_t *retval;
2420 {
2421 struct vattr vattr;
2422 struct vnode *vp;
2423 struct file *fp;
2424 int error;
2425
2426 AUDIT_ARG(fd, uap->fd);
2427 if (uap->length < 0)
2428 return(EINVAL);
2429
2430 if (error = fdgetf(p, uap->fd, &fp))
2431 return (error);
2432
2433 if (fp->f_type == DTYPE_PSXSHM) {
2434 return(pshm_truncate(p, fp, uap->fd, uap->length, retval));
2435 }
2436 if (fp->f_type != DTYPE_VNODE)
2437 return (EINVAL);
2438
2439 AUDIT_ARG(vnpath, (struct vnode *)fp->f_data, ARG_VNODE1);
2440
2441 if ((fp->f_flag & FWRITE) == 0)
2442 return (EINVAL);
2443 vp = (struct vnode *)fp->f_data;
2444 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2445 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2446 if (vp->v_type == VDIR)
2447 error = EISDIR;
2448 else if ((error = vn_writechk(vp)) == 0) {
2449 VATTR_NULL(&vattr);
2450 vattr.va_size = uap->length;
2451 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
2452 }
2453 VOP_UNLOCK(vp, 0, p);
2454 return (error);
2455 }
2456
2457 #if COMPAT_43
2458 /*
2459 * Truncate a file given its path name.
2460 */
2461 struct otruncate_args {
2462 char *path;
2463 long length;
2464 };
2465 /* ARGSUSED */
2466 int
2467 otruncate(p, uap, retval)
2468 struct proc *p;
2469 register struct otruncate_args *uap;
2470 register_t *retval;
2471 {
2472 struct truncate_args /* {
2473 syscallarg(char *) path;
2474 #ifdef DOUBLE_ALIGN_PARAMS
2475 syscallarg(int) pad;
2476 #endif
2477 syscallarg(off_t) length;
2478 } */ nuap;
2479
2480 nuap.path = uap->path;
2481 nuap.length = uap->length;
2482 return (truncate(p, &nuap, retval));
2483 }
2484
2485 /*
2486 * Truncate a file given a file descriptor.
2487 */
2488 struct oftruncate_args {
2489 int fd;
2490 long length;
2491 };
2492 /* ARGSUSED */
2493 int
2494 oftruncate(p, uap, retval)
2495 struct proc *p;
2496 register struct oftruncate_args *uap;
2497 register_t *retval;
2498 {
2499 struct ftruncate_args /* {
2500 syscallarg(int) fd;
2501 #ifdef DOUBLE_ALIGN_PARAMS
2502 syscallarg(int) pad;
2503 #endif
2504 syscallarg(off_t) length;
2505 } */ nuap;
2506
2507 nuap.fd = uap->fd;
2508 nuap.length = uap->length;
2509 return (ftruncate(p, &nuap, retval));
2510 }
2511 #endif /* COMPAT_43 */
2512
2513 /*
2514 * Sync an open file.
2515 */
2516 struct fsync_args {
2517 int fd;
2518 };
2519 /* ARGSUSED */
2520 int
2521 fsync(p, uap, retval)
2522 struct proc *p;
2523 struct fsync_args *uap;
2524 register_t *retval;
2525 {
2526 register struct vnode *vp;
2527 struct file *fp;
2528 int error;
2529
2530 if (error = getvnode(p, uap->fd, &fp))
2531 return (error);
2532 if (fref(fp) == -1)
2533 return (EBADF);
2534 vp = (struct vnode *)fp->f_data;
2535 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2536 error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
2537 VOP_UNLOCK(vp, 0, p);
2538 frele(fp);
2539 return (error);
2540 }
2541
2542 /*
2543 * Duplicate files. Source must be a file, target must be a file or
2544 * must not exist.
2545 */
2546
2547 struct copyfile_args {
2548 char *from;
2549 char *to;
2550 int mode;
2551 int flags;
2552 };
2553 /* ARGSUSED */
2554 int
2555 copyfile(p, uap, retval)
2556 struct proc *p;
2557 register struct copyfile_args *uap;
2558 register_t *retval;
2559 {
2560 register struct vnode *tvp, *fvp, *tdvp;
2561 register struct ucred *cred = p->p_ucred;
2562 struct nameidata fromnd, tond;
2563 int error;
2564
2565 /* Check that the flags are valid. */
2566
2567 if (uap->flags & ~CPF_MASK) {
2568 return(EINVAL);
2569 }
2570
2571 NDINIT(&fromnd, LOOKUP, SAVESTART | AUDITVNPATH1,
2572 UIO_USERSPACE, uap->from, p);
2573 if (error = namei(&fromnd))
2574 return (error);
2575 fvp = fromnd.ni_vp;
2576
2577 NDINIT(&tond, CREATE, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | AUDITVNPATH2,
2578 UIO_USERSPACE, uap->to, p);
2579 if (error = namei(&tond)) {
2580 vrele(fvp);
2581 goto out1;
2582 }
2583 tdvp = tond.ni_dvp;
2584 tvp = tond.ni_vp;
2585 if (tvp != NULL) {
2586 if (!(uap->flags & CPF_OVERWRITE)) {
2587 error = EEXIST;
2588 goto out;
2589 }
2590 }
2591
2592 if (fvp->v_type == VDIR || (tvp && tvp->v_type == VDIR)) {
2593 error = EISDIR;
2594 goto out;
2595 }
2596
2597 if (error = VOP_ACCESS(tdvp, VWRITE, cred, p))
2598 goto out;
2599
2600 if (fvp == tdvp)
2601 error = EINVAL;
2602 /*
2603 * If source is the same as the destination (that is the
2604 * same inode number) then there is nothing to do.
2605 * (fixed to have POSIX semantics - CSM 3/2/98)
2606 */
2607 if (fvp == tvp)
2608 error = -1;
2609 out:
2610 if (!error) {
2611 error = VOP_COPYFILE(fvp,tdvp,tvp,&tond.ni_cnd,uap->mode,uap->flags);
2612 } else {
2613 VOP_ABORTOP(tdvp, &tond.ni_cnd);
2614 if (tdvp == tvp)
2615 vrele(tdvp);
2616 else
2617 vput(tdvp);
2618 if (tvp)
2619 vput(tvp);
2620 vrele(fvp);
2621 }
2622 vrele(tond.ni_startdir);
2623 FREE_ZONE(tond.ni_cnd.cn_pnbuf, tond.ni_cnd.cn_pnlen, M_NAMEI);
2624 out1:
2625 if (fromnd.ni_startdir)
2626 vrele(fromnd.ni_startdir);
2627 FREE_ZONE(fromnd.ni_cnd.cn_pnbuf, fromnd.ni_cnd.cn_pnlen, M_NAMEI);
2628 if (error == -1)
2629 return (0);
2630 return (error);
2631 }
2632
2633 /*
2634 * Rename files. Source and destination must either both be directories,
2635 * or both not be directories. If target is a directory, it must be empty.
2636 */
2637 struct rename_args {
2638 char *from;
2639 char *to;
2640 };
2641 /* ARGSUSED */
2642 int
2643 rename(p, uap, retval)
2644 struct proc *p;
2645 register struct rename_args *uap;
2646 register_t *retval;
2647 {
2648 register struct vnode *tvp, *fvp, *tdvp;
2649 struct nameidata fromnd, tond;
2650 int error;
2651 int mntrename;
2652 int casesense,casepres;
2653 char *nameptr=NULL, *oname;
2654 struct vnode *oparent;
2655
2656 mntrename = FALSE;
2657
2658 bwillwrite();
2659 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART | AUDITVNPATH1,
2660 UIO_USERSPACE, uap->from, p);
2661 error = namei(&fromnd);
2662 if (error)
2663 return (error);
2664 fvp = fromnd.ni_vp;
2665
2666 NDINIT(&tond, RENAME,
2667 LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | AUDITVNPATH2,
2668 UIO_USERSPACE, uap->to, p);
2669 if (fromnd.ni_vp->v_type == VDIR)
2670 tond.ni_cnd.cn_flags |= WILLBEDIR;
2671 if (error = namei(&tond)) {
2672 /* Translate error code for rename("dir1", "dir2/."). */
2673 if (error == EISDIR && fvp->v_type == VDIR)
2674 error = EINVAL;
2675 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2676 vrele(fromnd.ni_dvp);
2677 vrele(fvp);
2678 goto out2;
2679 }
2680 tdvp = tond.ni_dvp;
2681 tvp = tond.ni_vp;
2682
2683 if (tvp != NULL) {
2684 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
2685 error = ENOTDIR;
2686 goto out;
2687 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
2688 error = EISDIR;
2689 goto out;
2690 }
2691 }
2692 if (fvp == tdvp)
2693 error = EINVAL;
2694 /*
2695 * If source is the same as the destination (that is the
2696 * same inode number) then there is nothing to do... EXCEPT if the
2697 * underlying file system supports case insensitivity and is case
2698 * preserving. Then a special case is made, i.e. foo -> Foo.
2699 *
2700 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
2701 * and _PC_CASE_PRESERVING can have this exception, and they need to
2702 * handle the special case of getting the same vnode as target and
2703 * source. NOTE: Then the target is unlocked going into VOP_RENAME,
2704 * so not to cause locking problems. There is a single reference on tvp.
2705 *
2706 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
2707 * that correct behaviour then is just to remove the source (link)
2708 */
2709 if (fvp == tvp && fromnd.ni_dvp == tdvp) {
2710 if (fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
2711 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
2712 fromnd.ni_cnd.cn_namelen)) {
2713 error = -1; /* Default "unix" behavior */
2714 } else { /* probe for file system specifics */
2715 if (VOP_PATHCONF(tdvp, _PC_CASE_SENSITIVE, &casesense))
2716 casesense = 1;
2717 if (VOP_PATHCONF(tdvp, _PC_CASE_PRESERVING, &casepres))
2718 casepres = 1;
2719 if (!casesense && casepres)
2720 vput(tvp); /* Unlock target and drop ref */
2721 }
2722 }
2723
2724 /*
2725 * Allow the renaming of mount points.
2726 * - target must not exist
2727 * - target must reside in the same directory as source
2728 * - union mounts cannot be renamed
2729 * - "/" cannot be renamed
2730 */
2731 if (!error &&
2732 (fvp->v_flag & VROOT) &&
2733 (fvp->v_type == VDIR) &&
2734 (tvp == NULL) &&
2735 (fvp->v_mountedhere == NULL) &&
2736 (fromnd.ni_dvp == tond.ni_dvp) &&
2737 ((fvp->v_mount->mnt_flag & (MNT_UNION | MNT_ROOTFS)) == 0) &&
2738 (fvp->v_mount->mnt_vnodecovered != NULLVP)) {
2739
2740 /* switch fvp to the covered vnode */
2741 fromnd.ni_vp = fvp->v_mount->mnt_vnodecovered;
2742 vrele(fvp);
2743 fvp = fromnd.ni_vp;
2744 VREF(fvp);
2745 mntrename = TRUE;
2746 }
2747 out:
2748 if (!error) {
2749 VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE);
2750 if (fromnd.ni_dvp != tdvp)
2751 VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2752 if (tvp)
2753 VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE);
2754
2755 // XXXdbg - so that the fs won't block when it vrele()'s
2756 // these nodes before returning
2757 if (fromnd.ni_dvp != tdvp) {
2758 vget(tdvp, 0, p);
2759 }
2760
2761 // save these off so we can later verify that fvp is the same
2762 oname = VNAME(fvp);
2763 oparent = VPARENT(fvp);
2764
2765 nameptr = add_name(tond.ni_cnd.cn_nameptr,
2766 tond.ni_cnd.cn_namelen,
2767 tond.ni_cnd.cn_hash, 0);
2768
2769
2770 error = VOP_RENAME(fromnd.ni_dvp, fvp, &fromnd.ni_cnd,
2771 tond.ni_dvp, tvp, &tond.ni_cnd);
2772 if (error) {
2773 remove_name(nameptr);
2774 nameptr = NULL;
2775 if (fromnd.ni_dvp != tdvp) {
2776 vrele(tdvp);
2777 }
2778
2779 goto out1;
2780 }
2781
2782 /*
2783 * update filesystem's mount point data
2784 */
2785 if (mntrename) {
2786 char *cp, *pathend, *mpname;
2787 char * tobuf;
2788 struct mount *mp;
2789 int maxlen;
2790 size_t len = 0;
2791
2792 VREF(fvp);
2793 vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p);
2794 mp = fvp->v_mountedhere;
2795
2796 if (vfs_busy(mp, LK_NOWAIT, 0, p)) {
2797 vput(fvp);
2798 error = EBUSY;
2799 goto out1;
2800 }
2801 VOP_UNLOCK(fvp, 0, p);
2802
2803 MALLOC_ZONE(tobuf, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
2804 error = copyinstr(uap->to, tobuf, MAXPATHLEN, &len);
2805 if (!error) {
2806 /* find current mount point prefix */
2807 pathend = &mp->mnt_stat.f_mntonname[0];
2808 for (cp = pathend; *cp != '\0'; ++cp) {
2809 if (*cp == '/')
2810 pathend = cp + 1;
2811 }
2812 /* find last component of target name */
2813 for (mpname = cp = tobuf; *cp != '\0'; ++cp) {
2814 if (*cp == '/')
2815 mpname = cp + 1;
2816 }
2817 /* append name to prefix */
2818 maxlen = MNAMELEN - (pathend - mp->mnt_stat.f_mntonname);
2819 bzero(pathend, maxlen);
2820 strncpy(pathend, mpname, maxlen - 1);
2821 }
2822 FREE_ZONE(tobuf, MAXPATHLEN, M_NAMEI);
2823
2824 vrele(fvp);
2825 vfs_unbusy(mp, p);
2826 }
2827
2828
2829 // fix up name & parent pointers. note that we first
2830 // check that fvp has the same name/parent pointers it
2831 // had before the rename call and then we lock fvp so
2832 // that it won't go away on us when we hit blocking
2833 // points like remove_name() or vrele() where fvp could
2834 // get recycled.
2835 if (oname == VNAME(fvp) && oparent == VPARENT(fvp) && vget(fvp, LK_EXCLUSIVE | LK_INTERLOCK, p) == 0) {
2836 if (VNAME(fvp)) {
2837 char *tmp = VNAME(fvp);
2838 VNAME(fvp) = NULL;
2839 remove_name(tmp);
2840 }
2841
2842 VNAME(fvp) = nameptr;
2843 nameptr = NULL;
2844
2845 if (fromnd.ni_dvp != tdvp) {
2846 struct vnode *tmpvp;
2847
2848 tmpvp = VPARENT(fvp);
2849 VPARENT(fvp) = NULL;
2850 vrele(tmpvp);
2851
2852 VPARENT(fvp) = tdvp;
2853
2854 // note: we don't vrele() tdvp because we want to keep
2855 // the reference until fvp gets recycled
2856 }
2857
2858 vput(fvp);
2859
2860 } else {
2861 // if fvp isn't kosher anymore and we locked tdvp,
2862 // release tdvp
2863 if (fromnd.ni_dvp != tdvp) {
2864 vrele(tdvp);
2865 }
2866 remove_name(nameptr);
2867 nameptr = NULL;
2868 }
2869
2870 } else {
2871 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
2872 if (tdvp == tvp)
2873 vrele(tdvp);
2874 else
2875 vput(tdvp);
2876 if (tvp)
2877 vput(tvp);
2878 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2879 vrele(fromnd.ni_dvp);
2880 vrele(fvp);
2881 }
2882 out1:
2883 vrele(tond.ni_startdir);
2884 FREE_ZONE(tond.ni_cnd.cn_pnbuf, tond.ni_cnd.cn_pnlen, M_NAMEI);
2885 out2:
2886 if (fromnd.ni_startdir)
2887 vrele(fromnd.ni_startdir);
2888 FREE_ZONE(fromnd.ni_cnd.cn_pnbuf, fromnd.ni_cnd.cn_pnlen, M_NAMEI);
2889 if (error == -1)
2890 return (0);
2891 return (error);
2892 }
2893
2894 /*
2895 * Make a directory file.
2896 */
2897 struct mkdir_args {
2898 char *path;
2899 int mode;
2900 };
2901 /* ARGSUSED */
2902 int
2903 mkdir(p, uap, retval)
2904 struct proc *p;
2905 register struct mkdir_args *uap;
2906 register_t *retval;
2907 {
2908 register struct vnode *vp;
2909 struct vattr vattr;
2910 int error;
2911 struct nameidata nd;
2912 char *nameptr;
2913
2914 AUDIT_ARG(mode, (mode_t)uap->mode);
2915 bwillwrite();
2916 NDINIT(&nd, CREATE, LOCKPARENT | AUDITVNPATH1, UIO_USERSPACE, uap->path, p);
2917 nd.ni_cnd.cn_flags |= WILLBEDIR;
2918 error = namei(&nd);
2919 if (error)
2920 return (error);
2921 vp = nd.ni_vp;
2922 if (vp != NULL) {
2923 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2924 if (nd.ni_dvp == vp)
2925 vrele(nd.ni_dvp);
2926 else
2927 vput(nd.ni_dvp);
2928 vrele(vp);
2929 return (EEXIST);
2930 }
2931 VATTR_NULL(&vattr);
2932 vattr.va_type = VDIR;
2933 vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask;
2934 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2935
2936 nameptr = add_name(nd.ni_cnd.cn_nameptr, nd.ni_cnd.cn_namelen, nd.ni_cnd.cn_hash, 0);
2937
2938 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
2939 if (!error) {
2940 VNAME(nd.ni_vp) = nameptr;
2941 if (VPARENT(nd.ni_vp) == NULL && vget(nd.ni_dvp, 0, p) == 0) {
2942 VPARENT(nd.ni_vp) = nd.ni_dvp;
2943 }
2944
2945 vput(nd.ni_vp);
2946 }
2947 return (error);
2948 }
2949
2950 /*
2951 * Remove a directory file.
2952 */
2953 struct rmdir_args {
2954 char *path;
2955 };
2956 /* ARGSUSED */
2957 int
2958 rmdir(p, uap, retval)
2959 struct proc *p;
2960 struct rmdir_args *uap;
2961 register_t *retval;
2962 {
2963 register struct vnode *vp;
2964 int error;
2965 struct nameidata nd;
2966
2967 bwillwrite();
2968 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNPATH1, UIO_USERSPACE,
2969 uap->path, p);
2970 error = namei(&nd);
2971 if (error)
2972 return (error);
2973 vp = nd.ni_vp;
2974 if (vp->v_type != VDIR) {
2975 error = ENOTDIR;
2976 goto out;
2977 }
2978 /*
2979 * No rmdir "." please.
2980 */
2981 if (nd.ni_dvp == vp) {
2982 error = EINVAL;
2983 goto out;
2984 }
2985 /*
2986 * The root of a mounted filesystem cannot be deleted.
2987 */
2988 if (vp->v_flag & VROOT)
2989 error = EBUSY;
2990 out:
2991 if (!error) {
2992 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2993 VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2994 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2995 } else {
2996 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2997 if (nd.ni_dvp == vp)
2998 vrele(nd.ni_dvp);
2999 else
3000 vput(nd.ni_dvp);
3001 vput(vp);
3002 }
3003 return (error);
3004 }
3005
3006 #if COMPAT_43
3007 /*
3008 * Read a block of directory entries in a file system independent format.
3009 */
3010 struct ogetdirentries_args {
3011 int fd;
3012 char *buf;
3013 u_int count;
3014 long *basep;
3015 };
3016 int
3017 ogetdirentries(p, uap, retval)
3018 struct proc *p;
3019 register struct ogetdirentries_args *uap;
3020 register_t *retval;
3021 {
3022 register struct vnode *vp;
3023 struct file *fp;
3024 struct uio auio, kuio;
3025 struct iovec aiov, kiov;
3026 struct dirent *dp, *edp;
3027 caddr_t dirbuf;
3028 int error, eofflag, readcnt;
3029 long loff;
3030
3031 AUDIT_ARG(fd, uap->fd);
3032 if (error = getvnode(p, uap->fd, &fp))
3033 return (error);
3034
3035 AUDIT_ARG(vnpath, (struct vnode *)fp->f_data, ARG_VNODE1);
3036
3037 if ((fp->f_flag & FREAD) == 0)
3038 return (EBADF);
3039 vp = (struct vnode *)fp->f_data;
3040 unionread:
3041 if (vp->v_type != VDIR)
3042 return (EINVAL);
3043 aiov.iov_base = uap->buf;
3044 aiov.iov_len = uap->count;
3045 auio.uio_iov = &aiov;
3046 auio.uio_iovcnt = 1;
3047 auio.uio_rw = UIO_READ;
3048 auio.uio_segflg = UIO_USERSPACE;
3049 auio.uio_procp = p;
3050 auio.uio_resid = uap->count;
3051 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
3052 loff = auio.uio_offset = fp->f_offset;
3053 # if (BYTE_ORDER != LITTLE_ENDIAN)
3054 if (vp->v_mount->mnt_maxsymlinklen <= 0) {
3055 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
3056 (int *)0, (u_long **)0);
3057 fp->f_offset = auio.uio_offset;
3058 } else
3059 # endif
3060 {
3061 kuio = auio;
3062 kuio.uio_iov = &kiov;
3063 kuio.uio_segflg = UIO_SYSSPACE;
3064 kiov.iov_len = uap->count;
3065 MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK);
3066 kiov.iov_base = dirbuf;
3067 error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
3068 (int *)0, (u_long **)0);
3069 fp->f_offset = kuio.uio_offset;
3070 if (error == 0) {
3071 readcnt = uap->count - kuio.uio_resid;
3072 edp = (struct dirent *)&dirbuf[readcnt];
3073 for (dp = (struct dirent *)dirbuf; dp < edp; ) {
3074 # if (BYTE_ORDER == LITTLE_ENDIAN)
3075 /*
3076 * The expected low byte of
3077 * dp->d_namlen is our dp->d_type.
3078 * The high MBZ byte of dp->d_namlen
3079 * is our dp->d_namlen.
3080 */
3081 dp->d_type = dp->d_namlen;
3082 dp->d_namlen = 0;
3083 # else
3084 /*
3085 * The dp->d_type is the high byte
3086 * of the expected dp->d_namlen,
3087 * so must be zero'ed.
3088 */
3089 dp->d_type = 0;
3090 # endif
3091 if (dp->d_reclen > 0) {
3092 dp = (struct dirent *)
3093 ((char *)dp + dp->d_reclen);
3094 } else {
3095 error = EIO;
3096 break;
3097 }
3098 }
3099 if (dp >= edp)
3100 error = uiomove(dirbuf, readcnt, &auio);
3101 }
3102 FREE(dirbuf, M_TEMP);
3103 }
3104 VOP_UNLOCK(vp, 0, p);
3105 if (error)
3106 return (error);
3107
3108 #if UNION
3109 {
3110 extern int (**union_vnodeop_p)(void *);
3111 extern struct vnode *union_dircache __P((struct vnode*, struct proc*));
3112
3113 if ((uap->count == auio.uio_resid) &&
3114 (vp->v_op == union_vnodeop_p)) {
3115 struct vnode *lvp;
3116
3117 lvp = union_dircache(vp, p);
3118 if (lvp != NULLVP) {
3119 struct vattr va;
3120
3121 /*
3122 * If the directory is opaque,
3123 * then don't show lower entries
3124 */
3125 error = VOP_GETATTR(vp, &va, fp->f_cred, p);
3126 if (va.va_flags & OPAQUE) {
3127 vput(lvp);
3128 lvp = NULL;
3129 }
3130 }
3131
3132 if (lvp != NULLVP) {
3133 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
3134 if (error) {
3135 vput(lvp);
3136 return (error);
3137 }
3138 VOP_UNLOCK(lvp, 0, p);
3139 fp->f_data = (caddr_t) lvp;
3140 fp->f_offset = 0;
3141 error = VOP_CLOSE(vp, FREAD, fp->f_cred, p);
3142 vrele(vp);
3143 if (error)
3144 return (error);
3145 vp = lvp;
3146 goto unionread;
3147 }
3148 }
3149 }
3150 #endif /* UNION */
3151
3152 if ((uap->count == auio.uio_resid) &&
3153 (vp->v_flag & VROOT) &&
3154 (vp->v_mount->mnt_flag & MNT_UNION)) {
3155 struct vnode *tvp = vp;
3156 vp = vp->v_mount->mnt_vnodecovered;
3157 VREF(vp);
3158 fp->f_data = (caddr_t) vp;
3159 fp->f_offset = 0;
3160 vrele(tvp);
3161 goto unionread;
3162 }
3163 error = copyout((caddr_t)&loff, (caddr_t)uap->basep,
3164 sizeof(long));
3165 *retval = uap->count - auio.uio_resid;
3166 return (error);
3167 }
3168 #endif /* COMPAT_43 */
3169
3170 /*
3171 * Read a block of directory entries in a file system independent format.
3172 */
3173 struct getdirentries_args {
3174 int fd;
3175 char *buf;
3176 u_int count;
3177 long *basep;
3178 };
3179 int
3180 getdirentries(p, uap, retval)
3181 struct proc *p;
3182 register struct getdirentries_args *uap;
3183 register_t *retval;
3184 {
3185 register struct vnode *vp;
3186 struct file *fp;
3187 struct uio auio;
3188 struct iovec aiov;
3189 long loff;
3190 int error, eofflag;
3191
3192 AUDIT_ARG(fd, uap->fd);
3193 error = getvnode(p, uap->fd, &fp);
3194 if (error)
3195 return (error);
3196
3197 AUDIT_ARG(vnpath, (struct vnode *)fp->f_data, ARG_VNODE1);
3198
3199 if ((fp->f_flag & FREAD) == 0)
3200 return (EBADF);
3201 vp = (struct vnode *)fp->f_data;
3202 unionread:
3203 if (vp->v_type != VDIR)
3204 return (EINVAL);
3205 aiov.iov_base = uap->buf;
3206 aiov.iov_len = uap->count;
3207 auio.uio_iov = &aiov;
3208 auio.uio_iovcnt = 1;
3209 auio.uio_rw = UIO_READ;
3210 auio.uio_segflg = UIO_USERSPACE;
3211 auio.uio_procp = p;
3212 auio.uio_resid = uap->count;
3213 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
3214 loff = auio.uio_offset = fp->f_offset;
3215 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
3216 (int *)0, (u_long **)0);
3217 fp->f_offset = auio.uio_offset;
3218 VOP_UNLOCK(vp, 0, p);
3219 if (error)
3220 return (error);
3221
3222 #if UNION
3223 {
3224 extern int (**union_vnodeop_p)(void *);
3225 extern struct vnode *union_dircache __P((struct vnode*, struct proc*));
3226
3227 if ((uap->count == auio.uio_resid) &&
3228 (vp->v_op == union_vnodeop_p)) {
3229 struct vnode *lvp;
3230
3231 lvp = union_dircache(vp, p);
3232 if (lvp != NULLVP) {
3233 struct vattr va;
3234
3235 /*
3236 * If the directory is opaque,
3237 * then don't show lower entries
3238 */
3239 error = VOP_GETATTR(vp, &va, fp->f_cred, p);
3240 if (va.va_flags & OPAQUE) {
3241 vput(lvp);
3242 lvp = NULL;
3243 }
3244 }
3245
3246 if (lvp != NULLVP) {
3247 error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
3248 if (error) {
3249 vput(lvp);
3250 return (error);
3251 }
3252 VOP_UNLOCK(lvp, 0, p);
3253 fp->f_data = (caddr_t) lvp;
3254 fp->f_offset = 0;
3255 error = VOP_CLOSE(vp, FREAD, fp->f_cred, p);
3256 vrele(vp);
3257 if (error)
3258 return (error);
3259 vp = lvp;
3260 goto unionread;
3261 }
3262 }
3263 }
3264 #endif /* UNION */
3265
3266 if ((uap->count == auio.uio_resid) &&
3267 (vp->v_flag & VROOT) &&
3268 (vp->v_mount->mnt_flag & MNT_UNION)) {
3269 struct vnode *tvp = vp;
3270 vp = vp->v_mount->mnt_vnodecovered;
3271 VREF(vp);
3272 fp->f_data = (caddr_t) vp;
3273 fp->f_offset = 0;
3274 vrele(tvp);
3275 goto unionread;
3276 }
3277 error = copyout((caddr_t)&loff, (caddr_t)uap->basep,
3278 sizeof(long));
3279 *retval = uap->count - auio.uio_resid;
3280 return (error);
3281 }
3282
3283 /*
3284 * Set the mode mask for creation of filesystem nodes.
3285 */
3286 struct umask_args {
3287 int newmask;
3288 };
3289 int
3290 umask(p, uap, retval)
3291 struct proc *p;
3292 struct umask_args *uap;
3293 register_t *retval;
3294 {
3295 register struct filedesc *fdp;
3296
3297 AUDIT_ARG(mask, uap->newmask);
3298 fdp = p->p_fd;
3299 *retval = fdp->fd_cmask;
3300 fdp->fd_cmask = uap->newmask & ALLPERMS;
3301 return (0);
3302 }
3303
3304 /*
3305 * Void all references to file by ripping underlying filesystem
3306 * away from vnode.
3307 */
3308 struct revoke_args {
3309 char *path;
3310 };
3311 /* ARGSUSED */
3312 int
3313 revoke(p, uap, retval)
3314 struct proc *p;
3315 register struct revoke_args *uap;
3316 register_t *retval;
3317 {
3318 register struct vnode *vp;
3319 struct vattr vattr;
3320 int error;
3321 struct nameidata nd;
3322
3323 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1, UIO_USERSPACE, uap->path, p);
3324 error = namei(&nd);
3325 if (error)
3326 return (error);
3327 vp = nd.ni_vp;
3328 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
3329 goto out;
3330 if (p->p_ucred->cr_uid != vattr.va_uid &&
3331 (error = suser(p->p_ucred, &p->p_acflag)))
3332 goto out;
3333 if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
3334 VOP_REVOKE(vp, REVOKEALL);
3335 out:
3336 vrele(vp);
3337 return (error);
3338 }
3339
3340 /*
3341 * Convert a user file descriptor to a kernel file entry.
3342 */
3343 int
3344 getvnode(p, fd, fpp)
3345 struct proc *p;
3346 int fd;
3347 struct file **fpp;
3348 {
3349 struct file *fp;
3350 int error;
3351
3352 if (error = fdgetf(p, fd, &fp))
3353 return (error);
3354 if (fp->f_type != DTYPE_VNODE)
3355 return (EINVAL);
3356 *fpp = fp;
3357 return (0);
3358 }
3359
3360 /*
3361 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
3362 * The following system calls are designed to support features
3363 * which are specific to the HFS & HFS Plus volume formats
3364 */
3365
3366 #ifdef __APPLE_API_OBSOLETE
3367
3368 /************************************************/
3369 /* *** Following calls will be deleted soon *** */
3370 /************************************************/
3371
3372 /*
3373 * Make a complex file. A complex file is one with multiple forks (data streams)
3374 */
3375 struct mkcomplex_args {
3376 const char *path; /* pathname of the file to be created */
3377 mode_t mode; /* access mode for the newly created file */
3378 u_long type; /* format of the complex file */
3379 };
3380 /* ARGSUSED */
3381 int
3382 mkcomplex(p,uap,retval)
3383 struct proc *p;
3384 register struct mkcomplex_args *uap;
3385 register_t *retval;
3386 {
3387 struct vnode *vp;
3388 struct vattr vattr;
3389 int error;
3390 struct nameidata nd;
3391
3392 /* mkcomplex wants the directory vnode locked so do that here */
3393
3394 NDINIT(&nd, CREATE, FOLLOW | LOCKPARENT, UIO_USERSPACE, (char *)uap->path, p);
3395 if (error = namei(&nd))
3396 return (error);
3397
3398 /* Set the attributes as specified by the user */
3399
3400 VATTR_NULL(&vattr);
3401 vattr.va_mode = (uap->mode & ACCESSPERMS);
3402 error = VOP_MKCOMPLEX(nd.ni_dvp, &vp, &nd.ni_cnd, &vattr, uap->type);
3403
3404 /* The mkcomplex call promises to release the parent vnode pointer
3405 * even an an error case so don't do it here unless the operation
3406 * is not supported. In that case, there isn't anyone to unlock the parent
3407 * The vnode pointer to the file will also be released.
3408 */
3409
3410 if (error)
3411 {
3412 if (error == EOPNOTSUPP)
3413 vput(nd.ni_dvp);
3414 return (error);
3415 }
3416
3417 return (0);
3418
3419 } /* end of mkcomplex system call */
3420
3421 /*
3422 * Extended stat call which returns volumeid and vnodeid as well as other info
3423 */
3424 struct statv_args {
3425 const char *path; /* pathname of the target file */
3426 struct vstat *vsb; /* vstat structure for returned info */
3427 };
3428 /* ARGSUSED */
3429 int
3430 statv(p,uap,retval)
3431 struct proc *p;
3432 register struct statv_args *uap;
3433 register_t *retval;
3434
3435 {
3436 return (EOPNOTSUPP); /* We'll just return an error for now */
3437
3438 } /* end of statv system call */
3439
3440 /*
3441 * Extended lstat call which returns volumeid and vnodeid as well as other info
3442 */
3443 struct lstatv_args {
3444 const char *path; /* pathname of the target file */
3445 struct vstat *vsb; /* vstat structure for returned info */
3446 };
3447 /* ARGSUSED */
3448 int
3449 lstatv(p,uap,retval)
3450 struct proc *p;
3451 register struct lstatv_args *uap;
3452 register_t *retval;
3453
3454 {
3455 return (EOPNOTSUPP); /* We'll just return an error for now */
3456 } /* end of lstatv system call */
3457
3458 /*
3459 * Extended fstat call which returns volumeid and vnodeid as well as other info
3460 */
3461 struct fstatv_args {
3462 int fd; /* file descriptor of the target file */
3463 struct vstat *vsb; /* vstat structure for returned info */
3464 };
3465 /* ARGSUSED */
3466 int
3467 fstatv(p,uap,retval)
3468 struct proc *p;
3469 register struct fstatv_args *uap;
3470 register_t *retval;
3471
3472 {
3473 return (EOPNOTSUPP); /* We'll just return an error for now */
3474 } /* end of fstatv system call */
3475
3476
3477 /************************************************/
3478 /* *** Preceding calls will be deleted soon *** */
3479 /************************************************/
3480
3481 #endif /* __APPLE_API_OBSOLETE */
3482
3483
3484 /*
3485 * Obtain attribute information about a file system object
3486 */
3487
3488 struct getattrlist_args {
3489 const char *path; /* pathname of the target object */
3490 struct attrlist * alist; /* Attributes desired by the user */
3491 void * attributeBuffer; /* buffer to hold returned attributes */
3492 size_t bufferSize; /* size of the return buffer */
3493 unsigned long options; /* options (follow/don't follow) */
3494 };
3495 /* ARGSUSED */
3496 int
3497 getattrlist (p,uap,retval)
3498 struct proc *p;
3499 register struct getattrlist_args *uap;
3500 register_t *retval;
3501
3502 {
3503 int error;
3504 struct nameidata nd;
3505 struct iovec aiov;
3506 struct uio auio;
3507 struct attrlist attributelist;
3508 u_long nameiflags;
3509
3510 /* Get the attributes desire and do our parameter checking */
3511
3512 if (error = copyin((caddr_t)uap->alist, (caddr_t) &attributelist,
3513 sizeof (attributelist)))
3514 {
3515 return(error);
3516 }
3517
3518 if (attributelist.bitmapcount != ATTR_BIT_MAP_COUNT
3519 #if 0
3520 || attributelist.commonattr & ~ATTR_CMN_VALIDMASK ||
3521 attributelist.volattr & ~ATTR_VOL_VALIDMASK ||
3522 attributelist.dirattr & ~ATTR_DIR_VALIDMASK ||
3523 attributelist.fileattr & ~ATTR_FILE_VALIDMASK ||
3524 attributelist.forkattr & ~ATTR_FORK_VALIDMASK
3525 #endif
3526 )
3527 {
3528 return (EINVAL);
3529 }
3530
3531 /* Get the vnode for the file we are getting info on. */
3532 nameiflags = LOCKLEAF | SHAREDLEAF;
3533 if ((uap->options & FSOPT_NOFOLLOW) == 0) nameiflags |= FOLLOW;
3534 NDINIT(&nd, LOOKUP, nameiflags | AUDITVNPATH1, UIO_USERSPACE,
3535 (char *)uap->path, p);
3536
3537 error = namei(&nd);
3538 if (error)
3539 return (error);
3540
3541 /* Set up the UIO structure for use by the vfs routine */
3542
3543 aiov.iov_base = uap->attributeBuffer;
3544 aiov.iov_len = uap->bufferSize;
3545 auio.uio_iov = &aiov;
3546 auio.uio_iovcnt = 1;
3547 auio.uio_offset = 0;
3548 auio.uio_rw = UIO_READ;
3549 auio.uio_segflg = UIO_USERSPACE;
3550 auio.uio_procp = p;
3551 auio.uio_resid = uap->bufferSize;
3552
3553
3554 error = VOP_GETATTRLIST(nd.ni_vp, &attributelist, &auio, p->p_ucred, p);
3555
3556 /* Unlock and release the vnode which will have been locked by namei */
3557
3558 vput(nd.ni_vp);
3559
3560 /* return the effort if we got one, otherwise return success */
3561
3562 if (error)
3563 {
3564 return (error);
3565 }
3566
3567 return(0);
3568
3569 } /* end of getattrlist system call */
3570
3571
3572
3573 /*
3574 * Set attribute information about a file system object
3575 */
3576
3577 struct setattrlist_args {
3578 const char *path; /* pathname of the target object */
3579 struct attrlist * alist; /* Attributes being set by the user */
3580 void * attributeBuffer; /* buffer with attribute values to be set */
3581 size_t bufferSize; /* size of the return buffer */
3582 unsigned long options; /* options (follow/don't follow) */
3583 };
3584 /* ARGSUSED */
3585 int
3586 setattrlist (p,uap,retval)
3587 struct proc *p;
3588 register struct setattrlist_args *uap;
3589 register_t *retval;
3590
3591 {
3592 int error;
3593 struct nameidata nd;
3594 struct iovec aiov;
3595 struct uio auio;
3596 struct attrlist alist;
3597 u_long nameiflags;
3598
3599 /* Get the attributes desired and do our parameter checking */
3600
3601 if ((error = copyin((caddr_t)uap->alist, (caddr_t) &alist,
3602 sizeof (alist)))) {
3603 return (error);
3604 }
3605
3606 if (alist.bitmapcount != ATTR_BIT_MAP_COUNT)
3607 return (EINVAL);
3608
3609 /* Get the vnode for the file whose attributes are being set. */
3610 nameiflags = LOCKLEAF;
3611 if ((uap->options & FSOPT_NOFOLLOW) == 0) nameiflags |= FOLLOW;
3612 NDINIT(&nd, LOOKUP, nameiflags | AUDITVNPATH1, UIO_USERSPACE,
3613 (char *)uap->path, p);
3614 error = namei(&nd);
3615 if (error)
3616 return (error);
3617
3618 /* Set up the UIO structure for use by the vfs routine */
3619 aiov.iov_base = uap->attributeBuffer;
3620 aiov.iov_len = uap->bufferSize;
3621 auio.uio_iov = &aiov;
3622 auio.uio_iovcnt = 1;
3623 auio.uio_offset = 0;
3624 auio.uio_rw = UIO_WRITE;
3625 auio.uio_segflg = UIO_USERSPACE;
3626 auio.uio_procp = p;
3627 auio.uio_resid = uap->bufferSize;
3628
3629 error = VOP_SETATTRLIST(nd.ni_vp, &alist, &auio, p->p_ucred, p);
3630
3631 vput(nd.ni_vp);
3632
3633 return (error);
3634
3635 } /* end of setattrlist system call */
3636
3637
3638 /*
3639 * Obtain attribute information on objects in a directory while enumerating
3640 * the directory. This call does not yet support union mounted directories.
3641 * TO DO
3642 * 1.union mounted directories.
3643 */
3644
3645 struct getdirentriesattr_args {
3646 int fd; /* file descriptor */
3647 struct attrlist *alist; /* bit map of requested attributes */
3648 void *buffer; /* buffer to hold returned attribute info */
3649 size_t buffersize; /* size of the return buffer */
3650 u_long *count; /* the count of entries requested/returned */
3651 u_long *basep; /* the offset of where we are leaving off in buffer */
3652 u_long *newstate; /* a flag to inform of changes in directory */
3653 u_long options; /* maybe unused for now */
3654 };
3655 /* ARGSUSED */
3656 int
3657 getdirentriesattr (p,uap,retval)
3658 struct proc *p;
3659 register struct getdirentriesattr_args *uap;
3660 register_t *retval;
3661
3662 {
3663 register struct vnode *vp;
3664 struct file *fp;
3665 struct uio auio;
3666 struct iovec aiov;
3667 u_long actualcount;
3668 u_long newstate;
3669 int error, eofflag;
3670 long loff;
3671 struct attrlist attributelist;
3672
3673 AUDIT_ARG(fd, uap->fd);
3674
3675 /* Get the attributes into kernel space */
3676 if (error = copyin((caddr_t)uap->alist, (caddr_t) &attributelist, sizeof (attributelist)))
3677 return(error);
3678 if (error = copyin((caddr_t)uap->count, (caddr_t) &actualcount, sizeof (u_long)))
3679 return(error);
3680
3681 if (error = getvnode(p, uap->fd, &fp))
3682 return (error);
3683
3684 AUDIT_ARG(vnpath, (struct vnode *)fp->f_data, ARG_VNODE1);
3685
3686 if ((fp->f_flag & FREAD) == 0)
3687 return(EBADF);
3688 vp = (struct vnode *)fp->f_data;
3689
3690 if (vp->v_type != VDIR)
3691 return(EINVAL);
3692
3693 /* set up the uio structure which will contain the users return buffer */
3694 aiov.iov_base = uap->buffer;
3695 aiov.iov_len = uap->buffersize;
3696 auio.uio_iov = &aiov;
3697 auio.uio_iovcnt = 1;
3698 auio.uio_rw = UIO_READ;
3699 auio.uio_segflg = UIO_USERSPACE;
3700 auio.uio_procp = p;
3701 auio.uio_resid = uap->buffersize;
3702
3703 loff = auio.uio_offset = fp->f_offset;
3704 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
3705 error = VOP_READDIRATTR (vp, &attributelist, &auio,
3706 actualcount, uap->options, &newstate, &eofflag,
3707 &actualcount, ((u_long **)0), p->p_ucred);
3708
3709 VOP_UNLOCK(vp, 0, p);
3710 if (error) return (error);
3711 fp->f_offset = auio.uio_offset; /* should be multiple of dirent, not variable */
3712
3713 if (error = copyout((caddr_t) &actualcount, (caddr_t) uap->count, sizeof(u_long)))
3714 return (error);
3715 if (error = copyout((caddr_t) &newstate, (caddr_t) uap->newstate, sizeof(u_long)))
3716 return (error);
3717 if (error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long)))
3718 return (error);
3719
3720 *retval = eofflag; /* similar to getdirentries */
3721 return (0); /* return error earlier, an retval of 0 or 1 now */
3722
3723 } /* end of getdirentryattr system call */
3724
3725 /*
3726 * Exchange data between two files
3727 */
3728
3729 struct exchangedata_args {
3730 const char *path1; /* pathname of the first swapee */
3731 const char *path2; /* pathname of the second swapee */
3732 unsigned long options; /* options */
3733 };
3734 /* ARGSUSED */
3735 int
3736 exchangedata (p,uap,retval)
3737 struct proc *p;
3738 register struct exchangedata_args *uap;
3739 register_t *retval;
3740
3741 {
3742
3743 struct nameidata fnd, snd;
3744 struct vnode *fvp, *svp;
3745 int error;
3746 u_long nameiflags;
3747
3748 nameiflags = 0;
3749 if ((uap->options & FSOPT_NOFOLLOW) == 0) nameiflags |= FOLLOW;
3750
3751 /* Global lock, to prevent race condition, only one exchange at a time */
3752 lockmgr(&exchangelock, LK_EXCLUSIVE , (struct slock *)0, p);
3753
3754 NDINIT(&fnd, LOOKUP, nameiflags | AUDITVNPATH1, UIO_USERSPACE,
3755 (char *) uap->path1, p);
3756
3757 error = namei(&fnd);
3758 if (error)
3759 goto out2;
3760
3761 fvp = fnd.ni_vp;
3762
3763 NDINIT(&snd, LOOKUP, nameiflags | AUDITVNPATH2, UIO_USERSPACE,
3764 (char *)uap->path2, p);
3765
3766 error = namei(&snd);
3767 if (error) {
3768 vrele(fvp);
3769 goto out2;
3770 }
3771
3772 svp = snd.ni_vp;
3773
3774 /* if the files are the same, return an inval error */
3775 if (svp == fvp) {
3776 vrele(fvp);
3777 vrele(svp);
3778 error = EINVAL;
3779 goto out2;
3780 }
3781
3782 vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p);
3783 vn_lock(svp, LK_EXCLUSIVE | LK_RETRY, p);
3784
3785 error = VOP_ACCESS(fvp, VWRITE, p->p_ucred, p);
3786 if (error) goto out;
3787
3788 error = VOP_ACCESS(svp, VWRITE, p->p_ucred, p);
3789 if (error) goto out;
3790
3791 /* Ok, make the call */
3792 error = VOP_EXCHANGE (fvp, svp, p->p_ucred, p);
3793
3794 if (error == 0 && VPARENT(fvp) != VPARENT(svp)) {
3795 struct vnode *tmp;
3796
3797 tmp = VPARENT(fvp);
3798 VPARENT(fvp) = VPARENT(svp);
3799 VPARENT(svp) = tmp;
3800 }
3801
3802 out:
3803 vput (svp);
3804 vput (fvp);
3805
3806 out2:
3807 lockmgr(&exchangelock, LK_RELEASE, (struct slock *)0, p);
3808
3809 if (error) {
3810 return (error);
3811 }
3812
3813 return (0);
3814
3815 } /* end of exchangedata system call */
3816
3817 #ifdef __APPLE_API_OBSOLETE
3818
3819 /************************************************/
3820 /* *** Following calls will be deleted soon *** */
3821 /************************************************/
3822
3823 /*
3824 * Check users access to a file
3825 */
3826
3827 struct checkuseraccess_args {
3828 const char *path; /* pathname of the target file */
3829 uid_t userid; /* user for whom we are checking access */
3830 gid_t *groups; /* Group that we are checking for */
3831 int ngroups; /* Number of groups being checked */
3832 int accessrequired; /* needed access to the file */
3833 unsigned long options; /* options */
3834 };
3835
3836 /* ARGSUSED */
3837 int
3838 checkuseraccess (p,uap,retval)
3839 struct proc *p;
3840 register struct checkuseraccess_args *uap;
3841 register_t *retval;
3842
3843 {
3844 register struct vnode *vp;
3845 int error;
3846 struct nameidata nd;
3847 struct ucred cred;
3848 int flags; /*what will actually get passed to access*/
3849 u_long nameiflags;
3850
3851 /* Make sure that the number of groups is correct before we do anything */
3852
3853 if ((uap->ngroups <= 0) || (uap->ngroups > NGROUPS))
3854 return (EINVAL);
3855
3856 /* Verify that the caller is root */
3857
3858 if (error = suser(p->p_ucred, &p->p_acflag))
3859 return(error);
3860
3861 /* Fill in the credential structure */
3862
3863 cred.cr_ref = 0;
3864 cred.cr_uid = uap->userid;
3865 cred.cr_ngroups = uap->ngroups;
3866 if (error = copyin((caddr_t) uap->groups, (caddr_t) &(cred.cr_groups), (sizeof(gid_t))*uap->ngroups))
3867 return (error);
3868
3869 /* Get our hands on the file */
3870
3871 nameiflags = LOCKLEAF;
3872 if ((uap->options & FSOPT_NOFOLLOW) == 0) nameiflags |= FOLLOW;
3873 NDINIT(&nd, LOOKUP, nameiflags | AUDITVNPATH1, UIO_USERSPACE, (char *)uap->path, p);
3874
3875 if (error = namei(&nd))
3876 return (error);
3877 vp = nd.ni_vp;
3878
3879 /* Flags == 0 means only check for existence. */
3880
3881 flags = 0;
3882
3883 if (uap->accessrequired) {
3884 if (uap->accessrequired & R_OK)
3885 flags |= VREAD;
3886 if (uap->accessrequired & W_OK)
3887 flags |= VWRITE;
3888 if (uap->accessrequired & X_OK)
3889 flags |= VEXEC;
3890 }
3891 error = VOP_ACCESS(vp, flags, &cred, p);
3892
3893 vput(vp);
3894
3895 if (error)
3896 return (error);
3897
3898 return (0);
3899
3900 } /* end of checkuseraccess system call */
3901
3902 /************************************************/
3903 /* *** Preceding calls will be deleted soon *** */
3904 /************************************************/
3905
3906 #endif /* __APPLE_API_OBSOLETE */
3907
3908
3909
3910 struct searchfs_args {
3911 const char *path;
3912 struct fssearchblock *searchblock;
3913 u_long *nummatches;
3914 u_long scriptcode;
3915 u_long options;
3916 struct searchstate *state;
3917 };
3918 /* ARGSUSED */
3919
3920 int
3921 searchfs (p,uap,retval)
3922 struct proc *p;
3923 register struct searchfs_args *uap;
3924 register_t *retval;
3925
3926 {
3927 register struct vnode *vp;
3928 int error=0;
3929 int fserror = 0;
3930 struct nameidata nd;
3931 struct fssearchblock searchblock;
3932 struct searchstate *state;
3933 struct attrlist *returnattrs;
3934 void *searchparams1,*searchparams2;
3935 struct iovec aiov;
3936 struct uio auio;
3937 u_long nummatches;
3938 int mallocsize;
3939 u_long nameiflags;
3940
3941
3942 /* Start by copying in fsearchblock paramater list */
3943
3944 if (error = copyin((caddr_t) uap->searchblock, (caddr_t) &searchblock,sizeof(struct fssearchblock)))
3945 return(error);
3946
3947 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
3948 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
3949 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
3950 /* block. */
3951
3952 mallocsize = searchblock.sizeofsearchparams1+searchblock.sizeofsearchparams2 +
3953 sizeof(struct attrlist) + sizeof(struct searchstate);
3954
3955 MALLOC(searchparams1, void *, mallocsize, M_TEMP, M_WAITOK);
3956
3957 /* Now set up the various pointers to the correct place in our newly allocated memory */
3958
3959 searchparams2 = (void *) (((caddr_t) searchparams1) + searchblock.sizeofsearchparams1);
3960 returnattrs = (struct attrlist *) (((caddr_t) searchparams2) + searchblock.sizeofsearchparams2);
3961 state = (struct searchstate *) (((caddr_t) returnattrs) + sizeof (struct attrlist));
3962
3963 /* Now copy in the stuff given our local variables. */
3964
3965 if (error = copyin((caddr_t) searchblock.searchparams1, searchparams1,searchblock.sizeofsearchparams1))
3966 goto freeandexit;
3967
3968 if (error = copyin((caddr_t) searchblock.searchparams2, searchparams2,searchblock.sizeofsearchparams2))
3969 goto freeandexit;
3970
3971 if (error = copyin((caddr_t) searchblock.returnattrs, (caddr_t) returnattrs, sizeof(struct attrlist)))
3972 goto freeandexit;
3973
3974 if (error = copyin((caddr_t) uap->state, (caddr_t) state, sizeof(struct searchstate)))
3975 goto freeandexit;
3976
3977 /* set up the uio structure which will contain the users return buffer */
3978
3979 aiov.iov_base = searchblock.returnbuffer;
3980 aiov.iov_len = searchblock.returnbuffersize;
3981 auio.uio_iov = &aiov;
3982 auio.uio_iovcnt = 1;
3983 auio.uio_rw = UIO_READ;
3984 auio.uio_segflg = UIO_USERSPACE;
3985 auio.uio_procp = p;
3986 auio.uio_resid = searchblock.returnbuffersize;
3987
3988 nameiflags = LOCKLEAF;
3989 if ((uap->options & FSOPT_NOFOLLOW) == 0) nameiflags |= FOLLOW;
3990 NDINIT(&nd, LOOKUP, nameiflags | AUDITVNPATH1, UIO_USERSPACE,
3991 (char *)uap->path, p);
3992
3993 error = namei(&nd);
3994 if (error)
3995 goto freeandexit;
3996
3997 vp = nd.ni_vp;
3998
3999
4000 /*
4001 * If searchblock.maxmatches == 0, then skip the search. This has happened
4002 * before and sometimes the underlyning code doesnt deal with it well.
4003 */
4004 if (searchblock.maxmatches == 0) {
4005 nummatches = 0;
4006 goto saveandexit;
4007 }
4008
4009 /*
4010 Allright, we have everything we need, so lets make that call.
4011
4012 We keep special track of the return value from the file system:
4013 EAGAIN is an acceptable error condition that shouldn't keep us
4014 from copying out any results...
4015 */
4016
4017 fserror = VOP_SEARCHFS(vp,
4018 searchparams1,
4019 searchparams2,
4020 &searchblock.searchattrs,
4021 searchblock.maxmatches,
4022 &searchblock.timelimit,
4023 returnattrs,
4024 &nummatches,
4025 uap->scriptcode,
4026 uap->options,
4027 &auio,
4028 state);
4029
4030 saveandexit:
4031
4032 vput(vp);
4033
4034 /* Now copy out the stuff that needs copying out. That means the number of matches, the
4035 search state. Everything was already put into he return buffer by the vop call. */
4036
4037 if (error = copyout((caddr_t) state, (caddr_t) uap->state, sizeof(struct searchstate)))
4038 goto freeandexit;
4039
4040 if (error = copyout((caddr_t) &nummatches, (caddr_t) uap->nummatches, sizeof(u_long)))
4041 goto freeandexit;
4042
4043 error = fserror;
4044
4045 freeandexit:
4046
4047 FREE(searchparams1,M_TEMP);
4048
4049 return(error);
4050
4051
4052 } /* end of searchfs system call */
4053
4054
4055 /*
4056 * Make a filesystem-specific control call:
4057 */
4058 struct fsctl_args {
4059 const char *path; /* pathname of the target object */
4060 u_long cmd; /* cmd (also encodes size/direction of arguments a la ioctl) */
4061 caddr_t data; /* pointer to argument buffer */
4062 u_long options; /* options for fsctl processing */
4063 };
4064 /* ARGSUSED */
4065 int
4066 fsctl (p,uap,retval)
4067 struct proc *p;
4068 struct fsctl_args *uap;
4069 register_t *retval;
4070
4071 {
4072 int error;
4073 struct nameidata nd;
4074 u_long nameiflags;
4075 u_long cmd = uap->cmd;
4076 register u_int size;
4077 #define STK_PARAMS 128
4078 char stkbuf[STK_PARAMS];
4079 caddr_t data, memp;
4080
4081 size = IOCPARM_LEN(cmd);
4082 if (size > IOCPARM_MAX) return (EINVAL);
4083
4084 memp = NULL;
4085 if (size > sizeof (stkbuf)) {
4086 if ((memp = (caddr_t)kalloc(size)) == 0) return ENOMEM;
4087 data = memp;
4088 } else {
4089 data = stkbuf;
4090 };
4091
4092 if (cmd & IOC_IN) {
4093 if (size) {
4094 error = copyin(uap->data, data, (u_int)size);
4095 if (error) goto FSCtl_Exit;
4096 } else {
4097 *(caddr_t *)data = uap->data;
4098 };
4099 } else if ((cmd & IOC_OUT) && size) {
4100 /*
4101 * Zero the buffer so the user always
4102 * gets back something deterministic.
4103 */
4104 bzero(data, size);
4105 } else if (cmd & IOC_VOID)
4106 *(caddr_t *)data = uap->data;
4107
4108 /* Get the vnode for the file we are getting info on: */
4109 nameiflags = LOCKLEAF;
4110 if ((uap->options & FSOPT_NOFOLLOW) == 0) nameiflags |= FOLLOW;
4111 NDINIT(&nd, LOOKUP, nameiflags, UIO_USERSPACE, (char *)uap->path, p);
4112 if (error = namei(&nd)) goto FSCtl_Exit;
4113
4114 /* Invoke the filesystem-specific code */
4115 error = VOP_IOCTL(nd.ni_vp, IOCBASECMD(cmd), data, uap->options, p->p_ucred, p);
4116
4117 vput(nd.ni_vp);
4118
4119 /*
4120 * Copy any data to user, size was
4121 * already set and checked above.
4122 */
4123 if (error == 0 && (cmd & IOC_OUT) && size) error = copyout(data, uap->data, (u_int)size);
4124
4125 FSCtl_Exit:
4126 if (memp) kfree(memp, size);
4127
4128 return error;
4129 }
4130 /* end of fsctl system call */
4131
4132 /*
4133 * An in-kernel sync for power management to call.
4134 */
4135 __private_extern__ int
4136 sync_internal(void)
4137 {
4138 boolean_t funnel_state;
4139 int error;
4140
4141 struct sync_args data;
4142
4143 int retval[2];
4144
4145 funnel_state = thread_funnel_set(kernel_flock, TRUE);
4146
4147 error = sync(current_proc(), &data, &retval);
4148
4149 thread_funnel_set(kernel_flock, funnel_state);
4150
4151 return (error);
4152 } /* end of sync_internal call */
4153
4154
4155
4156 // XXXdbg fmod watching calls
4157 #define NUM_CHANGE_NODES 256
4158 static int changed_init=0;
4159 static volatile int fmod_watch_enabled = 0;
4160 static pid_t fmod_watch_owner;
4161 static simple_lock_data_t changed_nodes_lock; // guard access
4162 static volatile struct vnode *changed_nodes[NUM_CHANGE_NODES];
4163 static volatile pid_t changed_nodes_pid[NUM_CHANGE_NODES];
4164 static volatile int changed_rd_index=0, changed_wr_index=0;
4165 static volatile int notifier_sleeping=0;
4166
4167
4168 void
4169 notify_filemod_watchers(struct vnode *vp, struct proc *p)
4170 {
4171 int ret;
4172
4173 // only want notification on regular files.
4174 if (fmod_watch_enabled == 0 || (vp->v_type != VREG && vp->v_type != VDIR)) {
4175 return;
4176 }
4177
4178 // grab a reference so it doesn't go away
4179 if (vget(vp, 0, p) != 0) {
4180 return;
4181 }
4182
4183 retry:
4184 simple_lock(&changed_nodes_lock);
4185
4186 // If the table is full, block until it clears up
4187 if (((changed_wr_index+1) % NUM_CHANGE_NODES) == changed_rd_index) {
4188 simple_unlock(&changed_nodes_lock);
4189
4190 notifier_sleeping++;
4191 // wait up to 10 seconds for the queue to drain
4192 ret = tsleep((caddr_t)&changed_wr_index, PINOD, "changed_nodes_full", 10*hz);
4193 if (ret != 0 || fmod_watch_enabled == 0) {
4194 notifier_sleeping--;
4195 printf("notify_filemod: err %d from tsleep/enabled %d. bailing out (vp 0x%x).\n",
4196 ret, fmod_watch_enabled, vp);
4197 vrele(vp);
4198 return;
4199 }
4200
4201 notifier_sleeping--;
4202 goto retry;
4203 }
4204
4205 // insert our new guy
4206 if (changed_nodes[changed_wr_index] != NULL) {
4207 panic("notify_fmod_watchers: index %d is 0x%x, not null!\n",
4208 changed_wr_index, changed_nodes[changed_wr_index]);
4209 }
4210 changed_nodes[changed_wr_index] = vp;
4211 changed_nodes_pid[changed_wr_index] = current_proc()->p_pid;
4212 changed_wr_index = (changed_wr_index + 1) % NUM_CHANGE_NODES;
4213
4214 simple_unlock(&changed_nodes_lock);
4215
4216 wakeup((caddr_t)&changed_rd_index);
4217 }
4218
4219
4220 struct fmod_watch_args {
4221 int *new_fd;
4222 char *pathbuf;
4223 int len;
4224 pid_t pid;
4225 };
4226
4227 int
4228 fmod_watch(struct proc *p, struct fmod_watch_args *uap, register_t *retval)
4229 {
4230 int fd, didhold = 0;
4231 struct filedesc *fdp;
4232 struct file *fp;
4233 struct vnode *vp;
4234 int flags;
4235 int type, indx, error, need_wakeup=0;
4236 struct flock lf;
4237 struct nameidata nd;
4238 extern struct fileops vnops;
4239 pid_t pid;
4240
4241 if (fmod_watch_enabled == 0) {
4242 *retval = -1;
4243 return EINVAL;
4244 }
4245
4246 p = current_proc();
4247
4248 if (changed_init == 0) {
4249 changed_init = 1;
4250 simple_lock_init(&changed_nodes_lock);
4251 }
4252
4253 if (changed_rd_index == changed_wr_index) {
4254 // there's nothing to do, go to sleep
4255 error = tsleep((caddr_t)&changed_rd_index, PUSER|PCATCH, "changed_nodes_empty", 0);
4256 if (error != 0) {
4257 // XXXdbg - what if after we unblock the changed_nodes
4258 // table is full? We should wakeup() the writer.
4259 *retval = -1;
4260 return error;
4261 }
4262 }
4263
4264 simple_lock(&changed_nodes_lock);
4265
4266 vp = (struct vnode *)changed_nodes[changed_rd_index];
4267 pid = changed_nodes_pid[changed_rd_index];
4268
4269 changed_nodes[changed_rd_index] = NULL;
4270 changed_rd_index = (changed_rd_index + 1) % NUM_CHANGE_NODES;
4271
4272 if (vp == NULL) {
4273 printf("watch_file_changes: Someone put a null vnode in my table! (%d %d)\n",
4274 changed_rd_index, changed_wr_index);
4275 error = EINVAL;
4276 goto err0;
4277 }
4278
4279 simple_unlock(&changed_nodes_lock);
4280
4281 // if the writers are blocked, wake them up as we just freed up
4282 // some space for them.
4283 if (notifier_sleeping > 0) {
4284 wakeup((caddr_t)&changed_wr_index);
4285 }
4286
4287 if (vp->v_type != VREG && vp->v_type != VDIR) {
4288 error = EBADF;
4289 goto err1;
4290 }
4291
4292 if ((error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p)) != 0) {
4293 printf("fmod_watch: vn_lock returned %d\n", error);
4294 goto err1;
4295 }
4296
4297 // first copy out the name
4298 if (uap->pathbuf) {
4299 char *buff;
4300 int len=MAXPATHLEN;
4301
4302 MALLOC(buff, char *, len, M_TEMP, M_WAITOK);
4303 error = vn_getpath(vp, buff, &len);
4304 if (error == 0) {
4305 if (len < uap->len)
4306 error = copyout(buff, (void *)uap->pathbuf, len);
4307 else
4308 error = ENOSPC;
4309 }
4310 FREE(buff, M_TEMP);
4311 if (error) {
4312 goto err1;
4313 }
4314 }
4315
4316 // now copy out the pid of the person that changed the file
4317 if (uap->pid) {
4318 if ((error = copyout((caddr_t)&pid, (void *)uap->pid, sizeof(pid_t))) != 0) {
4319 printf("fmod_watch: failed to copy out the pid (%d)\n", pid);
4320 goto err1;
4321 }
4322 }
4323
4324 // now create a file descriptor for this vnode
4325 fdp = p->p_fd;
4326 flags = FREAD;
4327 if (error = falloc(p, &fp, &indx)) {
4328 printf("fmod_watch: failed to allocate an fd...\n");
4329 goto err2;
4330 }
4331
4332 if ((error = copyout((caddr_t)&indx, (void *)uap->new_fd, sizeof(int))) != 0) {
4333 printf("fmod_watch: failed to copy out the new fd (%d)\n", indx);
4334 goto err3;
4335 }
4336
4337 fp->f_flag = flags & FMASK;
4338 fp->f_type = DTYPE_VNODE;
4339 fp->f_ops = &vnops;
4340 fp->f_data = (caddr_t)vp;
4341
4342 if (UBCINFOEXISTS(vp) && ((didhold = ubc_hold(vp)) == 0)) {
4343 goto err3;
4344 }
4345
4346 error = VOP_OPEN(vp, flags, p->p_ucred, p);
4347 if (error) {
4348 goto err4;
4349 }
4350
4351 VOP_UNLOCK(vp, 0, p);
4352
4353 *fdflags(p, indx) &= ~UF_RESERVED;
4354
4355 // note: we explicitly don't vrele() here because it
4356 // happens when the fd is closed.
4357
4358 return error;
4359
4360 err4:
4361 if (didhold) {
4362 ubc_rele(vp);
4363 }
4364 err3:
4365 ffree(fp);
4366 fdrelse(p, indx);
4367 err2:
4368 VOP_UNLOCK(vp, 0, p);
4369 err1:
4370 vrele(vp); // undoes the vref() in notify_filemod_watchers()
4371
4372 err0:
4373 *retval = -1;
4374 return error;
4375 }
4376
4377 static int
4378 enable_fmod_watching(register_t *retval)
4379 {
4380 *retval = -1;
4381
4382 if (!is_suser()) {
4383 return EPERM;
4384 }
4385
4386 // XXXdbg for now we only allow one watcher at a time.
4387 if (fmod_watch_enabled) {
4388 return EBUSY;
4389 }
4390
4391 fmod_watch_enabled++;
4392 fmod_watch_owner = current_proc()->p_pid;
4393
4394 *retval = 0;
4395 return 0;
4396 }
4397
4398 static int
4399 disable_fmod_watching(register_t *retval)
4400 {
4401 if (!is_suser()) {
4402 return EPERM;
4403 }
4404
4405 if (fmod_watch_enabled < 1) {
4406 printf("fmod_watching: too many disables! (%d)\n", fmod_watch_enabled);
4407 return EINVAL;
4408 }
4409
4410 fmod_watch_enabled--;
4411
4412 // if we're the last guy, clear out any remaining vnodes
4413 // in the table so they don't remain referenced.
4414 //
4415 if (fmod_watch_enabled == 0) {
4416 int i;
4417 for(i=changed_rd_index; i != changed_wr_index; ) {
4418 if (changed_nodes[i] == NULL) {
4419 panic("disable_fmod_watch: index %d is NULL!\n", i);
4420 }
4421 vrele((struct vnode *)changed_nodes[i]);
4422 changed_nodes[i] = NULL;
4423 i = (i + 1) % NUM_CHANGE_NODES;
4424 }
4425 changed_wr_index = changed_rd_index = 0;
4426
4427 fmod_watch_owner = 0;
4428 }
4429
4430 // wake up anyone that may be waiting for the
4431 // queue to clear out.
4432 //
4433 while(notifier_sleeping) {
4434 wakeup((caddr_t)&changed_wr_index);
4435
4436 // yield the cpu so the notifiers can run
4437 tsleep((caddr_t)&fmod_watch_enabled, PINOD, "disable_fmod_watch", 1);
4438 }
4439
4440 *retval = 0;
4441 return 0;
4442 }
4443
4444
4445 struct fmod_watch_enable_args {
4446 int on_or_off;
4447 };
4448
4449 int
4450 fmod_watch_enable(struct proc *p, struct fmod_watch_enable_args *uap, register_t *retval)
4451 {
4452 int ret;
4453
4454 if (uap->on_or_off != 0) {
4455 ret = enable_fmod_watching(retval);
4456 } else {
4457 ret = disable_fmod_watching(retval);
4458 }
4459
4460 return ret;
4461 }
4462
4463 void
4464 clean_up_fmod_watch(struct proc *p)
4465 {
4466 if (fmod_watch_enabled && fmod_watch_owner == p->p_pid) {
4467 register_t *retval;
4468
4469 disable_fmod_watching(&retval);
4470 }
4471 }