Fix various compiler warnings
[vd_agent/hramrach.git] / src / vdagentd.c
blob3419601cbc57f989c5becb1148d79f29178622df
1 /* vdagentd.c vdagentd (daemon) code
3 Copyright 2010 Red Hat, Inc.
5 Red Hat Authors:
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/>.
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <signal.h>
33 #include <sys/select.h>
34 #include <sys/stat.h>
35 #include <spice/vd_agent.h>
37 #include "udscs.h"
38 #include "vdagentd-proto.h"
39 #include "vdagentd-proto-strings.h"
40 #include "vdagentd-uinput.h"
41 #include "vdagentd-xorg-conf.h"
42 #include "vdagent-virtio-port.h"
43 #include "console-kit.h"
45 struct agent_data {
46 char *session;
47 int width;
48 int height;
49 struct vdagentd_guest_xorg_resolution *screen_info;
50 int screen_count;
53 /* variables */
54 static const char *logfilename = "/var/log/spice-vdagentd/spice-vdagentd.log";
55 static const char *pidfilename = "/var/run/spice-vdagentd/spice-vdagentd.pid";
56 static const char *portdev = "/dev/virtio-ports/com.redhat.spice.0";
57 static const char *uinput_device = "/dev/uinput";
58 static int debug = 0;
59 static struct udscs_server *server = NULL;
60 static struct vdagent_virtio_port *virtio_port = NULL;
61 #ifdef HAVE_CONSOLE_KIT
62 static struct console_kit *console_kit = NULL;
63 #endif
64 static struct vdagentd_uinput *uinput = NULL;
65 static VDAgentMonitorsConfig *mon_config = NULL;
66 static uint32_t *capabilities = NULL;
67 static int capabilities_size = 0;
68 #ifdef HAVE_CONSOLE_KIT
69 static const char *active_session = NULL;
70 #else
71 static unsigned int session_count = 0;
72 #endif
73 static struct udscs_connection *active_session_conn = NULL;
74 static int agent_owns_clipboard[256] = { 0, };
75 static FILE *logfile = NULL;
76 static int quit = 0;
77 static int retval = 0;
79 /* utility functions */
80 /* vdagentd <-> spice-client communication handling */
81 static void send_capabilities(struct vdagent_virtio_port *vport,
82 uint32_t request)
84 VDAgentAnnounceCapabilities *caps;
85 uint32_t size;
87 size = sizeof(*caps) + VD_AGENT_CAPS_BYTES;
88 caps = calloc(1, size);
89 if (!caps) {
90 fprintf(logfile,
91 "out of memory allocating capabilities array (write)\n");
92 return;
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);
102 vdagent_virtio_port_write(vport, VDP_CLIENT_PORT,
103 VD_AGENT_ANNOUNCE_CAPABILITIES, 0,
104 (uint8_t *)caps, size);
105 free(caps);
108 static void do_client_monitors(struct vdagent_virtio_port *vport, int port_nr,
109 VDAgentMessage *message_header, VDAgentMonitorsConfig *new_monitors)
111 VDAgentReply reply;
112 uint32_t size;
114 /* Store monitor config to send to agents when they connect */
115 size = sizeof(VDAgentMonitorsConfig) +
116 new_monitors->num_of_monitors * sizeof(VDAgentMonConfig);
117 if (message_header->size != size) {
118 fprintf(logfile, "invalid message size for VDAgentMonitorsConfig\n");
119 return;
122 vdagentd_write_xorg_conf(new_monitors, logfile);
124 if (new_monitors->num_of_monitors != 1) {
125 /* No use in sending this to the session agent it cannot handle it
126 anyways */
127 free(mon_config);
128 mon_config = NULL;
129 goto ack;
132 if (!mon_config ||
133 mon_config->num_of_monitors != new_monitors->num_of_monitors) {
134 free(mon_config);
135 mon_config = malloc(size);
136 if (!mon_config) {
137 fprintf(logfile, "out of memory allocating monitors config\n");
138 return;
141 memcpy(mon_config, new_monitors, size);
143 /* Send monitor config to currently connected agents */
144 udscs_server_write_all(server, VDAGENTD_MONITORS_CONFIG, 0, 0,
145 (uint8_t *)mon_config, size);
147 ack:
148 /* Acknowledge reception of monitors config to spice server / client */
149 reply.type = VD_AGENT_MONITORS_CONFIG;
150 reply.error = VD_AGENT_SUCCESS;
151 vdagent_virtio_port_write(vport, port_nr, VD_AGENT_REPLY, 0,
152 (uint8_t *)&reply, sizeof(reply));
155 static void do_client_capabilities(struct vdagent_virtio_port *vport,
156 VDAgentMessage *message_header,
157 VDAgentAnnounceCapabilities *caps)
159 int new_size = VD_AGENT_CAPS_SIZE_FROM_MSG_SIZE(message_header->size);
161 if (capabilities_size != new_size) {
162 capabilities_size = new_size;
163 free(capabilities);
164 capabilities = malloc(capabilities_size * sizeof(uint32_t));
165 if (!capabilities) {
166 fprintf(logfile,
167 "out of memory allocating capabilities array (read)\n");
168 capabilities_size = 0;
169 return;
172 memcpy(capabilities, caps->caps, capabilities_size * sizeof(uint32_t));
173 if (caps->request)
174 send_capabilities(vport, 0);
177 static void do_client_clipboard(struct vdagent_virtio_port *vport,
178 VDAgentMessage *message_header, uint8_t *data)
180 uint32_t msg_type = 0, data_type = 0, size = message_header->size;
181 uint8_t selection = VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD;
183 if (!active_session_conn) {
184 fprintf(logfile,
185 "Could not find an agent connnection belonging to the "
186 "active session, ignoring client clipboard request\n");
187 return;
190 if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
191 VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
192 selection = data[0];
193 data += 4;
194 size -= 4;
197 switch (message_header->type) {
198 case VD_AGENT_CLIPBOARD_GRAB:
199 msg_type = VDAGENTD_CLIPBOARD_GRAB;
200 agent_owns_clipboard[selection] = 0;
201 break;
202 case VD_AGENT_CLIPBOARD_REQUEST: {
203 VDAgentClipboardRequest *req = (VDAgentClipboardRequest *)data;
204 msg_type = VDAGENTD_CLIPBOARD_REQUEST;
205 data_type = req->type;
206 data = NULL;
207 size = 0;
208 break;
210 case VD_AGENT_CLIPBOARD: {
211 VDAgentClipboard *clipboard = (VDAgentClipboard *)data;
212 msg_type = VDAGENTD_CLIPBOARD_DATA;
213 data_type = clipboard->type;
214 size = size - sizeof(VDAgentClipboard);
215 data = clipboard->data;
216 break;
218 case VD_AGENT_CLIPBOARD_RELEASE:
219 msg_type = VDAGENTD_CLIPBOARD_RELEASE;
220 data = NULL;
221 size = 0;
222 break;
225 udscs_write(active_session_conn, msg_type, selection, data_type,
226 data, size);
229 int virtio_port_read_complete(
230 struct vdagent_virtio_port *vport,
231 int port_nr,
232 VDAgentMessage *message_header,
233 uint8_t *data)
235 uint32_t min_size = 0;
237 if (message_header->protocol != VD_AGENT_PROTOCOL) {
238 fprintf(logfile, "message with wrong protocol version ignoring\n");
239 return 0;
242 switch (message_header->type) {
243 case VD_AGENT_MOUSE_STATE:
244 if (message_header->size != sizeof(VDAgentMouseState))
245 goto size_error;
246 vdagentd_uinput_do_mouse(&uinput, (VDAgentMouseState *)data);
247 if (!uinput) {
248 /* Try to re-open the tablet */
249 struct agent_data *agent_data =
250 udscs_get_user_data(active_session_conn);
251 if (agent_data)
252 uinput = vdagentd_uinput_create(uinput_device,
253 agent_data->width,
254 agent_data->height,
255 agent_data->screen_info,
256 agent_data->screen_count,
257 logfile, debug > 1);
258 if (!uinput) {
259 fprintf(logfile, "Fatal uinput error\n");
260 retval = 1;
261 quit = 1;
264 break;
265 case VD_AGENT_MONITORS_CONFIG:
266 if (message_header->size < sizeof(VDAgentMonitorsConfig))
267 goto size_error;
268 do_client_monitors(vport, port_nr, message_header,
269 (VDAgentMonitorsConfig *)data);
270 break;
271 case VD_AGENT_ANNOUNCE_CAPABILITIES:
272 if (message_header->size < sizeof(VDAgentAnnounceCapabilities))
273 goto size_error;
274 do_client_capabilities(vport, message_header,
275 (VDAgentAnnounceCapabilities *)data);
276 break;
277 case VD_AGENT_CLIPBOARD_GRAB:
278 case VD_AGENT_CLIPBOARD_REQUEST:
279 case VD_AGENT_CLIPBOARD:
280 case VD_AGENT_CLIPBOARD_RELEASE:
281 switch (message_header->type) {
282 case VD_AGENT_CLIPBOARD_GRAB:
283 min_size = sizeof(VDAgentClipboardGrab); break;
284 case VD_AGENT_CLIPBOARD_REQUEST:
285 min_size = sizeof(VDAgentClipboardRequest); break;
286 case VD_AGENT_CLIPBOARD:
287 min_size = sizeof(VDAgentClipboard); break;
289 if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
290 VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
291 min_size += 4;
293 if (message_header->size < min_size) {
294 goto size_error;
296 do_client_clipboard(vport, message_header, data);
297 break;
298 default:
299 if (debug)
300 fprintf(logfile, "unknown message type %d\n", message_header->type);
301 break;
304 return 0;
306 size_error:
307 fprintf(logfile, "read: invalid message size: %u for message type: %u\n",
308 message_header->size, message_header->type);
309 return 0;
312 /* vdagentd <-> vdagent communication handling */
313 int do_agent_clipboard(struct udscs_connection *conn,
314 struct udscs_message_header *header, const uint8_t *data)
316 uint8_t selection = header->arg1;
317 uint32_t msg_type = 0, data_type = -1, size = header->size;
319 if (!VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
320 VD_AGENT_CAP_CLIPBOARD_BY_DEMAND))
321 goto error;
323 /* Check that this agent is from the currently active session */
324 if (conn != active_session_conn) {
325 fprintf(logfile, "Clipboard request from agent "
326 "which is not in the active session?\n");
327 goto error;
330 if (!virtio_port) {
331 fprintf(logfile,
332 "Clipboard request from agent but no client connection\n");
333 goto error;
336 if (!VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
337 VD_AGENT_CAP_CLIPBOARD_SELECTION) &&
338 selection != VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD) {
339 goto error;
342 switch (header->type) {
343 case VDAGENTD_CLIPBOARD_GRAB:
344 msg_type = VD_AGENT_CLIPBOARD_GRAB;
345 agent_owns_clipboard[selection] = 1;
346 break;
347 case VDAGENTD_CLIPBOARD_REQUEST:
348 msg_type = VD_AGENT_CLIPBOARD_REQUEST;
349 data_type = header->arg2;
350 size = 0;
351 break;
352 case VDAGENTD_CLIPBOARD_DATA:
353 msg_type = VD_AGENT_CLIPBOARD;
354 data_type = header->arg2;
355 break;
356 case VDAGENTD_CLIPBOARD_RELEASE:
357 msg_type = VD_AGENT_CLIPBOARD_RELEASE;
358 size = 0;
359 agent_owns_clipboard[selection] = 0;
360 break;
363 if (size != header->size) {
364 fprintf(logfile,
365 "unexpected extra data in clipboard msg, disconnecting agent\n");
366 return -1;
369 if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
370 VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
371 size += 4;
373 if (data_type != -1) {
374 size += 4;
377 vdagent_virtio_port_write_start(virtio_port, VDP_CLIENT_PORT, msg_type,
378 0, size);
380 if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
381 VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
382 uint8_t sel[4] = { selection, 0, 0, 0 };
383 vdagent_virtio_port_write_append(virtio_port, sel, 4);
385 if (data_type != -1) {
386 vdagent_virtio_port_write_append(virtio_port, (uint8_t*)&data_type, 4);
389 vdagent_virtio_port_write_append(virtio_port, data, header->size);
391 return 0;
393 error:
394 if (header->type == VDAGENTD_CLIPBOARD_REQUEST) {
395 /* Let the agent know no answer is coming */
396 udscs_write(conn, VDAGENTD_CLIPBOARD_DATA,
397 selection, VD_AGENT_CLIPBOARD_NONE, NULL, 0);
399 return 0;
402 /* When we open the vdagent virtio channel, the server automatically goes into
403 client mouse mode, so we can only have the channel open when we know the
404 active session resolution. This function checks that we have an agent in the
405 active session, and that it has told us its resolution. If these conditions
406 are met it sets the uinput tablet device's resolution and opens the virtio
407 channel (if it is not already open). If these conditions are not met, it
408 closes both. */
409 static void check_xorg_resolution(void)
411 struct agent_data *agent_data = udscs_get_user_data(active_session_conn);
413 if (agent_data && agent_data->screen_info) {
414 if (!uinput)
415 uinput = vdagentd_uinput_create(uinput_device,
416 agent_data->width,
417 agent_data->height,
418 agent_data->screen_info,
419 agent_data->screen_count,
420 logfile, debug > 1);
421 else
422 vdagentd_uinput_update_size(&uinput,
423 agent_data->width,
424 agent_data->height,
425 agent_data->screen_info,
426 agent_data->screen_count);
427 if (!uinput) {
428 fprintf(logfile, "Fatal uinput error\n");
429 retval = 1;
430 quit = 1;
431 return;
434 if (!virtio_port) {
435 fprintf(logfile, "opening vdagent virtio channel\n");
436 virtio_port = vdagent_virtio_port_create(portdev,
437 virtio_port_read_complete,
438 NULL, logfile);
439 if (!virtio_port) {
440 fprintf(logfile,
441 "Fatal error opening vdagent virtio channel\n");
442 retval = 1;
443 quit = 1;
444 return;
446 send_capabilities(virtio_port, 1);
448 } else {
449 vdagentd_uinput_destroy(&uinput);
450 if (virtio_port) {
451 vdagent_virtio_port_flush(&virtio_port);
452 vdagent_virtio_port_destroy(&virtio_port);
453 fprintf(logfile, "closed vdagent virtio channel\n");
458 #ifdef HAVE_CONSOLE_KIT
459 static int connection_matches_active_session(struct udscs_connection **connp,
460 void *priv)
462 struct udscs_connection **conn_ret = (struct udscs_connection **)priv;
463 struct agent_data *agent_data = udscs_get_user_data(*connp);
465 /* Check if this connection matches the currently active session */
466 if (!agent_data->session || !active_session)
467 return 0;
468 if (strcmp(agent_data->session, active_session))
469 return 0;
471 *conn_ret = *connp;
472 return 1;
474 #endif
476 void release_clipboards(void)
478 uint8_t sel;
480 for (sel = 0; sel < VD_AGENT_CLIPBOARD_SELECTION_SECONDARY; ++sel) {
481 if (agent_owns_clipboard[sel] && virtio_port) {
482 vdagent_virtio_port_write(virtio_port, VDP_CLIENT_PORT,
483 VD_AGENT_CLIPBOARD_RELEASE, 0, &sel, 1);
485 agent_owns_clipboard[sel] = 0;
489 void update_active_session_connection(void)
491 struct udscs_connection *new_conn = NULL;
492 int n;
494 #ifdef HAVE_CONSOLE_KIT
495 if (!active_session)
496 active_session = console_kit_get_active_session(console_kit);
498 n = udscs_server_for_all_clients(server, connection_matches_active_session,
499 (void*)&new_conn);
500 if (n != 1)
501 new_conn = NULL;
503 if (new_conn == active_session_conn)
504 return;
506 active_session_conn = new_conn;
507 #endif
509 release_clipboards();
511 check_xorg_resolution();
514 void agent_connect(struct udscs_connection *conn)
516 uint32_t pid;
517 struct agent_data *agent_data;
519 agent_data = calloc(1, sizeof(*agent_data));
520 if (!agent_data) {
521 fprintf(logfile, "Out of memory allocating agent data, disconnecting\n");
522 udscs_destroy_connection(&conn);
523 return;
525 #ifdef HAVE_CONSOLE_KIT
526 pid = udscs_get_peer_cred(conn).pid;
527 agent_data->session = console_kit_session_for_pid(console_kit, pid);
528 #else
529 session_count++;
530 if (session_count == 1) {
531 active_session_conn = conn;
532 } else {
533 /* disable communication with agents when we've got multiple
534 * connections to the vdagentd and no consolekit since we can't
535 * know to which one we should send data
537 fprintf(logfile, "Trying to use multiple vdagent without ConsoleKit support, "
538 "disabling vdagent to avoid potential information leak\n");
539 active_session_conn = NULL;
541 #endif
543 udscs_set_user_data(conn, (void *)agent_data);
544 update_active_session_connection();
546 udscs_write(conn, VDAGENTD_VERSION, 0, 0,
547 (uint8_t *)VERSION, strlen(VERSION) + 1);
549 if (mon_config)
550 udscs_write(conn, VDAGENTD_MONITORS_CONFIG, 0, 0,
551 (uint8_t *)mon_config, sizeof(VDAgentMonitorsConfig) +
552 mon_config->num_of_monitors * sizeof(VDAgentMonConfig));
555 void agent_disconnect(struct udscs_connection *conn)
557 struct agent_data *agent_data = udscs_get_user_data(conn);
559 free(agent_data->session);
560 agent_data->session = NULL;
561 update_active_session_connection();
563 free(agent_data);
564 #ifndef HAVE_CONSOLE_KIT
565 session_count--;
566 #endif
569 void agent_read_complete(struct udscs_connection **connp,
570 struct udscs_message_header *header, uint8_t *data)
572 struct agent_data *agent_data = udscs_get_user_data(*connp);
574 switch (header->type) {
575 case VDAGENTD_GUEST_XORG_RESOLUTION: {
576 struct vdagentd_guest_xorg_resolution *res;
577 int n = header->size / sizeof(*res);
579 /* Detect older version session agent, but don't disconnect, as
580 that stops it from getting the VDAGENTD_VERSION message, and then
581 it will never re-exec the new version... */
582 if (header->arg1 == 0 && header->arg2 == 0) {
583 fprintf(logfile, "got old session agent xorg resolution message, ignoring\n");
584 free(data);
585 return;
588 if (header->size != n * sizeof(*res)) {
589 fprintf(logfile,
590 "guest xorg resolution message has wrong size, disconnecting agent\n");
591 udscs_destroy_connection(connp);
592 free(data);
593 return;
596 free(agent_data->screen_info);
597 res = malloc(n * sizeof(*res));
598 if (!res) {
599 fprintf(logfile, "out of memory allocating screen info\n");
600 n = 0;
602 memcpy(res, data, n * sizeof(*res));
603 agent_data->width = header->arg1;
604 agent_data->height = header->arg2;
605 agent_data->screen_info = res;
606 agent_data->screen_count = n;
608 check_xorg_resolution();
609 break;
611 case VDAGENTD_CLIPBOARD_GRAB:
612 case VDAGENTD_CLIPBOARD_REQUEST:
613 case VDAGENTD_CLIPBOARD_DATA:
614 case VDAGENTD_CLIPBOARD_RELEASE:
615 if (do_agent_clipboard(*connp, header, data)) {
616 udscs_destroy_connection(connp);
617 free(data);
618 return;
620 break;
621 default:
622 fprintf(logfile, "unknown message from vdagent: %u, ignoring\n",
623 header->type);
625 free(data);
628 /* main */
630 static void usage(FILE *fp)
632 fprintf(fp,
633 "vdagentd\n"
634 "options:\n"
635 " -h print this text\n"
636 " -d log debug messages (use twice for extra info)\n"
637 " -s <port> set virtio serial port [%s]\n"
638 " -u <dev> set uinput device [%s]\n"
639 " -x don't daemonize (and log to logfile)\n",
640 portdev, uinput_device);
643 void daemonize(void)
645 int x;
646 FILE *pidfile;
648 /* detach from terminal */
649 switch (fork()) {
650 case 0:
651 close(0); close(1); close(2);
652 setsid();
653 x = open("/dev/null", O_RDWR); x = dup(x); x = dup(x);
654 pidfile = fopen(pidfilename, "w");
655 if (pidfile) {
656 fprintf(pidfile, "%d\n", (int)getpid());
657 fclose(pidfile);
659 break;
660 case -1:
661 fprintf(logfile, "fork: %s\n", strerror(errno));
662 retval = 1;
663 default:
664 udscs_destroy_server(server);
665 if (logfile != stderr)
666 fclose(logfile);
667 exit(retval);
671 void main_loop(void)
673 fd_set readfds, writefds;
674 int n, nfds, ck_fd = 0;
676 while (!quit) {
677 FD_ZERO(&readfds);
678 FD_ZERO(&writefds);
680 nfds = udscs_server_fill_fds(server, &readfds, &writefds);
681 n = vdagent_virtio_port_fill_fds(virtio_port, &readfds, &writefds);
682 if (n >= nfds)
683 nfds = n + 1;
685 #ifdef HAVE_CONSOLE_KIT
686 ck_fd = console_kit_get_fd(console_kit);
687 FD_SET(ck_fd, &readfds);
688 if (ck_fd >= nfds)
689 nfds = ck_fd + 1;
690 #endif
692 n = select(nfds, &readfds, &writefds, NULL, NULL);
693 if (n == -1) {
694 if (errno == EINTR)
695 continue;
696 fprintf(logfile, "Fatal error select: %s\n", strerror(errno));
697 retval = 1;
698 break;
701 udscs_server_handle_fds(server, &readfds, &writefds);
703 if (virtio_port) {
704 vdagent_virtio_port_handle_fds(&virtio_port, &readfds, &writefds);
705 if (!virtio_port) {
706 fprintf(logfile,
707 "AIIEEE lost spice client connection, reconnecting\n");
708 virtio_port = vdagent_virtio_port_create(portdev,
709 virtio_port_read_complete,
710 NULL, logfile);
712 if (!virtio_port) {
713 fprintf(logfile,
714 "Fatal error opening vdagent virtio channel\n");
715 retval = 1;
716 break;
720 #ifdef HAVE_CONSOLE_KIT
721 if (FD_ISSET(ck_fd, &readfds)) {
722 active_session = console_kit_get_active_session(console_kit);
723 update_active_session_connection();
725 #endif
726 fflush(logfile);
730 static void quit_handler(int sig)
732 quit = 1;
735 int main(int argc, char *argv[])
737 int c;
738 int do_daemonize = 1;
739 struct sigaction act;
741 for (;;) {
742 if (-1 == (c = getopt(argc, argv, "-dhxs:u:")))
743 break;
744 switch (c) {
745 case 'd':
746 debug++;
747 break;
748 case 's':
749 portdev = optarg;
750 break;
751 case 'u':
752 uinput_device = optarg;
753 break;
754 case 'x':
755 do_daemonize = 0;
756 break;
757 case 'h':
758 usage(stdout);
759 return 0;
760 default:
761 usage(stderr);
762 return 1;
766 memset(&act, 0, sizeof(act));
767 act.sa_flags = SA_RESTART;
768 act.sa_handler = quit_handler;
769 sigaction(SIGINT, &act, NULL);
770 sigaction(SIGHUP, &act, NULL);
771 sigaction(SIGTERM, &act, NULL);
772 sigaction(SIGQUIT, &act, NULL);
774 if (do_daemonize) {
775 logfile = fopen(logfilename, "a");
776 if (!logfile) {
777 fprintf(stderr, "Error opening %s: %s\n", logfilename,
778 strerror(errno));
779 logfile = stderr;
781 } else
782 logfile = stderr;
784 /* Setup communication with vdagent process(es) */
785 server = udscs_create_server(VDAGENTD_SOCKET, agent_connect,
786 agent_read_complete, agent_disconnect,
787 vdagentd_messages, VDAGENTD_NO_MESSAGES,
788 debug? logfile:NULL, logfile);
789 if (!server) {
790 fprintf(logfile, "Fatal could not create server socket %s\n",
791 VDAGENTD_SOCKET);
792 if (logfile != stderr)
793 fclose(logfile);
794 return 1;
796 if (chmod(VDAGENTD_SOCKET, 0666)) {
797 fprintf(logfile, "Fatal could not change permissions on %s: %s\n",
798 VDAGENTD_SOCKET, strerror(errno));
799 udscs_destroy_server(server);
800 if (logfile != stderr)
801 fclose(logfile);
802 return 1;
805 if (do_daemonize)
806 daemonize();
808 #ifdef HAVE_CONSOLE_KIT
809 console_kit = console_kit_create(logfile);
810 if (!console_kit) {
811 fprintf(logfile, "Fatal could not connect to console kit\n");
812 udscs_destroy_server(server);
813 if (logfile != stderr)
814 fclose(logfile);
815 return 1;
817 #endif
819 main_loop();
821 release_clipboards();
823 vdagentd_uinput_destroy(&uinput);
824 vdagent_virtio_port_flush(&virtio_port);
825 vdagent_virtio_port_destroy(&virtio_port);
826 #ifdef HAVE_CONSOLE_KIT
827 console_kit_destroy(console_kit);
828 #endif
829 udscs_destroy_server(server);
830 if (unlink(VDAGENTD_SOCKET) != 0)
831 fprintf(logfile, "unlink %s: %s\n", VDAGENTD_SOCKET, strerror(errno));
832 fprintf(logfile, "vdagentd quiting, returning status %d\n", retval);
833 if (logfile != stderr)
834 fclose(logfile);
836 if (do_daemonize)
837 unlink(pidfilename);
839 return retval;