7 #include <glib/gstdio.h>
10 #include <gio/gunixsocketaddress.h>
14 /* Timeout in ms waiting for the status we expect */
15 static int status_timeout_ms = 4000;
17 /* Timeout in ms to wait for SIGTERM to be handled by a child process */
18 #define KILL_TIMEOUT 2000
20 static gchar *test_runner_command;
21 static gchar *config_path;
22 static GKeyFile *config;
23 static GSocket *status_socket = NULL;
24 static gchar *status_socket_name = NULL;
25 static GList *statuses = NULL;
31 static GList *script = NULL;
32 static guint status_timeout = 0;
33 static gchar *temp_dir = NULL;
34 static int service_count;
40 static Process *lightdm_process = NULL;
41 static GHashTable *children = NULL;
42 static gboolean stop = FALSE;
43 static gint exit_status = 0;
44 static GDBusConnection *accounts_connection = NULL;
45 static GDBusNodeInfo *accounts_info;
46 static GDBusNodeInfo *user_info;
52 gchar *home_directory;
60 gboolean has_messages;
63 static GList *accounts_users = NULL;
64 static void handle_user_call (GDBusConnection *connection,
66 const gchar *object_path,
67 const gchar *interface_name,
68 const gchar *method_name,
70 GDBusMethodInvocation *invocation,
72 static GVariant *handle_user_get_property (GDBusConnection *connection,
74 const gchar *object_path,
75 const gchar *interface_name,
76 const gchar *property_name,
79 static const GDBusInterfaceVTable user_vtable =
82 handle_user_get_property,
84 static GDBusConnection *ck_connection = NULL;
85 static GDBusNodeInfo *ck_session_info;
93 static GList *ck_sessions = NULL;
94 static gint ck_session_index = 0;
95 static void handle_ck_session_call (GDBusConnection *connection,
97 const gchar *object_path,
98 const gchar *interface_name,
99 const gchar *method_name,
100 GVariant *parameters,
101 GDBusMethodInvocation *invocation,
103 static const GDBusInterfaceVTable ck_session_vtable =
105 handle_ck_session_call,
115 static GList *login1_sessions = NULL;
116 static gint login1_session_index = 0;
123 static GList *status_clients = NULL;
125 static void ready (void);
126 static void quit (int status);
127 static void check_status (const gchar *status);
128 static AccountsUser *get_accounts_user_by_uid (guint uid);
129 static AccountsUser *get_accounts_user_by_name (const gchar *username);
130 static void accounts_user_set_hidden (AccountsUser *user, gboolean hidden, gboolean emit_signal);
133 kill_timeout_cb (gpointer data)
135 Process *process = data;
137 process->kill_timeout = 0;
139 if (getenv ("DEBUG"))
140 g_print ("Sending SIGKILL to process %d\n", process->pid);
141 kill (process->pid, SIGKILL);
147 stop_process (Process *process)
149 if (process->kill_timeout != 0)
152 if (getenv ("DEBUG"))
153 g_print ("Sending SIGTERM to process %d\n", process->pid);
154 kill (process->pid, SIGTERM);
155 process->kill_timeout = g_timeout_add (KILL_TIMEOUT, kill_timeout_cb, process);
159 process_exit_cb (GPid pid, gint status, gpointer data)
164 if (getenv ("DEBUG"))
166 if (WIFEXITED (status))
167 g_print ("Process %d exited with status %d\n", pid, WEXITSTATUS (status));
169 g_print ("Process %d terminated with signal %d\n", pid, WTERMSIG (status));
172 if (lightdm_process && pid == lightdm_process->pid)
174 process = lightdm_process;
175 lightdm_process = NULL;
176 if (WIFEXITED (status))
177 status_text = g_strdup_printf ("RUNNER DAEMON-EXIT STATUS=%d", WEXITSTATUS (status));
179 status_text = g_strdup_printf ("RUNNER DAEMON-TERMINATE SIGNAL=%d", WTERMSIG (status));
180 check_status (status_text);
184 process = g_hash_table_lookup (children, GINT_TO_POINTER (pid));
187 g_hash_table_remove (children, GINT_TO_POINTER (pid));
190 if (process->kill_timeout)
191 g_source_remove (process->kill_timeout);
192 process->kill_timeout = 0;
194 /* Quit once all children have stopped */
200 watch_process (pid_t pid)
204 process = g_malloc0 (sizeof (Process));
206 process->kill_timeout = 0;
208 if (getenv ("DEBUG"))
209 g_print ("Watching process %d\n", process->pid);
210 g_child_watch_add (process->pid, process_exit_cb, NULL);
221 exit_status = status;
224 /* Stop all the children */
225 g_hash_table_iter_init (&iter, children);
230 if (!g_hash_table_iter_next (&iter, &key, &value))
233 stop_process ((Process *)value);
236 /* Don't quit until all children are stopped */
237 if (g_hash_table_size (children) > 0)
240 /* Stop the daemon */
243 stop_process (lightdm_process);
247 if (status_socket_name)
248 unlink (status_socket_name);
250 if (temp_dir && getenv ("DEBUG") == NULL)
252 gchar *command = g_strdup_printf ("rm -rf %s", temp_dir);
253 if (system (command))
254 perror ("Failed to delete temp directory");
261 fail (const gchar *event, const gchar *expected)
268 g_printerr ("Command line: %s", test_runner_command);
269 g_printerr ("Events:\n");
270 for (link = statuses; link; link = link->next)
271 g_printerr (" %s\n", (gchar *)link->data);
273 g_printerr (" %s\n", event);
275 g_printerr (" ^^^ expected \"%s\"\n", expected);
277 g_printerr ("^^^ expected nothing\n");
283 get_prefix (const gchar *text)
288 prefix = g_strdup (text);
289 for (i = 0; prefix[i] != '\0' && prefix[i] != ' '; i++);
296 get_script_line (const gchar *prefix)
300 for (link = script; link; link = link->next)
302 ScriptLine *line = link->data;
304 /* Ignore lines with other prefixes */
310 p = get_prefix (line->text);
311 matches = strcmp (prefix, p) == 0;
326 stop_loop (gpointer user_data)
328 g_main_loop_quit ((GMainLoop *)user_data);
329 return G_SOURCE_REMOVE;
333 handle_command (const gchar *command)
340 while (*c && !isspace (*c))
342 name = g_strdup_printf ("%.*s", (int) (c - command), command);
344 params = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
348 gchar *param_name, *param_value;
353 while (*c && !isspace (*c) && *c != '=')
358 param_name = g_strdup_printf ("%.*s", (int) (c - start), start);
367 gboolean escaped = FALSE;
371 value = g_string_new ("");
378 g_string_append_c (value, '\\');
384 else if (!escaped && *c == '\"')
387 g_string_append_c (value, *c);
390 param_value = value->str;
391 g_string_free (value, FALSE);
398 while (*c && !isspace (*c))
400 param_value = g_strdup_printf ("%.*s", (int) (c - start), start);
404 param_value = g_strdup ("");
406 g_hash_table_insert (params, param_name, param_value);
409 if (strcmp (name, "START-DAEMON") == 0)
411 GString *command_line;
412 gchar **lightdm_argv;
414 GError *error = NULL;
416 command_line = g_string_new ("lightdm");
417 if (getenv ("DEBUG"))
418 g_string_append (command_line, " --debug");
419 g_string_append_printf (command_line, " --cache-dir %s/cache", temp_dir);
421 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",
422 g_getenv ("PATH"), g_getenv ("LD_PRELOAD"), g_getenv ("LD_LIBRARY_PATH"), g_getenv ("LIGHTDM_TEST_ROOT"), g_getenv ("DBUS_SESSION_BUS_ADDRESS"),
425 if (!g_shell_parse_argv (command_line->str, NULL, &lightdm_argv, &error))
427 g_warning ("Error parsing command line: %s", error->message);
430 g_clear_error (&error);
432 if (!g_spawn_async (NULL, lightdm_argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL, NULL, &lightdm_pid, &error))
434 g_warning ("Error launching LightDM: %s", error->message);
437 g_clear_error (&error);
438 lightdm_process = watch_process (lightdm_pid);
440 check_status ("RUNNER DAEMON-START");
442 else if (strcmp (name, "WAIT") == 0)
444 /* Use a main loop so that our DBus functions are still responsive */
445 GMainLoop *loop = g_main_loop_new (NULL, FALSE);
446 g_timeout_add_seconds (1, stop_loop, loop);
447 g_main_loop_run (loop);
448 g_main_loop_unref (loop);
450 else if (strcmp (name, "LIST-SEATS") == 0)
452 GVariant *result, *value;
458 result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
459 "org.freedesktop.DisplayManager",
460 "/org/freedesktop/DisplayManager",
461 "org.freedesktop.DBus.Properties",
463 g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Seats"),
464 G_VARIANT_TYPE ("(v)"),
465 G_DBUS_CALL_FLAGS_NONE,
470 status = g_string_new ("RUNNER LIST-SEATS SEATS=");
471 g_variant_get (result, "(v)", &value);
472 g_variant_get (value, "ao", &iter);
473 while (g_variant_iter_loop (iter, "&o", &path))
476 g_string_append (status, ",");
477 g_string_append (status, path);
480 g_variant_unref (value);
481 g_variant_unref (result);
483 check_status (status->str);
484 g_string_free (status, TRUE);
486 else if (strcmp (name, "LIST-SESSIONS") == 0)
488 GVariant *result, *value;
494 result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
495 "org.freedesktop.DisplayManager",
496 "/org/freedesktop/DisplayManager",
497 "org.freedesktop.DBus.Properties",
499 g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Sessions"),
500 G_VARIANT_TYPE ("(v)"),
501 G_DBUS_CALL_FLAGS_NONE,
506 status = g_string_new ("RUNNER LIST-SESSIONS SESSIONS=");
507 g_variant_get (result, "(v)", &value);
508 g_variant_get (value, "ao", &iter);
509 while (g_variant_iter_loop (iter, "&o", &path))
512 g_string_append (status, ",");
513 g_string_append (status, path);
516 g_variant_unref (value);
517 g_variant_unref (result);
519 check_status (status->str);
520 g_string_free (status, TRUE);
522 else if (strcmp (name, "SWITCH-TO-GREETER") == 0)
524 g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
525 "org.freedesktop.DisplayManager",
526 "/org/freedesktop/DisplayManager/Seat0",
527 "org.freedesktop.DisplayManager.Seat",
529 g_variant_new ("()"),
530 G_VARIANT_TYPE ("()"),
531 G_DBUS_CALL_FLAGS_NONE,
535 check_status ("RUNNER SWITCH-TO-GREETER");
537 else if (strcmp (name, "SWITCH-TO-USER") == 0)
539 gchar *status_text, *username;
541 username = g_hash_table_lookup (params, "USERNAME");
542 g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
543 "org.freedesktop.DisplayManager",
544 "/org/freedesktop/DisplayManager/Seat0",
545 "org.freedesktop.DisplayManager.Seat",
547 g_variant_new ("(ss)", username, ""),
548 G_VARIANT_TYPE ("()"),
549 G_DBUS_CALL_FLAGS_NONE,
553 status_text = g_strdup_printf ("RUNNER SWITCH-TO-USER USERNAME=%s", username);
554 check_status (status_text);
555 g_free (status_text);
557 else if (strcmp (name, "SWITCH-TO-GUEST") == 0)
559 g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
560 "org.freedesktop.DisplayManager",
561 "/org/freedesktop/DisplayManager/Seat0",
562 "org.freedesktop.DisplayManager.Seat",
564 g_variant_new ("(s)", ""),
565 G_VARIANT_TYPE ("()"),
566 G_DBUS_CALL_FLAGS_NONE,
570 check_status ("RUNNER SWITCH-TO-GUEST");
572 else if (strcmp (name, "STOP-DAEMON") == 0)
573 stop_process (lightdm_process);
574 // FIXME: Make generic RUN-COMMAND
575 else if (strcmp (name, "START-XSERVER") == 0)
577 gchar *xserver_args, *command_line;
581 GError *error = NULL;
583 xserver_args = g_hash_table_lookup (params, "ARGS");
586 command_line = g_strdup_printf ("%s/tests/src/X %s", BUILDDIR, xserver_args);
588 if (!g_shell_parse_argv (command_line, NULL, &argv, &error) ||
589 !g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &error))
591 g_printerr ("Error starting X server: %s", error->message);
596 process = watch_process (pid);
597 g_hash_table_insert (children, GINT_TO_POINTER (process->pid), process);
600 else if (strcmp (name, "START-VNC-CLIENT") == 0)
602 gchar *vnc_client_args, *command_line;
606 GError *error = NULL;
608 vnc_client_args = g_hash_table_lookup (params, "ARGS");
609 if (!vnc_client_args)
610 vnc_client_args = "";
611 command_line = g_strdup_printf ("%s/tests/src/vnc-client %s", BUILDDIR, vnc_client_args);
613 if (!g_shell_parse_argv (command_line, NULL, &argv, &error) ||
614 !g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &error))
616 g_printerr ("Error starting VNC client: %s", error->message);
621 process = watch_process (pid);
622 g_hash_table_insert (children, GINT_TO_POINTER (process->pid), process);
625 else if (strcmp (name, "ADD-USER") == 0)
627 gchar *status_text, *username;
630 username = g_hash_table_lookup (params, "USERNAME");
631 user = get_accounts_user_by_name (username);
633 accounts_user_set_hidden (user, FALSE, TRUE);
635 g_warning ("Unknown user %s", username);
637 status_text = g_strdup_printf ("RUNNER ADD-USER USERNAME=%s", username);
638 check_status (status_text);
639 g_free (status_text);
641 else if (strcmp (name, "UPDATE-USER") == 0)
643 GString *status_text;
646 GError *error = NULL;
648 status_text = g_string_new ("RUNNER UPDATE-USER USERNAME=");
650 username = g_hash_table_lookup (params, "USERNAME");
651 g_string_append (status_text, username);
652 user = get_accounts_user_by_name (username);
655 if (g_hash_table_lookup (params, "NAME"))
657 user->user_name = g_strdup (g_hash_table_lookup (params, "NAME"));
658 g_string_append_printf (status_text, " NAME=%s", user->user_name);
660 if (g_hash_table_lookup (params, "REAL-NAME"))
662 user->real_name = g_strdup (g_hash_table_lookup (params, "REAL-NAME"));
663 g_string_append_printf (status_text, " REAL-NAME=%s", user->real_name);
665 if (g_hash_table_lookup (params, "HOME-DIRECTORY"))
667 user->home_directory = g_strdup (g_hash_table_lookup (params, "HOME-DIRECTORY"));
668 g_string_append_printf (status_text, " HOME-DIRECTORY=%s", user->home_directory);
670 if (g_hash_table_lookup (params, "IMAGE"))
672 user->image = g_strdup (g_hash_table_lookup (params, "IMAGE"));
673 g_string_append_printf (status_text, " IMAGE=%s", user->image);
675 if (g_hash_table_lookup (params, "BACKGROUND"))
677 user->background = g_strdup (g_hash_table_lookup (params, "BACKGROUND"));
678 g_string_append_printf (status_text, " BACKGROUND=%s", user->background);
680 if (g_hash_table_lookup (params, "LANGUAGE"))
682 user->language = g_strdup (g_hash_table_lookup (params, "LANGUAGE"));
683 g_string_append_printf (status_text, " LANGUAGE=%s", user->language);
685 if (g_hash_table_lookup (params, "LAYOUTS"))
687 const gchar *value = g_hash_table_lookup (params, "LAYOUTS");
688 user->layouts = g_strsplit (value, ";", -1);
689 g_string_append_printf (status_text, " LAYOUTS=%s", value);
691 if (g_hash_table_lookup (params, "HAS-MESSAGES"))
693 user->has_messages = g_strcmp0 (g_hash_table_lookup (params, "HAS-MESSAGES"), "TRUE") == 0;
694 g_string_append_printf (status_text, " HAS-MESSAGES=%s", user->has_messages ? "TRUE" : "FALSE");
696 if (g_hash_table_lookup (params, "SESSION"))
698 user->xsession = g_strdup (g_hash_table_lookup (params, "SESSION"));
699 g_string_append_printf (status_text, " SESSION=%s", user->xsession);
703 g_warning ("Unknown user %s", username);
705 g_dbus_connection_emit_signal (accounts_connection,
708 "org.freedesktop.Accounts.User",
710 g_variant_new ("()"),
713 g_warning ("Failed to emit Changed: %s", error->message);
714 g_clear_error (&error);
716 check_status (status_text->str);
717 g_string_free (status_text, TRUE);
719 else if (strcmp (name, "DELETE-USER") == 0)
721 gchar *status_text, *username;
724 username = g_hash_table_lookup (params, "USERNAME");
725 user = get_accounts_user_by_name (username);
727 accounts_user_set_hidden (user, TRUE, TRUE);
729 g_warning ("Unknown user %s", username);
731 status_text = g_strdup_printf ("RUNNER DELETE-USER USERNAME=%s", username);
732 check_status (status_text);
733 g_free (status_text);
735 /* Forward to external processes */
736 else if (g_str_has_prefix (name, "SESSION-") ||
737 g_str_has_prefix (name, "GREETER-") ||
738 g_str_has_prefix (name, "XSERVER-") ||
739 strcmp (name, "UNITY-SYSTEM-COMPOSITOR") == 0)
742 for (link = status_clients; link; link = link->next)
744 StatusClient *client = link->data;
746 GError *error = NULL;
748 length = strlen (command);
749 if (g_socket_send (client->socket, (gchar *) &length, sizeof (length), NULL, &error) < 0 ||
750 g_socket_send (client->socket, command, strlen (command), NULL, &error) < 0)
751 g_printerr ("Failed to write to client socket: %s\n", error->message);
752 g_clear_error (&error);
757 g_printerr ("Unknown command '%s'\n", name);
762 g_hash_table_unref (params);
768 /* Stop daemon if requested */
773 /* Commands start with an asterisk */
774 line = get_script_line (NULL);
775 if (!line || line->text[0] != '*')
778 statuses = g_list_append (statuses, g_strdup (line->text));
781 handle_command (line->text + 1);
784 /* Stop at the end of the script */
785 if (get_script_line (NULL) == NULL)
790 status_timeout_cb (gpointer data)
794 line = get_script_line (NULL);
795 fail ("(timeout)", line ? line->text : NULL);
801 check_status (const gchar *status)
804 gboolean result = FALSE;
810 statuses = g_list_append (statuses, g_strdup (status));
812 if (getenv ("DEBUG"))
813 g_print ("%s\n", status);
815 /* Try and match against expected */
816 prefix = get_prefix (status);
817 line = get_script_line (prefix);
821 gchar *full_pattern = g_strdup_printf ("^%s$", line->text);
822 result = g_regex_match_simple (full_pattern, status, 0, 0);
823 g_free (full_pattern);
829 line = get_script_line (NULL);
830 fail (NULL, line ? line->text : NULL);
836 /* Restart timeout */
838 g_source_remove (status_timeout);
839 status_timeout = g_timeout_add (status_timeout_ms, status_timeout_cb, NULL);
845 status_message_cb (GSocket *socket, GIOCondition condition, StatusClient *client)
850 GError *error = NULL;
852 n_read = g_socket_receive (socket, (gchar *)&length, sizeof (length), NULL, &error);
854 n_read = g_socket_receive (socket, buffer, length, NULL, &error);
856 g_warning ("Error reading from socket: %s", error->message);
857 g_clear_error (&error);
860 status_clients = g_list_remove (status_clients, client);
861 g_object_unref (client->socket);
867 buffer[n_read] = '\0';
868 check_status (buffer);
875 status_connect_cb (gpointer data)
878 GError *error = NULL;
880 socket = g_socket_accept (status_socket, NULL, &error);
882 g_warning ("Failed to accept status connection: %s", error->message);
883 g_clear_error (&error);
886 StatusClient *client;
888 client = g_malloc0 (sizeof (StatusClient));
889 client->socket = socket;
890 client->source = g_socket_create_source (socket, G_IO_IN, NULL);
891 status_clients = g_list_append (status_clients, client);
893 g_source_set_callback (client->source, (GSourceFunc) status_message_cb, client, NULL);
894 g_source_attach (client->source, NULL);
901 load_script (const gchar *filename)
904 gchar *data, **lines;
906 if (!g_file_get_contents (filename, &data, NULL, NULL))
908 g_printerr ("Unable to load script: %s\n", filename);
912 lines = g_strsplit (data, "\n", -1);
915 /* Load lines with #? prefix as expected behaviour */
916 for (i = 0; lines[i]; i++)
918 gchar *text = g_strstrip (lines[i]);
919 if (g_str_has_prefix (text, "#?"))
922 line = g_malloc0 (sizeof (ScriptLine));
923 line->text = g_strdup (text + 2);
925 script = g_list_append (script, line);
932 handle_upower_call (GDBusConnection *connection,
934 const gchar *object_path,
935 const gchar *interface_name,
936 const gchar *method_name,
937 GVariant *parameters,
938 GDBusMethodInvocation *invocation,
941 if (strcmp (method_name, "SuspendAllowed") == 0)
943 check_status ("UPOWER SUSPEND-ALLOWED");
944 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
946 else if (strcmp (method_name, "Suspend") == 0)
948 check_status ("UPOWER SUSPEND");
949 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
951 else if (strcmp (method_name, "HibernateAllowed") == 0)
953 check_status ("UPOWER HIBERNATE-ALLOWED");
954 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
956 else if (strcmp (method_name, "Hibernate") == 0)
958 check_status ("UPOWER HIBERNATE");
959 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
962 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
966 upower_name_acquired_cb (GDBusConnection *connection,
970 const gchar *upower_interface =
972 " <interface name='org.freedesktop.UPower'>"
973 " <method name='SuspendAllowed'>"
974 " <arg name='allowed' direction='out' type='b'/>"
976 " <method name='Suspend'/>"
977 " <method name='HibernateAllowed'>"
978 " <arg name='allowed' direction='out' type='b'/>"
980 " <method name='Hibernate'/>"
983 static const GDBusInterfaceVTable upower_vtable =
987 GDBusNodeInfo *upower_info;
988 GError *error = NULL;
990 upower_info = g_dbus_node_info_new_for_xml (upower_interface, &error);
992 g_warning ("Failed to parse D-Bus interface: %s", error->message);
993 g_clear_error (&error);
996 g_dbus_connection_register_object (connection,
997 "/org/freedesktop/UPower",
998 upower_info->interfaces[0],
1003 g_warning ("Failed to register UPower service: %s", error->message);
1004 g_clear_error (&error);
1005 g_dbus_node_info_unref (upower_info);
1008 if (service_count == 0)
1013 start_upower_daemon (void)
1016 g_bus_own_name (G_BUS_TYPE_SYSTEM,
1017 "org.freedesktop.UPower",
1018 G_BUS_NAME_OWNER_FLAGS_NONE,
1019 upower_name_acquired_cb,
1027 open_ck_session (GVariant *params)
1034 GError *error = NULL;
1036 session = g_malloc0 (sizeof (CKSession));
1037 ck_sessions = g_list_append (ck_sessions, session);
1039 cookie = g_string_new ("ck-cookie");
1040 g_variant_get (params, "a(sv)", &iter);
1041 while (g_variant_iter_loop (iter, "(&sv)", &name, &value))
1043 if (strcmp (name, "x11-display") == 0)
1045 const gchar *display;
1046 g_variant_get (value, "&s", &display);
1047 g_string_append_printf (cookie, "-x%s", display);
1051 session->cookie = cookie->str;
1052 g_string_free (cookie, FALSE);
1053 session->path = g_strdup_printf ("/org/freedesktop/ConsoleKit/Session%d", ck_session_index++);
1054 session->id = g_dbus_connection_register_object (ck_connection,
1056 ck_session_info->interfaces[0],
1062 g_warning ("Failed to register CK Session: %s", error->message);
1063 g_clear_error (&error);
1069 handle_ck_call (GDBusConnection *connection,
1070 const gchar *sender,
1071 const gchar *object_path,
1072 const gchar *interface_name,
1073 const gchar *method_name,
1074 GVariant *parameters,
1075 GDBusMethodInvocation *invocation,
1078 if (strcmp (method_name, "CanRestart") == 0)
1080 check_status ("CONSOLE-KIT CAN-RESTART");
1081 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
1083 else if (strcmp (method_name, "CanStop") == 0)
1085 check_status ("CONSOLE-KIT CAN-STOP");
1086 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
1088 else if (strcmp (method_name, "CloseSession") == 0)
1089 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", TRUE));
1090 else if (strcmp (method_name, "OpenSession") == 0)
1092 GVariantBuilder params;
1093 g_variant_builder_init (¶ms, G_VARIANT_TYPE ("a(sv)"));
1094 CKSession *session = open_ck_session (g_variant_builder_end (¶ms));
1095 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", session->cookie));
1097 else if (strcmp (method_name, "OpenSessionWithParameters") == 0)
1099 CKSession *session = open_ck_session (g_variant_get_child_value (parameters, 0));
1100 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", session->cookie));
1102 else if (strcmp (method_name, "GetSessionForCookie") == 0)
1107 g_variant_get (parameters, "(&s)", &cookie);
1109 for (link = ck_sessions; link; link = link->next)
1111 CKSession *session = link->data;
1112 if (strcmp (session->cookie, cookie) == 0)
1114 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", session->path));
1119 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Unable to find session for cookie");
1121 else if (strcmp (method_name, "Restart") == 0)
1123 check_status ("CONSOLE-KIT RESTART");
1124 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1126 else if (strcmp (method_name, "Stop") == 0)
1128 check_status ("CONSOLE-KIT STOP");
1129 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1132 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1136 handle_ck_session_call (GDBusConnection *connection,
1137 const gchar *sender,
1138 const gchar *object_path,
1139 const gchar *interface_name,
1140 const gchar *method_name,
1141 GVariant *parameters,
1142 GDBusMethodInvocation *invocation,
1145 CKSession *session = user_data;
1147 if (strcmp (method_name, "Lock") == 0)
1149 if (!session->locked)
1150 check_status ("CONSOLE-KIT LOCK-SESSION");
1151 session->locked = TRUE;
1152 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1154 else if (strcmp (method_name, "Unlock") == 0)
1156 if (session->locked)
1157 check_status ("CONSOLE-KIT UNLOCK-SESSION");
1158 session->locked = FALSE;
1159 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1161 else if (strcmp (method_name, "Activate") == 0)
1163 gchar *status = g_strdup_printf ("CONSOLE-KIT ACTIVATE-SESSION SESSION=%s", session->cookie);
1164 check_status (status);
1167 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1170 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1174 ck_name_acquired_cb (GDBusConnection *connection,
1178 const gchar *ck_interface =
1180 " <interface name='org.freedesktop.ConsoleKit.Manager'>"
1181 " <method name='CanRestart'>"
1182 " <arg name='can_restart' direction='out' type='b'/>"
1184 " <method name='CanStop'>"
1185 " <arg name='can_stop' direction='out' type='b'/>"
1187 " <method name='CloseSession'>"
1188 " <arg name='cookie' direction='in' type='s'/>"
1189 " <arg name='result' direction='out' type='b'/>"
1191 " <method name='OpenSession'>"
1192 " <arg name='cookie' direction='out' type='s'/>"
1194 " <method name='OpenSessionWithParameters'>"
1195 " <arg name='parameters' direction='in' type='a(sv)'/>"
1196 " <arg name='cookie' direction='out' type='s'/>"
1198 " <method name='GetSessionForCookie'>"
1199 " <arg name='cookie' direction='in' type='s'/>"
1200 " <arg name='ssid' direction='out' type='o'/>"
1202 " <method name='Restart'/>"
1203 " <method name='Stop'/>"
1204 " <signal name='SeatAdded'>"
1205 " <arg name='seat' type='o'/>"
1207 " <signal name='SeatRemoved'>"
1208 " <arg name='seat' type='o'/>"
1212 static const GDBusInterfaceVTable ck_vtable =
1216 const gchar *ck_session_interface =
1218 " <interface name='org.freedesktop.ConsoleKit.Session'>"
1219 " <method name='Lock'/>"
1220 " <method name='Unlock'/>"
1221 " <method name='Activate'/>"
1224 GDBusNodeInfo *ck_info;
1225 GError *error = NULL;
1227 ck_connection = connection;
1229 ck_info = g_dbus_node_info_new_for_xml (ck_interface, &error);
1231 g_warning ("Failed to parse D-Bus interface: %s", error->message);
1232 g_clear_error (&error);
1235 ck_session_info = g_dbus_node_info_new_for_xml (ck_session_interface, &error);
1237 g_warning ("Failed to parse D-Bus interface: %s", error->message);
1238 g_clear_error (&error);
1239 if (!ck_session_info)
1241 g_dbus_connection_register_object (connection,
1242 "/org/freedesktop/ConsoleKit/Manager",
1243 ck_info->interfaces[0],
1248 g_warning ("Failed to register console kit service: %s", error->message);
1249 g_clear_error (&error);
1250 g_dbus_node_info_unref (ck_info);
1253 if (service_count == 0)
1258 start_console_kit_daemon (void)
1261 g_bus_own_name (G_BUS_TYPE_SYSTEM,
1262 "org.freedesktop.ConsoleKit",
1263 G_BUS_NAME_OWNER_FLAGS_NONE,
1265 ck_name_acquired_cb,
1272 handle_login1_session_call (GDBusConnection *connection,
1273 const gchar *sender,
1274 const gchar *object_path,
1275 const gchar *interface_name,
1276 const gchar *method_name,
1277 GVariant *parameters,
1278 GDBusMethodInvocation *invocation,
1281 Login1Session *session = user_data;
1283 if (strcmp (method_name, "Lock") == 0)
1285 if (!session->locked)
1287 gchar *status = g_strdup_printf ("LOGIN1 LOCK-SESSION SESSION=%s", strrchr (object_path, '/') + 1);
1288 check_status (status);
1291 session->locked = TRUE;
1292 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1294 else if (strcmp (method_name, "Unlock") == 0)
1296 if (session->locked)
1298 gchar *status = g_strdup_printf ("LOGIN1 UNLOCK-SESSION SESSION=%s", strrchr (object_path, '/') + 1);
1299 check_status (status);
1302 session->locked = FALSE;
1303 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1305 else if (strcmp (method_name, "Activate") == 0)
1307 gchar *status = g_strdup_printf ("LOGIN1 ACTIVATE-SESSION SESSION=%s", strrchr (object_path, '/') + 1);
1308 check_status (status);
1311 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1314 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1317 static Login1Session *
1318 open_login1_session (GDBusConnection *connection,
1321 Login1Session *session;
1322 GError *error = NULL;
1323 GDBusNodeInfo *login1_session_info;
1325 const gchar *login1_session_interface =
1327 " <interface name='org.freedesktop.login1.Session'>"
1328 " <method name='Lock'/>"
1329 " <method name='Unlock'/>"
1330 " <method name='Activate'/>"
1333 static const GDBusInterfaceVTable login1_session_vtable =
1335 handle_login1_session_call,
1338 session = g_malloc0 (sizeof (Login1Session));
1339 login1_sessions = g_list_append (login1_sessions, session);
1341 session->path = g_strdup_printf("/org/freedesktop/login1/Session/c%d",
1342 login1_session_index++);
1346 login1_session_info = g_dbus_node_info_new_for_xml (login1_session_interface,
1349 g_warning ("Failed to parse login1 session D-Bus interface: %s",
1351 g_clear_error (&error);
1352 if (!login1_session_info)
1355 g_dbus_connection_register_object (connection,
1357 login1_session_info->interfaces[0],
1358 &login1_session_vtable,
1363 g_warning ("Failed to register login1 session: %s", error->message);
1364 g_clear_error (&error);
1365 g_dbus_node_info_unref (login1_session_info);
1372 handle_login1_call (GDBusConnection *connection,
1373 const gchar *sender,
1374 const gchar *object_path,
1375 const gchar *interface_name,
1376 const gchar *method_name,
1377 GVariant *parameters,
1378 GDBusMethodInvocation *invocation,
1382 if (strcmp (method_name, "GetSessionByPID") == 0)
1384 /* Look for a session with our PID, and create one if we don't have one
1388 Login1Session *ret = NULL;
1390 g_variant_get (parameters, "(u)", &pid);
1392 for (link = login1_sessions; link; link = link->next)
1394 Login1Session *session;
1395 session = link->data;
1396 if (session->pid == pid)
1404 ret = open_login1_session (connection, parameters);
1406 g_dbus_method_invocation_return_value (invocation,
1407 g_variant_new("(o)", ret->path));
1410 else if (strcmp (method_name, "CanReboot") == 0)
1412 check_status ("LOGIN1 CAN-REBOOT");
1413 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1415 else if (strcmp (method_name, "Reboot") == 0)
1417 gboolean interactive;
1418 g_variant_get (parameters, "(b)", &interactive);
1419 check_status ("LOGIN1 REBOOT");
1420 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1422 else if (strcmp (method_name, "CanPowerOff") == 0)
1424 check_status ("LOGIN1 CAN-POWER-OFF");
1425 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1427 else if (strcmp (method_name, "Suspend") == 0)
1429 gboolean interactive;
1430 g_variant_get (parameters, "(b)", &interactive);
1431 check_status ("LOGIN1 SUSPEND");
1432 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1434 else if (strcmp (method_name, "CanSuspend") == 0)
1436 check_status ("LOGIN1 CAN-SUSPEND");
1437 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1439 else if (strcmp (method_name, "PowerOff") == 0)
1441 gboolean interactive;
1442 g_variant_get (parameters, "(b)", &interactive);
1443 check_status ("LOGIN1 POWER-OFF");
1444 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1446 else if (strcmp (method_name, "CanHibernate") == 0)
1448 check_status ("LOGIN1 CAN-HIBERNATE");
1449 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "yes"));
1451 else if (strcmp (method_name, "Hibernate") == 0)
1453 gboolean interactive;
1454 g_variant_get (parameters, "(b)", &interactive);
1455 check_status ("LOGIN1 HIBERNATE");
1456 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1459 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1463 login1_name_acquired_cb (GDBusConnection *connection,
1467 const gchar *login1_interface =
1469 " <interface name='org.freedesktop.login1.Manager'>"
1470 " <method name='GetSessionByPID'>"
1471 " <arg name='pid' type='u' direction='in'/>"
1472 " <arg name='session' type='o' direction='out'/>"
1474 " <method name='CanReboot'>"
1475 " <arg name='result' direction='out' type='s'/>"
1477 " <method name='Reboot'>"
1478 " <arg name='interactive' direction='in' type='b'/>"
1480 " <method name='CanPowerOff'>"
1481 " <arg name='result' direction='out' type='s'/>"
1483 " <method name='PowerOff'>"
1484 " <arg name='interactive' direction='in' type='b'/>"
1486 " <method name='CanSuspend'>"
1487 " <arg name='result' direction='out' type='s'/>"
1489 " <method name='Suspend'>"
1490 " <arg name='interactive' direction='in' type='b'/>"
1492 " <method name='CanHibernate'>"
1493 " <arg name='result' direction='out' type='s'/>"
1495 " <method name='Hibernate'>"
1496 " <arg name='interactive' direction='in' type='b'/>"
1500 static const GDBusInterfaceVTable login1_vtable =
1504 GDBusNodeInfo *login1_info;
1505 GError *error = NULL;
1507 login1_info = g_dbus_node_info_new_for_xml (login1_interface, &error);
1509 g_warning ("Failed to parse login1 D-Bus interface: %s", error->message);
1510 g_clear_error (&error);
1513 g_dbus_connection_register_object (connection,
1514 "/org/freedesktop/login1",
1515 login1_info->interfaces[0],
1520 g_warning ("Failed to register login1 service: %s", error->message);
1521 g_clear_error (&error);
1522 g_dbus_node_info_unref (login1_info);
1525 if (service_count == 0)
1530 start_login1_daemon (void)
1533 g_bus_own_name (G_BUS_TYPE_SYSTEM,
1534 "org.freedesktop.login1",
1535 G_BUS_NAME_OWNER_FLAGS_NONE,
1537 login1_name_acquired_cb,
1543 static AccountsUser *
1544 get_accounts_user_by_uid (guint uid)
1548 for (link = accounts_users; link; link = link->next)
1550 AccountsUser *u = link->data;
1558 static AccountsUser *
1559 get_accounts_user_by_name (const gchar *username)
1563 for (link = accounts_users; link; link = link->next)
1565 AccountsUser *u = link->data;
1566 if (strcmp (u->user_name, username) == 0)
1574 accounts_user_set_hidden (AccountsUser *user, gboolean hidden, gboolean emit_signal)
1576 GError *error = NULL;
1578 user->hidden = hidden;
1580 if (user->hidden && user->id != 0)
1582 g_dbus_connection_unregister_object (accounts_connection, user->id);
1583 g_dbus_connection_emit_signal (accounts_connection,
1585 "/org/freedesktop/Accounts",
1586 "org.freedesktop.Accounts",
1588 g_variant_new ("(o)", user->path),
1591 g_warning ("Failed to emit UserDeleted: %s", error->message);
1592 g_clear_error (&error);
1596 if (!user->hidden && user->id == 0)
1598 user->id = g_dbus_connection_register_object (accounts_connection,
1600 user_info->interfaces[0],
1606 g_warning ("Failed to register user: %s", error->message);
1607 g_clear_error (&error);
1609 g_dbus_connection_emit_signal (accounts_connection,
1611 "/org/freedesktop/Accounts",
1612 "org.freedesktop.Accounts",
1614 g_variant_new ("(o)", user->path),
1617 g_warning ("Failed to emit UserAdded: %s", error->message);
1618 g_clear_error (&error);
1623 load_passwd_file (void)
1625 gchar *path, *data, **lines;
1626 gchar **user_filter = NULL;
1629 if (g_key_file_has_key (config, "test-runner-config", "accounts-service-user-filter", NULL))
1633 filter = g_key_file_get_string (config, "test-runner-config", "accounts-service-user-filter", NULL);
1634 user_filter = g_strsplit (filter, " ", -1);
1638 path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "passwd", NULL);
1639 g_file_get_contents (path, &data, NULL, NULL);
1641 lines = g_strsplit (data, "\n", -1);
1644 for (i = 0; lines[i]; i++)
1648 gchar *user_name, *real_name;
1649 AccountsUser *user = NULL;
1651 fields = g_strsplit (lines[i], ":", -1);
1652 if (fields == NULL || g_strv_length (fields) < 7)
1654 g_strfreev (fields);
1658 user_name = fields[0];
1659 uid = atoi (fields[2]);
1660 real_name = fields[4];
1662 user = get_accounts_user_by_uid (uid);
1666 GKeyFile *dmrc_file;
1668 user = g_malloc0 (sizeof (AccountsUser));
1669 accounts_users = g_list_append (accounts_users, user);
1671 /* Only allow users in whitelist */
1672 user->hidden = FALSE;
1677 user->hidden = TRUE;
1678 for (j = 0; user_filter[j] != NULL; j++)
1679 if (strcmp (user_name, user_filter[j]) == 0)
1680 user->hidden = FALSE;
1683 dmrc_file = g_key_file_new ();
1684 path = g_build_filename (temp_dir, "home", user_name, ".dmrc", NULL);
1685 g_key_file_load_from_file (dmrc_file, path, G_KEY_FILE_NONE, NULL);
1689 user->user_name = g_strdup (user_name);
1690 user->real_name = g_strdup (real_name);
1691 user->home_directory = g_build_filename (temp_dir, "home", user_name, NULL);
1692 user->language = g_key_file_get_string (dmrc_file, "Desktop", "Language", NULL);
1693 /* DMRC contains a locale, strip the codeset off it to get the language */
1696 gchar *c = strchr (user->language, '.');
1700 user->xsession = g_key_file_get_string (dmrc_file, "Desktop", "Session", NULL);
1701 user->layouts = g_key_file_get_string_list (dmrc_file, "X-Accounts", "Layouts", NULL, NULL);
1704 user->layouts = g_malloc (sizeof (gchar *) * 2);
1705 user->layouts[0] = g_key_file_get_string (dmrc_file, "Desktop", "Layout", NULL);
1706 user->layouts[1] = NULL;
1708 user->has_messages = g_key_file_get_boolean (dmrc_file, "X-Accounts", "HasMessages", NULL);
1709 user->path = g_strdup_printf ("/org/freedesktop/Accounts/User%d", uid);
1710 accounts_user_set_hidden (user, user->hidden, FALSE);
1712 g_key_file_free (dmrc_file);
1715 g_strfreev (fields);
1722 handle_accounts_call (GDBusConnection *connection,
1723 const gchar *sender,
1724 const gchar *object_path,
1725 const gchar *interface_name,
1726 const gchar *method_name,
1727 GVariant *parameters,
1728 GDBusMethodInvocation *invocation,
1731 if (strcmp (method_name, "ListCachedUsers") == 0)
1733 GVariantBuilder builder;
1736 g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
1738 load_passwd_file ();
1739 for (link = accounts_users; link; link = link->next)
1741 AccountsUser *user = link->data;
1742 if (!user->hidden && user->uid >= 1000)
1743 g_variant_builder_add_value (&builder, g_variant_new_object_path (user->path));
1746 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(ao)", &builder));
1748 else if (strcmp (method_name, "FindUserByName") == 0)
1750 AccountsUser *user = NULL;
1753 g_variant_get (parameters, "(&s)", &user_name);
1755 load_passwd_file ();
1756 user = get_accounts_user_by_name (user_name);
1760 accounts_user_set_hidden (user, FALSE, TRUE);
1761 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", user->path));
1764 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such user: %s", user_name);
1767 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1771 handle_user_call (GDBusConnection *connection,
1772 const gchar *sender,
1773 const gchar *object_path,
1774 const gchar *interface_name,
1775 const gchar *method_name,
1776 GVariant *parameters,
1777 GDBusMethodInvocation *invocation,
1780 AccountsUser *user = user_data;
1782 if (strcmp (method_name, "SetXSession") == 0)
1786 g_variant_get (parameters, "(&s)", &xsession);
1788 g_free (user->xsession);
1789 user->xsession = g_strdup (xsession);
1791 g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
1793 /* And notify others that it took */
1794 g_dbus_connection_emit_signal (accounts_connection,
1797 "org.freedesktop.Accounts.User",
1799 g_variant_new ("()"),
1803 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "No such method: %s", method_name);
1807 handle_user_get_property (GDBusConnection *connection,
1808 const gchar *sender,
1809 const gchar *object_path,
1810 const gchar *interface_name,
1811 const gchar *property_name,
1815 AccountsUser *user = user_data;
1817 if (strcmp (property_name, "UserName") == 0)
1818 return g_variant_new_string (user->user_name);
1819 else if (strcmp (property_name, "RealName") == 0)
1820 return g_variant_new_string (user->real_name);
1821 else if (strcmp (property_name, "HomeDirectory") == 0)
1822 return g_variant_new_string (user->home_directory);
1823 else if (strcmp (property_name, "SystemAccount") == 0)
1824 return g_variant_new_boolean (user->uid < 1000);
1825 else if (strcmp (property_name, "BackgroundFile") == 0)
1826 return g_variant_new_string (user->background ? user->background : "");
1827 else if (strcmp (property_name, "Language") == 0)
1828 return g_variant_new_string (user->language ? user->language : "");
1829 else if (strcmp (property_name, "IconFile") == 0)
1830 return g_variant_new_string (user->image ? user->image : "");
1831 else if (strcmp (property_name, "Shell") == 0)
1832 return g_variant_new_string ("/bin/sh");
1833 else if (strcmp (property_name, "Uid") == 0)
1834 return g_variant_new_uint64 (user->uid);
1835 else if (strcmp (property_name, "XSession") == 0)
1836 return g_variant_new_string (user->xsession ? user->xsession : "");
1837 else if (strcmp (property_name, "XKeyboardLayouts") == 0)
1839 if (user->layouts != NULL)
1840 return g_variant_new_strv ((const gchar * const *) user->layouts, -1);
1842 return g_variant_new_strv (NULL, 0);
1844 else if (strcmp (property_name, "XHasMessages") == 0)
1845 return g_variant_new_boolean (user->has_messages);
1851 accounts_name_acquired_cb (GDBusConnection *connection,
1855 const gchar *accounts_interface =
1857 " <interface name='org.freedesktop.Accounts'>"
1858 " <method name='ListCachedUsers'>"
1859 " <arg name='user' direction='out' type='ao'/>"
1861 " <method name='FindUserByName'>"
1862 " <arg name='name' direction='in' type='s'/>"
1863 " <arg name='user' direction='out' type='o'/>"
1865 " <signal name='UserAdded'>"
1866 " <arg name='user' type='o'/>"
1868 " <signal name='UserDeleted'>"
1869 " <arg name='user' type='o'/>"
1873 static const GDBusInterfaceVTable accounts_vtable =
1875 handle_accounts_call,
1877 const gchar *user_interface =
1879 " <interface name='org.freedesktop.Accounts.User'>"
1880 " <method name='SetXSession'>"
1881 " <arg name='x_session' direction='in' type='s'/>"
1883 " <property name='UserName' type='s' access='read'/>"
1884 " <property name='RealName' type='s' access='read'/>"
1885 " <property name='HomeDirectory' type='s' access='read'/>"
1886 " <property name='SystemAccount' type='b' access='read'/>"
1887 " <property name='BackgroundFile' type='s' access='read'/>"
1888 " <property name='Language' type='s' access='read'/>"
1889 " <property name='IconFile' type='s' access='read'/>"
1890 " <property name='Shell' type='s' access='read'/>"
1891 " <property name='Uid' type='t' access='read'/>"
1892 " <property name='XSession' type='s' access='read'/>"
1893 " <property name='XKeyboardLayouts' type='as' access='read'/>"
1894 " <property name='XHasMessages' type='b' access='read'/>"
1895 " <signal name='Changed' />"
1898 GError *error = NULL;
1900 accounts_connection = connection;
1902 accounts_info = g_dbus_node_info_new_for_xml (accounts_interface, &error);
1904 g_warning ("Failed to parse D-Bus interface: %s", error->message);
1905 g_clear_error (&error);
1908 user_info = g_dbus_node_info_new_for_xml (user_interface, &error);
1910 g_warning ("Failed to parse D-Bus interface: %s", error->message);
1911 g_clear_error (&error);
1914 g_dbus_connection_register_object (connection,
1915 "/org/freedesktop/Accounts",
1916 accounts_info->interfaces[0],
1922 g_warning ("Failed to register accounts service: %s", error->message);
1923 g_clear_error (&error);
1924 g_dbus_node_info_unref (accounts_info);
1927 if (service_count == 0)
1932 start_accounts_service_daemon (void)
1935 g_bus_own_name (G_BUS_TYPE_SYSTEM,
1936 "org.freedesktop.Accounts",
1937 G_BUS_NAME_OWNER_FLAGS_NONE,
1938 accounts_name_acquired_cb,
1952 signal_cb (gpointer user_data)
1954 g_print ("Caught signal, quitting\n");
1955 quit (EXIT_FAILURE);
1960 properties_changed_cb (GDBusConnection *connection,
1961 const gchar *sender_name,
1962 const gchar *object_path,
1963 const gchar *interface_name,
1964 const gchar *signal_name,
1965 GVariant *parameters,
1968 const gchar *interface, *name;
1971 GVariantIter *changed_properties, *invalidated_properties;
1974 g_variant_get (parameters, "(&sa{sv}as)", &interface, &changed_properties, &invalidated_properties);
1976 status = g_string_new ("RUNNER DBUS-PROPERTIES-CHANGED");
1977 g_string_append_printf (status, " PATH=%s", object_path);
1978 g_string_append_printf (status, " INTERFACE=%s", interface);
1979 for (i = 0; g_variant_iter_loop (changed_properties, "{&sv}", &name, &value); i++)
1982 g_string_append (status, " CHANGED=");
1984 g_string_append (status, ",");
1985 g_string_append (status, name);
1986 if (g_variant_is_of_type (value, G_VARIANT_TYPE ("ao")))
1991 g_variant_iter_init (&iter, value);
1992 while (g_variant_iter_loop (&iter, "&o", &path))
1993 g_string_append_printf (status, ":%s", path);
1996 for (i = 0; g_variant_iter_loop (invalidated_properties, "&s", &name); i++)
1999 g_string_append (status, " INVALIDATED=");
2001 g_string_append (status, ",");
2002 g_string_append (status, name);
2005 check_status (status->str);
2006 g_string_free (status, TRUE);
2010 dbus_signal_cb (GDBusConnection *connection,
2011 const gchar *sender_name,
2012 const gchar *object_path,
2013 const gchar *interface_name,
2014 const gchar *signal_name,
2015 GVariant *parameters,
2020 status = g_string_new ("RUNNER DBUS-SIGNAL");
2021 g_string_append_printf (status, " PATH=%s", object_path);
2022 g_string_append_printf (status, " INTERFACE=%s", interface_name);
2023 g_string_append_printf (status, " NAME=%s", signal_name);
2025 check_status (status->str);
2026 g_string_free (status, TRUE);
2030 main (int argc, char **argv)
2034 gchar *greeter = NULL, *script_name, *config_file, *additional_system_config;
2035 gchar *additional_config, *path, *path1, *path2, *ld_preload, *ld_library_path, *home_dir;
2036 GString *passwd_data, *group_data;
2037 GSource *status_source;
2039 GError *error = NULL;
2041 #if !defined(GLIB_VERSION_2_36)
2045 loop = g_main_loop_new (NULL, FALSE);
2047 g_unix_signal_add (SIGINT, signal_cb, NULL);
2048 g_unix_signal_add (SIGTERM, signal_cb, NULL);
2050 children = g_hash_table_new (g_direct_hash, g_direct_equal);
2054 g_printerr ("Usage %s SCRIPT-NAME GREETER\n", argv[0]);
2055 quit (EXIT_FAILURE);
2057 script_name = argv[1];
2058 config_file = g_strdup_printf ("%s.conf", script_name);
2059 config_path = g_build_filename (SRCDIR, "tests", "scripts", config_file, NULL);
2060 g_free (config_file);
2062 config = g_key_file_new ();
2063 g_key_file_load_from_file (config, config_path, G_KEY_FILE_NONE, NULL);
2065 load_script (config_path);
2067 if (!getcwd (cwd, 1024))
2069 g_critical ("Error getting current directory: %s", strerror (errno));
2070 quit (EXIT_FAILURE);
2073 /* Don't contact our X server */
2074 g_unsetenv ("DISPLAY");
2076 /* Don't let XDG vars from system affect tests */
2077 g_unsetenv ("XDG_CONFIG_DIRS");
2078 g_unsetenv ("XDG_DATA_DIRS");
2080 /* Override system calls */
2081 ld_preload = g_build_filename (BUILDDIR, "tests", "src", ".libs", "libsystem.so", NULL);
2082 g_setenv ("LD_PRELOAD", ld_preload, TRUE);
2083 g_free (ld_preload);
2085 /* Run test programs */
2086 path = g_strdup_printf ("%s/tests/src/.libs:%s/tests/src:%s/tests/src:%s/src:%s", BUILDDIR, BUILDDIR, SRCDIR, BUILDDIR, g_getenv ("PATH"));
2087 g_setenv ("PATH", path, TRUE);
2090 /* Use locally built libraries */
2091 path1 = g_build_filename (BUILDDIR, "liblightdm-gobject", ".libs", NULL);
2092 path2 = g_build_filename (BUILDDIR, "liblightdm-qt", ".libs", NULL);
2093 ld_library_path = g_strdup_printf ("%s:%s", path1, path2);
2096 g_setenv ("LD_LIBRARY_PATH", ld_library_path, TRUE);
2097 g_free (ld_library_path);
2098 path1 = g_build_filename (BUILDDIR, "liblightdm-gobject", NULL);
2099 g_setenv ("GI_TYPELIB_PATH", path1, TRUE);
2102 /* Run in a temporary directory inside the build directory */
2103 /* Note we have to pick a name that is short since Unix sockets in this directory have a 108 character limit on their paths */
2108 name = g_strdup_printf (".r%d", i);
2110 temp_dir = g_build_filename ("/tmp", name, NULL);
2112 if (!g_file_test (temp_dir, G_FILE_TEST_EXISTS))
2116 g_mkdir_with_parents (temp_dir, 0755);
2117 g_setenv ("LIGHTDM_TEST_ROOT", temp_dir, TRUE);
2119 /* Open socket for status */
2120 /* Note we have to pick a socket name that is short since there is a 108 character limit on the name */
2121 status_socket_name = g_build_filename (temp_dir, ".s", NULL);
2122 unlink (status_socket_name);
2123 status_socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, &error);
2125 g_warning ("Error creating status socket %s: %s", status_socket_name, error->message);
2126 g_clear_error (&error);
2129 GSocketAddress *address;
2132 address = g_unix_socket_address_new (status_socket_name);
2133 result = g_socket_bind (status_socket, address, FALSE, &error);
2134 g_object_unref (address);
2136 g_warning ("Error binding status socket %s: %s", status_socket_name, error->message);
2137 g_clear_error (&error);
2140 result = g_socket_listen (status_socket, &error);
2142 g_warning ("Error listening on status socket %s: %s", status_socket_name, error->message);
2143 g_clear_error (&error);
2147 g_object_unref (status_socket);
2148 status_socket = NULL;
2152 quit (EXIT_FAILURE);
2153 status_source = g_socket_create_source (status_socket, G_IO_IN, NULL);
2154 g_source_set_callback (status_source, status_connect_cb, NULL, NULL);
2155 g_source_attach (status_source, NULL);
2157 /* Set up a skeleton file system */
2158 g_mkdir_with_parents (g_strdup_printf ("%s/etc", temp_dir), 0755);
2159 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share", temp_dir), 0755);
2160 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/sessions", temp_dir), 0755);
2161 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/remote-sessions", temp_dir), 0755);
2162 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/greeters", temp_dir), 0755);
2163 g_mkdir_with_parents (g_strdup_printf ("%s/tmp", temp_dir), 0755);
2164 g_mkdir_with_parents (g_strdup_printf ("%s/var/lib/lightdm-data", temp_dir), 0755);
2165 g_mkdir_with_parents (g_strdup_printf ("%s/var/run", temp_dir), 0755);
2166 g_mkdir_with_parents (g_strdup_printf ("%s/var/log", temp_dir), 0755);
2168 /* Copy over the configuration */
2169 g_mkdir_with_parents (g_strdup_printf ("%s/etc/lightdm", temp_dir), 0755);
2170 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))
2171 if (system (g_strdup_printf ("cp %s %s/etc/lightdm/lightdm.conf", config_path, temp_dir)))
2172 perror ("Failed to copy configuration");
2174 additional_system_config = g_key_file_get_string (config, "test-runner-config", "additional-system-config", NULL);
2175 if (additional_system_config)
2179 g_mkdir_with_parents (g_strdup_printf ("%s/usr/share/lightdm/lightdm.conf.d", temp_dir), 0755);
2181 files = g_strsplit (additional_system_config, " ", -1);
2182 for (i = 0; files[i]; i++)
2183 if (system (g_strdup_printf ("cp %s/tests/scripts/%s %s/usr/share/lightdm/lightdm.conf.d", SRCDIR, files[i], temp_dir)))
2184 perror ("Failed to copy configuration");
2188 additional_config = g_key_file_get_string (config, "test-runner-config", "additional-config", NULL);
2189 if (additional_config)
2193 g_mkdir_with_parents (g_strdup_printf ("%s/etc/xdg/lightdm/lightdm.conf.d", temp_dir), 0755);
2195 files = g_strsplit (additional_config, " ", -1);
2196 for (i = 0; files[i]; i++)
2197 if (system (g_strdup_printf ("cp %s/tests/scripts/%s %s/etc/xdg/lightdm/lightdm.conf.d", SRCDIR, files[i], temp_dir)))
2198 perror ("Failed to copy configuration");
2202 if (g_key_file_has_key (config, "test-runner-config", "shared-data-dirs", NULL))
2208 dir_string = g_key_file_get_string (config, "test-runner-config", "shared-data-dirs", NULL);
2209 dirs = g_strsplit (dir_string, " ", -1);
2210 g_free (dir_string);
2212 for (i = 0; dirs[i]; i++)
2214 gchar **fields = g_strsplit (dirs[i], ":", -1);
2215 if (g_strv_length (fields) == 4)
2217 gchar *path = g_strdup_printf ("%s/var/lib/lightdm-data/%s", temp_dir, fields[0]);
2218 int uid = g_ascii_strtoll (fields[1], NULL, 10);
2219 int gid = g_ascii_strtoll (fields[2], NULL, 10);
2220 int mode = g_ascii_strtoll (fields[3], NULL, 8);
2221 g_mkdir (path, mode);
2222 g_chmod (path, mode); /* mkdir filters by umask, so make sure we have what we want */
2223 if (chown (path, uid, gid) < 0)
2224 g_warning ("chown (%s) failed: %s", path, strerror (errno));
2227 g_strfreev (fields);
2233 /* Always copy the script */
2234 if (system (g_strdup_printf ("cp %s %s/script", config_path, temp_dir)))
2235 perror ("Failed to copy configuration");
2237 /* Copy over the greeter files */
2238 if (system (g_strdup_printf ("cp %s/sessions/* %s/usr/share/lightdm/sessions", DATADIR, temp_dir)))
2239 perror ("Failed to copy sessions");
2240 if (system (g_strdup_printf ("cp %s/remote-sessions/* %s/usr/share/lightdm/remote-sessions", DATADIR, temp_dir)))
2241 perror ("Failed to copy remote sessions");
2242 if (system (g_strdup_printf ("cp %s/greeters/* %s/usr/share/lightdm/greeters", DATADIR, temp_dir)))
2243 perror ("Failed to copy greeters");
2245 /* Set up the default greeter */
2246 path = g_build_filename (temp_dir, "usr", "share", "lightdm", "greeters", "default.desktop", NULL);
2247 greeter = g_strdup_printf ("%s.desktop", argv[2]);
2248 if (symlink (greeter, path) < 0)
2250 g_printerr ("Failed to make greeter symlink %s->%s: %s\n", path, greeter, strerror (errno));
2251 quit (EXIT_FAILURE);
2256 home_dir = g_build_filename (temp_dir, "home", NULL);
2258 /* Make fake users */
2268 {"root", "", "root", 0},
2269 /* Unprivileged account for greeters */
2270 {"lightdm", "", "", 100},
2271 /* These accounts have a password */
2272 {"have-password1", "password", "Password User 1", 1000},
2273 {"have-password2", "password", "Password User 2", 1001},
2274 {"have-password3", "password", "Password User 3", 1002},
2275 {"have-password4", "password", "Password User 4", 1003},
2276 /* This account always prompts for a password, even if using the lightdm-autologin service */
2277 {"always-password", "password", "Password User 4", 1004},
2278 /* These accounts have no password */
2279 {"no-password1", "", "No Password User 1", 1005},
2280 {"no-password2", "", "No Password User 2", 1006},
2281 {"no-password3", "", "No Password User 3", 1007},
2282 {"no-password4", "", "No Password User 4", 1008},
2283 /* This account has a keyboard layout */
2284 {"have-layout", "", "Layout User", 1009},
2285 /* This account has a set of keyboard layouts */
2286 {"have-layouts", "", "Layouts User", 1010},
2287 /* This account has a language set */
2288 {"have-language", "", "Language User", 1011},
2289 /* This account has a preconfigured session */
2290 {"have-session", "", "Session User", 1012},
2291 /* This account has the home directory mounted on login */
2292 {"mount-home-dir", "", "Mounted Home Dir User", 1013},
2293 /* This account is denied access */
2294 {"denied", "", "Denied User", 1014},
2295 /* This account has expired */
2296 {"expired", "", "Expired User", 1015},
2297 /* This account needs a password change */
2298 {"new-authtok", "", "New Token User", 1016},
2299 /* This account is switched to change-user2 when authentication succeeds */
2300 {"change-user1", "", "Change User 1", 1017},
2301 {"change-user2", "", "Change User 2", 1018},
2302 /* This account switches to invalid-user when authentication succeeds */
2303 {"change-user-invalid", "", "Invalid Change User", 1019},
2304 /* This account crashes on authentication */
2305 {"crash-authenticate", "", "Crash Auth User", 1020},
2306 /* This account shows an informational prompt on login */
2307 {"info-prompt", "password", "Info Prompt", 1021},
2308 /* This account shows multiple informational prompts on login */
2309 {"multi-info-prompt","password", "Multi Info Prompt", 1022},
2310 /* This account uses two factor authentication */
2311 {"two-factor", "password", "Two Factor", 1023},
2312 /* This account has a special group */
2313 {"group-member", "password", "Group Member", 1024},
2314 /* This account has the home directory created when the session starts */
2315 {"make-home-dir", "", "Make Home Dir User", 1025},
2316 /* This account fails to open a session */
2317 {"session-error", "password", "Session Error", 1026},
2318 /* This account can't establish credentials */
2319 {"cred-error", "password", "Cred Error", 1027},
2320 /* This account has expired credentials */
2321 {"cred-expired", "password", "Cred Expired", 1028},
2322 /* This account has cannot access their credentials */
2323 {"cred-unavail", "password", "Cred Unavail", 1029},
2324 /* This account sends informational messages for each PAM function that is called */
2325 {"log-pam", "password", "Log PAM", 1030},
2326 /* This account shows multiple prompts on login */
2327 {"multi-prompt", "password", "Multi Prompt", 1031},
2328 /* This account has an existing corrupt X authority */
2329 {"corrupt-xauth", "password", "Corrupt Xauthority", 1032},
2330 /* User to test properties */
2331 {"prop-user", "", "TEST", 1033},
2332 {NULL, NULL, NULL, 0}
2334 passwd_data = g_string_new ("");
2335 group_data = g_string_new ("");
2336 for (i = 0; users[i].user_name; i++)
2338 GKeyFile *dmrc_file;
2339 gboolean save_dmrc = FALSE;
2341 if (strcmp (users[i].user_name, "mount-home-dir") != 0 && strcmp (users[i].user_name, "make-home-dir") != 0)
2343 path = g_build_filename (home_dir, users[i].user_name, NULL);
2344 g_mkdir_with_parents (path, 0755);
2345 if (chown (path, users[i].uid, users[i].uid) < 0)
2346 g_debug ("chown (%s) failed: %s", path, strerror (errno));
2350 dmrc_file = g_key_file_new ();
2351 if (strcmp (users[i].user_name, "have-session") == 0)
2353 g_key_file_set_string (dmrc_file, "Desktop", "Session", "alternative");
2356 if (strcmp (users[i].user_name, "have-layout") == 0)
2358 g_key_file_set_string (dmrc_file, "Desktop", "Layout", "us");
2361 if (strcmp (users[i].user_name, "have-layouts") == 0)
2363 g_key_file_set_string (dmrc_file, "Desktop", "Layout", "ru");
2364 g_key_file_set_string (dmrc_file, "X-Accounts", "Layouts", "fr\toss;ru;");
2367 if (strcmp (users[i].user_name, "have-language") == 0)
2369 g_key_file_set_string (dmrc_file, "Desktop", "Language", "en_AU.utf8");
2377 path = g_build_filename (home_dir, users[i].user_name, ".dmrc", NULL);
2378 data = g_key_file_to_data (dmrc_file, NULL, NULL);
2379 g_file_set_contents (path, data, -1, NULL);
2384 g_key_file_free (dmrc_file);
2386 /* Write corrupt X authority file */
2387 if (strcmp (users[i].user_name, "corrupt-xauth") == 0)
2389 gchar data[1] = { 0xFF };
2391 path = g_build_filename (home_dir, users[i].user_name, ".Xauthority", NULL);
2392 g_file_set_contents (path, data, 1, NULL);
2393 chmod (path, S_IRUSR | S_IWUSR);
2397 /* Add passwd file entry */
2398 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);
2400 /* Add group file entry */
2401 g_string_append_printf (group_data, "%s:x:%d:%s\n", users[i].user_name, users[i].uid, users[i].user_name);
2403 path = g_build_filename (temp_dir, "etc", "passwd", NULL);
2404 g_file_set_contents (path, passwd_data->str, -1, NULL);
2406 g_string_free (passwd_data, TRUE);
2408 /* Add an extra test group */
2409 g_string_append_printf (group_data, "test-group:x:111:\n");
2411 path = g_build_filename (temp_dir, "etc", "group", NULL);
2412 g_file_set_contents (path, group_data->str, -1, NULL);
2414 g_string_free (group_data, TRUE);
2416 if (g_key_file_has_key (config, "test-runner-config", "timeout", NULL))
2417 status_timeout_ms = g_key_file_get_integer (config, "test-runner-config", "timeout", NULL) * 1000;
2419 /* Start D-Bus services */
2420 if (!g_key_file_get_boolean (config, "test-runner-config", "disable-upower", NULL))
2421 start_upower_daemon ();
2422 if (!g_key_file_get_boolean (config, "test-runner-config", "disable-console-kit", NULL))
2423 start_console_kit_daemon ();
2424 if (!g_key_file_get_boolean (config, "test-runner-config", "disable-login1", NULL))
2425 start_login1_daemon ();
2426 if (!g_key_file_get_boolean (config, "test-runner-config", "disable-accounts-service", NULL))
2427 start_accounts_service_daemon ();
2429 /* Listen for daemon bus events */
2430 if (g_key_file_get_boolean (config, "test-runner-config", "log-dbus", NULL))
2432 g_dbus_connection_signal_subscribe (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
2433 "org.freedesktop.DisplayManager",
2434 "org.freedesktop.DBus.Properties",
2435 "PropertiesChanged",
2438 G_DBUS_SIGNAL_FLAGS_NONE,
2439 properties_changed_cb,
2442 g_dbus_connection_signal_subscribe (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
2443 "org.freedesktop.DisplayManager",
2444 "org.freedesktop.DisplayManager",
2448 G_DBUS_SIGNAL_FLAGS_NONE,
2454 g_main_loop_run (loop);
2456 return EXIT_FAILURE;