diff options
Diffstat (limited to 'src/vdagent.c')
-rw-r--r-- | src/vdagent.c | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/src/vdagent.c b/src/vdagent.c new file mode 100644 index 0000000..2a72adb --- /dev/null +++ b/src/vdagent.c @@ -0,0 +1,220 @@ +/* vdagent.c xorg-client to vdagentd (daemon). + + Copyright 2010 Red Hat, Inc. + + Red Hat Authors: + Hans de Goede <hdegoede@redhat.com> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <signal.h> +#include <sys/select.h> +#include <sys/stat.h> +#include <spice/vd_agent.h> + +#include "udscs.h" +#include "vdagentd-proto.h" +#include "vdagentd-proto-strings.h" +#include "vdagent-x11.h" + +static int verbose = 0; +static struct vdagent_x11 *x11 = NULL; +static struct udscs_connection *client = NULL; +static FILE *logfile = NULL; +static int quit = 0; + +void daemon_read_complete(struct udscs_connection **connp, + struct udscs_message_header *header, uint8_t *data) +{ + switch (header->type) { + case VDAGENTD_MONITORS_CONFIG: + vdagent_x11_set_monitor_config(x11, (VDAgentMonitorsConfig *)data); + free(data); + break; + case VDAGENTD_CLIPBOARD_REQUEST: + vdagent_x11_clipboard_request(x11, header->arg1, header->arg2); + free(data); + break; + case VDAGENTD_CLIPBOARD_GRAB: + vdagent_x11_clipboard_grab(x11, header->arg1, (uint32_t *)data, + header->size / sizeof(uint32_t)); + free(data); + break; + case VDAGENTD_CLIPBOARD_DATA: + vdagent_x11_clipboard_data(x11, header->arg1, header->arg2, + data, header->size); + /* vdagent_x11_clipboard_data takes ownership of the data (or frees + it immediately) */ + break; + case VDAGENTD_CLIPBOARD_RELEASE: + vdagent_x11_clipboard_release(x11, header->arg1); + free(data); + break; + default: + if (verbose) + fprintf(logfile, "Unknown message from vdagentd type: %d\n", + header->type); + free(data); + } +} + +static void usage(FILE *fp) +{ + fprintf(fp, + "vdagent -- spice agent xorg client\n" + "options:\n" + " -h print this text\n" + " -d log debug messages\n" + " -x don't daemonize (and log to logfile)\n"); +} + +static void quit_handler(int sig) +{ + quit = 1; +} + +void daemonize(void) +{ + int x, retval = 0; + + /* detach from terminal */ + switch (fork()) { + case 0: + close(0); close(1); close(2); + setsid(); + x = open("/dev/null", O_RDWR); dup(x); dup(x); + break; + case -1: + fprintf(logfile, "fork: %s\n", strerror(errno)); + retval = 1; + default: + udscs_destroy_connection(&client); + if (logfile != stderr) + fclose(logfile); + exit(retval); + } +} + +int main(int argc, char *argv[]) +{ + fd_set readfds, writefds; + int c, n, nfds, x11_fd, retval = 0; + int do_daemonize = 1; + char *home, filename[1024]; + struct sigaction act; + + for (;;) { + if (-1 == (c = getopt(argc, argv, "-dxh"))) + break; + switch (c) { + case 'd': + verbose++; + break; + case 'x': + do_daemonize = 0; + break; + case 'h': + usage(stdout); + return 0; + default: + usage(stderr); + return 1; + } + } + + memset(&act, 0, sizeof(act)); + act.sa_flags = SA_RESTART; + act.sa_handler = quit_handler; + sigaction(SIGINT, &act, NULL); + sigaction(SIGHUP, &act, NULL); + sigaction(SIGTERM, &act, NULL); + sigaction(SIGQUIT, &act, NULL); + + logfile = stderr; + home = getenv("HOME"); + if (home) { + snprintf(filename, sizeof(filename), "%s/.spice-vdagent", home); + n = mkdir(filename, 0755); + snprintf(filename, sizeof(filename), "%s/.spice-vdagent/log", home); + if (do_daemonize) { + logfile = fopen(filename, "w"); + if (!logfile) { + fprintf(stderr, "Error opening %s: %s\n", filename, + strerror(errno)); + logfile = stderr; + } + } + } else { + fprintf(stderr, "Could not get home directory, logging to stderr\n"); + } + + client = udscs_connect(VDAGENTD_SOCKET, daemon_read_complete, NULL, + vdagentd_messages, VDAGENTD_NO_MESSAGES, + verbose? logfile:NULL, logfile); + if (!client) { + if (logfile != stderr) + fclose(logfile); + return 1; + } + + if (do_daemonize) + daemonize(); + + x11 = vdagent_x11_create(client, logfile, verbose); + if (!x11) { + udscs_destroy_connection(&client); + if (logfile != stderr) + fclose(logfile); + return 1; + } + + while (client && !quit) { + FD_ZERO(&readfds); + FD_ZERO(&writefds); + + nfds = udscs_client_fill_fds(client, &readfds, &writefds); + x11_fd = vdagent_x11_get_fd(x11); + FD_SET(x11_fd, &readfds); + if (x11_fd >= nfds) + nfds = x11_fd + 1; + + n = select(nfds, &readfds, &writefds, NULL, NULL); + if (n == -1) { + if (errno == EINTR) + continue; + fprintf(logfile, "Fatal error select: %s\n", strerror(errno)); + retval = 1; + break; + } + + if (FD_ISSET(x11_fd, &readfds)) + vdagent_x11_do_read(x11); + udscs_client_handle_fds(&client, &readfds, &writefds); + fflush(logfile); + } + + vdagent_x11_destroy(x11); + udscs_destroy_connection(&client); + if (logfile != stderr) + fclose(logfile); + + return retval; +} |