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 GDBusNodeInfo *ck_session_info;
92 static GList *ck_sessions = NULL;
93 static gint ck_session_index = 0;
94 static void handle_ck_session_call (GDBusConnection *connection,
96 const gchar *object_path,
97 const gchar *interface_name,
98 const gchar *method_name,
100 GDBusMethodInvocation *invocation,
102 static const GDBusInterfaceVTable ck_session_vtable =
104 handle_ck_session_call,
111 gboolean can_graphical;
112 gboolean can_multi_session;
115 static GList *login1_seats = NULL;
117 static Login1Seat *add_login1_seat (GDBusConnection *connection, const gchar *id, gboolean emit_signal);
118 static Login1Seat *find_login1_seat (const gchar *id);
119 static void remove_login1_seat (GDBusConnection *connection, const gchar *id);
129 static GList *login1_sessions = NULL;
130 static gint login1_session_index = 0;
137 static GList *status_clients = NULL;
139 static void ready (void);
140 static void quit (int status);
141 static void check_status (const gchar *status);
142 static AccountsUser *get_accounts_user_by_uid (guint uid);
143 static AccountsUser *get_accounts_user_by_name (const gchar *username);
144 static void accounts_user_set_hidden (AccountsUser *user, gboolean hidden, gboolean emit_signal);
147 kill_timeout_cb (gpointer data)
149 Process *process = data;
151 process->kill_timeout = 0;
153 if (getenv ("DEBUG"))
154 g_print ("Sending SIGKILL to process %d\n", process->pid);
155 kill (process->pid, SIGKILL);
161 stop_process (Process *process)
163 if (process->kill_timeout != 0)
166 if (getenv ("DEBUG"))
167 g_print ("Sending SIGTERM to process %d\n", process->pid);
168 kill (process->pid, SIGTERM);
169 process->kill_timeout = g_timeout_add (KILL_TIMEOUT, kill_timeout_cb, process);
173 process_exit_cb (GPid pid, gint status, gpointer data)
178 if (getenv ("DEBUG"))
180 if (WIFEXITED (status))
181 g_print ("Process %d exited with status %d\n", pid, WEXITSTATUS (status));
183 g_print ("Process %d terminated with signal %d\n", pid, WTERMSIG (status));
186 if (lightdm_process && pid == lightdm_process->pid)
188 process = lightdm_process;
189 lightdm_process = NULL;
190 if (WIFEXITED (status))
191 status_text = g_strdup_printf ("RUNNER DAEMON-EXIT STATUS=%d", WEXITSTATUS (status));
193 status_text = g_strdup_printf ("RUNNER DAEMON-TERMINATE SIGNAL=%d", WTERMSIG (status));
194 check_status (status_text);
198 process = g_hash_table_lookup (children, GINT_TO_POINTER (pid));
201 g_hash_table_remove (children, GINT_TO_POINTER (pid));
204 if (process->kill_timeout)
205 g_source_remove (process->kill_timeout);
206 process->kill_timeout = 0;
208 /* Quit once all children have stopped */
214 watch_process (pid_t pid)
218 process = g_malloc0 (sizeof (Process));
220 process->kill_timeout = 0;
222 if (getenv ("DEBUG"))
223 g_print ("Watching process %d\n", process->pid);
224 g_child_watch_add (process->pid, process_exit_cb, NULL);
235 exit_status = status;
238 /* Stop all the children */
239 g_hash_table_iter_init (&iter, children);
244 if (!g_hash_table_iter_next (&iter, &key, &value))
247 stop_process ((Process *)value);
250 /* Don't quit until all children are stopped */
251 if (g_hash_table_size (children) > 0)
254 /* Stop the daemon */
257 stop_process (lightdm_process);
261 if (status_socket_name)
262 unlink (status_socket_name);
264 if (temp_dir && getenv ("DEBUG") == NULL)
266 gchar *command = g_strdup_printf ("rm -rf %s", temp_dir);
267 if (system (command))
268 perror ("Failed to delete temp directory");
275 fail (const gchar *event, const gchar *expected)
282 g_printerr ("Command line: %s", test_runner_command);
283 g_printerr ("Events:\n");
284 for (link = statuses; link; link = link->next)
285 g_printerr (" %s\n", (gchar *)link->data);
287 g_printerr (" %s\n", event);
289 g_printerr (" ^^^ expected \"%s\"\n", expected);
291 g_printerr ("^^^ expected nothing\n");
297 get_prefix (const gchar *text)
302 prefix = g_strdup (text);
303 for (i = 0; prefix[i] != '\0' && prefix[i] != ' '; i++);
310 get_script_line (const gchar *prefix)
314 for (link = script; link; link = link->next)
316 ScriptLine *line = link->data;
318 /* Ignore lines with other prefixes */
324 p = get_prefix (line->text);
325 matches = strcmp (prefix, p) == 0;
340 stop_loop (gpointer user_data)
342 g_main_loop_quit ((GMainLoop *)user_data);
343 return G_SOURCE_REMOVE;
347 switch_to_greeter_done_cb (GObject *bus, GAsyncResult *result, gpointer data)
350 GError *error = NULL;
352 r = g_dbus_connection_call_finish (G_DBUS_CONNECTION (bus), result, &error);
354 g_warning ("Failed to switch to greeter: %s\n", error->message);
355 g_clear_error (&error);
359 check_status ("RUNNER SWITCH-TO-GREETER");
363 check_status ("RUNNER SWITCH-TO-GREETER FAILED");
367 switch_to_user_done_cb (GObject *bus, GAsyncResult *result, gpointer data)
370 GError *error = NULL;
371 gchar *username = data, *status_text;
373 r = g_dbus_connection_call_finish (G_DBUS_CONNECTION (bus), result, &error);
375 g_warning ("Failed to switch to user: %s\n", error->message);
376 g_clear_error (&error);
380 status_text = g_strdup_printf ("RUNNER SWITCH-TO-USER USERNAME=%s", username);
384 status_text = g_strdup_printf ("RUNNER SWITCH-TO-USER USERNAME=%s FAILED", username);
385 check_status (status_text);
387 g_free (status_text);
392 switch_to_guest_done_cb (GObject *bus, GAsyncResult *result, gpointer data)
395 GError *error = NULL;
397 r = g_dbus_connection_call_finish (G_DBUS_CONNECTION (bus), result, &error);
399 g_warning ("Failed to switch to guest: %s\n", error->message);
400 g_clear_error (&error);
404 check_status ("RUNNER SWITCH-TO-GUEST");
408 check_status ("RUNNER SWITCH-TO-GUEST FAILED");
412 handle_command (const gchar *command)
419 while (*c && !isspace (*c))
421 name = g_strdup_printf ("%.*s", (int) (c - command), command);
423 params = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
427 gchar *param_name, *param_value;
432 while (*c && !isspace (*c) && *c != '=')
437 param_name = g_strdup_printf ("%.*s", (int) (c - start), start);
446 gboolean escaped = FALSE;
450 value = g_string_new ("");
457 g_string_append_c (value, '\\');
463 else if (!escaped && *c == '\"')
466 g_string_append_c (value, *c);
469 param_value = value->str;
470 g_string_free (value, FALSE);
477 while (*c && !isspace (*c))
479 param_value = g_strdup_printf ("%.*s", (int) (c - start), start);
483 param_value = g_strdup ("");
485 g_hash_table_insert (params, param_name, param_value);
488 if (strcmp (name, "START-DAEMON") == 0)
490 GString *command_line;
491 gchar **lightdm_argv;
493 GError *error = NULL;
495 command_line = g_string_new ("lightdm");
496 if (getenv ("DEBUG"))
497 g_string_append (command_line, " --debug");
498 g_string_append_printf (command_line, " --cache-dir %s/cache", temp_dir);
500 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",
501 g_getenv ("PATH"), g_getenv ("LD_PRELOAD"), g_getenv ("LD_LIBRARY_PATH"), g_getenv ("LIGHTDM_TEST_ROOT"), g_getenv ("DBUS_SESSION_BUS_ADDRESS"),
504 if (!g_shell_parse_argv (command_line->str, NULL, &lightdm_argv, &error))
506 g_warning ("Error parsing command line: %s", error->message);
509 g_clear_error (&error);
511 if (!g_spawn_async (NULL, lightdm_argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL, NULL, &lightdm_pid, &error))
513 g_warning ("Error launching LightDM: %s", error->message);
516 g_clear_error (&error);
517 lightdm_process = watch_process (lightdm_pid);
519 check_status ("RUNNER DAEMON-START");
521 else if (strcmp (name, "WAIT") == 0)
523 /* Use a main loop so that our DBus functions are still responsive */
524 GMainLoop *loop = g_main_loop_new (NULL, FALSE);
525 g_timeout_add_seconds (1, stop_loop, loop);
526 g_main_loop_run (loop);
527 g_main_loop_unref (loop);
529 else if (strcmp (name, "ADD-SEAT") == 0)
534 id = g_hash_table_lookup (params, "ID");
535 seat = add_login1_seat (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL), id, TRUE);
536 v = g_hash_table_lookup (params, "CAN-GRAPHICAL");
538 seat->can_graphical = strcmp (v, "TRUE") == 0;
539 v = g_hash_table_lookup (params, "CAN-MULTI-SESSION");
541 seat->can_multi_session = strcmp (v, "TRUE") == 0;
543 else if (strcmp (name, "UPDATE-SEAT") == 0)
548 id = g_hash_table_lookup (params, "ID");
549 seat = find_login1_seat (id);
553 GVariantBuilder invalidated_properties;
554 GError *error = NULL;
556 g_variant_builder_init (&invalidated_properties, G_VARIANT_TYPE_ARRAY);
558 v = g_hash_table_lookup (params, "CAN-GRAPHICAL");
561 seat->can_graphical = strcmp (v, "TRUE") == 0;
562 g_variant_builder_add (&invalidated_properties, "s", "CanGraphical");
564 v = g_hash_table_lookup (params, "CAN-MULTI-SESSION");
567 seat->can_multi_session = strcmp (v, "TRUE") == 0;
568 g_variant_builder_add (&invalidated_properties, "s", "CanMultiSession");
571 g_dbus_connection_emit_signal (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
574 "org.freedesktop.DBus.Properties",
576 g_variant_new ("(sa{sv}as)", "org.freedesktop.login1.Seat", NULL, &invalidated_properties),
579 g_warning ("Failed to emit PropertiesChanged: %s", error->message);
580 g_clear_error (&error);
583 else if (strcmp (name, "REMOVE-SEAT") == 0)
586 id = g_hash_table_lookup (params, "ID");
587 remove_login1_seat (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL), id);
589 else if (strcmp (name, "LIST-SEATS") == 0)
591 GVariant *result, *value;
597 result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
598 "org.freedesktop.DisplayManager",
599 "/org/freedesktop/DisplayManager",
600 "org.freedesktop.DBus.Properties",
602 g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Seats"),
603 G_VARIANT_TYPE ("(v)"),
604 G_DBUS_CALL_FLAGS_NONE,
609 status = g_string_new ("RUNNER LIST-SEATS SEATS=");
610 g_variant_get (result, "(v)", &value);
611 g_variant_get (value, "ao", &iter);
612 while (g_variant_iter_loop (iter, "&o", &path))
615 g_string_append (status, ",");
616 g_string_append (status, path);
619 g_variant_unref (value);
620 g_variant_unref (result);
622 check_status (status->str);
623 g_string_free (status, TRUE);
625 else if (strcmp (name, "LIST-SESSIONS") == 0)
627 GVariant *result, *value;
633 result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
634 "org.freedesktop.DisplayManager",
635 "/org/freedesktop/DisplayManager",
636 "org.freedesktop.DBus.Properties",
638 g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Sessions"),
639 G_VARIANT_TYPE ("(v)"),
640 G_DBUS_CALL_FLAGS_NONE,
645 status = g_string_new ("RUNNER LIST-SESSIONS SESSIONS=");
646 g_variant_get (result, "(v)", &value);
647 g_variant_get (value, "ao", &iter);
648 while (g_variant_iter_loop (iter, "&o", &path))
651 g_string_append (status, ",");
652 g_string_append (status, path);
655 g_variant_unref (value);
656 g_variant_unref (result);
658 check_status (status->str);
659 g_string_free (status, TRUE);
661 else if (strcmp (name, "SEAT-CAN-SWITCH") == 0)
663 GVariant *result, *value;
666 result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
667 "org.freedesktop.DisplayManager",
668 "/org/freedesktop/DisplayManager/Seat0",
669 "org.freedesktop.DBus.Properties",
671 g_variant_new ("(ss)", "org.freedesktop.DisplayManager.Seat", "CanSwitch"),
672 G_VARIANT_TYPE ("(v)"),
673 G_DBUS_CALL_FLAGS_NONE,
678 g_variant_get (result, "(v)", &value);
679 status = g_strdup_printf ("RUNNER SEAT-CAN-SWITCH CAN-SWITCH=%s", g_variant_get_boolean (value) ? "TRUE" : "FALSE");
680 g_variant_unref (value);
681 g_variant_unref (result);
682 check_status (status);
685 else if (strcmp (name, "SEAT-HAS-GUEST-ACCOUNT") == 0)
687 GVariant *result, *value;
690 result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
691 "org.freedesktop.DisplayManager",
692 "/org/freedesktop/DisplayManager/Seat0",
693 "org.freedesktop.DBus.Properties",
695 g_variant_new ("(ss)", "org.freedesktop.DisplayManager.Seat", "HasGuestAccount"),
696 G_VARIANT_TYPE ("(v)"),
697 G_DBUS_CALL_FLAGS_NONE,
702 g_variant_get (result, "(v)", &value);
703 status = g_strdup_printf ("RUNNER SEAT-HAS-GUEST-ACCOUNT HAS-GUEST-ACCOUNT=%s", g_variant_get_boolean (value) ? "TRUE" : "FALSE");
704 g_variant_unref (value);
705 g_variant_unref (result);
706 check_status (status);
709 else if (strcmp (name, "SWITCH-TO-GREETER") == 0)
711 g_dbus_connection_call (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
712 "org.freedesktop.DisplayManager",
713 "/org/freedesktop/DisplayManager/Seat0",
714 "org.freedesktop.DisplayManager.Seat",
716 g_variant_new ("()"),
717 G_VARIANT_TYPE ("()"),
718 G_DBUS_CALL_FLAGS_NONE,
721 switch_to_greeter_done_cb,
724 else if (strcmp (name, "SWITCH-TO-USER") == 0)
726 const gchar *username;
728 username = g_hash_table_lookup (params, "USERNAME");
729 g_dbus_connection_call (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
730 "org.freedesktop.DisplayManager",
731 "/org/freedesktop/DisplayManager/Seat0",
732 "org.freedesktop.DisplayManager.Seat",
734 g_variant_new ("(ss)", username, ""),
735 G_VARIANT_TYPE ("()"),
736 G_DBUS_CALL_FLAGS_NONE,
739 switch_to_user_done_cb,
740 g_strdup (username));
742 else if (strcmp (name, "SWITCH-TO-GUEST") == 0)
744 g_dbus_connection_call (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
745 "org.freedesktop.DisplayManager",
746 "/org/freedesktop/DisplayManager/Seat0",
747 "org.freedesktop.DisplayManager.Seat",
749 g_variant_new ("(s)", ""),
750 G_VARIANT_TYPE ("()"),
751 G_DBUS_CALL_FLAGS_NONE,
754 switch_to_guest_done_cb,
757 else if (strcmp (name, "STOP-DAEMON") == 0)
758 stop_process (lightdm_process);
759 // FIXME: Make generic RUN-COMMAND
760 else if (strcmp (name, "START-XSERVER") == 0)
762 gchar *xserver_args, *command_line;
766 GError *error = NULL;
768 xserver_args = g_hash_table_lookup (params, "ARGS");
771 command_line = g_strdup_printf ("%s/tests/src/X %s", BUILDDIR, xserver_args);
773 if (!g_shell_parse_argv (command_line, NULL, &argv, &error) ||
774 !g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &error))
776 g_printerr ("Error starting X server: %s", error->message);
781 process = watch_process (pid);
782 g_hash_table_insert (children, GINT_TO_POINTER (process->pid), process);
785 else if (strcmp (name, "START-VNC-CLIENT") == 0)
787 gchar *vnc_client_args, *command_line;
791 GError *error = NULL;
793 vnc_client_args = g_hash_table_lookup (params, "ARGS");
794 if (!vnc_client_args)
795 vnc_client_args = "";
796 command_line = g_strdup_printf ("%s/tests/src/vnc-client %s", BUILDDIR, vnc_client_args);
798 if (!g_shell_parse_argv (command_line, NULL, &argv, &error) ||
799 !g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &error))
801 g_printerr ("Error starting VNC client: %s", error->message);
806 process = watch_process (pid);
807 g_hash_table_insert (children, GINT_TO_POINTER (process->pid), process);
810 else if (strcmp (name, "ADD-USER") == 0)
812 gchar *status_text, *username;
815 username = g_hash_table_lookup (params, "USERNAME");
816 user = get_accounts_user_by_name (username);
818 accounts_user_set_hidden (user, FALSE, TRUE);
820 g_warning ("Unknown user %s", username);
822 status_text = g_strdup_printf ("RUNNER ADD-USER USERNAME=%s", username);
823 check_status (status_text);
824 g_free (status_text);
826 else if (strcmp (name, "UPDATE-USER") == 0)
828 GString *status_text;
831 GError *error = NULL;
833 status_text = g_string_new ("RUNNER UPDATE-USER USERNAME=");
835 username = g_hash_table_lookup (params, "USERNAME");
836 g_string_append (status_text, username);
837 user = get_accounts_user_by_name (username);
840 if (g_hash_table_lookup (params, "NAME"))
842 user->user_name = g_strdup (g_hash_table_lookup (params, "NAME"));
843 g_string_append_printf (status_text, " NAME=%s", user->user_name);
845 if (g_hash_table_lookup (params, "REAL-NAME"))
847 user->real_name = g_strdup (g_hash_table_lookup (params, "REAL-NAME"));
848 g_string_append_printf (status_text, " REAL-NAME=%s", user->real_name);
850 if (g_hash_table_lookup (params, "HOME-DIRECTORY"))
852 user->home_directory = g_strdup (g_hash_table_lookup (params, "HOME-DIRECTORY"));
853 g_string_append_printf (status_text, " HOME-DIRECTORY=%s", user->home_directory);
855 if (g_hash_table_lookup (params, "IMAGE"))
857 user->image = g_strdup (g_hash_table_lookup (params, "IMAGE"));
858 g_string_append_printf (status_text, " IMAGE=%s", user->image);
860 if (g_hash_table_lookup (params, "BACKGROUND"))
862 user->background = g_strdup (g_hash_table_lookup (params, "BACKGROUND"));
863 g_string_append_printf (status_text, " BACKGROUND=%s", user->background);
865 if (g_hash_table_lookup (params, "LANGUAGE"))
867 user->language = g_strdup (g_hash_table_lookup (params, "LANGUAGE"));
868 g_string_append_printf (status_text, " LANGUAGE=%s", user->language);
870 if (g_hash_table_lookup (params, "LAYOUTS"))
872 const gchar *value = g_hash_table_lookup (params, "LAYOUTS");
873 user->layouts = g_strsplit (value, ";", -1);
874 g_string_append_printf (status_text, " LAYOUTS=%s", value);
876 if (g_hash_table_lookup (params, "HAS-MESSAGES"))
878 user->has_messages = g_strcmp0 (g_hash_table_lookup (params, "HAS-MESSAGES"), "TRUE") == 0;
879 g_string_append_printf (status_text, " HAS-MESSAGES=%s", user->has_messages ? "TRUE" : "FALSE");
881 if (g_hash_table_lookup (params, "SESSION"))
883 user->xsession = g_strdup (g_hash_table_lookup (params, "SESSION"));
884 g_string_append_printf (status_text, " SESSION=%s", user->xsession);
888 g_warning ("Unknown user %s", username);
890 g_dbus_connection_emit_signal (accounts_connection,
893 "org.freedesktop.Accounts.User",
895 g_variant_new ("()"),
898 g_warning ("Failed to emit Changed: %s", error->message);
899 g_clear_error (&error);
901 check_status (status_text->str);
902 g_string_free (status_text, TRUE);
904 else if (strcmp (name, "DELETE-USER") == 0)
906 gchar *status_text, *username;
909 username = g_hash_table_lookup (params, "USERNAME");
910 user = get_accounts_user_by_name (username);
912 accounts_user_set_hidden (user, TRUE, TRUE);
914 g_warning ("Unknown user %s", username);
916 status_text = g_strdup_printf ("RUNNER DELETE-USER USERNAME=%s", username);
917 check_status (status_text);
918 g_free (status_text);
920 /* Forward to external processes */
921 else if (g_str_has_prefix (name, "SESSION-") ||
922 g_str_has_prefix (name, "GREETER-") ||
923 g_str_has_prefix (name, "XSERVER-") ||
924 strcmp (name, "UNITY-SYSTEM-COMPOSITOR") == 0)
927 for (link = status_clients; link; link = link->next)
929 StatusClient *client = link->data;
931 GError *error = NULL;
933 length = strlen (command);
934 if (g_socket_send (client->socket, (gchar *) &length, sizeof (length), NULL, &error) < 0 ||
935 g_socket_send (client->socket, command, strlen (command), NULL, &error) < 0)
936 g_printerr ("Failed to write to client socket: %s\n", error->message);
937 g_clear_error (&error);
942 g_printerr ("Unknown command '%s'\n", name);
947 g_hash_table_unref (params);
953 /* Stop daemon if requested */
958 /* Commands start with an asterisk */
959 line = get_script_line (NULL);
960 if (!line || line->text[0] != '*')
963 statuses = g_list_append (statuses, g_strdup (line->text));
966 handle_command (line->text + 1);
969 /* Stop at the end of the script */
970 if (get_script_line (NULL) == NULL)
975 status_timeout_cb (gpointer data)
979 line = get_script_line (NULL);
980 fail ("(timeout)", line ? line->text : NULL);
986 check_status (const gchar *status)
989 gboolean result = FALSE;
995 statuses = g_list_append (statuses, g_strdup (status));
997 if (getenv ("DEBUG"))
998 g_print ("%s\n", status);
1000 /* Try and match against expected */
1001 prefix = get_prefix (status);
1002 line = get_script_line (prefix);
1006 gchar *full_pattern = g_strdup_printf ("^%s$", line->text);
1007 result = g_regex_match_simple (full_pattern, status, 0, 0);
1008 g_free (full_pattern);
1014 line = get_script_line (NULL);
1015 fail (NULL, line ? line->text : NULL);
1021 /* Restart timeout */
1023 g_source_remove (status_timeout);
1024 status_timeout = g_timeout_add (status_timeout_ms, status_timeout_cb, NULL);
1030 status_message_cb (GSocket *socket, GIOCondition condition, StatusClient *client)
1035 GError *error = NULL;
1037 n_read = g_socket_receive (socket, (gchar *)&length, sizeof (length), NULL, &error);
1039 n_read = g_socket_receive (socket, buffer, length, NULL, &error);
1041 g_warning ("Error reading from socket: %s", error->message);
1042 g_clear_error (&error);
1045 status_clients = g_list_remove (status_clients, client);
1046 g_object_unref (client->socket);
1050 else if (n_read > 0)
1052 buffer[n_read] = '\0';
1053 check_status (buffer);
1060 status_connect_cb (gpointer data)
1063 GError *error = NULL;
1065 socket = g_socket_accept (status_socket, NULL, &error);
1067 g_warning ("Failed to accept status connection: %s", error->message);
1068 g_clear_error (&error);
1071 StatusClient *client;
1073 client = g_malloc0 (sizeof (StatusClient));
1074 client->socket = socket;
1075 client->source = g_socket_create_source (socket, G_IO_IN, NULL);
1076 status_clients = g_list_append (status_clients, client);
1078 g_source_set_callback (client->source, (GSourceFunc) status_message_cb, client, NULL);
1079 g_source_attach (client->source, NULL);
1086 load_script (const gchar *filename)
1089 gchar *data, **lines;
1091 if (!g_file_get_contents (filename, &data, NULL, NULL))
1093 g_printerr ("Unable to load script: %s\n", filename);
1094 quit (EXIT_FAILURE);
1097 lines = g_strsplit (data, "\n", -1);
1100 /* Load lines with #? prefix as expected behaviour */
1101 for (i = 0; lines[i]; i++)
1103 gchar *text = g_strstrip (lines[i]);
1104 if (g_str_has_prefix (text, "#?"))
1107 line = g_malloc0 (sizeof (ScriptLine));
1108 line->text = g_strdup (text + 2);
1110 script = g_list_append (script, line);
1117 handle_upower_call (GDBusConnection *connection,
1118 const gchar *sender,
1119 const gchar *object_path,
1120 const gchar *interface_name,
1121 const gchar *method_name,
1122 GVariant *parameters,
1123 GDBusMethodInvocation *invocation,
1126 if (strcmp (method_name, "SuspendAllowed") == 0)
1128 check_status ("UPOWER SUSPEND-ALLOWED");
1129 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
1131 else if (strcmp (method_name, "Suspend") == 0)
1133 check_status ("UPOWER SUSPEND");
1134 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1136 else if (strcmp (method_name, "HibernateAllowed") == 0)
1138 check_status ("UPOWER HIBERNATE-ALLOWED");
1139 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
1141 else if (strcmp (method_name, "Hibernate") == 0)
1143 check_status ("UPOWER HIBERNATE");
1144 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1147 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1151 upower_name_acquired_cb (GDBusConnection *connection,
1155 const gchar *upower_interface =
1157 " <interface name='org.freedesktop.UPower'>"
1158 " <method name='SuspendAllowed'>"
1159 " <arg name='allowed' direction='out' type='b'/>"
1161 " <method name='Suspend'/>"
1162 " <method name='HibernateAllowed'>"
1163 " <arg name='allowed' direction='out' type='b'/>"
1165 " <method name='Hibernate'/>"
1168 static const GDBusInterfaceVTable upower_vtable =
1172 GDBusNodeInfo *upower_info;
1173 GError *error = NULL;
1175 upower_info = g_dbus_node_info_new_for_xml (upower_interface, &error);
1177 g_warning ("Failed to parse D-Bus interface: %s", error->message);
1178 g_clear_error (&error);
1181 g_dbus_connection_register_object (connection,
1182 "/org/freedesktop/UPower",
1183 upower_info->interfaces[0],
1188 g_warning ("Failed to register UPower service: %s", error->message);
1189 g_clear_error (&error);
1190 g_dbus_node_info_unref (upower_info);
1193 if (service_count == 0)
1198 start_upower_daemon (void)
1201 g_bus_own_name (G_BUS_TYPE_SYSTEM,
1202 "org.freedesktop.UPower",
1203 G_BUS_NAME_OWNER_FLAGS_NONE,
1204 upower_name_acquired_cb,
1212 open_ck_session (GDBusConnection *connection, GVariant *params)
1219 GError *error = NULL;
1221 session = g_malloc0 (sizeof (CKSession));
1222 ck_sessions = g_list_append (ck_sessions, session);
1224 cookie = g_string_new ("ck-cookie");
1225 g_variant_get (params, "a(sv)", &iter);
1226 while (g_variant_iter_loop (iter, "(&sv)", &name, &value))
1228 if (strcmp (name, "x11-display") == 0)
1230 const gchar *display;
1231 g_variant_get (value, "&s", &display);
1232 g_string_append_printf (cookie, "-x%s", display);
1236 session->cookie = cookie->str;
1237 g_string_free (cookie, FALSE);
1238 session->path = g_strdup_printf ("/org/freedesktop/ConsoleKit/Session%d", ck_session_index++);
1239 session->id = g_dbus_connection_register_object (connection,
1241 ck_session_info->interfaces[0],
1247 g_warning ("Failed to register CK Session: %s", error->message);
1248 g_clear_error (&error);
1254 handle_ck_call (GDBusConnection *connection,
1255 const gchar *sender,
1256 const gchar *object_path,
1257 const gchar *interface_name,
1258 const gchar *method_name,
1259 GVariant *parameters,
1260 GDBusMethodInvocation *invocation,
1263 if (strcmp (method_name, "CanRestart") == 0)
1265 check_status ("CONSOLE-KIT CAN-RESTART");
1266 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
1268 else if (strcmp (method_name, "CanStop") == 0)
1270 check_status ("CONSOLE-KIT CAN-STOP");
1271 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
1273 else if (strcmp (method_name, "CloseSession") == 0)
1274 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
1275 else if (strcmp (method_name, "OpenSession") == 0)
1277 GVariantBuilder params;
1278 g_variant_builder_init (¶ms, G_VARIANT_TYPE ("a(sv)"));
1279 CKSession *session = open_ck_session (connection, g_variant_builder_end (¶ms));
1280 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", session->cookie));
1282 else if (strcmp (method_name, "OpenSessionWithParameters") == 0)
1284 CKSession *session = open_ck_session (connection, g_variant_get_child_value (parameters, 0));
1285 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", session->cookie));
1287 else if (strcmp (method_name, "GetSessionForCookie") == 0)
1292 g_variant_get (parameters, "(&s)", &cookie);
1294 for (link = ck_sessions; link; link = link->next)
1296 CKSession *session = link->data;
1297 if (strcmp (session->cookie, cookie) == 0)
1299 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", session->path));
1304 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Unable to find session for cookie");
1306 else if (strcmp (method_name, "Restart") == 0)
1308 check_status ("CONSOLE-KIT RESTART");
1309 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1311 else if (strcmp (method_name, "Stop") == 0)
1313 check_status ("CONSOLE-KIT STOP");
1314 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1317 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1321 handle_ck_session_call (GDBusConnection *connection,
1322 const gchar *sender,
1323 const gchar *object_path,
1324 const gchar *interface_name,
1325 const gchar *method_name,
1326 GVariant *parameters,
1327 GDBusMethodInvocation *invocation,
1330 CKSession *session = user_data;
1332 if (strcmp (method_name, "Lock") == 0)
1334 if (!session->locked)
1335 check_status ("CONSOLE-KIT LOCK-SESSION");
1336 session->locked = TRUE;
1337 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1339 else if (strcmp (method_name, "Unlock") == 0)
1341 if (session->locked)
1342 check_status ("CONSOLE-KIT UNLOCK-SESSION");
1343 session->locked = FALSE;
1344 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1346 else if (strcmp (method_name, "Activate") == 0)
1348 gchar *status = g_strdup_printf ("CONSOLE-KIT ACTIVATE-SESSION SESSION=%s", session->cookie);
1349 check_status (status);
1352 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1355 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1359 ck_name_acquired_cb (GDBusConnection *connection,
1363 const gchar *ck_interface =
1365 " <interface name='org.freedesktop.ConsoleKit.Manager'>"
1366 " <method name='CanRestart'>"
1367 " <arg name='can_restart' direction='out' type='b'/>"
1369 " <method name='CanStop'>"
1370 " <arg name='can_stop' direction='out' type='b'/>"
1372 " <method name='CloseSession'>"
1373 " <arg name='cookie' direction='in' type='s'/>"
1374 " <arg name='result' direction='out' type='b'/>"
1376 " <method name='OpenSession'>"
1377 " <arg name='cookie' direction='out' type='s'/>"
1379 " <method name='OpenSessionWithParameters'>"
1380 " <arg name='parameters' direction='in' type='a(sv)'/>"
1381 " <arg name='cookie' direction='out' type='s'/>"
1383 " <method name='GetSessionForCookie'>"
1384 " <arg name='cookie' direction='in' type='s'/>"
1385 " <arg name='ssid' direction='out' type='o'/>"
1387 " <method name='Restart'/>"
1388 " <method name='Stop'/>"
1389 " <signal name='SeatAdded'>"
1390 " <arg name='seat' type='o'/>"
1392 " <signal name='SeatRemoved'>"
1393 " <arg name='seat' type='o'/>"
1397 static const GDBusInterfaceVTable ck_vtable =
1401 const gchar *ck_session_interface =
1403 " <interface name='org.freedesktop.ConsoleKit.Session'>"
1404 " <method name='Lock'/>"
1405 " <method name='Unlock'/>"
1406 " <method name='Activate'/>"
1409 GDBusNodeInfo *ck_info;
1410 GError *error = NULL;
1412 ck_info = g_dbus_node_info_new_for_xml (ck_interface, &error);
1414 g_warning ("Failed to parse D-Bus interface: %s", error->message);
1415 g_clear_error (&error);
1418 ck_session_info = g_dbus_node_info_new_for_xml (ck_session_interface, &error);
1420 g_warning ("Failed to parse D-Bus interface: %s", error->message);
1421 g_clear_error (&error);
1422 if (!ck_session_info)
1424 g_dbus_connection_register_object (connection,
1425 "/org/freedesktop/ConsoleKit/Manager",
1426 ck_info->interfaces[0],
1431 g_warning ("Failed to register console kit service: %s", error->message);
1432 g_clear_error (&error);
1433 g_dbus_node_info_unref (ck_info);
1436 if (service_count == 0)
1441 start_console_kit_daemon (void)
1444 g_bus_own_name (G_BUS_TYPE_SYSTEM,
1445 "org.freedesktop.ConsoleKit",
1446 G_BUS_NAME_OWNER_FLAGS_NONE,
1448 ck_name_acquired_cb,
1455 handle_login1_seat_call (GDBusConnection *connection,
1456 const gchar *sender,
1457 const gchar *object_path,
1458 const gchar *interface_name,
1459 const gchar *method_name,
1460 GVariant *parameters,
1461 GDBusMethodInvocation *invocation,
1464 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1468 handle_login1_seat_get_property (GDBusConnection *connection,
1469 const gchar *sender,
1470 const gchar *object_path,
1471 const gchar *interface_name,
1472 const gchar *property_name,
1476 Login1Seat *seat = user_data;
1478 if (strcmp (property_name, "CanGraphical") == 0)
1479 return g_variant_new_boolean (seat->can_graphical);
1480 else if (strcmp (property_name, "CanMultiSession") == 0)
1481 return g_variant_new_boolean (seat->can_multi_session);
1482 else if (strcmp (property_name, "Id") == 0)
1483 return g_variant_new_string (seat->id);
1489 add_login1_seat (GDBusConnection *connection, const gchar *id, gboolean emit_signal)
1492 GError *error = NULL;
1493 GDBusNodeInfo *login1_seat_info;
1495 const gchar *login1_seat_interface =
1497 " <interface name='org.freedesktop.login1.Seat'>"
1498 " <property name='CanGraphical' type='b' access='read'/>"
1499 " <property name='CanMultiSession' type='b' access='read'/>"
1500 " <property name='Id' type='s' access='read'/>"
1503 static const GDBusInterfaceVTable login1_seat_vtable =
1505 handle_login1_seat_call,
1506 handle_login1_seat_get_property,
1509 seat = g_malloc0 (sizeof (Login1Seat));
1510 login1_seats = g_list_append (login1_seats, seat);
1511 seat->id = g_strdup (id);
1512 seat->path = g_strdup_printf ("/org/freedesktop/login1/seat/%s", seat->id);
1513 seat->can_graphical = TRUE;
1514 seat->can_multi_session = TRUE;
1516 login1_seat_info = g_dbus_node_info_new_for_xml (login1_seat_interface, &error);
1518 g_warning ("Failed to parse login1 seat D-Bus interface: %s", error->message);
1519 g_clear_error (&error);
1520 if (!login1_seat_info)
1523 g_dbus_connection_register_object (connection,
1525 login1_seat_info->interfaces[0],
1526 &login1_seat_vtable,
1531 g_warning ("Failed to register login1 seat: %s", error->message);
1532 g_clear_error (&error);
1533 g_dbus_node_info_unref (login1_seat_info);
1537 g_dbus_connection_emit_signal (connection,
1539 "/org/freedesktop/login1",
1540 "org.freedesktop.login1.Manager",
1542 g_variant_new ("(so)", seat->id, seat->path),
1545 g_warning ("Failed to emit SeatNew: %s", error->message);
1546 g_clear_error (&error);
1553 find_login1_seat (const gchar *id)
1558 for (link = login1_seats; link; link = link->next)
1561 if (strcmp (seat->id, id) == 0)
1569 remove_login1_seat (GDBusConnection *connection, const gchar *id)
1572 GError *error = NULL;
1574 seat = find_login1_seat (id);
1578 g_dbus_connection_emit_signal (connection,
1580 "/org/freedesktop/login1",
1581 "org.freedesktop.login1.Manager",
1583 g_variant_new ("(so)", seat->id, seat->path),
1586 g_warning ("Failed to emit SeatNew: %s", error->message);
1587 g_clear_error (&error);
1589 login1_seats = g_list_remove (login1_seats, seat);
1591 g_free (seat->path);
1596 handle_login1_session_call (GDBusConnection *connection,
1597 const gchar *sender,
1598 const gchar *object_path,
1599 const gchar *interface_name,
1600 const gchar *method_name,
1601 GVariant *parameters,
1602 GDBusMethodInvocation *invocation,
1605 /*Login1Session *session = user_data;*/
1606 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1609 static Login1Session *
1610 create_login1_session (GDBusConnection *connection)
1612 Login1Session *session;
1613 GError *error = NULL;
1614 GDBusNodeInfo *login1_session_info;
1616 const gchar *login1_session_interface =
1618 " <interface name='org.freedesktop.login1.Session'>"
1621 static const GDBusInterfaceVTable login1_session_vtable =
1623 handle_login1_session_call,
1626 session = g_malloc0 (sizeof (Login1Session));
1627 login1_sessions = g_list_append (login1_sessions, session);
1629 session->id = g_strdup_printf ("c%d", login1_session_index++);
1630 session->path = g_strdup_printf ("/org/freedesktop/login1/Session/%s", session->id);
1632 login1_session_info = g_dbus_node_info_new_for_xml (login1_session_interface, &error);
1634 g_warning ("Failed to parse login1 session D-Bus interface: %s", error->message);
1635 g_clear_error (&error);
1636 if (!login1_session_info)
1639 g_dbus_connection_register_object (connection,
1641 login1_session_info->interfaces[0],
1642 &login1_session_vtable,
1647 g_warning ("Failed to register login1 session: %s", error->message);
1648 g_clear_error (&error);
1649 g_dbus_node_info_unref (login1_session_info);
1654 static Login1Session *
1655 find_login1_session (const gchar *id)
1659 for (link = login1_sessions; link; link = link->next)
1661 Login1Session *session = link->data;
1662 if (strcmp (session->id, id) == 0)
1670 handle_login1_call (GDBusConnection *connection,
1671 const gchar *sender,
1672 const gchar *object_path,
1673 const gchar *interface_name,
1674 const gchar *method_name,
1675 GVariant *parameters,
1676 GDBusMethodInvocation *invocation,
1679 if (strcmp (method_name, "ListSeats") == 0)
1681 GVariantBuilder seats;
1684 g_variant_builder_init (&seats, G_VARIANT_TYPE ("a(so)"));
1685 for (link = login1_seats; link; link = link->next)
1687 Login1Seat *seat = link->data;
1688 g_variant_builder_add (&seats, "(so)", seat->id, seat->path);
1690 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a(so))", &seats));
1692 else if (strcmp (method_name, "CreateSession") == 0)
1694 /* Note: this is not the full CreateSession as used by logind, we just
1695 need one so our fake PAM stack can communicate with this service */
1696 Login1Session *session = create_login1_session (connection);
1697 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(so)", session->id, session->path));
1700 else if (strcmp (method_name, "LockSession") == 0)
1703 Login1Session *session;
1705 g_variant_get (parameters, "(&s)", &id);
1706 session = find_login1_session (id);
1709 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such session: %s", id);
1713 if (!session->locked)
1715 gchar *status = g_strdup_printf ("LOGIN1 LOCK-SESSION SESSION=%s", id);
1716 check_status (status);
1719 session->locked = TRUE;
1720 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1722 else if (strcmp (method_name, "UnlockSession") == 0)
1725 Login1Session *session;
1727 g_variant_get (parameters, "(&s)", &id);
1728 session = find_login1_session (id);
1731 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such session: %s", id);
1735 if (session->locked)
1737 gchar *status = g_strdup_printf ("LOGIN1 UNLOCK-SESSION SESSION=%s", id);
1738 check_status (status);
1741 session->locked = FALSE;
1742 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1744 else if (strcmp (method_name, "ActivateSession") == 0)
1747 Login1Session *session;
1749 g_variant_get (parameters, "(&s)", &id);
1750 session = find_login1_session (id);
1753 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such session: %s", id);
1757 gchar *status = g_strdup_printf ("LOGIN1 ACTIVATE-SESSION SESSION=%s", id);
1758 check_status (status);
1761 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1763 else if (strcmp (method_name, "CanReboot") == 0)
1765 check_status ("LOGIN1 CAN-REBOOT");
1766 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1768 else if (strcmp (method_name, "Reboot") == 0)
1770 gboolean interactive;
1771 g_variant_get (parameters, "(b)", &interactive);
1772 check_status ("LOGIN1 REBOOT");
1773 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1775 else if (strcmp (method_name, "CanPowerOff") == 0)
1777 check_status ("LOGIN1 CAN-POWER-OFF");
1778 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1780 else if (strcmp (method_name, "Suspend") == 0)
1782 gboolean interactive;
1783 g_variant_get (parameters, "(b)", &interactive);
1784 check_status ("LOGIN1 SUSPEND");
1785 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1787 else if (strcmp (method_name, "CanSuspend") == 0)
1789 check_status ("LOGIN1 CAN-SUSPEND");
1790 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1792 else if (strcmp (method_name, "PowerOff") == 0)
1794 gboolean interactive;
1795 g_variant_get (parameters, "(b)", &interactive);
1796 check_status ("LOGIN1 POWER-OFF");
1797 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1799 else if (strcmp (method_name, "CanHibernate") == 0)
1801 check_status ("LOGIN1 CAN-HIBERNATE");
1802 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1804 else if (strcmp (method_name, "Hibernate") == 0)
1806 gboolean interactive;
1807 g_variant_get (parameters, "(b)", &interactive);
1808 check_status ("LOGIN1 HIBERNATE");
1809 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1812 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1816 login1_name_acquired_cb (GDBusConnection *connection,
1820 const gchar *login1_interface =
1822 " <interface name='org.freedesktop.login1.Manager'>"
1823 " <method name='ListSeats'>"
1824 " <arg name='seats' type='a(so)' direction='out'/>"
1826 " <method name='CreateSession'>"
1827 " <arg name='id' type='s' direction='out'/>"
1828 " <arg name='path' type='o' direction='out'/>"
1830 " <method name='LockSession'>"
1831 " <arg name='id' type='s' direction='in'/>"
1833 " <method name='UnlockSession'>"
1834 " <arg name='id' type='s' direction='in'/>"
1836 " <method name='ActivateSession'>"
1837 " <arg name='id' type='s' direction='in'/>"
1839 " <method name='CanReboot'>"
1840 " <arg name='result' direction='out' type='s'/>"
1842 " <method name='Reboot'>"
1843 " <arg name='interactive' direction='in' type='b'/>"
1845 " <method name='CanPowerOff'>"
1846 " <arg name='result' direction='out' type='s'/>"
1848 " <method name='PowerOff'>"
1849 " <arg name='interactive' direction='in' type='b'/>"
1851 " <method name='CanSuspend'>"
1852 " <arg name='result' direction='out' type='s'/>"
1854 " <method name='Suspend'>"
1855 " <arg name='interactive' direction='in' type='b'/>"
1857 " <method name='CanHibernate'>"
1858 " <arg name='result' direction='out' type='s'/>"
1860 " <method name='Hibernate'>"
1861 " <arg name='interactive' direction='in' type='b'/>"
1863 " <signal name='SeatNew'>"
1864 " <arg name='seat' type='so'/>"
1866 " <signal name='SeatRemoved'>"
1867 " <arg name='seat' type='so'/>"
1871 static const GDBusInterfaceVTable login1_vtable =
1875 GDBusNodeInfo *login1_info;
1877 GError *error = NULL;
1879 login1_info = g_dbus_node_info_new_for_xml (login1_interface, &error);
1881 g_warning ("Failed to parse login1 D-Bus interface: %s", error->message);
1882 g_clear_error (&error);
1885 g_dbus_connection_register_object (connection,
1886 "/org/freedesktop/login1",
1887 login1_info->interfaces[0],
1892 g_warning ("Failed to register login1 service: %s", error->message);
1893 g_clear_error (&error);
1894 g_dbus_node_info_unref (login1_info);
1896 /* We always have seat0 */
1897 seat0 = add_login1_seat (connection, "seat0", FALSE);
1898 if (g_key_file_has_key (config, "test-runner-config", "seat0-can-graphical", NULL))
1899 seat0->can_graphical = g_key_file_get_boolean (config, "test-runner-config", "seat0-can-graphical", NULL);
1900 if (g_key_file_has_key (config, "test-runner-config", "seat0-can-multi-session", NULL))
1901 seat0->can_multi_session = g_key_file_get_boolean (config, "test-runner-config", "seat0-can-multi-session", NULL);
1904 if (service_count == 0)
1909 start_login1_daemon (void)
1912 g_bus_own_name (G_BUS_TYPE_SYSTEM,
1913 "org.freedesktop.login1",
1914 G_BUS_NAME_OWNER_FLAGS_NONE,
1916 login1_name_acquired_cb,
1922 static AccountsUser *
1923 get_accounts_user_by_uid (guint uid)
1927 for (link = accounts_users; link; link = link->next)
1929 AccountsUser *u = link->data;
1937 static AccountsUser *
1938 get_accounts_user_by_name (const gchar *username)
1942 for (link = accounts_users; link; link = link->next)
1944 AccountsUser *u = link->data;
1945 if (strcmp (u->user_name, username) == 0)
1953 accounts_user_set_hidden (AccountsUser *user, gboolean hidden, gboolean emit_signal)
1955 GError *error = NULL;
1957 user->hidden = hidden;
1959 if (user->hidden && user->id != 0)
1961 g_dbus_connection_unregister_object (accounts_connection, user->id);
1962 g_dbus_connection_emit_signal (accounts_connection,
1964 "/org/freedesktop/Accounts",
1965 "org.freedesktop.Accounts",
1967 g_variant_new ("(o)", user->path),
1970 g_warning ("Failed to emit UserDeleted: %s", error->message);
1971 g_clear_error (&error);
1975 if (!user->hidden && user->id == 0)
1977 user->id = g_dbus_connection_register_object (accounts_connection,
1979 user_info->interfaces[0],
1985 g_warning ("Failed to register user: %s", error->message);
1986 g_clear_error (&error);
1988 g_dbus_connection_emit_signal (accounts_connection,
1990 "/org/freedesktop/Accounts",
1991 "org.freedesktop.Accounts",
1993 g_variant_new ("(o)", user->path),
1996 g_warning ("Failed to emit UserAdded: %s", error->message);
1997 g_clear_error (&error);
2002 load_passwd_file (void)
2004 gchar *path, *data, **lines;
2005 gchar **user_filter = NULL;
2008 if (g_key_file_has_key (config, "test-runner-config", "accounts-service-user-filter", NULL))
2012 filter = g_key_file_get_string (config, "test-runner-config", "accounts-service-user-filter", NULL);
2013 user_filter = g_strsplit (filter, " ", -1);
2017 path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "passwd", NULL);
2018 g_file_get_contents (path, &data, NULL, NULL);
2020 lines = g_strsplit (data, "\n", -1);
2023 for (i = 0; lines[i]; i++)
2027 gchar *user_name, *real_name;
2028 AccountsUser *user = NULL;
2030 fields = g_strsplit (lines[i], ":", -1);
2031 if (fields == NULL || g_strv_length (fields) < 7)
2033 g_strfreev (fields);
2037 user_name = fields[0];
2038 uid = atoi (fields[2]);
2039 real_name = fields[4];
2041 user = get_accounts_user_by_uid (uid);
2045 GKeyFile *dmrc_file;
2047 user = g_malloc0 (sizeof (AccountsUser));
2048 accounts_users = g_list_append (accounts_users, user);
2050 /* Only allow users in whitelist */
2051 user->hidden = FALSE;
2056 user->hidden = TRUE;
2057 for (j = 0; user_filter[j] != NULL; j++)
2058 if (strcmp (user_name, user_filter[j]) == 0)
2059 user->hidden = FALSE;
2062 dmrc_file = g_key_file_new ();
2063 path = g_build_filename (temp_dir, "home", user_name, ".dmrc", NULL);
2064 g_key_file_load_from_file (dmrc_file, path, G_KEY_FILE_NONE, NULL);
2068 user->user_name = g_strdup (user_name);
2069 user->real_name = g_strdup (real_name);
2070 user->home_directory = g_build_filename (temp_dir, "home", user_name, NULL);
2071 user->language = g_key_file_get_string (dmrc_file, "Desktop", "Language", NULL);
2072 /* DMRC contains a locale, strip the codeset off it to get the language */
2075 gchar *c = strchr (user->language, '.');
2079 user->xsession = g_key_file_get_string (dmrc_file, "Desktop", "Session", NULL);
2080 user->layouts = g_key_file_get_string_list (dmrc_file, "X-Accounts", "Layouts", NULL, NULL);
2083 user->layouts = g_malloc (sizeof (gchar *) * 2);
2084 user->layouts[0] = g_key_file_get_string (dmrc_file, "Desktop", "Layout", NULL);
2085 user->layouts[1] = NULL;
2087 user->has_messages = g_key_file_get_boolean (dmrc_file, "X-Accounts", "HasMessages", NULL);
2088 user->path = g_strdup_printf ("/org/freedesktop/Accounts/User%d", uid);
2089 accounts_user_set_hidden (user, user->hidden, FALSE);
2091 g_key_file_free (dmrc_file);
2094 g_strfreev (fields);
2101 handle_accounts_call (GDBusConnection *connection,
2102 const gchar *sender,
2103 const gchar *object_path,
2104 const gchar *interface_name,
2105 const gchar *method_name,
2106 GVariant *parameters,
2107 GDBusMethodInvocation *invocation,
2110 if (strcmp (method_name, "ListCachedUsers") == 0)
2112 GVariantBuilder builder;
2115 g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
2117 load_passwd_file ();
2118 for (link = accounts_users; link; link = link->next)
2120 AccountsUser *user = link->data;
2121 if (!user->hidden && user->uid >= 1000)
2122 g_variant_builder_add_value (&builder, g_variant_new_object_path (user->path));
2125 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(ao)", &builder));
2127 else if (strcmp (method_name, "FindUserByName") == 0)
2129 AccountsUser *user = NULL;
2132 g_variant_get (parameters, "(&s)", &user_name);
2134 load_passwd_file ();
2135 user = get_accounts_user_by_name (user_name);
2139 accounts_user_set_hidden (user, FALSE, TRUE);
2140 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", user->path));
2143 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such user: %s", user_name);
2146 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
2150 handle_user_call (GDBusConnection *connection,
2151 const gchar *sender,
2152 const gchar *object_path,
2153 const gchar *interface_name,
2154 const gchar *method_name,
2155 GVariant *parameters,
2156 GDBusMethodInvocation *invocation,
2159 AccountsUser *user = user_data;
2161 if (strcmp (method_name, "SetXSession") == 0)
2165 g_variant_get (parameters, "(&s)", &xsession);
2167 g_free (user->xsession);
2168 user->xsession = g_strdup (xsession);
2170 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
2172 /* And notify others that it took */
2173 g_dbus_connection_emit_signal (accounts_connection,
2176 "org.freedesktop.Accounts.User",
2178 g_variant_new ("()"),
2182 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
2186 handle_user_get_property (GDBusConnection *connection,
2187 const gchar *sender,
2188 const gchar *object_path,
2189 const gchar *interface_name,
2190 const gchar *property_name,
2194 AccountsUser *user = user_data;
2196 if (strcmp (property_name, "UserName") == 0)
2197 return g_variant_new_string (user->user_name);
2198 else if (strcmp (property_name, "RealName") == 0)
2199 return g_variant_new_string (user->real_name);
2200 else if (strcmp (property_name, "HomeDirectory") == 0)
2201 return g_variant_new_string (user->home_directory);
2202 else if (strcmp (property_name, "SystemAccount") == 0)
2203 return g_variant_new_boolean (user->uid < 1000);
2204 else if (strcmp (property_name, "BackgroundFile") == 0)
2205 return g_variant_new_string (user->background ? user->background : "");
2206 else if (strcmp (property_name, "Language") == 0)
2207 return g_variant_new_string (user->language ? user->language : "");
2208 else if (strcmp (property_name, "IconFile") == 0)
2209 return g_variant_new_string (user->image ? user->image : "");
2210 else if (strcmp (property_name, "Shell") == 0)
2211 return g_variant_new_string ("/bin/sh");
2212 else if (strcmp (property_name, "Uid") == 0)
2213 return g_variant_new_uint64 (user->uid);
2214 else if (strcmp (property_name, "XSession") == 0)
2215 return g_variant_new_string (user->xsession ? user->xsession : "");
2216 else if (strcmp (property_name, "XKeyboardLayouts") == 0)
2218 if (user->layouts != NULL)
2219 return g_variant_new_strv ((const gchar * const *) user->layouts, -1);
2221 return g_variant_new_strv (NULL, 0);
2223 else if (strcmp (property_name, "XHasMessages") == 0)
2224 return g_variant_new_boolean (user->has_messages);
2230 accounts_name_acquired_cb (GDBusConnection *connection,
2234 const gchar *accounts_interface =
2236 " <interface name='org.freedesktop.Accounts'>"
2237 " <method name='ListCachedUsers'>"
2238 " <arg name='user' direction='out' type='ao'/>"
2240 " <method name='FindUserByName'>"
2241 " <arg name='name' direction='in' type='s'/>"
2242 " <arg name='user' direction='out' type='o'/>"
2244 " <signal name='UserAdded'>"
2245 " <arg name='user' type='o'/>"
2247 " <signal name='UserDeleted'>"
2248 " <arg name='user' type='o'/>"
2252 static const GDBusInterfaceVTable accounts_vtable =
2254 handle_accounts_call,
2256 const gchar *user_interface =
2258 " <interface name='org.freedesktop.Accounts.User'>"
2259 " <method name='SetXSession'>"
2260 " <arg name='x_session' direction='in' type='s'/>"
2262 " <property name='UserName' type='s' access='read'/>"
2263 " <property name='RealName' type='s' access='read'/>"
2264 " <property name='HomeDirectory' type='s' access='read'/>"
2265 " <property name='SystemAccount' type='b' access='read'/>"
2266 " <property name='BackgroundFile' type='s' access='read'/>"
2267 " <property name='Language' type='s' access='read'/>"
2268 " <property name='IconFile' type='s' access='read'/>"
2269 " <property name='Shell' type='s' access='read'/>"
2270 " <property name='Uid' type='t' access='read'/>"
2271 " <property name='XSession' type='s' access='read'/>"
2272 " <property name='XKeyboardLayouts' type='as' access='read'/>"
2273 " <property name='XHasMessages' type='b' access='read'/>"
2274 " <signal name='Changed' />"
2277 GError *error = NULL;
2279 accounts_connection = connection;
2281 accounts_info = g_dbus_node_info_new_for_xml (accounts_interface, &error);
2283 g_warning ("Failed to parse D-Bus interface: %s", error->message);
2284 g_clear_error (&error);
2287 user_info = g_dbus_node_info_new_for_xml (user_interface, &error);
2289 g_warning ("Failed to parse D-Bus interface: %s", error->message);
2290 g_clear_error (&error);
2293 g_dbus_connection_register_object (connection,
2294 "/org/freedesktop/Accounts",
2295 accounts_info->interfaces[0],
2301 g_warning ("Failed to register accounts service: %s", error->message);
2302 g_clear_error (&error);
2303 g_dbus_node_info_unref (accounts_info);
2306 if (service_count == 0)
2311 start_accounts_service_daemon (void)
2314 g_bus_own_name (G_BUS_TYPE_SYSTEM,
2315 "org.freedesktop.Accounts",
2316 G_BUS_NAME_OWNER_FLAGS_NONE,
2317 accounts_name_acquired_cb,
2331 signal_cb (gpointer user_data)
2333 g_print ("Caught signal, quitting\n");
2334 quit (EXIT_FAILURE);
2339 properties_changed_cb (GDBusConnection *connection,
2340 const gchar *sender_name,
2341 const gchar *object_path,
2342 const gchar *interface_name,
2343 const gchar *signal_name,
2344 GVariant *parameters,
2347 const gchar *interface, *name;
2350 GVariantIter *changed_properties, *invalidated_properties;
2353 g_variant_get (parameters, "(&sa{sv}as)", &interface, &changed_properties, &invalidated_properties);
2355 status = g_string_new ("RUNNER DBUS-PROPERTIES-CHANGED");
2356 g_string_append_printf (status, " PATH=%s", object_path);
2357 g_string_append_printf (status, " INTERFACE=%s", interface);
2358 for (i = 0; g_variant_iter_loop (changed_properties, "{&sv}", &name, &value); i++)
2361 g_string_append (status, " CHANGED=");
2363 g_string_append (status, ",");
2364 g_string_append (status, name);
2365 if (g_variant_is_of_type (value, G_VARIANT_TYPE ("ao")))
2370 g_variant_iter_init (&iter, value);
2371 while (g_variant_iter_loop (&iter, "&o", &path))
2372 g_string_append_printf (status, ":%s", path);
2375 for (i = 0; g_variant_iter_loop (invalidated_properties, "&s", &name); i++)
2378 g_string_append (status, " INVALIDATED=");
2380 g_string_append (status, ",");
2381 g_string_append (status, name);
2384 check_status (status->str);
2385 g_string_free (status, TRUE);
2389 dbus_signal_cb (GDBusConnection *connection,
2390 const gchar *sender_name,
2391 const gchar *object_path,
2392 const gchar *interface_name,
2393 const gchar *signal_name,
2394 GVariant *parameters,
2399 status = g_string_new ("RUNNER DBUS-SIGNAL");
2400 g_string_append_printf (status, " PATH=%s", object_path);
2401 g_string_append_printf (status, " INTERFACE=%s", interface_name);
2402 g_string_append_printf (status, " NAME=%s", signal_name);
2404 check_status (status->str);
2405 g_string_free (status, TRUE);
2409 main (int argc, char **argv)
2413 gchar *greeter = NULL, *script_name, *config_file, *additional_system_config;
2414 gchar *additional_config, *path, *path1, *path2, *ld_preload, *ld_library_path, *home_dir;
2415 GString *passwd_data, *group_data;
2416 GSource *status_source;
2418 GError *error = NULL;
2420 #if !defined(GLIB_VERSION_2_36)
2424 loop = g_main_loop_new (NULL, FALSE);
2426 g_unix_signal_add (SIGINT, signal_cb, NULL);
2427 g_unix_signal_add (SIGTERM, signal_cb, NULL);
2429 children = g_hash_table_new (g_direct_hash, g_direct_equal);
2433 g_printerr ("Usage %s SCRIPT-NAME GREETER\n", argv[0]);
2434 quit (EXIT_FAILURE);
2436 script_name = argv[1];
2437 config_file = g_strdup_printf ("%s.conf", script_name);
2438 config_path = g_build_filename (SRCDIR, "tests", "scripts", config_file, NULL);
2439 g_free (config_file);
2441 config = g_key_file_new ();
2442 g_key_file_load_from_file (config, config_path, G_KEY_FILE_NONE, NULL);
2444 load_script (config_path);
2446 if (!getcwd (cwd, 1024))
2448 g_critical ("Error getting current directory: %s", strerror (errno));
2449 quit (EXIT_FAILURE);
2452 /* Don't contact our X server */
2453 g_unsetenv ("DISPLAY");
2455 /* Don't let XDG vars from system affect tests */
2456 g_unsetenv ("XDG_CONFIG_DIRS");
2457 g_unsetenv ("XDG_DATA_DIRS");
2459 /* Override system calls */
2460 ld_preload = g_build_filename (BUILDDIR, "tests", "src", ".libs", "libsystem.so", NULL);
2461 g_setenv ("LD_PRELOAD", ld_preload, TRUE);
2462 g_free (ld_preload);
2464 /* Run test programs */
2465 path = g_strdup_printf ("%s/tests/src/.libs:%s/tests/src:%s/tests/src:%s/src:%s", BUILDDIR, BUILDDIR, SRCDIR, BUILDDIR, g_getenv ("PATH"));
2466 g_setenv ("PATH", path, TRUE);
2469 /* Use locally built libraries */
2470 path1 = g_build_filename (BUILDDIR, "liblightdm-gobject", ".libs", NULL);
2471 path2 = g_build_filename (BUILDDIR, "liblightdm-qt", ".libs", NULL);
2472 ld_library_path = g_strdup_printf ("%s:%s", path1, path2);
2475 g_setenv ("LD_LIBRARY_PATH", ld_library_path, TRUE);
2476 g_free (ld_library_path);
2477 path1 = g_build_filename (BUILDDIR, "liblightdm-gobject", NULL);
2478 g_setenv ("GI_TYPELIB_PATH", path1, TRUE);
2481 /* Run in a temporary directory inside the build directory */
2482 /* Note we have to pick a name that is short since Unix sockets in this directory have a 108 character limit on their paths */
2487 name = g_strdup_printf (".r%d", i);
2489 temp_dir = g_build_filename ("/tmp", name, NULL);
2491 if (!g_file_test (temp_dir, G_FILE_TEST_EXISTS))
2495 g_mkdir_with_parents (temp_dir, 0755);
2496 g_setenv ("LIGHTDM_TEST_ROOT", temp_dir, TRUE);
2498 /* Open socket for status */
2499 /* Note we have to pick a socket name that is short since there is a 108 character limit on the name */
2500 status_socket_name = g_build_filename (temp_dir, ".s", NULL);
2501 unlink (status_socket_name);
2502 status_socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, &error);
2504 g_warning ("Error creating status socket %s: %s", status_socket_name, error->message);
2505 g_clear_error (&error);
2508 GSocketAddress *address;
2511 address = g_unix_socket_address_new (status_socket_name);
2512 result = g_socket_bind (status_socket, address, FALSE, &error);
2513 g_object_unref (address);
2515 g_warning ("Error binding status socket %s: %s", status_socket_name, error->message);
2516 g_clear_error (&error);
2519 result = g_socket_listen (status_socket, &error);
2521 g_warning ("Error listening on status socket %s: %s", status_socket_name, error->message);
2522 g_clear_error (&error);
2526 g_object_unref (status_socket);
2527 status_socket = NULL;
2531 quit (EXIT_FAILURE);
2532 status_source = g_socket_create_source (status_socket, G_IO_IN, NULL);
2533 g_source_set_callback (status_source, status_connect_cb, NULL, NULL);
2534 g_source_attach (status_source, NULL);
2536 /* Set up a skeleton file system */
2537 g_mkdir_with_parents (g_strdup_printf ("%s/etc", temp_dir), 0755);
2538 g_mkdir_with_parents (g_strdup_printf ("%s/run", temp_dir), 0755);
2539 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share", temp_dir), 0755);
2540 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/sessions", temp_dir), 0755);
2541 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/remote-sessions", temp_dir), 0755);
2542 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/greeters", temp_dir), 0755);
2543 g_mkdir_with_parents (g_strdup_printf ("%s/tmp", temp_dir), 0755);
2544 g_mkdir_with_parents (g_strdup_printf ("%s/var/lib/lightdm-data", temp_dir), 0755);
2545 g_mkdir_with_parents (g_strdup_printf ("%s/var/run", temp_dir), 0755);
2546 g_mkdir_with_parents (g_strdup_printf ("%s/var/log", temp_dir), 0755);
2548 /* Copy over the configuration */
2549 g_mkdir_with_parents (g_strdup_printf ("%s/etc/lightdm", temp_dir), 0755);
2550 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))
2551 if (system (g_strdup_printf ("cp %s %s/etc/lightdm/lightdm.conf", config_path, temp_dir)))
2552 perror ("Failed to copy configuration");
2554 additional_system_config = g_key_file_get_string (config, "test-runner-config", "additional-system-config", NULL);
2555 if (additional_system_config)
2559 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/lightdm.conf.d", temp_dir), 0755);
2561 files = g_strsplit (additional_system_config, " ", -1);
2562 for (i = 0; files[i]; i++)
2563 if (system (g_strdup_printf ("cp %s/tests/scripts/%s %s/usr/share/lightdm/lightdm.conf.d", SRCDIR, files[i], temp_dir)))
2564 perror ("Failed to copy configuration");
2568 additional_config = g_key_file_get_string (config, "test-runner-config", "additional-config", NULL);
2569 if (additional_config)
2573 g_mkdir_with_parents (g_strdup_printf ("%s/etc/xdg/lightdm/lightdm.conf.d", temp_dir), 0755);
2575 files = g_strsplit (additional_config, " ", -1);
2576 for (i = 0; files[i]; i++)
2577 if (system (g_strdup_printf ("cp %s/tests/scripts/%s %s/etc/xdg/lightdm/lightdm.conf.d", SRCDIR, files[i], temp_dir)))
2578 perror ("Failed to copy configuration");
2582 if (g_key_file_has_key (config, "test-runner-config", "shared-data-dirs", NULL))
2588 dir_string = g_key_file_get_string (config, "test-runner-config", "shared-data-dirs", NULL);
2589 dirs = g_strsplit (dir_string, " ", -1);
2590 g_free (dir_string);
2592 for (i = 0; dirs[i]; i++)
2594 gchar **fields = g_strsplit (dirs[i], ":", -1);
2595 if (g_strv_length (fields) == 4)
2597 gchar *path = g_strdup_printf ("%s/var/lib/lightdm-data/%s", temp_dir, fields[0]);
2598 int uid = g_ascii_strtoll (fields[1], NULL, 10);
2599 int gid = g_ascii_strtoll (fields[2], NULL, 10);
2600 int mode = g_ascii_strtoll (fields[3], NULL, 8);
2601 g_mkdir (path, mode);
2602 g_chmod (path, mode); /* mkdir filters by umask, so make sure we have what we want */
2603 if (chown (path, uid, gid) < 0)
2604 g_warning ("chown (%s) failed: %s", path, strerror (errno));
2607 g_strfreev (fields);
2613 /* Always copy the script */
2614 if (system (g_strdup_printf ("cp %s %s/script", config_path, temp_dir)))
2615 perror ("Failed to copy configuration");
2617 /* Copy over the greeter files */
2618 if (system (g_strdup_printf ("cp %s/sessions/* %s/usr/share/lightdm/sessions", DATADIR, temp_dir)))
2619 perror ("Failed to copy sessions");
2620 if (system (g_strdup_printf ("cp %s/remote-sessions/* %s/usr/share/lightdm/remote-sessions", DATADIR, temp_dir)))
2621 perror ("Failed to copy remote sessions");
2622 if (system (g_strdup_printf ("cp %s/greeters/* %s/usr/share/lightdm/greeters", DATADIR, temp_dir)))
2623 perror ("Failed to copy greeters");
2625 /* Set up the default greeter */
2626 path = g_build_filename (temp_dir, "usr", "share", "lightdm", "greeters", "default.desktop", NULL);
2627 greeter = g_strdup_printf ("%s.desktop", argv[2]);
2628 if (symlink (greeter, path) < 0)
2630 g_printerr ("Failed to make greeter symlink %s->%s: %s\n", path, greeter, strerror (errno));
2631 quit (EXIT_FAILURE);
2636 home_dir = g_build_filename (temp_dir, "home", NULL);
2638 /* Make fake users */
2648 {"root", "", "root", 0},
2649 /* Unprivileged account for greeters */
2650 {"lightdm", "", "", 100},
2651 /* These accounts have a password */
2652 {"have-password1", "password", "Password User 1", 1000},
2653 {"have-password2", "password", "Password User 2", 1001},
2654 {"have-password3", "password", "Password User 3", 1002},
2655 {"have-password4", "password", "Password User 4", 1003},
2656 /* This account always prompts for a password, even if using the lightdm-autologin service */
2657 {"always-password", "password", "Password User 4", 1004},
2658 /* These accounts have no password */
2659 {"no-password1", "", "No Password User 1", 1005},
2660 {"no-password2", "", "No Password User 2", 1006},
2661 {"no-password3", "", "No Password User 3", 1007},
2662 {"no-password4", "", "No Password User 4", 1008},
2663 /* This account has a keyboard layout */
2664 {"have-layout", "", "Layout User", 1009},
2665 /* This account has a set of keyboard layouts */
2666 {"have-layouts", "", "Layouts User", 1010},
2667 /* This account has a language set */
2668 {"have-language", "", "Language User", 1011},
2669 /* This account has a preconfigured session */
2670 {"have-session", "", "Session User", 1012},
2671 /* This account has the home directory mounted on login */
2672 {"mount-home-dir", "", "Mounted Home Dir User", 1013},
2673 /* This account is denied access */
2674 {"denied", "", "Denied User", 1014},
2675 /* This account has expired */
2676 {"expired", "", "Expired User", 1015},
2677 /* This account needs a password change */
2678 {"new-authtok", "", "New Token User", 1016},
2679 /* This account is switched to change-user2 when authentication succeeds */
2680 {"change-user1", "", "Change User 1", 1017},
2681 {"change-user2", "", "Change User 2", 1018},
2682 /* This account switches to invalid-user when authentication succeeds */
2683 {"change-user-invalid", "", "Invalid Change User", 1019},
2684 /* This account crashes on authentication */
2685 {"crash-authenticate", "", "Crash Auth User", 1020},
2686 /* This account shows an informational prompt on login */
2687 {"info-prompt", "password", "Info Prompt", 1021},
2688 /* This account shows multiple informational prompts on login */
2689 {"multi-info-prompt","password", "Multi Info Prompt", 1022},
2690 /* This account uses two factor authentication */
2691 {"two-factor", "password", "Two Factor", 1023},
2692 /* This account has a special group */
2693 {"group-member", "password", "Group Member", 1024},
2694 /* This account has the home directory created when the session starts */
2695 {"make-home-dir", "", "Make Home Dir User", 1025},
2696 /* This account fails to open a session */
2697 {"session-error", "password", "Session Error", 1026},
2698 /* This account can't establish credentials */
2699 {"cred-error", "password", "Cred Error", 1027},
2700 /* This account has expired credentials */
2701 {"cred-expired", "password", "Cred Expired", 1028},
2702 /* This account has cannot access their credentials */
2703 {"cred-unavail", "password", "Cred Unavail", 1029},
2704 /* This account sends informational messages for each PAM function that is called */
2705 {"log-pam", "password", "Log PAM", 1030},
2706 /* This account shows multiple prompts on login */
2707 {"multi-prompt", "password", "Multi Prompt", 1031},
2708 /* This account has an existing corrupt X authority */
2709 {"corrupt-xauth", "password", "Corrupt Xauthority", 1032},
2710 /* User to test properties */
2711 {"prop-user", "", "TEST", 1033},
2712 {NULL, NULL, NULL, 0}
2714 passwd_data = g_string_new ("");
2715 group_data = g_string_new ("");
2716 for (i = 0; users[i].user_name; i++)
2718 GKeyFile *dmrc_file;
2719 gboolean save_dmrc = FALSE;
2721 if (strcmp (users[i].user_name, "mount-home-dir") != 0 && strcmp (users[i].user_name, "make-home-dir") != 0)
2723 path = g_build_filename (home_dir, users[i].user_name, NULL);
2724 g_mkdir_with_parents (path, 0755);
2725 if (chown (path, users[i].uid, users[i].uid) < 0)
2726 g_debug ("chown (%s) failed: %s", path, strerror (errno));
2730 dmrc_file = g_key_file_new ();
2731 if (strcmp (users[i].user_name, "have-session") == 0)
2733 g_key_file_set_string (dmrc_file, "Desktop", "Session", "alternative");
2736 if (strcmp (users[i].user_name, "have-layout") == 0)
2738 g_key_file_set_string (dmrc_file, "Desktop", "Layout", "us");
2741 if (strcmp (users[i].user_name, "have-layouts") == 0)
2743 g_key_file_set_string (dmrc_file, "Desktop", "Layout", "ru");
2744 g_key_file_set_string (dmrc_file, "X-Accounts", "Layouts", "fr\toss;ru;");
2747 if (strcmp (users[i].user_name, "have-language") == 0)
2749 g_key_file_set_string (dmrc_file, "Desktop", "Language", "en_AU.utf8");
2757 path = g_build_filename (home_dir, users[i].user_name, ".dmrc", NULL);
2758 data = g_key_file_to_data (dmrc_file, NULL, NULL);
2759 g_file_set_contents (path, data, -1, NULL);
2764 g_key_file_free (dmrc_file);
2766 /* Write corrupt X authority file */
2767 if (strcmp (users[i].user_name, "corrupt-xauth") == 0)
2769 gchar data[1] = { 0xFF };
2771 path = g_build_filename (home_dir, users[i].user_name, ".Xauthority", NULL);
2772 g_file_set_contents (path, data, 1, NULL);
2773 chmod (path, S_IRUSR | S_IWUSR);
2777 /* Add passwd file entry */
2778 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);
2780 /* Add group file entry */
2781 g_string_append_printf (group_data, "%s:x:%d:%s\n", users[i].user_name, users[i].uid, users[i].user_name);
2783 path = g_build_filename (temp_dir, "etc", "passwd", NULL);
2784 g_file_set_contents (path, passwd_data->str, -1, NULL);
2786 g_string_free (passwd_data, TRUE);
2788 /* Add an extra test group */
2789 g_string_append_printf (group_data, "test-group:x:111:\n");
2791 path = g_build_filename (temp_dir, "etc", "group", NULL);
2792 g_file_set_contents (path, group_data->str, -1, NULL);
2794 g_string_free (group_data, TRUE);
2796 if (g_key_file_has_key (config, "test-runner-config", "timeout", NULL))
2797 status_timeout_ms = g_key_file_get_integer (config, "test-runner-config", "timeout", NULL) * 1000;
2799 /* Start D-Bus services */
2800 if (!g_key_file_get_boolean (config, "test-runner-config", "disable-upower", NULL))
2801 start_upower_daemon ();
2802 if (!g_key_file_get_boolean (config, "test-runner-config", "disable-console-kit", NULL))
2803 start_console_kit_daemon ();
2804 if (!g_key_file_get_boolean (config, "test-runner-config", "disable-login1", NULL))
2805 start_login1_daemon ();
2806 if (!g_key_file_get_boolean (config, "test-runner-config", "disable-accounts-service", NULL))
2807 start_accounts_service_daemon ();
2809 /* Listen for daemon bus events */
2810 if (g_key_file_get_boolean (config, "test-runner-config", "log-dbus", NULL))
2812 g_dbus_connection_signal_subscribe (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
2813 "org.freedesktop.DisplayManager",
2814 "org.freedesktop.DBus.Properties",
2815 "PropertiesChanged",
2818 G_DBUS_SIGNAL_FLAGS_NONE,
2819 properties_changed_cb,
2822 g_dbus_connection_signal_subscribe (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
2823 "org.freedesktop.DisplayManager",
2824 "org.freedesktop.DisplayManager",
2828 G_DBUS_SIGNAL_FLAGS_NONE,
2834 g_main_loop_run (loop);
2836 return EXIT_FAILURE;