summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--linux-user/main.c2
-rw-r--r--linux-user/qemu.h1
-rw-r--r--linux-user/syscall.c62
3 files changed, 51 insertions, 14 deletions
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,12 +4863,35 @@ int host_to_target_waitstatus(int status)
     return status;
 }
 
+static int relstr_to_int(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;
+
+    tmp = 0;
+    for (i = 0; i < 3; i++) {
+        n = 0;
+        while (*s >= '0' && *s <= '9') {
+            n *= 10;
+            n += *s - '0';
+            s++;
+        }
+        tmp = (tmp << 8) + n;
+        if (*s == '.') {
+            s++;
+        }
+    }
+    return tmp;
+}
+
 int get_osversion(void)
 {
     static int osversion;
     struct new_utsname buf;
     const char *s;
-    int i, n, tmp;
+
     if (osversion)
         return osversion;
     if (qemu_uname_release && *qemu_uname_release) {
@@ -4878,22 +4901,33 @@ int get_osversion(void)
             return 0;
         s = buf.release;
     }
-    tmp = 0;
-    for (i = 0; i < 3; i++) {
-        n = 0;
-        while (*s >= '0' && *s <= '9') {
-            n *= 10;
-            n += *s - '0';
-            s++;
-        }
-        tmp = (tmp << 8) + n;
-        if (*s == '.')
-            s++;
-    }
-    osversion = tmp;
+    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)
 {