summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am6
-rw-r--r--src/ck-run-programs.c230
-rw-r--r--src/ck-run-programs.h38
-rw-r--r--src/ck-seat.c5
-rw-r--r--src/ck-session.c39
5 files changed, 318 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 3f142a3..ec4e04f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -98,6 +98,8 @@ console_kit_daemon_SOURCES = \
ck-session.c \
ck-log.h \
ck-log.c \
+ ck-run-programs.c \
+ ck-run-programs.h \
$(BUILT_SOURCES) \
$(NULL)
@@ -163,3 +165,7 @@ CLEANFILES = $(BUILT_SOURCES)
MAINTAINERCLEANFILES = \
*~ \
Makefile.in
+
+install-data-local:
+ -mkdir -p $(DESTDIR)$(sysconfdir)/ConsoleKit/run-session.d
+ -mkdir -p $(DESTDIR)$(libdir)/ConsoleKit/run-session.d
diff --git a/src/ck-run-programs.c b/src/ck-run-programs.c
new file mode 100644
index 0000000..f9d62c7
--- /dev/null
+++ b/src/ck-run-programs.c
@@ -0,0 +1,230 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 David Zeuthen <david@fubar.dk>
+ *
+ * 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 <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+
+#include "ck-run-programs.h"
+
+/* The number of wall-clock seconds a program is allowed to run before we kill it */
+#define TIMEOUT_SECONDS 15
+
+/* Guaranteed by POSIX; see 'man environ' for details */
+extern char **environ;
+
+typedef struct {
+ int refcount;
+
+ char *path;
+
+ gboolean child_is_running;
+ guint watch_id;
+ guint timeout_id;
+ GPid pid;
+} ChildData;
+
+static ChildData *
+_child_data_new (void)
+{
+ ChildData *cd;
+
+ cd = g_new0 (ChildData, 1);
+ cd->refcount = 1;
+ g_debug ("Allocated ChildData %p", cd);
+
+ return cd;
+}
+
+static ChildData *
+_child_data_ref (ChildData *cd)
+{
+ cd->refcount++;
+ return cd;
+}
+
+
+static void
+_child_data_unref (ChildData *cd)
+{
+ cd->refcount--;
+ if (cd->refcount == 0) {
+ g_free (cd->path);
+ g_free (cd);
+ g_debug ("Freeing ChildData %p", cd);
+ }
+}
+
+
+static void
+_child_watch (GPid pid,
+ int status,
+ ChildData *cd)
+{
+ g_debug ("In _child_watch for pid %d", pid);
+
+ g_spawn_close_pid (pid);
+ g_source_remove (cd->timeout_id);
+
+ cd->child_is_running = FALSE;
+
+ _child_data_unref (cd);
+}
+
+static gboolean
+_child_timeout (ChildData *cd)
+{
+ /* The program we ran timed out; this is a bug in the program */
+ g_warning ("The program %s didn't exit within %d seconds; killing it", cd->path, TIMEOUT_SECONDS);
+
+ kill (cd->pid, SIGTERM);
+
+ cd->child_is_running = FALSE;
+ return FALSE;
+}
+
+/**
+ * ck_run_programs:
+ * @dirpath: Path to a directory containing programs to run
+ * @action: Argument to pass to each program
+ * @extra_env: Extra environment to pass
+ *
+ * Synchronously run all scripts with suffix .ck in the given
+ * directory.
+ */
+void
+ck_run_programs (const char *dirpath,
+ const char *action,
+ char **extra_env)
+{
+ GDir *dir;
+ GError *error;
+ const char *name;
+ char **env_for_child;
+ int environ_len;
+ int extra_env_len;
+ int n;
+ int m;
+
+ g_return_if_fail (dirpath != NULL);
+ g_return_if_fail (action != NULL);
+
+ g_debug ("Running programs in %s for action %s", dirpath, action);
+
+ /* Construct an environment consisting of the existing and the given environment */
+ environ_len = environ != NULL ? g_strv_length (environ) : 0;
+ extra_env_len = extra_env != NULL ? g_strv_length (extra_env) : 0;
+ env_for_child = g_new0 (char *, environ_len + extra_env_len + 2);
+ m = 0;
+ for (n = 0; n < environ_len; n++) {
+ env_for_child [m++] = g_strdup (environ[n]);
+ }
+ for (n = 0; n < extra_env_len; n++) {
+ env_for_child [m++] = g_strdup (extra_env[n]);
+ }
+ env_for_child[m] = NULL;
+
+ error = NULL;
+
+ dir = g_dir_open (dirpath, 0, &error);
+ if (dir == NULL) {
+ /* This is unexpected; it means ConsoleKit isn't properly installed */
+ g_warning ("Unable to open directory %s: %s", dirpath, error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ while ((name = g_dir_read_name (dir)) != NULL) {
+ char *child_argv[3];
+ ChildData *cd;
+ gboolean res;
+
+ if (!g_str_has_suffix (name, ".ck"))
+ continue;
+
+ child_argv[0] = g_strdup_printf ("%s/%s", dirpath, name);
+ child_argv[1] = (char *) action;
+ child_argv[2] = NULL;
+
+ error = NULL;
+ cd = _child_data_new ();
+ cd->path = g_strdup (child_argv[0]);
+
+ /* The ChildData instance is also unreffed in _child_watch; we only ref
+ * it here to prevent cd from being destroyed while checking it in
+ * the mainloop
+ */
+ _child_data_ref (cd);
+
+ res = g_spawn_async (NULL,
+ child_argv,
+ env_for_child,
+ G_SPAWN_DO_NOT_REAP_CHILD,
+ NULL,
+ NULL,
+ &cd->pid,
+ &error);
+ if (! res) {
+ /* This is unexpected; it means the program to run isn't installed correctly */
+ g_warning ("Unable to spawn %s: %s", child_argv[0], error->message);
+ g_error_free (error);
+ _child_data_unref (cd);
+ _child_data_unref (cd);
+ goto out_loop;
+ }
+ cd->child_is_running = TRUE;
+
+ g_debug ("Waiting for child with pid %d", cd->pid);
+
+ cd->watch_id = g_child_watch_add (cd->pid,
+ (GChildWatchFunc)_child_watch,
+ cd);
+ cd->timeout_id = g_timeout_add (TIMEOUT_SECONDS * 1000,
+ (GSourceFunc)_child_timeout,
+ cd);
+
+ /* run the mainloop; this allows the main daemon to
+ * continue serving clients (including the program we
+ * just launched) */
+ while (cd->child_is_running) {
+ g_main_context_iteration (NULL, TRUE);
+ }
+
+ g_debug ("Done waiting for child with pid %d", cd->pid);
+ _child_data_unref (cd);
+
+ out_loop:
+ g_free (child_argv[0]);
+ }
+out:
+ g_strfreev (env_for_child);
+}
diff --git a/src/ck-run-programs.h b/src/ck-run-programs.h
new file mode 100644
index 0000000..77cdf48
--- /dev/null
+++ b/src/ck-run-programs.h
@@ -0,0 +1,38 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 David Zeuthen <david@fubar.dk>
+ *
+ * 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 __CK_RUN_PROGRAMS_H
+#define __CK_RUN_PROGRAMS_H
+
+#include <glib-object.h>
+#include <dbus/dbus-glib.h>
+#include "ck-session.h"
+
+G_BEGIN_DECLS
+
+void ck_run_programs (const char *dirpath, const char *action, char **extra_env);
+
+void ck_session_run_programs (CkSession *session, const char *action);
+
+
+G_END_DECLS
+
+#endif /* __CK_RUN_PROGRAMS_H */
diff --git a/src/ck-seat.c b/src/ck-seat.c
index e04b569..63d7b6c 100644
--- a/src/ck-seat.c
+++ b/src/ck-seat.c
@@ -42,6 +42,7 @@
#include "ck-session.h"
#include "ck-vt-monitor.h"
+#include "ck-run-programs.h"
#define CK_SEAT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CK_TYPE_SEAT, CkSeatPrivate))
@@ -547,6 +548,8 @@ ck_seat_remove_session (CkSeat *seat,
g_signal_handlers_disconnect_by_func (session, session_activate, seat);
+ ck_session_run_programs (session, "session_removed");
+
g_debug ("Emitting removed signal: %s", ssid);
g_signal_emit (seat, signals [SESSION_REMOVED], 0, ssid);
@@ -581,6 +584,8 @@ ck_seat_add_session (CkSeat *seat,
g_signal_connect_object (session, "activate", G_CALLBACK (session_activate), seat, 0);
/* FIXME: attach to property notify signals? */
+ ck_session_run_programs (session, "session_added");
+
g_debug ("Emitting added signal: %s", ssid);
g_signal_emit (seat, signals [SESSION_ADDED], 0, ssid);
diff --git a/src/ck-session.c b/src/ck-session.c
index f136333..6f16720 100644
--- a/src/ck-session.c
+++ b/src/ck-session.c
@@ -40,6 +40,7 @@
#include "ck-session.h"
#include "ck-session-glue.h"
#include "ck-marshal.h"
+#include "ck-run-programs.h"
#define CK_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CK_TYPE_SESSION, CkSessionPrivate))
@@ -394,6 +395,7 @@ ck_session_set_active (CkSession *session,
if (session->priv->active != active) {
session->priv->active = active;
+ ck_session_run_programs (session, "session_active_changed");
g_signal_emit (session, signals [ACTIVE_CHANGED], 0, active);
}
@@ -1206,3 +1208,40 @@ ck_session_new_with_parameters (const char *ssid,
return CK_SESSION (object);
}
+
+void
+ck_session_run_programs (CkSession *session,
+ const char *action)
+{
+ int n;
+ char *extra_env[11]; /* be sure to adjust this as needed */
+
+ n = 0;
+
+ extra_env[n++] = g_strdup_printf ("CK_SESSION_ID=%s", session->priv->id);
+ if (session->priv->session_type != NULL) {
+ extra_env[n++] = g_strdup_printf ("CK_SESSION_TYPE=%s", session->priv->session_type);
+ }
+ extra_env[n++] = g_strdup_printf ("CK_SESSION_SEAT_ID=%s", session->priv->seat_id);
+ extra_env[n++] = g_strdup_printf ("CK_SESSION_USER_UID=%d", session->priv->uid);
+ if (session->priv->display_device != NULL && strlen (session->priv->display_device) > 0) {
+ extra_env[n++] = g_strdup_printf ("CK_SESSION_DISPLAY_DEVICE=%s", session->priv->display_device);
+ }
+ if (session->priv->x11_display_device != NULL && strlen (session->priv->x11_display_device) > 0) {
+ extra_env[n++] = g_strdup_printf ("CK_SESSION_X11_DISPLAY_DEVICE=%s", session->priv->x11_display_device);
+ }
+ extra_env[n++] = g_strdup_printf ("CK_SESSION_X11_DISPLAY=%s", session->priv->x11_display);
+ if (session->priv->remote_host_name != NULL && strlen (session->priv->remote_host_name) > 0) {
+ extra_env[n++] = g_strdup_printf ("CK_SESSION_REMOTE_HOST_NAME=%s", session->priv->remote_host_name);
+ }
+ extra_env[n++] = g_strdup_printf ("CK_SESSION_IS_ACTIVE=%s", session->priv->active ? "true" : "false");
+ extra_env[n++] = g_strdup_printf ("CK_SESSION_IS_LOCAL=%s", session->priv->is_local ? "true" : "false");
+ extra_env[n++] = NULL;
+
+ ck_run_programs (SYSCONFDIR "/ConsoleKit/run-session.d", action, extra_env);
+ ck_run_programs (LIBDIR "/ConsoleKit/run-session.d", action, extra_env);
+
+ for (n = 0; extra_env[n] != NULL; n++) {
+ g_free (extra_env[n]);
+ }
+}