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