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