Add missing src/vdagentd-xorg-conf.h file
[vd_agent/hramrach.git] / src / vdagent.c
blobf0d3b32f30e113c9ea1568df5cb60848351b8b9e
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 const char *portdev = "/dev/virtio-ports/com.redhat.spice.0";
43 static int verbose = 0;
44 static struct vdagent_x11 *x11 = NULL;
45 static struct udscs_connection *client = NULL;
46 static FILE *logfile = NULL;
47 static int quit = 0;
48 static int version_mismatch = 0;
50 void daemon_read_complete(struct udscs_connection **connp,
51 struct udscs_message_header *header, uint8_t *data)
53 switch (header->type) {
54 case VDAGENTD_MONITORS_CONFIG:
55 vdagent_x11_set_monitor_config(x11, (VDAgentMonitorsConfig *)data);
56 free(data);
57 break;
58 case VDAGENTD_CLIPBOARD_REQUEST:
59 vdagent_x11_clipboard_request(x11, header->arg1, header->arg2);
60 free(data);
61 break;
62 case VDAGENTD_CLIPBOARD_GRAB:
63 vdagent_x11_clipboard_grab(x11, header->arg1, (uint32_t *)data,
64 header->size / sizeof(uint32_t));
65 free(data);
66 break;
67 case VDAGENTD_CLIPBOARD_DATA:
68 vdagent_x11_clipboard_data(x11, header->arg1, header->arg2,
69 data, header->size);
70 /* vdagent_x11_clipboard_data takes ownership of the data (or frees
71 it immediately) */
72 break;
73 case VDAGENTD_CLIPBOARD_RELEASE:
74 vdagent_x11_clipboard_release(x11, header->arg1);
75 free(data);
76 break;
77 case VDAGENTD_VERSION:
78 if (strcmp(data, VERSION) != 0) {
79 fprintf(logfile,
80 "Fatal vdagentd version mismatch: got %s expected %s\n",
81 data, VERSION);
82 udscs_destroy_connection(connp);
83 version_mismatch = 1;
85 break;
86 default:
87 if (verbose)
88 fprintf(logfile, "Unknown message from vdagentd type: %d\n",
89 header->type);
90 free(data);
94 int client_setup(int reconnect)
96 while (!quit) {
97 client = udscs_connect(VDAGENTD_SOCKET, daemon_read_complete, NULL,
98 vdagentd_messages, VDAGENTD_NO_MESSAGES,
99 verbose ? logfile : NULL, logfile);
100 if (client || !reconnect || quit) {
101 break;
103 sleep(1);
105 return client == NULL;
108 static void usage(FILE *fp)
110 fprintf(fp,
111 "vdagent -- spice agent xorg client\n"
112 "options:\n"
113 " -h print this text\n"
114 " -d log debug messages\n"
115 " -s <port> set virtio serial port [%s]\n"
116 " -x don't daemonize (and log to logfile)\n",
117 portdev);
120 static void quit_handler(int sig)
122 quit = 1;
125 void daemonize(void)
127 int x, retval = 0;
129 /* detach from terminal */
130 switch (fork()) {
131 case 0:
132 close(0); close(1); close(2);
133 setsid();
134 x = open("/dev/null", O_RDWR); dup(x); dup(x);
135 break;
136 case -1:
137 fprintf(logfile, "fork: %s\n", strerror(errno));
138 retval = 1;
139 default:
140 if (logfile != stderr)
141 fclose(logfile);
142 exit(retval);
146 static int file_test(const char *path)
148 struct stat buffer;
150 return stat(path, &buffer);
153 int main(int argc, char *argv[])
155 fd_set readfds, writefds;
156 int c, n, nfds, x11_fd, retval = 0;
157 int do_daemonize = 1;
158 char *home, filename[1024];
159 struct sigaction act;
161 for (;;) {
162 if (-1 == (c = getopt(argc, argv, "-dxhs:")))
163 break;
164 switch (c) {
165 case 'd':
166 verbose++;
167 break;
168 case 's':
169 portdev = optarg;
170 break;
171 case 'x':
172 do_daemonize = 0;
173 break;
174 case 'h':
175 usage(stdout);
176 return 0;
177 default:
178 usage(stderr);
179 return 1;
183 memset(&act, 0, sizeof(act));
184 act.sa_flags = SA_RESTART;
185 act.sa_handler = quit_handler;
186 sigaction(SIGINT, &act, NULL);
187 sigaction(SIGHUP, &act, NULL);
188 sigaction(SIGTERM, &act, NULL);
189 sigaction(SIGQUIT, &act, NULL);
191 logfile = stderr;
192 home = getenv("HOME");
193 if (home) {
194 snprintf(filename, sizeof(filename), "%s/.spice-vdagent", home);
195 n = mkdir(filename, 0755);
196 snprintf(filename, sizeof(filename), "%s/.spice-vdagent/log", home);
197 if (do_daemonize) {
198 logfile = fopen(filename, "w");
199 if (!logfile) {
200 fprintf(stderr, "Error opening %s: %s\n", filename,
201 strerror(errno));
202 logfile = stderr;
205 } else {
206 fprintf(stderr, "Could not get home directory, logging to stderr\n");
209 if (file_test(portdev) != 0) {
210 fprintf(logfile, "Missing virtio device: %s\n",
211 portdev, strerror(errno));
212 retval = 1;
213 goto finish;
216 if (do_daemonize)
217 daemonize();
219 reconnect:
220 if (version_mismatch) {
221 fprintf(logfile, "Version mismatch, restarting\n");
222 if (logfile != stderr)
223 fclose(logfile);
224 sleep(1);
225 execvp(argv[0], argv);
228 if (client_setup(do_daemonize)) {
229 retval = 1;
230 goto finish;
233 x11 = vdagent_x11_create(client, logfile, verbose);
234 if (!x11) {
235 udscs_destroy_connection(&client);
236 retval = 1;
237 goto finish;
240 while (client && !quit) {
241 FD_ZERO(&readfds);
242 FD_ZERO(&writefds);
244 nfds = udscs_client_fill_fds(client, &readfds, &writefds);
245 x11_fd = vdagent_x11_get_fd(x11);
246 FD_SET(x11_fd, &readfds);
247 if (x11_fd >= nfds)
248 nfds = x11_fd + 1;
250 n = select(nfds, &readfds, &writefds, NULL, NULL);
251 if (n == -1) {
252 if (errno == EINTR)
253 continue;
254 fprintf(logfile, "Fatal error select: %s\n", strerror(errno));
255 retval = 1;
256 break;
259 if (FD_ISSET(x11_fd, &readfds))
260 vdagent_x11_do_read(x11);
261 udscs_client_handle_fds(&client, &readfds, &writefds);
262 fflush(logfile);
265 vdagent_x11_destroy(x11);
266 udscs_destroy_connection(&client);
267 if (!quit)
268 goto reconnect;
270 finish:
271 if (logfile != stderr)
272 fclose(logfile);
274 return retval;