+Discussion:
https://resin.io/blog/building-arm-containers-on-any-x86-machine-even-dockerhub/
+
https://github.com/resin-io/qemu/commit/782e5bb77014ff136f7bb6133a911e5f53e914a7
https://github.com/resin-io/qemu/commit/782e5bb77014ff136f7bb6133a911e5f53e914a7#commitcomment-17193923
v3 changes:
- rebase the patchset against current code
---- qemu-2.7.0/linux-user/main.c~ 2016-09-26 12:07:20.000000000 +0300
-+++ qemu-2.7.0/linux-user/main.c 2016-09-26 12:09:24.258470304 +0300
-@@ -18,6 +18,7 @@
- */
- #include "qemu/osdep.h"
- #include "qemu-version.h"
-+#include <sys/auxv.h>
- #include <sys/syscall.h>
- #include <sys/resource.h>
-
-@@ -75,6 +76,7 @@ static void usage(int exitcode);
+diff --git a/linux-user/main.c b/linux-user/main.c
+index ee12035..5951279 100644
+--- a/linux-user/main.c
++++ b/linux-user/main.c
+@@ -79,6 +79,7 @@ static void usage(int exitcode);
static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
const char *qemu_uname_release;
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
we allocate a bigger stack. Need a better solution, for example
-@@ -3824,6 +3826,38 @@ static void handle_arg_guest_base(const char *arg)
+@@ -3828,6 +3829,11 @@ static void handle_arg_guest_base(const char *arg)
have_guest_base = 1;
}
+static void handle_arg_execve(const char *arg)
+{
-+ const char *execfn;
-+ char buf[PATH_MAX];
-+ char *ret;
-+ int len;
-+
-+ /* try getauxval() */
-+ execfn = (const char *) getauxval(AT_EXECFN);
-+
-+ if (execfn != 0) {
-+ ret = realpath(execfn, buf);
-+
-+ if (ret != NULL) {
-+ qemu_execve_path = strdup(buf);
-+ return;
-+ }
-+ }
-+
-+ /* try /proc/self/exe */
-+ len = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
-+
-+ if (len != -1) {
-+ buf[len] = '\0';
-+ qemu_execve_path = strdup(buf);
-+ return;
-+ }
-+
-+ fprintf(stderr, "qemu_execve: unable to determine intepreter's path\n");
-+ exit(EXIT_FAILURE);
++ qemu_execve_path = strdup(arg);
+}
+
static void handle_arg_reserved_va(const char *arg)
{
char *p;
-@@ -3909,6 +3943,8 @@ static const struct qemu_argument arg_table[] = {
+@@ -3913,6 +3919,8 @@ static const struct qemu_argument arg_table[] = {
"uname", "set qemu uname release string to 'uname'"},
{"B", "QEMU_GUEST_BASE", true, handle_arg_guest_base,
"address", "set guest_base address to 'address'"},
-+ {"execve", "QEMU_EXECVE", false, handle_arg_execve,
-+ "", "use this interpreter when a process calls execve()"},
++ {"execve", "QEMU_EXECVE", true, handle_arg_execve,
++ "path", "use interpreter at 'path' when a process calls execve()"},
{"R", "QEMU_RESERVED_VA", true, handle_arg_reserved_va,
"size", "reserve 'size' bytes for guest virtual address space"},
{"d", "QEMU_LOG", true, handle_arg_log,
extern unsigned long mmap_min_addr;
/* ??? See if we can avoid exposing so much of the loader internals. */
---- qemu-2.7.0/linux-user/syscall.c~ 2016-09-26 12:10:36.000000000 +0300
-+++ qemu-2.7.0/linux-user/syscall.c 2016-09-26 12:13:54.312490312 +0300
-@@ -99,6 +99,7 @@
- #include <linux/reboot.h>
- #include <linux/route.h>
- #include <linux/filter.h>
-+#include <linux/binfmts.h>
- #include <linux/blkpg.h>
- #include <netpacket/packet.h>
- #include <linux/netlink.h>
-@@ -5842,6 +5843,118 @@ static target_timer_t get_timer_id(abi_long arg)
+--- qemu-2.12.0/linux-user/syscall.c~ 2018-04-30 21:43:39.000000000 +0300
++++ qemu-2.12.0/linux-user/syscall.c 2018-04-30 21:46:36.362935706 +0300
+@@ -5854,6 +5854,109 @@ static target_timer_t get_timer_id(abi_long arg)
return timerid;
}
++#define BINPRM_BUF_SIZE 128
++
+/* qemu_execve() Must return target values and target errnos. */
+static abi_long qemu_execve(char *filename, char *argv[],
+ char *envp[])
+ char *cp;
+ char buf[BINPRM_BUF_SIZE];
+
-+ /* normal execve case */
-+ if (qemu_execve_path == NULL || *qemu_execve_path == 0) {
-+ return get_errno(execve(filename, argv, envp));
-+ }
-+
+ for (argc = 0; argv[argc] != NULL; argc++) {
+ /* nothing */ ;
+ }
+
+ fd = open(filename, O_RDONLY);
+ if (fd == -1) {
-+ return get_errno(fd);
++ return -ENOENT;
+ }
+
+ ret = read(fd, buf, BINPRM_BUF_SIZE);
+ if (ret == -1) {
+ close(fd);
-+ return get_errno(ret);
-+ }
-+
-+ /* if we have less than 2 bytes, we can guess it is not executable */
-+ if (ret < 2) {
-+ close(fd);
-+ return -host_to_target_errno(ENOEXEC);
++ return -ENOENT;
+ }
+
+ close(fd);
+ buf[BINPRM_BUF_SIZE - 1] = '\0';
+ cp = strchr(buf, '\n');
+ if (cp == NULL) {
-+ cp = buf + BINPRM_BUF_SIZE - 1;
++ cp = buf+BINPRM_BUF_SIZE-1;
+ }
+ *cp = '\0';
+ while (cp > buf) {
+ break;
+ }
+ }
-+ for (cp = buf + 2; (*cp == ' ') || (*cp == '\t'); cp++) {
++ for (cp = buf+2; (*cp == ' ') || (*cp == '\t'); cp++) {
+ /* nothing */ ;
+ }
+ if (*cp == '\0') {
+ return get_errno(safe_execve(qemu_execve_path, new_argp, envp));
+}
+
- /* do_syscall() should always have a single exit point at the end so
- that actions, such as logging of syscall results, can be performed.
- All errnos that do_syscall() returns must be -TARGET_<errcode>. */
-@@ -7703,7 +7703,7 @@
+ static int target_to_host_cpu_mask(unsigned long *host_mask,
+ size_t host_size,
+ abi_ulong target_addr,
+@@ -8257,7 +8257,12 @@
* before the execve completes and makes it the other
* program's problem.
*/
- ret = get_errno(safe_execve(p, argp, envp));
-+ ret = qemu_execve(p, argp, envp);
++ if (qemu_execve_path && *qemu_execve_path) {
++ ret = get_errno(qemu_execve(p, argp, envp));
++ } else {
++ ret = get_errno(safe_execve(p, argp, envp));
++ }
++
unlock_user(p, arg1, 0);
goto execve_end;