--- gnome-session-2.15.91/gnome-session/gdm-logout-action.c +++ gnome-session-2.15.91/gnome-session/gdm-logout-action.c @@ -56,6 +56,8 @@ #define GDM_ACTION_STR_REBOOT "REBOOT" #define GDM_ACTION_STR_SUSPEND "SUSPEND" +#define KDM_PROTOCOL_MSG_QUERY_ACTION "caps" + typedef struct { int fd; char *auth_cookie; @@ -64,6 +66,8 @@ GdmLogoutAction current_actions; time_t last_update; + + guint is_kdm : 1; } GdmProtocolData; static GdmProtocolData gdm_protocol_data = { @@ -71,11 +75,12 @@ NULL, GDM_LOGOUT_ACTION_NONE, GDM_LOGOUT_ACTION_NONE, - 0 + 0, + FALSE }; static char * -gdm_send_protocol_msg (GdmProtocolData *data, +dm_send_protocol_msg (GdmProtocolData *data, const char *msg) { GString *retval; @@ -87,7 +92,7 @@ if (write (data->fd, p, strlen (p)) < 0) { g_free (p); - g_warning ("Failed to send message to GDM: %s", + g_warning ("Failed to send message to display manager: %s", g_strerror (errno)); return NULL; } @@ -153,7 +158,7 @@ msg = g_strdup_printf (GDM_PROTOCOL_MSG_AUTHENTICATE " %s", data->auth_cookie); - response = gdm_send_protocol_msg (data, msg); + response = dm_send_protocol_msg (data, msg); g_free (msg); if (response && !strcmp (response, "OK")) { @@ -195,7 +200,7 @@ XauDisposeAuth (xau); msg = g_strdup_printf (GDM_PROTOCOL_MSG_AUTHENTICATE " %s", buffer); - response = gdm_send_protocol_msg (data, msg); + response = dm_send_protocol_msg (data, msg); g_free (msg); if (response && !strcmp (response, "OK")) { @@ -218,7 +223,7 @@ } static void -gdm_shutdown_protocol_connection (GdmProtocolData *data) +dm_shutdown_protocol_connection (GdmProtocolData *data) { if (data->fd) close (data->fd); @@ -237,7 +242,7 @@ if (data->fd < 0) { g_warning ("Failed to create GDM socket: %s", g_strerror (errno)); - gdm_shutdown_protocol_connection (data); + dm_shutdown_protocol_connection (data); return FALSE; } @@ -247,29 +252,93 @@ if (connect (data->fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) { g_warning ("Failed to establish a connection with GDM: %s", g_strerror (errno)); - gdm_shutdown_protocol_connection (data); + dm_shutdown_protocol_connection (data); return FALSE; } - response = gdm_send_protocol_msg (data, GDM_PROTOCOL_MSG_VERSION); + response = dm_send_protocol_msg (data, GDM_PROTOCOL_MSG_VERSION); if (!response || strncmp (response, "GDM ", strlen ("GDM ") != 0)) { g_free (response); g_warning ("Failed to get protocol version from GDM"); - gdm_shutdown_protocol_connection (data); + dm_shutdown_protocol_connection (data); return FALSE; } if (!gdm_authenticate_connection (data)) { g_warning ("Failed to authenticate with GDM"); - gdm_shutdown_protocol_connection (data); + dm_shutdown_protocol_connection (data); return FALSE; } return TRUE; } +static gboolean +kdm_init_protocol_connection (GdmProtocolData *data) +{ + struct sockaddr_un addr; + char *response; + char *dm_display; + char *dm_control; + char *p0 = NULL; + + g_assert (data->fd <= 0); + + data->fd = socket (AF_UNIX, SOCK_STREAM, 0); + if (data->fd < 0) { + g_warning ("Failed to create KDM socket: %s", + g_strerror (errno)); + dm_shutdown_protocol_connection (data); + return FALSE; + } + + dm_display = g_strdup (g_getenv ("DISPLAY")); + dm_control = g_strdup (g_getenv ("DM_CONTROL")); + + if (dm_display && (p0 = strchr (dm_display, ':'))) + p0 = strchr (p0, '.'); + + if (!dm_control || !strlen (dm_control) || + !dm_display || !strlen (dm_display)) { + g_free (dm_control); + g_free (dm_display); + + g_warning ("Could not locate KDM socket."); + dm_shutdown_protocol_connection (data); + return FALSE; + } + + snprintf (addr.sun_path, sizeof (addr.sun_path), "%s/dmctl-%.*s/socket", + dm_control, p0 ? p0 - dm_display : 512, dm_display); + addr.sun_family = AF_UNIX; + + g_free (dm_display); + g_free (dm_control); + + if (connect (data->fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) { + g_warning ("Failed to establish a connection with KDM: %s", + g_strerror (errno)); + dm_shutdown_protocol_connection (data); + return FALSE; + } + + return TRUE; +} + +static gboolean +dm_init_protocol_connection (GdmProtocolData *data) +{ + if (g_getenv ("DM_CONTROL") && !g_getenv ("GDMSESSION")) { + data->is_kdm = TRUE; + return kdm_init_protocol_connection (data); + } + + data->is_kdm = FALSE; + return gdm_init_protocol_connection (data); +} + static void gdm_parse_query_response (GdmProtocolData *data, const char *response) @@ -317,7 +386,21 @@ } static void -gdm_update_logout_actions (GdmProtocolData *data) +kdm_parse_query_response (GdmProtocolData *data, + const char *response) +{ + data->available_actions = GDM_LOGOUT_ACTION_NONE; + data->current_actions = GDM_LOGOUT_ACTION_NONE; + + if (!response) + return; + + if (strstr (response, "\tshutdown")) + data->available_actions |= GDM_LOGOUT_ACTION_SHUTDOWN | GDM_LOGOUT_ACTION_REBOOT; +} + +static void +dm_update_logout_actions (GdmProtocolData *data) { time_t current_time; char *response; @@ -328,21 +411,30 @@ data->last_update = current_time; - if (!gdm_init_protocol_connection (data)) + if (!dm_init_protocol_connection (data)) return; - - if ((response = gdm_send_protocol_msg (data, GDM_PROTOCOL_MSG_QUERY_ACTION))) { - gdm_parse_query_response (data, response); - g_free (response); - } - gdm_shutdown_protocol_connection (data); + if (data->is_kdm) { + /* KDM */ + if ((response = dm_send_protocol_msg (data, KDM_PROTOCOL_MSG_QUERY_ACTION))) { + kdm_parse_query_response (data, response); + g_free (response); + } + } else { + /* GDM */ + if ((response = dm_send_protocol_msg (data, GDM_PROTOCOL_MSG_QUERY_ACTION))) { + gdm_parse_query_response (data, response); + g_free (response); + } + } + + dm_shutdown_protocol_connection (data); } gboolean gdm_supports_logout_action (GdmLogoutAction action) { - gdm_update_logout_actions (&gdm_protocol_data); + dm_update_logout_actions (&gdm_protocol_data); return (gdm_protocol_data.available_actions & action) != 0; } @@ -350,20 +442,15 @@ GdmLogoutAction gdm_get_logout_action (void) { - gdm_update_logout_actions (&gdm_protocol_data); + dm_update_logout_actions (&gdm_protocol_data); return gdm_protocol_data.current_actions; } -void -gdm_set_logout_action (GdmLogoutAction action) +static char * +gdm_logout_action_msg (GdmLogoutAction action) { char *action_str = NULL; - char *msg; - char *response; - - if (!gdm_init_protocol_connection (&gdm_protocol_data)) - return; switch (action) { case GDM_LOGOUT_ACTION_NONE: @@ -380,14 +467,48 @@ break; } - msg = g_strdup_printf (GDM_PROTOCOL_MSG_SET_ACTION " %s", action_str); + return g_strdup_printf (GDM_PROTOCOL_MSG_SET_ACTION " %s", action_str); +} + +static char * +kdm_logout_action_msg (GdmLogoutAction action) +{ + char *msg = NULL; + + if (action == GDM_LOGOUT_ACTION_SHUTDOWN) + msg = g_strdup ("shutdown\thalt\task"); + else if (action == GDM_LOGOUT_ACTION_REBOOT) + msg = g_strdup ("shutdown\treboot\task"); + + return msg; +} + +void +gdm_set_logout_action (GdmLogoutAction action) +{ + char *action_str = NULL; + char *msg; + char *response; + + if (!dm_init_protocol_connection (&gdm_protocol_data)) + return; + + if (gdm_protocol_data.is_kdm) + msg = kdm_logout_action_msg (action); + else + msg = gdm_logout_action_msg (action); + + if (!msg) { + dm_shutdown_protocol_connection (&gdm_protocol_data); + return; + } - response = gdm_send_protocol_msg (&gdm_protocol_data, msg); + response = dm_send_protocol_msg (&gdm_protocol_data, msg); g_free (msg); g_free (response); gdm_protocol_data.last_update = 0; - gdm_shutdown_protocol_connection (&gdm_protocol_data); + dm_shutdown_protocol_connection (&gdm_protocol_data); }