summaryrefslogtreecommitdiffstats
path: root/sys/compat/linux
diff options
context:
space:
mode:
authoriedowse <iedowse@FreeBSD.org>2002-09-01 21:15:37 +0000
committeriedowse <iedowse@FreeBSD.org>2002-09-01 21:15:37 +0000
commit285c5385d508cc2abf4dea0b585eddf64ed7be7e (patch)
tree34bd9f42149c266a29158d0370095f104a0b9600 /sys/compat/linux
parenta51fc15f74707f874b83e753310ed60e15b7b5e8 (diff)
downloadFreeBSD-src-285c5385d508cc2abf4dea0b585eddf64ed7be7e.zip
FreeBSD-src-285c5385d508cc2abf4dea0b585eddf64ed7be7e.tar.gz
Add a new function linux_emul_convpath(), which is a version of
linux_emul_find() that does not use stack gap storage but instead always returns the resulting path in a malloc'd kernel buffer. Implement linux_emul_find() in terms of this function. Also add LCONVPATH* macros that wrap linux_emul_convpath in the same way that the CHECKALT* macros wrap linux_emul_find().
Diffstat (limited to 'sys/compat/linux')
-rw-r--r--sys/compat/linux/linux_util.c80
-rw-r--r--sys/compat/linux/linux_util.h16
2 files changed, 64 insertions, 32 deletions
diff --git a/sys/compat/linux/linux_util.c b/sys/compat/linux/linux_util.c
index 4949a45..7b34586 100644
--- a/sys/compat/linux/linux_util.c
+++ b/sys/compat/linux/linux_util.c
@@ -57,6 +57,39 @@ linux_emul_find(td, sgp, path, pbuf, cflag)
char **pbuf;
int cflag;
{
+ char *newpath;
+ size_t sz;
+ int error;
+
+ error = linux_emul_convpath(td, path, (sgp == NULL) ? UIO_SYSSPACE :
+ UIO_USERSPACE, &newpath, cflag);
+ if (newpath == NULL)
+ return (error);
+
+ if (sgp == NULL) {
+ *pbuf = newpath;
+ return (error);
+ }
+
+ sz = strlen(newpath);
+ *pbuf = stackgap_alloc(sgp, sz + 1);
+ if (*pbuf != NULL)
+ error = copyout(newpath, *pbuf, sz + 1);
+ else
+ error = ENAMETOOLONG;
+ free(newpath, M_TEMP);
+
+ return (error);
+}
+
+int
+linux_emul_convpath(td, path, pathseg, pbuf, cflag)
+ struct thread *td;
+ char *path;
+ enum uio_seg pathseg;
+ char **pbuf;
+ int cflag;
+{
struct nameidata nd;
struct nameidata ndroot;
struct vattr vat;
@@ -64,32 +97,30 @@ linux_emul_find(td, sgp, path, pbuf, cflag)
int error;
const char *prefix;
char *ptr, *buf, *cp;
- size_t sz, len;
+ size_t len, sz;
buf = (char *) malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
- *pbuf = path;
+ *pbuf = buf;
prefix = linux_emul_path;
for (ptr = buf; (*ptr = *prefix) != '\0'; ptr++, prefix++)
continue;
sz = MAXPATHLEN - (ptr - buf);
- /*
- * If sgp is not given then the path is already in kernel space
- */
- if (sgp == NULL)
+ if (pathseg == UIO_SYSSPACE)
error = copystr(path, ptr, sz, &len);
else
error = copyinstr(path, ptr, sz, &len);
if (error) {
+ *pbuf = NULL;
free(buf, M_TEMP);
return error;
}
if (*ptr != '/') {
- free(buf, M_TEMP);
- return EINVAL;
+ error = EINVAL;
+ goto keeporig;
}
/*
@@ -105,21 +136,16 @@ linux_emul_find(td, sgp, path, pbuf, cflag)
*cp = '\0';
NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, td);
-
- if ((error = namei(&nd)) != 0) {
- free(buf, M_TEMP);
- return error;
- }
-
+ error = namei(&nd);
*cp = '/';
+ if (error != 0)
+ goto keeporig;
}
else {
NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, td);
- if ((error = namei(&nd)) != 0) {
- free(buf, M_TEMP);
- return error;
- }
+ if ((error = namei(&nd)) != 0)
+ goto keeporig;
/*
* We now compare the vnode of the linux_root to the one
@@ -134,10 +160,9 @@ linux_emul_find(td, sgp, path, pbuf, cflag)
if ((error = namei(&ndroot)) != 0) {
/* Cannot happen! */
- free(buf, M_TEMP);
NDFREE(&nd, NDF_ONLY_PNBUF);
vrele(nd.ni_vp);
- return error;
+ goto keeporig;
}
if ((error = VOP_GETATTR(nd.ni_vp, &vat, td->td_ucred, td)) != 0) {
@@ -156,17 +181,6 @@ linux_emul_find(td, sgp, path, pbuf, cflag)
}
}
- if (sgp == NULL)
- *pbuf = buf;
- else {
- sz = &ptr[len] - buf;
- *pbuf = stackgap_alloc(sgp, sz + 1);
- if (*pbuf != NULL)
- error = copyout(buf, *pbuf, sz);
- else
- error = ENAMETOOLONG;
- free(buf, M_TEMP);
- }
NDFREE(&nd, NDF_ONLY_PNBUF);
vrele(nd.ni_vp);
@@ -181,6 +195,8 @@ bad:
vrele(ndroot.ni_vp);
NDFREE(&nd, NDF_ONLY_PNBUF);
vrele(nd.ni_vp);
- free(buf, M_TEMP);
+keeporig:
+ /* Keep the original path; copy it back to the start of the buffer. */
+ bcopy(ptr, buf, len);
return error;
}
diff --git a/sys/compat/linux/linux_util.h b/sys/compat/linux/linux_util.h
index ee421a2..7f69ad5 100644
--- a/sys/compat/linux/linux_util.h
+++ b/sys/compat/linux/linux_util.h
@@ -46,6 +46,7 @@
#include <sys/exec.h>
#include <sys/sysent.h>
#include <sys/cdefs.h>
+#include <sys/uio.h>
static __inline caddr_t stackgap_init(void);
static __inline void *stackgap_alloc(caddr_t *, size_t);
@@ -74,6 +75,7 @@ stackgap_alloc(sgp, sz)
extern const char linux_emul_path[];
+int linux_emul_convpath(struct thread *, char *, enum uio_seg, char **, int);
int linux_emul_find(struct thread *, caddr_t *, char *, char **, int);
#define CHECKALT(p, sgp, path, i) \
@@ -88,6 +90,20 @@ int linux_emul_find(struct thread *, caddr_t *, char *, char **, int);
#define CHECKALTEXIST(p, sgp, path) CHECKALT(p, sgp, path, 0)
#define CHECKALTCREAT(p, sgp, path) CHECKALT(p, sgp, path, 1)
+#define LCONVPATH(td, upath, pathp, i) \
+ do { \
+ int _error; \
+ \
+ _error = linux_emul_convpath(td, upath, UIO_USERSPACE, \
+ pathp, i); \
+ if (*(pathp) == NULL) \
+ return (_error); \
+ } while (0)
+
+#define LCONVPATHEXIST(td, upath, pathp) LCONVPATH(td, upath, pathp, 0)
+#define LCONVPATHCREAT(td, upath, pathp) LCONVPATH(td, upath, pathp, 1)
+#define LFREEPATH(path) free(path, M_TEMP)
+
#define DUMMY(s) \
int \
linux_ ## s(struct thread *p, struct linux_ ## s ## _args *args) \
OpenPOWER on IntegriCloud