17 #include <dbus/dbus.h>
22 #define BUS_NAME "org.freedesktop.systemd1"
23 #define BUS_NAME_MANAGER BUS_NAME ".Manager"
24 #define BUS_NAME_UNIT BUS_NAME ".Unit"
25 #define BUS_PATH "/org/freedesktop/systemd1"
27 static inline DBusMessage *
28 systemd_new_method(
const char *method)
39 static DBusConnection* systemd_proxy = NULL;
41 static inline DBusPendingCall *
42 systemd_send(DBusMessage *msg,
43 void(*done)(DBusPendingCall *pending,
void *user_data),
44 void *user_data,
int timeout)
46 return pcmk_dbus_send(msg, systemd_proxy, done, user_data, timeout);
49 static inline DBusMessage *
50 systemd_send_recv(DBusMessage *msg, DBusError *error,
int timeout)
67 systemd_call_simple_method(
const char *method)
69 DBusMessage *msg = systemd_new_method(method);
70 DBusMessage *reply = NULL;
77 crm_err(
"Could not create message to send %s to systemd", method);
81 dbus_error_init(&error);
83 dbus_message_unref(msg);
85 if (dbus_error_is_set(&error)) {
86 crm_err(
"Could not send %s to systemd: %s (%s)",
87 method, error.message, error.name);
88 dbus_error_free(&error);
91 }
else if (reply == NULL) {
92 crm_err(
"Could not send %s to systemd: no reply received", method);
102 static int need_init = 1;
106 && dbus_connection_get_is_connected(systemd_proxy) == FALSE) {
107 crm_warn(
"Connection to System DBus is closed. Reconnecting...");
109 systemd_proxy = NULL;
117 if (systemd_proxy == NULL) {
124 systemd_get_property(
const char *unit,
const char *name,
125 void (*callback)(
const char *name,
const char *value,
void *userdata),
126 void *userdata, DBusPendingCall **pending,
int timeout)
128 return systemd_proxy?
130 name, callback, userdata, pending, timeout)
139 systemd_proxy = NULL;
156 systemd_unit_extension(
const char *name)
159 const char *dot = strrchr(name,
'.');
161 if (dot && (!strcmp(dot,
".service") || !strcmp(dot,
".socket"))) {
169 systemd_service_name(
const char *name)
175 if (systemd_unit_extension(name)) {
183 systemd_daemon_reload_complete(DBusPendingCall *pending,
void *user_data)
186 DBusMessage *reply = NULL;
187 unsigned int reload_count = GPOINTER_TO_UINT(user_data);
189 dbus_error_init(&error);
191 reply = dbus_pending_call_steal_reply(pending);
195 crm_err(
"Could not issue systemd reload %d: %s", reload_count, error.message);
196 dbus_error_free(&error);
199 crm_trace(
"Reload %d complete", reload_count);
203 dbus_pending_call_unref(pending);
206 dbus_message_unref(reply);
211 systemd_daemon_reload(
int timeout)
213 static unsigned int reload_count = 0;
214 DBusMessage *msg = systemd_new_method(
"Reload");
218 systemd_send(msg, systemd_daemon_reload_complete,
219 GUINT_TO_POINTER(reload_count), timeout);
220 dbus_message_unref(msg);
229 if(strstr(error,
"org.freedesktop.systemd1.InvalidName")
230 || strstr(error,
"org.freedesktop.systemd1.LoadFailed")
231 || strstr(error,
"org.freedesktop.systemd1.NoSuchUnit")) {
234 crm_trace(
"Masking %s failure for %s: unknown services are stopped", op->
action, op->
rsc);
239 crm_trace(
"Mapping %s failure for %s: unknown services are not installed", op->
action, op->
rsc);
250 systemd_loadunit_result(DBusMessage *reply,
svc_action_t * op)
252 const char *path = NULL;
256 if(op && !systemd_mask_error(op, error.name)) {
257 crm_err(
"Could not load systemd unit %s for %s: %s",
258 op->
agent, op->
id, error.message);
260 dbus_error_free(&error);
263 dbus_message_get_args (reply, NULL,
264 DBUS_TYPE_OBJECT_PATH, &path,
282 systemd_loadunit_cb(DBusPendingCall *pending,
void *user_data)
284 DBusMessage *reply = NULL;
288 reply = dbus_pending_call_steal_reply(pending);
291 crm_trace(
"Got result: %p for %p / %p for %s", reply, pending, op->
opaque->pending, op->
id);
294 services_set_op_pending(op, NULL);
296 systemd_loadunit_result(reply, user_data);
299 dbus_message_unref(reply);
304 systemd_unit_by_name(
const gchar * arg_name,
svc_action_t *op)
307 DBusMessage *reply = NULL;
308 DBusPendingCall* pending = NULL;
319 if (systemd_init() == FALSE) {
323 msg = systemd_new_method(
"LoadUnit");
326 name = systemd_service_name(arg_name);
327 CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID));
331 const char *unit = NULL;
334 reply = systemd_send_recv(msg, NULL,
336 dbus_message_unref(msg);
338 unit = systemd_loadunit_result(reply, op);
340 munit = strdup(unit);
343 dbus_message_unref(reply);
348 pending = systemd_send(msg, systemd_loadunit_cb, op, op->
timeout);
350 services_set_op_pending(op, pending);
353 dbus_message_unref(msg);
362 DBusMessageIter args;
363 DBusMessageIter unit;
364 DBusMessageIter elem;
365 DBusMessage *reply = NULL;
367 if (systemd_init() == FALSE) {
377 reply = systemd_call_simple_method(
"ListUnits");
381 if (!dbus_message_iter_init(reply, &args)) {
382 crm_err(
"Could not list systemd units: systemd reply has no arguments");
383 dbus_message_unref(reply);
387 __FUNCTION__, __LINE__)) {
388 crm_err(
"Could not list systemd units: systemd reply has invalid arguments");
389 dbus_message_unref(reply);
393 dbus_message_iter_recurse(&args, &unit);
394 while (dbus_message_iter_get_arg_type (&unit) != DBUS_TYPE_INVALID) {
395 DBusBasicValue value;
401 dbus_message_iter_recurse(&unit, &elem);
406 dbus_message_iter_get_basic(&elem, &value);
407 crm_trace(
"DBus ListUnits listed: %s", value.str);
409 const char *match = systemd_unit_extension(value.str);
414 if (!strcmp(match,
".service")) {
416 unit_name =
strndup(value.str, match - value.str);
418 unit_name = strdup(value.str);
421 units = g_list_append(units, unit_name);
424 dbus_message_iter_next (&unit);
427 dbus_message_unref(reply);
429 crm_trace(
"Found %d systemd services", lpc);
441 unit = systemd_unit_by_name(name, NULL);
450 systemd_unit_metadata(
const char *name,
int timeout)
454 char *path = systemd_unit_by_name(name, NULL);
458 desc = systemd_get_property(path,
"Description", NULL, NULL, NULL,
465 "<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n"
466 "<resource-agent name=\"%s\" version=\"0.1\">\n"
467 " <version>1.0</version>\n"
468 " <longdesc lang=\"en\">\n"
471 " <shortdesc lang=\"en\">systemd unit file for %s</shortdesc>\n"
475 " <action name=\"start\" timeout=\"100\" />\n"
476 " <action name=\"stop\" timeout=\"100\" />\n"
477 " <action name=\"status\" timeout=\"100\" />\n"
478 " <action name=\"monitor\" timeout=\"100\" interval=\"60\"/>\n"
479 " <action name=\"meta-data\" timeout=\"5\" />\n"
481 " <special tag=\"systemd\">\n"
482 " </special>\n" "</resource-agent>\n", name, desc, name);
489 systemd_exec_result(DBusMessage *reply,
svc_action_t *op)
496 if (!systemd_mask_error(op, error.name)) {
497 crm_err(
"Could not issue %s for %s: %s", op->
action, op->
rsc, error.message);
499 dbus_error_free(&error);
503 crm_warn(
"Call to %s passed but return type was unexpected", op->
action);
507 const char *path = NULL;
509 dbus_message_get_args (reply, NULL,
510 DBUS_TYPE_OBJECT_PATH, &path,
521 systemd_async_dispatch(DBusPendingCall *pending,
void *user_data)
523 DBusMessage *reply = NULL;
527 reply = dbus_pending_call_steal_reply(pending);
533 services_set_op_pending(op, NULL);
534 systemd_exec_result(reply, op);
537 dbus_message_unref(reply);
541 #define SYSTEMD_OVERRIDE_ROOT "/run/systemd/system/"
544 systemd_unit_check(
const char *name,
const char *state,
void *userdata)
548 crm_trace(
"Resource %s has %s='%s'", op->
rsc, name, state);
553 }
else if (g_strcmp0(state,
"active") == 0) {
555 }
else if (g_strcmp0(state,
"activating") == 0) {
557 }
else if (g_strcmp0(state,
"deactivating") == 0) {
564 services_set_op_pending(op, NULL);
572 const char *method = op->
action;
573 DBusMessage *msg = NULL;
574 DBusMessage *reply = NULL;
579 DBusPendingCall *pending = NULL;
582 state = systemd_get_property(unit,
"ActiveState",
587 systemd_unit_check(
"ActiveState", state, op);
590 }
else if (pending) {
591 services_set_op_pending(op, pending);
598 }
else if (g_strcmp0(method,
"start") == 0) {
599 FILE *file_strm = NULL;
604 method =
"StartUnit";
610 orig_umask = umask(S_IWGRP | S_IWOTH);
611 file_strm = fopen(override_file,
"w");
614 if (file_strm != NULL) {
618 "Description=Cluster Controlled %s\n"
619 "Before=pacemaker.service\n"
625 int rc = fprintf(file_strm,
"%s\n",
override);
629 crm_perror(LOG_ERR,
"Cannot write to systemd override file %s", override_file);
633 crm_err(
"Cannot open systemd override file %s for writing", override_file);
636 if (file_strm != NULL) {
640 systemd_daemon_reload(op->
timeout);
644 }
else if (g_strcmp0(method,
"stop") == 0) {
648 unlink(override_file);
650 systemd_daemon_reload(op->
timeout);
652 }
else if (g_strcmp0(method,
"restart") == 0) {
653 method =
"RestartUnit";
660 crm_debug(
"Calling %s for %s: %s", method, op->
rsc, unit);
662 msg = systemd_new_method(method);
667 const char *replace_s =
"replace";
668 char *name = systemd_service_name(op->
agent);
670 CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID));
671 CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &replace_s, DBUS_TYPE_INVALID));
677 DBusPendingCall *pending = systemd_send(msg, systemd_async_dispatch,
680 dbus_message_unref(msg);
682 services_set_op_pending(op, pending);
690 reply = systemd_send_recv(msg, NULL, op->
timeout);
691 dbus_message_unref(msg);
692 systemd_exec_result(reply, op);
695 dbus_message_unref(reply);
709 systemd_timeout_callback(gpointer p)
730 crm_debug(
"Performing %ssynchronous %s op on systemd unit %s named '%s'",
744 unit = systemd_unit_by_name(op->
agent, op);
748 if (op->
opaque->pending) {
749 op->
opaque->timerid = g_timeout_add(op->
timeout + 5000, systemd_timeout_callback, op);
#define CRM_CHECK(expr, failure_action)
void crm_build_path(const char *path_c, mode_t mode)
Create a directory, including any parent directories needed.
void pcmk_dbus_disconnect(DBusConnection *connection)
#define DBUS_TIMEOUT_USE_DEFAULT
#define CRM_LOG_ASSERT(expr)
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
#define crm_debug(fmt, args...)
gboolean operation_finalize(svc_action_t *op)
gboolean systemd_unit_exists(const char *name)
#define crm_trace(fmt, args...)
char * pcmk_dbus_get_property(DBusConnection *connection, const char *target, const char *obj, const gchar *iface, const char *name, void(*callback)(const char *name, const char *value, void *userdata), void *userdata, DBusPendingCall **pending, int timeout)
#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)
void systemd_cleanup(void)
#define crm_perror(level, fmt, args...)
Log a system error message.
#define crm_err(fmt, args...)
bool pcmk_dbus_type_check(DBusMessage *msg, DBusMessageIter *field, int expected, const char *function, int line)
gboolean systemd_unit_exec_with_unit(svc_action_t *op, const char *unit)
#define safe_str_eq(a, b)
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
DBusMessage * pcmk_dbus_send_recv(DBusMessage *msg, DBusConnection *connection, DBusError *error, int timeout)
gboolean systemd_unit_exec(svc_action_t *op)
#define crm_info(fmt, args...)