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