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