diff --git a/linux-user/main.c b/linux-user/main.c index b6e434a203..88383053c8 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -3676,6 +3676,8 @@ int main(int argc, char **argv, char **envp) /* Scan interp_prefix dir for replacement files. */ init_paths(interp_prefix); + init_qemu_uname_release(); + if (cpu_model == NULL) { #if defined(TARGET_I386) #ifdef TARGET_X86_64 diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 4df4fcb865..6ffe5a2dec 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -197,6 +197,7 @@ extern THREAD CPUState *thread_cpu; void cpu_loop(CPUArchState *env); char *target_strerror(int err); int get_osversion(void); +void init_qemu_uname_release(void); void fork_start(void); void fork_end(int child); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index ea04db1a3e..c62d8754f0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4863,21 +4863,13 @@ int host_to_target_waitstatus(int status) return status; } -int get_osversion(void) +static int relstr_to_int(const char *s) { - static int osversion; - struct new_utsname buf; - const char *s; + /* Convert a uname release string like "2.6.18" to an integer + * of the form 0x020612. (Beware that 0x020612 is *not* 2.6.12.) + */ int i, n, tmp; - if (osversion) - return osversion; - if (qemu_uname_release && *qemu_uname_release) { - s = qemu_uname_release; - } else { - if (sys_uname(&buf)) - return 0; - s = buf.release; - } + tmp = 0; for (i = 0; i < 3; i++) { n = 0; @@ -4887,13 +4879,55 @@ int get_osversion(void) s++; } tmp = (tmp << 8) + n; - if (*s == '.') + if (*s == '.') { s++; + } } - osversion = tmp; + return tmp; +} + +int get_osversion(void) +{ + static int osversion; + struct new_utsname buf; + const char *s; + + if (osversion) + return osversion; + if (qemu_uname_release && *qemu_uname_release) { + s = qemu_uname_release; + } else { + if (sys_uname(&buf)) + return 0; + s = buf.release; + } + osversion = relstr_to_int(s); return osversion; } +void init_qemu_uname_release(void) +{ + /* Initialize qemu_uname_release for later use. + * If the host kernel is too old and the user hasn't asked for + * a specific fake version number, we might want to fake a minimum + * target kernel version. + */ +#ifdef UNAME_MINIMUM_RELEASE + struct new_utsname buf; + + if (qemu_uname_release && *qemu_uname_release) { + return; + } + + if (sys_uname(&buf)) { + return; + } + + if (relstr_to_int(buf.release) < relstr_to_int(UNAME_MINIMUM_RELEASE)) { + qemu_uname_release = UNAME_MINIMUM_RELEASE; + } +#endif +} static int open_self_maps(void *cpu_env, int fd) {