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;
113 gchar *active_session;
116 static GList *login1_seats = NULL;
118 static Login1Seat *add_login1_seat (GDBusConnection *connection, const gchar *id, gboolean emit_signal);
119 static Login1Seat *find_login1_seat (const gchar *id);
120 static void remove_login1_seat (GDBusConnection *connection, const gchar *id);
130 static GList *login1_sessions = NULL;
131 static gint login1_session_index = 0;
138 static GList *status_clients = NULL;
140 static void ready (void);
141 static void quit (int status);
142 static gboolean status_timeout_cb (gpointer data);
143 static void check_status (const gchar *status);
144 static AccountsUser *get_accounts_user_by_uid (guint uid);
145 static AccountsUser *get_accounts_user_by_name (const gchar *username);
146 static void accounts_user_set_hidden (AccountsUser *user, gboolean hidden, gboolean emit_signal);
147 static Login1Session *find_login1_session (const gchar *id);
150 kill_timeout_cb (gpointer data)
152 Process *process = data;
154 process->kill_timeout = 0;
156 if (getenv ("DEBUG"))
157 g_print ("Sending SIGKILL to process %d\n", process->pid);
158 kill (process->pid, SIGKILL);
164 stop_process (Process *process)
166 if (process->kill_timeout != 0)
169 if (getenv ("DEBUG"))
170 g_print ("Sending SIGTERM to process %d\n", process->pid);
171 kill (process->pid, SIGTERM);
172 process->kill_timeout = g_timeout_add (KILL_TIMEOUT, kill_timeout_cb, process);
176 process_exit_cb (GPid pid, gint status, gpointer data)
181 if (getenv ("DEBUG"))
183 if (WIFEXITED (status))
184 g_print ("Process %d exited with status %d\n", pid, WEXITSTATUS (status));
186 g_print ("Process %d terminated with signal %d\n", pid, WTERMSIG (status));
189 if (lightdm_process && pid == lightdm_process->pid)
191 process = lightdm_process;
192 lightdm_process = NULL;
193 if (WIFEXITED (status))
194 status_text = g_strdup_printf ("RUNNER DAEMON-EXIT STATUS=%d", WEXITSTATUS (status));
196 status_text = g_strdup_printf ("RUNNER DAEMON-TERMINATE SIGNAL=%d", WTERMSIG (status));
197 check_status (status_text);
201 process = g_hash_table_lookup (children, GINT_TO_POINTER (pid));
204 g_hash_table_remove (children, GINT_TO_POINTER (pid));
207 if (process->kill_timeout)
208 g_source_remove (process->kill_timeout);
209 process->kill_timeout = 0;
211 /* Quit once all children have stopped */
217 watch_process (pid_t pid)
221 process = g_malloc0 (sizeof (Process));
223 process->kill_timeout = 0;
225 if (getenv ("DEBUG"))
226 g_print ("Watching process %d\n", process->pid);
227 g_child_watch_add (process->pid, process_exit_cb, NULL);
238 exit_status = status;
241 /* Stop all the children */
242 g_hash_table_iter_init (&iter, children);
247 if (!g_hash_table_iter_next (&iter, &key, &value))
250 stop_process ((Process *)value);
253 /* Don't quit until all children are stopped */
254 if (g_hash_table_size (children) > 0)
257 /* Stop the daemon */
260 stop_process (lightdm_process);
264 if (status_socket_name)
265 unlink (status_socket_name);
267 if (temp_dir && getenv ("DEBUG") == NULL)
269 gchar *command = g_strdup_printf ("rm -rf %s", temp_dir);
270 if (system (command))
271 perror ("Failed to delete temp directory");
278 fail (const gchar *event, const gchar *expected)
285 g_printerr ("Command line: %s", test_runner_command);
286 g_printerr ("Events:\n");
287 for (link = statuses; link; link = link->next)
288 g_printerr (" %s\n", (gchar *)link->data);
290 g_printerr (" %s\n", event);
292 g_printerr (" ^^^ expected \"%s\"\n", expected);
294 g_printerr ("^^^ expected nothing\n");
300 get_prefix (const gchar *text)
305 prefix = g_strdup (text);
306 for (i = 0; prefix[i] != '\0' && prefix[i] != ' '; i++);
313 get_script_line (const gchar *prefix)
317 for (link = script; link; link = link->next)
319 ScriptLine *line = link->data;
321 /* Ignore lines with other prefixes */
327 p = get_prefix (line->text);
328 matches = strcmp (prefix, p) == 0;
343 stop_loop (gpointer user_data)
345 g_main_loop_quit ((GMainLoop *)user_data);
346 return G_SOURCE_REMOVE;
350 switch_to_greeter_done_cb (GObject *bus, GAsyncResult *result, gpointer data)
353 GError *error = NULL;
355 r = g_dbus_connection_call_finish (G_DBUS_CONNECTION (bus), result, &error);
357 g_warning ("Failed to switch to greeter: %s\n", error->message);
358 g_clear_error (&error);
362 check_status ("RUNNER SWITCH-TO-GREETER");
366 check_status ("RUNNER SWITCH-TO-GREETER FAILED");
370 switch_to_user_done_cb (GObject *bus, GAsyncResult *result, gpointer data)
373 GError *error = NULL;
374 gchar *username = data, *status_text;
376 r = g_dbus_connection_call_finish (G_DBUS_CONNECTION (bus), result, &error);
378 g_warning ("Failed to switch to user: %s\n", error->message);
379 g_clear_error (&error);
383 status_text = g_strdup_printf ("RUNNER SWITCH-TO-USER USERNAME=%s", username);
387 status_text = g_strdup_printf ("RUNNER SWITCH-TO-USER USERNAME=%s FAILED", username);
388 check_status (status_text);
390 g_free (status_text);
395 switch_to_guest_done_cb (GObject *bus, GAsyncResult *result, gpointer data)
398 GError *error = NULL;
400 r = g_dbus_connection_call_finish (G_DBUS_CONNECTION (bus), result, &error);
402 g_warning ("Failed to switch to guest: %s\n", error->message);
403 g_clear_error (&error);
407 check_status ("RUNNER SWITCH-TO-GUEST");
411 check_status ("RUNNER SWITCH-TO-GUEST FAILED");
415 handle_command (const gchar *command)
422 while (*c && !isspace (*c))
424 name = g_strdup_printf ("%.*s", (int) (c - command), command);
426 params = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
430 gchar *param_name, *param_value;
435 while (*c && !isspace (*c) && *c != '=')
440 param_name = g_strdup_printf ("%.*s", (int) (c - start), start);
449 gboolean escaped = FALSE;
453 value = g_string_new ("");
460 g_string_append_c (value, '\\');
466 else if (!escaped && *c == '\"')
469 g_string_append_c (value, *c);
472 param_value = value->str;
473 g_string_free (value, FALSE);
480 while (*c && !isspace (*c))
482 param_value = g_strdup_printf ("%.*s", (int) (c - start), start);
486 param_value = g_strdup ("");
488 g_hash_table_insert (params, param_name, param_value);
491 if (strcmp (name, "START-DAEMON") == 0)
493 GString *command_line;
494 gchar **lightdm_argv;
496 GError *error = NULL;
498 command_line = g_string_new ("lightdm");
499 if (getenv ("DEBUG"))
500 g_string_append (command_line, " --debug");
501 g_string_append_printf (command_line, " --cache-dir %s/cache", temp_dir);
503 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",
504 g_getenv ("PATH"), g_getenv ("LD_PRELOAD"), g_getenv ("LD_LIBRARY_PATH"), g_getenv ("LIGHTDM_TEST_ROOT"), g_getenv ("DBUS_SESSION_BUS_ADDRESS"),
507 if (!g_shell_parse_argv (command_line->str, NULL, &lightdm_argv, &error))
509 g_warning ("Error parsing command line: %s", error->message);
512 g_clear_error (&error);
514 if (!g_spawn_async (NULL, lightdm_argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL, NULL, &lightdm_pid, &error))
516 g_warning ("Error launching LightDM: %s", error->message);
519 g_clear_error (&error);
520 lightdm_process = watch_process (lightdm_pid);
522 check_status ("RUNNER DAEMON-START");
524 else if (strcmp (name, "WAIT") == 0)
529 /* Stop status timeout */
531 g_source_remove (status_timeout);
534 /* Use a main loop so that our DBus functions are still responsive */
535 GMainLoop *loop = g_main_loop_new (NULL, FALSE);
536 v = g_hash_table_lookup (params, "DURATION");
537 duration = v ? atoi (v) : 1;
540 g_timeout_add_seconds (duration, stop_loop, loop);
541 g_main_loop_run (loop);
542 g_main_loop_unref (loop);
544 /* Restart status timeout */
545 status_timeout = g_timeout_add (status_timeout_ms, status_timeout_cb, NULL);
547 else if (strcmp (name, "ADD-SEAT") == 0)
552 id = g_hash_table_lookup (params, "ID");
553 seat = add_login1_seat (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL), id, TRUE);
554 v = g_hash_table_lookup (params, "CAN-GRAPHICAL");
556 seat->can_graphical = strcmp (v, "TRUE") == 0;
557 v = g_hash_table_lookup (params, "CAN-MULTI-SESSION");
559 seat->can_multi_session = strcmp (v, "TRUE") == 0;
561 else if (strcmp (name, "ADD-LOCAL-X-SEAT") == 0)
566 v = g_hash_table_lookup (params, "DISPLAY");
567 result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
568 "org.freedesktop.DisplayManager",
569 "/org/freedesktop/DisplayManager",
570 "org.freedesktop.DisplayManager",
572 g_variant_new ("(i)", v ? atoi (v) : -1),
573 G_VARIANT_TYPE ("(o)"),
574 G_DBUS_CALL_FLAGS_NONE,
578 g_variant_unref (result);
580 else if (strcmp (name, "UPDATE-SEAT") == 0)
585 id = g_hash_table_lookup (params, "ID");
586 seat = find_login1_seat (id);
590 GVariantBuilder invalidated_properties;
591 GError *error = NULL;
593 g_variant_builder_init (&invalidated_properties, G_VARIANT_TYPE_ARRAY);
595 v = g_hash_table_lookup (params, "CAN-GRAPHICAL");
598 seat->can_graphical = strcmp (v, "TRUE") == 0;
599 g_variant_builder_add (&invalidated_properties, "s", "CanGraphical");
601 v = g_hash_table_lookup (params, "CAN-MULTI-SESSION");
604 seat->can_multi_session = strcmp (v, "TRUE") == 0;
605 g_variant_builder_add (&invalidated_properties, "s", "CanMultiSession");
607 v = g_hash_table_lookup (params, "ACTIVE-SESSION");
610 g_free (seat->active_session);
611 seat->active_session = g_strdup (v);
612 g_variant_builder_add (&invalidated_properties, "s", "ActiveSession");
615 g_dbus_connection_emit_signal (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
618 "org.freedesktop.DBus.Properties",
620 g_variant_new ("(sa{sv}as)", "org.freedesktop.login1.Seat", NULL, &invalidated_properties),
623 g_warning ("Failed to emit PropertiesChanged: %s", error->message);
624 g_clear_error (&error);
627 else if (strcmp (name, "REMOVE-SEAT") == 0)
630 id = g_hash_table_lookup (params, "ID");
631 remove_login1_seat (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL), id);
633 else if (strcmp (name, "LIST-SEATS") == 0)
635 GVariant *result, *value;
641 result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
642 "org.freedesktop.DisplayManager",
643 "/org/freedesktop/DisplayManager",
644 "org.freedesktop.DBus.Properties",
646 g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Seats"),
647 G_VARIANT_TYPE ("(v)"),
648 G_DBUS_CALL_FLAGS_NONE,
653 status = g_string_new ("RUNNER LIST-SEATS SEATS=");
654 g_variant_get (result, "(v)", &value);
655 g_variant_get (value, "ao", &iter);
656 while (g_variant_iter_loop (iter, "&o", &path))
659 g_string_append (status, ",");
660 g_string_append (status, path);
663 g_variant_unref (value);
664 g_variant_unref (result);
666 check_status (status->str);
667 g_string_free (status, TRUE);
669 else if (strcmp (name, "LIST-SESSIONS") == 0)
671 GVariant *result, *value;
677 result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
678 "org.freedesktop.DisplayManager",
679 "/org/freedesktop/DisplayManager",
680 "org.freedesktop.DBus.Properties",
682 g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Sessions"),
683 G_VARIANT_TYPE ("(v)"),
684 G_DBUS_CALL_FLAGS_NONE,
689 status = g_string_new ("RUNNER LIST-SESSIONS SESSIONS=");
690 g_variant_get (result, "(v)", &value);
691 g_variant_get (value, "ao", &iter);
692 while (g_variant_iter_loop (iter, "&o", &path))
695 g_string_append (status, ",");
696 g_string_append (status, path);
699 g_variant_unref (value);
700 g_variant_unref (result);
702 check_status (status->str);
703 g_string_free (status, TRUE);
705 else if (strcmp (name, "SEAT-CAN-SWITCH") == 0)
707 GVariant *result, *value;
710 result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
711 "org.freedesktop.DisplayManager",
712 "/org/freedesktop/DisplayManager/Seat0",
713 "org.freedesktop.DBus.Properties",
715 g_variant_new ("(ss)", "org.freedesktop.DisplayManager.Seat", "CanSwitch"),
716 G_VARIANT_TYPE ("(v)"),
717 G_DBUS_CALL_FLAGS_NONE,
722 g_variant_get (result, "(v)", &value);
723 status = g_strdup_printf ("RUNNER SEAT-CAN-SWITCH CAN-SWITCH=%s", g_variant_get_boolean (value) ? "TRUE" : "FALSE");
724 g_variant_unref (value);
725 g_variant_unref (result);
726 check_status (status);
729 else if (strcmp (name, "SEAT-HAS-GUEST-ACCOUNT") == 0)
731 GVariant *result, *value;
734 result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
735 "org.freedesktop.DisplayManager",
736 "/org/freedesktop/DisplayManager/Seat0",
737 "org.freedesktop.DBus.Properties",
739 g_variant_new ("(ss)", "org.freedesktop.DisplayManager.Seat", "HasGuestAccount"),
740 G_VARIANT_TYPE ("(v)"),
741 G_DBUS_CALL_FLAGS_NONE,
746 g_variant_get (result, "(v)", &value);
747 status = g_strdup_printf ("RUNNER SEAT-HAS-GUEST-ACCOUNT HAS-GUEST-ACCOUNT=%s", g_variant_get_boolean (value) ? "TRUE" : "FALSE");
748 g_variant_unref (value);
749 g_variant_unref (result);
750 check_status (status);
753 else if (strcmp (name, "SWITCH-TO-GREETER") == 0)
755 g_dbus_connection_call (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
756 "org.freedesktop.DisplayManager",
757 "/org/freedesktop/DisplayManager/Seat0",
758 "org.freedesktop.DisplayManager.Seat",
760 g_variant_new ("()"),
761 G_VARIANT_TYPE ("()"),
762 G_DBUS_CALL_FLAGS_NONE,
765 switch_to_greeter_done_cb,
768 else if (strcmp (name, "SWITCH-TO-USER") == 0)
770 const gchar *username;
772 username = g_hash_table_lookup (params, "USERNAME");
773 g_dbus_connection_call (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
774 "org.freedesktop.DisplayManager",
775 "/org/freedesktop/DisplayManager/Seat0",
776 "org.freedesktop.DisplayManager.Seat",
778 g_variant_new ("(ss)", username, ""),
779 G_VARIANT_TYPE ("()"),
780 G_DBUS_CALL_FLAGS_NONE,
783 switch_to_user_done_cb,
784 g_strdup (username));
786 else if (strcmp (name, "SWITCH-TO-GUEST") == 0)
788 g_dbus_connection_call (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
789 "org.freedesktop.DisplayManager",
790 "/org/freedesktop/DisplayManager/Seat0",
791 "org.freedesktop.DisplayManager.Seat",
793 g_variant_new ("(s)", ""),
794 G_VARIANT_TYPE ("()"),
795 G_DBUS_CALL_FLAGS_NONE,
798 switch_to_guest_done_cb,
801 else if (strcmp (name, "STOP-DAEMON") == 0)
802 stop_process (lightdm_process);
803 // FIXME: Make generic RUN-COMMAND
804 else if (strcmp (name, "START-XSERVER") == 0)
806 gchar *xserver_args, *command_line;
810 GError *error = NULL;
812 xserver_args = g_hash_table_lookup (params, "ARGS");
815 command_line = g_strdup_printf ("%s/tests/src/X %s", BUILDDIR, xserver_args);
817 if (!g_shell_parse_argv (command_line, NULL, &argv, &error) ||
818 !g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &error))
820 g_printerr ("Error starting X server: %s", error->message);
825 process = watch_process (pid);
826 g_hash_table_insert (children, GINT_TO_POINTER (process->pid), process);
829 else if (strcmp (name, "START-VNC-CLIENT") == 0)
831 gchar *vnc_client_args, *command_line;
835 GError *error = NULL;
837 vnc_client_args = g_hash_table_lookup (params, "ARGS");
838 if (!vnc_client_args)
839 vnc_client_args = "";
840 command_line = g_strdup_printf ("%s/tests/src/vnc-client %s", BUILDDIR, vnc_client_args);
842 if (!g_shell_parse_argv (command_line, NULL, &argv, &error) ||
843 !g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &error))
845 g_printerr ("Error starting VNC client: %s", error->message);
850 process = watch_process (pid);
851 g_hash_table_insert (children, GINT_TO_POINTER (process->pid), process);
854 else if (strcmp (name, "ADD-USER") == 0)
856 gchar *status_text, *username;
859 username = g_hash_table_lookup (params, "USERNAME");
860 user = get_accounts_user_by_name (username);
862 accounts_user_set_hidden (user, FALSE, TRUE);
864 g_warning ("Unknown user %s", username);
866 status_text = g_strdup_printf ("RUNNER ADD-USER USERNAME=%s", username);
867 check_status (status_text);
868 g_free (status_text);
870 else if (strcmp (name, "UPDATE-USER") == 0)
872 GString *status_text;
875 GError *error = NULL;
877 status_text = g_string_new ("RUNNER UPDATE-USER USERNAME=");
879 username = g_hash_table_lookup (params, "USERNAME");
880 g_string_append (status_text, username);
881 user = get_accounts_user_by_name (username);
884 if (g_hash_table_lookup (params, "NAME"))
886 user->user_name = g_strdup (g_hash_table_lookup (params, "NAME"));
887 g_string_append_printf (status_text, " NAME=%s", user->user_name);
889 if (g_hash_table_lookup (params, "REAL-NAME"))
891 user->real_name = g_strdup (g_hash_table_lookup (params, "REAL-NAME"));
892 g_string_append_printf (status_text, " REAL-NAME=%s", user->real_name);
894 if (g_hash_table_lookup (params, "HOME-DIRECTORY"))
896 user->home_directory = g_strdup (g_hash_table_lookup (params, "HOME-DIRECTORY"));
897 g_string_append_printf (status_text, " HOME-DIRECTORY=%s", user->home_directory);
899 if (g_hash_table_lookup (params, "IMAGE"))
901 user->image = g_strdup (g_hash_table_lookup (params, "IMAGE"));
902 g_string_append_printf (status_text, " IMAGE=%s", user->image);
904 if (g_hash_table_lookup (params, "BACKGROUND"))
906 user->background = g_strdup (g_hash_table_lookup (params, "BACKGROUND"));
907 g_string_append_printf (status_text, " BACKGROUND=%s", user->background);
909 if (g_hash_table_lookup (params, "LANGUAGE"))
911 user->language = g_strdup (g_hash_table_lookup (params, "LANGUAGE"));
912 g_string_append_printf (status_text, " LANGUAGE=%s", user->language);
914 if (g_hash_table_lookup (params, "LAYOUTS"))
916 const gchar *value = g_hash_table_lookup (params, "LAYOUTS");
917 user->layouts = g_strsplit (value, ";", -1);
918 g_string_append_printf (status_text, " LAYOUTS=%s", value);
920 if (g_hash_table_lookup (params, "HAS-MESSAGES"))
922 user->has_messages = g_strcmp0 (g_hash_table_lookup (params, "HAS-MESSAGES"), "TRUE") == 0;
923 g_string_append_printf (status_text, " HAS-MESSAGES=%s", user->has_messages ? "TRUE" : "FALSE");
925 if (g_hash_table_lookup (params, "SESSION"))
927 user->xsession = g_strdup (g_hash_table_lookup (params, "SESSION"));
928 g_string_append_printf (status_text, " SESSION=%s", user->xsession);
931 g_dbus_connection_emit_signal (accounts_connection,
934 "org.freedesktop.Accounts.User",
936 g_variant_new ("()"),
940 g_warning ("Unknown user %s", username);
943 g_warning ("Failed to emit Changed: %s", error->message);
944 g_clear_error (&error);
946 check_status (status_text->str);
947 g_string_free (status_text, TRUE);
949 else if (strcmp (name, "DELETE-USER") == 0)
951 gchar *status_text, *username;
954 username = g_hash_table_lookup (params, "USERNAME");
955 user = get_accounts_user_by_name (username);
957 accounts_user_set_hidden (user, TRUE, TRUE);
959 g_warning ("Unknown user %s", username);
961 status_text = g_strdup_printf ("RUNNER DELETE-USER USERNAME=%s", username);
962 check_status (status_text);
963 g_free (status_text);
965 else if (strcmp (name, "UNLOCK-SESSION") == 0)
967 gchar *status_text, *id;
968 Login1Session *session;
970 id = g_hash_table_lookup (params, "SESSION");
971 session = find_login1_session (id);
974 if (!session->locked)
975 g_warning ("Session %s is not locked", id);
976 session->locked = FALSE;
979 g_warning ("Unknown session %s", id);
981 status_text = g_strdup_printf ("RUNNER UNLOCK-SESSION SESSION=%s", id);
982 check_status (status_text);
983 g_free (status_text);
985 /* Forward to external processes */
986 else if (g_str_has_prefix (name, "SESSION-") ||
987 g_str_has_prefix (name, "GREETER-") ||
988 g_str_has_prefix (name, "XSERVER-") ||
989 g_str_has_prefix (name, "XMIR-") ||
990 g_str_has_prefix (name, "XVNC-") ||
991 strcmp (name, "UNITY-SYSTEM-COMPOSITOR") == 0)
994 for (link = status_clients; link; link = link->next)
996 StatusClient *client = link->data;
998 GError *error = NULL;
1000 length = strlen (command);
1001 if (g_socket_send (client->socket, (gchar *) &length, sizeof (length), NULL, &error) < 0 ||
1002 g_socket_send (client->socket, command, strlen (command), NULL, &error) < 0)
1003 g_printerr ("Failed to write to client socket: %s\n", error->message);
1004 g_clear_error (&error);
1009 g_printerr ("Unknown command '%s'\n", name);
1010 quit (EXIT_FAILURE);
1014 g_hash_table_unref (params);
1020 /* Stop daemon if requested */
1025 /* Commands start with an asterisk */
1026 line = get_script_line (NULL);
1027 if (!line || line->text[0] != '*')
1030 statuses = g_list_append (statuses, g_strdup (line->text));
1033 handle_command (line->text + 1);
1036 /* Stop at the end of the script */
1037 if (get_script_line (NULL) == NULL)
1038 quit (EXIT_SUCCESS);
1042 status_timeout_cb (gpointer data)
1048 line = get_script_line (NULL);
1049 fail ("(timeout)", line ? line->text : NULL);
1051 return G_SOURCE_REMOVE;
1055 check_status (const gchar *status)
1058 gboolean result = FALSE;
1064 statuses = g_list_append (statuses, g_strdup (status));
1066 if (getenv ("DEBUG"))
1067 g_print ("%s\n", status);
1069 /* Try and match against expected */
1070 prefix = get_prefix (status);
1071 line = get_script_line (prefix);
1075 gchar *full_pattern = g_strdup_printf ("^%s$", line->text);
1076 result = g_regex_match_simple (full_pattern, status, 0, 0);
1077 g_free (full_pattern);
1083 line = get_script_line (NULL);
1084 fail (NULL, line ? line->text : NULL);
1090 /* Restart timeout */
1092 g_source_remove (status_timeout);
1093 status_timeout = g_timeout_add (status_timeout_ms, status_timeout_cb, NULL);
1099 status_message_cb (GSocket *socket, GIOCondition condition, StatusClient *client)
1104 GError *error = NULL;
1106 n_read = g_socket_receive (socket, (gchar *)&length, sizeof (length), NULL, &error);
1108 n_read = g_socket_receive (socket, buffer, length, NULL, &error);
1111 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED))
1114 g_warning ("Error reading from socket: %s", error->message);
1116 g_clear_error (&error);
1119 status_clients = g_list_remove (status_clients, client);
1120 g_object_unref (client->socket);
1124 else if (n_read > 0)
1126 buffer[n_read] = '\0';
1127 check_status (buffer);
1134 status_connect_cb (gpointer data)
1137 GError *error = NULL;
1139 socket = g_socket_accept (status_socket, NULL, &error);
1141 g_warning ("Failed to accept status connection: %s", error->message);
1142 g_clear_error (&error);
1145 StatusClient *client;
1147 client = g_malloc0 (sizeof (StatusClient));
1148 client->socket = socket;
1149 client->source = g_socket_create_source (socket, G_IO_IN, NULL);
1150 status_clients = g_list_append (status_clients, client);
1152 g_source_set_callback (client->source, (GSourceFunc) status_message_cb, client, NULL);
1153 g_source_attach (client->source, NULL);
1160 load_script (const gchar *filename)
1163 gchar *data, **lines;
1165 if (!g_file_get_contents (filename, &data, NULL, NULL))
1167 g_printerr ("Unable to load script: %s\n", filename);
1168 quit (EXIT_FAILURE);
1171 lines = g_strsplit (data, "\n", -1);
1174 /* Load lines with #? prefix as expected behaviour */
1175 for (i = 0; lines[i]; i++)
1177 gchar *text = g_strstrip (lines[i]);
1178 if (g_str_has_prefix (text, "#?"))
1181 line = g_malloc0 (sizeof (ScriptLine));
1182 line->text = g_strdup (text + 2);
1184 script = g_list_append (script, line);
1191 handle_upower_call (GDBusConnection *connection,
1192 const gchar *sender,
1193 const gchar *object_path,
1194 const gchar *interface_name,
1195 const gchar *method_name,
1196 GVariant *parameters,
1197 GDBusMethodInvocation *invocation,
1200 if (strcmp (method_name, "SuspendAllowed") == 0)
1202 check_status ("UPOWER SUSPEND-ALLOWED");
1203 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
1205 else if (strcmp (method_name, "Suspend") == 0)
1207 check_status ("UPOWER SUSPEND");
1208 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1210 else if (strcmp (method_name, "HibernateAllowed") == 0)
1212 check_status ("UPOWER HIBERNATE-ALLOWED");
1213 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
1215 else if (strcmp (method_name, "Hibernate") == 0)
1217 check_status ("UPOWER HIBERNATE");
1218 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1221 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1225 upower_name_acquired_cb (GDBusConnection *connection,
1229 const gchar *upower_interface =
1231 " <interface name='org.freedesktop.UPower'>"
1232 " <method name='SuspendAllowed'>"
1233 " <arg name='allowed' direction='out' type='b'/>"
1235 " <method name='Suspend'/>"
1236 " <method name='HibernateAllowed'>"
1237 " <arg name='allowed' direction='out' type='b'/>"
1239 " <method name='Hibernate'/>"
1242 static const GDBusInterfaceVTable upower_vtable =
1246 GDBusNodeInfo *upower_info;
1247 GError *error = NULL;
1249 upower_info = g_dbus_node_info_new_for_xml (upower_interface, &error);
1251 g_warning ("Failed to parse D-Bus interface: %s", error->message);
1252 g_clear_error (&error);
1255 g_dbus_connection_register_object (connection,
1256 "/org/freedesktop/UPower",
1257 upower_info->interfaces[0],
1262 g_warning ("Failed to register UPower service: %s", error->message);
1263 g_clear_error (&error);
1264 g_dbus_node_info_unref (upower_info);
1267 if (service_count == 0)
1272 start_upower_daemon (void)
1275 g_bus_own_name (G_BUS_TYPE_SYSTEM,
1276 "org.freedesktop.UPower",
1277 G_BUS_NAME_OWNER_FLAGS_NONE,
1278 upower_name_acquired_cb,
1286 open_ck_session (GDBusConnection *connection, GVariant *params)
1293 GError *error = NULL;
1295 session = g_malloc0 (sizeof (CKSession));
1296 ck_sessions = g_list_append (ck_sessions, session);
1298 cookie = g_string_new ("ck-cookie");
1299 g_variant_get (params, "a(sv)", &iter);
1300 while (g_variant_iter_loop (iter, "(&sv)", &name, &value))
1302 if (strcmp (name, "x11-display") == 0)
1304 const gchar *display;
1305 g_variant_get (value, "&s", &display);
1306 g_string_append_printf (cookie, "-x%s", display);
1310 session->cookie = cookie->str;
1311 g_string_free (cookie, FALSE);
1312 session->path = g_strdup_printf ("/org/freedesktop/ConsoleKit/Session%d", ck_session_index++);
1313 session->id = g_dbus_connection_register_object (connection,
1315 ck_session_info->interfaces[0],
1321 g_warning ("Failed to register CK Session: %s", error->message);
1322 g_clear_error (&error);
1328 handle_ck_call (GDBusConnection *connection,
1329 const gchar *sender,
1330 const gchar *object_path,
1331 const gchar *interface_name,
1332 const gchar *method_name,
1333 GVariant *parameters,
1334 GDBusMethodInvocation *invocation,
1337 if (strcmp (method_name, "CanRestart") == 0)
1339 check_status ("CONSOLE-KIT CAN-RESTART");
1340 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
1342 else if (strcmp (method_name, "CanStop") == 0)
1344 check_status ("CONSOLE-KIT CAN-STOP");
1345 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
1347 else if (strcmp (method_name, "CloseSession") == 0)
1348 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
1349 else if (strcmp (method_name, "OpenSession") == 0)
1351 GVariantBuilder params;
1352 g_variant_builder_init (¶ms, G_VARIANT_TYPE ("a(sv)"));
1353 CKSession *session = open_ck_session (connection, g_variant_builder_end (¶ms));
1354 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", session->cookie));
1356 else if (strcmp (method_name, "OpenSessionWithParameters") == 0)
1358 CKSession *session = open_ck_session (connection, g_variant_get_child_value (parameters, 0));
1359 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", session->cookie));
1361 else if (strcmp (method_name, "GetSessionForCookie") == 0)
1366 g_variant_get (parameters, "(&s)", &cookie);
1368 for (link = ck_sessions; link; link = link->next)
1370 CKSession *session = link->data;
1371 if (strcmp (session->cookie, cookie) == 0)
1373 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", session->path));
1378 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Unable to find session for cookie");
1380 else if (strcmp (method_name, "Restart") == 0)
1382 check_status ("CONSOLE-KIT RESTART");
1383 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1385 else if (strcmp (method_name, "Stop") == 0)
1387 check_status ("CONSOLE-KIT STOP");
1388 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1391 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1395 handle_ck_session_call (GDBusConnection *connection,
1396 const gchar *sender,
1397 const gchar *object_path,
1398 const gchar *interface_name,
1399 const gchar *method_name,
1400 GVariant *parameters,
1401 GDBusMethodInvocation *invocation,
1404 CKSession *session = user_data;
1406 if (strcmp (method_name, "GetXDGRuntimeDir") == 0 && !g_key_file_get_boolean (config, "test-runner-config", "ck-no-xdg-runtime", NULL))
1408 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "/run/console-kit"));
1410 else if (strcmp (method_name, "Lock") == 0)
1412 if (!session->locked)
1413 check_status ("CONSOLE-KIT LOCK-SESSION");
1414 session->locked = TRUE;
1415 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1417 else if (strcmp (method_name, "Unlock") == 0)
1419 if (session->locked)
1420 check_status ("CONSOLE-KIT UNLOCK-SESSION");
1421 session->locked = FALSE;
1422 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1424 else if (strcmp (method_name, "Activate") == 0)
1426 gchar *status = g_strdup_printf ("CONSOLE-KIT ACTIVATE-SESSION SESSION=%s", session->cookie);
1427 check_status (status);
1430 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1433 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1437 ck_name_acquired_cb (GDBusConnection *connection,
1441 const gchar *ck_interface =
1443 " <interface name='org.freedesktop.ConsoleKit.Manager'>"
1444 " <method name='CanRestart'>"
1445 " <arg name='can_restart' direction='out' type='b'/>"
1447 " <method name='CanStop'>"
1448 " <arg name='can_stop' direction='out' type='b'/>"
1450 " <method name='CloseSession'>"
1451 " <arg name='cookie' direction='in' type='s'/>"
1452 " <arg name='result' direction='out' type='b'/>"
1454 " <method name='OpenSession'>"
1455 " <arg name='cookie' direction='out' type='s'/>"
1457 " <method name='OpenSessionWithParameters'>"
1458 " <arg name='parameters' direction='in' type='a(sv)'/>"
1459 " <arg name='cookie' direction='out' type='s'/>"
1461 " <method name='GetSessionForCookie'>"
1462 " <arg name='cookie' direction='in' type='s'/>"
1463 " <arg name='ssid' direction='out' type='o'/>"
1465 " <method name='Restart'/>"
1466 " <method name='Stop'/>"
1467 " <signal name='SeatAdded'>"
1468 " <arg name='seat' type='o'/>"
1470 " <signal name='SeatRemoved'>"
1471 " <arg name='seat' type='o'/>"
1475 static const GDBusInterfaceVTable ck_vtable =
1479 const gchar *ck_session_interface_old =
1481 " <interface name='org.freedesktop.ConsoleKit.Session'>"
1482 " <method name='Lock'/>"
1483 " <method name='Unlock'/>"
1484 " <method name='Activate'/>"
1487 const gchar *ck_session_interface =
1489 " <interface name='org.freedesktop.ConsoleKit.Session'>"
1490 " <method name='GetXDGRuntimeDir'>"
1491 " <arg name='dir' direction='out' type='s'/>"
1493 " <method name='Lock'/>"
1494 " <method name='Unlock'/>"
1495 " <method name='Activate'/>"
1498 GDBusNodeInfo *ck_info;
1499 GError *error = NULL;
1501 ck_info = g_dbus_node_info_new_for_xml (ck_interface, &error);
1503 g_warning ("Failed to parse D-Bus interface: %s", error->message);
1504 g_clear_error (&error);
1507 if (g_key_file_get_boolean (config, "test-runner-config", "ck-no-xdg-runtime", NULL))
1508 ck_session_info = g_dbus_node_info_new_for_xml (ck_session_interface_old, &error);
1510 ck_session_info = g_dbus_node_info_new_for_xml (ck_session_interface, &error);
1512 g_warning ("Failed to parse D-Bus interface: %s", error->message);
1513 g_clear_error (&error);
1514 if (!ck_session_info)
1516 g_dbus_connection_register_object (connection,
1517 "/org/freedesktop/ConsoleKit/Manager",
1518 ck_info->interfaces[0],
1523 g_warning ("Failed to register console kit service: %s", error->message);
1524 g_clear_error (&error);
1525 g_dbus_node_info_unref (ck_info);
1528 if (service_count == 0)
1533 start_console_kit_daemon (void)
1536 g_bus_own_name (G_BUS_TYPE_SYSTEM,
1537 "org.freedesktop.ConsoleKit",
1538 G_BUS_NAME_OWNER_FLAGS_NONE,
1540 ck_name_acquired_cb,
1547 handle_login1_seat_call (GDBusConnection *connection,
1548 const gchar *sender,
1549 const gchar *object_path,
1550 const gchar *interface_name,
1551 const gchar *method_name,
1552 GVariant *parameters,
1553 GDBusMethodInvocation *invocation,
1556 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1560 handle_login1_seat_get_property (GDBusConnection *connection,
1561 const gchar *sender,
1562 const gchar *object_path,
1563 const gchar *interface_name,
1564 const gchar *property_name,
1568 Login1Seat *seat = user_data;
1570 if (strcmp (property_name, "CanGraphical") == 0)
1571 return g_variant_new_boolean (seat->can_graphical);
1572 else if (strcmp (property_name, "CanMultiSession") == 0)
1573 return g_variant_new_boolean (seat->can_multi_session);
1574 else if (strcmp (property_name, "Id") == 0)
1575 return g_variant_new_string (seat->id);
1576 else if (strcmp (property_name, "ActiveSession") == 0)
1578 if (seat->active_session)
1583 path = g_strdup_printf ("/org/freedesktop/login1/session/%s", seat->active_session);
1584 ret = g_variant_new ("(so)", seat->active_session, path);
1597 add_login1_seat (GDBusConnection *connection, const gchar *id, gboolean emit_signal)
1600 GError *error = NULL;
1601 GDBusNodeInfo *login1_seat_info;
1603 const gchar *login1_seat_interface =
1605 " <interface name='org.freedesktop.login1.Seat'>"
1606 " <property name='CanGraphical' type='b' access='read'/>"
1607 " <property name='CanMultiSession' type='b' access='read'/>"
1608 " <property name='ActiveSession' type='(so)' access='read'/>"
1609 " <property name='Id' type='s' access='read'/>"
1612 static const GDBusInterfaceVTable login1_seat_vtable =
1614 handle_login1_seat_call,
1615 handle_login1_seat_get_property,
1618 seat = g_malloc0 (sizeof (Login1Seat));
1619 login1_seats = g_list_append (login1_seats, seat);
1620 seat->id = g_strdup (id);
1621 seat->path = g_strdup_printf ("/org/freedesktop/login1/seat/%s", seat->id);
1622 seat->can_graphical = TRUE;
1623 seat->can_multi_session = TRUE;
1624 seat->active_session = NULL;
1626 login1_seat_info = g_dbus_node_info_new_for_xml (login1_seat_interface, &error);
1628 g_warning ("Failed to parse login1 seat D-Bus interface: %s", error->message);
1629 g_clear_error (&error);
1630 if (!login1_seat_info)
1633 g_dbus_connection_register_object (connection,
1635 login1_seat_info->interfaces[0],
1636 &login1_seat_vtable,
1641 g_warning ("Failed to register login1 seat: %s", error->message);
1642 g_clear_error (&error);
1643 g_dbus_node_info_unref (login1_seat_info);
1647 g_dbus_connection_emit_signal (connection,
1649 "/org/freedesktop/login1",
1650 "org.freedesktop.login1.Manager",
1652 g_variant_new ("(so)", seat->id, seat->path),
1655 g_warning ("Failed to emit SeatNew: %s", error->message);
1656 g_clear_error (&error);
1663 find_login1_seat (const gchar *id)
1668 for (link = login1_seats; link; link = link->next)
1671 if (strcmp (seat->id, id) == 0)
1679 remove_login1_seat (GDBusConnection *connection, const gchar *id)
1682 GError *error = NULL;
1684 seat = find_login1_seat (id);
1688 g_dbus_connection_emit_signal (connection,
1690 "/org/freedesktop/login1",
1691 "org.freedesktop.login1.Manager",
1693 g_variant_new ("(so)", seat->id, seat->path),
1696 g_warning ("Failed to emit SeatNew: %s", error->message);
1697 g_clear_error (&error);
1699 login1_seats = g_list_remove (login1_seats, seat);
1701 g_free (seat->path);
1702 g_free (seat->active_session);
1707 handle_login1_session_call (GDBusConnection *connection,
1708 const gchar *sender,
1709 const gchar *object_path,
1710 const gchar *interface_name,
1711 const gchar *method_name,
1712 GVariant *parameters,
1713 GDBusMethodInvocation *invocation,
1716 /*Login1Session *session = user_data;*/
1717 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1720 static Login1Session *
1721 create_login1_session (GDBusConnection *connection)
1723 Login1Session *session;
1724 GError *error = NULL;
1725 GDBusNodeInfo *login1_session_info;
1727 const gchar *login1_session_interface =
1729 " <interface name='org.freedesktop.login1.Session'>"
1732 static const GDBusInterfaceVTable login1_session_vtable =
1734 handle_login1_session_call,
1737 session = g_malloc0 (sizeof (Login1Session));
1738 login1_sessions = g_list_append (login1_sessions, session);
1740 session->id = g_strdup_printf ("c%d", login1_session_index++);
1741 session->path = g_strdup_printf ("/org/freedesktop/login1/Session/%s", session->id);
1743 login1_session_info = g_dbus_node_info_new_for_xml (login1_session_interface, &error);
1745 g_warning ("Failed to parse login1 session D-Bus interface: %s", error->message);
1746 g_clear_error (&error);
1747 if (!login1_session_info)
1750 g_dbus_connection_register_object (connection,
1752 login1_session_info->interfaces[0],
1753 &login1_session_vtable,
1758 g_warning ("Failed to register login1 session: %s", error->message);
1759 g_clear_error (&error);
1760 g_dbus_node_info_unref (login1_session_info);
1765 static Login1Session *
1766 find_login1_session (const gchar *id)
1770 for (link = login1_sessions; link; link = link->next)
1772 Login1Session *session = link->data;
1773 if (strcmp (session->id, id) == 0)
1781 handle_login1_call (GDBusConnection *connection,
1782 const gchar *sender,
1783 const gchar *object_path,
1784 const gchar *interface_name,
1785 const gchar *method_name,
1786 GVariant *parameters,
1787 GDBusMethodInvocation *invocation,
1790 if (strcmp (method_name, "ListSeats") == 0)
1792 GVariantBuilder seats;
1795 g_variant_builder_init (&seats, G_VARIANT_TYPE ("a(so)"));
1796 for (link = login1_seats; link; link = link->next)
1798 Login1Seat *seat = link->data;
1799 g_variant_builder_add (&seats, "(so)", seat->id, seat->path);
1801 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a(so))", &seats));
1803 else if (strcmp (method_name, "CreateSession") == 0)
1805 /* Note: this is not the full CreateSession as used by logind, we just
1806 need one so our fake PAM stack can communicate with this service */
1807 Login1Session *session = create_login1_session (connection);
1808 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(so)", session->id, session->path));
1811 else if (strcmp (method_name, "LockSession") == 0)
1814 Login1Session *session;
1816 g_variant_get (parameters, "(&s)", &id);
1817 session = find_login1_session (id);
1820 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such session: %s", id);
1824 if (!session->locked)
1826 gchar *status = g_strdup_printf ("LOGIN1 LOCK-SESSION SESSION=%s", id);
1827 check_status (status);
1830 session->locked = TRUE;
1831 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1833 else if (strcmp (method_name, "UnlockSession") == 0)
1836 Login1Session *session;
1838 g_variant_get (parameters, "(&s)", &id);
1839 session = find_login1_session (id);
1842 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such session: %s", id);
1846 if (session->locked)
1848 gchar *status = g_strdup_printf ("LOGIN1 UNLOCK-SESSION SESSION=%s", id);
1849 check_status (status);
1852 session->locked = FALSE;
1853 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1855 else if (strcmp (method_name, "ActivateSession") == 0)
1858 Login1Session *session;
1860 g_variant_get (parameters, "(&s)", &id);
1861 session = find_login1_session (id);
1864 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such session: %s", id);
1868 gchar *status = g_strdup_printf ("LOGIN1 ACTIVATE-SESSION SESSION=%s", id);
1869 check_status (status);
1872 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1874 else if (strcmp (method_name, "CanReboot") == 0)
1876 check_status ("LOGIN1 CAN-REBOOT");
1877 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1879 else if (strcmp (method_name, "Reboot") == 0)
1881 gboolean interactive;
1882 g_variant_get (parameters, "(b)", &interactive);
1883 check_status ("LOGIN1 REBOOT");
1884 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1886 else if (strcmp (method_name, "CanPowerOff") == 0)
1888 check_status ("LOGIN1 CAN-POWER-OFF");
1889 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1891 else if (strcmp (method_name, "Suspend") == 0)
1893 gboolean interactive;
1894 g_variant_get (parameters, "(b)", &interactive);
1895 check_status ("LOGIN1 SUSPEND");
1896 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1898 else if (strcmp (method_name, "CanSuspend") == 0)
1900 check_status ("LOGIN1 CAN-SUSPEND");
1901 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1903 else if (strcmp (method_name, "PowerOff") == 0)
1905 gboolean interactive;
1906 g_variant_get (parameters, "(b)", &interactive);
1907 check_status ("LOGIN1 POWER-OFF");
1908 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1910 else if (strcmp (method_name, "CanHibernate") == 0)
1912 check_status ("LOGIN1 CAN-HIBERNATE");
1913 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1915 else if (strcmp (method_name, "Hibernate") == 0)
1917 gboolean interactive;
1918 g_variant_get (parameters, "(b)", &interactive);
1919 check_status ("LOGIN1 HIBERNATE");
1920 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1923 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1927 login1_name_acquired_cb (GDBusConnection *connection,
1931 const gchar *login1_interface =
1933 " <interface name='org.freedesktop.login1.Manager'>"
1934 " <method name='ListSeats'>"
1935 " <arg name='seats' type='a(so)' direction='out'/>"
1937 " <method name='CreateSession'>"
1938 " <arg name='id' type='s' direction='out'/>"
1939 " <arg name='path' type='o' direction='out'/>"
1941 " <method name='LockSession'>"
1942 " <arg name='id' type='s' direction='in'/>"
1944 " <method name='UnlockSession'>"
1945 " <arg name='id' type='s' direction='in'/>"
1947 " <method name='ActivateSession'>"
1948 " <arg name='id' type='s' direction='in'/>"
1950 " <method name='CanReboot'>"
1951 " <arg name='result' direction='out' type='s'/>"
1953 " <method name='Reboot'>"
1954 " <arg name='interactive' direction='in' type='b'/>"
1956 " <method name='CanPowerOff'>"
1957 " <arg name='result' direction='out' type='s'/>"
1959 " <method name='PowerOff'>"
1960 " <arg name='interactive' direction='in' type='b'/>"
1962 " <method name='CanSuspend'>"
1963 " <arg name='result' direction='out' type='s'/>"
1965 " <method name='Suspend'>"
1966 " <arg name='interactive' direction='in' type='b'/>"
1968 " <method name='CanHibernate'>"
1969 " <arg name='result' direction='out' type='s'/>"
1971 " <method name='Hibernate'>"
1972 " <arg name='interactive' direction='in' type='b'/>"
1974 " <signal name='SeatNew'>"
1975 " <arg name='seat' type='so'/>"
1977 " <signal name='SeatRemoved'>"
1978 " <arg name='seat' type='so'/>"
1982 static const GDBusInterfaceVTable login1_vtable =
1986 GDBusNodeInfo *login1_info;
1988 GError *error = NULL;
1990 login1_info = g_dbus_node_info_new_for_xml (login1_interface, &error);
1992 g_warning ("Failed to parse login1 D-Bus interface: %s", error->message);
1993 g_clear_error (&error);
1996 g_dbus_connection_register_object (connection,
1997 "/org/freedesktop/login1",
1998 login1_info->interfaces[0],
2003 g_warning ("Failed to register login1 service: %s", error->message);
2004 g_clear_error (&error);
2005 g_dbus_node_info_unref (login1_info);
2007 /* We always have seat0 */
2008 seat0 = add_login1_seat (connection, "seat0", FALSE);
2009 if (g_key_file_has_key (config, "test-runner-config", "seat0-can-graphical", NULL))
2010 seat0->can_graphical = g_key_file_get_boolean (config, "test-runner-config", "seat0-can-graphical", NULL);
2011 if (g_key_file_has_key (config, "test-runner-config", "seat0-can-multi-session", NULL))
2012 seat0->can_multi_session = g_key_file_get_boolean (config, "test-runner-config", "seat0-can-multi-session", NULL);
2015 if (service_count == 0)
2020 start_login1_daemon (void)
2023 g_bus_own_name (G_BUS_TYPE_SYSTEM,
2024 "org.freedesktop.login1",
2025 G_BUS_NAME_OWNER_FLAGS_NONE,
2027 login1_name_acquired_cb,
2033 static AccountsUser *
2034 get_accounts_user_by_uid (guint uid)
2038 for (link = accounts_users; link; link = link->next)
2040 AccountsUser *u = link->data;
2048 static AccountsUser *
2049 get_accounts_user_by_name (const gchar *username)
2053 for (link = accounts_users; link; link = link->next)
2055 AccountsUser *u = link->data;
2056 if (strcmp (u->user_name, username) == 0)
2064 accounts_user_set_hidden (AccountsUser *user, gboolean hidden, gboolean emit_signal)
2066 GError *error = NULL;
2068 user->hidden = hidden;
2070 if (user->hidden && user->id != 0)
2072 g_dbus_connection_unregister_object (accounts_connection, user->id);
2073 g_dbus_connection_emit_signal (accounts_connection,
2075 "/org/freedesktop/Accounts",
2076 "org.freedesktop.Accounts",
2078 g_variant_new ("(o)", user->path),
2081 g_warning ("Failed to emit UserDeleted: %s", error->message);
2082 g_clear_error (&error);
2086 if (!user->hidden && user->id == 0)
2088 user->id = g_dbus_connection_register_object (accounts_connection,
2090 user_info->interfaces[0],
2096 g_warning ("Failed to register user: %s", error->message);
2097 g_clear_error (&error);
2099 g_dbus_connection_emit_signal (accounts_connection,
2101 "/org/freedesktop/Accounts",
2102 "org.freedesktop.Accounts",
2104 g_variant_new ("(o)", user->path),
2107 g_warning ("Failed to emit UserAdded: %s", error->message);
2108 g_clear_error (&error);
2113 load_passwd_file (void)
2115 gchar *path, *data, **lines;
2116 gchar **user_filter = NULL;
2119 if (g_key_file_has_key (config, "test-runner-config", "accounts-service-user-filter", NULL))
2123 filter = g_key_file_get_string (config, "test-runner-config", "accounts-service-user-filter", NULL);
2124 user_filter = g_strsplit (filter, " ", -1);
2128 path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "passwd", NULL);
2129 g_file_get_contents (path, &data, NULL, NULL);
2131 lines = g_strsplit (data, "\n", -1);
2134 for (i = 0; lines[i]; i++)
2138 gchar *user_name, *real_name;
2139 AccountsUser *user = NULL;
2141 fields = g_strsplit (lines[i], ":", -1);
2142 if (fields == NULL || g_strv_length (fields) < 7)
2144 g_strfreev (fields);
2148 user_name = fields[0];
2149 uid = atoi (fields[2]);
2150 real_name = fields[4];
2152 user = get_accounts_user_by_uid (uid);
2156 GKeyFile *dmrc_file;
2158 user = g_malloc0 (sizeof (AccountsUser));
2159 accounts_users = g_list_append (accounts_users, user);
2161 /* Only allow users in whitelist */
2162 user->hidden = FALSE;
2167 user->hidden = TRUE;
2168 for (j = 0; user_filter[j] != NULL; j++)
2169 if (strcmp (user_name, user_filter[j]) == 0)
2170 user->hidden = FALSE;
2173 dmrc_file = g_key_file_new ();
2174 path = g_build_filename (temp_dir, "home", user_name, ".dmrc", NULL);
2175 g_key_file_load_from_file (dmrc_file, path, G_KEY_FILE_NONE, NULL);
2179 user->user_name = g_strdup (user_name);
2180 user->real_name = g_strdup (real_name);
2181 user->home_directory = g_build_filename (temp_dir, "home", user_name, NULL);
2182 user->language = g_key_file_get_string (dmrc_file, "Desktop", "Language", NULL);
2183 /* DMRC contains a locale, strip the codeset off it to get the language */
2186 gchar *c = strchr (user->language, '.');
2190 user->xsession = g_key_file_get_string (dmrc_file, "Desktop", "Session", NULL);
2191 user->layouts = g_key_file_get_string_list (dmrc_file, "X-Accounts", "Layouts", NULL, NULL);
2194 user->layouts = g_malloc (sizeof (gchar *) * 2);
2195 user->layouts[0] = g_key_file_get_string (dmrc_file, "Desktop", "Layout", NULL);
2196 user->layouts[1] = NULL;
2198 user->has_messages = g_key_file_get_boolean (dmrc_file, "X-Accounts", "HasMessages", NULL);
2199 user->path = g_strdup_printf ("/org/freedesktop/Accounts/User%d", uid);
2200 accounts_user_set_hidden (user, user->hidden, FALSE);
2202 g_key_file_free (dmrc_file);
2205 g_strfreev (fields);
2212 handle_accounts_call (GDBusConnection *connection,
2213 const gchar *sender,
2214 const gchar *object_path,
2215 const gchar *interface_name,
2216 const gchar *method_name,
2217 GVariant *parameters,
2218 GDBusMethodInvocation *invocation,
2221 if (strcmp (method_name, "ListCachedUsers") == 0)
2223 GVariantBuilder builder;
2226 g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
2228 load_passwd_file ();
2229 for (link = accounts_users; link; link = link->next)
2231 AccountsUser *user = link->data;
2232 if (!user->hidden && user->uid >= 1000)
2233 g_variant_builder_add_value (&builder, g_variant_new_object_path (user->path));
2236 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(ao)", &builder));
2238 else if (strcmp (method_name, "FindUserByName") == 0)
2240 AccountsUser *user = NULL;
2243 g_variant_get (parameters, "(&s)", &user_name);
2245 load_passwd_file ();
2246 user = get_accounts_user_by_name (user_name);
2250 accounts_user_set_hidden (user, FALSE, TRUE);
2251 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", user->path));
2254 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such user: %s", user_name);
2257 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
2261 handle_user_call (GDBusConnection *connection,
2262 const gchar *sender,
2263 const gchar *object_path,
2264 const gchar *interface_name,
2265 const gchar *method_name,
2266 GVariant *parameters,
2267 GDBusMethodInvocation *invocation,
2270 AccountsUser *user = user_data;
2272 if (strcmp (method_name, "SetXSession") == 0)
2276 g_variant_get (parameters, "(&s)", &xsession);
2278 g_free (user->xsession);
2279 user->xsession = g_strdup (xsession);
2281 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
2283 /* And notify others that it took */
2284 g_dbus_connection_emit_signal (accounts_connection,
2287 "org.freedesktop.Accounts.User",
2289 g_variant_new ("()"),
2293 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
2297 handle_user_get_property (GDBusConnection *connection,
2298 const gchar *sender,
2299 const gchar *object_path,
2300 const gchar *interface_name,
2301 const gchar *property_name,
2305 AccountsUser *user = user_data;
2307 if (strcmp (property_name, "UserName") == 0)
2308 return g_variant_new_string (user->user_name);
2309 else if (strcmp (property_name, "RealName") == 0)
2310 return g_variant_new_string (user->real_name);
2311 else if (strcmp (property_name, "HomeDirectory") == 0)
2312 return g_variant_new_string (user->home_directory);
2313 else if (strcmp (property_name, "SystemAccount") == 0)
2314 return g_variant_new_boolean (user->uid < 1000);
2315 else if (strcmp (property_name, "BackgroundFile") == 0)
2316 return g_variant_new_string (user->background ? user->background : "");
2317 else if (strcmp (property_name, "Language") == 0)
2318 return g_variant_new_string (user->language ? user->language : "");
2319 else if (strcmp (property_name, "IconFile") == 0)
2320 return g_variant_new_string (user->image ? user->image : "");
2321 else if (strcmp (property_name, "Shell") == 0)
2322 return g_variant_new_string ("/bin/sh");
2323 else if (strcmp (property_name, "Uid") == 0)
2324 return g_variant_new_uint64 (user->uid);
2325 else if (strcmp (property_name, "XSession") == 0)
2326 return g_variant_new_string (user->xsession ? user->xsession : "");
2327 else if (strcmp (property_name, "XKeyboardLayouts") == 0)
2329 if (user->layouts != NULL)
2330 return g_variant_new_strv ((const gchar * const *) user->layouts, -1);
2332 return g_variant_new_strv (NULL, 0);
2334 else if (strcmp (property_name, "XHasMessages") == 0)
2335 return g_variant_new_boolean (user->has_messages);
2341 accounts_name_acquired_cb (GDBusConnection *connection,
2345 const gchar *accounts_interface =
2347 " <interface name='org.freedesktop.Accounts'>"
2348 " <method name='ListCachedUsers'>"
2349 " <arg name='user' direction='out' type='ao'/>"
2351 " <method name='FindUserByName'>"
2352 " <arg name='name' direction='in' type='s'/>"
2353 " <arg name='user' direction='out' type='o'/>"
2355 " <signal name='UserAdded'>"
2356 " <arg name='user' type='o'/>"
2358 " <signal name='UserDeleted'>"
2359 " <arg name='user' type='o'/>"
2363 static const GDBusInterfaceVTable accounts_vtable =
2365 handle_accounts_call,
2367 const gchar *user_interface =
2369 " <interface name='org.freedesktop.Accounts.User'>"
2370 " <method name='SetXSession'>"
2371 " <arg name='x_session' direction='in' type='s'/>"
2373 " <property name='UserName' type='s' access='read'/>"
2374 " <property name='RealName' type='s' access='read'/>"
2375 " <property name='HomeDirectory' type='s' access='read'/>"
2376 " <property name='SystemAccount' type='b' access='read'/>"
2377 " <property name='BackgroundFile' type='s' access='read'/>"
2378 " <property name='Language' type='s' access='read'/>"
2379 " <property name='IconFile' type='s' access='read'/>"
2380 " <property name='Shell' type='s' access='read'/>"
2381 " <property name='Uid' type='t' access='read'/>"
2382 " <property name='XSession' type='s' access='read'/>"
2383 " <property name='XKeyboardLayouts' type='as' access='read'/>"
2384 " <property name='XHasMessages' type='b' access='read'/>"
2385 " <signal name='Changed' />"
2388 GError *error = NULL;
2390 accounts_connection = connection;
2392 accounts_info = g_dbus_node_info_new_for_xml (accounts_interface, &error);
2394 g_warning ("Failed to parse D-Bus interface: %s", error->message);
2395 g_clear_error (&error);
2398 user_info = g_dbus_node_info_new_for_xml (user_interface, &error);
2400 g_warning ("Failed to parse D-Bus interface: %s", error->message);
2401 g_clear_error (&error);
2404 g_dbus_connection_register_object (connection,
2405 "/org/freedesktop/Accounts",
2406 accounts_info->interfaces[0],
2412 g_warning ("Failed to register accounts service: %s", error->message);
2413 g_clear_error (&error);
2414 g_dbus_node_info_unref (accounts_info);
2417 if (service_count == 0)
2422 start_accounts_service_daemon (void)
2425 g_bus_own_name (G_BUS_TYPE_SYSTEM,
2426 "org.freedesktop.Accounts",
2427 G_BUS_NAME_OWNER_FLAGS_NONE,
2428 accounts_name_acquired_cb,
2442 signal_cb (gpointer user_data)
2444 g_print ("Caught signal, quitting\n");
2445 quit (EXIT_FAILURE);
2450 properties_changed_cb (GDBusConnection *connection,
2451 const gchar *sender_name,
2452 const gchar *object_path,
2453 const gchar *interface_name,
2454 const gchar *signal_name,
2455 GVariant *parameters,
2458 const gchar *interface, *name;
2461 GVariantIter *changed_properties, *invalidated_properties;
2464 g_variant_get (parameters, "(&sa{sv}as)", &interface, &changed_properties, &invalidated_properties);
2466 status = g_string_new ("RUNNER DBUS-PROPERTIES-CHANGED");
2467 g_string_append_printf (status, " PATH=%s", object_path);
2468 g_string_append_printf (status, " INTERFACE=%s", interface);
2469 for (i = 0; g_variant_iter_loop (changed_properties, "{&sv}", &name, &value); i++)
2472 g_string_append (status, " CHANGED=");
2474 g_string_append (status, ",");
2475 g_string_append (status, name);
2476 if (g_variant_is_of_type (value, G_VARIANT_TYPE ("ao")))
2481 g_variant_iter_init (&iter, value);
2482 while (g_variant_iter_loop (&iter, "&o", &path))
2483 g_string_append_printf (status, ":%s", path);
2486 for (i = 0; g_variant_iter_loop (invalidated_properties, "&s", &name); i++)
2489 g_string_append (status, " INVALIDATED=");
2491 g_string_append (status, ",");
2492 g_string_append (status, name);
2495 check_status (status->str);
2496 g_string_free (status, TRUE);
2500 dbus_signal_cb (GDBusConnection *connection,
2501 const gchar *sender_name,
2502 const gchar *object_path,
2503 const gchar *interface_name,
2504 const gchar *signal_name,
2505 GVariant *parameters,
2510 status = g_string_new ("RUNNER DBUS-SIGNAL");
2511 g_string_append_printf (status, " PATH=%s", object_path);
2512 g_string_append_printf (status, " INTERFACE=%s", interface_name);
2513 g_string_append_printf (status, " NAME=%s", signal_name);
2515 check_status (status->str);
2516 g_string_free (status, TRUE);
2520 main (int argc, char **argv)
2524 gchar *greeter = NULL, *script_name, *config_file, *additional_system_config;
2525 gchar *additional_config, *path, *path1, *path2, *ld_preload, *ld_library_path, *home_dir;
2526 GString *passwd_data, *group_data;
2527 GSource *status_source;
2529 GError *error = NULL;
2531 #if !defined(GLIB_VERSION_2_36)
2535 loop = g_main_loop_new (NULL, FALSE);
2537 g_unix_signal_add (SIGINT, signal_cb, NULL);
2538 g_unix_signal_add (SIGTERM, signal_cb, NULL);
2540 children = g_hash_table_new (g_direct_hash, g_direct_equal);
2544 g_printerr ("Usage %s SCRIPT-NAME GREETER\n", argv[0]);
2545 quit (EXIT_FAILURE);
2547 script_name = argv[1];
2548 config_file = g_strdup_printf ("%s.conf", script_name);
2549 config_path = g_build_filename (SRCDIR, "tests", "scripts", config_file, NULL);
2550 g_free (config_file);
2552 config = g_key_file_new ();
2553 g_key_file_load_from_file (config, config_path, G_KEY_FILE_NONE, NULL);
2555 load_script (config_path);
2557 if (!getcwd (cwd, 1024))
2559 g_critical ("Error getting current directory: %s", strerror (errno));
2560 quit (EXIT_FAILURE);
2563 /* Don't contact our X server */
2564 g_unsetenv ("DISPLAY");
2566 /* Don't let XDG vars from system affect tests */
2567 g_unsetenv ("XDG_CONFIG_DIRS");
2568 g_unsetenv ("XDG_DATA_DIRS");
2570 /* Override system calls */
2571 ld_preload = g_build_filename (BUILDDIR, "tests", "src", ".libs", "libsystem.so", NULL);
2572 g_setenv ("LD_PRELOAD", ld_preload, TRUE);
2573 g_free (ld_preload);
2575 /* Run test programs */
2576 path = g_strdup_printf ("%s/tests/src/.libs:%s/tests/src:%s/tests/src:%s/src:%s", BUILDDIR, BUILDDIR, SRCDIR, BUILDDIR, g_getenv ("PATH"));
2577 g_setenv ("PATH", path, TRUE);
2580 /* Use locally built libraries */
2581 path1 = g_build_filename (BUILDDIR, "liblightdm-gobject", ".libs", NULL);
2582 path2 = g_build_filename (BUILDDIR, "liblightdm-qt", ".libs", NULL);
2583 ld_library_path = g_strdup_printf ("%s:%s", path1, path2);
2586 g_setenv ("LD_LIBRARY_PATH", ld_library_path, TRUE);
2587 g_free (ld_library_path);
2588 path1 = g_build_filename (BUILDDIR, "liblightdm-gobject", NULL);
2589 g_setenv ("GI_TYPELIB_PATH", path1, TRUE);
2592 /* Run in a temporary directory inside the build directory */
2593 /* Note we have to pick a name that is short since Unix sockets in this directory have a 108 character limit on their paths */
2598 name = g_strdup_printf (".r%d", i);
2600 temp_dir = g_build_filename ("/tmp", name, NULL);
2602 if (!g_file_test (temp_dir, G_FILE_TEST_EXISTS))
2606 g_mkdir_with_parents (temp_dir, 0755);
2607 g_setenv ("LIGHTDM_TEST_ROOT", temp_dir, TRUE);
2609 /* Open socket for status */
2610 /* Note we have to pick a socket name that is short since there is a 108 character limit on the name */
2611 status_socket_name = g_build_filename (temp_dir, ".s", NULL);
2612 unlink (status_socket_name);
2613 status_socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, &error);
2615 g_warning ("Error creating status socket %s: %s", status_socket_name, error->message);
2616 g_clear_error (&error);
2619 GSocketAddress *address;
2622 address = g_unix_socket_address_new (status_socket_name);
2623 result = g_socket_bind (status_socket, address, FALSE, &error);
2624 g_object_unref (address);
2626 g_warning ("Error binding status socket %s: %s", status_socket_name, error->message);
2627 g_clear_error (&error);
2630 result = g_socket_listen (status_socket, &error);
2632 g_warning ("Error listening on status socket %s: %s", status_socket_name, error->message);
2633 g_clear_error (&error);
2637 g_object_unref (status_socket);
2638 status_socket = NULL;
2642 quit (EXIT_FAILURE);
2643 status_source = g_socket_create_source (status_socket, G_IO_IN, NULL);
2644 g_source_set_callback (status_source, status_connect_cb, NULL, NULL);
2645 g_source_attach (status_source, NULL);
2647 /* Set up a skeleton file system */
2648 g_mkdir_with_parents (g_strdup_printf ("%s/etc", temp_dir), 0755);
2649 g_mkdir_with_parents (g_strdup_printf ("%s/run", temp_dir), 0755);
2650 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share", temp_dir), 0755);
2651 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/sessions", temp_dir), 0755);
2652 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/remote-sessions", temp_dir), 0755);
2653 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/greeters", temp_dir), 0755);
2654 g_mkdir_with_parents (g_strdup_printf ("%s/tmp", temp_dir), 0755);
2655 g_mkdir_with_parents (g_strdup_printf ("%s/var/lib/lightdm-data", temp_dir), 0755);
2656 g_mkdir_with_parents (g_strdup_printf ("%s/var/run", temp_dir), 0755);
2657 g_mkdir_with_parents (g_strdup_printf ("%s/var/log", temp_dir), 0755);
2659 /* Copy over the configuration */
2660 g_mkdir_with_parents (g_strdup_printf ("%s/etc/lightdm", temp_dir), 0755);
2661 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))
2662 if (system (g_strdup_printf ("cp %s %s/etc/lightdm/lightdm.conf", config_path, temp_dir)))
2663 perror ("Failed to copy configuration");
2664 if (system (g_strdup_printf ("cp %s/tests/data/keys.conf %s/etc/lightdm/", SRCDIR, temp_dir)))
2665 perror ("Failed to copy key configuration");
2667 additional_system_config = g_key_file_get_string (config, "test-runner-config", "additional-system-config", NULL);
2668 if (additional_system_config)
2672 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/lightdm.conf.d", temp_dir), 0755);
2674 files = g_strsplit (additional_system_config, " ", -1);
2675 for (i = 0; files[i]; i++)
2676 if (system (g_strdup_printf ("cp %s/tests/scripts/%s %s/usr/share/lightdm/lightdm.conf.d", SRCDIR, files[i], temp_dir)))
2677 perror ("Failed to copy configuration");
2681 additional_config = g_key_file_get_string (config, "test-runner-config", "additional-config", NULL);
2682 if (additional_config)
2686 g_mkdir_with_parents (g_strdup_printf ("%s/etc/xdg/lightdm/lightdm.conf.d", temp_dir), 0755);
2688 files = g_strsplit (additional_config, " ", -1);
2689 for (i = 0; files[i]; i++)
2690 if (system (g_strdup_printf ("cp %s/tests/scripts/%s %s/etc/xdg/lightdm/lightdm.conf.d", SRCDIR, files[i], temp_dir)))
2691 perror ("Failed to copy configuration");
2695 if (g_key_file_has_key (config, "test-runner-config", "shared-data-dirs", NULL))
2701 dir_string = g_key_file_get_string (config, "test-runner-config", "shared-data-dirs", NULL);
2702 dirs = g_strsplit (dir_string, " ", -1);
2703 g_free (dir_string);
2705 for (i = 0; dirs[i]; i++)
2707 gchar **fields = g_strsplit (dirs[i], ":", -1);
2708 if (g_strv_length (fields) == 4)
2710 gchar *path = g_strdup_printf ("%s/var/lib/lightdm-data/%s", temp_dir, fields[0]);
2711 int uid = g_ascii_strtoll (fields[1], NULL, 10);
2712 int gid = g_ascii_strtoll (fields[2], NULL, 10);
2713 int mode = g_ascii_strtoll (fields[3], NULL, 8);
2714 g_mkdir (path, mode);
2715 g_chmod (path, mode); /* mkdir filters by umask, so make sure we have what we want */
2716 if (chown (path, uid, gid) < 0)
2717 g_warning ("chown (%s) failed: %s", path, strerror (errno));
2720 g_strfreev (fields);
2726 /* Always copy the script */
2727 if (system (g_strdup_printf ("cp %s %s/script", config_path, temp_dir)))
2728 perror ("Failed to copy configuration");
2730 /* Copy over the greeter files */
2731 if (system (g_strdup_printf ("cp %s/sessions/* %s/usr/share/lightdm/sessions", DATADIR, temp_dir)))
2732 perror ("Failed to copy sessions");
2733 if (system (g_strdup_printf ("cp %s/remote-sessions/* %s/usr/share/lightdm/remote-sessions", DATADIR, temp_dir)))
2734 perror ("Failed to copy remote sessions");
2735 if (system (g_strdup_printf ("cp %s/greeters/* %s/usr/share/lightdm/greeters", DATADIR, temp_dir)))
2736 perror ("Failed to copy greeters");
2738 /* Set up the default greeter */
2739 path = g_build_filename (temp_dir, "usr", "share", "lightdm", "greeters", "default.desktop", NULL);
2740 greeter = g_strdup_printf ("%s.desktop", argv[2]);
2741 if (symlink (greeter, path) < 0)
2743 g_printerr ("Failed to make greeter symlink %s->%s: %s\n", path, greeter, strerror (errno));
2744 quit (EXIT_FAILURE);
2749 home_dir = g_build_filename (temp_dir, "home", NULL);
2751 /* Make fake users */
2761 {"root", "", "root", 0},
2762 /* Unprivileged account for greeters */
2763 {"lightdm", "", "", 100},
2764 /* These accounts have a password */
2765 {"have-password1", "password", "Password User 1", 1000},
2766 {"have-password2", "password", "Password User 2", 1001},
2767 {"have-password3", "password", "Password User 3", 1002},
2768 {"have-password4", "password", "Password User 4", 1003},
2769 /* This account always prompts for a password, even if using the lightdm-autologin service */
2770 {"always-password", "password", "Password User 4", 1004},
2771 /* These accounts have no password */
2772 {"no-password1", "", "No Password User 1", 1005},
2773 {"no-password2", "", "No Password User 2", 1006},
2774 {"no-password3", "", "No Password User 3", 1007},
2775 {"no-password4", "", "No Password User 4", 1008},
2776 /* This account has a keyboard layout */
2777 {"have-layout", "", "Layout User", 1009},
2778 /* This account has a set of keyboard layouts */
2779 {"have-layouts", "", "Layouts User", 1010},
2780 /* This account has a language set */
2781 {"have-language", "", "Language User", 1011},
2782 /* This account has a preconfigured session */
2783 {"have-session", "", "Session User", 1012},
2784 /* This account has the home directory mounted on login */
2785 {"mount-home-dir", "", "Mounted Home Dir User", 1013},
2786 /* This account is denied access */
2787 {"denied", "", "Denied User", 1014},
2788 /* This account has expired */
2789 {"expired", "", "Expired User", 1015},
2790 /* This account needs a password change */
2791 {"new-authtok", "", "New Token User", 1016},
2792 /* This account is switched to change-user2 when authentication succeeds */
2793 {"change-user1", "", "Change User 1", 1017},
2794 {"change-user2", "", "Change User 2", 1018},
2795 /* This account switches to invalid-user when authentication succeeds */
2796 {"change-user-invalid", "", "Invalid Change User", 1019},
2797 /* This account crashes on authentication */
2798 {"crash-authenticate", "", "Crash Auth User", 1020},
2799 /* This account shows an informational prompt on login */
2800 {"info-prompt", "password", "Info Prompt", 1021},
2801 /* This account shows multiple informational prompts on login */
2802 {"multi-info-prompt","password", "Multi Info Prompt", 1022},
2803 /* This account uses two factor authentication */
2804 {"two-factor", "password", "Two Factor", 1023},
2805 /* This account has a special group */
2806 {"group-member", "password", "Group Member", 1024},
2807 /* This account has the home directory created when the session starts */
2808 {"make-home-dir", "", "Make Home Dir User", 1025},
2809 /* This account fails to open a session */
2810 {"session-error", "password", "Session Error", 1026},
2811 /* This account can't establish credentials */
2812 {"cred-error", "password", "Cred Error", 1027},
2813 /* This account has expired credentials */
2814 {"cred-expired", "password", "Cred Expired", 1028},
2815 /* This account has cannot access their credentials */
2816 {"cred-unavail", "password", "Cred Unavail", 1029},
2817 /* This account sends informational messages for each PAM function that is called */
2818 {"log-pam", "password", "Log PAM", 1030},
2819 /* This account shows multiple prompts on login */
2820 {"multi-prompt", "password", "Multi Prompt", 1031},
2821 /* This account has an existing corrupt X authority */
2822 {"corrupt-xauth", "password", "Corrupt Xauthority", 1032},
2823 /* User to test properties */
2824 {"prop-user", "", "TEST", 1033},
2825 {NULL, NULL, NULL, 0}
2827 passwd_data = g_string_new ("");
2828 group_data = g_string_new ("");
2829 for (i = 0; users[i].user_name; i++)
2831 GKeyFile *dmrc_file;
2832 gboolean save_dmrc = FALSE;
2834 if (strcmp (users[i].user_name, "mount-home-dir") != 0 && strcmp (users[i].user_name, "make-home-dir") != 0)
2836 path = g_build_filename (home_dir, users[i].user_name, NULL);
2837 g_mkdir_with_parents (path, 0755);
2838 if (chown (path, users[i].uid, users[i].uid) < 0)
2839 g_debug ("chown (%s) failed: %s", path, strerror (errno));
2843 dmrc_file = g_key_file_new ();
2844 if (strcmp (users[i].user_name, "have-session") == 0)
2846 g_key_file_set_string (dmrc_file, "Desktop", "Session", "alternative");
2849 if (strcmp (users[i].user_name, "have-layout") == 0)
2851 g_key_file_set_string (dmrc_file, "Desktop", "Layout", "us");
2854 if (strcmp (users[i].user_name, "have-layouts") == 0)
2856 g_key_file_set_string (dmrc_file, "Desktop", "Layout", "ru");
2857 g_key_file_set_string (dmrc_file, "X-Accounts", "Layouts", "fr\toss;ru;");
2860 if (strcmp (users[i].user_name, "have-language") == 0)
2862 g_key_file_set_string (dmrc_file, "Desktop", "Language", "en_AU.utf8");
2870 path = g_build_filename (home_dir, users[i].user_name, ".dmrc", NULL);
2871 data = g_key_file_to_data (dmrc_file, NULL, NULL);
2872 g_file_set_contents (path, data, -1, NULL);
2877 g_key_file_free (dmrc_file);
2879 /* Write corrupt X authority file */
2880 if (strcmp (users[i].user_name, "corrupt-xauth") == 0)
2882 gchar data[1] = { 0xFF };
2884 path = g_build_filename (home_dir, users[i].user_name, ".Xauthority", NULL);
2885 g_file_set_contents (path, data, 1, NULL);
2886 chmod (path, S_IRUSR | S_IWUSR);
2890 /* Add passwd file entry */
2891 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);
2893 /* Add group file entry */
2894 g_string_append_printf (group_data, "%s:x:%d:%s\n", users[i].user_name, users[i].uid, users[i].user_name);
2896 path = g_build_filename (temp_dir, "etc", "passwd", NULL);
2897 g_file_set_contents (path, passwd_data->str, -1, NULL);
2899 g_string_free (passwd_data, TRUE);
2901 /* Add an extra test group */
2902 g_string_append_printf (group_data, "test-group:x:111:\n");
2904 path = g_build_filename (temp_dir, "etc", "group", NULL);
2905 g_file_set_contents (path, group_data->str, -1, NULL);
2907 g_string_free (group_data, TRUE);
2909 if (g_key_file_has_key (config, "test-runner-config", "timeout", NULL))
2910 status_timeout_ms = g_key_file_get_integer (config, "test-runner-config", "timeout", NULL) * 1000;
2912 /* Start D-Bus services */
2913 if (!g_key_file_get_boolean (config, "test-runner-config", "disable-upower", NULL))
2914 start_upower_daemon ();
2915 if (!g_key_file_get_boolean (config, "test-runner-config", "disable-console-kit", NULL))
2916 start_console_kit_daemon ();
2917 if (!g_key_file_get_boolean (config, "test-runner-config", "disable-login1", NULL))
2918 start_login1_daemon ();
2919 if (!g_key_file_get_boolean (config, "test-runner-config", "disable-accounts-service", NULL))
2920 start_accounts_service_daemon ();
2922 /* Listen for daemon bus events */
2923 if (g_key_file_get_boolean (config, "test-runner-config", "log-dbus", NULL))
2925 g_dbus_connection_signal_subscribe (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
2926 "org.freedesktop.DisplayManager",
2927 "org.freedesktop.DBus.Properties",
2928 "PropertiesChanged",
2931 G_DBUS_SIGNAL_FLAGS_NONE,
2932 properties_changed_cb,
2935 g_dbus_connection_signal_subscribe (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
2936 "org.freedesktop.DisplayManager",
2937 "org.freedesktop.DisplayManager",
2941 G_DBUS_SIGNAL_FLAGS_NONE,
2947 g_main_loop_run (loop);
2949 return EXIT_FAILURE;