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