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