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