Hello, >From my experience, many times when one cross compiles software for linux at >some point one ends up creating a directory which contains a root filesystem >for the target. A nice thing with qemu is the ability to cross run programs >within that target dir with the linux-user -L option.
Due to the way the -L option (linux-user/path.c) works, when a file does not exist in the target directory qemu may open files from the hosts root. This may be undesirable when trying to simulate the behavior from the targets point of view. An example is with at least some versions of glibc's dynamic linker and a missing target/etc/ld.so.cache. Also, if the target/ tree contains many files, the startup time for a simulation can increase allot (up to minutes if qemu even manages to run before being killed by the OOM). This is because it takes a long time & memory for qemu to scan the entire tree and generate it's internal representation. IIUC, chroot can be used to avoid these issues but that would require that qemu itself be linked -static:ally and placed in target/. I think it would be nice to have a -sysroot option that does a more simple and strict path remapping by always prepending the sysroot. Something similar to what the --sysroot option in the sim/GDB simulators does. This patch shows how it could work. Only absolute paths get remapped. I would appreciate any comments on this. Thanks and best regards -- Edgar E. Iglesias Axis Communications AB diff --git a/darwin-user/qemu.h b/darwin-user/qemu.h index 41b57f8..2147da3 100644 --- a/darwin-user/qemu.h +++ b/darwin-user/qemu.h @@ -106,7 +106,7 @@ void write_dt(void *ptr, unsigned long addr, unsigned long limit, int flags); extern CPUState *global_env; void cpu_loop(CPUState *env); -void init_paths(const char *prefix); +void init_paths(const char *prefix, int sysroot); const char *path(const char *pathname); extern int loglevel; diff --git a/linux-user/main.c b/linux-user/main.c index 0079c7a..1c63610 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1912,6 +1912,7 @@ void usage(void) "-d options activate log (logfile=%s)\n" "-p pagesize set the host page size to 'pagesize'\n" "-strace log system calls\n" + "-sysroot Root for system calls with absolute file-names\n" "\n" "Environment variables:\n" "QEMU_STRACE Print system calls and arguments similar to the\n" @@ -1943,6 +1944,7 @@ int main(int argc, char **argv) int gdbstub_port = 0; int drop_ld_preload = 0, environ_count = 0; char **target_environ, **wrk, **dst; + char *sysroot = NULL; if (argc <= 1) usage(); @@ -2014,6 +2016,8 @@ int main(int argc, char **argv) drop_ld_preload = 1; } else if (!strcmp(r, "strace")) { do_strace = 1; + } else if (!strcmp(r, "sysroot")) { + sysroot = argv[optind++]; } else { usage(); @@ -2030,7 +2034,10 @@ int main(int argc, char **argv) memset(info, 0, sizeof(struct image_info)); /* Scan interp_prefix dir for replacement files. */ - init_paths(interp_prefix); + if (sysroot) + init_paths(sysroot, 1); + else + init_paths(interp_prefix, 0); if (cpu_model == NULL) { #if defined(TARGET_I386) diff --git a/linux-user/path.c b/linux-user/path.c index 7da0a8b..ece8d89 100644 --- a/linux-user/path.c +++ b/linux-user/path.c @@ -25,6 +25,8 @@ struct pathelem }; static struct pathelem *base; +static int use_sysroot; +static size_t sysroot_pathlen; /* First N chars of S1 match S2, and S2 is N chars long. */ static int strneq(const char *s1, unsigned int n, const char *s2) @@ -118,7 +120,7 @@ follow_path(const struct pathelem *cursor, const char *name) return NULL; } -void init_paths(const char *prefix) +void init_paths(const char *prefix, int sysroot) { char pref_buf[PATH_MAX]; @@ -137,13 +139,21 @@ void init_paths(const char *prefix) } else strcpy(pref_buf,prefix + 1); - base = new_entry("", NULL, pref_buf); - base = add_dir_maybe(base); - if (base->num_entries == 0) { - free (base); - base = NULL; + use_sysroot = sysroot; + if (sysroot) { + base = malloc(sizeof (*base)); + sysroot_pathlen = strlen(pref_buf); + base->pathname = malloc(sysroot_pathlen + PATH_MAX + 1); + memcpy(base->pathname, pref_buf, sysroot_pathlen); } else { - set_parents(base, base); + base = new_entry("", NULL, pref_buf); + base = add_dir_maybe(base); + if (base->num_entries == 0) { + free (base); + base = NULL; + } else { + set_parents(base, base); + } } } @@ -155,5 +165,11 @@ const char *path(const char *name) if (!base || name[0] != '/') return name; - return follow_path(base, name) ?: name; + if (use_sysroot) { + size_t name_len; + /* Prepend base->pathname to name. */ + name_len = strlen(name); + return memcpy (base->pathname + sysroot_pathlen, name, name_len + 1); + } else + return follow_path(base, name) ?: name; } diff --git a/linux-user/qemu.h b/linux-user/qemu.h index b33ad89..9e1b4f4 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -166,7 +166,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); extern CPUState *global_env; void cpu_loop(CPUState *env); -void init_paths(const char *prefix); +void init_paths(const char *prefix, int sysroot); const char *path(const char *pathname); char *target_strerror(int err); diff --git a/tests/test_path.c b/tests/test_path.c index 7d6e831..e146736 100644 --- a/tests/test_path.c +++ b/tests/test_path.c @@ -69,7 +69,7 @@ static unsigned int do_test(void) if (close(creat("/tmp/qemu-test_path/DIR1/DIR2/FILE5", 0600)) != 0) return __LINE__; - init_paths("/tmp/qemu-test_path"); + init_paths("/tmp/qemu-test_path", 0); NO_CHANGE("/tmp"); NO_CHANGE("/tmp/");