#ifndef _WIN32
#include <libgen.h>
-#include <pwd.h>
#include <sys/times.h>
#include <sys/wait.h>
#include <termios.h>
#ifdef __linux__
#include <pty.h>
#include <malloc.h>
-#include <sys/prctl.h>
#include <linux/ppdev.h>
#include <linux/parport.h>
#include <sys/ethernet.h>
#include <sys/sockio.h>
#include <netinet/arp.h>
-#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h> // must come after ip.h
#include "qemu-option.h"
#include "qemu-config.h"
#include "qemu-objects.h"
-#ifdef CONFIG_LINUX
+#include "qemu-options.h"
+#ifdef CONFIG_VIRTFS
#include "fsdev/qemu-fsdev.h"
#endif
int cursor_hide = 1;
int graphic_rotate = 0;
uint8_t irq0override = 1;
-#ifndef _WIN32
-int daemonize = 0;
-#endif
const char *watchdog;
const char *option_rom[MAX_OPTION_ROMS];
int nb_option_roms;
static QEMUBootSetHandler *boot_set_handler;
static void *boot_set_opaque;
+static NotifierList exit_notifiers =
+ NOTIFIER_LIST_INITIALIZER(exit_notifiers);
+
int kvm_allowed = 0;
uint32_t xen_domid;
enum xen_mode xen_mode = XEN_EMULATE;
return 0;
}
-/***********************************************************/
-
-static void set_proc_name(const char *s)
-{
-#if defined(__linux__) && defined(PR_SET_NAME)
- char name[16];
- if (!s)
- return;
- name[sizeof(name) - 1] = 0;
- strncpy(name, s, sizeof(name));
- /* Could rewrite argv[0] too, but that's a bit more complicated.
- This simple way is enough for `top'. */
- prctl(PR_SET_NAME, name);
-#endif
-}
-
/***********************************************************/
/* real time host monotonic timer */
return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
}
-#ifdef _WIN32
-/***********************************************************/
-/* Polling handling */
-
-typedef struct PollingEntry {
- PollingFunc *func;
- void *opaque;
- struct PollingEntry *next;
-} PollingEntry;
-
-static PollingEntry *first_polling_entry;
-
-int qemu_add_polling_cb(PollingFunc *func, void *opaque)
-{
- PollingEntry **ppe, *pe;
- pe = qemu_mallocz(sizeof(PollingEntry));
- pe->func = func;
- pe->opaque = opaque;
- for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next);
- *ppe = pe;
- return 0;
-}
-
-void qemu_del_polling_cb(PollingFunc *func, void *opaque)
-{
- PollingEntry **ppe, *pe;
- for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) {
- pe = *ppe;
- if (pe->func == func && pe->opaque == opaque) {
- *ppe = pe->next;
- qemu_free(pe);
- break;
- }
- }
-}
-
-/***********************************************************/
-/* Wait objects support */
-typedef struct WaitObjects {
- int num;
- HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];
- WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1];
- void *opaque[MAXIMUM_WAIT_OBJECTS + 1];
-} WaitObjects;
-
-static WaitObjects wait_objects = {0};
-
-int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
-{
- WaitObjects *w = &wait_objects;
-
- if (w->num >= MAXIMUM_WAIT_OBJECTS)
- return -1;
- w->events[w->num] = handle;
- w->func[w->num] = func;
- w->opaque[w->num] = opaque;
- w->num++;
- return 0;
-}
-
-void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
-{
- int i, found;
- WaitObjects *w = &wait_objects;
-
- found = 0;
- for (i = 0; i < w->num; i++) {
- if (w->events[i] == handle)
- found = 1;
- if (found) {
- w->events[i] = w->events[i + 1];
- w->func[i] = w->func[i + 1];
- w->opaque[i] = w->opaque[i + 1];
- }
- }
- if (found)
- w->num--;
-}
-#endif
-
/***********************************************************/
/* machine registration */
qemu_notify_event();
}
-#ifdef _WIN32
-static void host_main_loop_wait(int *timeout)
-{
- int ret, ret2, i;
- PollingEntry *pe;
-
-
- /* XXX: need to suppress polling by better using win32 events */
- ret = 0;
- for(pe = first_polling_entry; pe != NULL; pe = pe->next) {
- ret |= pe->func(pe->opaque);
- }
- if (ret == 0) {
- int err;
- WaitObjects *w = &wait_objects;
-
- ret = WaitForMultipleObjects(w->num, w->events, FALSE, *timeout);
- if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
- if (w->func[ret - WAIT_OBJECT_0])
- w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
-
- /* Check for additional signaled events */
- for(i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) {
-
- /* Check if event is signaled */
- ret2 = WaitForSingleObject(w->events[i], 0);
- if(ret2 == WAIT_OBJECT_0) {
- if (w->func[i])
- w->func[i](w->opaque[i]);
- } else if (ret2 == WAIT_TIMEOUT) {
- } else {
- err = GetLastError();
- fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err);
- }
- }
- } else if (ret == WAIT_TIMEOUT) {
- } else {
- err = GetLastError();
- fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err);
- }
- }
-
- *timeout = 0;
-}
-#else
-static void host_main_loop_wait(int *timeout)
-{
-}
-#endif
-
void main_loop_wait(int nonblocking)
{
IOHandlerRecord *ioh;
qemu_bh_update_timeout(&timeout);
}
- host_main_loop_wait(&timeout);
+ os_host_main_loop_wait(&timeout);
/* poll any events */
/* XXX: separate device handlers from system ones */
#define DEF(option, opt_arg, opt_enum, opt_help, arch_mask) \
opt_help
#define DEFHEADING(text) stringify(text) "\n"
-#include "qemu-options.h"
+#include "qemu-options.def"
#undef DEF
#undef DEFHEADING
#undef GEN_DOCS
#define HAS_ARG 0x0001
-enum {
-#define DEF(option, opt_arg, opt_enum, opt_help, arch_mask) \
- opt_enum,
-#define DEFHEADING(text)
-#include "qemu-options.h"
-#undef DEF
-#undef DEFHEADING
-#undef GEN_DOCS
-};
-
typedef struct QEMUOption {
const char *name;
int flags;
#define DEF(option, opt_arg, opt_enum, opt_help, arch_mask) \
{ option, opt_arg, opt_enum, arch_mask },
#define DEFHEADING(text)
-#include "qemu-options.h"
+#include "qemu-options.def"
#undef DEF
#undef DEFHEADING
#undef GEN_DOCS
return -1;
}
-#ifdef _WIN32
-static BOOL WINAPI qemu_ctrl_handler(DWORD type)
-{
- exit(STATUS_CONTROL_C_EXIT);
- return TRUE;
-}
-#endif
-
-#ifndef _WIN32
-
-static void termsig_handler(int signal)
-{
- qemu_system_shutdown_request();
-}
-
-static void sigchld_handler(int signal)
-{
- waitpid(-1, NULL, WNOHANG);
-}
-
-static void sighandler_setup(void)
-{
- struct sigaction act;
-
- memset(&act, 0, sizeof(act));
- act.sa_handler = termsig_handler;
- 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;
- char buf[PATH_MAX];
- 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__)
- {
- static int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
- size_t len = sizeof(buf) - 1;
-
- *buf = '\0';
- if (!sysctl(mib, sizeof(mib)/sizeof(*mib), buf, &len, NULL, 0) &&
- *buf) {
- buf[sizeof(buf) - 1] = '\0';
- p = buf;
- }
- }
-#endif
- /* If we don't have any way of figuring out the actual executable
- location then try argv[0]. */
- if (!p) {
- p = realpath(argv0, buf);
- 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;
- }
- }
-
- return res;
-}
-#undef SHARE_SUFFIX
-#undef BUILD_SUFFIX
-#endif
-
char *qemu_find_file(int type, const char *name)
{
int len;
return 0;
}
-#ifdef CONFIG_LINUX
+#ifdef CONFIG_VIRTFS
static int fsdev_init_func(QemuOpts *opts, void *opaque)
{
int ret;
return 0;
}
+void qemu_add_exit_notifier(Notifier *notify)
+{
+ notifier_list_add(&exit_notifiers, notify);
+}
+
+void qemu_remove_exit_notifier(Notifier *notify)
+{
+ notifier_list_remove(&exit_notifiers, notify);
+}
+
+static void qemu_run_exit_notifiers(void)
+{
+ notifier_list_notify(&exit_notifiers);
+}
+
static const QEMUOption *lookup_opt(int argc, char **argv,
const char **poptarg, int *poptind)
{
const char *loadvm = NULL;
QEMUMachine *machine;
const char *cpu_model;
-#ifndef _WIN32
- int fds[2];
-#endif
int tb_size;
const char *pid_file = NULL;
const char *incoming = NULL;
-#ifndef _WIN32
- int fd = 0;
- struct passwd *pwd = NULL;
- const char *chroot_dir = NULL;
- const char *run_as = NULL;
-#endif
int show_vnc_port = 0;
int defconfig = 1;
+ atexit(qemu_run_exit_notifiers);
error_set_progname(argv[0]);
init_clocks();
qemu_cache_utils_init(envp);
QLIST_INIT (&vm_change_state_head);
-#ifndef _WIN32
- {
- struct sigaction act;
- sigfillset(&act.sa_mask);
- act.sa_flags = 0;
- act.sa_handler = SIG_IGN;
- sigaction(SIGPIPE, &act, NULL);
- }
-#else
- SetConsoleCtrlHandler(qemu_ctrl_handler, TRUE);
- /* Note: cpu_interrupt() is currently not SMP safe, so we force
- QEMU to run on a single CPU */
- {
- HANDLE h;
- DWORD mask, smask;
- int i;
- h = GetCurrentProcess();
- if (GetProcessAffinityMask(h, &mask, &smask)) {
- for(i = 0; i < 32; i++) {
- if (mask & (1 << i))
- break;
- }
- if (i != 32) {
- mask = 1 << i;
- SetProcessAffinityMask(h, mask);
- }
- }
- }
-#endif
+ os_setup_early_signal_handling();
module_call_init(MODULE_INIT_MACHINE);
machine = find_default_machine();
case QEMU_OPTION_bootp:
legacy_bootp_filename = optarg;
break;
-#ifndef _WIN32
- case QEMU_OPTION_smb:
- if (net_slirp_smb(optarg) < 0)
- exit(1);
- break;
-#endif
case QEMU_OPTION_redir:
if (net_slirp_redir(optarg) < 0)
exit(1);
exit(1);
}
break;
-#ifdef CONFIG_LINUX
+#ifdef CONFIG_VIRTFS
case QEMU_OPTION_fsdev:
opts = qemu_opts_parse(&qemu_fsdev_opts, optarg, 1);
if (!opts) {
exit(1);
}
- len = strlen(",id=,path=");
+ if (qemu_opt_get(opts, "fstype") == NULL ||
+ qemu_opt_get(opts, "mount_tag") == NULL ||
+ qemu_opt_get(opts, "path") == NULL ||
+ qemu_opt_get(opts, "security_model") == NULL) {
+ fprintf(stderr, "Usage: -virtfs fstype,path=/share_path/,"
+ "security_model=[mapped|passthrough],"
+ "mnt_tag=tag.\n");
+ exit(1);
+ }
+
+ len = strlen(",id=,path=,security_model=");
len += strlen(qemu_opt_get(opts, "fstype"));
len += strlen(qemu_opt_get(opts, "mount_tag"));
len += strlen(qemu_opt_get(opts, "path"));
+ len += strlen(qemu_opt_get(opts, "security_model"));
arg_fsdev = qemu_malloc((len + 1) * sizeof(*arg_fsdev));
if (!arg_fsdev) {
exit(1);
}
- sprintf(arg_fsdev, "%s,id=%s,path=%s",
+ sprintf(arg_fsdev, "%s,id=%s,path=%s,security_model=%s",
qemu_opt_get(opts, "fstype"),
qemu_opt_get(opts, "mount_tag"),
- qemu_opt_get(opts, "path"));
+ qemu_opt_get(opts, "path"),
+ qemu_opt_get(opts, "security_model"));
len = strlen("virtio-9p-pci,fsdev=,mount_tag=");
len += 2*strlen(qemu_opt_get(opts, "mount_tag"));
exit(1);
}
break;
-#ifndef _WIN32
- case QEMU_OPTION_daemonize:
- daemonize = 1;
- break;
-#endif
case QEMU_OPTION_option_rom:
if (nb_option_roms >= MAX_OPTION_ROMS) {
fprintf(stderr, "Too many option ROMs\n");
exit(1);
}
p += 8;
- set_proc_name(p);
+ os_set_proc_name(p);
}
}
break;
default_cdrom = 0;
default_sdcard = 0;
break;
-#ifndef _WIN32
- case QEMU_OPTION_chroot:
- chroot_dir = optarg;
- break;
- case QEMU_OPTION_runas:
- run_as = optarg;
- break;
-#endif
case QEMU_OPTION_xen_domid:
if (!(xen_available())) {
printf("Option %s not supported for this target\n", popt->name);
fclose(fp);
break;
}
+ default:
+ os_parse_cmd_args(popt->index, optarg);
}
}
}
/* 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]);
+ data_dir = os_find_datadir(argv[0]);
}
/* If all else fails use the install patch specified when building. */
if (!data_dir) {
- data_dir = CONFIG_QEMU_SHAREDIR;
+ data_dir = CONFIG_QEMU_DATADIR;
}
/*
if (qemu_opts_foreach(&qemu_chardev_opts, chardev_init_func, NULL, 1) != 0)
exit(1);
-#ifdef CONFIG_LINUX
+#ifdef CONFIG_VIRTFS
if (qemu_opts_foreach(&qemu_fsdev_opts, fsdev_init_func, NULL, 1) != 0) {
exit(1);
}
#endif
-#ifndef _WIN32
- if (daemonize) {
- pid_t pid;
-
- if (pipe(fds) == -1)
- exit(1);
-
- pid = fork();
- if (pid > 0) {
- uint8_t status;
- ssize_t len;
-
- close(fds[1]);
-
- again:
- len = read(fds[0], &status, 1);
- if (len == -1 && (errno == EINTR))
- goto again;
-
- if (len != 1)
- exit(1);
- else if (status == 1) {
- fprintf(stderr, "Could not acquire pidfile: %s\n", strerror(errno));
- exit(1);
- } else
- exit(0);
- } else if (pid < 0)
- exit(1);
-
- close(fds[0]);
- qemu_set_cloexec(fds[1]);
-
- setsid();
-
- pid = fork();
- if (pid > 0)
- exit(0);
- else if (pid < 0)
- exit(1);
-
- umask(027);
-
- signal(SIGTSTP, SIG_IGN);
- signal(SIGTTOU, SIG_IGN);
- signal(SIGTTIN, SIG_IGN);
- }
-#endif
+ os_daemonize();
if (pid_file && qemu_create_pidfile(pid_file) != 0) {
-#ifndef _WIN32
- if (daemonize) {
- uint8_t status = 1;
- if (write(fds[1], &status, 1) != 1) {
- perror("daemonize. Writing to pipe\n");
- }
- } else
-#endif
- fprintf(stderr, "Could not acquire pid file: %s\n", strerror(errno));
+ os_pidfile_error();
exit(1);
}
exit(1);
}
-#ifndef _WIN32
- /* Win32 doesn't support line-buffering and requires size >= 2 */
- setvbuf(stdout, NULL, _IOLBF, 0);
-#endif
+ os_set_line_buffering();
if (init_timer_alarm() < 0) {
fprintf(stderr, "could not initialize alarm timer\n");
if (qemu_opts_foreach(&qemu_drive_opts, drive_init_func, &machine->use_scsi, 1) != 0)
exit(1);
- register_savevm_live("ram", 0, 3, NULL, ram_save_live, NULL,
+ register_savevm_live(NULL, "ram", 0, 4, NULL, ram_save_live, NULL,
ram_load, NULL);
if (nb_numa_nodes > 0) {
cpu_synchronize_all_post_init();
-#ifndef _WIN32
/* must be after terminal init, SDL library changes signal handlers */
- sighandler_setup();
-#endif
+ os_setup_signal_handling();
set_numa_modes();
if (dcl->dpy_refresh != NULL) {
ds->gui_timer = qemu_new_timer(rt_clock, gui_update, ds);
qemu_mod_timer(ds->gui_timer, qemu_get_clock(rt_clock));
+ break;
}
dcl = dcl->next;
}
}
if (incoming) {
- qemu_start_incoming_migration(incoming);
+ int ret = qemu_start_incoming_migration(incoming);
+ if (ret < 0) {
+ fprintf(stderr, "Migration failed. Exit code %s(%d), exiting.\n",
+ incoming, ret);
+ exit(ret);
+ }
} else if (autostart) {
vm_start();
}
-#ifndef _WIN32
- if (daemonize) {
- uint8_t status = 0;
- ssize_t len;
-
- again1:
- len = write(fds[1], &status, 1);
- if (len == -1 && (errno == EINTR))
- goto again1;
-
- if (len != 1)
- exit(1);
-
- if (chdir("/")) {
- perror("not able to chdir to /");
- exit(1);
- }
- TFR(fd = qemu_open("/dev/null", O_RDWR));
- if (fd == -1)
- exit(1);
- }
-
- if (run_as) {
- pwd = getpwnam(run_as);
- if (!pwd) {
- fprintf(stderr, "User \"%s\" doesn't exist\n", run_as);
- exit(1);
- }
- }
-
- if (chroot_dir) {
- if (chroot(chroot_dir) < 0) {
- fprintf(stderr, "chroot failed\n");
- exit(1);
- }
- if (chdir("/")) {
- perror("not able to chdir to /");
- exit(1);
- }
- }
-
- if (run_as) {
- if (setgid(pwd->pw_gid) < 0) {
- fprintf(stderr, "Failed to setgid(%d)\n", pwd->pw_gid);
- exit(1);
- }
- if (setuid(pwd->pw_uid) < 0) {
- fprintf(stderr, "Failed to setuid(%d)\n", pwd->pw_uid);
- exit(1);
- }
- if (setuid(0) != -1) {
- fprintf(stderr, "Dropping privileges failed\n");
- exit(1);
- }
- }
-
- if (daemonize) {
- dup2(fd, 0);
- dup2(fd, 1);
- dup2(fd, 2);
-
- close(fd);
- }
-#endif
+ os_setup_post();
main_loop();
quit_timers();