]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - tests/src/test-runner.c
Merge with trunk
[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 *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              strcmp (name, "UNITY-SYSTEM-COMPOSITOR") == 0)
538     {
539         GList *link;
540         for (link = status_clients; link; link = link->next)
541         {
542             StatusClient *client = link->data;
543             int length;
544             GError *error = NULL;
545
546             length = strlen (command);
547             g_socket_send (client->socket, (gchar *) &length, sizeof (length), NULL, &error);
548             g_socket_send (client->socket, command, strlen (command), NULL, &error);
549             if (error)
550                 g_printerr ("Failed to write to client socket: %s\n", error->message);
551             g_clear_error (&error);
552         }
553     }
554     else
555     {
556         g_printerr ("Unknown command '%s'\n", name);
557         quit (EXIT_FAILURE);
558     }
559
560     g_free (name);
561     g_hash_table_unref (params);
562 }
563
564 static void
565 run_commands (void)
566 {
567     /* Stop daemon if requested */
568     while (TRUE)
569     {
570         ScriptLine *line;
571
572         /* Commands start with an asterisk */
573         line = get_script_line (NULL);
574         if (!line || line->text[0] != '*')
575             break;
576
577         statuses = g_list_append (statuses, g_strdup (line->text));
578         line->done = TRUE;
579
580         handle_command (line->text + 1);
581     }
582
583     /* Stop at the end of the script */
584     if (get_script_line (NULL) == NULL)
585         quit (EXIT_SUCCESS);
586 }
587
588 static gboolean
589 status_timeout_cb (gpointer data)
590 {
591     ScriptLine *line;
592
593     line = get_script_line (NULL);
594     fail ("(timeout)", line ? line->text : NULL);
595
596     return FALSE;
597 }
598
599 static void
600 check_status (const gchar *status)
601 {
602     ScriptLine *line;
603     gboolean result = FALSE;
604     gchar *prefix;
605
606     if (stop)
607         return;
608
609     statuses = g_list_append (statuses, g_strdup (status));
610
611     if (getenv ("DEBUG"))
612         g_print ("%s\n", status);
613
614     /* Try and match against expected */
615     prefix = get_prefix (status);
616     line = get_script_line (prefix);
617     g_free (prefix);
618     if (line)
619     {
620         gchar *full_pattern = g_strdup_printf ("^%s$", line->text);
621         result = g_regex_match_simple (full_pattern, status, 0, 0);
622         g_free (full_pattern);
623     }
624
625     if (!result)
626     {
627         if (line == NULL)
628             line = get_script_line (NULL);
629         fail (NULL, line ? line->text : NULL);
630         return;
631     }
632
633     line->done = TRUE;
634
635     /* Restart timeout */
636     g_source_remove (status_timeout);
637     status_timeout = g_timeout_add (status_timeout_ms, status_timeout_cb, NULL);
638
639     run_commands ();
640 }
641
642 static gboolean
643 status_message_cb (GSocket *socket, GIOCondition condition, StatusClient *client)
644 {
645     int length;
646     gchar buffer[1024];
647     ssize_t n_read;
648     GError *error = NULL;
649
650     n_read = g_socket_receive (socket, (gchar *)&length, sizeof (length), NULL, &error);
651     if (n_read > 0)
652         n_read = g_socket_receive (socket, buffer, length, NULL, &error);
653     if (error)
654         g_warning ("Error reading from socket: %s", error->message);
655     g_clear_error (&error);
656     if (n_read == 0)
657     {
658         status_clients = g_list_remove (status_clients, client);
659         g_object_unref (client->socket);
660         g_free (client);
661         return FALSE;
662     }
663     else if (n_read > 0)
664     {
665         buffer[n_read] = '\0';
666         check_status (buffer);
667     }
668
669     return TRUE;
670 }
671
672 static gboolean
673 status_connect_cb (gpointer data)
674 {
675     GSocket *socket;
676     GError *error = NULL;
677
678     socket = g_socket_accept (status_socket, NULL, &error);
679     if (error)
680         g_warning ("Failed to accept status connection: %s", error->message);
681     g_clear_error (&error);
682     if (socket)
683     {
684         StatusClient *client;
685
686         client = g_malloc0 (sizeof (StatusClient));
687         client->socket = socket;
688         client->source = g_socket_create_source (socket, G_IO_IN, NULL);
689         status_clients = g_list_append (status_clients, client);
690
691         g_source_set_callback (client->source, (GSourceFunc) status_message_cb, client, NULL);
692         g_source_attach (client->source, NULL);
693     }
694
695     return TRUE;
696 }
697
698 static void
699 load_script (const gchar *filename)
700 {
701     int i;
702     gchar *data, **lines;
703
704     if (!g_file_get_contents (filename, &data, NULL, NULL))
705     {
706         g_printerr ("Unable to load script: %s\n", filename);
707         quit (EXIT_FAILURE);
708     }
709
710     lines = g_strsplit (data, "\n", -1);
711     g_free (data);
712
713     /* Load lines with #? prefix as expected behaviour */
714     for (i = 0; lines[i]; i++)
715     {
716         gchar *text = g_strstrip (lines[i]);
717         if (g_str_has_prefix (text, "#?"))
718         {
719             ScriptLine *line;
720             line = g_malloc0 (sizeof (ScriptLine));
721             line->text = g_strdup (text + 2);
722             line->done = FALSE;
723             script = g_list_append (script, line);
724         }
725     }
726     g_strfreev (lines);
727 }
728
729 static void
730 handle_upower_call (GDBusConnection       *connection,
731                     const gchar           *sender,
732                     const gchar           *object_path,
733                     const gchar           *interface_name,
734                     const gchar           *method_name,
735                     GVariant              *parameters,
736                     GDBusMethodInvocation *invocation,
737                     gpointer               user_data)
738 {
739     if (strcmp (method_name, "SuspendAllowed") == 0)
740     {
741         check_status ("UPOWER SUSPEND-ALLOWED");
742         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
743     }
744     else if (strcmp (method_name, "Suspend") == 0)
745     {
746         check_status ("UPOWER SUSPEND");
747         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
748     }
749     else if (strcmp (method_name, "HibernateAllowed") == 0)
750     {
751         check_status ("UPOWER HIBERNATE-ALLOWED");
752         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
753     }
754     else if (strcmp (method_name, "Hibernate") == 0)
755     {
756         check_status ("UPOWER HIBERNATE");
757         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
758     }
759     else
760         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
761 }
762
763 static void
764 upower_name_acquired_cb (GDBusConnection *connection,
765                          const gchar     *name,
766                          gpointer         user_data)
767 {
768     const gchar *upower_interface =
769         "<node>"
770         "  <interface name='org.freedesktop.UPower'>"
771         "    <method name='SuspendAllowed'>"
772         "      <arg name='allowed' direction='out' type='b'/>"
773         "    </method>"
774         "    <method name='Suspend'/>"
775         "    <method name='HibernateAllowed'>"
776         "      <arg name='allowed' direction='out' type='b'/>"
777         "    </method>"
778         "    <method name='Hibernate'/>"
779         "  </interface>"
780         "</node>";
781     static const GDBusInterfaceVTable upower_vtable =
782     {
783         handle_upower_call,
784     };
785     GDBusNodeInfo *upower_info;
786     GError *error = NULL;
787
788     upower_info = g_dbus_node_info_new_for_xml (upower_interface, &error);
789     if (error)
790         g_warning ("Failed to parse D-Bus interface: %s", error->message);
791     g_clear_error (&error);
792     if (!upower_info)
793         return;
794     g_dbus_connection_register_object (connection,
795                                        "/org/freedesktop/UPower",
796                                        upower_info->interfaces[0],
797                                        &upower_vtable,
798                                        NULL, NULL,
799                                        &error);
800     if (error)
801         g_warning ("Failed to register UPower service: %s", error->message);
802     g_clear_error (&error);
803     g_dbus_node_info_unref (upower_info);
804
805     service_count--;
806     if (service_count == 0)
807         run_lightdm ();
808 }
809
810 static void
811 start_upower_daemon ()
812 {
813     service_count++;
814     g_bus_own_name (G_BUS_TYPE_SYSTEM,
815                     "org.freedesktop.UPower",
816                     G_BUS_NAME_OWNER_FLAGS_NONE,
817                     upower_name_acquired_cb,
818                     NULL,
819                     NULL,
820                     NULL,
821                     NULL);
822 }
823
824 static CKSession *
825 open_ck_session (GVariant *params)
826 {
827     CKSession *session;
828     GString *cookie;
829     GVariantIter *iter;
830     const gchar *name;
831     GVariant *value;
832     GError *error = NULL;
833
834     session = g_malloc0 (sizeof (CKSession));
835     ck_sessions = g_list_append (ck_sessions, session);
836
837     cookie = g_string_new ("ck-cookie");
838     g_variant_get (params, "a(sv)", &iter);
839     while (g_variant_iter_loop (iter, "(&sv)", &name, &value))
840     {
841         if (strcmp (name, "x11-display") == 0)
842         {
843             const gchar *display;
844             g_variant_get (value, "&s", &display);
845             g_string_append_printf (cookie, "-x%s", display);
846         }
847     }
848
849     session->cookie = cookie->str;
850     g_string_free (cookie, FALSE);
851     session->path = g_strdup_printf ("/org/freedesktop/ConsoleKit/Session%d", ck_session_index++);
852     session->id = g_dbus_connection_register_object (ck_connection,
853                                                      session->path,
854                                                      ck_session_info->interfaces[0],
855                                                      &ck_session_vtable,
856                                                      session,
857                                                      NULL,
858                                                      &error);
859     if (error)
860         g_warning ("Failed to register CK Session: %s", error->message);
861     g_clear_error (&error);
862
863     return session;
864 }
865
866 static void
867 handle_ck_call (GDBusConnection       *connection,
868                 const gchar           *sender,
869                 const gchar           *object_path,
870                 const gchar           *interface_name,
871                 const gchar           *method_name,
872                 GVariant              *parameters,
873                 GDBusMethodInvocation *invocation,
874                 gpointer               user_data)
875 {
876     if (strcmp (method_name, "CanRestart") == 0)
877     {
878         check_status ("CONSOLE-KIT CAN-RESTART");
879         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
880     }
881     else if (strcmp (method_name, "CanStop") == 0)
882     {
883         check_status ("CONSOLE-KIT CAN-STOP");
884         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
885     }
886     else if (strcmp (method_name, "CloseSession") == 0)
887         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
888     else if (strcmp (method_name, "OpenSession") == 0)
889     {
890         GVariantBuilder params;
891         g_variant_builder_init (&params, G_VARIANT_TYPE ("a(sv)"));
892         CKSession *session = open_ck_session (g_variant_builder_end (&params));
893         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", session->cookie));
894     }
895     else if (strcmp (method_name, "OpenSessionWithParameters") == 0)
896     {
897         CKSession *session = open_ck_session (g_variant_get_child_value (parameters, 0));
898         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", session->cookie));
899     }
900     else if (strcmp (method_name, "GetSessionForCookie") == 0)
901     {
902         GList *link;
903         gchar *cookie;
904
905         g_variant_get (parameters, "(&s)", &cookie);
906
907         for (link = ck_sessions; link; link = link->next)
908         {
909             CKSession *session = link->data;
910             if (strcmp (session->cookie, cookie) != 0)
911             {
912                 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", session->path));
913                 return;
914             }
915         }
916
917         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Unable to find session for cookie");
918     }
919     else if (strcmp (method_name, "Restart") == 0)
920     {
921         check_status ("CONSOLE-KIT RESTART");
922         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
923     }
924     else if (strcmp (method_name, "Stop") == 0)
925     {
926         check_status ("CONSOLE-KIT STOP");
927         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
928     }
929     else
930         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
931 }
932
933
934 /* Shared between CK and Login1 - identical signatures */
935 static void
936 handle_session_call (GDBusConnection       *connection,
937                      const gchar           *sender,
938                      const gchar           *object_path,
939                      const gchar           *interface_name,
940                      const gchar           *method_name,
941                      GVariant              *parameters,
942                      GDBusMethodInvocation *invocation,
943                      gpointer               user_data)
944 {
945     if (strcmp (method_name, "Lock") == 0)
946         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
947     else if (strcmp (method_name, "Unlock") == 0)
948         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
949     else
950         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
951 }
952
953 static void
954 ck_name_acquired_cb (GDBusConnection *connection,
955                      const gchar     *name,
956                      gpointer         user_data)
957 {
958     const gchar *ck_interface =
959         "<node>"
960         "  <interface name='org.freedesktop.ConsoleKit.Manager'>"
961         "    <method name='CanRestart'>"
962         "      <arg name='can_restart' direction='out' type='b'/>"
963         "    </method>"
964         "    <method name='CanStop'>"
965         "      <arg name='can_stop' direction='out' type='b'/>"
966         "    </method>"
967         "    <method name='CloseSession'>"
968         "      <arg name='cookie' direction='in' type='s'/>"
969         "      <arg name='result' direction='out' type='b'/>"
970         "    </method>"
971         "    <method name='OpenSession'>"
972         "      <arg name='cookie' direction='out' type='s'/>"
973         "    </method>"
974         "    <method name='OpenSessionWithParameters'>"
975         "      <arg name='parameters' direction='in' type='a(sv)'/>"
976         "      <arg name='cookie' direction='out' type='s'/>"
977         "    </method>"
978         "    <method name='GetSessionForCookie'>"
979         "      <arg name='cookie' direction='in' type='s'/>"
980         "      <arg name='ssid' direction='out' type='o'/>"
981         "    </method>"
982         "    <method name='Restart'/>"
983         "    <method name='Stop'/>"
984         "    <signal name='SeatAdded'>"
985         "      <arg name='seat' type='o'/>"
986         "    </signal>"
987         "    <signal name='SeatRemoved'>"
988         "      <arg name='seat' type='o'/>"
989         "    </signal>"
990         "  </interface>"
991         "</node>";
992     static const GDBusInterfaceVTable ck_vtable =
993     {
994         handle_ck_call,
995     };
996     const gchar *ck_session_interface =
997         "<node>"
998         "  <interface name='org.freedesktop.ConsoleKit.Session'>"
999         "    <method name='Lock'/>"
1000         "    <method name='Unlock'/>"
1001         "  </interface>"
1002         "</node>";
1003     GDBusNodeInfo *ck_info;
1004     GError *error = NULL;
1005
1006     ck_connection = connection;
1007
1008     ck_info = g_dbus_node_info_new_for_xml (ck_interface, &error);
1009     if (error)
1010         g_warning ("Failed to parse D-Bus interface: %s", error->message);
1011     g_clear_error (&error);
1012     if (!ck_info)
1013         return;
1014     ck_session_info = g_dbus_node_info_new_for_xml (ck_session_interface, &error);
1015     if (error)
1016         g_warning ("Failed to parse D-Bus interface: %s", error->message);
1017     g_clear_error (&error);
1018     if (!ck_session_info)
1019         return;
1020     g_dbus_connection_register_object (connection,
1021                                        "/org/freedesktop/ConsoleKit/Manager",
1022                                        ck_info->interfaces[0],
1023                                        &ck_vtable,
1024                                        NULL, NULL,
1025                                        &error);
1026     if (error)
1027         g_warning ("Failed to register console kit service: %s", error->message);
1028     g_clear_error (&error);
1029     g_dbus_node_info_unref (ck_info);
1030
1031     service_count--;
1032     if (service_count == 0)
1033         run_lightdm ();
1034 }
1035
1036 static void
1037 start_console_kit_daemon (void)
1038 {
1039     service_count++;
1040     g_bus_own_name (G_BUS_TYPE_SYSTEM,
1041                     "org.freedesktop.ConsoleKit",
1042                     G_BUS_NAME_OWNER_FLAGS_NONE,
1043                     ck_name_acquired_cb,
1044                     NULL,
1045                     NULL,
1046                     NULL,
1047                     NULL);
1048 }
1049
1050 static Login1Session *
1051 open_login1_session (GDBusConnection *connection,
1052                      GVariant *params)
1053 {
1054     Login1Session *session;
1055     GError *error = NULL;
1056     GDBusNodeInfo *login1_session_info;
1057
1058     const gchar *login1_session_interface =
1059         "<node>"
1060         "  <interface name='org.freedesktop.login1.Session'>"
1061         "    <method name='Lock'/>"
1062         "    <method name='Unlock'/>"
1063         "  </interface>"
1064         "</node>";
1065     static const GDBusInterfaceVTable login1_session_vtable =
1066     {
1067         handle_session_call,
1068     };
1069
1070     session = g_malloc0 (sizeof (Login1Session));
1071     login1_sessions = g_list_append (login1_sessions, session);
1072
1073     session->path = g_strdup_printf("/org/freedesktop/login1/Session/c%d",
1074                                     login1_session_index++);
1075
1076
1077
1078     login1_session_info = g_dbus_node_info_new_for_xml (login1_session_interface,
1079                                                         &error);
1080     if (error)
1081         g_warning ("Failed to parse login1 session D-Bus interface: %s",
1082                    error->message);
1083     g_clear_error (&error);
1084     if (!login1_session_info)
1085         return;
1086
1087     g_dbus_connection_register_object (connection,
1088                                        session->path,
1089                                        login1_session_info->interfaces[0],
1090                                        &login1_session_vtable,
1091                                        session,
1092                                        NULL,
1093                                        &error);
1094     if (error)
1095         g_warning ("Failed to register login1 session: %s", error->message);
1096     g_clear_error (&error);
1097     g_dbus_node_info_unref (login1_session_info);
1098
1099     return session;
1100 }
1101
1102
1103 static void
1104 handle_login1_call (GDBusConnection       *connection,
1105                     const gchar           *sender,
1106                     const gchar           *object_path,
1107                     const gchar           *interface_name,
1108                     const gchar           *method_name,
1109                     GVariant              *parameters,
1110                     GDBusMethodInvocation *invocation,
1111                     gpointer               user_data)
1112 {
1113
1114     if (strcmp (method_name, "GetSessionByPID") == 0)
1115     {
1116         /* Look for a session with our PID, and create one if we don't have one
1117            already. */
1118         GList *link;
1119         guint pid;
1120         Login1Session *ret = NULL;
1121
1122         g_variant_get (parameters, "(u)", &pid);
1123
1124         for (link = login1_sessions; link; link = link->next)
1125         {
1126             Login1Session *session;
1127             session = link->data;
1128             if (session->pid == pid)
1129             {
1130                 ret = session;
1131                 break;
1132             }
1133         }
1134         /* Not found */
1135         if (!ret)
1136             ret = open_login1_session (connection, parameters);
1137
1138         g_dbus_method_invocation_return_value (invocation,
1139                                                g_variant_new("(o)", ret->path));
1140
1141     }
1142     else if (strcmp (method_name, "CanReboot") == 0)
1143     {
1144         check_status ("LOGIN1 CAN-REBOOT");
1145         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1146     }
1147     else if (strcmp (method_name, "Reboot") == 0)
1148     {
1149         gboolean interactive;
1150         g_variant_get (parameters, "(b)", &interactive);
1151         check_status ("LOGIN1 REBOOT");
1152         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1153     }
1154     else if (strcmp (method_name, "CanPowerOff") == 0)
1155     {
1156         check_status ("LOGIN1 CAN-POWER-OFF");
1157         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1158     }
1159     else if (strcmp (method_name, "Suspend") == 0)
1160     {
1161         gboolean interactive;
1162         g_variant_get (parameters, "(b)", &interactive);
1163         check_status ("LOGIN1 SUSPEND");
1164         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1165     }
1166     else if (strcmp (method_name, "CanSuspend") == 0)
1167     {
1168         check_status ("LOGIN1 CAN-SUSPEND");
1169         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1170     }
1171     else if (strcmp (method_name, "PowerOff") == 0)
1172     {
1173         gboolean interactive;
1174         g_variant_get (parameters, "(b)", &interactive);
1175         check_status ("LOGIN1 POWER-OFF");
1176         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1177     }
1178     else if (strcmp (method_name, "CanHibernate") == 0)
1179     {
1180         check_status ("LOGIN1 CAN-HIBERNATE");
1181         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1182     }
1183     else if (strcmp (method_name, "Hibernate") == 0)
1184     {
1185         gboolean interactive;
1186         g_variant_get (parameters, "(b)", &interactive);
1187         check_status ("LOGIN1 HIBERNATE");
1188         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1189     }
1190     else
1191         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1192 }
1193
1194 static void
1195 login1_name_acquired_cb (GDBusConnection *connection,
1196                          const gchar     *name,
1197                          gpointer         user_data)
1198 {
1199     const gchar *login1_interface =
1200         "<node>"
1201         "  <interface name='org.freedesktop.login1.Manager'>"
1202         "    <method name='GetSessionByPID'>"
1203         "      <arg name='pid' type='u' direction='in'/>"
1204         "      <arg name='session' type='o' direction='out'/>"
1205         "    </method>"
1206         "    <method name='CanReboot'>"
1207         "      <arg name='result' direction='out' type='s'/>"
1208         "    </method>"
1209         "    <method name='Reboot'>"
1210         "      <arg name='interactive' direction='in' type='b'/>"
1211         "    </method>"
1212         "    <method name='CanPowerOff'>"
1213         "      <arg name='result' direction='out' type='s'/>"
1214         "    </method>"
1215         "    <method name='PowerOff'>"
1216         "      <arg name='interactive' direction='in' type='b'/>"
1217         "    </method>"
1218         "    <method name='CanSuspend'>"
1219         "      <arg name='result' direction='out' type='s'/>"
1220         "    </method>"
1221         "    <method name='Suspend'>"
1222         "      <arg name='interactive' direction='in' type='b'/>"
1223         "    </method>"
1224         "    <method name='CanHibernate'>"
1225         "      <arg name='result' direction='out' type='s'/>"
1226         "    </method>"
1227         "    <method name='Hibernate'>"
1228         "      <arg name='interactive' direction='in' type='b'/>"
1229         "    </method>"
1230         "  </interface>"
1231         "</node>";
1232     static const GDBusInterfaceVTable login1_vtable =
1233     {
1234         handle_login1_call,
1235     };
1236     GDBusNodeInfo *login1_info;
1237     GError *error = NULL;
1238
1239     login1_info = g_dbus_node_info_new_for_xml (login1_interface, &error);
1240     if (error)
1241         g_warning ("Failed to parse login1 D-Bus interface: %s", error->message);
1242     g_clear_error (&error);
1243     if (!login1_info)
1244         return;
1245     g_dbus_connection_register_object (connection,
1246                                        "/org/freedesktop/login1",
1247                                        login1_info->interfaces[0],
1248                                        &login1_vtable,
1249                                        NULL, NULL,
1250                                        &error);
1251     if (error)
1252         g_warning ("Failed to register login1 service: %s", error->message);
1253     g_clear_error (&error);
1254     g_dbus_node_info_unref (login1_info);
1255
1256     service_count--;
1257     if (service_count == 0)
1258         run_lightdm ();
1259 }
1260
1261 static void
1262 start_login1_daemon ()
1263 {
1264     service_count++;
1265     g_bus_own_name (G_BUS_TYPE_SYSTEM,
1266                     "org.freedesktop.login1",
1267                     G_BUS_NAME_OWNER_FLAGS_NONE,
1268                     login1_name_acquired_cb,
1269                     NULL,
1270                     NULL,
1271                     NULL,
1272                     NULL);
1273 }
1274
1275 static AccountsUser *
1276 get_accounts_user_by_uid (guint uid)
1277 {
1278     GList *link;
1279
1280     for (link = accounts_users; link; link = link->next)
1281     {
1282         AccountsUser *u = link->data;
1283         if (u->uid == uid)
1284             return u;
1285     }
1286   
1287     return NULL;
1288 }
1289
1290 static AccountsUser *
1291 get_accounts_user_by_name (const gchar *username)
1292 {
1293     GList *link;
1294
1295     for (link = accounts_users; link; link = link->next)
1296     {
1297         AccountsUser *u = link->data;
1298         if (strcmp (u->user_name, username) == 0)
1299             return u;
1300     }
1301
1302     return NULL;
1303 }
1304
1305 static void
1306 accounts_user_set_hidden (AccountsUser *user, gboolean hidden, gboolean emit_signal)
1307 {
1308     GError *error = NULL;
1309
1310     user->hidden = hidden;
1311
1312     if (user->hidden && user->id != 0)
1313     {
1314         g_dbus_connection_unregister_object (accounts_connection, user->id);
1315         g_dbus_connection_emit_signal (accounts_connection,
1316                                        NULL,
1317                                        "/org/freedesktop/Accounts",
1318                                        "org.freedesktop.Accounts",
1319                                        "UserDeleted",
1320                                        g_variant_new ("(o)", user->path),
1321                                        &error);
1322         if (error)
1323             g_warning ("Failed to emit UserDeleted: %s", error->message);
1324         g_clear_error (&error);
1325
1326         user->id = 0;
1327     }
1328     if (!user->hidden && user->id == 0)
1329     {
1330         user->id = g_dbus_connection_register_object (accounts_connection,
1331                                                       user->path,
1332                                                       user_info->interfaces[0],
1333                                                       &user_vtable,
1334                                                       user,
1335                                                       NULL,
1336                                                       &error);
1337         if (error)
1338             g_warning ("Failed to register user: %s", error->message);
1339         g_clear_error (&error);
1340
1341         g_dbus_connection_emit_signal (accounts_connection,
1342                                        NULL,
1343                                        "/org/freedesktop/Accounts",
1344                                        "org.freedesktop.Accounts",
1345                                        "UserAdded",
1346                                        g_variant_new ("(o)", user->path),
1347                                        &error);
1348         if (error)
1349             g_warning ("Failed to emit UserAdded: %s", error->message);
1350         g_clear_error (&error);
1351     }
1352 }
1353
1354 static void
1355 load_passwd_file (void)
1356 {
1357     gchar *path, *data, **lines;
1358     gchar **user_filter = NULL;
1359     int i;
1360
1361     if (g_key_file_has_key (config, "test-runner-config", "accounts-service-user-filter", NULL))
1362     {
1363         gchar *filter;
1364
1365         filter = g_key_file_get_string (config, "test-runner-config", "accounts-service-user-filter", NULL);
1366         user_filter = g_strsplit (filter, " ", -1);
1367         g_free (filter);
1368     }
1369
1370     path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "passwd", NULL);
1371     g_file_get_contents (path, &data, NULL, NULL);
1372     g_free (path);
1373     lines = g_strsplit (data, "\n", -1);
1374     g_free (data);
1375
1376     for (i = 0; lines[i]; i++)
1377     {
1378         gchar **fields;
1379         guint uid;
1380         gchar *user_name, *real_name;
1381         GList *link;
1382         AccountsUser *user = NULL;
1383         GError *error = NULL;
1384
1385         fields = g_strsplit (lines[i], ":", -1);
1386         if (fields == NULL || g_strv_length (fields) < 7)
1387         {
1388             g_strfreev (fields);
1389             continue;
1390         }
1391
1392         user_name = fields[0];
1393         uid = atoi (fields[2]);
1394         real_name = fields[4];
1395
1396         user = get_accounts_user_by_uid (uid);
1397         if (!user)
1398         {
1399             gchar *path;
1400             GKeyFile *dmrc_file;
1401
1402             user = g_malloc0 (sizeof (AccountsUser));
1403             accounts_users = g_list_append (accounts_users, user);
1404
1405             /* Only allow users in whitelist */
1406             user->hidden = FALSE;
1407             if (user_filter)
1408             {
1409                 int j;
1410
1411                 user->hidden = TRUE;
1412                 for (j = 0; user_filter[j] != NULL; j++)
1413                     if (strcmp (user_name, user_filter[j]) == 0)
1414                         user->hidden = FALSE;
1415             }
1416
1417             dmrc_file = g_key_file_new ();
1418             path = g_build_filename (temp_dir, "home", user_name, ".dmrc", NULL);
1419             g_key_file_load_from_file (dmrc_file, path, G_KEY_FILE_NONE, NULL);
1420             g_free (path);
1421
1422             user->uid = uid;
1423             user->user_name = g_strdup (user_name);
1424             user->real_name = g_strdup (real_name);
1425             user->home_directory = g_build_filename (temp_dir, "home", user_name, NULL);
1426             user->language = g_key_file_get_string (dmrc_file, "Desktop", "Language", NULL);
1427             /* DMRC contains a locale, strip the codeset off it to get the language */
1428             if (user->language)
1429             {
1430                 gchar *c = strchr (user->language, '.');
1431                 if (c)
1432                     *c = '\0';
1433             }
1434             user->xsession = g_key_file_get_string (dmrc_file, "Desktop", "Session", NULL);
1435             user->layouts = g_key_file_get_string_list (dmrc_file, "X-Accounts", "Layouts", NULL, NULL);
1436             user->path = g_strdup_printf ("/org/freedesktop/Accounts/User%d", uid);
1437             accounts_user_set_hidden (user, user->hidden, FALSE);
1438
1439             g_key_file_free (dmrc_file);
1440         }
1441
1442         g_strfreev (fields);
1443     }
1444
1445     g_strfreev (lines);
1446 }
1447
1448 static void
1449 handle_accounts_call (GDBusConnection       *connection,
1450                       const gchar           *sender,
1451                       const gchar           *object_path,
1452                       const gchar           *interface_name,
1453                       const gchar           *method_name,
1454                       GVariant              *parameters,
1455                       GDBusMethodInvocation *invocation,
1456                       gpointer               user_data)
1457 {
1458     if (strcmp (method_name, "ListCachedUsers") == 0)
1459     {
1460         GVariantBuilder builder;
1461         GList *link;
1462
1463         g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
1464
1465         load_passwd_file ();
1466         for (link = accounts_users; link; link = link->next)
1467         {
1468             AccountsUser *user = link->data;
1469             if (!user->hidden)
1470                 g_variant_builder_add_value (&builder, g_variant_new_object_path (user->path));
1471         }
1472
1473         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(ao)", &builder));
1474     }
1475     else if (strcmp (method_name, "FindUserByName") == 0)
1476     {
1477         GList *link;
1478         AccountsUser *user = NULL;
1479         gchar *user_name;
1480
1481         g_variant_get (parameters, "(&s)", &user_name);
1482
1483         load_passwd_file ();
1484         user = get_accounts_user_by_name (user_name);
1485         if (user && !user->hidden)
1486             g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", user->path));
1487         else
1488             g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such user: %s", user_name);
1489     }
1490     else
1491         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1492 }
1493
1494 static void
1495 handle_user_call (GDBusConnection       *connection,
1496                   const gchar           *sender,
1497                   const gchar           *object_path,
1498                   const gchar           *interface_name,
1499                   const gchar           *method_name,
1500                   GVariant              *parameters,
1501                   GDBusMethodInvocation *invocation,
1502                   gpointer               user_data)
1503 {
1504     AccountsUser *user = user_data;
1505
1506     if (strcmp (method_name, "SetXSession") == 0)
1507     {
1508         gchar *xsession;
1509
1510         g_variant_get (parameters, "(&s)", &xsession);
1511
1512         g_free (user->xsession);
1513         user->xsession = g_strdup (xsession);
1514
1515         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1516     }
1517     else
1518         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1519 }
1520
1521 static GVariant *
1522 handle_user_get_property (GDBusConnection       *connection,
1523                           const gchar           *sender,
1524                           const gchar           *object_path,
1525                           const gchar           *interface_name,
1526                           const gchar           *property_name,
1527                           GError               **error,
1528                           gpointer               user_data)
1529 {
1530     AccountsUser *user = user_data;
1531
1532     if (strcmp (property_name, "UserName") == 0)
1533         return g_variant_new_string (user->user_name);
1534     else if (strcmp (property_name, "RealName") == 0)
1535         return g_variant_new_string (user->real_name);
1536     else if (strcmp (property_name, "HomeDirectory") == 0)
1537         return g_variant_new_string (user->home_directory);
1538     else if (strcmp (property_name, "BackgroundFile") == 0)
1539         return g_variant_new_string ("");
1540     else if (strcmp (property_name, "Language") == 0)
1541         return g_variant_new_string (user->language ? user->language : "");
1542     else if (strcmp (property_name, "XSession") == 0)
1543         return g_variant_new_string (user->xsession ? user->xsession : "");
1544     else if (strcmp (property_name, "XKeyboardLayouts") == 0)
1545     {
1546         if (user->layouts != NULL)
1547             return g_variant_new_strv ((const gchar * const *) user->layouts, -1);
1548         else
1549             return g_variant_new_strv (NULL, 0);
1550     }
1551     else if (strcmp (property_name, "XHasMessages") == 0)
1552         return g_variant_new_boolean (FALSE);
1553
1554     return NULL;
1555 }
1556
1557 static void
1558 accounts_name_acquired_cb (GDBusConnection *connection,
1559                            const gchar     *name,
1560                            gpointer         user_data)
1561 {
1562     const gchar *accounts_interface =
1563         "<node>"
1564         "  <interface name='org.freedesktop.Accounts'>"
1565         "    <method name='ListCachedUsers'>"
1566         "      <arg name='user' direction='out' type='ao'/>"
1567         "    </method>"
1568         "    <method name='FindUserByName'>"
1569         "      <arg name='name' direction='in' type='s'/>"
1570         "      <arg name='user' direction='out' type='o'/>"
1571         "    </method>"
1572         "    <signal name='UserAdded'>"
1573         "      <arg name='user' type='o'/>"
1574         "    </signal>"
1575         "    <signal name='UserDeleted'>"
1576         "      <arg name='user' type='o'/>"
1577         "    </signal>"
1578         "  </interface>"
1579         "</node>";
1580     static const GDBusInterfaceVTable accounts_vtable =
1581     {
1582         handle_accounts_call,
1583     };
1584     const gchar *user_interface =
1585         "<node>"
1586         "  <interface name='org.freedesktop.Accounts.User'>"
1587         "    <method name='SetXSession'>"
1588         "      <arg name='x_session' direction='in' type='s'/>"
1589         "    </method>"
1590         "    <property name='UserName' type='s' access='read'/>"
1591         "    <property name='RealName' type='s' access='read'/>"
1592         "    <property name='HomeDirectory' type='s' access='read'/>"
1593         "    <property name='BackgroundFile' type='s' access='read'/>"
1594         "    <property name='Language' type='s' access='read'/>"
1595         "    <property name='XSession' type='s' access='read'/>"
1596         "    <property name='XKeyboardLayouts' type='as' access='read'/>"
1597         "    <property name='XHasMessages' type='b' access='read'/>"
1598         "  </interface>"
1599         "</node>";
1600     GError *error = NULL;
1601
1602     accounts_connection = connection;
1603
1604     accounts_info = g_dbus_node_info_new_for_xml (accounts_interface, &error);
1605     if (error)
1606         g_warning ("Failed to parse D-Bus interface: %s", error->message);
1607     g_clear_error (&error);
1608     if (!accounts_info)
1609         return;
1610     user_info = g_dbus_node_info_new_for_xml (user_interface, &error);
1611     if (error)
1612         g_warning ("Failed to parse D-Bus interface: %s", error->message);
1613     g_clear_error (&error);
1614     if (!user_info)
1615         return;
1616     g_dbus_connection_register_object (connection,
1617                                        "/org/freedesktop/Accounts",
1618                                        accounts_info->interfaces[0],
1619                                        &accounts_vtable,
1620                                        NULL,
1621                                        NULL,
1622                                        &error);
1623     if (error)
1624         g_warning ("Failed to register accounts service: %s", error->message);
1625     g_clear_error (&error);
1626     g_dbus_node_info_unref (accounts_info);
1627
1628     service_count--;
1629     if (service_count == 0)
1630         run_lightdm ();
1631 }
1632
1633 static void
1634 start_accounts_service_daemon (void)
1635 {
1636     service_count++;
1637     g_bus_own_name (G_BUS_TYPE_SYSTEM,
1638                     "org.freedesktop.Accounts",
1639                     G_BUS_NAME_OWNER_FLAGS_NONE,
1640                     accounts_name_acquired_cb,
1641                     NULL,
1642                     NULL,
1643                     NULL,
1644                     NULL);
1645 }
1646
1647 static void
1648 run_lightdm (void)
1649 {
1650     GString *command_line;
1651     gchar **lightdm_argv;
1652     pid_t lightdm_pid;
1653     GError *error = NULL;
1654
1655     run_commands ();
1656
1657     status_timeout = g_timeout_add (status_timeout_ms, status_timeout_cb, NULL);
1658
1659     command_line = g_string_new ("lightdm");
1660     if (getenv ("DEBUG"))
1661         g_string_append (command_line, " --debug");
1662     g_string_append_printf (command_line, " --cache-dir %s/cache", temp_dir);
1663     g_string_append_printf (command_line, " --xsessions-dir=%s/usr/share/xsessions", temp_dir);
1664     g_string_append_printf (command_line, " --remote-sessions-dir=%s/usr/share/remote-sessions", temp_dir);
1665     g_string_append_printf (command_line, " --xgreeters-dir=%s/usr/share/xgreeters", temp_dir);
1666
1667     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",
1668                                            g_getenv ("PATH"), g_getenv ("LD_PRELOAD"), g_getenv ("LD_LIBRARY_PATH"), g_getenv ("LIGHTDM_TEST_ROOT"), g_getenv ("DBUS_SESSION_BUS_ADDRESS"),
1669                                            command_line->str);
1670
1671     if (!g_shell_parse_argv (command_line->str, NULL, &lightdm_argv, &error))
1672     {
1673         g_warning ("Error parsing command line: %s", error->message);
1674         quit (EXIT_FAILURE);
1675     }
1676     g_clear_error (&error);
1677
1678     if (!g_spawn_async (NULL, lightdm_argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL, NULL, &lightdm_pid, &error))
1679     {
1680         g_warning ("Error launching LightDM: %s", error->message);
1681         quit (EXIT_FAILURE);
1682     }
1683     g_clear_error (&error);
1684     lightdm_process = watch_process (lightdm_pid);
1685
1686     check_status ("RUNNER DAEMON-START");
1687 }
1688
1689 static gboolean
1690 signal_cb (gpointer user_data)
1691 {
1692     g_print ("Caught signal, quitting\n");
1693     quit (EXIT_FAILURE);
1694     return FALSE;
1695 }
1696
1697 int
1698 main (int argc, char **argv)
1699 {
1700     GMainLoop *loop;
1701     int i;
1702     gchar *greeter = NULL, *script_name, *config_file, *additional_config, *path, *path1, *path2, *ld_preload, *ld_library_path, *home_dir;
1703     GString *passwd_data, *group_data;
1704     GSource *status_source;
1705     gchar cwd[1024];
1706     GError *error = NULL;
1707
1708 #if !defined(GLIB_VERSION_2_36)
1709     g_type_init ();
1710 #endif
1711
1712     loop = g_main_loop_new (NULL, FALSE);
1713
1714     g_unix_signal_add (SIGINT, signal_cb, NULL);
1715     g_unix_signal_add (SIGTERM, signal_cb, NULL);
1716
1717     children = g_hash_table_new (g_direct_hash, g_direct_equal);
1718
1719     if (argc != 3)
1720     {
1721         g_printerr ("Usage %s SCRIPT-NAME GREETER\n", argv[0]);
1722         quit (EXIT_FAILURE);
1723     }
1724     script_name = argv[1];
1725     config_file = g_strdup_printf ("%s.conf", script_name);
1726     config_path = g_build_filename (SRCDIR, "tests", "scripts", config_file, NULL);
1727     g_free (config_file);
1728
1729     config = g_key_file_new ();
1730     g_key_file_load_from_file (config, config_path, G_KEY_FILE_NONE, NULL);
1731
1732     load_script (config_path);
1733
1734     if (!getcwd (cwd, 1024))
1735     {
1736         g_critical ("Error getting current directory: %s", strerror (errno));
1737         quit (EXIT_FAILURE);
1738     }
1739
1740     /* Don't contact our X server */
1741     g_unsetenv ("DISPLAY");
1742
1743     /* Override system calls */
1744     ld_preload = g_build_filename (BUILDDIR, "tests", "src", ".libs", "libsystem.so", NULL);
1745     g_setenv ("LD_PRELOAD", ld_preload, TRUE);
1746     g_free (ld_preload);
1747
1748     /* Run test programs */
1749     path = g_strdup_printf ("%s/tests/src/.libs:%s/tests/src:%s/tests/src:%s/src:%s", BUILDDIR, BUILDDIR, SRCDIR, BUILDDIR, g_getenv ("PATH"));
1750     g_setenv ("PATH", path, TRUE);
1751     g_free (path);
1752
1753     /* Use locally built libraries */
1754     path1 = g_build_filename (BUILDDIR, "liblightdm-gobject", ".libs", NULL);
1755     path2 = g_build_filename (BUILDDIR, "liblightdm-qt", ".libs", NULL);
1756     ld_library_path = g_strdup_printf ("%s:%s", path1, path2);
1757     g_free (path1);
1758     g_free (path2);
1759     g_setenv ("LD_LIBRARY_PATH", ld_library_path, TRUE);
1760     g_free (ld_library_path);
1761     path1 = g_build_filename (BUILDDIR, "liblightdm-gobject", NULL);
1762     g_setenv ("GI_TYPELIB_PATH", path1, TRUE);
1763     g_free (path1);
1764
1765     /* Run in a temporary directory inside the build directory */
1766     /* Note we have to pick a name that is short since Unix sockets in this directory have a 108 character limit on their paths */
1767     i = 0;
1768     while (TRUE) {
1769         gchar *name;
1770
1771         name = g_strdup_printf (".r%d", i);
1772         g_free (temp_dir);
1773         temp_dir = g_build_filename ("/tmp", name, NULL);
1774         g_free (name);
1775         if (!g_file_test (temp_dir, G_FILE_TEST_EXISTS))
1776             break;
1777         i++;
1778     }  
1779     g_mkdir_with_parents (temp_dir, 0755);
1780     g_setenv ("LIGHTDM_TEST_ROOT", temp_dir, TRUE);
1781
1782     /* Open socket for status */
1783     /* Note we have to pick a socket name that is short since there is a 108 character limit on the name */
1784     status_socket_name = g_build_filename (temp_dir, ".s", NULL);
1785     unlink (status_socket_name);
1786     status_socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, &error);
1787     if (error)
1788         g_warning ("Error creating status socket %s: %s", status_socket_name, error->message);
1789     g_clear_error (&error);
1790     if (status_socket)
1791     {
1792         GSocketAddress *address;
1793         gboolean result;
1794
1795         address = g_unix_socket_address_new (status_socket_name);
1796         result = g_socket_bind (status_socket, address, FALSE, &error);
1797         g_object_unref (address);
1798         if (error)
1799             g_warning ("Error binding status socket %s: %s", status_socket_name, error->message);
1800         g_clear_error (&error);
1801         if (result)
1802         {
1803             result = g_socket_listen (status_socket, &error);
1804             if (error)
1805                 g_warning ("Error listening on status socket %s: %s", status_socket_name, error->message);
1806             g_clear_error (&error);
1807         }
1808         if (!result)
1809         {
1810             g_object_unref (status_socket);
1811             status_socket = NULL;
1812         }
1813     }
1814     if (!status_socket)
1815         quit (EXIT_FAILURE);
1816     status_source = g_socket_create_source (status_socket, G_IO_IN, NULL);
1817     g_source_set_callback (status_source, status_connect_cb, NULL, NULL);
1818     g_source_attach (status_source, NULL);
1819
1820     /* Set up a skeleton file system */
1821     g_mkdir_with_parents (g_strdup_printf ("%s/etc", temp_dir), 0755);
1822     g_mkdir_with_parents (g_strdup_printf ("%s/usr/share", temp_dir), 0755);
1823     g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/xsessions", temp_dir), 0755);
1824     g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/remote-sessions", temp_dir), 0755);
1825     g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/xgreeters", temp_dir), 0755);
1826     g_mkdir_with_parents (g_strdup_printf ("%s/tmp", temp_dir), 0755);
1827     g_mkdir_with_parents (g_strdup_printf ("%s/var/run", temp_dir), 0755);
1828     g_mkdir_with_parents (g_strdup_printf ("%s/var/log", temp_dir), 0755);
1829
1830     /* Copy over the configuration */
1831     g_mkdir_with_parents (g_strdup_printf ("%s/etc/lightdm", temp_dir), 0755);
1832     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))
1833         if (system (g_strdup_printf ("cp %s %s/etc/lightdm/lightdm.conf", config_path, temp_dir)))
1834             perror ("Failed to copy configuration");
1835
1836     additional_config = g_key_file_get_string (config, "test-runner-config", "additional-config", NULL);
1837     if (additional_config)
1838     {
1839         gchar **files;
1840
1841         g_mkdir_with_parents (g_strdup_printf ("%s/etc/lightdm/lightdm.conf.d", temp_dir), 0755);
1842
1843         files = g_strsplit (additional_config, " ", -1);
1844         for (i = 0; files[i]; i++)
1845             if (system (g_strdup_printf ("cp %s/tests/scripts/%s %s/etc/lightdm/lightdm.conf.d", SRCDIR, files[i], temp_dir)))
1846                 perror ("Failed to copy configuration");
1847         g_strfreev (files);
1848     }
1849
1850     /* Always copy the script */
1851     if (system (g_strdup_printf ("cp %s %s/script", config_path, temp_dir)))
1852         perror ("Failed to copy configuration");
1853
1854     /* Copy over the greeter files */
1855     if (system (g_strdup_printf ("cp %s/xsessions/* %s/usr/share/xsessions", DATADIR, temp_dir)))
1856         perror ("Failed to copy xsessions");
1857     if (system (g_strdup_printf ("cp %s/remote-sessions/* %s/usr/share/remote-sessions", DATADIR, temp_dir)))
1858         perror ("Failed to copy remote sessions");
1859     if (system (g_strdup_printf ("cp %s/xgreeters/* %s/usr/share/xgreeters", DATADIR, temp_dir)))
1860         perror ("Failed to copy xgreeters");
1861
1862     /* Set up the default greeter */
1863     path = g_build_filename (temp_dir, "usr", "share", "xgreeters", "default.desktop", NULL);
1864     greeter = g_strdup_printf ("%s.desktop", argv[2]);
1865     if (symlink (greeter, path) < 0)
1866     {
1867         g_printerr ("Failed to make greeter symlink %s->%s: %s\n", path, greeter, strerror (errno));
1868         quit (EXIT_FAILURE);
1869     }
1870     g_free (path);
1871     g_free (greeter);
1872
1873     home_dir = g_build_filename (temp_dir, "home", NULL);
1874
1875     /* Make fake users */
1876     struct
1877     {
1878         gchar *user_name;
1879         gchar *password;
1880         gboolean have_home_dir;
1881         gchar *real_name;
1882         gchar *xsession;
1883         gchar *dmrc_layout;
1884         gchar *dbus_layouts;
1885         gchar *language;
1886         gint uid;
1887     } users[] =
1888     {
1889         /* Root account */
1890         {"root",             "",         TRUE,  "root",               NULL,  NULL, NULL,          NULL,             0},
1891         /* Unprivileged account for greeters */
1892         {"lightdm",          "",         TRUE,  "",                   NULL,  NULL, NULL,          NULL,           100},
1893         /* These accounts have a password */
1894         {"have-password1",   "password", TRUE,  "Password User 1",    NULL,  NULL, NULL,          NULL,          1000},
1895         {"have-password2",   "password", TRUE,  "Password User 2",    NULL,  NULL, NULL,          NULL,          1001},
1896         {"have-password3",   "password", TRUE,  "Password User 3",    NULL,  NULL, NULL,          NULL,          1002},
1897         {"have-password4",   "password", TRUE,  "Password User 4",    NULL,  NULL, NULL,          NULL,          1003},
1898         /* This account always prompts for a password, even if using the lightdm-autologin service */
1899         {"always-password",  "password", TRUE,  "Password User 4",    NULL,  NULL, NULL,          NULL,          1004},
1900         /* These accounts have no password */
1901         {"no-password1",     "",         TRUE,  "No Password User 1", NULL,  NULL, NULL,          NULL,          1005},
1902         {"no-password2",     "",         TRUE,  "No Password User 2", NULL,  NULL, NULL,          NULL,          1006},
1903         {"no-password3",     "",         TRUE,  "No Password User 3", NULL,  NULL, NULL,          NULL,          1007},
1904         {"no-password4",     "",         TRUE,  "No Password User 4", NULL,  NULL, NULL,          NULL,          1008},
1905         /* This account has a keyboard layout */
1906         {"have-layout",      "",         TRUE,  "Layout User",        NULL,  "us", NULL,          NULL,          1009},
1907         /* This account has a set of keyboard layouts */
1908         {"have-layouts",     "",         TRUE,  "Layouts User",       NULL,  "ru", "fr\toss;ru;", NULL,          1010},
1909         /* This account has a language set */
1910         {"have-language",    "",         TRUE,  "Language User",      NULL,  NULL, NULL,          "en_AU.utf8",  1011},
1911         /* This account has a preconfigured session */
1912         {"have-session",            "",  TRUE,  "Session User", "alternative", NULL, NULL,        NULL,          1012},
1913         /* This account has the home directory mounted on login */
1914         {"mount-home-dir",   "",         FALSE, "Mounted Home Dir User", NULL, NULL, NULL,        NULL,          1013},
1915         /* This account is denied access */
1916         {"denied",           "",         TRUE,  "Denied User",        NULL,  NULL, NULL,          NULL,          1014},
1917         /* This account has expired */
1918         {"expired",          "",         TRUE,  "Expired User",       NULL,  NULL, NULL,          NULL,          1015},
1919         /* This account needs a password change */
1920         {"new-authtok",      "",         TRUE,  "New Token User",     NULL,  NULL, NULL,          NULL,          1016},
1921         /* This account is switched to change-user2 when authentication succeeds */
1922         {"change-user1",     "",         TRUE,  "Change User 1",      NULL,  NULL, NULL,          NULL,          1017},
1923         {"change-user2",     "",         TRUE,  "Change User 2",      NULL,  NULL, NULL,          NULL,          1018},
1924         /* This account switches to invalid-user when authentication succeeds */
1925         {"change-user-invalid", "",      TRUE,  "Invalid Change User",NULL,  NULL, NULL,          NULL,          1019},
1926         /* This account crashes on authentication */
1927         {"crash-authenticate", "",       TRUE,  "Crash Auth User",    NULL,  NULL, NULL,          NULL,          1020},
1928         /* This account shows an informational prompt on login */
1929         {"info-prompt",      "password", TRUE,  "Info Prompt",        NULL,  NULL, NULL,          NULL,          1021},
1930         /* This account shows multiple informational prompts on login */
1931         {"multi-info-prompt","password", TRUE,  "Multi Info Prompt",  NULL,  NULL, NULL,          NULL,          1022},
1932         /* This account uses two factor authentication */
1933         {"two-factor",       "password", TRUE,  "Two Factor",         NULL,  NULL, NULL,          NULL,          1023},
1934         /* This account has a special group */
1935         {"group-member",     "password", TRUE,  "Group Member",       NULL,  NULL, NULL,          NULL,          1024},
1936         /* This account has the home directory created when the session starts */
1937         {"make-home-dir",    "",         FALSE, "Make Home Dir User", NULL,  NULL, NULL,          NULL,          1025},
1938         /* This account fails to open a session */
1939         {"session-error",    "password", TRUE,  "Session Error",      NULL,  NULL, NULL,          NULL,          1026},
1940         /* This account can't establish credentials */
1941         {"cred-error",       "password", TRUE,  "Cred Error",         NULL,  NULL, NULL,          NULL,          1027},
1942         /* This account has expired credentials */
1943         {"cred-expired",     "password", TRUE,  "Cred Expired",       NULL,  NULL, NULL,          NULL,          1028},
1944         /* This account has cannot access their credentials */
1945         {"cred-unavail",     "password", TRUE,  "Cred Unavail",       NULL,  NULL, NULL,          NULL,          1029},
1946         /* This account sends informational messages for each PAM function that is called */
1947         {"log-pam",          "password", TRUE,  "Log PAM",            NULL,  NULL, NULL,          NULL,          1030},
1948         /* This account shows multiple prompts on login */
1949         {"multi-prompt",     "password", TRUE,  "Multi Prompt",       NULL,  NULL, NULL,          NULL,          1031},
1950         {NULL,               NULL,       FALSE, NULL,                 NULL,  NULL, NULL,          NULL,             0}
1951     };
1952     passwd_data = g_string_new ("");
1953     group_data = g_string_new ("");
1954     for (i = 0; users[i].user_name; i++)
1955     {
1956         GKeyFile *dmrc_file;
1957         gboolean save_dmrc = FALSE;
1958
1959         if (users[i].have_home_dir)
1960         {
1961             path = g_build_filename (home_dir, users[i].user_name, NULL);
1962             g_mkdir_with_parents (path, 0755);
1963             if (chown (path, users[i].uid, users[i].uid) < 0)
1964               g_debug ("chown (%s) failed: %s", path, strerror (errno));
1965             g_free (path);
1966         }
1967
1968         dmrc_file = g_key_file_new ();
1969         if (users[i].xsession)
1970         {
1971             g_key_file_set_string (dmrc_file, "Desktop", "Session", users[i].xsession);
1972             save_dmrc = TRUE;
1973         }
1974         if (users[i].dmrc_layout)
1975         {
1976             g_key_file_set_string (dmrc_file, "Desktop", "Layout", users[i].dmrc_layout);
1977             save_dmrc = TRUE;
1978         }
1979         if (users[i].dbus_layouts)
1980         {
1981             g_key_file_set_string (dmrc_file, "X-Accounts", "Layouts", users[i].dbus_layouts);
1982             save_dmrc = TRUE;
1983
1984         }
1985         if (users[i].language)
1986         {
1987             g_key_file_set_string (dmrc_file, "Desktop", "Language", users[i].language);
1988             save_dmrc = TRUE;
1989         }
1990
1991         if (save_dmrc)
1992         {
1993             gchar *data;
1994
1995             path = g_build_filename (home_dir, users[i].user_name, ".dmrc", NULL);
1996             data = g_key_file_to_data (dmrc_file, NULL, NULL);
1997             g_file_set_contents (path, data, -1, NULL);
1998             g_free (data);
1999             g_free (path);
2000         }
2001
2002         g_key_file_free (dmrc_file);
2003
2004         /* Add passwd file entry */
2005         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);
2006
2007         /* Add group file entry */
2008         g_string_append_printf (group_data, "%s:x:%d:%s\n", users[i].user_name, users[i].uid, users[i].user_name);
2009     }
2010     path = g_build_filename (temp_dir, "etc", "passwd", NULL);
2011     g_file_set_contents (path, passwd_data->str, -1, NULL);
2012     g_free (path);
2013     g_string_free (passwd_data, TRUE);
2014
2015     /* Add an extra test group */
2016     g_string_append_printf (group_data, "test-group:x:111:\n");
2017
2018     path = g_build_filename (temp_dir, "etc", "group", NULL);
2019     g_file_set_contents (path, group_data->str, -1, NULL);
2020     g_free (path);
2021     g_string_free (group_data, TRUE);
2022
2023     if (g_key_file_has_key (config, "test-runner-config", "timeout", NULL))
2024         status_timeout_ms = g_key_file_get_integer (config, "test-runner-config", "timeout", NULL) * 1000;
2025
2026     /* Start D-Bus services */
2027     if (!g_key_file_get_boolean (config, "test-runner-config", "disable-upower", NULL))
2028         start_upower_daemon ();
2029     if (!g_key_file_get_boolean (config, "test-runner-config", "disable-console-kit", NULL))
2030         start_console_kit_daemon ();
2031     if (!g_key_file_get_boolean (config, "test-runner-config", "disable-login1", NULL))
2032         start_login1_daemon ();
2033     if (!g_key_file_get_boolean (config, "test-runner-config", "disable-accounts-service", NULL))
2034         start_accounts_service_daemon ();
2035
2036     g_main_loop_run (loop);
2037
2038     return EXIT_FAILURE;
2039 }