qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/3] Add options to make writing a front end easier
@ 2006-12-16 17:57 Anthony Liguori
  2006-12-16 18:00 ` [Qemu-devel] [PATCH 1/3] Add unix domain socket character device Anthony Liguori
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Anthony Liguori @ 2006-12-16 17:57 UTC (permalink / raw)
  To: qemu-devel

Howdy,

I've been working on a QEMU front end for a bit now.  The following 
patch introduces a number of things to make writing front ends in 
general a bit easier.  This includes making the char devices exposable 
as unix sockets and adding a daemonize option.

Unix sockets are useful for a front end because their permissions can be 
controlled and it's easier to guarantee uniqueness (verses trying to 
find an unused TCP port).

The daemonize option is useful as it provides a deterministic way to 
know that QEMU is ready to accept connections (for something like VNC).  
Otherwise, you have to use a connect loop and timeout attempting to 
connect.  This gets particularly ugly when an error occurs for some reason.

I've made an attempt to support the Win32 build but I haven't verified 
that current CVS is buildable (my changes shouldn't make it any worse).

Regards,

Anthony Liguori

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [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

end of thread, other threads:[~2006-12-19  1:08 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [Qemu-devel] [PATCH 3/3] Add daemonize option Anthony Liguori
2006-12-19  1:08   ` [Qemu-devel] [PATCH 3/3] [UPDATE] " Anthony Liguori

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).