mirror of
https://github.com/brl/mutter.git
synced 2024-11-28 19:10:43 -05:00
...
This commit is contained in:
parent
1385d192c5
commit
b1c7811e89
308
src/msm/client.c
308
src/msm/client.c
@ -30,8 +30,40 @@ struct _MsmClient
|
||||
char *hostname;
|
||||
char *desc;
|
||||
int restart_style;
|
||||
GList *properties;
|
||||
};
|
||||
|
||||
static GList* find_property_link_by_name (MsmClient *client,
|
||||
const char *name);
|
||||
|
||||
static SmProp* find_property_by_name (MsmClient *client,
|
||||
const char *name);
|
||||
|
||||
static gboolean find_card8_property (MsmClient *client,
|
||||
const char *name,
|
||||
int *result)
|
||||
|
||||
static gboolean find_string_property (MsmClient *client,
|
||||
const char *name,
|
||||
char **result);
|
||||
|
||||
static gboolean find_vector_property (MsmClient *client,
|
||||
const char *name,
|
||||
int *argcp,
|
||||
char ***argvp);
|
||||
|
||||
static gboolean get_card8_value (SmProp *prop,
|
||||
int *result);
|
||||
static gboolean get_string_value (SmProp *prop,
|
||||
char **result);
|
||||
static gboolean get_vector_value (SmProp *prop,
|
||||
int *argcp,
|
||||
char ***argvp);
|
||||
|
||||
static SmProp* copy_property (SmProp *prop);
|
||||
|
||||
#define DEFAULT_RESTART_STYLE SmRestartIfRunning
|
||||
|
||||
MsmClient*
|
||||
msm_client_new (MsmServer *server,
|
||||
SmsConn cnxn)
|
||||
@ -46,7 +78,8 @@ msm_client_new (MsmServer *server,
|
||||
client->id = NULL;
|
||||
client->hostname = NULL;
|
||||
client->desc = g_strdup ("unknown");
|
||||
client->restart_style = SmRestartIfRunning;
|
||||
client->restart_style = DEFAULT_RESTART_STYLE;
|
||||
client->properties = NULL;
|
||||
|
||||
return client;
|
||||
}
|
||||
@ -55,12 +88,25 @@ void
|
||||
msm_client_free (MsmClient *client)
|
||||
{
|
||||
IceConn ice_cnxn;
|
||||
GList *tmp;
|
||||
|
||||
ice_cnxn = SmsGetIceConnection (client->cnxn);
|
||||
SmsCleanUp (client->cnxn);
|
||||
IceSetShutdownNegotiation (ice_cnxn, False);
|
||||
IceCloseConnection (ice_cnxn);
|
||||
|
||||
tmp = client->properties;
|
||||
while (tmp != NULL)
|
||||
{
|
||||
SmProp *prop = tmp->data;
|
||||
|
||||
SmFreeProperty (prop);
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
g_list_free (client->properties);
|
||||
|
||||
g_free (client->id);
|
||||
g_free (client->hostname);
|
||||
g_free (client->desc);
|
||||
@ -92,6 +138,18 @@ msm_client_get_server (MsmClient *client)
|
||||
return client->server;
|
||||
}
|
||||
|
||||
const char*
|
||||
msm_client_get_id (MsmClient *client)
|
||||
{
|
||||
return client->id;
|
||||
}
|
||||
|
||||
int
|
||||
msm_client_get_restart_style (MsmClient *client)
|
||||
{
|
||||
return client->restart_style;
|
||||
}
|
||||
|
||||
void
|
||||
msm_client_register (MsmClient *client,
|
||||
const char *id)
|
||||
@ -233,23 +291,267 @@ msm_client_save_confirmed (MsmClient *client,
|
||||
}
|
||||
|
||||
void
|
||||
msm_client_set_property (MsmClient *client,
|
||||
msm_client_set_property_taking_ownership (MsmClient *client,
|
||||
SmProp *prop)
|
||||
{
|
||||
/* we own prop which should be freed with SmFreeProperty() */
|
||||
GList *list;
|
||||
|
||||
if (prop->name == NULL)
|
||||
{
|
||||
SmFreeProperty (prop);
|
||||
return;
|
||||
}
|
||||
|
||||
list = find_property_link_by_name (prop->name);
|
||||
if (list)
|
||||
{
|
||||
SmFreeProperty (list->data);
|
||||
list->data = prop;
|
||||
}
|
||||
else
|
||||
{
|
||||
client->properties = g_list_prepend (client->properties,
|
||||
prop);
|
||||
}
|
||||
|
||||
/* update pieces of the client struct */
|
||||
if (strcmp (prop->name, "SmRestartStyleHint") == 0)
|
||||
{
|
||||
int hint;
|
||||
if (get_card8_value (prop, &hint))
|
||||
client->restart_style = hint;
|
||||
else
|
||||
client->restart_style = DEFAULT_RESTART_STYLE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
msm_client_unset_property (MsmClient *client,
|
||||
const char *name)
|
||||
{
|
||||
GList *list;
|
||||
|
||||
list = find_property_link_by_name (prop->name);
|
||||
if (list)
|
||||
{
|
||||
SmFreeProperty (list->data);
|
||||
client->properties = g_list_delete_link (client->properties,
|
||||
list);
|
||||
}
|
||||
|
||||
/* Return to default values */
|
||||
if (strcmp (name, "SmRestartStyleHint") == 0)
|
||||
{
|
||||
client->restart_style = DEFAULT_RESTART_STYLE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
msm_client_send_properties (MsmClient *client)
|
||||
{
|
||||
SmsReturnProperties (/* FIXME */);
|
||||
int n_props;
|
||||
SmProp **props;
|
||||
GList *tmp;
|
||||
int i;
|
||||
|
||||
n_props = g_list_length (client->properties);
|
||||
props = g_new (SmProp, n_props);
|
||||
|
||||
i = 0;
|
||||
tmp = client->properties;
|
||||
while (tmp != NULL)
|
||||
{
|
||||
props[i] = tmp->data;
|
||||
|
||||
tmp = tmp->next;
|
||||
++i;
|
||||
}
|
||||
|
||||
SmsReturnProperties (client->cnxn, n_props, props);
|
||||
|
||||
g_free (props);
|
||||
}
|
||||
|
||||
/* Property functions stolen from gnome-session */
|
||||
|
||||
static GList*
|
||||
find_property_link_by_name (MsmClient *client,
|
||||
const char *name)
|
||||
{
|
||||
GList *list;
|
||||
|
||||
for (list = client->properties; list; list = list->next)
|
||||
{
|
||||
SmProp *prop = (SmProp *) list->data;
|
||||
if (strcmp (prop->name, name) == 0)
|
||||
return list;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
SmProp*
|
||||
find_property_by_name (MsmClient *client, const char *name)
|
||||
{
|
||||
GList *list;
|
||||
|
||||
list = find_property_link_by_name (client, name);
|
||||
|
||||
return list ? list->data : NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
find_card8_property (MsmClient *client, const char *name,
|
||||
int *result)
|
||||
{
|
||||
SmProp *prop;
|
||||
|
||||
g_return_val_if_fail (result != NULL, FALSE);
|
||||
|
||||
prop = find_property_by_name (client, name);
|
||||
if (prop == NULL)
|
||||
return FALSE;
|
||||
else
|
||||
return get_card8_value (prop, result);
|
||||
}
|
||||
|
||||
gboolean
|
||||
find_string_property (MsmClient *client, const char *name,
|
||||
char **result)
|
||||
{
|
||||
SmProp *prop;
|
||||
|
||||
g_return_val_if_fail (result != NULL, FALSE);
|
||||
|
||||
prop = find_property_by_name (client, name);
|
||||
if (prop == NULL)
|
||||
return FALSE;
|
||||
else
|
||||
return get_string_value (prop, result);
|
||||
}
|
||||
|
||||
gboolean
|
||||
find_vector_property (MsmClient *client, const char *name,
|
||||
int *argcp, char ***argvp)
|
||||
{
|
||||
SmProp *prop;
|
||||
|
||||
g_return_val_if_fail (argcp != NULL, FALSE);
|
||||
g_return_val_if_fail (argvp != NULL, FALSE);
|
||||
|
||||
prop = find_property_by_name (client, name);
|
||||
if (prop == NULL)
|
||||
return FALSE;
|
||||
else
|
||||
return get_vector_value (prop, argcp, argvp);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_card8_value (SmProp *prop,
|
||||
int *result)
|
||||
{
|
||||
g_return_val_if_fail (result != NULL, FALSE);
|
||||
|
||||
if (strcmp (prop->type, SmCARD8) == 0)
|
||||
{
|
||||
char *p;
|
||||
p = prop->vals[0].value;
|
||||
*result = *p;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_string_value (SmProp *prop,
|
||||
char **result)
|
||||
{
|
||||
g_return_val_if_fail (result != NULL, FALSE);
|
||||
|
||||
if (strcmp (prop->type, SmARRAY8) == 0)
|
||||
{
|
||||
*result = g_malloc (prop->vals[0].length + 1);
|
||||
memcpy (*result, prop->vals[0].value, prop->vals[0].length);
|
||||
(*result)[prop->vals[0].length] = '\0';
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_vector_value (SmProp *prop,
|
||||
int *argcp,
|
||||
char ***argvp)
|
||||
{
|
||||
g_return_val_if_fail (argcp != NULL, FALSE);
|
||||
g_return_val_if_fail (argvp != NULL, FALSE);
|
||||
|
||||
if (strcmp (prop->type, SmLISTofARRAY8) == 0)
|
||||
{
|
||||
int i;
|
||||
|
||||
*argcp = prop->num_vals;
|
||||
*argvp = g_new0 (char *, *argcp + 1);
|
||||
for (i = 0; i < *argcp; ++i)
|
||||
{
|
||||
(*argvp)[i] = g_malloc (prop->vals[i].length + 1);
|
||||
memcpy ((*argvp)[i], prop->vals[i].value, prop->vals[i].length);
|
||||
(*argvp)[i][prop->vals[i].length] = '\0';
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static SmProp*
|
||||
copy_property (SmProp *prop)
|
||||
{
|
||||
int i;
|
||||
SmProp *copy;
|
||||
|
||||
/* This all uses malloc so we can use SmFreeProperty() */
|
||||
|
||||
copy = msm_non_glib_malloc (sizeof (SmProp));
|
||||
|
||||
if (prop->name)
|
||||
copy->name = msm_non_glib_strdup (prop->name);
|
||||
else
|
||||
copy->name = NULL;
|
||||
|
||||
if (prop->type)
|
||||
copy->type = msm_non_glib_strdup (prop->type);
|
||||
else
|
||||
copy->type = NULL;
|
||||
|
||||
copy->num_vals = prop->num_vals;
|
||||
copy->vals = NULL;
|
||||
|
||||
if (copy->num_vals > 0 && prop->vals)
|
||||
{
|
||||
copy->vals = msm_non_glib_malloc (sizeof (SmPropValue) * copy->num_vals);
|
||||
|
||||
for (i = 0; i < copy->num_vals; i++)
|
||||
{
|
||||
if (prop->vals[i].value)
|
||||
{
|
||||
copy->vals[i].length = prop->vals[i].length;
|
||||
copy->vals[i].value = msm_non_glib_malloc (copy->vals[i].length);
|
||||
memcpy (copy->vals[i].value, prop->vals[i].value,
|
||||
copy->vals[i].length);
|
||||
}
|
||||
else
|
||||
{
|
||||
copy->vals[i].length = 0;
|
||||
copy->vals[i].value = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
@ -66,8 +66,11 @@ SmsConn msm_client_get_connection (MsmClient *client);
|
||||
const char* msm_client_get_description (MsmClient *client);
|
||||
MsmClientState msm_client_get_state (MsmClient *client);
|
||||
MsmServer* msm_client_get_server (MsmClient *client);
|
||||
/* can return NULL */
|
||||
const char* msm_client_get_id (MsmClient *client);
|
||||
int msm_client_get_restart_style (MsmClient *client);
|
||||
|
||||
void msm_client_set_property (MsmClient *client,
|
||||
void msm_client_set_property_taking_ownership (MsmClient *client,
|
||||
SmProp *prop);
|
||||
void msm_client_unset_property (MsmClient *client,
|
||||
const char *name);
|
||||
|
@ -60,6 +60,7 @@ main (int argc, char **argv)
|
||||
gboolean failsafe;
|
||||
struct sigaction act;
|
||||
sigset_t empty_mask;
|
||||
MsmServer *server;
|
||||
|
||||
sigemptyset (&empty_mask);
|
||||
act.sa_handler = SIG_IGN;
|
||||
@ -119,6 +120,13 @@ main (int argc, char **argv)
|
||||
++i;
|
||||
}
|
||||
|
||||
if (failsafe)
|
||||
server = msm_server_new_failsafe ();
|
||||
else
|
||||
server = msm_server_new (session_name);
|
||||
|
||||
msm_server_launch_session (server);
|
||||
|
||||
main_loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
g_main_run (main_loop);
|
||||
|
154
src/msm/server.c
154
src/msm/server.c
@ -42,6 +42,7 @@
|
||||
*/
|
||||
|
||||
#include "server.h"
|
||||
#include "session.h"
|
||||
|
||||
/* FIXME we need to time out anytime we're waiting for a client
|
||||
* response, such as InteractDone, SaveYourselfDone, ConnectionClosed
|
||||
@ -50,13 +51,15 @@
|
||||
|
||||
struct _MsmServer
|
||||
{
|
||||
MsmSession *session;
|
||||
GList *clients;
|
||||
IceAuthDataEntry *auth_entries;
|
||||
int n_auth_entries;
|
||||
MsmClient *currently_interacting;
|
||||
GList *interact_pending;
|
||||
|
||||
guint in_shutdown : 1;
|
||||
guint in_global_save : 1;
|
||||
guint in_shutdown : 1; /* TRUE only if in_global_save */
|
||||
guint save_allows_interaction : 1;
|
||||
};
|
||||
|
||||
@ -112,19 +115,21 @@ static gboolean create_auth_entries (MsmServer *server,
|
||||
int n_listen_objs);
|
||||
static void free_auth_entries (IceAuthDataEntry *entries);
|
||||
|
||||
MsmServer*
|
||||
msm_server_new (void)
|
||||
static void
|
||||
msm_server_new_with_session (MsmSession *session)
|
||||
{
|
||||
char errbuf[256];
|
||||
MsmServer *server;
|
||||
|
||||
server = g_new (MsmServer, 1);
|
||||
|
||||
server->session = session;
|
||||
server->clients = NULL;
|
||||
server->auth_entries = NULL;
|
||||
server->n_auth_entries = 0;
|
||||
server->currently_interacting = NULL;
|
||||
server->interact_pending = NULL;
|
||||
server->in_global_save = FALSE;
|
||||
server->in_shutdown = FALSE;
|
||||
server->save_allows_interaction = FALSE;
|
||||
|
||||
@ -140,6 +145,22 @@ msm_server_new (void)
|
||||
return server;
|
||||
}
|
||||
|
||||
MsmServer*
|
||||
msm_server_new (const char *session_name)
|
||||
{
|
||||
MsmSession *session;
|
||||
|
||||
session = msm_session_new (session_name);
|
||||
|
||||
return msm_server_new_with_session (session);
|
||||
}
|
||||
|
||||
MsmServer*
|
||||
msm_server_new_failsafe (void)
|
||||
{
|
||||
return msm_server_new_with_session (msm_session_get_failsafe ());
|
||||
}
|
||||
|
||||
void
|
||||
msm_server_free (MsmServer *server)
|
||||
{
|
||||
@ -225,13 +246,23 @@ register_client_callback (SmsConn cnxn,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIXME check for pending/known client IDs and register the client,
|
||||
* return TRUE if we know about this previous_id
|
||||
/* check for pending/known client IDs and register the client,
|
||||
* return TRUE if we know about this previous_id, return FALSE
|
||||
* if we do not know about it or it's already being used.
|
||||
*/
|
||||
|
||||
if (msm_server_client_id_in_use (server, previous_id) ||
|
||||
!msm_session_client_id_known (server->session, previous_id))
|
||||
{
|
||||
free (previous_id);
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
msm_client_register (client, previous_id);
|
||||
free (previous_id);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -389,9 +420,10 @@ set_properties_callback (SmsConn cnxn,
|
||||
i = 0;
|
||||
while (i < numProps)
|
||||
{
|
||||
msm_client_set_property (client, props[i]);
|
||||
msm_client_set_property_taking_ownership (client, props[i]);
|
||||
|
||||
SmFreeProperty (props[i]);
|
||||
/* Client owns it, so don't do this. */
|
||||
/* SmFreeProperty (props[i]); */
|
||||
|
||||
++i;
|
||||
}
|
||||
@ -452,10 +484,8 @@ new_client_callback (SmsConn cnxn,
|
||||
*/
|
||||
if (server->in_shutdown)
|
||||
{
|
||||
/* have to use malloc() */
|
||||
*failure_reason_ret = malloc (256);
|
||||
g_strncpy (*failure_reason_ret, _("Refusing new client connection because the session is currently being shut down\n"), 255);
|
||||
(*failure_reason_ret)[255] = '\0'; /* paranoia */
|
||||
*failure_reason_ret =
|
||||
msm_non_glib_strdup (_("Refusing new client connection because the session is currently being shut down\n"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -536,6 +566,8 @@ msm_server_save_all (MsmServer *server,
|
||||
{
|
||||
GList *tmp;
|
||||
|
||||
server->in_global_save = TRUE;
|
||||
|
||||
if (shut_down) /* never cancel a shutdown here */
|
||||
server->in_shutdown = TRUE;
|
||||
|
||||
@ -568,6 +600,7 @@ msm_server_cancel_shutdown (MsmServer *server)
|
||||
if (!server->in_shutdown)
|
||||
return;
|
||||
|
||||
server->in_global_save = FALSE;
|
||||
server->in_shutdown = FALSE;
|
||||
|
||||
/* Cancel any interactions in progress */
|
||||
@ -582,15 +615,25 @@ msm_server_cancel_shutdown (MsmServer *server)
|
||||
|
||||
client = tmp->data;
|
||||
|
||||
if (msm_client_get_state (client) == MSM_CLIENT_STATE_SAVING)
|
||||
switch (msm_client_get_state (client))
|
||||
{
|
||||
case MSM_CLIENT_STATE_SAVING:
|
||||
case MSM_CLIENT_STATE_PHASE2_REQUESTED:
|
||||
case MSM_CLIENT_STATE_SAVING_PHASE2:
|
||||
case MSM_CLIENT_STATE_SAVE_DONE:
|
||||
case MSM_CLIENT_STATE_SAVE_FAILED:
|
||||
msm_client_shutdown_cancelled (client);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Think about whether to move to phase 2, return to idle state,
|
||||
* or shut down
|
||||
* save session to disk, or shut down
|
||||
*/
|
||||
void
|
||||
msm_server_consider_phase_change (MsmServer *server)
|
||||
@ -658,6 +701,37 @@ msm_server_consider_phase_change (MsmServer *server)
|
||||
return;
|
||||
}
|
||||
|
||||
if (server->in_global_save)
|
||||
{
|
||||
GList *tmp;
|
||||
|
||||
tmp = server->clients;
|
||||
while (tmp != NULL)
|
||||
{
|
||||
MsmClient *client = tmp->data;
|
||||
|
||||
switch (msm_client_get_state (client))
|
||||
{
|
||||
case MSM_CLIENT_STATE_SAVE_DONE:
|
||||
/* Update it in the session, since it saved successfully. */
|
||||
msm_session_update_client (server->session, client);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
/* Write to disk. */
|
||||
msm_session_save (server->session);
|
||||
}
|
||||
|
||||
/* msm_session_save() may have cancelled any shutdown that was in progress,
|
||||
* so don't assume here that we are still in_global_save or in_shutdown.
|
||||
* Also, client states may have changed.
|
||||
*/
|
||||
|
||||
if (server->in_shutdown)
|
||||
{
|
||||
/* We are shutting down, and all clients are in the idle state.
|
||||
@ -678,10 +752,12 @@ msm_server_consider_phase_change (MsmServer *server)
|
||||
tmp = tmp->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* We don't leave the in_shutdown/in_global_save states in this case */
|
||||
}
|
||||
else
|
||||
else if (server->in_global_save)
|
||||
{
|
||||
/* Send SaveComplete to all clients that are finished saving */
|
||||
/* send SaveComplete to all clients that are finished saving */
|
||||
GList *tmp;
|
||||
|
||||
tmp = server->clients;
|
||||
@ -701,6 +777,9 @@ msm_server_consider_phase_change (MsmServer *server)
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
/* Leave in_global_save state */
|
||||
server->in_global_save = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -721,6 +800,40 @@ msm_server_foreach_client (MsmServer *server,
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
msm_server_client_id_in_use (MsmServer *server,
|
||||
const char *id)
|
||||
{
|
||||
GList *tmp;
|
||||
|
||||
tmp = server->clients;
|
||||
while (tmp != NULL)
|
||||
{
|
||||
MsmClient *client = tmp->data;
|
||||
const char *cid;
|
||||
|
||||
cid = msm_client_get_id (client);
|
||||
|
||||
if (cid && strcmp (cid, id) == 0)
|
||||
return TRUE;
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
msm_server_launch_session (MsmServer *server)
|
||||
{
|
||||
msm_session_launch (server->session);
|
||||
}
|
||||
|
||||
gboolean
|
||||
msm_server_in_shutdown (MsmServer *server)
|
||||
{
|
||||
return server->in_shutdown;
|
||||
}
|
||||
|
||||
/*
|
||||
* ICE utility code, cut-and-pasted from Metacity, and in turn
|
||||
@ -1000,13 +1113,7 @@ create_auth_entries (MsmServer *server,
|
||||
|
||||
original_umask = umask (0077); /* disallow non-owner access */
|
||||
|
||||
path = g_getenv ("SM_SAVE_DIR");
|
||||
if (!path)
|
||||
{
|
||||
path = g_get_home_dir ();
|
||||
if (!path)
|
||||
path = ".";
|
||||
}
|
||||
path = msm_get_work_directory ();
|
||||
|
||||
err = NULL;
|
||||
tmpl = g_strconcat (path, "/msm-add-commands-XXXXXX", NULL);
|
||||
@ -1138,4 +1245,3 @@ free_auth_entries (IceAuthDataEntry *entries,
|
||||
add_file = NULL;
|
||||
remove_file = NULL;
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,8 @@ typedef struct _MsmServer MsmServer;
|
||||
|
||||
typedef void (* MsmClientFunc) (MsmClient* client);
|
||||
|
||||
MsmServer* msm_server_new (void);
|
||||
MsmServer* msm_server_new (const char *session_name);
|
||||
MsmServer* msm_server_new_failsafe (void);
|
||||
void msm_server_free (MsmServer *server);
|
||||
|
||||
void msm_server_queue_interaction (MsmServer *server,
|
||||
@ -52,4 +53,11 @@ void msm_server_drop_client (MsmServer *server,
|
||||
|
||||
void msm_server_next_pending_interaction (MsmServer *server);
|
||||
|
||||
gboolean msm_server_client_id_in_use (MsmServer *server,
|
||||
const char *id);
|
||||
|
||||
void msm_server_launch_session (MsmServer *server);
|
||||
|
||||
gboolean msm_server_in_shutdown (MsmServer *server);
|
||||
|
||||
#endif
|
||||
|
358
src/msm/session.c
Normal file
358
src/msm/session.c
Normal file
@ -0,0 +1,358 @@
|
||||
/* msm session */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001 Havoc Pennington
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "session.h"
|
||||
|
||||
typedef struct _MsmSavedClient MsmSavedClient;
|
||||
|
||||
struct _MsmSavedClient
|
||||
{
|
||||
char **restart_command;
|
||||
|
||||
};
|
||||
|
||||
struct _MsmSession
|
||||
{
|
||||
char *name;
|
||||
GList *clients;
|
||||
char *filename;
|
||||
char *full_filename;
|
||||
int lock_fd;
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MSM_SESSION_FAILURE_OPENING_FILE,
|
||||
MSM_SESSION_FAILURE_LOCKING,
|
||||
MSM_SESSION_FAILURE_BAD_FILE,
|
||||
MSM_SESSION_FAILURE_EMPTY
|
||||
} MsmSessionFailureReason;
|
||||
|
||||
static GHashTable *sessions = NULL;
|
||||
|
||||
static MsmSession* recover_failed_session (MsmSession *session,
|
||||
MsmSessionFailureReason reason,
|
||||
const char *details);
|
||||
|
||||
static gboolean parse_session_file (MsmSession *session,
|
||||
GError **error);
|
||||
|
||||
void
|
||||
msm_session_update_client (MsmSession *session,
|
||||
MsmClient *client)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
msm_session_remove_client (MsmSession *session,
|
||||
MsmClient *client)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
gboolean
|
||||
msm_session_client_id_known (MsmSession *session,
|
||||
const char *previous_id)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
msm_session_launch (MsmSession *session)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
static const char*
|
||||
session_dir (void)
|
||||
{
|
||||
static char *dir;
|
||||
|
||||
if (dir == NULL)
|
||||
{
|
||||
dir = g_strconcat (msm_get_work_directory (),
|
||||
"/sessions",
|
||||
NULL);
|
||||
}
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
static void
|
||||
set_close_on_exec (int fd)
|
||||
{
|
||||
int val;
|
||||
|
||||
val = fcntl (fd, F_GETFD, 0);
|
||||
if (val < 0)
|
||||
{
|
||||
gconf_log (GCL_DEBUG, "couldn't F_GETFD: %s\n", g_strerror (errno));
|
||||
return;
|
||||
}
|
||||
|
||||
val |= FD_CLOEXEC;
|
||||
|
||||
if (fcntl (fd, F_SETFD, val) < 0)
|
||||
gconf_log (GCL_DEBUG, "couldn't F_SETFD: %s\n", g_strerror (errno));
|
||||
}
|
||||
|
||||
/* Your basic Stevens cut-and-paste */
|
||||
static int
|
||||
lock_reg (int fd, int cmd, int type, off_t offset, int whence, off_t len)
|
||||
{
|
||||
struct flock lock;
|
||||
|
||||
lock.l_type = type; /* F_RDLCK, F_WRLCK, F_UNLCK */
|
||||
lock.l_start = offset; /* byte offset relative to whence */
|
||||
lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
|
||||
lock.l_len = len; /* #bytes, 0 for eof */
|
||||
|
||||
return fcntl (fd, cmd, &lock);
|
||||
}
|
||||
|
||||
#define lock_entire_file(fd) \
|
||||
lock_reg ((fd), F_SETLK, F_WRLCK, 0, SEEK_SET, 0)
|
||||
#define unlock_entire_file(fd) \
|
||||
lock_reg ((fd), F_SETLK, F_UNLCK, 0, SEEK_SET, 0)
|
||||
|
||||
static MsmSession*
|
||||
msm_session_get_for_filename (const char *name,
|
||||
const char *filename)
|
||||
{
|
||||
MsmSession *session;
|
||||
int fd = -1;
|
||||
GError *dir_error = NULL;
|
||||
GError *err;
|
||||
gboolean use_global_file;
|
||||
|
||||
session = g_hash_table_lookup (sessions, filename);
|
||||
if (session)
|
||||
return session;
|
||||
|
||||
session = g_new0 (MsmSession, 1);
|
||||
session->name = g_strdup (name);
|
||||
session->clients = NULL;
|
||||
session->filename = g_strdup (filename);
|
||||
session->full_filename = g_strconcat (session_dir (), "/", filename, NULL);
|
||||
session->lock_fd = -1;
|
||||
|
||||
dir_error = NULL;
|
||||
msm_create_dir_and_parents (session_dir (), &dir_error);
|
||||
/* We save dir_error for later; if creating the file fails,
|
||||
* we give dir_error in the reason.
|
||||
*/
|
||||
|
||||
/* To use a session, we need to lock the file in the user's
|
||||
* save dir (by default in .msm/sessions/).
|
||||
*
|
||||
* If the file didn't previously exist, then we
|
||||
* init the session from the global session of the same name,
|
||||
* if any.
|
||||
*
|
||||
* This locking stuff has several races in it, and probably doesn't
|
||||
* work over NFS, and all that jazz, but avoiding the races
|
||||
* introduces stale lock issues, which are in practice more serious
|
||||
* for users than the usual issues one worries about when locking.
|
||||
*/
|
||||
|
||||
fd = open (session->full_filename, O_RDWR | O_CREAT | O_EXCL, 0700);
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
char *message;
|
||||
|
||||
message = g_strdup_printf (_("Failed to open the session file '%s': %s (%s)"),
|
||||
session->full_filename,
|
||||
g_strerror (errno),
|
||||
dir_error ?
|
||||
dir_error->message :
|
||||
_("file's parent directory created successfully"));
|
||||
|
||||
if (dir_error)
|
||||
g_error_free (dir_error);
|
||||
|
||||
session = recover_failed_session (session,
|
||||
MSM_SESSION_FAILURE_OPENING_FILE,
|
||||
message);
|
||||
|
||||
g_free (message);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
if (dir_error)
|
||||
{
|
||||
g_error_free (dir_error);
|
||||
dir_error = NULL;
|
||||
}
|
||||
|
||||
if (lock_entire_file (fd) < 0)
|
||||
{
|
||||
char *message;
|
||||
|
||||
close (fd);
|
||||
|
||||
message = g_strdup_printf (_("Failed to lock the session file '%s': %s"),
|
||||
session->full_filename,
|
||||
g_strerror (errno));
|
||||
|
||||
session = recover_failed_session (session,
|
||||
MSM_SESSION_FAILURE_LOCKING,
|
||||
message);
|
||||
|
||||
g_free (message);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
session->lock_fd = fd;
|
||||
set_close_on_exec (fd);
|
||||
|
||||
err = NULL;
|
||||
if (!parse_session_file (session, &err))
|
||||
{
|
||||
char *message;
|
||||
|
||||
message = g_strdup_printf (_("Failed to parse the session file '%s': %s\n"),
|
||||
session->full_filename,
|
||||
err->message);
|
||||
|
||||
g_error_free (err);
|
||||
|
||||
session = recover_failed_session (session,
|
||||
MSM_SESSION_FAILURE_BAD_FILE,
|
||||
message);
|
||||
|
||||
g_free (message);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
if (session->clients == NULL)
|
||||
{
|
||||
session = recover_failed_session (session,
|
||||
MSM_SESSION_FAILURE_EMPTY,
|
||||
_("Session doesn't contain any applications"));
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
MsmSession*
|
||||
msm_session_get (const char *name)
|
||||
{
|
||||
if (name == NULL)
|
||||
{
|
||||
return msm_session_get_for_filename (_("Default"), "Default.session");
|
||||
}
|
||||
else
|
||||
{
|
||||
char *filename;
|
||||
char *p;
|
||||
MsmSession *session;
|
||||
|
||||
filename = g_strconcat (name, ".session", NULL);
|
||||
|
||||
/* Remove path separators from the filename */
|
||||
p = filename;
|
||||
while (*p)
|
||||
{
|
||||
if (*p == '/')
|
||||
*p = '_';
|
||||
++p;
|
||||
}
|
||||
|
||||
session = msm_session_get_for_filename (name, filename);
|
||||
|
||||
g_free (filename);
|
||||
|
||||
return session;
|
||||
}
|
||||
}
|
||||
|
||||
MsmSession*
|
||||
msm_session_get_failsafe (void)
|
||||
{
|
||||
return msm_session_get_for_filename (_("Failsafe"), "Failsafe.session");
|
||||
}
|
||||
|
||||
void
|
||||
msm_session_save (MsmSession *session,
|
||||
MsmServer *server)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
recover_failed_session (MsmSession *session,
|
||||
MsmSessionFailureReason reason,
|
||||
const char *details)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_session_file (MsmSession *session,
|
||||
GError **error)
|
||||
{
|
||||
char *parse_file;
|
||||
struct stat sb;
|
||||
gboolean file_empty;
|
||||
|
||||
parse_file = NULL;
|
||||
file_empty = FALSE;
|
||||
|
||||
/* If the file is empty, probably because we just created it or have
|
||||
* never saved our session, then parse the global session file
|
||||
* instead of the user session file for our initial state.
|
||||
*/
|
||||
if (fstat (session->lock_fd, &sb) < 0)
|
||||
{
|
||||
/* Can't imagine this actually happening */
|
||||
msm_warning (_("Failed to stat new session file descriptor (%s)\n"),
|
||||
g_strerror (errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sb.st_size == 0)
|
||||
file_empty = TRUE;
|
||||
}
|
||||
|
||||
if (file_empty)
|
||||
parse_file = g_strconcat (MSM_PKGDATADIR, "/", session->filename, NULL);
|
||||
else
|
||||
parse_file = g_strdup (session->full_filename);
|
||||
|
||||
/* FIXME do the parsing */
|
||||
|
||||
g_free (parse_file);
|
||||
|
||||
return TRUE;
|
||||
}
|
42
src/msm/session.h
Normal file
42
src/msm/session.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* msm session */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2001 Havoc Pennington
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef MSM_SESSION_H
|
||||
#define MSM_SESSION_H
|
||||
|
||||
#include "client.h"
|
||||
|
||||
typedef struct _MsmSession MsmSession;
|
||||
|
||||
MsmSession* msm_session_get (const char *name);
|
||||
MsmSession* msm_session_get_failsafe (void);
|
||||
void msm_session_save (MsmSession *session);
|
||||
void msm_session_update_client (MsmSession *session,
|
||||
MsmClient *client);
|
||||
void msm_session_remove_client (MsmSession *session,
|
||||
MsmClient *client);
|
||||
void msm_session_launch (MsmSession *session);
|
||||
gboolean msm_session_client_id_known (MsmSession *session,
|
||||
const char *previous_id);
|
||||
|
||||
|
||||
#endif
|
||||
|
108
src/msm/util.c
108
src/msm/util.c
@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
#include "util.h"
|
||||
#include <unistd.h>
|
||||
|
||||
void
|
||||
msm_fatal (const char *format, ...)
|
||||
@ -66,3 +67,110 @@ msm_warning (const char *format, ...)
|
||||
exit (1);
|
||||
}
|
||||
|
||||
gboolean
|
||||
msm_create_dir_and_parents (const char *dir,
|
||||
int mode,
|
||||
GError **error)
|
||||
{
|
||||
char *parent;
|
||||
GSList *parents;
|
||||
GSList *tmp;
|
||||
|
||||
/* This function is crap; GNU fileutils has some really
|
||||
* robust code that does this.
|
||||
*/
|
||||
|
||||
parents = NULL;
|
||||
parent = g_path_get_dirname (dir);
|
||||
while (parent && parent[0] &&
|
||||
strcmp (parent, ".") != 0 &&
|
||||
strcmp (parent, "..") != 0 &&
|
||||
strcmp (parent, "/") != 0 &&
|
||||
/* an optimization since we will normally be using a homedir */
|
||||
strcmp (parent, g_get_home_dir ()) != 0)
|
||||
{
|
||||
parents = g_slist_prepend (parents, parent);
|
||||
parent = g_path_get_dirname (parent);
|
||||
}
|
||||
|
||||
/* Errors are a bit tricky; if we can't create /foo because
|
||||
* we lack write perms, and can't create /foo/bar because it exists,
|
||||
* but can create /foo/bar/baz, then it's not really an error.
|
||||
*
|
||||
* We more or less punt, and just display an error for the last mkdir.
|
||||
*/
|
||||
tmp = parents;
|
||||
while (tmp != NULL)
|
||||
{
|
||||
mkdir (tmp->data, mode);
|
||||
|
||||
g_free (tmp->data);
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
g_slist_free (parents);
|
||||
|
||||
if (mkdir (dir, mode) < 0)
|
||||
{
|
||||
if (errno != EEXIST)
|
||||
{
|
||||
g_set_error (error,
|
||||
G_FILE_ERROR,
|
||||
g_file_error_from_errno (errno),
|
||||
_("Failed to create directory '%s': %s\n"),
|
||||
dir, g_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
const char*
|
||||
msm_get_work_directory (void)
|
||||
{
|
||||
static char *dir = NULL;
|
||||
|
||||
if (dir == NULL)
|
||||
{
|
||||
dir = g_getenv ("SM_SAVE_DIR");
|
||||
if (dir == NULL)
|
||||
dir = g_strconcat (g_get_home_dir (), "/.msm", NULL);
|
||||
}
|
||||
|
||||
/* ignore errors here, we'll catch them later when we
|
||||
* try to use the dir
|
||||
*/
|
||||
msm_create_dir_and_parents (dir, 0700, NULL);
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
char*
|
||||
msm_non_glib_strdup (const char *str)
|
||||
{
|
||||
char *new_str;
|
||||
|
||||
if (str)
|
||||
{
|
||||
new_str = msm_non_glib_malloc (strlen (str) + 1);
|
||||
strcpy (new_str, str);
|
||||
}
|
||||
else
|
||||
new_str = NULL;
|
||||
|
||||
return new_str;
|
||||
}
|
||||
|
||||
void*
|
||||
msm_non_glib_malloc (int bytes)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
ptr = malloc (bytes);
|
||||
if (ptr == NULL)
|
||||
g_error ("Failed to allocate %d bytes\n", bytes);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
@ -36,5 +36,13 @@ void msm_fatal (const char *format,
|
||||
|
||||
void msm_quit (void);
|
||||
|
||||
const char* msm_get_work_directory (void);
|
||||
|
||||
char* msm_non_glib_strdup (const char *src);
|
||||
void* msm_non_glib_malloc (int bytes);
|
||||
|
||||
gboolean msm_create_dir_and_parents (const char *dir,
|
||||
int mode,
|
||||
GError **error);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user