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