vdagent-x11: Add support for incr. sending of clipboard data (rhbz#690164)
[vd_agent.git] / vdagent.c
blob7f1bee9a71ed9ba6ee950d784e29cddc2c1a8260
1 /* vdagent.c xorg-client to vdagentd (daemon).
3 Copyright 2010 Red Hat, Inc.
5 Red Hat Authors:
6 Hans de Goede <hdegoede@redhat.com>
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <errno.h>
28 #include <signal.h>
29 #include <sys/select.h>
30 #include <sys/stat.h>
31 #include <spice/vd_agent.h>
33 #include "udscs.h"
34 #include "vdagentd-proto.h"
35 #include "vdagentd-proto-strings.h"
36 #include "vdagent-x11.h"
38 static int verbose = 0;
39 static struct vdagent_x11 *x11 = NULL;
40 static struct udscs_connection *client = NULL;
41 static FILE *logfile = NULL;
42 static int quit = 0;
44 void daemon_read_complete(struct udscs_connection **connp,
45 struct udscs_message_header *header, uint8_t *data)
47 switch (header->type) {
48 case VDAGENTD_MONITORS_CONFIG:
49 vdagent_x11_set_monitor_config(x11, (VDAgentMonitorsConfig *)data);
50 free(data);
51 break;
52 case VDAGENTD_CLIPBOARD_REQUEST:
53 vdagent_x11_clipboard_request(x11, header->opaque);
54 free(data);
55 break;
56 case VDAGENTD_CLIPBOARD_GRAB:
57 vdagent_x11_clipboard_grab(x11, (uint32_t *)data,
58 header->size / sizeof(uint32_t));
59 free(data);
60 break;
61 case VDAGENTD_CLIPBOARD_DATA:
62 vdagent_x11_clipboard_data(x11, header->opaque, data, header->size);
63 /* vdagent_x11_clipboard_data takes ownership of the data (or frees
64 it immediately) */
65 break;
66 case VDAGENTD_CLIPBOARD_RELEASE:
67 vdagent_x11_clipboard_release(x11);
68 free(data);
69 break;
70 default:
71 if (verbose)
72 fprintf(logfile, "Unknown message from vdagentd type: %d\n",
73 header->type);
74 free(data);
78 static void usage(FILE *fp)
80 fprintf(fp,
81 "vdagent -- spice agent xorg client\n"
82 "options:\n"
83 " -h print this text\n"
84 " -d log debug messages\n"
85 " -x don't daemonize (and log to logfile)\n");
88 static void quit_handler(int sig)
90 quit = 1;
93 void daemonize(void)
95 int x, retval = 0;
97 /* detach from terminal */
98 switch (fork()) {
99 case 0:
100 close(0); close(1); close(2);
101 setsid();
102 x = open("/dev/null", O_RDWR); dup(x); dup(x);
103 break;
104 case -1:
105 fprintf(logfile, "fork: %s\n", strerror(errno));
106 retval = 1;
107 default:
108 udscs_destroy_connection(&client);
109 if (logfile != stderr)
110 fclose(logfile);
111 exit(retval);
115 int main(int argc, char *argv[])
117 fd_set readfds, writefds;
118 int c, n, nfds, x11_fd, retval = 0;
119 int do_daemonize = 1;
120 char *home, filename[1024];
121 struct sigaction act;
123 for (;;) {
124 if (-1 == (c = getopt(argc, argv, "-dxh")))
125 break;
126 switch (c) {
127 case 'd':
128 verbose++;
129 break;
130 case 'x':
131 do_daemonize = 0;
132 break;
133 case 'h':
134 usage(stdout);
135 return 0;
136 default:
137 usage(stderr);
138 return 1;
142 memset(&act, 0, sizeof(act));
143 act.sa_flags = SA_RESTART;
144 act.sa_handler = quit_handler;
145 sigaction(SIGINT, &act, NULL);
146 sigaction(SIGHUP, &act, NULL);
147 sigaction(SIGTERM, &act, NULL);
148 sigaction(SIGQUIT, &act, NULL);
150 logfile = stderr;
151 home = getenv("HOME");
152 if (home) {
153 snprintf(filename, sizeof(filename), "%s/.spice-vdagent", home);
154 n = mkdir(filename, 0755);
155 snprintf(filename, sizeof(filename), "%s/.spice-vdagent/log", home);
156 if (do_daemonize) {
157 logfile = fopen(filename, "w");
158 if (!logfile) {
159 fprintf(stderr, "Error opening %s: %s\n", filename,
160 strerror(errno));
161 logfile = stderr;
164 } else {
165 fprintf(stderr, "Could not get home directory, logging to stderr\n");
168 client = udscs_connect(VDAGENTD_SOCKET, daemon_read_complete, NULL,
169 vdagentd_messages, VDAGENTD_NO_MESSAGES,
170 verbose? logfile:NULL, logfile);
171 if (!client) {
172 if (logfile != stderr)
173 fclose(logfile);
174 return 1;
177 if (do_daemonize)
178 daemonize();
180 x11 = vdagent_x11_create(client, logfile, verbose);
181 if (!x11) {
182 udscs_destroy_connection(&client);
183 if (logfile != stderr)
184 fclose(logfile);
185 return 1;
188 while (client && !quit) {
189 FD_ZERO(&readfds);
190 FD_ZERO(&writefds);
192 nfds = udscs_client_fill_fds(client, &readfds, &writefds);
193 x11_fd = vdagent_x11_get_fd(x11);
194 FD_SET(x11_fd, &readfds);
195 if (x11_fd >= nfds)
196 nfds = x11_fd + 1;
198 n = select(nfds, &readfds, &writefds, NULL, NULL);
199 if (n == -1) {
200 if (errno == EINTR)
201 continue;
202 fprintf(logfile, "Fatal error select: %s\n", strerror(errno));
203 retval = 1;
204 break;
207 if (FD_ISSET(x11_fd, &readfds))
208 vdagent_x11_do_read(x11);
209 udscs_client_handle_fds(&client, &readfds, &writefds);
210 fflush(logfile);
213 vdagent_x11_destroy(x11);
214 udscs_destroy_connection(&client);
215 if (logfile != stderr)
216 fclose(logfile);
218 return retval;