+ register struct mount *mp;
+ register struct nameidata *ndp = &u.u_nd;
+ int error;
+
+ ndp->ni_nameiop = LOOKUP | FOLLOW;
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->path;
+ if (error = namei(ndp))
+ RETURN (error);
+ mp = ndp->ni_vp->v_mount;
+ vrele(ndp->ni_vp);
+ RETURN (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg));
+}
+
+/*
+ * get filesystem statistics
+ */
+/* ARGSUSED */
+statfs(p, uap, retval)
+ register struct proc *p;
+ register struct args {
+ char *path;
+ struct statfs *buf;
+ } *uap;
+ int *retval;
+{
+ register struct mount *mp;
+ register struct nameidata *ndp = &u.u_nd;
+ register struct statfs *sp;
+ int error;
+
+ ndp->ni_nameiop = LOOKUP | FOLLOW;
+ ndp->ni_segflg = UIO_USERSPACE;
+ ndp->ni_dirp = uap->path;
+ if (error = namei(ndp))
+ RETURN (error);
+ mp = ndp->ni_vp->v_mount;
+ sp = &mp->mnt_stat;
+ vrele(ndp->ni_vp);
+ if (error = VFS_STATFS(mp, sp))
+ RETURN (error);
+ sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
+ RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
+}
+
+/*
+ * get filesystem statistics
+ */
+/* ARGSUSED */
+fstatfs(p, uap, retval)
+ register struct proc *p;
+ register struct args {
+ int fd;
+ struct statfs *buf;
+ } *uap;
+ int *retval;
+{
+ struct file *fp;
+ struct mount *mp;
+ register struct statfs *sp;
+ int error;
+
+ if (error = getvnode(u.u_ofile, uap->fd, &fp))
+ RETURN (error);
+ mp = ((struct vnode *)fp->f_data)->v_mount;
+ sp = &mp->mnt_stat;
+ if (error = VFS_STATFS(mp, sp))
+ RETURN (error);
+ sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
+ RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
+}
+
+/*
+ * get statistics on all filesystems
+ */
+getfsstat(p, uap, retval)
+ register struct proc *p;
+ register struct args {
+ struct statfs *buf;
+ long bufsize;
+ int flags;
+ } *uap;
+ int *retval;
+{
+ register struct mount *mp;
+ register struct statfs *sp;
+ caddr_t sfsp;
+ long count, maxcount, error;
+
+ maxcount = uap->bufsize / sizeof(struct statfs);
+ sfsp = (caddr_t)uap->buf;
+ mp = rootfs;
+ count = 0;
+ do {
+ if (sfsp && count < maxcount &&
+ ((mp->mnt_flag & MNT_MLOCK) == 0)) {
+ sp = &mp->mnt_stat;
+ /*
+ * If MNT_NOWAIT is specified, do not refresh the
+ * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
+ */
+ if (((uap->flags & MNT_NOWAIT) == 0 ||
+ (uap->flags & MNT_WAIT)) &&
+ (error = VFS_STATFS(mp, sp))) {
+ mp = mp->mnt_prev;
+ continue;
+ }
+ sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
+ if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
+ RETURN (error);
+ sfsp += sizeof(*sp);
+ }
+ count++;
+ mp = mp->mnt_prev;
+ } while (mp != rootfs);
+ if (sfsp && count > maxcount)
+ *retval = maxcount;
+ else
+ *retval = count;
+ RETURN (0);
+}
+
+/*
+ * Change current working directory to a given file descriptor.
+ */
+/* ARGSUSED */
+fchdir(p, uap, retval)
+ register struct proc *p;
+ struct args {
+ int fd;
+ } *uap;
+ int *retval;
+{
+ register struct nameidata *ndp = &u.u_nd;
+ register struct vnode *vp;
+ struct file *fp;
+ int error;
+
+ if (error = getvnode(u.u_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, ndp->ni_cred);
+ VOP_UNLOCK(vp);
+ if (error)
+ RETURN (error);
+ VREF(vp);
+ vrele(ndp->ni_cdir);
+ ndp->ni_cdir = vp;
+ RETURN (0);
+}
+
+/*
+ * Change current working directory (``.'').
+ */
+/* ARGSUSED */
+chdir(p, uap, retval)
+ register struct proc *p;
+ struct args {