1 /* vdagentd.c vdagentd (daemon) code
3 Copyright 2010-2013 Red Hat, Inc.
4 Copyright (c) 2014 Samsung Electronics Co., Ltd.
7 Hans de Goede <hdegoede@redhat.com>
8 Gerd Hoffmann <kraxel@redhat.com>
10 This program is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 * Modifications by Samsung Electronics Co., Ltd.
24 1. modified pidfilename path
38 #include <sys/select.h>
40 #include <spice/vd_agent.h>
44 #include "vdagentd-proto.h"
45 #include "vdagentd-proto-strings.h"
46 #include "vdagentd-uinput.h"
47 #include "vdagentd-xorg-conf.h"
48 #include "vdagent-virtio-port.h"
49 #include "session-info.h"
55 struct vdagentd_guest_xorg_resolution *screen_info;
60 static const char *pidfilename = "/opt/var/run/spice-vdagentd/spice-vdagentd.pid";
61 static const char *portdev = "/dev/virtio-ports/com.redhat.spice.0";
62 static const char *vdagentd_socket = VDAGENTD_SOCKET;
63 static const char *uinput_device = "/dev/uinput";
65 static int uinput_fake = 0;
66 static struct udscs_server *server = NULL;
67 static struct vdagent_virtio_port *virtio_port = NULL;
68 static GHashTable *active_xfers = NULL;
69 static struct session_info *session_info = NULL;
70 static struct vdagentd_uinput *uinput = NULL;
71 static VDAgentMonitorsConfig *mon_config = NULL;
72 static uint32_t *capabilities = NULL;
73 static int capabilities_size = 0;
74 static const char *active_session = NULL;
75 static unsigned int session_count = 0;
76 static struct udscs_connection *active_session_conn = NULL;
77 static int agent_owns_clipboard[256] = { 0, };
79 static int retval = 0;
80 static int client_connected = 0;
82 /* utility functions */
83 /* vdagentd <-> spice-client communication handling */
84 static void send_capabilities(struct vdagent_virtio_port *vport,
87 VDAgentAnnounceCapabilities *caps;
90 size = sizeof(*caps) + VD_AGENT_CAPS_BYTES;
91 caps = calloc(1, size);
93 syslog(LOG_ERR, "out of memory allocating capabilities array (write)");
97 caps->request = request;
98 VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_MOUSE_STATE);
99 VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_MONITORS_CONFIG);
100 VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_REPLY);
101 VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND);
102 VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_CLIPBOARD_SELECTION);
103 VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_SPARSE_MONITORS_CONFIG);
104 VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_GUEST_LINEEND_LF);
106 vdagent_virtio_port_write(vport, VDP_CLIENT_PORT,
107 VD_AGENT_ANNOUNCE_CAPABILITIES, 0,
108 (uint8_t *)caps, size);
112 static void do_client_disconnect(void)
114 if (client_connected) {
115 udscs_server_write_all(server, VDAGENTD_CLIENT_DISCONNECTED, 0, 0,
117 client_connected = 0;
121 static void do_client_monitors(struct vdagent_virtio_port *vport, int port_nr,
122 VDAgentMessage *message_header, VDAgentMonitorsConfig *new_monitors)
127 /* Store monitor config to send to agents when they connect */
128 size = sizeof(VDAgentMonitorsConfig) +
129 new_monitors->num_of_monitors * sizeof(VDAgentMonConfig);
130 if (message_header->size != size) {
131 syslog(LOG_ERR, "invalid message size for VDAgentMonitorsConfig");
135 vdagentd_write_xorg_conf(new_monitors);
138 mon_config->num_of_monitors != new_monitors->num_of_monitors) {
140 mon_config = malloc(size);
142 syslog(LOG_ERR, "out of memory allocating monitors config");
146 memcpy(mon_config, new_monitors, size);
148 /* Send monitor config to currently active agent */
149 if (active_session_conn)
150 udscs_write(active_session_conn, VDAGENTD_MONITORS_CONFIG, 0, 0,
151 (uint8_t *)mon_config, size);
153 /* Acknowledge reception of monitors config to spice server / client */
154 reply.type = VD_AGENT_MONITORS_CONFIG;
155 reply.error = VD_AGENT_SUCCESS;
156 vdagent_virtio_port_write(vport, port_nr, VD_AGENT_REPLY, 0,
157 (uint8_t *)&reply, sizeof(reply));
160 static void do_client_capabilities(struct vdagent_virtio_port *vport,
161 VDAgentMessage *message_header,
162 VDAgentAnnounceCapabilities *caps)
164 int new_size = VD_AGENT_CAPS_SIZE_FROM_MSG_SIZE(message_header->size);
166 if (capabilities_size != new_size) {
167 capabilities_size = new_size;
169 capabilities = malloc(capabilities_size * sizeof(uint32_t));
171 syslog(LOG_ERR, "oom allocating capabilities array (read)");
172 capabilities_size = 0;
176 memcpy(capabilities, caps->caps, capabilities_size * sizeof(uint32_t));
178 /* Report the previous client has disconneced. */
179 do_client_disconnect();
181 syslog(LOG_DEBUG, "New client connected");
182 client_connected = 1;
183 send_capabilities(vport, 0);
187 static void do_client_clipboard(struct vdagent_virtio_port *vport,
188 VDAgentMessage *message_header, uint8_t *data)
190 uint32_t msg_type = 0, data_type = 0, size = message_header->size;
191 uint8_t selection = VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD;
193 if (!active_session_conn) {
195 "Could not find an agent connection belonging to the "
196 "active session, ignoring client clipboard request");
200 if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
201 VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
207 switch (message_header->type) {
208 case VD_AGENT_CLIPBOARD_GRAB:
209 msg_type = VDAGENTD_CLIPBOARD_GRAB;
210 agent_owns_clipboard[selection] = 0;
212 case VD_AGENT_CLIPBOARD_REQUEST: {
213 VDAgentClipboardRequest *req = (VDAgentClipboardRequest *)data;
214 msg_type = VDAGENTD_CLIPBOARD_REQUEST;
215 data_type = req->type;
220 case VD_AGENT_CLIPBOARD: {
221 VDAgentClipboard *clipboard = (VDAgentClipboard *)data;
222 msg_type = VDAGENTD_CLIPBOARD_DATA;
223 data_type = clipboard->type;
224 size = size - sizeof(VDAgentClipboard);
225 data = clipboard->data;
228 case VD_AGENT_CLIPBOARD_RELEASE:
229 msg_type = VDAGENTD_CLIPBOARD_RELEASE;
235 udscs_write(active_session_conn, msg_type, selection, data_type,
239 static void cancel_file_xfer(struct vdagent_virtio_port *vport,
240 const char *msg, uint32_t id)
242 VDAgentFileXferStatusMessage status = {
244 .result = VD_AGENT_FILE_XFER_STATUS_CANCELLED,
246 syslog(LOG_WARNING, msg, id);
248 vdagent_virtio_port_write(vport, VDP_CLIENT_PORT,
249 VD_AGENT_FILE_XFER_STATUS, 0,
250 (uint8_t *)&status, sizeof(status));
253 static void do_client_file_xfer(struct vdagent_virtio_port *vport,
254 VDAgentMessage *message_header,
257 uint32_t msg_type, id;
258 struct udscs_connection *conn;
260 switch (message_header->type) {
261 case VD_AGENT_FILE_XFER_START: {
262 VDAgentFileXferStartMessage *s = (VDAgentFileXferStartMessage *)data;
263 if (!active_session_conn) {
264 cancel_file_xfer(vport,
265 "Could not find an agent connnection belonging to the "
266 "active session, cancelling client file-xfer request %u",
270 udscs_write(active_session_conn, VDAGENTD_FILE_XFER_START, 0, 0,
271 data, message_header->size);
274 case VD_AGENT_FILE_XFER_STATUS: {
275 VDAgentFileXferStatusMessage *s = (VDAgentFileXferStatusMessage *)data;
276 msg_type = VDAGENTD_FILE_XFER_STATUS;
280 case VD_AGENT_FILE_XFER_DATA: {
281 VDAgentFileXferDataMessage *d = (VDAgentFileXferDataMessage *)data;
282 msg_type = VDAGENTD_FILE_XFER_DATA;
288 conn = g_hash_table_lookup(active_xfers, GUINT_TO_POINTER(id));
291 syslog(LOG_DEBUG, "Could not find file-xfer %u (cancelled?)", id);
294 udscs_write(conn, msg_type, 0, 0, data, message_header->size);
297 int virtio_port_read_complete(
298 struct vdagent_virtio_port *vport,
300 VDAgentMessage *message_header,
303 uint32_t min_size = 0;
305 if (message_header->protocol != VD_AGENT_PROTOCOL) {
306 syslog(LOG_ERR, "message with wrong protocol version ignoring");
310 switch (message_header->type) {
311 case VD_AGENT_MOUSE_STATE:
312 if (message_header->size != sizeof(VDAgentMouseState))
314 vdagentd_uinput_do_mouse(&uinput, (VDAgentMouseState *)data);
316 /* Try to re-open the tablet */
317 struct agent_data *agent_data =
318 udscs_get_user_data(active_session_conn);
320 uinput = vdagentd_uinput_create(uinput_device,
323 agent_data->screen_info,
324 agent_data->screen_count,
328 syslog(LOG_CRIT, "Fatal uinput error");
334 case VD_AGENT_MONITORS_CONFIG:
335 if (message_header->size < sizeof(VDAgentMonitorsConfig))
337 do_client_monitors(vport, port_nr, message_header,
338 (VDAgentMonitorsConfig *)data);
340 case VD_AGENT_ANNOUNCE_CAPABILITIES:
341 if (message_header->size < sizeof(VDAgentAnnounceCapabilities))
343 do_client_capabilities(vport, message_header,
344 (VDAgentAnnounceCapabilities *)data);
346 case VD_AGENT_CLIPBOARD_GRAB:
347 case VD_AGENT_CLIPBOARD_REQUEST:
348 case VD_AGENT_CLIPBOARD:
349 case VD_AGENT_CLIPBOARD_RELEASE:
350 switch (message_header->type) {
351 case VD_AGENT_CLIPBOARD_GRAB:
352 min_size = sizeof(VDAgentClipboardGrab); break;
353 case VD_AGENT_CLIPBOARD_REQUEST:
354 min_size = sizeof(VDAgentClipboardRequest); break;
355 case VD_AGENT_CLIPBOARD:
356 min_size = sizeof(VDAgentClipboard); break;
358 if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
359 VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
362 if (message_header->size < min_size) {
365 do_client_clipboard(vport, message_header, data);
367 case VD_AGENT_FILE_XFER_START:
368 case VD_AGENT_FILE_XFER_STATUS:
369 case VD_AGENT_FILE_XFER_DATA:
370 do_client_file_xfer(vport, message_header, data);
372 case VD_AGENT_CLIENT_DISCONNECTED:
373 vdagent_virtio_port_reset(vport, VDP_CLIENT_PORT);
374 do_client_disconnect();
377 syslog(LOG_WARNING, "unknown message type %d, ignoring",
378 message_header->type);
384 syslog(LOG_ERR, "read: invalid message size: %u for message type: %u",
385 message_header->size, message_header->type);
389 /* vdagentd <-> vdagent communication handling */
390 int do_agent_clipboard(struct udscs_connection *conn,
391 struct udscs_message_header *header, const uint8_t *data)
393 uint8_t selection = header->arg1;
394 uint32_t msg_type = 0, data_type = -1, size = header->size;
396 if (!VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
397 VD_AGENT_CAP_CLIPBOARD_BY_DEMAND))
400 /* Check that this agent is from the currently active session */
401 if (conn != active_session_conn) {
403 syslog(LOG_DEBUG, "%p clipboard req from agent which is not in "
404 "the active session?", conn);
409 syslog(LOG_ERR, "Clipboard req from agent but no client connection");
413 if (!VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
414 VD_AGENT_CAP_CLIPBOARD_SELECTION) &&
415 selection != VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD) {
419 switch (header->type) {
420 case VDAGENTD_CLIPBOARD_GRAB:
421 msg_type = VD_AGENT_CLIPBOARD_GRAB;
422 agent_owns_clipboard[selection] = 1;
424 case VDAGENTD_CLIPBOARD_REQUEST:
425 msg_type = VD_AGENT_CLIPBOARD_REQUEST;
426 data_type = header->arg2;
429 case VDAGENTD_CLIPBOARD_DATA:
430 msg_type = VD_AGENT_CLIPBOARD;
431 data_type = header->arg2;
433 case VDAGENTD_CLIPBOARD_RELEASE:
434 msg_type = VD_AGENT_CLIPBOARD_RELEASE;
436 agent_owns_clipboard[selection] = 0;
440 if (size != header->size) {
442 "unexpected extra data in clipboard msg, disconnecting agent");
446 if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
447 VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
450 if (data_type != -1) {
454 vdagent_virtio_port_write_start(virtio_port, VDP_CLIENT_PORT, msg_type,
457 if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
458 VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
459 uint8_t sel[4] = { selection, 0, 0, 0 };
460 vdagent_virtio_port_write_append(virtio_port, sel, 4);
462 if (data_type != -1) {
463 vdagent_virtio_port_write_append(virtio_port, (uint8_t*)&data_type, 4);
466 vdagent_virtio_port_write_append(virtio_port, data, header->size);
471 if (header->type == VDAGENTD_CLIPBOARD_REQUEST) {
472 /* Let the agent know no answer is coming */
473 udscs_write(conn, VDAGENTD_CLIPBOARD_DATA,
474 selection, VD_AGENT_CLIPBOARD_NONE, NULL, 0);
479 /* When we open the vdagent virtio channel, the server automatically goes into
480 client mouse mode, so we can only have the channel open when we know the
481 active session resolution. This function checks that we have an agent in the
482 active session, and that it has told us its resolution. If these conditions
483 are met it sets the uinput tablet device's resolution and opens the virtio
484 channel (if it is not already open). If these conditions are not met, it
486 static void check_xorg_resolution(void)
488 struct agent_data *agent_data = udscs_get_user_data(active_session_conn);
490 if (agent_data && agent_data->screen_info) {
492 uinput = vdagentd_uinput_create(uinput_device,
495 agent_data->screen_info,
496 agent_data->screen_count,
500 vdagentd_uinput_update_size(&uinput,
503 agent_data->screen_info,
504 agent_data->screen_count);
506 syslog(LOG_CRIT, "Fatal uinput error");
513 syslog(LOG_INFO, "opening vdagent virtio channel");
514 virtio_port = vdagent_virtio_port_create(portdev,
515 virtio_port_read_complete,
518 syslog(LOG_CRIT, "Fatal error opening vdagent virtio channel");
523 send_capabilities(virtio_port, 1);
526 #ifndef WITH_STATIC_UINPUT
527 vdagentd_uinput_destroy(&uinput);
530 vdagent_virtio_port_flush(&virtio_port);
531 vdagent_virtio_port_destroy(&virtio_port);
532 syslog(LOG_INFO, "closed vdagent virtio channel");
537 static int connection_matches_active_session(struct udscs_connection **connp,
540 struct udscs_connection **conn_ret = (struct udscs_connection **)priv;
541 struct agent_data *agent_data = udscs_get_user_data(*connp);
543 /* Check if this connection matches the currently active session */
544 if (!agent_data->session || !active_session)
546 if (strcmp(agent_data->session, active_session))
553 void release_clipboards(void)
557 for (sel = 0; sel < VD_AGENT_CLIPBOARD_SELECTION_SECONDARY; ++sel) {
558 if (agent_owns_clipboard[sel] && virtio_port) {
559 vdagent_virtio_port_write(virtio_port, VDP_CLIENT_PORT,
560 VD_AGENT_CLIPBOARD_RELEASE, 0, &sel, 1);
562 agent_owns_clipboard[sel] = 0;
566 void update_active_session_connection(struct udscs_connection *new_conn)
571 active_session = session_info_get_active_session(session_info);
572 session_count = udscs_server_for_all_clients(server,
573 connection_matches_active_session,
582 if (new_conn && session_count != 1) {
583 syslog(LOG_ERR, "multiple agents in one session, "
584 "disabling agent to avoid potential information leak");
588 if (new_conn == active_session_conn)
591 active_session_conn = new_conn;
593 syslog(LOG_DEBUG, "%p is now the active session", new_conn);
594 if (active_session_conn && mon_config)
595 udscs_write(active_session_conn, VDAGENTD_MONITORS_CONFIG, 0, 0,
596 (uint8_t *)mon_config, sizeof(VDAgentMonitorsConfig) +
597 mon_config->num_of_monitors * sizeof(VDAgentMonConfig));
599 release_clipboards();
601 check_xorg_resolution();
604 gboolean remove_active_xfers(gpointer key, gpointer value, gpointer conn)
607 cancel_file_xfer(virtio_port, "Agent disc; cancelling file-xfer %u",
608 GPOINTER_TO_UINT(key));
614 void agent_connect(struct udscs_connection *conn)
616 struct agent_data *agent_data;
618 agent_data = calloc(1, sizeof(*agent_data));
620 syslog(LOG_ERR, "Out of memory allocating agent data, disconnecting");
621 udscs_destroy_connection(&conn);
626 uint32_t pid = udscs_get_peer_cred(conn).pid;
627 agent_data->session = session_info_session_for_pid(session_info, pid);
630 udscs_set_user_data(conn, (void *)agent_data);
631 udscs_write(conn, VDAGENTD_VERSION, 0, 0,
632 (uint8_t *)VERSION, strlen(VERSION) + 1);
633 update_active_session_connection(conn);
636 void agent_disconnect(struct udscs_connection *conn)
638 struct agent_data *agent_data = udscs_get_user_data(conn);
640 g_hash_table_foreach_remove(active_xfers, remove_active_xfers, conn);
642 free(agent_data->session);
643 agent_data->session = NULL;
644 update_active_session_connection(NULL);
649 void agent_read_complete(struct udscs_connection **connp,
650 struct udscs_message_header *header, uint8_t *data)
652 struct agent_data *agent_data = udscs_get_user_data(*connp);
654 switch (header->type) {
655 case VDAGENTD_GUEST_XORG_RESOLUTION: {
656 struct vdagentd_guest_xorg_resolution *res;
657 int n = header->size / sizeof(*res);
659 /* Detect older version session agent, but don't disconnect, as
660 that stops it from getting the VDAGENTD_VERSION message, and then
661 it will never re-exec the new version... */
662 if (header->arg1 == 0 && header->arg2 == 0) {
663 syslog(LOG_INFO, "got old session agent xorg resolution message, "
669 if (header->size != n * sizeof(*res)) {
670 syslog(LOG_ERR, "guest xorg resolution message has wrong size, "
671 "disconnecting agent");
672 udscs_destroy_connection(connp);
677 free(agent_data->screen_info);
678 res = malloc(n * sizeof(*res));
680 syslog(LOG_ERR, "out of memory allocating screen info");
683 memcpy(res, data, n * sizeof(*res));
684 agent_data->width = header->arg1;
685 agent_data->height = header->arg2;
686 agent_data->screen_info = res;
687 agent_data->screen_count = n;
689 check_xorg_resolution();
692 case VDAGENTD_CLIPBOARD_GRAB:
693 case VDAGENTD_CLIPBOARD_REQUEST:
694 case VDAGENTD_CLIPBOARD_DATA:
695 case VDAGENTD_CLIPBOARD_RELEASE:
696 if (do_agent_clipboard(*connp, header, data)) {
697 udscs_destroy_connection(connp);
702 case VDAGENTD_FILE_XFER_STATUS:{
703 VDAgentFileXferStatusMessage status;
704 status.id = header->arg1;
705 status.result = header->arg2;
706 vdagent_virtio_port_write(virtio_port, VDP_CLIENT_PORT,
707 VD_AGENT_FILE_XFER_STATUS, 0,
708 (uint8_t *)&status, sizeof(status));
709 if (status.result == VD_AGENT_FILE_XFER_STATUS_CAN_SEND_DATA)
710 g_hash_table_insert(active_xfers, GUINT_TO_POINTER(status.id),
713 g_hash_table_remove(active_xfers, GUINT_TO_POINTER(status.id));
718 syslog(LOG_ERR, "unknown message from vdagent: %u, ignoring",
726 static void usage(FILE *fp)
729 "Usage: spice-vdagentd [OPTIONS]\n\n"
730 "Spice guest agent daemon, version %s.\n\n"
732 " -h print this text\n"
733 " -d log debug messages (use twice for extra info)\n"
734 " -s <port> set virtio serial port [%s]\n"
735 " -S <filename> set udcs socket [%s]\n"
736 " -u <dev> set uinput device [%s]\n"
737 " -x don't daemonize\n"
738 #ifdef HAVE_CONSOLE_KIT
739 " -X Disable console kit integration\n"
741 #ifdef HAVE_LIBSYSTEMD_LOGIN
742 " -X Disable systemd-logind integration\n"
744 ,VERSION, portdev, vdagentd_socket, uinput_device);
752 /* detach from terminal */
755 close(0); close(1); close(2);
757 x = open("/dev/null", O_RDWR); x = dup(x); x = dup(x);
758 pidfile = fopen(pidfilename, "w");
760 fprintf(pidfile, "%d\n", (int)getpid());
765 syslog(LOG_ERR, "fork: %m");
768 udscs_destroy_server(server);
775 fd_set readfds, writefds;
783 nfds = udscs_server_fill_fds(server, &readfds, &writefds);
784 n = vdagent_virtio_port_fill_fds(virtio_port, &readfds, &writefds);
789 ck_fd = session_info_get_fd(session_info);
790 FD_SET(ck_fd, &readfds);
795 n = select(nfds, &readfds, &writefds, NULL, NULL);
799 syslog(LOG_CRIT, "Fatal error select: %m");
804 udscs_server_handle_fds(server, &readfds, &writefds);
807 vdagent_virtio_port_handle_fds(&virtio_port, &readfds, &writefds);
809 int old_client_connected = client_connected;
811 "AIIEEE lost spice client connection, reconnecting");
812 virtio_port = vdagent_virtio_port_create(portdev,
813 virtio_port_read_complete,
817 "Fatal error opening vdagent virtio channel");
821 do_client_disconnect();
822 client_connected = old_client_connected;
826 if (session_info && FD_ISSET(ck_fd, &readfds)) {
827 active_session = session_info_get_active_session(session_info);
828 update_active_session_connection(NULL);
833 static void quit_handler(int sig)
838 int main(int argc, char *argv[])
841 int do_daemonize = 1;
842 int want_session_info = 1;
843 struct sigaction act;
846 if (-1 == (c = getopt(argc, argv, "-dhxXs:u:S:")))
856 vdagentd_socket = optarg;
859 uinput_device = optarg;
865 want_session_info = 0;
877 if (strncmp(uinput_device, "/dev", 4) != 0) {
878 syslog(LOG_INFO, "using fake uinput");
882 memset(&act, 0, sizeof(act));
883 act.sa_flags = SA_RESTART;
884 act.sa_handler = quit_handler;
885 sigaction(SIGINT, &act, NULL);
886 sigaction(SIGHUP, &act, NULL);
887 sigaction(SIGTERM, &act, NULL);
888 sigaction(SIGQUIT, &act, NULL);
890 openlog("spice-vdagentd", do_daemonize ? 0 : LOG_PERROR, LOG_USER);
892 /* Setup communication with vdagent process(es) */
893 server = udscs_create_server(vdagentd_socket, agent_connect,
894 agent_read_complete, agent_disconnect,
895 vdagentd_messages, VDAGENTD_NO_MESSAGES,
898 syslog(LOG_CRIT, "Fatal could not create server socket %s",
902 if (chmod(vdagentd_socket, 0666)) {
903 syslog(LOG_CRIT, "Fatal could not change permissions on %s: %m",
905 udscs_destroy_server(server);
912 #ifdef WITH_STATIC_UINPUT
913 uinput = vdagentd_uinput_create(uinput_device, 1024, 768, NULL, 0,
914 debug > 1, uinput_fake);
916 udscs_destroy_server(server);
921 if (want_session_info)
922 session_info = session_info_create(debug);
924 syslog(LOG_WARNING, "no session info, max 1 session agent allowed");
926 active_xfers = g_hash_table_new(g_direct_hash, g_direct_equal);
929 release_clipboards();
931 vdagentd_uinput_destroy(&uinput);
932 vdagent_virtio_port_flush(&virtio_port);
933 vdagent_virtio_port_destroy(&virtio_port);
934 session_info_destroy(session_info);
935 udscs_destroy_server(server);
936 if (unlink(vdagentd_socket) != 0)
937 syslog(LOG_ERR, "unlink %s: %s", vdagentd_socket, strerror(errno));
938 syslog(LOG_INFO, "vdagentd quiting, returning status %d", retval);