28 #include <dbus/dbus.h>
31 #define BUS_NAME "org.freedesktop.systemd1"
32 #define BUS_PATH "/org/freedesktop/systemd1"
34 #define BUS_PROPERTY_IFACE "org.freedesktop.DBus.Properties"
45 const char *description;
46 const char *load_state;
47 const char *active_state;
48 const char *sub_state;
49 const char *following;
50 const char *unit_path;
65 static DBusMessage *systemd_new_method(
const char *iface,
const char *method)
67 crm_trace(
"Calling: %s on %s", method, iface);
68 return dbus_message_new_method_call(
BUS_NAME,
75 static DBusConnection* systemd_proxy = NULL;
79 static int need_init = 1;
83 && dbus_connection_get_is_connected(systemd_proxy) == FALSE) {
84 crm_warn(
"Connection to System DBus is closed. Reconnecting...");
94 if (systemd_proxy == NULL) {
105 systemd_proxy = NULL;
110 systemd_service_name(
const char *name)
115 }
else if (strstr(name,
".service")) {
123 systemd_daemon_reload_complete(DBusPendingCall *pending,
void *user_data)
126 DBusMessage *reply = NULL;
127 unsigned int reload_count = GPOINTER_TO_UINT(user_data);
129 dbus_error_init(&error);
131 reply = dbus_pending_call_steal_reply(pending);
135 crm_err(
"Could not issue systemd reload %d: %s", reload_count, error.message);
138 crm_trace(
"Reload %d complete", reload_count);
142 dbus_pending_call_unref(pending);
145 dbus_message_unref(reply);
150 systemd_daemon_reload(
int timeout)
152 static unsigned int reload_count = 0;
153 const char *method =
"Reload";
154 DBusMessage *msg = systemd_new_method(
BUS_NAME".Manager", method);
158 pcmk_dbus_send(msg, systemd_proxy, systemd_daemon_reload_complete, GUINT_TO_POINTER(reload_count), timeout);
159 dbus_message_unref(msg);
168 if(strstr(error,
"org.freedesktop.systemd1.InvalidName")
169 || strstr(error,
"org.freedesktop.systemd1.LoadFailed")
170 || strstr(error,
"org.freedesktop.systemd1.NoSuchUnit")) {
173 crm_trace(
"Masking %s failure for %s: unknown services are stopped", op->
action, op->
rsc);
178 crm_trace(
"Mapping %s failure for %s: unknown services are not installed", op->
action, op->
rsc);
189 systemd_loadunit_result(DBusMessage *reply,
svc_action_t * op)
191 const char *path = NULL;
195 if(op && !systemd_mask_error(op, error.name)) {
196 crm_err(
"Could not find unit %s for %s: LoadUnit error '%s'",
197 op->
agent, op->
id, error.name);
201 dbus_message_get_args (reply, NULL,
202 DBUS_TYPE_OBJECT_PATH, &path,
220 systemd_loadunit_cb(DBusPendingCall *pending,
void *user_data)
222 DBusMessage *reply = NULL;
226 reply = dbus_pending_call_steal_reply(pending);
229 crm_trace(
"Got result: %p for %p / %p for %s", reply, pending, op->
opaque->pending, op->
id);
232 services_set_op_pending(op, NULL);
234 systemd_loadunit_result(reply, user_data);
237 dbus_message_unref(reply);
242 systemd_unit_by_name(
const gchar * arg_name,
svc_action_t *op)
245 DBusMessage *reply = NULL;
246 DBusPendingCall* pending = NULL;
257 if (systemd_init() == FALSE) {
261 msg = systemd_new_method(
BUS_NAME".Manager",
"LoadUnit");
264 name = systemd_service_name(arg_name);
265 CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID));
269 const char *unit = NULL;
273 dbus_error_init(&error);
275 dbus_message_unref(msg);
277 unit = systemd_loadunit_result(reply, op);
279 munit = strdup(unit);
282 dbus_message_unref(reply);
289 services_set_op_pending(op, pending);
292 dbus_message_unref(msg);
301 DBusMessageIter args;
302 DBusMessageIter unit;
303 DBusMessageIter elem;
304 DBusMessage *msg = NULL;
305 DBusMessage *reply = NULL;
306 const char *method =
"ListUnits";
309 if (systemd_init() == FALSE) {
319 dbus_error_init(&error);
320 msg = systemd_new_method(
BUS_NAME".Manager", method);
324 dbus_message_unref(msg);
327 crm_err(
"Call to %s failed: %s", method, error.name);
330 }
else if (reply == NULL) {
331 crm_err(
"Call to %s failed: Message has no reply", method);
334 }
else if (!dbus_message_iter_init(reply, &args)) {
335 crm_err(
"Call to %s failed: Message has no arguments", method);
336 dbus_message_unref(reply);
341 crm_err(
"Call to %s failed: Message has invalid arguments", method);
342 dbus_message_unref(reply);
346 dbus_message_iter_recurse(&args, &unit);
347 while (dbus_message_iter_get_arg_type (&unit) != DBUS_TYPE_INVALID) {
348 DBusBasicValue value;
354 dbus_message_iter_recurse(&unit, &elem);
359 dbus_message_iter_get_basic(&elem, &value);
362 char *match = strstr(value.str,
".service");
368 units = g_list_append(units, strdup(value.str));
371 dbus_message_iter_next (&unit);
374 dbus_message_unref(reply);
376 crm_trace(
"Found %d systemd services", lpc);
388 unit = systemd_unit_by_name(name, NULL);
397 systemd_unit_metadata(
const char *name,
int timeout)
401 char *path = systemd_unit_by_name(name, NULL);
411 "<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n"
412 "<resource-agent name=\"%s\" version=\"0.1\">\n"
413 " <version>1.0</version>\n"
414 " <longdesc lang=\"en\">\n"
417 " <shortdesc lang=\"en\">systemd unit file for %s</shortdesc>\n"
421 " <action name=\"start\" timeout=\"100\" />\n"
422 " <action name=\"stop\" timeout=\"100\" />\n"
423 " <action name=\"status\" timeout=\"100\" />\n"
424 " <action name=\"monitor\" timeout=\"100\" interval=\"60\"/>\n"
425 " <action name=\"meta-data\" timeout=\"5\" />\n"
427 " <special tag=\"systemd\">\n"
428 " </special>\n" "</resource-agent>\n", name, desc, name);
435 systemd_exec_result(DBusMessage *reply,
svc_action_t *op)
442 if (!systemd_mask_error(op, error.name)) {
443 crm_err(
"Could not issue %s for %s: %s", op->
action, op->
rsc, error.message);
448 crm_warn(
"Call to %s passed but return type was unexpected", op->
action);
452 const char *path = NULL;
454 dbus_message_get_args (reply, NULL,
455 DBUS_TYPE_OBJECT_PATH, &path,
466 systemd_async_dispatch(DBusPendingCall *pending,
void *user_data)
469 DBusMessage *reply = NULL;
472 dbus_error_init(&error);
474 reply = dbus_pending_call_steal_reply(pending);
480 services_set_op_pending(op, NULL);
481 systemd_exec_result(reply, op);
484 dbus_message_unref(reply);
488 #define SYSTEMD_OVERRIDE_ROOT "/run/systemd/system/"
491 systemd_unit_check(
const char *name,
const char *state,
void *userdata)
495 crm_trace(
"Resource %s has %s='%s'", op->
rsc, name, state);
500 }
else if (g_strcmp0(state,
"active") == 0) {
502 }
else if (g_strcmp0(state,
"activating") == 0) {
504 }
else if (g_strcmp0(state,
"deactivating") == 0) {
511 services_set_op_pending(op, NULL);
519 const char *method = op->
action;
520 DBusMessage *msg = NULL;
521 DBusMessage *reply = NULL;
526 DBusPendingCall *pending = NULL;
534 systemd_unit_check(
"ActiveState", state, op);
537 }
else if (pending) {
538 services_set_op_pending(op, pending);
545 }
else if (g_strcmp0(method,
"start") == 0) {
546 FILE *file_strm = NULL;
551 method =
"StartUnit";
557 orig_umask = umask(S_IWGRP | S_IWOTH);
558 file_strm = fopen(override_file,
"w");
561 if (file_strm != NULL) {
565 "Description=Cluster Controlled %s\n"
566 "Before=pacemaker.service\n"
572 int rc = fprintf(file_strm,
"%s\n",
override);
576 crm_perror(LOG_ERR,
"Cannot write to systemd override file %s", override_file);
580 crm_err(
"Cannot open systemd override file %s for writing", override_file);
583 if (file_strm != NULL) {
587 systemd_daemon_reload(op->
timeout);
591 }
else if (g_strcmp0(method,
"stop") == 0) {
595 unlink(override_file);
597 systemd_daemon_reload(op->
timeout);
599 }
else if (g_strcmp0(method,
"restart") == 0) {
600 method =
"RestartUnit";
607 crm_debug(
"Calling %s for %s: %s", method, op->
rsc, unit);
609 msg = systemd_new_method(
BUS_NAME".Manager", method);
614 const char *replace_s =
"replace";
615 char *name = systemd_service_name(op->
agent);
617 CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID));
618 CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &replace_s, DBUS_TYPE_INVALID));
624 DBusPendingCall* pending =
pcmk_dbus_send(msg, systemd_proxy, systemd_async_dispatch, op, op->
timeout);
626 dbus_message_unref(msg);
628 services_set_op_pending(op, pending);
639 dbus_message_unref(msg);
640 systemd_exec_result(reply, op);
643 dbus_message_unref(reply);
657 systemd_timeout_callback(gpointer p)
678 crm_debug(
"Performing %ssynchronous %s op on systemd unit %s named '%s'",
692 unit = systemd_unit_by_name(op->
agent, op);
696 if (op->
opaque->pending) {
697 op->
opaque->timerid = g_timeout_add(op->
timeout + 5000, systemd_timeout_callback, op);
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.
#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...)
bool pcmk_dbus_find_error(const char *method, DBusPendingCall *pending, DBusMessage *reply, DBusError *ret)