pacemaker  2.1.2-ada5c3b36
Scalable High-Availability cluster resource manager
dbus.c
Go to the documentation of this file.
1 /*
2  * Copyright 2014-2021 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 0x%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 0x%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(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  // First, check if the reply contains an error
598  if (pcmk_dbus_find_error((void*)&error, reply, &error)) {
599  crm_err("DBus query for %s property '%s' failed: %s",
600  data->object, data->name, error.message);
601  dbus_error_free(&error);
602  goto cleanup;
603  }
604 
605  // The lone output argument should be a DBus variant type
606  dbus_message_iter_init(reply, &args);
607  if (!pcmk_dbus_type_check(reply, &args, DBUS_TYPE_VARIANT,
608  __func__, __LINE__)) {
609  crm_err("DBus query for %s property '%s' failed: Unexpected reply type",
610  data->object, data->name);
611  goto cleanup;
612  }
613 
614  // The variant should be a string
615  dbus_message_iter_recurse(&args, &variant_iter);
616  if (!pcmk_dbus_type_check(reply, &variant_iter, DBUS_TYPE_STRING,
617  __func__, __LINE__)) {
618  crm_err("DBus query for %s property '%s' failed: "
619  "Unexpected variant type", data->object, data->name);
620  goto cleanup;
621  }
622  dbus_message_iter_get_basic(&variant_iter, &value);
623 
624  // There should be no more arguments (in variant or reply)
625  dbus_message_iter_next(&variant_iter);
626  if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_INVALID) {
627  crm_err("DBus query for %s property '%s' failed: "
628  "Too many arguments in reply",
629  data->object, data->name);
630  goto cleanup;
631  }
632  dbus_message_iter_next(&args);
633  if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_INVALID) {
634  crm_err("DBus query for %s property '%s' failed: "
635  "Too many arguments in reply", data->object, data->name);
636  goto cleanup;
637  }
638 
639  crm_trace("DBus query result for %s: %s='%s'",
640  data->object, data->name, (value.str? value.str : ""));
641 
642  if (data->callback) { // Query was asynchronous
643  data->callback(data->name, (value.str? value.str : ""), data->userdata);
644 
645  } else { // Query was synchronous
646  output = strdup(value.str? value.str : "");
647  }
648 
649  cleanup:
650  free_property_query(data);
651  return output;
652 }
653 
654 static void
655 async_query_result_cb(DBusPendingCall *pending, void *user_data)
656 {
657  DBusMessage *reply = NULL;
658  char *value = NULL;
659 
660  if (pending) {
661  reply = dbus_pending_call_steal_reply(pending);
662  }
663 
664  value = handle_query_result(reply, user_data);
665  free(value);
666 
667  if (reply) {
668  dbus_message_unref(reply);
669  }
670 }
671 
692 char *
693 pcmk_dbus_get_property(DBusConnection *connection, const char *target,
694  const char *obj, const gchar * iface, const char *name,
695  property_callback_func callback, void *userdata,
696  DBusPendingCall **pending, int timeout)
697 {
698  DBusMessage *msg;
699  char *output = NULL;
700  struct property_query *query_data = NULL;
701 
702  CRM_CHECK((connection != NULL) && (target != NULL) && (obj != NULL)
703  && (iface != NULL) && (name != NULL), return NULL);
704 
705  crm_trace("Querying DBus %s for %s property '%s'",
706  target, obj, name);
707 
708  // Create a new message to use to invoke method
709  msg = dbus_message_new_method_call(target, obj, BUS_PROPERTY_IFACE, "Get");
710  if (msg == NULL) {
711  crm_err("DBus query for %s property '%s' failed: "
712  "Unable to create message", obj, name);
713  return NULL;
714  }
715 
716  // Add the interface name and property name as message arguments
717  if (!dbus_message_append_args(msg,
718  DBUS_TYPE_STRING, &iface,
719  DBUS_TYPE_STRING, &name,
720  DBUS_TYPE_INVALID)) {
721  crm_err("DBus query for %s property '%s' failed: "
722  "Could not append arguments", obj, name);
723  dbus_message_unref(msg);
724  return NULL;
725  }
726 
727  query_data = malloc(sizeof(struct property_query));
728  if (query_data == NULL) {
729  crm_crit("DBus query for %s property '%s' failed: Out of memory",
730  obj, name);
731  dbus_message_unref(msg);
732  return NULL;
733  }
734 
735  query_data->target = strdup(target);
736  query_data->object = strdup(obj);
737  query_data->callback = callback;
738  query_data->userdata = userdata;
739  query_data->name = strdup(name);
740  CRM_CHECK((query_data->target != NULL)
741  && (query_data->object != NULL)
742  && (query_data->name != NULL),
743  free_property_query(query_data);
744  dbus_message_unref(msg);
745  return NULL);
746 
747  if (query_data->callback) { // Asynchronous
748  DBusPendingCall *local_pending;
749 
750  local_pending = pcmk_dbus_send(msg, connection, async_query_result_cb,
751  query_data, timeout);
752  if (local_pending == NULL) {
753  // async_query_result_cb() was not called in this case
754  free_property_query(query_data);
755  query_data = NULL;
756  }
757 
758  if (pending) {
759  *pending = local_pending;
760  }
761 
762  } else { // Synchronous
763  DBusMessage *reply = pcmk_dbus_send_recv(msg, connection, NULL,
764  timeout);
765 
766  output = handle_query_result(reply, query_data);
767 
768  if (reply) {
769  dbus_message_unref(reply);
770  }
771  }
772 
773  dbus_message_unref(msg);
774 
775  return output;
776 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:225
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:356
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:975
#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:32
#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:280
bool pcmk_dbus_find_error(DBusPendingCall *pending, DBusMessage *reply, DBusError *ret)
Definition: dbus.c:330
#define ERR_NO_REPLY
Definition: dbus.c:307
int(* dispatch)(gpointer userdata)
Dispatch function for mainloop file descriptor with data ready.
Definition: mainloop.h:137
#define ERR_SEND_FAILED
Definition: dbus.c:312
#define crm_debug(fmt, args...)
Definition: logging.h:362
#define crm_trace(fmt, args...)
Definition: logging.h:363
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:357
#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:1019
#define ERR_INVALID_REPLY
Definition: dbus.c:308
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:693
char * name
Definition: pcmk_fence.c:31
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:360
uint64_t flags
Definition: remote.c:149
#define ERR_NO_REQUEST
Definition: dbus.c:306