]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - tests/src/test-runner.c
Refactor LightDMUser and User classes to use the same code internally.
[sojka/lightdm.git] / tests / src / test-runner.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <errno.h>
6 #include <glib.h>
7 #include <glib/gstdio.h>
8 #include <glib-unix.h>
9 #include <gio/gio.h>
10 #include <gio/gunixsocketaddress.h>
11 #include <unistd.h>
12 #include <pwd.h>
13
14 /* Timeout in ms waiting for the status we expect */
15 static int status_timeout_ms = 4000;
16
17 /* Timeout in ms to wait for SIGTERM to be handled by a child process */
18 #define KILL_TIMEOUT 2000
19
20 static gchar *test_runner_command;
21 static gchar *config_path;
22 static GKeyFile *config;
23 static GSocket *status_socket = NULL;
24 static gchar *status_socket_name = NULL;
25 static GList *statuses = NULL;
26 typedef struct
27 {
28     gchar *text;
29     gboolean done;
30 } ScriptLine;
31 static GList *script = NULL;
32 static guint status_timeout = 0;
33 static gchar *temp_dir = NULL;
34 static int service_count;
35 typedef struct
36 {
37     pid_t pid;
38     guint kill_timeout;
39 } Process;
40 static Process *lightdm_process = NULL;
41 static GHashTable *children = NULL;
42 static gboolean stop = FALSE;
43 static gint exit_status = 0;
44 static GDBusConnection *accounts_connection = NULL;
45 static GDBusNodeInfo *accounts_info;
46 static GDBusNodeInfo *user_info;
47 typedef struct
48 {
49     guint uid;
50     gchar *user_name;
51     gchar *real_name;
52     gchar *home_directory;
53     gchar *image;
54     gchar *background;
55     gchar *path;
56     guint id;
57     gchar *language;
58     gchar *xsession;
59     gchar **layouts;
60     gboolean has_messages;
61     gboolean hidden;
62 } AccountsUser;
63 static GList *accounts_users = NULL;
64 static void handle_user_call (GDBusConnection       *connection,
65                               const gchar           *sender,
66                               const gchar           *object_path,
67                               const gchar           *interface_name,
68                               const gchar           *method_name,
69                               GVariant              *parameters,
70                               GDBusMethodInvocation *invocation,
71                               gpointer               user_data);
72 static GVariant *handle_user_get_property (GDBusConnection       *connection,
73                                            const gchar           *sender,
74                                            const gchar           *object_path,
75                                            const gchar           *interface_name,
76                                            const gchar           *property_name,
77                                            GError               **error,
78                                            gpointer               user_data);
79 static const GDBusInterfaceVTable user_vtable =
80 {
81     handle_user_call,
82     handle_user_get_property,
83 };
84 static GDBusConnection *ck_connection = NULL;
85 static GDBusNodeInfo *ck_session_info;
86 typedef struct
87 {
88     gchar *cookie;
89     gchar *path;
90     guint id;
91     gboolean locked;
92 } CKSession;
93 static GList *ck_sessions = NULL;
94 static gint ck_session_index = 0;
95 static void handle_ck_session_call (GDBusConnection       *connection,
96                                     const gchar           *sender,
97                                     const gchar           *object_path,
98                                     const gchar           *interface_name,
99                                     const gchar           *method_name,
100                                     GVariant              *parameters,
101                                     GDBusMethodInvocation *invocation,
102                                     gpointer               user_data);
103 static const GDBusInterfaceVTable ck_session_vtable =
104 {
105     handle_ck_session_call,
106 };
107
108 typedef struct
109 {
110     gchar *path;
111     guint pid;
112     gboolean locked;
113 } Login1Session;
114
115 static GList *login1_sessions = NULL;
116 static gint login1_session_index = 0;
117
118 typedef struct
119 {
120     GSocket *socket;
121     GSource *source;
122 } StatusClient;
123 static GList *status_clients = NULL;
124
125 static void run_lightdm (void);
126 static void quit (int status);
127 static void check_status (const gchar *status);
128 static AccountsUser *get_accounts_user_by_uid (guint uid);
129 static AccountsUser *get_accounts_user_by_name (const gchar *username);
130 static void accounts_user_set_hidden (AccountsUser *user, gboolean hidden, gboolean emit_signal);
131
132 static gboolean
133 kill_timeout_cb (gpointer data)
134 {
135     Process *process = data;
136
137     if (getenv ("DEBUG"))
138         g_print ("Sending SIGKILL to process %d\n", process->pid);
139     kill (process->pid, SIGKILL);
140     return FALSE;
141 }
142
143 static void
144 stop_process (Process *process)
145 {
146     if (process->kill_timeout != 0)
147         return;
148
149     if (getenv ("DEBUG"))
150         g_print ("Sending SIGTERM to process %d\n", process->pid);
151     kill (process->pid, SIGTERM);
152     process->kill_timeout = g_timeout_add (KILL_TIMEOUT, kill_timeout_cb, process);
153 }
154
155 static void
156 process_exit_cb (GPid pid, gint status, gpointer data)
157 {
158     Process *process;
159     gchar *status_text;
160
161     if (getenv ("DEBUG"))
162     {
163         if (WIFEXITED (status))
164             g_print ("Process %d exited with status %d\n", pid, WEXITSTATUS (status));
165         else
166             g_print ("Process %d terminated with signal %d\n", pid, WTERMSIG (status));
167     }
168
169     if (lightdm_process && pid == lightdm_process->pid)
170     {
171         process = lightdm_process;
172         lightdm_process = NULL;
173         if (WIFEXITED (status))
174             status_text = g_strdup_printf ("RUNNER DAEMON-EXIT STATUS=%d", WEXITSTATUS (status));
175         else
176             status_text = g_strdup_printf ("RUNNER DAEMON-TERMINATE SIGNAL=%d", WTERMSIG (status));
177         check_status (status_text);
178     }
179     else
180     {
181         process = g_hash_table_lookup (children, GINT_TO_POINTER (pid));
182         if (!process)
183             return;
184         g_hash_table_remove (children, GINT_TO_POINTER (pid));
185     }
186
187     if (process->kill_timeout)
188         g_source_remove (process->kill_timeout);
189     process->kill_timeout = 0;
190
191     /* Quit once all children have stopped */
192     if (stop)
193         quit (exit_status);
194 }
195
196 static Process *
197 watch_process (pid_t pid)
198 {
199     Process *process;
200
201     process = g_malloc0 (sizeof (Process));
202     process->pid = pid;
203     process->kill_timeout = 0;
204
205     if (getenv ("DEBUG"))
206         g_print ("Watching process %d\n", process->pid);
207     g_child_watch_add (process->pid, process_exit_cb, NULL);
208
209     return process;
210 }
211
212 static void
213 quit (int status)
214 {
215     GHashTableIter iter;
216
217     if (!stop)
218         exit_status = status;
219     stop = TRUE;
220
221     /* Stop all the children */
222     g_hash_table_iter_init (&iter, children);
223     while (TRUE)
224     {
225         gpointer key, value;
226
227         if (!g_hash_table_iter_next (&iter, &key, &value))
228             break;
229
230         stop_process ((Process *)value);
231     }
232
233     /* Don't quit until all children are stopped */
234     if (g_hash_table_size (children) > 0)
235         return;
236
237     /* Stop the daemon */
238     if (lightdm_process)
239     {
240         stop_process (lightdm_process);
241         return;
242     }
243
244     if (status_socket_name)
245         unlink (status_socket_name);
246
247     if (temp_dir && getenv ("DEBUG") == NULL)
248     {
249         gchar *command = g_strdup_printf ("rm -rf %s", temp_dir);
250         if (system (command))
251             perror ("Failed to delete temp directory");
252     }
253
254     exit (status);
255 }
256
257 static void
258 fail (const gchar *event, const gchar *expected)
259 {
260     GList *link;
261
262     if (stop)
263         return;
264
265     g_printerr ("Command line: %s", test_runner_command);
266     g_printerr ("Events:\n");
267     for (link = statuses; link; link = link->next)
268         g_printerr ("    %s\n", (gchar *)link->data);
269     if (event)
270         g_printerr ("    %s\n", event);
271     if (expected)
272         g_printerr ("    ^^^ expected \"%s\"\n", expected);
273     else
274         g_printerr ("^^^ expected nothing\n");
275
276     quit (EXIT_FAILURE);
277 }
278
279 static gchar *
280 get_prefix (const gchar *text)
281 {
282     gchar *prefix;
283     gint i;
284
285     prefix = g_strdup (text);
286     for (i = 0; prefix[i] != '\0' && prefix[i] != ' '; i++);
287     prefix[i] = '\0';
288
289     return prefix;
290 }
291
292 static ScriptLine *
293 get_script_line (const gchar *prefix)
294 {
295     GList *link;
296
297     for (link = script; link; link = link->next)
298     {
299         ScriptLine *line = link->data;
300
301         /* Ignore lines with other prefixes */
302         if (prefix)
303         {
304             gchar *p;
305             gboolean matches;
306
307             p = get_prefix (line->text);
308             matches = strcmp (prefix, p) == 0;
309             g_free (p);
310
311             if (!matches)
312                 continue;
313         }
314
315         if (!line->done)
316             return line;
317     }
318
319     return NULL;
320 }
321
322 static void
323 handle_command (const gchar *command)
324 {
325     const gchar *c;
326     gchar *name = NULL;
327     GHashTable *params;
328
329     c = command;
330     while (*c && !isspace (*c))
331         c++;
332     name = g_strdup_printf ("%.*s", (int) (c - command), command);
333
334     params = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
335     while (TRUE)
336     {
337         const gchar *start;
338         gchar *param_name, *param_value;
339
340         while (isspace (*c))
341             c++;
342         start = c;
343         while (*c && !isspace (*c) && *c != '=')
344             c++;
345         if (*c == '\0')
346             break;
347
348         param_name = g_strdup_printf ("%.*s", (int) (c - start), start);
349
350         if (*c == '=')
351         {
352             c++;
353             while (isspace (*c))
354                 c++;
355             if (*c == '\"')
356             {
357                 gboolean escaped = FALSE;
358                 GString *value;
359
360                 c++;
361                 value = g_string_new ("");
362                 while (*c)
363                 {
364                     if (*c == '\\')
365                     {
366                         if (escaped)
367                         {
368                             g_string_append_c (value, '\\');
369                             escaped = FALSE;
370                         }
371                         else
372                             escaped = TRUE;
373                     }
374                     else if (!escaped && *c == '\"')
375                         break;
376                     if (!escaped)
377                         g_string_append_c (value, *c);
378                     c++;
379                 }
380                 param_value = value->str;
381                 g_string_free (value, FALSE);
382                 if (*c == '\"')
383                     c++;
384             }
385             else
386             {
387                 start = c;
388                 while (*c && !isspace (*c))
389                     c++;
390                 param_value = g_strdup_printf ("%.*s", (int) (c - start), start);
391             }
392         }
393         else
394             param_value = g_strdup ("");
395
396         g_hash_table_insert (params, param_name, param_value);
397     }
398
399     if (strcmp (name, "WAIT") == 0)
400     {
401         sleep (1);
402     }
403     else if (strcmp (name, "LIST-SEATS") == 0)
404     {
405         GVariant *result, *value;
406         GString *status;
407         GVariantIter *iter;
408         const gchar *path;
409         int i = 0;
410
411         result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
412                                               "org.freedesktop.DisplayManager",
413                                               "/org/freedesktop/DisplayManager",
414                                               "org.freedesktop.DBus.Properties",
415                                               "Get",
416                                               g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Seats"),
417                                               G_VARIANT_TYPE ("(v)"),
418                                               G_DBUS_CALL_FLAGS_NONE,
419                                               1000,
420                                               NULL,
421                                               NULL);
422
423         status = g_string_new ("RUNNER LIST-SEATS SEATS=");
424         g_variant_get (result, "(v)", &value);
425         g_variant_get (value, "ao", &iter);
426         while (g_variant_iter_loop (iter, "&o", &path))
427         {
428             if (i != 0)
429                 g_string_append (status, ",");
430             g_string_append (status, path);
431             i++;
432         }
433         g_variant_unref (value);
434         g_variant_unref (result);
435
436         check_status (status->str);
437         g_string_free (status, TRUE);
438     }
439     else if (strcmp (name, "LIST-SESSIONS") == 0)
440     {
441         GVariant *result, *value;
442         GString *status;
443         GVariantIter *iter;
444         const gchar *path;
445         int i = 0;
446
447         result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
448                                               "org.freedesktop.DisplayManager",
449                                               "/org/freedesktop/DisplayManager",
450                                               "org.freedesktop.DBus.Properties",
451                                               "Get",
452                                               g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Sessions"),
453                                               G_VARIANT_TYPE ("(v)"),
454                                               G_DBUS_CALL_FLAGS_NONE,
455                                               1000,
456                                               NULL,
457                                               NULL);
458
459         status = g_string_new ("RUNNER LIST-SESSIONS SESSIONS=");
460         g_variant_get (result, "(v)", &value);
461         g_variant_get (value, "ao", &iter);
462         while (g_variant_iter_loop (iter, "&o", &path))
463         {
464             if (i != 0)
465                 g_string_append (status, ",");
466             g_string_append (status, path);
467             i++;
468         }
469         g_variant_unref (value);
470         g_variant_unref (result);
471
472         check_status (status->str);
473         g_string_free (status, TRUE);
474     }
475     else if (strcmp (name, "SWITCH-TO-GREETER") == 0)
476     {
477         g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
478                                      "org.freedesktop.DisplayManager",
479                                      "/org/freedesktop/DisplayManager/Seat0",
480                                      "org.freedesktop.DisplayManager.Seat",
481                                      "SwitchToGreeter",
482                                      g_variant_new ("()"),
483                                      G_VARIANT_TYPE ("()"),
484                                      G_DBUS_CALL_FLAGS_NONE,
485                                      1000,
486                                      NULL,
487                                      NULL);
488         check_status ("RUNNER SWITCH-TO-GREETER");
489     }
490     else if (strcmp (name, "SWITCH-TO-USER") == 0)
491     {
492         gchar *status_text, *username;
493
494         username = g_hash_table_lookup (params, "USERNAME");
495         g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
496                                      "org.freedesktop.DisplayManager",
497                                      "/org/freedesktop/DisplayManager/Seat0",
498                                      "org.freedesktop.DisplayManager.Seat",
499                                      "SwitchToUser",
500                                      g_variant_new ("(ss)", username, ""),
501                                      G_VARIANT_TYPE ("()"),
502                                      G_DBUS_CALL_FLAGS_NONE,
503                                      1000,
504                                      NULL,
505                                      NULL);
506         status_text = g_strdup_printf ("RUNNER SWITCH-TO-USER USERNAME=%s", username);
507         check_status (status_text);
508         g_free (status_text);
509     }
510     else if (strcmp (name, "SWITCH-TO-GUEST") == 0)
511     {
512         g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
513                                      "org.freedesktop.DisplayManager",
514                                      "/org/freedesktop/DisplayManager/Seat0",
515                                      "org.freedesktop.DisplayManager.Seat",
516                                      "SwitchToGuest",
517                                      g_variant_new ("(s)", ""),
518                                      G_VARIANT_TYPE ("()"),
519                                      G_DBUS_CALL_FLAGS_NONE,
520                                      1000,
521                                      NULL,
522                                      NULL);
523         check_status ("RUNNER SWITCH-TO-GUEST");
524     }
525     else if (strcmp (name, "STOP-DAEMON") == 0)
526         stop_process (lightdm_process);
527     // FIXME: Make generic RUN-COMMAND
528     else if (strcmp (name, "START-XSERVER") == 0)
529     {
530         gchar *xserver_args, *command_line;
531         gchar **argv;
532         GPid pid;
533         Process *process;
534         GError *error = NULL;
535
536         xserver_args = g_hash_table_lookup (params, "ARGS");
537         if (!xserver_args)
538             xserver_args = "";
539         command_line = g_strdup_printf ("%s/tests/src/X %s", BUILDDIR, xserver_args);
540
541         if (!g_shell_parse_argv (command_line, NULL, &argv, &error) ||
542             !g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &error))
543         {
544             g_printerr ("Error starting X server: %s", error->message);
545             quit (EXIT_FAILURE);
546         }
547         else
548         {
549             process = watch_process (pid);
550             g_hash_table_insert (children, GINT_TO_POINTER (process->pid), process);
551         }
552     }
553     else if (strcmp (name, "START-VNC-CLIENT") == 0)
554     {
555         gchar *vnc_client_args, *command_line;
556         gchar **argv;
557         GPid pid;
558         Process *process;
559         GError *error = NULL;
560
561         vnc_client_args = g_hash_table_lookup (params, "ARGS");
562         if (!vnc_client_args)
563             vnc_client_args = "";
564         command_line = g_strdup_printf ("%s/tests/src/vnc-client %s", BUILDDIR, vnc_client_args);
565
566         if (!g_shell_parse_argv (command_line, NULL, &argv, &error) ||
567             !g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &error))
568         {
569             g_printerr ("Error starting VNC client: %s", error->message);
570             quit (EXIT_FAILURE);
571         }
572         else
573         {
574             process = watch_process (pid);
575             g_hash_table_insert (children, GINT_TO_POINTER (process->pid), process);
576         }
577     }
578     else if (strcmp (name, "ADD-USER") == 0)
579     {
580         gchar *status_text, *username;
581         AccountsUser *user;
582
583         username = g_hash_table_lookup (params, "USERNAME");
584         user = get_accounts_user_by_name (username);
585         if (user)
586             accounts_user_set_hidden (user, FALSE, TRUE);
587         else
588             g_warning ("Unknown user %s", username);
589
590         status_text = g_strdup_printf ("RUNNER ADD-USER USERNAME=%s", username);
591         check_status (status_text);
592         g_free (status_text);
593     }
594     else if (strcmp (name, "UPDATE-USER") == 0)
595     {
596         GString *status_text;
597         gchar *username;
598         AccountsUser *user;
599         GError *error = NULL;
600
601         status_text = g_string_new ("RUNNER UPDATE-USER USERNAME=");
602
603         username = g_hash_table_lookup (params, "USERNAME");
604         g_string_append (status_text, username);
605         user = get_accounts_user_by_name (username);
606         if (user)
607         {
608             if (g_hash_table_lookup (params, "NAME"))
609             {
610                 user->user_name = g_strdup (g_hash_table_lookup (params, "NAME"));
611                 g_string_append_printf (status_text, " NAME=%s", user->user_name);
612             }
613             if (g_hash_table_lookup (params, "REAL-NAME"))
614             {
615                 user->real_name = g_strdup (g_hash_table_lookup (params, "REAL-NAME"));
616                 g_string_append_printf (status_text, " REAL-NAME=%s", user->real_name);
617             }
618             if (g_hash_table_lookup (params, "HOME-DIRECTORY"))
619             {
620                 user->home_directory = g_strdup (g_hash_table_lookup (params, "HOME-DIRECTORY"));
621                 g_string_append_printf (status_text, " HOME-DIRECTORY=%s", user->home_directory);
622             }
623             if (g_hash_table_lookup (params, "IMAGE"))
624             {
625                 user->image = g_strdup (g_hash_table_lookup (params, "IMAGE"));
626                 g_string_append_printf (status_text, " IMAGE=%s", user->image);
627             }
628             if (g_hash_table_lookup (params, "BACKGROUND"))
629             {
630                 user->background = g_strdup (g_hash_table_lookup (params, "BACKGROUND"));
631                 g_string_append_printf (status_text, " BACKGROUND=%s", user->background);
632             }
633             if (g_hash_table_lookup (params, "LANGUAGE"))
634             {
635                 user->language = g_strdup (g_hash_table_lookup (params, "LANGUAGE"));
636                 g_string_append_printf (status_text, " LANGUAGE=%s", user->language);
637             }
638             if (g_hash_table_lookup (params, "LAYOUTS"))
639             {
640                 const gchar *value = g_hash_table_lookup (params, "LAYOUTS");
641                 user->layouts = g_strsplit (value, ";", -1);
642                 g_string_append_printf (status_text, " LAYOUTS=%s", value);
643             }
644             if (g_hash_table_lookup (params, "HAS-MESSAGES"))
645             {
646                 user->has_messages = g_strcmp0 (g_hash_table_lookup (params, "HAS-MESSAGES"), "TRUE") == 0;
647                 g_string_append_printf (status_text, " HAS-MESSAGES=%s", user->has_messages ? "TRUE" : "FALSE");
648             }
649             if (g_hash_table_lookup (params, "SESSION"))
650             {
651                 user->xsession = g_strdup (g_hash_table_lookup (params, "SESSION"));
652                 g_string_append_printf (status_text, " SESSION=%s", user->xsession);
653             }
654         }
655         else
656             g_warning ("Unknown user %s", username);
657
658         g_dbus_connection_emit_signal (accounts_connection,
659                                        NULL,
660                                        user->path,
661                                        "org.freedesktop.Accounts.User",
662                                        "Changed",
663                                        g_variant_new ("()"),
664                                        &error);
665         if (error)
666             g_warning ("Failed to emit Changed: %s", error->message);
667         g_clear_error (&error);
668
669         check_status (status_text->str);
670         g_string_free (status_text, TRUE);
671     }
672     else if (strcmp (name, "DELETE-USER") == 0)
673     {
674         gchar *status_text, *username;
675         AccountsUser *user;
676
677         username = g_hash_table_lookup (params, "USERNAME");
678         user = get_accounts_user_by_name (username);
679         if (user)
680             accounts_user_set_hidden (user, TRUE, TRUE);
681         else
682             g_warning ("Unknown user %s", username);
683
684         status_text = g_strdup_printf ("RUNNER DELETE-USER USERNAME=%s", username);
685         check_status (status_text);
686         g_free (status_text);
687     }
688     /* Forward to external processes */
689     else if (g_str_has_prefix (name, "SESSION-") ||
690              g_str_has_prefix (name, "GREETER-") ||
691              g_str_has_prefix (name, "XSERVER-") ||
692              strcmp (name, "UNITY-SYSTEM-COMPOSITOR") == 0)
693     {
694         GList *link;
695         for (link = status_clients; link; link = link->next)
696         {
697             StatusClient *client = link->data;
698             int length;
699             GError *error = NULL;
700
701             length = strlen (command);
702             if (g_socket_send (client->socket, (gchar *) &length, sizeof (length), NULL, &error) < 0 ||
703                 g_socket_send (client->socket, command, strlen (command), NULL, &error) < 0)
704                 g_printerr ("Failed to write to client socket: %s\n", error->message);
705             g_clear_error (&error);
706         }
707     }
708     else
709     {
710         g_printerr ("Unknown command '%s'\n", name);
711         quit (EXIT_FAILURE);
712     }
713
714     g_free (name);
715     g_hash_table_unref (params);
716 }
717
718 static void
719 run_commands (void)
720 {
721     /* Stop daemon if requested */
722     while (TRUE)
723     {
724         ScriptLine *line;
725
726         /* Commands start with an asterisk */
727         line = get_script_line (NULL);
728         if (!line || line->text[0] != '*')
729             break;
730
731         statuses = g_list_append (statuses, g_strdup (line->text));
732         line->done = TRUE;
733
734         handle_command (line->text + 1);
735     }
736
737     /* Stop at the end of the script */
738     if (get_script_line (NULL) == NULL)
739         quit (EXIT_SUCCESS);
740 }
741
742 static gboolean
743 status_timeout_cb (gpointer data)
744 {
745     ScriptLine *line;
746
747     line = get_script_line (NULL);
748     fail ("(timeout)", line ? line->text : NULL);
749
750     return FALSE;
751 }
752
753 static void
754 check_status (const gchar *status)
755 {
756     ScriptLine *line;
757     gboolean result = FALSE;
758     gchar *prefix;
759
760     if (stop)
761         return;
762
763     statuses = g_list_append (statuses, g_strdup (status));
764
765     if (getenv ("DEBUG"))
766         g_print ("%s\n", status);
767
768     /* Try and match against expected */
769     prefix = get_prefix (status);
770     line = get_script_line (prefix);
771     g_free (prefix);
772     if (line)
773     {
774         gchar *full_pattern = g_strdup_printf ("^%s$", line->text);
775         result = g_regex_match_simple (full_pattern, status, 0, 0);
776         g_free (full_pattern);
777     }
778
779     if (!result)
780     {
781         if (line == NULL)
782             line = get_script_line (NULL);
783         fail (NULL, line ? line->text : NULL);
784         return;
785     }
786
787     line->done = TRUE;
788
789     /* Restart timeout */
790     g_source_remove (status_timeout);
791     status_timeout = g_timeout_add (status_timeout_ms, status_timeout_cb, NULL);
792
793     run_commands ();
794 }
795
796 static gboolean
797 status_message_cb (GSocket *socket, GIOCondition condition, StatusClient *client)
798 {
799     int length;
800     gchar buffer[1024];
801     ssize_t n_read;
802     GError *error = NULL;
803
804     n_read = g_socket_receive (socket, (gchar *)&length, sizeof (length), NULL, &error);
805     if (n_read > 0)
806         n_read = g_socket_receive (socket, buffer, length, NULL, &error);
807     if (error)
808         g_warning ("Error reading from socket: %s", error->message);
809     g_clear_error (&error);
810     if (n_read == 0)
811     {
812         status_clients = g_list_remove (status_clients, client);
813         g_object_unref (client->socket);
814         g_free (client);
815         return FALSE;
816     }
817     else if (n_read > 0)
818     {
819         buffer[n_read] = '\0';
820         check_status (buffer);
821     }
822
823     return TRUE;
824 }
825
826 static gboolean
827 status_connect_cb (gpointer data)
828 {
829     GSocket *socket;
830     GError *error = NULL;
831
832     socket = g_socket_accept (status_socket, NULL, &error);
833     if (error)
834         g_warning ("Failed to accept status connection: %s", error->message);
835     g_clear_error (&error);
836     if (socket)
837     {
838         StatusClient *client;
839
840         client = g_malloc0 (sizeof (StatusClient));
841         client->socket = socket;
842         client->source = g_socket_create_source (socket, G_IO_IN, NULL);
843         status_clients = g_list_append (status_clients, client);
844
845         g_source_set_callback (client->source, (GSourceFunc) status_message_cb, client, NULL);
846         g_source_attach (client->source, NULL);
847     }
848
849     return TRUE;
850 }
851
852 static void
853 load_script (const gchar *filename)
854 {
855     int i;
856     gchar *data, **lines;
857
858     if (!g_file_get_contents (filename, &data, NULL, NULL))
859     {
860         g_printerr ("Unable to load script: %s\n", filename);
861         quit (EXIT_FAILURE);
862     }
863
864     lines = g_strsplit (data, "\n", -1);
865     g_free (data);
866
867     /* Load lines with #? prefix as expected behaviour */
868     for (i = 0; lines[i]; i++)
869     {
870         gchar *text = g_strstrip (lines[i]);
871         if (g_str_has_prefix (text, "#?"))
872         {
873             ScriptLine *line;
874             line = g_malloc0 (sizeof (ScriptLine));
875             line->text = g_strdup (text + 2);
876             line->done = FALSE;
877             script = g_list_append (script, line);
878         }
879     }
880     g_strfreev (lines);
881 }
882
883 static void
884 handle_upower_call (GDBusConnection       *connection,
885                     const gchar           *sender,
886                     const gchar           *object_path,
887                     const gchar           *interface_name,
888                     const gchar           *method_name,
889                     GVariant              *parameters,
890                     GDBusMethodInvocation *invocation,
891                     gpointer               user_data)
892 {
893     if (strcmp (method_name, "SuspendAllowed") == 0)
894     {
895         check_status ("UPOWER SUSPEND-ALLOWED");
896         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
897     }
898     else if (strcmp (method_name, "Suspend") == 0)
899     {
900         check_status ("UPOWER SUSPEND");
901         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
902     }
903     else if (strcmp (method_name, "HibernateAllowed") == 0)
904     {
905         check_status ("UPOWER HIBERNATE-ALLOWED");
906         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
907     }
908     else if (strcmp (method_name, "Hibernate") == 0)
909     {
910         check_status ("UPOWER HIBERNATE");
911         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
912     }
913     else
914         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
915 }
916
917 static void
918 upower_name_acquired_cb (GDBusConnection *connection,
919                          const gchar     *name,
920                          gpointer         user_data)
921 {
922     const gchar *upower_interface =
923         "<node>"
924         "  <interface name='org.freedesktop.UPower'>"
925         "    <method name='SuspendAllowed'>"
926         "      <arg name='allowed' direction='out' type='b'/>"
927         "    </method>"
928         "    <method name='Suspend'/>"
929         "    <method name='HibernateAllowed'>"
930         "      <arg name='allowed' direction='out' type='b'/>"
931         "    </method>"
932         "    <method name='Hibernate'/>"
933         "  </interface>"
934         "</node>";
935     static const GDBusInterfaceVTable upower_vtable =
936     {
937         handle_upower_call,
938     };
939     GDBusNodeInfo *upower_info;
940     GError *error = NULL;
941
942     upower_info = g_dbus_node_info_new_for_xml (upower_interface, &error);
943     if (error)
944         g_warning ("Failed to parse D-Bus interface: %s", error->message);
945     g_clear_error (&error);
946     if (!upower_info)
947         return;
948     g_dbus_connection_register_object (connection,
949                                        "/org/freedesktop/UPower",
950                                        upower_info->interfaces[0],
951                                        &upower_vtable,
952                                        NULL, NULL,
953                                        &error);
954     if (error)
955         g_warning ("Failed to register UPower service: %s", error->message);
956     g_clear_error (&error);
957     g_dbus_node_info_unref (upower_info);
958
959     service_count--;
960     if (service_count == 0)
961         run_lightdm ();
962 }
963
964 static void
965 start_upower_daemon (void)
966 {
967     service_count++;
968     g_bus_own_name (G_BUS_TYPE_SYSTEM,
969                     "org.freedesktop.UPower",
970                     G_BUS_NAME_OWNER_FLAGS_NONE,
971                     upower_name_acquired_cb,
972                     NULL,
973                     NULL,
974                     NULL,
975                     NULL);
976 }
977
978 static CKSession *
979 open_ck_session (GVariant *params)
980 {
981     CKSession *session;
982     GString *cookie;
983     GVariantIter *iter;
984     const gchar *name;
985     GVariant *value;
986     GError *error = NULL;
987
988     session = g_malloc0 (sizeof (CKSession));
989     ck_sessions = g_list_append (ck_sessions, session);
990
991     cookie = g_string_new ("ck-cookie");
992     g_variant_get (params, "a(sv)", &iter);
993     while (g_variant_iter_loop (iter, "(&sv)", &name, &value))
994     {
995         if (strcmp (name, "x11-display") == 0)
996         {
997             const gchar *display;
998             g_variant_get (value, "&s", &display);
999             g_string_append_printf (cookie, "-x%s", display);
1000         }
1001     }
1002
1003     session->cookie = cookie->str;
1004     g_string_free (cookie, FALSE);
1005     session->path = g_strdup_printf ("/org/freedesktop/ConsoleKit/Session%d", ck_session_index++);
1006     session->id = g_dbus_connection_register_object (ck_connection,
1007                                                      session->path,
1008                                                      ck_session_info->interfaces[0],
1009                                                      &ck_session_vtable,
1010                                                      session,
1011                                                      NULL,
1012                                                      &error);
1013     if (error)
1014         g_warning ("Failed to register CK Session: %s", error->message);
1015     g_clear_error (&error);
1016
1017     return session;
1018 }
1019
1020 static void
1021 handle_ck_call (GDBusConnection       *connection,
1022                 const gchar           *sender,
1023                 const gchar           *object_path,
1024                 const gchar           *interface_name,
1025                 const gchar           *method_name,
1026                 GVariant              *parameters,
1027                 GDBusMethodInvocation *invocation,
1028                 gpointer               user_data)
1029 {
1030     if (strcmp (method_name, "CanRestart") == 0)
1031     {
1032         check_status ("CONSOLE-KIT CAN-RESTART");
1033         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
1034     }
1035     else if (strcmp (method_name, "CanStop") == 0)
1036     {
1037         check_status ("CONSOLE-KIT CAN-STOP");
1038         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
1039     }
1040     else if (strcmp (method_name, "CloseSession") == 0)
1041         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
1042     else if (strcmp (method_name, "OpenSession") == 0)
1043     {
1044         GVariantBuilder params;
1045         g_variant_builder_init (&params, G_VARIANT_TYPE ("a(sv)"));
1046         CKSession *session = open_ck_session (g_variant_builder_end (&params));
1047         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", session->cookie));
1048     }
1049     else if (strcmp (method_name, "OpenSessionWithParameters") == 0)
1050     {
1051         CKSession *session = open_ck_session (g_variant_get_child_value (parameters, 0));
1052         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", session->cookie));
1053     }
1054     else if (strcmp (method_name, "GetSessionForCookie") == 0)
1055     {
1056         GList *link;
1057         gchar *cookie;
1058
1059         g_variant_get (parameters, "(&s)", &cookie);
1060
1061         for (link = ck_sessions; link; link = link->next)
1062         {
1063             CKSession *session = link->data;
1064             if (strcmp (session->cookie, cookie) != 0)
1065             {
1066                 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", session->path));
1067                 return;
1068             }
1069         }
1070
1071         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Unable to find session for cookie");
1072     }
1073     else if (strcmp (method_name, "Restart") == 0)
1074     {
1075         check_status ("CONSOLE-KIT RESTART");
1076         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1077     }
1078     else if (strcmp (method_name, "Stop") == 0)
1079     {
1080         check_status ("CONSOLE-KIT STOP");
1081         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1082     }
1083     else
1084         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1085 }
1086
1087 static void
1088 handle_ck_session_call (GDBusConnection       *connection,
1089                         const gchar           *sender,
1090                         const gchar           *object_path,
1091                         const gchar           *interface_name,
1092                         const gchar           *method_name,
1093                         GVariant              *parameters,
1094                         GDBusMethodInvocation *invocation,
1095                         gpointer               user_data)
1096 {
1097     CKSession *session = user_data;
1098
1099     if (strcmp (method_name, "Lock") == 0)
1100     { 
1101         if (!session->locked)
1102             check_status ("CONSOLE-KIT LOCK-SESSION");
1103         session->locked = TRUE;
1104         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1105     }
1106     else if (strcmp (method_name, "Unlock") == 0)
1107     {
1108         if (session->locked)
1109             check_status ("CONSOLE-KIT UNLOCK-SESSION");
1110         session->locked = FALSE;
1111         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1112     }
1113     else
1114         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1115 }
1116
1117 static void
1118 ck_name_acquired_cb (GDBusConnection *connection,
1119                      const gchar     *name,
1120                      gpointer         user_data)
1121 {
1122     const gchar *ck_interface =
1123         "<node>"
1124         "  <interface name='org.freedesktop.ConsoleKit.Manager'>"
1125         "    <method name='CanRestart'>"
1126         "      <arg name='can_restart' direction='out' type='b'/>"
1127         "    </method>"
1128         "    <method name='CanStop'>"
1129         "      <arg name='can_stop' direction='out' type='b'/>"
1130         "    </method>"
1131         "    <method name='CloseSession'>"
1132         "      <arg name='cookie' direction='in' type='s'/>"
1133         "      <arg name='result' direction='out' type='b'/>"
1134         "    </method>"
1135         "    <method name='OpenSession'>"
1136         "      <arg name='cookie' direction='out' type='s'/>"
1137         "    </method>"
1138         "    <method name='OpenSessionWithParameters'>"
1139         "      <arg name='parameters' direction='in' type='a(sv)'/>"
1140         "      <arg name='cookie' direction='out' type='s'/>"
1141         "    </method>"
1142         "    <method name='GetSessionForCookie'>"
1143         "      <arg name='cookie' direction='in' type='s'/>"
1144         "      <arg name='ssid' direction='out' type='o'/>"
1145         "    </method>"
1146         "    <method name='Restart'/>"
1147         "    <method name='Stop'/>"
1148         "    <signal name='SeatAdded'>"
1149         "      <arg name='seat' type='o'/>"
1150         "    </signal>"
1151         "    <signal name='SeatRemoved'>"
1152         "      <arg name='seat' type='o'/>"
1153         "    </signal>"
1154         "  </interface>"
1155         "</node>";
1156     static const GDBusInterfaceVTable ck_vtable =
1157     {
1158         handle_ck_call,
1159     };
1160     const gchar *ck_session_interface =
1161         "<node>"
1162         "  <interface name='org.freedesktop.ConsoleKit.Session'>"
1163         "    <method name='Lock'/>"
1164         "    <method name='Unlock'/>"
1165         "  </interface>"
1166         "</node>";
1167     GDBusNodeInfo *ck_info;
1168     GError *error = NULL;
1169
1170     ck_connection = connection;
1171
1172     ck_info = g_dbus_node_info_new_for_xml (ck_interface, &error);
1173     if (error)
1174         g_warning ("Failed to parse D-Bus interface: %s", error->message);
1175     g_clear_error (&error);
1176     if (!ck_info)
1177         return;
1178     ck_session_info = g_dbus_node_info_new_for_xml (ck_session_interface, &error);
1179     if (error)
1180         g_warning ("Failed to parse D-Bus interface: %s", error->message);
1181     g_clear_error (&error);
1182     if (!ck_session_info)
1183         return;
1184     g_dbus_connection_register_object (connection,
1185                                        "/org/freedesktop/ConsoleKit/Manager",
1186                                        ck_info->interfaces[0],
1187                                        &ck_vtable,
1188                                        NULL, NULL,
1189                                        &error);
1190     if (error)
1191         g_warning ("Failed to register console kit service: %s", error->message);
1192     g_clear_error (&error);
1193     g_dbus_node_info_unref (ck_info);
1194
1195     service_count--;
1196     if (service_count == 0)
1197         run_lightdm ();
1198 }
1199
1200 static void
1201 start_console_kit_daemon (void)
1202 {
1203     service_count++;
1204     g_bus_own_name (G_BUS_TYPE_SYSTEM,
1205                     "org.freedesktop.ConsoleKit",
1206                     G_BUS_NAME_OWNER_FLAGS_NONE,
1207                     ck_name_acquired_cb,
1208                     NULL,
1209                     NULL,
1210                     NULL,
1211                     NULL);
1212 }
1213
1214 static void
1215 handle_login1_session_call (GDBusConnection       *connection,
1216                             const gchar           *sender,
1217                             const gchar           *object_path,
1218                             const gchar           *interface_name,
1219                             const gchar           *method_name,
1220                             GVariant              *parameters,
1221                             GDBusMethodInvocation *invocation,
1222                             gpointer               user_data)
1223 {
1224     Login1Session *session = user_data;
1225
1226     if (strcmp (method_name, "Lock") == 0)
1227     {
1228         if (!session->locked)
1229             check_status ("LOGIN1 LOCK-SESSION");
1230         session->locked = TRUE;
1231         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1232     }
1233     else if (strcmp (method_name, "Unlock") == 0)
1234     {
1235         if (session->locked)
1236             check_status ("LOGIN1 UNLOCK-SESSION");
1237         session->locked = FALSE;
1238         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1239     }
1240     else
1241         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1242 }
1243
1244 static Login1Session *
1245 open_login1_session (GDBusConnection *connection,
1246                      GVariant *params)
1247 {
1248     Login1Session *session;
1249     GError *error = NULL;
1250     GDBusNodeInfo *login1_session_info;
1251
1252     const gchar *login1_session_interface =
1253         "<node>"
1254         "  <interface name='org.freedesktop.login1.Session'>"
1255         "    <method name='Lock'/>"
1256         "    <method name='Unlock'/>"
1257         "  </interface>"
1258         "</node>";
1259     static const GDBusInterfaceVTable login1_session_vtable =
1260     {
1261         handle_login1_session_call,
1262     };
1263
1264     session = g_malloc0 (sizeof (Login1Session));
1265     login1_sessions = g_list_append (login1_sessions, session);
1266
1267     session->path = g_strdup_printf("/org/freedesktop/login1/Session/c%d",
1268                                     login1_session_index++);
1269
1270
1271
1272     login1_session_info = g_dbus_node_info_new_for_xml (login1_session_interface,
1273                                                         &error);
1274     if (error)
1275         g_warning ("Failed to parse login1 session D-Bus interface: %s",
1276                    error->message);
1277     g_clear_error (&error);
1278     if (!login1_session_info)
1279         return NULL;
1280
1281     g_dbus_connection_register_object (connection,
1282                                        session->path,
1283                                        login1_session_info->interfaces[0],
1284                                        &login1_session_vtable,
1285                                        session,
1286                                        NULL,
1287                                        &error);
1288     if (error)
1289         g_warning ("Failed to register login1 session: %s", error->message);
1290     g_clear_error (&error);
1291     g_dbus_node_info_unref (login1_session_info);
1292
1293     return session;
1294 }
1295
1296
1297 static void
1298 handle_login1_call (GDBusConnection       *connection,
1299                     const gchar           *sender,
1300                     const gchar           *object_path,
1301                     const gchar           *interface_name,
1302                     const gchar           *method_name,
1303                     GVariant              *parameters,
1304                     GDBusMethodInvocation *invocation,
1305                     gpointer               user_data)
1306 {
1307
1308     if (strcmp (method_name, "GetSessionByPID") == 0)
1309     {
1310         /* Look for a session with our PID, and create one if we don't have one
1311            already. */
1312         GList *link;
1313         guint pid;
1314         Login1Session *ret = NULL;
1315
1316         g_variant_get (parameters, "(u)", &pid);
1317
1318         for (link = login1_sessions; link; link = link->next)
1319         {
1320             Login1Session *session;
1321             session = link->data;
1322             if (session->pid == pid)
1323             {
1324                 ret = session;
1325                 break;
1326             }
1327         }
1328         /* Not found */
1329         if (!ret)
1330             ret = open_login1_session (connection, parameters);
1331
1332         g_dbus_method_invocation_return_value (invocation,
1333                                                g_variant_new("(o)", ret->path));
1334
1335     }
1336     else if (strcmp (method_name, "CanReboot") == 0)
1337     {
1338         check_status ("LOGIN1 CAN-REBOOT");
1339         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1340     }
1341     else if (strcmp (method_name, "Reboot") == 0)
1342     {
1343         gboolean interactive;
1344         g_variant_get (parameters, "(b)", &interactive);
1345         check_status ("LOGIN1 REBOOT");
1346         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1347     }
1348     else if (strcmp (method_name, "CanPowerOff") == 0)
1349     {
1350         check_status ("LOGIN1 CAN-POWER-OFF");
1351         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1352     }
1353     else if (strcmp (method_name, "Suspend") == 0)
1354     {
1355         gboolean interactive;
1356         g_variant_get (parameters, "(b)", &interactive);
1357         check_status ("LOGIN1 SUSPEND");
1358         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1359     }
1360     else if (strcmp (method_name, "CanSuspend") == 0)
1361     {
1362         check_status ("LOGIN1 CAN-SUSPEND");
1363         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1364     }
1365     else if (strcmp (method_name, "PowerOff") == 0)
1366     {
1367         gboolean interactive;
1368         g_variant_get (parameters, "(b)", &interactive);
1369         check_status ("LOGIN1 POWER-OFF");
1370         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1371     }
1372     else if (strcmp (method_name, "CanHibernate") == 0)
1373     {
1374         check_status ("LOGIN1 CAN-HIBERNATE");
1375         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1376     }
1377     else if (strcmp (method_name, "Hibernate") == 0)
1378     {
1379         gboolean interactive;
1380         g_variant_get (parameters, "(b)", &interactive);
1381         check_status ("LOGIN1 HIBERNATE");
1382         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1383     }
1384     else
1385         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1386 }
1387
1388 static void
1389 login1_name_acquired_cb (GDBusConnection *connection,
1390                          const gchar     *name,
1391                          gpointer         user_data)
1392 {
1393     const gchar *login1_interface =
1394         "<node>"
1395         "  <interface name='org.freedesktop.login1.Manager'>"
1396         "    <method name='GetSessionByPID'>"
1397         "      <arg name='pid' type='u' direction='in'/>"
1398         "      <arg name='session' type='o' direction='out'/>"
1399         "    </method>"
1400         "    <method name='CanReboot'>"
1401         "      <arg name='result' direction='out' type='s'/>"
1402         "    </method>"
1403         "    <method name='Reboot'>"
1404         "      <arg name='interactive' direction='in' type='b'/>"
1405         "    </method>"
1406         "    <method name='CanPowerOff'>"
1407         "      <arg name='result' direction='out' type='s'/>"
1408         "    </method>"
1409         "    <method name='PowerOff'>"
1410         "      <arg name='interactive' direction='in' type='b'/>"
1411         "    </method>"
1412         "    <method name='CanSuspend'>"
1413         "      <arg name='result' direction='out' type='s'/>"
1414         "    </method>"
1415         "    <method name='Suspend'>"
1416         "      <arg name='interactive' direction='in' type='b'/>"
1417         "    </method>"
1418         "    <method name='CanHibernate'>"
1419         "      <arg name='result' direction='out' type='s'/>"
1420         "    </method>"
1421         "    <method name='Hibernate'>"
1422         "      <arg name='interactive' direction='in' type='b'/>"
1423         "    </method>"
1424         "  </interface>"
1425         "</node>";
1426     static const GDBusInterfaceVTable login1_vtable =
1427     {
1428         handle_login1_call,
1429     };
1430     GDBusNodeInfo *login1_info;
1431     GError *error = NULL;
1432
1433     login1_info = g_dbus_node_info_new_for_xml (login1_interface, &error);
1434     if (error)
1435         g_warning ("Failed to parse login1 D-Bus interface: %s", error->message);
1436     g_clear_error (&error);
1437     if (!login1_info)
1438         return;
1439     g_dbus_connection_register_object (connection,
1440                                        "/org/freedesktop/login1",
1441                                        login1_info->interfaces[0],
1442                                        &login1_vtable,
1443                                        NULL, NULL,
1444                                        &error);
1445     if (error)
1446         g_warning ("Failed to register login1 service: %s", error->message);
1447     g_clear_error (&error);
1448     g_dbus_node_info_unref (login1_info);
1449
1450     service_count--;
1451     if (service_count == 0)
1452         run_lightdm ();
1453 }
1454
1455 static void
1456 start_login1_daemon (void)
1457 {
1458     service_count++;
1459     g_bus_own_name (G_BUS_TYPE_SYSTEM,
1460                     "org.freedesktop.login1",
1461                     G_BUS_NAME_OWNER_FLAGS_NONE,
1462                     login1_name_acquired_cb,
1463                     NULL,
1464                     NULL,
1465                     NULL,
1466                     NULL);
1467 }
1468
1469 static AccountsUser *
1470 get_accounts_user_by_uid (guint uid)
1471 {
1472     GList *link;
1473
1474     for (link = accounts_users; link; link = link->next)
1475     {
1476         AccountsUser *u = link->data;
1477         if (u->uid == uid)
1478             return u;
1479     }
1480   
1481     return NULL;
1482 }
1483
1484 static AccountsUser *
1485 get_accounts_user_by_name (const gchar *username)
1486 {
1487     GList *link;
1488
1489     for (link = accounts_users; link; link = link->next)
1490     {
1491         AccountsUser *u = link->data;
1492         if (strcmp (u->user_name, username) == 0)
1493             return u;
1494     }
1495
1496     return NULL;
1497 }
1498
1499 static void
1500 accounts_user_set_hidden (AccountsUser *user, gboolean hidden, gboolean emit_signal)
1501 {
1502     GError *error = NULL;
1503
1504     user->hidden = hidden;
1505
1506     if (user->hidden && user->id != 0)
1507     {
1508         g_dbus_connection_unregister_object (accounts_connection, user->id);
1509         g_dbus_connection_emit_signal (accounts_connection,
1510                                        NULL,
1511                                        "/org/freedesktop/Accounts",
1512                                        "org.freedesktop.Accounts",
1513                                        "UserDeleted",
1514                                        g_variant_new ("(o)", user->path),
1515                                        &error);
1516         if (error)
1517             g_warning ("Failed to emit UserDeleted: %s", error->message);
1518         g_clear_error (&error);
1519
1520         user->id = 0;
1521     }
1522     if (!user->hidden && user->id == 0)
1523     {
1524         user->id = g_dbus_connection_register_object (accounts_connection,
1525                                                       user->path,
1526                                                       user_info->interfaces[0],
1527                                                       &user_vtable,
1528                                                       user,
1529                                                       NULL,
1530                                                       &error);
1531         if (error)
1532             g_warning ("Failed to register user: %s", error->message);
1533         g_clear_error (&error);
1534
1535         g_dbus_connection_emit_signal (accounts_connection,
1536                                        NULL,
1537                                        "/org/freedesktop/Accounts",
1538                                        "org.freedesktop.Accounts",
1539                                        "UserAdded",
1540                                        g_variant_new ("(o)", user->path),
1541                                        &error);
1542         if (error)
1543             g_warning ("Failed to emit UserAdded: %s", error->message);
1544         g_clear_error (&error);
1545     }
1546 }
1547
1548 static void
1549 load_passwd_file (void)
1550 {
1551     gchar *path, *data, **lines;
1552     gchar **user_filter = NULL;
1553     int i;
1554
1555     if (g_key_file_has_key (config, "test-runner-config", "accounts-service-user-filter", NULL))
1556     {
1557         gchar *filter;
1558
1559         filter = g_key_file_get_string (config, "test-runner-config", "accounts-service-user-filter", NULL);
1560         user_filter = g_strsplit (filter, " ", -1);
1561         g_free (filter);
1562     }
1563
1564     path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "passwd", NULL);
1565     g_file_get_contents (path, &data, NULL, NULL);
1566     g_free (path);
1567     lines = g_strsplit (data, "\n", -1);
1568     g_free (data);
1569
1570     for (i = 0; lines[i]; i++)
1571     {
1572         gchar **fields;
1573         guint uid;
1574         gchar *user_name, *real_name;
1575         AccountsUser *user = NULL;
1576
1577         fields = g_strsplit (lines[i], ":", -1);
1578         if (fields == NULL || g_strv_length (fields) < 7)
1579         {
1580             g_strfreev (fields);
1581             continue;
1582         }
1583
1584         user_name = fields[0];
1585         uid = atoi (fields[2]);
1586         real_name = fields[4];
1587
1588         user = get_accounts_user_by_uid (uid);
1589         if (!user)
1590         {
1591             gchar *path;
1592             GKeyFile *dmrc_file;
1593
1594             user = g_malloc0 (sizeof (AccountsUser));
1595             accounts_users = g_list_append (accounts_users, user);
1596
1597             /* Only allow users in whitelist */
1598             user->hidden = FALSE;
1599             if (user_filter)
1600             {
1601                 int j;
1602
1603                 user->hidden = TRUE;
1604                 for (j = 0; user_filter[j] != NULL; j++)
1605                     if (strcmp (user_name, user_filter[j]) == 0)
1606                         user->hidden = FALSE;
1607             }
1608
1609             dmrc_file = g_key_file_new ();
1610             path = g_build_filename (temp_dir, "home", user_name, ".dmrc", NULL);
1611             g_key_file_load_from_file (dmrc_file, path, G_KEY_FILE_NONE, NULL);
1612             g_free (path);
1613
1614             user->uid = uid;
1615             user->user_name = g_strdup (user_name);
1616             user->real_name = g_strdup (real_name);
1617             user->home_directory = g_build_filename (temp_dir, "home", user_name, NULL);
1618             user->language = g_key_file_get_string (dmrc_file, "Desktop", "Language", NULL);
1619             /* DMRC contains a locale, strip the codeset off it to get the language */
1620             if (user->language)
1621             {
1622                 gchar *c = strchr (user->language, '.');
1623                 if (c)
1624                     *c = '\0';
1625             }
1626             user->xsession = g_key_file_get_string (dmrc_file, "Desktop", "Session", NULL);
1627             user->layouts = g_key_file_get_string_list (dmrc_file, "X-Accounts", "Layouts", NULL, NULL);
1628             if (!user->layouts)
1629             {
1630                 user->layouts = g_malloc (sizeof (gchar *) * 2);
1631                 user->layouts[0] = g_key_file_get_string (dmrc_file, "Desktop", "Layout", NULL);
1632                 user->layouts[1] = NULL;
1633             }
1634             user->has_messages = g_key_file_get_boolean (dmrc_file, "X-Accounts", "HasMessages", NULL);
1635             user->path = g_strdup_printf ("/org/freedesktop/Accounts/User%d", uid);
1636             accounts_user_set_hidden (user, user->hidden, FALSE);
1637
1638             g_key_file_free (dmrc_file);
1639         }
1640
1641         g_strfreev (fields);
1642     }
1643
1644     g_strfreev (lines);
1645 }
1646
1647 static void
1648 handle_accounts_call (GDBusConnection       *connection,
1649                       const gchar           *sender,
1650                       const gchar           *object_path,
1651                       const gchar           *interface_name,
1652                       const gchar           *method_name,
1653                       GVariant              *parameters,
1654                       GDBusMethodInvocation *invocation,
1655                       gpointer               user_data)
1656 {
1657     if (strcmp (method_name, "ListCachedUsers") == 0)
1658     {
1659         GVariantBuilder builder;
1660         GList *link;
1661
1662         g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
1663
1664         load_passwd_file ();
1665         for (link = accounts_users; link; link = link->next)
1666         {
1667             AccountsUser *user = link->data;
1668             if (!user->hidden && user->uid >= 1000)
1669                 g_variant_builder_add_value (&builder, g_variant_new_object_path (user->path));
1670         }
1671
1672         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(ao)", &builder));
1673     }
1674     else if (strcmp (method_name, "FindUserByName") == 0)
1675     {
1676         AccountsUser *user = NULL;
1677         gchar *user_name;
1678
1679         g_variant_get (parameters, "(&s)", &user_name);
1680
1681         load_passwd_file ();
1682         user = get_accounts_user_by_name (user_name);
1683         if (user)
1684         {
1685             if (user->hidden)
1686                 accounts_user_set_hidden (user, FALSE, TRUE);
1687             g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", user->path));
1688         }
1689         else
1690             g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such user: %s", user_name);
1691     }
1692     else
1693         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1694 }
1695
1696 static void
1697 handle_user_call (GDBusConnection       *connection,
1698                   const gchar           *sender,
1699                   const gchar           *object_path,
1700                   const gchar           *interface_name,
1701                   const gchar           *method_name,
1702                   GVariant              *parameters,
1703                   GDBusMethodInvocation *invocation,
1704                   gpointer               user_data)
1705 {
1706     AccountsUser *user = user_data;
1707
1708     if (strcmp (method_name, "SetXSession") == 0)
1709     {
1710         gchar *xsession;
1711
1712         g_variant_get (parameters, "(&s)", &xsession);
1713
1714         g_free (user->xsession);
1715         user->xsession = g_strdup (xsession);
1716
1717         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1718
1719         /* And notify others that it took */
1720         g_dbus_connection_emit_signal (accounts_connection,
1721                                        NULL,
1722                                        user->path,
1723                                        "org.freedesktop.Accounts.User",
1724                                        "Changed",
1725                                        g_variant_new ("()"),
1726                                        NULL);
1727     }
1728     else
1729         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1730 }
1731
1732 static GVariant *
1733 handle_user_get_property (GDBusConnection       *connection,
1734                           const gchar           *sender,
1735                           const gchar           *object_path,
1736                           const gchar           *interface_name,
1737                           const gchar           *property_name,
1738                           GError               **error,
1739                           gpointer               user_data)
1740 {
1741     AccountsUser *user = user_data;
1742
1743     if (strcmp (property_name, "UserName") == 0)
1744         return g_variant_new_string (user->user_name);
1745     else if (strcmp (property_name, "RealName") == 0)
1746         return g_variant_new_string (user->real_name);
1747     else if (strcmp (property_name, "HomeDirectory") == 0)
1748         return g_variant_new_string (user->home_directory);
1749     else if (strcmp (property_name, "SystemAccount") == 0)
1750         return g_variant_new_boolean (user->uid < 1000);
1751     else if (strcmp (property_name, "BackgroundFile") == 0)
1752         return g_variant_new_string (user->background ? user->background : "");
1753     else if (strcmp (property_name, "Language") == 0)
1754         return g_variant_new_string (user->language ? user->language : "");
1755     else if (strcmp (property_name, "IconFile") == 0)
1756         return g_variant_new_string (user->image ? user->image : "");
1757     else if (strcmp (property_name, "Shell") == 0)
1758         return g_variant_new_string ("/bin/sh");
1759     else if (strcmp (property_name, "Uid") == 0)
1760         return g_variant_new_uint64 (user->uid);
1761     else if (strcmp (property_name, "XSession") == 0)
1762         return g_variant_new_string (user->xsession ? user->xsession : "");
1763     else if (strcmp (property_name, "XKeyboardLayouts") == 0)
1764     {
1765         if (user->layouts != NULL)
1766             return g_variant_new_strv ((const gchar * const *) user->layouts, -1);
1767         else
1768             return g_variant_new_strv (NULL, 0);
1769     }
1770     else if (strcmp (property_name, "XHasMessages") == 0)
1771         return g_variant_new_boolean (user->has_messages);
1772
1773     return NULL;
1774 }
1775
1776 static void
1777 accounts_name_acquired_cb (GDBusConnection *connection,
1778                            const gchar     *name,
1779                            gpointer         user_data)
1780 {
1781     const gchar *accounts_interface =
1782         "<node>"
1783         "  <interface name='org.freedesktop.Accounts'>"
1784         "    <method name='ListCachedUsers'>"
1785         "      <arg name='user' direction='out' type='ao'/>"
1786         "    </method>"
1787         "    <method name='FindUserByName'>"
1788         "      <arg name='name' direction='in' type='s'/>"
1789         "      <arg name='user' direction='out' type='o'/>"
1790         "    </method>"
1791         "    <signal name='UserAdded'>"
1792         "      <arg name='user' type='o'/>"
1793         "    </signal>"
1794         "    <signal name='UserDeleted'>"
1795         "      <arg name='user' type='o'/>"
1796         "    </signal>"
1797         "  </interface>"
1798         "</node>";
1799     static const GDBusInterfaceVTable accounts_vtable =
1800     {
1801         handle_accounts_call,
1802     };
1803     const gchar *user_interface =
1804         "<node>"
1805         "  <interface name='org.freedesktop.Accounts.User'>"
1806         "    <method name='SetXSession'>"
1807         "      <arg name='x_session' direction='in' type='s'/>"
1808         "    </method>"
1809         "    <property name='UserName' type='s' access='read'/>"
1810         "    <property name='RealName' type='s' access='read'/>"
1811         "    <property name='HomeDirectory' type='s' access='read'/>"
1812         "    <property name='SystemAccount' type='b' access='read'/>"
1813         "    <property name='BackgroundFile' type='s' access='read'/>"
1814         "    <property name='Language' type='s' access='read'/>"
1815         "    <property name='IconFile' type='s' access='read'/>"
1816         "    <property name='Shell' type='s' access='read'/>"
1817         "    <property name='Uid' type='t' access='read'/>"
1818         "    <property name='XSession' type='s' access='read'/>"
1819         "    <property name='XKeyboardLayouts' type='as' access='read'/>"
1820         "    <property name='XHasMessages' type='b' access='read'/>"
1821         "    <signal name='Changed' />"
1822         "  </interface>"
1823         "</node>";
1824     GError *error = NULL;
1825
1826     accounts_connection = connection;
1827
1828     accounts_info = g_dbus_node_info_new_for_xml (accounts_interface, &error);
1829     if (error)
1830         g_warning ("Failed to parse D-Bus interface: %s", error->message);
1831     g_clear_error (&error);
1832     if (!accounts_info)
1833         return;
1834     user_info = g_dbus_node_info_new_for_xml (user_interface, &error);
1835     if (error)
1836         g_warning ("Failed to parse D-Bus interface: %s", error->message);
1837     g_clear_error (&error);
1838     if (!user_info)
1839         return;
1840     g_dbus_connection_register_object (connection,
1841                                        "/org/freedesktop/Accounts",
1842                                        accounts_info->interfaces[0],
1843                                        &accounts_vtable,
1844                                        NULL,
1845                                        NULL,
1846                                        &error);
1847     if (error)
1848         g_warning ("Failed to register accounts service: %s", error->message);
1849     g_clear_error (&error);
1850     g_dbus_node_info_unref (accounts_info);
1851
1852     service_count--;
1853     if (service_count == 0)
1854         run_lightdm ();
1855 }
1856
1857 static void
1858 start_accounts_service_daemon (void)
1859 {
1860     service_count++;
1861     g_bus_own_name (G_BUS_TYPE_SYSTEM,
1862                     "org.freedesktop.Accounts",
1863                     G_BUS_NAME_OWNER_FLAGS_NONE,
1864                     accounts_name_acquired_cb,
1865                     NULL,
1866                     NULL,
1867                     NULL,
1868                     NULL);
1869 }
1870
1871 static void
1872 run_lightdm (void)
1873 {
1874     GString *command_line;
1875     gchar **lightdm_argv;
1876     pid_t lightdm_pid;
1877     GError *error = NULL;
1878
1879     run_commands ();
1880
1881     status_timeout = g_timeout_add (status_timeout_ms, status_timeout_cb, NULL);
1882
1883     command_line = g_string_new ("lightdm");
1884     if (getenv ("DEBUG"))
1885         g_string_append (command_line, " --debug");
1886     g_string_append_printf (command_line, " --cache-dir %s/cache", temp_dir);
1887
1888     test_runner_command = g_strdup_printf ("PATH=%s LD_PRELOAD=%s LD_LIBRARY_PATH=%s LIGHTDM_TEST_ROOT=%s DBUS_SESSION_BUS_ADDRESS=%s %s\n",
1889                                            g_getenv ("PATH"), g_getenv ("LD_PRELOAD"), g_getenv ("LD_LIBRARY_PATH"), g_getenv ("LIGHTDM_TEST_ROOT"), g_getenv ("DBUS_SESSION_BUS_ADDRESS"),
1890                                            command_line->str);
1891
1892     if (!g_shell_parse_argv (command_line->str, NULL, &lightdm_argv, &error))
1893     {
1894         g_warning ("Error parsing command line: %s", error->message);
1895         quit (EXIT_FAILURE);
1896     }
1897     g_clear_error (&error);
1898
1899     if (!g_spawn_async (NULL, lightdm_argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL, NULL, &lightdm_pid, &error))
1900     {
1901         g_warning ("Error launching LightDM: %s", error->message);
1902         quit (EXIT_FAILURE);
1903     }
1904     g_clear_error (&error);
1905     lightdm_process = watch_process (lightdm_pid);
1906
1907     check_status ("RUNNER DAEMON-START");
1908 }
1909
1910 static gboolean
1911 signal_cb (gpointer user_data)
1912 {
1913     g_print ("Caught signal, quitting\n");
1914     quit (EXIT_FAILURE);
1915     return FALSE;
1916 }
1917
1918 int
1919 main (int argc, char **argv)
1920 {
1921     GMainLoop *loop;
1922     int i;
1923     gchar *greeter = NULL, *script_name, *config_file, *additional_system_config;
1924     gchar *additional_config, *path, *path1, *path2, *ld_preload, *ld_library_path, *home_dir;
1925     GString *passwd_data, *group_data;
1926     GSource *status_source;
1927     gchar cwd[1024];
1928     GError *error = NULL;
1929
1930 #if !defined(GLIB_VERSION_2_36)
1931     g_type_init ();
1932 #endif
1933
1934     loop = g_main_loop_new (NULL, FALSE);
1935
1936     g_unix_signal_add (SIGINT, signal_cb, NULL);
1937     g_unix_signal_add (SIGTERM, signal_cb, NULL);
1938
1939     children = g_hash_table_new (g_direct_hash, g_direct_equal);
1940
1941     if (argc != 3)
1942     {
1943         g_printerr ("Usage %s SCRIPT-NAME GREETER\n", argv[0]);
1944         quit (EXIT_FAILURE);
1945     }
1946     script_name = argv[1];
1947     config_file = g_strdup_printf ("%s.conf", script_name);
1948     config_path = g_build_filename (SRCDIR, "tests", "scripts", config_file, NULL);
1949     g_free (config_file);
1950
1951     config = g_key_file_new ();
1952     g_key_file_load_from_file (config, config_path, G_KEY_FILE_NONE, NULL);
1953
1954     load_script (config_path);
1955
1956     if (!getcwd (cwd, 1024))
1957     {
1958         g_critical ("Error getting current directory: %s", strerror (errno));
1959         quit (EXIT_FAILURE);
1960     }
1961
1962     /* Don't contact our X server */
1963     g_unsetenv ("DISPLAY");
1964
1965     /* Override system calls */
1966     ld_preload = g_build_filename (BUILDDIR, "tests", "src", ".libs", "libsystem.so", NULL);
1967     g_setenv ("LD_PRELOAD", ld_preload, TRUE);
1968     g_free (ld_preload);
1969
1970     /* Run test programs */
1971     path = g_strdup_printf ("%s/tests/src/.libs:%s/tests/src:%s/tests/src:%s/src:%s", BUILDDIR, BUILDDIR, SRCDIR, BUILDDIR, g_getenv ("PATH"));
1972     g_setenv ("PATH", path, TRUE);
1973     g_free (path);
1974
1975     /* Use locally built libraries */
1976     path1 = g_build_filename (BUILDDIR, "liblightdm-gobject", ".libs", NULL);
1977     path2 = g_build_filename (BUILDDIR, "liblightdm-qt", ".libs", NULL);
1978     ld_library_path = g_strdup_printf ("%s:%s", path1, path2);
1979     g_free (path1);
1980     g_free (path2);
1981     g_setenv ("LD_LIBRARY_PATH", ld_library_path, TRUE);
1982     g_free (ld_library_path);
1983     path1 = g_build_filename (BUILDDIR, "liblightdm-gobject", NULL);
1984     g_setenv ("GI_TYPELIB_PATH", path1, TRUE);
1985     g_free (path1);
1986
1987     /* Run in a temporary directory inside the build directory */
1988     /* Note we have to pick a name that is short since Unix sockets in this directory have a 108 character limit on their paths */
1989     i = 0;
1990     while (TRUE) {
1991         gchar *name;
1992
1993         name = g_strdup_printf (".r%d", i);
1994         g_free (temp_dir);
1995         temp_dir = g_build_filename ("/tmp", name, NULL);
1996         g_free (name);
1997         if (!g_file_test (temp_dir, G_FILE_TEST_EXISTS))
1998             break;
1999         i++;
2000     }  
2001     g_mkdir_with_parents (temp_dir, 0755);
2002     g_setenv ("LIGHTDM_TEST_ROOT", temp_dir, TRUE);
2003
2004     /* Open socket for status */
2005     /* Note we have to pick a socket name that is short since there is a 108 character limit on the name */
2006     status_socket_name = g_build_filename (temp_dir, ".s", NULL);
2007     unlink (status_socket_name);
2008     status_socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, &error);
2009     if (error)
2010         g_warning ("Error creating status socket %s: %s", status_socket_name, error->message);
2011     g_clear_error (&error);
2012     if (status_socket)
2013     {
2014         GSocketAddress *address;
2015         gboolean result;
2016
2017         address = g_unix_socket_address_new (status_socket_name);
2018         result = g_socket_bind (status_socket, address, FALSE, &error);
2019         g_object_unref (address);
2020         if (error)
2021             g_warning ("Error binding status socket %s: %s", status_socket_name, error->message);
2022         g_clear_error (&error);
2023         if (result)
2024         {
2025             result = g_socket_listen (status_socket, &error);
2026             if (error)
2027                 g_warning ("Error listening on status socket %s: %s", status_socket_name, error->message);
2028             g_clear_error (&error);
2029         }
2030         if (!result)
2031         {
2032             g_object_unref (status_socket);
2033             status_socket = NULL;
2034         }
2035     }
2036     if (!status_socket)
2037         quit (EXIT_FAILURE);
2038     status_source = g_socket_create_source (status_socket, G_IO_IN, NULL);
2039     g_source_set_callback (status_source, status_connect_cb, NULL, NULL);
2040     g_source_attach (status_source, NULL);
2041
2042     /* Set up a skeleton file system */
2043     g_mkdir_with_parents (g_strdup_printf ("%s/etc", temp_dir), 0755);
2044     g_mkdir_with_parents (g_strdup_printf ("%s/usr/share", temp_dir), 0755);
2045     g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/sessions", temp_dir), 0755);
2046     g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/remote-sessions", temp_dir), 0755);
2047     g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/greeters", temp_dir), 0755);
2048     g_mkdir_with_parents (g_strdup_printf ("%s/tmp", temp_dir), 0755);
2049     g_mkdir_with_parents (g_strdup_printf ("%s/var/run", temp_dir), 0755);
2050     g_mkdir_with_parents (g_strdup_printf ("%s/var/log", temp_dir), 0755);
2051
2052     /* Copy over the configuration */
2053     g_mkdir_with_parents (g_strdup_printf ("%s/etc/lightdm", temp_dir), 0755);
2054     if (!g_key_file_has_key (config, "test-runner-config", "have-config", NULL) || g_key_file_get_boolean (config, "test-runner-config", "have-config", NULL))
2055         if (system (g_strdup_printf ("cp %s %s/etc/lightdm/lightdm.conf", config_path, temp_dir)))
2056             perror ("Failed to copy configuration");
2057
2058     additional_system_config = g_key_file_get_string (config, "test-runner-config", "additional-system-config", NULL);
2059     if (additional_system_config)
2060     {
2061         gchar **files;
2062
2063         g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/lightdm.conf.d", temp_dir), 0755);
2064
2065         files = g_strsplit (additional_system_config, " ", -1);
2066         for (i = 0; files[i]; i++)
2067             if (system (g_strdup_printf ("cp %s/tests/scripts/%s %s/usr/share/lightdm/lightdm.conf.d", SRCDIR, files[i], temp_dir)))
2068                 perror ("Failed to copy configuration");
2069         g_strfreev (files);
2070     }
2071
2072     additional_config = g_key_file_get_string (config, "test-runner-config", "additional-config", NULL);
2073     if (additional_config)
2074     {
2075         gchar **files;
2076
2077         g_mkdir_with_parents (g_strdup_printf ("%s/etc/lightdm/lightdm.conf.d", temp_dir), 0755);
2078
2079         files = g_strsplit (additional_config, " ", -1);
2080         for (i = 0; files[i]; i++)
2081             if (system (g_strdup_printf ("cp %s/tests/scripts/%s %s/etc/lightdm/lightdm.conf.d", SRCDIR, files[i], temp_dir)))
2082                 perror ("Failed to copy configuration");
2083         g_strfreev (files);
2084     }
2085
2086     /* Always copy the script */
2087     if (system (g_strdup_printf ("cp %s %s/script", config_path, temp_dir)))
2088         perror ("Failed to copy configuration");
2089
2090     /* Copy over the greeter files */
2091     if (system (g_strdup_printf ("cp %s/sessions/* %s/usr/share/lightdm/sessions", DATADIR, temp_dir)))
2092         perror ("Failed to copy sessions");
2093     if (system (g_strdup_printf ("cp %s/remote-sessions/* %s/usr/share/lightdm/remote-sessions", DATADIR, temp_dir)))
2094         perror ("Failed to copy remote sessions");
2095     if (system (g_strdup_printf ("cp %s/greeters/* %s/usr/share/lightdm/greeters", DATADIR, temp_dir)))
2096         perror ("Failed to copy greeters");
2097
2098     /* Set up the default greeter */
2099     path = g_build_filename (temp_dir, "usr", "share", "lightdm", "greeters", "default.desktop", NULL);
2100     greeter = g_strdup_printf ("%s.desktop", argv[2]);
2101     if (symlink (greeter, path) < 0)
2102     {
2103         g_printerr ("Failed to make greeter symlink %s->%s: %s\n", path, greeter, strerror (errno));
2104         quit (EXIT_FAILURE);
2105     }
2106     g_free (path);
2107     g_free (greeter);
2108
2109     home_dir = g_build_filename (temp_dir, "home", NULL);
2110
2111     /* Make fake users */
2112     struct
2113     {
2114         gchar *user_name;
2115         gchar *password;
2116         gchar *real_name;
2117         gint uid;
2118     } users[] =
2119     {
2120         /* Root account */
2121         {"root",             "",          "root",                  0},
2122         /* Unprivileged account for greeters */
2123         {"lightdm",          "",          "",                    100},
2124         /* These accounts have a password */
2125         {"have-password1",   "password",  "Password User 1",    1000},
2126         {"have-password2",   "password",  "Password User 2",    1001},
2127         {"have-password3",   "password",  "Password User 3",    1002},
2128         {"have-password4",   "password",  "Password User 4",    1003},
2129         /* This account always prompts for a password, even if using the lightdm-autologin service */
2130         {"always-password",  "password",  "Password User 4",    1004},
2131         /* These accounts have no password */
2132         {"no-password1",     "",          "No Password User 1", 1005},
2133         {"no-password2",     "",          "No Password User 2", 1006},
2134         {"no-password3",     "",          "No Password User 3", 1007},
2135         {"no-password4",     "",          "No Password User 4", 1008},
2136         /* This account has a keyboard layout */
2137         {"have-layout",      "",          "Layout User",        1009},
2138         /* This account has a set of keyboard layouts */
2139         {"have-layouts",     "",          "Layouts User",       1010},
2140         /* This account has a language set */
2141         {"have-language",    "",          "Language User",      1011},
2142         /* This account has a preconfigured session */
2143         {"have-session",            "",   "Session User",       1012},
2144         /* This account has the home directory mounted on login */
2145         {"mount-home-dir",   "",          "Mounted Home Dir User", 1013},
2146         /* This account is denied access */
2147         {"denied",           "",          "Denied User",        1014},
2148         /* This account has expired */
2149         {"expired",          "",          "Expired User",       1015},
2150         /* This account needs a password change */
2151         {"new-authtok",      "",          "New Token User",     1016},
2152         /* This account is switched to change-user2 when authentication succeeds */
2153         {"change-user1",     "",          "Change User 1",      1017},
2154         {"change-user2",     "",          "Change User 2",      1018},
2155         /* This account switches to invalid-user when authentication succeeds */
2156         {"change-user-invalid", "",       "Invalid Change User", 1019},
2157         /* This account crashes on authentication */
2158         {"crash-authenticate", "",        "Crash Auth User",    1020},
2159         /* This account shows an informational prompt on login */
2160         {"info-prompt",      "password",  "Info Prompt",        1021},
2161         /* This account shows multiple informational prompts on login */
2162         {"multi-info-prompt","password",  "Multi Info Prompt",  1022},
2163         /* This account uses two factor authentication */
2164         {"two-factor",       "password",  "Two Factor",         1023},
2165         /* This account has a special group */
2166         {"group-member",     "password",  "Group Member",       1024},
2167         /* This account has the home directory created when the session starts */
2168         {"make-home-dir",    "",          "Make Home Dir User", 1025},
2169         /* This account fails to open a session */
2170         {"session-error",    "password",  "Session Error",      1026},
2171         /* This account can't establish credentials */
2172         {"cred-error",       "password",  "Cred Error",         1027},
2173         /* This account has expired credentials */
2174         {"cred-expired",     "password",  "Cred Expired",       1028},
2175         /* This account has cannot access their credentials */
2176         {"cred-unavail",     "password",  "Cred Unavail",       1029},
2177         /* This account sends informational messages for each PAM function that is called */
2178         {"log-pam",          "password",  "Log PAM",            1030},
2179         /* This account shows multiple prompts on login */
2180         {"multi-prompt",     "password",  "Multi Prompt",       1031},
2181         /* This account has an existing corrupt X authority */
2182         {"corrupt-xauth",    "password",  "Corrupt Xauthority", 1032},
2183         /* User to test properties */
2184         {"prop-user",        "",          "TEST",               1033},
2185         {NULL,               NULL,        NULL,                    0}
2186     };
2187     passwd_data = g_string_new ("");
2188     group_data = g_string_new ("");
2189     for (i = 0; users[i].user_name; i++)
2190     {
2191         GKeyFile *dmrc_file;
2192         gboolean save_dmrc = FALSE;
2193
2194         if (strcmp (users[i].user_name, "mount-home-dir") != 0 && strcmp (users[i].user_name, "make-home-dir") != 0)
2195         {
2196             path = g_build_filename (home_dir, users[i].user_name, NULL);
2197             g_mkdir_with_parents (path, 0755);
2198             if (chown (path, users[i].uid, users[i].uid) < 0)
2199               g_debug ("chown (%s) failed: %s", path, strerror (errno));
2200             g_free (path);
2201         }
2202
2203         dmrc_file = g_key_file_new ();
2204         if (strcmp (users[i].user_name, "have-session") == 0)
2205         {
2206             g_key_file_set_string (dmrc_file, "Desktop", "Session", "alternative");
2207             save_dmrc = TRUE;
2208         }
2209         if (strcmp (users[i].user_name, "have-layout") == 0)
2210         {
2211             g_key_file_set_string (dmrc_file, "Desktop", "Layout", "us");
2212             save_dmrc = TRUE;
2213         }
2214         if (strcmp (users[i].user_name, "have-layouts") == 0)
2215         {
2216             g_key_file_set_string (dmrc_file, "Desktop", "Layout", "ru");
2217             g_key_file_set_string (dmrc_file, "X-Accounts", "Layouts", "fr\toss;ru;");
2218             save_dmrc = TRUE;
2219         }
2220         if (strcmp (users[i].user_name, "have-language") == 0)
2221         {
2222             g_key_file_set_string (dmrc_file, "Desktop", "Language", "en_AU.utf8");
2223             save_dmrc = TRUE;
2224         }
2225
2226         if (save_dmrc)
2227         {
2228             gchar *data;
2229
2230             path = g_build_filename (home_dir, users[i].user_name, ".dmrc", NULL);
2231             data = g_key_file_to_data (dmrc_file, NULL, NULL);
2232             g_file_set_contents (path, data, -1, NULL);
2233             g_free (data);
2234             g_free (path);
2235         }
2236
2237         g_key_file_free (dmrc_file);
2238
2239         /* Write corrupt X authority file */
2240         if (strcmp (users[i].user_name, "corrupt-xauth") == 0)
2241         {
2242             gchar data[1] = { 0xFF };
2243
2244             path = g_build_filename (home_dir, users[i].user_name, ".Xauthority", NULL);
2245             g_file_set_contents (path, data, 1, NULL);
2246             chmod (path, S_IRUSR | S_IWUSR);
2247             g_free (path);
2248         }
2249
2250         /* Add passwd file entry */
2251         g_string_append_printf (passwd_data, "%s:%s:%d:%d:%s:%s/home/%s:/bin/sh\n", users[i].user_name, users[i].password, users[i].uid, users[i].uid, users[i].real_name, temp_dir, users[i].user_name);
2252
2253         /* Add group file entry */
2254         g_string_append_printf (group_data, "%s:x:%d:%s\n", users[i].user_name, users[i].uid, users[i].user_name);
2255     }
2256     path = g_build_filename (temp_dir, "etc", "passwd", NULL);
2257     g_file_set_contents (path, passwd_data->str, -1, NULL);
2258     g_free (path);
2259     g_string_free (passwd_data, TRUE);
2260
2261     /* Add an extra test group */
2262     g_string_append_printf (group_data, "test-group:x:111:\n");
2263
2264     path = g_build_filename (temp_dir, "etc", "group", NULL);
2265     g_file_set_contents (path, group_data->str, -1, NULL);
2266     g_free (path);
2267     g_string_free (group_data, TRUE);
2268
2269     if (g_key_file_has_key (config, "test-runner-config", "timeout", NULL))
2270         status_timeout_ms = g_key_file_get_integer (config, "test-runner-config", "timeout", NULL) * 1000;
2271
2272     /* Start D-Bus services */
2273     if (!g_key_file_get_boolean (config, "test-runner-config", "disable-upower", NULL))
2274         start_upower_daemon ();
2275     if (!g_key_file_get_boolean (config, "test-runner-config", "disable-console-kit", NULL))
2276         start_console_kit_daemon ();
2277     if (!g_key_file_get_boolean (config, "test-runner-config", "disable-login1", NULL))
2278         start_login1_daemon ();
2279     if (!g_key_file_get_boolean (config, "test-runner-config", "disable-accounts-service", NULL))
2280         start_accounts_service_daemon ();
2281
2282     g_main_loop_run (loop);
2283
2284     return EXIT_FAILURE;
2285 }