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