aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2005-02-07 18:44:55 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2005-02-07 18:44:55 +0000
commit76951d21d1d37261f8598543d45dc7497183a5de (patch)
treeff7cc7cc16c891dadf164e579f6845927917f2ef /sys
parentc90110d639ab79b88c15395ccb4e1e257f5a4dde (diff)
downloadsrc-76951d21d1d37261f8598543d45dc7497183a5de.tar.gz
src-76951d21d1d37261f8598543d45dc7497183a5de.zip
- Tweak kern_msgctl() to return a copy of the requested message queue id
structure in the struct pointed to by the 3rd argument for IPC_STAT and get rid of the 4th argument. The old way returned a pointer into the kernel array that the calling function would then access afterwards without holding the appropriate locks and doing non-lock-safe things like copyout() with the data anyways. This change removes that unsafeness and resulting race conditions as well as simplifying the interface. - Implement kern_foo wrappers for stat(), lstat(), fstat(), statfs(), fstatfs(), and fhstatfs(). Use these wrappers to cut out a lot of code duplication for freebsd4 and netbsd compatability system calls. - Add a new lookup function kern_alternate_path() that looks up a filename under an alternate prefix and determines which filename should be used. This is basically a more general version of linux_emul_convpath() that can be shared by all the ABIs thus allowing for further reduction of code duplication.
Notes
Notes: svn path=/head/; revision=141471
Diffstat (limited to 'sys')
-rw-r--r--sys/compat/linux/linux_ipc.c5
-rw-r--r--sys/kern/kern_descrip.c36
-rw-r--r--sys/kern/sysv_msg.c12
-rw-r--r--sys/kern/vfs_extattr.c218
-rw-r--r--sys/kern/vfs_lookup.c113
-rw-r--r--sys/kern/vfs_syscalls.c218
-rw-r--r--sys/sys/syscallsubr.h22
7 files changed, 346 insertions, 278 deletions
diff --git a/sys/compat/linux/linux_ipc.c b/sys/compat/linux/linux_ipc.c
index 8fc338786d2e..ddd4f0e81c62 100644
--- a/sys/compat/linux/linux_ipc.c
+++ b/sys/compat/linux/linux_ipc.c
@@ -637,7 +637,6 @@ linux_msgctl(struct thread *td, struct linux_msgctl_args *args)
int error, bsd_cmd;
struct l_msqid_ds linux_msqid;
struct msqid_ds bsd_msqid;
- struct msqid_ds *bsd_msqptr;
error = linux_msqid_pullup(args->cmd & LINUX_IPC_64,
&linux_msqid, (caddr_t)PTRIN(args->buf));
@@ -647,13 +646,13 @@ linux_msgctl(struct thread *td, struct linux_msgctl_args *args)
if (bsd_cmd == LINUX_IPC_SET)
linux_to_bsd_msqid_ds(&linux_msqid, &bsd_msqid);
- error = kern_msgctl(td, args->msqid, bsd_cmd, &bsd_msqid, &bsd_msqptr);
+ error = kern_msgctl(td, args->msqid, bsd_cmd, &bsd_msqid);
if (error != 0)
if (bsd_cmd != LINUX_IPC_RMID || error != EINVAL)
return (error);
if (bsd_cmd == LINUX_IPC_STAT) {
- bsd_to_linux_msqid_ds(bsd_msqptr, &linux_msqid);
+ bsd_to_linux_msqid_ds(&bsd_msqid, &linux_msqid);
return (linux_msqid_pushdown(args->cmd & LINUX_IPC_64,
&linux_msqid, (caddr_t)PTRIN(args->buf)));
}
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index 987ccdad8b46..81fead12e0ff 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -1030,20 +1030,15 @@ struct ofstat_args {
int
ofstat(struct thread *td, struct ofstat_args *uap)
{
- struct file *fp;
- struct stat ub;
struct ostat oub;
+ struct stat ub;
int error;
- if ((error = fget(td, uap->fd, &fp)) != 0)
- goto done2;
- error = fo_stat(fp, &ub, td->td_ucred, td);
+ error = kern_fstat(td, uap->fd, &ub);
if (error == 0) {
cvtstat(&ub, &oub);
error = copyout(&oub, uap->sb, sizeof(oub));
}
- fdrop(fp, td);
-done2:
return (error);
}
#endif /* COMPAT_43 */
@@ -1064,17 +1059,25 @@ struct fstat_args {
int
fstat(struct thread *td, struct fstat_args *uap)
{
- struct file *fp;
struct stat ub;
int error;
- if ((error = fget(td, uap->fd, &fp)) != 0)
- goto done2;
- error = fo_stat(fp, &ub, td->td_ucred, td);
+ error = kern_fstat(td, uap->fd, &ub);
if (error == 0)
error = copyout(&ub, uap->sb, sizeof(ub));
+ return (error);
+}
+
+int
+kern_fstat(struct thread *td, int fd, struct stat *sbp)
+{
+ struct file *fp;
+ int error;
+
+ if ((error = fget(td, fd, &fp)) != 0)
+ return (error);
+ error = fo_stat(fp, sbp, td->td_ucred, td);
fdrop(fp, td);
-done2:
return (error);
}
@@ -1094,20 +1097,15 @@ struct nfstat_args {
int
nfstat(struct thread *td, struct nfstat_args *uap)
{
- struct file *fp;
- struct stat ub;
struct nstat nub;
+ struct stat ub;
int error;
- if ((error = fget(td, uap->fd, &fp)) != 0)
- goto done2;
- error = fo_stat(fp, &ub, td->td_ucred, td);
+ error = kern_fstat(td, uap->fd, &ub);
if (error == 0) {
cvtnstat(&ub, &nub);
error = copyout(&nub, uap->sb, sizeof(nub));
}
- fdrop(fp, td);
-done2:
return (error);
}
diff --git a/sys/kern/sysv_msg.c b/sys/kern/sysv_msg.c
index efd630e027ce..f1a7122c9529 100644
--- a/sys/kern/sysv_msg.c
+++ b/sys/kern/sysv_msg.c
@@ -397,26 +397,24 @@ msgctl(td, uap)
int msqid = uap->msqid;
int cmd = uap->cmd;
struct msqid_ds msqbuf;
- struct msqid_ds *msqptr;
int error;
DPRINTF(("call to msgctl(%d, %d, 0x%x)\n", msqid, cmd, uap->buf));
if (cmd == IPC_SET &&
(error = copyin(uap->buf, &msqbuf, sizeof(msqbuf))) != 0)
return (error);
- error = kern_msgctl(td, msqid, cmd, &msqbuf, &msqptr);
+ error = kern_msgctl(td, msqid, cmd, &msqbuf);
if (cmd == IPC_STAT && error == 0)
- error = copyout(msqptr, uap->buf, sizeof(struct msqid_ds));
+ error = copyout(&msqbuf, uap->buf, sizeof(struct msqid_ds));
return (error);
}
int
-kern_msgctl(td, msqid, cmd, msqbuf, msqptr)
+kern_msgctl(td, msqid, cmd, msqbuf)
struct thread *td;
int msqid;
int cmd;
struct msqid_ds *msqbuf;
- struct msqid_ds **msqptr;
{
int rval, error, msqix;
register struct msqid_kernel *msqkptr;
@@ -545,7 +543,7 @@ kern_msgctl(td, msqid, cmd, msqbuf, msqptr)
DPRINTF(("requester doesn't have read access\n"));
goto done2;
}
- *msqptr = &(msqkptr->u);
+ *msqbuf = msqkptr->u;
break;
default:
@@ -558,7 +556,7 @@ kern_msgctl(td, msqid, cmd, msqbuf, msqptr)
td->td_retval[0] = rval;
done2:
mtx_unlock(&msq_mtx);
- return(error);
+ return (error);
}
#ifndef _SYS_SYSPROTO_H_
diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c
index 0fc6a4ef6961..cfefd08d97ef 100644
--- a/sys/kern/vfs_extattr.c
+++ b/sys/kern/vfs_extattr.c
@@ -221,13 +221,26 @@ statfs(td, uap)
struct statfs *buf;
} */ *uap;
{
+ struct statfs sf;
+ int error;
+
+ error = kern_statfs(td, uap->path, UIO_USERSPACE, &sf);
+ if (error == 0)
+ error = copyout(&sf, uap->buf, sizeof(sf));
+ return (error);
+}
+
+int
+kern_statfs(struct thread *td, char *path, enum uio_seg pathseg,
+ struct statfs *buf)
+{
struct mount *mp;
struct statfs *sp, sb;
int error;
struct nameidata nd;
mtx_lock(&Giant);
- NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
+ NDINIT(&nd, LOOKUP, FOLLOW, pathseg, path, td);
if ((error = namei(&nd)) != 0) {
mtx_unlock(&Giant);
return (error);
@@ -258,7 +271,8 @@ statfs(td, uap)
sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
sp = &sb;
}
- return (copyout(sp, uap->buf, sizeof(*sp)));
+ *buf = *sp;
+ return (0);
}
/*
@@ -278,12 +292,24 @@ fstatfs(td, uap)
struct statfs *buf;
} */ *uap;
{
+ struct statfs sf;
+ int error;
+
+ error = kern_fstatfs(td, uap->fd, &sf);
+ if (error == 0)
+ error = copyout(&sf, uap->buf, sizeof(sf));
+ return (error);
+}
+
+int
+kern_fstatfs(struct thread *td, int fd, struct statfs *buf)
+{
struct file *fp;
struct mount *mp;
struct statfs *sp, sb;
int error;
- if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
+ if ((error = getvnode(td->td_proc->p_fd, fd, &fp)) != 0)
return (error);
mtx_lock(&Giant);
mp = fp->f_vnode->v_mount;
@@ -315,7 +341,8 @@ fstatfs(td, uap)
sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
sp = &sb;
}
- return (copyout(sp, uap->buf, sizeof(*sp)));
+ *buf = *sp;
+ return (0);
}
/*
@@ -431,29 +458,14 @@ freebsd4_statfs(td, uap)
struct ostatfs *buf;
} */ *uap;
{
- struct mount *mp;
- struct statfs *sp;
struct ostatfs osb;
+ struct statfs sf;
int error;
- struct nameidata nd;
- NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
- if ((error = namei(&nd)) != 0)
- return (error);
- mp = nd.ni_vp->v_mount;
- sp = &mp->mnt_stat;
- NDFREE(&nd, NDF_ONLY_PNBUF);
- vrele(nd.ni_vp);
-#ifdef MAC
- error = mac_check_mount_stat(td->td_ucred, mp);
- if (error)
- return (error);
-#endif
- error = VFS_STATFS(mp, sp, td);
+ error = kern_statfs(td, uap->path, UIO_USERSPACE, &sf);
if (error)
return (error);
- sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
- cvtstatfs(td, sp, &osb);
+ cvtstatfs(td, &sf, &osb);
return (copyout(&osb, uap->buf, sizeof(osb)));
}
@@ -474,29 +486,14 @@ freebsd4_fstatfs(td, uap)
struct ostatfs *buf;
} */ *uap;
{
- struct file *fp;
- struct mount *mp;
- struct statfs *sp;
struct ostatfs osb;
+ struct statfs sf;
int error;
- if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
- return (error);
- mp = fp->f_vnode->v_mount;
- fdrop(fp, td);
- if (mp == NULL)
- return (EBADF);
-#ifdef MAC
- error = mac_check_mount_stat(td->td_ucred, mp);
- if (error)
- return (error);
-#endif
- sp = &mp->mnt_stat;
- error = VFS_STATFS(mp, sp, td);
+ error = kern_fstatfs(td, uap->fd, &sf);
if (error)
return (error);
- sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
- cvtstatfs(td, sp, &osb);
+ cvtstatfs(td, &sf, &osb);
return (copyout(&osb, uap->buf, sizeof(osb)));
}
@@ -598,34 +595,17 @@ freebsd4_fhstatfs(td, uap)
struct ostatfs *buf;
} */ *uap;
{
- struct statfs *sp;
- struct mount *mp;
- struct vnode *vp;
struct ostatfs osb;
+ struct statfs sf;
fhandle_t fh;
int error;
- error = suser(td);
- if (error)
- return (error);
if ((error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t))) != 0)
return (error);
- if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
- return (ESTALE);
- if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
- return (error);
- mp = vp->v_mount;
- sp = &mp->mnt_stat;
- vput(vp);
-#ifdef MAC
- error = mac_check_mount_stat(td->td_ucred, mp);
+ error = kern_fhstatfs(td, fh, &sf);
if (error)
return (error);
-#endif
- if ((error = VFS_STATFS(mp, sp, td)) != 0)
- return (error);
- sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
- cvtstatfs(td, sp, &osb);
+ cvtstatfs(td, &sf, &osb);
return (copyout(&osb, uap->buf, sizeof(osb)));
}
@@ -1972,15 +1952,8 @@ ostat(td, uap)
struct stat sb;
struct ostat osb;
int error;
- struct nameidata nd;
- NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
- uap->path, td);
- if ((error = namei(&nd)) != 0)
- return (error);
- NDFREE(&nd, NDF_ONLY_PNBUF);
- error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td);
- vput(nd.ni_vp);
+ error = kern_stat(td, uap->path, UIO_USERSPACE, &sb);
if (error)
return (error);
cvtstat(&sb, &osb);
@@ -2005,20 +1978,11 @@ olstat(td, uap)
struct ostat *ub;
} */ *uap;
{
- struct vnode *vp;
struct stat sb;
struct ostat osb;
int error;
- struct nameidata nd;
- NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
- uap->path, td);
- if ((error = namei(&nd)) != 0)
- return (error);
- vp = nd.ni_vp;
- error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td);
- NDFREE(&nd, NDF_ONLY_PNBUF);
- vput(vp);
+ error = kern_lstat(td, uap->path, UIO_USERSPACE, &sb);
if (error)
return (error);
cvtstat(&sb, &osb);
@@ -2075,15 +2039,26 @@ stat(td, uap)
{
struct stat sb;
int error;
+
+ error = kern_stat(td, uap->path, UIO_USERSPACE, &sb);
+ if (error == 0)
+ error = copyout(&sb, uap->ub, sizeof (sb));
+ return (error);
+}
+
+int
+kern_stat(struct thread *td, char *path, enum uio_seg pathseg, struct stat *sbp)
+{
struct nameidata nd;
- int vfslocked;
+ struct stat sb;
+ int error, vfslocked;
#ifdef LOOKUP_SHARED
NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | NOOBJ | MPSAFE,
- UIO_USERSPACE, uap->path, td);
+ pathseg, path, td);
#else
- NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ | MPSAFE, UIO_USERSPACE,
- uap->path, td);
+ NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ | MPSAFE, pathseg, path,
+ td);
#endif
if ((error = namei(&nd)) != 0)
return (error);
@@ -2094,8 +2069,8 @@ stat(td, uap)
VFS_UNLOCK_GIANT(vfslocked);
if (error)
return (error);
- error = copyout(&sb, uap->ub, sizeof (sb));
- return (error);
+ *sbp = sb;
+ return (0);
}
/*
@@ -2115,14 +2090,26 @@ lstat(td, uap)
struct stat *ub;
} */ *uap;
{
+ struct stat sb;
int error;
+
+ error = kern_lstat(td, uap->path, UIO_USERSPACE, &sb);
+ if (error == 0)
+ error = copyout(&sb, uap->ub, sizeof (sb));
+ return (error);
+}
+
+int
+kern_lstat(struct thread *td, char *path, enum uio_seg pathseg, struct stat *sbp)
+{
struct vnode *vp;
struct stat sb;
struct nameidata nd;
- int vfslocked;
+ int error, vfslocked;
+ /* XXX LOOKUP_SHARED? */
NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ | MPSAFE,
- UIO_USERSPACE, uap->path, td);
+ pathseg, path, td);
if ((error = namei(&nd)) != 0)
return (error);
vfslocked = NDHASGIANT(&nd);
@@ -2133,16 +2120,12 @@ lstat(td, uap)
VFS_UNLOCK_GIANT(vfslocked);
if (error)
return (error);
- error = copyout(&sb, uap->ub, sizeof (sb));
- return (error);
+ *sbp = sb;
+ return (0);
}
/*
- * Implementation of the NetBSD stat() function.
- * XXX This should probably be collapsed with the FreeBSD version,
- * as the differences are only due to vn_stat() clearing spares at
- * the end of the structures. vn_stat could be split to avoid this,
- * and thus collapse the following to close to zero code.
+ * Implementation of the NetBSD [l]stat() functions.
*/
void
cvtnstat(sb, nsb)
@@ -2185,18 +2168,8 @@ nstat(td, uap)
struct stat sb;
struct nstat nsb;
int error;
- struct nameidata nd;
- int vfslocked;
- NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ | MPSAFE, UIO_USERSPACE,
- uap->path, td);
- if ((error = namei(&nd)) != 0)
- return (error);
- vfslocked = NDHASGIANT(&nd);
- NDFREE(&nd, NDF_ONLY_PNBUF);
- error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td);
- vput(nd.ni_vp);
- VFS_UNLOCK_GIANT(vfslocked);
+ error = kern_stat(td, uap->path, UIO_USERSPACE, &sb);
if (error)
return (error);
cvtnstat(&sb, &nsb);
@@ -2221,23 +2194,11 @@ nlstat(td, uap)
struct nstat *ub;
} */ *uap;
{
- int error;
- struct vnode *vp;
struct stat sb;
struct nstat nsb;
- struct nameidata nd;
- int vfslocked;
+ int error;
- NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ | MPSAFE,
- UIO_USERSPACE, uap->path, td);
- if ((error = namei(&nd)) != 0)
- return (error);
- vfslocked = NDHASGIANT(&nd);
- vp = nd.ni_vp;
- NDFREE(&nd, NDF_ONLY_PNBUF);
- error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td);
- vput(vp);
- VFS_UNLOCK_GIANT(vfslocked);
+ error = kern_lstat(td, uap->path, UIO_USERSPACE, &sb);
if (error)
return (error);
cvtnstat(&sb, &nsb);
@@ -4234,17 +4195,29 @@ fhstatfs(td, uap)
struct statfs *buf;
} */ *uap;
{
+ struct statfs sf;
+ fhandle_t fh;
+ int error;
+
+ if ((error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t))) != 0)
+ return (error);
+ error = kern_fhstatfs(td, fh, &sf);
+ if (error == 0)
+ error = copyout(&sf, uap->buf, sizeof(sf));
+ return (error);
+}
+
+int
+kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf)
+{
struct statfs *sp;
struct mount *mp;
struct vnode *vp;
- fhandle_t fh;
int error;
error = suser(td);
if (error)
return (error);
- if ((error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t))) != 0)
- return (error);
if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
@@ -4265,7 +4238,8 @@ fhstatfs(td, uap)
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
if ((error = VFS_STATFS(mp, sp, td)) != 0)
return (error);
- return (copyout(sp, uap->buf, sizeof(*sp)));
+ *buf = *sp;
+ return (0);
}
/*
diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
index a06480d8a73a..52945a9f5776 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
#include <sys/mount.h>
#include <sys/filedesc.h>
#include <sys/proc.h>
+#include <sys/syscallsubr.h>
#ifdef KTRACE
#include <sys/ktrace.h>
#endif
@@ -807,3 +808,115 @@ bad:
*vpp = NULL;
return (error);
}
+
+/*
+ * Determine if there is a suitable alternate filename under the specified
+ * prefix for the specified path. If the create flag is set, then the
+ * alternate prefix will be used so long as the parent directory exists.
+ * This is used by the various compatiblity ABIs so that Linux binaries prefer
+ * files under /compat/linux for example. The chosen path (whether under
+ * the prefix or under /) is returned in a kernel malloc'd buffer pointed
+ * to by pathbuf. The caller is responsible for free'ing the buffer from
+ * the M_TEMP bucket if one is returned.
+ */
+int
+kern_alternate_path(struct thread *td, const char *prefix, char *path,
+ enum uio_seg pathseg, char **pathbuf, int create)
+{
+ struct nameidata nd, ndroot;
+ char *ptr, *buf, *cp;
+ size_t len, sz;
+ int error;
+
+ buf = (char *) malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
+ *pathbuf = buf;
+
+ /* Copy the prefix into the new pathname as a starting point. */
+ len = strlcpy(buf, prefix, MAXPATHLEN);
+ if (len >= MAXPATHLEN) {
+ *pathbuf = NULL;
+ free(buf, M_TEMP);
+ return (EINVAL);
+ }
+ sz = MAXPATHLEN - len;
+ ptr = buf + len;
+
+ /* Append the filename to the prefix. */
+ if (pathseg == UIO_SYSSPACE)
+ error = copystr(path, ptr, sz, &len);
+ else
+ error = copyinstr(path, ptr, sz, &len);
+
+ if (error) {
+ *pathbuf = NULL;
+ free(buf, M_TEMP);
+ return (error);
+ }
+
+ /* Only use a prefix with absolute pathnames. */
+ if (*ptr != '/') {
+ error = EINVAL;
+ goto keeporig;
+ }
+
+ /* XXX: VFS_LOCK_GIANT? */
+ mtx_lock(&Giant);
+
+ /*
+ * We know that there is a / somewhere in this pathname.
+ * Search backwards for it, to find the file's parent dir
+ * to see if it exists in the alternate tree. If it does,
+ * and we want to create a file (cflag is set). We don't
+ * need to worry about the root comparison in this case.
+ */
+
+ if (create) {
+ for (cp = &ptr[len] - 1; *cp != '/'; cp--);
+ *cp = '\0';
+
+ NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, td);
+ error = namei(&nd);
+ *cp = '/';
+ if (error != 0)
+ goto nd_failed;
+ } else {
+ NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, td);
+
+ error = namei(&nd);
+ if (error != 0)
+ goto nd_failed;
+
+ /*
+ * We now compare the vnode of the prefix to the one
+ * vnode asked. If they resolve to be the same, then we
+ * ignore the match so that the real root gets used.
+ * This avoids the problem of traversing "../.." to find the
+ * root directory and never finding it, because "/" resolves
+ * to the emulation root directory. This is expensive :-(
+ */
+ NDINIT(&ndroot, LOOKUP, FOLLOW, UIO_SYSSPACE, prefix, td);
+
+ /* We shouldn't ever get an error from this namei(). */
+ error = namei(&ndroot);
+ if (error == 0) {
+ if (nd.ni_vp == ndroot.ni_vp)
+ error = ENOENT;
+
+ NDFREE(&ndroot, NDF_ONLY_PNBUF);
+ vrele(ndroot.ni_vp);
+ }
+ }
+
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ vrele(nd.ni_vp);
+
+nd_failed:
+ /* XXX: VFS_UNLOCK_GIANT? */
+ mtx_unlock(&Giant);
+
+keeporig:
+ /* If there was an error, use the original path name. */
+ if (error)
+ bcopy(ptr, buf, len);
+ return (error);
+}
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index 0fc6a4ef6961..cfefd08d97ef 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -221,13 +221,26 @@ statfs(td, uap)
struct statfs *buf;
} */ *uap;
{
+ struct statfs sf;
+ int error;
+
+ error = kern_statfs(td, uap->path, UIO_USERSPACE, &sf);
+ if (error == 0)
+ error = copyout(&sf, uap->buf, sizeof(sf));
+ return (error);
+}
+
+int
+kern_statfs(struct thread *td, char *path, enum uio_seg pathseg,
+ struct statfs *buf)
+{
struct mount *mp;
struct statfs *sp, sb;
int error;
struct nameidata nd;
mtx_lock(&Giant);
- NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
+ NDINIT(&nd, LOOKUP, FOLLOW, pathseg, path, td);
if ((error = namei(&nd)) != 0) {
mtx_unlock(&Giant);
return (error);
@@ -258,7 +271,8 @@ statfs(td, uap)
sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
sp = &sb;
}
- return (copyout(sp, uap->buf, sizeof(*sp)));
+ *buf = *sp;
+ return (0);
}
/*
@@ -278,12 +292,24 @@ fstatfs(td, uap)
struct statfs *buf;
} */ *uap;
{
+ struct statfs sf;
+ int error;
+
+ error = kern_fstatfs(td, uap->fd, &sf);
+ if (error == 0)
+ error = copyout(&sf, uap->buf, sizeof(sf));
+ return (error);
+}
+
+int
+kern_fstatfs(struct thread *td, int fd, struct statfs *buf)
+{
struct file *fp;
struct mount *mp;
struct statfs *sp, sb;
int error;
- if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
+ if ((error = getvnode(td->td_proc->p_fd, fd, &fp)) != 0)
return (error);
mtx_lock(&Giant);
mp = fp->f_vnode->v_mount;
@@ -315,7 +341,8 @@ fstatfs(td, uap)
sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
sp = &sb;
}
- return (copyout(sp, uap->buf, sizeof(*sp)));
+ *buf = *sp;
+ return (0);
}
/*
@@ -431,29 +458,14 @@ freebsd4_statfs(td, uap)
struct ostatfs *buf;
} */ *uap;
{
- struct mount *mp;
- struct statfs *sp;
struct ostatfs osb;
+ struct statfs sf;
int error;
- struct nameidata nd;
- NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
- if ((error = namei(&nd)) != 0)
- return (error);
- mp = nd.ni_vp->v_mount;
- sp = &mp->mnt_stat;
- NDFREE(&nd, NDF_ONLY_PNBUF);
- vrele(nd.ni_vp);
-#ifdef MAC
- error = mac_check_mount_stat(td->td_ucred, mp);
- if (error)
- return (error);
-#endif
- error = VFS_STATFS(mp, sp, td);
+ error = kern_statfs(td, uap->path, UIO_USERSPACE, &sf);
if (error)
return (error);
- sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
- cvtstatfs(td, sp, &osb);
+ cvtstatfs(td, &sf, &osb);
return (copyout(&osb, uap->buf, sizeof(osb)));
}
@@ -474,29 +486,14 @@ freebsd4_fstatfs(td, uap)
struct ostatfs *buf;
} */ *uap;
{
- struct file *fp;
- struct mount *mp;
- struct statfs *sp;
struct ostatfs osb;
+ struct statfs sf;
int error;
- if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
- return (error);
- mp = fp->f_vnode->v_mount;
- fdrop(fp, td);
- if (mp == NULL)
- return (EBADF);
-#ifdef MAC
- error = mac_check_mount_stat(td->td_ucred, mp);
- if (error)
- return (error);
-#endif
- sp = &mp->mnt_stat;
- error = VFS_STATFS(mp, sp, td);
+ error = kern_fstatfs(td, uap->fd, &sf);
if (error)
return (error);
- sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
- cvtstatfs(td, sp, &osb);
+ cvtstatfs(td, &sf, &osb);
return (copyout(&osb, uap->buf, sizeof(osb)));
}
@@ -598,34 +595,17 @@ freebsd4_fhstatfs(td, uap)
struct ostatfs *buf;
} */ *uap;
{
- struct statfs *sp;
- struct mount *mp;
- struct vnode *vp;
struct ostatfs osb;
+ struct statfs sf;
fhandle_t fh;
int error;
- error = suser(td);
- if (error)
- return (error);
if ((error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t))) != 0)
return (error);
- if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
- return (ESTALE);
- if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
- return (error);
- mp = vp->v_mount;
- sp = &mp->mnt_stat;
- vput(vp);
-#ifdef MAC
- error = mac_check_mount_stat(td->td_ucred, mp);
+ error = kern_fhstatfs(td, fh, &sf);
if (error)
return (error);
-#endif
- if ((error = VFS_STATFS(mp, sp, td)) != 0)
- return (error);
- sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
- cvtstatfs(td, sp, &osb);
+ cvtstatfs(td, &sf, &osb);
return (copyout(&osb, uap->buf, sizeof(osb)));
}
@@ -1972,15 +1952,8 @@ ostat(td, uap)
struct stat sb;
struct ostat osb;
int error;
- struct nameidata nd;
- NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
- uap->path, td);
- if ((error = namei(&nd)) != 0)
- return (error);
- NDFREE(&nd, NDF_ONLY_PNBUF);
- error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td);
- vput(nd.ni_vp);
+ error = kern_stat(td, uap->path, UIO_USERSPACE, &sb);
if (error)
return (error);
cvtstat(&sb, &osb);
@@ -2005,20 +1978,11 @@ olstat(td, uap)
struct ostat *ub;
} */ *uap;
{
- struct vnode *vp;
struct stat sb;
struct ostat osb;
int error;
- struct nameidata nd;
- NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
- uap->path, td);
- if ((error = namei(&nd)) != 0)
- return (error);
- vp = nd.ni_vp;
- error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td);
- NDFREE(&nd, NDF_ONLY_PNBUF);
- vput(vp);
+ error = kern_lstat(td, uap->path, UIO_USERSPACE, &sb);
if (error)
return (error);
cvtstat(&sb, &osb);
@@ -2075,15 +2039,26 @@ stat(td, uap)
{
struct stat sb;
int error;
+
+ error = kern_stat(td, uap->path, UIO_USERSPACE, &sb);
+ if (error == 0)
+ error = copyout(&sb, uap->ub, sizeof (sb));
+ return (error);
+}
+
+int
+kern_stat(struct thread *td, char *path, enum uio_seg pathseg, struct stat *sbp)
+{
struct nameidata nd;
- int vfslocked;
+ struct stat sb;
+ int error, vfslocked;
#ifdef LOOKUP_SHARED
NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | NOOBJ | MPSAFE,
- UIO_USERSPACE, uap->path, td);
+ pathseg, path, td);
#else
- NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ | MPSAFE, UIO_USERSPACE,
- uap->path, td);
+ NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ | MPSAFE, pathseg, path,
+ td);
#endif
if ((error = namei(&nd)) != 0)
return (error);
@@ -2094,8 +2069,8 @@ stat(td, uap)
VFS_UNLOCK_GIANT(vfslocked);
if (error)
return (error);
- error = copyout(&sb, uap->ub, sizeof (sb));
- return (error);
+ *sbp = sb;
+ return (0);
}
/*
@@ -2115,14 +2090,26 @@ lstat(td, uap)
struct stat *ub;
} */ *uap;
{
+ struct stat sb;
int error;
+
+ error = kern_lstat(td, uap->path, UIO_USERSPACE, &sb);
+ if (error == 0)
+ error = copyout(&sb, uap->ub, sizeof (sb));
+ return (error);
+}
+
+int
+kern_lstat(struct thread *td, char *path, enum uio_seg pathseg, struct stat *sbp)
+{
struct vnode *vp;
struct stat sb;
struct nameidata nd;
- int vfslocked;
+ int error, vfslocked;
+ /* XXX LOOKUP_SHARED? */
NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ | MPSAFE,
- UIO_USERSPACE, uap->path, td);
+ pathseg, path, td);
if ((error = namei(&nd)) != 0)
return (error);
vfslocked = NDHASGIANT(&nd);
@@ -2133,16 +2120,12 @@ lstat(td, uap)
VFS_UNLOCK_GIANT(vfslocked);
if (error)
return (error);
- error = copyout(&sb, uap->ub, sizeof (sb));
- return (error);
+ *sbp = sb;
+ return (0);
}
/*
- * Implementation of the NetBSD stat() function.
- * XXX This should probably be collapsed with the FreeBSD version,
- * as the differences are only due to vn_stat() clearing spares at
- * the end of the structures. vn_stat could be split to avoid this,
- * and thus collapse the following to close to zero code.
+ * Implementation of the NetBSD [l]stat() functions.
*/
void
cvtnstat(sb, nsb)
@@ -2185,18 +2168,8 @@ nstat(td, uap)
struct stat sb;
struct nstat nsb;
int error;
- struct nameidata nd;
- int vfslocked;
- NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ | MPSAFE, UIO_USERSPACE,
- uap->path, td);
- if ((error = namei(&nd)) != 0)
- return (error);
- vfslocked = NDHASGIANT(&nd);
- NDFREE(&nd, NDF_ONLY_PNBUF);
- error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td);
- vput(nd.ni_vp);
- VFS_UNLOCK_GIANT(vfslocked);
+ error = kern_stat(td, uap->path, UIO_USERSPACE, &sb);
if (error)
return (error);
cvtnstat(&sb, &nsb);
@@ -2221,23 +2194,11 @@ nlstat(td, uap)
struct nstat *ub;
} */ *uap;
{
- int error;
- struct vnode *vp;
struct stat sb;
struct nstat nsb;
- struct nameidata nd;
- int vfslocked;
+ int error;
- NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ | MPSAFE,
- UIO_USERSPACE, uap->path, td);
- if ((error = namei(&nd)) != 0)
- return (error);
- vfslocked = NDHASGIANT(&nd);
- vp = nd.ni_vp;
- NDFREE(&nd, NDF_ONLY_PNBUF);
- error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td);
- vput(vp);
- VFS_UNLOCK_GIANT(vfslocked);
+ error = kern_lstat(td, uap->path, UIO_USERSPACE, &sb);
if (error)
return (error);
cvtnstat(&sb, &nsb);
@@ -4234,17 +4195,29 @@ fhstatfs(td, uap)
struct statfs *buf;
} */ *uap;
{
+ struct statfs sf;
+ fhandle_t fh;
+ int error;
+
+ if ((error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t))) != 0)
+ return (error);
+ error = kern_fhstatfs(td, fh, &sf);
+ if (error == 0)
+ error = copyout(&sf, uap->buf, sizeof(sf));
+ return (error);
+}
+
+int
+kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf)
+{
struct statfs *sp;
struct mount *mp;
struct vnode *vp;
- fhandle_t fh;
int error;
error = suser(td);
if (error)
return (error);
- if ((error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t))) != 0)
- return (error);
if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
return (ESTALE);
if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
@@ -4265,7 +4238,8 @@ fhstatfs(td, uap)
sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
if ((error = VFS_STATFS(mp, sp, td)) != 0)
return (error);
- return (copyout(sp, uap->buf, sizeof(*sp)));
+ *buf = *sp;
+ return (0);
}
/*
diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h
index 57bed2c50ac3..74ee11eb21a3 100644
--- a/sys/sys/syscallsubr.h
+++ b/sys/sys/syscallsubr.h
@@ -32,20 +32,24 @@
#include <sys/uio.h>
#include <sys/socket.h>
#include <sys/mac.h>
+#include <sys/mount.h>
+struct itimerval;
+struct image_args;
struct mbuf;
struct msghdr;
+struct msqid_ds;
struct rlimit;
struct rusage;
struct sockaddr;
-struct itimerval;
-struct msqid_ds;
-struct image_args;
+struct stat;
int kern___getcwd(struct thread *td, u_char *buf, enum uio_seg bufseg,
u_int buflen);
int kern_access(struct thread *td, char *path, enum uio_seg pathseg,
int flags);
+int kern_alternate_path(struct thread *td, const char *prefix, char *path,
+ enum uio_seg pathseg, char **pathbuf, int create);
int kern_bind(struct thread *td, int fd, struct sockaddr *sa);
int kern_chdir(struct thread *td, char *path, enum uio_seg pathseg);
int kern_chmod(struct thread *td, char *path, enum uio_seg pathseg,
@@ -56,6 +60,9 @@ int kern_connect(struct thread *td, int fd, struct sockaddr *sa);
int kern_execve(struct thread *td, struct image_args *args,
struct mac *mac_p);
int kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg);
+int kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf);
+int kern_fstat(struct thread *td, int fd, struct stat *sbp);
+int kern_fstatfs(struct thread *td, int fd, struct statfs *buf);
int kern_futimes(struct thread *td, int fd, struct timeval *tptr,
enum uio_seg tptrseg);
int kern_getitimer(struct thread *, u_int, struct itimerval *);
@@ -66,6 +73,8 @@ int kern_lchown(struct thread *td, char *path, enum uio_seg pathseg,
int uid, int gid);
int kern_link(struct thread *td, char *path, char *link,
enum uio_seg segflg);
+int kern_lstat(struct thread *td, char *path, enum uio_seg pathseg,
+ struct stat *sbp);
int kern_lutimes(struct thread *td, char *path, enum uio_seg pathseg,
struct timeval *tptr, enum uio_seg tptrseg);
int kern_mkdir(struct thread *td, char *path, enum uio_seg segflg,
@@ -74,8 +83,7 @@ int kern_mkfifo(struct thread *td, char *path, enum uio_seg pathseg,
int mode);
int kern_mknod(struct thread *td, char *path, enum uio_seg pathseg,
int mode, int dev);
-int kern_msgctl(struct thread *, int, int, struct msqid_ds *,
- struct msqid_ds **);
+int kern_msgctl(struct thread *, int, int, struct msqid_ds *);
int kern_nanosleep(struct thread *td, struct timespec *rqt,
struct timespec *rmt);
int kern_open(struct thread *td, char *path, enum uio_seg pathseg,
@@ -106,6 +114,10 @@ int kern_sigaltstack(struct thread *td, stack_t *ss, stack_t *oss);
int kern_sigprocmask(struct thread *td, int how,
sigset_t *set, sigset_t *oset, int old);
int kern_sigsuspend(struct thread *td, sigset_t mask);
+int kern_stat(struct thread *td, char *path, enum uio_seg pathseg,
+ struct stat *sbp);
+int kern_statfs(struct thread *td, char *path, enum uio_seg pathseg,
+ struct statfs *buf);
int kern_symlink(struct thread *td, char *path, char *link,
enum uio_seg segflg);
int kern_truncate(struct thread *td, char *path, enum uio_seg pathseg,