diff --git a/lib/services/systemd.c b/lib/services/systemd.c index cf99c1cb42..7b2be76f36 100644 --- a/lib/services/systemd.c +++ b/lib/services/systemd.c @@ -1,424 +1,424 @@ /* * 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 * * Copyright (C) 2012 Andrew Beekhof */ #include #include #include #include #include #include #include #define BUS_NAME "org.freedesktop.systemd1" #define BUS_PATH "/org/freedesktop/systemd1" #define BUS_PROPERTY_IFACE "org.freedesktop.DBus.Properties" /* /usr/share/dbus-1/interfaces/org.freedesktop.systemd1.Manager.xml */ struct unit_info { const char *id; const char *description; const char *load_state; const char *active_state; const char *sub_state; const char *following; const char *unit_path; uint32_t job_id; const char *job_type; const char *job_path; }; static GDBusProxy *systemd_proxy = NULL; static GDBusProxy * get_proxy(const char *path, const char *interface) { GError *error = NULL; GDBusProxy *proxy = NULL; g_type_init(); if(path == NULL) { path = BUS_PATH; } proxy = g_dbus_proxy_new_for_bus_sync ( G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, /* GDBusInterfaceInfo */ BUS_NAME, path, interface, NULL, /* GCancellable */ &error); if (error) { crm_err("Can't connect obtain proxy to %s interface: %s", interface, error->message); g_error_free(error); proxy = NULL; } return proxy; } static gboolean systemd_init(void) { if(systemd_proxy == NULL) { systemd_proxy = get_proxy(NULL, BUS_NAME".Manager"); } if(systemd_proxy == NULL) { return FALSE; } return TRUE; } void systemd_cleanup(void) { g_object_unref(systemd_proxy); systemd_proxy = NULL; } static char * systemd_service_name(const char *name) { if(name == NULL) { return NULL; } else if(strstr(name, ".service")) { return strdup(name); } return g_strdup_printf("%s.service", name); } static gboolean systemd_unit_by_name ( GDBusProxy *proxy, const gchar *arg_name, gchar **out_unit, GCancellable *cancellable, GError **error) { GVariant *_ret = NULL; char *name = NULL; /* " \n" \ " \n" \ " \n" \ " \n" \ */ name = systemd_service_name(arg_name); _ret = g_dbus_proxy_call_sync ( proxy, "GetUnit", g_variant_new ("(s)", name), G_DBUS_CALL_FLAGS_NONE, -1, cancellable, error); if (_ret) { g_variant_get (_ret, "(o)", out_unit); - crm_info("%s = %s", arg_name, *out_unit); + crm_debug("%s = %s", arg_name, *out_unit); g_variant_unref (_ret); } free(name); return _ret != NULL; } static char * systemd_unit_property(const char *obj, const gchar *iface, const char *name) { GError *error = NULL; GDBusProxy *proxy; GVariant *asv = NULL; GVariant *value = NULL; GVariant *_ret = NULL; char *output = NULL; crm_info("Calling GetAll on %s", obj); proxy = get_proxy(obj, BUS_PROPERTY_IFACE); _ret = g_dbus_proxy_call_sync ( proxy, "GetAll", g_variant_new ("(s)", iface), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (error) { crm_err("Cannot get properties for %s: %s", g_dbus_proxy_get_object_path(proxy), error->message); g_error_free(error); g_object_unref(proxy); return NULL; } crm_info("Call to GetAll passed: type '%s' %d\n", g_variant_get_type_string (_ret), g_variant_n_children (_ret)); asv = g_variant_get_child_value(_ret, 0); crm_trace("asv type '%s' %d\n", g_variant_get_type_string (asv), g_variant_n_children (asv)); value = g_variant_lookup_value(asv, name, NULL); if(value && g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) { - crm_info("Got value '%s' for %s[%s]", g_variant_get_string(value, NULL), obj, name); + crm_debug("Got value '%s' for %s[%s]", g_variant_get_string(value, NULL), obj, name); output = g_variant_dup_string(value, NULL); } else { crm_info("No value for %s[%s]", obj, name); } g_object_unref(proxy); return output; } GList * systemd_unit_listall(void) { int lpc = 0; GList *units = NULL; GError *error = NULL; GVariant *out_units = NULL; GVariantIter iter; struct unit_info u; GVariant *_ret = NULL; CRM_ASSERT(systemd_init()); /* " \n" \ " \n" \ " \n" \ */ _ret = g_dbus_proxy_call_sync ( systemd_proxy, "ListUnits", g_variant_new ("()"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (error || _ret == NULL) { - crm_err("Call to ListUnits failed: %s", error->message); + crm_info("Call to ListUnits failed: %s", error->message); g_error_free(error); return NULL; } g_variant_get (_ret, "(@a(ssssssouso))", &out_units); g_variant_iter_init (&iter, out_units); while (g_variant_iter_loop (&iter, "(ssssssouso)", &u.id, &u.description, &u.load_state, &u.active_state, &u.sub_state, &u.following, &u.unit_path, &u.job_id, &u.job_type, &u.job_path)) { char *match = strstr(u.id, ".service"); if(match) { lpc++; match[0] = 0; - crm_trace("Got %s = %s", u.id, u.description); + crm_trace("Got %s[%s] = %s", u.id, u.active_state, u.description); units = g_list_append(units, strdup(u.id)); } } crm_info("Call to ListUnits passed: type '%s' count %d", g_variant_get_type_string (out_units), lpc); g_variant_unref (_ret); return units; } gboolean systemd_unit_exists(const char *name) { char *path = NULL; GError *error = NULL; gboolean pass = FALSE; CRM_ASSERT(systemd_init()); pass = systemd_unit_by_name(systemd_proxy, name, &path, NULL, &error); if (error || pass == FALSE) { crm_err("Call to ListUnits failed: %s", error->message); g_error_free(error); pass = FALSE; } else { crm_trace("Got %s", path); } /* free(path) */ return pass; } static char * systemd_unit_metadata(const char *name) { char *path = NULL; char *meta = NULL; GError *error = NULL; CRM_ASSERT(systemd_init()); if(systemd_unit_by_name(systemd_proxy, name, &path, NULL, &error)) { char *desc = systemd_unit_property(path, BUS_NAME".Unit", "Description"); meta = g_strdup_printf( "\n" "\n" "\n" " 1.0\n" " \n" " %s\n" " \n" " systemd unit file for %s\n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "\n", name, desc, name); free(desc); } return meta; } static void systemd_unit_exec_done(GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; GVariant *_ret = NULL; svc_action_t* op = user_data; GDBusProxy *proxy = G_DBUS_PROXY (source_object); /* Obtain rc and stderr/out */ _ret = g_dbus_proxy_call_finish (proxy, res, &error); if (error) { /* ignore "already started" or "not running" errors */ if (safe_str_eq(op->action, "stop") && strstr(error->message, "systemd1.InvalidName")) { crm_trace("Masking Stop failure for %s: unknown services are stopped", op->rsc); op->rc = PCMK_EXECRA_OK; } else { crm_err("Could not issue %s for %s: %s (%s)", op->action, op->rsc, error->message, ""); } g_error_free(error); } else { char *path = NULL; g_variant_get(_ret, "(o)", &path); crm_info("Call to %s passed: type '%s' %s", op->action, g_variant_get_type_string (_ret), path); op->rc = PCMK_EXECRA_OK; } operation_finalize(op); } gboolean systemd_unit_exec(svc_action_t* op, gboolean synchronous) { char *unit = NULL; GError *error = NULL; gboolean pass = FALSE; GVariant *_ret = NULL; const char *action = op->action; char *name = systemd_service_name(op->rsc); op->rc = PCMK_EXECRA_UNKNOWN_ERROR; CRM_ASSERT(systemd_init()); pass = systemd_unit_by_name (systemd_proxy, op->rsc, &unit, NULL, &error); if (error || pass == FALSE) { crm_debug("Could not obtain unit named '%s': %s", op->rsc, error->message); if(strstr(error->message, "systemd1.NoSuchUnit")) { op->rc = PCMK_EXECRA_NOT_INSTALLED; } g_error_free(error); return FALSE; } if (safe_str_eq(op->action, "meta-data")) { op->stdout_data = systemd_unit_metadata(op->rsc); op->rc = PCMK_EXECRA_OK; goto cleanup; } if (safe_str_eq(op->action, "monitor") || safe_str_eq(action, "status")) { char *state = systemd_unit_property(unit, BUS_NAME".Unit", "ActiveState"); if ( !g_strcmp0(state, "active")) { op->rc = PCMK_EXECRA_OK; } else { op->rc = PCMK_EXECRA_NOT_RUNNING; } if(synchronous == FALSE) { operation_finalize(op); } free(state); goto cleanup; } else if (!g_strcmp0(action, "start")) { action = "StartUnit"; } else if (!g_strcmp0(action, "stop")) { action = "StopUnit"; } else if (!g_strcmp0(action, "restart")) { action = "RestartUnit"; } else { return PCMK_EXECRA_UNIMPLEMENT_FEATURE; } crm_debug("Calling %s for %s: %s", action, op->rsc, unit); if(synchronous == FALSE) { g_dbus_proxy_call( systemd_proxy, action, g_variant_new ("(ss)", name, "replace"), G_DBUS_CALL_FLAGS_NONE, op->timeout, NULL, systemd_unit_exec_done, op); free(unit); free(name); return TRUE; } _ret = g_dbus_proxy_call_sync ( systemd_proxy, action, g_variant_new ("(ss)", name, "replace"), G_DBUS_CALL_FLAGS_NONE, op->timeout, NULL, &error); if (error) { /* ignore "already started" or "not running" errors */ if (safe_str_eq(op->action, "stop") && strstr(error->message, "systemd1.InvalidName")) { crm_trace("Masking Stop failure for %s: unknown services are stopped", op->rsc); op->rc = PCMK_EXECRA_OK; } else { crm_err("Could not issue %s for %s: %s (%s)", action, op->rsc, error->message, unit); } g_error_free(error); } else { char *path = NULL; g_variant_get(_ret, "(o)", &path); crm_info("Call to %s passed: type '%s' %s", action, g_variant_get_type_string (_ret), path); op->rc = PCMK_EXECRA_OK; } cleanup: free(unit); free(name); return op->rc == PCMK_EXECRA_OK; }