Commit 8e6713f1 authored by Vincent Untz's avatar Vincent Untz

gsm: Make it possible for a .session file to define a fallback session

Two new keys are introduced: IsRunnableHelper and FallbackSession.

The first one defines a helper that is run to know if the session can be
used (only if the helper returns 0). The second defines the fallback
session to use if the helper doesn't return 0.

The helper cannot run for more than 500 ms.

There is a test program to make sure that our helper process management
works okay.
parent 30da8bec
......@@ -2,7 +2,8 @@ bin_PROGRAMS = gnome-session
noinst_LTLIBRARIES = libgsmutil.la
noinst_PROGRAMS = \
test-client-dbus \
test-inhibit
test-inhibit \
test-process-helper
AM_CPPFLAGS = \
$(GNOME_SESSION_CFLAGS) \
......@@ -48,6 +49,8 @@ gnome_session_SOURCES = \
gsm-inhibitor.c \
gsm-manager.c \
gsm-manager.h \
gsm-process-helper.c \
gsm-process-helper.h \
gsm-session-fill.c \
gsm-session-fill.h \
gsm-session-save.c \
......@@ -95,6 +98,9 @@ test_inhibit_LDADD = $(GNOME_SESSION_LIBS)
test_client_dbus_SOURCES = test-client-dbus.c
test_client_dbus_LDADD = $(DBUS_GLIB_LIBS)
test_process_helper_SOURCES = test-process-helper.c gsm-process-helper.c gsm-process-helper.h
test_process_helper_LDADD = $(DBUS_GLIB_LIBS)
gsm-marshal.c: gsm-marshal.list
$(AM_V_GEN)echo "#include \"gsm-marshal.h\"" > $@ && \
$(GLIB_GENMARSHAL) $< --prefix=gsm_marshal --body >> $@
......
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2010 Novell, Inc.
*
* 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
* Lesser 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 <config.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <glib.h>
#include "gsm-process-helper.h"
typedef struct {
const char *command_line;
GPid pid;
gboolean proper_exit;
int status;
GMainLoop *loop;
guint child_id;
guint timeout_id;
} GsmProcessHelper;
static void
on_child_exited_simple (GPid pid,
gint status,
gpointer data)
{
g_spawn_close_pid (pid);
}
static void
on_child_exited (GPid pid,
gint status,
gpointer data)
{
GsmProcessHelper *helper = data;
helper->proper_exit = TRUE;
helper->status = status;
g_spawn_close_pid (pid);
g_main_loop_quit (helper->loop);
}
static gboolean
on_child_timeout (gpointer data)
{
GsmProcessHelper *helper = data;
kill (helper->pid, SIGTERM);
g_warning ("Had to kill '%s' helper", helper->command_line);
helper->proper_exit = FALSE;
g_main_loop_quit (helper->loop);
return FALSE;
}
int
gsm_process_helper (const char *command_line,
unsigned int timeout)
{
GsmProcessHelper *helper;
gchar **argv = NULL;
GPid pid;
gboolean ret;
int exit_status = -1;
if (!g_shell_parse_argv (command_line, NULL, &argv, NULL))
return -1;
ret = g_spawn_async (NULL,
argv,
NULL,
G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD,
NULL,
NULL,
&pid,
NULL);
g_strfreev (argv);
if (!ret)
return -1;
helper = g_slice_new0 (GsmProcessHelper);
helper->command_line = command_line;
helper->pid = pid;
helper->proper_exit = FALSE;
helper->status = -1;
helper->loop = g_main_loop_new (NULL, FALSE);
helper->child_id = g_child_watch_add (helper->pid, on_child_exited, helper);
helper->timeout_id = g_timeout_add (timeout, on_child_timeout, helper);
g_main_loop_run (helper->loop);
if (helper->proper_exit && WIFEXITED (helper->status))
exit_status = WEXITSTATUS (helper->status);
else if (!helper->proper_exit) {
/* we'll need to call g_spawn_close_pid when the helper exits */
g_child_watch_add (pid, on_child_exited_simple, NULL);
}
if (helper->loop) {
g_main_loop_unref (helper->loop);
helper->loop = NULL;
}
if (helper->child_id) {
g_source_remove (helper->child_id);
helper->child_id = 0;
}
if (helper->timeout_id) {
g_source_remove (helper->timeout_id);
helper->timeout_id = 0;
}
g_slice_free (GsmProcessHelper, helper);
return exit_status;
}
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2010 Novell, Inc.
*
* 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
* Lesser 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 __GSM_PROCESS_HELPER_H
#define __GSM_PROCESS_HELPER_H
#include <glib.h>
G_BEGIN_DECLS
int gsm_process_helper (const char *command_line,
unsigned int timeout);
G_END_DECLS
#endif /* __GSM_PROCESS_HELPER_H */
......@@ -25,14 +25,19 @@
#include "gsm-consolekit.h"
#include "gsm-manager.h"
#include "gsm-process-helper.h"
#include "gsm-util.h"
#define GSM_DEFAULT_SESSION "gnome"
#define GSM_KEYFILE_SESSION_GROUP "GNOME Session"
#define GSM_KEYFILE_RUNNABLE_KEY "IsRunnableHelper"
#define GSM_KEYFILE_FALLBACK_KEY "FallbackSession"
#define GSM_KEYFILE_REQUIRED_KEY "Required"
#define GSM_KEYFILE_DEFAULT_KEY "DefaultApps"
#define GSM_RUNNABLE_HELPER_TIMEOUT 500 /* ms */
/* This doesn't contain the required components, so we need to always
* call append_required_apps() after a call to append_default_apps(). */
static void
......@@ -302,6 +307,48 @@ find_valid_session_keyfile (const char *session)
return keyfile;
}
static GKeyFile *
get_session_keyfile (const char *session)
{
GKeyFile *keyfile;
gboolean session_runnable;
char *value;
g_debug ("fill: *** Getting session '%s'", session);
keyfile = find_valid_session_keyfile (session);
session_runnable = TRUE;
value = g_key_file_get_string (keyfile,
GSM_KEYFILE_SESSION_GROUP, GSM_KEYFILE_RUNNABLE_KEY,
NULL);
if (!IS_STRING_EMPTY (value)) {
g_debug ("fill: *** Launching helper '%s' to know if session is runnable", value);
session_runnable = (gsm_process_helper (value, GSM_RUNNABLE_HELPER_TIMEOUT) == 0);
}
g_free (value);
if (session_runnable)
return keyfile;
g_debug ("fill: *** Session is not runnable");
/* We can't run this session, so try to use the fallback */
value = g_key_file_get_string (keyfile,
GSM_KEYFILE_SESSION_GROUP, GSM_KEYFILE_FALLBACK_KEY,
NULL);
g_key_file_free (keyfile);
keyfile = NULL;
if (!IS_STRING_EMPTY (value))
keyfile = get_session_keyfile (value);
g_free (value);
return keyfile;
}
gboolean
gsm_session_fill (GsmManager *manager,
char **override_autostart_dirs,
......@@ -317,7 +364,7 @@ gsm_session_fill (GsmManager *manager,
if (IS_STRING_EMPTY (session))
session = GSM_DEFAULT_SESSION;
keyfile = find_valid_session_keyfile (session);
keyfile = get_session_keyfile (session);
if (!keyfile)
return FALSE;
......
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2010 Red Hat, Inc.
*
* 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 <config.h>
#include <stdlib.h>
#include "gsm-process-helper.h"
int
main (int argc,
char *argv[])
{
int ret;
char *command_line = "xeyes";
int timeout = 500;
if (argc > 3) {
g_printerr ("Too many arguments.\n");
g_printerr ("Usage: %s [COMMAND] [TIMEOUT]\n", argv[0]);
return 1;
}
if (argc >= 2)
command_line = argv[1];
if (argc >= 3) {
int i = atoi (argv[2]);
if (i > 0)
timeout = i;
}
ret = gsm_process_helper (command_line, timeout);
if (ret < 0)
g_print ("Command did not succeed (or takes too much time).\n");
else
g_print ("Command returned %d.\n", ret);
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment