|
|
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;
603: sp = &mp->mnt_stat;
604: if (error = VFS_STATFS(mp, sp, p))
605: return (error);
606: sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
607: return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
608: }
609:
610: /*
611: * Get statistics on all filesystems.
612: */
613: struct getfsstat_args {
614: struct statfs *buf;
615: long bufsize;
616: int flags;
617: };
618: int
619: getfsstat(p, uap, retval)
620: struct proc *p;
621: register struct getfsstat_args *uap;
622: register_t *retval;
623: {
624: register struct mount *mp, *nmp;
625: register struct statfs *sp;
626: caddr_t sfsp;
627: long count, maxcount, error;
628:
629: maxcount = uap->bufsize / sizeof(struct statfs);
630: sfsp = (caddr_t)uap->buf;
631: count = 0;
632: simple_lock(&mountlist_slock);
633: for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
634: if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
635: nmp = mp->mnt_list.cqe_next;
636: continue;
637: }
638: if (sfsp && count < maxcount) {
639: sp = &mp->mnt_stat;
640: /*
641: * If MNT_NOWAIT is specified, do not refresh the
642: * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
643: */
644: if (((uap->flags & MNT_NOWAIT) == 0 ||
645: (uap->flags & MNT_WAIT)) &&
646: (error = VFS_STATFS(mp, sp, p))) {
647: simple_lock(&mountlist_slock);
648: nmp = mp->mnt_list.cqe_next;
649: vfs_unbusy(mp, p);
650: continue;
651: }
652: sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
653: if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
654: return (error);
655: sfsp += sizeof(*sp);
656: }
657: count++;
658: simple_lock(&mountlist_slock);
659: nmp = mp->mnt_list.cqe_next;
660: vfs_unbusy(mp, p);
661: }
662: simple_unlock(&mountlist_slock);
663: if (sfsp && count > maxcount)
664: *retval = maxcount;
665: else
666: *retval = count;
667: return (0);
668: }
669:
670: /*
671: * Change current working directory to a given file descriptor.
672: */
673: struct fchdir_args {
674: int fd;
675: };
676: /* ARGSUSED */
677: int
678: fchdir(p, uap, retval)
679: struct proc *p;
680: struct fchdir_args *uap;
681: register_t *retval;
682: {
683: register struct filedesc *fdp = p->p_fd;
684: struct vnode *vp, *tdp;
685: struct mount *mp;
686: struct file *fp;
687: int error;
688:
689: if (error = getvnode(p, uap->fd, &fp))
690: return (error);
691: vp = (struct vnode *)fp->f_data;
692: VREF(vp);
693: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
694: if (vp->v_type != VDIR)
695: error = ENOTDIR;
696: else
697: error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
698: while (!error && (mp = vp->v_mountedhere) != NULL) {
699: if (vfs_busy(mp, 0, 0, p))
700: continue;
701: error = VFS_ROOT(mp, &tdp);
702: vfs_unbusy(mp, p);
703: if (error)
704: break;
705: vput(vp);
706: vp = tdp;
707: }
708: if (error) {
709: vput(vp);
710: return (error);
711: }
712: VOP_UNLOCK(vp, 0, p);
713: vrele(fdp->fd_cdir);
714: fdp->fd_cdir = vp;
715: return (0);
716: }
717:
718: /*
719: * Change current working directory (``.'').
720: */
721: struct chdir_args {
722: char *path;
723: };
724: /* ARGSUSED */
725: int
726: chdir(p, uap, retval)
727: struct proc *p;
728: struct chdir_args *uap;
729: register_t *retval;
730: {
731: register struct filedesc *fdp = p->p_fd;
732: int error;
733: struct nameidata nd;
734:
735: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
736: uap->path, p);
737: if (error = change_dir(&nd, p))
738: return (error);
739: vrele(fdp->fd_cdir);
740: fdp->fd_cdir = nd.ni_vp;
741: return (0);
742: }
743:
744: /*
745: * Change notion of root (``/'') directory.
746: */
747: struct chroot_args {
748: char *path;
749: };
750: /* ARGSUSED */
751: int
752: chroot(p, uap, retval)
753: struct proc *p;
754: struct chroot_args *uap;
755: register_t *retval;
756: {
757: register struct filedesc *fdp = p->p_fd;
758: int error;
759: struct nameidata nd;
760:
761: if (error = suser(p->p_ucred, &p->p_acflag))
762: return (error);
763: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
764: uap->path, p);
765: if (error = change_dir(&nd, p))
766: return (error);
767: if (fdp->fd_rdir != NULL)
768: vrele(fdp->fd_rdir);
769: fdp->fd_rdir = nd.ni_vp;
770: return (0);
771: }
772:
773: /*
774: * Common routine for chroot and chdir.
775: */
776: static int
777: change_dir(ndp, p)
778: register struct nameidata *ndp;
779: struct proc *p;
780: {
781: struct vnode *vp;
782: int error;
783:
784: if (error = namei(ndp))
785: return (error);
786: vp = ndp->ni_vp;
787: if (vp->v_type != VDIR)
788: error = ENOTDIR;
789: else
790: error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
791: if (error)
792: vput(vp);
793: else
794: VOP_UNLOCK(vp, 0, p);
795: return (error);
796: }
797:
798: /*
799: * Check permissions, allocate an open file structure,
800: * and call the device open routine if any.
801: */
802: struct open_args {
803: char *path;
804: int flags;
805: int mode;
806: };
807: int
808: open(p, uap, retval)
809: struct proc *p;
810: register struct open_args *uap;
811: register_t *retval;
812: {
813: register struct filedesc *fdp = p->p_fd;
814: register struct file *fp;
815: register struct vnode *vp;
816: int flags, cmode;
817: struct file *nfp;
818: int type, indx, error;
819: struct flock lf;
820: struct nameidata nd;
821: extern struct fileops vnops;
822:
823: /* CERT advisory patch applied from FreeBSD */
824: /* Refer to Radar#2262895 A. Ramesh */
825: flags = FFLAGS(uap->flags);
826: if ((flags & (FREAD | FWRITE))==0)
827: return(EINVAL);
828: if (error = falloc(p, &nfp, &indx))
829: return (error);
830: fp = nfp;
831: cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
832: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
833: p->p_dupfd = -indx - 1; /* XXX check for fdopen */
834: if (error = vn_open(&nd, flags, cmode)) {
835: ffree(fp);
836: if ((error == ENODEV || error == ENXIO) &&
837: p->p_dupfd >= 0 && /* XXX from fdopen */
838: (error =
839: dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
840: *retval = indx;
841: return (0);
842: }
843: if (error == ERESTART)
844: error = EINTR;
845: fdrelse(p, indx);
846: return (error);
847: }
848: p->p_dupfd = 0;
849: vp = nd.ni_vp;
850: fp->f_flag = flags & FMASK;
851: fp->f_type = DTYPE_VNODE;
852: fp->f_ops = &vnops;
853: fp->f_data = (caddr_t)vp;
854: if (flags & (O_EXLOCK | O_SHLOCK)) {
855: lf.l_whence = SEEK_SET;
856: lf.l_start = 0;
857: lf.l_len = 0;
858: if (flags & O_EXLOCK)
859: lf.l_type = F_WRLCK;
860: else
861: lf.l_type = F_RDLCK;
862: type = F_FLOCK;
863: if ((flags & FNONBLOCK) == 0)
864: type |= F_WAIT;
865: VOP_UNLOCK(vp, 0, p);
866: if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
867: (void) vn_close(vp, fp->f_flag, fp->f_cred, p);
868: ffree(fp);
869: fdrelse(p, indx);
870: return (error);
871: }
872: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
873: fp->f_flag |= FHASLOCK;
874: }
875: VOP_UNLOCK(vp, 0, p);
876: *fdflags(p, indx) &= ~UF_RESERVED;
877: *retval = indx;
878: return (0);
879: }
880:
881: #if COMPAT_43
882: /*
883: * Create a file.
884: */
885: struct ocreat_args {
886: char *path;
887: int mode;
888: };
889: int
890: ocreat(p, uap, retval)
891: struct proc *p;
892: register struct ocreat_args *uap;
893: register_t *retval;
894: {
895: struct open_args nuap;
896:
897: nuap.path = uap->path;
898: nuap.mode = uap->mode;
899: nuap.flags = O_WRONLY | O_CREAT | O_TRUNC;
900: return (open(p, &nuap, retval));
901: }
902: #endif /* COMPAT_43 */
903:
904: /*
905: * Create a special file.
906: */
907: struct mknod_args {
908: char *path;
909: int mode;
910: int dev;
911: };
912: /* ARGSUSED */
913: int
914: mknod(p, uap, retval)
915: struct proc *p;
916: register struct mknod_args *uap;
917: register_t *retval;
918: {
919: register struct vnode *vp;
920: struct vattr vattr;
921: int error;
922: int whiteout;
923: struct nameidata nd;
924:
925: if (error = suser(p->p_ucred, &p->p_acflag))
926: return (error);
927: NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
928: if (error = namei(&nd))
929: return (error);
930: vp = nd.ni_vp;
931: if (vp != NULL)
932: error = EEXIST;
933: else {
934: VATTR_NULL(&vattr);
935: vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
936: vattr.va_rdev = uap->dev;
937: whiteout = 0;
938:
939: switch (uap->mode & S_IFMT) {
940: case S_IFMT: /* used by badsect to flag bad sectors */
941: vattr.va_type = VBAD;
942: break;
943: case S_IFCHR:
944: vattr.va_type = VCHR;
945: break;
946: case S_IFBLK:
947: vattr.va_type = VBLK;
948: break;
949: case S_IFWHT:
950: whiteout = 1;
951: break;
952: default:
953: error = EINVAL;
954: break;
955: }
956: }
957: if (!error) {
958: VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
959: if (whiteout) {
960: error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
961: if (error)
962: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
963: vput(nd.ni_dvp);
964: } else {
965: error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
966: &nd.ni_cnd, &vattr);
967: }
968: } else {
969: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
970: if (nd.ni_dvp == vp)
971: vrele(nd.ni_dvp);
972: else
973: vput(nd.ni_dvp);
974: if (vp)
975: vrele(vp);
976: }
977: return (error);
978: }
979:
980: /*
981: * Create a named pipe.
982: */
983: struct mkfifo_args {
984: char *path;
985: int mode;
986: };
987: /* ARGSUSED */
988: int
989: mkfifo(p, uap, retval)
990: struct proc *p;
991: register struct mkfifo_args *uap;
992: register_t *retval;
993: {
994: struct vattr vattr;
995: int error;
996: struct nameidata nd;
997:
998: #if !FIFO
999: return (EOPNOTSUPP);
1000: #else
1001: NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
1002: if (error = namei(&nd))
1003: return (error);
1004: if (nd.ni_vp != NULL) {
1005: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1006: if (nd.ni_dvp == nd.ni_vp)
1007: vrele(nd.ni_dvp);
1008: else
1009: vput(nd.ni_dvp);
1010: vrele(nd.ni_vp);
1011: return (EEXIST);
1012: }
1013: VATTR_NULL(&vattr);
1014: vattr.va_type = VFIFO;
1015: vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
1016: VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1017: return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
1018: #endif /* FIFO */
1019: }
1020:
1021: /*
1022: * Make a hard file link.
1023: */
1024: struct link_args {
1025: char *path;
1026: char *link;
1027: };
1028: /* ARGSUSED */
1029: int
1030: link(p, uap, retval)
1031: struct proc *p;
1032: register struct link_args *uap;
1033: register_t *retval;
1034: {
1035: register struct vnode *vp;
1036: struct nameidata nd;
1037: int error;
1038:
1039: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
1040: if (error = namei(&nd))
1041: return (error);
1042: vp = nd.ni_vp;
1043: if (vp->v_type == VDIR)
1044: error = EPERM; /* POSIX */
1045: else {
1046: nd.ni_cnd.cn_nameiop = CREATE;
1047: nd.ni_cnd.cn_flags = LOCKPARENT;
1048: nd.ni_dirp = uap->link;
1049: if ((error = namei(&nd)) == 0) {
1050: if (nd.ni_vp != NULL)
1051: error = EEXIST;
1052: if (!error) {
1053: VOP_LEASE(nd.ni_dvp, p, p->p_ucred,
1054: LEASE_WRITE);
1055: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1056: error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd);
1057: } else {
1058: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1059: if (nd.ni_dvp == nd.ni_vp)
1060: vrele(nd.ni_dvp);
1061: else
1062: vput(nd.ni_dvp);
1063: if (nd.ni_vp)
1064: vrele(nd.ni_vp);
1065: }
1066: }
1067: }
1068: vrele(vp);
1069: return (error);
1070: }
1071:
1072: /*
1073: * Make a symbolic link.
1074: */
1075: struct symlink_args {
1076: char *path;
1077: char *link;
1078: };
1079: /* ARGSUSED */
1080: int
1081: symlink(p, uap, retval)
1082: struct proc *p;
1083: register struct symlink_args *uap;
1084: register_t *retval;
1085: {
1086: struct vattr vattr;
1087: char *path;
1088: int error;
1089: struct nameidata nd;
1090:
1091: MALLOC_ZONE(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
1092: if (error = copyinstr(uap->path, path, MAXPATHLEN, NULL))
1093: goto out;
1094: NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p);
1095: if (error = namei(&nd))
1096: goto out;
1097: if (nd.ni_vp) {
1098: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1099: if (nd.ni_dvp == nd.ni_vp)
1100: vrele(nd.ni_dvp);
1101: else
1102: vput(nd.ni_dvp);
1103: vrele(nd.ni_vp);
1104: error = EEXIST;
1105: goto out;
1106: }
1107: VATTR_NULL(&vattr);
1108: vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
1109: VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1110: error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1111: out:
1112: FREE_ZONE(path, MAXPATHLEN, M_NAMEI);
1113: return (error);
1114: }
1115:
1116: /*
1117: * Delete a whiteout from the filesystem.
1118: */
1119: struct undelete_args {
1120: char *path;
1121: };
1122: /* ARGSUSED */
1123: int
1124: undelete(p, uap, retval)
1125: struct proc *p;
1126: register struct undelete_args *uap;
1127: register_t *retval;
1128: {
1129: int error;
1130: struct nameidata nd;
1131:
1132: NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
1133: uap->path, p);
1134: error = namei(&nd);
1135: if (error)
1136: return (error);
1137:
1138: if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
1139: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1140: if (nd.ni_dvp == nd.ni_vp)
1141: vrele(nd.ni_dvp);
1142: else
1143: vput(nd.ni_dvp);
1144: if (nd.ni_vp)
1145: vrele(nd.ni_vp);
1146: return (EEXIST);
1147: }
1148:
1149: VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1150: if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE))
1151: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1152: vput(nd.ni_dvp);
1153: return (error);
1154: }
1155:
1156: /*
1157: * Delete a name from the filesystem.
1158: */
1159: struct unlink_args {
1160: char *path;
1161: };
1162: /* ARGSUSED */
1163: int
1164: unlink(p, uap, retval)
1165: struct proc *p;
1166: struct unlink_args *uap;
1167: register_t *retval;
1168: {
1169: register struct vnode *vp;
1170: int error;
1171: struct nameidata nd;
1172:
1173: NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
1174: if (error = namei(&nd))
1175: return (error);
1176: vp = nd.ni_vp;
1177: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1178: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1179:
1180: if (vp->v_type == VDIR)
1181: error = EPERM; /* POSIX */
1182: else {
1183: /*
1184: * The root of a mounted filesystem cannot be deleted.
1185: *
1186: * XXX: can this only be a VDIR case?
1187: */
1188: if (vp->v_flag & VROOT)
1189: error = EBUSY;
1190: else
1191: (void) vnode_uncache(vp);
1192: }
1193:
1194: if (!error) {
1195: VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1196: error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1197: } else {
1198: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1199: if (nd.ni_dvp == vp)
1200: vrele(nd.ni_dvp);
1201: else
1202: vput(nd.ni_dvp);
1203: if (vp != NULLVP)
1204: vput(vp);
1205: }
1206: return (error);
1207: }
1208:
1209: /*
1210: * Reposition read/write file offset.
1211: */
1212: struct lseek_args {
1213: int fd;
1214: #ifdef DOUBLE_ALIGN_PARAMS
1215: int pad;
1216: #endif
1217: off_t offset;
1218: int whence;
1219: };
1220: int
1221: lseek(p, uap, retval)
1222: struct proc *p;
1223: register struct lseek_args *uap;
1224: register_t *retval;
1225: {
1226: struct ucred *cred = p->p_ucred;
1227: struct file *fp;
1228: struct vattr vattr;
1229: int error;
1230:
1231: if (error = fdgetf(p, uap->fd, &fp))
1232: return (error);
1233: if (fp->f_type != DTYPE_VNODE)
1234: return (ESPIPE);
1235: switch (uap->whence) {
1236: case L_INCR:
1237: fp->f_offset += uap->offset;
1238: break;
1239: case L_XTND:
1240: if (error =
1241: VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p))
1242: return (error);
1243: fp->f_offset = uap->offset + vattr.va_size;
1244: break;
1245: case L_SET:
1246: fp->f_offset = uap->offset;
1247: break;
1248: default:
1249: return (EINVAL);
1250: }
1251: *(off_t *)retval = fp->f_offset;
1252: return (0);
1253: }
1254:
1255: #if COMPAT_43
1256: /*
1257: * Reposition read/write file offset.
1258: */
1259: struct olseek_args {
1260: int fd;
1261: long offset;
1262: int whence;
1263: };
1264: int
1265: olseek(p, uap, retval)
1266: struct proc *p;
1267: register struct olseek_args *uap;
1268: register_t *retval;
1269: {
1270: struct lseek_args /* {
1271: syscallarg(int) fd;
1272: #ifdef DOUBLE_ALIGN_PARAMS
1273: syscallarg(int) pad;
1274: #endif
1275: syscallarg(off_t) offset;
1276: syscallarg(int) whence;
1277: } */ nuap;
1278: off_t qret;
1279: int error;
1280:
1281: nuap.fd = uap->fd;
1282: nuap.offset = uap->offset;
1283: nuap.whence = uap->whence;
1284: error = lseek(p, &nuap, &qret);
1285: *(long *)retval = qret;
1286: return (error);
1287: }
1288: #endif /* COMPAT_43 */
1289:
1290: /*
1291: * Check access permissions.
1292: */
1293: struct access_args {
1294: char *path;
1295: int flags;
1296: };
1297: int
1298: access(p, uap, retval)
1299: struct proc *p;
1300: register struct access_args *uap;
1301: register_t *retval;
1302: {
1303: register struct ucred *cred = p->p_ucred;
1304: register struct vnode *vp;
1305: int error, flags, t_gid, t_uid;
1306: struct nameidata nd;
1307:
1308: t_uid = cred->cr_uid;
1309: t_gid = cred->cr_groups[0];
1310: cred->cr_uid = p->p_cred->p_ruid;
1311: cred->cr_groups[0] = p->p_cred->p_rgid;
1312: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1313: uap->path, p);
1314: if (error = namei(&nd))
1315: goto out1;
1316: vp = nd.ni_vp;
1317:
1318: /* Flags == 0 means only check for existence. */
1319: if (uap->flags) {
1320: flags = 0;
1321: if (uap->flags & R_OK)
1322: flags |= VREAD;
1323: if (uap->flags & W_OK)
1324: flags |= VWRITE;
1325: if (uap->flags & X_OK)
1326: flags |= VEXEC;
1327: if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
1328: error = VOP_ACCESS(vp, flags, cred, p);
1329: }
1330: vput(vp);
1331: out1:
1332: cred->cr_uid = t_uid;
1333: cred->cr_groups[0] = t_gid;
1334: return (error);
1335: }
1336:
1337: #if COMPAT_43
1338: /*
1339: * Get file status; this version follows links.
1340: */
1341: struct ostat_args {
1342: char *path;
1343: struct ostat *ub;
1344: };
1345: /* ARGSUSED */
1346: int
1347: ostat(p, uap, retval)
1348: struct proc *p;
1349: register struct ostat_args *uap;
1350: register_t *retval;
1351: {
1352: struct stat sb;
1353: struct ostat osb;
1354: int error;
1355: struct nameidata nd;
1356:
1357: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1358: uap->path, p);
1359: if (error = namei(&nd))
1360: return (error);
1361: error = vn_stat(nd.ni_vp, &sb, p);
1362: vput(nd.ni_vp);
1363: if (error)
1364: return (error);
1365: cvtstat(&sb, &osb);
1366: error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
1367: return (error);
1368: }
1369:
1370: /*
1371: * Get file status; this version does not follow links.
1372: */
1373: struct olstat_args {
1374: char *path;
1375: struct ostat *ub;
1376: };
1377: /* ARGSUSED */
1378: int
1379: olstat(p, uap, retval)
1380: struct proc *p;
1381: register struct olstat_args *uap;
1382: register_t *retval;
1383: {
1384: struct vnode *vp, *dvp;
1385: struct stat sb, sb1;
1386: struct ostat osb;
1387: int error;
1388: struct nameidata nd;
1389:
1390: NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
1391: uap->path, p);
1392: if (error = namei(&nd))
1393: return (error);
1394: /*
1395: * For symbolic links, always return the attributes of its
1396: * containing directory, except for mode, size, and links.
1397: */
1398: vp = nd.ni_vp;
1399: dvp = nd.ni_dvp;
1400: if (vp->v_type != VLNK) {
1401: if (dvp == vp)
1402: vrele(dvp);
1403: else
1404: vput(dvp);
1405: error = vn_stat(vp, &sb, p);
1406: vput(vp);
1407: if (error)
1408: return (error);
1409: } else {
1410: error = vn_stat(dvp, &sb, p);
1411: vput(dvp);
1412: if (error) {
1413: vput(vp);
1414: return (error);
1415: }
1416: error = vn_stat(vp, &sb1, p);
1417: vput(vp);
1418: if (error)
1419: return (error);
1420: sb.st_mode &= ~S_IFDIR;
1421: sb.st_mode |= S_IFLNK;
1422: sb.st_nlink = sb1.st_nlink;
1423: sb.st_size = sb1.st_size;
1424: sb.st_blocks = sb1.st_blocks;
1425: }
1426: cvtstat(&sb, &osb);
1427: error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
1428: return (error);
1429: }
1430:
1431: /*
1432: * Convert from an old to a new stat structure.
1433: */
1434: void
1435: cvtstat(st, ost)
1436: struct stat *st;
1437: struct ostat *ost;
1438: {
1439:
1440: ost->st_dev = st->st_dev;
1441: ost->st_ino = st->st_ino;
1442: ost->st_mode = st->st_mode;
1443: ost->st_nlink = st->st_nlink;
1444: ost->st_uid = st->st_uid;
1445: ost->st_gid = st->st_gid;
1446: ost->st_rdev = st->st_rdev;
1447: if (st->st_size < (quad_t)1 << 32)
1448: ost->st_size = st->st_size;
1449: else
1450: ost->st_size = -2;
1451: ost->st_atime = st->st_atime;
1452: ost->st_mtime = st->st_mtime;
1453: ost->st_ctime = st->st_ctime;
1454: ost->st_blksize = st->st_blksize;
1455: ost->st_blocks = st->st_blocks;
1456: ost->st_flags = st->st_flags;
1457: ost->st_gen = st->st_gen;
1458: }
1459: #endif /* COMPAT_43 */
1460:
1461: /*
1462: * Get file status; this version follows links.
1463: */
1464: struct stat_args {
1465: char *path;
1466: struct stat *ub;
1467: };
1468: /* ARGSUSED */
1469: int
1470: stat(p, uap, retval)
1471: struct proc *p;
1472: register struct stat_args *uap;
1473: register_t *retval;
1474: {
1475: struct stat sb;
1476: int error;
1477: struct nameidata nd;
1478:
1479: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1480: uap->path, p);
1481: if (error = namei(&nd))
1482: return (error);
1483: error = vn_stat(nd.ni_vp, &sb, p);
1484: vput(nd.ni_vp);
1485: if (error)
1486: return (error);
1487: error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
1488: return (error);
1489: }
1490:
1491: /*
1492: * Get file status; this version does not follow links.
1493: */
1494: struct lstat_args {
1495: char *path;
1496: struct stat *ub;
1497: };
1498: /* ARGSUSED */
1499: int
1500: lstat(p, uap, retval)
1501: struct proc *p;
1502: register struct lstat_args *uap;
1503: register_t *retval;
1504: {
1505: int error;
1506: struct vnode *vp, *dvp;
1507: struct stat sb, sb1;
1508: struct nameidata nd;
1509:
1510: NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
1511: uap->path, p);
1512: if (error = namei(&nd))
1513: return (error);
1514: /*
1515: * For symbolic links, always return the attributes of its containing
1516: * directory, except for mode, size, inode number, and links.
1517: */
1518: vp = nd.ni_vp;
1519: dvp = nd.ni_dvp;
1520: if ((vp->v_type != VLNK) || ((vp->v_type == VLNK) && (vp->v_tag == VT_NFS))) {
1521: if (dvp == vp)
1522: vrele(dvp);
1523: else
1524: vput(dvp);
1525: error = vn_stat(vp, &sb, p);
1526: vput(vp);
1527: if (error)
1528: return (error);
1529: if (vp->v_type == VLNK)
1530: sb.st_mode |= S_IFLNK;
1531: } else {
1532: error = vn_stat(dvp, &sb, p);
1533: vput(dvp);
1534: if (error) {
1535: vput(vp);
1536: return (error);
1537: }
1538: error = vn_stat(vp, &sb1, p);
1539: vput(vp);
1540: if (error)
1541: return (error);
1542: sb.st_mode &= ~S_IFDIR;
1543: sb.st_mode |= S_IFLNK;
1544: sb.st_nlink = sb1.st_nlink;
1545: sb.st_size = sb1.st_size;
1546: sb.st_blocks = sb1.st_blocks;
1547: sb.st_ino = sb1.st_ino;
1548: }
1549: error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
1550: return (error);
1551: }
1552:
1553: /*
1554: * Get configurable pathname variables.
1555: */
1556: struct pathconf_args {
1557: char *path;
1558: int name;
1559: };
1560: /* ARGSUSED */
1561: int
1562: pathconf(p, uap, retval)
1563: struct proc *p;
1564: register struct pathconf_args *uap;
1565: register_t *retval;
1566: {
1567: int error;
1568: struct nameidata nd;
1569:
1570: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1571: uap->path, p);
1572: if (error = namei(&nd))
1573: return (error);
1574: error = VOP_PATHCONF(nd.ni_vp, uap->name, retval);
1575: vput(nd.ni_vp);
1576: return (error);
1577: }
1578:
1579: /*
1580: * Return target name of a symbolic link.
1581: */
1582: struct readlink_args {
1583: char *path;
1584: char *buf;
1585: int count;
1586: };
1587: /* ARGSUSED */
1588: int
1589: readlink(p, uap, retval)
1590: struct proc *p;
1591: register struct readlink_args *uap;
1592: register_t *retval;
1593: {
1594: register struct vnode *vp;
1595: struct iovec aiov;
1596: struct uio auio;
1597: int error;
1598: struct nameidata nd;
1599:
1600: NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
1601: uap->path, p);
1602: if (error = namei(&nd))
1603: return (error);
1604: vp = nd.ni_vp;
1605: if (vp->v_type != VLNK)
1606: error = EINVAL;
1607: else {
1608: aiov.iov_base = uap->buf;
1609: aiov.iov_len = uap->count;
1610: auio.uio_iov = &aiov;
1611: auio.uio_iovcnt = 1;
1612: auio.uio_offset = 0;
1613: auio.uio_rw = UIO_READ;
1614: auio.uio_segflg = UIO_USERSPACE;
1615: auio.uio_procp = p;
1616: auio.uio_resid = uap->count;
1617: error = VOP_READLINK(vp, &auio, p->p_ucred);
1618: }
1619: vput(vp);
1620: *retval = uap->count - auio.uio_resid;
1621: return (error);
1622: }
1623:
1624: /*
1625: * Change flags of a file given a path name.
1626: */
1627: struct chflags_args {
1628: char *path;
1629: int flags;
1630: };
1631: /* ARGSUSED */
1632: int
1633: chflags(p, uap, retval)
1634: struct proc *p;
1635: register struct chflags_args *uap;
1636: register_t *retval;
1637: {
1638: register struct vnode *vp;
1639: struct vattr vattr;
1640: int error;
1641: struct nameidata nd;
1642:
1643: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
1644: if (error = namei(&nd))
1645: return (error);
1646: vp = nd.ni_vp;
1647: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1648: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1649: VATTR_NULL(&vattr);
1650: vattr.va_flags = uap->flags;
1651: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1652: vput(vp);
1653: return (error);
1654: }
1655:
1656: /*
1657: * Change flags of a file given a file descriptor.
1658: */
1659: struct fchflags_args {
1660: int fd;
1661: int flags;
1662: };
1663: /* ARGSUSED */
1664: int
1665: fchflags(p, uap, retval)
1666: struct proc *p;
1667: register struct fchflags_args *uap;
1668: register_t *retval;
1669: {
1670: struct vattr vattr;
1671: struct vnode *vp;
1672: struct file *fp;
1673: int error;
1674:
1675: if (error = getvnode(p, uap->fd, &fp))
1676: return (error);
1677: vp = (struct vnode *)fp->f_data;
1678: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1679: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1680: VATTR_NULL(&vattr);
1681: vattr.va_flags = uap->flags;
1682: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1683: VOP_UNLOCK(vp, 0, p);
1684: return (error);
1685: }
1686:
1687: /*
1688: * Change mode of a file given path name.
1689: */
1690: struct chmod_args {
1691: char *path;
1692: int mode;
1693: };
1694: /* ARGSUSED */
1695: int
1696: chmod(p, uap, retval)
1697: struct proc *p;
1698: register struct chmod_args *uap;
1699: register_t *retval;
1700: {
1701: register struct vnode *vp;
1702: struct vattr vattr;
1703: int error;
1704: struct nameidata nd;
1705:
1706: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
1707: if (error = namei(&nd))
1708: return (error);
1709: vp = nd.ni_vp;
1710: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1711: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1712: VATTR_NULL(&vattr);
1713: vattr.va_mode = uap->mode & ALLPERMS;
1714: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1715: vput(vp);
1716: return (error);
1717: }
1718:
1719: /*
1720: * Change mode of a file given a file descriptor.
1721: */
1722: struct fchmod_args {
1723: int fd;
1724: int mode;
1725: };
1726: /* ARGSUSED */
1727: int
1728: fchmod(p, uap, retval)
1729: struct proc *p;
1730: register struct fchmod_args *uap;
1731: register_t *retval;
1732: {
1733: struct vattr vattr;
1734: struct vnode *vp;
1735: struct file *fp;
1736: int error;
1737:
1738: if (error = getvnode(p, uap->fd, &fp))
1739: return (error);
1740: vp = (struct vnode *)fp->f_data;
1741: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1742: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1743: VATTR_NULL(&vattr);
1744: vattr.va_mode = uap->mode & ALLPERMS;
1745: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1746: VOP_UNLOCK(vp, 0, p);
1747: return (error);
1748: }
1749:
1750: /*
1751: * Set ownership given a path name.
1752: */
1753: struct chown_args {
1754: char *path;
1755: int uid;
1756: int gid;
1757: };
1758: /* ARGSUSED */
1759: int
1760: chown(p, uap, retval)
1761: struct proc *p;
1762: register struct chown_args *uap;
1763: register_t *retval;
1764: {
1765: register struct vnode *vp;
1766: struct vattr vattr;
1767: int error;
1768: struct nameidata nd;
1769:
1770: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
1771: if (error = namei(&nd))
1772: return (error);
1773: vp = nd.ni_vp;
1774: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1775: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1776: VATTR_NULL(&vattr);
1777: vattr.va_uid = uap->uid;
1778: vattr.va_gid = uap->gid;
1779: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1780: vput(vp);
1781: return (error);
1782: }
1783:
1784: /*
1785: * Set ownership given a file descriptor.
1786: */
1787: struct fchown_args {
1788: int fd;
1789: int uid;
1790: int gid;
1791: };
1792: /* ARGSUSED */
1793: int
1794: fchown(p, uap, retval)
1795: struct proc *p;
1796: register struct fchown_args *uap;
1797: register_t *retval;
1798: {
1799: struct vattr vattr;
1800: struct vnode *vp;
1801: struct file *fp;
1802: int error;
1803:
1804: if (error = getvnode(p, uap->fd, &fp))
1805: return (error);
1806: vp = (struct vnode *)fp->f_data;
1807: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1808: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1809: VATTR_NULL(&vattr);
1810: vattr.va_uid = uap->uid;
1811: vattr.va_gid = uap->gid;
1812: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1813: VOP_UNLOCK(vp, 0, p);
1814: return (error);
1815: }
1816:
1817: /*
1818: * Set the access and modification times of a file.
1819: */
1820: struct utimes_args {
1821: char *path;
1822: struct timeval *tptr;
1823: };
1824: /* ARGSUSED */
1825: int
1826: utimes(p, uap, retval)
1827: struct proc *p;
1828: register struct utimes_args *uap;
1829: register_t *retval;
1830: {
1831: register struct vnode *vp;
1832: struct timeval tv[2];
1833: struct vattr vattr;
1834: int error;
1835: struct nameidata nd;
1836:
1837: VATTR_NULL(&vattr);
1838: if (uap->tptr == NULL) {
1839: microtime(&tv[0]);
1840: tv[1] = tv[0];
1841: vattr.va_vaflags |= VA_UTIMES_NULL;
1842: } else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv,
1843: sizeof (tv)))
1844: return (error);
1845: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
1846: if (error = namei(&nd))
1847: return (error);
1848: vp = nd.ni_vp;
1849: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1850: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1851: vattr.va_atime.tv_sec = tv[0].tv_sec;
1852: vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000;
1853: vattr.va_mtime.tv_sec = tv[1].tv_sec;
1854: vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000;
1855: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1856: vput(vp);
1857: return (error);
1858: }
1859:
1860: /*
1861: * Truncate a file given its path name.
1862: */
1863: struct truncate_args {
1864: char *path;
1865: #ifdef DOUBLE_ALIGN_PARAMS
1866: int pad;
1867: #endif
1868: off_t length;
1869: };
1870: /* ARGSUSED */
1871: int
1872: truncate(p, uap, retval)
1873: struct proc *p;
1874: register struct truncate_args *uap;
1875: register_t *retval;
1876: {
1877: register struct vnode *vp;
1878: struct vattr vattr;
1879: int error;
1880: struct nameidata nd;
1881:
1882: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
1883: if (error = namei(&nd))
1884: return (error);
1885: vp = nd.ni_vp;
1886: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1887: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1888: if (vp->v_type == VDIR)
1889: error = EISDIR;
1890: else if ((error = vn_writechk(vp)) == 0 &&
1891: (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
1892: VATTR_NULL(&vattr);
1893: vattr.va_size = uap->length;
1894: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1895: }
1896: vput(vp);
1897: return (error);
1898: }
1899:
1900: /*
1901: * Truncate a file given a file descriptor.
1902: */
1903: struct ftruncate_args {
1904: int fd;
1905: #ifdef DOUBLE_ALIGN_PARAMS
1906: int pad;
1907: #endif
1908: off_t length;
1909: };
1910: /* ARGSUSED */
1911: int
1912: ftruncate(p, uap, retval)
1913: struct proc *p;
1914: register struct ftruncate_args *uap;
1915: register_t *retval;
1916: {
1917: struct vattr vattr;
1918: struct vnode *vp;
1919: struct file *fp;
1920: int error;
1921:
1922: if (error = getvnode(p, uap->fd, &fp))
1923: return (error);
1924: if ((fp->f_flag & FWRITE) == 0)
1925: return (EINVAL);
1926: vp = (struct vnode *)fp->f_data;
1927: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1928: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1929: if (vp->v_type == VDIR)
1930: error = EISDIR;
1931: else if ((error = vn_writechk(vp)) == 0) {
1932: VATTR_NULL(&vattr);
1933: vattr.va_size = uap->length;
1934: error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
1935: }
1936: VOP_UNLOCK(vp, 0, p);
1937: return (error);
1938: }
1939:
1940: #if COMPAT_43
1941: /*
1942: * Truncate a file given its path name.
1943: */
1944: struct otruncate_args {
1945: char *path;
1946: long length;
1947: };
1948: /* ARGSUSED */
1949: int
1950: otruncate(p, uap, retval)
1951: struct proc *p;
1952: register struct otruncate_args *uap;
1953: register_t *retval;
1954: {
1955: struct truncate_args /* {
1956: syscallarg(char *) path;
1957: #ifdef DOUBLE_ALIGN_PARAMS
1958: syscallarg(int) pad;
1959: #endif
1960: syscallarg(off_t) length;
1961: } */ nuap;
1962:
1963: nuap.path = uap->path;
1964: nuap.length = uap->length;
1965: return (truncate(p, &nuap, retval));
1966: }
1967:
1968: /*
1969: * Truncate a file given a file descriptor.
1970: */
1971: struct oftruncate_args {
1972: int fd;
1973: long length;
1974: };
1975: /* ARGSUSED */
1976: int
1977: oftruncate(p, uap, retval)
1978: struct proc *p;
1979: register struct oftruncate_args *uap;
1980: register_t *retval;
1981: {
1982: struct ftruncate_args /* {
1983: syscallarg(int) fd;
1984: #ifdef DOUBLE_ALIGN_PARAMS
1985: syscallarg(int) pad;
1986: #endif
1987: syscallarg(off_t) length;
1988: } */ nuap;
1989:
1990: nuap.fd = uap->fd;
1991: nuap.length = uap->length;
1992: return (ftruncate(p, &nuap, retval));
1993: }
1994: #endif /* COMPAT_43 */
1995:
1996: /*
1997: * Sync an open file.
1998: */
1999: struct fsync_args {
2000: int fd;
2001: };
2002: /* ARGSUSED */
2003: int
2004: fsync(p, uap, retval)
2005: struct proc *p;
2006: struct fsync_args *uap;
2007: register_t *retval;
2008: {
2009: register struct vnode *vp;
2010: struct file *fp;
2011: int error;
2012:
2013: if (error = getvnode(p, uap->fd, &fp))
2014: return (error);
2015: vp = (struct vnode *)fp->f_data;
2016: #if MACH_NBC
2017: mapfs_fsync(vp);
2018: #endif
2019: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2020: error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
2021: VOP_UNLOCK(vp, 0, p);
2022: return (error);
2023: }
2024:
2025: /*
2026: * Rename files. Source and destination must either both be directories,
2027: * or both not be directories. If target is a directory, it must be empty.
2028: */
2029: struct rename_args {
2030: char *from;
2031: char *to;
2032: };
2033: /* ARGSUSED */
2034: int
2035: rename(p, uap, retval)
2036: struct proc *p;
2037: register struct rename_args *uap;
2038: register_t *retval;
2039: {
2040: register struct vnode *tvp, *fvp, *tdvp;
2041: struct nameidata fromnd, tond;
2042: int error;
2043:
2044: NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
2045: uap->from, p);
2046: if (error = namei(&fromnd))
2047: return (error);
2048: fvp = fromnd.ni_vp;
2049: NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
2050: UIO_USERSPACE, uap->to, p);
2051: if (error = namei(&tond)) {
2052: VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2053: vrele(fromnd.ni_dvp);
2054: vrele(fvp);
2055: goto out1;
2056: }
2057: tdvp = tond.ni_dvp;
2058: tvp = tond.ni_vp;
2059: if (tvp != NULL) {
2060: if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
2061: error = ENOTDIR;
2062: goto out;
2063: } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
2064: error = EISDIR;
2065: goto out;
2066: }
2067: }
2068: if (fvp == tdvp)
2069: error = EINVAL;
2070: /*
2071: * If source is the same as the destination (that is the
2072: * same inode number) then there is nothing to do.
2073: * (fixed to have POSIX semantics - CSM 3/2/98)
2074: */
2075: if (fvp == tvp)
2076: error = -1;
2077: out:
2078: if (!error) {
2079: VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE);
2080: if (fromnd.ni_dvp != tdvp)
2081: VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2082: if (tvp)
2083: VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE);
2084: error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
2085: tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
2086: } else {
2087: VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
2088: if (tdvp == tvp)
2089: vrele(tdvp);
2090: else
2091: vput(tdvp);
2092: if (tvp)
2093: vput(tvp);
2094: VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2095: vrele(fromnd.ni_dvp);
2096: vrele(fvp);
2097: }
2098: vrele(tond.ni_startdir);
2099: FREE_ZONE(tond.ni_cnd.cn_pnbuf, tond.ni_cnd.cn_pnlen, M_NAMEI);
2100: out1:
2101: if (fromnd.ni_startdir)
2102: vrele(fromnd.ni_startdir);
2103: FREE_ZONE(fromnd.ni_cnd.cn_pnbuf, fromnd.ni_cnd.cn_pnlen, M_NAMEI);
2104: if (error == -1)
2105: return (0);
2106: return (error);
2107: }
2108:
2109: /*
2110: * Make a directory file.
2111: */
2112: struct mkdir_args {
2113: char *path;
2114: int mode;
2115: };
2116: /* ARGSUSED */
2117: int
2118: mkdir(p, uap, retval)
2119: struct proc *p;
2120: register struct mkdir_args *uap;
2121: register_t *retval;
2122: {
2123: register struct vnode *vp;
2124: struct vattr vattr;
2125: int error;
2126: struct nameidata nd;
2127:
2128: NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
2129: if (error = namei(&nd))
2130: return (error);
2131: vp = nd.ni_vp;
2132: if (vp != NULL) {
2133: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2134: if (nd.ni_dvp == vp)
2135: vrele(nd.ni_dvp);
2136: else
2137: vput(nd.ni_dvp);
2138: vrele(vp);
2139: return (EEXIST);
2140: }
2141: VATTR_NULL(&vattr);
2142: vattr.va_type = VDIR;
2143: vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask;
2144: VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2145: error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
2146: if (!error)
2147: vput(nd.ni_vp);
2148: return (error);
2149: }
2150:
2151: /*
2152: * Remove a directory file.
2153: */
2154: struct rmdir_args {
2155: char *path;
2156: };
2157: /* ARGSUSED */
2158: int
2159: rmdir(p, uap, retval)
2160: struct proc *p;
2161: struct rmdir_args *uap;
2162: register_t *retval;
2163: {
2164: register struct vnode *vp;
2165: int error;
2166: struct nameidata nd;
2167:
2168: NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
2169: uap->path, p);
2170: if (error = namei(&nd))
2171: return (error);
2172: vp = nd.ni_vp;
2173: if (vp->v_type != VDIR) {
2174: error = ENOTDIR;
2175: goto out;
2176: }
2177: /*
2178: * No rmdir "." please.
2179: */
2180: if (nd.ni_dvp == vp) {
2181: error = EINVAL;
2182: goto out;
2183: }
2184: /*
2185: * The root of a mounted filesystem cannot be deleted.
2186: */
2187: if (vp->v_flag & VROOT)
2188: error = EBUSY;
2189: out:
2190: if (!error) {
2191: VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2192: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2193: error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2194: } else {
2195: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2196: if (nd.ni_dvp == vp)
2197: vrele(nd.ni_dvp);
2198: else
2199: vput(nd.ni_dvp);
2200: vput(vp);
2201: }
2202: return (error);
2203: }
2204:
2205: #if COMPAT_43
2206: /*
2207: * Read a block of directory entries in a file system independent format.
2208: */
2209: struct ogetdirentries_args {
2210: int fd;
2211: char *buf;
2212: u_int count;
2213: long *basep;
2214: };
2215: int
2216: ogetdirentries(p, uap, retval)
2217: struct proc *p;
2218: register struct ogetdirentries_args *uap;
2219: register_t *retval;
2220: {
2221: register struct vnode *vp;
2222: struct file *fp;
2223: struct uio auio, kuio;
2224: struct iovec aiov, kiov;
2225: struct dirent *dp, *edp;
2226: caddr_t dirbuf;
2227: int error, eofflag, readcnt;
2228: long loff;
2229:
2230: if (error = getvnode(p, uap->fd, &fp))
2231: return (error);
2232: if ((fp->f_flag & FREAD) == 0)
2233: return (EBADF);
2234: vp = (struct vnode *)fp->f_data;
2235: unionread:
2236: if (vp->v_type != VDIR)
2237: return (EINVAL);
2238: aiov.iov_base = uap->buf;
2239: aiov.iov_len = uap->count;
2240: auio.uio_iov = &aiov;
2241: auio.uio_iovcnt = 1;
2242: auio.uio_rw = UIO_READ;
2243: auio.uio_segflg = UIO_USERSPACE;
2244: auio.uio_procp = p;
2245: auio.uio_resid = uap->count;
2246: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2247: loff = auio.uio_offset = fp->f_offset;
2248: # if (BYTE_ORDER != LITTLE_ENDIAN)
2249: if (vp->v_mount->mnt_maxsymlinklen <= 0) {
2250: error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
2251: (int *)0, (u_long *)0);
2252: fp->f_offset = auio.uio_offset;
2253: } else
2254: # endif
2255: {
2256: kuio = auio;
2257: kuio.uio_iov = &kiov;
2258: kuio.uio_segflg = UIO_SYSSPACE;
2259: kiov.iov_len = uap->count;
2260: MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK);
2261: kiov.iov_base = dirbuf;
2262: error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
2263: (int *)0, (u_long *)0);
2264: fp->f_offset = kuio.uio_offset;
2265: if (error == 0) {
2266: readcnt = uap->count - kuio.uio_resid;
2267: edp = (struct dirent *)&dirbuf[readcnt];
2268: for (dp = (struct dirent *)dirbuf; dp < edp; ) {
2269: # if (BYTE_ORDER == LITTLE_ENDIAN)
2270: /*
2271: * The expected low byte of
2272: * dp->d_namlen is our dp->d_type.
2273: * The high MBZ byte of dp->d_namlen
2274: * is our dp->d_namlen.
2275: */
2276: dp->d_type = dp->d_namlen;
2277: dp->d_namlen = 0;
2278: # else
2279: /*
2280: * The dp->d_type is the high byte
2281: * of the expected dp->d_namlen,
2282: * so must be zero'ed.
2283: */
2284: dp->d_type = 0;
2285: # endif
2286: if (dp->d_reclen > 0) {
2287: dp = (struct dirent *)
2288: ((char *)dp + dp->d_reclen);
2289: } else {
2290: error = EIO;
2291: break;
2292: }
2293: }
2294: if (dp >= edp)
2295: error = uiomove(dirbuf, readcnt, &auio);
2296: }
2297: FREE(dirbuf, M_TEMP);
2298: }
2299: VOP_UNLOCK(vp, 0, p);
2300: if (error)
2301: return (error);
2302:
2303: #if UNION
2304: {
2305: extern int (**union_vnodeop_p)();
2306: extern struct vnode *union_dircache __P((struct vnode*, struct proc*));
2307:
2308: if ((uap->count == auio.uio_resid) &&
2309: (vp->v_op == union_vnodeop_p)) {
2310: struct vnode *lvp;
2311:
2312: lvp = union_dircache(vp, p);
2313: if (lvp != NULLVP) {
2314: struct vattr va;
2315:
2316: /*
2317: * If the directory is opaque,
2318: * then don't show lower entries
2319: */
2320: error = VOP_GETATTR(vp, &va, fp->f_cred, p);
2321: if (va.va_flags & OPAQUE) {
2322: vput(lvp);
2323: lvp = NULL;
2324: }
2325: }
2326:
2327: if (lvp != NULLVP) {
2328: error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
2329: if (error) {
2330: vput(lvp);
2331: return (error);
2332: }
2333: VOP_UNLOCK(lvp, 0, p);
2334: fp->f_data = (caddr_t) lvp;
2335: fp->f_offset = 0;
2336: error = vn_close(vp, FREAD, fp->f_cred, p);
2337: if (error)
2338: return (error);
2339: vp = lvp;
2340: goto unionread;
2341: }
2342: }
2343: }
2344: #endif /* UNION */
2345:
2346: if ((uap->count == auio.uio_resid) &&
2347: (vp->v_flag & VROOT) &&
2348: (vp->v_mount->mnt_flag & MNT_UNION)) {
2349: struct vnode *tvp = vp;
2350: vp = vp->v_mount->mnt_vnodecovered;
2351: VREF(vp);
2352: fp->f_data = (caddr_t) vp;
2353: fp->f_offset = 0;
2354: vrele(tvp);
2355: goto unionread;
2356: }
2357: error = copyout((caddr_t)&loff, (caddr_t)uap->basep,
2358: sizeof(long));
2359: *retval = uap->count - auio.uio_resid;
2360: return (error);
2361: }
2362: #endif /* COMPAT_43 */
2363:
2364: /*
2365: * Read a block of directory entries in a file system independent format.
2366: */
2367: struct getdirentries_args {
2368: int fd;
2369: char *buf;
2370: u_int count;
2371: long *basep;
2372: };
2373: int
2374: getdirentries(p, uap, retval)
2375: struct proc *p;
2376: register struct getdirentries_args *uap;
2377: register_t *retval;
2378: {
2379: register struct vnode *vp;
2380: struct file *fp;
2381: struct uio auio;
2382: struct iovec aiov;
2383: long loff;
2384: int error, eofflag;
2385:
2386: if (error = getvnode(p, uap->fd, &fp))
2387: return (error);
2388: if ((fp->f_flag & FREAD) == 0)
2389: return (EBADF);
2390: vp = (struct vnode *)fp->f_data;
2391: unionread:
2392: if (vp->v_type != VDIR)
2393: return (EINVAL);
2394: aiov.iov_base = uap->buf;
2395: aiov.iov_len = uap->count;
2396: auio.uio_iov = &aiov;
2397: auio.uio_iovcnt = 1;
2398: auio.uio_rw = UIO_READ;
2399: auio.uio_segflg = UIO_USERSPACE;
2400: auio.uio_procp = p;
2401: auio.uio_resid = uap->count;
2402: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2403: loff = auio.uio_offset = fp->f_offset;
2404: error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
2405: (int *)0, (u_long *)0);
2406: fp->f_offset = auio.uio_offset;
2407: VOP_UNLOCK(vp, 0, p);
2408: if (error)
2409: return (error);
2410:
2411: #if UNION
2412: {
2413: extern int (**union_vnodeop_p)();
2414: extern struct vnode *union_dircache __P((struct vnode*, struct proc*));
2415:
2416: if ((uap->count == auio.uio_resid) &&
2417: (vp->v_op == union_vnodeop_p)) {
2418: struct vnode *lvp;
2419:
2420: lvp = union_dircache(vp, p);
2421: if (lvp != NULLVP) {
2422: struct vattr va;
2423:
2424: /*
2425: * If the directory is opaque,
2426: * then don't show lower entries
2427: */
2428: error = VOP_GETATTR(vp, &va, fp->f_cred, p);
2429: if (va.va_flags & OPAQUE) {
2430: vput(lvp);
2431: lvp = NULL;
2432: }
2433: }
2434:
2435: if (lvp != NULLVP) {
2436: error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
2437: if (error) {
2438: vput(lvp);
2439: return (error);
2440: }
2441: VOP_UNLOCK(lvp, 0, p);
2442: fp->f_data = (caddr_t) lvp;
2443: fp->f_offset = 0;
2444: error = vn_close(vp, FREAD, fp->f_cred, p);
2445: if (error)
2446: return (error);
2447: vp = lvp;
2448: goto unionread;
2449: }
2450: }
2451: }
2452: #endif /* UNION */
2453:
2454: if ((uap->count == auio.uio_resid) &&
2455: (vp->v_flag & VROOT) &&
2456: (vp->v_mount->mnt_flag & MNT_UNION)) {
2457: struct vnode *tvp = vp;
2458: vp = vp->v_mount->mnt_vnodecovered;
2459: VREF(vp);
2460: fp->f_data = (caddr_t) vp;
2461: fp->f_offset = 0;
2462: vrele(tvp);
2463: goto unionread;
2464: }
2465: error = copyout((caddr_t)&loff, (caddr_t)uap->basep,
2466: sizeof(long));
2467: *retval = uap->count - auio.uio_resid;
2468: return (error);
2469: }
2470:
2471: /*
2472: * Set the mode mask for creation of filesystem nodes.
2473: */
2474: struct umask_args {
2475: int newmask;
2476: };
2477: int
2478: umask(p, uap, retval)
2479: struct proc *p;
2480: struct umask_args *uap;
2481: register_t *retval;
2482: {
2483: register struct filedesc *fdp;
2484:
2485: fdp = p->p_fd;
2486: *retval = fdp->fd_cmask;
2487: fdp->fd_cmask = uap->newmask & ALLPERMS;
2488: return (0);
2489: }
2490:
2491: /*
2492: * Void all references to file by ripping underlying filesystem
2493: * away from vnode.
2494: */
2495: struct revoke_args {
2496: char *path;
2497: };
2498: /* ARGSUSED */
2499: int
2500: revoke(p, uap, retval)
2501: struct proc *p;
2502: register struct revoke_args *uap;
2503: register_t *retval;
2504: {
2505: register struct vnode *vp;
2506: struct vattr vattr;
2507: int error;
2508: struct nameidata nd;
2509:
2510: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
2511: if (error = namei(&nd))
2512: return (error);
2513: vp = nd.ni_vp;
2514: if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
2515: goto out;
2516: if (p->p_ucred->cr_uid != vattr.va_uid &&
2517: (error = suser(p->p_ucred, &p->p_acflag)))
2518: goto out;
2519: if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
2520: VOP_REVOKE(vp, REVOKEALL);
2521: out:
2522: vrele(vp);
2523: return (error);
2524: }
2525:
2526: /*
2527: * Convert a user file descriptor to a kernel file entry.
2528: */
2529: int
2530: getvnode(p, fd, fpp)
2531: struct proc *p;
2532: int fd;
2533: struct file **fpp;
2534: {
2535: struct file *fp;
2536: int error;
2537:
2538: if (error = fdgetf(p, fd, &fp))
2539: return (error);
2540: if (fp->f_type != DTYPE_VNODE)
2541: return (EINVAL);
2542: *fpp = fp;
2543: return (0);
2544: }
2545: /*
2546: * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
2547: * The following 10 system calls are designed to support features
2548: * which are specific to the HFS & HFS Plus volume formats
2549: */
2550:
2551:
2552: /*
2553: * Make a complex file. A complex file is one with multiple forks (data streams)
2554: */
2555: struct mkcomplex_args {
2556: const char *path; /* pathname of the file to be created */
2557: mode_t mode; /* access mode for the newly created file */
2558: u_long type; /* format of the complex file */
2559: };
2560: /* ARGSUSED */
2561: int
2562: mkcomplex(p,uap,retval)
2563: struct proc *p;
2564: register struct mkcomplex_args *uap;
2565: register_t *retval;
2566:
2567: {
2568: struct vnode *vp;
2569: struct vattr vattr;
2570: int error;
2571: struct nameidata nd;
2572:
2573: /* mkcomplex wants the directory vnode locked so do that here */
2574:
2575: NDINIT(&nd, CREATE, FOLLOW | LOCKPARENT, UIO_USERSPACE, uap->path, p);
2576: if (error = namei(&nd))
2577: return (error);
2578:
2579: /* Set the attributes as specified by the user */
2580:
2581: VATTR_NULL(&vattr);
2582: vattr.va_mode = (uap->mode & ACCESSPERMS);
2583: error = VOP_MKCOMPLEX(nd.ni_dvp, &vp, &nd.ni_cnd, &vattr, uap->type);
2584:
2585: /* The mkcomplex call promises to release the parent vnode pointer
2586: * even an an error case so don't do it here unless the operation
2587: * is not supported. In that case, there isn't anyone to unlock the parent
2588: * The vnode pointer to the file will also be released.
2589: */
2590:
2591: if (error)
2592: {
2593: if (error == EOPNOTSUPP)
2594: vput(nd.ni_dvp);
2595: return (error);
2596: }
2597:
2598: return (0);
2599:
2600: } /* end of mkcomplex system call */
2601:
2602:
2603:
2604: /*
2605: * Extended stat call which returns volumeid and vnodeid as well as other info
2606: */
2607: struct statv_args {
2608: const char *path; /* pathname of the target file */
2609: struct vstat *vsb; /* vstat structure for returned info */
2610: };
2611: /* ARGSUSED */
2612: int
2613: statv(p,uap,retval)
2614: struct proc *p;
2615: register struct statv_args *uap;
2616: register_t *retval;
2617:
2618: {
2619: return (EOPNOTSUPP); /* We'll just return an error for now */
2620:
2621: } /* end of statv system call */
2622:
2623:
2624:
2625: /*
2626: * Extended lstat call which returns volumeid and vnodeid as well as other info
2627: */
2628: struct lstatv_args {
2629: const char *path; /* pathname of the target file */
2630: struct vstat *vsb; /* vstat structure for returned info */
2631: };
2632: /* ARGSUSED */
2633: int
2634: lstatv(p,uap,retval)
2635: struct proc *p;
2636: register struct lstatv_args *uap;
2637: register_t *retval;
2638:
2639: {
2640: return (EOPNOTSUPP); /* We'll just return an error for now */
2641: } /* end of lstatv system call */
2642:
2643:
2644:
2645: /*
2646: * Extended fstat call which returns volumeid and vnodeid as well as other info
2647: */
2648: struct fstatv_args {
2649: int fd; /* file descriptor of the target file */
2650: struct vstat *vsb; /* vstat structure for returned info */
2651: };
2652: /* ARGSUSED */
2653: int
2654: fstatv(p,uap,retval)
2655: struct proc *p;
2656: register struct fstatv_args *uap;
2657: register_t *retval;
2658:
2659: {
2660: return (EOPNOTSUPP); /* We'll just return an error for now */
2661: } /* end of fstatv system call */
2662:
2663:
2664:
2665: /*
2666: * Obtain attribute information about a file system object
2667: */
2668:
2669: struct getattrlist_args {
2670: const char *path; /* pathname of the target object */
2671: struct attrlist * alist; /* Attributes desired by the user */
2672: void * attributeBuffer; /* buffer to hold returned attributes */
2673: size_t bufferSize; /* size of the return buffer */
2674: };
2675: /* ARGSUSED */
2676: int
2677: getattrlist (p,uap,retval)
2678: struct proc *p;
2679: register struct getattrlist_args *uap;
2680: register_t *retval;
2681:
2682: {
2683: int error;
2684: struct nameidata nd;
2685: struct iovec aiov;
2686: struct uio auio;
2687: struct attrlist attributelist;
2688:
2689: /* Get the attributes desire and do our parameter checking */
2690:
2691: if (error = copyin((caddr_t)uap->alist, (caddr_t) &attributelist,
2692: sizeof (attributelist)))
2693: {
2694: return(error);
2695: }
2696:
2697: if (attributelist.bitmapcount != ATTR_BIT_MAP_COUNT
2698: #if 0
2699: || attributelist.commonattr & ~ATTR_CMN_VALIDMASK ||
2700: attributelist.volattr & ~ATTR_VOL_VALIDMASK ||
2701: attributelist.dirattr & ~ATTR_DIR_VALIDMASK ||
2702: attributelist.fileattr & ~ATTR_FILE_VALIDMASK ||
2703: attributelist.forkattr & ~ATTR_FORK_VALIDMASK
2704: #endif
2705: )
2706: {
2707: return (EINVAL);
2708: }
2709:
2710: /* Get the vnode for the file we are getting info on. */
2711: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
2712:
2713: if (error = namei(&nd))
2714: return (error);
2715:
2716: /* Set up the UIO structure for use by the vfs routine */
2717:
2718:
2719: aiov.iov_base = uap->attributeBuffer;
2720: aiov.iov_len = uap->bufferSize;
2721: auio.uio_iov = &aiov;
2722: auio.uio_iovcnt = 1;
2723: auio.uio_offset = 0;
2724: auio.uio_rw = UIO_READ;
2725: auio.uio_segflg = UIO_USERSPACE;
2726: auio.uio_procp = p;
2727: auio.uio_resid = uap->bufferSize;
2728:
2729:
2730: error = VOP_GETATTRLIST(nd.ni_vp, &attributelist, &auio, p->p_ucred, p);
2731:
2732: /* Unlock and release the vnode which will have been locked by namei */
2733:
2734: vput(nd.ni_vp);
2735:
2736: /* return the effort if we got one, otherwise return success */
2737:
2738: if (error)
2739: {
2740: return (error);
2741: }
2742:
2743: return(0);
2744:
2745: } /* end of getattrlist system call */
2746:
2747:
2748:
2749: /*
2750: * Set attribute information about a file system object
2751: */
2752:
2753: struct setattrlist_args {
2754: const char *path; /* pathname of the target object */
2755: struct attrlist * alist; /* Attributes being set by the user */
2756: void * attributeBuffer; /* buffer with attribute values to be set */
2757: size_t bufferSize; /* size of the return buffer */
2758: };
2759: /* ARGSUSED */
2760: int
2761: setattrlist (p,uap,retval)
2762: struct proc *p;
2763: register struct setattrlist_args *uap;
2764: register_t *retval;
2765:
2766: {
2767: int error;
2768: struct nameidata nd;
2769: struct iovec aiov;
2770: struct uio auio;
2771: struct attrlist attributelist;
2772:
2773: /* Get the attributes desire and do our parameter checking */
2774:
2775: if (error = copyin((caddr_t)uap->alist, (caddr_t) &attributelist,
2776: sizeof (attributelist)))
2777: {
2778: return(error);
2779: }
2780:
2781: if (attributelist.bitmapcount != ATTR_BIT_MAP_COUNT
2782: #if 0
2783: || attributelist.commonattr & ~ATTR_CMN_VALIDMASK ||
2784: attributelist.volattr & ~ATTR_VOL_VALIDMASK ||
2785: attributelist.dirattr & ~ATTR_DIR_VALIDMASK ||
2786: attributelist.fileattr & ~ATTR_FILE_VALIDMASK ||
2787: attributelist.forkattr & ~ATTR_FORK_VALIDMASK
2788: #endif
2789: )
2790: {
2791: return (EINVAL);
2792: }
2793:
2794: /* Get the vnode for the file we are getting info on. */
2795: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
2796:
2797: if (error = namei(&nd))
2798: return (error);
2799:
2800: /* Set up the UIO structure for use by the vfs routine */
2801:
2802: aiov.iov_base = uap->attributeBuffer;
2803: aiov.iov_len = uap->bufferSize;
2804: auio.uio_iov = &aiov;
2805: auio.uio_iovcnt = 1;
2806: auio.uio_offset = 0;
2807: auio.uio_rw = UIO_WRITE;
2808: auio.uio_segflg = UIO_USERSPACE;
2809: auio.uio_procp = p;
2810: auio.uio_resid = uap->bufferSize;
2811:
2812:
2813: error = VOP_SETATTRLIST(nd.ni_vp,&attributelist, &auio, p->p_ucred, p);
2814:
2815: /* Unlock and release the vnode which will have been locked by namei */
2816:
2817: vput(nd.ni_vp);
2818:
2819: /* return the error if we got one, otherwise return success */
2820:
2821: if (error)
2822: {
2823: return (error);
2824: }
2825:
2826: return(0);
2827:
2828: } /* end of setattrlist system call */
2829:
2830:
2831: /*
2832: * Obtain attribute information on objects in a directory while enumerating
2833: the directory. This call does not yet support union mounted directories.
2834: */
2835:
2836: struct getdirentryattr_args {
2837: int fd; /* file descriptor */
2838: int *index; /* Cookie from the user */
2839: struct attrlist *alist; /* bit map of requested attributes */
2840: void *attributebuffer; /* buffer to hold returned attribute info */
2841: size_t buffersize; /* size of the return buffer */
2842: };
2843: /* ARGSUSED */
2844: int
2845: getdirentryattr (p,uap,retval)
2846: struct proc *p;
2847: register struct getdirentryattr_args *uap;
2848: register_t *retval;
2849:
2850: {
2851: register struct vnode *vp;
2852: struct file *fp;
2853: struct uio auio;
2854: struct iovec aiov;
2855: int index;
2856: int error, eofflag;
2857: struct attrlist attributelist;
2858:
2859: /* Get the attributes desired and do our parameter checking */
2860:
2861: if (error = copyin((caddr_t)uap->alist, (caddr_t) &attributelist,
2862: sizeof (attributelist)))
2863: {
2864: return(error);
2865: }
2866:
2867: if (attributelist.bitmapcount != ATTR_BIT_MAP_COUNT)
2868: {
2869: return (EINVAL);
2870: }
2871:
2872: if (error = getvnode(p, uap->fd, &fp))
2873: return (error);
2874:
2875: if ((fp->f_flag & FREAD) == 0)
2876: {
2877: return(EBADF);
2878: }
2879:
2880: vp = (struct vnode *)fp->f_data;
2881:
2882: if (vp->v_type != VDIR)
2883: {
2884: return(EINVAL);
2885: }
2886:
2887: if (error = copyin((caddr_t) uap->index, (caddr_t) &index, sizeof(index)))
2888: return(error);
2889:
2890: /* set up the uio structure which will contain the users return buffer */
2891:
2892: aiov.iov_base = uap->attributebuffer;
2893: aiov.iov_len = uap->buffersize;
2894: auio.uio_iov = &aiov;
2895: auio.uio_iovcnt = 1;
2896: auio.uio_rw = UIO_READ;
2897: auio.uio_segflg = UIO_USERSPACE;
2898: auio.uio_procp = p;
2899: auio.uio_resid = uap->buffersize;
2900:
2901: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2902: error = VOP_READDIRATTR (vp, &attributelist, &auio, &index, &eofflag,((u_long*)0), ((u_long **)0),fp->f_cred);
2903: fp->f_offset = auio.uio_offset;
2904:
2905: if (error)
2906: return (error);
2907:
2908: VOP_UNLOCK(vp, 0, p);
2909:
2910: if (error = copyout((caddr_t) &index, (caddr_t) uap->index, sizeof(index)))
2911: return(error);
2912:
2913: return (0);
2914:
2915: } /* end of getdirentryattr system call */
2916:
2917: /*
2918: * Exchange data between two files
2919: */
2920:
2921: struct exchangedata_args {
2922: const char *path1; /* pathname of the first swapee */
2923: const char *path2; /* pathname of the second swapee */
2924: };
2925: /* ARGSUSED */
2926: int
2927: exchangedata (p,uap,retval)
2928: struct proc *p;
2929: register struct exchangedata_args *uap;
2930: register_t *retval;
2931:
2932: {
2933:
2934: struct nameidata fnd, snd;
2935: struct vnode *fvp, *svp;
2936: int error;
2937:
2938: /* Global lock, to prevent race condition, only one exchange at a time */
2939: lockmgr(&exchangelock, LK_EXCLUSIVE , (struct slock *)0, p);
2940:
2941: NDINIT(&fnd, LOOKUP,FOLLOW, UIO_USERSPACE, uap->path1, p);
2942:
2943: if (error = namei(&fnd))
2944: goto out2;
2945:
2946: fvp = fnd.ni_vp;
2947:
2948: NDINIT(&snd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path2, p);
2949:
2950: if (error = namei(&snd)) {
2951: vrele(fvp);
2952: goto out2;
2953: }
2954:
2955: svp = snd.ni_vp;
2956:
2957: /* if the files are the same, return an inval error */
2958: if (svp == fvp) {
2959: vrele(fvp);
2960: vrele(svp);
2961: error = EINVAL;
2962: goto out2;
2963: }
2964:
2965: vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p);
2966: vn_lock(svp, LK_EXCLUSIVE | LK_RETRY, p);
2967:
2968: error = VOP_ACCESS(fvp, VWRITE, p->p_ucred, p);
2969: if (error) goto out;
2970:
2971: error = VOP_ACCESS(svp, VWRITE, p->p_ucred, p);
2972: if (error) goto out;
2973:
2974: /* Ok, make the call */
2975: error = VOP_EXCHANGE (fvp, svp, p->p_ucred, p);
2976:
2977: out:
2978: vput (svp);
2979: vput (fvp);
2980:
2981: out2:
2982: lockmgr(&exchangelock, LK_RELEASE, (struct slock *)0, p);
2983:
2984: if (error) {
2985: return (error);
2986: }
2987:
2988: return (0);
2989:
2990: } /* end of exchangedata system call */
2991:
2992: /*
2993: * Check users access to a file
2994: */
2995:
2996: struct checkuseraccess_args {
2997: const char *path; /* pathname of the target file */
2998: uid_t userid; /* user for whom we are checking access */
2999: gid_t *groups; /* Group that we are checking for */
3000: int ngroups; /* Number of groups being checked */
3001: int accessrequired; /* needed access to the file */
3002: };
3003:
3004: /* ARGSUSED */
3005: int
3006: checkuseraccess (p,uap,retval)
3007: struct proc *p;
3008: register struct checkuseraccess_args *uap;
3009: register_t *retval;
3010:
3011: {
3012: register struct vnode *vp;
3013: int error;
3014: struct nameidata nd;
3015: struct ucred cred;
3016: int flags; /*what will actually get passed to access*/
3017:
3018: /* Make sure that the number of groups is correct before we do anything */
3019:
3020: if (uap->ngroups > NGROUPS)
3021: return (EINVAL);
3022:
3023: /* Verify that the caller is root */
3024:
3025: if (error = suser(p->p_ucred, &p->p_acflag))
3026: return(error);
3027:
3028: /* Fill in the credential structure */
3029:
3030: cred.cr_ref = 0;
3031: cred.cr_uid = uap->userid;
3032: cred.cr_ngroups = uap->ngroups;
3033: if (error = copyin((caddr_t) uap->groups, (caddr_t) &(cred.cr_groups), (sizeof(gid_t))*uap->ngroups))
3034: return (error);
3035:
3036: /* Get our hands on the file */
3037:
3038: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
3039:
3040: if (error = namei(&nd))
3041: return (error);
3042: vp = nd.ni_vp;
3043:
3044: /* Flags == 0 means only check for existence. */
3045:
3046: flags = 0;
3047:
3048: if (uap->accessrequired) {
3049: if (uap->accessrequired & R_OK)
3050: flags |= VREAD;
3051: if (uap->accessrequired & W_OK)
3052: flags |= VWRITE;
3053: if (uap->accessrequired & X_OK)
3054: flags |= VEXEC;
3055: }
3056: error = VOP_ACCESS(vp, flags, &cred, p);
3057:
3058: vput(vp);
3059:
3060: if (error)
3061: return (error);
3062:
3063: return (0);
3064:
3065: } /* end of checkuseraccess system call */
3066:
3067:
3068: struct searchfs_args {
3069: const char *path;
3070: struct fssearchblock *searchblock;
3071: u_long *nummatches;
3072: u_long scriptcode;
3073: u_long options;
3074: struct searchstate *state;
3075: };
3076: /* ARGSUSED */
3077:
3078: int
3079: searchfs (p,uap,retval)
3080: struct proc *p;
3081: register struct searchfs_args *uap;
3082: register_t *retval;
3083:
3084: {
3085: register struct vnode *vp;
3086: int error=0;
3087: int fserror = 0;
3088: struct nameidata nd;
3089: struct fssearchblock searchblock;
3090: struct searchstate *state;
3091: struct attrlist *returnattrs;
3092: void *searchparams1,*searchparams2;
3093: struct iovec aiov;
3094: struct uio auio;
3095: u_long nummatches;
3096: int mallocsize;
3097:
3098:
3099: /* Start by copying in fsearchblock paramater list */
3100:
3101: if (error = copyin((caddr_t) uap->searchblock, (caddr_t) &searchblock,sizeof(struct fssearchblock)))
3102: return(error);
3103:
3104: /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
3105: /* It all has to do into local memory and it's not that big so we might as well put it all together. */
3106: /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
3107: /* block. */
3108:
3109: mallocsize = searchblock.sizeofsearchparams1+searchblock.sizeofsearchparams2 +
3110: sizeof(struct attrlist) + sizeof(struct searchstate);
3111:
3112: MALLOC(searchparams1, void *, mallocsize, M_TEMP, M_WAITOK);
3113:
3114: /* Now set up the various pointers to the correct place in our newly allocated memory */
3115:
3116: searchparams2 = (void *) (((caddr_t) searchparams1) + searchblock.sizeofsearchparams1);
3117: returnattrs = (struct attrlist *) (((caddr_t) searchparams2) + searchblock.sizeofsearchparams2);
3118: state = (struct searchstate *) (((caddr_t) returnattrs) + sizeof (struct attrlist));
3119:
3120: /* Now copy in the stuff given our local variables. */
3121:
3122: if (error = copyin((caddr_t) searchblock.searchparams1, searchparams1,searchblock.sizeofsearchparams1))
3123: goto freeandexit;
3124:
3125: if (error = copyin((caddr_t) searchblock.searchparams2, searchparams2,searchblock.sizeofsearchparams2))
3126: goto freeandexit;
3127:
3128: if (error = copyin((caddr_t) searchblock.returnattrs, (caddr_t) returnattrs, sizeof(struct attrlist)))
3129: goto freeandexit;
3130:
3131: if (error = copyin((caddr_t) uap->state, (caddr_t) state, sizeof(struct searchstate)))
3132: goto freeandexit;
3133:
3134: /* set up the uio structure which will contain the users return buffer */
3135:
3136: aiov.iov_base = searchblock.returnbuffer;
3137: aiov.iov_len = searchblock.returnbuffersize;
3138: auio.uio_iov = &aiov;
3139: auio.uio_iovcnt = 1;
3140: auio.uio_rw = UIO_READ;
3141: auio.uio_segflg = UIO_USERSPACE;
3142: auio.uio_procp = p;
3143: auio.uio_resid = searchblock.returnbuffersize;
3144:
3145:
3146: NDINIT(&nd, LOOKUP, FOLLOW|LOCKLEAF, UIO_USERSPACE, uap->path, p);
3147:
3148: if (error = namei(&nd))
3149: goto freeandexit;
3150:
3151: vp = nd.ni_vp;
3152:
3153: /*
3154: Allright, we have everything we need, so lets make that call.
3155:
3156: We keep special track of the return value from the file system:
3157: EAGAIN is an acceptable error condition that shouldn't keep us
3158: from copying out any results...
3159: */
3160:
3161: fserror = VOP_SEARCHFS(vp,
3162: searchparams1,
3163: searchparams2,
3164: &searchblock.searchattrs,
3165: searchblock.maxmatches,
3166: &searchblock.timelimit,
3167: returnattrs,
3168: &nummatches,
3169: uap->scriptcode,
3170: uap->options,
3171: &auio,
3172: state);
3173:
3174: vput(vp);
3175:
3176: /* Now copy out the stuff that needs copying out. That means the number of matches, the
3177: search state. Everything was already put into he return buffer by the vop call. */
3178:
3179: if (error = copyout((caddr_t) state, (caddr_t) uap->state, sizeof(struct searchstate)))
3180: goto freeandexit;
3181:
3182: if (error = copyout((caddr_t) &nummatches, (caddr_t) uap->nummatches, sizeof(u_long)))
3183: goto freeandexit;
3184:
3185: error = fserror;
3186:
3187: freeandexit:
3188:
3189: FREE(searchparams1,M_TEMP);
3190:
3191: return(error);
3192:
3193:
3194: } /* end of searchfs system call */
3195:
3196:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.