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