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