Revived GUEST_BASE support for usermode emulation targets [v5]
[qemu] / vl.c
diff --git a/vl.c b/vl.c
index f8c0d00..3d213f3 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -33,6 +33,7 @@
 #include "config-host.h"
 
 #ifndef _WIN32
+#include <libgen.h>
 #include <pwd.h>
 #include <sys/times.h>
 #include <sys/wait.h>
 
 #ifdef CONFIG_SDL
 #ifdef __APPLE__
-#include <SDL/SDL.h>
+#include <SDL.h>
 int qemu_main(int argc, char **argv, char **envp);
 int main(int argc, char **argv)
 {
@@ -191,7 +192,7 @@ int main(int argc, char **argv)
 /* XXX: use a two level table to limit memory usage */
 #define MAX_IOPORTS 65536
 
-const char *bios_dir = CONFIG_QEMU_SHAREDIR;
+static const char *data_dir;
 const char *bios_name = NULL;
 static void *ioport_opaque[MAX_IOPORTS];
 static IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
@@ -243,6 +244,7 @@ int smp_cpus = 1;
 const char *vnc_display;
 int acpi_enabled = 1;
 int no_hpet = 0;
+int no_virtio_balloon = 0;
 int fd_bootchk = 1;
 int no_reboot = 0;
 int no_shutdown = 0;
@@ -1835,45 +1837,34 @@ int get_param_value(char *buf, int buf_size,
     return 0;
 }
 
-int check_params(const char * const *params, const char *str)
+int check_params(char *buf, int buf_size,
+                 const char * const *params, const char *str)
 {
-    int name_buf_size = 1;
     const char *p;
-    char *name_buf;
-    int i, len;
-    int ret = 0;
-
-    for (i = 0; params[i] != NULL; i++) {
-        len = strlen(params[i]) + 1;
-        if (len > name_buf_size) {
-            name_buf_size = len;
-        }
-    }
-    name_buf = qemu_malloc(name_buf_size);
+    int i;
 
     p = str;
     while (*p != '\0') {
-        p = get_opt_name(name_buf, name_buf_size, p, '=');
+        p = get_opt_name(buf, buf_size, p, '=');
         if (*p != '=') {
-            ret = -1;
-            break;
+            return -1;
         }
         p++;
-        for(i = 0; params[i] != NULL; i++)
-            if (!strcmp(params[i], name_buf))
+        for (i = 0; params[i] != NULL; i++) {
+            if (!strcmp(params[i], buf)) {
                 break;
+            }
+        }
         if (params[i] == NULL) {
-            ret = -1;
-            break;
+            return -1;
         }
         p = get_opt_value(NULL, 0, p);
-        if (*p != ',')
+        if (*p != ',') {
             break;
+        }
         p++;
     }
-
-    qemu_free(name_buf);
-    return ret;
+    return 0;
 }
 
 /***********************************************************/
@@ -2226,8 +2217,9 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque)
                                            "cache", "format", "serial", "werror",
                                            NULL };
 
-    if (check_params(params, str) < 0) {
-         fprintf(stderr, "qemu: unknown parameter in '%s'\n", str);
+    if (check_params(buf, sizeof(buf), params, str) < 0) {
+         fprintf(stderr, "qemu: unknown parameter '%s' in '%s'\n",
+                         buf, str);
          return -1;
     }
 
@@ -2708,7 +2700,7 @@ static int usb_device_add(const char *devname, int is_hotplug)
     } else if (strstart(devname, "net:", &p)) {
         int nic = nb_nics;
 
-        if (net_client_init("nic", p) < 0)
+        if (net_client_init(NULL, "nic", p) < 0)
             return -1;
         nd_table[nic].model = "usb";
         dev = usb_net_init(&nd_table[nic]);
@@ -4387,6 +4379,7 @@ static int tcg_has_work(void)
 
 static int qemu_calculate_timeout(void)
 {
+#ifndef CONFIG_IOTHREAD
     int timeout;
 
     if (!vm_running)
@@ -4432,6 +4425,9 @@ static int qemu_calculate_timeout(void)
     }
 
     return timeout;
+#else /* CONFIG_IOTHREAD */
+    return 1000;
+#endif
 }
 
 static int vm_can_run(void)
@@ -4467,11 +4463,7 @@ static void main_loop(void)
 #ifdef CONFIG_PROFILER
             ti = profile_getclock();
 #endif
-#ifdef CONFIG_IOTHREAD
-            main_loop_wait(1000);
-#else
             main_loop_wait(qemu_calculate_timeout());
-#endif
 #ifdef CONFIG_PROFILER
             dev_time += profile_getclock() - ti;
 #endif
@@ -4782,7 +4774,12 @@ static void termsig_handler(int signal)
     qemu_system_shutdown_request();
 }
 
-static void termsig_setup(void)
+static void sigchld_handler(int signal)
+{
+    waitpid(-1, NULL, WNOHANG);
+}
+
+static void sighandler_setup(void)
 {
     struct sigaction act;
 
@@ -4791,10 +4788,138 @@ static void termsig_setup(void)
     sigaction(SIGINT,  &act, NULL);
     sigaction(SIGHUP,  &act, NULL);
     sigaction(SIGTERM, &act, NULL);
+
+    act.sa_handler = sigchld_handler;
+    act.sa_flags = SA_NOCLDSTOP;
+    sigaction(SIGCHLD, &act, NULL);
 }
 
 #endif
 
+#ifdef _WIN32
+/* Look for support files in the same directory as the executable.  */
+static char *find_datadir(const char *argv0)
+{
+    char *p;
+    char buf[MAX_PATH];
+    DWORD len;
+
+    len = GetModuleFileName(NULL, buf, sizeof(buf) - 1);
+    if (len == 0) {
+        return NULL;
+    }
+
+    buf[len] = 0;
+    p = buf + len - 1;
+    while (p != buf && *p != '\\')
+        p--;
+    *p = 0;
+    if (access(buf, R_OK) == 0) {
+        return qemu_strdup(buf);
+    }
+    return NULL;
+}
+#else /* !_WIN32 */
+
+/* Find a likely location for support files using the location of the binary.
+   For installed binaries this will be "$bindir/../share/qemu".  When
+   running from the build tree this will be "$bindir/../pc-bios".  */
+#define SHARE_SUFFIX "/share/qemu"
+#define BUILD_SUFFIX "/pc-bios"
+static char *find_datadir(const char *argv0)
+{
+    char *dir;
+    char *p = NULL;
+    char *res;
+#ifdef PATH_MAX
+    char buf[PATH_MAX];
+#endif
+    size_t max_len;
+
+#if defined(__linux__)
+    {
+        int len;
+        len = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
+        if (len > 0) {
+            buf[len] = 0;
+            p = buf;
+        }
+    }
+#elif defined(__FreeBSD__)
+    {
+        int len;
+        len = readlink("/proc/curproc/file", buf, sizeof(buf) - 1);
+        if (len > 0) {
+            buf[len] = 0;
+            p = buf;
+        }
+    }
+#endif
+    /* If we don't have any way of figuring out the actual executable
+       location then try argv[0].  */
+    if (!p) {
+#ifdef PATH_MAX
+        p = buf;
+#endif
+        p = realpath(argv0, p);
+        if (!p) {
+            return NULL;
+        }
+    }
+    dir = dirname(p);
+    dir = dirname(dir);
+
+    max_len = strlen(dir) +
+        MAX(strlen(SHARE_SUFFIX), strlen(BUILD_SUFFIX)) + 1;
+    res = qemu_mallocz(max_len);
+    snprintf(res, max_len, "%s%s", dir, SHARE_SUFFIX);
+    if (access(res, R_OK)) {
+        snprintf(res, max_len, "%s%s", dir, BUILD_SUFFIX);
+        if (access(res, R_OK)) {
+            qemu_free(res);
+            res = NULL;
+        }
+    }
+#ifndef PATH_MAX
+    free(p);
+#endif
+    return res;
+}
+#undef SHARE_SUFFIX
+#undef BUILD_SUFFIX
+#endif
+
+char *qemu_find_file(int type, const char *name)
+{
+    int len;
+    const char *subdir;
+    char *buf;
+
+    /* If name contains path separators then try it as a straight path.  */
+    if ((strchr(name, '/') || strchr(name, '\\'))
+        && access(name, R_OK) == 0) {
+        return strdup(name);
+    }
+    switch (type) {
+    case QEMU_FILE_TYPE_BIOS:
+        subdir = "";
+        break;
+    case QEMU_FILE_TYPE_KEYMAP:
+        subdir = "keymaps/";
+        break;
+    default:
+        abort();
+    }
+    len = strlen(data_dir) + strlen(name) + strlen(subdir) + 2;
+    buf = qemu_mallocz(len);
+    snprintf(buf, len, "%s/%s%s", data_dir, subdir, name);
+    if (access(buf, R_OK)) {
+        qemu_free(buf);
+        return NULL;
+    }
+    return buf;
+}
+
 int main(int argc, char **argv, char **envp)
 {
     const char *gdbstub_dev = NULL;
@@ -5234,7 +5359,7 @@ int main(int argc, char **argv, char **envp)
                 gdbstub_dev = optarg;
                 break;
             case QEMU_OPTION_L:
-                bios_dir = optarg;
+                data_dir = optarg;
                 break;
             case QEMU_OPTION_bios:
                 bios_name = optarg;
@@ -5427,6 +5552,9 @@ int main(int argc, char **argv, char **envp)
             case QEMU_OPTION_no_hpet:
                 no_hpet = 1;
                 break;
+            case QEMU_OPTION_no_virtio_balloon:
+                no_virtio_balloon = 1;
+                break;
 #endif
             case QEMU_OPTION_no_reboot:
                 no_reboot = 1;
@@ -5560,6 +5688,16 @@ int main(int argc, char **argv, char **envp)
         }
     }
 
+    /* If no data_dir is specified then try to find it relative to the
+       executable path.  */
+    if (!data_dir) {
+        data_dir = find_datadir(argv[0]);
+    }
+    /* If all else fails use the install patch specified when building.  */
+    if (!data_dir) {
+        data_dir = CONFIG_QEMU_SHAREDIR;
+    }
+
 #if defined(CONFIG_KVM) && defined(CONFIG_KQEMU)
     if (kvm_allowed && kqemu_allowed) {
         fprintf(stderr,
@@ -5705,19 +5843,24 @@ int main(int argc, char **argv, char **envp)
        for (i = 0; i < nb_nics && i < 4; i++) {
            const char *model = nd_table[i].model;
            char buf[1024];
+            char *filename;
             if (net_boot & (1 << i)) {
                 if (model == NULL)
                     model = "ne2k_pci";
-                snprintf(buf, sizeof(buf), "%s/pxe-%s.bin", bios_dir, model);
-                if (get_image_size(buf) > 0) {
+                snprintf(buf, sizeof(buf), "pxe-%s.bin", model);
+                filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, buf);
+                if (filename && get_image_size(filename) > 0) {
                     if (nb_option_roms >= MAX_OPTION_ROMS) {
                         fprintf(stderr, "Too many option ROMs\n");
                         exit(1);
                     }
-                    option_rom[nb_option_roms] = strdup(buf);
+                    option_rom[nb_option_roms] = qemu_strdup(buf);
                     nb_option_roms++;
                     netroms++;
                 }
+                if (filename) {
+                    qemu_free(filename);
+                }
             }
        }
        if (netroms == 0) {
@@ -5780,7 +5923,7 @@ int main(int argc, char **argv, char **envp)
 
 #ifndef _WIN32
     /* must be after terminal init, SDL library changes signal handlers */
-    termsig_setup();
+    sighandler_setup();
 #endif
 
     /* Maintain compatibility with multiple stdio monitors */