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 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 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 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 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 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 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 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
);
693 void agent_read_complete(struct udscs_connection
**connp
,
694 struct udscs_message_header
*header
, uint8_t *data
)
696 struct agent_data
*agent_data
= udscs_get_user_data(*connp
);
698 switch (header
->type
) {
699 case VDAGENTD_GUEST_XORG_RESOLUTION
: {
700 struct vdagentd_guest_xorg_resolution
*res
;
701 int n
= header
->size
/ sizeof(*res
);
703 /* Detect older version session agent, but don't disconnect, as
704 that stops it from getting the VDAGENTD_VERSION message, and then
705 it will never re-exec the new version... */
706 if (header
->arg1
== 0 && header
->arg2
== 0) {
707 syslog(LOG_INFO
, "got old session agent xorg resolution message, "
713 if (header
->size
!= n
* sizeof(*res
)) {
714 syslog(LOG_ERR
, "guest xorg resolution message has wrong size, "
715 "disconnecting agent");
716 udscs_destroy_connection(connp
);
721 free(agent_data
->screen_info
);
722 res
= malloc(n
* sizeof(*res
));
724 syslog(LOG_ERR
, "out of memory allocating screen info");
727 memcpy(res
, data
, n
* sizeof(*res
));
728 agent_data
->width
= header
->arg1
;
729 agent_data
->height
= header
->arg2
;
730 agent_data
->screen_info
= res
;
731 agent_data
->screen_count
= n
;
733 check_xorg_resolution();
736 case VDAGENTD_CLIPBOARD_GRAB
:
737 case VDAGENTD_CLIPBOARD_REQUEST
:
738 case VDAGENTD_CLIPBOARD_DATA
:
739 case VDAGENTD_CLIPBOARD_RELEASE
:
740 if (do_agent_clipboard(*connp
, header
, data
)) {
741 udscs_destroy_connection(connp
);
746 case VDAGENTD_FILE_XFER_STATUS
:{
747 VDAgentFileXferStatusMessage status
;
748 status
.id
= header
->arg1
;
749 status
.result
= header
->arg2
;
750 vdagent_virtio_port_write(virtio_port
, VDP_CLIENT_PORT
,
751 VD_AGENT_FILE_XFER_STATUS
, 0,
752 (uint8_t *)&status
, sizeof(status
));
753 if (status
.result
== VD_AGENT_FILE_XFER_STATUS_CAN_SEND_DATA
)
754 g_hash_table_insert(active_xfers
, GUINT_TO_POINTER(status
.id
),
757 g_hash_table_remove(active_xfers
, GUINT_TO_POINTER(status
.id
));
762 syslog(LOG_ERR
, "unknown message from vdagent: %u, ignoring",
770 static void usage(FILE *fp
)
773 "Usage: spice-vdagentd [OPTIONS]\n\n"
774 "Spice guest agent daemon, version %s.\n\n"
776 " -h print this text\n"
777 " -d log debug messages (use twice for extra info)\n"
778 " -s <port> set virtio serial port [%s]\n"
779 " -S <filename> set udcs socket [%s]\n"
780 " -u <dev> set uinput device [%s]\n"
781 " -f treat uinput device as fake; no ioctls\n"
782 " -x don't daemonize\n"
783 " -o Only handle one virtio serial session.\n"
784 #ifdef HAVE_CONSOLE_KIT
785 " -X Disable console kit integration\n"
787 #ifdef HAVE_LIBSYSTEMD_LOGIN
788 " -X Disable systemd-logind integration\n"
790 ,VERSION
, portdev
, vdagentd_socket
, uinput_device
);
798 /* detach from terminal */
801 close(0); close(1); close(2);
803 x
= open("/dev/null", O_RDWR
); x
= dup(x
); x
= dup(x
);
804 pidfile
= fopen(pidfilename
, "w");
806 fprintf(pidfile
, "%d\n", (int)getpid());
811 syslog(LOG_ERR
, "fork: %m");
814 udscs_destroy_server(server
);
821 fd_set readfds
, writefds
;
830 nfds
= udscs_server_fill_fds(server
, &readfds
, &writefds
);
831 n
= vdagent_virtio_port_fill_fds(virtio_port
, &readfds
, &writefds
);
836 ck_fd
= session_info_get_fd(session_info
);
837 FD_SET(ck_fd
, &readfds
);
842 n
= select(nfds
, &readfds
, &writefds
, NULL
, NULL
);
846 syslog(LOG_CRIT
, "Fatal error select: %m");
851 udscs_server_handle_fds(server
, &readfds
, &writefds
);
855 vdagent_virtio_port_handle_fds(&virtio_port
, &readfds
, &writefds
);
857 int old_client_connected
= client_connected
;
859 "AIIEEE lost spice client connection, reconnecting");
860 virtio_port
= vdagent_virtio_port_create(portdev
,
861 virtio_port_read_complete
,
865 "Fatal error opening vdagent virtio channel");
869 do_client_disconnect();
870 client_connected
= old_client_connected
;
873 else if (only_once
&& once
)
875 syslog(LOG_INFO
, "Exiting after one client session.");
879 if (session_info
&& FD_ISSET(ck_fd
, &readfds
)) {
880 active_session
= session_info_get_active_session(session_info
);
881 update_active_session_connection(NULL
);
886 static void quit_handler(int sig
)
891 int main(int argc
, char *argv
[])
894 int do_daemonize
= 1;
895 int want_session_info
= 1;
896 struct sigaction act
;
899 if (-1 == (c
= getopt(argc
, argv
, "-dhxXfos:u:S:")))
909 vdagentd_socket
= optarg
;
912 uinput_device
= optarg
;
924 want_session_info
= 0;
936 memset(&act
, 0, sizeof(act
));
937 act
.sa_flags
= SA_RESTART
;
938 act
.sa_handler
= quit_handler
;
939 sigaction(SIGINT
, &act
, NULL
);
940 sigaction(SIGHUP
, &act
, NULL
);
941 sigaction(SIGTERM
, &act
, NULL
);
942 sigaction(SIGQUIT
, &act
, NULL
);
944 openlog("spice-vdagentd", do_daemonize
? 0 : LOG_PERROR
, LOG_USER
);
946 /* Setup communication with vdagent process(es) */
947 server
= udscs_create_server(vdagentd_socket
, agent_connect
,
948 agent_read_complete
, agent_disconnect
,
949 vdagentd_messages
, VDAGENTD_NO_MESSAGES
,
952 syslog(LOG_CRIT
, "Fatal could not create server socket %s",
956 if (chmod(vdagentd_socket
, 0666)) {
957 syslog(LOG_CRIT
, "Fatal could not change permissions on %s: %m",
959 udscs_destroy_server(server
);
966 #ifdef WITH_STATIC_UINPUT
967 uinput
= vdagentd_uinput_create(uinput_device
, 1024, 768, NULL
, 0,
968 debug
> 1, uinput_fake
);
970 udscs_destroy_server(server
);
975 if (want_session_info
)
976 session_info
= session_info_create(debug
);
978 syslog(LOG_WARNING
, "no session info, max 1 session agent allowed");
980 active_xfers
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
983 release_clipboards();
985 vdagentd_uinput_destroy(&uinput
);
986 vdagent_virtio_port_flush(&virtio_port
);
987 vdagent_virtio_port_destroy(&virtio_port
);
988 session_info_destroy(session_info
);
989 udscs_destroy_server(server
);
990 if (unlink(vdagentd_socket
) != 0)
991 syslog(LOG_ERR
, "unlink %s: %s", vdagentd_socket
, strerror(errno
));
992 syslog(LOG_INFO
, "vdagentd quiting, returning status %d", retval
);