vdagents: add VDAGENTD_VERSION message
[vd_agent.git] / src / vdagent.c
blobdb1861786ccdd9a32ff8195e471ed52227376a78
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 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <signal.h>
33 #include <sys/select.h>
34 #include <sys/stat.h>
35 #include <spice/vd_agent.h>
37 #include "udscs.h"
38 #include "vdagentd-proto.h"
39 #include "vdagentd-proto-strings.h"
40 #include "vdagent-x11.h"
42 static int verbose = 0;
43 static struct vdagent_x11 *x11 = NULL;
44 static struct udscs_connection *client = NULL;
45 static FILE *logfile = NULL;
46 static int quit = 0;
48 void daemon_read_complete(struct udscs_connection **connp,
49 struct udscs_message_header *header, uint8_t *data)
51 switch (header->type) {
52 case VDAGENTD_MONITORS_CONFIG:
53 vdagent_x11_set_monitor_config(x11, (VDAgentMonitorsConfig *)data);
54 free(data);
55 break;
56 case VDAGENTD_CLIPBOARD_REQUEST:
57 vdagent_x11_clipboard_request(x11, header->arg1, header->arg2);
58 free(data);
59 break;
60 case VDAGENTD_CLIPBOARD_GRAB:
61 vdagent_x11_clipboard_grab(x11, header->arg1, (uint32_t *)data,
62 header->size / sizeof(uint32_t));
63 free(data);
64 break;
65 case VDAGENTD_CLIPBOARD_DATA:
66 vdagent_x11_clipboard_data(x11, header->arg1, header->arg2,
67 data, header->size);
68 /* vdagent_x11_clipboard_data takes ownership of the data (or frees
69 it immediately) */
70 break;
71 case VDAGENTD_CLIPBOARD_RELEASE:
72 vdagent_x11_clipboard_release(x11, header->arg1);
73 free(data);
74 break;
75 case VDAGENTD_VERSION:
76 if (strcmp(data, VERSION) != 0) {
77 fprintf(logfile,
78 "Fatal vdagentd version mismatch: got %s expected %s\n",
79 data, VERSION);
80 udscs_destroy_connection(connp);
82 break;
83 default:
84 if (verbose)
85 fprintf(logfile, "Unknown message from vdagentd type: %d\n",
86 header->type);
87 free(data);
91 int client_setup(int reconnect)
93 while (1) {
94 client = udscs_connect(VDAGENTD_SOCKET, daemon_read_complete, NULL,
95 vdagentd_messages, VDAGENTD_NO_MESSAGES,
96 verbose ? logfile : NULL, logfile);
97 if (client || !reconnect) {
98 break;
100 sleep(1);
102 return client == NULL;
105 static void usage(FILE *fp)
107 fprintf(fp,
108 "vdagent -- spice agent xorg client\n"
109 "options:\n"
110 " -h print this text\n"
111 " -d log debug messages\n"
112 " -x don't daemonize (and log to logfile)\n");
115 static void quit_handler(int sig)
117 quit = 1;
120 void daemonize(void)
122 int x, retval = 0;
124 /* detach from terminal */
125 switch (fork()) {
126 case 0:
127 close(0); close(1); close(2);
128 setsid();
129 x = open("/dev/null", O_RDWR); dup(x); dup(x);
130 break;
131 case -1:
132 fprintf(logfile, "fork: %s\n", strerror(errno));
133 retval = 1;
134 default:
135 if (logfile != stderr)
136 fclose(logfile);
137 exit(retval);
141 int main(int argc, char *argv[])
143 fd_set readfds, writefds;
144 int c, n, nfds, x11_fd, retval = 0;
145 int do_daemonize = 1;
146 char *home, filename[1024];
147 struct sigaction act;
149 for (;;) {
150 if (-1 == (c = getopt(argc, argv, "-dxh")))
151 break;
152 switch (c) {
153 case 'd':
154 verbose++;
155 break;
156 case 'x':
157 do_daemonize = 0;
158 break;
159 case 'h':
160 usage(stdout);
161 return 0;
162 default:
163 usage(stderr);
164 return 1;
168 memset(&act, 0, sizeof(act));
169 act.sa_flags = SA_RESTART;
170 act.sa_handler = quit_handler;
171 sigaction(SIGINT, &act, NULL);
172 sigaction(SIGHUP, &act, NULL);
173 sigaction(SIGTERM, &act, NULL);
174 sigaction(SIGQUIT, &act, NULL);
176 logfile = stderr;
177 home = getenv("HOME");
178 if (home) {
179 snprintf(filename, sizeof(filename), "%s/.spice-vdagent", home);
180 n = mkdir(filename, 0755);
181 snprintf(filename, sizeof(filename), "%s/.spice-vdagent/log", home);
182 if (do_daemonize) {
183 logfile = fopen(filename, "w");
184 if (!logfile) {
185 fprintf(stderr, "Error opening %s: %s\n", filename,
186 strerror(errno));
187 logfile = stderr;
190 } else {
191 fprintf(stderr, "Could not get home directory, logging to stderr\n");
194 if (do_daemonize)
195 daemonize();
197 if (client_setup(do_daemonize)) {
198 retval = 1;
199 goto finish;
202 x11 = vdagent_x11_create(client, logfile, verbose);
203 if (!x11) {
204 udscs_destroy_connection(&client);
205 retval = 1;
206 goto finish;
209 while (client && !quit) {
210 FD_ZERO(&readfds);
211 FD_ZERO(&writefds);
213 nfds = udscs_client_fill_fds(client, &readfds, &writefds);
214 x11_fd = vdagent_x11_get_fd(x11);
215 FD_SET(x11_fd, &readfds);
216 if (x11_fd >= nfds)
217 nfds = x11_fd + 1;
219 n = select(nfds, &readfds, &writefds, NULL, NULL);
220 if (n == -1) {
221 if (errno == EINTR)
222 continue;
223 fprintf(logfile, "Fatal error select: %s\n", strerror(errno));
224 retval = 1;
225 break;
228 if (FD_ISSET(x11_fd, &readfds))
229 vdagent_x11_do_read(x11);
230 udscs_client_handle_fds(&client, &readfds, &writefds);
231 fflush(logfile);
234 vdagent_x11_destroy(x11);
235 udscs_destroy_connection(&client);
237 finish:
238 if (logfile != stderr)
239 fclose(logfile);
241 return retval;