diff options
author | Jeremy White <jwhite@codeweavers.com> | 2014-07-09 14:08:44 -0500 |
---|---|---|
committer | Alon Levy <alevy@redhat.com> | 2014-07-10 15:45:13 +0300 |
commit | 2f602c03ebd9446e97c97fa33f353c693dc6755e (patch) | |
tree | e0d007deb011358bd4114b9b257ec51adc8b6131 /src | |
parent | 251637aa23ddfa54b28975fdbb31e1edcfda901e (diff) | |
download | vd_agent-2f602c03ebd9446e97c97fa33f353c693dc6755e.tar.gz vd_agent-2f602c03ebd9446e97c97fa33f353c693dc6755e.tar.xz vd_agent-2f602c03ebd9446e97c97fa33f353c693dc6755e.zip |
Make sure the child is able to connect to the X server before exiting the mainline.
This allows the vdagent to be used in the Xsetup phase of an xdm session;
otherwise, it's X11 connection fails because of the greeter display grab.
The issue is that we daemonize before attempting the X connection.
We then immediately exit the main process; xdm then goes on to invoke the
greeter which performs an exclusive grab on the X server, so the child
connection fails.
The change is to have the main process wait for up to 10 seconds for an 'all clear'
message from the client. This lets us return a correct status on a real X
error, as well as letting our child successfully connect to the X server.
Signed-off-by: Jeremy White <jwhite@codeweavers.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/vdagent.c | 50 |
1 files changed, 44 insertions, 6 deletions
diff --git a/src/vdagent.c b/src/vdagent.c index d7f7aba..905ff5b 100644 --- a/src/vdagent.c +++ b/src/vdagent.c @@ -35,6 +35,7 @@ #include <sys/stat.h> #include <spice/vd_agent.h> #include <glib.h> +#include <poll.h> #include "udscs.h" #include "vdagentd-proto.h" @@ -151,9 +152,34 @@ static void quit_handler(int sig) quit = 1; } -void daemonize(void) +/* When we daemonize, it is useful to have the main process + wait to make sure the X connection worked. We wait up + to 10 seconds to get an 'all clear' from the child + before we exit. If we don't, we're able to exit with a + status that indicates an error occured */ +void wait_and_exit(int s) { - int x, retval = 0; + char buf[4]; + struct pollfd p; + p.fd = s; + p.events = POLLIN; + + if (poll(&p, 1, 10000) > 0) + if (read(s, buf, sizeof(buf)) > 0) + exit(0); + + exit(1); +} + +int daemonize(void) +{ + int x; + int fd[2]; + + if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fd)) { + syslog(LOG_ERR, "socketpair : %s", strerror(errno)); + exit(1); + } /* detach from terminal */ switch (fork()) { @@ -161,13 +187,17 @@ void daemonize(void) close(0); close(1); close(2); setsid(); x = open("/dev/null", O_RDWR); x = dup(x); x = dup(x); - break; + close(fd[0]); + return fd[1]; case -1: syslog(LOG_ERR, "fork: %s", strerror(errno)); - retval = 1; + exit(1); default: - exit(retval); + close(fd[1]); + wait_and_exit(fd[0]); } + + return 0; } static int file_test(const char *path) @@ -182,6 +212,7 @@ int main(int argc, char *argv[]) fd_set readfds, writefds; int c, n, nfds, x11_fd; int do_daemonize = 1; + int parent_socket = 0; int x11_sync = 0; struct sigaction act; @@ -236,7 +267,7 @@ int main(int argc, char *argv[]) } if (do_daemonize) - daemonize(); + parent_socket = daemonize(); reconnect: if (version_mismatch) { @@ -275,6 +306,13 @@ reconnect: vdagent_file_xfers = vdagent_file_xfers_create(client, fx_dir, fx_open_dir, debug); + if (parent_socket) { + if (write(parent_socket, "OK", 2) != 2) + syslog(LOG_WARNING, "Parent already gone."); + close(parent_socket); + parent_socket = 0; + } + while (client && !quit) { FD_ZERO(&readfds); FD_ZERO(&writefds); |