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);
128 static GList *login1_sessions = NULL;
129 static gint login1_session_index = 0;
136 static GList *status_clients = NULL;
138 static void ready (void);
139 static void quit (int status);
140 static void check_status (const gchar *status);
141 static AccountsUser *get_accounts_user_by_uid (guint uid);
142 static AccountsUser *get_accounts_user_by_name (const gchar *username);
143 static void accounts_user_set_hidden (AccountsUser *user, gboolean hidden, gboolean emit_signal);
146 kill_timeout_cb (gpointer data)
148 Process *process = data;
150 process->kill_timeout = 0;
152 if (getenv ("DEBUG"))
153 g_print ("Sending SIGKILL to process %d\n", process->pid);
154 kill (process->pid, SIGKILL);
160 stop_process (Process *process)
162 if (process->kill_timeout != 0)
165 if (getenv ("DEBUG"))
166 g_print ("Sending SIGTERM to process %d\n", process->pid);
167 kill (process->pid, SIGTERM);
168 process->kill_timeout = g_timeout_add (KILL_TIMEOUT, kill_timeout_cb, process);
172 process_exit_cb (GPid pid, gint status, gpointer data)
177 if (getenv ("DEBUG"))
179 if (WIFEXITED (status))
180 g_print ("Process %d exited with status %d\n", pid, WEXITSTATUS (status));
182 g_print ("Process %d terminated with signal %d\n", pid, WTERMSIG (status));
185 if (lightdm_process && pid == lightdm_process->pid)
187 process = lightdm_process;
188 lightdm_process = NULL;
189 if (WIFEXITED (status))
190 status_text = g_strdup_printf ("RUNNER DAEMON-EXIT STATUS=%d", WEXITSTATUS (status));
192 status_text = g_strdup_printf ("RUNNER DAEMON-TERMINATE SIGNAL=%d", WTERMSIG (status));
193 check_status (status_text);
197 process = g_hash_table_lookup (children, GINT_TO_POINTER (pid));
200 g_hash_table_remove (children, GINT_TO_POINTER (pid));
203 if (process->kill_timeout)
204 g_source_remove (process->kill_timeout);
205 process->kill_timeout = 0;
207 /* Quit once all children have stopped */
213 watch_process (pid_t pid)
217 process = g_malloc0 (sizeof (Process));
219 process->kill_timeout = 0;
221 if (getenv ("DEBUG"))
222 g_print ("Watching process %d\n", process->pid);
223 g_child_watch_add (process->pid, process_exit_cb, NULL);
234 exit_status = status;
237 /* Stop all the children */
238 g_hash_table_iter_init (&iter, children);
243 if (!g_hash_table_iter_next (&iter, &key, &value))
246 stop_process ((Process *)value);
249 /* Don't quit until all children are stopped */
250 if (g_hash_table_size (children) > 0)
253 /* Stop the daemon */
256 stop_process (lightdm_process);
260 if (status_socket_name)
261 unlink (status_socket_name);
263 if (temp_dir && getenv ("DEBUG") == NULL)
265 gchar *command = g_strdup_printf ("rm -rf %s", temp_dir);
266 if (system (command))
267 perror ("Failed to delete temp directory");
274 fail (const gchar *event, const gchar *expected)
281 g_printerr ("Command line: %s", test_runner_command);
282 g_printerr ("Events:\n");
283 for (link = statuses; link; link = link->next)
284 g_printerr (" %s\n", (gchar *)link->data);
286 g_printerr (" %s\n", event);
288 g_printerr (" ^^^ expected \"%s\"\n", expected);
290 g_printerr ("^^^ expected nothing\n");
296 get_prefix (const gchar *text)
301 prefix = g_strdup (text);
302 for (i = 0; prefix[i] != '\0' && prefix[i] != ' '; i++);
309 get_script_line (const gchar *prefix)
313 for (link = script; link; link = link->next)
315 ScriptLine *line = link->data;
317 /* Ignore lines with other prefixes */
323 p = get_prefix (line->text);
324 matches = strcmp (prefix, p) == 0;
339 stop_loop (gpointer user_data)
341 g_main_loop_quit ((GMainLoop *)user_data);
342 return G_SOURCE_REMOVE;
346 handle_command (const gchar *command)
353 while (*c && !isspace (*c))
355 name = g_strdup_printf ("%.*s", (int) (c - command), command);
357 params = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
361 gchar *param_name, *param_value;
366 while (*c && !isspace (*c) && *c != '=')
371 param_name = g_strdup_printf ("%.*s", (int) (c - start), start);
380 gboolean escaped = FALSE;
384 value = g_string_new ("");
391 g_string_append_c (value, '\\');
397 else if (!escaped && *c == '\"')
400 g_string_append_c (value, *c);
403 param_value = value->str;
404 g_string_free (value, FALSE);
411 while (*c && !isspace (*c))
413 param_value = g_strdup_printf ("%.*s", (int) (c - start), start);
417 param_value = g_strdup ("");
419 g_hash_table_insert (params, param_name, param_value);
422 if (strcmp (name, "START-DAEMON") == 0)
424 GString *command_line;
425 gchar **lightdm_argv;
427 GError *error = NULL;
429 command_line = g_string_new ("lightdm");
430 if (getenv ("DEBUG"))
431 g_string_append (command_line, " --debug");
432 g_string_append_printf (command_line, " --cache-dir %s/cache", temp_dir);
434 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",
435 g_getenv ("PATH"), g_getenv ("LD_PRELOAD"), g_getenv ("LD_LIBRARY_PATH"), g_getenv ("LIGHTDM_TEST_ROOT"), g_getenv ("DBUS_SESSION_BUS_ADDRESS"),
438 if (!g_shell_parse_argv (command_line->str, NULL, &lightdm_argv, &error))
440 g_warning ("Error parsing command line: %s", error->message);
443 g_clear_error (&error);
445 if (!g_spawn_async (NULL, lightdm_argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL, NULL, &lightdm_pid, &error))
447 g_warning ("Error launching LightDM: %s", error->message);
450 g_clear_error (&error);
451 lightdm_process = watch_process (lightdm_pid);
453 check_status ("RUNNER DAEMON-START");
455 else if (strcmp (name, "WAIT") == 0)
457 /* Use a main loop so that our DBus functions are still responsive */
458 GMainLoop *loop = g_main_loop_new (NULL, FALSE);
459 g_timeout_add_seconds (1, stop_loop, loop);
460 g_main_loop_run (loop);
461 g_main_loop_unref (loop);
463 else if (strcmp (name, "ADD-SEAT") == 0)
468 id = g_hash_table_lookup (params, "ID");
469 seat = add_login1_seat (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL), id, TRUE);
470 v = g_hash_table_lookup (params, "CAN-GRAPHICAL");
472 seat->can_graphical = strcmp (v, "TRUE") == 0;
473 v = g_hash_table_lookup (params, "CAN-MULTI-SESSION");
475 seat->can_multi_session = strcmp (v, "TRUE") == 0;
477 else if (strcmp (name, "UPDATE-SEAT") == 0)
482 id = g_hash_table_lookup (params, "ID");
483 seat = find_login1_seat (id);
487 GVariantBuilder changed_properties;
488 GError *error = NULL;
490 g_variant_builder_init (&changed_properties, G_VARIANT_TYPE_ARRAY);
492 v = g_hash_table_lookup (params, "CAN-GRAPHICAL");
495 seat->can_graphical = strcmp (v, "TRUE") == 0;
496 g_variant_builder_add (&changed_properties, "{sv}", "CanGraphical", g_variant_new_boolean (seat->can_graphical));
498 v = g_hash_table_lookup (params, "CAN-MULTI-SESSION");
501 seat->can_multi_session = strcmp (v, "TRUE") == 0;
502 g_variant_builder_add (&changed_properties, "{sv}", "CanMultiSession", g_variant_new_boolean (seat->can_multi_session));
505 g_dbus_connection_emit_signal (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
508 "org.freedesktop.DBus.Propeties",
510 g_variant_new ("(sa{sv}as)", "org.freedesktop.login1.Seat", &changed_properties, NULL),
513 g_warning ("Failed to emit PropertiesChanged: %s", error->message);
514 g_clear_error (&error);
517 else if (strcmp (name, "REMOVE-SEAT") == 0)
520 id = g_hash_table_lookup (params, "ID");
521 remove_login1_seat (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL), id);
523 else if (strcmp (name, "LIST-SEATS") == 0)
525 GVariant *result, *value;
531 result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
532 "org.freedesktop.DisplayManager",
533 "/org/freedesktop/DisplayManager",
534 "org.freedesktop.DBus.Properties",
536 g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Seats"),
537 G_VARIANT_TYPE ("(v)"),
538 G_DBUS_CALL_FLAGS_NONE,
543 status = g_string_new ("RUNNER LIST-SEATS SEATS=");
544 g_variant_get (result, "(v)", &value);
545 g_variant_get (value, "ao", &iter);
546 while (g_variant_iter_loop (iter, "&o", &path))
549 g_string_append (status, ",");
550 g_string_append (status, path);
553 g_variant_unref (value);
554 g_variant_unref (result);
556 check_status (status->str);
557 g_string_free (status, TRUE);
559 else if (strcmp (name, "LIST-SESSIONS") == 0)
561 GVariant *result, *value;
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.DBus.Properties",
572 g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Sessions"),
573 G_VARIANT_TYPE ("(v)"),
574 G_DBUS_CALL_FLAGS_NONE,
579 status = g_string_new ("RUNNER LIST-SESSIONS SESSIONS=");
580 g_variant_get (result, "(v)", &value);
581 g_variant_get (value, "ao", &iter);
582 while (g_variant_iter_loop (iter, "&o", &path))
585 g_string_append (status, ",");
586 g_string_append (status, path);
589 g_variant_unref (value);
590 g_variant_unref (result);
592 check_status (status->str);
593 g_string_free (status, TRUE);
595 else if (strcmp (name, "SEAT-CAN-SWITCH") == 0)
597 GVariant *result, *value;
600 result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
601 "org.freedesktop.DisplayManager",
602 "/org/freedesktop/DisplayManager/Seat0",
603 "org.freedesktop.DBus.Properties",
605 g_variant_new ("(ss)", "org.freedesktop.DisplayManager.Seat", "CanSwitch"),
606 G_VARIANT_TYPE ("(v)"),
607 G_DBUS_CALL_FLAGS_NONE,
612 g_variant_get (result, "(v)", &value);
613 status = g_strdup_printf ("RUNNER SEAT-CAN-SWITCH CAN-SWITCH=%s", g_variant_get_boolean (value) ? "TRUE" : "FALSE");
614 g_variant_unref (value);
615 g_variant_unref (result);
616 check_status (status);
619 else if (strcmp (name, "SEAT-HAS-GUEST-ACCOUNT") == 0)
621 GVariant *result, *value;
624 result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
625 "org.freedesktop.DisplayManager",
626 "/org/freedesktop/DisplayManager/Seat0",
627 "org.freedesktop.DBus.Properties",
629 g_variant_new ("(ss)", "org.freedesktop.DisplayManager.Seat", "HasGuestAccount"),
630 G_VARIANT_TYPE ("(v)"),
631 G_DBUS_CALL_FLAGS_NONE,
636 g_variant_get (result, "(v)", &value);
637 status = g_strdup_printf ("RUNNER SEAT-HAS-GUEST-ACCOUNT HAS-GUEST-ACCOUNT=%s", g_variant_get_boolean (value) ? "TRUE" : "FALSE");
638 g_variant_unref (value);
639 g_variant_unref (result);
640 check_status (status);
643 else if (strcmp (name, "SWITCH-TO-GREETER") == 0)
647 result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
648 "org.freedesktop.DisplayManager",
649 "/org/freedesktop/DisplayManager/Seat0",
650 "org.freedesktop.DisplayManager.Seat",
652 g_variant_new ("()"),
653 G_VARIANT_TYPE ("()"),
654 G_DBUS_CALL_FLAGS_NONE,
660 check_status ("RUNNER SWITCH-TO-GREETER");
661 g_variant_unref (result);
664 check_status ("RUNNER SWITCH-TO-GREETER FAILED");
666 else if (strcmp (name, "SWITCH-TO-USER") == 0)
669 const gchar *username;
671 username = g_hash_table_lookup (params, "USERNAME");
672 result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
673 "org.freedesktop.DisplayManager",
674 "/org/freedesktop/DisplayManager/Seat0",
675 "org.freedesktop.DisplayManager.Seat",
677 g_variant_new ("(ss)", username, ""),
678 G_VARIANT_TYPE ("()"),
679 G_DBUS_CALL_FLAGS_NONE,
686 status_text = g_strdup_printf ("RUNNER SWITCH-TO-USER USERNAME=%s", username);
687 check_status (status_text);
688 g_free (status_text);
689 g_variant_unref (result);
694 status_text = g_strdup_printf ("RUNNER SWITCH-TO-USER USERNAME=%s FAILED", username);
695 check_status (status_text);
696 g_free (status_text);
699 else if (strcmp (name, "SWITCH-TO-GUEST") == 0)
703 result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
704 "org.freedesktop.DisplayManager",
705 "/org/freedesktop/DisplayManager/Seat0",
706 "org.freedesktop.DisplayManager.Seat",
708 g_variant_new ("(s)", ""),
709 G_VARIANT_TYPE ("()"),
710 G_DBUS_CALL_FLAGS_NONE,
716 check_status ("RUNNER SWITCH-TO-GUEST");
717 g_variant_unref (result);
720 check_status ("RUNNER SWITCH-TO-GUEST FAILED");
722 else if (strcmp (name, "STOP-DAEMON") == 0)
723 stop_process (lightdm_process);
724 // FIXME: Make generic RUN-COMMAND
725 else if (strcmp (name, "START-XSERVER") == 0)
727 gchar *xserver_args, *command_line;
731 GError *error = NULL;
733 xserver_args = g_hash_table_lookup (params, "ARGS");
736 command_line = g_strdup_printf ("%s/tests/src/X %s", BUILDDIR, xserver_args);
738 if (!g_shell_parse_argv (command_line, NULL, &argv, &error) ||
739 !g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &error))
741 g_printerr ("Error starting X server: %s", error->message);
746 process = watch_process (pid);
747 g_hash_table_insert (children, GINT_TO_POINTER (process->pid), process);
750 else if (strcmp (name, "START-VNC-CLIENT") == 0)
752 gchar *vnc_client_args, *command_line;
756 GError *error = NULL;
758 vnc_client_args = g_hash_table_lookup (params, "ARGS");
759 if (!vnc_client_args)
760 vnc_client_args = "";
761 command_line = g_strdup_printf ("%s/tests/src/vnc-client %s", BUILDDIR, vnc_client_args);
763 if (!g_shell_parse_argv (command_line, NULL, &argv, &error) ||
764 !g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &error))
766 g_printerr ("Error starting VNC client: %s", error->message);
771 process = watch_process (pid);
772 g_hash_table_insert (children, GINT_TO_POINTER (process->pid), process);
775 else if (strcmp (name, "ADD-USER") == 0)
777 gchar *status_text, *username;
780 username = g_hash_table_lookup (params, "USERNAME");
781 user = get_accounts_user_by_name (username);
783 accounts_user_set_hidden (user, FALSE, TRUE);
785 g_warning ("Unknown user %s", username);
787 status_text = g_strdup_printf ("RUNNER ADD-USER USERNAME=%s", username);
788 check_status (status_text);
789 g_free (status_text);
791 else if (strcmp (name, "UPDATE-USER") == 0)
793 GString *status_text;
796 GError *error = NULL;
798 status_text = g_string_new ("RUNNER UPDATE-USER USERNAME=");
800 username = g_hash_table_lookup (params, "USERNAME");
801 g_string_append (status_text, username);
802 user = get_accounts_user_by_name (username);
805 if (g_hash_table_lookup (params, "NAME"))
807 user->user_name = g_strdup (g_hash_table_lookup (params, "NAME"));
808 g_string_append_printf (status_text, " NAME=%s", user->user_name);
810 if (g_hash_table_lookup (params, "REAL-NAME"))
812 user->real_name = g_strdup (g_hash_table_lookup (params, "REAL-NAME"));
813 g_string_append_printf (status_text, " REAL-NAME=%s", user->real_name);
815 if (g_hash_table_lookup (params, "HOME-DIRECTORY"))
817 user->home_directory = g_strdup (g_hash_table_lookup (params, "HOME-DIRECTORY"));
818 g_string_append_printf (status_text, " HOME-DIRECTORY=%s", user->home_directory);
820 if (g_hash_table_lookup (params, "IMAGE"))
822 user->image = g_strdup (g_hash_table_lookup (params, "IMAGE"));
823 g_string_append_printf (status_text, " IMAGE=%s", user->image);
825 if (g_hash_table_lookup (params, "BACKGROUND"))
827 user->background = g_strdup (g_hash_table_lookup (params, "BACKGROUND"));
828 g_string_append_printf (status_text, " BACKGROUND=%s", user->background);
830 if (g_hash_table_lookup (params, "LANGUAGE"))
832 user->language = g_strdup (g_hash_table_lookup (params, "LANGUAGE"));
833 g_string_append_printf (status_text, " LANGUAGE=%s", user->language);
835 if (g_hash_table_lookup (params, "LAYOUTS"))
837 const gchar *value = g_hash_table_lookup (params, "LAYOUTS");
838 user->layouts = g_strsplit (value, ";", -1);
839 g_string_append_printf (status_text, " LAYOUTS=%s", value);
841 if (g_hash_table_lookup (params, "HAS-MESSAGES"))
843 user->has_messages = g_strcmp0 (g_hash_table_lookup (params, "HAS-MESSAGES"), "TRUE") == 0;
844 g_string_append_printf (status_text, " HAS-MESSAGES=%s", user->has_messages ? "TRUE" : "FALSE");
846 if (g_hash_table_lookup (params, "SESSION"))
848 user->xsession = g_strdup (g_hash_table_lookup (params, "SESSION"));
849 g_string_append_printf (status_text, " SESSION=%s", user->xsession);
853 g_warning ("Unknown user %s", username);
855 g_dbus_connection_emit_signal (accounts_connection,
858 "org.freedesktop.Accounts.User",
860 g_variant_new ("()"),
863 g_warning ("Failed to emit Changed: %s", error->message);
864 g_clear_error (&error);
866 check_status (status_text->str);
867 g_string_free (status_text, TRUE);
869 else if (strcmp (name, "DELETE-USER") == 0)
871 gchar *status_text, *username;
874 username = g_hash_table_lookup (params, "USERNAME");
875 user = get_accounts_user_by_name (username);
877 accounts_user_set_hidden (user, TRUE, TRUE);
879 g_warning ("Unknown user %s", username);
881 status_text = g_strdup_printf ("RUNNER DELETE-USER USERNAME=%s", username);
882 check_status (status_text);
883 g_free (status_text);
885 /* Forward to external processes */
886 else if (g_str_has_prefix (name, "SESSION-") ||
887 g_str_has_prefix (name, "GREETER-") ||
888 g_str_has_prefix (name, "XSERVER-") ||
889 strcmp (name, "UNITY-SYSTEM-COMPOSITOR") == 0)
892 for (link = status_clients; link; link = link->next)
894 StatusClient *client = link->data;
896 GError *error = NULL;
898 length = strlen (command);
899 if (g_socket_send (client->socket, (gchar *) &length, sizeof (length), NULL, &error) < 0 ||
900 g_socket_send (client->socket, command, strlen (command), NULL, &error) < 0)
901 g_printerr ("Failed to write to client socket: %s\n", error->message);
902 g_clear_error (&error);
907 g_printerr ("Unknown command '%s'\n", name);
912 g_hash_table_unref (params);
918 /* Stop daemon if requested */
923 /* Commands start with an asterisk */
924 line = get_script_line (NULL);
925 if (!line || line->text[0] != '*')
928 statuses = g_list_append (statuses, g_strdup (line->text));
931 handle_command (line->text + 1);
934 /* Stop at the end of the script */
935 if (get_script_line (NULL) == NULL)
940 status_timeout_cb (gpointer data)
944 line = get_script_line (NULL);
945 fail ("(timeout)", line ? line->text : NULL);
951 check_status (const gchar *status)
954 gboolean result = FALSE;
960 statuses = g_list_append (statuses, g_strdup (status));
962 if (getenv ("DEBUG"))
963 g_print ("%s\n", status);
965 /* Try and match against expected */
966 prefix = get_prefix (status);
967 line = get_script_line (prefix);
971 gchar *full_pattern = g_strdup_printf ("^%s$", line->text);
972 result = g_regex_match_simple (full_pattern, status, 0, 0);
973 g_free (full_pattern);
979 line = get_script_line (NULL);
980 fail (NULL, line ? line->text : NULL);
986 /* Restart timeout */
988 g_source_remove (status_timeout);
989 status_timeout = g_timeout_add (status_timeout_ms, status_timeout_cb, NULL);
995 status_message_cb (GSocket *socket, GIOCondition condition, StatusClient *client)
1000 GError *error = NULL;
1002 n_read = g_socket_receive (socket, (gchar *)&length, sizeof (length), NULL, &error);
1004 n_read = g_socket_receive (socket, buffer, length, NULL, &error);
1006 g_warning ("Error reading from socket: %s", error->message);
1007 g_clear_error (&error);
1010 status_clients = g_list_remove (status_clients, client);
1011 g_object_unref (client->socket);
1015 else if (n_read > 0)
1017 buffer[n_read] = '\0';
1018 check_status (buffer);
1025 status_connect_cb (gpointer data)
1028 GError *error = NULL;
1030 socket = g_socket_accept (status_socket, NULL, &error);
1032 g_warning ("Failed to accept status connection: %s", error->message);
1033 g_clear_error (&error);
1036 StatusClient *client;
1038 client = g_malloc0 (sizeof (StatusClient));
1039 client->socket = socket;
1040 client->source = g_socket_create_source (socket, G_IO_IN, NULL);
1041 status_clients = g_list_append (status_clients, client);
1043 g_source_set_callback (client->source, (GSourceFunc) status_message_cb, client, NULL);
1044 g_source_attach (client->source, NULL);
1051 load_script (const gchar *filename)
1054 gchar *data, **lines;
1056 if (!g_file_get_contents (filename, &data, NULL, NULL))
1058 g_printerr ("Unable to load script: %s\n", filename);
1059 quit (EXIT_FAILURE);
1062 lines = g_strsplit (data, "\n", -1);
1065 /* Load lines with #? prefix as expected behaviour */
1066 for (i = 0; lines[i]; i++)
1068 gchar *text = g_strstrip (lines[i]);
1069 if (g_str_has_prefix (text, "#?"))
1072 line = g_malloc0 (sizeof (ScriptLine));
1073 line->text = g_strdup (text + 2);
1075 script = g_list_append (script, line);
1082 handle_upower_call (GDBusConnection *connection,
1083 const gchar *sender,
1084 const gchar *object_path,
1085 const gchar *interface_name,
1086 const gchar *method_name,
1087 GVariant *parameters,
1088 GDBusMethodInvocation *invocation,
1091 if (strcmp (method_name, "SuspendAllowed") == 0)
1093 check_status ("UPOWER SUSPEND-ALLOWED");
1094 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
1096 else if (strcmp (method_name, "Suspend") == 0)
1098 check_status ("UPOWER SUSPEND");
1099 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1101 else if (strcmp (method_name, "HibernateAllowed") == 0)
1103 check_status ("UPOWER HIBERNATE-ALLOWED");
1104 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
1106 else if (strcmp (method_name, "Hibernate") == 0)
1108 check_status ("UPOWER HIBERNATE");
1109 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1112 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1116 upower_name_acquired_cb (GDBusConnection *connection,
1120 const gchar *upower_interface =
1122 " <interface name='org.freedesktop.UPower'>"
1123 " <method name='SuspendAllowed'>"
1124 " <arg name='allowed' direction='out' type='b'/>"
1126 " <method name='Suspend'/>"
1127 " <method name='HibernateAllowed'>"
1128 " <arg name='allowed' direction='out' type='b'/>"
1130 " <method name='Hibernate'/>"
1133 static const GDBusInterfaceVTable upower_vtable =
1137 GDBusNodeInfo *upower_info;
1138 GError *error = NULL;
1140 upower_info = g_dbus_node_info_new_for_xml (upower_interface, &error);
1142 g_warning ("Failed to parse D-Bus interface: %s", error->message);
1143 g_clear_error (&error);
1146 g_dbus_connection_register_object (connection,
1147 "/org/freedesktop/UPower",
1148 upower_info->interfaces[0],
1153 g_warning ("Failed to register UPower service: %s", error->message);
1154 g_clear_error (&error);
1155 g_dbus_node_info_unref (upower_info);
1158 if (service_count == 0)
1163 start_upower_daemon (void)
1166 g_bus_own_name (G_BUS_TYPE_SYSTEM,
1167 "org.freedesktop.UPower",
1168 G_BUS_NAME_OWNER_FLAGS_NONE,
1169 upower_name_acquired_cb,
1177 open_ck_session (GDBusConnection *connection, GVariant *params)
1184 GError *error = NULL;
1186 session = g_malloc0 (sizeof (CKSession));
1187 ck_sessions = g_list_append (ck_sessions, session);
1189 cookie = g_string_new ("ck-cookie");
1190 g_variant_get (params, "a(sv)", &iter);
1191 while (g_variant_iter_loop (iter, "(&sv)", &name, &value))
1193 if (strcmp (name, "x11-display") == 0)
1195 const gchar *display;
1196 g_variant_get (value, "&s", &display);
1197 g_string_append_printf (cookie, "-x%s", display);
1201 session->cookie = cookie->str;
1202 g_string_free (cookie, FALSE);
1203 session->path = g_strdup_printf ("/org/freedesktop/ConsoleKit/Session%d", ck_session_index++);
1204 session->id = g_dbus_connection_register_object (connection,
1206 ck_session_info->interfaces[0],
1212 g_warning ("Failed to register CK Session: %s", error->message);
1213 g_clear_error (&error);
1219 handle_ck_call (GDBusConnection *connection,
1220 const gchar *sender,
1221 const gchar *object_path,
1222 const gchar *interface_name,
1223 const gchar *method_name,
1224 GVariant *parameters,
1225 GDBusMethodInvocation *invocation,
1228 if (strcmp (method_name, "CanRestart") == 0)
1230 check_status ("CONSOLE-KIT CAN-RESTART");
1231 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
1233 else if (strcmp (method_name, "CanStop") == 0)
1235 check_status ("CONSOLE-KIT CAN-STOP");
1236 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
1238 else if (strcmp (method_name, "CloseSession") == 0)
1239 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
1240 else if (strcmp (method_name, "OpenSession") == 0)
1242 GVariantBuilder params;
1243 g_variant_builder_init (¶ms, G_VARIANT_TYPE ("a(sv)"));
1244 CKSession *session = open_ck_session (connection, g_variant_builder_end (¶ms));
1245 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", session->cookie));
1247 else if (strcmp (method_name, "OpenSessionWithParameters") == 0)
1249 CKSession *session = open_ck_session (connection, g_variant_get_child_value (parameters, 0));
1250 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", session->cookie));
1252 else if (strcmp (method_name, "GetSessionForCookie") == 0)
1257 g_variant_get (parameters, "(&s)", &cookie);
1259 for (link = ck_sessions; link; link = link->next)
1261 CKSession *session = link->data;
1262 if (strcmp (session->cookie, cookie) == 0)
1264 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", session->path));
1269 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Unable to find session for cookie");
1271 else if (strcmp (method_name, "Restart") == 0)
1273 check_status ("CONSOLE-KIT RESTART");
1274 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1276 else if (strcmp (method_name, "Stop") == 0)
1278 check_status ("CONSOLE-KIT STOP");
1279 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1282 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1286 handle_ck_session_call (GDBusConnection *connection,
1287 const gchar *sender,
1288 const gchar *object_path,
1289 const gchar *interface_name,
1290 const gchar *method_name,
1291 GVariant *parameters,
1292 GDBusMethodInvocation *invocation,
1295 CKSession *session = user_data;
1297 if (strcmp (method_name, "Lock") == 0)
1299 if (!session->locked)
1300 check_status ("CONSOLE-KIT LOCK-SESSION");
1301 session->locked = TRUE;
1302 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1304 else if (strcmp (method_name, "Unlock") == 0)
1306 if (session->locked)
1307 check_status ("CONSOLE-KIT UNLOCK-SESSION");
1308 session->locked = FALSE;
1309 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1311 else if (strcmp (method_name, "Activate") == 0)
1313 gchar *status = g_strdup_printf ("CONSOLE-KIT ACTIVATE-SESSION SESSION=%s", session->cookie);
1314 check_status (status);
1317 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1320 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1324 ck_name_acquired_cb (GDBusConnection *connection,
1328 const gchar *ck_interface =
1330 " <interface name='org.freedesktop.ConsoleKit.Manager'>"
1331 " <method name='CanRestart'>"
1332 " <arg name='can_restart' direction='out' type='b'/>"
1334 " <method name='CanStop'>"
1335 " <arg name='can_stop' direction='out' type='b'/>"
1337 " <method name='CloseSession'>"
1338 " <arg name='cookie' direction='in' type='s'/>"
1339 " <arg name='result' direction='out' type='b'/>"
1341 " <method name='OpenSession'>"
1342 " <arg name='cookie' direction='out' type='s'/>"
1344 " <method name='OpenSessionWithParameters'>"
1345 " <arg name='parameters' direction='in' type='a(sv)'/>"
1346 " <arg name='cookie' direction='out' type='s'/>"
1348 " <method name='GetSessionForCookie'>"
1349 " <arg name='cookie' direction='in' type='s'/>"
1350 " <arg name='ssid' direction='out' type='o'/>"
1352 " <method name='Restart'/>"
1353 " <method name='Stop'/>"
1354 " <signal name='SeatAdded'>"
1355 " <arg name='seat' type='o'/>"
1357 " <signal name='SeatRemoved'>"
1358 " <arg name='seat' type='o'/>"
1362 static const GDBusInterfaceVTable ck_vtable =
1366 const gchar *ck_session_interface =
1368 " <interface name='org.freedesktop.ConsoleKit.Session'>"
1369 " <method name='Lock'/>"
1370 " <method name='Unlock'/>"
1371 " <method name='Activate'/>"
1374 GDBusNodeInfo *ck_info;
1375 GError *error = NULL;
1377 ck_info = g_dbus_node_info_new_for_xml (ck_interface, &error);
1379 g_warning ("Failed to parse D-Bus interface: %s", error->message);
1380 g_clear_error (&error);
1383 ck_session_info = g_dbus_node_info_new_for_xml (ck_session_interface, &error);
1385 g_warning ("Failed to parse D-Bus interface: %s", error->message);
1386 g_clear_error (&error);
1387 if (!ck_session_info)
1389 g_dbus_connection_register_object (connection,
1390 "/org/freedesktop/ConsoleKit/Manager",
1391 ck_info->interfaces[0],
1396 g_warning ("Failed to register console kit service: %s", error->message);
1397 g_clear_error (&error);
1398 g_dbus_node_info_unref (ck_info);
1401 if (service_count == 0)
1406 start_console_kit_daemon (void)
1409 g_bus_own_name (G_BUS_TYPE_SYSTEM,
1410 "org.freedesktop.ConsoleKit",
1411 G_BUS_NAME_OWNER_FLAGS_NONE,
1413 ck_name_acquired_cb,
1420 handle_login1_seat_call (GDBusConnection *connection,
1421 const gchar *sender,
1422 const gchar *object_path,
1423 const gchar *interface_name,
1424 const gchar *method_name,
1425 GVariant *parameters,
1426 GDBusMethodInvocation *invocation,
1429 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1433 handle_login1_seat_get_property (GDBusConnection *connection,
1434 const gchar *sender,
1435 const gchar *object_path,
1436 const gchar *interface_name,
1437 const gchar *property_name,
1441 Login1Seat *seat = user_data;
1443 if (strcmp (property_name, "CanGraphical") == 0)
1444 return g_variant_new_boolean (seat->can_graphical);
1445 else if (strcmp (property_name, "CanMultiSession") == 0)
1446 return g_variant_new_boolean (seat->can_multi_session);
1447 else if (strcmp (property_name, "Id") == 0)
1448 return g_variant_new_string (seat->id);
1454 add_login1_seat (GDBusConnection *connection, const gchar *id, gboolean emit_signal)
1457 GError *error = NULL;
1458 GDBusNodeInfo *login1_seat_info;
1460 const gchar *login1_seat_interface =
1462 " <interface name='org.freedesktop.login1.Seat'>"
1463 " <property name='CanGraphical' type='b' access='read'/>"
1464 " <property name='CanMultiSession' type='b' access='read'/>"
1465 " <property name='Id' type='s' access='read'/>"
1468 static const GDBusInterfaceVTable login1_seat_vtable =
1470 handle_login1_seat_call,
1471 handle_login1_seat_get_property,
1474 seat = g_malloc0 (sizeof (Login1Seat));
1475 login1_seats = g_list_append (login1_seats, seat);
1476 seat->id = g_strdup (id);
1477 seat->path = g_strdup_printf ("/org/freedesktop/login1/seat/%s", seat->id);
1478 seat->can_graphical = TRUE;
1479 seat->can_multi_session = TRUE;
1481 login1_seat_info = g_dbus_node_info_new_for_xml (login1_seat_interface, &error);
1483 g_warning ("Failed to parse login1 seat D-Bus interface: %s", error->message);
1484 g_clear_error (&error);
1485 if (!login1_seat_info)
1488 g_dbus_connection_register_object (connection,
1490 login1_seat_info->interfaces[0],
1491 &login1_seat_vtable,
1496 g_warning ("Failed to register login1 seat: %s", error->message);
1497 g_clear_error (&error);
1498 g_dbus_node_info_unref (login1_seat_info);
1502 g_dbus_connection_emit_signal (connection,
1504 "/org/freedesktop/login1",
1505 "org.freedesktop.login1.Manager",
1507 g_variant_new ("(so)", seat->id, seat->path),
1510 g_warning ("Failed to emit SeatNew: %s", error->message);
1511 g_clear_error (&error);
1518 find_login1_seat (const gchar *id)
1523 for (link = login1_seats; link; link = link->next)
1526 if (strcmp (seat->id, id) == 0)
1534 remove_login1_seat (GDBusConnection *connection, const gchar *id)
1537 GError *error = NULL;
1539 seat = find_login1_seat (id);
1543 g_dbus_connection_emit_signal (connection,
1545 "/org/freedesktop/login1",
1546 "org.freedesktop.login1.Manager",
1548 g_variant_new ("(so)", seat->id, seat->path),
1551 g_warning ("Failed to emit SeatNew: %s", error->message);
1552 g_clear_error (&error);
1554 login1_seats = g_list_remove (login1_seats, seat);
1556 g_free (seat->path);
1561 handle_login1_session_call (GDBusConnection *connection,
1562 const gchar *sender,
1563 const gchar *object_path,
1564 const gchar *interface_name,
1565 const gchar *method_name,
1566 GVariant *parameters,
1567 GDBusMethodInvocation *invocation,
1570 Login1Session *session = user_data;
1572 if (strcmp (method_name, "Lock") == 0)
1574 if (!session->locked)
1576 gchar *status = g_strdup_printf ("LOGIN1 LOCK-SESSION SESSION=%s", strrchr (object_path, '/') + 1);
1577 check_status (status);
1580 session->locked = TRUE;
1581 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1583 else if (strcmp (method_name, "Unlock") == 0)
1585 if (session->locked)
1587 gchar *status = g_strdup_printf ("LOGIN1 UNLOCK-SESSION SESSION=%s", strrchr (object_path, '/') + 1);
1588 check_status (status);
1591 session->locked = FALSE;
1592 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1594 else if (strcmp (method_name, "Activate") == 0)
1596 gchar *status = g_strdup_printf ("LOGIN1 ACTIVATE-SESSION SESSION=%s", strrchr (object_path, '/') + 1);
1597 check_status (status);
1600 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1603 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1606 static Login1Session *
1607 open_login1_session (GDBusConnection *connection,
1610 Login1Session *session;
1611 GError *error = NULL;
1612 GDBusNodeInfo *login1_session_info;
1614 const gchar *login1_session_interface =
1616 " <interface name='org.freedesktop.login1.Session'>"
1617 " <method name='Lock'/>"
1618 " <method name='Unlock'/>"
1619 " <method name='Activate'/>"
1622 static const GDBusInterfaceVTable login1_session_vtable =
1624 handle_login1_session_call,
1627 session = g_malloc0 (sizeof (Login1Session));
1628 login1_sessions = g_list_append (login1_sessions, session);
1630 session->path = g_strdup_printf ("/org/freedesktop/login1/Session/c%d", login1_session_index++);
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);
1655 handle_login1_call (GDBusConnection *connection,
1656 const gchar *sender,
1657 const gchar *object_path,
1658 const gchar *interface_name,
1659 const gchar *method_name,
1660 GVariant *parameters,
1661 GDBusMethodInvocation *invocation,
1664 if (strcmp (method_name, "ListSeats") == 0)
1666 GVariantBuilder seats;
1669 g_variant_builder_init (&seats, G_VARIANT_TYPE ("a(so)"));
1670 for (link = login1_seats; link; link = link->next)
1672 Login1Seat *seat = link->data;
1673 g_variant_builder_add (&seats, "(so)", seat->id, seat->path);
1675 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a(so))", &seats));
1677 else if (strcmp (method_name, "GetSessionByPID") == 0)
1679 /* Look for a session with our PID, and create one if we don't have one already. */
1682 Login1Session *ret = NULL;
1684 g_variant_get (parameters, "(u)", &pid);
1686 for (link = login1_sessions; link; link = link->next)
1688 Login1Session *session;
1689 session = link->data;
1690 if (session->pid == pid)
1698 ret = open_login1_session (connection, parameters);
1700 g_dbus_method_invocation_return_value (invocation,
1701 g_variant_new("(o)", ret->path));
1704 else if (strcmp (method_name, "CanReboot") == 0)
1706 check_status ("LOGIN1 CAN-REBOOT");
1707 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1709 else if (strcmp (method_name, "Reboot") == 0)
1711 gboolean interactive;
1712 g_variant_get (parameters, "(b)", &interactive);
1713 check_status ("LOGIN1 REBOOT");
1714 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1716 else if (strcmp (method_name, "CanPowerOff") == 0)
1718 check_status ("LOGIN1 CAN-POWER-OFF");
1719 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1721 else if (strcmp (method_name, "Suspend") == 0)
1723 gboolean interactive;
1724 g_variant_get (parameters, "(b)", &interactive);
1725 check_status ("LOGIN1 SUSPEND");
1726 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1728 else if (strcmp (method_name, "CanSuspend") == 0)
1730 check_status ("LOGIN1 CAN-SUSPEND");
1731 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1733 else if (strcmp (method_name, "PowerOff") == 0)
1735 gboolean interactive;
1736 g_variant_get (parameters, "(b)", &interactive);
1737 check_status ("LOGIN1 POWER-OFF");
1738 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1740 else if (strcmp (method_name, "CanHibernate") == 0)
1742 check_status ("LOGIN1 CAN-HIBERNATE");
1743 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1745 else if (strcmp (method_name, "Hibernate") == 0)
1747 gboolean interactive;
1748 g_variant_get (parameters, "(b)", &interactive);
1749 check_status ("LOGIN1 HIBERNATE");
1750 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1753 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1757 login1_name_acquired_cb (GDBusConnection *connection,
1761 const gchar *login1_interface =
1763 " <interface name='org.freedesktop.login1.Manager'>"
1764 " <method name='ListSeats'>"
1765 " <arg name='seats' type='a(so)' direction='out'/>"
1767 " <method name='GetSessionByPID'>"
1768 " <arg name='pid' type='u' direction='in'/>"
1769 " <arg name='session' type='o' direction='out'/>"
1771 " <method name='CanReboot'>"
1772 " <arg name='result' direction='out' type='s'/>"
1774 " <method name='Reboot'>"
1775 " <arg name='interactive' direction='in' type='b'/>"
1777 " <method name='CanPowerOff'>"
1778 " <arg name='result' direction='out' type='s'/>"
1780 " <method name='PowerOff'>"
1781 " <arg name='interactive' direction='in' type='b'/>"
1783 " <method name='CanSuspend'>"
1784 " <arg name='result' direction='out' type='s'/>"
1786 " <method name='Suspend'>"
1787 " <arg name='interactive' direction='in' type='b'/>"
1789 " <method name='CanHibernate'>"
1790 " <arg name='result' direction='out' type='s'/>"
1792 " <method name='Hibernate'>"
1793 " <arg name='interactive' direction='in' type='b'/>"
1795 " <signal name='SeatNew'>"
1796 " <arg name='seat' type='so'/>"
1798 " <signal name='SeatRemoved'>"
1799 " <arg name='seat' type='so'/>"
1803 static const GDBusInterfaceVTable login1_vtable =
1807 GDBusNodeInfo *login1_info;
1808 GError *error = NULL;
1810 login1_info = g_dbus_node_info_new_for_xml (login1_interface, &error);
1812 g_warning ("Failed to parse login1 D-Bus interface: %s", error->message);
1813 g_clear_error (&error);
1816 g_dbus_connection_register_object (connection,
1817 "/org/freedesktop/login1",
1818 login1_info->interfaces[0],
1823 g_warning ("Failed to register login1 service: %s", error->message);
1824 g_clear_error (&error);
1825 g_dbus_node_info_unref (login1_info);
1827 /* We always have seat0 */
1828 add_login1_seat (connection, "seat0", FALSE);
1831 if (service_count == 0)
1836 start_login1_daemon (void)
1839 g_bus_own_name (G_BUS_TYPE_SYSTEM,
1840 "org.freedesktop.login1",
1841 G_BUS_NAME_OWNER_FLAGS_NONE,
1843 login1_name_acquired_cb,
1849 static AccountsUser *
1850 get_accounts_user_by_uid (guint uid)
1854 for (link = accounts_users; link; link = link->next)
1856 AccountsUser *u = link->data;
1864 static AccountsUser *
1865 get_accounts_user_by_name (const gchar *username)
1869 for (link = accounts_users; link; link = link->next)
1871 AccountsUser *u = link->data;
1872 if (strcmp (u->user_name, username) == 0)
1880 accounts_user_set_hidden (AccountsUser *user, gboolean hidden, gboolean emit_signal)
1882 GError *error = NULL;
1884 user->hidden = hidden;
1886 if (user->hidden && user->id != 0)
1888 g_dbus_connection_unregister_object (accounts_connection, user->id);
1889 g_dbus_connection_emit_signal (accounts_connection,
1891 "/org/freedesktop/Accounts",
1892 "org.freedesktop.Accounts",
1894 g_variant_new ("(o)", user->path),
1897 g_warning ("Failed to emit UserDeleted: %s", error->message);
1898 g_clear_error (&error);
1902 if (!user->hidden && user->id == 0)
1904 user->id = g_dbus_connection_register_object (accounts_connection,
1906 user_info->interfaces[0],
1912 g_warning ("Failed to register user: %s", error->message);
1913 g_clear_error (&error);
1915 g_dbus_connection_emit_signal (accounts_connection,
1917 "/org/freedesktop/Accounts",
1918 "org.freedesktop.Accounts",
1920 g_variant_new ("(o)", user->path),
1923 g_warning ("Failed to emit UserAdded: %s", error->message);
1924 g_clear_error (&error);
1929 load_passwd_file (void)
1931 gchar *path, *data, **lines;
1932 gchar **user_filter = NULL;
1935 if (g_key_file_has_key (config, "test-runner-config", "accounts-service-user-filter", NULL))
1939 filter = g_key_file_get_string (config, "test-runner-config", "accounts-service-user-filter", NULL);
1940 user_filter = g_strsplit (filter, " ", -1);
1944 path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "passwd", NULL);
1945 g_file_get_contents (path, &data, NULL, NULL);
1947 lines = g_strsplit (data, "\n", -1);
1950 for (i = 0; lines[i]; i++)
1954 gchar *user_name, *real_name;
1955 AccountsUser *user = NULL;
1957 fields = g_strsplit (lines[i], ":", -1);
1958 if (fields == NULL || g_strv_length (fields) < 7)
1960 g_strfreev (fields);
1964 user_name = fields[0];
1965 uid = atoi (fields[2]);
1966 real_name = fields[4];
1968 user = get_accounts_user_by_uid (uid);
1972 GKeyFile *dmrc_file;
1974 user = g_malloc0 (sizeof (AccountsUser));
1975 accounts_users = g_list_append (accounts_users, user);
1977 /* Only allow users in whitelist */
1978 user->hidden = FALSE;
1983 user->hidden = TRUE;
1984 for (j = 0; user_filter[j] != NULL; j++)
1985 if (strcmp (user_name, user_filter[j]) == 0)
1986 user->hidden = FALSE;
1989 dmrc_file = g_key_file_new ();
1990 path = g_build_filename (temp_dir, "home", user_name, ".dmrc", NULL);
1991 g_key_file_load_from_file (dmrc_file, path, G_KEY_FILE_NONE, NULL);
1995 user->user_name = g_strdup (user_name);
1996 user->real_name = g_strdup (real_name);
1997 user->home_directory = g_build_filename (temp_dir, "home", user_name, NULL);
1998 user->language = g_key_file_get_string (dmrc_file, "Desktop", "Language", NULL);
1999 /* DMRC contains a locale, strip the codeset off it to get the language */
2002 gchar *c = strchr (user->language, '.');
2006 user->xsession = g_key_file_get_string (dmrc_file, "Desktop", "Session", NULL);
2007 user->layouts = g_key_file_get_string_list (dmrc_file, "X-Accounts", "Layouts", NULL, NULL);
2010 user->layouts = g_malloc (sizeof (gchar *) * 2);
2011 user->layouts[0] = g_key_file_get_string (dmrc_file, "Desktop", "Layout", NULL);
2012 user->layouts[1] = NULL;
2014 user->has_messages = g_key_file_get_boolean (dmrc_file, "X-Accounts", "HasMessages", NULL);
2015 user->path = g_strdup_printf ("/org/freedesktop/Accounts/User%d", uid);
2016 accounts_user_set_hidden (user, user->hidden, FALSE);
2018 g_key_file_free (dmrc_file);
2021 g_strfreev (fields);
2028 handle_accounts_call (GDBusConnection *connection,
2029 const gchar *sender,
2030 const gchar *object_path,
2031 const gchar *interface_name,
2032 const gchar *method_name,
2033 GVariant *parameters,
2034 GDBusMethodInvocation *invocation,
2037 if (strcmp (method_name, "ListCachedUsers") == 0)
2039 GVariantBuilder builder;
2042 g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
2044 load_passwd_file ();
2045 for (link = accounts_users; link; link = link->next)
2047 AccountsUser *user = link->data;
2048 if (!user->hidden && user->uid >= 1000)
2049 g_variant_builder_add_value (&builder, g_variant_new_object_path (user->path));
2052 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(ao)", &builder));
2054 else if (strcmp (method_name, "FindUserByName") == 0)
2056 AccountsUser *user = NULL;
2059 g_variant_get (parameters, "(&s)", &user_name);
2061 load_passwd_file ();
2062 user = get_accounts_user_by_name (user_name);
2066 accounts_user_set_hidden (user, FALSE, TRUE);
2067 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", user->path));
2070 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such user: %s", user_name);
2073 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
2077 handle_user_call (GDBusConnection *connection,
2078 const gchar *sender,
2079 const gchar *object_path,
2080 const gchar *interface_name,
2081 const gchar *method_name,
2082 GVariant *parameters,
2083 GDBusMethodInvocation *invocation,
2086 AccountsUser *user = user_data;
2088 if (strcmp (method_name, "SetXSession") == 0)
2092 g_variant_get (parameters, "(&s)", &xsession);
2094 g_free (user->xsession);
2095 user->xsession = g_strdup (xsession);
2097 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
2099 /* And notify others that it took */
2100 g_dbus_connection_emit_signal (accounts_connection,
2103 "org.freedesktop.Accounts.User",
2105 g_variant_new ("()"),
2109 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
2113 handle_user_get_property (GDBusConnection *connection,
2114 const gchar *sender,
2115 const gchar *object_path,
2116 const gchar *interface_name,
2117 const gchar *property_name,
2121 AccountsUser *user = user_data;
2123 if (strcmp (property_name, "UserName") == 0)
2124 return g_variant_new_string (user->user_name);
2125 else if (strcmp (property_name, "RealName") == 0)
2126 return g_variant_new_string (user->real_name);
2127 else if (strcmp (property_name, "HomeDirectory") == 0)
2128 return g_variant_new_string (user->home_directory);
2129 else if (strcmp (property_name, "SystemAccount") == 0)
2130 return g_variant_new_boolean (user->uid < 1000);
2131 else if (strcmp (property_name, "BackgroundFile") == 0)
2132 return g_variant_new_string (user->background ? user->background : "");
2133 else if (strcmp (property_name, "Language") == 0)
2134 return g_variant_new_string (user->language ? user->language : "");
2135 else if (strcmp (property_name, "IconFile") == 0)
2136 return g_variant_new_string (user->image ? user->image : "");
2137 else if (strcmp (property_name, "Shell") == 0)
2138 return g_variant_new_string ("/bin/sh");
2139 else if (strcmp (property_name, "Uid") == 0)
2140 return g_variant_new_uint64 (user->uid);
2141 else if (strcmp (property_name, "XSession") == 0)
2142 return g_variant_new_string (user->xsession ? user->xsession : "");
2143 else if (strcmp (property_name, "XKeyboardLayouts") == 0)
2145 if (user->layouts != NULL)
2146 return g_variant_new_strv ((const gchar * const *) user->layouts, -1);
2148 return g_variant_new_strv (NULL, 0);
2150 else if (strcmp (property_name, "XHasMessages") == 0)
2151 return g_variant_new_boolean (user->has_messages);
2157 accounts_name_acquired_cb (GDBusConnection *connection,
2161 const gchar *accounts_interface =
2163 " <interface name='org.freedesktop.Accounts'>"
2164 " <method name='ListCachedUsers'>"
2165 " <arg name='user' direction='out' type='ao'/>"
2167 " <method name='FindUserByName'>"
2168 " <arg name='name' direction='in' type='s'/>"
2169 " <arg name='user' direction='out' type='o'/>"
2171 " <signal name='UserAdded'>"
2172 " <arg name='user' type='o'/>"
2174 " <signal name='UserDeleted'>"
2175 " <arg name='user' type='o'/>"
2179 static const GDBusInterfaceVTable accounts_vtable =
2181 handle_accounts_call,
2183 const gchar *user_interface =
2185 " <interface name='org.freedesktop.Accounts.User'>"
2186 " <method name='SetXSession'>"
2187 " <arg name='x_session' direction='in' type='s'/>"
2189 " <property name='UserName' type='s' access='read'/>"
2190 " <property name='RealName' type='s' access='read'/>"
2191 " <property name='HomeDirectory' type='s' access='read'/>"
2192 " <property name='SystemAccount' type='b' access='read'/>"
2193 " <property name='BackgroundFile' type='s' access='read'/>"
2194 " <property name='Language' type='s' access='read'/>"
2195 " <property name='IconFile' type='s' access='read'/>"
2196 " <property name='Shell' type='s' access='read'/>"
2197 " <property name='Uid' type='t' access='read'/>"
2198 " <property name='XSession' type='s' access='read'/>"
2199 " <property name='XKeyboardLayouts' type='as' access='read'/>"
2200 " <property name='XHasMessages' type='b' access='read'/>"
2201 " <signal name='Changed' />"
2204 GError *error = NULL;
2206 accounts_connection = connection;
2208 accounts_info = g_dbus_node_info_new_for_xml (accounts_interface, &error);
2210 g_warning ("Failed to parse D-Bus interface: %s", error->message);
2211 g_clear_error (&error);
2214 user_info = g_dbus_node_info_new_for_xml (user_interface, &error);
2216 g_warning ("Failed to parse D-Bus interface: %s", error->message);
2217 g_clear_error (&error);
2220 g_dbus_connection_register_object (connection,
2221 "/org/freedesktop/Accounts",
2222 accounts_info->interfaces[0],
2228 g_warning ("Failed to register accounts service: %s", error->message);
2229 g_clear_error (&error);
2230 g_dbus_node_info_unref (accounts_info);
2233 if (service_count == 0)
2238 start_accounts_service_daemon (void)
2241 g_bus_own_name (G_BUS_TYPE_SYSTEM,
2242 "org.freedesktop.Accounts",
2243 G_BUS_NAME_OWNER_FLAGS_NONE,
2244 accounts_name_acquired_cb,
2258 signal_cb (gpointer user_data)
2260 g_print ("Caught signal, quitting\n");
2261 quit (EXIT_FAILURE);
2266 properties_changed_cb (GDBusConnection *connection,
2267 const gchar *sender_name,
2268 const gchar *object_path,
2269 const gchar *interface_name,
2270 const gchar *signal_name,
2271 GVariant *parameters,
2274 const gchar *interface, *name;
2277 GVariantIter *changed_properties, *invalidated_properties;
2280 g_variant_get (parameters, "(&sa{sv}as)", &interface, &changed_properties, &invalidated_properties);
2282 status = g_string_new ("RUNNER DBUS-PROPERTIES-CHANGED");
2283 g_string_append_printf (status, " PATH=%s", object_path);
2284 g_string_append_printf (status, " INTERFACE=%s", interface);
2285 for (i = 0; g_variant_iter_loop (changed_properties, "{&sv}", &name, &value); i++)
2288 g_string_append (status, " CHANGED=");
2290 g_string_append (status, ",");
2291 g_string_append (status, name);
2292 if (g_variant_is_of_type (value, G_VARIANT_TYPE ("ao")))
2297 g_variant_iter_init (&iter, value);
2298 while (g_variant_iter_loop (&iter, "&o", &path))
2299 g_string_append_printf (status, ":%s", path);
2302 for (i = 0; g_variant_iter_loop (invalidated_properties, "&s", &name); i++)
2305 g_string_append (status, " INVALIDATED=");
2307 g_string_append (status, ",");
2308 g_string_append (status, name);
2311 check_status (status->str);
2312 g_string_free (status, TRUE);
2316 dbus_signal_cb (GDBusConnection *connection,
2317 const gchar *sender_name,
2318 const gchar *object_path,
2319 const gchar *interface_name,
2320 const gchar *signal_name,
2321 GVariant *parameters,
2326 status = g_string_new ("RUNNER DBUS-SIGNAL");
2327 g_string_append_printf (status, " PATH=%s", object_path);
2328 g_string_append_printf (status, " INTERFACE=%s", interface_name);
2329 g_string_append_printf (status, " NAME=%s", signal_name);
2331 check_status (status->str);
2332 g_string_free (status, TRUE);
2336 main (int argc, char **argv)
2340 gchar *greeter = NULL, *script_name, *config_file, *additional_system_config;
2341 gchar *additional_config, *path, *path1, *path2, *ld_preload, *ld_library_path, *home_dir;
2342 GString *passwd_data, *group_data;
2343 GSource *status_source;
2345 GError *error = NULL;
2347 #if !defined(GLIB_VERSION_2_36)
2351 loop = g_main_loop_new (NULL, FALSE);
2353 g_unix_signal_add (SIGINT, signal_cb, NULL);
2354 g_unix_signal_add (SIGTERM, signal_cb, NULL);
2356 children = g_hash_table_new (g_direct_hash, g_direct_equal);
2360 g_printerr ("Usage %s SCRIPT-NAME GREETER\n", argv[0]);
2361 quit (EXIT_FAILURE);
2363 script_name = argv[1];
2364 config_file = g_strdup_printf ("%s.conf", script_name);
2365 config_path = g_build_filename (SRCDIR, "tests", "scripts", config_file, NULL);
2366 g_free (config_file);
2368 config = g_key_file_new ();
2369 g_key_file_load_from_file (config, config_path, G_KEY_FILE_NONE, NULL);
2371 load_script (config_path);
2373 if (!getcwd (cwd, 1024))
2375 g_critical ("Error getting current directory: %s", strerror (errno));
2376 quit (EXIT_FAILURE);
2379 /* Don't contact our X server */
2380 g_unsetenv ("DISPLAY");
2382 /* Don't let XDG vars from system affect tests */
2383 g_unsetenv ("XDG_CONFIG_DIRS");
2384 g_unsetenv ("XDG_DATA_DIRS");
2386 /* Override system calls */
2387 ld_preload = g_build_filename (BUILDDIR, "tests", "src", ".libs", "libsystem.so", NULL);
2388 g_setenv ("LD_PRELOAD", ld_preload, TRUE);
2389 g_free (ld_preload);
2391 /* Run test programs */
2392 path = g_strdup_printf ("%s/tests/src/.libs:%s/tests/src:%s/tests/src:%s/src:%s", BUILDDIR, BUILDDIR, SRCDIR, BUILDDIR, g_getenv ("PATH"));
2393 g_setenv ("PATH", path, TRUE);
2396 /* Use locally built libraries */
2397 path1 = g_build_filename (BUILDDIR, "liblightdm-gobject", ".libs", NULL);
2398 path2 = g_build_filename (BUILDDIR, "liblightdm-qt", ".libs", NULL);
2399 ld_library_path = g_strdup_printf ("%s:%s", path1, path2);
2402 g_setenv ("LD_LIBRARY_PATH", ld_library_path, TRUE);
2403 g_free (ld_library_path);
2404 path1 = g_build_filename (BUILDDIR, "liblightdm-gobject", NULL);
2405 g_setenv ("GI_TYPELIB_PATH", path1, TRUE);
2408 /* Run in a temporary directory inside the build directory */
2409 /* Note we have to pick a name that is short since Unix sockets in this directory have a 108 character limit on their paths */
2414 name = g_strdup_printf (".r%d", i);
2416 temp_dir = g_build_filename ("/tmp", name, NULL);
2418 if (!g_file_test (temp_dir, G_FILE_TEST_EXISTS))
2422 g_mkdir_with_parents (temp_dir, 0755);
2423 g_setenv ("LIGHTDM_TEST_ROOT", temp_dir, TRUE);
2425 /* Open socket for status */
2426 /* Note we have to pick a socket name that is short since there is a 108 character limit on the name */
2427 status_socket_name = g_build_filename (temp_dir, ".s", NULL);
2428 unlink (status_socket_name);
2429 status_socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, &error);
2431 g_warning ("Error creating status socket %s: %s", status_socket_name, error->message);
2432 g_clear_error (&error);
2435 GSocketAddress *address;
2438 address = g_unix_socket_address_new (status_socket_name);
2439 result = g_socket_bind (status_socket, address, FALSE, &error);
2440 g_object_unref (address);
2442 g_warning ("Error binding status socket %s: %s", status_socket_name, error->message);
2443 g_clear_error (&error);
2446 result = g_socket_listen (status_socket, &error);
2448 g_warning ("Error listening on status socket %s: %s", status_socket_name, error->message);
2449 g_clear_error (&error);
2453 g_object_unref (status_socket);
2454 status_socket = NULL;
2458 quit (EXIT_FAILURE);
2459 status_source = g_socket_create_source (status_socket, G_IO_IN, NULL);
2460 g_source_set_callback (status_source, status_connect_cb, NULL, NULL);
2461 g_source_attach (status_source, NULL);
2463 /* Set up a skeleton file system */
2464 g_mkdir_with_parents (g_strdup_printf ("%s/etc", temp_dir), 0755);
2465 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share", temp_dir), 0755);
2466 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/sessions", temp_dir), 0755);
2467 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/remote-sessions", temp_dir), 0755);
2468 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/greeters", temp_dir), 0755);
2469 g_mkdir_with_parents (g_strdup_printf ("%s/tmp", temp_dir), 0755);
2470 g_mkdir_with_parents (g_strdup_printf ("%s/var/lib/lightdm-data", temp_dir), 0755);
2471 g_mkdir_with_parents (g_strdup_printf ("%s/var/run", temp_dir), 0755);
2472 g_mkdir_with_parents (g_strdup_printf ("%s/var/log", temp_dir), 0755);
2474 /* Copy over the configuration */
2475 g_mkdir_with_parents (g_strdup_printf ("%s/etc/lightdm", temp_dir), 0755);
2476 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))
2477 if (system (g_strdup_printf ("cp %s %s/etc/lightdm/lightdm.conf", config_path, temp_dir)))
2478 perror ("Failed to copy configuration");
2480 additional_system_config = g_key_file_get_string (config, "test-runner-config", "additional-system-config", NULL);
2481 if (additional_system_config)
2485 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/lightdm.conf.d", temp_dir), 0755);
2487 files = g_strsplit (additional_system_config, " ", -1);
2488 for (i = 0; files[i]; i++)
2489 if (system (g_strdup_printf ("cp %s/tests/scripts/%s %s/usr/share/lightdm/lightdm.conf.d", SRCDIR, files[i], temp_dir)))
2490 perror ("Failed to copy configuration");
2494 additional_config = g_key_file_get_string (config, "test-runner-config", "additional-config", NULL);
2495 if (additional_config)
2499 g_mkdir_with_parents (g_strdup_printf ("%s/etc/xdg/lightdm/lightdm.conf.d", temp_dir), 0755);
2501 files = g_strsplit (additional_config, " ", -1);
2502 for (i = 0; files[i]; i++)
2503 if (system (g_strdup_printf ("cp %s/tests/scripts/%s %s/etc/xdg/lightdm/lightdm.conf.d", SRCDIR, files[i], temp_dir)))
2504 perror ("Failed to copy configuration");
2508 if (g_key_file_has_key (config, "test-runner-config", "shared-data-dirs", NULL))
2514 dir_string = g_key_file_get_string (config, "test-runner-config", "shared-data-dirs", NULL);
2515 dirs = g_strsplit (dir_string, " ", -1);
2516 g_free (dir_string);
2518 for (i = 0; dirs[i]; i++)
2520 gchar **fields = g_strsplit (dirs[i], ":", -1);
2521 if (g_strv_length (fields) == 4)
2523 gchar *path = g_strdup_printf ("%s/var/lib/lightdm-data/%s", temp_dir, fields[0]);
2524 int uid = g_ascii_strtoll (fields[1], NULL, 10);
2525 int gid = g_ascii_strtoll (fields[2], NULL, 10);
2526 int mode = g_ascii_strtoll (fields[3], NULL, 8);
2527 g_mkdir (path, mode);
2528 g_chmod (path, mode); /* mkdir filters by umask, so make sure we have what we want */
2529 if (chown (path, uid, gid) < 0)
2530 g_warning ("chown (%s) failed: %s", path, strerror (errno));
2533 g_strfreev (fields);
2539 /* Always copy the script */
2540 if (system (g_strdup_printf ("cp %s %s/script", config_path, temp_dir)))
2541 perror ("Failed to copy configuration");
2543 /* Copy over the greeter files */
2544 if (system (g_strdup_printf ("cp %s/sessions/* %s/usr/share/lightdm/sessions", DATADIR, temp_dir)))
2545 perror ("Failed to copy sessions");
2546 if (system (g_strdup_printf ("cp %s/remote-sessions/* %s/usr/share/lightdm/remote-sessions", DATADIR, temp_dir)))
2547 perror ("Failed to copy remote sessions");
2548 if (system (g_strdup_printf ("cp %s/greeters/* %s/usr/share/lightdm/greeters", DATADIR, temp_dir)))
2549 perror ("Failed to copy greeters");
2551 /* Set up the default greeter */
2552 path = g_build_filename (temp_dir, "usr", "share", "lightdm", "greeters", "default.desktop", NULL);
2553 greeter = g_strdup_printf ("%s.desktop", argv[2]);
2554 if (symlink (greeter, path) < 0)
2556 g_printerr ("Failed to make greeter symlink %s->%s: %s\n", path, greeter, strerror (errno));
2557 quit (EXIT_FAILURE);
2562 home_dir = g_build_filename (temp_dir, "home", NULL);
2564 /* Make fake users */
2574 {"root", "", "root", 0},
2575 /* Unprivileged account for greeters */
2576 {"lightdm", "", "", 100},
2577 /* These accounts have a password */
2578 {"have-password1", "password", "Password User 1", 1000},
2579 {"have-password2", "password", "Password User 2", 1001},
2580 {"have-password3", "password", "Password User 3", 1002},
2581 {"have-password4", "password", "Password User 4", 1003},
2582 /* This account always prompts for a password, even if using the lightdm-autologin service */
2583 {"always-password", "password", "Password User 4", 1004},
2584 /* These accounts have no password */
2585 {"no-password1", "", "No Password User 1", 1005},
2586 {"no-password2", "", "No Password User 2", 1006},
2587 {"no-password3", "", "No Password User 3", 1007},
2588 {"no-password4", "", "No Password User 4", 1008},
2589 /* This account has a keyboard layout */
2590 {"have-layout", "", "Layout User", 1009},
2591 /* This account has a set of keyboard layouts */
2592 {"have-layouts", "", "Layouts User", 1010},
2593 /* This account has a language set */
2594 {"have-language", "", "Language User", 1011},
2595 /* This account has a preconfigured session */
2596 {"have-session", "", "Session User", 1012},
2597 /* This account has the home directory mounted on login */
2598 {"mount-home-dir", "", "Mounted Home Dir User", 1013},
2599 /* This account is denied access */
2600 {"denied", "", "Denied User", 1014},
2601 /* This account has expired */
2602 {"expired", "", "Expired User", 1015},
2603 /* This account needs a password change */
2604 {"new-authtok", "", "New Token User", 1016},
2605 /* This account is switched to change-user2 when authentication succeeds */
2606 {"change-user1", "", "Change User 1", 1017},
2607 {"change-user2", "", "Change User 2", 1018},
2608 /* This account switches to invalid-user when authentication succeeds */
2609 {"change-user-invalid", "", "Invalid Change User", 1019},
2610 /* This account crashes on authentication */
2611 {"crash-authenticate", "", "Crash Auth User", 1020},
2612 /* This account shows an informational prompt on login */
2613 {"info-prompt", "password", "Info Prompt", 1021},
2614 /* This account shows multiple informational prompts on login */
2615 {"multi-info-prompt","password", "Multi Info Prompt", 1022},
2616 /* This account uses two factor authentication */
2617 {"two-factor", "password", "Two Factor", 1023},
2618 /* This account has a special group */
2619 {"group-member", "password", "Group Member", 1024},
2620 /* This account has the home directory created when the session starts */
2621 {"make-home-dir", "", "Make Home Dir User", 1025},
2622 /* This account fails to open a session */
2623 {"session-error", "password", "Session Error", 1026},
2624 /* This account can't establish credentials */
2625 {"cred-error", "password", "Cred Error", 1027},
2626 /* This account has expired credentials */
2627 {"cred-expired", "password", "Cred Expired", 1028},
2628 /* This account has cannot access their credentials */
2629 {"cred-unavail", "password", "Cred Unavail", 1029},
2630 /* This account sends informational messages for each PAM function that is called */
2631 {"log-pam", "password", "Log PAM", 1030},
2632 /* This account shows multiple prompts on login */
2633 {"multi-prompt", "password", "Multi Prompt", 1031},
2634 /* This account has an existing corrupt X authority */
2635 {"corrupt-xauth", "password", "Corrupt Xauthority", 1032},
2636 /* User to test properties */
2637 {"prop-user", "", "TEST", 1033},
2638 {NULL, NULL, NULL, 0}
2640 passwd_data = g_string_new ("");
2641 group_data = g_string_new ("");
2642 for (i = 0; users[i].user_name; i++)
2644 GKeyFile *dmrc_file;
2645 gboolean save_dmrc = FALSE;
2647 if (strcmp (users[i].user_name, "mount-home-dir") != 0 && strcmp (users[i].user_name, "make-home-dir") != 0)
2649 path = g_build_filename (home_dir, users[i].user_name, NULL);
2650 g_mkdir_with_parents (path, 0755);
2651 if (chown (path, users[i].uid, users[i].uid) < 0)
2652 g_debug ("chown (%s) failed: %s", path, strerror (errno));
2656 dmrc_file = g_key_file_new ();
2657 if (strcmp (users[i].user_name, "have-session") == 0)
2659 g_key_file_set_string (dmrc_file, "Desktop", "Session", "alternative");
2662 if (strcmp (users[i].user_name, "have-layout") == 0)
2664 g_key_file_set_string (dmrc_file, "Desktop", "Layout", "us");
2667 if (strcmp (users[i].user_name, "have-layouts") == 0)
2669 g_key_file_set_string (dmrc_file, "Desktop", "Layout", "ru");
2670 g_key_file_set_string (dmrc_file, "X-Accounts", "Layouts", "fr\toss;ru;");
2673 if (strcmp (users[i].user_name, "have-language") == 0)
2675 g_key_file_set_string (dmrc_file, "Desktop", "Language", "en_AU.utf8");
2683 path = g_build_filename (home_dir, users[i].user_name, ".dmrc", NULL);
2684 data = g_key_file_to_data (dmrc_file, NULL, NULL);
2685 g_file_set_contents (path, data, -1, NULL);
2690 g_key_file_free (dmrc_file);
2692 /* Write corrupt X authority file */
2693 if (strcmp (users[i].user_name, "corrupt-xauth") == 0)
2695 gchar data[1] = { 0xFF };
2697 path = g_build_filename (home_dir, users[i].user_name, ".Xauthority", NULL);
2698 g_file_set_contents (path, data, 1, NULL);
2699 chmod (path, S_IRUSR | S_IWUSR);
2703 /* Add passwd file entry */
2704 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);
2706 /* Add group file entry */
2707 g_string_append_printf (group_data, "%s:x:%d:%s\n", users[i].user_name, users[i].uid, users[i].user_name);
2709 path = g_build_filename (temp_dir, "etc", "passwd", NULL);
2710 g_file_set_contents (path, passwd_data->str, -1, NULL);
2712 g_string_free (passwd_data, TRUE);
2714 /* Add an extra test group */
2715 g_string_append_printf (group_data, "test-group:x:111:\n");
2717 path = g_build_filename (temp_dir, "etc", "group", NULL);
2718 g_file_set_contents (path, group_data->str, -1, NULL);
2720 g_string_free (group_data, TRUE);
2722 if (g_key_file_has_key (config, "test-runner-config", "timeout", NULL))
2723 status_timeout_ms = g_key_file_get_integer (config, "test-runner-config", "timeout", NULL) * 1000;
2725 /* Start D-Bus services */
2726 if (!g_key_file_get_boolean (config, "test-runner-config", "disable-upower", NULL))
2727 start_upower_daemon ();
2728 if (!g_key_file_get_boolean (config, "test-runner-config", "disable-console-kit", NULL))
2729 start_console_kit_daemon ();
2730 if (!g_key_file_get_boolean (config, "test-runner-config", "disable-login1", NULL))
2731 start_login1_daemon ();
2732 if (!g_key_file_get_boolean (config, "test-runner-config", "disable-accounts-service", NULL))
2733 start_accounts_service_daemon ();
2735 /* Listen for daemon bus events */
2736 if (g_key_file_get_boolean (config, "test-runner-config", "log-dbus", NULL))
2738 g_dbus_connection_signal_subscribe (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
2739 "org.freedesktop.DisplayManager",
2740 "org.freedesktop.DBus.Properties",
2741 "PropertiesChanged",
2744 G_DBUS_SIGNAL_FLAGS_NONE,
2745 properties_changed_cb,
2748 g_dbus_connection_signal_subscribe (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
2749 "org.freedesktop.DisplayManager",
2750 "org.freedesktop.DisplayManager",
2754 G_DBUS_SIGNAL_FLAGS_NONE,
2760 g_main_loop_run (loop);
2762 return EXIT_FAILURE;