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 /* To be used by vdagentd for failures in file-xfer such as when file-xfer was
253 * cancelled or an error happened */
254 static void send_file_xfer_status(struct vdagent_virtio_port
*vport
,
255 const char *msg
, uint32_t id
, uint32_t xfer_status
)
257 VDAgentFileXferStatusMessage status
= {
259 .result
= xfer_status
,
261 syslog(LOG_WARNING
, msg
, id
);
263 vdagent_virtio_port_write(vport
, VDP_CLIENT_PORT
,
264 VD_AGENT_FILE_XFER_STATUS
, 0,
265 (uint8_t *)&status
, sizeof(status
));
268 static void do_client_file_xfer(struct vdagent_virtio_port
*vport
,
269 VDAgentMessage
*message_header
,
272 uint32_t msg_type
, id
;
273 struct udscs_connection
*conn
;
275 switch (message_header
->type
) {
276 case VD_AGENT_FILE_XFER_START
: {
277 VDAgentFileXferStartMessage
*s
= (VDAgentFileXferStartMessage
*)data
;
278 if (!active_session_conn
) {
279 send_file_xfer_status(vport
,
280 "Could not find an agent connnection belonging to the "
281 "active session, cancelling client file-xfer request %u",
282 s
->id
, VD_AGENT_FILE_XFER_STATUS_CANCELLED
);
285 udscs_write(active_session_conn
, VDAGENTD_FILE_XFER_START
, 0, 0,
286 data
, message_header
->size
);
289 case VD_AGENT_FILE_XFER_STATUS
: {
290 VDAgentFileXferStatusMessage
*s
= (VDAgentFileXferStatusMessage
*)data
;
291 msg_type
= VDAGENTD_FILE_XFER_STATUS
;
295 case VD_AGENT_FILE_XFER_DATA
: {
296 VDAgentFileXferDataMessage
*d
= (VDAgentFileXferDataMessage
*)data
;
297 msg_type
= VDAGENTD_FILE_XFER_DATA
;
303 conn
= g_hash_table_lookup(active_xfers
, GUINT_TO_POINTER(id
));
306 syslog(LOG_DEBUG
, "Could not find file-xfer %u (cancelled?)", id
);
309 udscs_write(conn
, msg_type
, 0, 0, data
, message_header
->size
);
312 static int virtio_port_read_complete(
313 struct vdagent_virtio_port
*vport
,
315 VDAgentMessage
*message_header
,
318 uint32_t min_size
= 0;
320 if (message_header
->protocol
!= VD_AGENT_PROTOCOL
) {
321 syslog(LOG_ERR
, "message with wrong protocol version ignoring");
325 switch (message_header
->type
) {
326 case VD_AGENT_MOUSE_STATE
:
327 if (message_header
->size
!= sizeof(VDAgentMouseState
))
329 vdagentd_uinput_do_mouse(&uinput
, (VDAgentMouseState
*)data
);
331 /* Try to re-open the tablet */
332 struct agent_data
*agent_data
=
333 udscs_get_user_data(active_session_conn
);
335 uinput
= vdagentd_uinput_create(uinput_device
,
338 agent_data
->screen_info
,
339 agent_data
->screen_count
,
343 syslog(LOG_CRIT
, "Fatal uinput error");
349 case VD_AGENT_MONITORS_CONFIG
:
350 if (message_header
->size
< sizeof(VDAgentMonitorsConfig
))
352 do_client_monitors(vport
, port_nr
, message_header
,
353 (VDAgentMonitorsConfig
*)data
);
355 case VD_AGENT_ANNOUNCE_CAPABILITIES
:
356 if (message_header
->size
< sizeof(VDAgentAnnounceCapabilities
))
358 do_client_capabilities(vport
, message_header
,
359 (VDAgentAnnounceCapabilities
*)data
);
361 case VD_AGENT_CLIPBOARD_GRAB
:
362 case VD_AGENT_CLIPBOARD_REQUEST
:
363 case VD_AGENT_CLIPBOARD
:
364 case VD_AGENT_CLIPBOARD_RELEASE
:
365 switch (message_header
->type
) {
366 case VD_AGENT_CLIPBOARD_GRAB
:
367 min_size
= sizeof(VDAgentClipboardGrab
); break;
368 case VD_AGENT_CLIPBOARD_REQUEST
:
369 min_size
= sizeof(VDAgentClipboardRequest
); break;
370 case VD_AGENT_CLIPBOARD
:
371 min_size
= sizeof(VDAgentClipboard
); break;
373 if (VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
374 VD_AGENT_CAP_CLIPBOARD_SELECTION
)) {
377 if (message_header
->size
< min_size
) {
380 do_client_clipboard(vport
, message_header
, data
);
382 case VD_AGENT_FILE_XFER_START
:
383 case VD_AGENT_FILE_XFER_STATUS
:
384 case VD_AGENT_FILE_XFER_DATA
:
385 do_client_file_xfer(vport
, message_header
, data
);
387 case VD_AGENT_CLIENT_DISCONNECTED
:
388 vdagent_virtio_port_reset(vport
, VDP_CLIENT_PORT
);
389 do_client_disconnect();
391 case VD_AGENT_MAX_CLIPBOARD
:
392 if (message_header
->size
!= sizeof(VDAgentMaxClipboard
))
394 VDAgentMaxClipboard
*msg
= (VDAgentMaxClipboard
*)data
;
395 syslog(LOG_DEBUG
, "Set max clipboard: %d", msg
->max
);
396 max_clipboard
= msg
->max
;
398 case VD_AGENT_AUDIO_VOLUME_SYNC
:
399 if (message_header
->size
< sizeof(VDAgentAudioVolumeSync
))
402 do_client_volume_sync(vport
, port_nr
, message_header
,
403 (VDAgentAudioVolumeSync
*)data
);
406 syslog(LOG_WARNING
, "unknown message type %d, ignoring",
407 message_header
->type
);
413 syslog(LOG_ERR
, "read: invalid message size: %u for message type: %u",
414 message_header
->size
, message_header
->type
);
418 static void virtio_write_clipboard(uint8_t selection
, uint32_t msg_type
,
419 uint32_t data_type
, const uint8_t *data
, uint32_t data_size
)
421 uint32_t size
= data_size
;
423 if (VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
424 VD_AGENT_CAP_CLIPBOARD_SELECTION
)) {
427 if (data_type
!= -1) {
431 vdagent_virtio_port_write_start(virtio_port
, VDP_CLIENT_PORT
, msg_type
,
434 if (VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
435 VD_AGENT_CAP_CLIPBOARD_SELECTION
)) {
436 uint8_t sel
[4] = { selection
, 0, 0, 0 };
437 vdagent_virtio_port_write_append(virtio_port
, sel
, 4);
439 if (data_type
!= -1) {
440 vdagent_virtio_port_write_append(virtio_port
, (uint8_t*)&data_type
, 4);
443 vdagent_virtio_port_write_append(virtio_port
, data
, data_size
);
446 /* vdagentd <-> vdagent communication handling */
447 static int do_agent_clipboard(struct udscs_connection
*conn
,
448 struct udscs_message_header
*header
, const uint8_t *data
)
450 uint8_t selection
= header
->arg1
;
451 uint32_t msg_type
= 0, data_type
= -1, size
= header
->size
;
453 if (!VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
454 VD_AGENT_CAP_CLIPBOARD_BY_DEMAND
))
457 /* Check that this agent is from the currently active session */
458 if (conn
!= active_session_conn
) {
460 syslog(LOG_DEBUG
, "%p clipboard req from agent which is not in "
461 "the active session?", conn
);
466 syslog(LOG_ERR
, "Clipboard req from agent but no client connection");
470 if (!VD_AGENT_HAS_CAPABILITY(capabilities
, capabilities_size
,
471 VD_AGENT_CAP_CLIPBOARD_SELECTION
) &&
472 selection
!= VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD
) {
476 switch (header
->type
) {
477 case VDAGENTD_CLIPBOARD_GRAB
:
478 msg_type
= VD_AGENT_CLIPBOARD_GRAB
;
479 agent_owns_clipboard
[selection
] = 1;
481 case VDAGENTD_CLIPBOARD_REQUEST
:
482 msg_type
= VD_AGENT_CLIPBOARD_REQUEST
;
483 data_type
= header
->arg2
;
486 case VDAGENTD_CLIPBOARD_DATA
:
487 msg_type
= VD_AGENT_CLIPBOARD
;
488 data_type
= header
->arg2
;
489 if (max_clipboard
!= -1 && size
> max_clipboard
) {
490 syslog(LOG_WARNING
, "clipboard is too large (%d > %d), discarding",
491 size
, max_clipboard
);
492 virtio_write_clipboard(selection
, msg_type
, data_type
, NULL
, 0);
496 case VDAGENTD_CLIPBOARD_RELEASE
:
497 msg_type
= VD_AGENT_CLIPBOARD_RELEASE
;
499 agent_owns_clipboard
[selection
] = 0;
502 syslog(LOG_WARNING
, "unexpected clipboard message type");
506 if (size
!= header
->size
) {
508 "unexpected extra data in clipboard msg, disconnecting agent");
512 virtio_write_clipboard(selection
, msg_type
, data_type
, data
, header
->size
);
517 if (header
->type
== VDAGENTD_CLIPBOARD_REQUEST
) {
518 /* Let the agent know no answer is coming */
519 udscs_write(conn
, VDAGENTD_CLIPBOARD_DATA
,
520 selection
, VD_AGENT_CLIPBOARD_NONE
, NULL
, 0);
525 /* When we open the vdagent virtio channel, the server automatically goes into
526 client mouse mode, so we can only have the channel open when we know the
527 active session resolution. This function checks that we have an agent in the
528 active session, and that it has told us its resolution. If these conditions
529 are met it sets the uinput tablet device's resolution and opens the virtio
530 channel (if it is not already open). If these conditions are not met, it
532 static void check_xorg_resolution(void)
534 struct agent_data
*agent_data
= udscs_get_user_data(active_session_conn
);
536 if (agent_data
&& agent_data
->screen_info
) {
538 uinput
= vdagentd_uinput_create(uinput_device
,
541 agent_data
->screen_info
,
542 agent_data
->screen_count
,
546 vdagentd_uinput_update_size(&uinput
,
549 agent_data
->screen_info
,
550 agent_data
->screen_count
);
552 syslog(LOG_CRIT
, "Fatal uinput error");
559 syslog(LOG_INFO
, "opening vdagent virtio channel");
560 virtio_port
= vdagent_virtio_port_create(portdev
,
561 virtio_port_read_complete
,
564 syslog(LOG_CRIT
, "Fatal error opening vdagent virtio channel");
569 send_capabilities(virtio_port
, 1);
572 #ifndef WITH_STATIC_UINPUT
573 vdagentd_uinput_destroy(&uinput
);
576 vdagent_virtio_port_flush(&virtio_port
);
577 vdagent_virtio_port_destroy(&virtio_port
);
578 syslog(LOG_INFO
, "closed vdagent virtio channel");
583 static int connection_matches_active_session(struct udscs_connection
**connp
,
586 struct udscs_connection
**conn_ret
= (struct udscs_connection
**)priv
;
587 struct agent_data
*agent_data
= udscs_get_user_data(*connp
);
589 /* Check if this connection matches the currently active session */
590 if (!agent_data
->session
|| !active_session
)
592 if (strcmp(agent_data
->session
, active_session
))
599 static void release_clipboards(void)
603 for (sel
= 0; sel
< VD_AGENT_CLIPBOARD_SELECTION_SECONDARY
; ++sel
) {
604 if (agent_owns_clipboard
[sel
] && virtio_port
) {
605 vdagent_virtio_port_write(virtio_port
, VDP_CLIENT_PORT
,
606 VD_AGENT_CLIPBOARD_RELEASE
, 0, &sel
, 1);
608 agent_owns_clipboard
[sel
] = 0;
612 static void update_active_session_connection(struct udscs_connection
*new_conn
)
617 active_session
= session_info_get_active_session(session_info
);
618 session_count
= udscs_server_for_all_clients(server
,
619 connection_matches_active_session
,
628 if (new_conn
&& session_count
!= 1) {
629 syslog(LOG_ERR
, "multiple agents in one session, "
630 "disabling agent to avoid potential information leak");
634 if (new_conn
== active_session_conn
)
637 active_session_conn
= new_conn
;
639 syslog(LOG_DEBUG
, "%p is now the active session", new_conn
);
640 if (active_session_conn
&& mon_config
)
641 udscs_write(active_session_conn
, VDAGENTD_MONITORS_CONFIG
, 0, 0,
642 (uint8_t *)mon_config
, sizeof(VDAgentMonitorsConfig
) +
643 mon_config
->num_of_monitors
* sizeof(VDAgentMonConfig
));
645 release_clipboards();
647 check_xorg_resolution();
650 static gboolean
remove_active_xfers(gpointer key
, gpointer value
, gpointer conn
)
653 send_file_xfer_status(virtio_port
,
654 "Agent disc; cancelling file-xfer %u",
655 GPOINTER_TO_UINT(key
),
656 VD_AGENT_FILE_XFER_STATUS_CANCELLED
);
662 static void agent_connect(struct udscs_connection
*conn
)
664 struct agent_data
*agent_data
;
666 agent_data
= calloc(1, sizeof(*agent_data
));
668 syslog(LOG_ERR
, "Out of memory allocating agent data, disconnecting");
669 udscs_destroy_connection(&conn
);
674 uint32_t pid
= udscs_get_peer_cred(conn
).pid
;
675 agent_data
->session
= session_info_session_for_pid(session_info
, pid
);
678 udscs_set_user_data(conn
, (void *)agent_data
);
679 udscs_write(conn
, VDAGENTD_VERSION
, 0, 0,
680 (uint8_t *)VERSION
, strlen(VERSION
) + 1);
681 update_active_session_connection(conn
);
684 static void agent_disconnect(struct udscs_connection
*conn
)
686 struct agent_data
*agent_data
= udscs_get_user_data(conn
);
688 g_hash_table_foreach_remove(active_xfers
, remove_active_xfers
, conn
);
690 free(agent_data
->session
);
691 agent_data
->session
= NULL
;
692 update_active_session_connection(NULL
);
694 free(agent_data
->screen_info
);
698 static void agent_read_complete(struct udscs_connection
**connp
,
699 struct udscs_message_header
*header
, uint8_t *data
)
701 struct agent_data
*agent_data
= udscs_get_user_data(*connp
);
703 switch (header
->type
) {
704 case VDAGENTD_GUEST_XORG_RESOLUTION
: {
705 struct vdagentd_guest_xorg_resolution
*res
;
706 int n
= header
->size
/ sizeof(*res
);
708 /* Detect older version session agent, but don't disconnect, as
709 that stops it from getting the VDAGENTD_VERSION message, and then
710 it will never re-exec the new version... */
711 if (header
->arg1
== 0 && header
->arg2
== 0) {
712 syslog(LOG_INFO
, "got old session agent xorg resolution message, "
718 if (header
->size
!= n
* sizeof(*res
)) {
719 syslog(LOG_ERR
, "guest xorg resolution message has wrong size, "
720 "disconnecting agent");
721 udscs_destroy_connection(connp
);
726 free(agent_data
->screen_info
);
727 res
= malloc(n
* sizeof(*res
));
729 syslog(LOG_ERR
, "out of memory allocating screen info");
732 memcpy(res
, data
, n
* sizeof(*res
));
733 agent_data
->width
= header
->arg1
;
734 agent_data
->height
= header
->arg2
;
735 agent_data
->screen_info
= res
;
736 agent_data
->screen_count
= n
;
738 check_xorg_resolution();
741 case VDAGENTD_CLIPBOARD_GRAB
:
742 case VDAGENTD_CLIPBOARD_REQUEST
:
743 case VDAGENTD_CLIPBOARD_DATA
:
744 case VDAGENTD_CLIPBOARD_RELEASE
:
745 if (do_agent_clipboard(*connp
, header
, data
)) {
746 udscs_destroy_connection(connp
);
751 case VDAGENTD_FILE_XFER_STATUS
:{
752 VDAgentFileXferStatusMessage status
;
753 status
.id
= header
->arg1
;
754 status
.result
= header
->arg2
;
755 vdagent_virtio_port_write(virtio_port
, VDP_CLIENT_PORT
,
756 VD_AGENT_FILE_XFER_STATUS
, 0,
757 (uint8_t *)&status
, sizeof(status
));
758 if (status
.result
== VD_AGENT_FILE_XFER_STATUS_CAN_SEND_DATA
)
759 g_hash_table_insert(active_xfers
, GUINT_TO_POINTER(status
.id
),
762 g_hash_table_remove(active_xfers
, GUINT_TO_POINTER(status
.id
));
767 syslog(LOG_ERR
, "unknown message from vdagent: %u, ignoring",
775 static void usage(FILE *fp
)
778 "Usage: spice-vdagentd [OPTIONS]\n\n"
779 "Spice guest agent daemon, version %s.\n\n"
781 " -h print this text\n"
782 " -d log debug messages (use twice for extra info)\n"
783 " -s <port> set virtio serial port [%s]\n"
784 " -S <filename> set udcs socket [%s]\n"
785 " -u <dev> set uinput device [%s]\n"
786 " -f treat uinput device as fake; no ioctls\n"
787 " -x don't daemonize\n"
788 " -o Only handle one virtio serial session.\n"
789 #ifdef HAVE_CONSOLE_KIT
790 " -X Disable console kit integration\n"
792 #ifdef HAVE_LIBSYSTEMD_LOGIN
793 " -X Disable systemd-logind integration\n"
795 ,VERSION
, portdev
, vdagentd_socket
, uinput_device
);
798 static void daemonize(void)
803 /* detach from terminal */
806 close(0); close(1); close(2);
808 x
= open("/dev/null", O_RDWR
); x
= dup(x
); x
= dup(x
);
809 pidfile
= fopen(pidfilename
, "w");
811 fprintf(pidfile
, "%d\n", (int)getpid());
816 syslog(LOG_ERR
, "fork: %m");
819 udscs_destroy_server(server
);
824 static void main_loop(void)
826 fd_set readfds
, writefds
;
835 nfds
= udscs_server_fill_fds(server
, &readfds
, &writefds
);
836 n
= vdagent_virtio_port_fill_fds(virtio_port
, &readfds
, &writefds
);
841 ck_fd
= session_info_get_fd(session_info
);
842 FD_SET(ck_fd
, &readfds
);
847 n
= select(nfds
, &readfds
, &writefds
, NULL
, NULL
);
851 syslog(LOG_CRIT
, "Fatal error select: %m");
856 udscs_server_handle_fds(server
, &readfds
, &writefds
);
860 vdagent_virtio_port_handle_fds(&virtio_port
, &readfds
, &writefds
);
862 int old_client_connected
= client_connected
;
864 "AIIEEE lost spice client connection, reconnecting");
865 virtio_port
= vdagent_virtio_port_create(portdev
,
866 virtio_port_read_complete
,
870 "Fatal error opening vdagent virtio channel");
874 do_client_disconnect();
875 client_connected
= old_client_connected
;
878 else if (only_once
&& once
)
880 syslog(LOG_INFO
, "Exiting after one client session.");
884 if (session_info
&& FD_ISSET(ck_fd
, &readfds
)) {
885 active_session
= session_info_get_active_session(session_info
);
886 update_active_session_connection(NULL
);
891 static void quit_handler(int sig
)
896 int main(int argc
, char *argv
[])
899 int do_daemonize
= 1;
900 int want_session_info
= 1;
901 struct sigaction act
;
904 if (-1 == (c
= getopt(argc
, argv
, "-dhxXfos:u:S:")))
914 vdagentd_socket
= optarg
;
917 uinput_device
= optarg
;
929 want_session_info
= 0;
941 memset(&act
, 0, sizeof(act
));
942 act
.sa_flags
= SA_RESTART
;
943 act
.sa_handler
= quit_handler
;
944 sigaction(SIGINT
, &act
, NULL
);
945 sigaction(SIGHUP
, &act
, NULL
);
946 sigaction(SIGTERM
, &act
, NULL
);
947 sigaction(SIGQUIT
, &act
, NULL
);
949 openlog("spice-vdagentd", do_daemonize
? 0 : LOG_PERROR
, LOG_USER
);
951 /* Setup communication with vdagent process(es) */
952 server
= udscs_create_server(vdagentd_socket
, agent_connect
,
953 agent_read_complete
, agent_disconnect
,
954 vdagentd_messages
, VDAGENTD_NO_MESSAGES
,
957 syslog(LOG_CRIT
, "Fatal could not create server socket %s",
961 if (chmod(vdagentd_socket
, 0666)) {
962 syslog(LOG_CRIT
, "Fatal could not change permissions on %s: %m",
964 udscs_destroy_server(server
);
971 #ifdef WITH_STATIC_UINPUT
972 uinput
= vdagentd_uinput_create(uinput_device
, 1024, 768, NULL
, 0,
973 debug
> 1, uinput_fake
);
975 udscs_destroy_server(server
);
980 if (want_session_info
)
981 session_info
= session_info_create(debug
);
983 syslog(LOG_WARNING
, "no session info, max 1 session agent allowed");
985 active_xfers
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
988 release_clipboards();
990 vdagentd_uinput_destroy(&uinput
);
991 vdagent_virtio_port_flush(&virtio_port
);
992 vdagent_virtio_port_destroy(&virtio_port
);
993 session_info_destroy(session_info
);
994 udscs_destroy_server(server
);
995 if (unlink(vdagentd_socket
) != 0)
996 syslog(LOG_ERR
, "unlink %s: %s", vdagentd_socket
, strerror(errno
));
997 syslog(LOG_INFO
, "vdagentd quiting, returning status %d", retval
);
1000 unlink(pidfilename
);