diff options
-rw-r--r-- | common/gdm-settings-desktop-backend.c | 4 | ||||
-rw-r--r-- | common/gdm-settings-direct.c | 2 | ||||
-rw-r--r-- | common/gdm-settings-utils.c | 2 | ||||
-rw-r--r-- | common/gdm-settings.c | 2 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | daemon/gdm-greeter-proxy.c | 180 | ||||
-rw-r--r-- | daemon/gdm-greeter-proxy.h | 12 | ||||
-rw-r--r-- | daemon/gdm-session.c | 219 | ||||
-rw-r--r-- | daemon/gdm-session.h | 61 | ||||
-rw-r--r-- | daemon/gdm-slave.c | 528 | ||||
-rw-r--r-- | daemon/gdm-slave.h | 8 | ||||
-rw-r--r-- | daemon/slave-main.c | 40 | ||||
-rw-r--r-- | daemon/test-session.c | 6 | ||||
-rw-r--r-- | gui/Makefile.am | 4 | ||||
-rw-r--r-- | gui/gdm-greeter.c | 51 | ||||
-rw-r--r-- | gui/gdm-greeter.h | 11 | ||||
-rw-r--r-- | gui/greeter/greeter.c | 55 |
17 files changed, 785 insertions, 402 deletions
diff --git a/common/gdm-settings-desktop-backend.c b/common/gdm-settings-desktop-backend.c index d710f481..f69c83a7 100644 --- a/common/gdm-settings-desktop-backend.c +++ b/common/gdm-settings-desktop-backend.c @@ -76,7 +76,7 @@ parse_key_string (const char *keystring, g = k = v = l = NULL; split1 = split2 = NULL; - g_debug ("Attempting to parse key string: %s", keystring); + /*g_debug ("Attempting to parse key string: %s", keystring);*/ split1 = g_strsplit (keystring, "/", 2); if (split1 == NULL || split1 [0] == NULL || split1 [1] == NULL) { @@ -147,7 +147,7 @@ gdm_settings_desktop_backend_get_value (GdmSettingsBackend *backend, return FALSE; } - g_debug ("Getting key: %s %s %s", g, k, l); + /*g_debug ("Getting key: %s %s %s", g, k, l);*/ local_error = NULL; val = g_key_file_get_value (GDM_SETTINGS_DESKTOP_BACKEND (backend)->priv->key_file, g, diff --git a/common/gdm-settings-direct.c b/common/gdm-settings-direct.c index 38e004b2..0b9385ab 100644 --- a/common/gdm-settings-direct.c +++ b/common/gdm-settings-direct.c @@ -78,10 +78,8 @@ get_value (const char *key, res = gdm_settings_get_value (settings_object, key, &str, &error); if (! res) { if (error != NULL) { - g_debug ("Failed to get value for %s: %s", key, error->message); g_error_free (error); } else { - g_debug ("Failed to get value for %s", key); } return FALSE; diff --git a/common/gdm-settings-utils.c b/common/gdm-settings-utils.c index 65e979e7..82293c98 100644 --- a/common/gdm-settings-utils.c +++ b/common/gdm-settings-utils.c @@ -123,7 +123,7 @@ start_element_cb (GMarkupParseContext *ctx, static void add_schema_entry (ParserInfo *info) { - g_debug ("Inserting entry %s", info->entry->key); + /*g_debug ("Inserting entry %s", info->entry->key);*/ info->list = g_slist_prepend (info->list, info->entry); } diff --git a/common/gdm-settings.c b/common/gdm-settings.c index ee8f0864..07bb3776 100644 --- a/common/gdm-settings.c +++ b/common/gdm-settings.c @@ -94,8 +94,6 @@ gdm_settings_get_value (GdmSettings *settings, g_return_val_if_fail (GDM_IS_SETTINGS (settings), FALSE); g_return_val_if_fail (key != NULL, FALSE); - g_debug ("Getting key %s", key); - local_error = NULL; res = gdm_settings_backend_get_value (settings->priv->backend, key, diff --git a/configure.ac b/configure.ac index c82c9b6e..10f2d1f5 100644 --- a/configure.ac +++ b/configure.ac @@ -11,7 +11,7 @@ IT_PROG_INTLTOOL([0.35.0]) GNOME_DOC_INIT DBUS_REQUIRED=0.30 -GLIB_REQUIRED=2.8.0 +GLIB_REQUIRED=2.13.0 GTK_REQUIRED=2.6.0 PANGO_REQUIRED=1.3.0 LIBGLADE_REQUIRED=1.99.2 diff --git a/daemon/gdm-greeter-proxy.c b/daemon/gdm-greeter-proxy.c index 1467e240..98cc5acd 100644 --- a/daemon/gdm-greeter-proxy.c +++ b/daemon/gdm-greeter-proxy.c @@ -60,21 +60,21 @@ extern char **environ; struct GdmGreeterProxyPrivate { - char *command; - GPid pid; + char *command; + GPid pid; - char *user_name; - char *group_name; + char *user_name; + char *group_name; - char *x11_display_name; - char *x11_authority_file; + char *x11_display_name; + char *x11_authority_file; - int user_max_filesize; + int user_max_filesize; - gboolean interrupted; - gboolean always_restart_greeter; + gboolean interrupted; + gboolean always_restart_greeter; - guint child_watch_id; + guint child_watch_id; DBusServer *server; char *server_address; @@ -90,7 +90,9 @@ enum { }; enum { - ANSWER, + QUERY_ANSWER, + SESSION_SELECTED, + LANGUAGE_SELECTED, STARTED, STOPPED, LAST_SIGNAL @@ -267,7 +269,6 @@ static GPtrArray * get_greeter_environment (GdmGreeterProxy *greeter_proxy) { GPtrArray *env; - char **l; GHashTable *hash; struct passwd *pwent; @@ -276,14 +277,6 @@ get_greeter_environment (GdmGreeterProxy *greeter_proxy) /* create a hash table of current environment, then update keys has necessary */ hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); -#if 0 - for (l = environ; *l != NULL; l++) { - char **str; - str = g_strsplit (*l, "=", 2); - g_hash_table_insert (hash, str[0], str[1]); - } -#endif - g_hash_table_insert (hash, g_strdup ("GDM_GREETER_DBUS_ADDRESS"), g_strdup (greeter_proxy->priv->server_address)); g_hash_table_insert (hash, g_strdup ("XAUTHORITY"), g_strdup (greeter_proxy->priv->x11_authority_file)); @@ -446,6 +439,87 @@ generate_address (void) } static DBusHandlerResult +handle_answer_query (GdmGreeterProxy *greeter_proxy, + DBusConnection *connection, + DBusMessage *message) +{ + DBusMessage *reply; + DBusError error; + const char *text; + + dbus_error_init (&error); + if (! dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &text, + DBUS_TYPE_INVALID)) { + g_warning ("ERROR: %s", error.message); + } + + g_debug ("AnswerQuery: %s", text); + + reply = dbus_message_new_method_return (message); + dbus_connection_send (connection, reply, NULL); + dbus_message_unref (reply); + + g_signal_emit (greeter_proxy, signals [QUERY_ANSWER], 0, text); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusHandlerResult +handle_select_session (GdmGreeterProxy *greeter_proxy, + DBusConnection *connection, + DBusMessage *message) +{ + DBusMessage *reply; + DBusError error; + const char *text; + + dbus_error_init (&error); + if (! dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &text, + DBUS_TYPE_INVALID)) { + g_warning ("ERROR: %s", error.message); + } + + g_debug ("SelectSession: %s", text); + + reply = dbus_message_new_method_return (message); + dbus_connection_send (connection, reply, NULL); + dbus_message_unref (reply); + + g_signal_emit (greeter_proxy, signals [SESSION_SELECTED], 0, text); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusHandlerResult +handle_select_language (GdmGreeterProxy *greeter_proxy, + DBusConnection *connection, + DBusMessage *message) +{ + DBusMessage *reply; + DBusError error; + const char *text; + + dbus_error_init (&error); + if (! dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &text, + DBUS_TYPE_INVALID)) { + g_warning ("ERROR: %s", error.message); + } + + g_debug ("SelectLanguage: %s", text); + + reply = dbus_message_new_method_return (message); + dbus_connection_send (connection, reply, NULL); + dbus_message_unref (reply); + + g_signal_emit (greeter_proxy, signals [LANGUAGE_SELECTED], 0, text); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusHandlerResult greeter_handle_child_message (DBusConnection *connection, DBusMessage *message, void *user_data) @@ -453,26 +527,11 @@ greeter_handle_child_message (DBusConnection *connection, GdmGreeterProxy *greeter_proxy = GDM_GREETER_PROXY (user_data); if (dbus_message_is_method_call (message, GDM_GREETER_SERVER_DBUS_INTERFACE, "AnswerQuery")) { - DBusMessage *reply; - DBusError error; - const char *text; - - dbus_error_init (&error); - if (! dbus_message_get_args (message, &error, - DBUS_TYPE_STRING, &text, - DBUS_TYPE_INVALID)) { - g_warning ("ERROR: %s", error.message); - } - - g_debug ("AnswerQuery: %s", text); - - reply = dbus_message_new_method_return (message); - dbus_connection_send (connection, reply, NULL); - dbus_message_unref (reply); - - g_signal_emit (greeter_proxy, signals [ANSWER], 0, text); - - return DBUS_HANDLER_RESULT_HANDLED; + return handle_answer_query (greeter_proxy, connection, message); + } else if (dbus_message_is_method_call (message, GDM_GREETER_SERVER_DBUS_INTERFACE, "SelectSession")) { + return handle_select_session (greeter_proxy, connection, message); + } else if (dbus_message_is_method_call (message, GDM_GREETER_SERVER_DBUS_INTERFACE, "SelectSession")) { + return handle_select_language (greeter_proxy, connection, message); } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; @@ -504,6 +563,12 @@ do_introspect (DBusConnection *connection, " <method name=\"AnswerQuery\">\n" " <arg name=\"text\" direction=\"in\" type=\"s\"/>\n" " </method>\n" + " <method name=\"SelectSession\">\n" + " <arg name=\"text\" direction=\"in\" type=\"s\"/>\n" + " </method>\n" + " <method name=\"SelectLanguage\">\n" + " <arg name=\"text\" direction=\"in\" type=\"s\"/>\n" + " </method>\n" " <signal name=\"Info\">\n" " <arg name=\"text\" type=\"s\"/>\n" " </signal>\n" @@ -547,8 +612,6 @@ greeter_server_message_handler (DBusConnection *connection, DBusMessage *message, void *user_data) { - GdmGreeterProxy *greeter_proxy = GDM_GREETER_PROXY (user_data); - g_debug ("greeter_server_message_handler: destination=%s obj_path=%s interface=%s method=%s", dbus_message_get_destination (message), dbus_message_get_path (message), @@ -591,8 +654,6 @@ static void greeter_server_unregister_handler (DBusConnection *connection, void *user_data) { - GdmGreeterProxy *greeter_proxy = GDM_GREETER_PROXY (user_data); - g_debug ("greeter_server_unregister_handler"); } @@ -700,7 +761,6 @@ create_dbus_server (GdmGreeterProxy *greeter_proxy) DBusError error; gboolean ret; char *address; - char *server_address; const char *auth_mechanisms[] = {"EXTERNAL", NULL}; ret = FALSE; @@ -1055,11 +1115,33 @@ gdm_greeter_proxy_class_init (GdmGreeterProxyClass *klass) "group name", "gdm", G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - signals [ANSWER] = - g_signal_new ("answer", + signals [QUERY_ANSWER] = + g_signal_new ("query-answer", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdmGreeterProxyClass, query_answer), + NULL, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); + signals [SESSION_SELECTED] = + g_signal_new ("session-selected", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdmGreeterProxyClass, session_selected), + NULL, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); + signals [LANGUAGE_SELECTED] = + g_signal_new ("language-selected", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GdmGreeterProxyClass, answer), + G_STRUCT_OFFSET (GdmGreeterProxyClass, language_selected), NULL, NULL, g_cclosure_marshal_VOID__STRING, @@ -1096,7 +1178,7 @@ gdm_greeter_proxy_init (GdmGreeterProxy *greeter_proxy) greeter_proxy->priv->pid = -1; - greeter_proxy->priv->command = g_strdup (LIBEXECDIR "/gdmgreeter"); + greeter_proxy->priv->command = g_strdup (LIBEXECDIR "/gdmgreeter --g-fatal-warnings"); greeter_proxy->priv->user_max_filesize = 65536; } diff --git a/daemon/gdm-greeter-proxy.h b/daemon/gdm-greeter-proxy.h index 4458b64b..6e8eb28f 100644 --- a/daemon/gdm-greeter-proxy.h +++ b/daemon/gdm-greeter-proxy.h @@ -45,10 +45,14 @@ typedef struct { GObjectClass parent_class; - void (* answer) (GdmGreeterProxy *greeter_proxy, - const char *text); - void (* started) (GdmGreeterProxy *greeter_proxy); - void (* stopped) (GdmGreeterProxy *greeter_proxy); + void (* query_answer) (GdmGreeterProxy *greeter_proxy, + const char *text); + void (* session_selected) (GdmGreeterProxy *greeter_proxy, + const char *name); + void (* language_selected) (GdmGreeterProxy *greeter_proxy, + const char *name); + void (* started) (GdmGreeterProxy *greeter_proxy); + void (* stopped) (GdmGreeterProxy *greeter_proxy); } GdmGreeterProxyClass; GType gdm_greeter_proxy_get_type (void); diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c index 472e3fe8..996c4067 100644 --- a/daemon/gdm-session.c +++ b/daemon/gdm-session.c @@ -2091,7 +2091,7 @@ gdm_session_worker_pam_new_messages_handler (int number_o sizeof (struct pam_response)); for (i = 0; i < number_of_messages; i++) { gboolean got_response; - char *response_text; + char *response_text; response_text = NULL; got_response = gdm_session_worker_process_pam_message (worker, @@ -2331,7 +2331,8 @@ gdm_session_worker_set_environment_variable (GdmSessionWorker *worker, * better? */ g_hash_table_replace (worker->environment, - key_and_value[0], key_and_value[1]); + key_and_value[0], + key_and_value[1]); /* We are calling g_free instead of g_strfreev because the * hash table is taking over ownership of the individual @@ -2663,6 +2664,177 @@ gdm_session_worker_watch_child (GdmSessionWorker *worker) g_source_unref (worker->child_watch_source); } +/* adapted from glib script_execute */ +static void +script_execute (const gchar *file, + char **argv, + char **envp, + gboolean search_path) +{ + /* Count the arguments. */ + int argc = 0; + + while (argv[argc]) + ++argc; + + /* Construct an argument list for the shell. */ + { + char **new_argv; + + new_argv = g_new0 (gchar*, argc + 2); /* /bin/sh and NULL */ + + new_argv[0] = (char *) "/bin/sh"; + new_argv[1] = (char *) file; + while (argc > 0) { + new_argv[argc + 1] = argv[argc]; + --argc; + } + + /* Execute the shell. */ + if (envp) + execve (new_argv[0], new_argv, envp); + else + execv (new_argv[0], new_argv); + + g_free (new_argv); + } +} + +static char * +my_strchrnul (const char *str, char c) +{ + char *p = (char*) str; + while (*p && (*p != c)) + ++p; + + return p; +} + +/* adapted from glib g_execute */ +static gint +gdm_session_execute (const char *file, + char **argv, + char **envp, + gboolean search_path) +{ + if (*file == '\0') { + /* We check the simple case first. */ + errno = ENOENT; + return -1; + } + + if (!search_path || strchr (file, '/') != NULL) { + /* Don't search when it contains a slash. */ + if (envp) + execve (file, argv, envp); + else + execv (file, argv); + + if (errno == ENOEXEC) + script_execute (file, argv, envp, FALSE); + } else { + gboolean got_eacces = 0; + const char *path, *p; + char *name, *freeme; + gsize len; + gsize pathlen; + + path = g_getenv ("PATH"); + if (path == NULL) { + /* There is no `PATH' in the environment. The default + * search path in libc is the current directory followed by + * the path `confstr' returns for `_CS_PATH'. + */ + + /* In GLib we put . last, for security, and don't use the + * unportable confstr(); UNIX98 does not actually specify + * what to search if PATH is unset. POSIX may, dunno. + */ + + path = "/bin:/usr/bin:."; + } + + len = strlen (file) + 1; + pathlen = strlen (path); + freeme = name = g_malloc (pathlen + len + 1); + + /* Copy the file name at the top, including '\0' */ + memcpy (name + pathlen + 1, file, len); + name = name + pathlen; + /* And add the slash before the filename */ + *name = '/'; + + p = path; + do { + char *startp; + + path = p; + p = my_strchrnul (path, ':'); + + if (p == path) + /* Two adjacent colons, or a colon at the beginning or the end + * of `PATH' means to search the current directory. + */ + startp = name + 1; + else + startp = memcpy (name - (p - path), path, p - path); + + /* Try to execute this name. If it works, execv will not return. */ + if (envp) + execve (startp, argv, envp); + else + execv (startp, argv); + + if (errno == ENOEXEC) + script_execute (startp, argv, envp, search_path); + + switch (errno) { + case EACCES: + /* Record the we got a `Permission denied' error. If we end + * up finding no executable we can use, we want to diagnose + * that we did find one but were denied access. + */ + got_eacces = TRUE; + + /* FALL THRU */ + + case ENOENT: +#ifdef ESTALE + case ESTALE: +#endif +#ifdef ENOTDIR + case ENOTDIR: +#endif + /* Those errors indicate the file is missing or not executable + * by us, in which case we want to just try the next path + * directory. + */ + break; + + default: + /* Some other error means we found an executable file, but + * something went wrong executing it; return the error to our + * caller. + */ + g_free (freeme); + return -1; + } + } while (*p++ != '\0'); + + /* We tried every element and none of them worked. */ + if (got_eacces) + /* At least one failure was due to permissions, so report that + * error. + */ + errno = EACCES; + + g_free (freeme); + } + + /* Return the error from the last attempt (probably ENOENT). */ + return -1; +} + static gboolean gdm_session_worker_open_user_session (GdmSessionWorker *worker, GError **error) @@ -2707,12 +2879,10 @@ gdm_session_worker_open_user_session (GdmSessionWorker *worker, char *home_dir; int fd; - worker->inherited_fd_list = - g_slist_append (NULL, - GINT_TO_POINTER (worker->standard_output_fd)); - worker->inherited_fd_list = - g_slist_append (worker->inherited_fd_list, - GINT_TO_POINTER (worker->standard_error_fd)); + worker->inherited_fd_list = g_slist_append (NULL, + GINT_TO_POINTER (worker->standard_output_fd)); + worker->inherited_fd_list = g_slist_append (worker->inherited_fd_list, + GINT_TO_POINTER (worker->standard_error_fd)); #if 0 gdm_session_worker_close_open_fds (worker); @@ -2763,10 +2933,14 @@ gdm_session_worker_open_user_session (GdmSessionWorker *worker, g_chdir ("/"); } - execve (worker->arguments[0], worker->arguments, environment); + gdm_session_execute (worker->arguments[0], + worker->arguments, + environment, + TRUE); g_debug ("child '%s' could not be started - %s", - worker->arguments[0], g_strerror (errno)); + worker->arguments[0], + g_strerror (errno)); g_strfreev (environment); _exit (127); @@ -2890,7 +3064,7 @@ gdm_session_worker_handle_verification_message (GdmSessionWorker *w } static void -gdm_session_worker_handle_start_program_message (GdmSessionWorker *worker, +gdm_session_worker_handle_start_program_message (GdmSessionWorker *worker, GdmSessionStartProgramMessage *message) { GError *start_error; @@ -3814,26 +3988,29 @@ gdm_session_open_for_user (GdmSession *session, } void -gdm_session_start_program (GdmSession *session, - const char * const *args) +gdm_session_start_program (GdmSession *session, + int argc, + const char **argv) { GdmSessionMessage *message; - int argc, i; + int i; g_return_if_fail (session != NULL); g_return_if_fail (session != NULL); g_return_if_fail (gdm_session_is_running (session) == FALSE); - g_return_if_fail (args != NULL); - g_return_if_fail (args[0] != NULL); + g_return_if_fail (argv != NULL); + g_return_if_fail (argv[0] != NULL); - argc = g_strv_length ((char **) args); session->priv->arguments = g_new0 (char *, (argc + 1)); - for (i = 0; args[i] != NULL; i++) - session->priv->arguments[i] = g_strdup (args[i]); + for (i = 0; argv[i] != NULL; i++) { + session->priv->arguments[i] = g_strdup (argv[i]); + } - message = gdm_session_start_program_message_new (args); - gdm_write_message (session->priv->worker_message_pipe_fd, message, message->size, + message = gdm_session_start_program_message_new (argv); + gdm_write_message (session->priv->worker_message_pipe_fd, + message, + message->size, NULL); gdm_session_message_free (message); } diff --git a/daemon/gdm-session.h b/daemon/gdm-session.h index 49510d1e..cd5c0867 100644 --- a/daemon/gdm-session.h +++ b/daemon/gdm-session.h @@ -99,36 +99,37 @@ GQuark gdm_session_error_quark (void); GdmSession * gdm_session_new (void) G_GNUC_MALLOC; -gboolean gdm_session_open (GdmSession *session, - const char *service_name, - const char *hostname, - const char *console_name, - int standard_output_fd, - int standard_error_fd, - GError **error); - -gboolean gdm_session_open_for_user (GdmSession *session, - const char *service_name, - const char *username, - const char *hostname, - const char *console_name, - int standard_output_fd, - int standard_error_fd, - GError **error); -void gdm_session_start_program (GdmSession *session, - const char * const * args); - -void gdm_session_set_environment_variable (GdmSession *session, - const char *key, - const char *value); - -void gdm_session_answer_query (GdmSession *session, - const char *answer); - -char * gdm_session_get_username (GdmSession *session); - -void gdm_session_close (GdmSession *session); -gboolean gdm_session_is_running (GdmSession *session); +gboolean gdm_session_open (GdmSession *session, + const char *service_name, + const char *hostname, + const char *console_name, + int standard_output_fd, + int standard_error_fd, + GError **error); + +gboolean gdm_session_open_for_user (GdmSession *session, + const char *service_name, + const char *username, + const char *hostname, + const char *console_name, + int standard_output_fd, + int standard_error_fd, + GError **error); +void gdm_session_start_program (GdmSession *session, + int argc, + const char **argv); + +void gdm_session_set_environment_variable (GdmSession *session, + const char *key, + const char *value); + +void gdm_session_answer_query (GdmSession *session, + const char *answer); + +char * gdm_session_get_username (GdmSession *session); + +void gdm_session_close (GdmSession *session); +gboolean gdm_session_is_running (GdmSession *session); G_END_DECLS diff --git a/daemon/gdm-slave.c b/daemon/gdm-slave.c index 6722ab9b..cb0c3422 100644 --- a/daemon/gdm-slave.c +++ b/daemon/gdm-slave.c @@ -88,6 +88,9 @@ struct GdmSlavePrivate char *parent_display_name; char *parent_display_x11_authority_file; + /* user selected */ + char *selected_session; + char *selected_language; GdmServer *server; GdmGreeterProxy *greeter; @@ -101,271 +104,21 @@ enum { PROP_DISPLAY_ID, }; +enum { + SESSION_STARTED, + SESSION_EXITED, + SESSION_DIED, + LAST_SIGNAL +}; + +static guint signals [LAST_SIGNAL] = { 0, }; + static void gdm_slave_class_init (GdmSlaveClass *klass); static void gdm_slave_init (GdmSlave *slave); static void gdm_slave_finalize (GObject *object); G_DEFINE_TYPE (GdmSlave, gdm_slave, G_TYPE_OBJECT) -/* adapted from gspawn.c */ -static int -wait_on_child (int pid) -{ - int status; - - wait_again: - if (waitpid (pid, &status, 0) < 0) { - if (errno == EINTR) { - goto wait_again; - } else if (errno == ECHILD) { - ; /* do nothing, child already reaped */ - } else { - g_debug ("waitpid () should not fail in 'GdmSpawn'"); - } - } - - return status; -} - -static void -slave_died (GdmSlave *slave) -{ - int exit_status; - - g_debug ("Waiting on process %d", slave->priv->pid); - exit_status = wait_on_child (slave->priv->pid); - - if (WIFEXITED (exit_status) && (WEXITSTATUS (exit_status) != 0)) { - g_debug ("Wait on child process failed"); - } else { - /* exited normally */ - } - - g_spawn_close_pid (slave->priv->pid); - slave->priv->pid = -1; - - g_debug ("Slave died"); -} - -static gboolean -output_watch (GIOChannel *source, - GIOCondition condition, - GdmSlave *slave) -{ - gboolean finished = FALSE; - - if (condition & G_IO_IN) { - GIOStatus status; - GError *error = NULL; - char *line; - - line = NULL; - status = g_io_channel_read_line (source, &line, NULL, NULL, &error); - - switch (status) { - case G_IO_STATUS_NORMAL: - { - char *p; - - g_debug ("command output: %s", line); - - if ((p = strstr (line, "ADDRESS=")) != NULL) { - char *address; - - address = g_strdup (p + strlen ("ADDRESS=")); - g_debug ("Got address %s", address); - - g_free (address); - } - } - break; - case G_IO_STATUS_EOF: - finished = TRUE; - break; - case G_IO_STATUS_ERROR: - finished = TRUE; - g_debug ("Error reading from child: %s\n", error->message); - return FALSE; - case G_IO_STATUS_AGAIN: - default: - break; - } - - g_free (line); - } else if (condition & G_IO_HUP) { - finished = TRUE; - } - - if (finished) { - slave_died (slave); - - slave->priv->output_watch_id = 0; - - return FALSE; - } - - return TRUE; -} - -/* just for debugging */ -static gboolean -error_watch (GIOChannel *source, - GIOCondition condition, - GdmSlave *slave) -{ - gboolean finished = FALSE; - - if (condition & G_IO_IN) { - GIOStatus status; - GError *error = NULL; - char *line; - - line = NULL; - status = g_io_channel_read_line (source, &line, NULL, NULL, &error); - - switch (status) { - case G_IO_STATUS_NORMAL: - g_debug ("command error output: %s", line); - break; - case G_IO_STATUS_EOF: - finished = TRUE; - break; - case G_IO_STATUS_ERROR: - finished = TRUE; - g_debug ("Error reading from child: %s\n", error->message); - return FALSE; - case G_IO_STATUS_AGAIN: - default: - break; - } - g_free (line); - } else if (condition & G_IO_HUP) { - finished = TRUE; - } - - if (finished) { - slave->priv->error_watch_id = 0; - - return FALSE; - } - - return TRUE; -} - -static gboolean -spawn_slave (GdmSlave *slave) -{ - char *command; - char **argv; - gboolean result; - GIOChannel *channel; - GError *error = NULL; - int standard_output; - int standard_error; - - - result = FALSE; - - command = g_strdup_printf ("%s --id %s", GDM_SLAVE_COMMAND, slave->priv->display_id); - - if (! g_shell_parse_argv (command, NULL, &argv, &error)) { - g_warning ("Could not parse command: %s", error->message); - g_error_free (error); - goto out; - } - - error = NULL; - result = g_spawn_async_with_pipes (NULL, - argv, - NULL, - G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, - NULL, - NULL, - &slave->priv->pid, - NULL, - &standard_output, - &standard_error, - &error); - - if (! result) { - g_warning ("Could not start command '%s': %s", command, error->message); - g_error_free (error); - g_strfreev (argv); - goto out; - } - - g_strfreev (argv); - - /* output channel */ - channel = g_io_channel_unix_new (standard_output); - g_io_channel_set_close_on_unref (channel, TRUE); - g_io_channel_set_flags (channel, - g_io_channel_get_flags (channel) | G_IO_FLAG_NONBLOCK, - NULL); - slave->priv->output_watch_id = g_io_add_watch (channel, - G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, - (GIOFunc)output_watch, - slave); - g_io_channel_unref (channel); - - /* error channel */ - channel = g_io_channel_unix_new (standard_error); - g_io_channel_set_close_on_unref (channel, TRUE); - g_io_channel_set_flags (channel, - g_io_channel_get_flags (channel) | G_IO_FLAG_NONBLOCK, - NULL); - slave->priv->error_watch_id = g_io_add_watch (channel, - G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, - (GIOFunc)error_watch, - slave); - g_io_channel_unref (channel); - - result = TRUE; - - out: - g_free (command); - - return result; -} - -static int -signal_pid (int pid, - int signal) -{ - int status = -1; - - /* perhaps block sigchld */ - - status = kill (pid, signal); - - if (status < 0) { - if (errno == ESRCH) { - g_warning ("Child process %lu was already dead.", - (unsigned long) pid); - } else { - g_warning ("Couldn't kill child process %lu: %s", - (unsigned long) pid, - g_strerror (errno)); - } - } - - /* perhaps unblock sigchld */ - - return status; -} - -static void -kill_slave (GdmSlave *slave) -{ - if (slave->priv->pid <= 1) { - return; - } - - signal_pid (slave->priv->pid, SIGTERM); - - /* watch should call slave_died */ -} - static void set_busy_cursor (GdmSlave *slave) { @@ -435,7 +188,6 @@ get_script_environment (GdmSlave *slave, const char *username) { GPtrArray *env; - char **l; GHashTable *hash; struct passwd *pwent; char *x_servers_file; @@ -445,14 +197,6 @@ get_script_environment (GdmSlave *slave, /* create a hash table of current environment, then update keys has necessary */ hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); -#if 0 - for (l = environ; *l != NULL; l++) { - char **str; - str = g_strsplit (*l, "=", 2); - g_hash_table_insert (hash, str[0], str[1]); - } -#endif - /* modify environment here */ g_hash_table_insert (hash, g_strdup ("HOME"), g_strdup ("/")); g_hash_table_insert (hash, g_strdup ("PWD"), g_strdup ("/")); @@ -619,6 +363,7 @@ on_session_started (GdmSession *session, GdmSlave *slave) { g_debug ("session started on pid %d\n", (int) pid); + g_signal_emit (slave, signals [SESSION_STARTED], 0, pid); } static void @@ -627,7 +372,7 @@ on_session_exited (GdmSession *session, GdmSlave *slave) { g_debug ("session exited with code %d\n", exit_code); - exit (0); + g_signal_emit (slave, signals [SESSION_EXITED], 0, exit_code); } static void @@ -638,15 +383,159 @@ on_session_died (GdmSession *session, g_debug ("session died with signal %d, (%s)", signal_number, g_strsignal (signal_number)); - exit (1); + g_signal_emit (slave, signals [SESSION_DIED], 0, signal_number); +} + +static gboolean +is_prog_in_path (const char *prog) +{ + char *f; + gboolean ret; + + f = g_find_program_in_path (prog); + ret = (f != NULL); + g_free (f); + return ret; +} + +static gboolean +get_session_command (const char *file, + char **command) +{ + GKeyFile *key_file; + GError *error; + char *full_path; + char *exec; + gboolean ret; + gboolean res; + const char *search_dirs[] = { + "/etc/X11/sessions/", + DMCONFDIR "/Sessions/", + DATADIR "/gdm/BuiltInSessions/", + DATADIR "/xsessions/", + NULL + }; + + exec = NULL; + ret = FALSE; + if (command != NULL) { + *command = NULL; + } + + key_file = g_key_file_new (); + + error = NULL; + full_path = NULL; + res = g_key_file_load_from_dirs (key_file, + file, + search_dirs, + &full_path, + G_KEY_FILE_NONE, + &error); + if (! res) { + g_debug ("File '%s' not found: %s", file, error->message); + g_error_free (error); + if (command != NULL) { + *command = NULL; + } + goto out; + } + + error = NULL; + res = g_key_file_get_boolean (key_file, + G_KEY_FILE_DESKTOP_GROUP, + G_KEY_FILE_DESKTOP_KEY_HIDDEN, + &error); + if (error == NULL && res) { + g_debug ("Session %s is marked as hidden", file); + goto out; + } + + error = NULL; + exec = g_key_file_get_string (key_file, + G_KEY_FILE_DESKTOP_GROUP, + G_KEY_FILE_DESKTOP_KEY_TRY_EXEC, + &error); + if (exec == NULL) { + g_debug ("%s key not found", G_KEY_FILE_DESKTOP_KEY_TRY_EXEC); + goto out; + } + + res = is_prog_in_path (exec); + g_free (exec); + + if (! res) { + g_debug ("Command not found: %s", G_KEY_FILE_DESKTOP_KEY_TRY_EXEC); + goto out; + } + + error = NULL; + exec = g_key_file_get_string (key_file, + G_KEY_FILE_DESKTOP_GROUP, + G_KEY_FILE_DESKTOP_KEY_EXEC, + &error); + if (error != NULL) { + g_debug ("%s key not found: %s", + G_KEY_FILE_DESKTOP_KEY_EXEC, + error->message); + g_error_free (error); + goto out; + } + + if (command != NULL) { + *command = g_strdup (exec); + } + ret = TRUE; + +out: + g_free (exec); + + return ret; +} + +static void +setup_session_environment (GdmSlave *slave) +{ + + gdm_session_set_environment_variable (slave->priv->session, + "GDMSESSION", + slave->priv->selected_session); + gdm_session_set_environment_variable (slave->priv->session, + "DESKTOP_SESSION", + slave->priv->selected_session); + + gdm_session_set_environment_variable (slave->priv->session, + "LANG", + slave->priv->selected_language); + gdm_session_set_environment_variable (slave->priv->session, + "GDM_LANG", + slave->priv->selected_language); + + gdm_session_set_environment_variable (slave->priv->session, + "DISPLAY", + slave->priv->display_name); + gdm_session_set_environment_variable (slave->priv->session, + "XAUTHORITY", + slave->priv->display_x11_authority_file); + + gdm_session_set_environment_variable (slave->priv->session, + "PATH", + "/bin:/usr/bin:" BINDIR); } static void on_user_verified (GdmSession *session, GdmSlave *slave) { - char *username; - const char *args[] = { "/usr/bin/gedit", "/tmp/foo.log", NULL }; + char *username; + int argc; + char **argv; + char *command; + char *filename; + GError *error; + gboolean res; + + gdm_greeter_proxy_stop (slave->priv->greeter); username = gdm_session_get_username (session); @@ -655,7 +544,34 @@ on_user_verified (GdmSession *session, username ? " " : ""); g_free (username); - gdm_session_start_program (session, args); + if (slave->priv->selected_session != NULL) { + filename = g_strdup (slave->priv->selected_session); + } else { + filename = g_strdup ("gnome.desktop"); + } + + setup_session_environment (slave); + + res = get_session_command (filename, &command); + if (! res) { + g_warning ("Could find session file: %s", filename); + return; + } + + error = NULL; + res = g_shell_parse_argv (command, &argc, &argv, &error); + if (! res) { + g_warning ("Could not parse command: %s", error->message); + g_error_free (error); + } + + gdm_session_start_program (session, + argc, + (const char **)argv); + + g_free (filename); + g_free (command); + g_strfreev (argv); } static void @@ -721,6 +637,24 @@ on_greeter_answer (GdmGreeterProxy *greeter, } static void +on_greeter_session_selected (GdmGreeterProxy *greeter, + const char *text, + GdmSlave *slave) +{ + g_free (slave->priv->selected_session); + slave->priv->selected_session = g_strdup (text); +} + +static void +on_greeter_language_selected (GdmGreeterProxy *greeter, + const char *text, + GdmSlave *slave) +{ + g_free (slave->priv->selected_language); + slave->priv->selected_language = g_strdup (text); +} + +static void on_greeter_start (GdmGreeterProxy *greeter, GdmSlave *slave) { @@ -812,12 +746,10 @@ run_greeter (GdmSlave *slave) "session-started", G_CALLBACK (on_session_started), slave); - g_signal_connect (slave->priv->session, "session-exited", G_CALLBACK (on_session_exited), slave); - g_signal_connect (slave->priv->session, "session-died", G_CALLBACK (on_session_died), @@ -825,10 +757,18 @@ run_greeter (GdmSlave *slave) slave->priv->greeter = gdm_greeter_proxy_new (slave->priv->display_name); g_signal_connect (slave->priv->greeter, - "answer", + "query-answer", G_CALLBACK (on_greeter_answer), slave); g_signal_connect (slave->priv->greeter, + "session-selected", + G_CALLBACK (on_greeter_session_selected), + slave); + g_signal_connect (slave->priv->greeter, + "language-selected", + G_CALLBACK (on_greeter_language_selected), + slave); + g_signal_connect (slave->priv->greeter, "started", G_CALLBACK (on_greeter_start), slave); @@ -1246,6 +1186,42 @@ gdm_slave_class_init (GdmSlaveClass *klass) NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + signals [SESSION_STARTED] = + g_signal_new ("session-started", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdmSlaveClass, session_started), + NULL, + NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, + 1, + G_TYPE_INT); + + signals [SESSION_EXITED] = + g_signal_new ("session-exited", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdmSlaveClass, session_exited), + NULL, + NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, + 1, + G_TYPE_INT); + + signals [SESSION_DIED] = + g_signal_new ("session-died", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GdmSlaveClass, session_exited), + NULL, + NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, + 1, + G_TYPE_INT); + dbus_g_object_type_install_info (GDM_TYPE_SLAVE, &dbus_glib_gdm_slave_object_info); } diff --git a/daemon/gdm-slave.h b/daemon/gdm-slave.h index ffc198ae..8c96d6cb 100644 --- a/daemon/gdm-slave.h +++ b/daemon/gdm-slave.h @@ -37,7 +37,7 @@ typedef struct GdmSlavePrivate GdmSlavePrivate; typedef struct { - GObject parent; + GObject parent; GdmSlavePrivate *priv; } GdmSlave; @@ -45,6 +45,12 @@ typedef struct { GObjectClass parent_class; + void (* session_started) (GdmSlave *slave, + GPid pid); + void (* session_exited) (GdmSlave *slave, + int exit_code); + void (* session_died) (GdmSlave *slave, + int signal_number); } GdmSlaveClass; GType gdm_slave_get_type (void); diff --git a/daemon/slave-main.c b/daemon/slave-main.c index aa9fef5f..c75651ef 100644 --- a/daemon/slave-main.c +++ b/daemon/slave-main.c @@ -42,6 +42,8 @@ #include "gdm-log.h" #include "gdm-slave.h" +static int gdm_return_code = 0; + static DBusGConnection * get_system_bus (void) { @@ -129,6 +131,28 @@ signal_cb (int signo, return ret; } +static void +on_session_exited (GdmSlave *slave, + int exit_code, + GMainLoop *main_loop) +{ + g_debug ("session exited with code %d\n", exit_code); + gdm_return_code = exit_code; + g_main_loop_quit (main_loop); +} + +static void +on_session_died (GdmSlave *slave, + int signal_number, + GMainLoop *main_loop) +{ + g_debug ("session died with signal %d, (%s)", + signal_number, + g_strsignal (signal_number)); + gdm_return_code = 1; + g_main_loop_quit (main_loop); +} + int main (int argc, char **argv) @@ -136,7 +160,6 @@ main (int argc, GMainLoop *main_loop; GOptionContext *context; DBusGConnection *connection; - int ret; GdmSlave *slave; static char *display_id = NULL; GdmSignalHandler *signal_handler; @@ -149,8 +172,6 @@ main (int argc, textdomain (GETTEXT_PACKAGE); setlocale (LC_ALL, ""); - ret = 1; - g_type_init (); context = g_option_context_new (_("GNOME Display Manager Slave")); @@ -191,6 +212,15 @@ main (int argc, if (slave == NULL) { goto out; } + g_signal_connect (slave, + "session-exited", + G_CALLBACK (on_session_exited), + main_loop); + g_signal_connect (slave, + "session-died", + G_CALLBACK (on_session_died), + main_loop); + gdm_slave_start (slave); g_main_loop_run (main_loop); @@ -205,11 +235,9 @@ main (int argc, g_main_loop_unref (main_loop); - ret = 0; - out: g_debug ("Slave finished"); - return ret; + return gdm_return_code; } diff --git a/daemon/test-session.c b/daemon/test-session.c index ec807e67..73c7ab4d 100644 --- a/daemon/test-session.c +++ b/daemon/test-session.c @@ -61,7 +61,7 @@ static void on_user_verified (GdmSession *session) { char *username; - const char *args[] = { "/usr/bin/gedit", "/tmp/foo.log", NULL }; + const char *argv[] = { "/usr/bin/gedit", "/tmp/foo.log", NULL }; username = gdm_session_get_username (session); @@ -69,7 +69,7 @@ on_user_verified (GdmSession *session) username? username : "", username? " " : ""); g_free (username); - gdm_session_start_program (session, args); + gdm_session_start_program (session, 2, argv); } static void @@ -169,8 +169,6 @@ main (int argc, GdmSession *session; char *username; int exit_code; - char **args; - int i; exit_code = 0; diff --git a/gui/Makefile.am b/gui/Makefile.am index c4c416c3..b26f4e69 100644 --- a/gui/Makefile.am +++ b/gui/Makefile.am @@ -1,6 +1,6 @@ NULL = -SUBDIRS = +SUBDIRS = \ . \ greeter \ modules \ @@ -24,7 +24,7 @@ DEFS = @DEFS@ \ -DSBINDIR=\"@sbindir@\" \ $(NULL) -INCLUDES = \ +INCLUDES = \ -I. \ -I.. \ -I$(top_srcdir)/daemon \ diff --git a/gui/gdm-greeter.c b/gui/gdm-greeter.c index 2d8c3772..8667d1e4 100644 --- a/gui/gdm-greeter.c +++ b/gui/gdm-greeter.c @@ -48,6 +48,8 @@ enum { enum { QUERY_ANSWER, + SESSION_SELECTED, + LANGUAGE_SELECTED, LAST_SIGNAL }; @@ -220,6 +222,34 @@ gdm_greeter_answer_query (GdmGreeter *greeter, g_debug ("Answer query: %s", text); g_signal_emit (greeter, signals[QUERY_ANSWER], 0, text); + + return TRUE; +} + +gboolean +gdm_greeter_select_session (GdmGreeter *greeter, + const char *text) +{ + g_return_val_if_fail (GDM_IS_GREETER (greeter), FALSE); + + g_debug ("Select session: %s", text); + + g_signal_emit (greeter, signals[SESSION_SELECTED], 0, text); + + return TRUE; +} + +gboolean +gdm_greeter_select_language (GdmGreeter *greeter, + const char *text) +{ + g_return_val_if_fail (GDM_IS_GREETER (greeter), FALSE); + + g_debug ("Select language: %s", text); + + g_signal_emit (greeter, signals[LANGUAGE_SELECTED], 0, text); + + return TRUE; } static void @@ -263,7 +293,6 @@ gdm_greeter_constructor (GType type, { GdmGreeter *greeter; GdmGreeterClass *klass; - gboolean res; klass = GDM_GREETER_CLASS (g_type_class_peek (GDM_TYPE_GREETER)); @@ -316,6 +345,26 @@ gdm_greeter_class_init (GdmGreeterClass *klass) g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); + signals [LANGUAGE_SELECTED] = + g_signal_new ("language-selected", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdmGreeterClass, language_selected), + NULL, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, + 1, G_TYPE_STRING); + signals [SESSION_SELECTED] = + g_signal_new ("session-selected", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdmGreeterClass, session_selected), + NULL, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, + 1, G_TYPE_STRING); g_type_class_add_private (klass, sizeof (GdmGreeterPrivate)); } diff --git a/gui/gdm-greeter.h b/gui/gdm-greeter.h index 59b20e5c..c54f6baf 100644 --- a/gui/gdm-greeter.h +++ b/gui/gdm-greeter.h @@ -48,6 +48,11 @@ typedef struct /* signals */ void (* query_answer) (GdmGreeter *greeter, const char *text); + void (* session_selected) (GdmGreeter *greeter, + const char *text); + void (* language_selected) (GdmGreeter *greeter, + const char *text); + /* methods */ gboolean (*start) (GdmGreeter *greeter); gboolean (*stop) (GdmGreeter *greeter); @@ -76,9 +81,15 @@ GType gdm_greeter_get_type (void); gboolean gdm_greeter_start (GdmGreeter *greeter); gboolean gdm_greeter_stop (GdmGreeter *greeter); +/* emit signals */ gboolean gdm_greeter_answer_query (GdmGreeter *greeter, const char *text); +gboolean gdm_greeter_select_session (GdmGreeter *greeter, + const char *text); +gboolean gdm_greeter_select_language (GdmGreeter *greeter, + const char *text); +/* actions */ gboolean gdm_greeter_info_query (GdmGreeter *greeter, const char *text); gboolean gdm_greeter_secret_info_query (GdmGreeter *greeter, diff --git a/gui/greeter/greeter.c b/gui/greeter/greeter.c index 3a0ec4ff..b7a83674 100644 --- a/gui/greeter/greeter.c +++ b/gui/greeter/greeter.c @@ -121,6 +121,52 @@ on_query_answer (GdmGreeter *greeter, } static void +on_select_session (GdmGreeter *greeter, + const char *text, + gpointer data) +{ + gboolean res; + GError *error; + + g_debug ("GREETER session selected: %s", text); + + error = NULL; + res = dbus_g_proxy_call (server_proxy, + "SelectSession", + &error, + G_TYPE_STRING, text, + G_TYPE_INVALID, + G_TYPE_INVALID); + if (! res) { + g_warning ("Unable to send SelectSession: %s", error->message); + g_error_free (error); + } +} + +static void +on_select_language (GdmGreeter *greeter, + const char *text, + gpointer data) +{ + gboolean res; + GError *error; + + g_debug ("GREETER session selected: %s", text); + + error = NULL; + res = dbus_g_proxy_call (server_proxy, + "SelectLanguage", + &error, + G_TYPE_STRING, text, + G_TYPE_INVALID, + G_TYPE_INVALID); + if (! res) { + g_warning ("Unable to send SelectLanguage: %s", error->message); + g_error_free (error); + } +} + +static void proxy_destroyed (GObject *object, gpointer data) { @@ -222,6 +268,15 @@ main (int argc, char *argv[]) "query-answer", G_CALLBACK (on_query_answer), NULL); + g_signal_connect (greeter, + "session-selected", + G_CALLBACK (on_select_session), + NULL); + g_signal_connect (greeter, + "language-selected", + G_CALLBACK (on_select_language), + NULL); + gtk_main (); if (greeter != NULL) { |