pass &u to syscall routines (eventually to become a syscontext)
[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 *
d7b2a16c 17 * @(#)vfs_syscalls.c 7.13 (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
KM
26#include "vnode.h"
27#include "../ufs/inode.h"
28#include "mount.h"
94368568 29#include "proc.h"
94368568 30#include "uio.h"
fc2aed1e 31#include "malloc.h"
88a7a62a 32
fc2aed1e
KM
33/*
34 * Virtual File System System Calls
35 */
3e78e260 36
4f083fd7 37/*
fc2aed1e 38 * mount system call
4f083fd7 39 */
fc2aed1e 40mount()
3e78e260 41{
fc2aed1e
KM
42 register struct a {
43 int type;
44 char *dir;
45 int flags;
46 caddr_t data;
47 } *uap = (struct a *)u.u_ap;
48 register struct nameidata *ndp = &u.u_nd;
49 struct vnode *vp;
50 struct mount *mp;
51 int error;
3e78e260 52
fc2aed1e
KM
53 /*
54 * Must be super user
55 */
56 if (error = suser(u.u_cred, &u.u_acflag))
57 RETURN (error);
58 /*
59 * Get vnode to be covered
60 */
61 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
62 ndp->ni_segflg = UIO_USERSPACE;
63 ndp->ni_dirp = uap->dir;
64 if (error = namei(ndp))
65 RETURN (error);
66 vp = ndp->ni_vp;
67 if (vp->v_count != 1) {
68 vput(vp);
69 RETURN (EBUSY);
70 }
71 if (vp->v_type != VDIR) {
72 vput(vp);
73 RETURN (ENOTDIR);
74 }
75 if (uap->type > MOUNT_MAXTYPE ||
76 vfssw[uap->type] == (struct vfsops *)0) {
77 vput(vp);
78 RETURN (ENODEV);
79 }
80
81 /*
82 * Mount the filesystem.
83 */
84 mp = (struct mount *)malloc((u_long)sizeof(struct mount),
85 M_MOUNT, M_WAITOK);
86 mp->m_op = vfssw[uap->type];
87 mp->m_flag = 0;
88 mp->m_exroot = 0;
89 error = vfs_add(vp, mp, uap->flags);
90 if (!error)
91 error = VFS_MOUNT(mp, uap->dir, uap->data, ndp);
92 cache_purge(vp);
93 VOP_UNLOCK(vp);
94 if (!error) {
95 vfs_unlock(mp);
96 } else {
97 vfs_remove(mp);
98 free((caddr_t)mp, M_MOUNT);
99 vrele(vp);
100 }
101 RETURN (error);
3e78e260
BJ
102}
103
4f083fd7 104/*
fc2aed1e
KM
105 * Unmount system call.
106 *
107 * Note: unmount takes a path to the vnode mounted on as argument,
108 * not special file (as before).
4f083fd7 109 */
fc2aed1e
KM
110unmount()
111{
112 struct a {
113 char *pathp;
114 int flags;
115 } *uap = (struct a *)u.u_ap;
116 register struct vnode *vp;
117 register struct mount *mp;
118 register struct nameidata *ndp = &u.u_nd;
119 struct vnode *coveredvp;
120 int error;
121
122 /*
123 * Must be super user
124 */
125 if (error = suser(u.u_cred, &u.u_acflag))
126 RETURN (error);
127
128 ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
129 ndp->ni_segflg = UIO_USERSPACE;
130 ndp->ni_dirp = uap->pathp;
131 if (error = namei(ndp))
132 RETURN (error);
133 vp = ndp->ni_vp;
134 /*
135 * Must be the root of the filesystem
136 */
137 if ((vp->v_flag & VROOT) == 0) {
138 vput(vp);
139 RETURN (EINVAL);
140 }
141 mp = vp->v_mount;
142 vput(vp);
143 /*
144 * Do the unmount.
145 */
146 coveredvp = mp->m_vnodecovered;
147 if (error = vfs_lock(mp))
148 RETURN (error);
149
150 xumount(mp); /* remove unused sticky files from text table */
151 cache_purgevfs(mp); /* remove cache entries for this file sys */
152 VFS_SYNC(mp, MNT_WAIT);
153
154 error = VFS_UNMOUNT(mp, uap->flags);
155 if (error) {
156 vfs_unlock(mp);
157 } else {
158 vrele(coveredvp);
159 vfs_remove(mp);
160 free((caddr_t)mp, M_MOUNT);
161 }
162 RETURN (error);
163}
164
165/*
166 * Sync system call.
167 * Sync each mounted filesystem.
168 */
169sync()
3e78e260 170{
fc2aed1e
KM
171 register struct mount *mp;
172
173 mp = rootfs;
174 do {
175 if ((mp->m_flag & M_RDONLY) == 0)
176 VFS_SYNC(mp, MNT_NOWAIT);
177 mp = mp->m_next;
178 } while (mp != rootfs);
179}
180
181/*
182 * get filesystem statistics
183 */
184statfs()
185{
186 struct a {
187 char *path;
188 struct statfs *buf;
189 } *uap = (struct a *)u.u_ap;
190 register struct vnode *vp;
191 register struct nameidata *ndp = &u.u_nd;
192 struct statfs sb;
193 int error;
3e78e260 194
fc2aed1e
KM
195 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
196 ndp->ni_segflg = UIO_USERSPACE;
197 ndp->ni_dirp = uap->path;
198 if (error = namei(ndp))
199 RETURN (error);
200 vp = ndp->ni_vp;
201 if (error = VFS_STATFS(vp->v_mount, &sb))
202 goto out;
203 error = copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb));
204out:
205 vput(vp);
206 RETURN (error);
207}
208
209fstatfs()
210{
211 struct a {
212 int fd;
213 struct statfs *buf;
214 } *uap = (struct a *)u.u_ap;
215 struct file *fp;
216 struct statfs sb;
217 int error;
218
219 if (error = getvnode(uap->fd, &fp))
220 RETURN (error);
221 if (error = VFS_STATFS(((struct vnode *)fp->f_data)->v_mount, &sb))
222 RETURN (error);
223 RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)));
3e78e260
BJ
224}
225
bfcdbfbf
KM
226/*
227 * get statistics on all filesystems
228 */
229getfsstat()
230{
231 struct a {
232 struct statfs *buf;
233 long bufsize;
234 } *uap = (struct a *)u.u_ap;
235 register struct mount *mp;
236 register struct statfs *sfsp;
237 long count, maxcount, error;
238
239 maxcount = uap->bufsize / sizeof(struct statfs);
240 sfsp = uap->buf;
241 mp = rootfs;
242 count = 0;
243 do {
244 count++;
245 if (sfsp && count <= maxcount) {
246 if (error = VFS_STATFS(mp, sfsp))
247 RETURN (error);
248 sfsp++;
249 }
250 mp = mp->m_prev;
251 } while (mp != rootfs);
252 if (sfsp && count > maxcount)
253 u.u_r.r_val1 = maxcount;
254 else
255 u.u_r.r_val1 = count;
256 RETURN (0);
257}
258
6995a2cb
KM
259/*
260 * Change current working directory to a given file descriptor.
261 */
262fchdir()
263{
264 struct a {
265 int fd;
266 } *uap = (struct a *)u.u_ap;
267 register struct vnode *vp;
268 struct file *fp;
269 int error;
270
271 if (error = getvnode(uap->fd, &fp))
272 RETURN (error);
273 vp = (struct vnode *)fp->f_data;
274 VOP_LOCK(vp);
275 if (vp->v_type != VDIR)
276 error = ENOTDIR;
277 else
d7b2a16c 278 error = VOP_ACCESS(vp, VEXEC, u.u_cred);
6995a2cb
KM
279 VOP_UNLOCK(vp);
280 vrele(u.u_cdir);
281 u.u_cdir = vp;
282 RETURN (error);
283}
284
4f083fd7 285/*
fc2aed1e 286 * Change current working directory (``.'').
4f083fd7 287 */
fc2aed1e 288chdir()
3e78e260 289{
3e78e260
BJ
290 struct a {
291 char *fname;
715baff1
KM
292 } *uap = (struct a *)u.u_ap;
293 register struct nameidata *ndp = &u.u_nd;
fc2aed1e 294 int error;
3e78e260 295
fc2aed1e 296 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
715baff1
KM
297 ndp->ni_segflg = UIO_USERSPACE;
298 ndp->ni_dirp = uap->fname;
fc2aed1e
KM
299 if (error = chdirec(ndp))
300 RETURN (error);
301 vrele(u.u_cdir);
302 u.u_cdir = ndp->ni_vp;
303 RETURN (0);
304}
305
306/*
307 * Change notion of root (``/'') directory.
308 */
309chroot()
310{
311 struct a {
312 char *fname;
313 } *uap = (struct a *)u.u_ap;
314 register struct nameidata *ndp = &u.u_nd;
315 int error;
316
317 if (error = suser(u.u_cred, &u.u_acflag))
318 RETURN (error);
319 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
320 ndp->ni_segflg = UIO_USERSPACE;
321 ndp->ni_dirp = uap->fname;
322 if (error = chdirec(ndp))
323 RETURN (error);
324 vrele(u.u_rdir);
325 u.u_rdir = ndp->ni_vp;
326 RETURN (0);
327}
328
329/*
330 * Common routine for chroot and chdir.
331 */
332chdirec(ndp)
333 register struct nameidata *ndp;
334{
335 struct vnode *vp;
336 int error;
337
338 if (error = namei(ndp))
339 return (error);
340 vp = ndp->ni_vp;
341 if (vp->v_type != VDIR)
342 error = ENOTDIR;
343 else
d7b2a16c 344 error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
fc2aed1e
KM
345 VOP_UNLOCK(vp);
346 if (error)
347 vrele(vp);
348 return (error);
3e78e260
BJ
349}
350
351/*
352 * Open system call.
353 */
354open()
355{
88a7a62a 356 struct a {
3e78e260 357 char *fname;
528f664c 358 int mode;
88a7a62a
SL
359 int crtmode;
360 } *uap = (struct a *) u.u_ap;
fc2aed1e 361 struct nameidata *ndp = &u.u_nd;
3e78e260 362
fc2aed1e
KM
363 ndp->ni_segflg = UIO_USERSPACE;
364 ndp->ni_dirp = uap->fname;
365 RETURN (copen(uap->mode-FOPEN, uap->crtmode &~ u.u_cmask, ndp,
366 &u.u_r.r_val1));
3e78e260
BJ
367}
368
369/*
370 * Creat system call.
371 */
88a7a62a 372creat()
3e78e260 373{
88a7a62a 374 struct a {
3e78e260
BJ
375 char *fname;
376 int fmode;
88a7a62a 377 } *uap = (struct a *)u.u_ap;
fc2aed1e 378 struct nameidata *ndp = &u.u_nd;
3e78e260 379
fc2aed1e
KM
380 ndp->ni_segflg = UIO_USERSPACE;
381 ndp->ni_dirp = uap->fname;
382 RETURN (copen(FWRITE|FCREAT|FTRUNC, uap->fmode &~ u.u_cmask, ndp,
383 &u.u_r.r_val1));
3e78e260
BJ
384}
385
386/*
387 * Common code for open and creat.
88a7a62a
SL
388 * Check permissions, allocate an open file structure,
389 * and call the device open routine if any.
3e78e260 390 */
fc2aed1e
KM
391copen(fmode, cmode, ndp, resultfd)
392 int fmode, cmode;
393 struct nameidata *ndp;
394 int *resultfd;
3e78e260
BJ
395{
396 register struct file *fp;
fc2aed1e
KM
397 struct file *nfp;
398 int indx, error;
399 extern struct fileops vnops;
400
401 if (error = falloc(&nfp, &indx))
402 return (error);
403 fp = nfp;
404 u.u_r.r_val1 = indx; /* XXX for fdopen() */
405 if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) {
49873122 406 u.u_ofile[indx] = NULL;
fc2aed1e
KM
407 crfree(fp->f_cred);
408 fp->f_count--;
409 return (error);
528f664c 410 }
fc2aed1e
KM
411 fp->f_flag = fmode & FMASK;
412 fp->f_type = DTYPE_VNODE;
413 fp->f_ops = &vnops;
414 fp->f_data = (caddr_t)ndp->ni_vp;
415 if (resultfd)
416 *resultfd = indx;
417 return (0);
3e78e260
BJ
418}
419
420/*
421 * Mknod system call
422 */
423mknod()
424{
3e78e260
BJ
425 register struct a {
426 char *fname;
427 int fmode;
428 int dev;
715baff1
KM
429 } *uap = (struct a *)u.u_ap;
430 register struct nameidata *ndp = &u.u_nd;
fc2aed1e
KM
431 register struct vnode *vp;
432 struct vattr vattr;
433 int error;
3e78e260 434
fc2aed1e
KM
435 if (error = suser(u.u_cred, &u.u_acflag))
436 RETURN (error);
437 ndp->ni_nameiop = CREATE | LOCKPARENT;
715baff1
KM
438 ndp->ni_segflg = UIO_USERSPACE;
439 ndp->ni_dirp = uap->fname;
fc2aed1e
KM
440 if (error = namei(ndp))
441 RETURN (error);
442 vp = ndp->ni_vp;
443 if (vp != NULL) {
444 error = EEXIST;
88a7a62a 445 goto out;
3e78e260 446 }
fc2aed1e
KM
447 vattr_null(&vattr);
448 switch (uap->fmode & IFMT) {
88a7a62a 449
7bfaea72 450 case IFMT: /* used by badsect to flag bad sectors */
fc2aed1e
KM
451 vattr.va_type = VBAD;
452 break;
88a7a62a 453 case IFCHR:
fc2aed1e
KM
454 vattr.va_type = VCHR;
455 break;
88a7a62a 456 case IFBLK:
fc2aed1e
KM
457 vattr.va_type = VBLK;
458 break;
459 default:
460 error = EINVAL;
461 goto out;
3e78e260 462 }
fc2aed1e
KM
463 vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask;
464 vattr.va_rdev = uap->dev;
3e78e260 465out:
fc2aed1e
KM
466 if (error)
467 VOP_ABORTOP(ndp);
468 else
469 error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
470 RETURN (error);
3e78e260
BJ
471}
472
473/*
474 * link system call
475 */
476link()
477{
3e78e260
BJ
478 register struct a {
479 char *target;
480 char *linkname;
715baff1
KM
481 } *uap = (struct a *)u.u_ap;
482 register struct nameidata *ndp = &u.u_nd;
fc2aed1e
KM
483 register struct vnode *vp, *xp;
484 int error;
3e78e260 485
715baff1
KM
486 ndp->ni_nameiop = LOOKUP | FOLLOW;
487 ndp->ni_segflg = UIO_USERSPACE;
488 ndp->ni_dirp = uap->target;
fc2aed1e
KM
489 if (error = namei(ndp))
490 RETURN (error);
491 vp = ndp->ni_vp;
492 if (vp->v_type == VDIR &&
493 (error = suser(u.u_cred, &u.u_acflag)))
494 goto out1;
495 ndp->ni_nameiop = CREATE | LOCKPARENT;
715baff1 496 ndp->ni_dirp = (caddr_t)uap->linkname;
fc2aed1e
KM
497 if (error = namei(ndp))
498 goto out1;
499 xp = ndp->ni_vp;
3e78e260 500 if (xp != NULL) {
fc2aed1e 501 error = EEXIST;
3e78e260
BJ
502 goto out;
503 }
fc2aed1e
KM
504 xp = ndp->ni_dvp;
505 if (vp->v_mount != xp->v_mount)
506 error = EXDEV;
3e78e260 507out:
fc2aed1e
KM
508 if (error)
509 VOP_ABORTOP(ndp);
510 else
511 error = VOP_LINK(vp, ndp);
512out1:
513 vrele(vp);
514 RETURN (error);
3e78e260
BJ
515}
516
517/*
518 * symlink -- make a symbolic link
519 */
520symlink()
521{
fc2aed1e 522 struct a {
3e78e260
BJ
523 char *target;
524 char *linkname;
715baff1 525 } *uap = (struct a *)u.u_ap;
715baff1 526 register struct nameidata *ndp = &u.u_nd;
fc2aed1e
KM
527 register struct vnode *vp;
528 struct vattr vattr;
529 char *target;
530 int error;
3e78e260 531
715baff1
KM
532 ndp->ni_segflg = UIO_USERSPACE;
533 ndp->ni_dirp = uap->linkname;
fc2aed1e
KM
534 MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
535 if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
536 goto out1;
537 ndp->ni_nameiop = CREATE | LOCKPARENT;
538 if (error = namei(ndp))
539 goto out1;
540 vp = ndp->ni_vp;
541 if (vp) {
542 error = EEXIST;
543 goto out;
3e78e260 544 }
fc2aed1e
KM
545 vp = ndp->ni_dvp;
546 vattr_null(&vattr);
547 vattr.va_mode = 0777 &~ u.u_cmask;
548out:
549 if (error)
550 VOP_ABORTOP(ndp);
551 else
552 error = VOP_SYMLINK(ndp, &vattr, target);
553out1:
554 FREE(target, M_NAMEI);
555 RETURN (error);
3e78e260
BJ
556}
557
558/*
559 * Unlink system call.
560 * Hard to avoid races here, especially
561 * in unlinking directories.
562 */
563unlink()
564{
3e78e260
BJ
565 struct a {
566 char *fname;
715baff1 567 } *uap = (struct a *)u.u_ap;
715baff1 568 register struct nameidata *ndp = &u.u_nd;
fc2aed1e
KM
569 register struct vnode *vp;
570 int error;
3e78e260 571
fc2aed1e 572 ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
715baff1
KM
573 ndp->ni_segflg = UIO_USERSPACE;
574 ndp->ni_dirp = uap->fname;
fc2aed1e
KM
575 if (error = namei(ndp))
576 RETURN (error);
577 vp = ndp->ni_vp;
578 if (vp->v_type == VDIR &&
579 (error = suser(u.u_cred, &u.u_acflag)))
3e78e260
BJ
580 goto out;
581 /*
582 * Don't unlink a mounted file.
583 */
fc2aed1e
KM
584 if (vp->v_flag & VROOT) {
585 error = EBUSY;
3e78e260
BJ
586 goto out;
587 }
fc2aed1e
KM
588 if (vp->v_flag & VTEXT)
589 xrele(vp); /* try once to free text */
3e78e260 590out:
fc2aed1e
KM
591 if (error)
592 VOP_ABORTOP(ndp);
8eee8525 593 else
fc2aed1e
KM
594 error = VOP_REMOVE(ndp);
595 RETURN (error);
3e78e260
BJ
596}
597
598/*
599 * Seek system call
600 */
35e7c31a 601lseek()
3e78e260
BJ
602{
603 register struct file *fp;
604 register struct a {
fc2aed1e 605 int fdes;
3e78e260
BJ
606 off_t off;
607 int sbase;
715baff1 608 } *uap = (struct a *)u.u_ap;
fc2aed1e
KM
609 struct vattr vattr;
610 int error;
611
612 if ((unsigned)uap->fdes >= NOFILE ||
613 (fp = u.u_ofile[uap->fdes]) == NULL)
614 RETURN (EBADF);
615 if (fp->f_type != DTYPE_VNODE)
616 RETURN (ESPIPE);
b4d1aee9
SL
617 switch (uap->sbase) {
618
619 case L_INCR:
620 fp->f_offset += uap->off;
621 break;
622
623 case L_XTND:
fc2aed1e
KM
624 if (error = VOP_GETATTR((struct vnode *)fp->f_data,
625 &vattr, u.u_cred))
626 RETURN (error);
627 fp->f_offset = uap->off + vattr.va_size;
b4d1aee9
SL
628 break;
629
630 case L_SET:
631 fp->f_offset = uap->off;
632 break;
633
634 default:
fc2aed1e 635 RETURN (EINVAL);
b4d1aee9
SL
636 }
637 u.u_r.r_off = fp->f_offset;
fc2aed1e 638 RETURN (0);
3e78e260
BJ
639}
640
641/*
642 * Access system call
643 */
644saccess()
645{
3e78e260
BJ
646 register struct a {
647 char *fname;
648 int fmode;
715baff1
KM
649 } *uap = (struct a *)u.u_ap;
650 register struct nameidata *ndp = &u.u_nd;
fc2aed1e
KM
651 register struct vnode *vp;
652 int error, mode, svuid, svgid;
3e78e260 653
3e78e260
BJ
654 svuid = u.u_uid;
655 svgid = u.u_gid;
656 u.u_uid = u.u_ruid;
657 u.u_gid = u.u_rgid;
fc2aed1e 658 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
715baff1
KM
659 ndp->ni_segflg = UIO_USERSPACE;
660 ndp->ni_dirp = uap->fname;
fc2aed1e
KM
661 if (error = namei(ndp))
662 goto out1;
663 vp = ndp->ni_vp;
664 /*
665 * fmode == 0 means only check for exist
666 */
667 if (uap->fmode) {
668 mode = 0;
669 if (uap->fmode & R_OK)
670 mode |= VREAD;
671 if (uap->fmode & W_OK)
672 mode |= VWRITE;
673 if (uap->fmode & X_OK)
674 mode |= VEXEC;
d7b2a16c
KM
675 if ((error = vn_writechk(vp)) == 0)
676 error = VOP_ACCESS(vp, mode, ndp->ni_cred);
3e78e260 677 }
fc2aed1e
KM
678 vput(vp);
679out1:
3e78e260
BJ
680 u.u_uid = svuid;
681 u.u_gid = svgid;
fc2aed1e 682 RETURN (error);
3e78e260 683}
d67a03eb 684
d67a03eb 685/*
6459ebe0 686 * Stat system call. This version follows links.
d67a03eb
BJ
687 */
688stat()
689{
d67a03eb 690
715baff1 691 stat1(FOLLOW);
d67a03eb
BJ
692}
693
5485e062 694/*
6459ebe0 695 * Lstat system call. This version does not follow links.
5485e062
BJ
696 */
697lstat()
88a7a62a
SL
698{
699
715baff1 700 stat1(NOFOLLOW);
88a7a62a
SL
701}
702
703stat1(follow)
704 int follow;
5485e062 705{
5485e062
BJ
706 register struct a {
707 char *fname;
88a7a62a 708 struct stat *ub;
715baff1 709 } *uap = (struct a *)u.u_ap;
715baff1 710 register struct nameidata *ndp = &u.u_nd;
fc2aed1e
KM
711 struct stat sb;
712 int error;
5485e062 713
fc2aed1e 714 ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow;
715baff1
KM
715 ndp->ni_segflg = UIO_USERSPACE;
716 ndp->ni_dirp = uap->fname;
fc2aed1e
KM
717 if (error = namei(ndp))
718 RETURN (error);
719 error = vn_stat(ndp->ni_vp, &sb);
720 vput(ndp->ni_vp);
721 if (error)
722 RETURN (error);
723 error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
724 RETURN (error);
d67a03eb
BJ
725}
726
727/*
5485e062
BJ
728 * Return target name of a symbolic link
729 */
730readlink()
731{
5485e062
BJ
732 register struct a {
733 char *name;
734 char *buf;
735 int count;
31949305 736 } *uap = (struct a *)u.u_ap;
715baff1 737 register struct nameidata *ndp = &u.u_nd;
fc2aed1e
KM
738 register struct vnode *vp;
739 struct iovec aiov;
740 struct uio auio;
741 int error;
5485e062 742
fc2aed1e 743 ndp->ni_nameiop = LOOKUP | LOCKLEAF;
715baff1
KM
744 ndp->ni_segflg = UIO_USERSPACE;
745 ndp->ni_dirp = uap->name;
fc2aed1e
KM
746 if (error = namei(ndp))
747 RETURN (error);
748 vp = ndp->ni_vp;
749 if (vp->v_type != VLNK) {
750 error = EINVAL;
5485e062
BJ
751 goto out;
752 }
fc2aed1e
KM
753 aiov.iov_base = uap->buf;
754 aiov.iov_len = uap->count;
755 auio.uio_iov = &aiov;
756 auio.uio_iovcnt = 1;
757 auio.uio_offset = 0;
758 auio.uio_rw = UIO_READ;
759 auio.uio_segflg = UIO_USERSPACE;
760 auio.uio_resid = uap->count;
761 error = VOP_READLINK(vp, &auio, ndp->ni_cred);
5485e062 762out:
fc2aed1e
KM
763 vput(vp);
764 u.u_r.r_val1 = uap->count - auio.uio_resid;
765 RETURN (error);
5485e062
BJ
766}
767
6995a2cb
KM
768/*
769 * Change flags of a file given path name.
770 */
771chflags()
772{
773 struct a {
774 char *fname;
775 int flags;
776 } *uap = (struct a *)u.u_ap;
777 register struct nameidata *ndp = &u.u_nd;
778 register struct vnode *vp;
779 struct vattr vattr;
780 int error;
781
782 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
783 ndp->ni_segflg = UIO_USERSPACE;
784 ndp->ni_dirp = uap->fname;
785 vattr_null(&vattr);
786 vattr.va_flags = uap->flags;
787 if (error = namei(ndp))
788 RETURN (error);
789 vp = ndp->ni_vp;
790 if (vp->v_mount->m_flag & M_RDONLY) {
791 error = EROFS;
792 goto out;
793 }
794 error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
795out:
796 vput(vp);
797 RETURN (error);
798}
799
800/*
801 * Change flags of a file given a file descriptor.
802 */
803fchflags()
804{
805 struct a {
806 int fd;
807 int flags;
808 } *uap = (struct a *)u.u_ap;
809 struct vattr vattr;
810 struct vnode *vp;
811 struct file *fp;
812 int error;
813
814 if (error = getvnode(uap->fd, &fp))
815 RETURN (error);
816 vattr_null(&vattr);
817 vattr.va_flags = uap->flags;
818 vp = (struct vnode *)fp->f_data;
819 VOP_LOCK(vp);
820 if (vp->v_mount->m_flag & M_RDONLY) {
821 error = EROFS;
822 goto out;
823 }
824 error = VOP_SETATTR(vp, &vattr, fp->f_cred);
825out:
826 VOP_UNLOCK(vp);
827 RETURN (error);
828}
829
4f083fd7
SL
830/*
831 * Change mode of a file given path name.
832 */
3e78e260 833chmod()
5485e062 834{
528f664c 835 struct a {
3e78e260
BJ
836 char *fname;
837 int fmode;
715baff1 838 } *uap = (struct a *)u.u_ap;
fc2aed1e
KM
839 register struct nameidata *ndp = &u.u_nd;
840 register struct vnode *vp;
841 struct vattr vattr;
842 int error;
5485e062 843
fc2aed1e
KM
844 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
845 ndp->ni_segflg = UIO_USERSPACE;
846 ndp->ni_dirp = uap->fname;
847 vattr_null(&vattr);
848 vattr.va_mode = uap->fmode & 07777;
849 if (error = namei(ndp))
850 RETURN (error);
851 vp = ndp->ni_vp;
852 if (vp->v_mount->m_flag & M_RDONLY) {
853 error = EROFS;
854 goto out;
855 }
856 error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
857out:
858 vput(vp);
859 RETURN (error);
528f664c 860}
f94ceb3b 861
4f083fd7
SL
862/*
863 * Change mode of a file given a file descriptor.
864 */
528f664c
SL
865fchmod()
866{
867 struct a {
868 int fd;
869 int fmode;
715baff1 870 } *uap = (struct a *)u.u_ap;
fc2aed1e
KM
871 struct vattr vattr;
872 struct vnode *vp;
873 struct file *fp;
874 int error;
875
876 if (error = getvnode(uap->fd, &fp))
877 RETURN (error);
878 vattr_null(&vattr);
879 vattr.va_mode = uap->fmode & 07777;
880 vp = (struct vnode *)fp->f_data;
881 VOP_LOCK(vp);
882 if (vp->v_mount->m_flag & M_RDONLY) {
883 error = EROFS;
884 goto out;
f94ceb3b 885 }
fc2aed1e
KM
886 error = VOP_SETATTR(vp, &vattr, fp->f_cred);
887out:
888 VOP_UNLOCK(vp);
889 RETURN (error);
5485e062
BJ
890}
891
4f083fd7
SL
892/*
893 * Set ownership given a path name.
894 */
3e78e260 895chown()
d67a03eb 896{
528f664c 897 struct a {
3e78e260
BJ
898 char *fname;
899 int uid;
900 int gid;
715baff1 901 } *uap = (struct a *)u.u_ap;
18b0bce6 902 register struct nameidata *ndp = &u.u_nd;
fc2aed1e
KM
903 register struct vnode *vp;
904 struct vattr vattr;
905 int error;
d67a03eb 906
fc2aed1e 907 ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
18b0bce6
KB
908 ndp->ni_segflg = UIO_USERSPACE;
909 ndp->ni_dirp = uap->fname;
fc2aed1e
KM
910 vattr_null(&vattr);
911 vattr.va_uid = uap->uid;
912 vattr.va_gid = uap->gid;
913 if (error = namei(ndp))
914 RETURN (error);
915 vp = ndp->ni_vp;
916 if (vp->v_mount->m_flag & M_RDONLY) {
917 error = EROFS;
918 goto out;
919 }
920 error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
921out:
922 vput(vp);
923 RETURN (error);
528f664c 924}
f94ceb3b 925
4f083fd7
SL
926/*
927 * Set ownership given a file descriptor.
928 */
528f664c
SL
929fchown()
930{
931 struct a {
932 int fd;
933 int uid;
934 int gid;
715baff1 935 } *uap = (struct a *)u.u_ap;
fc2aed1e
KM
936 struct vattr vattr;
937 struct vnode *vp;
938 struct file *fp;
939 int error;
940
941 if (error = getvnode(uap->fd, &fp))
942 RETURN (error);
943 vattr_null(&vattr);
944 vattr.va_uid = uap->uid;
945 vattr.va_gid = uap->gid;
946 vp = (struct vnode *)fp->f_data;
947 VOP_LOCK(vp);
948 if (vp->v_mount->m_flag & M_RDONLY) {
949 error = EROFS;
950 goto out;
951 }
952 error = VOP_SETATTR(vp, &vattr, fp->f_cred);
953out:
954 VOP_UNLOCK(vp);
955 RETURN (error);
d67a03eb
BJ
956}
957
bb1b75f4
SL
958utimes()
959{
960 register struct a {
961 char *fname;
962 struct timeval *tptr;
963 } *uap = (struct a *)u.u_ap;
fc2aed1e
KM
964 register struct nameidata *ndp = &u.u_nd;
965 register struct vnode *vp;
bb1b75f4 966 struct timeval tv[2];
fc2aed1e
KM
967 struct vattr vattr;
968 int error;
bb1b75f4 969
fc2aed1e
KM
970 if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
971 RETURN (error);
972 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
973 ndp->ni_segflg = UIO_USERSPACE;
974 ndp->ni_dirp = uap->fname;
975 vattr_null(&vattr);
976 vattr.va_atime = tv[0];
977 vattr.va_mtime = tv[1];
978 if (error = namei(ndp))
979 RETURN (error);
980 vp = ndp->ni_vp;
981 if (vp->v_mount->m_flag & M_RDONLY) {
982 error = EROFS;
983 goto out;
bb1b75f4 984 }
fc2aed1e
KM
985 error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
986out:
987 vput(vp);
988 RETURN (error);
d67a03eb 989}
64d3a787 990
4f083fd7
SL
991/*
992 * Truncate a file given its path name.
993 */
528f664c
SL
994truncate()
995{
996 struct a {
997 char *fname;
c979c6ce 998 off_t length;
31949305 999 } *uap = (struct a *)u.u_ap;
715baff1 1000 register struct nameidata *ndp = &u.u_nd;
fc2aed1e
KM
1001 register struct vnode *vp;
1002 struct vattr vattr;
1003 int error;
528f664c 1004
fc2aed1e 1005 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
715baff1
KM
1006 ndp->ni_segflg = UIO_USERSPACE;
1007 ndp->ni_dirp = uap->fname;
fc2aed1e
KM
1008 vattr_null(&vattr);
1009 vattr.va_size = uap->length;
1010 if (error = namei(ndp))
1011 RETURN (error);
1012 vp = ndp->ni_vp;
1013 if (vp->v_type == VDIR) {
1014 error = EISDIR;
1015 goto out;
528f664c 1016 }
d7b2a16c
KM
1017 if ((error = vn_writechk(vp)) ||
1018 (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
fc2aed1e
KM
1019 goto out;
1020 error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
1021out:
1022 vput(vp);
1023 RETURN (error);
528f664c
SL
1024}
1025
4f083fd7
SL
1026/*
1027 * Truncate a file given a file descriptor.
1028 */
528f664c
SL
1029ftruncate()
1030{
1031 struct a {
1032 int fd;
c979c6ce 1033 off_t length;
31949305 1034 } *uap = (struct a *)u.u_ap;
fc2aed1e
KM
1035 struct vattr vattr;
1036 struct vnode *vp;
528f664c 1037 struct file *fp;
fc2aed1e
KM
1038 int error;
1039
1040 if (error = getvnode(uap->fd, &fp))
1041 RETURN (error);
1042 if ((fp->f_flag & FWRITE) == 0)
1043 RETURN (EINVAL);
1044 vattr_null(&vattr);
1045 vattr.va_size = uap->length;
1046 vp = (struct vnode *)fp->f_data;
1047 VOP_LOCK(vp);
1048 if (vp->v_type == VDIR) {
1049 error = EISDIR;
1050 goto out;
528f664c 1051 }
d7b2a16c 1052 if (error = vn_writechk(vp))
fc2aed1e
KM
1053 goto out;
1054 error = VOP_SETATTR(vp, &vattr, fp->f_cred);
1055out:
1056 VOP_UNLOCK(vp);
1057 RETURN (error);
4f083fd7
SL
1058}
1059
1060/*
1061 * Synch an open file.
1062 */
1063fsync()
1064{
1065 struct a {
1066 int fd;
1067 } *uap = (struct a *)u.u_ap;
4f083fd7 1068 struct file *fp;
fc2aed1e 1069 int error;
4f083fd7 1070
fc2aed1e
KM
1071 if (error = getvnode(uap->fd, &fp))
1072 RETURN (error);
1073 error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred);
1074 RETURN (error);
528f664c
SL
1075}
1076
4f083fd7
SL
1077/*
1078 * Rename system call.
4f083fd7
SL
1079 *
1080 * Source and destination must either both be directories, or both
1081 * not be directories. If target is a directory, it must be empty.
1082 */
528f664c
SL
1083rename()
1084{
1085 struct a {
1086 char *from;
1087 char *to;
715baff1 1088 } *uap = (struct a *)u.u_ap;
fc2aed1e 1089 register struct vnode *tvp, *fvp, *tdvp;
715baff1 1090 register struct nameidata *ndp = &u.u_nd;
fc2aed1e
KM
1091 struct nameidata tond;
1092 int error;
4f083fd7 1093
fc2aed1e 1094 ndp->ni_nameiop = DELETE | WANTPARENT;
715baff1
KM
1095 ndp->ni_segflg = UIO_USERSPACE;
1096 ndp->ni_dirp = uap->from;
fc2aed1e
KM
1097 if (error = namei(ndp))
1098 RETURN (error);
1099 fvp = ndp->ni_vp;
41eb2f3d 1100 nddup(ndp, &tond);
fc2aed1e
KM
1101 tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
1102 tond.ni_segflg = UIO_USERSPACE;
1103 tond.ni_dirp = uap->to;
fc2aed1e
KM
1104 error = namei(&tond);
1105 tdvp = tond.ni_dvp;
1106 tvp = tond.ni_vp;
1107 if (tvp != NULL) {
1108 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
a5390dce 1109 error = EISDIR;
fc2aed1e
KM
1110 goto out;
1111 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
1112 error = ENOTDIR;
1113 goto out;
a5390dce 1114 }
4f083fd7 1115 }
fc2aed1e
KM
1116 if (error) {
1117 VOP_ABORTOP(ndp);
1118 goto out1;
4f083fd7 1119 }
fc2aed1e
KM
1120 if (fvp->v_mount != tdvp->v_mount) {
1121 error = EXDEV;
1122 goto out;
64d3a787 1123 }
fc2aed1e
KM
1124 if (fvp == tdvp || fvp == tvp)
1125 error = EINVAL;
1126out:
1127 if (error) {
1128 VOP_ABORTOP(&tond);
1129 VOP_ABORTOP(ndp);
1130 } else {
1131 error = VOP_RENAME(ndp, &tond);
64d3a787 1132 }
fc2aed1e 1133out1:
41eb2f3d 1134 ndrele(&tond);
fc2aed1e 1135 RETURN (error);
64d3a787 1136}
88a7a62a 1137
88a7a62a
SL
1138/*
1139 * Mkdir system call
1140 */
1141mkdir()
1142{
1143 struct a {
1144 char *name;
1145 int dmode;
715baff1 1146 } *uap = (struct a *)u.u_ap;
715baff1 1147 register struct nameidata *ndp = &u.u_nd;
fc2aed1e
KM
1148 register struct vnode *vp;
1149 struct vattr vattr;
1150 int error;
88a7a62a 1151
fc2aed1e 1152 ndp->ni_nameiop = CREATE | LOCKPARENT;
715baff1
KM
1153 ndp->ni_segflg = UIO_USERSPACE;
1154 ndp->ni_dirp = uap->name;
fc2aed1e
KM
1155 if (error = namei(ndp))
1156 RETURN (error);
1157 vp = ndp->ni_vp;
1158 if (vp != NULL) {
1159 VOP_ABORTOP(ndp);
1160 RETURN (EEXIST);
88a7a62a 1161 }
fc2aed1e
KM
1162 vattr_null(&vattr);
1163 vattr.va_type = VDIR;
1164 vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask;
1165 error = VOP_MKDIR(ndp, &vattr);
5dfd04f0
KM
1166 if (!error)
1167 vput(ndp->ni_vp);
fc2aed1e 1168 RETURN (error);
88a7a62a
SL
1169}
1170
1171/*
1172 * Rmdir system call.
1173 */
1174rmdir()
1175{
1176 struct a {
1177 char *name;
715baff1 1178 } *uap = (struct a *)u.u_ap;
715baff1 1179 register struct nameidata *ndp = &u.u_nd;
fc2aed1e
KM
1180 register struct vnode *vp;
1181 int error;
88a7a62a 1182
fc2aed1e 1183 ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
715baff1
KM
1184 ndp->ni_segflg = UIO_USERSPACE;
1185 ndp->ni_dirp = uap->name;
fc2aed1e
KM
1186 if (error = namei(ndp))
1187 RETURN (error);
1188 vp = ndp->ni_vp;
1189 if (vp->v_type != VDIR) {
1190 error = ENOTDIR;
88a7a62a
SL
1191 goto out;
1192 }
1193 /*
fc2aed1e 1194 * No rmdir "." please.
88a7a62a 1195 */
fc2aed1e
KM
1196 if (ndp->ni_dvp == vp) {
1197 error = EINVAL;
88a7a62a
SL
1198 goto out;
1199 }
1200 /*
fc2aed1e 1201 * Don't unlink a mounted file.
88a7a62a 1202 */
fc2aed1e
KM
1203 if (vp->v_flag & VROOT)
1204 error = EBUSY;
88a7a62a 1205out:
fc2aed1e
KM
1206 if (error)
1207 VOP_ABORTOP(ndp);
1208 else
1209 error = VOP_RMDIR(ndp);
1210 RETURN (error);
88a7a62a
SL
1211}
1212
fc2aed1e
KM
1213/*
1214 * Read a block of directory entries in a file system independent format
1215 */
1216getdirentries()
88a7a62a 1217{
fc2aed1e
KM
1218 register struct a {
1219 int fd;
1220 char *buf;
1221 unsigned count;
1222 long *basep;
1223 } *uap = (struct a *)u.u_ap;
8462a185 1224 struct file *fp;
fc2aed1e
KM
1225 struct uio auio;
1226 struct iovec aiov;
58030ad2 1227 off_t off;
fc2aed1e
KM
1228 int error;
1229
1230 if (error = getvnode(uap->fd, &fp))
1231 RETURN (error);
1232 if ((fp->f_flag & FREAD) == 0)
1233 RETURN (EBADF);
1234 aiov.iov_base = uap->buf;
1235 aiov.iov_len = uap->count;
1236 auio.uio_iov = &aiov;
1237 auio.uio_iovcnt = 1;
1238 auio.uio_rw = UIO_READ;
1239 auio.uio_segflg = UIO_USERSPACE;
1240 auio.uio_resid = uap->count;
58030ad2 1241 off = fp->f_offset;
fc2aed1e
KM
1242 if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio,
1243 &(fp->f_offset), fp->f_cred))
1244 RETURN (error);
58030ad2 1245 error = copyout((caddr_t)&off, (caddr_t)uap->basep,
fc2aed1e
KM
1246 sizeof(long));
1247 u.u_r.r_val1 = uap->count - auio.uio_resid;
1248 RETURN (error);
88a7a62a
SL
1249}
1250
1251/*
1252 * mode mask for creation of files
1253 */
1254umask()
1255{
1256 register struct a {
1257 int mask;
715baff1 1258 } *uap = (struct a *)u.u_ap;
88a7a62a 1259
88a7a62a
SL
1260 u.u_r.r_val1 = u.u_cmask;
1261 u.u_cmask = uap->mask & 07777;
fc2aed1e
KM
1262 RETURN (0);
1263}
1264
1265getvnode(fdes, fpp)
1266 struct file **fpp;
1267 int fdes;
1268{
1269 struct file *fp;
1270
1271 if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL)
1272 return (EBADF);
1273 if (fp->f_type != DTYPE_VNODE)
1274 return (EINVAL);
1275 *fpp = fp;
1276 return (0);
88a7a62a 1277}