summaryrefslogtreecommitdiffstats
path: root/lib/plugins/lrm/upstart-dbus.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--lib/plugins/lrm/upstart-dbus.c406
1 files changed, 406 insertions, 0 deletions
diff --git a/lib/plugins/lrm/upstart-dbus.c b/lib/plugins/lrm/upstart-dbus.c
new file mode 100644
index 0000000..b994d87
--- /dev/null
+++ b/lib/plugins/lrm/upstart-dbus.c
@@ -0,0 +1,406 @@
+/*
+ * 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.1 of the License, or (at your option) any later version.
+ *
+ * This software 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 library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * File: upstart-dbus.c
+ * Copyright (C) 2010 Senko Rasic <senko.rasic@dobarkod.hr>
+ * Copyright (c) 2010 Ante Karamatic <ivoks@init.hr>
+ *
+ *
+ * Each exported function is standalone, and creates a new connection to
+ * the upstart daemon. This is because lrmd plugins fork off for exec,
+ * and if we try and share the connection, the whole thing blocks
+ * indefinitely.
+ */
+
+#include "upstart-dbus.h"
+
+#include <glib.h>
+#include <dbus/dbus-glib.h>
+
+#include <dbus/dbus.h>
+
+#include "dbus/Upstart.h"
+#include "dbus/Upstart_Job.h"
+#include "dbus/Upstart_Instance.h"
+
+#include <stdio.h>
+
+#define SYSTEM_BUS_ADDRESS "unix:path=/var/run/dbus/system_bus_socket"
+#define UPSTART_BUS_ADDRESS "unix:abstract=/com/ubuntu/upstart"
+#define UPSTART_SERVICE_NAME "com.ubuntu.Upstart"
+#define UPSTART_MANAGER_PATH "/com/ubuntu/Upstart"
+#define UPSTART_IFACE "com.ubuntu.Upstart0_6"
+#define UPSTART_JOB_IFACE UPSTART_IFACE ".Job"
+#define UPSTART_INSTANCE_IFACE UPSTART_IFACE ".Instance"
+#define UPSTART_ERROR_ALREADY_STARTED UPSTART_IFACE ".Error.AlreadyStarted"
+#define UPSTART_ERROR_UNKNOWN_INSTANCE UPSTART_IFACE ".Error.UnknownInstance"
+
+static DBusGConnection *
+get_connection(void)
+{
+ GError *error = NULL;
+ DBusGConnection *conn;
+
+ conn = dbus_g_bus_get_private(DBUS_BUS_SYSTEM, NULL, &error);
+
+ if (error)
+ {
+ g_error_free(error);
+ error = NULL;
+
+ conn = dbus_g_connection_open("unix:abstract=/com/ubuntu/upstart",
+ &error);
+
+ if (error)
+ {
+ g_warning("Can't connect to either system or Upstart "
+ "DBus bus.");
+ g_error_free(error);
+
+ return NULL;
+ }
+ }
+
+ return conn;
+}
+
+static DBusGProxy *
+new_proxy(DBusGConnection *conn, const gchar *object_path,
+ const gchar *iface)
+{
+ return dbus_g_proxy_new_for_name(conn,
+ UPSTART_SERVICE_NAME,
+ object_path,
+ iface);
+}
+
+static GHashTable *
+get_object_properties(DBusGProxy *obj, const gchar *iface)
+{
+ GError *error = NULL;
+ DBusGProxy *proxy;
+ GHashTable *asv;
+ GHashTable *retval;
+ GHashTableIter iter;
+ gpointer k, v;
+
+ proxy = dbus_g_proxy_new_from_proxy(obj,
+ DBUS_INTERFACE_PROPERTIES, NULL);
+
+ dbus_g_proxy_call(proxy, "GetAll", &error, G_TYPE_STRING,
+ iface, G_TYPE_INVALID,
+ dbus_g_type_get_map("GHashTable",
+ G_TYPE_STRING,
+ G_TYPE_VALUE),
+ &asv, G_TYPE_INVALID);
+
+ if (error) {
+ g_warning("Error getting %s properties: %s", iface, error->message);
+ g_error_free(error);
+ g_object_unref(proxy);
+ return NULL;
+ }
+
+ retval = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, g_free);
+
+ g_hash_table_iter_init(&iter, asv);
+ while (g_hash_table_iter_next(&iter, &k, &v)) {
+ gchar *key = k;
+ GValue *val = v;
+
+ /* all known properties are strings */
+ if (G_VALUE_TYPE(val) == G_TYPE_STRING) {
+ g_hash_table_insert(retval, g_strdup(key),
+ g_value_dup_string(val));
+ }
+ }
+
+ g_hash_table_destroy(asv);
+
+ return retval;
+}
+
+gchar **
+upstart_get_all_jobs(void)
+{
+ DBusGConnection *conn;
+ DBusGProxy *manager;
+ GError *error = NULL;
+ GPtrArray *array;
+ gchar **retval = NULL;
+ gint i, j;
+
+ conn = get_connection();
+ if (!conn)
+ return NULL;
+
+ manager = new_proxy(conn, UPSTART_MANAGER_PATH, UPSTART_IFACE);
+
+ dbus_g_proxy_call(manager, "GetAllJobs", &error, G_TYPE_INVALID,
+ dbus_g_type_get_collection("GPtrArray", DBUS_TYPE_G_OBJECT_PATH),
+ &array, G_TYPE_INVALID);
+
+ if (error)
+ {
+ g_warning("Can't call GetAllJobs: %s", error->message);
+ g_error_free(error);
+ g_object_unref(manager);
+ dbus_g_connection_unref(conn);
+ return NULL;
+ }
+
+ retval = g_new0(gchar *, array->len + 1);
+
+ for (i = 0, j = 0; i < array->len; i++)
+ {
+ DBusGProxy *job;
+
+ job = new_proxy(conn, g_ptr_array_index(array, i),
+ UPSTART_JOB_IFACE);
+
+ if (job) {
+ GHashTable *props = get_object_properties(job,
+ UPSTART_JOB_IFACE);
+
+ if (props) {
+ gchar *name = g_hash_table_lookup(props,
+ "name");
+
+ if (name)
+ retval[j++] = g_strdup(name);
+
+ g_hash_table_destroy(props);
+ }
+
+ g_object_unref(job);
+ }
+ }
+
+ g_ptr_array_free(array, TRUE);
+
+ g_object_unref(manager);
+ dbus_g_connection_unref(conn);
+
+ return retval;
+}
+
+static DBusGProxy *
+upstart_get_job_by_name(DBusGConnection *conn, DBusGProxy *manager,
+ const gchar *name)
+{
+ GError *error = NULL;
+ gchar *object_path;
+ DBusGProxy *retval;
+
+ dbus_g_proxy_call(manager, "GetJobByName", &error, G_TYPE_STRING,
+ name, G_TYPE_INVALID, DBUS_TYPE_G_OBJECT_PATH, &object_path,
+ G_TYPE_INVALID);
+
+ if (error)
+ {
+ g_warning("Error calling GetJobByName: %s", error->message);
+ g_error_free(error);
+ return NULL;
+ }
+
+ retval = new_proxy(conn, object_path, UPSTART_JOB_IFACE);
+
+ g_free(object_path);
+
+ return retval;
+}
+
+static gchar **
+get_job_instances(DBusGProxy *job)
+{
+ GError *error = NULL;
+ GPtrArray *array;
+ gchar **retval;
+ gint i;
+
+ dbus_g_proxy_call(job, "GetAllInstances", &error, G_TYPE_INVALID,
+ dbus_g_type_get_collection("GPtrArray", DBUS_TYPE_G_OBJECT_PATH),
+ &array, G_TYPE_INVALID);
+
+ if (error)
+ {
+ g_warning("Can't call GetAllInstances: %s", error->message);
+ g_error_free(error);
+ return NULL;
+ }
+
+ retval = g_new0(gchar *, array->len + 1);
+
+ for (i = 0; i < array->len; i++)
+ {
+ retval[i] = g_ptr_array_index(array, i);
+ }
+
+ g_ptr_array_free(array, TRUE);
+
+ return retval;
+}
+
+static DBusGProxy *
+get_first_instance(DBusGConnection *conn, DBusGProxy *job)
+{
+ gchar **instances;
+ DBusGProxy *instance = NULL;
+
+ instances = get_job_instances(job);
+
+ if (!instances)
+ return NULL;
+
+ if (*instances)
+ {
+ instance = new_proxy(conn, instances[0],
+ UPSTART_INSTANCE_IFACE);
+ }
+
+ g_strfreev(instances);
+ return instance;
+}
+
+gboolean
+upstart_job_is_running(const gchar *name)
+{
+ DBusGConnection *conn;
+ DBusGProxy *manager;
+ DBusGProxy *job;
+ gboolean retval = FALSE;
+
+ conn = get_connection();
+ if (!conn)
+ return FALSE;
+
+ manager = new_proxy(conn, UPSTART_MANAGER_PATH, UPSTART_IFACE);
+
+ job = upstart_get_job_by_name(conn, manager, name);
+ if (job) {
+ DBusGProxy *instance = get_first_instance(conn, job);
+
+ if (instance) {
+ GHashTable *props = get_object_properties(instance,
+ UPSTART_INSTANCE_IFACE);
+
+ if (props) {
+ const gchar *state = g_hash_table_lookup(props,
+ "state");
+
+ retval = !g_strcmp0(state, "running");
+
+ g_hash_table_destroy(props);
+ }
+
+ g_object_unref(instance);
+ }
+
+ g_object_unref(job);
+ }
+
+ g_object_unref(manager);
+ dbus_g_connection_unref(conn);
+
+ return retval;
+}
+
+gboolean
+upstart_job_do(const gchar *name, UpstartJobCommand cmd, const int timeout)
+{
+ DBusGConnection *conn;
+ DBusGProxy *manager;
+ DBusGProxy *job;
+ gboolean retval;
+
+ conn = get_connection();
+ if (!conn)
+ return FALSE;
+
+ manager = new_proxy(conn, UPSTART_MANAGER_PATH, UPSTART_IFACE);
+
+ job = upstart_get_job_by_name(conn, manager, name);
+ if (job) {
+ GError *error = NULL;
+ const gchar *cmd_name = NULL;
+ gchar *instance_path = NULL;
+ gchar *no_args[] = { NULL };
+
+ switch (cmd) {
+ case UPSTART_JOB_START:
+ cmd_name = "Start";
+ dbus_g_proxy_call_with_timeout (job, cmd_name,
+ timeout, &error,
+ G_TYPE_STRV, no_args,
+ G_TYPE_BOOLEAN, TRUE,
+ G_TYPE_INVALID,
+ DBUS_TYPE_G_OBJECT_PATH, &instance_path,
+ G_TYPE_INVALID);
+ g_free (instance_path);
+ break;
+ case UPSTART_JOB_STOP:
+ cmd_name = "Stop";
+ dbus_g_proxy_call_with_timeout(job, cmd_name,
+ timeout, &error,
+ G_TYPE_STRV, no_args,
+ G_TYPE_BOOLEAN, TRUE,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
+ break;
+ case UPSTART_JOB_RESTART:
+ cmd_name = "Restart";
+ dbus_g_proxy_call_with_timeout (job, cmd_name,
+ timeout, &error,
+ G_TYPE_STRV, no_args,
+ G_TYPE_BOOLEAN, TRUE,
+ G_TYPE_INVALID,
+ DBUS_TYPE_G_OBJECT_PATH, &instance_path,
+ G_TYPE_INVALID);
+ g_free (instance_path);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (error) {
+ g_warning("Could not issue %s: %s", cmd_name,
+ error->message);
+
+ /* ignore "already started" or "not running" errors */
+ if (dbus_g_error_has_name(error,
+ UPSTART_ERROR_ALREADY_STARTED) ||
+ dbus_g_error_has_name(error,
+ UPSTART_ERROR_UNKNOWN_INSTANCE)) {
+ retval = TRUE;
+ } else {
+ retval = FALSE;
+ }
+ g_error_free(error);
+ } else {
+ retval = TRUE;
+ }
+
+ g_object_unref(job);
+ } else {
+ retval = FALSE;
+ }
+
+ g_object_unref(manager);
+ dbus_g_connection_unref(conn);
+ return retval;
+}
+
+