1 /* vdagentd.c vdagentd (daemon) code
3 Copyright 2010-2013 Red Hat, Inc.
6 Hans de Goede <hdegoede@redhat.com>
7 Gerd Hoffmann <kraxel@redhat.com>
9 This program is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 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 "vdagentd-uinput.h"
43 #include "vdagentd-xorg-conf.h"
44 #include "vdagent-virtio-port.h"
45 #include "session-info.h"
51 struct vdagentd_guest_xorg_resolution
*screen_info
;
56 static const char *pidfilename
= "/var/run/spice-vdagentd/spice-vdagentd.pid";
57 static const char *portdev
= "/dev/virtio-ports/com.redhat.spice.0";
58 static const char *vdagentd_socket
= VDAGENTD_SOCKET
;
59 static const char *uinput_device
= "/dev/uinput";
61 static int uinput_fake
= 0;
62 static struct udscs_server
*server
= NULL
;
63 static struct vdagent_virtio_port
*virtio_port
= NULL
;
64 static GHashTable
*active_xfers
= NULL
;
65 static struct session_info
*session_info
= NULL
;
66 static struct vdagentd_uinput
*uinput
= NULL
;
67 static VDAgentMonitorsConfig
*mon_config
= NULL
;
68 static uint32_t *capabilities
= NULL
;
69 static int capabilities_size
= 0;
70 static const char *active_session
= NULL
;
71 static unsigned int session_count
= 0;
72 static struct udscs_connection
*active_session_conn
= NULL
;
73 static int agent_owns_clipboard
[256] = { 0, };
75 static int retval
= 0;
76 static int client_connected
= 0;
77 static int max_clipboard
= -1;
79 /* utility functions */
80 /* vdagentd <-> spice-client communication handling */
81 static void send_capabilities(struct vdagent_virtio_port
*vport
,
84 VDAgentAnnounceCapabilities
*caps
;
87 size
= sizeof(*caps
) + VD_AGENT_CAPS_BYTES
;
88 caps
= calloc(1, size
);
90 syslog(LOG_ERR
, "out of memory allocating capabilities array (write)");
94 caps
->request
= request
;
95 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_MOUSE_STATE
);
96 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_MONITORS_CONFIG
);
97 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_REPLY
);
98 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND
);
99 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_CLIPBOARD_SELECTION
);
100 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_SPARSE_MONITORS_CONFIG
);
101 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_GUEST_LINEEND_LF
);
102 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_MAX_CLIPBOARD
);
104 vdagent_virtio_port_write(vport
, VDP_CLIENT_PORT
,
105 VD_AGENT_ANNOUNCE_CAPABILITIES
, 0,
106 (uint8_t *)caps
, size
);
110 static void do_client_disconnect(void)
112 if (client_connected
) {
113 udscs_server_write_all(server
, VDAGENTD_CLIENT_DISCONNECTED
, 0, 0,
115 client_connected
= 0;
119 static void do_client_monitors(struct vdagent_virtio_port
*vport
, int port_nr
,
120 VDAgentMessage
*message_header
, VDAgentMonitorsConfig
*new_monitors
)
125 /* Store monitor config to send to agents when they connect */
126 size
= sizeof(VDAgentMonitorsConfig
) +
127 new_monitors
->num_of_monitors
* sizeof(VDAgentMonConfig
);
128 if (message_header
->size
!= size
) {
129 syslog(LOG_ERR
, "invalid message size for VDAgentMonitorsConfig");
133 vdagentd_write_xorg_conf(new_monitors
);
136 mon_config
->num_of_monitors
!= new_monitors
->num_of_monitors
) {
138 mon_config
= malloc(size
);
140 syslog(LOG_ERR
, "out of memory allocating monitors config");
144 memcpy(mon_config
, new_monitors
, size
);
146 /* Send monitor config to currently active agent */
147 if (active_session_conn
)
148 udscs_write(active_session_conn
, VDAGENTD_MONITORS_CONFIG
, 0, 0,
149 (uint8_t *)mon_config
, size
);
151 /* Acknowledge reception of monitors config to spice server / client */
152 reply
.type
= VD_AGENT_MONITORS_CONFIG
;
153 reply
.error
= VD_AGENT_SUCCESS
;
154 vdagent_virtio_port_write(vport
, port_nr
, VD_AGENT_REPLY
, 0,
155 (uint8_t *)&reply
, sizeof(reply
));
158 static void do_client_capabilities(struct vdagent_virtio_port
*vport
,
159 VDAgentMessage
*message_header
,
160 VDAgentAnnounceCapabilities
*caps
)
162 int new_size
= VD_AGENT_CAPS_SIZE_FROM_MSG_SIZE(message_header
->size
);
164 if (capabilities_size
!= new_size
) {
165 capabilities_size
= new_size
;
167 capabilities
= malloc(capabilities_size
* sizeof(uint32_t));
169 syslog(LOG_ERR
, "oom allocating capabilities array (read)");
170 capabilities_size
= 0;
174 memcpy(capabilities
, caps
->caps
, capabilities_size
* sizeof(uint32_t));
176 /* Report the previous client has disconneced. */
177 do_client_disconnect();
179 syslog(LOG_DEBUG
, "New client connected");
180 client_connected
= 1;
181 send_capabilities(vport
, 0);
185 static void do_client_clipboard(struct vdagent_virtio_port
*vport
,
186 VDAgentMessage
*message_header
, uint8_t *data
)
188 uint32_t msg_type
= 0, data_type
= 0, size
= message_header
->size
;
189 uint8_t selection
= VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD
;
191 if (!active_session_conn
) {
193 "Could not find an agent connection belonging to the "
194 "active session, ignoring client clipboard request");
198 if (VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
199 VD_AGENT_CAP_CLIPBOARD_SELECTION
)) {
205 switch (message_header
->type
) {
206 case VD_AGENT_CLIPBOARD_GRAB
:
207 msg_type
= VDAGENTD_CLIPBOARD_GRAB
;
208 agent_owns_clipboard
[selection
] = 0;
210 case VD_AGENT_CLIPBOARD_REQUEST
: {
211 VDAgentClipboardRequest
*req
= (VDAgentClipboardRequest
*)data
;
212 msg_type
= VDAGENTD_CLIPBOARD_REQUEST
;
213 data_type
= req
->type
;
218 case VD_AGENT_CLIPBOARD
: {
219 VDAgentClipboard
*clipboard
= (VDAgentClipboard
*)data
;
220 msg_type
= VDAGENTD_CLIPBOARD_DATA
;
221 data_type
= clipboard
->type
;
222 size
= size
- sizeof(VDAgentClipboard
);
223 data
= clipboard
->data
;
226 case VD_AGENT_CLIPBOARD_RELEASE
:
227 msg_type
= VDAGENTD_CLIPBOARD_RELEASE
;
233 udscs_write(active_session_conn
, msg_type
, selection
, data_type
,
237 static void cancel_file_xfer(struct vdagent_virtio_port
*vport
,
238 const char *msg
, uint32_t id
)
240 VDAgentFileXferStatusMessage status
= {
242 .result
= VD_AGENT_FILE_XFER_STATUS_CANCELLED
,
244 syslog(LOG_WARNING
, msg
, id
);
246 vdagent_virtio_port_write(vport
, VDP_CLIENT_PORT
,
247 VD_AGENT_FILE_XFER_STATUS
, 0,
248 (uint8_t *)&status
, sizeof(status
));
251 static void do_client_file_xfer(struct vdagent_virtio_port
*vport
,
252 VDAgentMessage
*message_header
,
255 uint32_t msg_type
, id
;
256 struct udscs_connection
*conn
;
258 switch (message_header
->type
) {
259 case VD_AGENT_FILE_XFER_START
: {
260 VDAgentFileXferStartMessage
*s
= (VDAgentFileXferStartMessage
*)data
;
261 if (!active_session_conn
) {
262 cancel_file_xfer(vport
,
263 "Could not find an agent connnection belonging to the "
264 "active session, cancelling client file-xfer request %u",
268 udscs_write(active_session_conn
, VDAGENTD_FILE_XFER_START
, 0, 0,
269 data
, message_header
->size
);
272 case VD_AGENT_FILE_XFER_STATUS
: {
273 VDAgentFileXferStatusMessage
*s
= (VDAgentFileXferStatusMessage
*)data
;
274 msg_type
= VDAGENTD_FILE_XFER_STATUS
;
278 case VD_AGENT_FILE_XFER_DATA
: {
279 VDAgentFileXferDataMessage
*d
= (VDAgentFileXferDataMessage
*)data
;
280 msg_type
= VDAGENTD_FILE_XFER_DATA
;
286 conn
= g_hash_table_lookup(active_xfers
, GUINT_TO_POINTER(id
));
289 syslog(LOG_DEBUG
, "Could not find file-xfer %u (cancelled?)", id
);
292 udscs_write(conn
, msg_type
, 0, 0, data
, message_header
->size
);
295 int virtio_port_read_complete(
296 struct vdagent_virtio_port
*vport
,
298 VDAgentMessage
*message_header
,
301 uint32_t min_size
= 0;
303 if (message_header
->protocol
!= VD_AGENT_PROTOCOL
) {
304 syslog(LOG_ERR
, "message with wrong protocol version ignoring");
308 switch (message_header
->type
) {
309 case VD_AGENT_MOUSE_STATE
:
310 if (message_header
->size
!= sizeof(VDAgentMouseState
))
312 vdagentd_uinput_do_mouse(&uinput
, (VDAgentMouseState
*)data
);
314 /* Try to re-open the tablet */
315 struct agent_data
*agent_data
=
316 udscs_get_user_data(active_session_conn
);
318 uinput
= vdagentd_uinput_create(uinput_device
,
321 agent_data
->screen_info
,
322 agent_data
->screen_count
,
326 syslog(LOG_CRIT
, "Fatal uinput error");
332 case VD_AGENT_MONITORS_CONFIG
:
333 if (message_header
->size
< sizeof(VDAgentMonitorsConfig
))
335 do_client_monitors(vport
, port_nr
, message_header
,
336 (VDAgentMonitorsConfig
*)data
);
338 case VD_AGENT_ANNOUNCE_CAPABILITIES
:
339 if (message_header
->size
< sizeof(VDAgentAnnounceCapabilities
))
341 do_client_capabilities(vport
, message_header
,
342 (VDAgentAnnounceCapabilities
*)data
);
344 case VD_AGENT_CLIPBOARD_GRAB
:
345 case VD_AGENT_CLIPBOARD_REQUEST
:
346 case VD_AGENT_CLIPBOARD
:
347 case VD_AGENT_CLIPBOARD_RELEASE
:
348 switch (message_header
->type
) {
349 case VD_AGENT_CLIPBOARD_GRAB
:
350 min_size
= sizeof(VDAgentClipboardGrab
); break;
351 case VD_AGENT_CLIPBOARD_REQUEST
:
352 min_size
= sizeof(VDAgentClipboardRequest
); break;
353 case VD_AGENT_CLIPBOARD
:
354 min_size
= sizeof(VDAgentClipboard
); break;
356 if (VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
357 VD_AGENT_CAP_CLIPBOARD_SELECTION
)) {
360 if (message_header
->size
< min_size
) {
363 do_client_clipboard(vport
, message_header
, data
);
365 case VD_AGENT_FILE_XFER_START
:
366 case VD_AGENT_FILE_XFER_STATUS
:
367 case VD_AGENT_FILE_XFER_DATA
:
368 do_client_file_xfer(vport
, message_header
, data
);
370 case VD_AGENT_CLIENT_DISCONNECTED
:
371 vdagent_virtio_port_reset(vport
, VDP_CLIENT_PORT
);
372 do_client_disconnect();
374 case VD_AGENT_MAX_CLIPBOARD
:
375 if (message_header
->size
!= sizeof(VDAgentMaxClipboard
))
377 VDAgentMaxClipboard
*msg
= (VDAgentMaxClipboard
*)data
;
378 syslog(LOG_DEBUG
, "Set max clipboard: %d", msg
->max
);
379 max_clipboard
= msg
->max
;
382 syslog(LOG_WARNING
, "unknown message type %d, ignoring",
383 message_header
->type
);
389 syslog(LOG_ERR
, "read: invalid message size: %u for message type: %u",
390 message_header
->size
, message_header
->type
);
394 static void virtio_write_clipboard(uint8_t selection
, uint32_t msg_type
,
395 uint32_t data_type
, const uint8_t *data
, uint32_t data_size
)
397 uint32_t size
= data_size
;
399 if (VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
400 VD_AGENT_CAP_CLIPBOARD_SELECTION
)) {
403 if (data_type
!= -1) {
407 vdagent_virtio_port_write_start(virtio_port
, VDP_CLIENT_PORT
, msg_type
,
410 if (VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
411 VD_AGENT_CAP_CLIPBOARD_SELECTION
)) {
412 uint8_t sel
[4] = { selection
, 0, 0, 0 };
413 vdagent_virtio_port_write_append(virtio_port
, sel
, 4);
415 if (data_type
!= -1) {
416 vdagent_virtio_port_write_append(virtio_port
, (uint8_t*)&data_type
, 4);
419 vdagent_virtio_port_write_append(virtio_port
, data
, data_size
);
422 /* vdagentd <-> vdagent communication handling */
423 int do_agent_clipboard(struct udscs_connection
*conn
,
424 struct udscs_message_header
*header
, const uint8_t *data
)
426 uint8_t selection
= header
->arg1
;
427 uint32_t msg_type
= 0, data_type
= -1, size
= header
->size
;
429 if (!VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
430 VD_AGENT_CAP_CLIPBOARD_BY_DEMAND
))
433 /* Check that this agent is from the currently active session */
434 if (conn
!= active_session_conn
) {
436 syslog(LOG_DEBUG
, "%p clipboard req from agent which is not in "
437 "the active session?", conn
);
442 syslog(LOG_ERR
, "Clipboard req from agent but no client connection");
446 if (!VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
447 VD_AGENT_CAP_CLIPBOARD_SELECTION
) &&
448 selection
!= VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD
) {
452 switch (header
->type
) {
453 case VDAGENTD_CLIPBOARD_GRAB
:
454 msg_type
= VD_AGENT_CLIPBOARD_GRAB
;
455 agent_owns_clipboard
[selection
] = 1;
457 case VDAGENTD_CLIPBOARD_REQUEST
:
458 msg_type
= VD_AGENT_CLIPBOARD_REQUEST
;
459 data_type
= header
->arg2
;
462 case VDAGENTD_CLIPBOARD_DATA
:
463 msg_type
= VD_AGENT_CLIPBOARD
;
464 data_type
= header
->arg2
;
465 if (max_clipboard
!= -1 && size
> max_clipboard
) {
466 syslog(LOG_WARNING
, "clipboard is too large (%d > %d), discarding",
467 size
, max_clipboard
);
468 virtio_write_clipboard(selection
, msg_type
, data_type
, NULL
, 0);
472 case VDAGENTD_CLIPBOARD_RELEASE
:
473 msg_type
= VD_AGENT_CLIPBOARD_RELEASE
;
475 agent_owns_clipboard
[selection
] = 0;
478 syslog(LOG_WARNING
, "unexpected clipboard message type");
482 if (size
!= header
->size
) {
484 "unexpected extra data in clipboard msg, disconnecting agent");
488 virtio_write_clipboard(selection
, msg_type
, data_type
, data
, header
->size
);
493 if (header
->type
== VDAGENTD_CLIPBOARD_REQUEST
) {
494 /* Let the agent know no answer is coming */
495 udscs_write(conn
, VDAGENTD_CLIPBOARD_DATA
,
496 selection
, VD_AGENT_CLIPBOARD_NONE
, NULL
, 0);
501 /* When we open the vdagent virtio channel, the server automatically goes into
502 client mouse mode, so we can only have the channel open when we know the
503 active session resolution. This function checks that we have an agent in the
504 active session, and that it has told us its resolution. If these conditions
505 are met it sets the uinput tablet device's resolution and opens the virtio
506 channel (if it is not already open). If these conditions are not met, it
508 static void check_xorg_resolution(void)
510 struct agent_data
*agent_data
= udscs_get_user_data(active_session_conn
);
512 if (agent_data
&& agent_data
->screen_info
) {
514 uinput
= vdagentd_uinput_create(uinput_device
,
517 agent_data
->screen_info
,
518 agent_data
->screen_count
,
522 vdagentd_uinput_update_size(&uinput
,
525 agent_data
->screen_info
,
526 agent_data
->screen_count
);
528 syslog(LOG_CRIT
, "Fatal uinput error");
535 syslog(LOG_INFO
, "opening vdagent virtio channel");
536 virtio_port
= vdagent_virtio_port_create(portdev
,
537 virtio_port_read_complete
,
540 syslog(LOG_CRIT
, "Fatal error opening vdagent virtio channel");
545 send_capabilities(virtio_port
, 1);
548 #ifndef WITH_STATIC_UINPUT
549 vdagentd_uinput_destroy(&uinput
);
552 vdagent_virtio_port_flush(&virtio_port
);
553 vdagent_virtio_port_destroy(&virtio_port
);
554 syslog(LOG_INFO
, "closed vdagent virtio channel");
559 static int connection_matches_active_session(struct udscs_connection
**connp
,
562 struct udscs_connection
**conn_ret
= (struct udscs_connection
**)priv
;
563 struct agent_data
*agent_data
= udscs_get_user_data(*connp
);
565 /* Check if this connection matches the currently active session */
566 if (!agent_data
->session
|| !active_session
)
568 if (strcmp(agent_data
->session
, active_session
))
575 void release_clipboards(void)
579 for (sel
= 0; sel
< VD_AGENT_CLIPBOARD_SELECTION_SECONDARY
; ++sel
) {
580 if (agent_owns_clipboard
[sel
] && virtio_port
) {
581 vdagent_virtio_port_write(virtio_port
, VDP_CLIENT_PORT
,
582 VD_AGENT_CLIPBOARD_RELEASE
, 0, &sel
, 1);
584 agent_owns_clipboard
[sel
] = 0;
588 void update_active_session_connection(struct udscs_connection
*new_conn
)
593 active_session
= session_info_get_active_session(session_info
);
594 session_count
= udscs_server_for_all_clients(server
,
595 connection_matches_active_session
,
604 if (new_conn
&& session_count
!= 1) {
605 syslog(LOG_ERR
, "multiple agents in one session, "
606 "disabling agent to avoid potential information leak");
610 if (new_conn
== active_session_conn
)
613 active_session_conn
= new_conn
;
615 syslog(LOG_DEBUG
, "%p is now the active session", new_conn
);
616 if (active_session_conn
&& mon_config
)
617 udscs_write(active_session_conn
, VDAGENTD_MONITORS_CONFIG
, 0, 0,
618 (uint8_t *)mon_config
, sizeof(VDAgentMonitorsConfig
) +
619 mon_config
->num_of_monitors
* sizeof(VDAgentMonConfig
));
621 release_clipboards();
623 check_xorg_resolution();
626 gboolean
remove_active_xfers(gpointer key
, gpointer value
, gpointer conn
)
629 cancel_file_xfer(virtio_port
, "Agent disc; cancelling file-xfer %u",
630 GPOINTER_TO_UINT(key
));
636 void agent_connect(struct udscs_connection
*conn
)
638 struct agent_data
*agent_data
;
640 agent_data
= calloc(1, sizeof(*agent_data
));
642 syslog(LOG_ERR
, "Out of memory allocating agent data, disconnecting");
643 udscs_destroy_connection(&conn
);
648 uint32_t pid
= udscs_get_peer_cred(conn
).pid
;
649 agent_data
->session
= session_info_session_for_pid(session_info
, pid
);
652 udscs_set_user_data(conn
, (void *)agent_data
);
653 udscs_write(conn
, VDAGENTD_VERSION
, 0, 0,
654 (uint8_t *)VERSION
, strlen(VERSION
) + 1);
655 update_active_session_connection(conn
);
658 void agent_disconnect(struct udscs_connection
*conn
)
660 struct agent_data
*agent_data
= udscs_get_user_data(conn
);
662 g_hash_table_foreach_remove(active_xfers
, remove_active_xfers
, conn
);
664 free(agent_data
->session
);
665 agent_data
->session
= NULL
;
666 update_active_session_connection(NULL
);
671 void agent_read_complete(struct udscs_connection
**connp
,
672 struct udscs_message_header
*header
, uint8_t *data
)
674 struct agent_data
*agent_data
= udscs_get_user_data(*connp
);
676 switch (header
->type
) {
677 case VDAGENTD_GUEST_XORG_RESOLUTION
: {
678 struct vdagentd_guest_xorg_resolution
*res
;
679 int n
= header
->size
/ sizeof(*res
);
681 /* Detect older version session agent, but don't disconnect, as
682 that stops it from getting the VDAGENTD_VERSION message, and then
683 it will never re-exec the new version... */
684 if (header
->arg1
== 0 && header
->arg2
== 0) {
685 syslog(LOG_INFO
, "got old session agent xorg resolution message, "
691 if (header
->size
!= n
* sizeof(*res
)) {
692 syslog(LOG_ERR
, "guest xorg resolution message has wrong size, "
693 "disconnecting agent");
694 udscs_destroy_connection(connp
);
699 free(agent_data
->screen_info
);
700 res
= malloc(n
* sizeof(*res
));
702 syslog(LOG_ERR
, "out of memory allocating screen info");
705 memcpy(res
, data
, n
* sizeof(*res
));
706 agent_data
->width
= header
->arg1
;
707 agent_data
->height
= header
->arg2
;
708 agent_data
->screen_info
= res
;
709 agent_data
->screen_count
= n
;
711 check_xorg_resolution();
714 case VDAGENTD_CLIPBOARD_GRAB
:
715 case VDAGENTD_CLIPBOARD_REQUEST
:
716 case VDAGENTD_CLIPBOARD_DATA
:
717 case VDAGENTD_CLIPBOARD_RELEASE
:
718 if (do_agent_clipboard(*connp
, header
, data
)) {
719 udscs_destroy_connection(connp
);
724 case VDAGENTD_FILE_XFER_STATUS
:{
725 VDAgentFileXferStatusMessage status
;
726 status
.id
= header
->arg1
;
727 status
.result
= header
->arg2
;
728 vdagent_virtio_port_write(virtio_port
, VDP_CLIENT_PORT
,
729 VD_AGENT_FILE_XFER_STATUS
, 0,
730 (uint8_t *)&status
, sizeof(status
));
731 if (status
.result
== VD_AGENT_FILE_XFER_STATUS_CAN_SEND_DATA
)
732 g_hash_table_insert(active_xfers
, GUINT_TO_POINTER(status
.id
),
735 g_hash_table_remove(active_xfers
, GUINT_TO_POINTER(status
.id
));
740 syslog(LOG_ERR
, "unknown message from vdagent: %u, ignoring",
748 static void usage(FILE *fp
)
751 "Usage: spice-vdagentd [OPTIONS]\n\n"
752 "Spice guest agent daemon, version %s.\n\n"
754 " -h print this text\n"
755 " -d log debug messages (use twice for extra info)\n"
756 " -s <port> set virtio serial port [%s]\n"
757 " -S <filename> set udcs socket [%s]\n"
758 " -u <dev> set uinput device [%s]\n"
759 " -x don't daemonize\n"
760 #ifdef HAVE_CONSOLE_KIT
761 " -X Disable console kit integration\n"
763 #ifdef HAVE_LIBSYSTEMD_LOGIN
764 " -X Disable systemd-logind integration\n"
766 ,VERSION
, portdev
, vdagentd_socket
, uinput_device
);
774 /* detach from terminal */
777 close(0); close(1); close(2);
779 x
= open("/dev/null", O_RDWR
); x
= dup(x
); x
= dup(x
);
780 pidfile
= fopen(pidfilename
, "w");
782 fprintf(pidfile
, "%d\n", (int)getpid());
787 syslog(LOG_ERR
, "fork: %m");
790 udscs_destroy_server(server
);
797 fd_set readfds
, writefds
;
805 nfds
= udscs_server_fill_fds(server
, &readfds
, &writefds
);
806 n
= vdagent_virtio_port_fill_fds(virtio_port
, &readfds
, &writefds
);
811 ck_fd
= session_info_get_fd(session_info
);
812 FD_SET(ck_fd
, &readfds
);
817 n
= select(nfds
, &readfds
, &writefds
, NULL
, NULL
);
821 syslog(LOG_CRIT
, "Fatal error select: %m");
826 udscs_server_handle_fds(server
, &readfds
, &writefds
);
829 vdagent_virtio_port_handle_fds(&virtio_port
, &readfds
, &writefds
);
831 int old_client_connected
= client_connected
;
833 "AIIEEE lost spice client connection, reconnecting");
834 virtio_port
= vdagent_virtio_port_create(portdev
,
835 virtio_port_read_complete
,
839 "Fatal error opening vdagent virtio channel");
843 do_client_disconnect();
844 client_connected
= old_client_connected
;
848 if (session_info
&& FD_ISSET(ck_fd
, &readfds
)) {
849 active_session
= session_info_get_active_session(session_info
);
850 update_active_session_connection(NULL
);
855 static void quit_handler(int sig
)
860 int main(int argc
, char *argv
[])
863 int do_daemonize
= 1;
864 int want_session_info
= 1;
865 struct sigaction act
;
868 if (-1 == (c
= getopt(argc
, argv
, "-dhxXs:u:S:")))
878 vdagentd_socket
= optarg
;
881 uinput_device
= optarg
;
887 want_session_info
= 0;
899 if (strncmp(uinput_device
, "/dev", 4) != 0) {
900 syslog(LOG_INFO
, "using fake uinput");
904 memset(&act
, 0, sizeof(act
));
905 act
.sa_flags
= SA_RESTART
;
906 act
.sa_handler
= quit_handler
;
907 sigaction(SIGINT
, &act
, NULL
);
908 sigaction(SIGHUP
, &act
, NULL
);
909 sigaction(SIGTERM
, &act
, NULL
);
910 sigaction(SIGQUIT
, &act
, NULL
);
912 openlog("spice-vdagentd", do_daemonize
? 0 : LOG_PERROR
, LOG_USER
);
914 /* Setup communication with vdagent process(es) */
915 server
= udscs_create_server(vdagentd_socket
, agent_connect
,
916 agent_read_complete
, agent_disconnect
,
917 vdagentd_messages
, VDAGENTD_NO_MESSAGES
,
920 syslog(LOG_CRIT
, "Fatal could not create server socket %s",
924 if (chmod(vdagentd_socket
, 0666)) {
925 syslog(LOG_CRIT
, "Fatal could not change permissions on %s: %m",
927 udscs_destroy_server(server
);
934 #ifdef WITH_STATIC_UINPUT
935 uinput
= vdagentd_uinput_create(uinput_device
, 1024, 768, NULL
, 0,
936 debug
> 1, uinput_fake
);
938 udscs_destroy_server(server
);
943 if (want_session_info
)
944 session_info
= session_info_create(debug
);
946 syslog(LOG_WARNING
, "no session info, max 1 session agent allowed");
948 active_xfers
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
951 release_clipboards();
953 vdagentd_uinput_destroy(&uinput
);
954 vdagent_virtio_port_flush(&virtio_port
);
955 vdagent_virtio_port_destroy(&virtio_port
);
956 session_info_destroy(session_info
);
957 udscs_destroy_server(server
);
958 if (unlink(vdagentd_socket
) != 0)
959 syslog(LOG_ERR
, "unlink %s: %s", vdagentd_socket
, strerror(errno
));
960 syslog(LOG_INFO
, "vdagentd quiting, returning status %d", retval
);