This commit is contained in:
Havoc Pennington 2001-09-14 06:30:50 +00:00
parent 1385d192c5
commit b1c7811e89
10 changed files with 987 additions and 44 deletions

View File

@ -1,5 +1,5 @@
INCLUDES=@MSM_CFLAGS@ -DMSM_PKGDATADIR=\"$(datadir)/msm\"
INCLUDES=@MSM_CFLAGS@ -DMSM_PKGDATADIR=\"$(datadir)/msm\"
msm_SOURCES= \
client.c \

View File

@ -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,
SmProp *prop)
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)
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;
}

View File

@ -66,9 +66,12 @@ 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,
SmProp *prop);
void msm_client_set_property_taking_ownership (MsmClient *client,
SmProp *prop);
void msm_client_unset_property (MsmClient *client,
const char *name);
void msm_client_send_properties (MsmClient *client);

View File

@ -60,7 +60,8 @@ main (int argc, char **argv)
gboolean failsafe;
struct sigaction act;
sigset_t empty_mask;
MsmServer *server;
sigemptyset (&empty_mask);
act.sa_handler = SIG_IGN;
act.sa_mask = empty_mask;
@ -118,7 +119,14 @@ 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);

View File

@ -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,12 +246,22 @@ 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.
*/
free (previous_id);
return FALSE;
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;
}
}
}
@ -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;
@ -567,7 +599,8 @@ 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 */
@ -581,16 +614,26 @@ msm_server_cancel_shutdown (MsmServer *server)
MsmClient *client;
client = tmp->data;
if (msm_client_get_state (client) == MSM_CLIENT_STATE_SAVING)
msm_client_shutdown_cancelled (client);
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;
}

View File

@ -31,8 +31,9 @@ typedef struct _MsmServer MsmServer;
typedef void (* MsmClientFunc) (MsmClient* client);
MsmServer* msm_server_new (void);
void msm_server_free (MsmServer *server);
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,
MsmClient *client);
@ -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
View 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
View 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

View File

@ -20,6 +20,7 @@
*/
#include "util.h"
#include <unistd.h>
void
msm_fatal (const char *format, ...)
@ -65,4 +66,111 @@ 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;
}

View File

@ -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