19 #include <dbus/dbus.h>
24 #define BUS_NAME "org.freedesktop.systemd1"
25 #define BUS_NAME_MANAGER BUS_NAME ".Manager"
26 #define BUS_NAME_UNIT BUS_NAME ".Unit"
27 #define BUS_PATH "/org/freedesktop/systemd1"
29 static inline DBusMessage *
30 systemd_new_method(
const char *method)
41 static DBusConnection* systemd_proxy = NULL;
43 static inline DBusPendingCall *
44 systemd_send(DBusMessage *msg,
45 void(*done)(DBusPendingCall *pending,
void *user_data),
46 void *user_data,
int timeout)
48 return pcmk_dbus_send(msg, systemd_proxy, done, user_data, timeout);
51 static inline DBusMessage *
52 systemd_send_recv(DBusMessage *msg, DBusError *error,
int timeout)
69 systemd_call_simple_method(
const char *method)
71 DBusMessage *msg = systemd_new_method(method);
72 DBusMessage *reply = NULL;
79 crm_err(
"Could not create message to send %s to systemd", method);
83 dbus_error_init(&error);
85 dbus_message_unref(msg);
87 if (dbus_error_is_set(&error)) {
88 crm_err(
"Could not send %s to systemd: %s (%s)",
89 method, error.message, error.name);
90 dbus_error_free(&error);
93 }
else if (reply == NULL) {
94 crm_err(
"Could not send %s to systemd: no reply received", method);
104 static int need_init = 1;
108 && dbus_connection_get_is_connected(systemd_proxy) == FALSE) {
109 crm_warn(
"Connection to System DBus is closed. Reconnecting...");
111 systemd_proxy = NULL;
119 if (systemd_proxy == NULL) {
126 systemd_get_property(
const char *unit,
const char *name,
127 void (*callback)(
const char *name,
const char *value,
void *userdata),
128 void *userdata, DBusPendingCall **pending,
int timeout)
130 return systemd_proxy?
132 name, callback, userdata, pending, timeout)
141 systemd_proxy = NULL;
158 systemd_unit_extension(
const char *name)
161 const char *dot = strrchr(name,
'.');
163 if (dot && (!strcmp(dot,
".service")
164 || !strcmp(dot,
".socket")
165 || !strcmp(dot,
".mount")
166 || !strcmp(dot,
".timer")
167 || !strcmp(dot,
".path"))) {
175 systemd_service_name(
const char *name)
181 if (systemd_unit_extension(name)) {
189 systemd_daemon_reload_complete(DBusPendingCall *pending,
void *user_data)
192 DBusMessage *reply = NULL;
193 unsigned int reload_count = GPOINTER_TO_UINT(user_data);
195 dbus_error_init(&error);
197 reply = dbus_pending_call_steal_reply(pending);
201 crm_err(
"Could not issue systemd reload %d: %s", reload_count, error.message);
202 dbus_error_free(&error);
205 crm_trace(
"Reload %d complete", reload_count);
209 dbus_pending_call_unref(pending);
212 dbus_message_unref(reply);
217 systemd_daemon_reload(
int timeout)
219 static unsigned int reload_count = 0;
220 DBusMessage *msg = systemd_new_method(
"Reload");
224 systemd_send(msg, systemd_daemon_reload_complete,
225 GUINT_TO_POINTER(reload_count), timeout);
226 dbus_message_unref(msg);
235 if(strstr(error,
"org.freedesktop.systemd1.InvalidName")
236 || strstr(error,
"org.freedesktop.systemd1.LoadFailed")
237 || strstr(error,
"org.freedesktop.systemd1.NoSuchUnit")) {
240 crm_trace(
"Masking %s failure for %s: unknown services are stopped", op->
action, op->
rsc);
245 crm_trace(
"Mapping %s failure for %s: unknown services are not installed", op->
action, op->
rsc);
256 systemd_loadunit_result(DBusMessage *reply,
svc_action_t * op)
258 const char *path = NULL;
262 if(op && !systemd_mask_error(op, error.name)) {
263 crm_err(
"Could not load systemd unit %s for %s: %s",
264 op->
agent, op->
id, error.message);
266 dbus_error_free(&error);
269 dbus_message_get_args (reply, NULL,
270 DBUS_TYPE_OBJECT_PATH, &path,
288 systemd_loadunit_cb(DBusPendingCall *pending,
void *user_data)
290 DBusMessage *reply = NULL;
294 reply = dbus_pending_call_steal_reply(pending);
297 crm_trace(
"Got result: %p for %p / %p for %s", reply, pending, op->
opaque->pending, op->
id);
300 services_set_op_pending(op, NULL);
302 systemd_loadunit_result(reply, user_data);
305 dbus_message_unref(reply);
310 systemd_unit_by_name(
const gchar * arg_name,
svc_action_t *op)
313 DBusMessage *reply = NULL;
314 DBusPendingCall* pending = NULL;
325 if (systemd_init() == FALSE) {
329 msg = systemd_new_method(
"LoadUnit");
332 name = systemd_service_name(arg_name);
333 CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID));
337 const char *unit = NULL;
340 reply = systemd_send_recv(msg, NULL,
342 dbus_message_unref(msg);
344 unit = systemd_loadunit_result(reply, op);
346 munit = strdup(unit);
349 dbus_message_unref(reply);
354 pending = systemd_send(msg, systemd_loadunit_cb, op, op->
timeout);
356 services_set_op_pending(op, pending);
359 dbus_message_unref(msg);
368 DBusMessageIter args;
369 DBusMessageIter unit;
370 DBusMessageIter elem;
371 DBusMessage *reply = NULL;
373 if (systemd_init() == FALSE) {
383 reply = systemd_call_simple_method(
"ListUnitFiles");
387 if (!dbus_message_iter_init(reply, &args)) {
388 crm_err(
"Could not list systemd unit files: systemd reply has no arguments");
389 dbus_message_unref(reply);
393 __FUNCTION__, __LINE__)) {
394 crm_err(
"Could not list systemd unit files: systemd reply has invalid arguments");
395 dbus_message_unref(reply);
399 dbus_message_iter_recurse(&args, &unit);
400 for (; dbus_message_iter_get_arg_type(&unit) != DBUS_TYPE_INVALID;
401 dbus_message_iter_next(&unit)) {
403 DBusBasicValue value;
404 const char *match = NULL;
405 char *unit_name = NULL;
406 char *basename = NULL;
409 crm_debug(
"ListUnitFiles reply has unexpected type");
413 dbus_message_iter_recurse(&unit, &elem);
415 crm_debug(
"ListUnitFiles reply does not contain a string");
419 dbus_message_iter_get_basic(&elem, &value);
420 if (value.str == NULL) {
421 crm_debug(
"ListUnitFiles reply did not provide a string");
424 crm_trace(
"DBus ListUnitFiles listed: %s", value.str);
426 match = systemd_unit_extension(value.str);
429 crm_debug(
"ListUnitFiles entry '%s' is not supported as resource",
435 basename = strrchr(value.str,
'/');
437 basename = basename + 1;
439 basename = value.str;
442 if (!strcmp(match,
".service")) {
444 unit_name =
strndup(basename, match - basename);
446 unit_name = strdup(basename);
450 units = g_list_prepend(units, unit_name);
453 dbus_message_unref(reply);
455 crm_trace(
"Found %d manageable systemd unit files", nfiles);
468 unit = systemd_unit_by_name(name, NULL);
477 systemd_unit_metadata(
const char *name,
int timeout)
481 char *path = systemd_unit_by_name(name, NULL);
485 desc = systemd_get_property(path,
"Description", NULL, NULL, NULL,
492 "<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n"
494 " <version>1.0</version>\n"
495 " <longdesc lang=\"en\">\n"
498 " <shortdesc lang=\"en\">systemd unit file for %s</shortdesc>\n"
502 " <action name=\"start\" timeout=\"100\" />\n"
503 " <action name=\"stop\" timeout=\"100\" />\n"
504 " <action name=\"status\" timeout=\"100\" />\n"
505 " <action name=\"monitor\" timeout=\"100\" interval=\"60\"/>\n"
506 " <action name=\"meta-data\" timeout=\"5\" />\n"
508 " <special tag=\"systemd\">\n"
509 " </special>\n" "</resource-agent>\n", name, desc, name);
516 systemd_exec_result(DBusMessage *reply,
svc_action_t *op)
523 if (!systemd_mask_error(op, error.name)) {
524 crm_err(
"Could not issue %s for %s: %s", op->
action, op->
rsc, error.message);
526 dbus_error_free(&error);
530 crm_warn(
"Call to %s passed but return type was unexpected", op->
action);
534 const char *path = NULL;
536 dbus_message_get_args (reply, NULL,
537 DBUS_TYPE_OBJECT_PATH, &path,
548 systemd_async_dispatch(DBusPendingCall *pending,
void *user_data)
550 DBusMessage *reply = NULL;
554 reply = dbus_pending_call_steal_reply(pending);
560 services_set_op_pending(op, NULL);
561 systemd_exec_result(reply, op);
564 dbus_message_unref(reply);
568 #define SYSTEMD_OVERRIDE_ROOT "/run/systemd/system/"
579 #define SYSTEMD_OVERRIDE_TEMPLATE \
581 "Description=Cluster Controlled %s\n" \
582 "Before=pacemaker.service pacemaker_remote.service\n" \
589 create_world_readable(
const char *filename)
591 mode_t orig_umask = umask(S_IWGRP | S_IWOTH);
592 FILE *fp = fopen(filename,
"w");
599 create_override_dir(
const char *agent)
602 "/%s.service.d", agent);
609 get_override_filename(
const char *agent)
612 "/%s.service.d/50-pacemaker.conf", agent);
616 systemd_create_override(
const char *agent,
int timeout)
618 FILE *file_strm = NULL;
619 char *override_file = get_override_filename(agent);
621 create_override_dir(agent);
626 file_strm = create_world_readable(override_file);
627 if (file_strm == NULL) {
628 crm_err(
"Cannot open systemd override file %s for writing",
633 int rc = fprintf(file_strm,
"%s\n",
override);
637 crm_perror(LOG_WARNING,
"Cannot write to systemd override file %s",
642 systemd_daemon_reload(timeout);
649 systemd_remove_override(
const char *agent,
int timeout)
651 char *override_file = get_override_filename(agent);
652 int rc = unlink(override_file);
656 crm_perror(LOG_DEBUG,
"Cannot remove systemd override file %s",
659 systemd_daemon_reload(timeout);
665 systemd_unit_check(
const char *name,
const char *state,
void *userdata)
669 crm_trace(
"Resource %s has %s='%s'", op->
rsc, name, state);
674 }
else if (g_strcmp0(state,
"active") == 0) {
676 }
else if (g_strcmp0(state,
"reloading") == 0) {
678 }
else if (g_strcmp0(state,
"activating") == 0) {
680 }
else if (g_strcmp0(state,
"deactivating") == 0) {
687 services_set_op_pending(op, NULL);
695 const char *method = op->
action;
696 DBusMessage *msg = NULL;
697 DBusMessage *reply = NULL;
702 DBusPendingCall *pending = NULL;
705 state = systemd_get_property(unit,
"ActiveState",
710 systemd_unit_check(
"ActiveState", state, op);
713 }
else if (pending) {
714 services_set_op_pending(op, pending);
721 }
else if (g_strcmp0(method,
"start") == 0) {
722 method =
"StartUnit";
725 }
else if (g_strcmp0(method,
"stop") == 0) {
729 }
else if (g_strcmp0(method,
"restart") == 0) {
730 method =
"RestartUnit";
737 crm_debug(
"Calling %s for %s: %s", method, op->
rsc, unit);
739 msg = systemd_new_method(method);
744 const char *replace_s =
"replace";
745 char *name = systemd_service_name(op->
agent);
747 CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID));
748 CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &replace_s, DBUS_TYPE_INVALID));
754 DBusPendingCall *pending = systemd_send(msg, systemd_async_dispatch,
757 dbus_message_unref(msg);
759 services_set_op_pending(op, pending);
767 reply = systemd_send_recv(msg, NULL, op->
timeout);
768 dbus_message_unref(msg);
769 systemd_exec_result(reply, op);
772 dbus_message_unref(reply);
786 systemd_timeout_callback(gpointer p)
807 crm_debug(
"Performing %ssynchronous %s op on systemd unit %s named '%s'",
821 unit = systemd_unit_by_name(op->
agent, op);
825 if (op->
opaque->pending) {
826 op->
opaque->timerid = g_timeout_add(op->
timeout + 5000, systemd_timeout_callback, op);