+statfs(scp)
+ register struct syscontext *scp;
+{
+ struct a {
+ char *path;
+ struct statfs *buf;
+ } *uap = (struct a *)scp->sc_ap;
+ register struct vnode *vp;
+ register struct nameidata *ndp = &scp->sc_nd;
+ struct statfs sb;
+ int error;
+
+ ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->path;
+ if (error = namei(ndp))
+ RETURN (error);
+ vp = ndp->ni_vp;
+ if (error = VFS_STATFS(vp->v_mount, &sb))
+ goto out;
+ error = copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb));
+out:
+ vput(vp);
+ RETURN (error);
+}
+
+fstatfs(scp)
+ register struct syscontext *scp;
+{
+ struct a {
+ int fd;
+ struct statfs *buf;
+ } *uap = (struct a *)scp->sc_ap;
+ struct file *fp;
+ struct statfs sb;
+ int error;
+
+ if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
+ RETURN (error);
+ if (error = VFS_STATFS(((struct vnode *)fp->f_data)->v_mount, &sb))
+ RETURN (error);
+ RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)));
+}
+
+/*
+ * get statistics on all filesystems
+ */
+getfsstat(scp)
+ register struct syscontext *scp;
+{
+ struct a {
+ struct statfs *buf;
+ long bufsize;
+ } *uap = (struct a *)scp->sc_ap;
+ register struct mount *mp;
+ register struct statfs *sfsp;
+ long count, maxcount, error;
+
+ maxcount = uap->bufsize / sizeof(struct statfs);
+ sfsp = uap->buf;
+ mp = rootfs;
+ count = 0;
+ do {
+ count++;
+ if (sfsp && count <= maxcount) {
+ if (error = VFS_STATFS(mp, sfsp))
+ RETURN (error);
+ sfsp++;
+ }
+ mp = mp->m_prev;
+ } while (mp != rootfs);
+ if (sfsp && count > maxcount)
+ scp->sc_retval1 = maxcount;
+ else
+ scp->sc_retval1 = count;
+ RETURN (0);
+}
+
+/*
+ * Change current working directory to a given file descriptor.
+ */
+fchdir(scp)
+ register struct syscontext *scp;
+{
+ struct a {
+ int fd;
+ } *uap = (struct a *)scp->sc_ap;
+ register struct vnode *vp;
+ struct file *fp;
+ int error;
+
+ if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
+ RETURN (error);
+ vp = (struct vnode *)fp->f_data;
+ VOP_LOCK(vp);
+ if (vp->v_type != VDIR)
+ error = ENOTDIR;
+ else
+ error = VOP_ACCESS(vp, VEXEC, scp->sc_cred);
+ VOP_UNLOCK(vp);
+ vrele(scp->sc_cdir);
+ scp->sc_cdir = vp;
+ RETURN (error);
+}
+
+/*
+ * Change current working directory (``.'').
+ */
+chdir(scp)
+ register struct syscontext *scp;
+{
+ struct a {
+ char *fname;
+ } *uap = (struct a *)scp->sc_ap;
+ register struct nameidata *ndp = &scp->sc_nd;
+ int error;
+
+ ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->fname;
+ if (error = chdirec(ndp))
+ RETURN (error);
+ vrele(scp->sc_cdir);
+ scp->sc_cdir = ndp->ni_vp;
+ RETURN (0);
+}
+
+/*
+ * Change notion of root (``/'') directory.
+ */
+chroot(scp)
+ register struct syscontext *scp;
+{
+ struct a {
+ char *fname;
+ } *uap = (struct a *)scp->sc_ap;
+ register struct nameidata *ndp = &scp->sc_nd;
+ int error;
+
+ if (error = suser(scp->sc_cred, &scp->sc_acflag))
+ RETURN (error);
+ ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->fname;
+ if (error = chdirec(ndp))
+ RETURN (error);
+ vrele(scp->sc_rdir);
+ scp->sc_rdir = ndp->ni_vp;
+ RETURN (0);
+}
+
+/*
+ * Common routine for chroot and chdir.
+ */
+chdirec(ndp)
+ register struct nameidata *ndp;
+{
+ struct vnode *vp;
+ int error;
+
+ if (error = namei(ndp))
+ return (error);
+ vp = ndp->ni_vp;
+ if (vp->v_type != VDIR)
+ error = ENOTDIR;
+ else
+ error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
+ VOP_UNLOCK(vp);
+ if (error)
+ vrele(vp);
+ return (error);
+}
+
+/*
+ * Open system call.
+ */
+open(scp)
+ register struct syscontext *scp;
+{
+ struct a {
+ char *fname;
+ int mode;
+ int crtmode;
+ } *uap = (struct a *) scp->sc_ap;
+ struct nameidata *ndp = &scp->sc_nd;
+
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->fname;
+ RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp,
+ &scp->sc_retval1));
+}
+
+/*
+ * Creat system call.
+ */
+creat(scp)
+ register struct syscontext *scp;
+{
+ struct a {
+ char *fname;
+ int fmode;
+ } *uap = (struct a *)scp->sc_ap;
+ struct nameidata *ndp = &scp->sc_nd;
+
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->fname;
+ RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask,
+ ndp, &scp->sc_retval1));
+}
+
+/*
+ * Common code for open and creat.
+ * Check permissions, allocate an open file structure,
+ * and call the device open routine if any.
+ */
+copen(scp, fmode, cmode, ndp, resultfd)
+ register struct syscontext *scp;
+ int fmode, cmode;
+ struct nameidata *ndp;
+ int *resultfd;
+{
+ register struct file *fp;
+ struct file *nfp;
+ int indx, error;
+ extern struct fileops vnops;
+
+ if (error = falloc(&nfp, &indx))
+ return (error);
+ fp = nfp;
+ scp->sc_retval1 = indx; /* XXX for fdopen() */
+ if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) {
+ scp->sc_ofile[indx] = NULL;
+ crfree(fp->f_cred);
+ fp->f_count--;
+ return (error);
+ }
+ fp->f_flag = fmode & FMASK;
+ fp->f_type = DTYPE_VNODE;
+ fp->f_ops = &vnops;
+ fp->f_data = (caddr_t)ndp->ni_vp;
+ if (resultfd)
+ *resultfd = indx;
+ return (0);
+}
+
+/*
+ * Mknod system call
+ */
+mknod(scp)
+ register struct syscontext *scp;