Annotation of sys/kern/vfs_syscalls.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: vfs_syscalls.c,v 1.141 2007/08/06 16:58:26 millert Exp $ */
2: /* $NetBSD: vfs_syscalls.c,v 1.71 1996/04/23 10:29:02 mycroft Exp $ */
3:
4: /*
5: * Copyright (c) 1989, 1993
6: * The Regents of the University of California. All rights reserved.
7: * (c) UNIX System Laboratories, Inc.
8: * All or some portions of this file are derived from material licensed
9: * to the University of California by American Telephone and Telegraph
10: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11: * the permission of UNIX System Laboratories, Inc.
12: *
13: * Redistribution and use in source and binary forms, with or without
14: * modification, are permitted provided that the following conditions
15: * are met:
16: * 1. Redistributions of source code must retain the above copyright
17: * notice, this list of conditions and the following disclaimer.
18: * 2. Redistributions in binary form must reproduce the above copyright
19: * notice, this list of conditions and the following disclaimer in the
20: * documentation and/or other materials provided with the distribution.
21: * 3. Neither the name of the University nor the names of its contributors
22: * may be used to endorse or promote products derived from this software
23: * without specific prior written permission.
24: *
25: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35: * SUCH DAMAGE.
36: *
37: * @(#)vfs_syscalls.c 8.28 (Berkeley) 12/10/94
38: */
39:
40: #include <sys/param.h>
41: #include <sys/systm.h>
42: #include <sys/namei.h>
43: #include <sys/filedesc.h>
44: #include <sys/kernel.h>
45: #include <sys/file.h>
46: #include <sys/stat.h>
47: #include <sys/vnode.h>
48: #include <sys/mount.h>
49: #include <sys/proc.h>
50: #include <sys/uio.h>
51: #include <sys/malloc.h>
52: #include <sys/pool.h>
53: #include <sys/dirent.h>
54: #include <sys/dkio.h>
55: #include <sys/disklabel.h>
56:
57: #include <sys/syscallargs.h>
58:
59: #include <uvm/uvm_extern.h>
60: #include <sys/sysctl.h>
61:
62: extern int suid_clear;
63: int usermount = 0; /* sysctl: by default, users may not mount */
64:
65: static int change_dir(struct nameidata *, struct proc *);
66:
67: void checkdirs(struct vnode *);
68:
69: int copyout_statfs(struct statfs *, void *, struct proc *);
70:
71: /*
72: * Virtual File System System Calls
73: */
74:
75: /*
76: * Mount a file system.
77: */
78: /* ARGSUSED */
79: int
80: sys_mount(struct proc *p, void *v, register_t *retval)
81: {
82: struct sys_mount_args /* {
83: syscallarg(const char *) type;
84: syscallarg(const char *) path;
85: syscallarg(int) flags;
86: syscallarg(void *) data;
87: } */ *uap = v;
88: struct vnode *vp;
89: struct mount *mp;
90: int error, flag = 0;
91: #ifdef COMPAT_43
92: u_long fstypenum = 0;
93: #endif
94: char fstypename[MFSNAMELEN];
95: char fspath[MNAMELEN];
96: struct vattr va;
97: struct nameidata nd;
98: struct vfsconf *vfsp;
99:
100: if (usermount == 0 && (error = suser(p, 0)))
101: return (error);
102:
103: /*
104: * Mount points must fit in MNAMELEN, not MAXPATHLEN.
105: */
106: error = copyinstr(SCARG(uap, path), fspath, MNAMELEN, NULL);
107: if (error)
108: return(error);
109:
110: /*
111: * Get vnode to be covered
112: */
113: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspath, p);
114: if ((error = namei(&nd)) != 0)
115: return (error);
116: vp = nd.ni_vp;
117: if (SCARG(uap, flags) & MNT_UPDATE) {
118: if ((vp->v_flag & VROOT) == 0) {
119: vput(vp);
120: return (EINVAL);
121: }
122: mp = vp->v_mount;
123: flag = mp->mnt_flag;
124: /*
125: * We only allow the filesystem to be reloaded if it
126: * is currently mounted read-only.
127: */
128: if ((SCARG(uap, flags) & MNT_RELOAD) &&
129: ((mp->mnt_flag & MNT_RDONLY) == 0)) {
130: vput(vp);
131: return (EOPNOTSUPP); /* Needs translation */
132: }
133:
134: /*
135: * Only root, or the user that did the original mount is
136: * permitted to update it.
137: */
138: if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid &&
139: (error = suser(p, 0))) {
140: vput(vp);
141: return (error);
142: }
143: /*
144: * Do not allow NFS export by non-root users. Silently
145: * enforce MNT_NOSUID and MNT_NODEV for non-root users, and
146: * inherit MNT_NOEXEC from the mount point.
147: */
148: if (p->p_ucred->cr_uid != 0) {
149: if (SCARG(uap, flags) & MNT_EXPORTED) {
150: vput(vp);
151: return (EPERM);
152: }
153: SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
154: if (flag & MNT_NOEXEC)
155: SCARG(uap, flags) |= MNT_NOEXEC;
156: }
157: if ((error = vfs_busy(mp, VB_READ|VB_NOWAIT)) != 0) {
158: vput(vp);
159: return (error);
160: }
161: VOP_UNLOCK(vp, 0, p);
162: mp->mnt_flag |= SCARG(uap, flags) & (MNT_RELOAD | MNT_UPDATE);
163: goto update;
164: }
165: /*
166: * If the user is not root, ensure that they own the directory
167: * onto which we are attempting to mount.
168: */
169: if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) ||
170: (va.va_uid != p->p_ucred->cr_uid &&
171: (error = suser(p, 0)))) {
172: vput(vp);
173: return (error);
174: }
175: /*
176: * Do not allow NFS export by non-root users. Silently
177: * enforce MNT_NOSUID and MNT_NODEV for non-root users, and inherit
178: * MNT_NOEXEC from the mount point.
179: */
180: if (p->p_ucred->cr_uid != 0) {
181: if (SCARG(uap, flags) & MNT_EXPORTED) {
182: vput(vp);
183: return (EPERM);
184: }
185: SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
186: if (vp->v_mount->mnt_flag & MNT_NOEXEC)
187: SCARG(uap, flags) |= MNT_NOEXEC;
188: }
189: if ((error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) != 0) {
190: vput(vp);
191: return (error);
192: }
193: if (vp->v_type != VDIR) {
194: vput(vp);
195: return (ENOTDIR);
196: }
197: error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL);
198: if (error) {
199: #ifdef COMPAT_43
200: /*
201: * Historically filesystem types were identified by number.
202: * If we get an integer for the filesystem type instead of a
203: * string, we check to see if it matches one of the historic
204: * filesystem types.
205: */
206: fstypenum = (u_long)SCARG(uap, type);
207:
208: for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
209: if (vfsp->vfc_typenum == fstypenum)
210: break;
211: if (vfsp == NULL) {
212: vput(vp);
213: return (ENODEV);
214: }
215: strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN);
216:
217: #else
218: vput(vp);
219: return (error);
220: #endif
221: }
222: for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) {
223: if (!strcmp(vfsp->vfc_name, fstypename))
224: break;
225: }
226:
227: if (vfsp == NULL) {
228: vput(vp);
229: return (EOPNOTSUPP);
230: }
231:
232: if (vp->v_mountedhere != NULL) {
233: vput(vp);
234: return (EBUSY);
235: }
236:
237: /*
238: * Allocate and initialize the file system.
239: */
240: mp = (struct mount *)malloc((u_long)sizeof(struct mount),
241: M_MOUNT, M_WAITOK);
242: bzero((char *)mp, (u_long)sizeof(struct mount));
243: (void) vfs_busy(mp, VB_READ|VB_NOWAIT);
244: mp->mnt_op = vfsp->vfc_vfsops;
245: mp->mnt_vfc = vfsp;
246: mp->mnt_flag |= (vfsp->vfc_flags & MNT_VISFLAGMASK);
247: strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
248: mp->mnt_vnodecovered = vp;
249: mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
250: update:
251: /*
252: * Set the mount level flags.
253: */
254: if (SCARG(uap, flags) & MNT_RDONLY)
255: mp->mnt_flag |= MNT_RDONLY;
256: else if (mp->mnt_flag & MNT_RDONLY)
257: mp->mnt_flag |= MNT_WANTRDWR;
258: mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
259: MNT_SYNCHRONOUS | MNT_ASYNC | MNT_SOFTDEP | MNT_NOATIME |
260: MNT_FORCE);
261: mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC |
262: MNT_NODEV | MNT_SYNCHRONOUS | MNT_ASYNC | MNT_SOFTDEP |
263: MNT_NOATIME | MNT_FORCE);
264: /*
265: * Mount the filesystem.
266: */
267: error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p);
268: if (!error) {
269: mp->mnt_stat.f_ctime = time_second;
270: }
271: if (mp->mnt_flag & MNT_UPDATE) {
272: vrele(vp);
273: if (mp->mnt_flag & MNT_WANTRDWR)
274: mp->mnt_flag &= ~MNT_RDONLY;
275: mp->mnt_flag &=~
276: (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR);
277: if (error)
278: mp->mnt_flag = flag;
279:
280: if ((mp->mnt_flag & MNT_RDONLY) == 0) {
281: if (mp->mnt_syncer == NULL)
282: error = vfs_allocate_syncvnode(mp);
283: } else {
284: if (mp->mnt_syncer != NULL)
285: vgone(mp->mnt_syncer);
286: mp->mnt_syncer = NULL;
287: }
288:
289: vfs_unbusy(mp);
290: return (error);
291: }
292:
293: vp->v_mountedhere = mp;
294:
295: /*
296: * Put the new filesystem on the mount list after root.
297: */
298: cache_purge(vp);
299: if (!error) {
300: vfsp->vfc_refcount++;
301: CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
302: checkdirs(vp);
303: VOP_UNLOCK(vp, 0, p);
304: if ((mp->mnt_flag & MNT_RDONLY) == 0)
305: error = vfs_allocate_syncvnode(mp);
306: vfs_unbusy(mp);
307: (void) VFS_STATFS(mp, &mp->mnt_stat, p);
308: if ((error = VFS_START(mp, 0, p)) != 0)
309: vrele(vp);
310: } else {
311: mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
312: vfs_unbusy(mp);
313: free(mp, M_MOUNT);
314: vput(vp);
315: }
316: return (error);
317: }
318:
319: /*
320: * Scan all active processes to see if any of them have a current
321: * or root directory onto which the new filesystem has just been
322: * mounted. If so, replace them with the new mount point.
323: */
324: void
325: checkdirs(struct vnode *olddp)
326: {
327: struct filedesc *fdp;
328: struct vnode *newdp;
329: struct proc *p;
330:
331: if (olddp->v_usecount == 1)
332: return;
333: if (VFS_ROOT(olddp->v_mountedhere, &newdp))
334: panic("mount: lost mount");
335: for (p = LIST_FIRST(&allproc); p != 0; p = LIST_NEXT(p, p_list)) {
336: fdp = p->p_fd;
337: if (fdp->fd_cdir == olddp) {
338: vrele(fdp->fd_cdir);
339: VREF(newdp);
340: fdp->fd_cdir = newdp;
341: }
342: if (fdp->fd_rdir == olddp) {
343: vrele(fdp->fd_rdir);
344: VREF(newdp);
345: fdp->fd_rdir = newdp;
346: }
347: }
348: if (rootvnode == olddp) {
349: vrele(rootvnode);
350: VREF(newdp);
351: rootvnode = newdp;
352: }
353: vput(newdp);
354: }
355:
356: /*
357: * Unmount a file system.
358: *
359: * Note: unmount takes a path to the vnode mounted on as argument,
360: * not special file (as before).
361: */
362: /* ARGSUSED */
363: int
364: sys_unmount(struct proc *p, void *v, register_t *retval)
365: {
366: struct sys_unmount_args /* {
367: syscallarg(const char *) path;
368: syscallarg(int) flags;
369: } */ *uap = v;
370: struct vnode *vp;
371: struct mount *mp;
372: int error;
373: struct nameidata nd;
374:
375: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
376: SCARG(uap, path), p);
377: if ((error = namei(&nd)) != 0)
378: return (error);
379: vp = nd.ni_vp;
380: mp = vp->v_mount;
381:
382: /*
383: * Only root, or the user that did the original mount is
384: * permitted to unmount this filesystem.
385: */
386: if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) &&
387: (error = suser(p, 0))) {
388: vput(vp);
389: return (error);
390: }
391:
392: /*
393: * Don't allow unmounting the root file system.
394: */
395: if (mp->mnt_flag & MNT_ROOTFS) {
396: vput(vp);
397: return (EINVAL);
398: }
399:
400: /*
401: * Must be the root of the filesystem
402: */
403: if ((vp->v_flag & VROOT) == 0) {
404: vput(vp);
405: return (EINVAL);
406: }
407: vput(vp);
408:
409: if (vfs_busy(mp, VB_WRITE|VB_WAIT))
410: return (EBUSY);
411:
412: return (dounmount(mp, SCARG(uap, flags), p, vp));
413: }
414:
415: /*
416: * Do the actual file system unmount.
417: */
418: int
419: dounmount(struct mount *mp, int flags, struct proc *p, struct vnode *olddp)
420: {
421: struct vnode *coveredvp;
422: int error;
423: int hadsyncer = 0;
424:
425: mp->mnt_flag &=~ MNT_ASYNC;
426: cache_purgevfs(mp); /* remove cache entries for this file sys */
427: if (mp->mnt_syncer != NULL) {
428: hadsyncer = 1;
429: vgone(mp->mnt_syncer);
430: mp->mnt_syncer = NULL;
431: }
432: if (((mp->mnt_flag & MNT_RDONLY) ||
433: (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) ||
434: (flags & MNT_FORCE))
435: error = VFS_UNMOUNT(mp, flags, p);
436:
437: if (error && error != EIO && !(flags & MNT_DOOMED)) {
438: if ((mp->mnt_flag & MNT_RDONLY) == 0 && hadsyncer)
439: (void) vfs_allocate_syncvnode(mp);
440: vfs_unbusy(mp);
441: return (error);
442: }
443:
444: CIRCLEQ_REMOVE(&mountlist, mp, mnt_list);
445: if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) {
446: coveredvp->v_mountedhere = NULL;
447: vrele(coveredvp);
448: }
449:
450: mp->mnt_vfc->vfc_refcount--;
451:
452: if (!LIST_EMPTY(&mp->mnt_vnodelist))
453: panic("unmount: dangling vnode");
454:
455: vfs_unbusy(mp);
456: free(mp, M_MOUNT);
457:
458: return (0);
459: }
460:
461: /*
462: * Sync each mounted filesystem.
463: */
464: #ifdef DEBUG
465: int syncprt = 0;
466: struct ctldebug debug0 = { "syncprt", &syncprt };
467: #endif
468:
469: /* ARGSUSED */
470: int
471: sys_sync(struct proc *p, void *v, register_t *retval)
472: {
473: struct mount *mp, *nmp;
474: int asyncflag;
475:
476: for (mp = CIRCLEQ_LAST(&mountlist); mp != CIRCLEQ_END(&mountlist);
477: mp = nmp) {
478: if (vfs_busy(mp, VB_READ|VB_NOWAIT)) {
479: nmp = CIRCLEQ_PREV(mp, mnt_list);
480: continue;
481: }
482: if ((mp->mnt_flag & MNT_RDONLY) == 0) {
483: asyncflag = mp->mnt_flag & MNT_ASYNC;
484: mp->mnt_flag &= ~MNT_ASYNC;
485: uvm_vnp_sync(mp);
486: VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
487: if (asyncflag)
488: mp->mnt_flag |= MNT_ASYNC;
489: }
490: nmp = CIRCLEQ_PREV(mp, mnt_list);
491: vfs_unbusy(mp);
492: }
493:
494: #ifdef DEBUG
495: if (syncprt)
496: vfs_bufstats();
497: #endif /* DEBUG */
498: return (0);
499: }
500:
501: /*
502: * Change filesystem quotas.
503: */
504: /* ARGSUSED */
505: int
506: sys_quotactl(struct proc *p, void *v, register_t *retval)
507: {
508: struct sys_quotactl_args /* {
509: syscallarg(const char *) path;
510: syscallarg(int) cmd;
511: syscallarg(int) uid;
512: syscallarg(char *) arg;
513: } */ *uap = v;
514: struct mount *mp;
515: int error;
516: struct nameidata nd;
517:
518: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
519: if ((error = namei(&nd)) != 0)
520: return (error);
521: mp = nd.ni_vp->v_mount;
522: vrele(nd.ni_vp);
523: return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
524: SCARG(uap, arg), p));
525: }
526:
527: int
528: copyout_statfs(struct statfs *sp, void *uaddr, struct proc *p)
529: {
530: size_t co_sz1 = offsetof(struct statfs, f_fsid);
531: size_t co_off2 = co_sz1 + sizeof(fsid_t);
532: size_t co_sz2 = sizeof(struct statfs) - co_off2;
533: char *s, *d;
534: int error;
535:
536: /* Don't let non-root see filesystem id (for NFS security) */
537: if (suser(p, 0)) {
538: fsid_t fsid;
539:
540: s = (char *)sp;
541: d = (char *)uaddr;
542:
543: memset(&fsid, 0, sizeof(fsid));
544:
545: if ((error = copyout(s, d, co_sz1)) != 0)
546: return (error);
547: if ((error = copyout(&fsid, d + co_sz1, sizeof(fsid))) != 0)
548: return (error);
549: return (copyout(s + co_off2, d + co_off2, co_sz2));
550: }
551:
552: return (copyout(sp, uaddr, sizeof(*sp)));
553: }
554:
555: /*
556: * Get filesystem statistics.
557: */
558: /* ARGSUSED */
559: int
560: sys_statfs(struct proc *p, void *v, register_t *retval)
561: {
562: struct sys_statfs_args /* {
563: syscallarg(const char *) path;
564: syscallarg(struct statfs *) buf;
565: } */ *uap = v;
566: struct mount *mp;
567: struct statfs *sp;
568: int error;
569: struct nameidata nd;
570:
571: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
572: if ((error = namei(&nd)) != 0)
573: return (error);
574: mp = nd.ni_vp->v_mount;
575: sp = &mp->mnt_stat;
576: vrele(nd.ni_vp);
577: if ((error = VFS_STATFS(mp, sp, p)) != 0)
578: return (error);
579: sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
580: #if notyet
581: if (mp->mnt_flag & MNT_SOFTDEP)
582: sp->f_eflags = STATFS_SOFTUPD;
583: #endif
584: return (copyout_statfs(sp, SCARG(uap, buf), p));
585: }
586:
587: /*
588: * Get filesystem statistics.
589: */
590: /* ARGSUSED */
591: int
592: sys_fstatfs(struct proc *p, void *v, register_t *retval)
593: {
594: struct sys_fstatfs_args /* {
595: syscallarg(int) fd;
596: syscallarg(struct statfs *) buf;
597: } */ *uap = v;
598: struct file *fp;
599: struct mount *mp;
600: struct statfs *sp;
601: int error;
602:
603: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
604: return (error);
605: mp = ((struct vnode *)fp->f_data)->v_mount;
606: if (!mp) {
607: FRELE(fp);
608: return (ENOENT);
609: }
610: sp = &mp->mnt_stat;
611: error = VFS_STATFS(mp, sp, p);
612: FRELE(fp);
613: if (error)
614: return (error);
615: sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
616: #if notyet
617: if (mp->mnt_flag & MNT_SOFTDEP)
618: sp->f_eflags = STATFS_SOFTUPD;
619: #endif
620: return (copyout_statfs(sp, SCARG(uap, buf), p));
621: }
622:
623: /*
624: * Get statistics on all filesystems.
625: */
626: int
627: sys_getfsstat(struct proc *p, void *v, register_t *retval)
628: {
629: struct sys_getfsstat_args /* {
630: syscallarg(struct statfs *) buf;
631: syscallarg(size_t) bufsize;
632: syscallarg(int) flags;
633: } */ *uap = v;
634: struct mount *mp, *nmp;
635: struct statfs *sp;
636: struct statfs *sfsp;
637: size_t count, maxcount;
638: int error, flags = SCARG(uap, flags);
639:
640: maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
641: sfsp = SCARG(uap, buf);
642: count = 0;
643:
644: for (mp = CIRCLEQ_FIRST(&mountlist); mp != CIRCLEQ_END(&mountlist);
645: mp = nmp) {
646: if (vfs_busy(mp, VB_READ|VB_NOWAIT)) {
647: nmp = CIRCLEQ_NEXT(mp, mnt_list);
648: continue;
649: }
650: if (sfsp && count < maxcount) {
651: sp = &mp->mnt_stat;
652:
653: /* Refresh stats unless MNT_NOWAIT is specified */
654: if (flags != MNT_NOWAIT &&
655: flags != MNT_LAZY &&
656: (flags == MNT_WAIT ||
657: flags == 0) &&
658: (error = VFS_STATFS(mp, sp, p))) {
659: nmp = CIRCLEQ_NEXT(mp, mnt_list);
660: vfs_unbusy(mp);
661: continue;
662: }
663:
664: sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
665: #if notyet
666: if (mp->mnt_flag & MNT_SOFTDEP)
667: sp->f_eflags = STATFS_SOFTUPD;
668: #endif
669: error = (copyout_statfs(sp, sfsp, p));
670: if (error) {
671: vfs_unbusy(mp);
672: return (error);
673: }
674: sfsp++;
675: }
676: count++;
677: nmp = CIRCLEQ_NEXT(mp, mnt_list);
678: vfs_unbusy(mp);
679: }
680:
681: if (sfsp && count > maxcount)
682: *retval = maxcount;
683: else
684: *retval = count;
685:
686: return (0);
687: }
688:
689: /*
690: * Change current working directory to a given file descriptor.
691: */
692: /* ARGSUSED */
693: int
694: sys_fchdir(struct proc *p, void *v, register_t *retval)
695: {
696: struct sys_fchdir_args /* {
697: syscallarg(int) fd;
698: } */ *uap = v;
699: struct filedesc *fdp = p->p_fd;
700: struct vnode *vp, *tdp;
701: struct mount *mp;
702: struct file *fp;
703: int error;
704:
705: if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0)
706: return (error);
707: vp = (struct vnode *)fp->f_data;
708: VREF(vp);
709: FRELE(fp);
710: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
711: if (vp->v_type != VDIR)
712: error = ENOTDIR;
713: else
714: error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
715:
716: while (!error && (mp = vp->v_mountedhere) != NULL) {
717: if (vfs_busy(mp, VB_READ|VB_WAIT))
718: continue;
719: error = VFS_ROOT(mp, &tdp);
720: vfs_unbusy(mp);
721: if (error)
722: break;
723: vput(vp);
724: vp = tdp;
725: }
726: if (error) {
727: vput(vp);
728: return (error);
729: }
730: VOP_UNLOCK(vp, 0, p);
731: vrele(fdp->fd_cdir);
732: fdp->fd_cdir = vp;
733: return (0);
734: }
735:
736: /*
737: * Change current working directory (``.'').
738: */
739: /* ARGSUSED */
740: int
741: sys_chdir(struct proc *p, void *v, register_t *retval)
742: {
743: struct sys_chdir_args /* {
744: syscallarg(const char *) path;
745: } */ *uap = v;
746: struct filedesc *fdp = p->p_fd;
747: int error;
748: struct nameidata nd;
749:
750: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
751: SCARG(uap, path), p);
752: if ((error = change_dir(&nd, p)) != 0)
753: return (error);
754: vrele(fdp->fd_cdir);
755: fdp->fd_cdir = nd.ni_vp;
756: return (0);
757: }
758:
759: /*
760: * Change notion of root (``/'') directory.
761: */
762: /* ARGSUSED */
763: int
764: sys_chroot(struct proc *p, void *v, register_t *retval)
765: {
766: struct sys_chroot_args /* {
767: syscallarg(const char *) path;
768: } */ *uap = v;
769: struct filedesc *fdp = p->p_fd;
770: int error;
771: struct nameidata nd;
772:
773: if ((error = suser(p, 0)) != 0)
774: return (error);
775: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
776: SCARG(uap, path), p);
777: if ((error = change_dir(&nd, p)) != 0)
778: return (error);
779: if (fdp->fd_rdir != NULL) {
780: /*
781: * A chroot() done inside a changed root environment does
782: * an automatic chdir to avoid the out-of-tree experience.
783: */
784: vrele(fdp->fd_rdir);
785: vrele(fdp->fd_cdir);
786: VREF(nd.ni_vp);
787: fdp->fd_cdir = nd.ni_vp;
788: }
789: fdp->fd_rdir = nd.ni_vp;
790: return (0);
791: }
792:
793: /*
794: * Common routine for chroot and chdir.
795: */
796: static int
797: change_dir(struct nameidata *ndp, struct proc *p)
798: {
799: struct vnode *vp;
800: int error;
801:
802: if ((error = namei(ndp)) != 0)
803: return (error);
804: vp = ndp->ni_vp;
805: if (vp->v_type != VDIR)
806: error = ENOTDIR;
807: else
808: error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
809: if (error)
810: vput(vp);
811: else
812: VOP_UNLOCK(vp, 0, p);
813: return (error);
814: }
815:
816: /*
817: * Check permissions, allocate an open file structure,
818: * and call the device open routine if any.
819: */
820: int
821: sys_open(struct proc *p, void *v, register_t *retval)
822: {
823: struct sys_open_args /* {
824: syscallarg(const char *) path;
825: syscallarg(int) flags;
826: syscallarg(mode_t) mode;
827: } */ *uap = v;
828: struct filedesc *fdp = p->p_fd;
829: struct file *fp;
830: struct vnode *vp;
831: struct vattr vattr;
832: int flags, cmode;
833: int type, indx, error, localtrunc = 0;
834: struct flock lf;
835: struct nameidata nd;
836:
837: fdplock(fdp);
838:
839: if ((error = falloc(p, &fp, &indx)) != 0)
840: goto out;
841:
842: flags = FFLAGS(SCARG(uap, flags));
843: cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
844: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
845: p->p_dupfd = -1; /* XXX check for fdopen */
846: if ((flags & O_TRUNC) && (flags & (O_EXLOCK | O_SHLOCK))) {
847: localtrunc = 1;
848: flags &= ~O_TRUNC; /* Must do truncate ourselves */
849: }
850: if ((error = vn_open(&nd, flags, cmode)) != 0) {
851: if ((error == ENODEV || error == ENXIO) &&
852: p->p_dupfd >= 0 && /* XXX from fdopen */
853: (error =
854: dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
855: closef(fp, p);
856: *retval = indx;
857: goto out;
858: }
859: if (error == ERESTART)
860: error = EINTR;
861: fdremove(fdp, indx);
862: closef(fp, p);
863: goto out;
864: }
865: p->p_dupfd = 0;
866: vp = nd.ni_vp;
867: fp->f_flag = flags & FMASK;
868: fp->f_type = DTYPE_VNODE;
869: fp->f_ops = &vnops;
870: fp->f_data = vp;
871: if (flags & (O_EXLOCK | O_SHLOCK)) {
872: lf.l_whence = SEEK_SET;
873: lf.l_start = 0;
874: lf.l_len = 0;
875: if (flags & O_EXLOCK)
876: lf.l_type = F_WRLCK;
877: else
878: lf.l_type = F_RDLCK;
879: type = F_FLOCK;
880: if ((flags & FNONBLOCK) == 0)
881: type |= F_WAIT;
882: VOP_UNLOCK(vp, 0, p);
883: error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type);
884: if (error) {
885: /* closef will vn_close the file for us. */
886: fdremove(fdp, indx);
887: closef(fp, p);
888: goto out;
889: }
890: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
891: fp->f_flag |= FHASLOCK;
892: }
893: if (localtrunc) {
894: if ((fp->f_flag & FWRITE) == 0)
895: error = EACCES;
896: else if (vp->v_mount->mnt_flag & MNT_RDONLY)
897: error = EROFS;
898: else if (vp->v_type == VDIR)
899: error = EISDIR;
900: else if ((error = vn_writechk(vp)) == 0) {
901: VATTR_NULL(&vattr);
902: vattr.va_size = 0;
903: error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
904: }
905: if (error) {
906: VOP_UNLOCK(vp, 0, p);
907: /* closef will close the file for us. */
908: fdremove(fdp, indx);
909: closef(fp, p);
910: goto out;
911: }
912: }
913: VOP_UNLOCK(vp, 0, p);
914: *retval = indx;
915: FILE_SET_MATURE(fp);
916: out:
917: fdpunlock(fdp);
918: return (error);
919: }
920:
921: /*
922: * Get file handle system call
923: */
924: int
925: sys_getfh(struct proc *p, void *v, register_t *retval)
926: {
927: struct sys_getfh_args /* {
928: syscallarg(const char *) fname;
929: syscallarg(fhandle_t *) fhp;
930: } */ *uap = v;
931: struct vnode *vp;
932: fhandle_t fh;
933: int error;
934: struct nameidata nd;
935:
936: /*
937: * Must be super user
938: */
939: error = suser(p, 0);
940: if (error)
941: return (error);
942: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
943: SCARG(uap, fname), p);
944: error = namei(&nd);
945: if (error)
946: return (error);
947: vp = nd.ni_vp;
948: bzero(&fh, sizeof(fh));
949: fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
950: error = VFS_VPTOFH(vp, &fh.fh_fid);
951: vput(vp);
952: if (error)
953: return (error);
954: error = copyout(&fh, SCARG(uap, fhp), sizeof(fh));
955: return (error);
956: }
957:
958: /*
959: * Open a file given a file handle.
960: *
961: * Check permissions, allocate an open file structure,
962: * and call the device open routine if any.
963: */
964: int
965: sys_fhopen(struct proc *p, void *v, register_t *retval)
966: {
967: struct sys_fhopen_args /* {
968: syscallarg(const fhandle_t *) fhp;
969: syscallarg(int) flags;
970: } */ *uap = v;
971: struct filedesc *fdp = p->p_fd;
972: struct file *fp;
973: struct vnode *vp = NULL;
974: struct mount *mp;
975: struct ucred *cred = p->p_ucred;
976: int flags;
977: int type, indx, error=0;
978: struct flock lf;
979: struct vattr va;
980: fhandle_t fh;
981:
982: /*
983: * Must be super user
984: */
985: if ((error = suser(p, 0)))
986: return (error);
987:
988: flags = FFLAGS(SCARG(uap, flags));
989: if ((flags & (FREAD | FWRITE)) == 0)
990: return (EINVAL);
991: if ((flags & O_CREAT))
992: return (EINVAL);
993:
994: fdplock(fdp);
995: if ((error = falloc(p, &fp, &indx)) != 0) {
996: fp = NULL;
997: goto bad;
998: }
999:
1000: if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
1001: goto bad;
1002:
1003: if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) {
1004: error = ESTALE;
1005: goto bad;
1006: }
1007:
1008: if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)) != 0) {
1009: vp = NULL; /* most likely unnecessary sanity for bad: */
1010: goto bad;
1011: }
1012:
1013: /* Now do an effective vn_open */
1014:
1015: if (vp->v_type == VSOCK) {
1016: error = EOPNOTSUPP;
1017: goto bad;
1018: }
1019: if (flags & FREAD) {
1020: if ((error = VOP_ACCESS(vp, VREAD, cred, p)) != 0)
1021: goto bad;
1022: }
1023: if (flags & (FWRITE | O_TRUNC)) {
1024: if (vp->v_type == VDIR) {
1025: error = EISDIR;
1026: goto bad;
1027: }
1028: if ((error = vn_writechk(vp)) != 0 ||
1029: (error = VOP_ACCESS(vp, VWRITE, cred, p)) != 0)
1030: goto bad;
1031: }
1032: if (flags & O_TRUNC) {
1033: VATTR_NULL(&va);
1034: va.va_size = 0;
1035: if ((error = VOP_SETATTR(vp, &va, cred, p)) != 0)
1036: goto bad;
1037: }
1038: if ((error = VOP_OPEN(vp, flags, cred, p)) != 0)
1039: goto bad;
1040: if (flags & FWRITE)
1041: vp->v_writecount++;
1042:
1043: /* done with modified vn_open, now finish what sys_open does. */
1044:
1045: fp->f_flag = flags & FMASK;
1046: fp->f_type = DTYPE_VNODE;
1047: fp->f_ops = &vnops;
1048: fp->f_data = vp;
1049: if (flags & (O_EXLOCK | O_SHLOCK)) {
1050: lf.l_whence = SEEK_SET;
1051: lf.l_start = 0;
1052: lf.l_len = 0;
1053: if (flags & O_EXLOCK)
1054: lf.l_type = F_WRLCK;
1055: else
1056: lf.l_type = F_RDLCK;
1057: type = F_FLOCK;
1058: if ((flags & FNONBLOCK) == 0)
1059: type |= F_WAIT;
1060: VOP_UNLOCK(vp, 0, p);
1061: error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type);
1062: if (error)
1063: goto bad;
1064: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1065: fp->f_flag |= FHASLOCK;
1066: }
1067: VOP_UNLOCK(vp, 0, p);
1068: *retval = indx;
1069: FILE_SET_MATURE(fp);
1070:
1071: fdpunlock(fdp);
1072: return (0);
1073:
1074: bad:
1075: if (fp) {
1076: fdremove(fdp, indx);
1077: closef(fp, p);
1078: if (vp != NULL)
1079: vput(vp);
1080: }
1081: fdpunlock(fdp);
1082: return (error);
1083: }
1084:
1085: /* ARGSUSED */
1086: int
1087: sys_fhstat(struct proc *p, void *v, register_t *retval)
1088: {
1089: struct sys_fhstat_args /* {
1090: syscallarg(const fhandle_t *) fhp;
1091: syscallarg(struct stat *) sb;
1092: } */ *uap = v;
1093: struct stat sb;
1094: int error;
1095: fhandle_t fh;
1096: struct mount *mp;
1097: struct vnode *vp;
1098:
1099: /*
1100: * Must be super user
1101: */
1102: if ((error = suser(p, 0)))
1103: return (error);
1104:
1105: if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
1106: return (error);
1107:
1108: if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
1109: return (ESTALE);
1110: if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
1111: return (error);
1112: error = vn_stat(vp, &sb, p);
1113: vput(vp);
1114: if (error)
1115: return (error);
1116: error = copyout(&sb, SCARG(uap, sb), sizeof(sb));
1117: return (error);
1118: }
1119:
1120: /* ARGSUSED */
1121: int
1122: sys_fhstatfs(struct proc *p, void *v, register_t *retval)
1123: {
1124: struct sys_fhstatfs_args /*
1125: syscallarg(const fhandle_t *) fhp;
1126: syscallarg(struct statfs *) buf;
1127: } */ *uap = v;
1128: struct statfs *sp;
1129: fhandle_t fh;
1130: struct mount *mp;
1131: struct vnode *vp;
1132: int error;
1133:
1134: /*
1135: * Must be super user
1136: */
1137: if ((error = suser(p, 0)))
1138: return (error);
1139:
1140: if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
1141: return (error);
1142:
1143: if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
1144: return (ESTALE);
1145: if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
1146: return (error);
1147: mp = vp->v_mount;
1148: sp = &mp->mnt_stat;
1149: vput(vp);
1150: if ((error = VFS_STATFS(mp, sp, p)) != 0)
1151: return (error);
1152: sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
1153: return (copyout(sp, SCARG(uap, buf), sizeof(sp)));
1154: }
1155:
1156: /*
1157: * Create a special file.
1158: */
1159: /* ARGSUSED */
1160: int
1161: sys_mknod(struct proc *p, void *v, register_t *retval)
1162: {
1163: struct sys_mknod_args /* {
1164: syscallarg(const char *) path;
1165: syscallarg(mode_t) mode;
1166: syscallarg(int) dev;
1167: } */ *uap = v;
1168: struct vnode *vp;
1169: struct vattr vattr;
1170: int error;
1171: struct nameidata nd;
1172:
1173: if ((error = suser(p, 0)) != 0)
1174: return (error);
1175: if (p->p_fd->fd_rdir)
1176: return (EINVAL);
1177: NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
1178: if ((error = namei(&nd)) != 0)
1179: return (error);
1180: vp = nd.ni_vp;
1181: if (vp != NULL)
1182: error = EEXIST;
1183: else {
1184: VATTR_NULL(&vattr);
1185: vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
1186: vattr.va_rdev = SCARG(uap, dev);
1187:
1188: switch (SCARG(uap, mode) & S_IFMT) {
1189: case S_IFMT: /* used by badsect to flag bad sectors */
1190: vattr.va_type = VBAD;
1191: break;
1192: case S_IFCHR:
1193: vattr.va_type = VCHR;
1194: break;
1195: case S_IFBLK:
1196: vattr.va_type = VBLK;
1197: break;
1198: default:
1199: error = EINVAL;
1200: break;
1201: }
1202: }
1203: if (!error) {
1204: error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
1205: } else {
1206: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1207: if (nd.ni_dvp == vp)
1208: vrele(nd.ni_dvp);
1209: else
1210: vput(nd.ni_dvp);
1211: if (vp)
1212: vrele(vp);
1213: }
1214: return (error);
1215: }
1216:
1217: /*
1218: * Create a named pipe.
1219: */
1220: /* ARGSUSED */
1221: int
1222: sys_mkfifo(struct proc *p, void *v, register_t *retval)
1223: {
1224: #ifndef FIFO
1225: return (EOPNOTSUPP);
1226: #else
1227: struct sys_mkfifo_args /* {
1228: syscallarg(const char *) path;
1229: syscallarg(mode_t) mode;
1230: } */ *uap = v;
1231: struct vattr vattr;
1232: int error;
1233: struct nameidata nd;
1234:
1235: NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
1236: if ((error = namei(&nd)) != 0)
1237: return (error);
1238: if (nd.ni_vp != NULL) {
1239: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1240: if (nd.ni_dvp == nd.ni_vp)
1241: vrele(nd.ni_dvp);
1242: else
1243: vput(nd.ni_dvp);
1244: vrele(nd.ni_vp);
1245: return (EEXIST);
1246: }
1247: VATTR_NULL(&vattr);
1248: vattr.va_type = VFIFO;
1249: vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
1250: return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
1251: #endif /* FIFO */
1252: }
1253:
1254: /*
1255: * Make a hard file link.
1256: */
1257: /* ARGSUSED */
1258: int
1259: sys_link(struct proc *p, void *v, register_t *retval)
1260: {
1261: struct sys_link_args /* {
1262: syscallarg(const char *) path;
1263: syscallarg(const char *) link;
1264: } */ *uap = v;
1265: struct vnode *vp;
1266: struct nameidata nd;
1267: int error;
1268: int flags;
1269:
1270: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1271: if ((error = namei(&nd)) != 0)
1272: return (error);
1273: vp = nd.ni_vp;
1274:
1275: flags = LOCKPARENT;
1276: if (vp->v_type == VDIR) {
1277: flags |= STRIPSLASHES;
1278: }
1279:
1280: NDINIT(&nd, CREATE, flags, UIO_USERSPACE, SCARG(uap, link), p);
1281: if ((error = namei(&nd)) != 0)
1282: goto out;
1283: if (nd.ni_vp) {
1284: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1285: if (nd.ni_dvp == nd.ni_vp)
1286: vrele(nd.ni_dvp);
1287: else
1288: vput(nd.ni_dvp);
1289: vrele(nd.ni_vp);
1290: error = EEXIST;
1291: goto out;
1292: }
1293: error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
1294: out:
1295: vrele(vp);
1296: return (error);
1297: }
1298:
1299: /*
1300: * Make a symbolic link.
1301: */
1302: /* ARGSUSED */
1303: int
1304: sys_symlink(struct proc *p, void *v, register_t *retval)
1305: {
1306: struct sys_symlink_args /* {
1307: syscallarg(const char *) path;
1308: syscallarg(const char *) link;
1309: } */ *uap = v;
1310: struct vattr vattr;
1311: char *path;
1312: int error;
1313: struct nameidata nd;
1314:
1315: path = pool_get(&namei_pool, PR_WAITOK);
1316: error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL);
1317: if (error)
1318: goto out;
1319: NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p);
1320: if ((error = namei(&nd)) != 0)
1321: goto out;
1322: if (nd.ni_vp) {
1323: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1324: if (nd.ni_dvp == nd.ni_vp)
1325: vrele(nd.ni_dvp);
1326: else
1327: vput(nd.ni_dvp);
1328: vrele(nd.ni_vp);
1329: error = EEXIST;
1330: goto out;
1331: }
1332: VATTR_NULL(&vattr);
1333: vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
1334: error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1335: out:
1336: pool_put(&namei_pool, path);
1337: return (error);
1338: }
1339:
1340: /*
1341: * Delete a name from the filesystem.
1342: */
1343: /* ARGSUSED */
1344: int
1345: sys_unlink(struct proc *p, void *v, register_t *retval)
1346: {
1347: struct sys_unlink_args /* {
1348: syscallarg(const char *) path;
1349: } */ *uap = v;
1350: struct vnode *vp;
1351: int error;
1352: struct nameidata nd;
1353:
1354: NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
1355: SCARG(uap, path), p);
1356: if ((error = namei(&nd)) != 0)
1357: return (error);
1358: vp = nd.ni_vp;
1359:
1360: /*
1361: * The root of a mounted filesystem cannot be deleted.
1362: */
1363: if (vp->v_flag & VROOT) {
1364: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1365: if (nd.ni_dvp == vp)
1366: vrele(nd.ni_dvp);
1367: else
1368: vput(nd.ni_dvp);
1369: vput(vp);
1370: error = EBUSY;
1371: goto out;
1372: }
1373:
1374: (void)uvm_vnp_uncache(vp);
1375:
1376: error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1377: out:
1378: return (error);
1379: }
1380:
1381: /*
1382: * Reposition read/write file offset.
1383: */
1384: int
1385: sys_lseek(struct proc *p, void *v, register_t *retval)
1386: {
1387: struct sys_lseek_args /* {
1388: syscallarg(int) fd;
1389: syscallarg(int) pad;
1390: syscallarg(off_t) offset;
1391: syscallarg(int) whence;
1392: } */ *uap = v;
1393: struct ucred *cred = p->p_ucred;
1394: struct filedesc *fdp = p->p_fd;
1395: struct file *fp;
1396: struct vattr vattr;
1397: struct vnode *vp;
1398: off_t offarg, newoff;
1399: int error, special;
1400:
1401: if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
1402: return (EBADF);
1403: if (fp->f_type != DTYPE_VNODE)
1404: return (ESPIPE);
1405: vp = (struct vnode *)fp->f_data;
1406: if (vp->v_type == VFIFO)
1407: return (ESPIPE);
1408: if (vp->v_type == VCHR)
1409: special = 1;
1410: else
1411: special = 0;
1412: offarg = SCARG(uap, offset);
1413:
1414: switch (SCARG(uap, whence)) {
1415: case SEEK_CUR:
1416: newoff = fp->f_offset + offarg;;
1417: break;
1418: case SEEK_END:
1419: error = VOP_GETATTR((struct vnode *)fp->f_data, &vattr,
1420: cred, p);
1421: if (error)
1422: return (error);
1423: newoff = offarg + (off_t)vattr.va_size;
1424: break;
1425: case SEEK_SET:
1426: newoff = offarg;
1427: break;
1428: default:
1429: return (EINVAL);
1430: }
1431: if (!special) {
1432: if (newoff < 0)
1433: return (EINVAL);
1434: } else {
1435: /*
1436: * Make sure the user don't seek beyond the end of the
1437: * partition.
1438: */
1439: struct partinfo dpart;
1440: error = vn_ioctl(fp, DIOCGPART, (void *)&dpart, p);
1441: if (!error) {
1442: if (newoff >= DL_GETPSIZE(dpart.part) *
1443: dpart.disklab->d_secsize)
1444: return (EINVAL);
1445: }
1446: }
1447: *(off_t *)retval = fp->f_offset = newoff;
1448: fp->f_seek++;
1449: return (0);
1450: }
1451:
1452: /*
1453: * Check access permissions.
1454: */
1455: int
1456: sys_access(struct proc *p, void *v, register_t *retval)
1457: {
1458: struct sys_access_args /* {
1459: syscallarg(const char *) path;
1460: syscallarg(int) flags;
1461: } */ *uap = v;
1462: struct ucred *cred = p->p_ucred;
1463: struct vnode *vp;
1464: int error, flags, t_gid, t_uid;
1465: struct nameidata nd;
1466:
1467: if (SCARG(uap, flags) & ~(R_OK | W_OK | X_OK))
1468: return (EINVAL);
1469: t_uid = cred->cr_uid;
1470: t_gid = cred->cr_gid;
1471: cred->cr_uid = p->p_cred->p_ruid;
1472: cred->cr_gid = p->p_cred->p_rgid;
1473: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1474: SCARG(uap, path), p);
1475: if ((error = namei(&nd)) != 0)
1476: goto out1;
1477: vp = nd.ni_vp;
1478:
1479: /* Flags == 0 means only check for existence. */
1480: if (SCARG(uap, flags)) {
1481: flags = 0;
1482: if (SCARG(uap, flags) & R_OK)
1483: flags |= VREAD;
1484: if (SCARG(uap, flags) & W_OK)
1485: flags |= VWRITE;
1486: if (SCARG(uap, flags) & X_OK)
1487: flags |= VEXEC;
1488: if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
1489: error = VOP_ACCESS(vp, flags, cred, p);
1490: }
1491: vput(vp);
1492: out1:
1493: cred->cr_uid = t_uid;
1494: cred->cr_gid = t_gid;
1495: return (error);
1496: }
1497:
1498: /*
1499: * Get file status; this version follows links.
1500: */
1501: /* ARGSUSED */
1502: int
1503: sys_stat(struct proc *p, void *v, register_t *retval)
1504: {
1505: struct sys_stat_args /* {
1506: syscallarg(const char *) path;
1507: syscallarg(struct stat *) ub;
1508: } */ *uap = v;
1509: struct stat sb;
1510: int error;
1511: struct nameidata nd;
1512:
1513: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1514: SCARG(uap, path), p);
1515: if ((error = namei(&nd)) != 0)
1516: return (error);
1517: error = vn_stat(nd.ni_vp, &sb, p);
1518: vput(nd.ni_vp);
1519: if (error)
1520: return (error);
1521: /* Don't let non-root see generation numbers (for NFS security) */
1522: if (suser(p, 0))
1523: sb.st_gen = 0;
1524: error = copyout(&sb, SCARG(uap, ub), sizeof(sb));
1525: return (error);
1526: }
1527:
1528: /*
1529: * Get file status; this version does not follow links.
1530: */
1531: /* ARGSUSED */
1532: int
1533: sys_lstat(struct proc *p, void *v, register_t *retval)
1534: {
1535: struct sys_lstat_args /* {
1536: syscallarg(const char *) path;
1537: syscallarg(struct stat *) ub;
1538: } */ *uap = v;
1539: struct stat sb;
1540: int error;
1541: struct nameidata nd;
1542:
1543: NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
1544: SCARG(uap, path), p);
1545: if ((error = namei(&nd)) != 0)
1546: return (error);
1547: error = vn_stat(nd.ni_vp, &sb, p);
1548: vput(nd.ni_vp);
1549: if (error)
1550: return (error);
1551: /* Don't let non-root see generation numbers (for NFS security) */
1552: if (suser(p, 0))
1553: sb.st_gen = 0;
1554: error = copyout(&sb, SCARG(uap, ub), sizeof(sb));
1555: return (error);
1556: }
1557:
1558: /*
1559: * Get configurable pathname variables.
1560: */
1561: /* ARGSUSED */
1562: int
1563: sys_pathconf(struct proc *p, void *v, register_t *retval)
1564: {
1565: struct sys_pathconf_args /* {
1566: syscallarg(const char *) path;
1567: syscallarg(int) name;
1568: } */ *uap = v;
1569: int error;
1570: struct nameidata nd;
1571:
1572: NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1573: SCARG(uap, path), p);
1574: if ((error = namei(&nd)) != 0)
1575: return (error);
1576: error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval);
1577: vput(nd.ni_vp);
1578: return (error);
1579: }
1580:
1581: /*
1582: * Return target name of a symbolic link.
1583: */
1584: /* ARGSUSED */
1585: int
1586: sys_readlink(struct proc *p, void *v, register_t *retval)
1587: {
1588: struct sys_readlink_args /* {
1589: syscallarg(const char *) path;
1590: syscallarg(char *) buf;
1591: syscallarg(size_t) count;
1592: } */ *uap = v;
1593: struct vnode *vp;
1594: struct iovec aiov;
1595: struct uio auio;
1596: int error;
1597: struct nameidata nd;
1598:
1599: NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
1600: SCARG(uap, path), p);
1601: if ((error = namei(&nd)) != 0)
1602: return (error);
1603: vp = nd.ni_vp;
1604: if (vp->v_type != VLNK)
1605: error = EINVAL;
1606: else {
1607: aiov.iov_base = SCARG(uap, buf);
1608: aiov.iov_len = SCARG(uap, count);
1609: auio.uio_iov = &aiov;
1610: auio.uio_iovcnt = 1;
1611: auio.uio_offset = 0;
1612: auio.uio_rw = UIO_READ;
1613: auio.uio_segflg = UIO_USERSPACE;
1614: auio.uio_procp = p;
1615: auio.uio_resid = SCARG(uap, count);
1616: error = VOP_READLINK(vp, &auio, p->p_ucred);
1617: }
1618: vput(vp);
1619: *retval = SCARG(uap, count) - auio.uio_resid;
1620: return (error);
1621: }
1622:
1623: /*
1624: * Change flags of a file given a path name.
1625: */
1626: /* ARGSUSED */
1627: int
1628: sys_chflags(struct proc *p, void *v, register_t *retval)
1629: {
1630: struct sys_chflags_args /* {
1631: syscallarg(const char *) path;
1632: syscallarg(u_int) flags;
1633: } */ *uap = v;
1634: struct vnode *vp;
1635: struct vattr vattr;
1636: int error;
1637: struct nameidata nd;
1638:
1639: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1640: if ((error = namei(&nd)) != 0)
1641: return (error);
1642: vp = nd.ni_vp;
1643: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1644: if (vp->v_mount->mnt_flag & MNT_RDONLY)
1645: error = EROFS;
1646: else if (SCARG(uap, flags) == VNOVAL)
1647: error = EINVAL;
1648: else {
1649: if (suser(p, 0)) {
1650: if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0)
1651: goto out;
1652: if (vattr.va_type == VCHR || vattr.va_type == VBLK) {
1653: error = EINVAL;
1654: goto out;
1655: }
1656: }
1657: VATTR_NULL(&vattr);
1658: vattr.va_flags = SCARG(uap, flags);
1659: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1660: }
1661: out:
1662: vput(vp);
1663: return (error);
1664: }
1665:
1666: /*
1667: * Change flags of a file given a file descriptor.
1668: */
1669: /* ARGSUSED */
1670: int
1671: sys_fchflags(struct proc *p, void *v, register_t *retval)
1672: {
1673: struct sys_fchflags_args /* {
1674: syscallarg(int) fd;
1675: syscallarg(u_int) flags;
1676: } */ *uap = v;
1677: struct vattr vattr;
1678: struct vnode *vp;
1679: struct file *fp;
1680: int error;
1681:
1682: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
1683: return (error);
1684: vp = (struct vnode *)fp->f_data;
1685: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1686: if (vp->v_mount && vp->v_mount->mnt_flag & MNT_RDONLY)
1687: error = EROFS;
1688: else if (SCARG(uap, flags) == VNOVAL)
1689: error = EINVAL;
1690: else {
1691: if (suser(p, 0)) {
1692: if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
1693: != 0)
1694: goto out;
1695: if (vattr.va_type == VCHR || vattr.va_type == VBLK) {
1696: error = EINVAL;
1697: goto out;
1698: }
1699: }
1700: VATTR_NULL(&vattr);
1701: vattr.va_flags = SCARG(uap, flags);
1702: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1703: }
1704: out:
1705: VOP_UNLOCK(vp, 0, p);
1706: FRELE(fp);
1707: return (error);
1708: }
1709:
1710: /*
1711: * Change mode of a file given path name.
1712: */
1713: /* ARGSUSED */
1714: int
1715: sys_chmod(struct proc *p, void *v, register_t *retval)
1716: {
1717: struct sys_chmod_args /* {
1718: syscallarg(const char *) path;
1719: syscallarg(mode_t) mode;
1720: } */ *uap = v;
1721: struct vnode *vp;
1722: struct vattr vattr;
1723: int error;
1724: struct nameidata nd;
1725:
1726: if (SCARG(uap, mode) & ~(S_IFMT | ALLPERMS))
1727: return (EINVAL);
1728:
1729: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1730: if ((error = namei(&nd)) != 0)
1731: return (error);
1732: vp = nd.ni_vp;
1733: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1734: if (vp->v_mount->mnt_flag & MNT_RDONLY)
1735: error = EROFS;
1736: else {
1737: VATTR_NULL(&vattr);
1738: vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
1739: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1740: }
1741: vput(vp);
1742: return (error);
1743: }
1744:
1745: /*
1746: * Change mode of a file given a file descriptor.
1747: */
1748: /* ARGSUSED */
1749: int
1750: sys_fchmod(struct proc *p, void *v, register_t *retval)
1751: {
1752: struct sys_fchmod_args /* {
1753: syscallarg(int) fd;
1754: syscallarg(mode_t) mode;
1755: } */ *uap = v;
1756: struct vattr vattr;
1757: struct vnode *vp;
1758: struct file *fp;
1759: int error;
1760:
1761: if (SCARG(uap, mode) & ~(S_IFMT | ALLPERMS))
1762: return (EINVAL);
1763:
1764: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
1765: return (error);
1766: vp = (struct vnode *)fp->f_data;
1767: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1768: if (vp->v_mount && vp->v_mount->mnt_flag & MNT_RDONLY)
1769: error = EROFS;
1770: else {
1771: VATTR_NULL(&vattr);
1772: vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
1773: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1774: }
1775: VOP_UNLOCK(vp, 0, p);
1776: FRELE(fp);
1777: return (error);
1778: }
1779:
1780: /*
1781: * Set ownership given a path name.
1782: */
1783: /* ARGSUSED */
1784: int
1785: sys_chown(struct proc *p, void *v, register_t *retval)
1786: {
1787: struct sys_chown_args /* {
1788: syscallarg(const char *) path;
1789: syscallarg(uid_t) uid;
1790: syscallarg(gid_t) gid;
1791: } */ *uap = v;
1792: struct vnode *vp;
1793: struct vattr vattr;
1794: int error;
1795: struct nameidata nd;
1796: mode_t mode;
1797:
1798: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1799: if ((error = namei(&nd)) != 0)
1800: return (error);
1801: vp = nd.ni_vp;
1802: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1803: if (vp->v_mount->mnt_flag & MNT_RDONLY)
1804: error = EROFS;
1805: else {
1806: if ((SCARG(uap, uid) != -1 || SCARG(uap, gid) != -1) &&
1807: (suser(p, 0) || suid_clear)) {
1808: error = VOP_GETATTR(vp, &vattr, p->p_ucred, p);
1809: if (error)
1810: goto out;
1811: mode = vattr.va_mode & ~(VSUID | VSGID);
1812: if (mode == vattr.va_mode)
1813: mode = VNOVAL;
1814: }
1815: else
1816: mode = VNOVAL;
1817: VATTR_NULL(&vattr);
1818: vattr.va_uid = SCARG(uap, uid);
1819: vattr.va_gid = SCARG(uap, gid);
1820: vattr.va_mode = mode;
1821: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1822: }
1823: out:
1824: vput(vp);
1825: return (error);
1826: }
1827:
1828: /*
1829: * Set ownership given a path name, without following links.
1830: */
1831: /* ARGSUSED */
1832: int
1833: sys_lchown(struct proc *p, void *v, register_t *retval)
1834: {
1835: struct sys_lchown_args /* {
1836: syscallarg(const char *) path;
1837: syscallarg(uid_t) uid;
1838: syscallarg(gid_t) gid;
1839: } */ *uap = v;
1840: struct vnode *vp;
1841: struct vattr vattr;
1842: int error;
1843: struct nameidata nd;
1844: mode_t mode;
1845:
1846: NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1847: if ((error = namei(&nd)) != 0)
1848: return (error);
1849: vp = nd.ni_vp;
1850: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1851: if (vp->v_mount->mnt_flag & MNT_RDONLY)
1852: error = EROFS;
1853: else {
1854: if ((SCARG(uap, uid) != -1 || SCARG(uap, gid) != -1) &&
1855: (suser(p, 0) || suid_clear)) {
1856: error = VOP_GETATTR(vp, &vattr, p->p_ucred, p);
1857: if (error)
1858: goto out;
1859: mode = vattr.va_mode & ~(VSUID | VSGID);
1860: if (mode == vattr.va_mode)
1861: mode = VNOVAL;
1862: }
1863: else
1864: mode = VNOVAL;
1865: VATTR_NULL(&vattr);
1866: vattr.va_uid = SCARG(uap, uid);
1867: vattr.va_gid = SCARG(uap, gid);
1868: vattr.va_mode = mode;
1869: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1870: }
1871: out:
1872: vput(vp);
1873: return (error);
1874: }
1875:
1876: /*
1877: * Set ownership given a file descriptor.
1878: */
1879: /* ARGSUSED */
1880: int
1881: sys_fchown(struct proc *p, void *v, register_t *retval)
1882: {
1883: struct sys_fchown_args /* {
1884: syscallarg(int) fd;
1885: syscallarg(uid_t) uid;
1886: syscallarg(gid_t) gid;
1887: } */ *uap = v;
1888: struct vnode *vp;
1889: struct vattr vattr;
1890: int error;
1891: struct file *fp;
1892: mode_t mode;
1893:
1894: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
1895: return (error);
1896: vp = (struct vnode *)fp->f_data;
1897: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1898: if (vp->v_mount->mnt_flag & MNT_RDONLY)
1899: error = EROFS;
1900: else {
1901: if ((SCARG(uap, uid) != -1 || SCARG(uap, gid) != -1) &&
1902: (suser(p, 0) || suid_clear)) {
1903: error = VOP_GETATTR(vp, &vattr, p->p_ucred, p);
1904: if (error)
1905: goto out;
1906: mode = vattr.va_mode & ~(VSUID | VSGID);
1907: if (mode == vattr.va_mode)
1908: mode = VNOVAL;
1909: } else
1910: mode = VNOVAL;
1911: VATTR_NULL(&vattr);
1912: vattr.va_uid = SCARG(uap, uid);
1913: vattr.va_gid = SCARG(uap, gid);
1914: vattr.va_mode = mode;
1915: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1916: }
1917: out:
1918: VOP_UNLOCK(vp, 0, p);
1919: FRELE(fp);
1920: return (error);
1921: }
1922:
1923: /*
1924: * Set the access and modification times given a path name.
1925: */
1926: /* ARGSUSED */
1927: int
1928: sys_utimes(struct proc *p, void *v, register_t *retval)
1929: {
1930: struct sys_utimes_args /* {
1931: syscallarg(const char *) path;
1932: syscallarg(const struct timeval *) tptr;
1933: } */ *uap = v;
1934: struct vnode *vp;
1935: struct timeval tv[2];
1936: struct vattr vattr;
1937: int error;
1938: struct nameidata nd;
1939:
1940: VATTR_NULL(&vattr);
1941: if (SCARG(uap, tptr) == NULL) {
1942: microtime(&tv[0]);
1943: tv[1] = tv[0];
1944: vattr.va_vaflags |= VA_UTIMES_NULL;
1945: } else {
1946: error = copyin(SCARG(uap, tptr), tv,
1947: sizeof(tv));
1948: if (error)
1949: return (error);
1950: /* XXX workaround timeval matching the VFS constant VNOVAL */
1951: if (tv[0].tv_sec == VNOVAL)
1952: tv[0].tv_sec = VNOVAL - 1;
1953: if (tv[1].tv_sec == VNOVAL)
1954: tv[1].tv_sec = VNOVAL - 1;
1955: }
1956: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1957: if ((error = namei(&nd)) != 0)
1958: return (error);
1959: vp = nd.ni_vp;
1960: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1961: if (vp->v_mount->mnt_flag & MNT_RDONLY)
1962: error = EROFS;
1963: else {
1964: vattr.va_atime.tv_sec = tv[0].tv_sec;
1965: vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000;
1966: vattr.va_mtime.tv_sec = tv[1].tv_sec;
1967: vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000;
1968: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1969: }
1970: vput(vp);
1971: return (error);
1972: }
1973:
1974: /*
1975: * Set the access and modification times given a file descriptor.
1976: */
1977: /* ARGSUSED */
1978: int
1979: sys_futimes(struct proc *p, void *v, register_t *retval)
1980: {
1981: struct sys_futimes_args /* {
1982: syscallarg(int) fd;
1983: syscallarg(const struct timeval *) tptr;
1984: } */ *uap = v;
1985: struct vnode *vp;
1986: struct timeval tv[2];
1987: struct vattr vattr;
1988: int error;
1989: struct file *fp;
1990:
1991: VATTR_NULL(&vattr);
1992: if (SCARG(uap, tptr) == NULL) {
1993: microtime(&tv[0]);
1994: tv[1] = tv[0];
1995: vattr.va_vaflags |= VA_UTIMES_NULL;
1996: } else {
1997: error = copyin(SCARG(uap, tptr), tv,
1998: sizeof(tv));
1999: if (error)
2000: return (error);
2001: /* XXX workaround timeval matching the VFS constant VNOVAL */
2002: if (tv[0].tv_sec == VNOVAL)
2003: tv[0].tv_sec = VNOVAL - 1;
2004: if (tv[1].tv_sec == VNOVAL)
2005: tv[1].tv_sec = VNOVAL - 1;
2006: }
2007: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2008: return (error);
2009: vp = (struct vnode *)fp->f_data;
2010: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2011: if (vp->v_mount && vp->v_mount->mnt_flag & MNT_RDONLY)
2012: error = EROFS;
2013: else {
2014: vattr.va_atime.tv_sec = tv[0].tv_sec;
2015: vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000;
2016: vattr.va_mtime.tv_sec = tv[1].tv_sec;
2017: vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000;
2018: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2019: }
2020: VOP_UNLOCK(vp, 0, p);
2021: FRELE(fp);
2022: return (error);
2023: }
2024:
2025: /*
2026: * Truncate a file given its path name.
2027: */
2028: /* ARGSUSED */
2029: int
2030: sys_truncate(struct proc *p, void *v, register_t *retval)
2031: {
2032: struct sys_truncate_args /* {
2033: syscallarg(const char *) path;
2034: syscallarg(int) pad;
2035: syscallarg(off_t) length;
2036: } */ *uap = v;
2037: struct vnode *vp;
2038: struct vattr vattr;
2039: int error;
2040: struct nameidata nd;
2041:
2042: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2043: if ((error = namei(&nd)) != 0)
2044: return (error);
2045: vp = nd.ni_vp;
2046: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2047: if (vp->v_type == VDIR)
2048: error = EISDIR;
2049: else if ((error = vn_writechk(vp)) == 0 &&
2050: (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
2051: VATTR_NULL(&vattr);
2052: vattr.va_size = SCARG(uap, length);
2053: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2054: }
2055: vput(vp);
2056: return (error);
2057: }
2058:
2059: /*
2060: * Truncate a file given a file descriptor.
2061: */
2062: /* ARGSUSED */
2063: int
2064: sys_ftruncate(struct proc *p, void *v, register_t *retval)
2065: {
2066: struct sys_ftruncate_args /* {
2067: syscallarg(int) fd;
2068: syscallarg(int) pad;
2069: syscallarg(off_t) length;
2070: } */ *uap = v;
2071: struct vattr vattr;
2072: struct vnode *vp;
2073: struct file *fp;
2074: off_t len;
2075: int error;
2076:
2077: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2078: return (error);
2079: len = SCARG(uap, length);
2080: if ((fp->f_flag & FWRITE) == 0 || len < 0) {
2081: error = EINVAL;
2082: goto bad;
2083: }
2084: vp = (struct vnode *)fp->f_data;
2085: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2086: if (vp->v_type == VDIR)
2087: error = EISDIR;
2088: else if ((error = vn_writechk(vp)) == 0) {
2089: VATTR_NULL(&vattr);
2090: vattr.va_size = len;
2091: error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
2092: }
2093: VOP_UNLOCK(vp, 0, p);
2094: bad:
2095: FRELE(fp);
2096: return (error);
2097: }
2098:
2099: /*
2100: * Sync an open file.
2101: */
2102: /* ARGSUSED */
2103: int
2104: sys_fsync(struct proc *p, void *v, register_t *retval)
2105: {
2106: struct sys_fsync_args /* {
2107: syscallarg(int) fd;
2108: } */ *uap = v;
2109: struct vnode *vp;
2110: struct file *fp;
2111: int error;
2112:
2113: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2114: return (error);
2115: vp = (struct vnode *)fp->f_data;
2116: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2117: error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
2118: #ifdef FFS_SOFTUPDATES
2119: if (error == 0 && vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP))
2120: error = softdep_fsync(vp);
2121: #endif
2122:
2123: VOP_UNLOCK(vp, 0, p);
2124: FRELE(fp);
2125: return (error);
2126: }
2127:
2128: /*
2129: * Rename files. Source and destination must either both be directories,
2130: * or both not be directories. If target is a directory, it must be empty.
2131: */
2132: /* ARGSUSED */
2133: int
2134: sys_rename(struct proc *p, void *v, register_t *retval)
2135: {
2136: struct sys_rename_args /* {
2137: syscallarg(const char *) from;
2138: syscallarg(const char *) to;
2139: } */ *uap = v;
2140: struct vnode *tvp, *fvp, *tdvp;
2141: struct nameidata fromnd, tond;
2142: int error;
2143: int flags;
2144:
2145: NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
2146: SCARG(uap, from), p);
2147: if ((error = namei(&fromnd)) != 0)
2148: return (error);
2149: fvp = fromnd.ni_vp;
2150:
2151: flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
2152: /*
2153: * rename("foo/", "bar/"); is OK
2154: */
2155: if (fvp->v_type == VDIR)
2156: flags |= STRIPSLASHES;
2157:
2158: NDINIT(&tond, RENAME, flags,
2159: UIO_USERSPACE, SCARG(uap, to), p);
2160: if ((error = namei(&tond)) != 0) {
2161: VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2162: vrele(fromnd.ni_dvp);
2163: vrele(fvp);
2164: goto out1;
2165: }
2166: tdvp = tond.ni_dvp;
2167: tvp = tond.ni_vp;
2168: if (tvp != NULL) {
2169: if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
2170: error = ENOTDIR;
2171: goto out;
2172: } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
2173: error = EISDIR;
2174: goto out;
2175: }
2176: }
2177: if (fvp == tdvp)
2178: error = EINVAL;
2179: /*
2180: * If source is the same as the destination (that is the
2181: * same inode number)
2182: */
2183: if (fvp == tvp)
2184: error = -1;
2185: out:
2186: if (!error) {
2187: if (tvp) {
2188: (void)uvm_vnp_uncache(tvp);
2189: }
2190: error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
2191: tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
2192: } else {
2193: VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
2194: if (tdvp == tvp)
2195: vrele(tdvp);
2196: else
2197: vput(tdvp);
2198: if (tvp)
2199: vput(tvp);
2200: VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2201: vrele(fromnd.ni_dvp);
2202: vrele(fvp);
2203: }
2204: vrele(tond.ni_startdir);
2205: pool_put(&namei_pool, tond.ni_cnd.cn_pnbuf);
2206: out1:
2207: if (fromnd.ni_startdir)
2208: vrele(fromnd.ni_startdir);
2209: pool_put(&namei_pool, fromnd.ni_cnd.cn_pnbuf);
2210: if (error == -1)
2211: return (0);
2212: return (error);
2213: }
2214:
2215: /*
2216: * Make a directory file.
2217: */
2218: /* ARGSUSED */
2219: int
2220: sys_mkdir(struct proc *p, void *v, register_t *retval)
2221: {
2222: struct sys_mkdir_args /* {
2223: syscallarg(const char *) path;
2224: syscallarg(mode_t) mode;
2225: } */ *uap = v;
2226: struct vnode *vp;
2227: struct vattr vattr;
2228: int error;
2229: struct nameidata nd;
2230:
2231: NDINIT(&nd, CREATE, LOCKPARENT | STRIPSLASHES,
2232: UIO_USERSPACE, SCARG(uap, path), p);
2233: if ((error = namei(&nd)) != 0)
2234: return (error);
2235: vp = nd.ni_vp;
2236: if (vp != NULL) {
2237: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2238: if (nd.ni_dvp == vp)
2239: vrele(nd.ni_dvp);
2240: else
2241: vput(nd.ni_dvp);
2242: vrele(vp);
2243: return (EEXIST);
2244: }
2245: VATTR_NULL(&vattr);
2246: vattr.va_type = VDIR;
2247: vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask;
2248: error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
2249: if (!error)
2250: vput(nd.ni_vp);
2251: return (error);
2252: }
2253:
2254: /*
2255: * Remove a directory file.
2256: */
2257: /* ARGSUSED */
2258: int
2259: sys_rmdir(struct proc *p, void *v, register_t *retval)
2260: {
2261: struct sys_rmdir_args /* {
2262: syscallarg(const char *) path;
2263: } */ *uap = v;
2264: struct vnode *vp;
2265: int error;
2266: struct nameidata nd;
2267:
2268: NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
2269: SCARG(uap, path), p);
2270: if ((error = namei(&nd)) != 0)
2271: return (error);
2272: vp = nd.ni_vp;
2273: if (vp->v_type != VDIR) {
2274: error = ENOTDIR;
2275: goto out;
2276: }
2277: /*
2278: * No rmdir "." please.
2279: */
2280: if (nd.ni_dvp == vp) {
2281: error = EBUSY;
2282: goto out;
2283: }
2284: /*
2285: * The root of a mounted filesystem cannot be deleted.
2286: */
2287: if (vp->v_flag & VROOT)
2288: error = EBUSY;
2289: out:
2290: if (!error) {
2291: error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2292: } else {
2293: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2294: if (nd.ni_dvp == vp)
2295: vrele(nd.ni_dvp);
2296: else
2297: vput(nd.ni_dvp);
2298: vput(vp);
2299: }
2300: return (error);
2301: }
2302:
2303: /*
2304: * Read a block of directory entries in a file system independent format.
2305: */
2306: int
2307: sys_getdirentries(struct proc *p, void *v, register_t *retval)
2308: {
2309: struct sys_getdirentries_args /* {
2310: syscallarg(int) fd;
2311: syscallarg(char *) buf;
2312: syscallarg(int) count;
2313: syscallarg(long *) basep;
2314: } */ *uap = v;
2315: struct vnode *vp;
2316: struct file *fp;
2317: struct uio auio;
2318: struct iovec aiov;
2319: long loff;
2320: int error, eofflag;
2321:
2322: if (SCARG(uap, count) < 0)
2323: return EINVAL;
2324: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
2325: return (error);
2326: if ((fp->f_flag & FREAD) == 0) {
2327: error = EBADF;
2328: goto bad;
2329: }
2330: vp = (struct vnode *)fp->f_data;
2331: if (vp->v_type != VDIR) {
2332: error = EINVAL;
2333: goto bad;
2334: }
2335: aiov.iov_base = SCARG(uap, buf);
2336: aiov.iov_len = SCARG(uap, count);
2337: auio.uio_iov = &aiov;
2338: auio.uio_iovcnt = 1;
2339: auio.uio_rw = UIO_READ;
2340: auio.uio_segflg = UIO_USERSPACE;
2341: auio.uio_procp = p;
2342: auio.uio_resid = SCARG(uap, count);
2343: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2344: loff = auio.uio_offset = fp->f_offset;
2345: error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, 0, 0);
2346: fp->f_offset = auio.uio_offset;
2347: VOP_UNLOCK(vp, 0, p);
2348: if (error)
2349: goto bad;
2350: error = copyout(&loff, SCARG(uap, basep),
2351: sizeof(long));
2352: *retval = SCARG(uap, count) - auio.uio_resid;
2353: bad:
2354: FRELE(fp);
2355: return (error);
2356: }
2357:
2358: /*
2359: * Set the mode mask for creation of filesystem nodes.
2360: */
2361: int
2362: sys_umask(struct proc *p, void *v, register_t *retval)
2363: {
2364: struct sys_umask_args /* {
2365: syscallarg(mode_t) newmask;
2366: } */ *uap = v;
2367: struct filedesc *fdp;
2368:
2369: fdp = p->p_fd;
2370: *retval = fdp->fd_cmask;
2371: fdp->fd_cmask = SCARG(uap, newmask) & ACCESSPERMS;
2372: return (0);
2373: }
2374:
2375: /*
2376: * Void all references to file by ripping underlying filesystem
2377: * away from vnode.
2378: */
2379: /* ARGSUSED */
2380: int
2381: sys_revoke(struct proc *p, void *v, register_t *retval)
2382: {
2383: struct sys_revoke_args /* {
2384: syscallarg(const char *) path;
2385: } */ *uap = v;
2386: struct vnode *vp;
2387: struct vattr vattr;
2388: int error;
2389: struct nameidata nd;
2390:
2391: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2392: if ((error = namei(&nd)) != 0)
2393: return (error);
2394: vp = nd.ni_vp;
2395: if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0)
2396: goto out;
2397: if (p->p_ucred->cr_uid != vattr.va_uid &&
2398: (error = suser(p, 0)))
2399: goto out;
2400: if (vp->v_usecount > 1 || (vp->v_flag & (VALIASED)))
2401: VOP_REVOKE(vp, REVOKEALL);
2402: out:
2403: vrele(vp);
2404: return (error);
2405: }
2406:
2407: /*
2408: * Convert a user file descriptor to a kernel file entry.
2409: *
2410: * On return *fpp is FREF:ed.
2411: */
2412: int
2413: getvnode(struct filedesc *fdp, int fd, struct file **fpp)
2414: {
2415: struct file *fp;
2416: struct vnode *vp;
2417:
2418: if ((fp = fd_getfile(fdp, fd)) == NULL)
2419: return (EBADF);
2420:
2421: if (fp->f_type != DTYPE_VNODE)
2422: return (EINVAL);
2423:
2424: vp = (struct vnode *)fp->f_data;
2425: if (vp->v_type == VBAD)
2426: return (EBADF);
2427:
2428: FREF(fp);
2429: *fpp = fp;
2430:
2431: return (0);
2432: }
2433:
2434: /*
2435: * Positional read system call.
2436: */
2437: int
2438: sys_pread(struct proc *p, void *v, register_t *retval)
2439: {
2440: struct sys_pread_args /* {
2441: syscallarg(int) fd;
2442: syscallarg(void *) buf;
2443: syscallarg(size_t) nbyte;
2444: syscallarg(int) pad;
2445: syscallarg(off_t) offset;
2446: } */ *uap = v;
2447: struct filedesc *fdp = p->p_fd;
2448: struct file *fp;
2449: struct vnode *vp;
2450: off_t offset;
2451: int fd = SCARG(uap, fd);
2452:
2453: if ((fp = fd_getfile(fdp, fd)) == NULL)
2454: return (EBADF);
2455: if ((fp->f_flag & FREAD) == 0)
2456: return (EBADF);
2457:
2458: vp = (struct vnode *)fp->f_data;
2459: if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
2460: return (ESPIPE);
2461: }
2462:
2463: offset = SCARG(uap, offset);
2464:
2465: FREF(fp);
2466:
2467: /* dofileread() will FRELE the descriptor for us */
2468: return (dofileread(p, fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
2469: &offset, retval));
2470: }
2471:
2472: /*
2473: * Positional scatter read system call.
2474: */
2475: int
2476: sys_preadv(struct proc *p, void *v, register_t *retval)
2477: {
2478: struct sys_preadv_args /* {
2479: syscallarg(int) fd;
2480: syscallarg(const struct iovec *) iovp;
2481: syscallarg(int) iovcnt;
2482: syscallarg(int) pad;
2483: syscallarg(off_t) offset;
2484: } */ *uap = v;
2485: struct filedesc *fdp = p->p_fd;
2486: struct file *fp;
2487: struct vnode *vp;
2488: off_t offset;
2489: int fd = SCARG(uap, fd);
2490:
2491: if ((fp = fd_getfile(fdp, fd)) == NULL)
2492: return (EBADF);
2493: if ((fp->f_flag & FREAD) == 0)
2494: return (EBADF);
2495:
2496: vp = (struct vnode *)fp->f_data;
2497: if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
2498: return (ESPIPE);
2499: }
2500:
2501: FREF(fp);
2502:
2503: offset = SCARG(uap, offset);
2504:
2505: /* dofilereadv() will FRELE the descriptor for us */
2506: return (dofilereadv(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt),
2507: &offset, retval));
2508: }
2509:
2510: /*
2511: * Positional write system call.
2512: */
2513: int
2514: sys_pwrite(struct proc *p, void *v, register_t *retval)
2515: {
2516: struct sys_pwrite_args /* {
2517: syscallarg(int) fd;
2518: syscallarg(const void *) buf;
2519: syscallarg(size_t) nbyte;
2520: syscallarg(int) pad;
2521: syscallarg(off_t) offset;
2522: } */ *uap = v;
2523: struct filedesc *fdp = p->p_fd;
2524: struct file *fp;
2525: struct vnode *vp;
2526: off_t offset;
2527: int fd = SCARG(uap, fd);
2528:
2529: if ((fp = fd_getfile(fdp, fd)) == NULL)
2530: return (EBADF);
2531: if ((fp->f_flag & FWRITE) == 0)
2532: return (EBADF);
2533:
2534: vp = (struct vnode *)fp->f_data;
2535: if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
2536: return (ESPIPE);
2537: }
2538:
2539: FREF(fp);
2540:
2541: offset = SCARG(uap, offset);
2542:
2543: /* dofilewrite() will FRELE the descriptor for us */
2544: return (dofilewrite(p, fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
2545: &offset, retval));
2546: }
2547:
2548: /*
2549: * Positional gather write system call.
2550: */
2551: int
2552: sys_pwritev(struct proc *p, void *v, register_t *retval)
2553: {
2554: struct sys_pwritev_args /* {
2555: syscallarg(int) fd;
2556: syscallarg(const struct iovec *) iovp;
2557: syscallarg(int) iovcnt;
2558: syscallarg(int) pad;
2559: syscallarg(off_t) offset;
2560: } */ *uap = v;
2561: struct filedesc *fdp = p->p_fd;
2562: struct file *fp;
2563: struct vnode *vp;
2564: off_t offset;
2565: int fd = SCARG(uap, fd);
2566:
2567: if ((fp = fd_getfile(fdp, fd)) == NULL)
2568: return (EBADF);
2569: if ((fp->f_flag & FWRITE) == 0)
2570: return (EBADF);
2571:
2572: vp = (struct vnode *)fp->f_data;
2573: if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
2574: return (ESPIPE);
2575: }
2576:
2577: FREF(fp);
2578:
2579: offset = SCARG(uap, offset);
2580:
2581: /* dofilewritev() will FRELE the descriptor for us */
2582: return (dofilewritev(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt),
2583: &offset, retval));
2584: }
CVSweb