diff --git a/lib/services/upstart.c b/lib/services/upstart.c index d308c0edad..7aa51559c7 100644 --- a/lib/services/upstart.c +++ b/lib/services/upstart.c @@ -1,403 +1,410 @@ /* * 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 * Copyright (c) 2010 Ante Karamatic * * * 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 +#include +#include #include #include #include #include "dbus/Upstart.h" #include "dbus/Upstart_Job.h" #include "dbus/Upstart_Instance.h" #include #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 *upstart_conn = NULL; + 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; + GError *error = NULL; + if(upstart_conn) { + return upstart_conn; + } + + upstart_conn = dbus_g_bus_get_private(DBUS_BUS_SYSTEM, NULL, &error); + if (error) { + g_error_free(error); + error = NULL; + + upstart_conn = dbus_g_connection_open("unix:abstract=/com/ubuntu/upstart", &error); + + if (error) { + crm_err("Can't connect to either system or Upstart DBus bus."); + g_error_free(error); + upstart_conn = NULL; + } + } + + return upstart_conn; } static DBusGProxy * -new_proxy(DBusGConnection *conn, const gchar *object_path, - const gchar *iface) +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); + return dbus_g_proxy_new_for_name(conn, + UPSTART_SERVICE_NAME, + object_path, + iface); } -static GHashTable * -get_object_properties(DBusGProxy *obj, const gchar *iface) +static char * +get_object_property(DBusGProxy *obj, const gchar *iface, const char *name) { - 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; + GError *error = NULL; + DBusGProxy *proxy; + GHashTable *asv; + GValue *value; + + 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) { + crm_err("Cannot get properties for %s: %s", iface, error->message); + g_error_free(error); + g_object_unref(proxy); + return NULL; + } + + value = g_hash_table_lookup(asv, name); + if(value && G_VALUE_TYPE(val) == G_TYPE_STRING) { + return g_value_dup_string(value); + } + g_hash_table_destroy(asv); + return NULL; } -gchar ** +GList * 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; + DBusGConnection *conn; + DBusGProxy *manager; + GError *error = NULL; + GPtrArray *array; + GList *list = 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) { + crm_err("Can't call GetAllJobs: %s", error->message); + g_error_free(error); + g_object_unref(manager); + return NULL; + } + + for (i = 0, j = 0; i < array->len; i++) { + DBusGProxy *job = new_proxy(conn, g_ptr_array_index(array, i), + UPSTART_JOB_IFACE); + + if (job) { + char *name = get_object_property(job, UPSTART_JOB_IFACE, "name"); + if (name) { + list = g_list_append(list, name); + } + + g_object_unref(job); + } + } + + g_ptr_array_free(array, TRUE); + g_object_unref(manager); + return retval; } static DBusGProxy * upstart_get_job_by_name(DBusGConnection *conn, DBusGProxy *manager, - const gchar *name) + const gchar *name) { - GError *error = NULL; - gchar *object_path; - DBusGProxy *retval; + 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); + 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; - } + 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); + retval = new_proxy(conn, object_path, UPSTART_JOB_IFACE); - g_free(object_path); + g_free(object_path); - return retval; + return retval; } -static gchar ** +static GList * 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); + GError *error = NULL; + GPtrArray *array; + GList *list = NULL; + 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; + } + + for (i = 0; i < array->len; i++) { + list = g_list_append(list, g_ptr_array_index(array, i)); + } + + g_ptr_array_free(array, TRUE); + return list; +} - if (error) - { - g_warning("Can't call GetAllInstances: %s", error->message); - g_error_free(error); - return NULL; - } +static DBusGProxy * +get_first_instance(DBusGConnection *conn, DBusGProxy *job) +{ + gchar **instances; + DBusGProxy *instance = NULL; - retval = g_new0(gchar *, array->len + 1); + instances = get_job_instances(job); - for (i = 0; i < array->len; i++) - { - retval[i] = g_ptr_array_index(array, i); - } + if (!instances) + return NULL; - g_ptr_array_free(array, TRUE); + if (*instances) + { + instance = new_proxy(conn, instances[0], + UPSTART_INSTANCE_IFACE); + } - return retval; + g_strfreev(instances); + return instance; } -static DBusGProxy * -get_first_instance(DBusGConnection *conn, DBusGProxy *job) +gboolean +upstart_job_exists(const gchar *name) { - gchar **instances; - DBusGProxy *instance = NULL; + DBusGConnection *conn; + DBusGProxy *manager; + DBusGProxy *job; - instances = get_job_instances(job); + conn = get_connection(); + if (!conn) + return FALSE; - if (!instances) - return NULL; + manager = new_proxy(conn, UPSTART_MANAGER_PATH, UPSTART_IFACE); - if (*instances) - { - instance = new_proxy(conn, instances[0], - UPSTART_INSTANCE_IFACE); - } + job = upstart_get_job_by_name(conn, manager, name); + if (job) { + return TRUE; + } - g_strfreev(instances); - return instance; + g_object_unref(job); + g_object_unref(manager); + return FALSE; } gboolean upstart_job_is_running(const gchar *name) { - DBusGConnection *conn; - DBusGProxy *manager; - DBusGProxy *job; - gboolean retval = FALSE; + 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); - conn = get_connection(); - if (!conn) - return FALSE; + if (instance) { + char *state = get_object_property(instance, UPSTART_INSTANCE_IFACE, "state"); + retval = !g_strcmp0(state, "running"); + free(state); - manager = new_proxy(conn, UPSTART_MANAGER_PATH, UPSTART_IFACE); + g_object_unref(instance); + } - job = upstart_get_job_by_name(conn, manager, name); - if (job) { - DBusGProxy *instance = get_first_instance(conn, job); + g_object_unref(job); + } - if (instance) { - GHashTable *props = get_object_properties(instance, - UPSTART_INSTANCE_IFACE); + g_object_unref(manager); + return retval; +} - if (props) { - const gchar *state = g_hash_table_lookup(props, - "state"); +static char * +upstart_job_metadata(const char *name) +{ + static const char *template = + "\n" + "\n" + "\n" + " 1.0\n" + " \n" + " Upstart agent for controlling the system %s service" + " \n" + " %s upstart agent\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + + return g_strdup_printf(template, name, name, name); +} + +int +upstart_job_do(svc_action_t* op, gboolean synchronous) +{ + DBusGProxy *job; + DBusGProxy *manager; + DBusGConnection *conn = get_connection(); - retval = !g_strcmp0(state, "running"); + int ret = PCMK_EXECRA_OK; - g_hash_table_destroy(props); - } - - g_object_unref(instance); - } + GError *error = NULL; + gchar *instance_path = NULL; + gchar *no_args[] = { NULL }; + const char *action = op->action; - g_object_unref(job); - } + if (!conn) + return FALSE; - g_object_unref(manager); - dbus_g_connection_unref(conn); + manager = new_proxy(conn, UPSTART_MANAGER_PATH, UPSTART_IFACE); - return retval; + job = upstart_get_job_by_name(conn, manager, op->name); + if (job == NULL) { + goto cleanup; + } + + if (safe_str_eq(op_type, "meta-data")) { + op->stdout_data = upstart_job_metadata(rsc_type); + rc = PCMK_EXECRA_OK; + goto cleanup; + } + + if (safe_str_eq(op->action, "monitor") || safe_str_eq(action, "status")) { + gboolean running = upstart_job_is_running (op->name); + crm_trace("%s", running ? "running" : "stopped"); + + if (running) { + return PCMK_EXECRA_OK; + } + return PCMK_EXECRA_NOT_RUNNING; + + } else if (!g_strcmp0(action, "start")) { + action = "Start"; + } else if (!g_strcmp0(action, "stop")) { + action = "Stop"; + } else if (!g_strcmp0(action, "restart")) { + action = "Restart"; + } else { + return PCMK_EXECRA_UNIMPLEMENT_FEATURE; + } + + dbus_g_proxy_call (job, action, &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); + + if (error) { + /* ignore "already started" or "not running" errors */ + if (safe_str_eq(action, "Start") && dbus_g_error_has_name(error, UPSTART_ERROR_ALREADY_STARTED)) { + crm_trace("Masking Start failure for %s: already started", op->name); + ret = PCMK_EXECRA_OK; + } else if (safe_str_eq(action, "Start") && dbus_g_error_has_name(error, UPSTART_ERROR_UNKNOWN_INSTANCE)) { + crm_trace("Masking Stop failure for %s: unknown services are stopped", op->name); + ret = PCMK_EXECRA_OK; + } else { + crm_err("Could not issue %s for %s: %s", action, op->name, error->message); + ret = PCMK_EXECRA_UNKNOWN_ERROR; + } + g_error_free(error); + } + + cleanup: + if(job) { + g_object_unref(job); + } + g_object_unref(manager); + return ret; } -gboolean -upstart_job_do(const gchar *name, UpstartJobCommand cmd) +void upstart_cleanup(void) { - 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 (job, cmd_name, &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(job, cmd_name, &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 (job, cmd_name, &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; + dbus_g_connection_unref(upstart_conn); + upstart_conn = NULL; } diff --git a/lib/services/upstart.h b/lib/services/upstart.h index d9932ec37e..9411c0724a 100644 --- a/lib/services/upstart.h +++ b/lib/services/upstart.h @@ -1,36 +1,34 @@ /* * 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 * Copyright (c) 2010 Ante Karamatic */ #ifndef _UPSTART_DBUS_H_ #define _UPSTART_DBUS_H_ #include +#include "crm/services.h" -typedef enum { - UPSTART_JOB_START, - UPSTART_JOB_STOP, - UPSTART_JOB_RESTART -} UpstartJobCommand; - -G_GNUC_INTERNAL gchar **upstart_get_all_jobs(void); -G_GNUC_INTERNAL gboolean upstart_job_do(const gchar *name, UpstartJobCommand cmd); +G_GNUC_INTERNAL GList *upstart_get_all_jobs(void); +G_GNUC_INTERNAL int upstart_job_do(svc_action_t* op, gboolean synchronous); +G_GNUC_INTERNAL gboolean upstart_job_exists (const gchar *name); G_GNUC_INTERNAL gboolean upstart_job_is_running (const gchar *name); +void upstart_cleanup(void); + #endif /* _UPSTART_DBUS_H_ */