update contrib line
[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 *
ac85da8a 7 * @(#)vfs_syscalls.c 8.5 (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;
6aaf085a
KM
598 if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
599 VOP_UNLOCK(vp);
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 }
b40ecf6f 605 fp->f_flag |= FHASLOCK;
ff8d1617 606 }
6aaf085a 607 VOP_UNLOCK(vp);
6a6a1e5f 608 *retval = indx;
8429d022 609 return (0);
3e78e260
BJ
610}
611
4fde03dc 612#ifdef COMPAT_43
3e78e260 613/*
7121fdf0 614 * Create a file.
3e78e260 615 */
9e97623a 616struct ocreat_args {
7121fdf0
KB
617 char *path;
618 int mode;
9e97623a 619};
4fde03dc 620ocreat(p, uap, retval)
6a6a1e5f 621 struct proc *p;
9e97623a 622 register struct ocreat_args *uap;
6a6a1e5f 623 int *retval;
3e78e260 624{
9e97623a 625 struct open_args openuap;
6a6a1e5f 626
7121fdf0
KB
627 openuap.path = uap->path;
628 openuap.mode = uap->mode;
629 openuap.flags = O_WRONLY | O_CREAT | O_TRUNC;
8429d022 630 return (open(p, &openuap, retval));
6a6a1e5f 631}
4fde03dc 632#endif /* COMPAT_43 */
6a6a1e5f
KM
633
634/*
7121fdf0 635 * Create a special file.
6a6a1e5f 636 */
9e97623a 637struct mknod_args {
7121fdf0
KB
638 char *path;
639 int mode;
9e97623a
CT
640 int dev;
641};
6a6a1e5f
KM
642/* ARGSUSED */
643mknod(p, uap, retval)
5e00df3b 644 struct proc *p;
9e97623a 645 register struct mknod_args *uap;
6a6a1e5f
KM
646 int *retval;
647{
fc2aed1e
KM
648 register struct vnode *vp;
649 struct vattr vattr;
650 int error;
8429d022 651 struct nameidata nd;
3e78e260 652
a5368812 653 CHECKPOINTREF;
8429d022
MK
654 if (error = suser(p->p_ucred, &p->p_acflag))
655 return (error);
7121fdf0 656 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
dd4c01c2 657 if (error = namei(&nd))
8429d022 658 return (error);
dd4c01c2 659 vp = nd.ni_vp;
cf5ef508 660 if (vp != NULL)
fc2aed1e 661 error = EEXIST;
cf5ef508
KB
662 else {
663 VATTR_NULL(&vattr);
664 vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
665 vattr.va_rdev = uap->dev;
666
667 switch (uap->mode & S_IFMT) {
668 case S_IFMT: /* used by badsect to flag bad sectors */
669 vattr.va_type = VBAD;
670 break;
671 case S_IFCHR:
672 vattr.va_type = VCHR;
673 break;
674 case S_IFBLK:
675 vattr.va_type = VBLK;
676 break;
677 default:
678 error = EINVAL;
679 break;
680 }
3e78e260 681 }
66955caf 682 if (!error) {
dd4c01c2
KM
683 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
684 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
66955caf 685 } else {
dd4c01c2
KM
686 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
687 if (nd.ni_dvp == vp)
688 vrele(nd.ni_dvp);
6c44e83b 689 else
dd4c01c2 690 vput(nd.ni_dvp);
66955caf
KM
691 if (vp)
692 vrele(vp);
693 }
a5368812 694 CHECKREFS("mknod");
8429d022 695 return (error);
3e78e260
BJ
696}
697
4751dd21 698/*
7121fdf0 699 * Create named pipe.
4751dd21 700 */
9e97623a 701struct mkfifo_args {
7121fdf0
KB
702 char *path;
703 int mode;
9e97623a 704};
6a6a1e5f
KM
705/* ARGSUSED */
706mkfifo(p, uap, retval)
5e00df3b 707 struct proc *p;
9e97623a 708 register struct mkfifo_args *uap;
6a6a1e5f
KM
709 int *retval;
710{
4751dd21
KM
711 struct vattr vattr;
712 int error;
8429d022 713 struct nameidata nd;
4751dd21
KM
714
715#ifndef FIFO
8429d022 716 return (EOPNOTSUPP);
4751dd21 717#else
7121fdf0 718 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
dd4c01c2 719 if (error = namei(&nd))
8429d022 720 return (error);
dd4c01c2
KM
721 if (nd.ni_vp != NULL) {
722 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
723 if (nd.ni_dvp == nd.ni_vp)
724 vrele(nd.ni_dvp);
6c44e83b 725 else
dd4c01c2
KM
726 vput(nd.ni_dvp);
727 vrele(nd.ni_vp);
8429d022 728 return (EEXIST);
4751dd21 729 }
3658f091
KB
730 VATTR_NULL(&vattr);
731 vattr.va_type = VFIFO;
7121fdf0 732 vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
dd4c01c2
KM
733 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
734 return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
4751dd21
KM
735#endif /* FIFO */
736}
737
3e78e260 738/*
7121fdf0 739 * Make a hard file link.
3e78e260 740 */
9e97623a 741struct link_args {
7121fdf0
KB
742 char *path;
743 char *link;
9e97623a 744};
6a6a1e5f
KM
745/* ARGSUSED */
746link(p, uap, retval)
5e00df3b 747 struct proc *p;
9e97623a 748 register struct link_args *uap;
6a6a1e5f
KM
749 int *retval;
750{
7121fdf0 751 register struct vnode *vp;
8429d022 752 struct nameidata nd;
7121fdf0 753 int error;
3e78e260 754
a5368812 755 CHECKPOINTREF;
7121fdf0 756 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
dd4c01c2 757 if (error = namei(&nd))
8429d022 758 return (error);
dd4c01c2 759 vp = nd.ni_vp;
cf5ef508
KB
760 if (vp->v_type != VDIR ||
761 (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
762 nd.ni_cnd.cn_nameiop = CREATE;
763 nd.ni_cnd.cn_flags = LOCKPARENT;
764 nd.ni_dirp = uap->link;
765 if ((error = namei(&nd)) == 0) {
766 if (nd.ni_vp != NULL)
767 error = EEXIST;
768 if (!error) {
769 LEASE_CHECK(nd.ni_dvp,
770 p, p->p_ucred, LEASE_WRITE);
771 LEASE_CHECK(vp,
772 p, p->p_ucred, LEASE_WRITE);
773 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
774 } else {
775 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
776 if (nd.ni_dvp == nd.ni_vp)
777 vrele(nd.ni_dvp);
778 else
779 vput(nd.ni_dvp);
780 if (nd.ni_vp)
781 vrele(nd.ni_vp);
782 }
783 }
66955caf 784 }
cf5ef508 785 vrele(vp);
a5368812 786 CHECKREFS("link");
8429d022 787 return (error);
3e78e260
BJ
788}
789
790/*
d4ed1dcd 791 * Make a symbolic link.
3e78e260 792 */
9e97623a 793struct symlink_args {
7121fdf0
KB
794 char *path;
795 char *link;
9e97623a 796};
6a6a1e5f
KM
797/* ARGSUSED */
798symlink(p, uap, retval)
5e00df3b 799 struct proc *p;
9e97623a 800 register struct symlink_args *uap;
6a6a1e5f
KM
801 int *retval;
802{
fc2aed1e 803 struct vattr vattr;
7121fdf0 804 char *path;
fc2aed1e 805 int error;
8429d022 806 struct nameidata nd;
3e78e260 807
a5368812 808 CHECKPOINTREF;
7121fdf0
KB
809 MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
810 if (error = copyinstr(uap->path, path, MAXPATHLEN, NULL))
66955caf 811 goto out;
7121fdf0 812 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p);
dd4c01c2 813 if (error = namei(&nd))
66955caf 814 goto out;
dd4c01c2
KM
815 if (nd.ni_vp) {
816 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
817 if (nd.ni_dvp == nd.ni_vp)
818 vrele(nd.ni_dvp);
6c44e83b 819 else
dd4c01c2
KM
820 vput(nd.ni_dvp);
821 vrele(nd.ni_vp);
fc2aed1e
KM
822 error = EEXIST;
823 goto out;
3e78e260 824 }
3ee1461b 825 VATTR_NULL(&vattr);
7121fdf0 826 vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
dd4c01c2 827 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
7121fdf0 828 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
fc2aed1e 829out:
7121fdf0 830 FREE(path, M_NAMEI);
a5368812 831 CHECKREFS("symlink");
8429d022 832 return (error);
3e78e260
BJ
833}
834
835/*
d4ed1dcd 836 * Delete a name from the filesystem.
3e78e260 837 */
9e97623a 838struct unlink_args {
7121fdf0 839 char *path;
9e97623a 840};
6a6a1e5f
KM
841/* ARGSUSED */
842unlink(p, uap, retval)
5e00df3b 843 struct proc *p;
9e97623a 844 struct unlink_args *uap;
6a6a1e5f
KM
845 int *retval;
846{
fc2aed1e
KM
847 register struct vnode *vp;
848 int error;
8429d022 849 struct nameidata nd;
3e78e260 850
a5368812 851 CHECKPOINTREF;
7121fdf0 852 NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
dd4c01c2 853 if (error = namei(&nd))
8429d022 854 return (error);
dd4c01c2 855 vp = nd.ni_vp;
dbcf7de6
KM
856 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
857 VOP_LOCK(vp);
7121fdf0 858
cf5ef508
KB
859 if (vp->v_type != VDIR ||
860 (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
861 /*
862 * The root of a mounted filesystem cannot be deleted.
863 */
864 if (vp->v_flag & VROOT)
865 error = EBUSY;
866 else
867 (void)vnode_pager_uncache(vp);
868 }
869
870 if (!error) {
dd4c01c2 871 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
dd4c01c2 872 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
66955caf 873 } else {
dd4c01c2
KM
874 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
875 if (nd.ni_dvp == vp)
876 vrele(nd.ni_dvp);
6c44e83b 877 else
dd4c01c2 878 vput(nd.ni_dvp);
66955caf
KM
879 vput(vp);
880 }
a5368812 881 CHECKREFS("unlink");
8429d022 882 return (error);
3e78e260
BJ
883}
884
7121fdf0
KB
885/*
886 * Reposition read/write file offset.
887 */
95c0eb1e 888struct lseek_args {
7121fdf0 889 int fd;
2f2b3b3d 890 int pad;
7121fdf0
KB
891 off_t offset;
892 int whence;
2f2b3b3d 893};
201e5411 894lseek(p, uap, retval)
5e00df3b 895 struct proc *p;
95c0eb1e 896 register struct lseek_args *uap;
9e97623a 897 int *retval;
6a6a1e5f 898{
8429d022 899 struct ucred *cred = p->p_ucred;
5e00df3b 900 register struct filedesc *fdp = p->p_fd;
6a6a1e5f 901 register struct file *fp;
fc2aed1e
KM
902 struct vattr vattr;
903 int error;
904
7121fdf0
KB
905 if ((u_int)uap->fd >= fdp->fd_nfiles ||
906 (fp = fdp->fd_ofiles[uap->fd]) == NULL)
8429d022 907 return (EBADF);
fc2aed1e 908 if (fp->f_type != DTYPE_VNODE)
8429d022 909 return (ESPIPE);
7121fdf0 910 switch (uap->whence) {
b4d1aee9 911 case L_INCR:
7121fdf0 912 fp->f_offset += uap->offset;
b4d1aee9 913 break;
b4d1aee9 914 case L_XTND:
7121fdf0
KB
915 if (error =
916 VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p))
8429d022 917 return (error);
7121fdf0 918 fp->f_offset = uap->offset + vattr.va_size;
b4d1aee9 919 break;
b4d1aee9 920 case L_SET:
7121fdf0 921 fp->f_offset = uap->offset;
b4d1aee9 922 break;
b4d1aee9 923 default:
8429d022 924 return (EINVAL);
b4d1aee9 925 }
9e97623a 926 *(off_t *)retval = fp->f_offset;
8429d022 927 return (0);
3e78e260
BJ
928}
929
201e5411 930#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
64deb204 931/*
7121fdf0 932 * Reposition read/write file offset.
64deb204 933 */
95c0eb1e 934struct olseek_args {
7121fdf0
KB
935 int fd;
936 long offset;
937 int whence;
64deb204 938};
201e5411 939olseek(p, uap, retval)
64deb204 940 struct proc *p;
95c0eb1e 941 register struct olseek_args *uap;
64deb204
KM
942 int *retval;
943{
95c0eb1e 944 struct lseek_args nuap;
64deb204
KM
945 off_t qret;
946 int error;
947
7121fdf0
KB
948 nuap.fd = uap->fd;
949 nuap.offset = uap->offset;
950 nuap.whence = uap->whence;
95c0eb1e 951 error = lseek(p, &nuap, &qret);
64deb204
KM
952 *(long *)retval = qret;
953 return (error);
954}
201e5411 955#endif /* COMPAT_43 */
64deb204 956
3e78e260 957/*
d4ed1dcd 958 * Check access permissions.
3e78e260 959 */
b54e8954 960struct access_args {
7121fdf0
KB
961 char *path;
962 int flags;
9e97623a 963};
b54e8954 964access(p, uap, retval)
5e00df3b 965 struct proc *p;
b54e8954 966 register struct access_args *uap;
6a6a1e5f
KM
967 int *retval;
968{
8429d022 969 register struct ucred *cred = p->p_ucred;
fc2aed1e 970 register struct vnode *vp;
cf5ef508 971 int error, flags, t_gid, t_uid;
8429d022 972 struct nameidata nd;
3e78e260 973
cf5ef508
KB
974 t_uid = cred->cr_uid;
975 t_gid = cred->cr_groups[0];
8429d022
MK
976 cred->cr_uid = p->p_cred->p_ruid;
977 cred->cr_groups[0] = p->p_cred->p_rgid;
7121fdf0 978 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
dd4c01c2 979 if (error = namei(&nd))
fc2aed1e 980 goto out1;
dd4c01c2 981 vp = nd.ni_vp;
7121fdf0
KB
982
983 /* Flags == 0 means only check for existence. */
984 if (uap->flags) {
985 flags = 0;
986 if (uap->flags & R_OK)
987 flags |= VREAD;
988 if (uap->flags & W_OK)
989 flags |= VWRITE;
990 if (uap->flags & X_OK)
991 flags |= VEXEC;
992 if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
993 error = VOP_ACCESS(vp, flags, cred, p);
3e78e260 994 }
fc2aed1e
KM
995 vput(vp);
996out1:
cf5ef508
KB
997 cred->cr_uid = t_uid;
998 cred->cr_groups[0] = t_gid;
8429d022 999 return (error);
3e78e260 1000}
d67a03eb 1001
8932276d 1002#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
d67a03eb 1003/*
7121fdf0 1004 * Get file status; this version follows links.
d67a03eb 1005 */
9e97623a 1006struct ostat_args {
7121fdf0 1007 char *path;
9e97623a
CT
1008 struct ostat *ub;
1009};
6a6a1e5f 1010/* ARGSUSED */
ae9b6dc3 1011ostat(p, uap, retval)
be320a2b 1012 struct proc *p;
9e97623a 1013 register struct ostat_args *uap;
be320a2b
KM
1014 int *retval;
1015{
1016 struct stat sb;
1017 struct ostat osb;
1018 int error;
1019 struct nameidata nd;
1020
7121fdf0 1021 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
be320a2b
KM
1022 if (error = namei(&nd))
1023 return (error);
1024 error = vn_stat(nd.ni_vp, &sb, p);
1025 vput(nd.ni_vp);
1026 if (error)
1027 return (error);
1028 cvtstat(&sb, &osb);
1029 error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
1030 return (error);
1031}
1032
1033/*
7121fdf0 1034 * Get file status; this version does not follow links.
be320a2b 1035 */
9e97623a 1036struct olstat_args {
7121fdf0 1037 char *path;
9e97623a
CT
1038 struct ostat *ub;
1039};
be320a2b 1040/* ARGSUSED */
ae9b6dc3 1041olstat(p, uap, retval)
be320a2b 1042 struct proc *p;
9e97623a 1043 register struct olstat_args *uap;
be320a2b
KM
1044 int *retval;
1045{
1046 struct stat sb;
1047 struct ostat osb;
1048 int error;
1049 struct nameidata nd;
1050
7121fdf0 1051 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
be320a2b
KM
1052 if (error = namei(&nd))
1053 return (error);
1054 error = vn_stat(nd.ni_vp, &sb, p);
1055 vput(nd.ni_vp);
1056 if (error)
1057 return (error);
1058 cvtstat(&sb, &osb);
1059 error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
1060 return (error);
1061}
1062
1063/*
7121fdf0 1064 * Convert from an old to a new stat structure.
be320a2b
KM
1065 */
1066cvtstat(st, ost)
1067 struct stat *st;
1068 struct ostat *ost;
1069{
1070
1071 ost->st_dev = st->st_dev;
1072 ost->st_ino = st->st_ino;
1073 ost->st_mode = st->st_mode;
1074 ost->st_nlink = st->st_nlink;
1075 ost->st_uid = st->st_uid;
1076 ost->st_gid = st->st_gid;
1077 ost->st_rdev = st->st_rdev;
1078 if (st->st_size < (quad_t)1 << 32)
1079 ost->st_size = st->st_size;
1080 else
1081 ost->st_size = -2;
1082 ost->st_atime = st->st_atime;
1083 ost->st_mtime = st->st_mtime;
1084 ost->st_ctime = st->st_ctime;
1085 ost->st_blksize = st->st_blksize;
1086 ost->st_blocks = st->st_blocks;
1087 ost->st_flags = st->st_flags;
1088 ost->st_gen = st->st_gen;
1089}
8932276d 1090#endif /* COMPAT_43 || COMPAT_SUNOS */
be320a2b
KM
1091
1092/*
7121fdf0 1093 * Get file status; this version follows links.
be320a2b 1094 */
9e97623a 1095struct stat_args {
7121fdf0 1096 char *path;
9e97623a
CT
1097 struct stat *ub;
1098};
be320a2b 1099/* ARGSUSED */
ae9b6dc3 1100stat(p, uap, retval)
5e00df3b 1101 struct proc *p;
9e97623a 1102 register struct stat_args *uap;
6a6a1e5f 1103 int *retval;
d67a03eb 1104{
6a6a1e5f
KM
1105 struct stat sb;
1106 int error;
8429d022 1107 struct nameidata nd;
d67a03eb 1108
7121fdf0 1109 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
dd4c01c2 1110 if (error = namei(&nd))
8429d022 1111 return (error);
dd4c01c2
KM
1112 error = vn_stat(nd.ni_vp, &sb, p);
1113 vput(nd.ni_vp);
6a6a1e5f 1114 if (error)
8429d022 1115 return (error);
6a6a1e5f 1116 error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
8429d022 1117 return (error);
d67a03eb
BJ
1118}
1119
5485e062 1120/*
7121fdf0 1121 * Get file status; this version does not follow links.
5485e062 1122 */
9e97623a 1123struct lstat_args {
7121fdf0 1124 char *path;
9e97623a
CT
1125 struct stat *ub;
1126};
6a6a1e5f 1127/* ARGSUSED */
ae9b6dc3 1128lstat(p, uap, retval)
5e00df3b 1129 struct proc *p;
9e97623a 1130 register struct lstat_args *uap;
6a6a1e5f
KM
1131 int *retval;
1132{
fc2aed1e 1133 int error;
49f762b8
KM
1134 struct vnode *vp, *dvp;
1135 struct stat sb, sb1;
8429d022 1136 struct nameidata nd;
5485e062 1137
49f762b8 1138 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
7121fdf0 1139 uap->path, p);
dd4c01c2 1140 if (error = namei(&nd))
8429d022 1141 return (error);
49f762b8
KM
1142 /*
1143 * For symbolic links, always return the attributes of its
1144 * containing directory, except for mode, size, and links.
1145 */
1146 vp = nd.ni_vp;
1147 dvp = nd.ni_dvp;
1148 if (vp->v_type != VLNK) {
1149 if (dvp == vp)
1150 vrele(dvp);
1151 else
1152 vput(dvp);
1153 error = vn_stat(vp, &sb, p);
1154 vput(vp);
1155 if (error)
1156 return (error);
1157 } else {
1158 error = vn_stat(dvp, &sb, p);
1159 vput(dvp);
1160 if (error) {
1161 vput(vp);
1162 return (error);
1163 }
1164 error = vn_stat(vp, &sb1, p);
1165 vput(vp);
1166 if (error)
1167 return (error);
1168 sb.st_mode &= ~S_IFDIR;
1169 sb.st_mode |= S_IFLNK;
1170 sb.st_nlink = sb1.st_nlink;
1171 sb.st_size = sb1.st_size;
1172 sb.st_blocks = sb1.st_blocks;
1173 }
fc2aed1e 1174 error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
8429d022 1175 return (error);
d67a03eb
BJ
1176}
1177
201e5411 1178/*
7121fdf0 1179 * Get configurable pathname variables.
201e5411
KM
1180 */
1181struct pathconf_args {
7121fdf0 1182 char *path;
201e5411
KM
1183 int name;
1184};
1185/* ARGSUSED */
1186pathconf(p, uap, retval)
1187 struct proc *p;
1188 register struct pathconf_args *uap;
1189 int *retval;
1190{
1191 int error;
1192 struct nameidata nd;
1193
7121fdf0 1194 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
201e5411
KM
1195 if (error = namei(&nd))
1196 return (error);
1197 error = VOP_PATHCONF(nd.ni_vp, uap->name, retval);
1198 vput(nd.ni_vp);
1199 return (error);
1200}
1201
d67a03eb 1202/*
d4ed1dcd 1203 * Return target name of a symbolic link.
5485e062 1204 */
9e97623a 1205struct readlink_args {
7121fdf0 1206 char *path;
9e97623a
CT
1207 char *buf;
1208 int count;
1209};
6a6a1e5f
KM
1210/* ARGSUSED */
1211readlink(p, uap, retval)
5e00df3b 1212 struct proc *p;
9e97623a 1213 register struct readlink_args *uap;
6a6a1e5f
KM
1214 int *retval;
1215{
fc2aed1e
KM
1216 register struct vnode *vp;
1217 struct iovec aiov;
1218 struct uio auio;
1219 int error;
8429d022 1220 struct nameidata nd;
5485e062 1221
a5368812 1222 CHECKPOINTREF;
7121fdf0 1223 NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
dd4c01c2 1224 if (error = namei(&nd))
8429d022 1225 return (error);
dd4c01c2 1226 vp = nd.ni_vp;
7121fdf0 1227 if (vp->v_type != VLNK)
fc2aed1e 1228 error = EINVAL;
7121fdf0
KB
1229 else {
1230 aiov.iov_base = uap->buf;
1231 aiov.iov_len = uap->count;
1232 auio.uio_iov = &aiov;
1233 auio.uio_iovcnt = 1;
1234 auio.uio_offset = 0;
1235 auio.uio_rw = UIO_READ;
1236 auio.uio_segflg = UIO_USERSPACE;
1237 auio.uio_procp = p;
1238 auio.uio_resid = uap->count;
1239 error = VOP_READLINK(vp, &auio, p->p_ucred);
5485e062 1240 }
fc2aed1e 1241 vput(vp);
6a6a1e5f 1242 *retval = uap->count - auio.uio_resid;
a5368812 1243 CHECKREFS("readlink");
8429d022 1244 return (error);
5485e062
BJ
1245}
1246
6995a2cb 1247/*
7121fdf0 1248 * Change flags of a file given a path name.
6995a2cb 1249 */
9e97623a 1250struct chflags_args {
7121fdf0 1251 char *path;
9e97623a
CT
1252 int flags;
1253};
6a6a1e5f
KM
1254/* ARGSUSED */
1255chflags(p, uap, retval)
5e00df3b 1256 struct proc *p;
9e97623a 1257 register struct chflags_args *uap;
6a6a1e5f
KM
1258 int *retval;
1259{
6995a2cb
KM
1260 register struct vnode *vp;
1261 struct vattr vattr;
1262 int error;
8429d022 1263 struct nameidata nd;
6995a2cb 1264
7121fdf0 1265 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
dd4c01c2 1266 if (error = namei(&nd))
8429d022 1267 return (error);
dd4c01c2 1268 vp = nd.ni_vp;
dbcf7de6
KM
1269 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
1270 VOP_LOCK(vp);
7121fdf0 1271 if (vp->v_mount->mnt_flag & MNT_RDONLY)
6995a2cb 1272 error = EROFS;
7121fdf0
KB
1273 else {
1274 VATTR_NULL(&vattr);
1275 vattr.va_flags = uap->flags;
1276 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
6995a2cb 1277 }
6995a2cb 1278 vput(vp);
8429d022 1279 return (error);
6995a2cb
KM
1280}
1281
1282/*
1283 * Change flags of a file given a file descriptor.
1284 */
9e97623a
CT
1285struct fchflags_args {
1286 int fd;
1287 int flags;
1288};
6a6a1e5f
KM
1289/* ARGSUSED */
1290fchflags(p, uap, retval)
5e00df3b 1291 struct proc *p;
9e97623a 1292 register struct fchflags_args *uap;
6a6a1e5f
KM
1293 int *retval;
1294{
6995a2cb
KM
1295 struct vattr vattr;
1296 struct vnode *vp;
1297 struct file *fp;
1298 int error;
1299
5e00df3b 1300 if (error = getvnode(p->p_fd, uap->fd, &fp))
8429d022 1301 return (error);
6995a2cb 1302 vp = (struct vnode *)fp->f_data;
dbcf7de6 1303 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
6995a2cb 1304 VOP_LOCK(vp);
7121fdf0 1305 if (vp->v_mount->mnt_flag & MNT_RDONLY)
6995a2cb 1306 error = EROFS;
7121fdf0
KB
1307 else {
1308 VATTR_NULL(&vattr);
1309 vattr.va_flags = uap->flags;
1310 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
6995a2cb 1311 }
6995a2cb 1312 VOP_UNLOCK(vp);
8429d022 1313 return (error);
6995a2cb
KM
1314}
1315
4f083fd7
SL
1316/*
1317 * Change mode of a file given path name.
1318 */
9e97623a 1319struct chmod_args {
7121fdf0
KB
1320 char *path;
1321 int mode;
9e97623a 1322};
6a6a1e5f
KM
1323/* ARGSUSED */
1324chmod(p, uap, retval)
5e00df3b 1325 struct proc *p;
9e97623a 1326 register struct chmod_args *uap;
6a6a1e5f
KM
1327 int *retval;
1328{
fc2aed1e
KM
1329 register struct vnode *vp;
1330 struct vattr vattr;
1331 int error;
8429d022 1332 struct nameidata nd;
5485e062 1333
7121fdf0 1334 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
dd4c01c2 1335 if (error = namei(&nd))
8429d022 1336 return (error);
dd4c01c2 1337 vp = nd.ni_vp;
dbcf7de6
KM
1338 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
1339 VOP_LOCK(vp);
7121fdf0 1340 if (vp->v_mount->mnt_flag & MNT_RDONLY)
fc2aed1e 1341 error = EROFS;
7121fdf0
KB
1342 else {
1343 VATTR_NULL(&vattr);
1344 vattr.va_mode = uap->mode & ALLPERMS;
1345 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
fc2aed1e 1346 }
fc2aed1e 1347 vput(vp);
8429d022 1348 return (error);
528f664c 1349}
f94ceb3b 1350
4f083fd7
SL
1351/*
1352 * Change mode of a file given a file descriptor.
1353 */
9e97623a
CT
1354struct fchmod_args {
1355 int fd;
7121fdf0 1356 int mode;
9e97623a 1357};
6a6a1e5f
KM
1358/* ARGSUSED */
1359fchmod(p, uap, retval)
5e00df3b 1360 struct proc *p;
9e97623a 1361 register struct fchmod_args *uap;
6a6a1e5f
KM
1362 int *retval;
1363{
fc2aed1e
KM
1364 struct vattr vattr;
1365 struct vnode *vp;
1366 struct file *fp;
1367 int error;
1368
5e00df3b 1369 if (error = getvnode(p->p_fd, uap->fd, &fp))
8429d022 1370 return (error);
fc2aed1e 1371 vp = (struct vnode *)fp->f_data;
dbcf7de6 1372 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
fc2aed1e 1373 VOP_LOCK(vp);
7121fdf0 1374 if (vp->v_mount->mnt_flag & MNT_RDONLY)
fc2aed1e 1375 error = EROFS;
7121fdf0
KB
1376 else {
1377 VATTR_NULL(&vattr);
1378 vattr.va_mode = uap->mode & ALLPERMS;
1379 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
f94ceb3b 1380 }
fc2aed1e 1381 VOP_UNLOCK(vp);
8429d022 1382 return (error);
5485e062
BJ
1383}
1384
4f083fd7
SL
1385/*
1386 * Set ownership given a path name.
1387 */
9e97623a 1388struct chown_args {
7121fdf0 1389 char *path;
9e97623a
CT
1390 int uid;
1391 int gid;
1392};
6a6a1e5f
KM
1393/* ARGSUSED */
1394chown(p, uap, retval)
5e00df3b 1395 struct proc *p;
9e97623a 1396 register struct chown_args *uap;
6a6a1e5f
KM
1397 int *retval;
1398{
fc2aed1e
KM
1399 register struct vnode *vp;
1400 struct vattr vattr;
1401 int error;
8429d022 1402 struct nameidata nd;
d67a03eb 1403
7121fdf0 1404 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, p);
dd4c01c2 1405 if (error = namei(&nd))
8429d022 1406 return (error);
dd4c01c2 1407 vp = nd.ni_vp;
dbcf7de6
KM
1408 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
1409 VOP_LOCK(vp);
7121fdf0 1410 if (vp->v_mount->mnt_flag & MNT_RDONLY)
fc2aed1e 1411 error = EROFS;
7121fdf0
KB
1412 else {
1413 VATTR_NULL(&vattr);
1414 vattr.va_uid = uap->uid;
1415 vattr.va_gid = uap->gid;
1416 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
fc2aed1e 1417 }
fc2aed1e 1418 vput(vp);
8429d022 1419 return (error);
528f664c 1420}
f94ceb3b 1421
4f083fd7
SL
1422/*
1423 * Set ownership given a file descriptor.
1424 */
9e97623a
CT
1425struct fchown_args {
1426 int fd;
1427 int uid;
1428 int gid;
1429};
6a6a1e5f
KM
1430/* ARGSUSED */
1431fchown(p, uap, retval)
5e00df3b 1432 struct proc *p;
9e97623a 1433 register struct fchown_args *uap;
6a6a1e5f
KM
1434 int *retval;
1435{
fc2aed1e
KM
1436 struct vattr vattr;
1437 struct vnode *vp;
1438 struct file *fp;
1439 int error;
1440
5e00df3b 1441 if (error = getvnode(p->p_fd, uap->fd, &fp))
8429d022 1442 return (error);
fc2aed1e 1443 vp = (struct vnode *)fp->f_data;
dbcf7de6 1444 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
fc2aed1e 1445 VOP_LOCK(vp);
7121fdf0 1446 if (vp->v_mount->mnt_flag & MNT_RDONLY)
fc2aed1e 1447 error = EROFS;
7121fdf0
KB
1448 else {
1449 VATTR_NULL(&vattr);
1450 vattr.va_uid = uap->uid;
1451 vattr.va_gid = uap->gid;
1452 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
fc2aed1e 1453 }
fc2aed1e 1454 VOP_UNLOCK(vp);
8429d022 1455 return (error);
d67a03eb
BJ
1456}
1457
6a6a1e5f
KM
1458/*
1459 * Set the access and modification times of a file.
1460 */
9e97623a 1461struct utimes_args {
7121fdf0 1462 char *path;
9e97623a
CT
1463 struct timeval *tptr;
1464};
6a6a1e5f
KM
1465/* ARGSUSED */
1466utimes(p, uap, retval)
5e00df3b 1467 struct proc *p;
9e97623a 1468 register struct utimes_args *uap;
6a6a1e5f
KM
1469 int *retval;
1470{
fc2aed1e 1471 register struct vnode *vp;
bb1b75f4 1472 struct timeval tv[2];
fc2aed1e 1473 struct vattr vattr;
8e88b0cd 1474 int error;
8429d022 1475 struct nameidata nd;
bb1b75f4 1476
f8ee9a49
KB
1477 VATTR_NULL(&vattr);
1478 if (uap->tptr == NULL) {
1479 microtime(&tv[0]);
1480 tv[1] = tv[0];
fcba749b 1481 vattr.va_vaflags |= VA_UTIMES_NULL;
f8ee9a49
KB
1482 } else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
1483 return (error);
7121fdf0 1484 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
dd4c01c2 1485 if (error = namei(&nd))
8429d022 1486 return (error);
dd4c01c2 1487 vp = nd.ni_vp;
dbcf7de6
KM
1488 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
1489 VOP_LOCK(vp);
7121fdf0 1490 if (vp->v_mount->mnt_flag & MNT_RDONLY)
fc2aed1e 1491 error = EROFS;
7121fdf0
KB
1492 else {
1493 vattr.va_atime.ts_sec = tv[0].tv_sec;
1494 vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
1495 vattr.va_mtime.ts_sec = tv[1].tv_sec;
1496 vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
1497 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
bb1b75f4 1498 }
fc2aed1e 1499 vput(vp);
8429d022 1500 return (error);
d67a03eb 1501}
64d3a787 1502
7121fdf0
KB
1503/*
1504 * Truncate a file given its path name.
1505 */
95c0eb1e 1506struct truncate_args {
7121fdf0 1507 char *path;
2f2b3b3d
CT
1508 int pad;
1509 off_t length;
1510};
be320a2b 1511/* ARGSUSED */
201e5411 1512truncate(p, uap, retval)
5e00df3b 1513 struct proc *p;
95c0eb1e 1514 register struct truncate_args *uap;
6a6a1e5f
KM
1515 int *retval;
1516{
fc2aed1e
KM
1517 register struct vnode *vp;
1518 struct vattr vattr;
1519 int error;
8429d022 1520 struct nameidata nd;
528f664c 1521
7121fdf0 1522 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
dd4c01c2 1523 if (error = namei(&nd))
8429d022 1524 return (error);
dd4c01c2 1525 vp = nd.ni_vp;
dbcf7de6
KM
1526 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
1527 VOP_LOCK(vp);
7121fdf0 1528 if (vp->v_type == VDIR)
fc2aed1e 1529 error = EISDIR;
7121fdf0
KB
1530 else if ((error = vn_writechk(vp)) == 0 &&
1531 (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
1532 VATTR_NULL(&vattr);
1533 vattr.va_size = uap->length;
1534 error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
528f664c 1535 }
fc2aed1e 1536 vput(vp);
8429d022 1537 return (error);
528f664c
SL
1538}
1539
7121fdf0
KB
1540/*
1541 * Truncate a file given a file descriptor.
1542 */
95c0eb1e 1543struct ftruncate_args {
2f2b3b3d
CT
1544 int fd;
1545 int pad;
1546 off_t length;
1547};
6a6a1e5f 1548/* ARGSUSED */
201e5411 1549ftruncate(p, uap, retval)
5e00df3b 1550 struct proc *p;
95c0eb1e 1551 register struct ftruncate_args *uap;
6a6a1e5f
KM
1552 int *retval;
1553{
fc2aed1e
KM
1554 struct vattr vattr;
1555 struct vnode *vp;
528f664c 1556 struct file *fp;
fc2aed1e
KM
1557 int error;
1558
5e00df3b 1559 if (error = getvnode(p->p_fd, uap->fd, &fp))
8429d022 1560 return (error);
fc2aed1e 1561 if ((fp->f_flag & FWRITE) == 0)
8429d022 1562 return (EINVAL);
fc2aed1e 1563 vp = (struct vnode *)fp->f_data;
dbcf7de6 1564 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
fc2aed1e 1565 VOP_LOCK(vp);
7121fdf0 1566 if (vp->v_type == VDIR)
fc2aed1e 1567 error = EISDIR;
7121fdf0
KB
1568 else if ((error = vn_writechk(vp)) == 0) {
1569 VATTR_NULL(&vattr);
1570 vattr.va_size = uap->length;
1571 error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
528f664c 1572 }
fc2aed1e 1573 VOP_UNLOCK(vp);
8429d022 1574 return (error);
4f083fd7
SL
1575}
1576
2f2b3b3d
CT
1577#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1578/*
1579 * Truncate a file given its path name.
1580 */
95c0eb1e 1581struct otruncate_args {
7121fdf0 1582 char *path;
9e97623a
CT
1583 long length;
1584};
2f2b3b3d 1585/* ARGSUSED */
51a9a1cf 1586otruncate(p, uap, retval)
2f2b3b3d 1587 struct proc *p;
95c0eb1e 1588 register struct otruncate_args *uap;
2f2b3b3d
CT
1589 int *retval;
1590{
95c0eb1e 1591 struct truncate_args nuap;
2f2b3b3d 1592
7121fdf0 1593 nuap.path = uap->path;
2f2b3b3d 1594 nuap.length = uap->length;
95c0eb1e 1595 return (truncate(p, &nuap, retval));
2f2b3b3d
CT
1596}
1597
1598/*
1599 * Truncate a file given a file descriptor.
1600 */
95c0eb1e 1601struct oftruncate_args {
9e97623a
CT
1602 int fd;
1603 long length;
1604};
2f2b3b3d 1605/* ARGSUSED */
51a9a1cf 1606oftruncate(p, uap, retval)
2f2b3b3d 1607 struct proc *p;
95c0eb1e 1608 register struct oftruncate_args *uap;
2f2b3b3d
CT
1609 int *retval;
1610{
95c0eb1e 1611 struct ftruncate_args nuap;
2f2b3b3d
CT
1612
1613 nuap.fd = uap->fd;
1614 nuap.length = uap->length;
95c0eb1e 1615 return (ftruncate(p, &nuap, retval));
2f2b3b3d
CT
1616}
1617#endif /* COMPAT_43 || COMPAT_SUNOS */
1618
4f083fd7 1619/*
7121fdf0 1620 * Sync an open file.
4f083fd7 1621 */
9e97623a
CT
1622struct fsync_args {
1623 int fd;
1624};
6a6a1e5f
KM
1625/* ARGSUSED */
1626fsync(p, uap, retval)
5e00df3b 1627 struct proc *p;
9e97623a 1628 struct fsync_args *uap;
6a6a1e5f
KM
1629 int *retval;
1630{
e79467ea 1631 register struct vnode *vp;
4f083fd7 1632 struct file *fp;
fc2aed1e 1633 int error;
4f083fd7 1634
5e00df3b 1635 if (error = getvnode(p->p_fd, uap->fd, &fp))
8429d022 1636 return (error);
e79467ea
KM
1637 vp = (struct vnode *)fp->f_data;
1638 VOP_LOCK(vp);
09d2ef1a 1639 error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
e79467ea 1640 VOP_UNLOCK(vp);
8429d022 1641 return (error);
528f664c
SL
1642}
1643
4f083fd7 1644/*
7121fdf0
KB
1645 * Rename files. Source and destination must either both be directories,
1646 * or both not be directories. If target is a directory, it must be empty.
4f083fd7 1647 */
9e97623a
CT
1648struct rename_args {
1649 char *from;
1650 char *to;
1651};
6a6a1e5f
KM
1652/* ARGSUSED */
1653rename(p, uap, retval)
5e00df3b 1654 struct proc *p;
9e97623a 1655 register struct rename_args *uap;
6a6a1e5f
KM
1656 int *retval;
1657{
fc2aed1e 1658 register struct vnode *tvp, *fvp, *tdvp;
5718fad3 1659 struct nameidata fromnd, tond;
fc2aed1e 1660 int error;
4f083fd7 1661
a5368812 1662 CHECKPOINTREF;
dd4c01c2
KM
1663 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
1664 uap->from, p);
1665 if (error = namei(&fromnd))
8429d022 1666 return (error);
5718fad3 1667 fvp = fromnd.ni_vp;
dd4c01c2
KM
1668 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
1669 UIO_USERSPACE, uap->to, p);
1670 if (error = namei(&tond)) {
cfef4373 1671 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
5718fad3 1672 vrele(fromnd.ni_dvp);
66955caf
KM
1673 vrele(fvp);
1674 goto out1;
1675 }
fc2aed1e
KM
1676 tdvp = tond.ni_dvp;
1677 tvp = tond.ni_vp;
1678 if (tvp != NULL) {
1679 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
9259ee95 1680 error = ENOTDIR;
fc2aed1e
KM
1681 goto out;
1682 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
9259ee95 1683 error = EISDIR;
fc2aed1e 1684 goto out;
a5390dce 1685 }
64d3a787 1686 }
fe562f32 1687 if (fvp == tdvp)
fc2aed1e 1688 error = EINVAL;
fe562f32 1689 /*
5718fad3
KM
1690 * If source is the same as the destination (that is the
1691 * same inode number with the same name in the same directory),
fe562f32
KM
1692 * then there is nothing to do.
1693 */
5718fad3 1694 if (fvp == tvp && fromnd.ni_dvp == tdvp &&
dd4c01c2
KM
1695 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
1696 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
1697 fromnd.ni_cnd.cn_namelen))
fe562f32 1698 error = -1;
fc2aed1e 1699out:
66955caf 1700 if (!error) {
e62d4143
KM
1701 LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE);
1702 if (fromnd.ni_dvp != tdvp)
1703 LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1704 if (tvp)
1705 LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE);
cfef4373
JH
1706 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
1707 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
66955caf 1708 } else {
cfef4373 1709 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
6c44e83b
KM
1710 if (tdvp == tvp)
1711 vrele(tdvp);
1712 else
1713 vput(tdvp);
66955caf
KM
1714 if (tvp)
1715 vput(tvp);
cfef4373 1716 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
5718fad3 1717 vrele(fromnd.ni_dvp);
66955caf 1718 vrele(fvp);
64d3a787 1719 }
c03959f9 1720 p->p_spare[1]--;
5718fad3 1721 vrele(tond.ni_startdir);
dd4c01c2 1722 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
fc2aed1e 1723out1:
c03959f9 1724 p->p_spare[1]--;
5718fad3 1725 vrele(fromnd.ni_startdir);
dd4c01c2 1726 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
a5368812 1727 CHECKREFS("rename");
fe562f32 1728 if (error == -1)
8429d022
MK
1729 return (0);
1730 return (error);
64d3a787 1731}
88a7a62a 1732
88a7a62a 1733/*
7121fdf0 1734 * Make a directory file.
88a7a62a 1735 */
9e97623a 1736struct mkdir_args {
7121fdf0
KB
1737 char *path;
1738 int mode;
9e97623a 1739};
6a6a1e5f
KM
1740/* ARGSUSED */
1741mkdir(p, uap, retval)
5e00df3b 1742 struct proc *p;
9e97623a 1743 register struct mkdir_args *uap;
6a6a1e5f
KM
1744 int *retval;
1745{
fc2aed1e
KM
1746 register struct vnode *vp;
1747 struct vattr vattr;
1748 int error;
8429d022 1749 struct nameidata nd;
88a7a62a 1750
a5368812 1751 CHECKPOINTREF;
7121fdf0 1752 NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
dd4c01c2 1753 if (error = namei(&nd))
8429d022 1754 return (error);
dd4c01c2 1755 vp = nd.ni_vp;
fc2aed1e 1756 if (vp != NULL) {
dd4c01c2
KM
1757 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1758 if (nd.ni_dvp == vp)
1759 vrele(nd.ni_dvp);
6c44e83b 1760 else
dd4c01c2 1761 vput(nd.ni_dvp);
66955caf 1762 vrele(vp);
a5368812 1763 CHECKREFS("mkdir1");
8429d022 1764 return (EEXIST);
88a7a62a 1765 }
3ee1461b 1766 VATTR_NULL(&vattr);
fc2aed1e 1767 vattr.va_type = VDIR;
7121fdf0 1768 vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask;
dd4c01c2
KM
1769 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1770 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
5dfd04f0 1771 if (!error)
dd4c01c2 1772 vput(nd.ni_vp);
a5368812 1773 CHECKREFS("mkdir2");
8429d022 1774 return (error);
88a7a62a
SL
1775}
1776
1777/*
7121fdf0 1778 * Remove a directory file.
88a7a62a 1779 */
9e97623a 1780struct rmdir_args {
7121fdf0 1781 char *path;
9e97623a 1782};
6a6a1e5f
KM
1783/* ARGSUSED */
1784rmdir(p, uap, retval)
5e00df3b 1785 struct proc *p;
9e97623a 1786 struct rmdir_args *uap;
6a6a1e5f
KM
1787 int *retval;
1788{
fc2aed1e
KM
1789 register struct vnode *vp;
1790 int error;
8429d022 1791 struct nameidata nd;
88a7a62a 1792
a5368812 1793 CHECKPOINTREF;
7121fdf0 1794 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p);
dd4c01c2 1795 if (error = namei(&nd))
8429d022 1796 return (error);
dd4c01c2 1797 vp = nd.ni_vp;
fc2aed1e
KM
1798 if (vp->v_type != VDIR) {
1799 error = ENOTDIR;
88a7a62a
SL
1800 goto out;
1801 }
1802 /*
fc2aed1e 1803 * No rmdir "." please.
88a7a62a 1804 */
dd4c01c2 1805 if (nd.ni_dvp == vp) {
fc2aed1e 1806 error = EINVAL;
88a7a62a
SL
1807 goto out;
1808 }
1809 /*
d4ed1dcd 1810 * The root of a mounted filesystem cannot be deleted.
88a7a62a 1811 */
fc2aed1e
KM
1812 if (vp->v_flag & VROOT)
1813 error = EBUSY;
88a7a62a 1814out:
66955caf 1815 if (!error) {
dd4c01c2 1816 LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
e62d4143 1817 LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
dd4c01c2 1818 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
66955caf 1819 } else {
dd4c01c2
KM
1820 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1821 if (nd.ni_dvp == vp)
1822 vrele(nd.ni_dvp);
6c44e83b 1823 else
dd4c01c2 1824 vput(nd.ni_dvp);
66955caf
KM
1825 vput(vp);
1826 }
a5368812 1827 CHECKREFS("rmdir");
8429d022 1828 return (error);
88a7a62a
SL
1829}
1830
3d92fa10
KM
1831#ifdef COMPAT_43
1832/*
1833 * Read a block of directory entries in a file system independent format.
1834 */
9e97623a
CT
1835struct ogetdirentries_args {
1836 int fd;
1837 char *buf;
7121fdf0 1838 u_int count;
9e97623a
CT
1839 long *basep;
1840};
3d92fa10
KM
1841ogetdirentries(p, uap, retval)
1842 struct proc *p;
9e97623a 1843 register struct ogetdirentries_args *uap;
3d92fa10
KM
1844 int *retval;
1845{
3d92fa10
KM
1846 register struct vnode *vp;
1847 struct file *fp;
1848 struct uio auio, kuio;
1849 struct iovec aiov, kiov;
1850 struct dirent *dp, *edp;
1851 caddr_t dirbuf;
1852 int error, readcnt;
d80c3f56 1853 long loff;
3d92fa10
KM
1854
1855 if (error = getvnode(p->p_fd, uap->fd, &fp))
1856 return (error);
1857 if ((fp->f_flag & FREAD) == 0)
1858 return (EBADF);
1859 vp = (struct vnode *)fp->f_data;
1860 if (vp->v_type != VDIR)
1861 return (EINVAL);
1862 aiov.iov_base = uap->buf;
1863 aiov.iov_len = uap->count;
1864 auio.uio_iov = &aiov;
1865 auio.uio_iovcnt = 1;
1866 auio.uio_rw = UIO_READ;
1867 auio.uio_segflg = UIO_USERSPACE;
1868 auio.uio_procp = p;
1869 auio.uio_resid = uap->count;
1870 VOP_LOCK(vp);
d80c3f56 1871 loff = auio.uio_offset = fp->f_offset;
3d92fa10 1872# if (BYTE_ORDER != LITTLE_ENDIAN)
a801b5ab 1873 if (vp->v_mount->mnt_maxsymlinklen <= 0) {
3d92fa10 1874 error = VOP_READDIR(vp, &auio, fp->f_cred);
a801b5ab
KM
1875 fp->f_offset = auio.uio_offset;
1876 } else
3d92fa10
KM
1877# endif
1878 {
1879 kuio = auio;
1880 kuio.uio_iov = &kiov;
1881 kuio.uio_segflg = UIO_SYSSPACE;
1882 kiov.iov_len = uap->count;
1883 MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK);
1884 kiov.iov_base = dirbuf;
1885 error = VOP_READDIR(vp, &kuio, fp->f_cred);
a801b5ab 1886 fp->f_offset = kuio.uio_offset;
3d92fa10
KM
1887 if (error == 0) {
1888 readcnt = uap->count - kuio.uio_resid;
1889 edp = (struct dirent *)&dirbuf[readcnt];
1890 for (dp = (struct dirent *)dirbuf; dp < edp; ) {
3d92fa10 1891# if (BYTE_ORDER == LITTLE_ENDIAN)
d80c3f56 1892 /*
30445fe6
KM
1893 * The expected low byte of
1894 * dp->d_namlen is our dp->d_type.
1895 * The high MBZ byte of dp->d_namlen
1896 * is our dp->d_namlen.
d80c3f56 1897 */
30445fe6
KM
1898 dp->d_type = dp->d_namlen;
1899 dp->d_namlen = 0;
1900# else
1901 /*
1902 * The dp->d_type is the high byte
1903 * of the expected dp->d_namlen,
1904 * so must be zero'ed.
1905 */
1906 dp->d_type = 0;
3d92fa10
KM
1907# endif
1908 if (dp->d_reclen > 0) {
1909 dp = (struct dirent *)
1910 ((char *)dp + dp->d_reclen);
1911 } else {
1912 error = EIO;
1913 break;
1914 }
1915 }
1916 if (dp >= edp)
1917 error = uiomove(dirbuf, readcnt, &auio);
1918 }
1919 FREE(dirbuf, M_TEMP);
1920 }
3d92fa10
KM
1921 VOP_UNLOCK(vp);
1922 if (error)
1923 return (error);
d80c3f56 1924 error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
3d92fa10
KM
1925 *retval = uap->count - auio.uio_resid;
1926 return (error);
1927}
1928#endif
1929
fc2aed1e 1930/*
d4ed1dcd 1931 * Read a block of directory entries in a file system independent format.
fc2aed1e 1932 */
9e97623a
CT
1933struct getdirentries_args {
1934 int fd;
1935 char *buf;
7121fdf0 1936 u_int count;
9e97623a
CT
1937 long *basep;
1938};
6a6a1e5f 1939getdirentries(p, uap, retval)
5e00df3b 1940 struct proc *p;
9e97623a 1941 register struct getdirentries_args *uap;
6a6a1e5f
KM
1942 int *retval;
1943{
e79467ea 1944 register struct vnode *vp;
8462a185 1945 struct file *fp;
fc2aed1e
KM
1946 struct uio auio;
1947 struct iovec aiov;
d80c3f56 1948 long loff;
09d2ef1a 1949 int error;
fc2aed1e 1950
5e00df3b 1951 if (error = getvnode(p->p_fd, uap->fd, &fp))
8429d022 1952 return (error);
fc2aed1e 1953 if ((fp->f_flag & FREAD) == 0)
8429d022 1954 return (EBADF);
e79467ea 1955 vp = (struct vnode *)fp->f_data;
95a9cadb 1956unionread:
e79467ea 1957 if (vp->v_type != VDIR)
8429d022 1958 return (EINVAL);
fc2aed1e
KM
1959 aiov.iov_base = uap->buf;
1960 aiov.iov_len = uap->count;
1961 auio.uio_iov = &aiov;
1962 auio.uio_iovcnt = 1;
1963 auio.uio_rw = UIO_READ;
1964 auio.uio_segflg = UIO_USERSPACE;
2c69fe14 1965 auio.uio_procp = p;
fc2aed1e 1966 auio.uio_resid = uap->count;
e79467ea 1967 VOP_LOCK(vp);
d80c3f56 1968 loff = auio.uio_offset = fp->f_offset;
09d2ef1a 1969 error = VOP_READDIR(vp, &auio, fp->f_cred);
e79467ea
KM
1970 fp->f_offset = auio.uio_offset;
1971 VOP_UNLOCK(vp);
1972 if (error)
8429d022 1973 return (error);
95a9cadb
JSP
1974 if ((uap->count == auio.uio_resid) &&
1975 (vp->v_flag & VROOT) &&
1976 (vp->v_mount->mnt_flag & MNT_UNION)) {
1977 struct vnode *tvp = vp;
1978 vp = vp->v_mount->mnt_vnodecovered;
1979 VREF(vp);
1980 fp->f_data = (caddr_t) vp;
1981 fp->f_offset = 0;
1982 vrele(tvp);
1983 goto unionread;
1984 }
d80c3f56 1985 error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
6a6a1e5f 1986 *retval = uap->count - auio.uio_resid;
8429d022 1987 return (error);
88a7a62a
SL
1988}
1989
1990/*
d4ed1dcd 1991 * Set the mode mask for creation of filesystem nodes.
88a7a62a 1992 */
9e97623a 1993struct umask_args {
7121fdf0 1994 int newmask;
9e97623a
CT
1995};
1996mode_t /* XXX */
6a6a1e5f 1997umask(p, uap, retval)
5e00df3b 1998 struct proc *p;
9e97623a 1999 struct umask_args *uap;
6a6a1e5f
KM
2000 int *retval;
2001{
7121fdf0 2002 register struct filedesc *fdp;
88a7a62a 2003
7121fdf0 2004 fdp = p->p_fd;
5e00df3b 2005 *retval = fdp->fd_cmask;
7121fdf0 2006 fdp->fd_cmask = uap->newmask & ALLPERMS;
8429d022 2007 return (0);
fc2aed1e
KM
2008}
2009
b0a98f13
MT
2010/*
2011 * Void all references to file by ripping underlying filesystem
2012 * away from vnode.
2013 */
9e97623a 2014struct revoke_args {
7121fdf0 2015 char *path;
9e97623a 2016};
6a6a1e5f
KM
2017/* ARGSUSED */
2018revoke(p, uap, retval)
5e00df3b 2019 struct proc *p;
9e97623a 2020 register struct revoke_args *uap;
6a6a1e5f
KM
2021 int *retval;
2022{
b0a98f13
MT
2023 register struct vnode *vp;
2024 struct vattr vattr;
2025 int error;
8429d022 2026 struct nameidata nd;
b0a98f13 2027
7121fdf0 2028 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
dd4c01c2 2029 if (error = namei(&nd))
8429d022 2030 return (error);
dd4c01c2 2031 vp = nd.ni_vp;
b0a98f13
MT
2032 if (vp->v_type != VCHR && vp->v_type != VBLK) {
2033 error = EINVAL;
2034 goto out;
2035 }
2c69fe14 2036 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
b0a98f13 2037 goto out;
8429d022
MK
2038 if (p->p_ucred->cr_uid != vattr.va_uid &&
2039 (error = suser(p->p_ucred, &p->p_acflag)))
b0a98f13 2040 goto out;
8b81d198 2041 if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
c9345cca 2042 vgoneall(vp);
b0a98f13
MT
2043out:
2044 vrele(vp);
8429d022 2045 return (error);
b0a98f13
MT
2046}
2047
d4ed1dcd
KM
2048/*
2049 * Convert a user file descriptor to a kernel file entry.
2050 */
7121fdf0 2051getvnode(fdp, fd, fpp)
5e00df3b 2052 struct filedesc *fdp;
fc2aed1e 2053 struct file **fpp;
7121fdf0 2054 int fd;
fc2aed1e
KM
2055{
2056 struct file *fp;
2057
7121fdf0
KB
2058 if ((u_int)fd >= fdp->fd_nfiles ||
2059 (fp = fdp->fd_ofiles[fd]) == NULL)
fc2aed1e
KM
2060 return (EBADF);
2061 if (fp->f_type != DTYPE_VNODE)
2062 return (EINVAL);
2063 *fpp = fp;
2064 return (0);
88a7a62a 2065}