]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - tests/src/Xvnc.c
Allow guest sessions more access to the upstart session socket
[sojka/lightdm.git] / tests / src / Xvnc.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <sys/types.h>
5 #include <unistd.h>
6 #include <sys/stat.h>
7 #include <fcntl.h>
8 #include <errno.h>
9 #include <gio/gio.h>
10 #include <glib-unix.h>
11
12 #include "status.h"
13 #include "x-server.h"
14 #include "x-authority.h"
15
16 static GMainLoop *loop;
17 static int exit_status = EXIT_SUCCESS;
18
19 static GKeyFile *config;
20
21 /* Path to lock file */
22 static gchar *lock_path = NULL;
23
24 /* Path to authority database to use */
25 static gchar *auth_path = NULL;
26
27 /* ID to use for test reporting */
28 static gchar *id;
29
30 /* Display number being served */
31 static int display_number = 0;
32
33 /* X server */
34 static XServer *xserver = NULL;
35
36 static void
37 cleanup (void)
38 {
39     if (lock_path)
40         unlink (lock_path);
41     if (xserver)
42         g_object_unref (xserver);
43 }
44
45 static void
46 quit (int status)
47 {
48     exit_status = status;
49     g_main_loop_quit (loop);
50 }
51
52 static gboolean
53 sighup_cb (gpointer user_data)
54 {
55     status_notify ("%s DISCONNECT-CLIENTS", id);
56     return TRUE;
57 }
58
59 static gboolean
60 sigint_cb (gpointer user_data)
61 {
62     status_notify ("%s TERMINATE SIGNAL=%d", id, SIGINT);
63     quit (EXIT_SUCCESS);
64     return TRUE;
65 }
66
67 static gboolean
68 sigterm_cb (gpointer user_data)
69 {
70     status_notify ("%s TERMINATE SIGNAL=%d", id, SIGTERM);
71     quit (EXIT_SUCCESS);
72     return TRUE;
73 }
74
75 static void
76 client_connected_cb (XServer *server, XClient *client)
77 {
78     status_notify ("%s ACCEPT-CONNECT", id);
79     x_client_send_success (client);
80 }
81
82 static void
83 client_disconnected_cb (XServer *server, XClient *client)
84 {
85     g_signal_handlers_disconnect_matched (client, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, NULL);
86 }
87
88 static gboolean
89 vnc_data_cb (GIOChannel *channel, GIOCondition condition, gpointer data)
90 {
91     gchar buffer[1024];
92     gsize n_read;
93     GIOStatus status;
94     GError *error = NULL;
95
96     status = g_io_channel_read_chars (channel, buffer, 1023, &n_read, &error);
97     if (error)
98         g_warning ("Error reading from VNC client: %s", error->message);
99     g_clear_error (&error);
100
101     if (status == G_IO_STATUS_NORMAL)
102     {
103         buffer[n_read] = '\0';
104         if (g_str_has_suffix (buffer, "\n"))
105             buffer[n_read-1] = '\0';
106         status_notify ("%s VNC-CLIENT-CONNECT VERSION=\"%s\"", id, buffer);
107     }
108
109     return TRUE;
110 }
111
112 static void
113 request_cb (const gchar *name, GHashTable *params)
114 {
115     if (!name)
116     {
117         g_main_loop_quit (loop);
118         return;
119     }
120
121     if (strcmp (name, "INDICATE-READY") == 0)
122     {
123         void *handler;
124
125         handler = signal (SIGUSR1, SIG_IGN);
126         if (handler == SIG_IGN)
127         {
128             status_notify ("%s INDICATE-READY", id);
129             kill (getppid (), SIGUSR1);
130         }
131         signal (SIGUSR1, handler);
132     }
133
134     else if (strcmp (name, "START-VNC") == 0)
135     {
136         /* Send server protocol version to client */
137         g_print ("RFB 003.007\n");
138     }
139 }
140
141 int
142 main (int argc, char **argv)
143 {
144     int i;
145     char *pid_string;
146     gboolean use_inetd = FALSE;
147     gboolean has_option = FALSE;
148     gchar *geometry = g_strdup ("640x480");
149     gint depth = 8;
150     gchar *lock_filename;
151     int lock_file;
152
153 #if !defined(GLIB_VERSION_2_36)
154     g_type_init ();
155 #endif
156
157     loop = g_main_loop_new (NULL, FALSE);
158
159     g_unix_signal_add (SIGINT, sigint_cb, NULL);
160     g_unix_signal_add (SIGTERM, sigterm_cb, NULL);
161     g_unix_signal_add (SIGHUP, sighup_cb, NULL);
162
163     for (i = 1; i < argc; i++)
164     {
165         char *arg = argv[i];
166
167         if (arg[0] == ':')
168         {
169             display_number = atoi (arg + 1);
170         }
171         else if (strcmp (arg, "-auth") == 0)
172         {
173             auth_path = argv[i+1];
174             i++;
175         }
176         else if (strcmp (arg, "-nolisten") == 0)
177         {
178             char *protocol = argv[i+1];
179             i++;
180             if (strcmp (protocol, "tcp") == 0)
181                 ;//listen_tcp = FALSE;
182             else if (strcmp (protocol, "unix") == 0)
183                 ;//listen_unix = FALSE;
184         }
185         else if (strcmp (arg, "-geometry") == 0)
186         {
187             g_free (geometry);
188             geometry = g_strdup (argv[i+1]);
189             i++;
190         }
191         else if (strcmp (arg, "-depth") == 0)
192         {
193             depth = atoi (argv[i+1]);
194             i++;
195         }
196         else if (strcmp (arg, "-inetd") == 0)
197         {
198             use_inetd = TRUE;
199         }
200         else if (strcmp (arg, "-option") == 0)
201         {
202             has_option = TRUE;
203         }
204         else
205         {
206             g_printerr ("Unrecognized option: %s\n"
207                         "Use: %s [:<display>] [option]\n"
208                         "-auth file             Select authorization file\n"
209                         "-nolisten protocol     Don't listen on protocol\n"
210                         "-geometry WxH          Set framebuffer width & height\n"
211                         "-depth D               Set framebuffer depth\n"
212                         "-inetd                 Xvnc is launched by inetd\n",
213                         arg, argv[0]);
214             return EXIT_FAILURE;
215         }
216     }
217
218     id = g_strdup_printf ("XVNC-%d", display_number);
219
220     status_connect (request_cb, id);
221
222     xserver = x_server_new (display_number);
223     g_signal_connect (xserver, X_SERVER_SIGNAL_CLIENT_CONNECTED, G_CALLBACK (client_connected_cb), NULL);
224     g_signal_connect (xserver, X_SERVER_SIGNAL_CLIENT_DISCONNECTED, G_CALLBACK (client_disconnected_cb), NULL);
225
226     status_notify ("%s START GEOMETRY=%s DEPTH=%d OPTION=%s", id, geometry, depth, has_option ? "TRUE" : "FALSE");
227
228     config = g_key_file_new ();
229     g_key_file_load_from_file (config, g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "script", NULL), G_KEY_FILE_NONE, NULL);
230
231     if (use_inetd)
232     {
233         if (!g_io_add_watch (g_io_channel_unix_new (STDIN_FILENO), G_IO_IN, vnc_data_cb, NULL))
234             return EXIT_FAILURE;
235     }
236     else
237     {
238         g_printerr ("Only supported in -inetd mode\n");
239         return EXIT_FAILURE;
240     }
241
242     lock_filename = g_strdup_printf (".X%d-lock", display_number);
243     lock_path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "tmp", lock_filename, NULL);
244     g_free (lock_filename);
245     lock_file = open (lock_path, O_CREAT | O_EXCL | O_WRONLY, 0444);
246     if (lock_file < 0)
247     {
248         char *lock_contents = NULL;
249
250         if (g_file_get_contents (lock_path, &lock_contents, NULL, NULL))
251         {
252             gchar *proc_filename;
253             pid_t pid;
254
255             pid = atol (lock_contents);
256             g_free (lock_contents);
257
258             proc_filename = g_strdup_printf ("/proc/%d", pid);
259             if (!g_file_test (proc_filename, G_FILE_TEST_EXISTS))
260             {
261                 gchar *socket_dir;
262                 gchar *socket_filename;
263                 gchar *socket_path;
264
265                 socket_dir = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "tmp", ".X11-unix", NULL);
266                 g_mkdir_with_parents (socket_dir, 0755);
267
268                 socket_filename = g_strdup_printf ("X%d", display_number);
269                 socket_path = g_build_filename (socket_dir, socket_filename, NULL);
270
271                 g_printerr ("Breaking lock on non-existant process %d\n", pid);
272                 unlink (lock_path);
273                 unlink (socket_path);
274
275                 g_free (socket_dir);
276                 g_free (socket_filename);
277                 g_free (socket_path);
278             }
279             g_free (proc_filename);
280
281             lock_file = open (lock_path, O_CREAT | O_EXCL | O_WRONLY, 0444);
282         }
283     }
284     if (lock_file < 0)
285     {
286         fprintf (stderr,
287                  "Fatal server error:\n"
288                  "Server is already active for display %d\n"
289                  "      If this server is no longer running, remove %s\n"
290                  "      and start again.\n", display_number, lock_path);
291         g_free (lock_path);
292         lock_path = NULL;
293         return EXIT_FAILURE;
294     }
295     pid_string = g_strdup_printf ("%10ld", (long) getpid ());
296     if (write (lock_file, pid_string, strlen (pid_string)) < 0)
297     {
298         g_warning ("Error writing PID file: %s", strerror (errno));
299         return EXIT_FAILURE;
300     }
301     g_free (pid_string);
302
303     if (!x_server_start (xserver))
304         return EXIT_FAILURE;
305
306     g_main_loop_run (loop);
307
308     cleanup ();
309
310     return exit_status;
311 }