pacemaker  2.1.7-0f7f88312f
Scalable High-Availability cluster resource manager
dbus.c
Go to the documentation of this file.
1 /*
2  * Copyright 2014-2022 the Pacemaker project contributors
3  *
4  * The version control history for this file may have further details.
5  *
6  * This source code is licensed under the GNU Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 #include <crm/crm.h>
12 #include <dbus/dbus.h>
13 #include <pcmk-dbus.h>
14 
15 /*
16  * DBus message dispatch
17  */
18 
19 // List of DBus connections (DBusConnection*) with messages available
20 static GList *conn_dispatches = NULL;
21 
36 static void
37 update_dispatch_status(DBusConnection *connection,
38  DBusDispatchStatus new_status, void *data)
39 {
40  if (new_status == DBUS_DISPATCH_DATA_REMAINS) {
41  crm_trace("DBus connection has messages available for dispatch");
42  conn_dispatches = g_list_prepend(conn_dispatches, connection);
43  } else {
44  crm_trace("DBus connection has no messages available for dispatch "
45  "(status %d)", new_status);
46  }
47 }
48 
53 static void
54 dispatch_messages(void)
55 {
56  for (GList *gIter = conn_dispatches; gIter != NULL; gIter = gIter->next) {
57  DBusConnection *connection = gIter->data;
58 
59  while (dbus_connection_get_dispatch_status(connection)
60  == DBUS_DISPATCH_DATA_REMAINS) {
61  crm_trace("Dispatching available messages on DBus connection");
62  dbus_connection_dispatch(connection);
63  }
64  }
65  g_list_free(conn_dispatches);
66  conn_dispatches = NULL;
67 }
68 
69 
70 /*
71  * DBus file descriptor watches
72  *
73  * The DBus library allows the caller to register functions for the library to
74  * use for file descriptor notifications via a main loop.
75  */
76 
77 /* Copied from dbus-watch.c */
78 static const char*
79 dbus_watch_flags_to_string(int flags)
80 {
81  const char *watch_type;
82 
83  if ((flags & DBUS_WATCH_READABLE) && (flags & DBUS_WATCH_WRITABLE)) {
84  watch_type = "read/write";
85  } else if (flags & DBUS_WATCH_READABLE) {
86  watch_type = "read";
87  } else if (flags & DBUS_WATCH_WRITABLE) {
88  watch_type = "write";
89  } else {
90  watch_type = "neither read nor write";
91  }
92  return watch_type;
93 }
94 
106 static int
107 dispatch_fd_data(gpointer userdata)
108 {
109  bool oom = FALSE;
110  DBusWatch *watch = userdata;
111  int flags = dbus_watch_get_flags(watch);
112  bool enabled = dbus_watch_get_enabled (watch);
113 
114  crm_trace("Dispatching DBus watch for file descriptor %d "
115  "with flags %#x (%s)",
116  dbus_watch_get_unix_fd(watch), flags,
117  dbus_watch_flags_to_string(flags));
118 
119  if (enabled && (flags & (DBUS_WATCH_READABLE|DBUS_WATCH_WRITABLE))) {
120  oom = !dbus_watch_handle(watch, flags);
121 
122  } else if (enabled) {
123  oom = !dbus_watch_handle(watch, DBUS_WATCH_ERROR);
124  }
125 
126  if (flags != dbus_watch_get_flags(watch)) {
127  flags = dbus_watch_get_flags(watch);
128  crm_trace("Dispatched DBus file descriptor watch: now %#x (%s)",
129  flags, dbus_watch_flags_to_string(flags));
130  }
131 
132  if (oom) {
133  crm_crit("Could not dispatch DBus file descriptor data: Out of memory");
134  } else {
135  dispatch_messages();
136  }
137  return 0;
138 }
139 
140 static void
141 watch_fd_closed(gpointer userdata)
142 {
143  crm_trace("DBus watch for file descriptor %d is now closed",
144  dbus_watch_get_unix_fd((DBusWatch *) userdata));
145 }
146 
147 static struct mainloop_fd_callbacks pcmk_dbus_cb = {
148  .dispatch = dispatch_fd_data,
149  .destroy = watch_fd_closed,
150 };
151 
152 static dbus_bool_t
153 add_dbus_watch(DBusWatch *watch, void *data)
154 {
155  int fd = dbus_watch_get_unix_fd(watch);
156 
157  mainloop_io_t *client = mainloop_add_fd("dbus", G_PRIORITY_DEFAULT, fd,
158  watch, &pcmk_dbus_cb);
159 
160  crm_trace("Added DBus watch for file descriptor %d", fd);
161  dbus_watch_set_data(watch, client, NULL);
162  return TRUE;
163 }
164 
165 static void
166 toggle_dbus_watch(DBusWatch *watch, void *data)
167 {
168  // @TODO Should this do something more?
169  crm_debug("DBus watch for file descriptor %d is now %s",
170  dbus_watch_get_unix_fd(watch),
171  (dbus_watch_get_enabled(watch)? "enabled" : "disabled"));
172 }
173 
174 static void
175 remove_dbus_watch(DBusWatch *watch, void *data)
176 {
177  crm_trace("Removed DBus watch for file descriptor %d",
178  dbus_watch_get_unix_fd(watch));
179  mainloop_del_fd((mainloop_io_t *) dbus_watch_get_data(watch));
180 }
181 
182 static void
183 register_watch_functions(DBusConnection *connection)
184 {
185  dbus_connection_set_watch_functions(connection, add_dbus_watch,
186  remove_dbus_watch,
187  toggle_dbus_watch, NULL, NULL);
188 }
189 
190 /*
191  * DBus main loop timeouts
192  *
193  * The DBus library allows the caller to register functions for the library to
194  * use for managing timers via a main loop.
195  */
196 
197 static gboolean
198 timer_popped(gpointer data)
199 {
200  crm_debug("%dms DBus timer expired",
201  dbus_timeout_get_interval((DBusTimeout *) data));
202  dbus_timeout_handle(data);
203  return FALSE;
204 }
205 
206 static dbus_bool_t
207 add_dbus_timer(DBusTimeout *timeout, void *data)
208 {
209  int interval_ms = dbus_timeout_get_interval(timeout);
210  guint id = g_timeout_add(interval_ms, timer_popped, timeout);
211 
212  if (id) {
213  dbus_timeout_set_data(timeout, GUINT_TO_POINTER(id), NULL);
214  }
215  crm_trace("Added %dms DBus timer", interval_ms);
216  return TRUE;
217 }
218 
219 static void
220 remove_dbus_timer(DBusTimeout *timeout, void *data)
221 {
222  void *vid = dbus_timeout_get_data(timeout);
223  guint id = GPOINTER_TO_UINT(vid);
224 
225  crm_trace("Removing %dms DBus timer", dbus_timeout_get_interval(timeout));
226  if (id) {
227  g_source_remove(id);
228  dbus_timeout_set_data(timeout, 0, NULL);
229  }
230 }
231 
232 static void
233 toggle_dbus_timer(DBusTimeout *timeout, void *data)
234 {
235  bool enabled = dbus_timeout_get_enabled(timeout);
236 
237  crm_trace("Toggling %dms DBus timer %s",
238  dbus_timeout_get_interval(timeout), (enabled? "off": "on"));
239  if (enabled) {
240  add_dbus_timer(timeout, data);
241  } else {
242  remove_dbus_timer(timeout, data);
243  }
244 }
245 
246 static void
247 register_timer_functions(DBusConnection *connection)
248 {
249  dbus_connection_set_timeout_functions(connection, add_dbus_timer,
250  remove_dbus_timer,
251  toggle_dbus_timer, NULL, NULL);
252 }
253 
254 /*
255  * General DBus utilities
256  */
257 
258 DBusConnection *
260 {
261  DBusError err;
262  DBusConnection *connection;
263 
264  dbus_error_init(&err);
265  connection = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
266  if (dbus_error_is_set(&err)) {
267  crm_err("Could not connect to DBus: %s", err.message);
268  dbus_error_free(&err);
269  return NULL;
270  }
271  if (connection == NULL) {
272  return NULL;
273  }
274 
275  /* Tell libdbus not to exit the process when a disconnect happens. This
276  * defaults to FALSE but is toggled on by the dbus_bus_get() call above.
277  */
278  dbus_connection_set_exit_on_disconnect(connection, FALSE);
279 
280  // Set custom handlers for various situations
281  register_timer_functions(connection);
282  register_watch_functions(connection);
283  dbus_connection_set_dispatch_status_function(connection,
284  update_dispatch_status,
285  NULL, NULL);
286 
287  // Call the dispatch function to check for any messages waiting already
288  update_dispatch_status(connection,
289  dbus_connection_get_dispatch_status(connection),
290  NULL);
291  return connection;
292 }
293 
294 void
295 pcmk_dbus_disconnect(DBusConnection *connection)
296 {
297  /* Per the DBus documentation, connections created with
298  * dbus_connection_open() are owned by libdbus and should never be closed.
299  *
300  * @TODO Should we call dbus_connection_unref() here?
301  */
302  return;
303 }
304 
305 // Custom DBus error names to use
306 #define ERR_NO_REQUEST "org.clusterlabs.pacemaker.NoRequest"
307 #define ERR_NO_REPLY "org.clusterlabs.pacemaker.NoReply"
308 #define ERR_INVALID_REPLY "org.clusterlabs.pacemaker.InvalidReply"
309 #define ERR_INVALID_REPLY_METHOD "org.clusterlabs.pacemaker.InvalidReply.Method"
310 #define ERR_INVALID_REPLY_SIGNAL "org.clusterlabs.pacemaker.InvalidReply.Signal"
311 #define ERR_INVALID_REPLY_TYPE "org.clusterlabs.pacemaker.InvalidReply.Type"
312 #define ERR_SEND_FAILED "org.clusterlabs.pacemaker.SendFailed"
313 
329 bool
330 pcmk_dbus_find_error(const DBusPendingCall *pending, DBusMessage *reply,
331  DBusError *ret)
332 {
333  DBusError error;
334 
335  dbus_error_init(&error);
336 
337  if (pending == NULL) {
338  dbus_set_error_const(&error, ERR_NO_REQUEST, "No request sent");
339 
340  } else if (reply == NULL) {
341  dbus_set_error_const(&error, ERR_NO_REPLY, "No reply");
342 
343  } else {
344  DBusMessageIter args;
345  int dtype = dbus_message_get_type(reply);
346 
347  switch (dtype) {
348  case DBUS_MESSAGE_TYPE_METHOD_RETURN:
349  {
350  char *sig = NULL;
351 
352  dbus_message_iter_init(reply, &args);
353  crm_trace("Received DBus reply with argument type '%s'",
354  (sig = dbus_message_iter_get_signature(&args)));
355  if (sig != NULL) {
356  dbus_free(sig);
357  }
358  }
359  break;
360  case DBUS_MESSAGE_TYPE_INVALID:
361  dbus_set_error_const(&error, ERR_INVALID_REPLY,
362  "Invalid reply");
363  break;
364  case DBUS_MESSAGE_TYPE_METHOD_CALL:
365  dbus_set_error_const(&error, ERR_INVALID_REPLY_METHOD,
366  "Invalid reply (method call)");
367  break;
368  case DBUS_MESSAGE_TYPE_SIGNAL:
369  dbus_set_error_const(&error, ERR_INVALID_REPLY_SIGNAL,
370  "Invalid reply (signal)");
371  break;
372  case DBUS_MESSAGE_TYPE_ERROR:
373  dbus_set_error_from_message(&error, reply);
374  break;
375  default:
376  dbus_set_error(&error, ERR_INVALID_REPLY_TYPE,
377  "Unknown reply type %d", dtype);
378  }
379  }
380 
381  if (dbus_error_is_set(&error)) {
382  crm_trace("DBus reply indicated error '%s' (%s)",
383  error.name, error.message);
384  if (ret) {
385  dbus_error_init(ret);
386  dbus_move_error(&error, ret);
387  } else {
388  dbus_error_free(&error);
389  }
390  return TRUE;
391  }
392 
393  return FALSE;
394 }
395 
411 DBusMessage *
412 pcmk_dbus_send_recv(DBusMessage *msg, DBusConnection *connection,
413  DBusError *error, int timeout)
414 {
415  const char *method = NULL;
416  DBusMessage *reply = NULL;
417  DBusPendingCall* pending = NULL;
418 
419  CRM_ASSERT(dbus_message_get_type (msg) == DBUS_MESSAGE_TYPE_METHOD_CALL);
420  method = dbus_message_get_member (msg);
421 
422  /* Ensure caller can reliably check whether error is set */
423  if (error) {
424  dbus_error_init(error);
425  }
426 
427  if (timeout <= 0) {
428  /* DBUS_TIMEOUT_USE_DEFAULT (-1) tells DBus to use a sane default */
430  }
431 
432  // send message and get a handle for a reply
433  if (!dbus_connection_send_with_reply(connection, msg, &pending, timeout)) {
434  if (error) {
435  dbus_set_error(error, ERR_SEND_FAILED,
436  "Could not queue DBus '%s' request", method);
437  }
438  return NULL;
439  }
440 
441  dbus_connection_flush(connection);
442 
443  if (pending) {
444  /* block until we receive a reply */
445  dbus_pending_call_block(pending);
446 
447  /* get the reply message */
448  reply = dbus_pending_call_steal_reply(pending);
449  }
450 
451  (void) pcmk_dbus_find_error(pending, reply, error);
452 
453  if (pending) {
454  /* free the pending message handle */
455  dbus_pending_call_unref(pending);
456  }
457 
458  return reply;
459 }
460 
475 DBusPendingCall *
476 pcmk_dbus_send(DBusMessage *msg, DBusConnection *connection,
477  void (*done)(DBusPendingCall *pending, void *user_data),
478  void *user_data, int timeout)
479 {
480  const char *method = NULL;
481  DBusPendingCall* pending = NULL;
482 
483  CRM_ASSERT(done);
484  CRM_ASSERT(dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_CALL);
485  method = dbus_message_get_member(msg);
486 
487  if (timeout <= 0) {
488  /* DBUS_TIMEOUT_USE_DEFAULT (-1) tells DBus to use a sane default */
490  }
491 
492  // send message and get a handle for a reply
493  if (!dbus_connection_send_with_reply(connection, msg, &pending, timeout)) {
494  crm_err("Could not send DBus %s message: failed", method);
495  return NULL;
496 
497  } else if (pending == NULL) {
498  crm_err("Could not send DBus %s message: connection may be closed",
499  method);
500  return NULL;
501  }
502 
503  if (dbus_pending_call_get_completed(pending)) {
504  crm_info("DBus %s message completed too soon", method);
505  /* Calling done() directly in this case instead of setting notify below
506  * breaks things
507  */
508  }
509  if (!dbus_pending_call_set_notify(pending, done, user_data, NULL)) {
510  return NULL;
511  }
512  return pending;
513 }
514 
515 bool
516 pcmk_dbus_type_check(DBusMessage *msg, DBusMessageIter *field, int expected,
517  const char *function, int line)
518 {
519  int dtype = 0;
520  DBusMessageIter lfield;
521 
522  if (field == NULL) {
523  if (dbus_message_iter_init(msg, &lfield)) {
524  field = &lfield;
525  }
526  }
527 
528  if (field == NULL) {
529  do_crm_log_alias(LOG_INFO, __FILE__, function, line,
530  "DBus reply has empty parameter list (expected '%c')",
531  expected);
532  return FALSE;
533  }
534 
535  dtype = dbus_message_iter_get_arg_type(field);
536 
537  if (dtype != expected) {
538  DBusMessageIter args;
539  char *sig;
540 
541  dbus_message_iter_init(msg, &args);
542  sig = dbus_message_iter_get_signature(&args);
543  do_crm_log_alias(LOG_INFO, __FILE__, function, line,
544  "DBus reply has unexpected type "
545  "(expected '%c' not '%c' in '%s')",
546  expected, dtype, sig);
547  dbus_free(sig);
548  return FALSE;
549  }
550 
551  return TRUE;
552 }
553 
554 
555 /*
556  * Property queries
557  */
558 
559 /* DBus APIs often provide queryable properties that use this standard
560  * interface. See:
561  * https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties
562  */
563 #define BUS_PROPERTY_IFACE "org.freedesktop.DBus.Properties"
564 
565 // Callback prototype for when a DBus property query result is received
566 typedef void (*property_callback_func)(const char *name, // Property name
567  const char *value, // Property value
568  void *userdata); // Caller-provided data
569 
570 // Data needed by DBus property queries
571 struct property_query {
572  char *name; // Property name being queried
573  char *target; // Name of DBus bus that query should be sent to
574  char *object; // DBus object path for object with the property
575  void *userdata; // Caller-provided data to supply to callback
576  property_callback_func callback; // Function to call when result is received
577 };
578 
579 static void
580 free_property_query(struct property_query *data)
581 {
582  free(data->target);
583  free(data->object);
584  free(data->name);
585  free(data);
586 }
587 
588 static char *
589 handle_query_result(DBusMessage *reply, struct property_query *data)
590 {
591  DBusError error;
592  char *output = NULL;
593  DBusMessageIter args;
594  DBusMessageIter variant_iter;
595  DBusBasicValue value;
596 
597  dbus_error_init(&error);
598 
599  // First, check if the reply contains an error
600  if (pcmk_dbus_find_error((void*)&error, reply, &error)) {
601  crm_err("DBus query for %s property '%s' failed: %s",
602  data->object, data->name, error.message);
603  dbus_error_free(&error);
604  goto cleanup;
605  }
606 
607  // The lone output argument should be a DBus variant type
608  dbus_message_iter_init(reply, &args);
609  if (!pcmk_dbus_type_check(reply, &args, DBUS_TYPE_VARIANT,
610  __func__, __LINE__)) {
611  crm_err("DBus query for %s property '%s' failed: Unexpected reply type",
612  data->object, data->name);
613  goto cleanup;
614  }
615 
616  // The variant should be a string
617  dbus_message_iter_recurse(&args, &variant_iter);
618  if (!pcmk_dbus_type_check(reply, &variant_iter, DBUS_TYPE_STRING,
619  __func__, __LINE__)) {
620  crm_err("DBus query for %s property '%s' failed: "
621  "Unexpected variant type", data->object, data->name);
622  goto cleanup;
623  }
624  dbus_message_iter_get_basic(&variant_iter, &value);
625 
626  // There should be no more arguments (in variant or reply)
627  dbus_message_iter_next(&variant_iter);
628  if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_INVALID) {
629  crm_err("DBus query for %s property '%s' failed: "
630  "Too many arguments in reply",
631  data->object, data->name);
632  goto cleanup;
633  }
634  dbus_message_iter_next(&args);
635  if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_INVALID) {
636  crm_err("DBus query for %s property '%s' failed: "
637  "Too many arguments in reply", data->object, data->name);
638  goto cleanup;
639  }
640 
641  crm_trace("DBus query result for %s: %s='%s'",
642  data->object, data->name, (value.str? value.str : ""));
643 
644  if (data->callback) { // Query was asynchronous
645  data->callback(data->name, (value.str? value.str : ""), data->userdata);
646 
647  } else { // Query was synchronous
648  output = strdup(value.str? value.str : "");
649  }
650 
651  cleanup:
652  free_property_query(data);
653  return output;
654 }
655 
656 static void
657 async_query_result_cb(DBusPendingCall *pending, void *user_data)
658 {
659  DBusMessage *reply = NULL;
660  char *value = NULL;
661 
662  if (pending) {
663  reply = dbus_pending_call_steal_reply(pending);
664  }
665 
666  value = handle_query_result(reply, user_data);
667  free(value);
668 
669  if (reply) {
670  dbus_message_unref(reply);
671  }
672 }
673 
694 char *
695 pcmk_dbus_get_property(DBusConnection *connection, const char *target,
696  const char *obj, const gchar * iface, const char *name,
697  property_callback_func callback, void *userdata,
698  DBusPendingCall **pending, int timeout)
699 {
700  DBusMessage *msg;
701  char *output = NULL;
702  struct property_query *query_data = NULL;
703 
704  CRM_CHECK((connection != NULL) && (target != NULL) && (obj != NULL)
705  && (iface != NULL) && (name != NULL), return NULL);
706 
707  crm_trace("Querying DBus %s for %s property '%s'",
708  target, obj, name);
709 
710  // Create a new message to use to invoke method
711  msg = dbus_message_new_method_call(target, obj, BUS_PROPERTY_IFACE, "Get");
712  if (msg == NULL) {
713  crm_err("DBus query for %s property '%s' failed: "
714  "Unable to create message", obj, name);
715  return NULL;
716  }
717 
718  // Add the interface name and property name as message arguments
719  if (!dbus_message_append_args(msg,
720  DBUS_TYPE_STRING, &iface,
721  DBUS_TYPE_STRING, &name,
722  DBUS_TYPE_INVALID)) {
723  crm_err("DBus query for %s property '%s' failed: "
724  "Could not append arguments", obj, name);
725  dbus_message_unref(msg);
726  return NULL;
727  }
728 
729  query_data = malloc(sizeof(struct property_query));
730  if (query_data == NULL) {
731  crm_crit("DBus query for %s property '%s' failed: Out of memory",
732  obj, name);
733  dbus_message_unref(msg);
734  return NULL;
735  }
736 
737  query_data->target = strdup(target);
738  query_data->object = strdup(obj);
739  query_data->callback = callback;
740  query_data->userdata = userdata;
741  query_data->name = strdup(name);
742  CRM_CHECK((query_data->target != NULL)
743  && (query_data->object != NULL)
744  && (query_data->name != NULL),
745  free_property_query(query_data);
746  dbus_message_unref(msg);
747  return NULL);
748 
749  if (query_data->callback) { // Asynchronous
750  DBusPendingCall *local_pending;
751 
752  local_pending = pcmk_dbus_send(msg, connection, async_query_result_cb,
753  query_data, timeout);
754  if (local_pending == NULL) {
755  // async_query_result_cb() was not called in this case
756  free_property_query(query_data);
757  query_data = NULL;
758  }
759 
760  if (pending) {
761  *pending = local_pending;
762  }
763 
764  } else { // Synchronous
765  DBusMessage *reply = pcmk_dbus_send_recv(msg, connection, NULL,
766  timeout);
767 
768  output = handle_query_result(reply, query_data);
769 
770  if (reply) {
771  dbus_message_unref(reply);
772  }
773  }
774 
775  dbus_message_unref(msg);
776 
777  return output;
778 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:238
A dumping ground.
void(* property_callback_func)(const char *name, const char *value, void *userdata)
Definition: dbus.c:566
#define ERR_INVALID_REPLY_SIGNAL
Definition: dbus.c:310
#define crm_crit(fmt, args...)
Definition: logging.h:380
char data[0]
Definition: cpg.c:55
mainloop_io_t * mainloop_add_fd(const char *name, int priority, int fd, void *userdata, struct mainloop_fd_callbacks *callbacks)
Definition: mainloop.c:959
const char * name
Definition: cib.c:26
#define BUS_PROPERTY_IFACE
Definition: dbus.c:563
#define ERR_INVALID_REPLY_TYPE
Definition: dbus.c:311
void pcmk_dbus_disconnect(DBusConnection *connection)
Definition: dbus.c:295
#define DBUS_TIMEOUT_USE_DEFAULT
Definition: pcmk-dbus.h:16
struct mainloop_io_s mainloop_io_t
Definition: mainloop.h:33
#define do_crm_log_alias(level, file, function, line, fmt, args...)
Log a message as if it came from a different code location.
Definition: logging.h:293
#define ERR_NO_REPLY
Definition: dbus.c:307
int(* dispatch)(gpointer userdata)
Dispatch function for mainloop file descriptor with data ready.
Definition: mainloop.h:138
#define ERR_SEND_FAILED
Definition: dbus.c:312
#define crm_debug(fmt, args...)
Definition: logging.h:386
#define crm_trace(fmt, args...)
Definition: logging.h:387
DBusPendingCall * pcmk_dbus_send(DBusMessage *msg, DBusConnection *connection, void(*done)(DBusPendingCall *pending, void *user_data), void *user_data, int timeout)
Definition: dbus.c:476
DBusConnection * pcmk_dbus_connect(void)
Definition: dbus.c:259
const char * target
Definition: pcmk_fence.c:29
#define ERR_INVALID_REPLY_METHOD
Definition: dbus.c:309
#define crm_err(fmt, args...)
Definition: logging.h:381
#define CRM_ASSERT(expr)
Definition: results.h:42
bool pcmk_dbus_type_check(DBusMessage *msg, DBusMessageIter *field, int expected, const char *function, int line)
Definition: dbus.c:516
void mainloop_del_fd(mainloop_io_t *client)
Definition: mainloop.c:1003
#define ERR_INVALID_REPLY
Definition: dbus.c:308
bool pcmk_dbus_find_error(const DBusPendingCall *pending, DBusMessage *reply, DBusError *ret)
Definition: dbus.c:330
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)
Definition: dbus.c:695
unsigned int timeout
Definition: pcmk_fence.c:32
DBusMessage * pcmk_dbus_send_recv(DBusMessage *msg, DBusConnection *connection, DBusError *error, int timeout)
Definition: dbus.c:412
#define crm_info(fmt, args...)
Definition: logging.h:384
uint64_t flags
Definition: remote.c:215
#define ERR_NO_REQUEST
Definition: dbus.c:306