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