21 #include <dbus/dbus.h>    24 static void invoke_unit_by_path(
svc_action_t *op, 
const char *unit);
    26 #define BUS_NAME         "org.freedesktop.systemd1"    27 #define BUS_NAME_MANAGER BUS_NAME ".Manager"    28 #define BUS_NAME_UNIT    BUS_NAME ".Unit"    29 #define BUS_PATH         "/org/freedesktop/systemd1"    64 static inline DBusMessage *
    65 systemd_new_method(
const char *method)
    76 static DBusConnection* systemd_proxy = NULL;
    78 static inline DBusPendingCall *
    79 systemd_send(DBusMessage *msg,
    80              void(*done)(DBusPendingCall *pending, 
void *user_data),
    86 static inline DBusMessage *
    87 systemd_send_recv(DBusMessage *msg, DBusError *error, 
int timeout)
   104 systemd_call_simple_method(
const char *method)
   106     DBusMessage *msg = systemd_new_method(method);
   107     DBusMessage *reply = NULL;
   114         crm_err(
"Could not create message to send %s to systemd", method);
   118     dbus_error_init(&error);
   120     dbus_message_unref(msg);
   122     if (dbus_error_is_set(&error)) {
   123         crm_err(
"Could not send %s to systemd: %s (%s)",
   124                 method, error.message, error.name);
   125         dbus_error_free(&error);
   128     } 
else if (reply == NULL) {
   129         crm_err(
"Could not send %s to systemd: no reply received", method);
   139     static int need_init = 1;
   143         && dbus_connection_get_is_connected(systemd_proxy) == FALSE) {
   144         crm_warn(
"Connection to System DBus is closed. Reconnecting...");
   146         systemd_proxy = NULL;
   154     if (systemd_proxy == NULL) {
   161 systemd_get_property(
const char *unit, 
const char *
name,
   162                      void (*callback)(
const char *
name, 
const char *value, 
void *userdata),
   163                      void *userdata, DBusPendingCall **pending, 
int timeout)
   165     return systemd_proxy?
   176         systemd_proxy = NULL;
   193 systemd_unit_extension(
const char *
name)
   196         const char *dot = strrchr(
name, 
'.');
   198         if (dot && (!strcmp(dot, 
".service")
   199                     || !strcmp(dot, 
".socket")
   200                     || !strcmp(dot, 
".mount")
   201                     || !strcmp(dot, 
".timer")
   202                     || !strcmp(dot, 
".path"))) {
   210 systemd_service_name(
const char *
name, 
bool add_instance_name)
   212     const char *dot = NULL;
   214     if (pcmk__str_empty(
name)) {
   227     dot = systemd_unit_extension(
name);
   230         if (dot != 
name && *(dot-1) == 
'@') {
   233             if (asprintf(&s, 
"%.*spacemaker%s", (
int) (dot-
name), 
name, dot) == -1) {
   243     } 
else if (add_instance_name && *(
name+strlen(
name)-1) == 
'@') {
   252 systemd_daemon_reload_complete(DBusPendingCall *pending, 
void *user_data)
   255     DBusMessage *reply = NULL;
   256     unsigned int reload_count = GPOINTER_TO_UINT(user_data);
   258     dbus_error_init(&error);
   260         reply = dbus_pending_call_steal_reply(pending);
   264         crm_warn(
"Could not issue systemd reload %d: %s",
   265                  reload_count, error.message);
   266         dbus_error_free(&error);
   269         crm_trace(
"Reload %d complete", reload_count);
   273         dbus_pending_call_unref(pending);
   276         dbus_message_unref(reply);
   281 systemd_daemon_reload(
int timeout)
   283     static unsigned int reload_count = 0;
   284     DBusMessage *msg = systemd_new_method(
"Reload");
   288     systemd_send(msg, systemd_daemon_reload_complete,
   289                  GUINT_TO_POINTER(reload_count), 
timeout);
   290     dbus_message_unref(msg);
   303 set_result_from_method_error(
svc_action_t *op, 
const DBusError *error)
   306                          "Unable to invoke systemd DBus method");
   308     if (strstr(error->name, 
"org.freedesktop.systemd1.InvalidName")
   309         || strstr(error->name, 
"org.freedesktop.systemd1.LoadFailed")
   310         || strstr(error->name, 
"org.freedesktop.systemd1.NoSuchUnit")) {
   313             crm_trace(
"Masking systemd stop failure (%s) for %s "   314                       "because unknown service can be considered stopped",
   315                       error->name, pcmk__s(op->
rsc, 
"unknown resource"));
   322                                "systemd unit %s not found", op->
agent);
   325     crm_info(
"DBus request for %s of systemd unit %s%s%s failed: %s",
   327              ((op->
rsc == NULL)? 
"" : 
" for resource "), pcmk__s(op->
rsc, 
""),
   342 execute_after_loadunit(DBusMessage *reply, 
svc_action_t *op)
   344     const char *
path = NULL;
   352             set_result_from_method_error(op, &error);
   354         dbus_error_free(&error);
   357                                      __func__, __LINE__)) {
   360                                  "systemd DBus method had unexpected reply");
   361             crm_info(
"Could not load systemd unit %s for %s: "   362                      "DBus reply has unexpected type", op->
agent, op->
id);
   364             crm_info(
"Could not load systemd unit: "   365                      "DBus reply has unexpected type");
   369         dbus_message_get_args (reply, NULL,
   370                                DBUS_TYPE_OBJECT_PATH, &
path,
   376             invoke_unit_by_path(op, 
path);
   380                                     "No DBus object found for systemd unit %s",
   397 loadunit_completed(DBusPendingCall *pending, 
void *user_data)
   399     DBusMessage *reply = NULL;
   402     crm_trace(
"LoadUnit result for %s arrived", op->
id);
   405     if (pending != NULL) {
   406         reply = dbus_pending_call_steal_reply(pending);
   411     services_set_op_pending(op, NULL);
   414     execute_after_loadunit(reply, user_data);
   416         dbus_message_unref(reply);
   439     DBusMessage *reply = NULL;
   440     DBusPendingCall *pending = NULL;
   443     if (!systemd_init()) {
   446                                  "No DBus connection");
   459     msg = systemd_new_method(
"LoadUnit");
   463     name = systemd_service_name(arg_name,
   465                                 || pcmk__str_eq(op->
action,
   474         const char *unit = NULL;
   477         reply = systemd_send_recv(msg, NULL,
   479         dbus_message_unref(msg);
   481         unit = execute_after_loadunit(reply, op);
   487         } 
else if (
path != NULL) {
   488             *
path = strdup(unit);
   495             dbus_message_unref(reply);
   501     pending = systemd_send(msg, loadunit_completed, op, op->
timeout);
   502     if (pending == NULL) {
   504                              "Unable to send DBus message");
   505         dbus_message_unref(msg);
   511     services_set_op_pending(op, pending);
   512     dbus_message_unref(msg);
   529 sort_str(gconstpointer a, gconstpointer b)
   538     return strcasecmp(a, b);
   546     DBusMessageIter args;
   547     DBusMessageIter unit;
   548     DBusMessageIter elem;
   549     DBusMessage *reply = NULL;
   551     if (systemd_init() == FALSE) {
   561     reply = systemd_call_simple_method(
"ListUnitFiles");
   565     if (!dbus_message_iter_init(reply, &args)) {
   566         crm_err(
"Could not list systemd unit files: systemd reply has no arguments");
   567         dbus_message_unref(reply);
   571                               __func__, __LINE__)) {
   572         crm_err(
"Could not list systemd unit files: systemd reply has invalid arguments");
   573         dbus_message_unref(reply);
   577     dbus_message_iter_recurse(&args, &unit);
   578     for (; dbus_message_iter_get_arg_type(&unit) != DBUS_TYPE_INVALID;
   579         dbus_message_iter_next(&unit)) {
   581         DBusBasicValue value;
   582         const char *match = NULL;
   583         char *unit_name = NULL;
   584         char *basename = NULL;
   587             crm_warn(
"Skipping systemd reply argument with unexpected type");
   591         dbus_message_iter_recurse(&unit, &elem);
   593             crm_warn(
"Skipping systemd reply argument with no string");
   597         dbus_message_iter_get_basic(&elem, &value);
   598         if (value.str == NULL) {
   599             crm_debug(
"ListUnitFiles reply did not provide a string");
   602         crm_trace(
"DBus ListUnitFiles listed: %s", value.str);
   604         match = systemd_unit_extension(value.str);
   607             crm_debug(
"ListUnitFiles entry '%s' is not supported as resource",
   613         basename = strrchr(value.str, 
'/');
   615             basename = basename + 1;
   617             basename = value.str;
   620         if (!strcmp(match, 
".service")) {
   622             unit_name = strndup(basename, match - basename);
   624             unit_name = strdup(basename);
   628         units = g_list_prepend(units, unit_name);
   631     dbus_message_unref(reply);
   633     crm_trace(
"Found %d manageable systemd unit files", nfiles);
   634     units = g_list_sort(units, sort_str);
   656     state = systemd_get_property(
path, 
"LoadState", NULL, NULL, NULL,
   668 #define METADATA_FORMAT                                                        \   669     "<?xml " PCMK_XA_VERSION "=\"1.0\"?>\n"                                    \   670     "<" PCMK_XE_RESOURCE_AGENT " "                                             \   671         PCMK_XA_NAME "=\"%s\" "                                                \   672         PCMK_XA_VERSION "=\"" PCMK_DEFAULT_AGENT_VERSION "\">\n"               \   673     "  <" PCMK_XE_VERSION ">1.1</" PCMK_XE_VERSION ">\n"                       \   674     "  <" PCMK_XE_LONGDESC " " PCMK_XA_LANG "=\"" PCMK__VALUE_EN "\">\n"       \   676     "  </" PCMK_XE_LONGDESC ">\n"                                              \   677     "  <" PCMK_XE_SHORTDESC " " PCMK_XA_LANG "=\"" PCMK__VALUE_EN "\">"        \   678         "systemd unit file for %s"                                             \   679       "</" PCMK_XE_SHORTDESC ">\n"                                             \   680     "  <" PCMK_XE_PARAMETERS "/>\n"                                            \   681     "  <" PCMK_XE_ACTIONS ">\n"                                                \   682     "    <" PCMK_XE_ACTION " " PCMK_XA_NAME "=\"" PCMK_ACTION_START "\""       \   683                            " " PCMK_META_TIMEOUT "=\"100s\" />\n"              \   684     "    <" PCMK_XE_ACTION " " PCMK_XA_NAME "=\"" PCMK_ACTION_STOP "\""        \   685                            " " PCMK_META_TIMEOUT "=\"100s\" />\n"              \   686     "    <" PCMK_XE_ACTION " " PCMK_XA_NAME "=\"" PCMK_ACTION_STATUS "\""      \   687                            " " PCMK_META_TIMEOUT "=\"100s\" />\n"              \   688     "    <" PCMK_XE_ACTION " " PCMK_XA_NAME "=\"" PCMK_ACTION_MONITOR "\""     \   689                            " " PCMK_META_TIMEOUT "=\"100s\""                   \   690                            " " PCMK_META_INTERVAL "=\"60s\" />\n"              \   691     "    <" PCMK_XE_ACTION " " PCMK_XA_NAME "=\"" PCMK_ACTION_META_DATA "\""   \   692                            " " PCMK_META_TIMEOUT "=\"5s\" />\n"                \   693     "  </" PCMK_XE_ACTIONS ">\n"                                               \   694     "  <" PCMK_XE_SPECIAL " " PCMK_XA_TAG "=\"systemd\"/>\n"                   \   695     "</" PCMK_XE_RESOURCE_AGENT ">\n"   698 systemd_unit_metadata(
const char *
name, 
int timeout)
   706         desc = systemd_get_property(
path, 
"Description", NULL, NULL, NULL,
   735 process_unit_method_reply(DBusMessage *reply, 
svc_action_t *op)
   739     dbus_error_init(&error);
   745         set_result_from_method_error(op, &error);
   746         dbus_error_free(&error);
   749                                      __func__, __LINE__)) {
   750         crm_info(
"DBus request for %s of %s succeeded but "   751                  "return type was unexpected",
   752                  op->
action, pcmk__s(op->
rsc, 
"unknown resource"));
   754                              "systemd DBus method had unexpected reply");
   757         const char *
path = NULL;
   759         dbus_message_get_args(reply, NULL,
   760                               DBUS_TYPE_OBJECT_PATH, &
path,
   762         crm_debug(
"DBus request for %s of %s using %s succeeded",
   776 unit_method_complete(DBusPendingCall *pending, 
void *user_data)
   778     DBusMessage *reply = NULL;
   784     if (pending != NULL) {
   785         reply = dbus_pending_call_steal_reply(pending);
   790     services_set_op_pending(op, NULL);
   793     process_unit_method_reply(reply, op);
   796         dbus_message_unref(reply);
   800 #define SYSTEMD_OVERRIDE_ROOT "/run/systemd/system/"   811 #define SYSTEMD_OVERRIDE_TEMPLATE                           \   813     "Description=Cluster Controlled %s\n"                   \   814     "Before=pacemaker.service pacemaker_remote.service\n"   \   821 create_world_readable(
const char *filename)
   823     mode_t orig_umask = umask(S_IWGRP | S_IWOTH);
   824     FILE *fp = fopen(filename, 
"w");
   831 create_override_dir(
const char *agent)
   834                                            "/%s.service.d", agent);
   838         crm_warn(
"Could not create systemd override directory %s: %s",
   845 get_override_filename(
const char *agent)
   848                              "/%s.service.d/50-pacemaker.conf", agent);
   852 systemd_create_override(
const char *agent, 
int timeout)
   854     FILE *file_strm = NULL;
   855     char *override_file = get_override_filename(agent);
   857     create_override_dir(agent);
   862     file_strm = create_world_readable(override_file);
   863     if (file_strm == NULL) {
   864         crm_err(
"Cannot open systemd override file %s for writing",
   869         int rc = fprintf(file_strm, 
"%s\n", 
override);
   873             crm_perror(LOG_WARNING, 
"Cannot write to systemd override file %s",
   878         systemd_daemon_reload(
timeout);
   885 systemd_remove_override(
const char *agent, 
int timeout)
   887     char *override_file = get_override_filename(agent);
   888     int rc = unlink(override_file);
   892         crm_perror(LOG_DEBUG, 
"Cannot remove systemd override file %s",
   895         systemd_daemon_reload(
timeout);
   912 parse_status_result(
const char *
name, 
const char *state, 
void *userdata)
   917               pcmk__s(op->
rsc, 
"(unspecified)"), 
name,
   918               pcmk__s(state, 
"<null>"));
   937         services_set_op_pending(op, NULL);
   952     const char *method = NULL;
   953     DBusMessage *msg = NULL;
   954     DBusMessage *reply = NULL;
   958         DBusPendingCall *pending = NULL;
   961         state = systemd_get_property(unit, 
"ActiveState",
   966             parse_status_result(
"ActiveState", state, op);
   969         } 
else if (pending == NULL) { 
   971                                     "Could not get state for unit %s from DBus",
   976             services_set_op_pending(op, pending);
   981         method = 
"StartUnit";
   989         method = 
"RestartUnit";
   994                                 "Action %s not implemented "   995                                 "for systemd resources",
   996                                 pcmk__s(op->
action, 
"(unspecified)"));
  1003     crm_trace(
"Calling %s for unit path %s%s%s",
  1005               ((op->
rsc == NULL)? 
"" : 
" for resource "), pcmk__s(op->
rsc, 
""));
  1007     msg = systemd_new_method(method);
  1012         const char *replace_s = 
"replace";
  1013         char *
name = systemd_service_name(op->
agent,
  1018         CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &
name, DBUS_TYPE_INVALID));
  1019         CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &replace_s, DBUS_TYPE_INVALID));
  1025         reply = systemd_send_recv(msg, NULL, op->
timeout);
  1026         dbus_message_unref(msg);
  1027         process_unit_method_reply(reply, op);
  1028         if (reply != NULL) {
  1029             dbus_message_unref(reply);
  1033         DBusPendingCall *pending = systemd_send(msg, unit_method_complete, op,
  1036         dbus_message_unref(msg);
  1037         if (pending == NULL) {
  1039                                  "Unable to send DBus message");
  1043             services_set_op_pending(op, pending);
  1049 systemd_timeout_callback(gpointer p)
  1054     crm_info(
"%s action for systemd unit %s named '%s' timed out",
  1057                             "%s action for systemd unit %s "  1058                             "did not complete in time", op->
action, op->
agent);
  1084     if ((op->
action == NULL) || (op->
agent == NULL)) {
  1086                              "Bug in action caller");
  1090     if (!systemd_init()) {
  1092                              "No DBus connection");
  1096     crm_debug(
"Performing %ssynchronous %s op on systemd unit %s%s%s",
  1098               ((op->
rsc == NULL)? 
"" : 
" for resource "), pcmk__s(op->
rsc, 
""));
  1110                          "Bug in service library");
  1114                                             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. 
 
char * pcmk__xml_escape(const char *text, enum pcmk__xml_escape_type type)
 
void pcmk_dbus_disconnect(DBusConnection *connection)
 
bool pcmk__xml_needs_escape(const char *text, enum pcmk__xml_escape_type type)
 
#define DBUS_TIMEOUT_USE_DEFAULT
 
#define PCMK_ACTION_META_DATA
 
#define PCMK_ACTION_MONITOR
 
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. 
 
#define PCMK_ACTION_STATUS
 
#define crm_warn(fmt, args...)
 
void services__format_result(svc_action_t *action, int agent_status, enum pcmk_exec_status exec_status, const char *format,...) G_GNUC_PRINTF(4
 
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)
 
int pcmk__build_path(const char *path_c, mode_t mode)
 
#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. 
 
#define PCMK_ACTION_START
 
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)
 
Wrappers for and extensions to libxml2. 
 
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. 
 
bool pcmk_dbus_find_error(const DBusPendingCall *pending, DBusMessage *reply, DBusError *ret)
 
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. 
 
#define crm_info(fmt, args...)