* [Qemu-devel] [PATCH 1/3] Add unix domain socket character device
2006-12-16 17:57 [Qemu-devel] [PATCH 0/3] Add options to make writing a front end easier Anthony Liguori
@ 2006-12-16 18:00 ` Anthony Liguori
2006-12-16 18:04 ` [Qemu-devel] [PATCH 2/3] Add unix domain socket and interface restriction to VNC Anthony Liguori
2006-12-16 18:08 ` [Qemu-devel] [PATCH 3/3] Add daemonize option Anthony Liguori
2 siblings, 0 replies; 5+ messages in thread
From: Anthony Liguori @ 2006-12-16 18:00 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 242 bytes --]
This patch introduces a unix: domain socket. It reuses the tcp: code so
it will behave almost identically.
An example usage would be:
qemu -hda ~/win2k.img -monitor unix:/home/anthony/monitor.sock,server,nowait
Regards,
Anthony Liguori
[-- Attachment #2: qemu-char-unix.diff --]
[-- Type: text/x-patch, Size: 7296 bytes --]
diff -r 01fafeaa2f64 qemu_socket.h
--- a/qemu_socket.h Thu Dec 14 20:48:11 2006 +0000
+++ b/qemu_socket.h Sat Dec 16 11:19:45 2006 -0600
@@ -19,6 +19,7 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
+#include <sys/un.h>
#define socket_error() errno
#define closesocket(s) close(s)
diff -r 01fafeaa2f64 vl.c
--- a/vl.c Thu Dec 14 20:48:11 2006 +0000
+++ b/vl.c Sat Dec 16 11:42:40 2006 -0600
@@ -2206,6 +2206,7 @@ static void udp_chr_add_read_handler(Cha
}
int parse_host_port(struct sockaddr_in *saddr, const char *str);
+int parse_unix_path(struct sockaddr_un *uaddr, const char *str);
int parse_host_src_port(struct sockaddr_in *haddr,
struct sockaddr_in *saddr,
const char *str);
@@ -2270,6 +2271,7 @@ typedef struct {
int connected;
int max_size;
int do_telnetopt;
+ int is_unix;
} TCPCharDriver;
static void tcp_chr_accept(void *opaque);
@@ -2291,6 +2293,8 @@ static int tcp_chr_read_poll(void *opaqu
TCPCharDriver *s = chr->opaque;
if (!s->connected)
return 0;
+ if (!s->fd_can_read)
+ return 0;
s->max_size = s->fd_can_read(s->fd_opaque);
return s->max_size;
}
@@ -2416,12 +2420,25 @@ static void tcp_chr_accept(void *opaque)
CharDriverState *chr = opaque;
TCPCharDriver *s = chr->opaque;
struct sockaddr_in saddr;
+#ifndef _WIN32
+ struct sockaddr_un uaddr;
+#endif
+ struct sockaddr *addr;
socklen_t len;
int fd;
for(;;) {
- len = sizeof(saddr);
- fd = accept(s->listen_fd, (struct sockaddr *)&saddr, &len);
+#ifndef _WIN32
+ if (s->is_unix) {
+ len = sizeof(uaddr);
+ addr = (struct sockaddr *)&uaddr;
+ } else
+#endif
+ {
+ len = sizeof(saddr);
+ addr = (struct sockaddr *)&saddr;
+ }
+ fd = accept(s->listen_fd, addr, &len);
if (fd < 0 && errno != EINTR) {
return;
} else if (fd >= 0) {
@@ -2447,7 +2464,8 @@ static void tcp_chr_close(CharDriverStat
}
static CharDriverState *qemu_chr_open_tcp(const char *host_str,
- int is_telnet)
+ int is_telnet,
+ int is_unix)
{
CharDriverState *chr = NULL;
TCPCharDriver *s = NULL;
@@ -2456,9 +2474,26 @@ static CharDriverState *qemu_chr_open_tc
int is_waitconnect = 1;
const char *ptr;
struct sockaddr_in saddr;
-
- if (parse_host_port(&saddr, host_str) < 0)
- goto fail;
+#ifndef _WIN32
+ struct sockaddr_un uaddr;
+#endif
+ struct sockaddr *addr;
+ socklen_t addrlen;
+
+#ifndef _WIN32
+ if (is_unix) {
+ addr = (struct sockaddr *)&uaddr;
+ addrlen = sizeof(uaddr);
+ if (parse_unix_path(&uaddr, host_str) < 0)
+ goto fail;
+ } else
+#endif
+ {
+ addr = (struct sockaddr *)&saddr;
+ addrlen = sizeof(saddr);
+ if (parse_host_port(&saddr, host_str) < 0)
+ goto fail;
+ }
ptr = host_str;
while((ptr = strchr(ptr,','))) {
@@ -2481,8 +2516,14 @@ static CharDriverState *qemu_chr_open_tc
s = qemu_mallocz(sizeof(TCPCharDriver));
if (!s)
goto fail;
-
- fd = socket(PF_INET, SOCK_STREAM, 0);
+
+#ifndef _WIN32
+ if (is_unix)
+ fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ else
+#endif
+ fd = socket(PF_INET, SOCK_STREAM, 0);
+
if (fd < 0)
goto fail;
@@ -2492,24 +2533,43 @@ static CharDriverState *qemu_chr_open_tc
s->connected = 0;
s->fd = -1;
s->listen_fd = -1;
+ s->is_unix = is_unix;
+
+ chr->opaque = s;
+ chr->chr_write = tcp_chr_write;
+ chr->chr_add_read_handler = tcp_chr_add_read_handler;
+ chr->chr_close = tcp_chr_close;
+
if (is_listen) {
/* allow fast reuse */
- val = 1;
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
+#ifndef _WIN32
+ if (is_unix) {
+ char path[109];
+ strncpy(path, uaddr.sun_path, 108);
+ path[108] = 0;
+ unlink(path);
+ } else
+#endif
+ {
+ val = 1;
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
+ }
- ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
- if (ret < 0)
+ ret = bind(fd, addr, addrlen);
+ if (ret < 0)
goto fail;
+
ret = listen(fd, 0);
if (ret < 0)
goto fail;
+
s->listen_fd = fd;
qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
if (is_telnet)
s->do_telnetopt = 1;
} else {
for(;;) {
- ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
+ ret = connect(fd, addr, addrlen);
if (ret < 0) {
err = socket_error();
if (err == EINTR || err == EWOULDBLOCK) {
@@ -2530,10 +2590,6 @@ static CharDriverState *qemu_chr_open_tc
qemu_set_fd_handler(s->fd, NULL, tcp_chr_connect, chr);
}
- chr->opaque = s;
- chr->chr_write = tcp_chr_write;
- chr->chr_add_read_handler = tcp_chr_add_read_handler;
- chr->chr_close = tcp_chr_close;
if (is_listen && is_waitconnect) {
printf("QEMU waiting for connection on: %s\n", host_str);
tcp_chr_accept(chr);
@@ -2559,16 +2615,18 @@ CharDriverState *qemu_chr_open(const cha
return qemu_chr_open_null();
} else
if (strstart(filename, "tcp:", &p)) {
- return qemu_chr_open_tcp(p, 0);
+ return qemu_chr_open_tcp(p, 0, 0);
} else
if (strstart(filename, "telnet:", &p)) {
- return qemu_chr_open_tcp(p, 1);
+ return qemu_chr_open_tcp(p, 1, 0);
} else
if (strstart(filename, "udp:", &p)) {
return qemu_chr_open_udp(p);
} else
#ifndef _WIN32
- if (strstart(filename, "file:", &p)) {
+ if (strstart(filename, "unix:", &p)) {
+ return qemu_chr_open_tcp(p, 0, 1);
+ } else if (strstart(filename, "file:", &p)) {
return qemu_chr_open_file_out(p);
} else if (strstart(filename, "pipe:", &p)) {
return qemu_chr_open_pipe(p);
@@ -2740,6 +2798,24 @@ int parse_host_port(struct sockaddr_in *
if (r == p)
return -1;
saddr->sin_port = htons(port);
+ return 0;
+}
+
+int parse_unix_path(struct sockaddr_un *uaddr, const char *str)
+{
+ const char *p;
+ int len;
+
+ len = MIN(108, strlen(str));
+ p = strchr(str, ',');
+ if (p)
+ len = MIN(len, p - str);
+
+ memset(uaddr, 0, sizeof(*uaddr));
+
+ uaddr->sun_family = AF_UNIX;
+ memcpy(uaddr->sun_path, str, len);
+
return 0;
}
@@ -6955,6 +7031,7 @@ int main(int argc, char **argv)
vm_start();
}
}
+
main_loop();
quit_timers();
return 0;
diff -r 01fafeaa2f64 qemu-doc.texi
--- a/qemu-doc.texi Thu Dec 14 20:48:11 2006 +0000
+++ b/qemu-doc.texi Sat Dec 16 11:45:08 2006 -0600
@@ -586,6 +586,11 @@ sequence. Typically in unix telnet you
sequence. Typically in unix telnet you do it with Control-] and then
type "send break" followed by pressing the enter key.
+@item unix:path[,server][,nowait]
+A unix domain socket is used instead of a tcp socket. The option works the
+same as if you had specified @code{-serial tcp} except the unix domain socket
+@var{path} is used for connections.
+
@end table
@item -parallel dev
^ permalink raw reply [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH 2/3] Add unix domain socket and interface restriction to VNC
2006-12-16 17:57 [Qemu-devel] [PATCH 0/3] Add options to make writing a front end easier Anthony Liguori
2006-12-16 18:00 ` [Qemu-devel] [PATCH 1/3] Add unix domain socket character device Anthony Liguori
@ 2006-12-16 18:04 ` Anthony Liguori
2006-12-16 18:08 ` [Qemu-devel] [PATCH 3/3] Add daemonize option Anthony Liguori
2 siblings, 0 replies; 5+ messages in thread
From: Anthony Liguori @ 2006-12-16 18:04 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 754 bytes --]
The following patch allows a user to restrict which interface the VNC
server will listen on. It also adds unix domain socket support to VNC.
N.B. The old syntax of:
qemu -vnc 1
Is now:
qemu -vnc :1
Also, the syntax between the unix char devices and VNC is a bit
different. This is because the current VNC server does not support
reverse connections. I don't really think supporting reverse
connections is all that useful so I'm happy to leave it this way.
Some example usages:
qemu -hda ~/win2k.img -vnc :1 # listen on 0.0.0.0:5901 TCP
qemu -hda ~/win2k.img -vnc 192.168.1.0:1 # listen on 192.168.1.0:5901 TCP
qemu -hda ~/win2k.img -vnc unix:/home/anthony/vga.sock # listen on unix
socket /home/anthony/vga.sock
Regards,
Anthony Liguori
[-- Attachment #2: qemu-vnc-unix.diff --]
[-- Type: text/x-patch, Size: 5896 bytes --]
diff -r 9b429747f69c qemu-doc.texi
--- a/qemu-doc.texi Sat Dec 16 11:45:18 2006 -0600
+++ b/qemu-doc.texi Sat Dec 16 11:50:07 2006 -0600
@@ -247,14 +247,21 @@ the console. Therefore, you can still us
the console. Therefore, you can still use QEMU to debug a Linux kernel
with a serial console.
-@item -vnc d
+@item -vnc display
Normally, QEMU uses SDL to display the VGA output. With this option,
-you can have QEMU listen on VNC display @var{d} and redirect the VGA
+you can have QEMU listen on VNC display @var{display} and redirect the VGA
display over the VNC session. It is very useful to enable the usb
tablet device when using this option (option @option{-usbdevice
tablet}). When using the VNC display, you must use the @option{-k}
-option to set the keyboard layout.
+option to set the keyboard layout if you are not using en-us.
+
+@var{display} may be in the form @var{interface:d}, in which case connections
+will only be allowed from @var{interface} on display @var{d}. Optionally,
+@var{interface} can be omitted. @var{display} can also be in the form
+@var{unix:path} where @var{path} is the location of a unix socket to listen for
+connections on.
+
@item -k language
diff -r 9b429747f69c vl.c
--- a/vl.c Sat Dec 16 11:45:18 2006 -0600
+++ b/vl.c Sat Dec 16 11:49:32 2006 -0600
@@ -152,7 +152,7 @@ int usb_enabled = 0;
int usb_enabled = 0;
static VLANState *first_vlan;
int smp_cpus = 1;
-int vnc_display = -1;
+const char *vnc_display;
#if defined(TARGET_SPARC)
#define MAX_CPUS 16
#elif defined(TARGET_I386)
@@ -6818,11 +6818,7 @@ int main(int argc, char **argv)
}
break;
case QEMU_OPTION_vnc:
- vnc_display = atoi(optarg);
- if (vnc_display < 0) {
- fprintf(stderr, "Invalid VNC display\n");
- exit(1);
- }
+ vnc_display = optarg;
break;
case QEMU_OPTION_no_acpi:
acpi_enabled = 0;
@@ -6946,7 +6942,7 @@ int main(int argc, char **argv)
/* terminal init */
if (nographic) {
dumb_display_init(ds);
- } else if (vnc_display != -1) {
+ } else if (vnc_display != NULL) {
vnc_display_init(ds, vnc_display);
} else {
#if defined(CONFIG_SDL)
diff -r 9b429747f69c vl.h
--- a/vl.h Sat Dec 16 11:45:18 2006 -0600
+++ b/vl.h Sat Dec 16 11:45:25 2006 -0600
@@ -867,7 +867,7 @@ void cocoa_display_init(DisplayState *ds
void cocoa_display_init(DisplayState *ds, int full_screen);
/* vnc.c */
-void vnc_display_init(DisplayState *ds, int display);
+void vnc_display_init(DisplayState *ds, const char *display);
/* ide.c */
#define MAX_DISKS 4
diff -r 9b429747f69c vnc.c
--- a/vnc.c Sat Dec 16 11:45:18 2006 -0600
+++ b/vnc.c Sat Dec 16 11:45:25 2006 -0600
@@ -1101,10 +1101,18 @@ static void vnc_listen_read(void *opaque
}
}
-void vnc_display_init(DisplayState *ds, int display)
-{
- struct sockaddr_in addr;
+extern int parse_host_port(struct sockaddr_in *saddr, const char *str);
+
+void vnc_display_init(DisplayState *ds, const char *arg)
+{
+ struct sockaddr *addr;
+ struct sockaddr_in iaddr;
+#ifndef _WIN32
+ struct sockaddr_un uaddr;
+#endif
int reuse_addr, ret;
+ socklen_t addrlen;
+ const char *p;
VncState *vs;
vs = qemu_mallocz(sizeof(VncState));
@@ -1125,39 +1133,6 @@ void vnc_display_init(DisplayState *ds,
vs->kbd_layout = init_keyboard_layout(keyboard_layout);
if (!vs->kbd_layout)
exit(1);
-
- vs->lsock = socket(PF_INET, SOCK_STREAM, 0);
- if (vs->lsock == -1) {
- fprintf(stderr, "Could not create socket\n");
- exit(1);
- }
-
- addr.sin_family = AF_INET;
- addr.sin_port = htons(5900 + display);
- memset(&addr.sin_addr, 0, sizeof(addr.sin_addr));
-
- reuse_addr = 1;
- ret = setsockopt(vs->lsock, SOL_SOCKET, SO_REUSEADDR,
- (const char *)&reuse_addr, sizeof(reuse_addr));
- if (ret == -1) {
- fprintf(stderr, "setsockopt() failed\n");
- exit(1);
- }
-
- if (bind(vs->lsock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
- fprintf(stderr, "bind() failed\n");
- exit(1);
- }
-
- if (listen(vs->lsock, 1) == -1) {
- fprintf(stderr, "listen() failed\n");
- exit(1);
- }
-
- ret = qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs);
- if (ret == -1) {
- exit(1);
- }
vs->ds->data = NULL;
vs->ds->dpy_update = vnc_dpy_update;
@@ -1167,4 +1142,63 @@ void vnc_display_init(DisplayState *ds,
memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
vnc_dpy_resize(vs->ds, 640, 400);
-}
+
+#ifndef _WIN32
+ if (strstart(arg, "unix:", &p)) {
+ addr = (struct sockaddr *)&uaddr;
+ addrlen = sizeof(uaddr);
+
+ vs->lsock = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (vs->lsock == -1) {
+ fprintf(stderr, "Could not create socket\n");
+ exit(1);
+ }
+
+ uaddr.sun_family = AF_UNIX;
+ memset(uaddr.sun_path, 0, 108);
+ snprintf(uaddr.sun_path, 108, "%s", p);
+
+ unlink(uaddr.sun_path);
+ } else
+#endif
+ {
+ addr = (struct sockaddr *)&iaddr;
+ addrlen = sizeof(iaddr);
+
+ vs->lsock = socket(PF_INET, SOCK_STREAM, 0);
+ if (vs->lsock == -1) {
+ fprintf(stderr, "Could not create socket\n");
+ exit(1);
+ }
+
+ if (parse_host_port(&iaddr, arg) < 0) {
+ fprintf(stderr, "Could not parse VNC address\n");
+ exit(1);
+ }
+
+ iaddr.sin_port = htons(ntohs(iaddr.sin_port) + 5900);
+
+ reuse_addr = 1;
+ ret = setsockopt(vs->lsock, SOL_SOCKET, SO_REUSEADDR,
+ (const char *)&reuse_addr, sizeof(reuse_addr));
+ if (ret == -1) {
+ fprintf(stderr, "setsockopt() failed\n");
+ exit(1);
+ }
+ }
+
+ if (bind(vs->lsock, addr, addrlen) == -1) {
+ fprintf(stderr, "bind() failed\n");
+ exit(1);
+ }
+
+ if (listen(vs->lsock, 1) == -1) {
+ fprintf(stderr, "listen() failed\n");
+ exit(1);
+ }
+
+ ret = qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs);
+ if (ret == -1) {
+ exit(1);
+ }
+}
^ permalink raw reply [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH 3/3] Add daemonize option
2006-12-16 17:57 [Qemu-devel] [PATCH 0/3] Add options to make writing a front end easier Anthony Liguori
2006-12-16 18:00 ` [Qemu-devel] [PATCH 1/3] Add unix domain socket character device Anthony Liguori
2006-12-16 18:04 ` [Qemu-devel] [PATCH 2/3] Add unix domain socket and interface restriction to VNC Anthony Liguori
@ 2006-12-16 18:08 ` Anthony Liguori
2006-12-19 1:08 ` [Qemu-devel] [PATCH 3/3] [UPDATE] " Anthony Liguori
2 siblings, 1 reply; 5+ messages in thread
From: Anthony Liguori @ 2006-12-16 18:08 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 659 bytes --]
This adds a -daemonize option. This option is mostly useful for
front-ends as it provides a deterministic way to connect to QEMU's
various devices. For instance, if you wanted to execute:
qemu -hda ~/win2k.img -monitor telnet:localhost:1024,server &
telnet localhost:1024
Occasionally, you will get a connection refused as there is a race
condition. However, with this option, you can write:
qemu -hda ~/win2k.img -monitor telnet:localhost:1024,server -daemonize
telnet localhost:1024
And it should always work. This is because the daemonize code doesn't
detach until after all of the character devices are initialized.
Regards,
Anthony Liguori
[-- Attachment #2: qemu-daemonize.diff --]
[-- Type: text/x-patch, Size: 3704 bytes --]
diff -r 953722fbdf7e qemu-doc.texi
--- a/qemu-doc.texi Sat Dec 16 11:50:12 2006 -0600
+++ b/qemu-doc.texi Sat Dec 16 11:50:23 2006 -0600
@@ -308,6 +308,12 @@ Start in full screen.
@item -pidfile file
Store the QEMU process PID in @var{file}. It is useful if you launch QEMU
from a script.
+
+@item -daemonize
+Daemonize the QEMU process after initialization. QEMU will not detach from
+standard IO until it is ready to receive connections on any of its devices.
+This option is a useful way for external programs to launch QEMU without having
+to cope with initialization race conditions.
@item -win2k-hack
Use it when installing Windows 2000 to avoid a disk full bug. After
diff -r 953722fbdf7e vl.c
--- a/vl.c Sat Dec 16 11:50:12 2006 -0600
+++ b/vl.c Sat Dec 16 11:50:15 2006 -0600
@@ -163,6 +163,7 @@ int acpi_enabled = 1;
int acpi_enabled = 1;
int fd_bootchk = 1;
int no_reboot = 0;
+int daemonize = 0;
/***********************************************************/
/* x86 ISA bus support */
@@ -6018,6 +6019,9 @@ void help(void)
"-no-reboot exit instead of rebooting\n"
"-loadvm file start right away with a saved state (loadvm in monitor)\n"
"-vnc display start a VNC server on display\n"
+#ifndef _WIN32
+ "-daemonize daemonize QEMU after initializing\n"
+#endif
"\n"
"During emulation, the following keys are useful:\n"
"ctrl-alt-f toggle full screen\n"
@@ -6098,6 +6102,7 @@ enum {
QEMU_OPTION_vnc,
QEMU_OPTION_no_acpi,
QEMU_OPTION_no_reboot,
+ QEMU_OPTION_daemonize,
};
typedef struct QEMUOption {
@@ -6178,6 +6183,7 @@ const QEMUOption qemu_options[] = {
{ "cirrusvga", 0, QEMU_OPTION_cirrusvga },
{ "no-acpi", 0, QEMU_OPTION_no_acpi },
{ "no-reboot", 0, QEMU_OPTION_no_reboot },
+ { "daemonize", 0, QEMU_OPTION_daemonize },
{ NULL },
};
@@ -6408,6 +6414,7 @@ int main(int argc, char **argv)
QEMUMachine *machine;
char usb_devices[MAX_USB_CMDLINE][128];
int usb_devices_index;
+ int fds[2];
LIST_INIT (&vm_change_state_head);
#ifndef _WIN32
@@ -6826,9 +6833,59 @@ int main(int argc, char **argv)
case QEMU_OPTION_no_reboot:
no_reboot = 1;
break;
+ case QEMU_OPTION_daemonize:
+ daemonize = 1;
}
}
}
+
+#ifndef _WIN32
+ if (daemonize && !nographic && vnc_display == NULL) {
+ fprintf(stderr, "Can only daemonize if using -nographic or -vnc\n");
+ daemonize = 0;
+ }
+
+ 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 || status != 0)
+ exit(1);
+ else
+ exit(0);
+ } else if (pid < 0)
+ exit(1);
+
+ setsid();
+
+ pid = fork();
+ if (pid > 0)
+ exit(0);
+ else if (pid < 0)
+ exit(1);
+
+ umask(027);
+ chdir("/");
+
+ signal(SIGTSTP, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+ signal(SIGTTIN, SIG_IGN);
+ }
+#endif
#ifdef USE_KQEMU
if (smp_cpus > 1)
@@ -7028,6 +7085,30 @@ int main(int argc, char **argv)
}
}
+ if (daemonize) {
+ uint8_t status = 0;
+ ssize_t len;
+ int fd;
+
+ again1:
+ len = write(fds[1], &status, 1);
+ if (len == -1 && (errno == EINTR))
+ goto again1;
+
+ if (len != 1)
+ exit(1);
+
+ fd = open("/dev/null", O_RDWR);
+ if (fd == -1)
+ exit(1);
+
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+
+ close(fd);
+ }
+
main_loop();
quit_timers();
return 0;
^ permalink raw reply [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH 3/3] [UPDATE] Add daemonize option
2006-12-16 18:08 ` [Qemu-devel] [PATCH 3/3] Add daemonize option Anthony Liguori
@ 2006-12-19 1:08 ` Anthony Liguori
0 siblings, 0 replies; 5+ messages in thread
From: Anthony Liguori @ 2006-12-19 1:08 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 538 bytes --]
Anthony Liguori wrote:
> @@ -6826,9 +6833,59 @@ int main(int argc, char **argv)
> case QEMU_OPTION_no_reboot:
> no_reboot = 1;
> break;
> + case QEMU_OPTION_daemonize:
> + daemonize = 1;
> }
>
The indenting is off here and it's missing a break. New patch
attached. Sorry 'bout that.
BTW, all of these patches are available in my QEMU patch queue
(including a few that I haven't yet submitted here).
http://hg.codemonkey.ws/qemu-pq
Regards,
Anthony Liguori
[-- Attachment #2: qemu-daemonize.diff --]
[-- Type: text/x-patch, Size: 3710 bytes --]
diff -r 74a061504619 qemu-doc.texi
--- a/qemu-doc.texi Mon Dec 18 18:39:18 2006 -0600
+++ b/qemu-doc.texi Mon Dec 18 18:39:20 2006 -0600
@@ -308,6 +308,12 @@ Start in full screen.
@item -pidfile file
Store the QEMU process PID in @var{file}. It is useful if you launch QEMU
from a script.
+
+@item -daemonize
+Daemonize the QEMU process after initialization. QEMU will not detach from
+standard IO until it is ready to receive connections on any of its devices.
+This option is a useful way for external programs to launch QEMU without having
+to cope with initialization race conditions.
@item -win2k-hack
Use it when installing Windows 2000 to avoid a disk full bug. After
diff -r 74a061504619 vl.c
--- a/vl.c Mon Dec 18 18:39:18 2006 -0600
+++ b/vl.c Mon Dec 18 18:39:32 2006 -0600
@@ -163,6 +163,7 @@ int acpi_enabled = 1;
int acpi_enabled = 1;
int fd_bootchk = 1;
int no_reboot = 0;
+int daemonize = 0;
/***********************************************************/
/* x86 ISA bus support */
@@ -6018,6 +6019,9 @@ void help(void)
"-no-reboot exit instead of rebooting\n"
"-loadvm file start right away with a saved state (loadvm in monitor)\n"
"-vnc display start a VNC server on display\n"
+#ifndef _WIN32
+ "-daemonize daemonize QEMU after initializing\n"
+#endif
"\n"
"During emulation, the following keys are useful:\n"
"ctrl-alt-f toggle full screen\n"
@@ -6098,6 +6102,7 @@ enum {
QEMU_OPTION_vnc,
QEMU_OPTION_no_acpi,
QEMU_OPTION_no_reboot,
+ QEMU_OPTION_daemonize,
};
typedef struct QEMUOption {
@@ -6178,6 +6183,7 @@ const QEMUOption qemu_options[] = {
{ "cirrusvga", 0, QEMU_OPTION_cirrusvga },
{ "no-acpi", 0, QEMU_OPTION_no_acpi },
{ "no-reboot", 0, QEMU_OPTION_no_reboot },
+ { "daemonize", 0, QEMU_OPTION_daemonize },
{ NULL },
};
@@ -6408,6 +6414,7 @@ int main(int argc, char **argv)
QEMUMachine *machine;
char usb_devices[MAX_USB_CMDLINE][128];
int usb_devices_index;
+ int fds[2];
LIST_INIT (&vm_change_state_head);
#ifndef _WIN32
@@ -6826,9 +6833,60 @@ int main(int argc, char **argv)
case QEMU_OPTION_no_reboot:
no_reboot = 1;
break;
+ case QEMU_OPTION_daemonize:
+ daemonize = 1;
+ break;
}
}
}
+
+#ifndef _WIN32
+ if (daemonize && !nographic && vnc_display == NULL) {
+ fprintf(stderr, "Can only daemonize if using -nographic or -vnc\n");
+ daemonize = 0;
+ }
+
+ 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 || status != 0)
+ exit(1);
+ else
+ exit(0);
+ } else if (pid < 0)
+ exit(1);
+
+ setsid();
+
+ pid = fork();
+ if (pid > 0)
+ exit(0);
+ else if (pid < 0)
+ exit(1);
+
+ umask(027);
+ chdir("/");
+
+ signal(SIGTSTP, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+ signal(SIGTTIN, SIG_IGN);
+ }
+#endif
#ifdef USE_KQEMU
if (smp_cpus > 1)
@@ -7028,6 +7086,30 @@ int main(int argc, char **argv)
}
}
+ if (daemonize) {
+ uint8_t status = 0;
+ ssize_t len;
+ int fd;
+
+ again1:
+ len = write(fds[1], &status, 1);
+ if (len == -1 && (errno == EINTR))
+ goto again1;
+
+ if (len != 1)
+ exit(1);
+
+ fd = open("/dev/null", O_RDWR);
+ if (fd == -1)
+ exit(1);
+
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+
+ close(fd);
+ }
+
main_loop();
quit_timers();
return 0;
^ permalink raw reply [flat|nested] 5+ messages in thread