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