]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - tests/src/X.c
Check the version of the X server we are running so we correctly pass -listen tcp...
[sojka/lightdm.git] / tests / src / X.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 <glib-unix.h>
10
11 #include "status.h"
12 #include "x-server.h"
13 #include "x-authority.h"
14 #include "xdmcp-client.h"
15
16 static GMainLoop *loop;
17 static int exit_status = EXIT_SUCCESS;
18
19 static GKeyFile *config;
20
21 /* Version to pretend to be */
22 static gchar *xorg_version;
23 static gint xorg_version_major, xorg_version_minor;
24
25 /* Path to lock file */
26 static gchar *lock_path = NULL;
27
28 /* TRUE if we allow TCP connections */
29 static gboolean listen_tcp = TRUE;
30
31 /* TRUE if we allow Unix connections */
32 static gboolean listen_unix = TRUE;
33
34 /* Path to authority database to use */
35 static gchar *auth_path = NULL;
36
37 /* ID to use for test reporting */
38 static gchar *id;
39
40 /* Display number being served */
41 static int display_number = 0;
42
43 /* VT being run on */
44 static int vt_number = -1;
45
46 /* X server */
47 static XServer *xserver = NULL;
48
49 /* XDMCP client */
50 static XDMCPClient *xdmcp_client = NULL;
51
52 /* Authorization provided by XDMCP server */
53 static guint16 xdmcp_cookie_length = 0;
54 static guint8 *xdmcp_cookie = NULL;
55
56 static void
57 cleanup (void)
58 {
59     if (lock_path)
60         unlink (lock_path);
61     if (xserver)
62         g_object_unref (xserver);
63     if (xdmcp_client)
64         g_object_unref (xdmcp_client);
65 }
66
67 static void
68 quit (int status)
69 {
70     exit_status = status;
71     g_main_loop_quit (loop);
72 }
73
74 static gboolean
75 sighup_cb (gpointer user_data)
76 {
77     status_notify ("%s DISCONNECT-CLIENTS", id);
78     return TRUE;
79 }
80
81 static gboolean
82 sigint_cb (gpointer user_data)
83 {
84     status_notify ("%s TERMINATE SIGNAL=%d", id, SIGINT);
85     quit (EXIT_SUCCESS);
86     return TRUE;
87 }
88
89 static gboolean
90 sigterm_cb (gpointer user_data)
91 {
92     status_notify ("%s TERMINATE SIGNAL=%d", id, SIGTERM);
93     quit (EXIT_SUCCESS);
94     return TRUE;
95 }
96
97 static void
98 xdmcp_query_cb (XDMCPClient *client)
99 {
100     static gboolean notified_query = FALSE;
101
102     if (!notified_query)
103     {
104         status_notify ("%s SEND-QUERY", id);
105         notified_query = TRUE;
106     }
107 }
108
109 static void
110 xdmcp_willing_cb (XDMCPClient *client, XDMCPWilling *message)
111 {
112     gchar **authorization_names;
113     GInetAddress *addresses[2];
114
115     status_notify ("%s GOT-WILLING AUTHENTICATION-NAME=\"%s\" HOSTNAME=\"%s\" STATUS=\"%s\"", id, message->authentication_name, message->hostname, message->status);
116
117     status_notify ("%s SEND-REQUEST DISPLAY-NUMBER=%d AUTHORIZATION-NAME=\"%s\" MFID=\"%s\"", id, display_number, "MIT-MAGIC-COOKIE-1", "TEST XSERVER");
118
119     authorization_names = g_strsplit ("MIT-MAGIC-COOKIE-1", " ", -1);
120     addresses[0] = xdmcp_client_get_local_address (client);
121     addresses[1] = NULL;
122     xdmcp_client_send_request (client, display_number,
123                                addresses,
124                                "", NULL, 0,
125                                authorization_names, "TEST XSERVER");
126     g_strfreev (authorization_names);
127 }
128
129 static void
130 xdmcp_accept_cb (XDMCPClient *client, XDMCPAccept *message)
131 {
132     status_notify ("%s GOT-ACCEPT SESSION-ID=%d AUTHENTICATION-NAME=\"%s\" AUTHORIZATION-NAME=\"%s\"", id, message->session_id, message->authentication_name, message->authorization_name);
133
134     /* Ignore if haven't picked a valid authorization */
135     if (strcmp (message->authorization_name, "MIT-MAGIC-COOKIE-1") != 0)
136         return;
137
138     g_free (xdmcp_cookie);
139     xdmcp_cookie_length = message->authorization_data_length;
140     xdmcp_cookie = g_malloc (message->authorization_data_length);
141     memcpy (xdmcp_cookie, message->authorization_data, message->authorization_data_length);
142
143     status_notify ("%s SEND-MANAGE SESSION-ID=%d DISPLAY-NUMBER=%d DISPLAY-CLASS=\"%s\"", id, message->session_id, display_number, "DISPLAY CLASS");
144     xdmcp_client_send_manage (client, message->session_id, display_number, "DISPLAY CLASS");
145 }
146
147 static void
148 xdmcp_decline_cb (XDMCPClient *client, XDMCPDecline *message)
149 {
150     status_notify ("%s GOT-DECLINE STATUS=\"%s\" AUTHENTICATION-NAME=\"%s\"", id, message->status, message->authentication_name);
151 }
152
153 static void
154 xdmcp_failed_cb (XDMCPClient *client, XDMCPFailed *message)
155 {
156     status_notify ("%s GOT-FAILED SESSION-ID=%d STATUS=\"%s\"", id, message->session_id, message->status);
157 }
158
159 static void
160 client_connected_cb (XServer *server, XClient *client)
161 {
162     status_notify ("%s ACCEPT-CONNECT", id);
163     x_client_send_success (client);
164 }
165
166 static void
167 client_disconnected_cb (XServer *server, XClient *client)
168 {
169     g_signal_handlers_disconnect_matched (client, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, NULL);
170 }
171
172 static void
173 request_cb (const gchar *name, GHashTable *params)
174 {
175     if (!name)
176     {
177         g_main_loop_quit (loop);
178         return;
179     }
180
181     if (strcmp (name, "CRASH") == 0)
182     {
183         cleanup ();
184         kill (getpid (), SIGSEGV);
185     }
186
187     else if (strcmp (name, "INDICATE-READY") == 0)
188     {
189         void *handler;
190
191         handler = signal (SIGUSR1, SIG_IGN);
192         if (handler == SIG_IGN)
193         {
194             status_notify ("%s INDICATE-READY", id);
195             kill (getppid (), SIGUSR1);
196         }
197         signal (SIGUSR1, handler);
198     }
199
200     else if (strcmp (name, "START-XDMCP") == 0)
201     {
202         if (!xdmcp_client_start (xdmcp_client))
203             quit (EXIT_FAILURE);
204     }
205 }
206
207 static int
208 version_compare (int major, int minor)
209 {
210     if (major == xorg_version_major)
211         return xorg_version_minor - minor;
212     else
213         return xorg_version_major - major;
214 }
215
216 int
217 main (int argc, char **argv)
218 {
219     int i;
220     gchar **tokens;
221     char *pid_string;
222     gboolean do_xdmcp = FALSE;
223     guint xdmcp_port = 0;
224     gchar *xdmcp_host = NULL;
225     gchar *seat = NULL;
226     gchar *mir_id = NULL;
227     gchar *lock_filename;
228     int lock_file;
229     GString *status_text;
230
231 #if !defined(GLIB_VERSION_2_36)
232     g_type_init ();
233 #endif
234
235     loop = g_main_loop_new (NULL, FALSE);
236
237     g_unix_signal_add (SIGINT, sigint_cb, NULL);
238     g_unix_signal_add (SIGTERM, sigterm_cb, NULL);
239     g_unix_signal_add (SIGHUP, sighup_cb, NULL);
240
241     config = g_key_file_new ();
242     g_key_file_load_from_file (config, g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "script", NULL), G_KEY_FILE_NONE, NULL);
243
244     xorg_version = g_key_file_get_string (config, "test-xserver-config", "version", NULL);
245     if (!xorg_version)
246         xorg_version = g_strdup ("1.16.0");
247     tokens = g_strsplit (xorg_version, ".", -1);
248     xorg_version_major = g_strv_length (tokens) > 0 ? atoi (tokens[0]) : 0;
249     xorg_version_minor = g_strv_length (tokens) > 1 ? atoi (tokens[1]) : 0;
250     g_strfreev (tokens);
251
252     /* TCP listening default changed in 1.17.0 */
253     listen_tcp = version_compare (1, 17) < 0;
254
255     for (i = 1; i < argc; i++)
256     {
257         char *arg = argv[i];
258
259         if (arg[0] == ':')
260         {
261             display_number = atoi (arg + 1);
262         }
263         else if (strcmp (arg, "-auth") == 0)
264         {
265             auth_path = argv[i+1];
266             i++;
267         }
268         else if (strcmp (arg, "-listen") == 0 && version_compare (1, 17) >= 0)
269         {
270             char *protocol = argv[i+1];
271             i++;
272             if (strcmp (protocol, "tcp") == 0)
273                 listen_tcp = TRUE;
274             else if (strcmp (protocol, "unix") == 0)
275                 listen_unix = TRUE;
276         }
277         else if (strcmp (arg, "-nolisten") == 0)
278         {
279             char *protocol = argv[i+1];
280             i++;
281             if (strcmp (protocol, "tcp") == 0)
282                 listen_tcp = FALSE;
283             else if (strcmp (protocol, "unix") == 0)
284                 listen_unix = FALSE;
285         }
286         else if (strcmp (arg, "-nr") == 0)
287         {
288         }
289         else if (strcmp (arg, "-background") == 0)
290         {
291             /* Ignore arg */
292             i++;
293         }
294         else if (strcmp (arg, "-port") == 0)
295         {
296             xdmcp_port = atoi (argv[i+1]);
297             i++;
298         }
299         else if (strcmp (arg, "-query") == 0)
300         {
301             do_xdmcp = TRUE;
302             xdmcp_host = argv[i+1];
303             listen_tcp = TRUE;
304             i++;
305         }
306         else if (strcmp (arg, "-broadcast") == 0)
307         {
308             do_xdmcp = TRUE;
309             listen_tcp = TRUE;
310         }
311         else if (g_str_has_prefix (arg, "vt"))
312         {
313             vt_number = atoi (arg + 2);
314         }
315         else if (strcmp (arg, "-novtswitch") == 0)
316         {
317             /* Ignore VT args */
318         }
319         else if (strcmp (arg, "-seat") == 0)
320         {
321             seat = argv[i+1];
322             i++;
323         }
324         else if (strcmp (arg, "-mir") == 0)
325         {
326             mir_id = argv[i+1];
327             i++;
328         }
329         else if (strcmp (arg, "-mirSocket") == 0)
330         {
331             /* FIXME */
332             i++;
333         }
334         else if (strcmp (arg, "-version") == 0)
335         {
336             fprintf (stderr, "\nX.Org X Server %s\nBlah blah blah\n", xorg_version);
337             return EXIT_SUCCESS;
338         }
339         else
340         {
341             g_printerr ("Unrecognized option: %s\n"
342                         "Use: %s [:<display>] [option]\n"
343                         "-auth file             Select authorization file\n"
344                         "-nolisten protocol     Don't listen on protocol\n"
345                         "-listen protocol       Listen on protocol\n"
346                         "-background [none]     Create root window with no background\n"
347                         "-nr                    (Ubuntu-specific) Synonym for -background none\n"
348                         "-query host-name       Contact named host for XDMCP\n"
349                         "-broadcast             Broadcast for XDMCP\n"
350                         "-port port-num         UDP port number to send messages to\n"
351                         "-seat string           seat to run on\n"
352                         "-mir id                Mir ID to use\n"
353                         "-mirSocket name        Mir socket to use\n"
354                         "-version               show the server version\n"
355                         "vtxx                   Use virtual terminal xx instead of the next available\n",
356                         arg, argv[0]);
357             return EXIT_FAILURE;
358         }
359     }
360
361     id = g_strdup_printf ("XSERVER-%d", display_number);
362
363     status_connect (request_cb, id);
364
365     xserver = x_server_new (display_number);
366     g_signal_connect (xserver, X_SERVER_SIGNAL_CLIENT_CONNECTED, G_CALLBACK (client_connected_cb), NULL);
367     g_signal_connect (xserver, X_SERVER_SIGNAL_CLIENT_DISCONNECTED, G_CALLBACK (client_disconnected_cb), NULL);
368
369     status_text = g_string_new ("");
370     g_string_printf (status_text, "%s START", id);
371     if (vt_number >= 0)
372         g_string_append_printf (status_text, " VT=%d", vt_number);
373     if (listen_tcp)
374         g_string_append (status_text, " LISTEN-TCP");
375     if (!listen_unix)
376         g_string_append (status_text, " NO-LISTEN-UNIX");
377     if (seat != NULL)
378         g_string_append_printf (status_text, " SEAT=%s", seat);
379     if (mir_id != NULL)
380         g_string_append_printf (status_text, " MIR-ID=%s", mir_id);
381     status_notify ("%s", status_text->str);
382     g_string_free (status_text, TRUE);
383
384     if (g_key_file_has_key (config, "test-xserver-config", "return-value", NULL))
385     {
386         int return_value = g_key_file_get_integer (config, "test-xserver-config", "return-value", NULL);
387         status_notify ("%s EXIT CODE=%d", id, return_value);
388         return return_value;
389     }
390
391     lock_filename = g_strdup_printf (".X%d-lock", display_number);
392     lock_path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "tmp", lock_filename, NULL);
393     g_free (lock_filename);
394     lock_file = open (lock_path, O_CREAT | O_EXCL | O_WRONLY, 0444);
395     if (lock_file < 0)
396     {
397         char *lock_contents = NULL;
398
399         if (g_file_get_contents (lock_path, &lock_contents, NULL, NULL))
400         {
401             gchar *proc_filename;
402             pid_t pid;
403
404             pid = atol (lock_contents);
405             g_free (lock_contents);
406
407             proc_filename = g_strdup_printf ("/proc/%d", pid);
408             if (!g_file_test (proc_filename, G_FILE_TEST_EXISTS))
409             {
410                 gchar *socket_dir;
411                 gchar *socket_filename;
412                 gchar *socket_path;
413
414                 socket_dir = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "tmp", ".X11-unix", NULL);
415                 g_mkdir_with_parents (socket_dir, 0755);
416
417                 socket_filename = g_strdup_printf ("X%d", display_number);
418                 socket_path = g_build_filename (socket_dir, socket_filename, NULL);
419
420                 g_printerr ("Breaking lock on non-existant process %d\n", pid);
421                 unlink (lock_path);
422                 unlink (socket_path);
423
424                 g_free (socket_dir);
425                 g_free (socket_filename);
426                 g_free (socket_path);
427             }
428             g_free (proc_filename);
429
430             lock_file = open (lock_path, O_CREAT | O_EXCL | O_WRONLY, 0444);
431         }
432     }
433     if (lock_file < 0)
434     {
435         fprintf (stderr,
436                  "Fatal server error:\n"
437                  "Server is already active for display %d\n"
438                  "      If this server is no longer running, remove %s\n"
439                  "      and start again.\n", display_number, lock_path);
440         g_free (lock_path);
441         lock_path = NULL;
442         return EXIT_FAILURE;
443     }
444     pid_string = g_strdup_printf ("%10ld", (long) getpid ());
445     if (write (lock_file, pid_string, strlen (pid_string)) < 0)
446     {
447         g_warning ("Error writing PID file: %s", strerror (errno));
448         return EXIT_FAILURE;
449     }
450     g_free (pid_string);
451
452     if (!x_server_start (xserver))
453         return EXIT_FAILURE;
454
455     /* Enable XDMCP */
456     if (do_xdmcp)
457     {
458         xdmcp_client = xdmcp_client_new ();
459         if (xdmcp_host > 0)
460             xdmcp_client_set_hostname (xdmcp_client, xdmcp_host);
461         if (xdmcp_port > 0)
462             xdmcp_client_set_port (xdmcp_client, xdmcp_port);
463         g_signal_connect (xdmcp_client, XDMCP_CLIENT_SIGNAL_QUERY, G_CALLBACK (xdmcp_query_cb), NULL);
464         g_signal_connect (xdmcp_client, XDMCP_CLIENT_SIGNAL_WILLING, G_CALLBACK (xdmcp_willing_cb), NULL);
465         g_signal_connect (xdmcp_client, XDMCP_CLIENT_SIGNAL_ACCEPT, G_CALLBACK (xdmcp_accept_cb), NULL);
466         g_signal_connect (xdmcp_client, XDMCP_CLIENT_SIGNAL_DECLINE, G_CALLBACK (xdmcp_decline_cb), NULL);
467         g_signal_connect (xdmcp_client, XDMCP_CLIENT_SIGNAL_FAILED, G_CALLBACK (xdmcp_failed_cb), NULL);
468     }
469
470     g_main_loop_run (loop);
471
472     cleanup ();
473
474     return exit_status;
475 }