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