Attempt to reconnect to system socket every second when daemonized
[vd_agent/hramrach.git] / src / vdagent.c
blob2b69865564c97f23b3b291a8e06db8603fcec54e
1 /* vdagent.c xorg-client to vdagentd (daemon).
3 Copyright 2010 Red Hat, Inc.
5 Red Hat Authors:
6 Hans de Goede <hdegoede@redhat.com>
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <errno.h>
28 #include <signal.h>
29 #include <sys/select.h>
30 #include <sys/stat.h>
31 #include <spice/vd_agent.h>
33 #include "udscs.h"
34 #include "vdagentd-proto.h"
35 #include "vdagentd-proto-strings.h"
36 #include "vdagent-x11.h"
38 static int verbose = 0;
39 static struct vdagent_x11 *x11 = NULL;
40 static struct udscs_connection *client = NULL;
41 static FILE *logfile = NULL;
42 static int quit = 0;
44 void daemon_read_complete(struct udscs_connection **connp,
45 struct udscs_message_header *header, uint8_t *data)
47 switch (header->type) {
48 case VDAGENTD_MONITORS_CONFIG:
49 vdagent_x11_set_monitor_config(x11, (VDAgentMonitorsConfig *)data);
50 free(data);
51 break;
52 case VDAGENTD_CLIPBOARD_REQUEST:
53 vdagent_x11_clipboard_request(x11, header->arg1, header->arg2);
54 free(data);
55 break;
56 case VDAGENTD_CLIPBOARD_GRAB:
57 vdagent_x11_clipboard_grab(x11, header->arg1, (uint32_t *)data,
58 header->size / sizeof(uint32_t));
59 free(data);
60 break;
61 case VDAGENTD_CLIPBOARD_DATA:
62 vdagent_x11_clipboard_data(x11, header->arg1, header->arg2,
63 data, header->size);
64 /* vdagent_x11_clipboard_data takes ownership of the data (or frees
65 it immediately) */
66 break;
67 case VDAGENTD_CLIPBOARD_RELEASE:
68 vdagent_x11_clipboard_release(x11, header->arg1);
69 free(data);
70 break;
71 default:
72 if (verbose)
73 fprintf(logfile, "Unknown message from vdagentd type: %d\n",
74 header->type);
75 free(data);
79 int client_setup(int reconnect)
81 while (1) {
82 client = udscs_connect(VDAGENTD_SOCKET, daemon_read_complete, NULL,
83 vdagentd_messages, VDAGENTD_NO_MESSAGES,
84 verbose ? logfile : NULL, logfile);
85 if (client || !reconnect) {
86 break;
88 sleep(1);
90 return client == NULL;
93 static void usage(FILE *fp)
95 fprintf(fp,
96 "vdagent -- spice agent xorg client\n"
97 "options:\n"
98 " -h print this text\n"
99 " -d log debug messages\n"
100 " -x don't daemonize (and log to logfile)\n");
103 static void quit_handler(int sig)
105 quit = 1;
108 void daemonize(void)
110 int x, retval = 0;
112 /* detach from terminal */
113 switch (fork()) {
114 case 0:
115 close(0); close(1); close(2);
116 setsid();
117 x = open("/dev/null", O_RDWR); dup(x); dup(x);
118 break;
119 case -1:
120 fprintf(logfile, "fork: %s\n", strerror(errno));
121 retval = 1;
122 default:
123 if (logfile != stderr)
124 fclose(logfile);
125 exit(retval);
129 int main(int argc, char *argv[])
131 fd_set readfds, writefds;
132 int c, n, nfds, x11_fd, retval = 0;
133 int do_daemonize = 1;
134 char *home, filename[1024];
135 struct sigaction act;
137 for (;;) {
138 if (-1 == (c = getopt(argc, argv, "-dxh")))
139 break;
140 switch (c) {
141 case 'd':
142 verbose++;
143 break;
144 case 'x':
145 do_daemonize = 0;
146 break;
147 case 'h':
148 usage(stdout);
149 return 0;
150 default:
151 usage(stderr);
152 return 1;
156 memset(&act, 0, sizeof(act));
157 act.sa_flags = SA_RESTART;
158 act.sa_handler = quit_handler;
159 sigaction(SIGINT, &act, NULL);
160 sigaction(SIGHUP, &act, NULL);
161 sigaction(SIGTERM, &act, NULL);
162 sigaction(SIGQUIT, &act, NULL);
164 logfile = stderr;
165 home = getenv("HOME");
166 if (home) {
167 snprintf(filename, sizeof(filename), "%s/.spice-vdagent", home);
168 n = mkdir(filename, 0755);
169 snprintf(filename, sizeof(filename), "%s/.spice-vdagent/log", home);
170 if (do_daemonize) {
171 logfile = fopen(filename, "w");
172 if (!logfile) {
173 fprintf(stderr, "Error opening %s: %s\n", filename,
174 strerror(errno));
175 logfile = stderr;
178 } else {
179 fprintf(stderr, "Could not get home directory, logging to stderr\n");
182 if (do_daemonize)
183 daemonize();
185 if (client_setup(do_daemonize)) {
186 retval = 1;
187 goto finish;
190 x11 = vdagent_x11_create(client, logfile, verbose);
191 if (!x11) {
192 udscs_destroy_connection(&client);
193 retval = 1;
194 goto finish;
197 while (client && !quit) {
198 FD_ZERO(&readfds);
199 FD_ZERO(&writefds);
201 nfds = udscs_client_fill_fds(client, &readfds, &writefds);
202 x11_fd = vdagent_x11_get_fd(x11);
203 FD_SET(x11_fd, &readfds);
204 if (x11_fd >= nfds)
205 nfds = x11_fd + 1;
207 n = select(nfds, &readfds, &writefds, NULL, NULL);
208 if (n == -1) {
209 if (errno == EINTR)
210 continue;
211 fprintf(logfile, "Fatal error select: %s\n", strerror(errno));
212 retval = 1;
213 break;
216 if (FD_ISSET(x11_fd, &readfds))
217 vdagent_x11_do_read(x11);
218 udscs_client_handle_fds(&client, &readfds, &writefds);
219 fflush(logfile);
222 vdagent_x11_destroy(x11);
223 udscs_destroy_connection(&client);
225 finish:
226 if (logfile != stderr)
227 fclose(logfile);
229 return retval;