new calling convension for system calls
[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 *
6a6a1e5f 17 * @(#)vfs_syscalls.c 7.48 (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
6a6a1e5f 33#define RETURN(val) { u.u_error = (val); if (u.u_spare[0] != 0) panic("lock count"); return (u.u_error); }
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;
561 u.u_r.u_rv.R_val1 = indx; /* XXX for fdopen() */
562 if (error = vn_open(ndp, fmode, cmode)) {
fc2aed1e
KM
563 crfree(fp->f_cred);
564 fp->f_count--;
6a6a1e5f
KM
565 if (error == EJUSTRETURN) { /* XXX from fdopen */
566 *retval = indx;
567 RETURN (0);
568 }
b10521d6
KM
569 if (error == ERESTART)
570 error = EINTR;
6a6a1e5f
KM
571 u.u_ofile[indx] = NULL;
572 RETURN (error);
528f664c 573 }
fc2aed1e
KM
574 fp->f_flag = fmode & FMASK;
575 fp->f_type = DTYPE_VNODE;
576 fp->f_ops = &vnops;
577 fp->f_data = (caddr_t)ndp->ni_vp;
6a6a1e5f
KM
578 *retval = indx;
579 RETURN (0);
3e78e260
BJ
580}
581
582/*
6a6a1e5f 583 * Creat system call.
3e78e260 584 */
6a6a1e5f
KM
585creat(p, uap, retval)
586 struct proc *p;
587 register struct args {
588 char *fname;
589 int fmode;
590 } *uap;
591 int *retval;
3e78e260 592{
6a6a1e5f
KM
593 struct args {
594 char *fname;
595 int mode;
596 int crtmode;
597 } openuap;
598
599 openuap.fname = uap->fname;
600 openuap.crtmode = uap->fmode;
601 openuap.mode = O_WRONLY | O_CREAT | O_TRUNC;
602 RETURN (open(p, &openuap, retval));
603}
604
605/*
606 * Mknod system call
607 */
608/* ARGSUSED */
609mknod(p, uap, retval)
610 register struct proc *p;
611 register struct args {
3e78e260
BJ
612 char *fname;
613 int fmode;
614 int dev;
6a6a1e5f
KM
615 } *uap;
616 int *retval;
617{
618 register struct nameidata *ndp = &u.u_nd;
fc2aed1e
KM
619 register struct vnode *vp;
620 struct vattr vattr;
621 int error;
3e78e260 622
6a6a1e5f 623 if (error = suser(ndp->ni_cred, &u.u_acflag))
fc2aed1e
KM
624 RETURN (error);
625 ndp->ni_nameiop = CREATE | LOCKPARENT;
715baff1
KM
626 ndp->ni_segflg = UIO_USERSPACE;
627 ndp->ni_dirp = uap->fname;
fc2aed1e
KM
628 if (error = namei(ndp))
629 RETURN (error);
630 vp = ndp->ni_vp;
631 if (vp != NULL) {
632 error = EEXIST;
88a7a62a 633 goto out;
3e78e260 634 }
3ee1461b 635 VATTR_NULL(&vattr);
ab389897 636 switch (uap->fmode & S_IFMT) {
88a7a62a 637
ab389897 638 case S_IFMT: /* used by badsect to flag bad sectors */
fc2aed1e
KM
639 vattr.va_type = VBAD;
640 break;
ab389897 641 case S_IFCHR:
fc2aed1e
KM
642 vattr.va_type = VCHR;
643 break;
ab389897 644 case S_IFBLK:
fc2aed1e
KM
645 vattr.va_type = VBLK;
646 break;
647 default:
648 error = EINVAL;
649 goto out;
3e78e260 650 }
6a6a1e5f 651 vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask;
fc2aed1e 652 vattr.va_rdev = uap->dev;
3e78e260 653out:
fc2aed1e
KM
654 if (error)
655 VOP_ABORTOP(ndp);
656 else
657 error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
658 RETURN (error);
3e78e260
BJ
659}
660
4751dd21
KM
661/*
662 * Mkfifo system call
663 */
6a6a1e5f
KM
664/* ARGSUSED */
665mkfifo(p, uap, retval)
666 register struct proc *p;
667 register struct args {
4751dd21
KM
668 char *fname;
669 int fmode;
6a6a1e5f
KM
670 } *uap;
671 int *retval;
672{
673 register struct nameidata *ndp = &u.u_nd;
4751dd21
KM
674 struct vattr vattr;
675 int error;
676
677#ifndef FIFO
678 RETURN (EOPNOTSUPP);
679#else
680 ndp->ni_nameiop = CREATE | LOCKPARENT;
681 ndp->ni_segflg = UIO_USERSPACE;
682 ndp->ni_dirp = uap->fname;
683 if (error = namei(ndp))
684 RETURN (error);
685 if (ndp->ni_vp != NULL) {
686 VOP_ABORTOP(ndp);
687 RETURN (EEXIST);
688 } else {
3ee1461b 689 VATTR_NULL(&vattr);
4751dd21 690 vattr.va_type = VFIFO;
6a6a1e5f 691 vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask;
4751dd21
KM
692 }
693 RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred));
694#endif /* FIFO */
695}
696
3e78e260
BJ
697/*
698 * link system call
699 */
6a6a1e5f
KM
700/* ARGSUSED */
701link(p, uap, retval)
702 register struct proc *p;
703 register struct args {
3e78e260
BJ
704 char *target;
705 char *linkname;
6a6a1e5f
KM
706 } *uap;
707 int *retval;
708{
709 register struct nameidata *ndp = &u.u_nd;
fc2aed1e
KM
710 register struct vnode *vp, *xp;
711 int error;
3e78e260 712
715baff1
KM
713 ndp->ni_nameiop = LOOKUP | FOLLOW;
714 ndp->ni_segflg = UIO_USERSPACE;
715 ndp->ni_dirp = uap->target;
fc2aed1e
KM
716 if (error = namei(ndp))
717 RETURN (error);
718 vp = ndp->ni_vp;
719 if (vp->v_type == VDIR &&
6a6a1e5f 720 (error = suser(ndp->ni_cred, &u.u_acflag)))
fc2aed1e
KM
721 goto out1;
722 ndp->ni_nameiop = CREATE | LOCKPARENT;
715baff1 723 ndp->ni_dirp = (caddr_t)uap->linkname;
fc2aed1e
KM
724 if (error = namei(ndp))
725 goto out1;
726 xp = ndp->ni_vp;
3e78e260 727 if (xp != NULL) {
fc2aed1e 728 error = EEXIST;
3e78e260
BJ
729 goto out;
730 }
fc2aed1e
KM
731 xp = ndp->ni_dvp;
732 if (vp->v_mount != xp->v_mount)
733 error = EXDEV;
3e78e260 734out:
fc2aed1e
KM
735 if (error)
736 VOP_ABORTOP(ndp);
737 else
738 error = VOP_LINK(vp, ndp);
739out1:
740 vrele(vp);
741 RETURN (error);
3e78e260
BJ
742}
743
744/*
745 * symlink -- make a symbolic link
746 */
6a6a1e5f
KM
747/* ARGSUSED */
748symlink(p, uap, retval)
749 register struct proc *p;
750 register struct args {
3e78e260
BJ
751 char *target;
752 char *linkname;
6a6a1e5f
KM
753 } *uap;
754 int *retval;
755{
756 register struct nameidata *ndp = &u.u_nd;
fc2aed1e
KM
757 register struct vnode *vp;
758 struct vattr vattr;
759 char *target;
760 int error;
3e78e260 761
715baff1
KM
762 ndp->ni_segflg = UIO_USERSPACE;
763 ndp->ni_dirp = uap->linkname;
fc2aed1e
KM
764 MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
765 if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
766 goto out1;
767 ndp->ni_nameiop = CREATE | LOCKPARENT;
768 if (error = namei(ndp))
769 goto out1;
770 vp = ndp->ni_vp;
771 if (vp) {
772 error = EEXIST;
773 goto out;
3e78e260 774 }
fc2aed1e 775 vp = ndp->ni_dvp;
3ee1461b 776 VATTR_NULL(&vattr);
6a6a1e5f 777 vattr.va_mode = 0777 &~ u.u_cmask;
fc2aed1e
KM
778out:
779 if (error)
780 VOP_ABORTOP(ndp);
781 else
782 error = VOP_SYMLINK(ndp, &vattr, target);
783out1:
784 FREE(target, M_NAMEI);
785 RETURN (error);
3e78e260
BJ
786}
787
788/*
789 * Unlink system call.
790 * Hard to avoid races here, especially
791 * in unlinking directories.
792 */
6a6a1e5f
KM
793/* ARGSUSED */
794unlink(p, uap, retval)
795 register struct proc *p;
796 struct args {
3e78e260 797 char *fname;
6a6a1e5f
KM
798 } *uap;
799 int *retval;
800{
801 register struct nameidata *ndp = &u.u_nd;
fc2aed1e
KM
802 register struct vnode *vp;
803 int error;
3e78e260 804
fc2aed1e 805 ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
715baff1
KM
806 ndp->ni_segflg = UIO_USERSPACE;
807 ndp->ni_dirp = uap->fname;
fc2aed1e
KM
808 if (error = namei(ndp))
809 RETURN (error);
810 vp = ndp->ni_vp;
811 if (vp->v_type == VDIR &&
6a6a1e5f 812 (error = suser(ndp->ni_cred, &u.u_acflag)))
3e78e260
BJ
813 goto out;
814 /*
815 * Don't unlink a mounted file.
816 */
fc2aed1e
KM
817 if (vp->v_flag & VROOT) {
818 error = EBUSY;
3e78e260
BJ
819 goto out;
820 }
fc2aed1e
KM
821 if (vp->v_flag & VTEXT)
822 xrele(vp); /* try once to free text */
3e78e260 823out:
fc2aed1e
KM
824 if (error)
825 VOP_ABORTOP(ndp);
8eee8525 826 else
fc2aed1e
KM
827 error = VOP_REMOVE(ndp);
828 RETURN (error);
3e78e260
BJ
829}
830
831/*
832 * Seek system call
833 */
6a6a1e5f
KM
834lseek(p, uap, retval)
835 register struct proc *p;
836 register struct args {
fc2aed1e 837 int fdes;
3e78e260
BJ
838 off_t off;
839 int sbase;
6a6a1e5f
KM
840 } *uap;
841 off_t *retval;
842{
843 struct ucred *cred = u.u_nd.ni_cred;
844 register struct file *fp;
fc2aed1e
KM
845 struct vattr vattr;
846 int error;
847
848 if ((unsigned)uap->fdes >= NOFILE ||
6a6a1e5f 849 (fp = u.u_ofile[uap->fdes]) == NULL)
fc2aed1e
KM
850 RETURN (EBADF);
851 if (fp->f_type != DTYPE_VNODE)
852 RETURN (ESPIPE);
b4d1aee9
SL
853 switch (uap->sbase) {
854
855 case L_INCR:
856 fp->f_offset += uap->off;
857 break;
858
859 case L_XTND:
fc2aed1e 860 if (error = VOP_GETATTR((struct vnode *)fp->f_data,
6a6a1e5f 861 &vattr, cred))
fc2aed1e
KM
862 RETURN (error);
863 fp->f_offset = uap->off + vattr.va_size;
b4d1aee9
SL
864 break;
865
866 case L_SET:
867 fp->f_offset = uap->off;
868 break;
869
870 default:
fc2aed1e 871 RETURN (EINVAL);
b4d1aee9 872 }
6a6a1e5f 873 *retval = fp->f_offset;
fc2aed1e 874 RETURN (0);
3e78e260
BJ
875}
876
877/*
878 * Access system call
879 */
6a6a1e5f
KM
880/* ARGSUSED */
881saccess(p, uap, retval)
882 register struct proc *p;
883 register struct args {
3e78e260
BJ
884 char *fname;
885 int fmode;
6a6a1e5f
KM
886 } *uap;
887 int *retval;
888{
889 register struct nameidata *ndp = &u.u_nd;
890 register struct ucred *cred = ndp->ni_cred;
fc2aed1e
KM
891 register struct vnode *vp;
892 int error, mode, svuid, svgid;
3e78e260 893
6a6a1e5f
KM
894 svuid = cred->cr_uid;
895 svgid = cred->cr_groups[0];
896 cred->cr_uid = p->p_ruid;
897 cred->cr_groups[0] = p->p_rgid;
fc2aed1e 898 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
715baff1
KM
899 ndp->ni_segflg = UIO_USERSPACE;
900 ndp->ni_dirp = uap->fname;
fc2aed1e
KM
901 if (error = namei(ndp))
902 goto out1;
903 vp = ndp->ni_vp;
904 /*
905 * fmode == 0 means only check for exist
906 */
907 if (uap->fmode) {
908 mode = 0;
909 if (uap->fmode & R_OK)
910 mode |= VREAD;
911 if (uap->fmode & W_OK)
912 mode |= VWRITE;
913 if (uap->fmode & X_OK)
914 mode |= VEXEC;
9230ead4 915 if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
d7b2a16c 916 error = VOP_ACCESS(vp, mode, ndp->ni_cred);
3e78e260 917 }
fc2aed1e
KM
918 vput(vp);
919out1:
6a6a1e5f
KM
920 cred->cr_uid = svuid;
921 cred->cr_groups[0] = svgid;
fc2aed1e 922 RETURN (error);
3e78e260 923}
d67a03eb 924
d67a03eb 925/*
6459ebe0 926 * Stat system call. This version follows links.
d67a03eb 927 */
6a6a1e5f
KM
928/* ARGSUSED */
929stat(p, uap, retval)
930 register struct proc *p;
931 register struct args {
932 char *fname;
933 struct stat *ub;
934 } *uap;
935 int *retval;
d67a03eb 936{
6a6a1e5f
KM
937 register struct nameidata *ndp = &u.u_nd;
938 struct stat sb;
939 int error;
d67a03eb 940
6a6a1e5f
KM
941 ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
942 ndp->ni_segflg = UIO_USERSPACE;
943 ndp->ni_dirp = uap->fname;
944 if (error = namei(ndp))
945 RETURN (error);
946 error = vn_stat(ndp->ni_vp, &sb);
947 vput(ndp->ni_vp);
948 if (error)
949 RETURN (error);
950 error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
951 RETURN (error);
d67a03eb
BJ
952}
953
5485e062 954/*
6459ebe0 955 * Lstat system call. This version does not follow links.
5485e062 956 */
6a6a1e5f
KM
957/* ARGSUSED */
958lstat(p, uap, retval)
959 register struct proc *p;
960 register struct args {
5485e062 961 char *fname;
88a7a62a 962 struct stat *ub;
6a6a1e5f
KM
963 } *uap;
964 int *retval;
965{
966 register struct nameidata *ndp = &u.u_nd;
fc2aed1e
KM
967 struct stat sb;
968 int error;
5485e062 969
6a6a1e5f 970 ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW;
715baff1
KM
971 ndp->ni_segflg = UIO_USERSPACE;
972 ndp->ni_dirp = uap->fname;
fc2aed1e
KM
973 if (error = namei(ndp))
974 RETURN (error);
975 error = vn_stat(ndp->ni_vp, &sb);
976 vput(ndp->ni_vp);
977 if (error)
978 RETURN (error);
979 error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
980 RETURN (error);
d67a03eb
BJ
981}
982
983/*
5485e062
BJ
984 * Return target name of a symbolic link
985 */
6a6a1e5f
KM
986/* ARGSUSED */
987readlink(p, uap, retval)
988 register struct proc *p;
989 register struct args {
5485e062
BJ
990 char *name;
991 char *buf;
992 int count;
6a6a1e5f
KM
993 } *uap;
994 int *retval;
995{
996 register struct nameidata *ndp = &u.u_nd;
fc2aed1e
KM
997 register struct vnode *vp;
998 struct iovec aiov;
999 struct uio auio;
1000 int error;
5485e062 1001
fc2aed1e 1002 ndp->ni_nameiop = LOOKUP | LOCKLEAF;
715baff1
KM
1003 ndp->ni_segflg = UIO_USERSPACE;
1004 ndp->ni_dirp = uap->name;
fc2aed1e
KM
1005 if (error = namei(ndp))
1006 RETURN (error);
1007 vp = ndp->ni_vp;
1008 if (vp->v_type != VLNK) {
1009 error = EINVAL;
5485e062
BJ
1010 goto out;
1011 }
fc2aed1e
KM
1012 aiov.iov_base = uap->buf;
1013 aiov.iov_len = uap->count;
1014 auio.uio_iov = &aiov;
1015 auio.uio_iovcnt = 1;
1016 auio.uio_offset = 0;
1017 auio.uio_rw = UIO_READ;
1018 auio.uio_segflg = UIO_USERSPACE;
1019 auio.uio_resid = uap->count;
1020 error = VOP_READLINK(vp, &auio, ndp->ni_cred);
5485e062 1021out:
fc2aed1e 1022 vput(vp);
6a6a1e5f 1023 *retval = uap->count - auio.uio_resid;
fc2aed1e 1024 RETURN (error);
5485e062
BJ
1025}
1026
6995a2cb
KM
1027/*
1028 * Change flags of a file given path name.
1029 */
6a6a1e5f
KM
1030/* ARGSUSED */
1031chflags(p, uap, retval)
1032 register struct proc *p;
1033 register struct args {
6995a2cb
KM
1034 char *fname;
1035 int flags;
6a6a1e5f
KM
1036 } *uap;
1037 int *retval;
1038{
1039 register struct nameidata *ndp = &u.u_nd;
6995a2cb
KM
1040 register struct vnode *vp;
1041 struct vattr vattr;
1042 int error;
1043
1044 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
1045 ndp->ni_segflg = UIO_USERSPACE;
1046 ndp->ni_dirp = uap->fname;
3ee1461b 1047 VATTR_NULL(&vattr);
6995a2cb
KM
1048 vattr.va_flags = uap->flags;
1049 if (error = namei(ndp))
1050 RETURN (error);
1051 vp = ndp->ni_vp;
54fb9dc2 1052 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
6995a2cb
KM
1053 error = EROFS;
1054 goto out;
1055 }
1056 error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
1057out:
1058 vput(vp);
1059 RETURN (error);
1060}
1061
1062/*
1063 * Change flags of a file given a file descriptor.
1064 */
6a6a1e5f
KM
1065/* ARGSUSED */
1066fchflags(p, uap, retval)
1067 register struct proc *p;
1068 register struct args {
6995a2cb
KM
1069 int fd;
1070 int flags;
6a6a1e5f
KM
1071 } *uap;
1072 int *retval;
1073{
6995a2cb
KM
1074 struct vattr vattr;
1075 struct vnode *vp;
1076 struct file *fp;
1077 int error;
1078
6a6a1e5f 1079 if (error = getvnode(u.u_ofile, uap->fd, &fp))
6995a2cb 1080 RETURN (error);
3ee1461b 1081 VATTR_NULL(&vattr);
6995a2cb
KM
1082 vattr.va_flags = uap->flags;
1083 vp = (struct vnode *)fp->f_data;
1084 VOP_LOCK(vp);
54fb9dc2 1085 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
6995a2cb
KM
1086 error = EROFS;
1087 goto out;
1088 }
1089 error = VOP_SETATTR(vp, &vattr, fp->f_cred);
1090out:
1091 VOP_UNLOCK(vp);
1092 RETURN (error);
1093}
1094
4f083fd7
SL
1095/*
1096 * Change mode of a file given path name.
1097 */
6a6a1e5f
KM
1098/* ARGSUSED */
1099chmod(p, uap, retval)
1100 register struct proc *p;
1101 register struct args {
3e78e260
BJ
1102 char *fname;
1103 int fmode;
6a6a1e5f
KM
1104 } *uap;
1105 int *retval;
1106{
1107 register struct nameidata *ndp = &u.u_nd;
fc2aed1e
KM
1108 register struct vnode *vp;
1109 struct vattr vattr;
1110 int error;
5485e062 1111
fc2aed1e
KM
1112 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
1113 ndp->ni_segflg = UIO_USERSPACE;
1114 ndp->ni_dirp = uap->fname;
3ee1461b 1115 VATTR_NULL(&vattr);
fc2aed1e
KM
1116 vattr.va_mode = uap->fmode & 07777;
1117 if (error = namei(ndp))
1118 RETURN (error);
1119 vp = ndp->ni_vp;
54fb9dc2 1120 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
fc2aed1e
KM
1121 error = EROFS;
1122 goto out;
1123 }
1124 error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
1125out:
1126 vput(vp);
1127 RETURN (error);
528f664c 1128}
f94ceb3b 1129
4f083fd7
SL
1130/*
1131 * Change mode of a file given a file descriptor.
1132 */
6a6a1e5f
KM
1133/* ARGSUSED */
1134fchmod(p, uap, retval)
1135 register struct proc *p;
1136 register struct args {
528f664c
SL
1137 int fd;
1138 int fmode;
6a6a1e5f
KM
1139 } *uap;
1140 int *retval;
1141{
fc2aed1e
KM
1142 struct vattr vattr;
1143 struct vnode *vp;
1144 struct file *fp;
1145 int error;
1146
6a6a1e5f 1147 if (error = getvnode(u.u_ofile, uap->fd, &fp))
fc2aed1e 1148 RETURN (error);
3ee1461b 1149 VATTR_NULL(&vattr);
fc2aed1e
KM
1150 vattr.va_mode = uap->fmode & 07777;
1151 vp = (struct vnode *)fp->f_data;
1152 VOP_LOCK(vp);
54fb9dc2 1153 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
fc2aed1e
KM
1154 error = EROFS;
1155 goto out;
f94ceb3b 1156 }
fc2aed1e
KM
1157 error = VOP_SETATTR(vp, &vattr, fp->f_cred);
1158out:
1159 VOP_UNLOCK(vp);
1160 RETURN (error);
5485e062
BJ
1161}
1162
4f083fd7
SL
1163/*
1164 * Set ownership given a path name.
1165 */
6a6a1e5f
KM
1166/* ARGSUSED */
1167chown(p, uap, retval)
1168 register struct proc *p;
1169 register struct args {
3e78e260
BJ
1170 char *fname;
1171 int uid;
1172 int gid;
6a6a1e5f
KM
1173 } *uap;
1174 int *retval;
1175{
1176 register struct nameidata *ndp = &u.u_nd;
fc2aed1e
KM
1177 register struct vnode *vp;
1178 struct vattr vattr;
1179 int error;
d67a03eb 1180
fc2aed1e 1181 ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
18b0bce6
KB
1182 ndp->ni_segflg = UIO_USERSPACE;
1183 ndp->ni_dirp = uap->fname;
3ee1461b 1184 VATTR_NULL(&vattr);
fc2aed1e
KM
1185 vattr.va_uid = uap->uid;
1186 vattr.va_gid = uap->gid;
1187 if (error = namei(ndp))
1188 RETURN (error);
1189 vp = ndp->ni_vp;
54fb9dc2 1190 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
fc2aed1e
KM
1191 error = EROFS;
1192 goto out;
1193 }
1194 error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
1195out:
1196 vput(vp);
1197 RETURN (error);
528f664c 1198}
f94ceb3b 1199
4f083fd7
SL
1200/*
1201 * Set ownership given a file descriptor.
1202 */
6a6a1e5f
KM
1203/* ARGSUSED */
1204fchown(p, uap, retval)
1205 register struct proc *p;
1206 register struct args {
528f664c
SL
1207 int fd;
1208 int uid;
1209 int gid;
6a6a1e5f
KM
1210 } *uap;
1211 int *retval;
1212{
fc2aed1e
KM
1213 struct vattr vattr;
1214 struct vnode *vp;
1215 struct file *fp;
1216 int error;
1217
6a6a1e5f 1218 if (error = getvnode(u.u_ofile, uap->fd, &fp))
fc2aed1e 1219 RETURN (error);
3ee1461b 1220 VATTR_NULL(&vattr);
fc2aed1e
KM
1221 vattr.va_uid = uap->uid;
1222 vattr.va_gid = uap->gid;
1223 vp = (struct vnode *)fp->f_data;
1224 VOP_LOCK(vp);
54fb9dc2 1225 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
fc2aed1e
KM
1226 error = EROFS;
1227 goto out;
1228 }
1229 error = VOP_SETATTR(vp, &vattr, fp->f_cred);
1230out:
1231 VOP_UNLOCK(vp);
1232 RETURN (error);
d67a03eb
BJ
1233}
1234
6a6a1e5f
KM
1235/*
1236 * Set the access and modification times of a file.
1237 */
1238/* ARGSUSED */
1239utimes(p, uap, retval)
1240 register struct proc *p;
1241 register struct args {
bb1b75f4
SL
1242 char *fname;
1243 struct timeval *tptr;
6a6a1e5f
KM
1244 } *uap;
1245 int *retval;
1246{
1247 register struct nameidata *ndp = &u.u_nd;
fc2aed1e 1248 register struct vnode *vp;
bb1b75f4 1249 struct timeval tv[2];
fc2aed1e
KM
1250 struct vattr vattr;
1251 int error;
bb1b75f4 1252
fc2aed1e
KM
1253 if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
1254 RETURN (error);
1255 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
1256 ndp->ni_segflg = UIO_USERSPACE;
1257 ndp->ni_dirp = uap->fname;
3ee1461b 1258 VATTR_NULL(&vattr);
fc2aed1e
KM
1259 vattr.va_atime = tv[0];
1260 vattr.va_mtime = tv[1];
1261 if (error = namei(ndp))
1262 RETURN (error);
1263 vp = ndp->ni_vp;
54fb9dc2 1264 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
fc2aed1e
KM
1265 error = EROFS;
1266 goto out;
bb1b75f4 1267 }
fc2aed1e
KM
1268 error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
1269out:
1270 vput(vp);
1271 RETURN (error);
d67a03eb 1272}
64d3a787 1273
4f083fd7
SL
1274/*
1275 * Truncate a file given its path name.
1276 */
6a6a1e5f
KM
1277/* ARGSUSED */
1278truncate(p, uap, retval)
1279 register struct proc *p;
1280 register struct args {
528f664c 1281 char *fname;
c979c6ce 1282 off_t length;
6a6a1e5f
KM
1283 } *uap;
1284 int *retval;
1285{
1286 register struct nameidata *ndp = &u.u_nd;
fc2aed1e
KM
1287 register struct vnode *vp;
1288 struct vattr vattr;
1289 int error;
528f664c 1290
fc2aed1e 1291 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
715baff1
KM
1292 ndp->ni_segflg = UIO_USERSPACE;
1293 ndp->ni_dirp = uap->fname;
3ee1461b 1294 VATTR_NULL(&vattr);
fc2aed1e
KM
1295 vattr.va_size = uap->length;
1296 if (error = namei(ndp))
1297 RETURN (error);
1298 vp = ndp->ni_vp;
1299 if (vp->v_type == VDIR) {
1300 error = EISDIR;
1301 goto out;
528f664c 1302 }
d7b2a16c
KM
1303 if ((error = vn_writechk(vp)) ||
1304 (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
fc2aed1e
KM
1305 goto out;
1306 error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
1307out:
1308 vput(vp);
1309 RETURN (error);
528f664c
SL
1310}
1311
4f083fd7
SL
1312/*
1313 * Truncate a file given a file descriptor.
1314 */
6a6a1e5f
KM
1315/* ARGSUSED */
1316ftruncate(p, uap, retval)
1317 register struct proc *p;
1318 register struct args {
528f664c 1319 int fd;
c979c6ce 1320 off_t length;
6a6a1e5f
KM
1321 } *uap;
1322 int *retval;
1323{
fc2aed1e
KM
1324 struct vattr vattr;
1325 struct vnode *vp;
528f664c 1326 struct file *fp;
fc2aed1e
KM
1327 int error;
1328
6a6a1e5f 1329 if (error = getvnode(u.u_ofile, uap->fd, &fp))
fc2aed1e
KM
1330 RETURN (error);
1331 if ((fp->f_flag & FWRITE) == 0)
1332 RETURN (EINVAL);
3ee1461b 1333 VATTR_NULL(&vattr);
fc2aed1e
KM
1334 vattr.va_size = uap->length;
1335 vp = (struct vnode *)fp->f_data;
1336 VOP_LOCK(vp);
1337 if (vp->v_type == VDIR) {
1338 error = EISDIR;
1339 goto out;
528f664c 1340 }
d7b2a16c 1341 if (error = vn_writechk(vp))
fc2aed1e
KM
1342 goto out;
1343 error = VOP_SETATTR(vp, &vattr, fp->f_cred);
1344out:
1345 VOP_UNLOCK(vp);
1346 RETURN (error);
4f083fd7
SL
1347}
1348
1349/*
1350 * Synch an open file.
1351 */
6a6a1e5f
KM
1352/* ARGSUSED */
1353fsync(p, uap, retval)
1354 register struct proc *p;
1355 struct args {
4f083fd7 1356 int fd;
6a6a1e5f
KM
1357 } *uap;
1358 int *retval;
1359{
e79467ea 1360 register struct vnode *vp;
4f083fd7 1361 struct file *fp;
fc2aed1e 1362 int error;
4f083fd7 1363
6a6a1e5f 1364 if (error = getvnode(u.u_ofile, uap->fd, &fp))
fc2aed1e 1365 RETURN (error);
e79467ea
KM
1366 vp = (struct vnode *)fp->f_data;
1367 VOP_LOCK(vp);
1368 error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT);
1369 VOP_UNLOCK(vp);
fc2aed1e 1370 RETURN (error);
528f664c
SL
1371}
1372
4f083fd7
SL
1373/*
1374 * Rename system call.
4f083fd7
SL
1375 *
1376 * Source and destination must either both be directories, or both
1377 * not be directories. If target is a directory, it must be empty.
1378 */
6a6a1e5f
KM
1379/* ARGSUSED */
1380rename(p, uap, retval)
1381 register struct proc *p;
1382 register struct args {
528f664c
SL
1383 char *from;
1384 char *to;
6a6a1e5f
KM
1385 } *uap;
1386 int *retval;
1387{
fc2aed1e 1388 register struct vnode *tvp, *fvp, *tdvp;
6a6a1e5f 1389 register struct nameidata *ndp = &u.u_nd;
fc2aed1e
KM
1390 struct nameidata tond;
1391 int error;
4f083fd7 1392
fc2aed1e 1393 ndp->ni_nameiop = DELETE | WANTPARENT;
715baff1
KM
1394 ndp->ni_segflg = UIO_USERSPACE;
1395 ndp->ni_dirp = uap->from;
fc2aed1e
KM
1396 if (error = namei(ndp))
1397 RETURN (error);
1398 fvp = ndp->ni_vp;
41eb2f3d 1399 nddup(ndp, &tond);
fc2aed1e
KM
1400 tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
1401 tond.ni_segflg = UIO_USERSPACE;
1402 tond.ni_dirp = uap->to;
fc2aed1e
KM
1403 error = namei(&tond);
1404 tdvp = tond.ni_dvp;
1405 tvp = tond.ni_vp;
1406 if (tvp != NULL) {
1407 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
9259ee95 1408 error = ENOTDIR;
fc2aed1e
KM
1409 goto out;
1410 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
9259ee95 1411 error = EISDIR;
fc2aed1e 1412 goto out;
a5390dce 1413 }
4f083fd7 1414 }
fc2aed1e
KM
1415 if (error) {
1416 VOP_ABORTOP(ndp);
1417 goto out1;
4f083fd7 1418 }
fc2aed1e
KM
1419 if (fvp->v_mount != tdvp->v_mount) {
1420 error = EXDEV;
1421 goto out;
64d3a787 1422 }
fe562f32 1423 if (fvp == tdvp)
fc2aed1e 1424 error = EINVAL;
fe562f32
KM
1425 /*
1426 * If source is the same as the destination,
1427 * then there is nothing to do.
1428 */
1429 if (fvp == tvp)
1430 error = -1;
fc2aed1e
KM
1431out:
1432 if (error) {
1433 VOP_ABORTOP(&tond);
1434 VOP_ABORTOP(ndp);
1435 } else {
1436 error = VOP_RENAME(ndp, &tond);
64d3a787 1437 }
fc2aed1e 1438out1:
41eb2f3d 1439 ndrele(&tond);
fe562f32
KM
1440 if (error == -1)
1441 RETURN (0);
fc2aed1e 1442 RETURN (error);
64d3a787 1443}
88a7a62a 1444
88a7a62a
SL
1445/*
1446 * Mkdir system call
1447 */
6a6a1e5f
KM
1448/* ARGSUSED */
1449mkdir(p, uap, retval)
1450 register struct proc *p;
1451 register struct args {
88a7a62a
SL
1452 char *name;
1453 int dmode;
6a6a1e5f
KM
1454 } *uap;
1455 int *retval;
1456{
1457 register struct nameidata *ndp = &u.u_nd;
fc2aed1e
KM
1458 register struct vnode *vp;
1459 struct vattr vattr;
1460 int error;
88a7a62a 1461
fc2aed1e 1462 ndp->ni_nameiop = CREATE | LOCKPARENT;
715baff1
KM
1463 ndp->ni_segflg = UIO_USERSPACE;
1464 ndp->ni_dirp = uap->name;
fc2aed1e
KM
1465 if (error = namei(ndp))
1466 RETURN (error);
1467 vp = ndp->ni_vp;
1468 if (vp != NULL) {
1469 VOP_ABORTOP(ndp);
1470 RETURN (EEXIST);
88a7a62a 1471 }
3ee1461b 1472 VATTR_NULL(&vattr);
fc2aed1e 1473 vattr.va_type = VDIR;
6a6a1e5f 1474 vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask;
fc2aed1e 1475 error = VOP_MKDIR(ndp, &vattr);
5dfd04f0
KM
1476 if (!error)
1477 vput(ndp->ni_vp);
fc2aed1e 1478 RETURN (error);
88a7a62a
SL
1479}
1480
1481/*
1482 * Rmdir system call.
1483 */
6a6a1e5f
KM
1484/* ARGSUSED */
1485rmdir(p, uap, retval)
1486 register struct proc *p;
1487 struct args {
88a7a62a 1488 char *name;
6a6a1e5f
KM
1489 } *uap;
1490 int *retval;
1491{
1492 register struct nameidata *ndp = &u.u_nd;
fc2aed1e
KM
1493 register struct vnode *vp;
1494 int error;
88a7a62a 1495
fc2aed1e 1496 ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
715baff1
KM
1497 ndp->ni_segflg = UIO_USERSPACE;
1498 ndp->ni_dirp = uap->name;
fc2aed1e
KM
1499 if (error = namei(ndp))
1500 RETURN (error);
1501 vp = ndp->ni_vp;
1502 if (vp->v_type != VDIR) {
1503 error = ENOTDIR;
88a7a62a
SL
1504 goto out;
1505 }
1506 /*
fc2aed1e 1507 * No rmdir "." please.
88a7a62a 1508 */
fc2aed1e
KM
1509 if (ndp->ni_dvp == vp) {
1510 error = EINVAL;
88a7a62a
SL
1511 goto out;
1512 }
1513 /*
fc2aed1e 1514 * Don't unlink a mounted file.
88a7a62a 1515 */
fc2aed1e
KM
1516 if (vp->v_flag & VROOT)
1517 error = EBUSY;
88a7a62a 1518out:
fc2aed1e
KM
1519 if (error)
1520 VOP_ABORTOP(ndp);
1521 else
1522 error = VOP_RMDIR(ndp);
1523 RETURN (error);
88a7a62a
SL
1524}
1525
fc2aed1e
KM
1526/*
1527 * Read a block of directory entries in a file system independent format
1528 */
6a6a1e5f
KM
1529getdirentries(p, uap, retval)
1530 register struct proc *p;
1531 register struct args {
fc2aed1e
KM
1532 int fd;
1533 char *buf;
1534 unsigned count;
1535 long *basep;
6a6a1e5f
KM
1536 } *uap;
1537 int *retval;
1538{
e79467ea 1539 register struct vnode *vp;
8462a185 1540 struct file *fp;
fc2aed1e
KM
1541 struct uio auio;
1542 struct iovec aiov;
58030ad2 1543 off_t off;
c242ace6 1544 int error, eofflag;
fc2aed1e 1545
6a6a1e5f 1546 if (error = getvnode(u.u_ofile, uap->fd, &fp))
fc2aed1e
KM
1547 RETURN (error);
1548 if ((fp->f_flag & FREAD) == 0)
1549 RETURN (EBADF);
e79467ea
KM
1550 vp = (struct vnode *)fp->f_data;
1551 if (vp->v_type != VDIR)
1552 RETURN (EINVAL);
fc2aed1e
KM
1553 aiov.iov_base = uap->buf;
1554 aiov.iov_len = uap->count;
1555 auio.uio_iov = &aiov;
1556 auio.uio_iovcnt = 1;
1557 auio.uio_rw = UIO_READ;
1558 auio.uio_segflg = UIO_USERSPACE;
1559 auio.uio_resid = uap->count;
e79467ea
KM
1560 VOP_LOCK(vp);
1561 auio.uio_offset = off = fp->f_offset;
c242ace6 1562 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag);
e79467ea
KM
1563 fp->f_offset = auio.uio_offset;
1564 VOP_UNLOCK(vp);
1565 if (error)
fc2aed1e 1566 RETURN (error);
e79467ea 1567 error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
6a6a1e5f 1568 *retval = uap->count - auio.uio_resid;
fc2aed1e 1569 RETURN (error);
88a7a62a
SL
1570}
1571
1572/*
1573 * mode mask for creation of files
1574 */
6a6a1e5f
KM
1575mode_t
1576umask(p, uap, retval)
1577 register struct proc *p;
1578 struct args {
88a7a62a 1579 int mask;
6a6a1e5f
KM
1580 } *uap;
1581 int *retval;
1582{
88a7a62a 1583
6a6a1e5f
KM
1584 *retval = u.u_cmask;
1585 u.u_cmask = uap->mask & 07777;
fc2aed1e
KM
1586 RETURN (0);
1587}
1588
b0a98f13
MT
1589/*
1590 * Void all references to file by ripping underlying filesystem
1591 * away from vnode.
1592 */
6a6a1e5f
KM
1593/* ARGSUSED */
1594revoke(p, uap, retval)
1595 register struct proc *p;
1596 register struct args {
b0a98f13 1597 char *fname;
a99a44da 1598 int flags;
6a6a1e5f
KM
1599 } *uap;
1600 int *retval;
1601{
1602 register struct nameidata *ndp = &u.u_nd;
b0a98f13
MT
1603 register struct vnode *vp;
1604 struct vattr vattr;
1605 int error;
1606
1607 ndp->ni_nameiop = LOOKUP | FOLLOW;
1608 ndp->ni_segflg = UIO_USERSPACE;
1609 ndp->ni_dirp = uap->fname;
1610 if (error = namei(ndp))
1611 RETURN (error);
1612 vp = ndp->ni_vp;
1613 if (vp->v_type != VCHR && vp->v_type != VBLK) {
1614 error = EINVAL;
1615 goto out;
1616 }
6a6a1e5f 1617 if (error = VOP_GETATTR(vp, &vattr, ndp->ni_cred))
b0a98f13 1618 goto out;
6a6a1e5f
KM
1619 if (ndp->ni_cred->cr_uid != vattr.va_uid ||
1620 (error = suser(ndp->ni_cred, &u.u_acflag)))
b0a98f13 1621 goto out;
8b81d198 1622 if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
c9345cca 1623 vgoneall(vp);
b0a98f13
MT
1624out:
1625 vrele(vp);
1626 RETURN (error);
1627}
1628
601de38e
KM
1629getvnode(ofile, fdes, fpp)
1630 struct file *ofile[];
fc2aed1e
KM
1631 struct file **fpp;
1632 int fdes;
1633{
1634 struct file *fp;
1635
601de38e 1636 if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL)
fc2aed1e
KM
1637 return (EBADF);
1638 if (fp->f_type != DTYPE_VNODE)
1639 return (EINVAL);
1640 *fpp = fp;
1641 return (0);
88a7a62a 1642}