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"
43 #include "xorg-conf.h"
44 #include "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 void do_client_mouse(struct vdagentd_uinput
**uinputp
, VDAgentMouseState
*mouse
)
123 vdagentd_uinput_do_mouse(uinputp
, mouse
);
125 /* Try to re-open the tablet */
126 struct agent_data
*agent_data
=
127 udscs_get_user_data(active_session_conn
);
129 *uinputp
= vdagentd_uinput_create(uinput_device
,
132 agent_data
->screen_info
,
133 agent_data
->screen_count
,
137 syslog(LOG_CRIT
, "Fatal uinput error");
144 static void do_client_monitors(struct vdagent_virtio_port
*vport
, int port_nr
,
145 VDAgentMessage
*message_header
, VDAgentMonitorsConfig
*new_monitors
)
150 /* Store monitor config to send to agents when they connect */
151 size
= sizeof(VDAgentMonitorsConfig
) +
152 new_monitors
->num_of_monitors
* sizeof(VDAgentMonConfig
);
153 if (message_header
->size
!= size
) {
154 syslog(LOG_ERR
, "invalid message size for VDAgentMonitorsConfig");
158 vdagentd_write_xorg_conf(new_monitors
);
161 mon_config
->num_of_monitors
!= new_monitors
->num_of_monitors
) {
163 mon_config
= malloc(size
);
165 syslog(LOG_ERR
, "out of memory allocating monitors config");
169 memcpy(mon_config
, new_monitors
, size
);
171 /* Send monitor config to currently active agent */
172 if (active_session_conn
)
173 udscs_write(active_session_conn
, VDAGENTD_MONITORS_CONFIG
, 0, 0,
174 (uint8_t *)mon_config
, size
);
176 /* Acknowledge reception of monitors config to spice server / client */
177 reply
.type
= VD_AGENT_MONITORS_CONFIG
;
178 reply
.error
= VD_AGENT_SUCCESS
;
179 vdagent_virtio_port_write(vport
, port_nr
, VD_AGENT_REPLY
, 0,
180 (uint8_t *)&reply
, sizeof(reply
));
183 static void do_client_volume_sync(struct vdagent_virtio_port
*vport
, int port_nr
,
184 VDAgentMessage
*message_header
,
185 VDAgentAudioVolumeSync
*avs
)
187 if (active_session_conn
== NULL
) {
188 syslog(LOG_DEBUG
, "No active session - Can't volume-sync");
192 udscs_write(active_session_conn
, VDAGENTD_AUDIO_VOLUME_SYNC
, 0, 0,
193 (uint8_t *)avs
, message_header
->size
);
196 static void do_client_capabilities(struct vdagent_virtio_port
*vport
,
197 VDAgentMessage
*message_header
,
198 VDAgentAnnounceCapabilities
*caps
)
200 int new_size
= VD_AGENT_CAPS_SIZE_FROM_MSG_SIZE(message_header
->size
);
202 if (capabilities_size
!= new_size
) {
203 capabilities_size
= new_size
;
205 capabilities
= malloc(capabilities_size
* sizeof(uint32_t));
207 syslog(LOG_ERR
, "oom allocating capabilities array (read)");
208 capabilities_size
= 0;
212 memcpy(capabilities
, caps
->caps
, capabilities_size
* sizeof(uint32_t));
214 /* Report the previous client has disconneced. */
215 do_client_disconnect();
217 syslog(LOG_DEBUG
, "New client connected");
218 client_connected
= 1;
219 send_capabilities(vport
, 0);
223 static void do_client_clipboard(struct vdagent_virtio_port
*vport
,
224 VDAgentMessage
*message_header
, uint8_t *data
)
226 uint32_t msg_type
= 0, data_type
= 0, size
= message_header
->size
;
227 uint8_t selection
= VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD
;
229 if (!active_session_conn
) {
231 "Could not find an agent connection belonging to the "
232 "active session, ignoring client clipboard request");
236 if (VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
237 VD_AGENT_CAP_CLIPBOARD_SELECTION
)) {
243 switch (message_header
->type
) {
244 case VD_AGENT_CLIPBOARD_GRAB
:
245 msg_type
= VDAGENTD_CLIPBOARD_GRAB
;
246 agent_owns_clipboard
[selection
] = 0;
248 case VD_AGENT_CLIPBOARD_REQUEST
: {
249 VDAgentClipboardRequest
*req
= (VDAgentClipboardRequest
*)data
;
250 msg_type
= VDAGENTD_CLIPBOARD_REQUEST
;
251 data_type
= req
->type
;
256 case VD_AGENT_CLIPBOARD
: {
257 VDAgentClipboard
*clipboard
= (VDAgentClipboard
*)data
;
258 msg_type
= VDAGENTD_CLIPBOARD_DATA
;
259 data_type
= clipboard
->type
;
260 size
= size
- sizeof(VDAgentClipboard
);
261 data
= clipboard
->data
;
264 case VD_AGENT_CLIPBOARD_RELEASE
:
265 msg_type
= VDAGENTD_CLIPBOARD_RELEASE
;
271 udscs_write(active_session_conn
, msg_type
, selection
, data_type
,
275 /* To be used by vdagentd for failures in file-xfer such as when file-xfer was
276 * cancelled or an error happened */
277 static void send_file_xfer_status(struct vdagent_virtio_port
*vport
,
278 const char *msg
, uint32_t id
, uint32_t xfer_status
)
280 VDAgentFileXferStatusMessage status
= {
282 .result
= xfer_status
,
284 syslog(LOG_WARNING
, msg
, id
);
286 vdagent_virtio_port_write(vport
, VDP_CLIENT_PORT
,
287 VD_AGENT_FILE_XFER_STATUS
, 0,
288 (uint8_t *)&status
, sizeof(status
));
291 static void do_client_file_xfer(struct vdagent_virtio_port
*vport
,
292 VDAgentMessage
*message_header
,
295 uint32_t msg_type
, id
;
296 struct udscs_connection
*conn
;
298 switch (message_header
->type
) {
299 case VD_AGENT_FILE_XFER_START
: {
300 VDAgentFileXferStartMessage
*s
= (VDAgentFileXferStartMessage
*)data
;
301 if (!active_session_conn
) {
302 send_file_xfer_status(vport
,
303 "Could not find an agent connnection belonging to the "
304 "active session, cancelling client file-xfer request %u",
305 s
->id
, VD_AGENT_FILE_XFER_STATUS_CANCELLED
);
307 } else if (session_info_session_is_locked(session_info
)) {
308 syslog(LOG_DEBUG
, "Session is locked, skipping file-xfer-start");
309 send_file_xfer_status(vport
,
310 "User's session is locked and cannot start file transfer. "
311 "Cancelling client file-xfer request %u",
312 s
->id
, VD_AGENT_FILE_XFER_STATUS_ERROR
);
315 udscs_write(active_session_conn
, VDAGENTD_FILE_XFER_START
, 0, 0,
316 data
, message_header
->size
);
319 case VD_AGENT_FILE_XFER_STATUS
: {
320 VDAgentFileXferStatusMessage
*s
= (VDAgentFileXferStatusMessage
*)data
;
321 msg_type
= VDAGENTD_FILE_XFER_STATUS
;
325 case VD_AGENT_FILE_XFER_DATA
: {
326 VDAgentFileXferDataMessage
*d
= (VDAgentFileXferDataMessage
*)data
;
327 msg_type
= VDAGENTD_FILE_XFER_DATA
;
333 conn
= g_hash_table_lookup(active_xfers
, GUINT_TO_POINTER(id
));
336 syslog(LOG_DEBUG
, "Could not find file-xfer %u (cancelled?)", id
);
339 udscs_write(conn
, msg_type
, 0, 0, data
, message_header
->size
);
342 static int virtio_port_read_complete(
343 struct vdagent_virtio_port
*vport
,
345 VDAgentMessage
*message_header
,
348 uint32_t min_size
= 0;
350 if (message_header
->protocol
!= VD_AGENT_PROTOCOL
) {
351 syslog(LOG_ERR
, "message with wrong protocol version ignoring");
355 switch (message_header
->type
) {
356 case VD_AGENT_MOUSE_STATE
:
357 if (message_header
->size
!= sizeof(VDAgentMouseState
))
359 do_client_mouse(&uinput
, (VDAgentMouseState
*)data
);
361 case VD_AGENT_MONITORS_CONFIG
:
362 if (message_header
->size
< sizeof(VDAgentMonitorsConfig
))
364 do_client_monitors(vport
, port_nr
, message_header
,
365 (VDAgentMonitorsConfig
*)data
);
367 case VD_AGENT_ANNOUNCE_CAPABILITIES
:
368 if (message_header
->size
< sizeof(VDAgentAnnounceCapabilities
))
370 do_client_capabilities(vport
, message_header
,
371 (VDAgentAnnounceCapabilities
*)data
);
373 case VD_AGENT_CLIPBOARD_GRAB
:
374 case VD_AGENT_CLIPBOARD_REQUEST
:
375 case VD_AGENT_CLIPBOARD
:
376 case VD_AGENT_CLIPBOARD_RELEASE
:
377 switch (message_header
->type
) {
378 case VD_AGENT_CLIPBOARD_GRAB
:
379 min_size
= sizeof(VDAgentClipboardGrab
); break;
380 case VD_AGENT_CLIPBOARD_REQUEST
:
381 min_size
= sizeof(VDAgentClipboardRequest
); break;
382 case VD_AGENT_CLIPBOARD
:
383 min_size
= sizeof(VDAgentClipboard
); break;
385 if (VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
386 VD_AGENT_CAP_CLIPBOARD_SELECTION
)) {
389 if (message_header
->size
< min_size
) {
392 do_client_clipboard(vport
, message_header
, data
);
394 case VD_AGENT_FILE_XFER_START
:
395 case VD_AGENT_FILE_XFER_STATUS
:
396 case VD_AGENT_FILE_XFER_DATA
:
397 do_client_file_xfer(vport
, message_header
, data
);
399 case VD_AGENT_CLIENT_DISCONNECTED
:
400 vdagent_virtio_port_reset(vport
, VDP_CLIENT_PORT
);
401 do_client_disconnect();
403 case VD_AGENT_MAX_CLIPBOARD
:
404 if (message_header
->size
!= sizeof(VDAgentMaxClipboard
))
406 VDAgentMaxClipboard
*msg
= (VDAgentMaxClipboard
*)data
;
407 syslog(LOG_DEBUG
, "Set max clipboard: %d", msg
->max
);
408 max_clipboard
= msg
->max
;
410 case VD_AGENT_AUDIO_VOLUME_SYNC
:
411 if (message_header
->size
< sizeof(VDAgentAudioVolumeSync
))
414 do_client_volume_sync(vport
, port_nr
, message_header
,
415 (VDAgentAudioVolumeSync
*)data
);
418 syslog(LOG_WARNING
, "unknown message type %d, ignoring",
419 message_header
->type
);
425 syslog(LOG_ERR
, "read: invalid message size: %u for message type: %u",
426 message_header
->size
, message_header
->type
);
430 static void virtio_write_clipboard(uint8_t selection
, uint32_t msg_type
,
431 uint32_t data_type
, const uint8_t *data
, uint32_t data_size
)
433 uint32_t size
= data_size
;
435 if (VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
436 VD_AGENT_CAP_CLIPBOARD_SELECTION
)) {
439 if (data_type
!= -1) {
443 vdagent_virtio_port_write_start(virtio_port
, VDP_CLIENT_PORT
, msg_type
,
446 if (VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
447 VD_AGENT_CAP_CLIPBOARD_SELECTION
)) {
448 uint8_t sel
[4] = { selection
, 0, 0, 0 };
449 vdagent_virtio_port_write_append(virtio_port
, sel
, 4);
451 if (data_type
!= -1) {
452 vdagent_virtio_port_write_append(virtio_port
, (uint8_t*)&data_type
, 4);
455 vdagent_virtio_port_write_append(virtio_port
, data
, data_size
);
458 /* vdagentd <-> vdagent communication handling */
459 static int do_agent_clipboard(struct udscs_connection
*conn
,
460 struct udscs_message_header
*header
, const uint8_t *data
)
462 uint8_t selection
= header
->arg1
;
463 uint32_t msg_type
= 0, data_type
= -1, size
= header
->size
;
465 if (!VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
466 VD_AGENT_CAP_CLIPBOARD_BY_DEMAND
))
469 /* Check that this agent is from the currently active session */
470 if (conn
!= active_session_conn
) {
472 syslog(LOG_DEBUG
, "%p clipboard req from agent which is not in "
473 "the active session?", conn
);
478 syslog(LOG_ERR
, "Clipboard req from agent but no client connection");
482 if (!VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
483 VD_AGENT_CAP_CLIPBOARD_SELECTION
) &&
484 selection
!= VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD
) {
488 switch (header
->type
) {
489 case VDAGENTD_CLIPBOARD_GRAB
:
490 msg_type
= VD_AGENT_CLIPBOARD_GRAB
;
491 agent_owns_clipboard
[selection
] = 1;
493 case VDAGENTD_CLIPBOARD_REQUEST
:
494 msg_type
= VD_AGENT_CLIPBOARD_REQUEST
;
495 data_type
= header
->arg2
;
498 case VDAGENTD_CLIPBOARD_DATA
:
499 msg_type
= VD_AGENT_CLIPBOARD
;
500 data_type
= header
->arg2
;
501 if (max_clipboard
!= -1 && size
> max_clipboard
) {
502 syslog(LOG_WARNING
, "clipboard is too large (%d > %d), discarding",
503 size
, max_clipboard
);
504 virtio_write_clipboard(selection
, msg_type
, data_type
, NULL
, 0);
508 case VDAGENTD_CLIPBOARD_RELEASE
:
509 msg_type
= VD_AGENT_CLIPBOARD_RELEASE
;
511 agent_owns_clipboard
[selection
] = 0;
514 syslog(LOG_WARNING
, "unexpected clipboard message type");
518 if (size
!= header
->size
) {
520 "unexpected extra data in clipboard msg, disconnecting agent");
524 virtio_write_clipboard(selection
, msg_type
, data_type
, data
, header
->size
);
529 if (header
->type
== VDAGENTD_CLIPBOARD_REQUEST
) {
530 /* Let the agent know no answer is coming */
531 udscs_write(conn
, VDAGENTD_CLIPBOARD_DATA
,
532 selection
, VD_AGENT_CLIPBOARD_NONE
, NULL
, 0);
537 /* When we open the vdagent virtio channel, the server automatically goes into
538 client mouse mode, so we can only have the channel open when we know the
539 active session resolution. This function checks that we have an agent in the
540 active session, and that it has told us its resolution. If these conditions
541 are met it sets the uinput tablet device's resolution and opens the virtio
542 channel (if it is not already open). If these conditions are not met, it
544 static void check_xorg_resolution(void)
546 struct agent_data
*agent_data
= udscs_get_user_data(active_session_conn
);
548 if (agent_data
&& agent_data
->screen_info
) {
550 uinput
= vdagentd_uinput_create(uinput_device
,
553 agent_data
->screen_info
,
554 agent_data
->screen_count
,
558 vdagentd_uinput_update_size(&uinput
,
561 agent_data
->screen_info
,
562 agent_data
->screen_count
);
564 syslog(LOG_CRIT
, "Fatal uinput error");
571 syslog(LOG_INFO
, "opening vdagent virtio channel");
572 virtio_port
= vdagent_virtio_port_create(portdev
,
573 virtio_port_read_complete
,
576 syslog(LOG_CRIT
, "Fatal error opening vdagent virtio channel");
581 send_capabilities(virtio_port
, 1);
584 #ifndef WITH_STATIC_UINPUT
585 vdagentd_uinput_destroy(&uinput
);
588 vdagent_virtio_port_flush(&virtio_port
);
589 vdagent_virtio_port_destroy(&virtio_port
);
590 syslog(LOG_INFO
, "closed vdagent virtio channel");
595 static int connection_matches_active_session(struct udscs_connection
**connp
,
598 struct udscs_connection
**conn_ret
= (struct udscs_connection
**)priv
;
599 struct agent_data
*agent_data
= udscs_get_user_data(*connp
);
601 /* Check if this connection matches the currently active session */
602 if (!agent_data
->session
|| !active_session
)
604 if (strcmp(agent_data
->session
, active_session
))
611 static void release_clipboards(void)
615 for (sel
= 0; sel
< VD_AGENT_CLIPBOARD_SELECTION_SECONDARY
; ++sel
) {
616 if (agent_owns_clipboard
[sel
] && virtio_port
) {
617 vdagent_virtio_port_write(virtio_port
, VDP_CLIENT_PORT
,
618 VD_AGENT_CLIPBOARD_RELEASE
, 0, &sel
, 1);
620 agent_owns_clipboard
[sel
] = 0;
624 static void update_active_session_connection(struct udscs_connection
*new_conn
)
629 active_session
= session_info_get_active_session(session_info
);
630 session_count
= udscs_server_for_all_clients(server
,
631 connection_matches_active_session
,
640 if (new_conn
&& session_count
!= 1) {
641 syslog(LOG_ERR
, "multiple agents in one session, "
642 "disabling agent to avoid potential information leak");
646 if (new_conn
== active_session_conn
)
649 active_session_conn
= new_conn
;
651 syslog(LOG_DEBUG
, "%p is now the active session", new_conn
);
653 if (active_session_conn
&& !session_info_is_user(session_info
)) {
655 syslog(LOG_DEBUG
, "New session agent does not belong to user: "
656 "disabling file-xfer");
657 udscs_write(active_session_conn
, VDAGENTD_FILE_XFER_DISABLE
, 0, 0,
661 if (active_session_conn
&& mon_config
)
662 udscs_write(active_session_conn
, VDAGENTD_MONITORS_CONFIG
, 0, 0,
663 (uint8_t *)mon_config
, sizeof(VDAgentMonitorsConfig
) +
664 mon_config
->num_of_monitors
* sizeof(VDAgentMonConfig
));
666 release_clipboards();
668 check_xorg_resolution();
671 static gboolean
remove_active_xfers(gpointer key
, gpointer value
, gpointer conn
)
674 send_file_xfer_status(virtio_port
,
675 "Agent disc; cancelling file-xfer %u",
676 GPOINTER_TO_UINT(key
),
677 VD_AGENT_FILE_XFER_STATUS_CANCELLED
);
683 static void agent_connect(struct udscs_connection
*conn
)
685 struct agent_data
*agent_data
;
687 agent_data
= calloc(1, sizeof(*agent_data
));
689 syslog(LOG_ERR
, "Out of memory allocating agent data, disconnecting");
690 udscs_destroy_connection(&conn
);
695 uint32_t pid
= udscs_get_peer_cred(conn
).pid
;
696 agent_data
->session
= session_info_session_for_pid(session_info
, pid
);
699 udscs_set_user_data(conn
, (void *)agent_data
);
700 udscs_write(conn
, VDAGENTD_VERSION
, 0, 0,
701 (uint8_t *)VERSION
, strlen(VERSION
) + 1);
702 update_active_session_connection(conn
);
705 static void agent_disconnect(struct udscs_connection
*conn
)
707 struct agent_data
*agent_data
= udscs_get_user_data(conn
);
709 g_hash_table_foreach_remove(active_xfers
, remove_active_xfers
, conn
);
711 free(agent_data
->session
);
712 agent_data
->session
= NULL
;
713 update_active_session_connection(NULL
);
715 free(agent_data
->screen_info
);
719 static void agent_read_complete(struct udscs_connection
**connp
,
720 struct udscs_message_header
*header
, uint8_t *data
)
722 struct agent_data
*agent_data
= udscs_get_user_data(*connp
);
724 switch (header
->type
) {
725 case VDAGENTD_GUEST_XORG_RESOLUTION
: {
726 struct vdagentd_guest_xorg_resolution
*res
;
727 int n
= header
->size
/ sizeof(*res
);
729 /* Detect older version session agent, but don't disconnect, as
730 that stops it from getting the VDAGENTD_VERSION message, and then
731 it will never re-exec the new version... */
732 if (header
->arg1
== 0 && header
->arg2
== 0) {
733 syslog(LOG_INFO
, "got old session agent xorg resolution message, "
738 if (header
->size
!= n
* sizeof(*res
)) {
739 syslog(LOG_ERR
, "guest xorg resolution message has wrong size, "
740 "disconnecting agent");
741 udscs_destroy_connection(connp
);
745 free(agent_data
->screen_info
);
746 res
= malloc(n
* sizeof(*res
));
748 syslog(LOG_ERR
, "out of memory allocating screen info");
751 memcpy(res
, data
, n
* sizeof(*res
));
752 agent_data
->width
= header
->arg1
;
753 agent_data
->height
= header
->arg2
;
754 agent_data
->screen_info
= res
;
755 agent_data
->screen_count
= n
;
757 check_xorg_resolution();
760 case VDAGENTD_CLIPBOARD_GRAB
:
761 case VDAGENTD_CLIPBOARD_REQUEST
:
762 case VDAGENTD_CLIPBOARD_DATA
:
763 case VDAGENTD_CLIPBOARD_RELEASE
:
764 if (do_agent_clipboard(*connp
, header
, data
)) {
765 udscs_destroy_connection(connp
);
769 case VDAGENTD_FILE_XFER_STATUS
:{
770 VDAgentFileXferStatusMessage status
;
771 status
.id
= header
->arg1
;
772 status
.result
= header
->arg2
;
773 vdagent_virtio_port_write(virtio_port
, VDP_CLIENT_PORT
,
774 VD_AGENT_FILE_XFER_STATUS
, 0,
775 (uint8_t *)&status
, sizeof(status
));
776 if (status
.result
== VD_AGENT_FILE_XFER_STATUS_CAN_SEND_DATA
)
777 g_hash_table_insert(active_xfers
, GUINT_TO_POINTER(status
.id
),
780 g_hash_table_remove(active_xfers
, GUINT_TO_POINTER(status
.id
));
785 syslog(LOG_ERR
, "unknown message from vdagent: %u, ignoring",
792 static void usage(FILE *fp
)
795 "Usage: spice-vdagentd [OPTIONS]\n\n"
796 "Spice guest agent daemon, version %s.\n\n"
798 " -h print this text\n"
799 " -d log debug messages (use twice for extra info)\n"
800 " -s <port> set virtio serial port [%s]\n"
801 " -S <filename> set vdagent Unix domain socket [%s]\n"
802 " -u <dev> set uinput device [%s]\n"
803 " -f treat uinput device as fake; no ioctls\n"
804 " -x don't daemonize\n"
805 " -o only handle one virtio serial session\n"
806 #ifdef HAVE_CONSOLE_KIT
807 " -X disable console kit integration\n"
809 #ifdef HAVE_LIBSYSTEMD_LOGIN
810 " -X disable systemd-logind integration\n"
812 ,VERSION
, portdev
, vdagentd_socket
, uinput_device
);
815 static void daemonize(void)
820 /* detach from terminal */
823 close(0); close(1); close(2);
825 x
= open("/dev/null", O_RDWR
); x
= dup(x
); x
= dup(x
);
826 pidfile
= fopen(pidfilename
, "w");
828 fprintf(pidfile
, "%d\n", (int)getpid());
833 syslog(LOG_ERR
, "fork: %m");
836 udscs_destroy_server(server
);
841 static void main_loop(void)
843 fd_set readfds
, writefds
;
852 nfds
= udscs_server_fill_fds(server
, &readfds
, &writefds
);
853 n
= vdagent_virtio_port_fill_fds(virtio_port
, &readfds
, &writefds
);
858 ck_fd
= session_info_get_fd(session_info
);
859 FD_SET(ck_fd
, &readfds
);
864 n
= select(nfds
, &readfds
, &writefds
, NULL
, NULL
);
868 syslog(LOG_CRIT
, "Fatal error select: %m");
873 udscs_server_handle_fds(server
, &readfds
, &writefds
);
877 vdagent_virtio_port_handle_fds(&virtio_port
, &readfds
, &writefds
);
879 int old_client_connected
= client_connected
;
881 "AIIEEE lost spice client connection, reconnecting");
882 virtio_port
= vdagent_virtio_port_create(portdev
,
883 virtio_port_read_complete
,
887 "Fatal error opening vdagent virtio channel");
891 do_client_disconnect();
892 client_connected
= old_client_connected
;
895 else if (only_once
&& once
)
897 syslog(LOG_INFO
, "Exiting after one client session.");
901 if (session_info
&& FD_ISSET(ck_fd
, &readfds
)) {
902 active_session
= session_info_get_active_session(session_info
);
903 update_active_session_connection(NULL
);
908 static void quit_handler(int sig
)
913 int main(int argc
, char *argv
[])
916 int do_daemonize
= 1;
917 int want_session_info
= 1;
918 struct sigaction act
;
921 if (-1 == (c
= getopt(argc
, argv
, "-dhxXfos:u:S:")))
931 vdagentd_socket
= optarg
;
934 uinput_device
= optarg
;
946 want_session_info
= 0;
958 memset(&act
, 0, sizeof(act
));
959 act
.sa_flags
= SA_RESTART
;
960 act
.sa_handler
= quit_handler
;
961 sigaction(SIGINT
, &act
, NULL
);
962 sigaction(SIGHUP
, &act
, NULL
);
963 sigaction(SIGTERM
, &act
, NULL
);
964 sigaction(SIGQUIT
, &act
, NULL
);
966 openlog("spice-vdagentd", do_daemonize
? 0 : LOG_PERROR
, LOG_USER
);
968 /* Setup communication with vdagent process(es) */
969 server
= udscs_create_server(vdagentd_socket
, agent_connect
,
970 agent_read_complete
, agent_disconnect
,
971 vdagentd_messages
, VDAGENTD_NO_MESSAGES
,
974 if (errno
== EADDRINUSE
) {
975 syslog(LOG_CRIT
, "Fatal the server socket %s exists already. Delete it?",
978 syslog(LOG_CRIT
, "Fatal could not create the server socket %s: %m",
983 if (chmod(vdagentd_socket
, 0666)) {
984 syslog(LOG_CRIT
, "Fatal could not change permissions on %s: %m",
986 udscs_destroy_server(server
);
993 #ifdef WITH_STATIC_UINPUT
994 uinput
= vdagentd_uinput_create(uinput_device
, 1024, 768, NULL
, 0,
995 debug
> 1, uinput_fake
);
997 udscs_destroy_server(server
);
1002 if (want_session_info
)
1003 session_info
= session_info_create(debug
);
1005 syslog(LOG_WARNING
, "no session info, max 1 session agent allowed");
1007 active_xfers
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
1010 release_clipboards();
1012 vdagentd_uinput_destroy(&uinput
);
1013 vdagent_virtio_port_flush(&virtio_port
);
1014 vdagent_virtio_port_destroy(&virtio_port
);
1015 session_info_destroy(session_info
);
1016 udscs_destroy_server(server
);
1017 if (unlink(vdagentd_socket
) != 0)
1018 syslog(LOG_ERR
, "unlink %s: %s", vdagentd_socket
, strerror(errno
));
1019 syslog(LOG_INFO
, "vdagentd quiting, returning status %d", retval
);
1022 unlink(pidfilename
);