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