more-or-less working with new proc & user structs
[unix-history] / usr / src / sys / kern / vfs_syscalls.c
CommitLineData
da7c5cc6 1/*
fc2aed1e
KM
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
da7c5cc6 4 *
dbf0c423 5 * %sccs.include.redist.c%
fc2aed1e 6 *
8429d022 7 * @(#)vfs_syscalls.c 7.65 (Berkeley) %G%
da7c5cc6 8 */
6459ebe0 9
94368568
JB
10#include "param.h"
11#include "systm.h"
8429d022 12#include "namei.h"
5e00df3b 13#include "filedesc.h"
94368568
JB
14#include "kernel.h"
15#include "file.h"
16#include "stat.h"
fc2aed1e 17#include "vnode.h"
fc2aed1e 18#include "mount.h"
94368568 19#include "proc.h"
94368568 20#include "uio.h"
fc2aed1e 21#include "malloc.h"
88a7a62a 22
fc2aed1e
KM
23/*
24 * Virtual File System System Calls
25 */
3e78e260 26
4f083fd7 27/*
fc2aed1e 28 * mount system call
4f083fd7 29 */
6a6a1e5f
KM
30/* ARGSUSED */
31mount(p, uap, retval)
5e00df3b 32 struct proc *p;
6a6a1e5f 33 register struct args {
fc2aed1e
KM
34 int type;
35 char *dir;
36 int flags;
37 caddr_t data;
6a6a1e5f
KM
38 } *uap;
39 int *retval;
40{
8429d022 41 register struct nameidata *ndp;
d48157d5
KM
42 register struct vnode *vp;
43 register struct mount *mp;
47971887 44 int error, flag;
8429d022 45 struct nameidata nd;
3e78e260 46
fc2aed1e
KM
47 /*
48 * Must be super user
49 */
8429d022
MK
50 if (error = suser(p->p_ucred, &p->p_acflag))
51 return (error);
fc2aed1e
KM
52 /*
53 * Get vnode to be covered
54 */
8429d022 55 ndp = &nd;
fc2aed1e
KM
56 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
57 ndp->ni_segflg = UIO_USERSPACE;
58 ndp->ni_dirp = uap->dir;
8429d022
MK
59 if (error = namei(ndp, p))
60 return (error);
fc2aed1e 61 vp = ndp->ni_vp;
54fb9dc2 62 if (uap->flags & MNT_UPDATE) {
d48157d5
KM
63 if ((vp->v_flag & VROOT) == 0) {
64 vput(vp);
8429d022 65 return (EINVAL);
d48157d5
KM
66 }
67 mp = vp->v_mount;
68 /*
69 * We allow going from read-only to read-write,
70 * but not from read-write to read-only.
71 */
54fb9dc2
KM
72 if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
73 (uap->flags & MNT_RDONLY) != 0) {
d48157d5 74 vput(vp);
8429d022 75 return (EOPNOTSUPP); /* Needs translation */
d48157d5 76 }
54fb9dc2
KM
77 flag = mp->mnt_flag;
78 mp->mnt_flag |= MNT_UPDATE;
d48157d5
KM
79 VOP_UNLOCK(vp);
80 goto update;
81 }
89cdb378 82 vinvalbuf(vp, 1);
8b81d198 83 if (vp->v_usecount != 1) {
fc2aed1e 84 vput(vp);
8429d022 85 return (EBUSY);
fc2aed1e
KM
86 }
87 if (vp->v_type != VDIR) {
88 vput(vp);
8429d022 89 return (ENOTDIR);
fc2aed1e 90 }
62d239e5 91 if ((unsigned long)uap->type > MOUNT_MAXTYPE ||
fc2aed1e
KM
92 vfssw[uap->type] == (struct vfsops *)0) {
93 vput(vp);
8429d022 94 return (ENODEV);
fc2aed1e
KM
95 }
96
97 /*
d48157d5 98 * Allocate and initialize the file system.
fc2aed1e
KM
99 */
100 mp = (struct mount *)malloc((u_long)sizeof(struct mount),
101 M_MOUNT, M_WAITOK);
54fb9dc2
KM
102 mp->mnt_op = vfssw[uap->type];
103 mp->mnt_flag = 0;
104 mp->mnt_exroot = 0;
105 mp->mnt_mounth = NULLVP;
d48157d5
KM
106 if (error = vfs_lock(mp)) {
107 free((caddr_t)mp, M_MOUNT);
108 vput(vp);
8429d022 109 return (error);
d48157d5
KM
110 }
111 if (vp->v_mountedhere != (struct mount *)0) {
112 vfs_unlock(mp);
113 free((caddr_t)mp, M_MOUNT);
114 vput(vp);
8429d022 115 return (EBUSY);
d48157d5 116 }
d48157d5 117 vp->v_mountedhere = mp;
54fb9dc2 118 mp->mnt_vnodecovered = vp;
d48157d5
KM
119update:
120 /*
121 * Set the mount level flags.
122 */
54fb9dc2
KM
123 if (uap->flags & MNT_RDONLY)
124 mp->mnt_flag |= MNT_RDONLY;
d48157d5 125 else
54fb9dc2
KM
126 mp->mnt_flag &= ~MNT_RDONLY;
127 if (uap->flags & MNT_NOSUID)
128 mp->mnt_flag |= MNT_NOSUID;
d48157d5 129 else
54fb9dc2
KM
130 mp->mnt_flag &= ~MNT_NOSUID;
131 if (uap->flags & MNT_NOEXEC)
132 mp->mnt_flag |= MNT_NOEXEC;
d48157d5 133 else
54fb9dc2
KM
134 mp->mnt_flag &= ~MNT_NOEXEC;
135 if (uap->flags & MNT_NODEV)
136 mp->mnt_flag |= MNT_NODEV;
d48157d5 137 else
54fb9dc2
KM
138 mp->mnt_flag &= ~MNT_NODEV;
139 if (uap->flags & MNT_SYNCHRONOUS)
140 mp->mnt_flag |= MNT_SYNCHRONOUS;
d48157d5 141 else
54fb9dc2 142 mp->mnt_flag &= ~MNT_SYNCHRONOUS;
d48157d5
KM
143 /*
144 * Mount the filesystem.
145 */
146 error = VFS_MOUNT(mp, uap->dir, uap->data, ndp);
54fb9dc2
KM
147 if (mp->mnt_flag & MNT_UPDATE) {
148 mp->mnt_flag &= ~MNT_UPDATE;
d48157d5 149 vrele(vp);
47971887 150 if (error)
54fb9dc2 151 mp->mnt_flag = flag;
8429d022 152 return (error);
d48157d5 153 }
92d0de98
KM
154 /*
155 * Put the new filesystem on the mount list after root.
156 */
54fb9dc2
KM
157 mp->mnt_next = rootfs->mnt_next;
158 mp->mnt_prev = rootfs;
159 rootfs->mnt_next = mp;
160 mp->mnt_next->mnt_prev = mp;
fc2aed1e 161 cache_purge(vp);
fc2aed1e 162 if (!error) {
d48157d5 163 VOP_UNLOCK(vp);
fc2aed1e 164 vfs_unlock(mp);
97d8a528 165 error = VFS_START(mp, 0);
fc2aed1e
KM
166 } else {
167 vfs_remove(mp);
168 free((caddr_t)mp, M_MOUNT);
d48157d5 169 vput(vp);
fc2aed1e 170 }
8429d022 171 return (error);
3e78e260
BJ
172}
173
4f083fd7 174/*
fc2aed1e
KM
175 * Unmount system call.
176 *
177 * Note: unmount takes a path to the vnode mounted on as argument,
178 * not special file (as before).
4f083fd7 179 */
6a6a1e5f
KM
180/* ARGSUSED */
181unmount(p, uap, retval)
5e00df3b 182 struct proc *p;
6a6a1e5f 183 register struct args {
fc2aed1e
KM
184 char *pathp;
185 int flags;
6a6a1e5f
KM
186 } *uap;
187 int *retval;
188{
fc2aed1e 189 register struct vnode *vp;
8429d022 190 register struct nameidata *ndp;
9151110e 191 struct mount *mp;
fc2aed1e 192 int error;
8429d022 193 struct nameidata nd;
fc2aed1e
KM
194
195 /*
196 * Must be super user
197 */
8429d022
MK
198 if (error = suser(p->p_ucred, &p->p_acflag))
199 return (error);
fc2aed1e 200
8429d022 201 ndp = &nd;
fc2aed1e
KM
202 ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
203 ndp->ni_segflg = UIO_USERSPACE;
204 ndp->ni_dirp = uap->pathp;
8429d022
MK
205 if (error = namei(ndp, p))
206 return (error);
fc2aed1e
KM
207 vp = ndp->ni_vp;
208 /*
209 * Must be the root of the filesystem
210 */
211 if ((vp->v_flag & VROOT) == 0) {
212 vput(vp);
8429d022 213 return (EINVAL);
fc2aed1e
KM
214 }
215 mp = vp->v_mount;
216 vput(vp);
8429d022 217 return (dounmount(mp, uap->flags));
9151110e
KM
218}
219
220/*
221 * Do an unmount.
222 */
223dounmount(mp, flags)
224 register struct mount *mp;
225 int flags;
226{
227 struct vnode *coveredvp;
228 int error;
229
54fb9dc2 230 coveredvp = mp->mnt_vnodecovered;
c001b1c3
KM
231 if (vfs_busy(mp))
232 return (EBUSY);
54fb9dc2 233 mp->mnt_flag |= MNT_UNMOUNT;
fc2aed1e 234 if (error = vfs_lock(mp))
9151110e 235 return (error);
fc2aed1e 236
a42e0ed8 237#ifdef NVM
9db58063 238 vnode_pager_umount(mp); /* release cached vnodes */
a42e0ed8
KM
239#else
240 xumount(mp); /* remove unused sticky files from text table */
241#endif
fc2aed1e 242 cache_purgevfs(mp); /* remove cache entries for this file sys */
a99a44da
KM
243 if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE))
244 error = VFS_UNMOUNT(mp, flags);
54fb9dc2 245 mp->mnt_flag &= ~MNT_UNMOUNT;
c001b1c3 246 vfs_unbusy(mp);
fc2aed1e
KM
247 if (error) {
248 vfs_unlock(mp);
249 } else {
250 vrele(coveredvp);
251 vfs_remove(mp);
252 free((caddr_t)mp, M_MOUNT);
253 }
9151110e 254 return (error);
fc2aed1e
KM
255}
256
257/*
258 * Sync system call.
259 * Sync each mounted filesystem.
260 */
ff4fb102 261/* ARGSUSED */
6a6a1e5f 262sync(p, uap, retval)
5e00df3b 263 struct proc *p;
8429d022 264 void *uap;
6a6a1e5f 265 int *retval;
3e78e260 266{
fc2aed1e 267 register struct mount *mp;
c001b1c3 268 struct mount *omp;
fc2aed1e
KM
269
270 mp = rootfs;
271 do {
62e35d50
KM
272 /*
273 * The lock check below is to avoid races with mount
274 * and unmount.
275 */
54fb9dc2 276 if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
c001b1c3 277 !vfs_busy(mp)) {
fc2aed1e 278 VFS_SYNC(mp, MNT_NOWAIT);
c001b1c3 279 omp = mp;
54fb9dc2 280 mp = mp->mnt_next;
c001b1c3
KM
281 vfs_unbusy(omp);
282 } else
54fb9dc2 283 mp = mp->mnt_next;
fc2aed1e
KM
284 } while (mp != rootfs);
285}
286
c001b1c3
KM
287/*
288 * operate on filesystem quotas
289 */
6a6a1e5f
KM
290/* ARGSUSED */
291quotactl(p, uap, retval)
5e00df3b 292 struct proc *p;
6a6a1e5f 293 register struct args {
c001b1c3
KM
294 char *path;
295 int cmd;
296 int uid;
297 caddr_t arg;
6a6a1e5f
KM
298 } *uap;
299 int *retval;
300{
c001b1c3 301 register struct mount *mp;
8429d022 302 register struct nameidata *ndp;
c001b1c3 303 int error;
8429d022 304 struct nameidata nd;
c001b1c3 305
8429d022 306 ndp = &nd;
c001b1c3
KM
307 ndp->ni_nameiop = LOOKUP | FOLLOW;
308 ndp->ni_segflg = UIO_USERSPACE;
309 ndp->ni_dirp = uap->path;
8429d022
MK
310 if (error = namei(ndp, p))
311 return (error);
c001b1c3
KM
312 mp = ndp->ni_vp->v_mount;
313 vrele(ndp->ni_vp);
8429d022 314 return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg));
c001b1c3
KM
315}
316
fc2aed1e
KM
317/*
318 * get filesystem statistics
319 */
6a6a1e5f
KM
320/* ARGSUSED */
321statfs(p, uap, retval)
5e00df3b 322 struct proc *p;
6a6a1e5f 323 register struct args {
fc2aed1e
KM
324 char *path;
325 struct statfs *buf;
6a6a1e5f
KM
326 } *uap;
327 int *retval;
328{
3f705640 329 register struct mount *mp;
8429d022 330 register struct nameidata *ndp;
62e35d50 331 register struct statfs *sp;
fc2aed1e 332 int error;
8429d022 333 struct nameidata nd;
3e78e260 334
8429d022 335 ndp = &nd;
e114af99 336 ndp->ni_nameiop = LOOKUP | FOLLOW;
fc2aed1e
KM
337 ndp->ni_segflg = UIO_USERSPACE;
338 ndp->ni_dirp = uap->path;
8429d022
MK
339 if (error = namei(ndp, p))
340 return (error);
e114af99 341 mp = ndp->ni_vp->v_mount;
54fb9dc2 342 sp = &mp->mnt_stat;
e114af99 343 vrele(ndp->ni_vp);
62e35d50 344 if (error = VFS_STATFS(mp, sp))
8429d022 345 return (error);
54fb9dc2 346 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
8429d022 347 return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
fc2aed1e
KM
348}
349
6a6a1e5f
KM
350/*
351 * get filesystem statistics
352 */
353/* ARGSUSED */
354fstatfs(p, uap, retval)
5e00df3b 355 struct proc *p;
6a6a1e5f 356 register struct args {
fc2aed1e
KM
357 int fd;
358 struct statfs *buf;
6a6a1e5f
KM
359 } *uap;
360 int *retval;
361{
fc2aed1e 362 struct file *fp;
3f705640 363 struct mount *mp;
62e35d50 364 register struct statfs *sp;
fc2aed1e
KM
365 int error;
366
5e00df3b 367 if (error = getvnode(p->p_fd, uap->fd, &fp))
8429d022 368 return (error);
3f705640 369 mp = ((struct vnode *)fp->f_data)->v_mount;
54fb9dc2 370 sp = &mp->mnt_stat;
62e35d50 371 if (error = VFS_STATFS(mp, sp))
8429d022 372 return (error);
54fb9dc2 373 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
8429d022 374 return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
3e78e260
BJ
375}
376
bfcdbfbf
KM
377/*
378 * get statistics on all filesystems
379 */
6a6a1e5f 380getfsstat(p, uap, retval)
5e00df3b 381 struct proc *p;
6a6a1e5f 382 register struct args {
bfcdbfbf
KM
383 struct statfs *buf;
384 long bufsize;
62e35d50 385 int flags;
6a6a1e5f
KM
386 } *uap;
387 int *retval;
388{
bfcdbfbf 389 register struct mount *mp;
62e35d50 390 register struct statfs *sp;
f62fad9a 391 caddr_t sfsp;
bfcdbfbf
KM
392 long count, maxcount, error;
393
394 maxcount = uap->bufsize / sizeof(struct statfs);
f62fad9a 395 sfsp = (caddr_t)uap->buf;
bfcdbfbf
KM
396 mp = rootfs;
397 count = 0;
398 do {
54fb9dc2
KM
399 if (sfsp && count < maxcount &&
400 ((mp->mnt_flag & MNT_MLOCK) == 0)) {
401 sp = &mp->mnt_stat;
62e35d50
KM
402 /*
403 * If MNT_NOWAIT is specified, do not refresh the
404 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
405 */
406 if (((uap->flags & MNT_NOWAIT) == 0 ||
407 (uap->flags & MNT_WAIT)) &&
408 (error = VFS_STATFS(mp, sp))) {
54fb9dc2 409 mp = mp->mnt_prev;
fd8516be
KM
410 continue;
411 }
54fb9dc2 412 sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
62e35d50 413 if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
8429d022 414 return (error);
62e35d50 415 sfsp += sizeof(*sp);
bfcdbfbf 416 }
f62fad9a 417 count++;
54fb9dc2 418 mp = mp->mnt_prev;
bfcdbfbf
KM
419 } while (mp != rootfs);
420 if (sfsp && count > maxcount)
6a6a1e5f 421 *retval = maxcount;
bfcdbfbf 422 else
6a6a1e5f 423 *retval = count;
8429d022 424 return (0);
bfcdbfbf
KM
425}
426
6995a2cb
KM
427/*
428 * Change current working directory to a given file descriptor.
429 */
6a6a1e5f
KM
430/* ARGSUSED */
431fchdir(p, uap, retval)
5e00df3b 432 struct proc *p;
6a6a1e5f 433 struct args {
6995a2cb 434 int fd;
6a6a1e5f
KM
435 } *uap;
436 int *retval;
437{
5e00df3b 438 register struct filedesc *fdp = p->p_fd;
6995a2cb
KM
439 register struct vnode *vp;
440 struct file *fp;
441 int error;
442
5e00df3b 443 if (error = getvnode(fdp, uap->fd, &fp))
8429d022 444 return (error);
6995a2cb
KM
445 vp = (struct vnode *)fp->f_data;
446 VOP_LOCK(vp);
447 if (vp->v_type != VDIR)
448 error = ENOTDIR;
449 else
8429d022 450 error = VOP_ACCESS(vp, VEXEC, p->p_ucred);
6995a2cb 451 VOP_UNLOCK(vp);
ab214c34 452 if (error)
8429d022 453 return (error);
ab214c34 454 VREF(vp);
5e00df3b
KM
455 vrele(fdp->fd_cdir);
456 fdp->fd_cdir = vp;
8429d022 457 return (0);
6995a2cb
KM
458}
459
4f083fd7 460/*
fc2aed1e 461 * Change current working directory (``.'').
4f083fd7 462 */
6a6a1e5f
KM
463/* ARGSUSED */
464chdir(p, uap, retval)
5e00df3b 465 struct proc *p;
6a6a1e5f 466 struct args {
3e78e260 467 char *fname;
6a6a1e5f
KM
468 } *uap;
469 int *retval;
470{
8429d022 471 register struct nameidata *ndp;
5e00df3b 472 register struct filedesc *fdp = p->p_fd;
fc2aed1e 473 int error;
8429d022 474 struct nameidata nd;
3e78e260 475
8429d022 476 ndp = &nd;
fc2aed1e 477 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
715baff1
KM
478 ndp->ni_segflg = UIO_USERSPACE;
479 ndp->ni_dirp = uap->fname;
8429d022
MK
480 if (error = chdirec(ndp, p))
481 return (error);
5e00df3b
KM
482 vrele(fdp->fd_cdir);
483 fdp->fd_cdir = ndp->ni_vp;
8429d022 484 return (0);
fc2aed1e
KM
485}
486
487/*
488 * Change notion of root (``/'') directory.
489 */
6a6a1e5f
KM
490/* ARGSUSED */
491chroot(p, uap, retval)
5e00df3b 492 struct proc *p;
6a6a1e5f 493 struct args {
fc2aed1e 494 char *fname;
6a6a1e5f
KM
495 } *uap;
496 int *retval;
497{
8429d022 498 register struct nameidata *ndp;
5e00df3b 499 register struct filedesc *fdp = p->p_fd;
fc2aed1e 500 int error;
8429d022 501 struct nameidata nd;
fc2aed1e 502
8429d022
MK
503 if (error = suser(p->p_ucred, &p->p_acflag))
504 return (error);
505 ndp = &nd;
fc2aed1e
KM
506 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
507 ndp->ni_segflg = UIO_USERSPACE;
508 ndp->ni_dirp = uap->fname;
8429d022
MK
509 if (error = chdirec(ndp, p))
510 return (error);
5e00df3b
KM
511 if (fdp->fd_rdir != NULL)
512 vrele(fdp->fd_rdir);
513 fdp->fd_rdir = ndp->ni_vp;
8429d022 514 return (0);
fc2aed1e
KM
515}
516
517/*
518 * Common routine for chroot and chdir.
519 */
8429d022
MK
520chdirec(ndp, p)
521 struct nameidata *ndp;
522 struct proc *p;
fc2aed1e
KM
523{
524 struct vnode *vp;
525 int error;
526
8429d022 527 if (error = namei(ndp, p))
fc2aed1e
KM
528 return (error);
529 vp = ndp->ni_vp;
530 if (vp->v_type != VDIR)
531 error = ENOTDIR;
532 else
8429d022 533 error = VOP_ACCESS(vp, VEXEC, p->p_ucred);
fc2aed1e
KM
534 VOP_UNLOCK(vp);
535 if (error)
536 vrele(vp);
537 return (error);
3e78e260
BJ
538}
539
540/*
541 * Open system call.
6a6a1e5f
KM
542 * Check permissions, allocate an open file structure,
543 * and call the device open routine if any.
3e78e260 544 */
6a6a1e5f 545open(p, uap, retval)
5e00df3b 546 struct proc *p;
6a6a1e5f 547 register struct args {
3e78e260 548 char *fname;
528f664c 549 int mode;
88a7a62a 550 int crtmode;
6a6a1e5f
KM
551 } *uap;
552 int *retval;
3e78e260 553{
8429d022 554 struct nameidata *ndp;
5e00df3b 555 register struct filedesc *fdp = p->p_fd;
3e78e260 556 register struct file *fp;
6a6a1e5f 557 int fmode, cmode;
fc2aed1e
KM
558 struct file *nfp;
559 int indx, error;
8429d022 560 struct nameidata nd;
fc2aed1e
KM
561 extern struct fileops vnops;
562
5e00df3b 563 if (error = falloc(p, &nfp, &indx))
8429d022 564 return (error);
fc2aed1e 565 fp = nfp;
13b8b20b 566 fmode = FFLAGS(uap->mode);
5e00df3b 567 cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX;
8429d022 568 ndp = &nd;
6a6a1e5f
KM
569 ndp->ni_segflg = UIO_USERSPACE;
570 ndp->ni_dirp = uap->fname;
03951846 571 p->p_dupfd = -indx - 1; /* XXX check for fdopen */
8429d022 572 if (error = vn_open(ndp, p, fmode, cmode)) {
fc2aed1e
KM
573 crfree(fp->f_cred);
574 fp->f_count--;
198ba51a 575 if (error == ENODEV && /* XXX from fdopen */
03951846 576 p->p_dupfd >= 0 &&
5e00df3b 577 (error = dupfdopen(fdp, indx, p->p_dupfd, fmode)) == 0) {
6a6a1e5f 578 *retval = indx;
8429d022 579 return (0);
6a6a1e5f 580 }
b10521d6
KM
581 if (error == ERESTART)
582 error = EINTR;
5e00df3b 583 OFILE(fdp, indx) = NULL;
8429d022 584 return (error);
528f664c 585 }
fc2aed1e
KM
586 fp->f_flag = fmode & FMASK;
587 fp->f_type = DTYPE_VNODE;
588 fp->f_ops = &vnops;
589 fp->f_data = (caddr_t)ndp->ni_vp;
6a6a1e5f 590 *retval = indx;
8429d022 591 return (0);
3e78e260
BJ
592}
593
4fde03dc 594#ifdef COMPAT_43
3e78e260 595/*
6a6a1e5f 596 * Creat system call.
3e78e260 597 */
4fde03dc 598ocreat(p, uap, retval)
6a6a1e5f
KM
599 struct proc *p;
600 register struct args {
601 char *fname;
602 int fmode;
603 } *uap;
604 int *retval;
3e78e260 605{
6a6a1e5f
KM
606 struct args {
607 char *fname;
608 int mode;
609 int crtmode;
610 } openuap;
611
612 openuap.fname = uap->fname;
613 openuap.crtmode = uap->fmode;
614 openuap.mode = O_WRONLY | O_CREAT | O_TRUNC;
8429d022 615 return (open(p, &openuap, retval));
6a6a1e5f 616}
4fde03dc 617#endif /* COMPAT_43 */
6a6a1e5f
KM
618
619/*
620 * Mknod system call
621 */
622/* ARGSUSED */
623mknod(p, uap, retval)
5e00df3b 624 struct proc *p;
6a6a1e5f 625 register struct args {
3e78e260
BJ
626 char *fname;
627 int fmode;
628 int dev;
6a6a1e5f
KM
629 } *uap;
630 int *retval;
631{
8429d022 632 register struct nameidata *ndp;
fc2aed1e
KM
633 register struct vnode *vp;
634 struct vattr vattr;
635 int error;
8429d022 636 struct nameidata nd;
3e78e260 637
8429d022
MK
638 if (error = suser(p->p_ucred, &p->p_acflag))
639 return (error);
640 ndp = &nd;
fc2aed1e 641 ndp->ni_nameiop = CREATE | LOCKPARENT;
715baff1
KM
642 ndp->ni_segflg = UIO_USERSPACE;
643 ndp->ni_dirp = uap->fname;
8429d022
MK
644 if (error = namei(ndp, p))
645 return (error);
fc2aed1e
KM
646 vp = ndp->ni_vp;
647 if (vp != NULL) {
648 error = EEXIST;
88a7a62a 649 goto out;
3e78e260 650 }
3ee1461b 651 VATTR_NULL(&vattr);
ab389897 652 switch (uap->fmode & S_IFMT) {
88a7a62a 653
ab389897 654 case S_IFMT: /* used by badsect to flag bad sectors */
fc2aed1e
KM
655 vattr.va_type = VBAD;
656 break;
ab389897 657 case S_IFCHR:
fc2aed1e
KM
658 vattr.va_type = VCHR;
659 break;
ab389897 660 case S_IFBLK:
fc2aed1e
KM
661 vattr.va_type = VBLK;
662 break;
663 default:
664 error = EINVAL;
665 goto out;
3e78e260 666 }
5e00df3b 667 vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
fc2aed1e 668 vattr.va_rdev = uap->dev;
3e78e260 669out:
66955caf 670 if (!error) {
8429d022 671 error = VOP_MKNOD(ndp, &vattr, p->p_ucred);
66955caf
KM
672 } else {
673 VOP_ABORTOP(ndp);
6c44e83b
KM
674 if (ndp->ni_dvp == vp)
675 vrele(ndp->ni_dvp);
676 else
677 vput(ndp->ni_dvp);
66955caf
KM
678 if (vp)
679 vrele(vp);
680 }
8429d022 681 return (error);
3e78e260
BJ
682}
683
4751dd21
KM
684/*
685 * Mkfifo system call
686 */
6a6a1e5f
KM
687/* ARGSUSED */
688mkfifo(p, uap, retval)
5e00df3b 689 struct proc *p;
6a6a1e5f 690 register struct args {
4751dd21
KM
691 char *fname;
692 int fmode;
6a6a1e5f
KM
693 } *uap;
694 int *retval;
695{
8429d022 696 register struct nameidata *ndp;
4751dd21
KM
697 struct vattr vattr;
698 int error;
8429d022 699 struct nameidata nd;
4751dd21
KM
700
701#ifndef FIFO
8429d022 702 return (EOPNOTSUPP);
4751dd21 703#else
8429d022 704 ndp = &nd;
4751dd21
KM
705 ndp->ni_nameiop = CREATE | LOCKPARENT;
706 ndp->ni_segflg = UIO_USERSPACE;
707 ndp->ni_dirp = uap->fname;
8429d022
MK
708 if (error = namei(ndp, p))
709 return (error);
4751dd21
KM
710 if (ndp->ni_vp != NULL) {
711 VOP_ABORTOP(ndp);
6c44e83b
KM
712 if (ndp->ni_dvp == ndp->ni_vp)
713 vrele(ndp->ni_dvp);
714 else
715 vput(ndp->ni_dvp);
66955caf 716 vrele(ndp->ni_vp);
8429d022 717 return (EEXIST);
4751dd21 718 }
3658f091
KB
719 VATTR_NULL(&vattr);
720 vattr.va_type = VFIFO;
5e00df3b 721 vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
8429d022 722 return (VOP_MKNOD(ndp, &vattr, p->p_ucred));
4751dd21
KM
723#endif /* FIFO */
724}
725
3e78e260
BJ
726/*
727 * link system call
728 */
6a6a1e5f
KM
729/* ARGSUSED */
730link(p, uap, retval)
5e00df3b 731 struct proc *p;
6a6a1e5f 732 register struct args {
3e78e260
BJ
733 char *target;
734 char *linkname;
6a6a1e5f
KM
735 } *uap;
736 int *retval;
737{
8429d022 738 register struct nameidata *ndp;
fc2aed1e
KM
739 register struct vnode *vp, *xp;
740 int error;
8429d022 741 struct nameidata nd;
3e78e260 742
8429d022 743 ndp = &nd;
715baff1
KM
744 ndp->ni_nameiop = LOOKUP | FOLLOW;
745 ndp->ni_segflg = UIO_USERSPACE;
746 ndp->ni_dirp = uap->target;
8429d022
MK
747 if (error = namei(ndp, p))
748 return (error);
fc2aed1e
KM
749 vp = ndp->ni_vp;
750 if (vp->v_type == VDIR &&
8429d022 751 (error = suser(p->p_ucred, &p->p_acflag)))
fc2aed1e
KM
752 goto out1;
753 ndp->ni_nameiop = CREATE | LOCKPARENT;
715baff1 754 ndp->ni_dirp = (caddr_t)uap->linkname;
8429d022 755 if (error = namei(ndp, p))
fc2aed1e
KM
756 goto out1;
757 xp = ndp->ni_vp;
3e78e260 758 if (xp != NULL) {
fc2aed1e 759 error = EEXIST;
3e78e260
BJ
760 goto out;
761 }
fc2aed1e
KM
762 xp = ndp->ni_dvp;
763 if (vp->v_mount != xp->v_mount)
764 error = EXDEV;
3e78e260 765out:
66955caf 766 if (!error) {
fc2aed1e 767 error = VOP_LINK(vp, ndp);
66955caf
KM
768 } else {
769 VOP_ABORTOP(ndp);
6c44e83b
KM
770 if (ndp->ni_dvp == ndp->ni_vp)
771 vrele(ndp->ni_dvp);
772 else
773 vput(ndp->ni_dvp);
66955caf
KM
774 if (ndp->ni_vp)
775 vrele(ndp->ni_vp);
776 }
fc2aed1e
KM
777out1:
778 vrele(vp);
8429d022 779 return (error);
3e78e260
BJ
780}
781
782/*
783 * symlink -- make a symbolic link
784 */
6a6a1e5f
KM
785/* ARGSUSED */
786symlink(p, uap, retval)
5e00df3b 787 struct proc *p;
6a6a1e5f 788 register struct args {
3e78e260
BJ
789 char *target;
790 char *linkname;
6a6a1e5f
KM
791 } *uap;
792 int *retval;
793{
8429d022 794 register struct nameidata *ndp;
fc2aed1e
KM
795 struct vattr vattr;
796 char *target;
797 int error;
8429d022 798 struct nameidata nd;
3e78e260 799
8429d022 800 ndp = &nd;
715baff1
KM
801 ndp->ni_segflg = UIO_USERSPACE;
802 ndp->ni_dirp = uap->linkname;
fc2aed1e
KM
803 MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
804 if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
66955caf 805 goto out;
fc2aed1e 806 ndp->ni_nameiop = CREATE | LOCKPARENT;
8429d022 807 if (error = namei(ndp, p))
66955caf
KM
808 goto out;
809 if (ndp->ni_vp) {
810 VOP_ABORTOP(ndp);
6c44e83b
KM
811 if (ndp->ni_dvp == ndp->ni_vp)
812 vrele(ndp->ni_dvp);
813 else
814 vput(ndp->ni_dvp);
66955caf 815 vrele(ndp->ni_vp);
fc2aed1e
KM
816 error = EEXIST;
817 goto out;
3e78e260 818 }
3ee1461b 819 VATTR_NULL(&vattr);
5e00df3b 820 vattr.va_mode = 0777 &~ p->p_fd->fd_cmask;
66955caf 821 error = VOP_SYMLINK(ndp, &vattr, target);
fc2aed1e 822out:
fc2aed1e 823 FREE(target, M_NAMEI);
8429d022 824 return (error);
3e78e260
BJ
825}
826
827/*
828 * Unlink system call.
829 * Hard to avoid races here, especially
830 * in unlinking directories.
831 */
6a6a1e5f
KM
832/* ARGSUSED */
833unlink(p, uap, retval)
5e00df3b 834 struct proc *p;
6a6a1e5f 835 struct args {
3e78e260 836 char *fname;
6a6a1e5f
KM
837 } *uap;
838 int *retval;
839{
8429d022 840 register struct nameidata *ndp;
fc2aed1e
KM
841 register struct vnode *vp;
842 int error;
8429d022 843 struct nameidata nd;
3e78e260 844
8429d022 845 ndp = &nd;
fc2aed1e 846 ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
715baff1
KM
847 ndp->ni_segflg = UIO_USERSPACE;
848 ndp->ni_dirp = uap->fname;
8429d022
MK
849 if (error = namei(ndp, p))
850 return (error);
fc2aed1e
KM
851 vp = ndp->ni_vp;
852 if (vp->v_type == VDIR &&
8429d022 853 (error = suser(p->p_ucred, &p->p_acflag)))
3e78e260
BJ
854 goto out;
855 /*
856 * Don't unlink a mounted file.
857 */
fc2aed1e
KM
858 if (vp->v_flag & VROOT) {
859 error = EBUSY;
3e78e260
BJ
860 goto out;
861 }
a42e0ed8 862#ifdef NVM
9db58063 863 (void) vnode_pager_uncache(vp);
a42e0ed8
KM
864#else
865 if (vp->v_flag & VTEXT)
866 xrele(vp); /* try once to free text */
867#endif
3e78e260 868out:
66955caf 869 if (!error) {
fc2aed1e 870 error = VOP_REMOVE(ndp);
66955caf
KM
871 } else {
872 VOP_ABORTOP(ndp);
6c44e83b
KM
873 if (ndp->ni_dvp == vp)
874 vrele(ndp->ni_dvp);
875 else
876 vput(ndp->ni_dvp);
66955caf
KM
877 vput(vp);
878 }
8429d022 879 return (error);
3e78e260
BJ
880}
881
882/*
883 * Seek system call
884 */
6a6a1e5f 885lseek(p, uap, retval)
5e00df3b 886 struct proc *p;
6a6a1e5f 887 register struct args {
fc2aed1e 888 int fdes;
3e78e260
BJ
889 off_t off;
890 int sbase;
6a6a1e5f
KM
891 } *uap;
892 off_t *retval;
893{
8429d022 894 struct ucred *cred = p->p_ucred;
5e00df3b 895 register struct filedesc *fdp = p->p_fd;
6a6a1e5f 896 register struct file *fp;
fc2aed1e
KM
897 struct vattr vattr;
898 int error;
899
8429d022 900 if ((unsigned)uap->fdes >= fdp->fd_nfiles ||
5e00df3b 901 (fp = OFILE(fdp, uap->fdes)) == NULL)
8429d022 902 return (EBADF);
fc2aed1e 903 if (fp->f_type != DTYPE_VNODE)
8429d022 904 return (ESPIPE);
b4d1aee9
SL
905 switch (uap->sbase) {
906
907 case L_INCR:
908 fp->f_offset += uap->off;
909 break;
910
911 case L_XTND:
fc2aed1e 912 if (error = VOP_GETATTR((struct vnode *)fp->f_data,
6a6a1e5f 913 &vattr, cred))
8429d022 914 return (error);
fc2aed1e 915 fp->f_offset = uap->off + vattr.va_size;
b4d1aee9
SL
916 break;
917
918 case L_SET:
919 fp->f_offset = uap->off;
920 break;
921
922 default:
8429d022 923 return (EINVAL);
b4d1aee9 924 }
6a6a1e5f 925 *retval = fp->f_offset;
8429d022 926 return (0);
3e78e260
BJ
927}
928
929/*
930 * Access system call
931 */
6a6a1e5f
KM
932/* ARGSUSED */
933saccess(p, uap, retval)
5e00df3b 934 struct proc *p;
6a6a1e5f 935 register struct args {
3e78e260
BJ
936 char *fname;
937 int fmode;
6a6a1e5f
KM
938 } *uap;
939 int *retval;
940{
8429d022
MK
941 register struct nameidata *ndp;
942 register struct ucred *cred = p->p_ucred;
fc2aed1e
KM
943 register struct vnode *vp;
944 int error, mode, svuid, svgid;
8429d022 945 struct nameidata nd;
3e78e260 946
8429d022 947 ndp = &nd;
6a6a1e5f
KM
948 svuid = cred->cr_uid;
949 svgid = cred->cr_groups[0];
8429d022
MK
950 cred->cr_uid = p->p_cred->p_ruid;
951 cred->cr_groups[0] = p->p_cred->p_rgid;
fc2aed1e 952 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
715baff1
KM
953 ndp->ni_segflg = UIO_USERSPACE;
954 ndp->ni_dirp = uap->fname;
8429d022 955 if (error = namei(ndp, p))
fc2aed1e
KM
956 goto out1;
957 vp = ndp->ni_vp;
958 /*
959 * fmode == 0 means only check for exist
960 */
961 if (uap->fmode) {
962 mode = 0;
963 if (uap->fmode & R_OK)
964 mode |= VREAD;
965 if (uap->fmode & W_OK)
966 mode |= VWRITE;
967 if (uap->fmode & X_OK)
968 mode |= VEXEC;
9230ead4 969 if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
8429d022 970 error = VOP_ACCESS(vp, mode, cred);
3e78e260 971 }
fc2aed1e
KM
972 vput(vp);
973out1:
6a6a1e5f
KM
974 cred->cr_uid = svuid;
975 cred->cr_groups[0] = svgid;
8429d022 976 return (error);
3e78e260 977}
d67a03eb 978
d67a03eb 979/*
6459ebe0 980 * Stat system call. This version follows links.
d67a03eb 981 */
6a6a1e5f
KM
982/* ARGSUSED */
983stat(p, uap, retval)
5e00df3b 984 struct proc *p;
6a6a1e5f
KM
985 register struct args {
986 char *fname;
987 struct stat *ub;
988 } *uap;
989 int *retval;
d67a03eb 990{
8429d022 991 register struct nameidata *ndp;
6a6a1e5f
KM
992 struct stat sb;
993 int error;
8429d022 994 struct nameidata nd;
d67a03eb 995
8429d022 996 ndp = &nd;
6a6a1e5f
KM
997 ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
998 ndp->ni_segflg = UIO_USERSPACE;
999 ndp->ni_dirp = uap->fname;
8429d022
MK
1000 if (error = namei(ndp, p))
1001 return (error);
6a6a1e5f
KM
1002 error = vn_stat(ndp->ni_vp, &sb);
1003 vput(ndp->ni_vp);
1004 if (error)
8429d022 1005 return (error);
6a6a1e5f 1006 error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
8429d022 1007 return (error);
d67a03eb
BJ
1008}
1009
5485e062 1010/*
6459ebe0 1011 * Lstat system call. This version does not follow links.
5485e062 1012 */
6a6a1e5f
KM
1013/* ARGSUSED */
1014lstat(p, uap, retval)
5e00df3b 1015 struct proc *p;
6a6a1e5f 1016 register struct args {
5485e062 1017 char *fname;
88a7a62a 1018 struct stat *ub;
6a6a1e5f
KM
1019 } *uap;
1020 int *retval;
1021{
8429d022 1022 register struct nameidata *ndp;
fc2aed1e
KM
1023 struct stat sb;
1024 int error;
8429d022 1025 struct nameidata nd;
5485e062 1026
8429d022 1027 ndp = &nd;
6a6a1e5f 1028 ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW;
715baff1
KM
1029 ndp->ni_segflg = UIO_USERSPACE;
1030 ndp->ni_dirp = uap->fname;
8429d022
MK
1031 if (error = namei(ndp, p))
1032 return (error);
fc2aed1e
KM
1033 error = vn_stat(ndp->ni_vp, &sb);
1034 vput(ndp->ni_vp);
1035 if (error)
8429d022 1036 return (error);
fc2aed1e 1037 error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
8429d022 1038 return (error);
d67a03eb
BJ
1039}
1040
1041/*
5485e062
BJ
1042 * Return target name of a symbolic link
1043 */
6a6a1e5f
KM
1044/* ARGSUSED */
1045readlink(p, uap, retval)
5e00df3b 1046 struct proc *p;
6a6a1e5f 1047 register struct args {
5485e062
BJ
1048 char *name;
1049 char *buf;
1050 int count;
6a6a1e5f
KM
1051 } *uap;
1052 int *retval;
1053{
8429d022 1054 register struct nameidata *ndp;
fc2aed1e
KM
1055 register struct vnode *vp;
1056 struct iovec aiov;
1057 struct uio auio;
1058 int error;
8429d022 1059 struct nameidata nd;
5485e062 1060
8429d022 1061 ndp = &nd;
fc2aed1e 1062 ndp->ni_nameiop = LOOKUP | LOCKLEAF;
715baff1
KM
1063 ndp->ni_segflg = UIO_USERSPACE;
1064 ndp->ni_dirp = uap->name;
8429d022
MK
1065 if (error = namei(ndp, p))
1066 return (error);
fc2aed1e
KM
1067 vp = ndp->ni_vp;
1068 if (vp->v_type != VLNK) {
1069 error = EINVAL;
5485e062
BJ
1070 goto out;
1071 }
fc2aed1e
KM
1072 aiov.iov_base = uap->buf;
1073 aiov.iov_len = uap->count;
1074 auio.uio_iov = &aiov;
1075 auio.uio_iovcnt = 1;
1076 auio.uio_offset = 0;
1077 auio.uio_rw = UIO_READ;
1078 auio.uio_segflg = UIO_USERSPACE;
1079 auio.uio_resid = uap->count;
8429d022 1080 error = VOP_READLINK(vp, &auio, p->p_ucred);
5485e062 1081out:
fc2aed1e 1082 vput(vp);
6a6a1e5f 1083 *retval = uap->count - auio.uio_resid;
8429d022 1084 return (error);
5485e062
BJ
1085}
1086
6995a2cb
KM
1087/*
1088 * Change flags of a file given path name.
1089 */
6a6a1e5f
KM
1090/* ARGSUSED */
1091chflags(p, uap, retval)
5e00df3b 1092 struct proc *p;
6a6a1e5f 1093 register struct args {
6995a2cb
KM
1094 char *fname;
1095 int flags;
6a6a1e5f
KM
1096 } *uap;
1097 int *retval;
1098{
8429d022 1099 register struct nameidata *ndp;
6995a2cb
KM
1100 register struct vnode *vp;
1101 struct vattr vattr;
1102 int error;
8429d022 1103 struct nameidata nd;
6995a2cb 1104
8429d022 1105 ndp = &nd;
6995a2cb
KM
1106 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
1107 ndp->ni_segflg = UIO_USERSPACE;
1108 ndp->ni_dirp = uap->fname;
8429d022
MK
1109 if (error = namei(ndp, p))
1110 return (error);
6995a2cb 1111 vp = ndp->ni_vp;
54fb9dc2 1112 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
6995a2cb
KM
1113 error = EROFS;
1114 goto out;
1115 }
3658f091
KB
1116 VATTR_NULL(&vattr);
1117 vattr.va_flags = uap->flags;
8429d022 1118 error = VOP_SETATTR(vp, &vattr, p->p_ucred);
6995a2cb
KM
1119out:
1120 vput(vp);
8429d022 1121 return (error);
6995a2cb
KM
1122}
1123
1124/*
1125 * Change flags of a file given a file descriptor.
1126 */
6a6a1e5f
KM
1127/* ARGSUSED */
1128fchflags(p, uap, retval)
5e00df3b 1129 struct proc *p;
6a6a1e5f 1130 register struct args {
6995a2cb
KM
1131 int fd;
1132 int flags;
6a6a1e5f
KM
1133 } *uap;
1134 int *retval;
1135{
6995a2cb
KM
1136 struct vattr vattr;
1137 struct vnode *vp;
1138 struct file *fp;
1139 int error;
1140
5e00df3b 1141 if (error = getvnode(p->p_fd, uap->fd, &fp))
8429d022 1142 return (error);
6995a2cb
KM
1143 vp = (struct vnode *)fp->f_data;
1144 VOP_LOCK(vp);
54fb9dc2 1145 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
6995a2cb
KM
1146 error = EROFS;
1147 goto out;
1148 }
3658f091
KB
1149 VATTR_NULL(&vattr);
1150 vattr.va_flags = uap->flags;
8429d022 1151 error = VOP_SETATTR(vp, &vattr, p->p_ucred);
6995a2cb
KM
1152out:
1153 VOP_UNLOCK(vp);
8429d022 1154 return (error);
6995a2cb
KM
1155}
1156
4f083fd7
SL
1157/*
1158 * Change mode of a file given path name.
1159 */
6a6a1e5f
KM
1160/* ARGSUSED */
1161chmod(p, uap, retval)
5e00df3b 1162 struct proc *p;
6a6a1e5f 1163 register struct args {
3e78e260
BJ
1164 char *fname;
1165 int fmode;
6a6a1e5f
KM
1166 } *uap;
1167 int *retval;
1168{
8429d022 1169 register struct nameidata *ndp;
fc2aed1e
KM
1170 register struct vnode *vp;
1171 struct vattr vattr;
1172 int error;
8429d022 1173 struct nameidata nd;
5485e062 1174
8429d022 1175 ndp = &nd;
fc2aed1e
KM
1176 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
1177 ndp->ni_segflg = UIO_USERSPACE;
1178 ndp->ni_dirp = uap->fname;
8429d022
MK
1179 if (error = namei(ndp, p))
1180 return (error);
fc2aed1e 1181 vp = ndp->ni_vp;
54fb9dc2 1182 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
fc2aed1e
KM
1183 error = EROFS;
1184 goto out;
1185 }
3658f091
KB
1186 VATTR_NULL(&vattr);
1187 vattr.va_mode = uap->fmode & 07777;
8429d022 1188 error = VOP_SETATTR(vp, &vattr, p->p_ucred);
fc2aed1e
KM
1189out:
1190 vput(vp);
8429d022 1191 return (error);
528f664c 1192}
f94ceb3b 1193
4f083fd7
SL
1194/*
1195 * Change mode of a file given a file descriptor.
1196 */
6a6a1e5f
KM
1197/* ARGSUSED */
1198fchmod(p, uap, retval)
5e00df3b 1199 struct proc *p;
6a6a1e5f 1200 register struct args {
528f664c
SL
1201 int fd;
1202 int fmode;
6a6a1e5f
KM
1203 } *uap;
1204 int *retval;
1205{
fc2aed1e
KM
1206 struct vattr vattr;
1207 struct vnode *vp;
1208 struct file *fp;
1209 int error;
1210
5e00df3b 1211 if (error = getvnode(p->p_fd, uap->fd, &fp))
8429d022 1212 return (error);
fc2aed1e
KM
1213 vp = (struct vnode *)fp->f_data;
1214 VOP_LOCK(vp);
54fb9dc2 1215 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
fc2aed1e
KM
1216 error = EROFS;
1217 goto out;
f94ceb3b 1218 }
3658f091
KB
1219 VATTR_NULL(&vattr);
1220 vattr.va_mode = uap->fmode & 07777;
8429d022 1221 error = VOP_SETATTR(vp, &vattr, p->p_ucred);
fc2aed1e
KM
1222out:
1223 VOP_UNLOCK(vp);
8429d022 1224 return (error);
5485e062
BJ
1225}
1226
4f083fd7
SL
1227/*
1228 * Set ownership given a path name.
1229 */
6a6a1e5f
KM
1230/* ARGSUSED */
1231chown(p, uap, retval)
5e00df3b 1232 struct proc *p;
6a6a1e5f 1233 register struct args {
3e78e260
BJ
1234 char *fname;
1235 int uid;
1236 int gid;
6a6a1e5f
KM
1237 } *uap;
1238 int *retval;
1239{
8429d022 1240 register struct nameidata *ndp;
fc2aed1e
KM
1241 register struct vnode *vp;
1242 struct vattr vattr;
1243 int error;
8429d022 1244 struct nameidata nd;
d67a03eb 1245
8429d022 1246 ndp = &nd;
fc2aed1e 1247 ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
18b0bce6
KB
1248 ndp->ni_segflg = UIO_USERSPACE;
1249 ndp->ni_dirp = uap->fname;
8429d022
MK
1250 if (error = namei(ndp, p))
1251 return (error);
fc2aed1e 1252 vp = ndp->ni_vp;
54fb9dc2 1253 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
fc2aed1e
KM
1254 error = EROFS;
1255 goto out;
1256 }
3658f091
KB
1257 VATTR_NULL(&vattr);
1258 vattr.va_uid = uap->uid;
1259 vattr.va_gid = uap->gid;
8429d022 1260 error = VOP_SETATTR(vp, &vattr, p->p_ucred);
fc2aed1e
KM
1261out:
1262 vput(vp);
8429d022 1263 return (error);
528f664c 1264}
f94ceb3b 1265
4f083fd7
SL
1266/*
1267 * Set ownership given a file descriptor.
1268 */
6a6a1e5f
KM
1269/* ARGSUSED */
1270fchown(p, uap, retval)
5e00df3b 1271 struct proc *p;
6a6a1e5f 1272 register struct args {
528f664c
SL
1273 int fd;
1274 int uid;
1275 int gid;
6a6a1e5f
KM
1276 } *uap;
1277 int *retval;
1278{
fc2aed1e
KM
1279 struct vattr vattr;
1280 struct vnode *vp;
1281 struct file *fp;
1282 int error;
1283
5e00df3b 1284 if (error = getvnode(p->p_fd, uap->fd, &fp))
8429d022 1285 return (error);
fc2aed1e
KM
1286 vp = (struct vnode *)fp->f_data;
1287 VOP_LOCK(vp);
54fb9dc2 1288 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
fc2aed1e
KM
1289 error = EROFS;
1290 goto out;
1291 }
3658f091
KB
1292 VATTR_NULL(&vattr);
1293 vattr.va_uid = uap->uid;
1294 vattr.va_gid = uap->gid;
8429d022 1295 error = VOP_SETATTR(vp, &vattr, p->p_ucred);
fc2aed1e
KM
1296out:
1297 VOP_UNLOCK(vp);
8429d022 1298 return (error);
d67a03eb
BJ
1299}
1300
6a6a1e5f
KM
1301/*
1302 * Set the access and modification times of a file.
1303 */
1304/* ARGSUSED */
1305utimes(p, uap, retval)
5e00df3b 1306 struct proc *p;
6a6a1e5f 1307 register struct args {
bb1b75f4
SL
1308 char *fname;
1309 struct timeval *tptr;
6a6a1e5f
KM
1310 } *uap;
1311 int *retval;
1312{
8429d022 1313 register struct nameidata *ndp;
fc2aed1e 1314 register struct vnode *vp;
bb1b75f4 1315 struct timeval tv[2];
fc2aed1e
KM
1316 struct vattr vattr;
1317 int error;
8429d022 1318 struct nameidata nd;
bb1b75f4 1319
fc2aed1e 1320 if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
8429d022
MK
1321 return (error);
1322 ndp = &nd;
fc2aed1e
KM
1323 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
1324 ndp->ni_segflg = UIO_USERSPACE;
1325 ndp->ni_dirp = uap->fname;
8429d022
MK
1326 if (error = namei(ndp, p))
1327 return (error);
fc2aed1e 1328 vp = ndp->ni_vp;
54fb9dc2 1329 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
fc2aed1e
KM
1330 error = EROFS;
1331 goto out;
bb1b75f4 1332 }
3658f091
KB
1333 VATTR_NULL(&vattr);
1334 vattr.va_atime = tv[0];
1335 vattr.va_mtime = tv[1];
8429d022 1336 error = VOP_SETATTR(vp, &vattr, p->p_ucred);
fc2aed1e
KM
1337out:
1338 vput(vp);
8429d022 1339 return (error);
d67a03eb 1340}
64d3a787 1341
4f083fd7
SL
1342/*
1343 * Truncate a file given its path name.
1344 */
6a6a1e5f
KM
1345/* ARGSUSED */
1346truncate(p, uap, retval)
5e00df3b 1347 struct proc *p;
6a6a1e5f 1348 register struct args {
528f664c 1349 char *fname;
c979c6ce 1350 off_t length;
6a6a1e5f
KM
1351 } *uap;
1352 int *retval;
1353{
8429d022 1354 register struct nameidata *ndp;
fc2aed1e
KM
1355 register struct vnode *vp;
1356 struct vattr vattr;
1357 int error;
8429d022 1358 struct nameidata nd;
528f664c 1359
8429d022 1360 ndp = &nd;
fc2aed1e 1361 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
715baff1
KM
1362 ndp->ni_segflg = UIO_USERSPACE;
1363 ndp->ni_dirp = uap->fname;
8429d022
MK
1364 if (error = namei(ndp, p))
1365 return (error);
fc2aed1e
KM
1366 vp = ndp->ni_vp;
1367 if (vp->v_type == VDIR) {
1368 error = EISDIR;
1369 goto out;
528f664c 1370 }
d7b2a16c 1371 if ((error = vn_writechk(vp)) ||
8429d022 1372 (error = VOP_ACCESS(vp, VWRITE, p->p_ucred)))
fc2aed1e 1373 goto out;
3658f091
KB
1374 VATTR_NULL(&vattr);
1375 vattr.va_size = uap->length;
8429d022 1376 error = VOP_SETATTR(vp, &vattr, p->p_ucred);
fc2aed1e
KM
1377out:
1378 vput(vp);
8429d022 1379 return (error);
528f664c
SL
1380}
1381
4f083fd7
SL
1382/*
1383 * Truncate a file given a file descriptor.
1384 */
6a6a1e5f
KM
1385/* ARGSUSED */
1386ftruncate(p, uap, retval)
5e00df3b 1387 struct proc *p;
6a6a1e5f 1388 register struct args {
528f664c 1389 int fd;
c979c6ce 1390 off_t length;
6a6a1e5f
KM
1391 } *uap;
1392 int *retval;
1393{
fc2aed1e
KM
1394 struct vattr vattr;
1395 struct vnode *vp;
528f664c 1396 struct file *fp;
fc2aed1e
KM
1397 int error;
1398
5e00df3b 1399 if (error = getvnode(p->p_fd, uap->fd, &fp))
8429d022 1400 return (error);
fc2aed1e 1401 if ((fp->f_flag & FWRITE) == 0)
8429d022 1402 return (EINVAL);
fc2aed1e
KM
1403 vp = (struct vnode *)fp->f_data;
1404 VOP_LOCK(vp);
1405 if (vp->v_type == VDIR) {
1406 error = EISDIR;
1407 goto out;
528f664c 1408 }
d7b2a16c 1409 if (error = vn_writechk(vp))
fc2aed1e 1410 goto out;
3658f091
KB
1411 VATTR_NULL(&vattr);
1412 vattr.va_size = uap->length;
fc2aed1e
KM
1413 error = VOP_SETATTR(vp, &vattr, fp->f_cred);
1414out:
1415 VOP_UNLOCK(vp);
8429d022 1416 return (error);
4f083fd7
SL
1417}
1418
1419/*
1420 * Synch an open file.
1421 */
6a6a1e5f
KM
1422/* ARGSUSED */
1423fsync(p, uap, retval)
5e00df3b 1424 struct proc *p;
6a6a1e5f 1425 struct args {
4f083fd7 1426 int fd;
6a6a1e5f
KM
1427 } *uap;
1428 int *retval;
1429{
e79467ea 1430 register struct vnode *vp;
4f083fd7 1431 struct file *fp;
fc2aed1e 1432 int error;
4f083fd7 1433
5e00df3b 1434 if (error = getvnode(p->p_fd, uap->fd, &fp))
8429d022 1435 return (error);
e79467ea
KM
1436 vp = (struct vnode *)fp->f_data;
1437 VOP_LOCK(vp);
1438 error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT);
1439 VOP_UNLOCK(vp);
8429d022 1440 return (error);
528f664c
SL
1441}
1442
4f083fd7
SL
1443/*
1444 * Rename system call.
4f083fd7
SL
1445 *
1446 * Source and destination must either both be directories, or both
1447 * not be directories. If target is a directory, it must be empty.
1448 */
6a6a1e5f
KM
1449/* ARGSUSED */
1450rename(p, uap, retval)
5e00df3b 1451 struct proc *p;
6a6a1e5f 1452 register struct args {
528f664c
SL
1453 char *from;
1454 char *to;
6a6a1e5f
KM
1455 } *uap;
1456 int *retval;
1457{
fc2aed1e 1458 register struct vnode *tvp, *fvp, *tdvp;
8429d022 1459 register struct nameidata *ndp;
fc2aed1e 1460 int error;
8429d022 1461 struct nameidata nd, tond;
4f083fd7 1462
8429d022 1463 ndp = &nd;
fc2aed1e 1464 ndp->ni_nameiop = DELETE | WANTPARENT;
715baff1
KM
1465 ndp->ni_segflg = UIO_USERSPACE;
1466 ndp->ni_dirp = uap->from;
8429d022
MK
1467 if (error = namei(ndp, p))
1468 return (error);
fc2aed1e 1469 fvp = ndp->ni_vp;
41eb2f3d 1470 nddup(ndp, &tond);
fc2aed1e
KM
1471 tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
1472 tond.ni_segflg = UIO_USERSPACE;
1473 tond.ni_dirp = uap->to;
8429d022 1474 if (error = namei(&tond, p)) {
66955caf
KM
1475 VOP_ABORTOP(ndp);
1476 vrele(ndp->ni_dvp);
1477 vrele(fvp);
1478 goto out1;
1479 }
fc2aed1e
KM
1480 tdvp = tond.ni_dvp;
1481 tvp = tond.ni_vp;
1482 if (tvp != NULL) {
1483 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
9259ee95 1484 error = ENOTDIR;
fc2aed1e
KM
1485 goto out;
1486 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
9259ee95 1487 error = EISDIR;
fc2aed1e 1488 goto out;
a5390dce 1489 }
73f5d967
KM
1490 if (fvp->v_mount != tvp->v_mount) {
1491 error = EXDEV;
1492 goto out;
1493 }
4f083fd7 1494 }
fc2aed1e
KM
1495 if (fvp->v_mount != tdvp->v_mount) {
1496 error = EXDEV;
1497 goto out;
64d3a787 1498 }
fe562f32 1499 if (fvp == tdvp)
fc2aed1e 1500 error = EINVAL;
fe562f32
KM
1501 /*
1502 * If source is the same as the destination,
1503 * then there is nothing to do.
1504 */
1505 if (fvp == tvp)
1506 error = -1;
fc2aed1e 1507out:
66955caf
KM
1508 if (!error) {
1509 error = VOP_RENAME(ndp, &tond);
1510 } else {
fc2aed1e 1511 VOP_ABORTOP(&tond);
6c44e83b
KM
1512 if (tdvp == tvp)
1513 vrele(tdvp);
1514 else
1515 vput(tdvp);
66955caf
KM
1516 if (tvp)
1517 vput(tvp);
fc2aed1e 1518 VOP_ABORTOP(ndp);
66955caf
KM
1519 vrele(ndp->ni_dvp);
1520 vrele(fvp);
64d3a787 1521 }
fc2aed1e 1522out1:
41eb2f3d 1523 ndrele(&tond);
fe562f32 1524 if (error == -1)
8429d022
MK
1525 return (0);
1526 return (error);
64d3a787 1527}
88a7a62a 1528
88a7a62a
SL
1529/*
1530 * Mkdir system call
1531 */
6a6a1e5f
KM
1532/* ARGSUSED */
1533mkdir(p, uap, retval)
5e00df3b 1534 struct proc *p;
6a6a1e5f 1535 register struct args {
88a7a62a
SL
1536 char *name;
1537 int dmode;
6a6a1e5f
KM
1538 } *uap;
1539 int *retval;
1540{
8429d022 1541 register struct nameidata *ndp;
fc2aed1e
KM
1542 register struct vnode *vp;
1543 struct vattr vattr;
1544 int error;
8429d022 1545 struct nameidata nd;
88a7a62a 1546
8429d022 1547 ndp = &nd;
fc2aed1e 1548 ndp->ni_nameiop = CREATE | LOCKPARENT;
715baff1
KM
1549 ndp->ni_segflg = UIO_USERSPACE;
1550 ndp->ni_dirp = uap->name;
8429d022
MK
1551 if (error = namei(ndp, p))
1552 return (error);
fc2aed1e
KM
1553 vp = ndp->ni_vp;
1554 if (vp != NULL) {
1555 VOP_ABORTOP(ndp);
6c44e83b
KM
1556 if (ndp->ni_dvp == vp)
1557 vrele(ndp->ni_dvp);
1558 else
1559 vput(ndp->ni_dvp);
66955caf 1560 vrele(vp);
8429d022 1561 return (EEXIST);
88a7a62a 1562 }
3ee1461b 1563 VATTR_NULL(&vattr);
fc2aed1e 1564 vattr.va_type = VDIR;
5e00df3b 1565 vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask;
fc2aed1e 1566 error = VOP_MKDIR(ndp, &vattr);
5dfd04f0
KM
1567 if (!error)
1568 vput(ndp->ni_vp);
8429d022 1569 return (error);
88a7a62a
SL
1570}
1571
1572/*
1573 * Rmdir system call.
1574 */
6a6a1e5f
KM
1575/* ARGSUSED */
1576rmdir(p, uap, retval)
5e00df3b 1577 struct proc *p;
6a6a1e5f 1578 struct args {
88a7a62a 1579 char *name;
6a6a1e5f
KM
1580 } *uap;
1581 int *retval;
1582{
8429d022 1583 register struct nameidata *ndp;
fc2aed1e
KM
1584 register struct vnode *vp;
1585 int error;
8429d022 1586 struct nameidata nd;
88a7a62a 1587
8429d022 1588 ndp = &nd;
fc2aed1e 1589 ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
715baff1
KM
1590 ndp->ni_segflg = UIO_USERSPACE;
1591 ndp->ni_dirp = uap->name;
8429d022
MK
1592 if (error = namei(ndp, p))
1593 return (error);
fc2aed1e
KM
1594 vp = ndp->ni_vp;
1595 if (vp->v_type != VDIR) {
1596 error = ENOTDIR;
88a7a62a
SL
1597 goto out;
1598 }
1599 /*
fc2aed1e 1600 * No rmdir "." please.
88a7a62a 1601 */
fc2aed1e
KM
1602 if (ndp->ni_dvp == vp) {
1603 error = EINVAL;
88a7a62a
SL
1604 goto out;
1605 }
1606 /*
fc2aed1e 1607 * Don't unlink a mounted file.
88a7a62a 1608 */
fc2aed1e
KM
1609 if (vp->v_flag & VROOT)
1610 error = EBUSY;
88a7a62a 1611out:
66955caf 1612 if (!error) {
fc2aed1e 1613 error = VOP_RMDIR(ndp);
66955caf
KM
1614 } else {
1615 VOP_ABORTOP(ndp);
6c44e83b
KM
1616 if (ndp->ni_dvp == vp)
1617 vrele(ndp->ni_dvp);
1618 else
1619 vput(ndp->ni_dvp);
66955caf
KM
1620 vput(vp);
1621 }
8429d022 1622 return (error);
88a7a62a
SL
1623}
1624
fc2aed1e
KM
1625/*
1626 * Read a block of directory entries in a file system independent format
1627 */
6a6a1e5f 1628getdirentries(p, uap, retval)
5e00df3b 1629 struct proc *p;
6a6a1e5f 1630 register struct args {
fc2aed1e
KM
1631 int fd;
1632 char *buf;
1633 unsigned count;
1634 long *basep;
6a6a1e5f
KM
1635 } *uap;
1636 int *retval;
1637{
e79467ea 1638 register struct vnode *vp;
8462a185 1639 struct file *fp;
fc2aed1e
KM
1640 struct uio auio;
1641 struct iovec aiov;
58030ad2 1642 off_t off;
c242ace6 1643 int error, eofflag;
fc2aed1e 1644
5e00df3b 1645 if (error = getvnode(p->p_fd, uap->fd, &fp))
8429d022 1646 return (error);
fc2aed1e 1647 if ((fp->f_flag & FREAD) == 0)
8429d022 1648 return (EBADF);
e79467ea
KM
1649 vp = (struct vnode *)fp->f_data;
1650 if (vp->v_type != VDIR)
8429d022 1651 return (EINVAL);
fc2aed1e
KM
1652 aiov.iov_base = uap->buf;
1653 aiov.iov_len = uap->count;
1654 auio.uio_iov = &aiov;
1655 auio.uio_iovcnt = 1;
1656 auio.uio_rw = UIO_READ;
1657 auio.uio_segflg = UIO_USERSPACE;
1658 auio.uio_resid = uap->count;
e79467ea
KM
1659 VOP_LOCK(vp);
1660 auio.uio_offset = off = fp->f_offset;
c242ace6 1661 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag);
e79467ea
KM
1662 fp->f_offset = auio.uio_offset;
1663 VOP_UNLOCK(vp);
1664 if (error)
8429d022 1665 return (error);
e79467ea 1666 error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
6a6a1e5f 1667 *retval = uap->count - auio.uio_resid;
8429d022 1668 return (error);
88a7a62a
SL
1669}
1670
1671/*
1672 * mode mask for creation of files
1673 */
6a6a1e5f
KM
1674mode_t
1675umask(p, uap, retval)
5e00df3b 1676 struct proc *p;
6a6a1e5f 1677 struct args {
88a7a62a 1678 int mask;
6a6a1e5f
KM
1679 } *uap;
1680 int *retval;
1681{
5e00df3b 1682 register struct filedesc *fdp = p->p_fd;
88a7a62a 1683
5e00df3b
KM
1684 *retval = fdp->fd_cmask;
1685 fdp->fd_cmask = uap->mask & 07777;
8429d022 1686 return (0);
fc2aed1e
KM
1687}
1688
b0a98f13
MT
1689/*
1690 * Void all references to file by ripping underlying filesystem
1691 * away from vnode.
1692 */
6a6a1e5f
KM
1693/* ARGSUSED */
1694revoke(p, uap, retval)
5e00df3b 1695 struct proc *p;
6a6a1e5f 1696 register struct args {
b0a98f13 1697 char *fname;
6a6a1e5f
KM
1698 } *uap;
1699 int *retval;
1700{
8429d022 1701 register struct nameidata *ndp;
b0a98f13
MT
1702 register struct vnode *vp;
1703 struct vattr vattr;
1704 int error;
8429d022 1705 struct nameidata nd;
b0a98f13 1706
8429d022 1707 ndp = &nd;
b0a98f13
MT
1708 ndp->ni_nameiop = LOOKUP | FOLLOW;
1709 ndp->ni_segflg = UIO_USERSPACE;
1710 ndp->ni_dirp = uap->fname;
8429d022
MK
1711 if (error = namei(ndp, p))
1712 return (error);
b0a98f13
MT
1713 vp = ndp->ni_vp;
1714 if (vp->v_type != VCHR && vp->v_type != VBLK) {
1715 error = EINVAL;
1716 goto out;
1717 }
8429d022 1718 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred))
b0a98f13 1719 goto out;
8429d022
MK
1720 if (p->p_ucred->cr_uid != vattr.va_uid &&
1721 (error = suser(p->p_ucred, &p->p_acflag)))
b0a98f13 1722 goto out;
8b81d198 1723 if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
c9345cca 1724 vgoneall(vp);
b0a98f13
MT
1725out:
1726 vrele(vp);
8429d022 1727 return (error);
b0a98f13
MT
1728}
1729
5e00df3b
KM
1730getvnode(fdp, fdes, fpp)
1731 struct filedesc *fdp;
fc2aed1e
KM
1732 struct file **fpp;
1733 int fdes;
1734{
1735 struct file *fp;
1736
8429d022 1737 if ((unsigned)fdes >= fdp->fd_nfiles ||
5e00df3b 1738 (fp = OFILE(fdp, fdes)) == NULL)
fc2aed1e
KM
1739 return (EBADF);
1740 if (fp->f_type != DTYPE_VNODE)
1741 return (EINVAL);
1742 *fpp = fp;
1743 return (0);
88a7a62a 1744}