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 int only_once
= 0;
63 static struct udscs_server
*server
= NULL
;
64 static struct vdagent_virtio_port
*virtio_port
= NULL
;
65 static GHashTable
*active_xfers
= NULL
;
66 static struct session_info
*session_info
= NULL
;
67 static struct vdagentd_uinput
*uinput
= NULL
;
68 static VDAgentMonitorsConfig
*mon_config
= NULL
;
69 static uint32_t *capabilities
= NULL
;
70 static int capabilities_size
= 0;
71 static const char *active_session
= NULL
;
72 static unsigned int session_count
= 0;
73 static struct udscs_connection
*active_session_conn
= NULL
;
74 static int agent_owns_clipboard
[256] = { 0, };
76 static int retval
= 0;
77 static int client_connected
= 0;
78 static int max_clipboard
= -1;
80 /* utility functions */
81 /* vdagentd <-> spice-client communication handling */
82 static void send_capabilities(struct vdagent_virtio_port
*vport
,
85 VDAgentAnnounceCapabilities
*caps
;
88 size
= sizeof(*caps
) + VD_AGENT_CAPS_BYTES
;
89 caps
= calloc(1, size
);
91 syslog(LOG_ERR
, "out of memory allocating capabilities array (write)");
95 caps
->request
= request
;
96 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_MOUSE_STATE
);
97 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_MONITORS_CONFIG
);
98 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_REPLY
);
99 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND
);
100 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_CLIPBOARD_SELECTION
);
101 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_SPARSE_MONITORS_CONFIG
);
102 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_GUEST_LINEEND_LF
);
103 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_MAX_CLIPBOARD
);
104 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_AUDIO_VOLUME_SYNC
);
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_volume_sync(struct vdagent_virtio_port
*vport
, int port_nr
,
161 VDAgentMessage
*message_header
,
162 VDAgentAudioVolumeSync
*avs
)
164 if (active_session_conn
== NULL
) {
165 syslog(LOG_DEBUG
, "No active session - Can't volume-sync");
169 udscs_write(active_session_conn
, VDAGENTD_AUDIO_VOLUME_SYNC
, 0, 0,
170 (uint8_t *)avs
, message_header
->size
);
173 static void do_client_capabilities(struct vdagent_virtio_port
*vport
,
174 VDAgentMessage
*message_header
,
175 VDAgentAnnounceCapabilities
*caps
)
177 int new_size
= VD_AGENT_CAPS_SIZE_FROM_MSG_SIZE(message_header
->size
);
179 if (capabilities_size
!= new_size
) {
180 capabilities_size
= new_size
;
182 capabilities
= malloc(capabilities_size
* sizeof(uint32_t));
184 syslog(LOG_ERR
, "oom allocating capabilities array (read)");
185 capabilities_size
= 0;
189 memcpy(capabilities
, caps
->caps
, capabilities_size
* sizeof(uint32_t));
191 /* Report the previous client has disconneced. */
192 do_client_disconnect();
194 syslog(LOG_DEBUG
, "New client connected");
195 client_connected
= 1;
196 send_capabilities(vport
, 0);
200 static void do_client_clipboard(struct vdagent_virtio_port
*vport
,
201 VDAgentMessage
*message_header
, uint8_t *data
)
203 uint32_t msg_type
= 0, data_type
= 0, size
= message_header
->size
;
204 uint8_t selection
= VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD
;
206 if (!active_session_conn
) {
208 "Could not find an agent connection belonging to the "
209 "active session, ignoring client clipboard request");
213 if (VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
214 VD_AGENT_CAP_CLIPBOARD_SELECTION
)) {
220 switch (message_header
->type
) {
221 case VD_AGENT_CLIPBOARD_GRAB
:
222 msg_type
= VDAGENTD_CLIPBOARD_GRAB
;
223 agent_owns_clipboard
[selection
] = 0;
225 case VD_AGENT_CLIPBOARD_REQUEST
: {
226 VDAgentClipboardRequest
*req
= (VDAgentClipboardRequest
*)data
;
227 msg_type
= VDAGENTD_CLIPBOARD_REQUEST
;
228 data_type
= req
->type
;
233 case VD_AGENT_CLIPBOARD
: {
234 VDAgentClipboard
*clipboard
= (VDAgentClipboard
*)data
;
235 msg_type
= VDAGENTD_CLIPBOARD_DATA
;
236 data_type
= clipboard
->type
;
237 size
= size
- sizeof(VDAgentClipboard
);
238 data
= clipboard
->data
;
241 case VD_AGENT_CLIPBOARD_RELEASE
:
242 msg_type
= VDAGENTD_CLIPBOARD_RELEASE
;
248 udscs_write(active_session_conn
, msg_type
, selection
, data_type
,
252 static void cancel_file_xfer(struct vdagent_virtio_port
*vport
,
253 const char *msg
, uint32_t id
)
255 VDAgentFileXferStatusMessage status
= {
257 .result
= VD_AGENT_FILE_XFER_STATUS_CANCELLED
,
259 syslog(LOG_WARNING
, msg
, id
);
261 vdagent_virtio_port_write(vport
, VDP_CLIENT_PORT
,
262 VD_AGENT_FILE_XFER_STATUS
, 0,
263 (uint8_t *)&status
, sizeof(status
));
266 static void do_client_file_xfer(struct vdagent_virtio_port
*vport
,
267 VDAgentMessage
*message_header
,
270 uint32_t msg_type
, id
;
271 struct udscs_connection
*conn
;
273 switch (message_header
->type
) {
274 case VD_AGENT_FILE_XFER_START
: {
275 VDAgentFileXferStartMessage
*s
= (VDAgentFileXferStartMessage
*)data
;
276 if (!active_session_conn
) {
277 cancel_file_xfer(vport
,
278 "Could not find an agent connnection belonging to the "
279 "active session, cancelling client file-xfer request %u",
283 udscs_write(active_session_conn
, VDAGENTD_FILE_XFER_START
, 0, 0,
284 data
, message_header
->size
);
287 case VD_AGENT_FILE_XFER_STATUS
: {
288 VDAgentFileXferStatusMessage
*s
= (VDAgentFileXferStatusMessage
*)data
;
289 msg_type
= VDAGENTD_FILE_XFER_STATUS
;
293 case VD_AGENT_FILE_XFER_DATA
: {
294 VDAgentFileXferDataMessage
*d
= (VDAgentFileXferDataMessage
*)data
;
295 msg_type
= VDAGENTD_FILE_XFER_DATA
;
301 conn
= g_hash_table_lookup(active_xfers
, GUINT_TO_POINTER(id
));
304 syslog(LOG_DEBUG
, "Could not find file-xfer %u (cancelled?)", id
);
307 udscs_write(conn
, msg_type
, 0, 0, data
, message_header
->size
);
310 static int virtio_port_read_complete(
311 struct vdagent_virtio_port
*vport
,
313 VDAgentMessage
*message_header
,
316 uint32_t min_size
= 0;
318 if (message_header
->protocol
!= VD_AGENT_PROTOCOL
) {
319 syslog(LOG_ERR
, "message with wrong protocol version ignoring");
323 switch (message_header
->type
) {
324 case VD_AGENT_MOUSE_STATE
:
325 if (message_header
->size
!= sizeof(VDAgentMouseState
))
327 vdagentd_uinput_do_mouse(&uinput
, (VDAgentMouseState
*)data
);
329 /* Try to re-open the tablet */
330 struct agent_data
*agent_data
=
331 udscs_get_user_data(active_session_conn
);
333 uinput
= vdagentd_uinput_create(uinput_device
,
336 agent_data
->screen_info
,
337 agent_data
->screen_count
,
341 syslog(LOG_CRIT
, "Fatal uinput error");
347 case VD_AGENT_MONITORS_CONFIG
:
348 if (message_header
->size
< sizeof(VDAgentMonitorsConfig
))
350 do_client_monitors(vport
, port_nr
, message_header
,
351 (VDAgentMonitorsConfig
*)data
);
353 case VD_AGENT_ANNOUNCE_CAPABILITIES
:
354 if (message_header
->size
< sizeof(VDAgentAnnounceCapabilities
))
356 do_client_capabilities(vport
, message_header
,
357 (VDAgentAnnounceCapabilities
*)data
);
359 case VD_AGENT_CLIPBOARD_GRAB
:
360 case VD_AGENT_CLIPBOARD_REQUEST
:
361 case VD_AGENT_CLIPBOARD
:
362 case VD_AGENT_CLIPBOARD_RELEASE
:
363 switch (message_header
->type
) {
364 case VD_AGENT_CLIPBOARD_GRAB
:
365 min_size
= sizeof(VDAgentClipboardGrab
); break;
366 case VD_AGENT_CLIPBOARD_REQUEST
:
367 min_size
= sizeof(VDAgentClipboardRequest
); break;
368 case VD_AGENT_CLIPBOARD
:
369 min_size
= sizeof(VDAgentClipboard
); break;
371 if (VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
372 VD_AGENT_CAP_CLIPBOARD_SELECTION
)) {
375 if (message_header
->size
< min_size
) {
378 do_client_clipboard(vport
, message_header
, data
);
380 case VD_AGENT_FILE_XFER_START
:
381 case VD_AGENT_FILE_XFER_STATUS
:
382 case VD_AGENT_FILE_XFER_DATA
:
383 do_client_file_xfer(vport
, message_header
, data
);
385 case VD_AGENT_CLIENT_DISCONNECTED
:
386 vdagent_virtio_port_reset(vport
, VDP_CLIENT_PORT
);
387 do_client_disconnect();
389 case VD_AGENT_MAX_CLIPBOARD
:
390 if (message_header
->size
!= sizeof(VDAgentMaxClipboard
))
392 VDAgentMaxClipboard
*msg
= (VDAgentMaxClipboard
*)data
;
393 syslog(LOG_DEBUG
, "Set max clipboard: %d", msg
->max
);
394 max_clipboard
= msg
->max
;
396 case VD_AGENT_AUDIO_VOLUME_SYNC
:
397 if (message_header
->size
< sizeof(VDAgentAudioVolumeSync
))
400 do_client_volume_sync(vport
, port_nr
, message_header
,
401 (VDAgentAudioVolumeSync
*)data
);
404 syslog(LOG_WARNING
, "unknown message type %d, ignoring",
405 message_header
->type
);
411 syslog(LOG_ERR
, "read: invalid message size: %u for message type: %u",
412 message_header
->size
, message_header
->type
);
416 static void virtio_write_clipboard(uint8_t selection
, uint32_t msg_type
,
417 uint32_t data_type
, const uint8_t *data
, uint32_t data_size
)
419 uint32_t size
= data_size
;
421 if (VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
422 VD_AGENT_CAP_CLIPBOARD_SELECTION
)) {
425 if (data_type
!= -1) {
429 vdagent_virtio_port_write_start(virtio_port
, VDP_CLIENT_PORT
, msg_type
,
432 if (VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
433 VD_AGENT_CAP_CLIPBOARD_SELECTION
)) {
434 uint8_t sel
[4] = { selection
, 0, 0, 0 };
435 vdagent_virtio_port_write_append(virtio_port
, sel
, 4);
437 if (data_type
!= -1) {
438 vdagent_virtio_port_write_append(virtio_port
, (uint8_t*)&data_type
, 4);
441 vdagent_virtio_port_write_append(virtio_port
, data
, data_size
);
444 /* vdagentd <-> vdagent communication handling */
445 static int do_agent_clipboard(struct udscs_connection
*conn
,
446 struct udscs_message_header
*header
, const uint8_t *data
)
448 uint8_t selection
= header
->arg1
;
449 uint32_t msg_type
= 0, data_type
= -1, size
= header
->size
;
451 if (!VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
452 VD_AGENT_CAP_CLIPBOARD_BY_DEMAND
))
455 /* Check that this agent is from the currently active session */
456 if (conn
!= active_session_conn
) {
458 syslog(LOG_DEBUG
, "%p clipboard req from agent which is not in "
459 "the active session?", conn
);
464 syslog(LOG_ERR
, "Clipboard req from agent but no client connection");
468 if (!VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
469 VD_AGENT_CAP_CLIPBOARD_SELECTION
) &&
470 selection
!= VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD
) {
474 switch (header
->type
) {
475 case VDAGENTD_CLIPBOARD_GRAB
:
476 msg_type
= VD_AGENT_CLIPBOARD_GRAB
;
477 agent_owns_clipboard
[selection
] = 1;
479 case VDAGENTD_CLIPBOARD_REQUEST
:
480 msg_type
= VD_AGENT_CLIPBOARD_REQUEST
;
481 data_type
= header
->arg2
;
484 case VDAGENTD_CLIPBOARD_DATA
:
485 msg_type
= VD_AGENT_CLIPBOARD
;
486 data_type
= header
->arg2
;
487 if (max_clipboard
!= -1 && size
> max_clipboard
) {
488 syslog(LOG_WARNING
, "clipboard is too large (%d > %d), discarding",
489 size
, max_clipboard
);
490 virtio_write_clipboard(selection
, msg_type
, data_type
, NULL
, 0);
494 case VDAGENTD_CLIPBOARD_RELEASE
:
495 msg_type
= VD_AGENT_CLIPBOARD_RELEASE
;
497 agent_owns_clipboard
[selection
] = 0;
500 syslog(LOG_WARNING
, "unexpected clipboard message type");
504 if (size
!= header
->size
) {
506 "unexpected extra data in clipboard msg, disconnecting agent");
510 virtio_write_clipboard(selection
, msg_type
, data_type
, data
, header
->size
);
515 if (header
->type
== VDAGENTD_CLIPBOARD_REQUEST
) {
516 /* Let the agent know no answer is coming */
517 udscs_write(conn
, VDAGENTD_CLIPBOARD_DATA
,
518 selection
, VD_AGENT_CLIPBOARD_NONE
, NULL
, 0);
523 /* When we open the vdagent virtio channel, the server automatically goes into
524 client mouse mode, so we can only have the channel open when we know the
525 active session resolution. This function checks that we have an agent in the
526 active session, and that it has told us its resolution. If these conditions
527 are met it sets the uinput tablet device's resolution and opens the virtio
528 channel (if it is not already open). If these conditions are not met, it
530 static void check_xorg_resolution(void)
532 struct agent_data
*agent_data
= udscs_get_user_data(active_session_conn
);
534 if (agent_data
&& agent_data
->screen_info
) {
536 uinput
= vdagentd_uinput_create(uinput_device
,
539 agent_data
->screen_info
,
540 agent_data
->screen_count
,
544 vdagentd_uinput_update_size(&uinput
,
547 agent_data
->screen_info
,
548 agent_data
->screen_count
);
550 syslog(LOG_CRIT
, "Fatal uinput error");
557 syslog(LOG_INFO
, "opening vdagent virtio channel");
558 virtio_port
= vdagent_virtio_port_create(portdev
,
559 virtio_port_read_complete
,
562 syslog(LOG_CRIT
, "Fatal error opening vdagent virtio channel");
567 send_capabilities(virtio_port
, 1);
570 #ifndef WITH_STATIC_UINPUT
571 vdagentd_uinput_destroy(&uinput
);
574 vdagent_virtio_port_flush(&virtio_port
);
575 vdagent_virtio_port_destroy(&virtio_port
);
576 syslog(LOG_INFO
, "closed vdagent virtio channel");
581 static int connection_matches_active_session(struct udscs_connection
**connp
,
584 struct udscs_connection
**conn_ret
= (struct udscs_connection
**)priv
;
585 struct agent_data
*agent_data
= udscs_get_user_data(*connp
);
587 /* Check if this connection matches the currently active session */
588 if (!agent_data
->session
|| !active_session
)
590 if (strcmp(agent_data
->session
, active_session
))
597 static void release_clipboards(void)
601 for (sel
= 0; sel
< VD_AGENT_CLIPBOARD_SELECTION_SECONDARY
; ++sel
) {
602 if (agent_owns_clipboard
[sel
] && virtio_port
) {
603 vdagent_virtio_port_write(virtio_port
, VDP_CLIENT_PORT
,
604 VD_AGENT_CLIPBOARD_RELEASE
, 0, &sel
, 1);
606 agent_owns_clipboard
[sel
] = 0;
610 static void update_active_session_connection(struct udscs_connection
*new_conn
)
615 active_session
= session_info_get_active_session(session_info
);
616 session_count
= udscs_server_for_all_clients(server
,
617 connection_matches_active_session
,
626 if (new_conn
&& session_count
!= 1) {
627 syslog(LOG_ERR
, "multiple agents in one session, "
628 "disabling agent to avoid potential information leak");
632 if (new_conn
== active_session_conn
)
635 active_session_conn
= new_conn
;
637 syslog(LOG_DEBUG
, "%p is now the active session", new_conn
);
638 if (active_session_conn
&& mon_config
)
639 udscs_write(active_session_conn
, VDAGENTD_MONITORS_CONFIG
, 0, 0,
640 (uint8_t *)mon_config
, sizeof(VDAgentMonitorsConfig
) +
641 mon_config
->num_of_monitors
* sizeof(VDAgentMonConfig
));
643 release_clipboards();
645 check_xorg_resolution();
648 static gboolean
remove_active_xfers(gpointer key
, gpointer value
, gpointer conn
)
651 cancel_file_xfer(virtio_port
, "Agent disc; cancelling file-xfer %u",
652 GPOINTER_TO_UINT(key
));
658 static void agent_connect(struct udscs_connection
*conn
)
660 struct agent_data
*agent_data
;
662 agent_data
= calloc(1, sizeof(*agent_data
));
664 syslog(LOG_ERR
, "Out of memory allocating agent data, disconnecting");
665 udscs_destroy_connection(&conn
);
670 uint32_t pid
= udscs_get_peer_cred(conn
).pid
;
671 agent_data
->session
= session_info_session_for_pid(session_info
, pid
);
674 udscs_set_user_data(conn
, (void *)agent_data
);
675 udscs_write(conn
, VDAGENTD_VERSION
, 0, 0,
676 (uint8_t *)VERSION
, strlen(VERSION
) + 1);
677 update_active_session_connection(conn
);
680 static void agent_disconnect(struct udscs_connection
*conn
)
682 struct agent_data
*agent_data
= udscs_get_user_data(conn
);
684 g_hash_table_foreach_remove(active_xfers
, remove_active_xfers
, conn
);
686 free(agent_data
->session
);
687 agent_data
->session
= NULL
;
688 update_active_session_connection(NULL
);
690 free(agent_data
->screen_info
);
694 static void agent_read_complete(struct udscs_connection
**connp
,
695 struct udscs_message_header
*header
, uint8_t *data
)
697 struct agent_data
*agent_data
= udscs_get_user_data(*connp
);
699 switch (header
->type
) {
700 case VDAGENTD_GUEST_XORG_RESOLUTION
: {
701 struct vdagentd_guest_xorg_resolution
*res
;
702 int n
= header
->size
/ sizeof(*res
);
704 /* Detect older version session agent, but don't disconnect, as
705 that stops it from getting the VDAGENTD_VERSION message, and then
706 it will never re-exec the new version... */
707 if (header
->arg1
== 0 && header
->arg2
== 0) {
708 syslog(LOG_INFO
, "got old session agent xorg resolution message, "
714 if (header
->size
!= n
* sizeof(*res
)) {
715 syslog(LOG_ERR
, "guest xorg resolution message has wrong size, "
716 "disconnecting agent");
717 udscs_destroy_connection(connp
);
722 free(agent_data
->screen_info
);
723 res
= malloc(n
* sizeof(*res
));
725 syslog(LOG_ERR
, "out of memory allocating screen info");
728 memcpy(res
, data
, n
* sizeof(*res
));
729 agent_data
->width
= header
->arg1
;
730 agent_data
->height
= header
->arg2
;
731 agent_data
->screen_info
= res
;
732 agent_data
->screen_count
= n
;
734 check_xorg_resolution();
737 case VDAGENTD_CLIPBOARD_GRAB
:
738 case VDAGENTD_CLIPBOARD_REQUEST
:
739 case VDAGENTD_CLIPBOARD_DATA
:
740 case VDAGENTD_CLIPBOARD_RELEASE
:
741 if (do_agent_clipboard(*connp
, header
, data
)) {
742 udscs_destroy_connection(connp
);
747 case VDAGENTD_FILE_XFER_STATUS
:{
748 VDAgentFileXferStatusMessage status
;
749 status
.id
= header
->arg1
;
750 status
.result
= header
->arg2
;
751 vdagent_virtio_port_write(virtio_port
, VDP_CLIENT_PORT
,
752 VD_AGENT_FILE_XFER_STATUS
, 0,
753 (uint8_t *)&status
, sizeof(status
));
754 if (status
.result
== VD_AGENT_FILE_XFER_STATUS_CAN_SEND_DATA
)
755 g_hash_table_insert(active_xfers
, GUINT_TO_POINTER(status
.id
),
758 g_hash_table_remove(active_xfers
, GUINT_TO_POINTER(status
.id
));
763 syslog(LOG_ERR
, "unknown message from vdagent: %u, ignoring",
771 static void usage(FILE *fp
)
774 "Usage: spice-vdagentd [OPTIONS]\n\n"
775 "Spice guest agent daemon, version %s.\n\n"
777 " -h print this text\n"
778 " -d log debug messages (use twice for extra info)\n"
779 " -s <port> set virtio serial port [%s]\n"
780 " -S <filename> set udcs socket [%s]\n"
781 " -u <dev> set uinput device [%s]\n"
782 " -f treat uinput device as fake; no ioctls\n"
783 " -x don't daemonize\n"
784 " -o Only handle one virtio serial session.\n"
785 #ifdef HAVE_CONSOLE_KIT
786 " -X Disable console kit integration\n"
788 #ifdef HAVE_LIBSYSTEMD_LOGIN
789 " -X Disable systemd-logind integration\n"
791 ,VERSION
, portdev
, vdagentd_socket
, uinput_device
);
794 static void daemonize(void)
799 /* detach from terminal */
802 close(0); close(1); close(2);
804 x
= open("/dev/null", O_RDWR
); x
= dup(x
); x
= dup(x
);
805 pidfile
= fopen(pidfilename
, "w");
807 fprintf(pidfile
, "%d\n", (int)getpid());
812 syslog(LOG_ERR
, "fork: %m");
815 udscs_destroy_server(server
);
820 static void main_loop(void)
822 fd_set readfds
, writefds
;
831 nfds
= udscs_server_fill_fds(server
, &readfds
, &writefds
);
832 n
= vdagent_virtio_port_fill_fds(virtio_port
, &readfds
, &writefds
);
837 ck_fd
= session_info_get_fd(session_info
);
838 FD_SET(ck_fd
, &readfds
);
843 n
= select(nfds
, &readfds
, &writefds
, NULL
, NULL
);
847 syslog(LOG_CRIT
, "Fatal error select: %m");
852 udscs_server_handle_fds(server
, &readfds
, &writefds
);
856 vdagent_virtio_port_handle_fds(&virtio_port
, &readfds
, &writefds
);
858 int old_client_connected
= client_connected
;
860 "AIIEEE lost spice client connection, reconnecting");
861 virtio_port
= vdagent_virtio_port_create(portdev
,
862 virtio_port_read_complete
,
866 "Fatal error opening vdagent virtio channel");
870 do_client_disconnect();
871 client_connected
= old_client_connected
;
874 else if (only_once
&& once
)
876 syslog(LOG_INFO
, "Exiting after one client session.");
880 if (session_info
&& FD_ISSET(ck_fd
, &readfds
)) {
881 active_session
= session_info_get_active_session(session_info
);
882 update_active_session_connection(NULL
);
887 static void quit_handler(int sig
)
892 int main(int argc
, char *argv
[])
895 int do_daemonize
= 1;
896 int want_session_info
= 1;
897 struct sigaction act
;
900 if (-1 == (c
= getopt(argc
, argv
, "-dhxXfos:u:S:")))
910 vdagentd_socket
= optarg
;
913 uinput_device
= optarg
;
925 want_session_info
= 0;
937 memset(&act
, 0, sizeof(act
));
938 act
.sa_flags
= SA_RESTART
;
939 act
.sa_handler
= quit_handler
;
940 sigaction(SIGINT
, &act
, NULL
);
941 sigaction(SIGHUP
, &act
, NULL
);
942 sigaction(SIGTERM
, &act
, NULL
);
943 sigaction(SIGQUIT
, &act
, NULL
);
945 openlog("spice-vdagentd", do_daemonize
? 0 : LOG_PERROR
, LOG_USER
);
947 /* Setup communication with vdagent process(es) */
948 server
= udscs_create_server(vdagentd_socket
, agent_connect
,
949 agent_read_complete
, agent_disconnect
,
950 vdagentd_messages
, VDAGENTD_NO_MESSAGES
,
953 syslog(LOG_CRIT
, "Fatal could not create server socket %s",
957 if (chmod(vdagentd_socket
, 0666)) {
958 syslog(LOG_CRIT
, "Fatal could not change permissions on %s: %m",
960 udscs_destroy_server(server
);
967 #ifdef WITH_STATIC_UINPUT
968 uinput
= vdagentd_uinput_create(uinput_device
, 1024, 768, NULL
, 0,
969 debug
> 1, uinput_fake
);
971 udscs_destroy_server(server
);
976 if (want_session_info
)
977 session_info
= session_info_create(debug
);
979 syslog(LOG_WARNING
, "no session info, max 1 session agent allowed");
981 active_xfers
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
984 release_clipboards();
986 vdagentd_uinput_destroy(&uinput
);
987 vdagent_virtio_port_flush(&virtio_port
);
988 vdagent_virtio_port_destroy(&virtio_port
);
989 session_info_destroy(session_info
);
990 udscs_destroy_server(server
);
991 if (unlink(vdagentd_socket
) != 0)
992 syslog(LOG_ERR
, "unlink %s: %s", vdagentd_socket
, strerror(errno
));
993 syslog(LOG_INFO
, "vdagentd quiting, returning status %d", retval
);