diff options
author | iedowse <iedowse@FreeBSD.org> | 2002-09-01 21:15:37 +0000 |
---|---|---|
committer | iedowse <iedowse@FreeBSD.org> | 2002-09-01 21:15:37 +0000 |
commit | 285c5385d508cc2abf4dea0b585eddf64ed7be7e (patch) | |
tree | 34bd9f42149c266a29158d0370095f104a0b9600 /sys/compat/linux | |
parent | a51fc15f74707f874b83e753310ed60e15b7b5e8 (diff) | |
download | FreeBSD-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.c | 80 | ||||
-rw-r--r-- | sys/compat/linux/linux_util.h | 16 |
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) \ |