Back to index

lightdm  1.3.2
test-runner.c
Go to the documentation of this file.
00001 #include <stdlib.h>
00002 #include <stdio.h>
00003 #include <string.h>
00004 #include <ctype.h>
00005 #include <errno.h>
00006 #include <glib.h>
00007 #include <glib/gstdio.h>
00008 #include <glib-unix.h>
00009 #include <gio/gio.h>
00010 #include <gio/gunixsocketaddress.h>
00011 #include <unistd.h>
00012 #include <pwd.h>
00013 
00014 /* Timeout in ms waiting for the status we expect */
00015 #define STATUS_TIMEOUT 2000
00016 
00017 /* Timeout in ms to wait for SIGTERM to be handled by a child process */
00018 #define KILL_TIMEOUT 2000
00019 
00020 static gchar *config_path;
00021 static GKeyFile *config;
00022 static GSocket *status_socket = NULL;
00023 static gchar *status_socket_name = NULL;
00024 static GList *statuses = NULL;
00025 static GList *script = NULL;
00026 static GList *script_iter = NULL;
00027 static guint status_timeout = 0;
00028 static gchar *temp_dir = NULL;
00029 static int service_count;
00030 typedef struct
00031 {
00032     pid_t pid;
00033     guint kill_timeout;
00034 } Process;
00035 static Process *lightdm_process = NULL;
00036 static GHashTable *children = NULL;
00037 static gboolean stop = FALSE;
00038 static gint exit_status = 0;
00039 static GDBusConnection *accounts_connection = NULL;
00040 static GDBusNodeInfo *accounts_info;
00041 static GDBusNodeInfo *user_info;
00042 typedef struct
00043 {
00044     guint uid;
00045     gchar *user_name;
00046     gchar *real_name;
00047     gchar *home_directory;
00048     gchar *path;
00049     guint id;
00050     gchar *language;
00051     gchar *xsession;
00052     gchar **layouts;
00053 } AccountsUser;
00054 static GList *accounts_users = NULL;
00055 static void handle_user_call (GDBusConnection       *connection,
00056                               const gchar           *sender,
00057                               const gchar           *object_path,
00058                               const gchar           *interface_name,
00059                               const gchar           *method_name,
00060                               GVariant              *parameters,
00061                               GDBusMethodInvocation *invocation,
00062                               gpointer               user_data);
00063 static GVariant *handle_user_get_property (GDBusConnection       *connection,
00064                                            const gchar           *sender,
00065                                            const gchar           *object_path,
00066                                            const gchar           *interface_name,
00067                                            const gchar           *property_name,
00068                                            GError               **error,
00069                                            gpointer               user_data);
00070 static const GDBusInterfaceVTable user_vtable =
00071 {
00072     handle_user_call,
00073     handle_user_get_property,
00074 };
00075 static GDBusConnection *ck_connection = NULL;
00076 static GDBusNodeInfo *ck_session_info;
00077 typedef struct
00078 {
00079     gchar *cookie;
00080     gchar *path;
00081     guint id;
00082 } CKSession;
00083 static GList *ck_sessions = NULL;
00084 static gint ck_session_index = 0;
00085 static void handle_ck_session_call (GDBusConnection       *connection,
00086                                     const gchar           *sender,
00087                                     const gchar           *object_path,
00088                                     const gchar           *interface_name,
00089                                     const gchar           *method_name,
00090                                     GVariant              *parameters,
00091                                     GDBusMethodInvocation *invocation,
00092                                     gpointer               user_data);
00093 static const GDBusInterfaceVTable ck_session_vtable =
00094 {
00095     handle_ck_session_call,
00096 };
00097 typedef struct
00098 {
00099     GSocket *socket;
00100     GSource *source;
00101 } StatusClient;
00102 static GList *status_clients = NULL;
00103 
00104 static void run_lightdm (void);
00105 static void quit (int status);
00106 static void check_status (const gchar *status);
00107 
00108 static gboolean
00109 kill_timeout_cb (gpointer data)
00110 {
00111     Process *process = data;
00112 
00113     if (getenv ("DEBUG"))
00114         g_print ("Sending SIGKILL to process %d\n", process->pid);
00115     kill (process->pid, SIGKILL);
00116     return FALSE;
00117 }
00118 
00119 static void
00120 stop_process (Process *process)
00121 {
00122     if (process->kill_timeout != 0)
00123         return;
00124 
00125     if (getenv ("DEBUG"))
00126         g_print ("Sending SIGTERM to process %d\n", process->pid);
00127     kill (process->pid, SIGTERM);
00128     process->kill_timeout = g_timeout_add (KILL_TIMEOUT, kill_timeout_cb, process);
00129 }
00130 
00131 static void
00132 process_exit_cb (GPid pid, gint status, gpointer data)
00133 {
00134     Process *process;
00135     gchar *status_text;
00136   
00137     if (getenv ("DEBUG"))
00138     {
00139         if (WIFEXITED (status))
00140             g_print ("Process %d exited with status %d\n", pid, WEXITSTATUS (status));
00141         else
00142             g_print ("Process %d terminated with signal %d\n", pid, WTERMSIG (status));
00143     }
00144 
00145     if (lightdm_process && pid == lightdm_process->pid)
00146     {
00147         process = lightdm_process;
00148         lightdm_process = NULL;
00149         if (WIFEXITED (status))
00150             status_text = g_strdup_printf ("RUNNER DAEMON-EXIT STATUS=%d", WEXITSTATUS (status));
00151         else
00152             status_text = g_strdup_printf ("RUNNER DAEMON-TERMINATE SIGNAL=%d", WTERMSIG (status));
00153         check_status (status_text);
00154     }
00155     else
00156     {
00157         process = g_hash_table_lookup (children, GINT_TO_POINTER (pid));
00158         if (!process)
00159             return;
00160         g_hash_table_remove (children, GINT_TO_POINTER (pid));
00161     }
00162 
00163     if (process->kill_timeout)
00164         g_source_remove (process->kill_timeout);
00165     process->kill_timeout = 0;
00166 
00167     /* Quit once all children have stopped */
00168     if (stop)
00169         quit (exit_status);
00170 }
00171 
00172 static Process *
00173 watch_process (pid_t pid)
00174 {
00175     Process *process;  
00176 
00177     process = g_malloc0 (sizeof (Process));
00178     process->pid = pid;
00179     process->kill_timeout = 0;
00180 
00181     if (getenv ("DEBUG"))
00182         g_print ("Watching process %d\n", process->pid);
00183     g_child_watch_add (process->pid, process_exit_cb, NULL);
00184 
00185     return process;
00186 }
00187 
00188 static void
00189 quit (int status)
00190 {
00191     GHashTableIter iter;
00192 
00193     if (!stop)
00194         exit_status = status;
00195     stop = TRUE;
00196 
00197     /* Stop all the children */
00198     g_hash_table_iter_init (&iter, children);
00199     while (TRUE)
00200     {
00201         gpointer key, value;
00202 
00203         if (!g_hash_table_iter_next (&iter, &key, &value))
00204             break;
00205 
00206         stop_process ((Process *)value);
00207     }
00208 
00209     /* Don't quit until all children are stopped */
00210     if (g_hash_table_size (children) > 0)
00211         return;
00212 
00213     /* Stop the daemon */
00214     if (lightdm_process)
00215     {
00216         stop_process (lightdm_process);
00217         return;
00218     }
00219 
00220     if (status_socket_name)
00221         unlink (status_socket_name);
00222 
00223     if (temp_dir)
00224     {
00225         gchar *command = g_strdup_printf ("rm -r %s", temp_dir);
00226         if (system (command))
00227             perror ("Failed to delete temp directory");
00228     }
00229 
00230     exit (status);
00231 }
00232 
00233 static void
00234 fail (const gchar *event, const gchar *expected)
00235 {
00236     GList *link;
00237 
00238     if (stop)
00239         return;
00240 
00241     g_printerr ("Test failed, got the following events:\n");
00242     for (link = statuses; link; link = link->next)
00243         g_printerr ("    %s\n", (gchar *)link->data);
00244     if (event)
00245         g_printerr ("    %s\n", event);
00246     if (expected)
00247         g_printerr ("    ^^^ expected \"%s\"\n", expected);
00248     else
00249         g_printerr ("^^^ expected nothing\n");
00250 
00251     quit (EXIT_FAILURE);
00252 }
00253 
00254 static const gchar *
00255 get_script_line ()
00256 {
00257     if (!script_iter)
00258         return NULL;
00259     return script_iter->data;
00260 }
00261 
00262 static void
00263 handle_command (const gchar *command)
00264 {
00265     const gchar *c;
00266     gchar *name = NULL;
00267     GHashTable *params;
00268 
00269     c = command;
00270     while (*c && !isspace (*c))
00271         c++;
00272     name = g_strdup_printf ("%.*s", (int) (c - command), command);
00273 
00274     params = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
00275     while (TRUE)
00276     {
00277         const gchar *start;
00278         gchar *param_name, *param_value;
00279 
00280         while (isspace (*c))
00281             c++;
00282         start = c;
00283         while (*c && !isspace (*c) && *c != '=')
00284             c++;
00285         if (*c == '\0')
00286             break;
00287 
00288         param_name = g_strdup_printf ("%.*s", (int) (c - start), start);
00289 
00290         if (*c == '=')
00291         {
00292             c++;
00293             while (isspace (*c))
00294                 c++;
00295             if (*c == '\"')
00296             {
00297                 gboolean escaped = FALSE;
00298                 GString *value;
00299 
00300                 c++;
00301                 value = g_string_new ("");
00302                 while (*c)
00303                 {
00304                     if (*c == '\\')
00305                     {
00306                         if (escaped)
00307                         {
00308                             g_string_append_c (value, '\\');
00309                             escaped = FALSE;
00310                         }
00311                         else
00312                             escaped = TRUE;
00313                     }
00314                     else if (!escaped && *c == '\"')
00315                         break;
00316                     if (!escaped)
00317                         g_string_append_c (value, *c);
00318                     c++;
00319                 }
00320                 param_value = value->str;
00321                 g_string_free (value, FALSE);
00322                 if (*c == '\"')
00323                     c++;
00324             }
00325             else
00326             {
00327                 start = c;
00328                 while (*c && !isspace (*c))
00329                     c++;
00330                 param_value = g_strdup_printf ("%.*s", (int) (c - start), start);
00331             }
00332         }
00333         else
00334             param_value = g_strdup ("");
00335 
00336         g_hash_table_insert (params, param_name, param_value);
00337     }
00338 
00339     if (strcmp (name, "WAIT") == 0)
00340     {
00341         sleep (1);
00342     }
00343     else if (strcmp (name, "SWITCH-TO-GREETER") == 0)
00344     {
00345         g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
00346                                      "org.freedesktop.DisplayManager",
00347                                      "/org/freedesktop/DisplayManager/Seat0",
00348                                      "org.freedesktop.DisplayManager.Seat",
00349                                      "SwitchToGreeter",
00350                                      g_variant_new ("()"),
00351                                      G_VARIANT_TYPE ("()"),
00352                                      G_DBUS_CALL_FLAGS_NONE,
00353                                      1000,
00354                                      NULL,
00355                                      NULL);
00356         check_status ("RUNNER SWITCH-TO-GREETER");
00357     }
00358     else if (strcmp (name, "SWITCH-TO-USER") == 0)
00359     {
00360         gchar *status_text, *username;
00361           
00362         username = g_hash_table_lookup (params, "USERNAME");
00363         g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
00364                                      "org.freedesktop.DisplayManager",
00365                                      "/org/freedesktop/DisplayManager/Seat0",
00366                                      "org.freedesktop.DisplayManager.Seat",
00367                                      "SwitchToUser",
00368                                      g_variant_new ("(ss)", username, ""),
00369                                      G_VARIANT_TYPE ("()"),
00370                                      G_DBUS_CALL_FLAGS_NONE,
00371                                      1000,
00372                                      NULL,
00373                                      NULL);
00374         status_text = g_strdup_printf ("RUNNER SWITCH-TO-USER USERNAME=%s", username);
00375         check_status (status_text);
00376         g_free (status_text);
00377     }
00378     else if (strcmp (name, "SWITCH-TO-GUEST") == 0)
00379     {
00380         g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
00381                                      "org.freedesktop.DisplayManager",
00382                                      "/org/freedesktop/DisplayManager/Seat0",
00383                                      "org.freedesktop.DisplayManager.Seat",
00384                                      "SwitchToGuest",
00385                                      g_variant_new ("(s)", ""),
00386                                      G_VARIANT_TYPE ("()"),
00387                                      G_DBUS_CALL_FLAGS_NONE,
00388                                      1000,
00389                                      NULL,
00390                                      NULL);
00391         check_status ("RUNNER SWITCH-TO-GUEST");
00392     }
00393     else if (strcmp (name, "STOP-DAEMON") == 0)
00394         stop_process (lightdm_process);
00395     // FIXME: Make generic RUN-COMMAND
00396     else if (strcmp (name, "START-XSERVER") == 0)
00397     {
00398         gchar *xserver_args, *command_line;
00399         gchar **argv;
00400         GPid pid;
00401         Process *process;
00402         GError *error = NULL;
00403 
00404         xserver_args = g_hash_table_lookup (params, "ARGS");
00405         if (!xserver_args)
00406             xserver_args = "";
00407         command_line = g_strdup_printf ("%s/tests/src/X %s", BUILDDIR, xserver_args);
00408 
00409         if (!g_shell_parse_argv (command_line, NULL, &argv, &error) ||
00410             !g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &error))
00411         {
00412             g_printerr ("Error starting X server: %s", error->message);
00413             quit (EXIT_FAILURE);
00414         }
00415         else
00416         {
00417             process = watch_process (pid);
00418             g_hash_table_insert (children, GINT_TO_POINTER (process->pid), process);
00419         }
00420     }
00421     else if (strcmp (name, "START-VNC-CLIENT") == 0)
00422     {
00423         gchar *vnc_client_args, *command_line;
00424         gchar **argv;
00425         GPid pid;
00426         Process *process;
00427         GError *error = NULL;
00428 
00429         vnc_client_args = g_hash_table_lookup (params, "ARGS");
00430         if (!vnc_client_args)
00431             vnc_client_args = "";
00432         command_line = g_strdup_printf ("%s/tests/src/vnc-client %s", BUILDDIR, vnc_client_args);
00433 
00434         if (!g_shell_parse_argv (command_line, NULL, &argv, &error) ||
00435             !g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &error))
00436         {
00437             g_printerr ("Error starting VNC client: %s", error->message);
00438             quit (EXIT_FAILURE);
00439         }
00440         else
00441         {
00442             process = watch_process (pid);
00443             g_hash_table_insert (children, GINT_TO_POINTER (process->pid), process);
00444         }
00445     }
00446     /* Forward to external processes */
00447     else if (strcmp (name, "SESSION") == 0 ||
00448              strcmp (name, "GREETER") == 0 ||
00449              strcmp (name, "XSERVER") == 0)
00450     {
00451         GList *link;
00452         for (link = status_clients; link; link = link->next)
00453         {
00454             StatusClient *client = link->data;
00455             int length;
00456             GError *error = NULL;
00457       
00458             length = strlen (command);
00459             g_socket_send (client->socket, (gchar *) &length, sizeof (length), NULL, &error);
00460             g_socket_send (client->socket, command, strlen (command), NULL, &error);
00461             if (error)
00462                 g_printerr ("Failed to write to client socket: %s\n", error->message);
00463             g_clear_error (&error);
00464         }     
00465     }
00466     else
00467     {
00468         g_printerr ("Unknown command '%s'\n", name);
00469         quit (EXIT_FAILURE);
00470     }
00471   
00472     g_free (name);
00473     g_hash_table_unref (params);
00474 }
00475 
00476 static void
00477 run_commands ()
00478 {
00479     /* Stop daemon if requested */
00480     while (TRUE)
00481     {
00482         const gchar *command;
00483 
00484         /* Commands start with an asterisk */
00485         command = get_script_line ();
00486         if (!command || command[0] != '*')
00487             break;
00488 
00489         statuses = g_list_append (statuses, g_strdup (command));
00490         script_iter = script_iter->next;
00491 
00492         handle_command (command + 1);
00493     }
00494 
00495     /* Stop at the end of the script */
00496     if (get_script_line () == NULL)
00497         quit (EXIT_SUCCESS);
00498 }
00499 
00500 static gboolean
00501 status_timeout_cb (gpointer data)
00502 {
00503     fail ("(timeout)", get_script_line ());
00504     return FALSE;
00505 }
00506 
00507 static void
00508 check_status (const gchar *status)
00509 {
00510     const gchar *pattern;
00511     gboolean result = FALSE;
00512 
00513     if (stop)
00514         return;
00515   
00516     statuses = g_list_append (statuses, g_strdup (status));
00517   
00518     if (getenv ("DEBUG"))
00519         g_print ("%s\n", status);
00520 
00521     /* Try and match against expected */
00522     pattern = get_script_line ();
00523     if (pattern)
00524     {
00525         gchar *full_pattern = g_strdup_printf ("^%s$", pattern);
00526         result = g_regex_match_simple (full_pattern, status, 0, 0);
00527         g_free (full_pattern);
00528     }
00529   
00530     if (!result)
00531     {
00532         fail (NULL, pattern);
00533         return;
00534     }
00535     script_iter = script_iter->next;
00536 
00537     /* Restart timeout */
00538     g_source_remove (status_timeout);
00539     status_timeout = g_timeout_add (STATUS_TIMEOUT, status_timeout_cb, NULL);
00540 
00541     run_commands ();
00542 }
00543 
00544 static gboolean
00545 status_message_cb (GSocket *socket, GIOCondition condition, StatusClient *client)
00546 {
00547     int length;
00548     gchar buffer[1024];
00549     ssize_t n_read;
00550     GError *error = NULL;
00551 
00552     n_read = g_socket_receive (socket, (gchar *)&length, sizeof (length), NULL, &error);
00553     if (n_read > 0)
00554         n_read = g_socket_receive (socket, buffer, length, NULL, &error);
00555     if (error)
00556         g_warning ("Error reading from socket: %s", error->message);
00557     g_clear_error (&error);
00558     if (n_read == 0)
00559     {
00560         status_clients = g_list_remove (status_clients, client);
00561         g_object_unref (client->socket);
00562         g_free (client);
00563         return FALSE;
00564     }
00565     else if (n_read > 0)
00566     {
00567         buffer[n_read] = '\0';
00568         check_status (buffer);
00569     }
00570 
00571     return TRUE;
00572 }
00573 
00574 static gboolean
00575 status_connect_cb (gpointer data)
00576 {
00577     GSocket *socket;
00578     GError *error = NULL;
00579 
00580     socket = g_socket_accept (status_socket, NULL, &error);
00581     if (error)
00582         g_warning ("Failed to accept status connection: %s", error->message);
00583     g_clear_error (&error);
00584     if (socket)
00585     {
00586         StatusClient *client;
00587 
00588         client = g_malloc0 (sizeof (StatusClient));
00589         client->socket = socket;
00590         client->source = g_socket_create_source (socket, G_IO_IN, NULL);
00591         status_clients = g_list_append (status_clients, client);
00592 
00593         g_source_set_callback (client->source, (GSourceFunc) status_message_cb, client, NULL);
00594         g_source_attach (client->source, NULL);
00595     }
00596 
00597     return TRUE;
00598 }
00599 
00600 static void
00601 load_script (const gchar *filename)
00602 {
00603     int i;
00604     gchar *data, **lines;
00605 
00606     if (!g_file_get_contents (filename, &data, NULL, NULL))
00607     {
00608         g_printerr ("Unable to load script: %s\n", filename);
00609         quit (EXIT_FAILURE);
00610     }
00611 
00612     lines = g_strsplit (data, "\n", -1);
00613     g_free (data);
00614 
00615     /* Load lines with #? prefix as expected behaviour */
00616     for (i = 0; lines[i]; i++)
00617     {
00618         gchar *line = g_strstrip (lines[i]);
00619         if (g_str_has_prefix (line, "#?"))
00620             script = g_list_append (script, g_strdup (line+2));
00621     }
00622     script_iter = script;
00623     g_strfreev (lines);
00624 }
00625 
00626 static CKSession *
00627 open_ck_session (GVariant *params)
00628 {
00629     CKSession *session;
00630     GString *cookie;
00631     GVariantIter *iter;
00632     const gchar *name;
00633     GVariant *value;
00634     GError *error = NULL;
00635 
00636     session = g_malloc0 (sizeof (CKSession));
00637     ck_sessions = g_list_append (ck_sessions, session);
00638 
00639     cookie = g_string_new ("ck-cookie");
00640     g_variant_get (params, "a(sv)", &iter);
00641     while (g_variant_iter_loop (iter, "(&sv)", &name, &value))
00642     {
00643         if (strcmp (name, "x11-display") == 0)
00644         {
00645             const gchar *display;
00646             g_variant_get (value, "&s", &display);
00647             g_string_append_printf (cookie, "-x%s", display);
00648         }
00649     }
00650 
00651     session->cookie = cookie->str;
00652     g_string_free (cookie, FALSE);
00653     session->path = g_strdup_printf ("/org/freedesktop/ConsoleKit/Session%d", ck_session_index++);
00654     session->id = g_dbus_connection_register_object (ck_connection,
00655                                                      session->path,
00656                                                      ck_session_info->interfaces[0],
00657                                                      &ck_session_vtable,
00658                                                      session,
00659                                                      NULL,
00660                                                      &error);
00661     if (error)
00662         g_warning ("Failed to register CK Session: %s", error->message);
00663     g_clear_error (&error);
00664 
00665     return session;
00666 }
00667 
00668 static void
00669 handle_ck_call (GDBusConnection       *connection,
00670                 const gchar           *sender,
00671                 const gchar           *object_path,
00672                 const gchar           *interface_name,
00673                 const gchar           *method_name,
00674                 GVariant              *parameters,
00675                 GDBusMethodInvocation *invocation,
00676                 gpointer               user_data)
00677 {
00678     if (strcmp (method_name, "CanRestart") == 0)
00679         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
00680     else if (strcmp (method_name, "CanStop") == 0)
00681         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
00682     else if (strcmp (method_name, "CloseSession") == 0)
00683         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
00684     else if (strcmp (method_name, "OpenSession") == 0)
00685     {
00686         GVariantBuilder params;
00687         g_variant_builder_init (&params, G_VARIANT_TYPE ("a(sv)"));
00688         CKSession *session = open_ck_session (g_variant_builder_end (&params));
00689         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", session->cookie));
00690     }
00691     else if (strcmp (method_name, "OpenSessionWithParameters") == 0)
00692     {
00693         CKSession *session = open_ck_session (g_variant_get_child_value (parameters, 0));
00694         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", session->cookie));
00695     }
00696     else if (strcmp (method_name, "GetSessionForCookie") == 0)
00697     {
00698         GList *link;
00699         gchar *cookie;
00700 
00701         g_variant_get (parameters, "(&s)", &cookie);
00702 
00703         for (link = ck_sessions; link; link = link->next)
00704         {
00705             CKSession *session = link->data;
00706             if (strcmp (session->cookie, cookie) != 0)
00707             {
00708                 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", session->path));
00709                 return;
00710             }
00711         }
00712 
00713         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Unable to find session for cookie");
00714     }
00715     else if (strcmp (method_name, "Restart") == 0)
00716         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
00717     else if (strcmp (method_name, "Stop") == 0)
00718         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
00719     else
00720         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
00721 }
00722 
00723 static void
00724 handle_ck_session_call (GDBusConnection       *connection,
00725                         const gchar           *sender,
00726                         const gchar           *object_path,
00727                         const gchar           *interface_name,
00728                         const gchar           *method_name,
00729                         GVariant              *parameters,
00730                         GDBusMethodInvocation *invocation,
00731                         gpointer               user_data)
00732 {
00733     if (strcmp (method_name, "Lock") == 0)
00734         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
00735     else if (strcmp (method_name, "Unlock") == 0)
00736         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
00737     else
00738         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
00739 }
00740 
00741 static void
00742 ck_name_acquired_cb (GDBusConnection *connection,
00743                      const gchar     *name,
00744                      gpointer         user_data)
00745 {
00746     const gchar *ck_interface =
00747         "<node>"
00748         "  <interface name='org.freedesktop.ConsoleKit.Manager'>"
00749         "    <method name='CanRestart'>"
00750         "      <arg name='can_restart' direction='out' type='b'/>"
00751         "    </method>"
00752         "    <method name='CanStop'>"
00753         "      <arg name='can_stop' direction='out' type='b'/>"
00754         "    </method>"
00755         "    <method name='CloseSession'>"
00756         "      <arg name='cookie' direction='in' type='s'/>"
00757         "      <arg name='result' direction='out' type='b'/>"
00758         "    </method>"
00759         "    <method name='OpenSession'>"
00760         "      <arg name='cookie' direction='out' type='s'/>"
00761         "    </method>"
00762         "    <method name='OpenSessionWithParameters'>"
00763         "      <arg name='parameters' direction='in' type='a(sv)'/>"
00764         "      <arg name='cookie' direction='out' type='s'/>"
00765         "    </method>"
00766         "    <method name='GetSessionForCookie'>"
00767         "      <arg name='cookie' direction='in' type='s'/>"
00768         "      <arg name='ssid' direction='out' type='o'/>"
00769         "    </method>"
00770         "    <method name='Restart'/>"
00771         "    <method name='Stop'/>"
00772         "    <signal name='SeatAdded'>"
00773         "      <arg name='seat' type='o'/>"
00774         "    </signal>"
00775         "    <signal name='SeatRemoved'>"
00776         "      <arg name='seat' type='o'/>"
00777         "    </signal>"
00778         "  </interface>"
00779         "</node>";
00780     static const GDBusInterfaceVTable ck_vtable =
00781     {
00782         handle_ck_call,
00783     };
00784     const gchar *ck_session_interface =
00785         "<node>"
00786         "  <interface name='org.freedesktop.ConsoleKit.Session'>"
00787         "    <method name='Lock'/>"
00788         "    <method name='Unlock'/>"
00789         "  </interface>"
00790         "</node>";
00791     GDBusNodeInfo *ck_info;
00792     GError *error = NULL;
00793 
00794     ck_connection = connection;
00795 
00796     ck_info = g_dbus_node_info_new_for_xml (ck_interface, &error);
00797     if (error)
00798         g_warning ("Failed to parse D-Bus interface: %s", error->message);  
00799     g_clear_error (&error);
00800     if (!ck_info)
00801         return;
00802     ck_session_info = g_dbus_node_info_new_for_xml (ck_session_interface, &error);
00803     if (error)
00804         g_warning ("Failed to parse D-Bus interface: %s", error->message);  
00805     g_clear_error (&error);
00806     if (!ck_session_info)
00807         return;
00808     g_dbus_connection_register_object (connection,
00809                                        "/org/freedesktop/ConsoleKit/Manager",
00810                                        ck_info->interfaces[0],
00811                                        &ck_vtable,
00812                                        NULL, NULL,
00813                                        &error);
00814     if (error)
00815         g_warning ("Failed to register console kit service: %s", error->message);
00816     g_clear_error (&error);
00817     g_dbus_node_info_unref (ck_info);
00818 
00819     service_count--;
00820     if (service_count == 0)
00821         run_lightdm ();
00822 }
00823 
00824 static void
00825 start_console_kit_daemon ()
00826 {
00827     service_count++;
00828     g_bus_own_name (G_BUS_TYPE_SYSTEM,
00829                     "org.freedesktop.ConsoleKit",
00830                     G_BUS_NAME_OWNER_FLAGS_NONE,
00831                     ck_name_acquired_cb,
00832                     NULL,
00833                     NULL,
00834                     NULL,
00835                     NULL);
00836 }
00837 
00838 static void
00839 load_passwd_file ()
00840 {
00841     gchar *path, *data, **lines;
00842     int i;
00843 
00844     path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "passwd", NULL);
00845     g_file_get_contents (path, &data, NULL, NULL);
00846     g_free (path);
00847     lines = g_strsplit (data, "\n", -1);
00848     g_free (data);
00849 
00850     for (i = 0; lines[i]; i++)
00851     {
00852         gchar **fields;
00853         guint uid;
00854         gchar *user_name, *real_name;
00855         GList *link;
00856         AccountsUser *user = NULL;
00857         GError *error = NULL;
00858 
00859         fields = g_strsplit (lines[i], ":", -1);
00860         if (fields == NULL || g_strv_length (fields) < 7)
00861             continue;
00862 
00863         user_name = fields[0];
00864         uid = atoi (fields[2]);
00865         real_name = fields[4];
00866 
00867         for (link = accounts_users; link; link = link->next)
00868         {
00869             AccountsUser *u = link->data;
00870             if (u->uid == uid)
00871             {
00872                 user = u;
00873                 break;
00874             }
00875         }
00876         if (!user)
00877         {
00878             gchar *path;
00879             GKeyFile *dmrc_file;
00880 
00881             user = g_malloc0 (sizeof (AccountsUser));
00882             accounts_users = g_list_append (accounts_users, user);
00883 
00884             dmrc_file = g_key_file_new ();
00885             path = g_build_filename (temp_dir, "home", user_name, ".dmrc", NULL);
00886             g_key_file_load_from_file (dmrc_file, path, G_KEY_FILE_NONE, NULL);
00887             g_free (path);
00888 
00889             user->uid = uid;
00890             user->user_name = g_strdup (user_name);
00891             user->real_name = g_strdup (real_name);
00892             user->home_directory = g_build_filename (temp_dir, "home", user_name, NULL);
00893             user->language = g_key_file_get_string (dmrc_file, "Desktop", "Language", NULL);
00894             /* DMRC contains a locale, strip the codeset off it to get the language */
00895             if (user->language)
00896             {
00897                 gchar *c = strchr (user->language, '.');
00898                 if (c)
00899                     *c = '\0';
00900             }
00901             user->xsession = g_key_file_get_string (dmrc_file, "Desktop", "Session", NULL);
00902             user->layouts = g_key_file_get_string_list (dmrc_file, "X-Accounts", "Layouts", NULL, NULL);
00903             user->path = g_strdup_printf ("/org/freedesktop/Accounts/User%d", uid);
00904             user->id = g_dbus_connection_register_object (accounts_connection,
00905                                                           user->path,
00906                                                           user_info->interfaces[0],
00907                                                           &user_vtable,
00908                                                           user,
00909                                                           NULL,
00910                                                           &error);
00911             if (error)
00912                 g_warning ("Failed to register user: %s", error->message);
00913             g_clear_error (&error);
00914 
00915             g_key_file_free (dmrc_file);
00916         }
00917 
00918         g_strfreev (fields);
00919     }
00920 
00921     g_strfreev (lines);
00922 }
00923 
00924 static void
00925 handle_accounts_call (GDBusConnection       *connection,
00926                       const gchar           *sender,
00927                       const gchar           *object_path,
00928                       const gchar           *interface_name,
00929                       const gchar           *method_name,
00930                       GVariant              *parameters,
00931                       GDBusMethodInvocation *invocation,
00932                       gpointer               user_data)
00933 {
00934     if (strcmp (method_name, "ListCachedUsers") == 0)
00935     {
00936         GVariantBuilder builder;
00937         GList *link;
00938 
00939         g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
00940 
00941         load_passwd_file ();      
00942         for (link = accounts_users; link; link = link->next)
00943         {
00944             AccountsUser *user = link->data;
00945             g_variant_builder_add_value (&builder, g_variant_new_object_path (user->path));
00946         }
00947 
00948         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(ao)", &builder));
00949     }
00950     else if (strcmp (method_name, "FindUserByName") == 0)
00951     {
00952         GList *link;
00953         AccountsUser *user = NULL;
00954         gchar *user_name;
00955 
00956         g_variant_get (parameters, "(&s)", &user_name);
00957 
00958         load_passwd_file ();
00959         for (link = accounts_users; link; link = link->next)
00960         {
00961             AccountsUser *u = link->data;
00962             if (strcmp (u->user_name, user_name) == 0)
00963             {
00964                 user = u;
00965                 break;
00966             }
00967         }
00968         if (user)
00969             g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", user->path));
00970         else
00971             g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such user: %s", user_name);
00972     }
00973     else
00974         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);    
00975 }
00976 
00977 static void
00978 handle_user_call (GDBusConnection       *connection,
00979                   const gchar           *sender,
00980                   const gchar           *object_path,
00981                   const gchar           *interface_name,
00982                   const gchar           *method_name,
00983                   GVariant              *parameters,
00984                   GDBusMethodInvocation *invocation,
00985                   gpointer               user_data)
00986 {
00987     AccountsUser *user = user_data;
00988 
00989     if (strcmp (method_name, "SetXSession") == 0)
00990     {
00991         gchar *xsession;
00992 
00993         g_variant_get (parameters, "(&s)", &xsession);
00994 
00995         g_free (user->xsession);
00996         user->xsession = g_strdup (xsession);
00997 
00998         g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
00999     }
01000     else
01001         g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
01002 }
01003 
01004 static GVariant *
01005 handle_user_get_property (GDBusConnection       *connection,
01006                           const gchar           *sender,
01007                           const gchar           *object_path,
01008                           const gchar           *interface_name,
01009                           const gchar           *property_name,
01010                           GError               **error,
01011                           gpointer               user_data)
01012 {
01013     AccountsUser *user = user_data;
01014 
01015     if (strcmp (property_name, "UserName") == 0)
01016         return g_variant_new_string (user->user_name);
01017     else if (strcmp (property_name, "RealName") == 0)
01018         return g_variant_new_string (user->real_name);
01019     else if (strcmp (property_name, "HomeDirectory") == 0)
01020         return g_variant_new_string (user->home_directory);
01021     else if (strcmp (property_name, "BackgroundFile") == 0)
01022         return g_variant_new_string ("");
01023     else if (strcmp (property_name, "Language") == 0)
01024         return g_variant_new_string (user->language ? user->language : "");
01025     else if (strcmp (property_name, "XSession") == 0)
01026         return g_variant_new_string (user->xsession ? user->xsession : "");
01027     else if (strcmp (property_name, "XKeyboardLayouts") == 0)
01028     {
01029         if (user->layouts != NULL)
01030             return g_variant_new_strv ((const gchar * const *) user->layouts, -1);
01031         else
01032             return g_variant_new_strv (NULL, 0);
01033     }
01034     else if (strcmp (property_name, "XHasMessages") == 0)
01035         return g_variant_new_boolean (FALSE);
01036 
01037     return NULL;
01038 }
01039 
01040 static void
01041 accounts_name_acquired_cb (GDBusConnection *connection,
01042                            const gchar     *name,
01043                            gpointer         user_data)
01044 {
01045     const gchar *accounts_interface =
01046         "<node>"
01047         "  <interface name='org.freedesktop.Accounts'>"
01048         "    <method name='ListCachedUsers'>"
01049         "      <arg name='user' direction='out' type='ao'/>"
01050         "    </method>"
01051         "    <method name='FindUserByName'>"
01052         "      <arg name='name' direction='in' type='s'/>"
01053         "      <arg name='user' direction='out' type='o'/>"
01054         "    </method>"
01055         "  </interface>"
01056         "</node>";
01057     static const GDBusInterfaceVTable accounts_vtable =
01058     {
01059         handle_accounts_call,
01060     };
01061     const gchar *user_interface =
01062         "<node>"
01063         "  <interface name='org.freedesktop.Accounts.User'>"
01064         "    <method name='SetXSession'>"
01065         "      <arg name='x_session' direction='in' type='s'/>"
01066         "    </method>"
01067         "    <property name='UserName' type='s' access='read'/>"
01068         "    <property name='RealName' type='s' access='read'/>"
01069         "    <property name='HomeDirectory' type='s' access='read'/>"
01070         "    <property name='BackgroundFile' type='s' access='read'/>"
01071         "    <property name='Language' type='s' access='read'/>"
01072         "    <property name='XSession' type='s' access='read'/>"
01073         "    <property name='XKeyboardLayouts' type='as' access='read'/>"
01074         "    <property name='XHasMessages' type='b' access='read'/>"
01075         "  </interface>"
01076         "</node>";
01077     GError *error = NULL;
01078 
01079     accounts_connection = connection;
01080 
01081     accounts_info = g_dbus_node_info_new_for_xml (accounts_interface, &error);
01082     if (error)
01083         g_warning ("Failed to parse D-Bus interface: %s", error->message);  
01084     g_clear_error (&error);
01085     if (!accounts_info)
01086         return;
01087     user_info = g_dbus_node_info_new_for_xml (user_interface, &error);
01088     if (error)
01089         g_warning ("Failed to parse D-Bus interface: %s", error->message);  
01090     g_clear_error (&error);
01091     if (!user_info)
01092         return;
01093     g_dbus_connection_register_object (connection,
01094                                        "/org/freedesktop/Accounts",
01095                                        accounts_info->interfaces[0],
01096                                        &accounts_vtable,
01097                                        NULL,
01098                                        NULL,
01099                                        &error);
01100     if (error)
01101         g_warning ("Failed to register accounts service: %s", error->message);
01102     g_clear_error (&error);
01103     g_dbus_node_info_unref (accounts_info);
01104 
01105     service_count--;
01106     if (service_count == 0)
01107         run_lightdm ();
01108 }
01109 
01110 static void
01111 start_accounts_service_daemon ()
01112 {
01113     service_count++;
01114     g_bus_own_name (G_BUS_TYPE_SYSTEM,
01115                     "org.freedesktop.Accounts",
01116                     G_BUS_NAME_OWNER_FLAGS_NONE,
01117                     accounts_name_acquired_cb,
01118                     NULL,
01119                     NULL,
01120                     NULL,
01121                     NULL);
01122 }
01123 
01124 static void
01125 run_lightdm ()
01126 {
01127     GString *command_line;
01128     gchar **lightdm_argv;
01129     pid_t lightdm_pid;
01130     GError *error = NULL;
01131 
01132     run_commands ();
01133 
01134     status_timeout = g_timeout_add (STATUS_TIMEOUT, status_timeout_cb, NULL);
01135 
01136     command_line = g_string_new ("lightdm");
01137     if (getenv ("DEBUG"))
01138         g_string_append (command_line, " --debug");
01139     g_string_append_printf (command_line, " --cache-dir %s/cache", temp_dir);
01140     g_string_append_printf (command_line, " --xsessions-dir=%s/usr/share/xsessions", temp_dir);
01141     g_string_append_printf (command_line, " --xgreeters-dir=%s/usr/share/xgreeters", temp_dir);
01142 
01143     g_print ("Start daemon with command: PATH=%s LD_PRELOAD=%s LD_LIBRARY_PATH=%s LIGHTDM_TEST_ROOT=%s DBUS_SESSION_BUS_ADDRESS=%s %s\n",
01144              g_getenv ("PATH"), g_getenv ("LD_PRELOAD"), g_getenv ("LD_LIBRARY_PATH"), g_getenv ("LIGHTDM_TEST_ROOT"), g_getenv ("DBUS_SESSION_BUS_ADDRESS"),
01145              command_line->str);
01146 
01147     if (!g_shell_parse_argv (command_line->str, NULL, &lightdm_argv, &error))
01148     {
01149         g_warning ("Error parsing command line: %s", error->message);
01150         quit (EXIT_FAILURE);
01151     }
01152     g_clear_error (&error);
01153 
01154     if (!g_spawn_async (NULL, lightdm_argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL, NULL, &lightdm_pid, &error))
01155     {
01156         g_warning ("Error launching LightDM: %s", error->message);
01157         quit (EXIT_FAILURE);
01158     }
01159     g_clear_error (&error);
01160     lightdm_process = watch_process (lightdm_pid);
01161 
01162     check_status ("RUNNER DAEMON-START");
01163 }
01164 
01165 static gboolean
01166 signal_cb (gpointer user_data)
01167 {
01168     g_print ("Caught signal, quitting\n");
01169     quit (EXIT_FAILURE);
01170     return FALSE;
01171 }
01172 
01173 int
01174 main (int argc, char **argv)
01175 {
01176     GMainLoop *loop;
01177     gchar *greeter = NULL, *script_name, *config_file, *path, *path1, *path2, *ld_preload, *ld_library_path, *home_dir;
01178     GString *passwd_data, *group_data;
01179     GSource *status_source;
01180     gchar cwd[1024];
01181     GError *error = NULL;
01182 
01183     g_type_init ();
01184 
01185     loop = g_main_loop_new (NULL, FALSE);
01186 
01187     g_unix_signal_add (SIGINT, signal_cb, NULL);
01188     g_unix_signal_add (SIGTERM, signal_cb, NULL);
01189 
01190     children = g_hash_table_new (g_direct_hash, g_direct_equal);
01191 
01192     if (argc != 3)
01193     {
01194         g_printerr ("Usage %s SCRIPT-NAME GREETER\n", argv[0]);
01195         quit (EXIT_FAILURE);
01196     }
01197     script_name = argv[1];
01198     config_file = g_strdup_printf ("%s.conf", script_name);
01199     config_path = g_build_filename (SRCDIR, "tests", "scripts", config_file, NULL);
01200     g_free (config_file);
01201 
01202     config = g_key_file_new ();
01203     g_key_file_load_from_file (config, config_path, G_KEY_FILE_NONE, NULL);
01204 
01205     load_script (config_path);
01206 
01207     g_print ("----------------------------------------\n");
01208     g_print ("Running script %s\n", script_name);
01209 
01210     if (!getcwd (cwd, 1024))
01211     {
01212         g_critical ("Error getting current directory: %s", strerror (errno));
01213         quit (EXIT_FAILURE);
01214     }
01215   
01216     /* Don't contact our X server */
01217     g_unsetenv ("DISPLAY");
01218 
01219     /* Override system calls */
01220     ld_preload = g_build_filename (BUILDDIR, "tests", "src", ".libs", "libsystem.so", NULL);
01221     g_setenv ("LD_PRELOAD", ld_preload, TRUE);
01222     g_free (ld_preload);
01223 
01224     /* Run test programs */
01225     path = g_strdup_printf ("%s/tests/src/.libs:%s/tests/src:%s/tests/src:%s/src:%s", BUILDDIR, BUILDDIR, SRCDIR, BUILDDIR, g_getenv ("PATH"));
01226     g_setenv ("PATH", path, TRUE);
01227     g_free (path);
01228 
01229     /* Use locally built libraries */
01230     path1 = g_build_filename (BUILDDIR, "liblightdm-gobject", ".libs", NULL);  
01231     path2 = g_build_filename (BUILDDIR, "liblightdm-qt", ".libs", NULL);
01232     ld_library_path = g_strdup_printf ("%s:%s", path1, path2);
01233     g_free (path1);
01234     g_free (path2);
01235     g_setenv ("LD_LIBRARY_PATH", ld_library_path, TRUE);
01236     g_free (ld_library_path);
01237     path1 = g_build_filename (BUILDDIR, "liblightdm-gobject", NULL);
01238     g_setenv ("GI_TYPELIB_PATH", path1, TRUE);
01239     g_free (path1);
01240 
01241     /* Run from a temporary directory */
01242     temp_dir = g_build_filename (g_get_tmp_dir (), "lightdm-test-XXXXXX", NULL);
01243     if (!mkdtemp (temp_dir))
01244     {
01245         g_warning ("Error creating temporary directory: %s", strerror (errno));
01246         quit (EXIT_FAILURE);
01247     }
01248     g_chmod (temp_dir, 0755);
01249     g_setenv ("LIGHTDM_TEST_ROOT", temp_dir, TRUE);
01250 
01251     /* Open socket for status */
01252     status_socket_name = g_build_filename (temp_dir, ".status-socket", NULL);
01253     unlink (status_socket_name);
01254     status_socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, &error);
01255     if (error)
01256         g_warning ("Error creating status socket: %s", error->message);
01257     g_clear_error (&error);
01258     if (status_socket)
01259     {
01260         GSocketAddress *address;
01261         gboolean result;
01262 
01263         address = g_unix_socket_address_new (status_socket_name);
01264         result = g_socket_bind (status_socket, address, FALSE, &error);
01265         g_object_unref (address);
01266         if (error)
01267             g_warning ("Error binding status socket: %s", error->message);
01268         g_clear_error (&error);
01269         if (result)
01270         {
01271             result = g_socket_listen (status_socket, &error);
01272             if (error)
01273                 g_warning ("Error listening on status socket: %s", error->message);
01274             g_clear_error (&error);
01275         }
01276         if (!result)
01277         {
01278             g_object_unref (status_socket);
01279             status_socket = NULL;
01280         }
01281     }
01282     if (!status_socket)
01283         quit (EXIT_FAILURE);
01284     status_source = g_socket_create_source (status_socket, G_IO_IN, NULL);
01285     g_source_set_callback (status_source, status_connect_cb, NULL, NULL);
01286     g_source_attach (status_source, NULL);
01287 
01288     /* Set up a skeleton file system */
01289     g_mkdir_with_parents (g_strdup_printf ("%s/etc", temp_dir), 0755);
01290     g_mkdir_with_parents (g_strdup_printf ("%s/usr/share", temp_dir), 0755);
01291 
01292     /* Copy over the configuration */
01293     g_mkdir_with_parents (g_strdup_printf ("%s/etc/lightdm", temp_dir), 0755);
01294     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))
01295         if (system (g_strdup_printf ("cp %s %s/etc/lightdm/lightdm.conf", config_path, temp_dir)))
01296             perror ("Failed to copy configuration");
01297 
01298     /* Always copy the script */
01299     if (system (g_strdup_printf ("cp %s %s/script", config_path, temp_dir)))
01300         perror ("Failed to copy configuration");  
01301 
01302     /* Copy over the greeter files */
01303     if (system (g_strdup_printf ("cp -r %s/xsessions %s/usr/share", DATADIR, temp_dir)))
01304         perror ("Failed to copy xsessions");
01305     if (system (g_strdup_printf ("cp -r %s/xgreeters %s/usr/share", DATADIR, temp_dir)))
01306         perror ("Failed to copy xgreeters");
01307 
01308     /* Set up the default greeter */
01309     path = g_build_filename (temp_dir, "usr", "share", "xgreeters", "default.desktop", NULL);
01310     greeter = g_strdup_printf ("%s.desktop", argv[2]);
01311     if (symlink (greeter, path) < 0)
01312     {
01313         g_printerr ("Failed to make greeter symlink %s->%s: %s\n", path, greeter, strerror (errno));
01314         quit (EXIT_FAILURE);
01315     }
01316     g_free (path);
01317     g_free (greeter);
01318 
01319     home_dir = g_build_filename (temp_dir, "home", NULL);
01320 
01321     /* Make fake users */
01322     struct
01323     {
01324         gchar *user_name;
01325         gchar *password;
01326         gboolean have_home_dir;
01327         gchar *real_name;
01328         gchar *xsession;
01329         gchar *dmrc_layout;
01330         gchar *dbus_layouts;
01331         gchar *language;
01332         gint uid;
01333     } users[] =
01334     {
01335         /* Root account */
01336         {"root",             "",         TRUE,  "root",               NULL,  NULL, NULL,          NULL,             0},
01337         /* Unprivileged account for greeters */
01338         {"lightdm",          "",         TRUE,  "",                   NULL,  NULL, NULL,          NULL,           100},
01339         /* These accounts have a password */
01340         {"have-password1",   "password", TRUE,  "Password User 1",    NULL,  NULL, NULL,          NULL,          1000},
01341         {"have-password2",   "password", TRUE,  "Password User 2",    NULL,  NULL, NULL,          NULL,          1001},
01342         {"have-password3",   "password", TRUE,  "Password User 3",    NULL,  NULL, NULL,          NULL,          1002},
01343         {"have-password4",   "password", TRUE,  "Password User 4",    NULL,  NULL, NULL,          NULL,          1003},
01344         /* This account always prompts for a password, even if using the lightdm-autologin service */
01345         {"always-password",  "password", TRUE,  "Password User 4",    NULL,  NULL, NULL,          NULL,          1004},
01346         /* These accounts have no password */
01347         {"no-password1",     "",         TRUE,  "No Password User 1", NULL,  NULL, NULL,          NULL,          1005},
01348         {"no-password2",     "",         TRUE,  "No Password User 2", NULL,  NULL, NULL,          NULL,          1006},
01349         {"no-password3",     "",         TRUE,  "No Password User 3", NULL,  NULL, NULL,          NULL,          1007},
01350         {"no-password4",     "",         TRUE,  "No Password User 4", NULL,  NULL, NULL,          NULL,          1008},
01351         /* This account has a keyboard layout */
01352         {"have-layout",      "",         TRUE,  "Layout User",        NULL,  "us", NULL,          NULL,          1009},
01353         /* This account has a set of keyboard layouts */
01354         {"have-layouts",     "",         TRUE,  "Layouts User",       NULL,  "ru", "fr\toss;ru;", NULL,          1010},
01355         /* This account has a language set */
01356         {"have-language",    "",         TRUE,  "Language User",      NULL,  NULL, NULL,          "en_AU.utf8",  1011},      
01357         /* This account has a preconfigured session */
01358         {"have-session",            "",  TRUE,  "Session User", "alternative", NULL, NULL,        NULL,          1012},
01359         /* This account has the home directory mounted on login */
01360         {"mount-home-dir",   "",         FALSE, "Mounted Home Dir User", NULL, NULL, NULL,        NULL,          1013},
01361         /* This account is denied access */
01362         {"denied",           "",         TRUE,  "Denied User",        NULL,  NULL, NULL,          NULL,          1014},
01363         /* This account has expired */
01364         {"expired",          "",         TRUE,  "Expired User",       NULL,  NULL, NULL,          NULL,          1015},
01365         /* This account needs a password change */
01366         {"new-authtok",      "",         TRUE,  "New Token User",     NULL,  NULL, NULL,          NULL,          1016},
01367         /* This account is switched to change-user2 when authentication succeeds */
01368         {"change-user1",     "",         TRUE,  "Change User 1",      NULL,  NULL, NULL,          NULL,          1017},
01369         {"change-user2",     "",         TRUE,  "Change User 2",      NULL,  NULL, NULL,          NULL,          1018},
01370         /* This account switches to invalid-user when authentication succeeds */
01371         {"change-user-invalid", "",      TRUE,  "Invalid Change User",NULL,  NULL, NULL,          NULL,          1019},
01372         /* This account crashes on authentication */
01373         {"crash-authenticate", "",       TRUE,  "Crash Auth User",    NULL,  NULL, NULL,          NULL,          1020},
01374         /* This account shows an informational prompt on login */
01375         {"info-prompt",      "password", TRUE,  "Info Prompt",        NULL,  NULL, NULL,          NULL,          1021},
01376         /* This account shows multiple informational prompts on login */
01377         {"multi-info-prompt","password", TRUE,  "Multi Info Prompt",  NULL,  NULL, NULL,          NULL,          1022},
01378         /* This account uses two factor authentication */
01379         {"two-factor",       "password", TRUE,  "Two Factor",         NULL,  NULL, NULL,          NULL,          1023},
01380         /* This account has a special group */
01381         {"group-member",     "password", TRUE,  "Group Member",       NULL,  NULL, NULL,          NULL,          1024},
01382         /* This account has the home directory created when the session starts */
01383         {"make-home-dir",    "",         FALSE, "Make Home Dir User", NULL,  NULL, NULL,          NULL,          1025},
01384         /* This account fails to open a session */
01385         {"session-error",    "password", TRUE,  "Session Error",      NULL,  NULL, NULL,          NULL,          1026},
01386         /* This account can't establish credentials */
01387         {"cred-error",       "password", TRUE,  "Cred Error",         NULL,  NULL, NULL,          NULL,          1027},
01388         /* This account has expired credentials */
01389         {"cred-expired",     "password", TRUE,  "Cred Expired",       NULL,  NULL, NULL,          NULL,          1028},
01390         /* This account has cannot access their credentials */
01391         {"cred-unavail",     "password", TRUE,  "Cred Unavail",       NULL,  NULL, NULL,          NULL,          1029},
01392         /* This account sends informational messages for each PAM function that is called */
01393         {"log-pam",          "password", TRUE,  "Log PAM",            NULL,  NULL, NULL,          NULL,          1030},
01394         {NULL,               NULL,       FALSE, NULL,                 NULL,  NULL, NULL,          NULL,             0}
01395     };
01396     passwd_data = g_string_new ("");
01397     group_data = g_string_new ("");
01398     int i;
01399     for (i = 0; users[i].user_name; i++)
01400     {
01401         GKeyFile *dmrc_file;
01402         gboolean save_dmrc = FALSE;
01403 
01404         if (users[i].have_home_dir)
01405         {
01406             path = g_build_filename (home_dir, users[i].user_name, NULL);
01407             g_mkdir_with_parents (path, 0755);
01408             if (chown (path, users[i].uid, users[i].uid) < 0)
01409               g_debug ("chown (%s) failed: %s", path, strerror (errno));
01410             g_free (path);
01411         }
01412 
01413         dmrc_file = g_key_file_new ();
01414         if (users[i].xsession)
01415         {
01416             g_key_file_set_string (dmrc_file, "Desktop", "Session", users[i].xsession);
01417             save_dmrc = TRUE;
01418         }
01419         if (users[i].dmrc_layout)
01420         {
01421             g_key_file_set_string (dmrc_file, "Desktop", "Layout", users[i].dmrc_layout);
01422             save_dmrc = TRUE;
01423         }
01424         if (users[i].dbus_layouts)
01425         {
01426             g_key_file_set_string (dmrc_file, "X-Accounts", "Layouts", users[i].dbus_layouts);
01427             save_dmrc = TRUE;
01428         }
01429         if (users[i].language)
01430         {
01431             g_key_file_set_string (dmrc_file, "Desktop", "Language", users[i].language);
01432             save_dmrc = TRUE;
01433         }
01434 
01435         if (save_dmrc)
01436         {
01437             gchar *data;
01438 
01439             path = g_build_filename (home_dir, users[i].user_name, ".dmrc", NULL);
01440             data = g_key_file_to_data (dmrc_file, NULL, NULL);
01441             g_file_set_contents (path, data, -1, NULL);
01442             g_free (data);
01443             g_free (path);         
01444         }
01445 
01446         g_key_file_free (dmrc_file);
01447 
01448         /* Add passwd file entry */
01449         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);
01450 
01451         /* Add group file entry */
01452         g_string_append_printf (group_data, "%s:x:%d:%s\n", users[i].user_name, users[i].uid, users[i].user_name);
01453     }
01454     path = g_build_filename (temp_dir, "etc", "passwd", NULL);
01455     g_file_set_contents (path, passwd_data->str, -1, NULL);
01456     g_free (path);
01457     g_string_free (passwd_data, TRUE);
01458 
01459     /* Add an extra test group */
01460     g_string_append_printf (group_data, "test-group:x:111:\n");
01461 
01462     path = g_build_filename (temp_dir, "etc", "group", NULL);
01463     g_file_set_contents (path, group_data->str, -1, NULL);
01464     g_free (path);
01465     g_string_free (group_data, TRUE);
01466 
01467     /* Start D-Bus services */
01468     if (!g_key_file_get_boolean (config, "test-runner-config", "disable-console-kit", NULL))
01469         start_console_kit_daemon ();
01470     if (!g_key_file_get_boolean (config, "test-runner-config", "disable-accounts-service", NULL))
01471         start_accounts_service_daemon ();
01472 
01473     g_main_loop_run (loop);
01474 
01475     return EXIT_FAILURE;
01476 }