20 #include <dbus/dbus.h>    23 static void invoke_unit_by_path(
svc_action_t *op, 
const char *unit);
    25 #define BUS_NAME         "org.freedesktop.systemd1"    26 #define BUS_NAME_MANAGER BUS_NAME ".Manager"    27 #define BUS_NAME_UNIT    BUS_NAME ".Unit"    28 #define BUS_PATH         "/org/freedesktop/systemd1"    63 static inline DBusMessage *
    64 systemd_new_method(
const char *method)
    75 static DBusConnection* systemd_proxy = NULL;
    77 static inline DBusPendingCall *
    78 systemd_send(DBusMessage *msg,
    79              void(*done)(DBusPendingCall *pending, 
void *user_data),
    85 static inline DBusMessage *
    86 systemd_send_recv(DBusMessage *msg, DBusError *error, 
int timeout)
   103 systemd_call_simple_method(
const char *method)
   105     DBusMessage *msg = systemd_new_method(method);
   106     DBusMessage *reply = NULL;
   113         crm_err(
"Could not create message to send %s to systemd", method);
   117     dbus_error_init(&error);
   119     dbus_message_unref(msg);
   121     if (dbus_error_is_set(&error)) {
   122         crm_err(
"Could not send %s to systemd: %s (%s)",
   123                 method, error.message, error.name);
   124         dbus_error_free(&error);
   127     } 
else if (reply == NULL) {
   128         crm_err(
"Could not send %s to systemd: no reply received", method);
   138     static int need_init = 1;
   142         && dbus_connection_get_is_connected(systemd_proxy) == FALSE) {
   143         crm_warn(
"Connection to System DBus is closed. Reconnecting...");
   145         systemd_proxy = NULL;
   153     if (systemd_proxy == NULL) {
   160 systemd_get_property(
const char *unit, 
const char *
name,
   161                      void (*callback)(
const char *
name, 
const char *value, 
void *userdata),
   162                      void *userdata, DBusPendingCall **pending, 
int timeout)
   164     return systemd_proxy?
   175         systemd_proxy = NULL;
   192 systemd_unit_extension(
const char *
name)
   195         const char *dot = strrchr(
name, 
'.');
   197         if (dot && (!strcmp(dot, 
".service")
   198                     || !strcmp(dot, 
".socket")
   199                     || !strcmp(dot, 
".mount")
   200                     || !strcmp(dot, 
".timer")
   201                     || !strcmp(dot, 
".path"))) {
   209 systemd_service_name(
const char *
name)
   215     if (systemd_unit_extension(
name)) {
   223 systemd_daemon_reload_complete(DBusPendingCall *pending, 
void *user_data)
   226     DBusMessage *reply = NULL;
   227     unsigned int reload_count = GPOINTER_TO_UINT(user_data);
   229     dbus_error_init(&error);
   231         reply = dbus_pending_call_steal_reply(pending);
   235         crm_err(
"Could not issue systemd reload %d: %s", reload_count, error.message);
   236         dbus_error_free(&error);
   239         crm_trace(
"Reload %d complete", reload_count);
   243         dbus_pending_call_unref(pending);
   246         dbus_message_unref(reply);
   251 systemd_daemon_reload(
int timeout)
   253     static unsigned int reload_count = 0;
   254     DBusMessage *msg = systemd_new_method(
"Reload");
   258     systemd_send(msg, systemd_daemon_reload_complete,
   259                  GUINT_TO_POINTER(reload_count), 
timeout);
   260     dbus_message_unref(msg);
   273 set_result_from_method_error(
svc_action_t *op, 
const DBusError *error)
   276                          "Unable to invoke systemd DBus method");
   278     if (strstr(error->name, 
"org.freedesktop.systemd1.InvalidName")
   279         || strstr(error->name, 
"org.freedesktop.systemd1.LoadFailed")
   280         || strstr(error->name, 
"org.freedesktop.systemd1.NoSuchUnit")) {
   283             crm_trace(
"Masking systemd stop failure (%s) for %s "   284                       "because unknown service can be considered stopped",
   294     crm_err(
"DBus request for %s of systemd unit %s for resource %s failed: %s",
   309 execute_after_loadunit(DBusMessage *reply, 
svc_action_t *op)
   311     const char *path = NULL;
   319             set_result_from_method_error(op, &error);
   321         dbus_error_free(&error);
   324                                      __func__, __LINE__)) {
   327                                  "systemd DBus method had unexpected reply");
   328             crm_err(
"Could not load systemd unit %s for %s: "   329                     "DBus reply has unexpected type", op->
agent, op->
id);
   331             crm_err(
"Could not load systemd unit: "   332                     "DBus reply has unexpected type");
   336         dbus_message_get_args (reply, NULL,
   337                                DBUS_TYPE_OBJECT_PATH, &path,
   343             invoke_unit_by_path(op, path);
   347                                  "No DBus object found for systemd unit");
   363 loadunit_completed(DBusPendingCall *pending, 
void *user_data)
   365     DBusMessage *reply = NULL;
   368     crm_trace(
"LoadUnit result for %s arrived", op->
id);
   371     if (pending != NULL) {
   372         reply = dbus_pending_call_steal_reply(pending);
   377     services_set_op_pending(op, NULL);
   380     execute_after_loadunit(reply, user_data);
   382         dbus_message_unref(reply);
   402 invoke_unit_by_name(
const char *arg_name, 
svc_action_t *op, 
char **path)
   405     DBusMessage *reply = NULL;
   406     DBusPendingCall *pending = NULL;
   409     if (!systemd_init()) {
   412                                  "No DBus connection");
   425     msg = systemd_new_method(
"LoadUnit");
   429     name = systemd_service_name(arg_name);
   436         const char *unit = NULL;
   439         reply = systemd_send_recv(msg, NULL,
   441         dbus_message_unref(msg);
   443         unit = execute_after_loadunit(reply, op);
   449         } 
else if (path != NULL) {
   450             *path = strdup(unit);
   457             dbus_message_unref(reply);
   463     pending = systemd_send(msg, loadunit_completed, op, op->
timeout);
   464     if (pending == NULL) {
   466                              "Unable to send DBus message");
   467         dbus_message_unref(msg);
   473     services_set_op_pending(op, pending);
   474     dbus_message_unref(msg);
   491 sort_str(gconstpointer a, gconstpointer b)
   500     return strcasecmp(a, b);
   508     DBusMessageIter args;
   509     DBusMessageIter unit;
   510     DBusMessageIter elem;
   511     DBusMessage *reply = NULL;
   513     if (systemd_init() == FALSE) {
   523     reply = systemd_call_simple_method(
"ListUnitFiles");
   527     if (!dbus_message_iter_init(reply, &args)) {
   528         crm_err(
"Could not list systemd unit files: systemd reply has no arguments");
   529         dbus_message_unref(reply);
   533                               __func__, __LINE__)) {
   534         crm_err(
"Could not list systemd unit files: systemd reply has invalid arguments");
   535         dbus_message_unref(reply);
   539     dbus_message_iter_recurse(&args, &unit);
   540     for (; dbus_message_iter_get_arg_type(&unit) != DBUS_TYPE_INVALID;
   541         dbus_message_iter_next(&unit)) {
   543         DBusBasicValue value;
   544         const char *match = NULL;
   545         char *unit_name = NULL;
   546         char *basename = NULL;
   549             crm_warn(
"Skipping systemd reply argument with unexpected type");
   553         dbus_message_iter_recurse(&unit, &elem);
   555             crm_warn(
"Skipping systemd reply argument with no string");
   559         dbus_message_iter_get_basic(&elem, &value);
   560         if (value.str == NULL) {
   561             crm_debug(
"ListUnitFiles reply did not provide a string");
   564         crm_trace(
"DBus ListUnitFiles listed: %s", value.str);
   566         match = systemd_unit_extension(value.str);
   569             crm_debug(
"ListUnitFiles entry '%s' is not supported as resource",
   575         basename = strrchr(value.str, 
'/');
   577             basename = basename + 1;
   579             basename = value.str;
   582         if (!strcmp(match, 
".service")) {
   584             unit_name = 
strndup(basename, match - basename);
   586             unit_name = strdup(basename);
   590         units = g_list_prepend(units, unit_name);
   593     dbus_message_unref(reply);
   595     crm_trace(
"Found %d manageable systemd unit files", nfiles);
   596     units = g_list_sort(units, sort_str);
   618     state = systemd_get_property(path, 
"LoadState", NULL, NULL, NULL,
   629 #define METADATA_FORMAT                                                     \   630     "<?xml version=\"1.0\"?>\n"                                             \   631     "<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n"                   \   632     "<resource-agent name=\"%s\" version=\"" PCMK_DEFAULT_AGENT_VERSION "\">\n" \   633     "  <version>1.1</version>\n"                                            \   634     "  <longdesc lang=\"en\">\n"                                            \   637     "  <shortdesc lang=\"en\">systemd unit file for %s</shortdesc>\n"       \   640     "    <action name=\"start\"     timeout=\"100\" />\n"                   \   641     "    <action name=\"stop\"      timeout=\"100\" />\n"                   \   642     "    <action name=\"status\"    timeout=\"100\" />\n"                   \   643     "    <action name=\"monitor\"   timeout=\"100\" interval=\"60\"/>\n"    \   644     "    <action name=\"meta-data\" timeout=\"5\"   />\n"                   \   646     "  <special tag=\"systemd\"/>\n"                                        \   647     "</resource-agent>\n"   650 systemd_unit_metadata(
const char *
name, 
int timeout)
   658         desc = systemd_get_property(path, 
"Description", NULL, NULL, NULL,
   678 process_unit_method_reply(DBusMessage *reply, 
svc_action_t *op)
   686         set_result_from_method_error(op, &error);
   687         dbus_error_free(&error);
   690                                      __func__, __LINE__)) {
   691         crm_warn(
"DBus request for %s of %s succeeded but "   694                              "systemd DBus method had unexpected reply");
   697         const char *path = NULL;
   699         dbus_message_get_args(reply, NULL,
   700                               DBUS_TYPE_OBJECT_PATH, &path,
   702         crm_debug(
"DBus request for %s of %s using %s succeeded",
   716 unit_method_complete(DBusPendingCall *pending, 
void *user_data)
   718     DBusMessage *reply = NULL;
   724     if (pending != NULL) {
   725         reply = dbus_pending_call_steal_reply(pending);
   730     services_set_op_pending(op, NULL);
   733     process_unit_method_reply(reply, op);
   736         dbus_message_unref(reply);
   740 #define SYSTEMD_OVERRIDE_ROOT "/run/systemd/system/"   751 #define SYSTEMD_OVERRIDE_TEMPLATE                           \   753     "Description=Cluster Controlled %s\n"                   \   754     "Before=pacemaker.service pacemaker_remote.service\n"   \   761 create_world_readable(
const char *filename)
   763     mode_t orig_umask = umask(S_IWGRP | S_IWOTH);
   764     FILE *fp = fopen(filename, 
"w");
   771 create_override_dir(
const char *agent)
   774                                            "/%s.service.d", agent);
   778         crm_warn(
"Could not create systemd override directory %s: %s",
   785 get_override_filename(
const char *agent)
   788                              "/%s.service.d/50-pacemaker.conf", agent);
   792 systemd_create_override(
const char *agent, 
int timeout)
   794     FILE *file_strm = NULL;
   795     char *override_file = get_override_filename(agent);
   797     create_override_dir(agent);
   802     file_strm = create_world_readable(override_file);
   803     if (file_strm == NULL) {
   804         crm_err(
"Cannot open systemd override file %s for writing",
   809         int rc = fprintf(file_strm, 
"%s\n", 
override);
   813             crm_perror(LOG_WARNING, 
"Cannot write to systemd override file %s",
   818         systemd_daemon_reload(
timeout);
   825 systemd_remove_override(
const char *agent, 
int timeout)
   827     char *override_file = get_override_filename(agent);
   828     int rc = unlink(override_file);
   832         crm_perror(LOG_DEBUG, 
"Cannot remove systemd override file %s",
   835         systemd_daemon_reload(
timeout);
   852 parse_status_result(
const char *
name, 
const char *state, 
void *userdata)
   876         services_set_op_pending(op, NULL);
   891     const char *method = NULL;
   892     DBusMessage *msg = NULL;
   893     DBusMessage *reply = NULL;
   896         DBusPendingCall *pending = NULL;
   899         state = systemd_get_property(unit, 
"ActiveState",
   904             parse_status_result(
"ActiveState", state, op);
   907         } 
else if (pending == NULL) { 
   909                                  "Could not get unit state from DBus");
   913             services_set_op_pending(op, pending);
   918         method = 
"StartUnit";
   926         method = 
"RestartUnit";
   930                              "Action not implemented for systemd resources");
   937     crm_trace(
"Calling %s for unit path %s named %s",
   940     msg = systemd_new_method(method);
   945         const char *replace_s = 
"replace";
   946         char *
name = systemd_service_name(op->
agent);
   948         CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &
name, DBUS_TYPE_INVALID));
   949         CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &replace_s, DBUS_TYPE_INVALID));
   955         reply = systemd_send_recv(msg, NULL, op->
timeout);
   956         dbus_message_unref(msg);
   957         process_unit_method_reply(reply, op);
   959             dbus_message_unref(reply);
   963         DBusPendingCall *pending = systemd_send(msg, unit_method_complete, op,
   966         dbus_message_unref(msg);
   967         if (pending == NULL) {
   969                                  "Unable to send DBus message");
   973             services_set_op_pending(op, pending);
   979 systemd_timeout_callback(gpointer p)
   986                          "Systemd action did not complete within specified timeout");
  1012     if ((op->
action == NULL) || (op->
agent == NULL)) {
  1014                              "Bug in action caller");
  1018     if (!systemd_init()) {
  1020                              "No DBus connection");
  1024     crm_debug(
"Performing %ssynchronous %s op on systemd unit %s named '%s'",
  1038                          "Bug in service library");
  1042                                             systemd_timeout_callback, op);
 
int rc
Exit status of action (set by library upon completion) 
 
#define CRM_CHECK(expr, failure_action)
 
int services__execute_systemd(svc_action_t *op)
 
ocf_exitcode
Exit status codes for resource agents. 
 
void pcmk_dbus_disconnect(DBusConnection *connection)
 
#define DBUS_TIMEOUT_USE_DEFAULT
 
char * rsc
XML ID of resource being executed for resource actions, otherwise NULL. 
 
#define CRM_LOG_ASSERT(expr)
 
int timeout
Action timeout (in milliseconds) 
 
Action did not complete in time. 
 
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code. 
 
Wrappers for and extensions to glib mainloop. 
 
bool pcmk_dbus_find_error(DBusPendingCall *pending, DBusMessage *reply, DBusError *ret)
 
char * strndup(const char *str, size_t len)
 
#define crm_warn(fmt, args...)
 
svc_action_private_t * opaque
This field should be treated as internal to Pacemaker. 
 
#define crm_debug(fmt, args...)
 
char * stdout_data
Action stdout (set by library) 
 
Parameter invalid (inherently) 
 
gboolean systemd_unit_exists(const char *name)
 
#define crm_trace(fmt, args...)
 
int services__finalize_async_op(svc_action_t *op)
 
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
 
Object for executing external actions. 
 
char * agent
Resource agent name for resource actions, otherwise NULL. 
 
void services__set_result(svc_action_t *action, int agent_status, enum pcmk_exec_status exec_status, const char *exit_reason)
 
Action completed, result is known. 
 
Execution failed, do not retry anywhere. 
 
Dependencies not available locally. 
 
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
 
#define SYSTEMD_OVERRIDE_ROOT
 
GList * systemd_unit_listall(void)
 
DBusPendingCall * pcmk_dbus_send(DBusMessage *msg, DBusConnection *connection, void(*done)(DBusPendingCall *pending, void *user_data), void *user_data, int timeout)
 
DBusConnection * pcmk_dbus_connect(void)
 
void services_add_inflight_op(svc_action_t *op)
 
Requested action not implemented. 
 
int services__systemd_prepare(svc_action_t *op)
 
void systemd_cleanup(void)
 
char * action
Name of action being executed for resource actions, otherwise NULL. 
 
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr. 
 
#define crm_err(fmt, args...)
 
enum ocf_exitcode services__systemd2ocf(int exit_status)
 
bool pcmk_dbus_type_check(DBusMessage *msg, DBusMessageIter *field, int expected, const char *function, int line)
 
Agent or dependency not available locally. 
 
char * pcmk_dbus_get_property(DBusConnection *connection, const char *target, const char *obj, const gchar *iface, const char *name, property_callback_func callback, void *userdata, DBusPendingCall **pending, int timeout)
 
#define SYSTEMD_OVERRIDE_TEMPLATE
 
DBusMessage * pcmk_dbus_send_recv(DBusMessage *msg, DBusConnection *connection, DBusError *error, int timeout)
 
Execution failed, may be retried. 
 
int pcmk__build_path(const char *path_c, mode_t mode)