7 #include <glib/gstdio.h>
10 #include <gio/gunixsocketaddress.h>
14 /* Timeout in ms waiting for the status we expect */
15 static int status_timeout_ms = 4000;
17 /* Timeout in ms to wait for SIGTERM to be handled by a child process */
18 #define KILL_TIMEOUT 2000
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;
31 static GList *script = NULL;
32 static guint status_timeout = 0;
33 static gchar *temp_dir = NULL;
34 static int service_count;
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;
52 gchar *home_directory;
60 gboolean has_messages;
63 static GList *accounts_users = NULL;
64 static void handle_user_call (GDBusConnection *connection,
66 const gchar *object_path,
67 const gchar *interface_name,
68 const gchar *method_name,
70 GDBusMethodInvocation *invocation,
72 static GVariant *handle_user_get_property (GDBusConnection *connection,
74 const gchar *object_path,
75 const gchar *interface_name,
76 const gchar *property_name,
79 static const GDBusInterfaceVTable user_vtable =
82 handle_user_get_property,
84 static GDBusConnection *ck_connection = NULL;
85 static GDBusNodeInfo *ck_session_info;
93 static GList *ck_sessions = NULL;
94 static gint ck_session_index = 0;
95 static void handle_ck_session_call (GDBusConnection *connection,
97 const gchar *object_path,
98 const gchar *interface_name,
99 const gchar *method_name,
100 GVariant *parameters,
101 GDBusMethodInvocation *invocation,
103 static const GDBusInterfaceVTable ck_session_vtable =
105 handle_ck_session_call,
115 static GList *login1_sessions = NULL;
116 static gint login1_session_index = 0;
123 static GList *status_clients = NULL;
125 static void run_lightdm (void);
126 static void quit (int status);
127 static void check_status (const gchar *status);
128 static AccountsUser *get_accounts_user_by_uid (guint uid);
129 static AccountsUser *get_accounts_user_by_name (const gchar *username);
130 static void accounts_user_set_hidden (AccountsUser *user, gboolean hidden, gboolean emit_signal);
133 kill_timeout_cb (gpointer data)
135 Process *process = data;
137 if (getenv ("DEBUG"))
138 g_print ("Sending SIGKILL to process %d\n", process->pid);
139 kill (process->pid, SIGKILL);
144 stop_process (Process *process)
146 if (process->kill_timeout != 0)
149 if (getenv ("DEBUG"))
150 g_print ("Sending SIGTERM to process %d\n", process->pid);
151 kill (process->pid, SIGTERM);
152 process->kill_timeout = g_timeout_add (KILL_TIMEOUT, kill_timeout_cb, process);
156 process_exit_cb (GPid pid, gint status, gpointer data)
161 if (getenv ("DEBUG"))
163 if (WIFEXITED (status))
164 g_print ("Process %d exited with status %d\n", pid, WEXITSTATUS (status));
166 g_print ("Process %d terminated with signal %d\n", pid, WTERMSIG (status));
169 if (lightdm_process && pid == lightdm_process->pid)
171 process = lightdm_process;
172 lightdm_process = NULL;
173 if (WIFEXITED (status))
174 status_text = g_strdup_printf ("RUNNER DAEMON-EXIT STATUS=%d", WEXITSTATUS (status));
176 status_text = g_strdup_printf ("RUNNER DAEMON-TERMINATE SIGNAL=%d", WTERMSIG (status));
177 check_status (status_text);
181 process = g_hash_table_lookup (children, GINT_TO_POINTER (pid));
184 g_hash_table_remove (children, GINT_TO_POINTER (pid));
187 if (process->kill_timeout)
188 g_source_remove (process->kill_timeout);
189 process->kill_timeout = 0;
191 /* Quit once all children have stopped */
197 watch_process (pid_t pid)
201 process = g_malloc0 (sizeof (Process));
203 process->kill_timeout = 0;
205 if (getenv ("DEBUG"))
206 g_print ("Watching process %d\n", process->pid);
207 g_child_watch_add (process->pid, process_exit_cb, NULL);
218 exit_status = status;
221 /* Stop all the children */
222 g_hash_table_iter_init (&iter, children);
227 if (!g_hash_table_iter_next (&iter, &key, &value))
230 stop_process ((Process *)value);
233 /* Don't quit until all children are stopped */
234 if (g_hash_table_size (children) > 0)
237 /* Stop the daemon */
240 stop_process (lightdm_process);
244 if (status_socket_name)
245 unlink (status_socket_name);
247 if (temp_dir && getenv ("DEBUG") == NULL)
249 gchar *command = g_strdup_printf ("rm -rf %s", temp_dir);
250 if (system (command))
251 perror ("Failed to delete temp directory");
258 fail (const gchar *event, const gchar *expected)
265 g_printerr ("Command line: %s", test_runner_command);
266 g_printerr ("Events:\n");
267 for (link = statuses; link; link = link->next)
268 g_printerr (" %s\n", (gchar *)link->data);
270 g_printerr (" %s\n", event);
272 g_printerr (" ^^^ expected \"%s\"\n", expected);
274 g_printerr ("^^^ expected nothing\n");
280 get_prefix (const gchar *text)
285 prefix = g_strdup (text);
286 for (i = 0; prefix[i] != '\0' && prefix[i] != ' '; i++);
293 get_script_line (const gchar *prefix)
297 for (link = script; link; link = link->next)
299 ScriptLine *line = link->data;
301 /* Ignore lines with other prefixes */
307 p = get_prefix (line->text);
308 matches = strcmp (prefix, p) == 0;
323 handle_command (const gchar *command)
330 while (*c && !isspace (*c))
332 name = g_strdup_printf ("%.*s", (int) (c - command), command);
334 params = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
338 gchar *param_name, *param_value;
343 while (*c && !isspace (*c) && *c != '=')
348 param_name = g_strdup_printf ("%.*s", (int) (c - start), start);
357 gboolean escaped = FALSE;
361 value = g_string_new ("");
368 g_string_append_c (value, '\\');
374 else if (!escaped && *c == '\"')
377 g_string_append_c (value, *c);
380 param_value = value->str;
381 g_string_free (value, FALSE);
388 while (*c && !isspace (*c))
390 param_value = g_strdup_printf ("%.*s", (int) (c - start), start);
394 param_value = g_strdup ("");
396 g_hash_table_insert (params, param_name, param_value);
399 if (strcmp (name, "WAIT") == 0)
403 else if (strcmp (name, "LIST-SEATS") == 0)
405 GVariant *result, *value;
411 result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
412 "org.freedesktop.DisplayManager",
413 "/org/freedesktop/DisplayManager",
414 "org.freedesktop.DBus.Properties",
416 g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Seats"),
417 G_VARIANT_TYPE ("(v)"),
418 G_DBUS_CALL_FLAGS_NONE,
423 status = g_string_new ("RUNNER LIST-SEATS SEATS=");
424 g_variant_get (result, "(v)", &value);
425 g_variant_get (value, "ao", &iter);
426 while (g_variant_iter_loop (iter, "&o", &path))
429 g_string_append (status, ",");
430 g_string_append (status, path);
433 g_variant_unref (value);
434 g_variant_unref (result);
436 check_status (status->str);
437 g_string_free (status, TRUE);
439 else if (strcmp (name, "LIST-SESSIONS") == 0)
441 GVariant *result, *value;
447 result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
448 "org.freedesktop.DisplayManager",
449 "/org/freedesktop/DisplayManager",
450 "org.freedesktop.DBus.Properties",
452 g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Sessions"),
453 G_VARIANT_TYPE ("(v)"),
454 G_DBUS_CALL_FLAGS_NONE,
459 status = g_string_new ("RUNNER LIST-SESSIONS SESSIONS=");
460 g_variant_get (result, "(v)", &value);
461 g_variant_get (value, "ao", &iter);
462 while (g_variant_iter_loop (iter, "&o", &path))
465 g_string_append (status, ",");
466 g_string_append (status, path);
469 g_variant_unref (value);
470 g_variant_unref (result);
472 check_status (status->str);
473 g_string_free (status, TRUE);
475 else if (strcmp (name, "SWITCH-TO-GREETER") == 0)
477 g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
478 "org.freedesktop.DisplayManager",
479 "/org/freedesktop/DisplayManager/Seat0",
480 "org.freedesktop.DisplayManager.Seat",
482 g_variant_new ("()"),
483 G_VARIANT_TYPE ("()"),
484 G_DBUS_CALL_FLAGS_NONE,
488 check_status ("RUNNER SWITCH-TO-GREETER");
490 else if (strcmp (name, "SWITCH-TO-USER") == 0)
492 gchar *status_text, *username;
494 username = g_hash_table_lookup (params, "USERNAME");
495 g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
496 "org.freedesktop.DisplayManager",
497 "/org/freedesktop/DisplayManager/Seat0",
498 "org.freedesktop.DisplayManager.Seat",
500 g_variant_new ("(ss)", username, ""),
501 G_VARIANT_TYPE ("()"),
502 G_DBUS_CALL_FLAGS_NONE,
506 status_text = g_strdup_printf ("RUNNER SWITCH-TO-USER USERNAME=%s", username);
507 check_status (status_text);
508 g_free (status_text);
510 else if (strcmp (name, "SWITCH-TO-GUEST") == 0)
512 g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
513 "org.freedesktop.DisplayManager",
514 "/org/freedesktop/DisplayManager/Seat0",
515 "org.freedesktop.DisplayManager.Seat",
517 g_variant_new ("(s)", ""),
518 G_VARIANT_TYPE ("()"),
519 G_DBUS_CALL_FLAGS_NONE,
523 check_status ("RUNNER SWITCH-TO-GUEST");
525 else if (strcmp (name, "STOP-DAEMON") == 0)
526 stop_process (lightdm_process);
527 // FIXME: Make generic RUN-COMMAND
528 else if (strcmp (name, "START-XSERVER") == 0)
530 gchar *xserver_args, *command_line;
534 GError *error = NULL;
536 xserver_args = g_hash_table_lookup (params, "ARGS");
539 command_line = g_strdup_printf ("%s/tests/src/X %s", BUILDDIR, xserver_args);
541 if (!g_shell_parse_argv (command_line, NULL, &argv, &error) ||
542 !g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &error))
544 g_printerr ("Error starting X server: %s", error->message);
549 process = watch_process (pid);
550 g_hash_table_insert (children, GINT_TO_POINTER (process->pid), process);
553 else if (strcmp (name, "START-VNC-CLIENT") == 0)
555 gchar *vnc_client_args, *command_line;
559 GError *error = NULL;
561 vnc_client_args = g_hash_table_lookup (params, "ARGS");
562 if (!vnc_client_args)
563 vnc_client_args = "";
564 command_line = g_strdup_printf ("%s/tests/src/vnc-client %s", BUILDDIR, vnc_client_args);
566 if (!g_shell_parse_argv (command_line, NULL, &argv, &error) ||
567 !g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &error))
569 g_printerr ("Error starting VNC client: %s", error->message);
574 process = watch_process (pid);
575 g_hash_table_insert (children, GINT_TO_POINTER (process->pid), process);
578 else if (strcmp (name, "ADD-USER") == 0)
580 gchar *status_text, *username;
583 username = g_hash_table_lookup (params, "USERNAME");
584 user = get_accounts_user_by_name (username);
586 accounts_user_set_hidden (user, FALSE, TRUE);
588 g_warning ("Unknown user %s", username);
590 status_text = g_strdup_printf ("RUNNER ADD-USER USERNAME=%s", username);
591 check_status (status_text);
592 g_free (status_text);
594 else if (strcmp (name, "UPDATE-USER") == 0)
596 GString *status_text;
599 GError *error = NULL;
601 status_text = g_string_new ("RUNNER UPDATE-USER USERNAME=");
603 username = g_hash_table_lookup (params, "USERNAME");
604 g_string_append (status_text, username);
605 user = get_accounts_user_by_name (username);
608 if (g_hash_table_lookup (params, "NAME"))
610 user->user_name = g_strdup (g_hash_table_lookup (params, "NAME"));
611 g_string_append_printf (status_text, " NAME=%s", user->user_name);
613 if (g_hash_table_lookup (params, "REAL-NAME"))
615 user->real_name = g_strdup (g_hash_table_lookup (params, "REAL-NAME"));
616 g_string_append_printf (status_text, " REAL-NAME=%s", user->real_name);
618 if (g_hash_table_lookup (params, "HOME-DIRECTORY"))
620 user->home_directory = g_strdup (g_hash_table_lookup (params, "HOME-DIRECTORY"));
621 g_string_append_printf (status_text, " HOME-DIRECTORY=%s", user->home_directory);
623 if (g_hash_table_lookup (params, "IMAGE"))
625 user->image = g_strdup (g_hash_table_lookup (params, "IMAGE"));
626 g_string_append_printf (status_text, " IMAGE=%s", user->image);
628 if (g_hash_table_lookup (params, "BACKGROUND"))
630 user->background = g_strdup (g_hash_table_lookup (params, "BACKGROUND"));
631 g_string_append_printf (status_text, " BACKGROUND=%s", user->background);
633 if (g_hash_table_lookup (params, "LANGUAGE"))
635 user->language = g_strdup (g_hash_table_lookup (params, "LANGUAGE"));
636 g_string_append_printf (status_text, " LANGUAGE=%s", user->language);
638 if (g_hash_table_lookup (params, "LAYOUTS"))
640 const gchar *value = g_hash_table_lookup (params, "LAYOUTS");
641 user->layouts = g_strsplit (value, ";", -1);
642 g_string_append_printf (status_text, " LAYOUTS=%s", value);
644 if (g_hash_table_lookup (params, "HAS-MESSAGES"))
646 user->has_messages = g_strcmp0 (g_hash_table_lookup (params, "HAS-MESSAGES"), "TRUE") == 0;
647 g_string_append_printf (status_text, " HAS-MESSAGES=%s", user->has_messages ? "TRUE" : "FALSE");
649 if (g_hash_table_lookup (params, "SESSION"))
651 user->xsession = g_strdup (g_hash_table_lookup (params, "SESSION"));
652 g_string_append_printf (status_text, " SESSION=%s", user->xsession);
656 g_warning ("Unknown user %s", username);
658 g_dbus_connection_emit_signal (accounts_connection,
661 "org.freedesktop.Accounts.User",
663 g_variant_new ("()"),
666 g_warning ("Failed to emit Changed: %s", error->message);
667 g_clear_error (&error);
669 check_status (status_text->str);
670 g_string_free (status_text, TRUE);
672 else if (strcmp (name, "DELETE-USER") == 0)
674 gchar *status_text, *username;
677 username = g_hash_table_lookup (params, "USERNAME");
678 user = get_accounts_user_by_name (username);
680 accounts_user_set_hidden (user, TRUE, TRUE);
682 g_warning ("Unknown user %s", username);
684 status_text = g_strdup_printf ("RUNNER DELETE-USER USERNAME=%s", username);
685 check_status (status_text);
686 g_free (status_text);
688 /* Forward to external processes */
689 else if (g_str_has_prefix (name, "SESSION-") ||
690 g_str_has_prefix (name, "GREETER-") ||
691 g_str_has_prefix (name, "XSERVER-") ||
692 strcmp (name, "UNITY-SYSTEM-COMPOSITOR") == 0)
695 for (link = status_clients; link; link = link->next)
697 StatusClient *client = link->data;
699 GError *error = NULL;
701 length = strlen (command);
702 if (g_socket_send (client->socket, (gchar *) &length, sizeof (length), NULL, &error) < 0 ||
703 g_socket_send (client->socket, command, strlen (command), NULL, &error) < 0)
704 g_printerr ("Failed to write to client socket: %s\n", error->message);
705 g_clear_error (&error);
710 g_printerr ("Unknown command '%s'\n", name);
715 g_hash_table_unref (params);
721 /* Stop daemon if requested */
726 /* Commands start with an asterisk */
727 line = get_script_line (NULL);
728 if (!line || line->text[0] != '*')
731 statuses = g_list_append (statuses, g_strdup (line->text));
734 handle_command (line->text + 1);
737 /* Stop at the end of the script */
738 if (get_script_line (NULL) == NULL)
743 status_timeout_cb (gpointer data)
747 line = get_script_line (NULL);
748 fail ("(timeout)", line ? line->text : NULL);
754 check_status (const gchar *status)
757 gboolean result = FALSE;
763 statuses = g_list_append (statuses, g_strdup (status));
765 if (getenv ("DEBUG"))
766 g_print ("%s\n", status);
768 /* Try and match against expected */
769 prefix = get_prefix (status);
770 line = get_script_line (prefix);
774 gchar *full_pattern = g_strdup_printf ("^%s$", line->text);
775 result = g_regex_match_simple (full_pattern, status, 0, 0);
776 g_free (full_pattern);
782 line = get_script_line (NULL);
783 fail (NULL, line ? line->text : NULL);
789 /* Restart timeout */
790 g_source_remove (status_timeout);
791 status_timeout = g_timeout_add (status_timeout_ms, status_timeout_cb, NULL);
797 status_message_cb (GSocket *socket, GIOCondition condition, StatusClient *client)
802 GError *error = NULL;
804 n_read = g_socket_receive (socket, (gchar *)&length, sizeof (length), NULL, &error);
806 n_read = g_socket_receive (socket, buffer, length, NULL, &error);
808 g_warning ("Error reading from socket: %s", error->message);
809 g_clear_error (&error);
812 status_clients = g_list_remove (status_clients, client);
813 g_object_unref (client->socket);
819 buffer[n_read] = '\0';
820 check_status (buffer);
827 status_connect_cb (gpointer data)
830 GError *error = NULL;
832 socket = g_socket_accept (status_socket, NULL, &error);
834 g_warning ("Failed to accept status connection: %s", error->message);
835 g_clear_error (&error);
838 StatusClient *client;
840 client = g_malloc0 (sizeof (StatusClient));
841 client->socket = socket;
842 client->source = g_socket_create_source (socket, G_IO_IN, NULL);
843 status_clients = g_list_append (status_clients, client);
845 g_source_set_callback (client->source, (GSourceFunc) status_message_cb, client, NULL);
846 g_source_attach (client->source, NULL);
853 load_script (const gchar *filename)
856 gchar *data, **lines;
858 if (!g_file_get_contents (filename, &data, NULL, NULL))
860 g_printerr ("Unable to load script: %s\n", filename);
864 lines = g_strsplit (data, "\n", -1);
867 /* Load lines with #? prefix as expected behaviour */
868 for (i = 0; lines[i]; i++)
870 gchar *text = g_strstrip (lines[i]);
871 if (g_str_has_prefix (text, "#?"))
874 line = g_malloc0 (sizeof (ScriptLine));
875 line->text = g_strdup (text + 2);
877 script = g_list_append (script, line);
884 handle_upower_call (GDBusConnection *connection,
886 const gchar *object_path,
887 const gchar *interface_name,
888 const gchar *method_name,
889 GVariant *parameters,
890 GDBusMethodInvocation *invocation,
893 if (strcmp (method_name, "SuspendAllowed") == 0)
895 check_status ("UPOWER SUSPEND-ALLOWED");
896 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
898 else if (strcmp (method_name, "Suspend") == 0)
900 check_status ("UPOWER SUSPEND");
901 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
903 else if (strcmp (method_name, "HibernateAllowed") == 0)
905 check_status ("UPOWER HIBERNATE-ALLOWED");
906 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
908 else if (strcmp (method_name, "Hibernate") == 0)
910 check_status ("UPOWER HIBERNATE");
911 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
914 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
918 upower_name_acquired_cb (GDBusConnection *connection,
922 const gchar *upower_interface =
924 " <interface name='org.freedesktop.UPower'>"
925 " <method name='SuspendAllowed'>"
926 " <arg name='allowed' direction='out' type='b'/>"
928 " <method name='Suspend'/>"
929 " <method name='HibernateAllowed'>"
930 " <arg name='allowed' direction='out' type='b'/>"
932 " <method name='Hibernate'/>"
935 static const GDBusInterfaceVTable upower_vtable =
939 GDBusNodeInfo *upower_info;
940 GError *error = NULL;
942 upower_info = g_dbus_node_info_new_for_xml (upower_interface, &error);
944 g_warning ("Failed to parse D-Bus interface: %s", error->message);
945 g_clear_error (&error);
948 g_dbus_connection_register_object (connection,
949 "/org/freedesktop/UPower",
950 upower_info->interfaces[0],
955 g_warning ("Failed to register UPower service: %s", error->message);
956 g_clear_error (&error);
957 g_dbus_node_info_unref (upower_info);
960 if (service_count == 0)
965 start_upower_daemon (void)
968 g_bus_own_name (G_BUS_TYPE_SYSTEM,
969 "org.freedesktop.UPower",
970 G_BUS_NAME_OWNER_FLAGS_NONE,
971 upower_name_acquired_cb,
979 open_ck_session (GVariant *params)
986 GError *error = NULL;
988 session = g_malloc0 (sizeof (CKSession));
989 ck_sessions = g_list_append (ck_sessions, session);
991 cookie = g_string_new ("ck-cookie");
992 g_variant_get (params, "a(sv)", &iter);
993 while (g_variant_iter_loop (iter, "(&sv)", &name, &value))
995 if (strcmp (name, "x11-display") == 0)
997 const gchar *display;
998 g_variant_get (value, "&s", &display);
999 g_string_append_printf (cookie, "-x%s", display);
1003 session->cookie = cookie->str;
1004 g_string_free (cookie, FALSE);
1005 session->path = g_strdup_printf ("/org/freedesktop/ConsoleKit/Session%d", ck_session_index++);
1006 session->id = g_dbus_connection_register_object (ck_connection,
1008 ck_session_info->interfaces[0],
1014 g_warning ("Failed to register CK Session: %s", error->message);
1015 g_clear_error (&error);
1021 handle_ck_call (GDBusConnection *connection,
1022 const gchar *sender,
1023 const gchar *object_path,
1024 const gchar *interface_name,
1025 const gchar *method_name,
1026 GVariant *parameters,
1027 GDBusMethodInvocation *invocation,
1030 if (strcmp (method_name, "CanRestart") == 0)
1032 check_status ("CONSOLE-KIT CAN-RESTART");
1033 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
1035 else if (strcmp (method_name, "CanStop") == 0)
1037 check_status ("CONSOLE-KIT CAN-STOP");
1038 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
1040 else if (strcmp (method_name, "CloseSession") == 0)
1041 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
1042 else if (strcmp (method_name, "OpenSession") == 0)
1044 GVariantBuilder params;
1045 g_variant_builder_init (¶ms, G_VARIANT_TYPE ("a(sv)"));
1046 CKSession *session = open_ck_session (g_variant_builder_end (¶ms));
1047 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", session->cookie));
1049 else if (strcmp (method_name, "OpenSessionWithParameters") == 0)
1051 CKSession *session = open_ck_session (g_variant_get_child_value (parameters, 0));
1052 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", session->cookie));
1054 else if (strcmp (method_name, "GetSessionForCookie") == 0)
1059 g_variant_get (parameters, "(&s)", &cookie);
1061 for (link = ck_sessions; link; link = link->next)
1063 CKSession *session = link->data;
1064 if (strcmp (session->cookie, cookie) != 0)
1066 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", session->path));
1071 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Unable to find session for cookie");
1073 else if (strcmp (method_name, "Restart") == 0)
1075 check_status ("CONSOLE-KIT RESTART");
1076 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1078 else if (strcmp (method_name, "Stop") == 0)
1080 check_status ("CONSOLE-KIT STOP");
1081 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1084 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1088 handle_ck_session_call (GDBusConnection *connection,
1089 const gchar *sender,
1090 const gchar *object_path,
1091 const gchar *interface_name,
1092 const gchar *method_name,
1093 GVariant *parameters,
1094 GDBusMethodInvocation *invocation,
1097 CKSession *session = user_data;
1099 if (strcmp (method_name, "Lock") == 0)
1101 if (!session->locked)
1102 check_status ("CONSOLE-KIT LOCK-SESSION");
1103 session->locked = TRUE;
1104 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1106 else if (strcmp (method_name, "Unlock") == 0)
1108 if (session->locked)
1109 check_status ("CONSOLE-KIT UNLOCK-SESSION");
1110 session->locked = FALSE;
1111 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1114 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1118 ck_name_acquired_cb (GDBusConnection *connection,
1122 const gchar *ck_interface =
1124 " <interface name='org.freedesktop.ConsoleKit.Manager'>"
1125 " <method name='CanRestart'>"
1126 " <arg name='can_restart' direction='out' type='b'/>"
1128 " <method name='CanStop'>"
1129 " <arg name='can_stop' direction='out' type='b'/>"
1131 " <method name='CloseSession'>"
1132 " <arg name='cookie' direction='in' type='s'/>"
1133 " <arg name='result' direction='out' type='b'/>"
1135 " <method name='OpenSession'>"
1136 " <arg name='cookie' direction='out' type='s'/>"
1138 " <method name='OpenSessionWithParameters'>"
1139 " <arg name='parameters' direction='in' type='a(sv)'/>"
1140 " <arg name='cookie' direction='out' type='s'/>"
1142 " <method name='GetSessionForCookie'>"
1143 " <arg name='cookie' direction='in' type='s'/>"
1144 " <arg name='ssid' direction='out' type='o'/>"
1146 " <method name='Restart'/>"
1147 " <method name='Stop'/>"
1148 " <signal name='SeatAdded'>"
1149 " <arg name='seat' type='o'/>"
1151 " <signal name='SeatRemoved'>"
1152 " <arg name='seat' type='o'/>"
1156 static const GDBusInterfaceVTable ck_vtable =
1160 const gchar *ck_session_interface =
1162 " <interface name='org.freedesktop.ConsoleKit.Session'>"
1163 " <method name='Lock'/>"
1164 " <method name='Unlock'/>"
1167 GDBusNodeInfo *ck_info;
1168 GError *error = NULL;
1170 ck_connection = connection;
1172 ck_info = g_dbus_node_info_new_for_xml (ck_interface, &error);
1174 g_warning ("Failed to parse D-Bus interface: %s", error->message);
1175 g_clear_error (&error);
1178 ck_session_info = g_dbus_node_info_new_for_xml (ck_session_interface, &error);
1180 g_warning ("Failed to parse D-Bus interface: %s", error->message);
1181 g_clear_error (&error);
1182 if (!ck_session_info)
1184 g_dbus_connection_register_object (connection,
1185 "/org/freedesktop/ConsoleKit/Manager",
1186 ck_info->interfaces[0],
1191 g_warning ("Failed to register console kit service: %s", error->message);
1192 g_clear_error (&error);
1193 g_dbus_node_info_unref (ck_info);
1196 if (service_count == 0)
1201 start_console_kit_daemon (void)
1204 g_bus_own_name (G_BUS_TYPE_SYSTEM,
1205 "org.freedesktop.ConsoleKit",
1206 G_BUS_NAME_OWNER_FLAGS_NONE,
1207 ck_name_acquired_cb,
1215 handle_login1_session_call (GDBusConnection *connection,
1216 const gchar *sender,
1217 const gchar *object_path,
1218 const gchar *interface_name,
1219 const gchar *method_name,
1220 GVariant *parameters,
1221 GDBusMethodInvocation *invocation,
1224 Login1Session *session = user_data;
1226 if (strcmp (method_name, "Lock") == 0)
1228 if (!session->locked)
1229 check_status ("LOGIN1 LOCK-SESSION");
1230 session->locked = TRUE;
1231 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1233 else if (strcmp (method_name, "Unlock") == 0)
1235 if (session->locked)
1236 check_status ("LOGIN1 UNLOCK-SESSION");
1237 session->locked = FALSE;
1238 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1241 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1244 static Login1Session *
1245 open_login1_session (GDBusConnection *connection,
1248 Login1Session *session;
1249 GError *error = NULL;
1250 GDBusNodeInfo *login1_session_info;
1252 const gchar *login1_session_interface =
1254 " <interface name='org.freedesktop.login1.Session'>"
1255 " <method name='Lock'/>"
1256 " <method name='Unlock'/>"
1259 static const GDBusInterfaceVTable login1_session_vtable =
1261 handle_login1_session_call,
1264 session = g_malloc0 (sizeof (Login1Session));
1265 login1_sessions = g_list_append (login1_sessions, session);
1267 session->path = g_strdup_printf("/org/freedesktop/login1/Session/c%d",
1268 login1_session_index++);
1272 login1_session_info = g_dbus_node_info_new_for_xml (login1_session_interface,
1275 g_warning ("Failed to parse login1 session D-Bus interface: %s",
1277 g_clear_error (&error);
1278 if (!login1_session_info)
1281 g_dbus_connection_register_object (connection,
1283 login1_session_info->interfaces[0],
1284 &login1_session_vtable,
1289 g_warning ("Failed to register login1 session: %s", error->message);
1290 g_clear_error (&error);
1291 g_dbus_node_info_unref (login1_session_info);
1298 handle_login1_call (GDBusConnection *connection,
1299 const gchar *sender,
1300 const gchar *object_path,
1301 const gchar *interface_name,
1302 const gchar *method_name,
1303 GVariant *parameters,
1304 GDBusMethodInvocation *invocation,
1308 if (strcmp (method_name, "GetSessionByPID") == 0)
1310 /* Look for a session with our PID, and create one if we don't have one
1314 Login1Session *ret = NULL;
1316 g_variant_get (parameters, "(u)", &pid);
1318 for (link = login1_sessions; link; link = link->next)
1320 Login1Session *session;
1321 session = link->data;
1322 if (session->pid == pid)
1330 ret = open_login1_session (connection, parameters);
1332 g_dbus_method_invocation_return_value (invocation,
1333 g_variant_new("(o)", ret->path));
1336 else if (strcmp (method_name, "CanReboot") == 0)
1338 check_status ("LOGIN1 CAN-REBOOT");
1339 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1341 else if (strcmp (method_name, "Reboot") == 0)
1343 gboolean interactive;
1344 g_variant_get (parameters, "(b)", &interactive);
1345 check_status ("LOGIN1 REBOOT");
1346 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1348 else if (strcmp (method_name, "CanPowerOff") == 0)
1350 check_status ("LOGIN1 CAN-POWER-OFF");
1351 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1353 else if (strcmp (method_name, "Suspend") == 0)
1355 gboolean interactive;
1356 g_variant_get (parameters, "(b)", &interactive);
1357 check_status ("LOGIN1 SUSPEND");
1358 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1360 else if (strcmp (method_name, "CanSuspend") == 0)
1362 check_status ("LOGIN1 CAN-SUSPEND");
1363 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1365 else if (strcmp (method_name, "PowerOff") == 0)
1367 gboolean interactive;
1368 g_variant_get (parameters, "(b)", &interactive);
1369 check_status ("LOGIN1 POWER-OFF");
1370 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1372 else if (strcmp (method_name, "CanHibernate") == 0)
1374 check_status ("LOGIN1 CAN-HIBERNATE");
1375 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1377 else if (strcmp (method_name, "Hibernate") == 0)
1379 gboolean interactive;
1380 g_variant_get (parameters, "(b)", &interactive);
1381 check_status ("LOGIN1 HIBERNATE");
1382 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1385 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1389 login1_name_acquired_cb (GDBusConnection *connection,
1393 const gchar *login1_interface =
1395 " <interface name='org.freedesktop.login1.Manager'>"
1396 " <method name='GetSessionByPID'>"
1397 " <arg name='pid' type='u' direction='in'/>"
1398 " <arg name='session' type='o' direction='out'/>"
1400 " <method name='CanReboot'>"
1401 " <arg name='result' direction='out' type='s'/>"
1403 " <method name='Reboot'>"
1404 " <arg name='interactive' direction='in' type='b'/>"
1406 " <method name='CanPowerOff'>"
1407 " <arg name='result' direction='out' type='s'/>"
1409 " <method name='PowerOff'>"
1410 " <arg name='interactive' direction='in' type='b'/>"
1412 " <method name='CanSuspend'>"
1413 " <arg name='result' direction='out' type='s'/>"
1415 " <method name='Suspend'>"
1416 " <arg name='interactive' direction='in' type='b'/>"
1418 " <method name='CanHibernate'>"
1419 " <arg name='result' direction='out' type='s'/>"
1421 " <method name='Hibernate'>"
1422 " <arg name='interactive' direction='in' type='b'/>"
1426 static const GDBusInterfaceVTable login1_vtable =
1430 GDBusNodeInfo *login1_info;
1431 GError *error = NULL;
1433 login1_info = g_dbus_node_info_new_for_xml (login1_interface, &error);
1435 g_warning ("Failed to parse login1 D-Bus interface: %s", error->message);
1436 g_clear_error (&error);
1439 g_dbus_connection_register_object (connection,
1440 "/org/freedesktop/login1",
1441 login1_info->interfaces[0],
1446 g_warning ("Failed to register login1 service: %s", error->message);
1447 g_clear_error (&error);
1448 g_dbus_node_info_unref (login1_info);
1451 if (service_count == 0)
1456 start_login1_daemon (void)
1459 g_bus_own_name (G_BUS_TYPE_SYSTEM,
1460 "org.freedesktop.login1",
1461 G_BUS_NAME_OWNER_FLAGS_NONE,
1462 login1_name_acquired_cb,
1469 static AccountsUser *
1470 get_accounts_user_by_uid (guint uid)
1474 for (link = accounts_users; link; link = link->next)
1476 AccountsUser *u = link->data;
1484 static AccountsUser *
1485 get_accounts_user_by_name (const gchar *username)
1489 for (link = accounts_users; link; link = link->next)
1491 AccountsUser *u = link->data;
1492 if (strcmp (u->user_name, username) == 0)
1500 accounts_user_set_hidden (AccountsUser *user, gboolean hidden, gboolean emit_signal)
1502 GError *error = NULL;
1504 user->hidden = hidden;
1506 if (user->hidden && user->id != 0)
1508 g_dbus_connection_unregister_object (accounts_connection, user->id);
1509 g_dbus_connection_emit_signal (accounts_connection,
1511 "/org/freedesktop/Accounts",
1512 "org.freedesktop.Accounts",
1514 g_variant_new ("(o)", user->path),
1517 g_warning ("Failed to emit UserDeleted: %s", error->message);
1518 g_clear_error (&error);
1522 if (!user->hidden && user->id == 0)
1524 user->id = g_dbus_connection_register_object (accounts_connection,
1526 user_info->interfaces[0],
1532 g_warning ("Failed to register user: %s", error->message);
1533 g_clear_error (&error);
1535 g_dbus_connection_emit_signal (accounts_connection,
1537 "/org/freedesktop/Accounts",
1538 "org.freedesktop.Accounts",
1540 g_variant_new ("(o)", user->path),
1543 g_warning ("Failed to emit UserAdded: %s", error->message);
1544 g_clear_error (&error);
1549 load_passwd_file (void)
1551 gchar *path, *data, **lines;
1552 gchar **user_filter = NULL;
1555 if (g_key_file_has_key (config, "test-runner-config", "accounts-service-user-filter", NULL))
1559 filter = g_key_file_get_string (config, "test-runner-config", "accounts-service-user-filter", NULL);
1560 user_filter = g_strsplit (filter, " ", -1);
1564 path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "passwd", NULL);
1565 g_file_get_contents (path, &data, NULL, NULL);
1567 lines = g_strsplit (data, "\n", -1);
1570 for (i = 0; lines[i]; i++)
1574 gchar *user_name, *real_name;
1575 AccountsUser *user = NULL;
1577 fields = g_strsplit (lines[i], ":", -1);
1578 if (fields == NULL || g_strv_length (fields) < 7)
1580 g_strfreev (fields);
1584 user_name = fields[0];
1585 uid = atoi (fields[2]);
1586 real_name = fields[4];
1588 user = get_accounts_user_by_uid (uid);
1592 GKeyFile *dmrc_file;
1594 user = g_malloc0 (sizeof (AccountsUser));
1595 accounts_users = g_list_append (accounts_users, user);
1597 /* Only allow users in whitelist */
1598 user->hidden = FALSE;
1603 user->hidden = TRUE;
1604 for (j = 0; user_filter[j] != NULL; j++)
1605 if (strcmp (user_name, user_filter[j]) == 0)
1606 user->hidden = FALSE;
1609 dmrc_file = g_key_file_new ();
1610 path = g_build_filename (temp_dir, "home", user_name, ".dmrc", NULL);
1611 g_key_file_load_from_file (dmrc_file, path, G_KEY_FILE_NONE, NULL);
1615 user->user_name = g_strdup (user_name);
1616 user->real_name = g_strdup (real_name);
1617 user->home_directory = g_build_filename (temp_dir, "home", user_name, NULL);
1618 user->language = g_key_file_get_string (dmrc_file, "Desktop", "Language", NULL);
1619 /* DMRC contains a locale, strip the codeset off it to get the language */
1622 gchar *c = strchr (user->language, '.');
1626 user->xsession = g_key_file_get_string (dmrc_file, "Desktop", "Session", NULL);
1627 user->layouts = g_key_file_get_string_list (dmrc_file, "X-Accounts", "Layouts", NULL, NULL);
1630 user->layouts = g_malloc (sizeof (gchar *) * 2);
1631 user->layouts[0] = g_key_file_get_string (dmrc_file, "Desktop", "Layout", NULL);
1632 user->layouts[1] = NULL;
1634 user->has_messages = g_key_file_get_boolean (dmrc_file, "X-Accounts", "HasMessages", NULL);
1635 user->path = g_strdup_printf ("/org/freedesktop/Accounts/User%d", uid);
1636 accounts_user_set_hidden (user, user->hidden, FALSE);
1638 g_key_file_free (dmrc_file);
1641 g_strfreev (fields);
1648 handle_accounts_call (GDBusConnection *connection,
1649 const gchar *sender,
1650 const gchar *object_path,
1651 const gchar *interface_name,
1652 const gchar *method_name,
1653 GVariant *parameters,
1654 GDBusMethodInvocation *invocation,
1657 if (strcmp (method_name, "ListCachedUsers") == 0)
1659 GVariantBuilder builder;
1662 g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
1664 load_passwd_file ();
1665 for (link = accounts_users; link; link = link->next)
1667 AccountsUser *user = link->data;
1668 if (!user->hidden && user->uid >= 1000)
1669 g_variant_builder_add_value (&builder, g_variant_new_object_path (user->path));
1672 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(ao)", &builder));
1674 else if (strcmp (method_name, "FindUserByName") == 0)
1676 AccountsUser *user = NULL;
1679 g_variant_get (parameters, "(&s)", &user_name);
1681 load_passwd_file ();
1682 user = get_accounts_user_by_name (user_name);
1686 accounts_user_set_hidden (user, FALSE, TRUE);
1687 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", user->path));
1690 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such user: %s", user_name);
1693 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1697 handle_user_call (GDBusConnection *connection,
1698 const gchar *sender,
1699 const gchar *object_path,
1700 const gchar *interface_name,
1701 const gchar *method_name,
1702 GVariant *parameters,
1703 GDBusMethodInvocation *invocation,
1706 AccountsUser *user = user_data;
1708 if (strcmp (method_name, "SetXSession") == 0)
1712 g_variant_get (parameters, "(&s)", &xsession);
1714 g_free (user->xsession);
1715 user->xsession = g_strdup (xsession);
1717 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1720 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1724 handle_user_get_property (GDBusConnection *connection,
1725 const gchar *sender,
1726 const gchar *object_path,
1727 const gchar *interface_name,
1728 const gchar *property_name,
1732 AccountsUser *user = user_data;
1734 if (strcmp (property_name, "UserName") == 0)
1735 return g_variant_new_string (user->user_name);
1736 else if (strcmp (property_name, "RealName") == 0)
1737 return g_variant_new_string (user->real_name);
1738 else if (strcmp (property_name, "HomeDirectory") == 0)
1739 return g_variant_new_string (user->home_directory);
1740 else if (strcmp (property_name, "SystemAccount") == 0)
1741 return g_variant_new_boolean (user->uid < 1000);
1742 else if (strcmp (property_name, "BackgroundFile") == 0)
1743 return g_variant_new_string (user->background ? user->background : "");
1744 else if (strcmp (property_name, "Language") == 0)
1745 return g_variant_new_string (user->language ? user->language : "");
1746 else if (strcmp (property_name, "IconFile") == 0)
1747 return g_variant_new_string (user->image ? user->image : "");
1748 else if (strcmp (property_name, "XSession") == 0)
1749 return g_variant_new_string (user->xsession ? user->xsession : "");
1750 else if (strcmp (property_name, "XKeyboardLayouts") == 0)
1752 if (user->layouts != NULL)
1753 return g_variant_new_strv ((const gchar * const *) user->layouts, -1);
1755 return g_variant_new_strv (NULL, 0);
1757 else if (strcmp (property_name, "XHasMessages") == 0)
1758 return g_variant_new_boolean (user->has_messages);
1764 accounts_name_acquired_cb (GDBusConnection *connection,
1768 const gchar *accounts_interface =
1770 " <interface name='org.freedesktop.Accounts'>"
1771 " <method name='ListCachedUsers'>"
1772 " <arg name='user' direction='out' type='ao'/>"
1774 " <method name='FindUserByName'>"
1775 " <arg name='name' direction='in' type='s'/>"
1776 " <arg name='user' direction='out' type='o'/>"
1778 " <signal name='UserAdded'>"
1779 " <arg name='user' type='o'/>"
1781 " <signal name='UserDeleted'>"
1782 " <arg name='user' type='o'/>"
1786 static const GDBusInterfaceVTable accounts_vtable =
1788 handle_accounts_call,
1790 const gchar *user_interface =
1792 " <interface name='org.freedesktop.Accounts.User'>"
1793 " <method name='SetXSession'>"
1794 " <arg name='x_session' direction='in' type='s'/>"
1796 " <property name='UserName' type='s' access='read'/>"
1797 " <property name='RealName' type='s' access='read'/>"
1798 " <property name='HomeDirectory' type='s' access='read'/>"
1799 " <property name='SystemAccount' type='b' access='read'/>"
1800 " <property name='BackgroundFile' type='s' access='read'/>"
1801 " <property name='Language' type='s' access='read'/>"
1802 " <property name='IconFile' type='s' access='read'/>"
1803 " <property name='XSession' type='s' access='read'/>"
1804 " <property name='XKeyboardLayouts' type='as' access='read'/>"
1805 " <property name='XHasMessages' type='b' access='read'/>"
1806 " <signal name='Changed' />"
1809 GError *error = NULL;
1811 accounts_connection = connection;
1813 accounts_info = g_dbus_node_info_new_for_xml (accounts_interface, &error);
1815 g_warning ("Failed to parse D-Bus interface: %s", error->message);
1816 g_clear_error (&error);
1819 user_info = g_dbus_node_info_new_for_xml (user_interface, &error);
1821 g_warning ("Failed to parse D-Bus interface: %s", error->message);
1822 g_clear_error (&error);
1825 g_dbus_connection_register_object (connection,
1826 "/org/freedesktop/Accounts",
1827 accounts_info->interfaces[0],
1833 g_warning ("Failed to register accounts service: %s", error->message);
1834 g_clear_error (&error);
1835 g_dbus_node_info_unref (accounts_info);
1838 if (service_count == 0)
1843 start_accounts_service_daemon (void)
1846 g_bus_own_name (G_BUS_TYPE_SYSTEM,
1847 "org.freedesktop.Accounts",
1848 G_BUS_NAME_OWNER_FLAGS_NONE,
1849 accounts_name_acquired_cb,
1859 GString *command_line;
1860 gchar **lightdm_argv;
1862 GError *error = NULL;
1866 status_timeout = g_timeout_add (status_timeout_ms, status_timeout_cb, NULL);
1868 command_line = g_string_new ("lightdm");
1869 if (getenv ("DEBUG"))
1870 g_string_append (command_line, " --debug");
1871 g_string_append_printf (command_line, " --cache-dir %s/cache", temp_dir);
1873 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",
1874 g_getenv ("PATH"), g_getenv ("LD_PRELOAD"), g_getenv ("LD_LIBRARY_PATH"), g_getenv ("LIGHTDM_TEST_ROOT"), g_getenv ("DBUS_SESSION_BUS_ADDRESS"),
1877 if (!g_shell_parse_argv (command_line->str, NULL, &lightdm_argv, &error))
1879 g_warning ("Error parsing command line: %s", error->message);
1880 quit (EXIT_FAILURE);
1882 g_clear_error (&error);
1884 if (!g_spawn_async (NULL, lightdm_argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL, NULL, &lightdm_pid, &error))
1886 g_warning ("Error launching LightDM: %s", error->message);
1887 quit (EXIT_FAILURE);
1889 g_clear_error (&error);
1890 lightdm_process = watch_process (lightdm_pid);
1892 check_status ("RUNNER DAEMON-START");
1896 signal_cb (gpointer user_data)
1898 g_print ("Caught signal, quitting\n");
1899 quit (EXIT_FAILURE);
1904 main (int argc, char **argv)
1908 gchar *greeter = NULL, *script_name, *config_file, *additional_system_config;
1909 gchar *additional_config, *path, *path1, *path2, *ld_preload, *ld_library_path, *home_dir;
1910 GString *passwd_data, *group_data;
1911 GSource *status_source;
1913 GError *error = NULL;
1915 #if !defined(GLIB_VERSION_2_36)
1919 loop = g_main_loop_new (NULL, FALSE);
1921 g_unix_signal_add (SIGINT, signal_cb, NULL);
1922 g_unix_signal_add (SIGTERM, signal_cb, NULL);
1924 children = g_hash_table_new (g_direct_hash, g_direct_equal);
1928 g_printerr ("Usage %s SCRIPT-NAME GREETER\n", argv[0]);
1929 quit (EXIT_FAILURE);
1931 script_name = argv[1];
1932 config_file = g_strdup_printf ("%s.conf", script_name);
1933 config_path = g_build_filename (SRCDIR, "tests", "scripts", config_file, NULL);
1934 g_free (config_file);
1936 config = g_key_file_new ();
1937 g_key_file_load_from_file (config, config_path, G_KEY_FILE_NONE, NULL);
1939 load_script (config_path);
1941 if (!getcwd (cwd, 1024))
1943 g_critical ("Error getting current directory: %s", strerror (errno));
1944 quit (EXIT_FAILURE);
1947 /* Don't contact our X server */
1948 g_unsetenv ("DISPLAY");
1950 /* Override system calls */
1951 ld_preload = g_build_filename (BUILDDIR, "tests", "src", ".libs", "libsystem.so", NULL);
1952 g_setenv ("LD_PRELOAD", ld_preload, TRUE);
1953 g_free (ld_preload);
1955 /* Run test programs */
1956 path = g_strdup_printf ("%s/tests/src/.libs:%s/tests/src:%s/tests/src:%s/src:%s", BUILDDIR, BUILDDIR, SRCDIR, BUILDDIR, g_getenv ("PATH"));
1957 g_setenv ("PATH", path, TRUE);
1960 /* Use locally built libraries */
1961 path1 = g_build_filename (BUILDDIR, "liblightdm-gobject", ".libs", NULL);
1962 path2 = g_build_filename (BUILDDIR, "liblightdm-qt", ".libs", NULL);
1963 ld_library_path = g_strdup_printf ("%s:%s", path1, path2);
1966 g_setenv ("LD_LIBRARY_PATH", ld_library_path, TRUE);
1967 g_free (ld_library_path);
1968 path1 = g_build_filename (BUILDDIR, "liblightdm-gobject", NULL);
1969 g_setenv ("GI_TYPELIB_PATH", path1, TRUE);
1972 /* Run in a temporary directory inside the build directory */
1973 /* Note we have to pick a name that is short since Unix sockets in this directory have a 108 character limit on their paths */
1978 name = g_strdup_printf (".r%d", i);
1980 temp_dir = g_build_filename ("/tmp", name, NULL);
1982 if (!g_file_test (temp_dir, G_FILE_TEST_EXISTS))
1986 g_mkdir_with_parents (temp_dir, 0755);
1987 g_setenv ("LIGHTDM_TEST_ROOT", temp_dir, TRUE);
1989 /* Open socket for status */
1990 /* Note we have to pick a socket name that is short since there is a 108 character limit on the name */
1991 status_socket_name = g_build_filename (temp_dir, ".s", NULL);
1992 unlink (status_socket_name);
1993 status_socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, &error);
1995 g_warning ("Error creating status socket %s: %s", status_socket_name, error->message);
1996 g_clear_error (&error);
1999 GSocketAddress *address;
2002 address = g_unix_socket_address_new (status_socket_name);
2003 result = g_socket_bind (status_socket, address, FALSE, &error);
2004 g_object_unref (address);
2006 g_warning ("Error binding status socket %s: %s", status_socket_name, error->message);
2007 g_clear_error (&error);
2010 result = g_socket_listen (status_socket, &error);
2012 g_warning ("Error listening on status socket %s: %s", status_socket_name, error->message);
2013 g_clear_error (&error);
2017 g_object_unref (status_socket);
2018 status_socket = NULL;
2022 quit (EXIT_FAILURE);
2023 status_source = g_socket_create_source (status_socket, G_IO_IN, NULL);
2024 g_source_set_callback (status_source, status_connect_cb, NULL, NULL);
2025 g_source_attach (status_source, NULL);
2027 /* Set up a skeleton file system */
2028 g_mkdir_with_parents (g_strdup_printf ("%s/etc", temp_dir), 0755);
2029 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share", temp_dir), 0755);
2030 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/sessions", temp_dir), 0755);
2031 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/remote-sessions", temp_dir), 0755);
2032 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/greeters", temp_dir), 0755);
2033 g_mkdir_with_parents (g_strdup_printf ("%s/tmp", temp_dir), 0755);
2034 g_mkdir_with_parents (g_strdup_printf ("%s/var/run", temp_dir), 0755);
2035 g_mkdir_with_parents (g_strdup_printf ("%s/var/log", temp_dir), 0755);
2037 /* Copy over the configuration */
2038 g_mkdir_with_parents (g_strdup_printf ("%s/etc/lightdm", temp_dir), 0755);
2039 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))
2040 if (system (g_strdup_printf ("cp %s %s/etc/lightdm/lightdm.conf", config_path, temp_dir)))
2041 perror ("Failed to copy configuration");
2043 additional_system_config = g_key_file_get_string (config, "test-runner-config", "additional-system-config", NULL);
2044 if (additional_system_config)
2048 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/lightdm.conf.d", temp_dir), 0755);
2050 files = g_strsplit (additional_system_config, " ", -1);
2051 for (i = 0; files[i]; i++)
2052 if (system (g_strdup_printf ("cp %s/tests/scripts/%s %s/usr/share/lightdm/lightdm.conf.d", SRCDIR, files[i], temp_dir)))
2053 perror ("Failed to copy configuration");
2057 additional_config = g_key_file_get_string (config, "test-runner-config", "additional-config", NULL);
2058 if (additional_config)
2062 g_mkdir_with_parents (g_strdup_printf ("%s/etc/lightdm/lightdm.conf.d", temp_dir), 0755);
2064 files = g_strsplit (additional_config, " ", -1);
2065 for (i = 0; files[i]; i++)
2066 if (system (g_strdup_printf ("cp %s/tests/scripts/%s %s/etc/lightdm/lightdm.conf.d", SRCDIR, files[i], temp_dir)))
2067 perror ("Failed to copy configuration");
2071 /* Always copy the script */
2072 if (system (g_strdup_printf ("cp %s %s/script", config_path, temp_dir)))
2073 perror ("Failed to copy configuration");
2075 /* Copy over the greeter files */
2076 if (system (g_strdup_printf ("cp %s/sessions/* %s/usr/share/lightdm/sessions", DATADIR, temp_dir)))
2077 perror ("Failed to copy sessions");
2078 if (system (g_strdup_printf ("cp %s/remote-sessions/* %s/usr/share/lightdm/remote-sessions", DATADIR, temp_dir)))
2079 perror ("Failed to copy remote sessions");
2080 if (system (g_strdup_printf ("cp %s/greeters/* %s/usr/share/lightdm/greeters", DATADIR, temp_dir)))
2081 perror ("Failed to copy greeters");
2083 /* Set up the default greeter */
2084 path = g_build_filename (temp_dir, "usr", "share", "lightdm", "greeters", "default.desktop", NULL);
2085 greeter = g_strdup_printf ("%s.desktop", argv[2]);
2086 if (symlink (greeter, path) < 0)
2088 g_printerr ("Failed to make greeter symlink %s->%s: %s\n", path, greeter, strerror (errno));
2089 quit (EXIT_FAILURE);
2094 home_dir = g_build_filename (temp_dir, "home", NULL);
2096 /* Make fake users */
2106 {"root", "", "root", 0},
2107 /* Unprivileged account for greeters */
2108 {"lightdm", "", "", 100},
2109 /* These accounts have a password */
2110 {"have-password1", "password", "Password User 1", 1000},
2111 {"have-password2", "password", "Password User 2", 1001},
2112 {"have-password3", "password", "Password User 3", 1002},
2113 {"have-password4", "password", "Password User 4", 1003},
2114 /* This account always prompts for a password, even if using the lightdm-autologin service */
2115 {"always-password", "password", "Password User 4", 1004},
2116 /* These accounts have no password */
2117 {"no-password1", "", "No Password User 1", 1005},
2118 {"no-password2", "", "No Password User 2", 1006},
2119 {"no-password3", "", "No Password User 3", 1007},
2120 {"no-password4", "", "No Password User 4", 1008},
2121 /* This account has a keyboard layout */
2122 {"have-layout", "", "Layout User", 1009},
2123 /* This account has a set of keyboard layouts */
2124 {"have-layouts", "", "Layouts User", 1010},
2125 /* This account has a language set */
2126 {"have-language", "", "Language User", 1011},
2127 /* This account has a preconfigured session */
2128 {"have-session", "", "Session User", 1012},
2129 /* This account has the home directory mounted on login */
2130 {"mount-home-dir", "", "Mounted Home Dir User", 1013},
2131 /* This account is denied access */
2132 {"denied", "", "Denied User", 1014},
2133 /* This account has expired */
2134 {"expired", "", "Expired User", 1015},
2135 /* This account needs a password change */
2136 {"new-authtok", "", "New Token User", 1016},
2137 /* This account is switched to change-user2 when authentication succeeds */
2138 {"change-user1", "", "Change User 1", 1017},
2139 {"change-user2", "", "Change User 2", 1018},
2140 /* This account switches to invalid-user when authentication succeeds */
2141 {"change-user-invalid", "", "Invalid Change User", 1019},
2142 /* This account crashes on authentication */
2143 {"crash-authenticate", "", "Crash Auth User", 1020},
2144 /* This account shows an informational prompt on login */
2145 {"info-prompt", "password", "Info Prompt", 1021},
2146 /* This account shows multiple informational prompts on login */
2147 {"multi-info-prompt","password", "Multi Info Prompt", 1022},
2148 /* This account uses two factor authentication */
2149 {"two-factor", "password", "Two Factor", 1023},
2150 /* This account has a special group */
2151 {"group-member", "password", "Group Member", 1024},
2152 /* This account has the home directory created when the session starts */
2153 {"make-home-dir", "", "Make Home Dir User", 1025},
2154 /* This account fails to open a session */
2155 {"session-error", "password", "Session Error", 1026},
2156 /* This account can't establish credentials */
2157 {"cred-error", "password", "Cred Error", 1027},
2158 /* This account has expired credentials */
2159 {"cred-expired", "password", "Cred Expired", 1028},
2160 /* This account has cannot access their credentials */
2161 {"cred-unavail", "password", "Cred Unavail", 1029},
2162 /* This account sends informational messages for each PAM function that is called */
2163 {"log-pam", "password", "Log PAM", 1030},
2164 /* This account shows multiple prompts on login */
2165 {"multi-prompt", "password", "Multi Prompt", 1031},
2166 /* This account has an existing corrupt X authority */
2167 {"corrupt-xauth", "password", "Corrupt Xauthority", 1032},
2168 /* User to test properties */
2169 {"prop-user", "", "TEST", 1033},
2170 {NULL, NULL, NULL, 0}
2172 passwd_data = g_string_new ("");
2173 group_data = g_string_new ("");
2174 for (i = 0; users[i].user_name; i++)
2176 GKeyFile *dmrc_file;
2177 gboolean save_dmrc = FALSE;
2179 if (strcmp (users[i].user_name, "mount-home-dir") != 0 && strcmp (users[i].user_name, "make-home-dir") != 0)
2181 path = g_build_filename (home_dir, users[i].user_name, NULL);
2182 g_mkdir_with_parents (path, 0755);
2183 if (chown (path, users[i].uid, users[i].uid) < 0)
2184 g_debug ("chown (%s) failed: %s", path, strerror (errno));
2188 dmrc_file = g_key_file_new ();
2189 if (strcmp (users[i].user_name, "have-session") == 0)
2191 g_key_file_set_string (dmrc_file, "Desktop", "Session", "alternative");
2194 if (strcmp (users[i].user_name, "have-layout") == 0)
2196 g_key_file_set_string (dmrc_file, "Desktop", "Layout", "us");
2199 if (strcmp (users[i].user_name, "have-layouts") == 0)
2201 g_key_file_set_string (dmrc_file, "Desktop", "Layout", "ru");
2202 g_key_file_set_string (dmrc_file, "X-Accounts", "Layouts", "fr\toss;ru;");
2205 if (strcmp (users[i].user_name, "have-language") == 0)
2207 g_key_file_set_string (dmrc_file, "Desktop", "Language", "en_AU.utf8");
2215 path = g_build_filename (home_dir, users[i].user_name, ".dmrc", NULL);
2216 data = g_key_file_to_data (dmrc_file, NULL, NULL);
2217 g_file_set_contents (path, data, -1, NULL);
2222 g_key_file_free (dmrc_file);
2224 /* Write corrupt X authority file */
2225 if (strcmp (users[i].user_name, "corrupt-xauth") == 0)
2227 gchar data[1] = { 0xFF };
2229 path = g_build_filename (home_dir, users[i].user_name, ".Xauthority", NULL);
2230 g_file_set_contents (path, data, 1, NULL);
2231 chmod (path, S_IRUSR | S_IWUSR);
2235 /* Add passwd file entry */
2236 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);
2238 /* Add group file entry */
2239 g_string_append_printf (group_data, "%s:x:%d:%s\n", users[i].user_name, users[i].uid, users[i].user_name);
2241 path = g_build_filename (temp_dir, "etc", "passwd", NULL);
2242 g_file_set_contents (path, passwd_data->str, -1, NULL);
2244 g_string_free (passwd_data, TRUE);
2246 /* Add an extra test group */
2247 g_string_append_printf (group_data, "test-group:x:111:\n");
2249 path = g_build_filename (temp_dir, "etc", "group", NULL);
2250 g_file_set_contents (path, group_data->str, -1, NULL);
2252 g_string_free (group_data, TRUE);
2254 if (g_key_file_has_key (config, "test-runner-config", "timeout", NULL))
2255 status_timeout_ms = g_key_file_get_integer (config, "test-runner-config", "timeout", NULL) * 1000;
2257 /* Start D-Bus services */
2258 if (!g_key_file_get_boolean (config, "test-runner-config", "disable-upower", NULL))
2259 start_upower_daemon ();
2260 if (!g_key_file_get_boolean (config, "test-runner-config", "disable-console-kit", NULL))
2261 start_console_kit_daemon ();
2262 if (!g_key_file_get_boolean (config, "test-runner-config", "disable-login1", NULL))
2263 start_login1_daemon ();
2264 if (!g_key_file_get_boolean (config, "test-runner-config", "disable-accounts-service", NULL))
2265 start_accounts_service_daemon ();
2267 g_main_loop_run (loop);
2269 return EXIT_FAILURE;