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