This is all stuff first added in 4.2BSD, according to Mike Karels.
[unix-history] / usr / src / sys / kern / vfs_syscalls.c
CommitLineData
da7c5cc6 1/*
47a73614
KB
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
adb35f79
KB
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.
da7c5cc6 9 *
dbf0c423 10 * %sccs.include.redist.c%
fc2aed1e 11 *
f0e827e3 12 * @(#)vfs_syscalls.c 8.11 (Berkeley) %G%
da7c5cc6 13 */
6459ebe0 14
38a01dbe
KB
15#include <sys/param.h>
16#include <sys/systm.h>
17#include <sys/namei.h>
18#include <sys/filedesc.h>
19#include <sys/kernel.h>
20#include <sys/file.h>
21#include <sys/stat.h>
22#include <sys/vnode.h>
23#include <sys/mount.h>
24#include <sys/proc.h>
25#include <sys/uio.h>
26#include <sys/malloc.h>
27#include <sys/dirent.h>
28
be320a2b 29#include <vm/vm.h>
6aecdd4c 30#include <sys/sysctl.h>
88a7a62a 31
7121fdf0
KB
32static int change_dir __P((struct nameidata *ndp, struct proc *p));
33
a5368812
KM
34#ifdef REF_DIAGNOSTIC
35#define CURCOUNT (curproc ? curproc->p_spare[0] : 0)
36#define CHECKPOINTREF int oldrefcount = CURCOUNT;
37#define CHECKREFS(F) if (oldrefcount != CURCOUNT) \
38 printf("REFCOUNT: %s, old=%d, new=%d\n", (F), oldrefcount, CURCOUNT);
39#else
40#define CHECKPOINTREF
41#define CHECKREFS(D)
42#endif
43
fc2aed1e
KM
44/*
45 * Virtual File System System Calls
46 */
3e78e260 47
4f083fd7 48/*
7121fdf0 49 * Mount a file system.
4f083fd7 50 */
9e97623a
CT
51struct mount_args {
52 int type;
7121fdf0 53 char *path;
9e97623a
CT
54 int flags;
55 caddr_t data;
56};
6a6a1e5f
KM
57/* ARGSUSED */
58mount(p, uap, retval)
5e00df3b 59 struct proc *p;
9e97623a 60 register struct mount_args *uap;
6a6a1e5f
KM
61 int *retval;
62{
d48157d5
KM
63 register struct vnode *vp;
64 register struct mount *mp;
47971887 65 int error, flag;
8429d022 66 struct nameidata nd;
3e78e260 67
fc2aed1e
KM
68 /*
69 * Must be super user
70 */
8429d022
MK
71 if (error = suser(p->p_ucred, &p->p_acflag))
72 return (error);
fc2aed1e
KM
73 /*
74 * Get vnode to be covered
75 */
7121fdf0 76 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
dd4c01c2 77 if (error = namei(&nd))
8429d022 78 return (error);
dd4c01c2 79 vp = nd.ni_vp;
54fb9dc2 80 if (uap->flags & MNT_UPDATE) {
d48157d5
KM
81 if ((vp->v_flag & VROOT) == 0) {
82 vput(vp);
8429d022 83 return (EINVAL);
d48157d5
KM
84 }
85 mp = vp->v_mount;
db62a40f 86 flag = mp->mnt_flag;
d48157d5 87 /*
db62a40f
KM
88 * We only allow the filesystem to be reloaded if it
89 * is currently mounted read-only.
d48157d5 90 */
db62a40f
KM
91 if ((uap->flags & MNT_RELOAD) &&
92 ((mp->mnt_flag & MNT_RDONLY) == 0)) {
d48157d5 93 vput(vp);
8429d022 94 return (EOPNOTSUPP); /* Needs translation */
d48157d5 95 }
db62a40f
KM
96 mp->mnt_flag |=
97 uap->flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
d48157d5
KM
98 VOP_UNLOCK(vp);
99 goto update;
100 }
c05286bd 101 if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0))
09d2ef1a 102 return (error);
fc2aed1e
KM
103 if (vp->v_type != VDIR) {
104 vput(vp);
8429d022 105 return (ENOTDIR);
fc2aed1e 106 }
7121fdf0 107 if ((u_long)uap->type > MOUNT_MAXTYPE || vfssw[uap->type] == NULL) {
fc2aed1e 108 vput(vp);
8429d022 109 return (ENODEV);
fc2aed1e
KM
110 }
111
112 /*
d48157d5 113 * Allocate and initialize the file system.
fc2aed1e
KM
114 */
115 mp = (struct mount *)malloc((u_long)sizeof(struct mount),
116 M_MOUNT, M_WAITOK);
b1341251 117 bzero((char *)mp, (u_long)sizeof(struct mount));
54fb9dc2 118 mp->mnt_op = vfssw[uap->type];
d48157d5
KM
119 if (error = vfs_lock(mp)) {
120 free((caddr_t)mp, M_MOUNT);
121 vput(vp);
8429d022 122 return (error);
d48157d5 123 }
7121fdf0 124 if (vp->v_mountedhere != NULL) {
d48157d5
KM
125 vfs_unlock(mp);
126 free((caddr_t)mp, M_MOUNT);
127 vput(vp);
8429d022 128 return (EBUSY);
d48157d5 129 }
d48157d5 130 vp->v_mountedhere = mp;
54fb9dc2 131 mp->mnt_vnodecovered = vp;
d48157d5
KM
132update:
133 /*
134 * Set the mount level flags.
135 */
54fb9dc2
KM
136 if (uap->flags & MNT_RDONLY)
137 mp->mnt_flag |= MNT_RDONLY;
db62a40f
KM
138 else if (mp->mnt_flag & MNT_RDONLY)
139 mp->mnt_flag |= MNT_WANTRDWR;
ac85da8a
KM
140 mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
141 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC);
142 mp->mnt_flag |= uap->flags & (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
143 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC);
d48157d5
KM
144 /*
145 * Mount the filesystem.
146 */
7121fdf0 147 error = VFS_MOUNT(mp, uap->path, uap->data, &nd, p);
54fb9dc2 148 if (mp->mnt_flag & MNT_UPDATE) {
d48157d5 149 vrele(vp);
db62a40f
KM
150 if (mp->mnt_flag & MNT_WANTRDWR)
151 mp->mnt_flag &= ~MNT_RDONLY;
152 mp->mnt_flag &=~
153 (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR);
47971887 154 if (error)
54fb9dc2 155 mp->mnt_flag = flag;
8429d022 156 return (error);
d48157d5 157 }
92d0de98
KM
158 /*
159 * Put the new filesystem on the mount list after root.
160 */
fc2aed1e 161 cache_purge(vp);
fc2aed1e 162 if (!error) {
0f66cdec 163 TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
d48157d5 164 VOP_UNLOCK(vp);
fc2aed1e 165 vfs_unlock(mp);
2c69fe14 166 error = VFS_START(mp, 0, p);
fc2aed1e 167 } else {
0f66cdec
KM
168 mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
169 vfs_unlock(mp);
fc2aed1e 170 free((caddr_t)mp, M_MOUNT);
d48157d5 171 vput(vp);
fc2aed1e 172 }
8429d022 173 return (error);
3e78e260
BJ
174}
175
4f083fd7 176/*
7121fdf0 177 * Unmount a file system.
fc2aed1e
KM
178 *
179 * Note: unmount takes a path to the vnode mounted on as argument,
180 * not special file (as before).
4f083fd7 181 */
9e97623a 182struct unmount_args {
7121fdf0 183 char *path;
9e97623a
CT
184 int flags;
185};
6a6a1e5f
KM
186/* ARGSUSED */
187unmount(p, uap, retval)
5e00df3b 188 struct proc *p;
9e97623a 189 register struct unmount_args *uap;
6a6a1e5f
KM
190 int *retval;
191{
fc2aed1e 192 register struct vnode *vp;
9151110e 193 struct mount *mp;
fc2aed1e 194 int error;
8429d022 195 struct nameidata nd;
fc2aed1e 196
7121fdf0 197 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
dd4c01c2 198 if (error = namei(&nd))
8429d022 199 return (error);
dd4c01c2 200 vp = nd.ni_vp;
f0e827e3
JSP
201
202 /*
203 * Unless this is a user mount, then must
204 * have suser privilege.
205 */
206 if (((vp->v_mount->mnt_flag & MNT_USER) == 0) &&
207 (error = suser(p->p_ucred, &p->p_acflag))) {
208 vput(vp);
209 return (error);
210 }
211
fc2aed1e
KM
212 /*
213 * Must be the root of the filesystem
214 */
215 if ((vp->v_flag & VROOT) == 0) {
216 vput(vp);
8429d022 217 return (EINVAL);
fc2aed1e
KM
218 }
219 mp = vp->v_mount;
220 vput(vp);
2c69fe14 221 return (dounmount(mp, uap->flags, p));
9151110e
KM
222}
223
224/*
7121fdf0 225 * Do the actual file system unmount.
9151110e 226 */
2c69fe14 227dounmount(mp, flags, p)
9151110e
KM
228 register struct mount *mp;
229 int flags;
2c69fe14 230 struct proc *p;
9151110e
KM
231{
232 struct vnode *coveredvp;
233 int error;
234
54fb9dc2 235 coveredvp = mp->mnt_vnodecovered;
c001b1c3
KM
236 if (vfs_busy(mp))
237 return (EBUSY);
54fb9dc2 238 mp->mnt_flag |= MNT_UNMOUNT;
fc2aed1e 239 if (error = vfs_lock(mp))
9151110e 240 return (error);
fc2aed1e 241
1c295f6f 242 mp->mnt_flag &=~ MNT_ASYNC;
9db58063 243 vnode_pager_umount(mp); /* release cached vnodes */
fc2aed1e 244 cache_purgevfs(mp); /* remove cache entries for this file sys */
09d2ef1a
KM
245 if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 ||
246 (flags & MNT_FORCE))
2c69fe14 247 error = VFS_UNMOUNT(mp, flags, p);
54fb9dc2 248 mp->mnt_flag &= ~MNT_UNMOUNT;
c001b1c3 249 vfs_unbusy(mp);
fc2aed1e
KM
250 if (error) {
251 vfs_unlock(mp);
252 } else {
253 vrele(coveredvp);
0f66cdec
KM
254 TAILQ_REMOVE(&mountlist, mp, mnt_list);
255 mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
256 vfs_unlock(mp);
257 if (mp->mnt_vnodelist.lh_first != NULL)
ea2761aa 258 panic("unmount: dangling vnode");
fc2aed1e
KM
259 free((caddr_t)mp, M_MOUNT);
260 }
9151110e 261 return (error);
fc2aed1e
KM
262}
263
264/*
fc2aed1e
KM
265 * Sync each mounted filesystem.
266 */
0649728d
KM
267#ifdef DIAGNOSTIC
268int syncprt = 0;
6aecdd4c 269struct ctldebug debug0 = { "syncprt", &syncprt };
0649728d
KM
270#endif
271
9e97623a
CT
272struct sync_args {
273 int dummy;
274};
ff4fb102 275/* ARGSUSED */
6a6a1e5f 276sync(p, uap, retval)
5e00df3b 277 struct proc *p;
9e97623a 278 struct sync_args *uap;
6a6a1e5f 279 int *retval;
3e78e260 280{
0f66cdec 281 register struct mount *mp, *nmp;
1c295f6f 282 int asyncflag;
fc2aed1e 283
0f66cdec
KM
284 for (mp = mountlist.tqh_first; mp != NULL; mp = nmp) {
285 nmp = mp->mnt_list.tqe_next;
62e35d50
KM
286 /*
287 * The lock check below is to avoid races with mount
288 * and unmount.
289 */
54fb9dc2 290 if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
c001b1c3 291 !vfs_busy(mp)) {
1c295f6f
KM
292 asyncflag = mp->mnt_flag & MNT_ASYNC;
293 mp->mnt_flag &= ~MNT_ASYNC;
09d2ef1a 294 VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
1c295f6f
KM
295 if (asyncflag)
296 mp->mnt_flag |= MNT_ASYNC;
0f66cdec
KM
297 vfs_unbusy(mp);
298 }
299 }
0649728d
KM
300#ifdef DIAGNOSTIC
301 if (syncprt)
302 vfs_bufstats();
303#endif /* DIAGNOSTIC */
78eeb014 304 return (0);
fc2aed1e
KM
305}
306
c001b1c3 307/*
7121fdf0 308 * Change filesystem quotas.
c001b1c3 309 */
9e97623a
CT
310struct quotactl_args {
311 char *path;
312 int cmd;
313 int uid;
314 caddr_t arg;
315};
6a6a1e5f
KM
316/* ARGSUSED */
317quotactl(p, uap, retval)
5e00df3b 318 struct proc *p;
9e97623a 319 register struct quotactl_args *uap;
6a6a1e5f
KM
320 int *retval;
321{
c001b1c3 322 register struct mount *mp;
c001b1c3 323 int error;
8429d022 324 struct nameidata nd;
c001b1c3 325
dd4c01c2
KM
326 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
327 if (error = namei(&nd))
8429d022 328 return (error);
dd4c01c2
KM
329 mp = nd.ni_vp->v_mount;
330 vrele(nd.ni_vp);
2c69fe14 331 return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p));
c001b1c3
KM
332}
333
fc2aed1e 334/*
d4ed1dcd 335 * Get filesystem statistics.
fc2aed1e 336 */
9e97623a
CT
337struct statfs_args {
338 char *path;
339 struct statfs *buf;
340};
6a6a1e5f
KM
341/* ARGSUSED */
342statfs(p, uap, retval)
5e00df3b 343 struct proc *p;
9e97623a 344 register struct statfs_args *uap;
6a6a1e5f
KM
345 int *retval;
346{
3f705640 347 register struct mount *mp;
62e35d50 348 register struct statfs *sp;
fc2aed1e 349 int error;
8429d022 350 struct nameidata nd;
3e78e260 351
dd4c01c2
KM
352 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
353 if (error = namei(&nd))
8429d022 354 return (error);
dd4c01c2 355 mp = nd.ni_vp->v_mount;
54fb9dc2 356 sp = &mp->mnt_stat;
dd4c01c2 357 vrele(nd.ni_vp);
2c69fe14 358 if (error = VFS_STATFS(mp, sp, p))
8429d022 359 return (error);
54fb9dc2 360 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
8429d022 361 return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
fc2aed1e
KM
362}
363
6a6a1e5f 364/*
d4ed1dcd 365 * Get filesystem statistics.
6a6a1e5f 366 */
9e97623a
CT
367struct fstatfs_args {
368 int fd;
369 struct statfs *buf;
370};
6a6a1e5f
KM
371/* ARGSUSED */
372fstatfs(p, uap, retval)
5e00df3b 373 struct proc *p;
9e97623a 374 register struct fstatfs_args *uap;
6a6a1e5f
KM
375 int *retval;
376{
fc2aed1e 377 struct file *fp;
3f705640 378 struct mount *mp;
62e35d50 379 register struct statfs *sp;
fc2aed1e
KM
380 int error;
381
5e00df3b 382 if (error = getvnode(p->p_fd, uap->fd, &fp))
8429d022 383 return (error);
3f705640 384 mp = ((struct vnode *)fp->f_data)->v_mount;
54fb9dc2 385 sp = &mp->mnt_stat;
2c69fe14 386 if (error = VFS_STATFS(mp, sp, p))
8429d022 387 return (error);
54fb9dc2 388 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
8429d022 389 return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
3e78e260
BJ
390}
391
bfcdbfbf 392/*
d4ed1dcd 393 * Get statistics on all filesystems.
bfcdbfbf 394 */
9e97623a
CT
395struct getfsstat_args {
396 struct statfs *buf;
397 long bufsize;
398 int flags;
399};
6a6a1e5f 400getfsstat(p, uap, retval)
5e00df3b 401 struct proc *p;
9e97623a 402 register struct getfsstat_args *uap;
6a6a1e5f
KM
403 int *retval;
404{
0f66cdec 405 register struct mount *mp, *nmp;
62e35d50 406 register struct statfs *sp;
f62fad9a 407 caddr_t sfsp;
bfcdbfbf
KM
408 long count, maxcount, error;
409
410 maxcount = uap->bufsize / sizeof(struct statfs);
f62fad9a 411 sfsp = (caddr_t)uap->buf;
0f66cdec
KM
412 for (count = 0, mp = mountlist.tqh_first; mp != NULL; mp = nmp) {
413 nmp = mp->mnt_list.tqe_next;
54fb9dc2
KM
414 if (sfsp && count < maxcount &&
415 ((mp->mnt_flag & MNT_MLOCK) == 0)) {
416 sp = &mp->mnt_stat;
62e35d50
KM
417 /*
418 * If MNT_NOWAIT is specified, do not refresh the
419 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
420 */
421 if (((uap->flags & MNT_NOWAIT) == 0 ||
422 (uap->flags & MNT_WAIT)) &&
0f66cdec 423 (error = VFS_STATFS(mp, sp, p)))
fd8516be 424 continue;
54fb9dc2 425 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
62e35d50 426 if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
8429d022 427 return (error);
62e35d50 428 sfsp += sizeof(*sp);
bfcdbfbf 429 }
f62fad9a 430 count++;
0f66cdec 431 }
bfcdbfbf 432 if (sfsp && count > maxcount)
6a6a1e5f 433 *retval = maxcount;
bfcdbfbf 434 else
6a6a1e5f 435 *retval = count;
8429d022 436 return (0);
bfcdbfbf
KM
437}
438
6995a2cb
KM
439/*
440 * Change current working directory to a given file descriptor.
441 */
9e97623a
CT
442struct fchdir_args {
443 int fd;
444};
6a6a1e5f
KM
445/* ARGSUSED */
446fchdir(p, uap, retval)
5e00df3b 447 struct proc *p;
9e97623a 448 struct fchdir_args *uap;
6a6a1e5f
KM
449 int *retval;
450{
5e00df3b 451 register struct filedesc *fdp = p->p_fd;
6995a2cb
KM
452 register struct vnode *vp;
453 struct file *fp;
454 int error;
455
5e00df3b 456 if (error = getvnode(fdp, uap->fd, &fp))
8429d022 457 return (error);
6995a2cb
KM
458 vp = (struct vnode *)fp->f_data;
459 VOP_LOCK(vp);
460 if (vp->v_type != VDIR)
461 error = ENOTDIR;
462 else
2c69fe14 463 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
6995a2cb 464 VOP_UNLOCK(vp);
ab214c34 465 if (error)
8429d022 466 return (error);
ab214c34 467 VREF(vp);
5e00df3b
KM
468 vrele(fdp->fd_cdir);
469 fdp->fd_cdir = vp;
8429d022 470 return (0);
6995a2cb
KM
471}
472
4f083fd7 473/*
fc2aed1e 474 * Change current working directory (``.'').
4f083fd7 475 */
9e97623a 476struct chdir_args {
7121fdf0 477 char *path;
9e97623a 478};
6a6a1e5f
KM
479/* ARGSUSED */
480chdir(p, uap, retval)
5e00df3b 481 struct proc *p;
9e97623a 482 struct chdir_args *uap;
6a6a1e5f
KM
483 int *retval;
484{
5e00df3b 485 register struct filedesc *fdp = p->p_fd;
fc2aed1e 486 int error;
8429d022 487 struct nameidata nd;
3e78e260 488
7121fdf0
KB
489 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
490 if (error = change_dir(&nd, p))
8429d022 491 return (error);
5e00df3b 492 vrele(fdp->fd_cdir);
dd4c01c2 493 fdp->fd_cdir = nd.ni_vp;
8429d022 494 return (0);
fc2aed1e
KM
495}
496
497/*
498 * Change notion of root (``/'') directory.
499 */
9e97623a 500struct chroot_args {
7121fdf0 501 char *path;
9e97623a 502};
6a6a1e5f
KM
503/* ARGSUSED */
504chroot(p, uap, retval)
5e00df3b 505 struct proc *p;
9e97623a 506 struct chroot_args *uap;
6a6a1e5f
KM
507 int *retval;
508{
5e00df3b 509 register struct filedesc *fdp = p->p_fd;
fc2aed1e 510 int error;
8429d022 511 struct nameidata nd;
fc2aed1e 512
8429d022
MK
513 if (error = suser(p->p_ucred, &p->p_acflag))
514 return (error);
7121fdf0
KB
515 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
516 if (error = change_dir(&nd, p))
8429d022 517 return (error);
5e00df3b
KM
518 if (fdp->fd_rdir != NULL)
519 vrele(fdp->fd_rdir);
dd4c01c2 520 fdp->fd_rdir = nd.ni_vp;
8429d022 521 return (0);
fc2aed1e
KM
522}
523
524/*
525 * Common routine for chroot and chdir.
526 */
7121fdf0
KB
527static int
528change_dir(ndp, p)
dd4c01c2 529 register struct nameidata *ndp;
8429d022 530 struct proc *p;
fc2aed1e
KM
531{
532 struct vnode *vp;
533 int error;
534
dd4c01c2 535 if (error = namei(ndp))
fc2aed1e
KM
536 return (error);
537 vp = ndp->ni_vp;
538 if (vp->v_type != VDIR)
539 error = ENOTDIR;
540 else
2c69fe14 541 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
fc2aed1e
KM
542 VOP_UNLOCK(vp);
543 if (error)
544 vrele(vp);
545 return (error);
3e78e260
BJ
546}
547
548/*
6a6a1e5f
KM
549 * Check permissions, allocate an open file structure,
550 * and call the device open routine if any.
3e78e260 551 */
9e97623a 552struct open_args {
7121fdf0
KB
553 char *path;
554 int flags;
9e97623a 555 int mode;
9e97623a 556};
6a6a1e5f 557open(p, uap, retval)
5e00df3b 558 struct proc *p;
9e97623a 559 register struct open_args *uap;
6a6a1e5f 560 int *retval;
3e78e260 561{
5e00df3b 562 register struct filedesc *fdp = p->p_fd;
3e78e260 563 register struct file *fp;
6aaf085a 564 register struct vnode *vp;
7121fdf0 565 int flags, cmode;
fc2aed1e 566 struct file *nfp;
ff8d1617
KM
567 int type, indx, error;
568 struct flock lf;
8429d022 569 struct nameidata nd;
fc2aed1e
KM
570 extern struct fileops vnops;
571
5e00df3b 572 if (error = falloc(p, &nfp, &indx))
8429d022 573 return (error);
fc2aed1e 574 fp = nfp;
7121fdf0
KB
575 flags = FFLAGS(uap->flags);
576 cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
577 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
03951846 578 p->p_dupfd = -indx - 1; /* XXX check for fdopen */
7121fdf0 579 if (error = vn_open(&nd, flags, cmode)) {
336f999d 580 ffree(fp);
f0e12026
KM
581 if ((error == ENODEV || error == ENXIO) &&
582 p->p_dupfd >= 0 && /* XXX from fdopen */
7121fdf0
KB
583 (error =
584 dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
6a6a1e5f 585 *retval = indx;
8429d022 586 return (0);
6a6a1e5f 587 }
b10521d6
KM
588 if (error == ERESTART)
589 error = EINTR;
78eeb014 590 fdp->fd_ofiles[indx] = NULL;
8429d022 591 return (error);
528f664c 592 }
da5acac3 593 p->p_dupfd = 0;
dd4c01c2 594 vp = nd.ni_vp;
7121fdf0 595 fp->f_flag = flags & FMASK;
8932276d
KM
596 fp->f_type = DTYPE_VNODE;
597 fp->f_ops = &vnops;
598 fp->f_data = (caddr_t)vp;
7121fdf0 599 if (flags & (O_EXLOCK | O_SHLOCK)) {
ff8d1617
KM
600 lf.l_whence = SEEK_SET;
601 lf.l_start = 0;
602 lf.l_len = 0;
7121fdf0 603 if (flags & O_EXLOCK)
ff8d1617
KM
604 lf.l_type = F_WRLCK;
605 else
606 lf.l_type = F_RDLCK;
607 type = F_FLOCK;
7121fdf0 608 if ((flags & FNONBLOCK) == 0)
ff8d1617 609 type |= F_WAIT;
70b7fe1d 610 VOP_UNLOCK(vp);
6aaf085a 611 if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
6aaf085a 612 (void) vn_close(vp, fp->f_flag, fp->f_cred, p);
336f999d 613 ffree(fp);
ff8d1617
KM
614 fdp->fd_ofiles[indx] = NULL;
615 return (error);
616 }
70b7fe1d 617 VOP_LOCK(vp);
b40ecf6f 618 fp->f_flag |= FHASLOCK;
ff8d1617 619 }
6aaf085a 620 VOP_UNLOCK(vp);
6a6a1e5f 621 *retval = indx;
8429d022 622 return (0);
3e78e260
BJ
623}
624
4fde03dc 625#ifdef COMPAT_43
3e78e260 626/*
7121fdf0 627 * Create a file.
3e78e260 628 */
9e97623a 629struct ocreat_args {
7121fdf0
KB
630 char *path;
631 int mode;
9e97623a 632};
4fde03dc 633ocreat(p, uap, retval)
6a6a1e5f 634 struct proc *p;
9e97623a 635 register struct ocreat_args *uap;
6a6a1e5f 636 int *retval;
3e78e260 637{
9e97623a 638 struct open_args openuap;
6a6a1e5f 639
7121fdf0
KB
640 openuap.path = uap->path;
641 openuap.mode = uap->mode;
642 openuap.flags = O_WRONLY | O_CREAT | O_TRUNC;
8429d022 643 return (open(p, &openuap, retval));
6a6a1e5f 644}
4fde03dc 645#endif /* COMPAT_43 */
6a6a1e5f
KM
646
647/*
7121fdf0 648 * Create a special file.
6a6a1e5f 649 */
9e97623a 650struct mknod_args {
7121fdf0
KB
651 char *path;
652 int mode;
9e97623a
CT
653 int dev;
654};
6a6a1e5f
KM
655/* ARGSUSED */
656mknod(p, uap, retval)
5e00df3b 657 struct proc *p;
9e97623a 658 register struct mknod_args *uap;
6a6a1e5f
KM
659 int *retval;
660{
fc2aed1e
KM
661 register struct vnode *vp;
662 struct vattr vattr;
663 int error;
8429d022 664 struct nameidata nd;
3e78e260 665
a5368812 666 CHECKPOINTREF;
8429d022
MK
667 if (error = suser(p->p_ucred, &p->p_acflag))
668 return (error);
7121fdf0 669 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
dd4c01c2 670 if (error = namei(&nd))
8429d022 671 return (error);
dd4c01c2 672 vp = nd.ni_vp;
cf5ef508 673 if (vp != NULL)
fc2aed1e 674 error = EEXIST;
cf5ef508
KB
675 else {
676 VATTR_NULL(&vattr);
677 vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
678 vattr.va_rdev = uap->dev;
679
680 switch (uap->mode & S_IFMT) {
681 case S_IFMT: /* used by badsect to flag bad sectors */
682 vattr.va_type = VBAD;
683 break;
684 case S_IFCHR:
685 vattr.va_type = VCHR;
686 break;
687 case S_IFBLK:
688 vattr.va_type = VBLK;
689 break;
690 default:
691 error = EINVAL;
692 break;
693 }
3e78e260 694 }
66955caf 695 if (!error) {
dd4c01c2
KM
696 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
697 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
66955caf 698 } else {
dd4c01c2
KM
699 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
700 if (nd.ni_dvp == vp)
701 vrele(nd.ni_dvp);
6c44e83b 702 else
dd4c01c2 703 vput(nd.ni_dvp);
66955caf
KM
704 if (vp)
705 vrele(vp);
706 }
a5368812 707 CHECKREFS("mknod");
8429d022 708 return (error);
3e78e260
BJ
709}
710
4751dd21 711/*
7121fdf0 712 * Create named pipe.
4751dd21 713 */
9e97623a 714struct mkfifo_args {
7121fdf0
KB
715 char *path;
716 int mode;
9e97623a 717};
6a6a1e5f
KM
718/* ARGSUSED */
719mkfifo(p, uap, retval)
5e00df3b 720 struct proc *p;
9e97623a 721 register struct mkfifo_args *uap;
6a6a1e5f
KM
722 int *retval;
723{
4751dd21
KM
724 struct vattr vattr;
725 int error;
8429d022 726 struct nameidata nd;
4751dd21
KM
727
728#ifndef FIFO
8429d022 729 return (EOPNOTSUPP);
4751dd21 730#else
7121fdf0 731 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
dd4c01c2 732 if (error = namei(&nd))
8429d022 733 return (error);
dd4c01c2
KM
734 if (nd.ni_vp != NULL) {
735 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
736 if (nd.ni_dvp == nd.ni_vp)
737 vrele(nd.ni_dvp);
6c44e83b 738 else
dd4c01c2
KM
739 vput(nd.ni_dvp);
740 vrele(nd.ni_vp);
8429d022 741 return (EEXIST);
4751dd21 742 }
3658f091
KB
743 VATTR_NULL(&vattr);
744 vattr.va_type = VFIFO;
7121fdf0 745 vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
dd4c01c2
KM
746 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
747 return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
4751dd21
KM
748#endif /* FIFO */
749}
750
3e78e260 751/*
7121fdf0 752 * Make a hard file link.
3e78e260 753 */
9e97623a 754struct link_args {
7121fdf0
KB
755 char *path;
756 char *link;
9e97623a 757};
6a6a1e5f
KM
758/* ARGSUSED */
759link(p, uap, retval)
5e00df3b 760 struct proc *p;
9e97623a 761 register struct link_args *uap;
6a6a1e5f
KM
762 int *retval;
763{
7121fdf0 764 register struct vnode *vp;
8429d022 765 struct nameidata nd;
7121fdf0 766 int error;
3e78e260 767
a5368812 768 CHECKPOINTREF;
7121fdf0 769 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
dd4c01c2 770 if (error = namei(&nd))
8429d022 771 return (error);
dd4c01c2 772 vp = nd.ni_vp;
cf5ef508
KB
773 if (vp->v_type != VDIR ||
774 (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
775 nd.ni_cnd.cn_nameiop = CREATE;
776 nd.ni_cnd.cn_flags = LOCKPARENT;
777 nd.ni_dirp = uap->link;
778 if ((error = namei(&nd)) == 0) {
779 if (nd.ni_vp != NULL)
780 error = EEXIST;
781 if (!error) {
782 LEASE_CHECK(nd.ni_dvp,
783 p, p->p_ucred, LEASE_WRITE);
784 LEASE_CHECK(vp,
785 p, p->p_ucred, LEASE_WRITE);
786 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
787 } else {
788 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
789 if (nd.ni_dvp == nd.ni_vp)
790 vrele(nd.ni_dvp);
791 else
792 vput(nd.ni_dvp);
793 if (nd.ni_vp)
794 vrele(nd.ni_vp);
795 }
796 }
66955caf 797 }
cf5ef508 798 vrele(vp);
a5368812 799 CHECKREFS("link");
8429d022 800 return (error);
3e78e260
BJ
801}
802
803/*
d4ed1dcd 804 * Make a symbolic link.
3e78e260 805 */
9e97623a 806struct symlink_args {
7121fdf0
KB
807 char *path;
808 char *link;
9e97623a 809};
6a6a1e5f
KM
810/* ARGSUSED */
811symlink(p, uap, retval)
5e00df3b 812 struct proc *p;
9e97623a 813 register struct symlink_args *uap;
6a6a1e5f
KM
814 int *retval;
815{
fc2aed1e 816 struct vattr vattr;
7121fdf0 817 char *path;
fc2aed1e 818 int error;
8429d022 819 struct nameidata nd;
3e78e260 820
a5368812 821 CHECKPOINTREF;
7121fdf0
KB
822 MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
823 if (error = copyinstr(uap->path, path, MAXPATHLEN, NULL))
66955caf 824 goto out;
7121fdf0 825 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p);
dd4c01c2 826 if (error = namei(&nd))
66955caf 827 goto out;
dd4c01c2
KM
828 if (nd.ni_vp) {
829 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
830 if (nd.ni_dvp == nd.ni_vp)
831 vrele(nd.ni_dvp);
6c44e83b 832 else
dd4c01c2
KM
833 vput(nd.ni_dvp);
834 vrele(nd.ni_vp);
fc2aed1e
KM
835 error = EEXIST;
836 goto out;
3e78e260 837 }
3ee1461b 838 VATTR_NULL(&vattr);
7121fdf0 839 vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
dd4c01c2 840 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
7121fdf0 841 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
fc2aed1e 842out:
7121fdf0 843 FREE(path, M_NAMEI);
a5368812 844 CHECKREFS("symlink");
8429d022 845 return (error);
3e78e260
BJ
846}
847
848/*
d4ed1dcd 849 * Delete a name from the filesystem.
3e78e260 850 */
9e97623a 851struct unlink_args {
7121fdf0 852 char *path;
9e97623a 853};
6a6a1e5f
KM
854/* ARGSUSED */
855unlink(p, uap, retval)
5e00df3b 856 struct proc *p;
9e97623a 857 struct unlink_args *uap;
6a6a1e5f
KM
858 int *retval;
859{
fc2aed1e
KM
860 register struct vnode *vp;
861 int error;
8429d022 862 struct nameidata nd;
3e78e260 863
a5368812 864 CHECKPOINTREF;
7121fdf0 865 NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
dd4c01c2 866 if (error = namei(&nd))
8429d022 867 return (error);
dd4c01c2 868 vp = nd.ni_vp;
dbcf7de6
KM
869 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
870 VOP_LOCK(vp);
7121fdf0 871
cf5ef508
KB
872 if (vp->v_type != VDIR ||
873 (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
874 /*
875 * The root of a mounted filesystem cannot be deleted.
876 */
877 if (vp->v_flag & VROOT)
878 error = EBUSY;
879 else
880 (void)vnode_pager_uncache(vp);
881 }
882
883 if (!error) {
dd4c01c2 884 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
dd4c01c2 885 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
66955caf 886 } else {
dd4c01c2
KM
887 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
888 if (nd.ni_dvp == vp)
889 vrele(nd.ni_dvp);
6c44e83b 890 else
dd4c01c2 891 vput(nd.ni_dvp);
66955caf
KM
892 vput(vp);
893 }
a5368812 894 CHECKREFS("unlink");
8429d022 895 return (error);
3e78e260
BJ
896}
897
7121fdf0
KB
898/*
899 * Reposition read/write file offset.
900 */
95c0eb1e 901struct lseek_args {
7121fdf0 902 int fd;
2f2b3b3d 903 int pad;
7121fdf0
KB
904 off_t offset;
905 int whence;
2f2b3b3d 906};
201e5411 907lseek(p, uap, retval)
5e00df3b 908 struct proc *p;
95c0eb1e 909 register struct lseek_args *uap;
9e97623a 910 int *retval;
6a6a1e5f 911{
8429d022 912 struct ucred *cred = p->p_ucred;
5e00df3b 913 register struct filedesc *fdp = p->p_fd;
6a6a1e5f 914 register struct file *fp;
fc2aed1e
KM
915 struct vattr vattr;
916 int error;
917
7121fdf0
KB
918 if ((u_int)uap->fd >= fdp->fd_nfiles ||
919 (fp = fdp->fd_ofiles[uap->fd]) == NULL)
8429d022 920 return (EBADF);
fc2aed1e 921 if (fp->f_type != DTYPE_VNODE)
8429d022 922 return (ESPIPE);
7121fdf0 923 switch (uap->whence) {
b4d1aee9 924 case L_INCR:
7121fdf0 925 fp->f_offset += uap->offset;
b4d1aee9 926 break;
b4d1aee9 927 case L_XTND:
7121fdf0
KB
928 if (error =
929 VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p))
8429d022 930 return (error);
7121fdf0 931 fp->f_offset = uap->offset + vattr.va_size;
b4d1aee9 932 break;
b4d1aee9 933 case L_SET:
7121fdf0 934 fp->f_offset = uap->offset;
b4d1aee9 935 break;
b4d1aee9 936 default:
8429d022 937 return (EINVAL);
b4d1aee9 938 }
9e97623a 939 *(off_t *)retval = fp->f_offset;
8429d022 940 return (0);
3e78e260
BJ
941}
942
201e5411 943#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
64deb204 944/*
7121fdf0 945 * Reposition read/write file offset.
64deb204 946 */
95c0eb1e 947struct olseek_args {
7121fdf0
KB
948 int fd;
949 long offset;
950 int whence;
64deb204 951};
201e5411 952olseek(p, uap, retval)
64deb204 953 struct proc *p;
95c0eb1e 954 register struct olseek_args *uap;
64deb204
KM
955 int *retval;
956{
95c0eb1e 957 struct lseek_args nuap;
64deb204
KM
958 off_t qret;
959 int error;
960
7121fdf0
KB
961 nuap.fd = uap->fd;
962 nuap.offset = uap->offset;
963 nuap.whence = uap->whence;
95c0eb1e 964 error = lseek(p, &nuap, &qret);
64deb204
KM
965 *(long *)retval = qret;
966 return (error);
967}
201e5411 968#endif /* COMPAT_43 */
64deb204 969
3e78e260 970/*
d4ed1dcd 971 * Check access permissions.
3e78e260 972 */
b54e8954 973struct access_args {
7121fdf0
KB
974 char *path;
975 int flags;
9e97623a 976};
b54e8954 977access(p, uap, retval)
5e00df3b 978 struct proc *p;
b54e8954 979 register struct access_args *uap;
6a6a1e5f
KM
980 int *retval;
981{
8429d022 982 register struct ucred *cred = p->p_ucred;
fc2aed1e 983 register struct vnode *vp;
cf5ef508 984 int error, flags, t_gid, t_uid;
8429d022 985 struct nameidata nd;
3e78e260 986
cf5ef508
KB
987 t_uid = cred->cr_uid;
988 t_gid = cred->cr_groups[0];
8429d022
MK
989 cred->cr_uid = p->p_cred->p_ruid;
990 cred->cr_groups[0] = p->p_cred->p_rgid;
7121fdf0 991 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
dd4c01c2 992 if (error = namei(&nd))
fc2aed1e 993 goto out1;
dd4c01c2 994 vp = nd.ni_vp;
7121fdf0
KB
995
996 /* Flags == 0 means only check for existence. */
997 if (uap->flags) {
998 flags = 0;
999 if (uap->flags & R_OK)
1000 flags |= VREAD;
1001 if (uap->flags & W_OK)
1002 flags |= VWRITE;
1003 if (uap->flags & X_OK)
1004 flags |= VEXEC;
1005 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
1006 error = VOP_ACCESS(vp, flags, cred, p);
3e78e260 1007 }
fc2aed1e
KM
1008 vput(vp);
1009out1:
cf5ef508
KB
1010 cred->cr_uid = t_uid;
1011 cred->cr_groups[0] = t_gid;
8429d022 1012 return (error);
3e78e260 1013}
d67a03eb 1014
8932276d 1015#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
d67a03eb 1016/*
7121fdf0 1017 * Get file status; this version follows links.
d67a03eb 1018 */
9e97623a 1019struct ostat_args {
7121fdf0 1020 char *path;
9e97623a
CT
1021 struct ostat *ub;
1022};
6a6a1e5f 1023/* ARGSUSED */
ae9b6dc3 1024ostat(p, uap, retval)
be320a2b 1025 struct proc *p;
9e97623a 1026 register struct ostat_args *uap;
be320a2b
KM
1027 int *retval;
1028{
1029 struct stat sb;
1030 struct ostat osb;
1031 int error;
1032 struct nameidata nd;
1033
7121fdf0 1034 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
be320a2b
KM
1035 if (error = namei(&nd))
1036 return (error);
1037 error = vn_stat(nd.ni_vp, &sb, p);
1038 vput(nd.ni_vp);
1039 if (error)
1040 return (error);
1041 cvtstat(&sb, &osb);
1042 error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
1043 return (error);
1044}
1045
1046/*
7121fdf0 1047 * Get file status; this version does not follow links.
be320a2b 1048 */
9e97623a 1049struct olstat_args {
7121fdf0 1050 char *path;
9e97623a
CT
1051 struct ostat *ub;
1052};
be320a2b 1053/* ARGSUSED */
ae9b6dc3 1054olstat(p, uap, retval)
be320a2b 1055 struct proc *p;
9e97623a 1056 register struct olstat_args *uap;
be320a2b
KM
1057 int *retval;
1058{
1059 struct stat sb;
1060 struct ostat osb;
1061 int error;
1062 struct nameidata nd;
1063
7121fdf0 1064 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
be320a2b
KM
1065 if (error = namei(&nd))
1066 return (error);
1067 error = vn_stat(nd.ni_vp, &sb, p);
1068 vput(nd.ni_vp);
1069 if (error)
1070 return (error);
1071 cvtstat(&sb, &osb);
1072 error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
1073 return (error);
1074}
1075
1076/*
7121fdf0 1077 * Convert from an old to a new stat structure.
be320a2b
KM
1078 */
1079cvtstat(st, ost)
1080 struct stat *st;
1081 struct ostat *ost;
1082{
1083
1084 ost->st_dev = st->st_dev;
1085 ost->st_ino = st->st_ino;
1086 ost->st_mode = st->st_mode;
1087 ost->st_nlink = st->st_nlink;
1088 ost->st_uid = st->st_uid;
1089 ost->st_gid = st->st_gid;
1090 ost->st_rdev = st->st_rdev;
1091 if (st->st_size < (quad_t)1 << 32)
1092 ost->st_size = st->st_size;
1093 else
1094 ost->st_size = -2;
1095 ost->st_atime = st->st_atime;
1096 ost->st_mtime = st->st_mtime;
1097 ost->st_ctime = st->st_ctime;
1098 ost->st_blksize = st->st_blksize;
1099 ost->st_blocks = st->st_blocks;
1100 ost->st_flags = st->st_flags;
1101 ost->st_gen = st->st_gen;
1102}
8932276d 1103#endif /* COMPAT_43 || COMPAT_SUNOS */
be320a2b
KM
1104
1105/*
7121fdf0 1106 * Get file status; this version follows links.
be320a2b 1107 */
9e97623a 1108struct stat_args {
7121fdf0 1109 char *path;
9e97623a
CT
1110 struct stat *ub;
1111};
be320a2b 1112/* ARGSUSED */
ae9b6dc3 1113stat(p, uap, retval)
5e00df3b 1114 struct proc *p;
9e97623a 1115 register struct stat_args *uap;
6a6a1e5f 1116 int *retval;
d67a03eb 1117{
6a6a1e5f
KM
1118 struct stat sb;
1119 int error;
8429d022 1120 struct nameidata nd;
d67a03eb 1121
7121fdf0 1122 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
dd4c01c2 1123 if (error = namei(&nd))
8429d022 1124 return (error);
dd4c01c2
KM
1125 error = vn_stat(nd.ni_vp, &sb, p);
1126 vput(nd.ni_vp);
6a6a1e5f 1127 if (error)
8429d022 1128 return (error);
6a6a1e5f 1129 error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
8429d022 1130 return (error);
d67a03eb
BJ
1131}
1132
5485e062 1133/*
7121fdf0 1134 * Get file status; this version does not follow links.
5485e062 1135 */
9e97623a 1136struct lstat_args {
7121fdf0 1137 char *path;
9e97623a
CT
1138 struct stat *ub;
1139};
6a6a1e5f 1140/* ARGSUSED */
ae9b6dc3 1141lstat(p, uap, retval)
5e00df3b 1142 struct proc *p;
9e97623a 1143 register struct lstat_args *uap;
6a6a1e5f
KM
1144 int *retval;
1145{
fc2aed1e 1146 int error;
49f762b8
KM
1147 struct vnode *vp, *dvp;
1148 struct stat sb, sb1;
8429d022 1149 struct nameidata nd;
5485e062 1150
49f762b8 1151 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
7121fdf0 1152 uap->path, p);
dd4c01c2 1153 if (error = namei(&nd))
8429d022 1154 return (error);
49f762b8
KM
1155 /*
1156 * For symbolic links, always return the attributes of its
1157 * containing directory, except for mode, size, and links.
1158 */
1159 vp = nd.ni_vp;
1160 dvp = nd.ni_dvp;
1161 if (vp->v_type != VLNK) {
1162 if (dvp == vp)
1163 vrele(dvp);
1164 else
1165 vput(dvp);
1166 error = vn_stat(vp, &sb, p);
1167 vput(vp);
1168 if (error)
1169 return (error);
1170 } else {
1171 error = vn_stat(dvp, &sb, p);
1172 vput(dvp);
1173 if (error) {
1174 vput(vp);
1175 return (error);
1176 }
1177 error = vn_stat(vp, &sb1, p);
1178 vput(vp);
1179 if (error)
1180 return (error);
1181 sb.st_mode &= ~S_IFDIR;
1182 sb.st_mode |= S_IFLNK;
1183 sb.st_nlink = sb1.st_nlink;
1184 sb.st_size = sb1.st_size;
1185 sb.st_blocks = sb1.st_blocks;
1186 }
fc2aed1e 1187 error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
8429d022 1188 return (error);
d67a03eb
BJ
1189}
1190
201e5411 1191/*
7121fdf0 1192 * Get configurable pathname variables.
201e5411
KM
1193 */
1194struct pathconf_args {
7121fdf0 1195 char *path;
201e5411
KM
1196 int name;
1197};
1198/* ARGSUSED */
1199pathconf(p, uap, retval)
1200 struct proc *p;
1201 register struct pathconf_args *uap;
1202 int *retval;
1203{
1204 int error;
1205 struct nameidata nd;
1206
7121fdf0 1207 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
201e5411
KM
1208 if (error = namei(&nd))
1209 return (error);
1210 error = VOP_PATHCONF(nd.ni_vp, uap->name, retval);
1211 vput(nd.ni_vp);
1212 return (error);
1213}
1214
d67a03eb 1215/*
d4ed1dcd 1216 * Return target name of a symbolic link.
5485e062 1217 */
9e97623a 1218struct readlink_args {
7121fdf0 1219 char *path;
9e97623a
CT
1220 char *buf;
1221 int count;
1222};
6a6a1e5f
KM
1223/* ARGSUSED */
1224readlink(p, uap, retval)
5e00df3b 1225 struct proc *p;
9e97623a 1226 register struct readlink_args *uap;
6a6a1e5f
KM
1227 int *retval;
1228{
fc2aed1e
KM
1229 register struct vnode *vp;
1230 struct iovec aiov;
1231 struct uio auio;
1232 int error;
8429d022 1233 struct nameidata nd;
5485e062 1234
a5368812 1235 CHECKPOINTREF;
7121fdf0 1236 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
dd4c01c2 1237 if (error = namei(&nd))
8429d022 1238 return (error);
dd4c01c2 1239 vp = nd.ni_vp;
7121fdf0 1240 if (vp->v_type != VLNK)
fc2aed1e 1241 error = EINVAL;
7121fdf0
KB
1242 else {
1243 aiov.iov_base = uap->buf;
1244 aiov.iov_len = uap->count;
1245 auio.uio_iov = &aiov;
1246 auio.uio_iovcnt = 1;
1247 auio.uio_offset = 0;
1248 auio.uio_rw = UIO_READ;
1249 auio.uio_segflg = UIO_USERSPACE;
1250 auio.uio_procp = p;
1251 auio.uio_resid = uap->count;
1252 error = VOP_READLINK(vp, &auio, p->p_ucred);
5485e062 1253 }
fc2aed1e 1254 vput(vp);
6a6a1e5f 1255 *retval = uap->count - auio.uio_resid;
a5368812 1256 CHECKREFS("readlink");
8429d022 1257 return (error);
5485e062
BJ
1258}
1259
6995a2cb 1260/*
7121fdf0 1261 * Change flags of a file given a path name.
6995a2cb 1262 */
9e97623a 1263struct chflags_args {
7121fdf0 1264 char *path;
9e97623a
CT
1265 int flags;
1266};
6a6a1e5f
KM
1267/* ARGSUSED */
1268chflags(p, uap, retval)
5e00df3b 1269 struct proc *p;
9e97623a 1270 register struct chflags_args *uap;
6a6a1e5f
KM
1271 int *retval;
1272{
6995a2cb
KM
1273 register struct vnode *vp;
1274 struct vattr vattr;
1275 int error;
8429d022 1276 struct nameidata nd;
6995a2cb 1277
7121fdf0 1278 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
dd4c01c2 1279 if (error = namei(&nd))
8429d022 1280 return (error);
dd4c01c2 1281 vp = nd.ni_vp;
dbcf7de6
KM
1282 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
1283 VOP_LOCK(vp);
7121fdf0 1284 if (vp->v_mount->mnt_flag & MNT_RDONLY)
6995a2cb 1285 error = EROFS;
7121fdf0
KB
1286 else {
1287 VATTR_NULL(&vattr);
1288 vattr.va_flags = uap->flags;
1289 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
6995a2cb 1290 }
6995a2cb 1291 vput(vp);
8429d022 1292 return (error);
6995a2cb
KM
1293}
1294
1295/*
1296 * Change flags of a file given a file descriptor.
1297 */
9e97623a
CT
1298struct fchflags_args {
1299 int fd;
1300 int flags;
1301};
6a6a1e5f
KM
1302/* ARGSUSED */
1303fchflags(p, uap, retval)
5e00df3b 1304 struct proc *p;
9e97623a 1305 register struct fchflags_args *uap;
6a6a1e5f
KM
1306 int *retval;
1307{
6995a2cb
KM
1308 struct vattr vattr;
1309 struct vnode *vp;
1310 struct file *fp;
1311 int error;
1312
5e00df3b 1313 if (error = getvnode(p->p_fd, uap->fd, &fp))
8429d022 1314 return (error);
6995a2cb 1315 vp = (struct vnode *)fp->f_data;
dbcf7de6 1316 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
6995a2cb 1317 VOP_LOCK(vp);
7121fdf0 1318 if (vp->v_mount->mnt_flag & MNT_RDONLY)
6995a2cb 1319 error = EROFS;
7121fdf0
KB
1320 else {
1321 VATTR_NULL(&vattr);
1322 vattr.va_flags = uap->flags;
1323 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
6995a2cb 1324 }
6995a2cb 1325 VOP_UNLOCK(vp);
8429d022 1326 return (error);
6995a2cb
KM
1327}
1328
4f083fd7
SL
1329/*
1330 * Change mode of a file given path name.
1331 */
9e97623a 1332struct chmod_args {
7121fdf0
KB
1333 char *path;
1334 int mode;
9e97623a 1335};
6a6a1e5f
KM
1336/* ARGSUSED */
1337chmod(p, uap, retval)
5e00df3b 1338 struct proc *p;
9e97623a 1339 register struct chmod_args *uap;
6a6a1e5f
KM
1340 int *retval;
1341{
fc2aed1e
KM
1342 register struct vnode *vp;
1343 struct vattr vattr;
1344 int error;
8429d022 1345 struct nameidata nd;
5485e062 1346
7121fdf0 1347 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
dd4c01c2 1348 if (error = namei(&nd))
8429d022 1349 return (error);
dd4c01c2 1350 vp = nd.ni_vp;
dbcf7de6
KM
1351 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
1352 VOP_LOCK(vp);
7121fdf0 1353 if (vp->v_mount->mnt_flag & MNT_RDONLY)
fc2aed1e 1354 error = EROFS;
7121fdf0
KB
1355 else {
1356 VATTR_NULL(&vattr);
1357 vattr.va_mode = uap->mode & ALLPERMS;
1358 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
fc2aed1e 1359 }
fc2aed1e 1360 vput(vp);
8429d022 1361 return (error);
528f664c 1362}
f94ceb3b 1363
4f083fd7
SL
1364/*
1365 * Change mode of a file given a file descriptor.
1366 */
9e97623a
CT
1367struct fchmod_args {
1368 int fd;
7121fdf0 1369 int mode;
9e97623a 1370};
6a6a1e5f
KM
1371/* ARGSUSED */
1372fchmod(p, uap, retval)
5e00df3b 1373 struct proc *p;
9e97623a 1374 register struct fchmod_args *uap;
6a6a1e5f
KM
1375 int *retval;
1376{
fc2aed1e
KM
1377 struct vattr vattr;
1378 struct vnode *vp;
1379 struct file *fp;
1380 int error;
1381
5e00df3b 1382 if (error = getvnode(p->p_fd, uap->fd, &fp))
8429d022 1383 return (error);
fc2aed1e 1384 vp = (struct vnode *)fp->f_data;
dbcf7de6 1385 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
fc2aed1e 1386 VOP_LOCK(vp);
7121fdf0 1387 if (vp->v_mount->mnt_flag & MNT_RDONLY)
fc2aed1e 1388 error = EROFS;
7121fdf0
KB
1389 else {
1390 VATTR_NULL(&vattr);
1391 vattr.va_mode = uap->mode & ALLPERMS;
1392 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
f94ceb3b 1393 }
fc2aed1e 1394 VOP_UNLOCK(vp);
8429d022 1395 return (error);
5485e062
BJ
1396}
1397
4f083fd7
SL
1398/*
1399 * Set ownership given a path name.
1400 */
9e97623a 1401struct chown_args {
7121fdf0 1402 char *path;
9e97623a
CT
1403 int uid;
1404 int gid;
1405};
6a6a1e5f
KM
1406/* ARGSUSED */
1407chown(p, uap, retval)
5e00df3b 1408 struct proc *p;
9e97623a 1409 register struct chown_args *uap;
6a6a1e5f
KM
1410 int *retval;
1411{
fc2aed1e
KM
1412 register struct vnode *vp;
1413 struct vattr vattr;
1414 int error;
8429d022 1415 struct nameidata nd;
d67a03eb 1416
7121fdf0 1417 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, p);
dd4c01c2 1418 if (error = namei(&nd))
8429d022 1419 return (error);
dd4c01c2 1420 vp = nd.ni_vp;
dbcf7de6
KM
1421 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
1422 VOP_LOCK(vp);
7121fdf0 1423 if (vp->v_mount->mnt_flag & MNT_RDONLY)
fc2aed1e 1424 error = EROFS;
7121fdf0
KB
1425 else {
1426 VATTR_NULL(&vattr);
1427 vattr.va_uid = uap->uid;
1428 vattr.va_gid = uap->gid;
1429 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
fc2aed1e 1430 }
fc2aed1e 1431 vput(vp);
8429d022 1432 return (error);
528f664c 1433}
f94ceb3b 1434
4f083fd7
SL
1435/*
1436 * Set ownership given a file descriptor.
1437 */
9e97623a
CT
1438struct fchown_args {
1439 int fd;
1440 int uid;
1441 int gid;
1442};
6a6a1e5f
KM
1443/* ARGSUSED */
1444fchown(p, uap, retval)
5e00df3b 1445 struct proc *p;
9e97623a 1446 register struct fchown_args *uap;
6a6a1e5f
KM
1447 int *retval;
1448{
fc2aed1e
KM
1449 struct vattr vattr;
1450 struct vnode *vp;
1451 struct file *fp;
1452 int error;
1453
5e00df3b 1454 if (error = getvnode(p->p_fd, uap->fd, &fp))
8429d022 1455 return (error);
fc2aed1e 1456 vp = (struct vnode *)fp->f_data;
dbcf7de6 1457 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
fc2aed1e 1458 VOP_LOCK(vp);
7121fdf0 1459 if (vp->v_mount->mnt_flag & MNT_RDONLY)
fc2aed1e 1460 error = EROFS;
7121fdf0
KB
1461 else {
1462 VATTR_NULL(&vattr);
1463 vattr.va_uid = uap->uid;
1464 vattr.va_gid = uap->gid;
1465 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
fc2aed1e 1466 }
fc2aed1e 1467 VOP_UNLOCK(vp);
8429d022 1468 return (error);
d67a03eb
BJ
1469}
1470
6a6a1e5f
KM
1471/*
1472 * Set the access and modification times of a file.
1473 */
9e97623a 1474struct utimes_args {
7121fdf0 1475 char *path;
9e97623a
CT
1476 struct timeval *tptr;
1477};
6a6a1e5f
KM
1478/* ARGSUSED */
1479utimes(p, uap, retval)
5e00df3b 1480 struct proc *p;
9e97623a 1481 register struct utimes_args *uap;
6a6a1e5f
KM
1482 int *retval;
1483{
fc2aed1e 1484 register struct vnode *vp;
bb1b75f4 1485 struct timeval tv[2];
fc2aed1e 1486 struct vattr vattr;
8e88b0cd 1487 int error;
8429d022 1488 struct nameidata nd;
bb1b75f4 1489
f8ee9a49
KB
1490 VATTR_NULL(&vattr);
1491 if (uap->tptr == NULL) {
1492 microtime(&tv[0]);
1493 tv[1] = tv[0];
fcba749b 1494 vattr.va_vaflags |= VA_UTIMES_NULL;
f8ee9a49
KB
1495 } else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
1496 return (error);
7121fdf0 1497 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
dd4c01c2 1498 if (error = namei(&nd))
8429d022 1499 return (error);
dd4c01c2 1500 vp = nd.ni_vp;
dbcf7de6
KM
1501 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
1502 VOP_LOCK(vp);
7121fdf0 1503 if (vp->v_mount->mnt_flag & MNT_RDONLY)
fc2aed1e 1504 error = EROFS;
7121fdf0
KB
1505 else {
1506 vattr.va_atime.ts_sec = tv[0].tv_sec;
1507 vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
1508 vattr.va_mtime.ts_sec = tv[1].tv_sec;
1509 vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
1510 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
bb1b75f4 1511 }
fc2aed1e 1512 vput(vp);
8429d022 1513 return (error);
d67a03eb 1514}
64d3a787 1515
7121fdf0
KB
1516/*
1517 * Truncate a file given its path name.
1518 */
95c0eb1e 1519struct truncate_args {
7121fdf0 1520 char *path;
2f2b3b3d
CT
1521 int pad;
1522 off_t length;
1523};
be320a2b 1524/* ARGSUSED */
201e5411 1525truncate(p, uap, retval)
5e00df3b 1526 struct proc *p;
95c0eb1e 1527 register struct truncate_args *uap;
6a6a1e5f
KM
1528 int *retval;
1529{
fc2aed1e
KM
1530 register struct vnode *vp;
1531 struct vattr vattr;
1532 int error;
8429d022 1533 struct nameidata nd;
528f664c 1534
7121fdf0 1535 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
dd4c01c2 1536 if (error = namei(&nd))
8429d022 1537 return (error);
dd4c01c2 1538 vp = nd.ni_vp;
dbcf7de6
KM
1539 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
1540 VOP_LOCK(vp);
7121fdf0 1541 if (vp->v_type == VDIR)
fc2aed1e 1542 error = EISDIR;
7121fdf0
KB
1543 else if ((error = vn_writechk(vp)) == 0 &&
1544 (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
1545 VATTR_NULL(&vattr);
1546 vattr.va_size = uap->length;
1547 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
528f664c 1548 }
fc2aed1e 1549 vput(vp);
8429d022 1550 return (error);
528f664c
SL
1551}
1552
7121fdf0
KB
1553/*
1554 * Truncate a file given a file descriptor.
1555 */
95c0eb1e 1556struct ftruncate_args {
2f2b3b3d
CT
1557 int fd;
1558 int pad;
1559 off_t length;
1560};
6a6a1e5f 1561/* ARGSUSED */
201e5411 1562ftruncate(p, uap, retval)
5e00df3b 1563 struct proc *p;
95c0eb1e 1564 register struct ftruncate_args *uap;
6a6a1e5f
KM
1565 int *retval;
1566{
fc2aed1e
KM
1567 struct vattr vattr;
1568 struct vnode *vp;
528f664c 1569 struct file *fp;
fc2aed1e
KM
1570 int error;
1571
5e00df3b 1572 if (error = getvnode(p->p_fd, uap->fd, &fp))
8429d022 1573 return (error);
fc2aed1e 1574 if ((fp->f_flag & FWRITE) == 0)
8429d022 1575 return (EINVAL);
fc2aed1e 1576 vp = (struct vnode *)fp->f_data;
dbcf7de6 1577 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
fc2aed1e 1578 VOP_LOCK(vp);
7121fdf0 1579 if (vp->v_type == VDIR)
fc2aed1e 1580 error = EISDIR;
7121fdf0
KB
1581 else if ((error = vn_writechk(vp)) == 0) {
1582 VATTR_NULL(&vattr);
1583 vattr.va_size = uap->length;
1584 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
528f664c 1585 }
fc2aed1e 1586 VOP_UNLOCK(vp);
8429d022 1587 return (error);
4f083fd7
SL
1588}
1589
2f2b3b3d
CT
1590#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1591/*
1592 * Truncate a file given its path name.
1593 */
95c0eb1e 1594struct otruncate_args {
7121fdf0 1595 char *path;
9e97623a
CT
1596 long length;
1597};
2f2b3b3d 1598/* ARGSUSED */
51a9a1cf 1599otruncate(p, uap, retval)
2f2b3b3d 1600 struct proc *p;
95c0eb1e 1601 register struct otruncate_args *uap;
2f2b3b3d
CT
1602 int *retval;
1603{
95c0eb1e 1604 struct truncate_args nuap;
2f2b3b3d 1605
7121fdf0 1606 nuap.path = uap->path;
2f2b3b3d 1607 nuap.length = uap->length;
95c0eb1e 1608 return (truncate(p, &nuap, retval));
2f2b3b3d
CT
1609}
1610
1611/*
1612 * Truncate a file given a file descriptor.
1613 */
95c0eb1e 1614struct oftruncate_args {
9e97623a
CT
1615 int fd;
1616 long length;
1617};
2f2b3b3d 1618/* ARGSUSED */
51a9a1cf 1619oftruncate(p, uap, retval)
2f2b3b3d 1620 struct proc *p;
95c0eb1e 1621 register struct oftruncate_args *uap;
2f2b3b3d
CT
1622 int *retval;
1623{
95c0eb1e 1624 struct ftruncate_args nuap;
2f2b3b3d
CT
1625
1626 nuap.fd = uap->fd;
1627 nuap.length = uap->length;
95c0eb1e 1628 return (ftruncate(p, &nuap, retval));
2f2b3b3d
CT
1629}
1630#endif /* COMPAT_43 || COMPAT_SUNOS */
1631
4f083fd7 1632/*
7121fdf0 1633 * Sync an open file.
4f083fd7 1634 */
9e97623a
CT
1635struct fsync_args {
1636 int fd;
1637};
6a6a1e5f
KM
1638/* ARGSUSED */
1639fsync(p, uap, retval)
5e00df3b 1640 struct proc *p;
9e97623a 1641 struct fsync_args *uap;
6a6a1e5f
KM
1642 int *retval;
1643{
e79467ea 1644 register struct vnode *vp;
4f083fd7 1645 struct file *fp;
fc2aed1e 1646 int error;
4f083fd7 1647
5e00df3b 1648 if (error = getvnode(p->p_fd, uap->fd, &fp))
8429d022 1649 return (error);
e79467ea
KM
1650 vp = (struct vnode *)fp->f_data;
1651 VOP_LOCK(vp);
09d2ef1a 1652 error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
e79467ea 1653 VOP_UNLOCK(vp);
8429d022 1654 return (error);
528f664c
SL
1655}
1656
4f083fd7 1657/*
7121fdf0
KB
1658 * Rename files. Source and destination must either both be directories,
1659 * or both not be directories. If target is a directory, it must be empty.
4f083fd7 1660 */
9e97623a
CT
1661struct rename_args {
1662 char *from;
1663 char *to;
1664};
6a6a1e5f
KM
1665/* ARGSUSED */
1666rename(p, uap, retval)
5e00df3b 1667 struct proc *p;
9e97623a 1668 register struct rename_args *uap;
6a6a1e5f
KM
1669 int *retval;
1670{
fc2aed1e 1671 register struct vnode *tvp, *fvp, *tdvp;
5718fad3 1672 struct nameidata fromnd, tond;
fc2aed1e 1673 int error;
4f083fd7 1674
a5368812 1675 CHECKPOINTREF;
dd4c01c2
KM
1676 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
1677 uap->from, p);
1678 if (error = namei(&fromnd))
8429d022 1679 return (error);
5718fad3 1680 fvp = fromnd.ni_vp;
dd4c01c2
KM
1681 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
1682 UIO_USERSPACE, uap->to, p);
1683 if (error = namei(&tond)) {
cfef4373 1684 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
5718fad3 1685 vrele(fromnd.ni_dvp);
66955caf
KM
1686 vrele(fvp);
1687 goto out1;
1688 }
fc2aed1e
KM
1689 tdvp = tond.ni_dvp;
1690 tvp = tond.ni_vp;
1691 if (tvp != NULL) {
1692 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
9259ee95 1693 error = ENOTDIR;
fc2aed1e
KM
1694 goto out;
1695 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
9259ee95 1696 error = EISDIR;
fc2aed1e 1697 goto out;
a5390dce 1698 }
64d3a787 1699 }
fe562f32 1700 if (fvp == tdvp)
fc2aed1e 1701 error = EINVAL;
fe562f32 1702 /*
5718fad3
KM
1703 * If source is the same as the destination (that is the
1704 * same inode number with the same name in the same directory),
fe562f32
KM
1705 * then there is nothing to do.
1706 */
5718fad3 1707 if (fvp == tvp && fromnd.ni_dvp == tdvp &&
dd4c01c2
KM
1708 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
1709 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
1710 fromnd.ni_cnd.cn_namelen))
fe562f32 1711 error = -1;
fc2aed1e 1712out:
66955caf 1713 if (!error) {
e62d4143
KM
1714 LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE);
1715 if (fromnd.ni_dvp != tdvp)
1716 LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1717 if (tvp)
1718 LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE);
cfef4373
JH
1719 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
1720 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
66955caf 1721 } else {
cfef4373 1722 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
6c44e83b
KM
1723 if (tdvp == tvp)
1724 vrele(tdvp);
1725 else
1726 vput(tdvp);
66955caf
KM
1727 if (tvp)
1728 vput(tvp);
cfef4373 1729 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
5718fad3 1730 vrele(fromnd.ni_dvp);
66955caf 1731 vrele(fvp);
64d3a787 1732 }
c03959f9 1733 p->p_spare[1]--;
5718fad3 1734 vrele(tond.ni_startdir);
dd4c01c2 1735 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
fc2aed1e 1736out1:
c03959f9 1737 p->p_spare[1]--;
5718fad3 1738 vrele(fromnd.ni_startdir);
dd4c01c2 1739 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
a5368812 1740 CHECKREFS("rename");
fe562f32 1741 if (error == -1)
8429d022
MK
1742 return (0);
1743 return (error);
64d3a787 1744}
88a7a62a 1745
88a7a62a 1746/*
7121fdf0 1747 * Make a directory file.
88a7a62a 1748 */
9e97623a 1749struct mkdir_args {
7121fdf0
KB
1750 char *path;
1751 int mode;
9e97623a 1752};
6a6a1e5f
KM
1753/* ARGSUSED */
1754mkdir(p, uap, retval)
5e00df3b 1755 struct proc *p;
9e97623a 1756 register struct mkdir_args *uap;
6a6a1e5f
KM
1757 int *retval;
1758{
fc2aed1e
KM
1759 register struct vnode *vp;
1760 struct vattr vattr;
1761 int error;
8429d022 1762 struct nameidata nd;
88a7a62a 1763
a5368812 1764 CHECKPOINTREF;
7121fdf0 1765 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
dd4c01c2 1766 if (error = namei(&nd))
8429d022 1767 return (error);
dd4c01c2 1768 vp = nd.ni_vp;
fc2aed1e 1769 if (vp != NULL) {
dd4c01c2
KM
1770 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1771 if (nd.ni_dvp == vp)
1772 vrele(nd.ni_dvp);
6c44e83b 1773 else
dd4c01c2 1774 vput(nd.ni_dvp);
66955caf 1775 vrele(vp);
a5368812 1776 CHECKREFS("mkdir1");
8429d022 1777 return (EEXIST);
88a7a62a 1778 }
3ee1461b 1779 VATTR_NULL(&vattr);
fc2aed1e 1780 vattr.va_type = VDIR;
7121fdf0 1781 vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask;
dd4c01c2
KM
1782 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1783 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
5dfd04f0 1784 if (!error)
dd4c01c2 1785 vput(nd.ni_vp);
a5368812 1786 CHECKREFS("mkdir2");
8429d022 1787 return (error);
88a7a62a
SL
1788}
1789
1790/*
7121fdf0 1791 * Remove a directory file.
88a7a62a 1792 */
9e97623a 1793struct rmdir_args {
7121fdf0 1794 char *path;
9e97623a 1795};
6a6a1e5f
KM
1796/* ARGSUSED */
1797rmdir(p, uap, retval)
5e00df3b 1798 struct proc *p;
9e97623a 1799 struct rmdir_args *uap;
6a6a1e5f
KM
1800 int *retval;
1801{
fc2aed1e
KM
1802 register struct vnode *vp;
1803 int error;
8429d022 1804 struct nameidata nd;
88a7a62a 1805
a5368812 1806 CHECKPOINTREF;
7121fdf0 1807 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p);
dd4c01c2 1808 if (error = namei(&nd))
8429d022 1809 return (error);
dd4c01c2 1810 vp = nd.ni_vp;
fc2aed1e
KM
1811 if (vp->v_type != VDIR) {
1812 error = ENOTDIR;
88a7a62a
SL
1813 goto out;
1814 }
1815 /*
fc2aed1e 1816 * No rmdir "." please.
88a7a62a 1817 */
dd4c01c2 1818 if (nd.ni_dvp == vp) {
fc2aed1e 1819 error = EINVAL;
88a7a62a
SL
1820 goto out;
1821 }
1822 /*
d4ed1dcd 1823 * The root of a mounted filesystem cannot be deleted.
88a7a62a 1824 */
fc2aed1e
KM
1825 if (vp->v_flag & VROOT)
1826 error = EBUSY;
88a7a62a 1827out:
66955caf 1828 if (!error) {
dd4c01c2 1829 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
e62d4143 1830 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
dd4c01c2 1831 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
66955caf 1832 } else {
dd4c01c2
KM
1833 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1834 if (nd.ni_dvp == vp)
1835 vrele(nd.ni_dvp);
6c44e83b 1836 else
dd4c01c2 1837 vput(nd.ni_dvp);
66955caf
KM
1838 vput(vp);
1839 }
a5368812 1840 CHECKREFS("rmdir");
8429d022 1841 return (error);
88a7a62a
SL
1842}
1843
3d92fa10
KM
1844#ifdef COMPAT_43
1845/*
1846 * Read a block of directory entries in a file system independent format.
1847 */
9e97623a
CT
1848struct ogetdirentries_args {
1849 int fd;
1850 char *buf;
7121fdf0 1851 u_int count;
9e97623a
CT
1852 long *basep;
1853};
3d92fa10
KM
1854ogetdirentries(p, uap, retval)
1855 struct proc *p;
9e97623a 1856 register struct ogetdirentries_args *uap;
3d92fa10
KM
1857 int *retval;
1858{
3d92fa10
KM
1859 register struct vnode *vp;
1860 struct file *fp;
1861 struct uio auio, kuio;
1862 struct iovec aiov, kiov;
1863 struct dirent *dp, *edp;
1864 caddr_t dirbuf;
1865 int error, readcnt;
d80c3f56 1866 long loff;
3d92fa10
KM
1867
1868 if (error = getvnode(p->p_fd, uap->fd, &fp))
1869 return (error);
1870 if ((fp->f_flag & FREAD) == 0)
1871 return (EBADF);
1872 vp = (struct vnode *)fp->f_data;
1873 if (vp->v_type != VDIR)
1874 return (EINVAL);
1875 aiov.iov_base = uap->buf;
1876 aiov.iov_len = uap->count;
1877 auio.uio_iov = &aiov;
1878 auio.uio_iovcnt = 1;
1879 auio.uio_rw = UIO_READ;
1880 auio.uio_segflg = UIO_USERSPACE;
1881 auio.uio_procp = p;
1882 auio.uio_resid = uap->count;
1883 VOP_LOCK(vp);
d80c3f56 1884 loff = auio.uio_offset = fp->f_offset;
3d92fa10 1885# if (BYTE_ORDER != LITTLE_ENDIAN)
a801b5ab 1886 if (vp->v_mount->mnt_maxsymlinklen <= 0) {
3d92fa10 1887 error = VOP_READDIR(vp, &auio, fp->f_cred);
a801b5ab
KM
1888 fp->f_offset = auio.uio_offset;
1889 } else
3d92fa10
KM
1890# endif
1891 {
1892 kuio = auio;
1893 kuio.uio_iov = &kiov;
1894 kuio.uio_segflg = UIO_SYSSPACE;
1895 kiov.iov_len = uap->count;
1896 MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK);
1897 kiov.iov_base = dirbuf;
1898 error = VOP_READDIR(vp, &kuio, fp->f_cred);
a801b5ab 1899 fp->f_offset = kuio.uio_offset;
3d92fa10
KM
1900 if (error == 0) {
1901 readcnt = uap->count - kuio.uio_resid;
1902 edp = (struct dirent *)&dirbuf[readcnt];
1903 for (dp = (struct dirent *)dirbuf; dp < edp; ) {
3d92fa10 1904# if (BYTE_ORDER == LITTLE_ENDIAN)
d80c3f56 1905 /*
30445fe6
KM
1906 * The expected low byte of
1907 * dp->d_namlen is our dp->d_type.
1908 * The high MBZ byte of dp->d_namlen
1909 * is our dp->d_namlen.
d80c3f56 1910 */
30445fe6
KM
1911 dp->d_type = dp->d_namlen;
1912 dp->d_namlen = 0;
1913# else
1914 /*
1915 * The dp->d_type is the high byte
1916 * of the expected dp->d_namlen,
1917 * so must be zero'ed.
1918 */
1919 dp->d_type = 0;
3d92fa10
KM
1920# endif
1921 if (dp->d_reclen > 0) {
1922 dp = (struct dirent *)
1923 ((char *)dp + dp->d_reclen);
1924 } else {
1925 error = EIO;
1926 break;
1927 }
1928 }
1929 if (dp >= edp)
1930 error = uiomove(dirbuf, readcnt, &auio);
1931 }
1932 FREE(dirbuf, M_TEMP);
1933 }
3d92fa10
KM
1934 VOP_UNLOCK(vp);
1935 if (error)
1936 return (error);
d80c3f56 1937 error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
3d92fa10
KM
1938 *retval = uap->count - auio.uio_resid;
1939 return (error);
1940}
1941#endif
1942
fc2aed1e 1943/*
d4ed1dcd 1944 * Read a block of directory entries in a file system independent format.
fc2aed1e 1945 */
9e97623a
CT
1946struct getdirentries_args {
1947 int fd;
1948 char *buf;
7121fdf0 1949 u_int count;
9e97623a
CT
1950 long *basep;
1951};
6a6a1e5f 1952getdirentries(p, uap, retval)
5e00df3b 1953 struct proc *p;
9e97623a 1954 register struct getdirentries_args *uap;
6a6a1e5f
KM
1955 int *retval;
1956{
e79467ea 1957 register struct vnode *vp;
8462a185 1958 struct file *fp;
fc2aed1e
KM
1959 struct uio auio;
1960 struct iovec aiov;
d80c3f56 1961 long loff;
09d2ef1a 1962 int error;
fc2aed1e 1963
5e00df3b 1964 if (error = getvnode(p->p_fd, uap->fd, &fp))
8429d022 1965 return (error);
fc2aed1e 1966 if ((fp->f_flag & FREAD) == 0)
8429d022 1967 return (EBADF);
e79467ea 1968 vp = (struct vnode *)fp->f_data;
95a9cadb 1969unionread:
e79467ea 1970 if (vp->v_type != VDIR)
8429d022 1971 return (EINVAL);
fc2aed1e
KM
1972 aiov.iov_base = uap->buf;
1973 aiov.iov_len = uap->count;
1974 auio.uio_iov = &aiov;
1975 auio.uio_iovcnt = 1;
1976 auio.uio_rw = UIO_READ;
1977 auio.uio_segflg = UIO_USERSPACE;
2c69fe14 1978 auio.uio_procp = p;
fc2aed1e 1979 auio.uio_resid = uap->count;
e79467ea 1980 VOP_LOCK(vp);
d80c3f56 1981 loff = auio.uio_offset = fp->f_offset;
09d2ef1a 1982 error = VOP_READDIR(vp, &auio, fp->f_cred);
e79467ea
KM
1983 fp->f_offset = auio.uio_offset;
1984 VOP_UNLOCK(vp);
1985 if (error)
8429d022 1986 return (error);
57b06c10
JSP
1987
1988#ifdef UNION
1989{
1990 extern int (**union_vnodeop_p)();
1991 extern struct vnode *union_lowervp __P((struct vnode *));
1992
1993 if ((uap->count == auio.uio_resid) &&
1994 (vp->v_op == union_vnodeop_p)) {
1995 struct vnode *tvp = vp;
1996
1997 vp = union_lowervp(vp);
1998 if (vp != NULLVP) {
1999 VOP_LOCK(vp);
2000 error = VOP_OPEN(vp, FREAD);
2001 VOP_UNLOCK(vp);
2002
2003 if (error) {
2004 vrele(vp);
2005 return (error);
2006 }
2007 fp->f_data = (caddr_t) vp;
2008 fp->f_offset = 0;
2009 error = vn_close(tvp, FREAD, fp->f_cred, p);
2010 if (error)
2011 return (error);
2012 goto unionread;
2013 }
2014 }
2015}
2016#endif
2017
95a9cadb
JSP
2018 if ((uap->count == auio.uio_resid) &&
2019 (vp->v_flag & VROOT) &&
2020 (vp->v_mount->mnt_flag & MNT_UNION)) {
2021 struct vnode *tvp = vp;
2022 vp = vp->v_mount->mnt_vnodecovered;
2023 VREF(vp);
2024 fp->f_data = (caddr_t) vp;
2025 fp->f_offset = 0;
2026 vrele(tvp);
2027 goto unionread;
2028 }
d80c3f56 2029 error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
6a6a1e5f 2030 *retval = uap->count - auio.uio_resid;
8429d022 2031 return (error);
88a7a62a
SL
2032}
2033
2034/*
d4ed1dcd 2035 * Set the mode mask for creation of filesystem nodes.
88a7a62a 2036 */
9e97623a 2037struct umask_args {
7121fdf0 2038 int newmask;
9e97623a
CT
2039};
2040mode_t /* XXX */
6a6a1e5f 2041umask(p, uap, retval)
5e00df3b 2042 struct proc *p;
9e97623a 2043 struct umask_args *uap;
6a6a1e5f
KM
2044 int *retval;
2045{
7121fdf0 2046 register struct filedesc *fdp;
88a7a62a 2047
7121fdf0 2048 fdp = p->p_fd;
5e00df3b 2049 *retval = fdp->fd_cmask;
7121fdf0 2050 fdp->fd_cmask = uap->newmask & ALLPERMS;
8429d022 2051 return (0);
fc2aed1e
KM
2052}
2053
b0a98f13
MT
2054/*
2055 * Void all references to file by ripping underlying filesystem
2056 * away from vnode.
2057 */
9e97623a 2058struct revoke_args {
7121fdf0 2059 char *path;
9e97623a 2060};
6a6a1e5f
KM
2061/* ARGSUSED */
2062revoke(p, uap, retval)
5e00df3b 2063 struct proc *p;
9e97623a 2064 register struct revoke_args *uap;
6a6a1e5f
KM
2065 int *retval;
2066{
b0a98f13
MT
2067 register struct vnode *vp;
2068 struct vattr vattr;
2069 int error;
8429d022 2070 struct nameidata nd;
b0a98f13 2071
7121fdf0 2072 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
dd4c01c2 2073 if (error = namei(&nd))
8429d022 2074 return (error);
dd4c01c2 2075 vp = nd.ni_vp;
b0a98f13
MT
2076 if (vp->v_type != VCHR && vp->v_type != VBLK) {
2077 error = EINVAL;
2078 goto out;
2079 }
2c69fe14 2080 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
b0a98f13 2081 goto out;
8429d022
MK
2082 if (p->p_ucred->cr_uid != vattr.va_uid &&
2083 (error = suser(p->p_ucred, &p->p_acflag)))
b0a98f13 2084 goto out;
8b81d198 2085 if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
c9345cca 2086 vgoneall(vp);
b0a98f13
MT
2087out:
2088 vrele(vp);
8429d022 2089 return (error);
b0a98f13
MT
2090}
2091
d4ed1dcd
KM
2092/*
2093 * Convert a user file descriptor to a kernel file entry.
2094 */
7121fdf0 2095getvnode(fdp, fd, fpp)
5e00df3b 2096 struct filedesc *fdp;
fc2aed1e 2097 struct file **fpp;
7121fdf0 2098 int fd;
fc2aed1e
KM
2099{
2100 struct file *fp;
2101
7121fdf0
KB
2102 if ((u_int)fd >= fdp->fd_nfiles ||
2103 (fp = fdp->fd_ofiles[fd]) == NULL)
fc2aed1e
KM
2104 return (EBADF);
2105 if (fp->f_type != DTYPE_VNODE)
2106 return (EINVAL);
2107 *fpp = fp;
2108 return (0);
88a7a62a 2109}