root/lib/services/dbus.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pcmk_dbus_connect
  2. pcmk_dbus_disconnect
  3. pcmk_dbus_find_error
  4. pcmk_dbus_send_recv
  5. pcmk_dbus_send
  6. pcmk_dbus_type_check
  7. pcmk_dbus_lookup_result
  8. pcmk_dbus_lookup_cb
  9. pcmk_dbus_get_property
  10. pcmk_dbus_connection_dispatch_status
  11. pcmk_dbus_connections_dispatch
  12. dbus_watch_flags_to_string
  13. pcmk_dbus_watch_dispatch
  14. pcmk_dbus_watch_destroy
  15. pcmk_dbus_watch_add
  16. pcmk_dbus_watch_toggle
  17. pcmk_dbus_watch_remove
  18. pcmk_dbus_timeout_dispatch
  19. pcmk_dbus_timeout_add
  20. pcmk_dbus_timeout_remove
  21. pcmk_dbus_timeout_toggle
  22. pcmk_dbus_connection_setup_with_select

   1 /*
   2  * Copyright (C) 2014-2016 Andrew Beekhof <andrew@beekhof.net>
   3  *
   4  * This source code is licensed under the GNU Lesser General Public License
   5  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
   6  */
   7 
   8 #include <crm_internal.h>
   9 #include <crm/crm.h>
  10 #include <crm/services.h>
  11 #include <dbus/dbus.h>
  12 #include <pcmk-dbus.h>
  13 
  14 #define BUS_PROPERTY_IFACE "org.freedesktop.DBus.Properties"
  15 
  16 static GList *conn_dispatches = NULL;
  17 
  18 struct db_getall_data {
  19     char *name;
  20     char *target;
  21     char *object;
  22     void *userdata;
  23     void (*callback)(const char *name, const char *value, void *userdata);
  24 };
  25 
  26 DBusConnection *
  27 pcmk_dbus_connect(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  28 {
  29     DBusError err;
  30     DBusConnection *connection;
  31 
  32     dbus_error_init(&err);
  33     connection = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
  34     if (dbus_error_is_set(&err)) {
  35         crm_err("Could not connect to System DBus: %s", err.message);
  36         dbus_error_free(&err);
  37         return NULL;
  38     }
  39     if(connection) {
  40         pcmk_dbus_connection_setup_with_select(connection);
  41     }
  42     return connection;
  43 }
  44 
  45 void
  46 pcmk_dbus_disconnect(DBusConnection *connection)
     /* [previous][next][first][last][top][bottom][index][help] */
  47 {
  48     return;
  49 }
  50 
  51 /*!
  52  * \internal
  53  * \brief Check whether a DBus reply indicates an error occurred
  54  *
  55  * \param[in]  pending If non-NULL, indicates that a DBus request was sent
  56  * \param[in]  reply   Reply received from DBus
  57  * \param[out] ret     If non-NULL, will be set to DBus error, if any
  58  *
  59  * \return TRUE if an error was found, FALSE otherwise
  60  *
  61  * \note Following the DBus API convention, a TRUE return is exactly equivalent
  62  *       to ret being set. If ret is provided and this function returns TRUE,
  63  *       the caller is responsible for calling dbus_error_free() on ret when
  64  *       done using it.
  65  */
  66 bool
  67 pcmk_dbus_find_error(DBusPendingCall *pending, DBusMessage *reply,
     /* [previous][next][first][last][top][bottom][index][help] */
  68                      DBusError *ret)
  69 {
  70     DBusError error;
  71 
  72     dbus_error_init(&error);
  73 
  74     if(pending == NULL) {
  75         dbus_set_error_const(&error, "org.clusterlabs.pacemaker.NoRequest",
  76                              "No request sent");
  77 
  78     } else if(reply == NULL) {
  79         dbus_set_error_const(&error, "org.clusterlabs.pacemaker.NoReply",
  80                              "No reply");
  81 
  82     } else {
  83         DBusMessageIter args;
  84         int dtype = dbus_message_get_type(reply);
  85         char *sig;
  86 
  87         switch(dtype) {
  88             case DBUS_MESSAGE_TYPE_METHOD_RETURN:
  89                 dbus_message_iter_init(reply, &args);
  90                 sig = dbus_message_iter_get_signature(&args);
  91                 crm_trace("DBus call returned output args '%s'", sig);
  92                 dbus_free(sig);
  93                 break;
  94             case DBUS_MESSAGE_TYPE_INVALID:
  95                 dbus_set_error_const(&error,
  96                                      "org.clusterlabs.pacemaker.InvalidReply",
  97                                      "Invalid reply");
  98                 break;
  99             case DBUS_MESSAGE_TYPE_METHOD_CALL:
 100                 dbus_set_error_const(&error,
 101                                      "org.clusterlabs.pacemaker.InvalidReply.Method",
 102                                      "Invalid reply (method call)");
 103                 break;
 104             case DBUS_MESSAGE_TYPE_SIGNAL:
 105                 dbus_set_error_const(&error,
 106                                      "org.clusterlabs.pacemaker.InvalidReply.Signal",
 107                                      "Invalid reply (signal)");
 108                 break;
 109             case DBUS_MESSAGE_TYPE_ERROR:
 110                 dbus_set_error_from_message(&error, reply);
 111                 break;
 112             default:
 113                 dbus_set_error(&error,
 114                                "org.clusterlabs.pacemaker.InvalidReply.Type",
 115                                "Unknown reply type %d", dtype);
 116         }
 117     }
 118 
 119     if (dbus_error_is_set(&error)) {
 120         crm_trace("DBus reply indicated error '%s' (%s)",
 121                   error.name, error.message);
 122         if (ret) {
 123             dbus_error_init(ret);
 124             dbus_move_error(&error, ret);
 125         } else {
 126             dbus_error_free(&error);
 127         }
 128         return TRUE;
 129     }
 130 
 131     return FALSE;
 132 }
 133 
 134 /*!
 135  * \internal
 136  * \brief Send a DBus request and wait for the reply
 137  *
 138  * \param[in]  msg         DBus request to send
 139  * \param[in]  connection  DBus connection to use
 140  * \param[out] error       If non-NULL, will be set to error, if any
 141  * \param[in]  timeout     Timeout to use for request
 142  *
 143  * \return DBus reply
 144  *
 145  * \note If error is non-NULL, it is initialized, so the caller may always use
 146  *       dbus_error_is_set() to determine whether an error occurred; the caller
 147  *       is responsible for calling dbus_error_free() in this case.
 148  */
 149 DBusMessage *
 150 pcmk_dbus_send_recv(DBusMessage *msg, DBusConnection *connection,
     /* [previous][next][first][last][top][bottom][index][help] */
 151                     DBusError *error, int timeout)
 152 {
 153     const char *method = NULL;
 154     DBusMessage *reply = NULL;
 155     DBusPendingCall* pending = NULL;
 156 
 157     CRM_ASSERT(dbus_message_get_type (msg) == DBUS_MESSAGE_TYPE_METHOD_CALL);
 158     method = dbus_message_get_member (msg);
 159 
 160     /* Ensure caller can reliably check whether error is set */
 161     if (error) {
 162         dbus_error_init(error);
 163     }
 164 
 165     if (timeout <= 0) {
 166         /* DBUS_TIMEOUT_USE_DEFAULT (-1) tells DBus to use a sane default */
 167         timeout = DBUS_TIMEOUT_USE_DEFAULT;
 168     }
 169 
 170     // send message and get a handle for a reply
 171     if (!dbus_connection_send_with_reply(connection, msg, &pending, timeout)) {
 172         if(error) {
 173             dbus_set_error(error, "org.clusterlabs.pacemaker.SendFailed",
 174                            "Could not queue DBus '%s' request", method);
 175         }
 176         return NULL;
 177     }
 178 
 179     dbus_connection_flush(connection);
 180 
 181     if(pending) {
 182         /* block until we receive a reply */
 183         dbus_pending_call_block(pending);
 184 
 185         /* get the reply message */
 186         reply = dbus_pending_call_steal_reply(pending);
 187     }
 188 
 189     (void)pcmk_dbus_find_error(pending, reply, error);
 190 
 191     if(pending) {
 192         /* free the pending message handle */
 193         dbus_pending_call_unref(pending);
 194     }
 195 
 196     return reply;
 197 }
 198 
 199 DBusPendingCall *
 200 pcmk_dbus_send(DBusMessage *msg, DBusConnection *connection,
     /* [previous][next][first][last][top][bottom][index][help] */
 201                void(*done)(DBusPendingCall *pending, void *user_data),
 202                void *user_data, int timeout)
 203 {
 204     const char *method = NULL;
 205     DBusPendingCall* pending = NULL;
 206 
 207     CRM_ASSERT(done);
 208     CRM_ASSERT(dbus_message_get_type (msg) == DBUS_MESSAGE_TYPE_METHOD_CALL);
 209     method = dbus_message_get_member (msg);
 210 
 211 
 212     if (timeout <= 0) {
 213         /* DBUS_TIMEOUT_USE_DEFAULT (-1) tells DBus to use a sane default */
 214         timeout = DBUS_TIMEOUT_USE_DEFAULT;
 215     }
 216 
 217     // send message and get a handle for a reply
 218     if (!dbus_connection_send_with_reply(connection, msg, &pending, timeout)) {
 219         crm_err("Send with reply failed for %s", method);
 220         return NULL;
 221 
 222     } else if (pending == NULL) {
 223         crm_err("No pending call found for %s: Connection to System DBus may be closed", method);
 224         return NULL;
 225     }
 226 
 227     crm_trace("DBus %s call sent", method);
 228     if (dbus_pending_call_get_completed(pending)) {
 229         crm_info("DBus %s call completed too soon", method);
 230         if(done) {
 231 #if 0
 232             /* This sounds like a good idea, but allegedly it breaks things */
 233             done(pending, user_data);
 234             pending = NULL;
 235 #else
 236             CRM_ASSERT(dbus_pending_call_set_notify(pending, done, user_data, NULL));
 237 #endif
 238         }
 239 
 240     } else if(done) {
 241         CRM_ASSERT(dbus_pending_call_set_notify(pending, done, user_data, NULL));
 242     }
 243     return pending;
 244 }
 245 
 246 bool
 247 pcmk_dbus_type_check(DBusMessage *msg, DBusMessageIter *field, int expected,
     /* [previous][next][first][last][top][bottom][index][help] */
 248                      const char *function, int line)
 249 {
 250     int dtype = 0;
 251     DBusMessageIter lfield;
 252 
 253     if(field == NULL) {
 254         if(dbus_message_iter_init(msg, &lfield)) {
 255             field = &lfield;
 256         }
 257     }
 258 
 259     if(field == NULL) {
 260         do_crm_log_alias(LOG_ERR, __FILE__, function, line,
 261                          "Empty parameter list in reply expecting '%c'", expected);
 262         return FALSE;
 263     }
 264 
 265     dtype = dbus_message_iter_get_arg_type(field);
 266 
 267     if(dtype != expected) {
 268         DBusMessageIter args;
 269         char *sig;
 270 
 271         dbus_message_iter_init(msg, &args);
 272         sig = dbus_message_iter_get_signature(&args);
 273         do_crm_log_alias(LOG_ERR, __FILE__, function, line,
 274                          "Unexpected DBus type, expected %c in '%s' instead of %c",
 275                          expected, sig, dtype);
 276         dbus_free(sig);
 277         return FALSE;
 278     }
 279 
 280     return TRUE;
 281 }
 282 
 283 static char *
 284 pcmk_dbus_lookup_result(DBusMessage *reply, struct db_getall_data *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 285 {
 286     DBusError error;
 287     char *output = NULL;
 288     DBusMessageIter dict;
 289     DBusMessageIter args;
 290 
 291     if (pcmk_dbus_find_error((void*)&error, reply, &error)) {
 292         crm_err("Cannot get properties from %s for %s: %s",
 293                 data->target, data->object, error.message);
 294         dbus_error_free(&error);
 295         goto cleanup;
 296     }
 297 
 298     dbus_message_iter_init(reply, &args);
 299     if(!pcmk_dbus_type_check(reply, &args, DBUS_TYPE_ARRAY, __FUNCTION__, __LINE__)) {
 300         crm_err("Invalid reply from %s for %s", data->target, data->object);
 301         goto cleanup;
 302     }
 303 
 304     dbus_message_iter_recurse(&args, &dict);
 305     while (dbus_message_iter_get_arg_type (&dict) != DBUS_TYPE_INVALID) {
 306         DBusMessageIter sv;
 307         DBusMessageIter v;
 308         DBusBasicValue name;
 309         DBusBasicValue value;
 310 
 311         if(!pcmk_dbus_type_check(reply, &dict, DBUS_TYPE_DICT_ENTRY, __FUNCTION__, __LINE__)) {
 312             dbus_message_iter_next (&dict);
 313             continue;
 314         }
 315 
 316         dbus_message_iter_recurse(&dict, &sv);
 317         while (dbus_message_iter_get_arg_type (&sv) != DBUS_TYPE_INVALID) {
 318             int dtype = dbus_message_iter_get_arg_type(&sv);
 319 
 320             switch(dtype) {
 321                 case DBUS_TYPE_STRING:
 322                     dbus_message_iter_get_basic(&sv, &name);
 323 
 324                     if(data->name && strcmp(name.str, data->name) != 0) {
 325                         dbus_message_iter_next (&sv); /* Skip the value */
 326                     }
 327                     break;
 328                 case DBUS_TYPE_VARIANT:
 329                     dbus_message_iter_recurse(&sv, &v);
 330                     if(pcmk_dbus_type_check(reply, &v, DBUS_TYPE_STRING, __FUNCTION__, __LINE__)) {
 331                         dbus_message_iter_get_basic(&v, &value);
 332 
 333                         crm_trace("Property %s[%s] is '%s'", data->object, name.str, value.str);
 334                         if(data->callback) {
 335                             data->callback(name.str, value.str, data->userdata);
 336 
 337                         } else {
 338                             free(output);
 339                             output = strdup(value.str);
 340                         }
 341 
 342                         if(data->name) {
 343                             goto cleanup;
 344                         }
 345                     }
 346                     break;
 347                 default:
 348                     pcmk_dbus_type_check(reply, &sv, DBUS_TYPE_STRING, __FUNCTION__, __LINE__);
 349             }
 350             dbus_message_iter_next (&sv);
 351         }
 352 
 353         dbus_message_iter_next (&dict);
 354     }
 355 
 356     if(data->name && data->callback) {
 357         crm_trace("No value for property %s[%s]", data->object, data->name);
 358         data->callback(data->name, NULL, data->userdata);
 359     }
 360 
 361   cleanup:
 362     free(data->target);
 363     free(data->object);
 364     free(data->name);
 365     free(data);
 366 
 367     return output;
 368 }
 369 
 370 static void
 371 pcmk_dbus_lookup_cb(DBusPendingCall *pending, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 372 {
 373     DBusMessage *reply = NULL;
 374     char *value = NULL;
 375 
 376     if(pending) {
 377         reply = dbus_pending_call_steal_reply(pending);
 378     }
 379 
 380     value = pcmk_dbus_lookup_result(reply, user_data);
 381     free(value);
 382 
 383     if(reply) {
 384         dbus_message_unref(reply);
 385     }
 386 }
 387 
 388 char *
 389 pcmk_dbus_get_property(DBusConnection *connection, const char *target,
     /* [previous][next][first][last][top][bottom][index][help] */
 390                        const char *obj, const gchar * iface, const char *name,
 391                        void (*callback)(const char *name, const char *value, void *userdata),
 392                        void *userdata, DBusPendingCall **pending, int timeout)
 393 {
 394     DBusMessage *msg;
 395     const char *method = "GetAll";
 396     char *output = NULL;
 397     struct db_getall_data *query_data = NULL;
 398 
 399     crm_debug("Calling: %s on %s", method, target);
 400     msg = dbus_message_new_method_call(target, // target for the method call
 401                                        obj, // object to call on
 402                                        BUS_PROPERTY_IFACE, // interface to call on
 403                                        method); // method name
 404     if (NULL == msg) {
 405         crm_err("Call to %s failed: No message", method);
 406         return NULL;
 407     }
 408 
 409     CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &iface, DBUS_TYPE_INVALID));
 410 
 411     query_data = malloc(sizeof(struct db_getall_data));
 412     if(query_data == NULL) {
 413         crm_err("Call to %s failed: malloc failed", method);
 414         return NULL;
 415     }
 416 
 417     query_data->target = strdup(target);
 418     query_data->object = strdup(obj);
 419     query_data->callback = callback;
 420     query_data->userdata = userdata;
 421     query_data->name = NULL;
 422 
 423     if(name) {
 424         query_data->name = strdup(name);
 425     }
 426 
 427     if(query_data->callback) {
 428         DBusPendingCall* _pending;
 429         _pending = pcmk_dbus_send(msg, connection, pcmk_dbus_lookup_cb, query_data, timeout);
 430         if (pending != NULL) {
 431             *pending = _pending;
 432         }
 433 
 434     } else {
 435         DBusMessage *reply = pcmk_dbus_send_recv(msg, connection, NULL, timeout);
 436 
 437         output = pcmk_dbus_lookup_result(reply, query_data);
 438 
 439         if(reply) {
 440             dbus_message_unref(reply);
 441         }
 442     }
 443 
 444     dbus_message_unref(msg);
 445 
 446     return output;
 447 }
 448 
 449 static void
 450 pcmk_dbus_connection_dispatch_status(DBusConnection *connection,
     /* [previous][next][first][last][top][bottom][index][help] */
 451                               DBusDispatchStatus new_status, void *data)
 452 {
 453     crm_trace("New status %d for connection %p", new_status, connection);
 454     if (new_status == DBUS_DISPATCH_DATA_REMAINS){
 455         conn_dispatches = g_list_prepend(conn_dispatches, connection);
 456     }
 457 }
 458 
 459 static void
 460 pcmk_dbus_connections_dispatch()
     /* [previous][next][first][last][top][bottom][index][help] */
 461 {
 462     GList *gIter = NULL;
 463 
 464     for (gIter = conn_dispatches; gIter != NULL; gIter = gIter->next) {
 465         DBusConnection *connection = gIter->data;
 466 
 467         while (dbus_connection_get_dispatch_status(connection) == DBUS_DISPATCH_DATA_REMAINS) {
 468             crm_trace("Dispatching for connection %p", connection);
 469             dbus_connection_dispatch(connection);
 470         }
 471     }
 472 
 473     g_list_free(conn_dispatches);
 474     conn_dispatches = NULL;
 475 }
 476 
 477 /* Copied from dbus-watch.c */
 478 
 479 static const char*
 480 dbus_watch_flags_to_string(int flags)
     /* [previous][next][first][last][top][bottom][index][help] */
 481 {
 482     const char *watch_type;
 483 
 484     if ((flags & DBUS_WATCH_READABLE) && (flags & DBUS_WATCH_WRITABLE)) {
 485         watch_type = "readwrite";
 486     } else if (flags & DBUS_WATCH_READABLE) {
 487         watch_type = "read";
 488     } else if (flags & DBUS_WATCH_WRITABLE) {
 489         watch_type = "write";
 490     } else {
 491         watch_type = "not read or write";
 492     }
 493     return watch_type;
 494 }
 495 
 496 static int
 497 pcmk_dbus_watch_dispatch(gpointer userdata)
     /* [previous][next][first][last][top][bottom][index][help] */
 498 {
 499     bool oom = FALSE;
 500     DBusWatch *watch = userdata;
 501     int flags = dbus_watch_get_flags(watch);
 502     bool enabled = dbus_watch_get_enabled (watch);
 503     mainloop_io_t *client = dbus_watch_get_data(watch);
 504 
 505     crm_trace("Dispatching client %p: %s", client, dbus_watch_flags_to_string(flags));
 506     if (enabled && (flags & (DBUS_WATCH_READABLE|DBUS_WATCH_WRITABLE))) {
 507         oom = !dbus_watch_handle(watch, flags);
 508 
 509     } else if(enabled) {
 510         oom = !dbus_watch_handle(watch, DBUS_WATCH_ERROR);
 511     }
 512 
 513     if(flags != dbus_watch_get_flags(watch)) {
 514         flags = dbus_watch_get_flags(watch);
 515         crm_trace("Dispatched client %p: %s (%d)", client,
 516                   dbus_watch_flags_to_string(flags), flags);
 517     }
 518 
 519     if(oom) {
 520         crm_err("DBus encountered OOM while attempting to dispatch %p (%s)",
 521                 client, dbus_watch_flags_to_string(flags));
 522 
 523     } else {
 524         pcmk_dbus_connections_dispatch();
 525     }
 526 
 527     return 0;
 528 }
 529 
 530 static void
 531 pcmk_dbus_watch_destroy(gpointer userdata)
     /* [previous][next][first][last][top][bottom][index][help] */
 532 {
 533     mainloop_io_t *client = dbus_watch_get_data(userdata);
 534     crm_trace("Destroyed %p", client);
 535 }
 536 
 537 
 538 struct mainloop_fd_callbacks pcmk_dbus_cb = {
 539     .dispatch = pcmk_dbus_watch_dispatch,
 540     .destroy = pcmk_dbus_watch_destroy,
 541 };
 542 
 543 static dbus_bool_t
 544 pcmk_dbus_watch_add(DBusWatch *watch, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 545 {
 546     int fd = dbus_watch_get_unix_fd(watch);
 547 
 548     mainloop_io_t *client = mainloop_add_fd(
 549         "dbus", G_PRIORITY_DEFAULT, fd, watch, &pcmk_dbus_cb);
 550 
 551     crm_trace("Added watch %p with fd=%d to client %p", watch, fd, client);
 552     dbus_watch_set_data(watch, client, NULL);
 553     return TRUE;
 554 }
 555 
 556 static void
 557 pcmk_dbus_watch_toggle(DBusWatch *watch, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 558 {
 559     mainloop_io_t *client = dbus_watch_get_data(watch);
 560     crm_notice("DBus client %p is now %s",
 561                client, (dbus_watch_get_enabled(watch)? "enabled" : "disabled"));
 562 }
 563 
 564 
 565 static void
 566 pcmk_dbus_watch_remove(DBusWatch *watch, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 567 {
 568     mainloop_io_t *client = dbus_watch_get_data(watch);
 569 
 570     crm_trace("Removed client %p (%p)", client, data);
 571     mainloop_del_fd(client);
 572 }
 573 
 574 static gboolean
 575 pcmk_dbus_timeout_dispatch(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 576 {
 577     crm_info("Timeout %p expired", data);
 578     dbus_timeout_handle(data);
 579     return FALSE;
 580 }
 581 
 582 static dbus_bool_t
 583 pcmk_dbus_timeout_add(DBusTimeout *timeout, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 584 {
 585     guint id = g_timeout_add(dbus_timeout_get_interval(timeout),
 586                              pcmk_dbus_timeout_dispatch, timeout);
 587 
 588     crm_trace("Adding timeout %p (%d)", timeout, dbus_timeout_get_interval(timeout));
 589 
 590     if(id) {
 591         dbus_timeout_set_data(timeout, GUINT_TO_POINTER(id), NULL);
 592     }
 593     return TRUE;
 594 }
 595 
 596 static void
 597 pcmk_dbus_timeout_remove(DBusTimeout *timeout, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 598 {
 599     void *vid = dbus_timeout_get_data(timeout);
 600     guint id = GPOINTER_TO_UINT(vid);
 601 
 602     crm_trace("Removing timeout %p (%p)", timeout, data);
 603 
 604     if(id) {
 605         g_source_remove(id);
 606         dbus_timeout_set_data(timeout, 0, NULL);
 607     }
 608 }
 609 
 610 static void
 611 pcmk_dbus_timeout_toggle(DBusTimeout *timeout, void *data)
     /* [previous][next][first][last][top][bottom][index][help] */
 612 {
 613     bool enabled = dbus_timeout_get_enabled(timeout);
 614 
 615     crm_trace("Toggling timeout for %p to %s", timeout, enabled?"off":"on");
 616 
 617     if(enabled) {
 618         pcmk_dbus_timeout_add(timeout, data);
 619     } else {
 620         pcmk_dbus_timeout_remove(timeout, data);
 621     }
 622 }
 623 
 624 /* Inspired by http://www.kolej.mff.cuni.cz/~vesej3am/devel/dbus-select.c */
 625 
 626 void
 627 pcmk_dbus_connection_setup_with_select(DBusConnection *c)
     /* [previous][next][first][last][top][bottom][index][help] */
 628 {
 629     dbus_connection_set_exit_on_disconnect(c, FALSE);
 630     dbus_connection_set_timeout_functions(c, pcmk_dbus_timeout_add,
 631                                           pcmk_dbus_timeout_remove,
 632                                           pcmk_dbus_timeout_toggle, NULL, NULL);
 633     dbus_connection_set_watch_functions(c, pcmk_dbus_watch_add,
 634                                         pcmk_dbus_watch_remove,
 635                                         pcmk_dbus_watch_toggle, NULL, NULL);
 636     dbus_connection_set_dispatch_status_function(c, pcmk_dbus_connection_dispatch_status, NULL, NULL);
 637     pcmk_dbus_connection_dispatch_status(c, dbus_connection_get_dispatch_status(c), NULL);
 638 }

/* [previous][next][first][last][top][bottom][index][help] */