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