]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - tests/src/X.c
Remove trailing whitespace
[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     gboolean sharevts = FALSE;
209     int lock_file;
210     GString *status_text;
211
212 #if !defined(GLIB_VERSION_2_36)
213     g_type_init ();
214 #endif
215
216     loop = g_main_loop_new (NULL, FALSE);
217
218     g_unix_signal_add (SIGINT, sigint_cb, NULL);
219     g_unix_signal_add (SIGTERM, sigterm_cb, NULL);
220     g_unix_signal_add (SIGHUP, sighup_cb, NULL);
221
222     for (i = 1; i < argc; i++)
223     {
224         char *arg = argv[i];
225
226         if (arg[0] == ':')
227         {
228             display_number = atoi (arg + 1);
229         }
230         else if (strcmp (arg, "-auth") == 0)
231         {
232             auth_path = argv[i+1];
233             i++;
234         }
235         else if (strcmp (arg, "-nolisten") == 0)
236         {
237             char *protocol = argv[i+1];
238             i++;
239             if (strcmp (protocol, "tcp") == 0)
240                 ;//listen_tcp = FALSE;
241             else if (strcmp (protocol, "unix") == 0)
242                 ;//listen_unix = FALSE;
243         }
244         else if (strcmp (arg, "-nr") == 0)
245         {
246         }
247         else if (strcmp (arg, "-background") == 0)
248         {
249             /* Ignore arg */
250             i++;
251         }
252         else if (strcmp (arg, "-port") == 0)
253         {
254             xdmcp_port = atoi (argv[i+1]);
255             i++;
256         }
257         else if (strcmp (arg, "-query") == 0)
258         {
259             do_xdmcp = TRUE;
260             xdmcp_host = argv[i+1];
261             i++;
262         }
263         else if (strcmp (arg, "-broadcast") == 0)
264         {
265             do_xdmcp = TRUE;
266         }
267         else if (g_str_has_prefix (arg, "vt"))
268         {
269             vt_number = atoi (arg + 2);
270         }
271         else if (strcmp (arg, "-novtswitch") == 0)
272         {
273             /* Ignore VT args */
274         }
275         else if (strcmp (arg, "-seat") == 0)
276         {
277             seat = argv[i+1];
278             i++;
279         }
280         else if (strcmp (arg, "-sharevts") == 0)
281         {
282             sharevts = TRUE;
283         }
284         else if (strcmp (arg, "-mir") == 0)
285         {
286             mir_id = argv[i+1];
287             i++;
288         }
289         else if (strcmp (arg, "-mirSocket") == 0)
290         {
291             /* FIXME */
292             i++;
293         }
294         else
295         {
296             g_printerr ("Unrecognized option: %s\n"
297                         "Use: %s [:<display>] [option]\n"
298                         "-auth file             Select authorization file\n"
299                         "-nolisten protocol     Don't listen on protocol\n"
300                         "-background [none]     Create root window with no background\n"
301                         "-nr                    (Ubuntu-specific) Synonym for -background none\n"
302                         "-query host-name       Contact named host for XDMCP\n"
303                         "-broadcast             Broadcast for XDMCP\n"
304                         "-port port-num         UDP port number to send messages to\n"
305                         "-seat string           seat to run on\n"
306                         "-sharevts              share VTs with another X server\n"
307                         "-mir id                Mir ID to use\n"
308                         "-mirSocket name        Mir socket to use\n"
309                         "vtxx                   Use virtual terminal xx instead of the next available\n",
310                         arg, argv[0]);
311             return EXIT_FAILURE;
312         }
313     }
314
315     id = g_strdup_printf ("XSERVER-%d", display_number);
316
317     status_connect (request_cb, id);
318
319     xserver = x_server_new (display_number);
320     g_signal_connect (xserver, "client-connected", G_CALLBACK (client_connected_cb), NULL);
321     g_signal_connect (xserver, "client-disconnected", G_CALLBACK (client_disconnected_cb), NULL);
322
323     status_text = g_string_new ("");
324     g_string_printf (status_text, "%s START", id);
325     if (vt_number >= 0)
326         g_string_append_printf (status_text, " VT=%d", vt_number);
327     if (seat != NULL)
328         g_string_append_printf (status_text, " SEAT=%s", seat);
329     if (sharevts)
330         g_string_append (status_text, " SHAREVTS=TRUE");
331     if (mir_id != NULL)
332         g_string_append_printf (status_text, " MIR-ID=%s", mir_id);
333     status_notify ("%s", status_text->str);
334     g_string_free (status_text, TRUE);
335
336     config = g_key_file_new ();
337     g_key_file_load_from_file (config, g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "script", NULL), G_KEY_FILE_NONE, NULL);
338
339     if (g_key_file_has_key (config, "test-xserver-config", "return-value", NULL))
340     {
341         int return_value = g_key_file_get_integer (config, "test-xserver-config", "return-value", NULL);
342         status_notify ("%s EXIT CODE=%d", id, return_value);
343         return return_value;
344     }
345
346     lock_filename = g_strdup_printf (".X%d-lock", display_number);
347     lock_path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "tmp", lock_filename, NULL);
348     g_free (lock_filename);
349     lock_file = open (lock_path, O_CREAT | O_EXCL | O_WRONLY, 0444);
350     if (lock_file < 0)
351     {
352         char *lock_contents = NULL;
353
354         if (g_file_get_contents (lock_path, &lock_contents, NULL, NULL))
355         {
356             gchar *proc_filename;
357             pid_t pid;
358
359             pid = atol (lock_contents);
360             g_free (lock_contents);
361
362             proc_filename = g_strdup_printf ("/proc/%d", pid);
363             if (!g_file_test (proc_filename, G_FILE_TEST_EXISTS))
364             {
365                 gchar *socket_dir;
366                 gchar *socket_filename;
367                 gchar *socket_path;
368
369                 socket_dir = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "tmp", ".X11-unix", NULL);
370                 g_mkdir_with_parents (socket_dir, 0755);
371
372                 socket_filename = g_strdup_printf ("X%d", display_number);
373                 socket_path = g_build_filename (socket_dir, socket_filename, NULL);
374
375                 g_printerr ("Breaking lock on non-existant process %d\n", pid);
376                 unlink (lock_path);
377                 unlink (socket_path);
378
379                 g_free (socket_dir);
380                 g_free (socket_filename);
381                 g_free (socket_path);
382             }
383             g_free (proc_filename);
384
385             lock_file = open (lock_path, O_CREAT | O_EXCL | O_WRONLY, 0444);
386         }
387     }
388     if (lock_file < 0)
389     {
390         fprintf (stderr,
391                  "Fatal server error:\n"
392                  "Server is already active for display %d\n"
393                  "      If this server is no longer running, remove %s\n"
394                  "      and start again.\n", display_number, lock_path);
395         g_free (lock_path);
396         lock_path = NULL;
397         return EXIT_FAILURE;
398     }
399     pid_string = g_strdup_printf ("%10ld", (long) getpid ());
400     if (write (lock_file, pid_string, strlen (pid_string)) < 0)
401     {
402         g_warning ("Error writing PID file: %s", strerror (errno));
403         return EXIT_FAILURE;
404     }
405     g_free (pid_string);
406
407     if (!x_server_start (xserver))
408         return EXIT_FAILURE;
409
410     /* Enable XDMCP */
411     if (do_xdmcp)
412     {
413         xdmcp_client = xdmcp_client_new ();
414         if (xdmcp_host > 0)
415             xdmcp_client_set_hostname (xdmcp_client, xdmcp_host);
416         if (xdmcp_port > 0)
417             xdmcp_client_set_port (xdmcp_client, xdmcp_port);
418         g_signal_connect (xdmcp_client, "query", G_CALLBACK (xdmcp_query_cb), NULL);
419         g_signal_connect (xdmcp_client, "willing", G_CALLBACK (xdmcp_willing_cb), NULL);
420         g_signal_connect (xdmcp_client, "accept", G_CALLBACK (xdmcp_accept_cb), NULL);
421         g_signal_connect (xdmcp_client, "decline", G_CALLBACK (xdmcp_decline_cb), NULL);
422         g_signal_connect (xdmcp_client, "failed", G_CALLBACK (xdmcp_failed_cb), NULL);
423     }
424
425     g_main_loop_run (loop);
426
427     cleanup ();
428
429     return exit_status;
430 }