1 /* vdagent.c xorg-client to vdagentd (daemon).
3 Copyright 2010-2013 Red Hat, Inc.
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/>.
34 #include <sys/select.h>
36 #include <spice/vd_agent.h>
40 #include "vdagentd-proto.h"
41 #include "vdagentd-proto-strings.h"
42 #include "vdagent-x11.h"
43 #include "vdagent-file-xfers.h"
45 static const char *portdev = "/dev/virtio-ports/com.redhat.spice.0";
46 static const char *vdagentd_socket = VDAGENTD_SOCKET;
48 static const char *fx_dir = NULL;
49 static int fx_open_dir = -1;
50 static struct vdagent_x11 *x11 = NULL;
51 static struct vdagent_file_xfers *vdagent_file_xfers = NULL;
52 static struct udscs_connection *client = NULL;
54 static int version_mismatch = 0;
56 void daemon_read_complete(struct udscs_connection **connp,
57 struct udscs_message_header *header, uint8_t *data)
59 switch (header->type) {
60 case VDAGENTD_MONITORS_CONFIG:
61 vdagent_x11_set_monitor_config(x11, (VDAgentMonitorsConfig *)data, 0);
64 case VDAGENTD_CLIPBOARD_REQUEST:
65 vdagent_x11_clipboard_request(x11, header->arg1, header->arg2);
68 case VDAGENTD_CLIPBOARD_GRAB:
69 vdagent_x11_clipboard_grab(x11, header->arg1, (uint32_t *)data,
70 header->size / sizeof(uint32_t));
73 case VDAGENTD_CLIPBOARD_DATA:
74 vdagent_x11_clipboard_data(x11, header->arg1, header->arg2,
76 /* vdagent_x11_clipboard_data takes ownership of the data (or frees
79 case VDAGENTD_CLIPBOARD_RELEASE:
80 vdagent_x11_clipboard_release(x11, header->arg1);
83 case VDAGENTD_VERSION:
84 if (strcmp((char *)data, VERSION) != 0) {
85 syslog(LOG_INFO, "vdagentd version mismatch: got %s expected %s",
87 udscs_destroy_connection(connp);
91 case VDAGENTD_FILE_XFER_START:
92 vdagent_file_xfers_start(vdagent_file_xfers,
93 (VDAgentFileXferStartMessage *)data);
96 case VDAGENTD_FILE_XFER_STATUS:
97 vdagent_file_xfers_status(vdagent_file_xfers,
98 (VDAgentFileXferStatusMessage *)data);
101 case VDAGENTD_FILE_XFER_DATA:
102 vdagent_file_xfers_data(vdagent_file_xfers,
103 (VDAgentFileXferDataMessage *)data);
106 case VDAGENTD_CLIENT_DISCONNECTED:
107 vdagent_x11_client_disconnected(x11);
108 vdagent_file_xfers_destroy(vdagent_file_xfers);
109 vdagent_file_xfers = vdagent_file_xfers_create(client, fx_dir,
113 syslog(LOG_ERR, "Unknown message from vdagentd type: %d, ignoring",
119 int client_setup(int reconnect)
122 client = udscs_connect(vdagentd_socket, daemon_read_complete, NULL,
123 vdagentd_messages, VDAGENTD_NO_MESSAGES,
125 if (client || !reconnect || quit) {
130 return client == NULL;
133 static void usage(FILE *fp)
136 "Usage: spice-vdagent [OPTIONS]\n\n"
137 "Spice guest agent X11 session agent, version %s.\n\n"
139 " -h print this text\n"
140 " -d log debug messages\n"
141 " -s <port> set virtio serial port\n"
142 " -S <filename> set udcs socket\n"
143 " -x don't daemonize\n"
144 " -f <dir|xdg-desktop|xdg-download> file xfer save dir\n"
145 " -o <0|1> open dir on file xfer completion\n",
149 static void quit_handler(int sig)
158 /* detach from terminal */
161 close(0); close(1); close(2);
163 x = open("/dev/null", O_RDWR); x = dup(x); x = dup(x);
166 syslog(LOG_ERR, "fork: %s", strerror(errno));
173 static int file_test(const char *path)
177 return stat(path, &buffer);
180 int main(int argc, char *argv[])
182 fd_set readfds, writefds;
183 int c, n, nfds, x11_fd;
184 int do_daemonize = 1;
186 struct sigaction act;
189 if (-1 == (c = getopt(argc, argv, "-dxhys:f:o:S:")))
211 fx_open_dir = atoi(optarg);
214 vdagentd_socket = optarg;
223 memset(&act, 0, sizeof(act));
224 act.sa_flags = SA_RESTART;
225 act.sa_handler = quit_handler;
226 sigaction(SIGINT, &act, NULL);
227 sigaction(SIGHUP, &act, NULL);
228 sigaction(SIGTERM, &act, NULL);
229 sigaction(SIGQUIT, &act, NULL);
231 openlog("spice-vdagent", do_daemonize ? LOG_PID : (LOG_PID | LOG_PERROR),
234 if (file_test(portdev) != 0) {
242 if (version_mismatch) {
243 syslog(LOG_INFO, "Version mismatch, restarting");
245 execvp(argv[0], argv);
248 if (client_setup(do_daemonize)) {
252 x11 = vdagent_x11_create(client, debug, x11_sync);
254 udscs_destroy_connection(&client);
259 if (vdagent_x11_has_icons_on_desktop(x11))
260 fx_dir = "xdg-desktop";
262 fx_dir = "xdg-download";
264 if (fx_open_dir == -1)
265 fx_open_dir = !vdagent_x11_has_icons_on_desktop(x11);
266 if (!strcmp(fx_dir, "xdg-desktop"))
267 fx_dir = g_get_user_special_dir(G_USER_DIRECTORY_DESKTOP);
268 else if (!strcmp(fx_dir, "xdg-download"))
269 fx_dir = g_get_user_special_dir(G_USER_DIRECTORY_DOWNLOAD);
272 "warning could not get file xfer save dir, using cwd");
275 vdagent_file_xfers = vdagent_file_xfers_create(client, fx_dir,
278 while (client && !quit) {
282 nfds = udscs_client_fill_fds(client, &readfds, &writefds);
283 x11_fd = vdagent_x11_get_fd(x11);
284 FD_SET(x11_fd, &readfds);
288 n = select(nfds, &readfds, &writefds, NULL, NULL);
292 syslog(LOG_ERR, "Fatal error select: %s", strerror(errno));
296 if (FD_ISSET(x11_fd, &readfds))
297 vdagent_x11_do_read(x11);
298 udscs_client_handle_fds(&client, &readfds, &writefds);
301 vdagent_file_xfers_destroy(vdagent_file_xfers);
302 vdagent_x11_destroy(x11, client == NULL);
303 udscs_destroy_connection(&client);
304 if (!quit && do_daemonize)