root/lib/services/upstart.c

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

DEFINITIONS

This source file includes following definitions.
  1. services__upstart_prepare
  2. services__upstart2ocf
  3. upstart_init
  4. upstart_cleanup
  5. object_path_for_job
  6. fix
  7. fix_upstart_name
  8. upstart_job_listall
  9. upstart_job_exists
  10. get_first_instance
  11. parse_status_result
  12. upstart_job_metadata
  13. set_result_from_method_error
  14. job_method_complete
  15. services__execute_upstart

   1 /*
   2  * Original copyright 2010 Senko Rasic <senko.rasic@dobarkod.hr>
   3  *                         and Ante Karamatic <ivoks@init.hr>
   4  * Later changes copyright 2012-2021 the Pacemaker project contributors
   5  *
   6  * The version control history for this file may have further details.
   7  *
   8  * This source code is licensed under the GNU Lesser General Public License
   9  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
  10  */
  11 
  12 #include <crm_internal.h>
  13 
  14 #include <stdio.h>
  15 
  16 #include <crm/crm.h>
  17 #include <crm/services.h>
  18 #include <crm/common/mainloop.h>
  19 
  20 #include <services_private.h>
  21 #include <upstart.h>
  22 #include <dbus/dbus.h>
  23 #include <pcmk-dbus.h>
  24 
  25 #include <glib.h>
  26 #include <gio/gio.h>
  27 
  28 #define BUS_NAME "com.ubuntu.Upstart"
  29 #define BUS_PATH "/com/ubuntu/Upstart"
  30 
  31 #define UPSTART_06_API     BUS_NAME"0_6"
  32 #define UPSTART_JOB_IFACE  UPSTART_06_API".Job"
  33 #define BUS_PROPERTY_IFACE "org.freedesktop.DBus.Properties"
  34 
  35 /*
  36   http://upstart.ubuntu.com/wiki/DBusInterface
  37 */
  38 static DBusConnection *upstart_proxy = NULL;
  39 
  40 /*!
  41  * \internal
  42  * \brief Prepare an Upstart action
  43  *
  44  * \param[in] op  Action to prepare
  45  *
  46  * \return Standard Pacemaker return code
  47  */
  48 int
  49 services__upstart_prepare(svc_action_t *op)
     /* [previous][next][first][last][top][bottom][index][help] */
  50 {
  51     op->opaque->exec = strdup("upstart-dbus");
  52     if (op->opaque->exec == NULL) {
  53         return ENOMEM;
  54     }
  55     return pcmk_rc_ok;
  56 }
  57 
  58 /*!
  59  * \internal
  60  * \brief Map a Upstart result to a standard OCF result
  61  *
  62  * \param[in] exit_status  Upstart result
  63  *
  64  * \return Standard OCF result
  65  */
  66 enum ocf_exitcode
  67 services__upstart2ocf(int exit_status)
     /* [previous][next][first][last][top][bottom][index][help] */
  68 {
  69     // This library uses OCF codes for Upstart actions
  70     return (enum ocf_exitcode) exit_status;
  71 }
  72 
  73 static gboolean
  74 upstart_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  75 {
  76     static int need_init = 1;
  77 
  78     if (need_init) {
  79         need_init = 0;
  80         upstart_proxy = pcmk_dbus_connect();
  81     }
  82     if (upstart_proxy == NULL) {
  83         return FALSE;
  84     }
  85     return TRUE;
  86 }
  87 
  88 void
  89 upstart_cleanup(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  90 {
  91     if (upstart_proxy) {
  92         pcmk_dbus_disconnect(upstart_proxy);
  93         upstart_proxy = NULL;
  94     }
  95 }
  96 
  97 /*!
  98  * \internal
  99  * \brief Get the DBus object path corresponding to a job name
 100  *
 101  * \param[in]  arg_name  Name of job to get path for
 102  * \param[out] path      If not NULL, where to store DBus object path
 103  * \param[in]  timeout   Give up after this many seconds
 104  *
 105  * \return true if object path was found, false otherwise
 106  * \note The caller is responsible for freeing *path if it is non-NULL.
 107  */
 108 static bool
 109 object_path_for_job(const gchar *arg_name, char **path, int timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
 110 {
 111     /*
 112         com.ubuntu.Upstart0_6.GetJobByName (in String name, out ObjectPath job)
 113     */
 114     DBusError error;
 115     DBusMessage *msg;
 116     DBusMessage *reply = NULL;
 117     bool rc = false;
 118 
 119     if (path != NULL) {
 120         *path = NULL;
 121     }
 122 
 123     if (!upstart_init()) {
 124         return false;
 125     }
 126     msg = dbus_message_new_method_call(BUS_NAME, // target for the method call
 127                                        BUS_PATH, // object to call on
 128                                        UPSTART_06_API,  // interface to call on
 129                                        "GetJobByName"); // method name
 130 
 131     dbus_error_init(&error);
 132     CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &arg_name,
 133                                             DBUS_TYPE_INVALID));
 134     reply = pcmk_dbus_send_recv(msg, upstart_proxy, &error, timeout);
 135     dbus_message_unref(msg);
 136 
 137     if (dbus_error_is_set(&error)) {
 138         crm_err("Could not get DBus object path for %s: %s",
 139                 arg_name, error.message);
 140         dbus_error_free(&error);
 141 
 142     } else if (!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH,
 143                                      __func__, __LINE__)) {
 144         crm_err("Could not get DBus object path for %s: Invalid return type",
 145                 arg_name);
 146 
 147     } else {
 148         if (path != NULL) {
 149             dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, path,
 150                                   DBUS_TYPE_INVALID);
 151             if (*path != NULL) {
 152                 *path = strdup(*path);
 153             }
 154         }
 155         rc = true;
 156     }
 157 
 158     if (reply != NULL) {
 159         dbus_message_unref(reply);
 160     }
 161     return rc;
 162 }
 163 
 164 static void
 165 fix(char *input, const char *search, char replace)
     /* [previous][next][first][last][top][bottom][index][help] */
 166 {
 167     char *match = NULL;
 168     int shuffle = strlen(search) - 1;
 169 
 170     while (TRUE) {
 171         int len, lpc;
 172 
 173         match = strstr(input, search);
 174         if (match == NULL) {
 175             break;
 176         }
 177         crm_trace("Found: %s", match);
 178         match[0] = replace;
 179         len = strlen(match) - shuffle;
 180         for (lpc = 1; lpc <= len; lpc++) {
 181             match[lpc] = match[lpc + shuffle];
 182         }
 183     }
 184 }
 185 
 186 static char *
 187 fix_upstart_name(const char *input)
     /* [previous][next][first][last][top][bottom][index][help] */
 188 {
 189     char *output = strdup(input);
 190 
 191     fix(output, "_2b", '+');
 192     fix(output, "_2c", ',');
 193     fix(output, "_2d", '-');
 194     fix(output, "_2e", '.');
 195     fix(output, "_40", '@');
 196     fix(output, "_5f", '_');
 197     return output;
 198 }
 199 
 200 GList *
 201 upstart_job_listall(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 202 {
 203     GList *units = NULL;
 204     DBusMessageIter args;
 205     DBusMessageIter unit;
 206     DBusMessage *msg = NULL;
 207     DBusMessage *reply = NULL;
 208     const char *method = "GetAllJobs";
 209     DBusError error;
 210     int lpc = 0;
 211 
 212     if (upstart_init() == FALSE) {
 213         return NULL;
 214     }
 215 
 216 /*
 217   com.ubuntu.Upstart0_6.GetAllJobs (out <Array of ObjectPath> jobs)
 218 */
 219 
 220     dbus_error_init(&error);
 221     msg = dbus_message_new_method_call(BUS_NAME, // target for the method call
 222                                        BUS_PATH, // object to call on
 223                                        UPSTART_06_API, // interface to call on
 224                                        method); // method name
 225     CRM_ASSERT(msg != NULL);
 226 
 227     reply = pcmk_dbus_send_recv(msg, upstart_proxy, &error, DBUS_TIMEOUT_USE_DEFAULT);
 228     dbus_message_unref(msg);
 229 
 230     if (dbus_error_is_set(&error)) {
 231         crm_err("Call to %s failed: %s", method, error.message);
 232         dbus_error_free(&error);
 233         return NULL;
 234 
 235     } else if (!dbus_message_iter_init(reply, &args)) {
 236         crm_err("Call to %s failed: Message has no arguments", method);
 237         dbus_message_unref(reply);
 238         return NULL;
 239     }
 240 
 241     if(!pcmk_dbus_type_check(reply, &args, DBUS_TYPE_ARRAY, __func__, __LINE__)) {
 242         crm_err("Call to %s failed: Message has invalid arguments", method);
 243         dbus_message_unref(reply);
 244         return NULL;
 245     }
 246 
 247     dbus_message_iter_recurse(&args, &unit);
 248     while (dbus_message_iter_get_arg_type (&unit) != DBUS_TYPE_INVALID) {
 249         DBusBasicValue value;
 250         const char *job = NULL;
 251         char *path = NULL;
 252 
 253         if(!pcmk_dbus_type_check(reply, &unit, DBUS_TYPE_OBJECT_PATH, __func__, __LINE__)) {
 254             crm_warn("Skipping Upstart reply argument with unexpected type");
 255             continue;
 256         }
 257 
 258         dbus_message_iter_get_basic(&unit, &value);
 259 
 260         if(value.str) {
 261             int llpc = 0;
 262             path = value.str;
 263             job = value.str;
 264             while (path[llpc] != 0) {
 265                 if (path[llpc] == '/') {
 266                     job = path + llpc + 1;
 267                 }
 268                 llpc++;
 269             }
 270             lpc++;
 271             crm_trace("%s -> %s", path, job);
 272             units = g_list_append(units, fix_upstart_name(job));
 273         }
 274         dbus_message_iter_next (&unit);
 275     }
 276 
 277     dbus_message_unref(reply);
 278     crm_trace("Found %d upstart jobs", lpc);
 279     return units;
 280 }
 281 
 282 gboolean
 283 upstart_job_exists(const char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
 284 {
 285     return object_path_for_job(name, NULL, DBUS_TIMEOUT_USE_DEFAULT);
 286 }
 287 
 288 static char *
 289 get_first_instance(const gchar * job, int timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
 290 {
 291     char *instance = NULL;
 292     const char *method = "GetAllInstances";
 293     DBusError error;
 294     DBusMessage *msg;
 295     DBusMessage *reply;
 296     DBusMessageIter args;
 297     DBusMessageIter unit;
 298 
 299     dbus_error_init(&error);
 300     msg = dbus_message_new_method_call(BUS_NAME, // target for the method call
 301                                        job, // object to call on
 302                                        UPSTART_JOB_IFACE, // interface to call on
 303                                        method); // method name
 304     CRM_ASSERT(msg != NULL);
 305 
 306     dbus_message_append_args(msg, DBUS_TYPE_INVALID);
 307     reply = pcmk_dbus_send_recv(msg, upstart_proxy, &error, timeout);
 308     dbus_message_unref(msg);
 309 
 310     if (dbus_error_is_set(&error)) {
 311         crm_err("Call to %s failed: %s", method, error.message);
 312         dbus_error_free(&error);
 313         goto done;
 314 
 315     } else if(reply == NULL) {
 316         crm_err("Call to %s failed: no reply", method);
 317         goto done;
 318 
 319     } else if (!dbus_message_iter_init(reply, &args)) {
 320         crm_err("Call to %s failed: Message has no arguments", method);
 321         goto done;
 322     }
 323 
 324     if(!pcmk_dbus_type_check(reply, &args, DBUS_TYPE_ARRAY, __func__, __LINE__)) {
 325         crm_err("Call to %s failed: Message has invalid arguments", method);
 326         goto done;
 327     }
 328 
 329     dbus_message_iter_recurse(&args, &unit);
 330     if(pcmk_dbus_type_check(reply, &unit, DBUS_TYPE_OBJECT_PATH, __func__, __LINE__)) {
 331         DBusBasicValue value;
 332 
 333         dbus_message_iter_get_basic(&unit, &value);
 334 
 335         if(value.str) {
 336             instance = strdup(value.str);
 337             crm_trace("Result: %s", instance);
 338         }
 339     }
 340 
 341   done:
 342     if(reply) {
 343         dbus_message_unref(reply);
 344     }
 345     return instance;
 346 }
 347 
 348 /*!
 349  * \internal
 350  * \brief Parse result of Upstart status check
 351  *
 352  * \param[in] name      DBus interface name for property that was checked
 353  * \param[in] state     Property value
 354  * \param[in] userdata  Status action that check was done for
 355  */
 356 static void
 357 parse_status_result(const char *name, const char *state, void *userdata)
     /* [previous][next][first][last][top][bottom][index][help] */
 358 {
 359     svc_action_t *op = userdata;
 360 
 361     if (pcmk__str_eq(state, "running", pcmk__str_none)) {
 362         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 363     } else {
 364         services__set_result(op, PCMK_OCF_NOT_RUNNING, PCMK_EXEC_DONE, state);
 365     }
 366 
 367     if (!(op->synchronous)) {
 368         services_set_op_pending(op, NULL);
 369         services__finalize_async_op(op);
 370     }
 371 }
 372 
 373 #define METADATA_FORMAT                                                     \
 374     "<?xml version=\"1.0\"?>\n"                                             \
 375     "<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n"                   \
 376     "<resource-agent name=\"%s\" version=\"" PCMK_DEFAULT_AGENT_VERSION "\">\n" \
 377     "  <version>1.1</version>\n"                                            \
 378     "  <longdesc lang=\"en\">\n"                                            \
 379     "    Upstart agent for controlling the system %s service\n"             \
 380     "  </longdesc>\n"                                                       \
 381     "  <shortdesc lang=\"en\">Upstart job for %s</shortdesc>\n"             \
 382     "  <parameters/>\n"                                                     \
 383     "  <actions>\n"                                                         \
 384     "    <action name=\"start\"     timeout=\"15\" />\n"                    \
 385     "    <action name=\"stop\"      timeout=\"15\" />\n"                    \
 386     "    <action name=\"status\"    timeout=\"15\" />\n"                    \
 387     "    <action name=\"restart\"   timeout=\"15\" />\n"                    \
 388     "    <action name=\"monitor\"   timeout=\"15\" interval=\"15\" start-delay=\"15\" />\n" \
 389     "    <action name=\"meta-data\" timeout=\"5\" />\n"                     \
 390     "  </actions>\n"                                                        \
 391     "  <special tag=\"upstart\"/>\n"                                        \
 392     "</resource-agent>\n"
 393 
 394 static char *
 395 upstart_job_metadata(const char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
 396 {
 397     return crm_strdup_printf(METADATA_FORMAT, name, name, name);
 398 }
 399 
 400 /*!
 401  * \internal
 402  * \brief Set an action result based on a method error
 403  *
 404  * \param[in] op     Action to set result for
 405  * \param[in] error  Method error
 406  */
 407 static void
 408 set_result_from_method_error(svc_action_t *op, const DBusError *error)
     /* [previous][next][first][last][top][bottom][index][help] */
 409 {
 410     services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
 411                          "Unable to invoke Upstart DBus method");
 412 
 413     if (strstr(error->name, UPSTART_06_API ".Error.UnknownInstance")) {
 414 
 415         if (pcmk__str_eq(op->action, "stop", pcmk__str_casei)) {
 416             crm_trace("Masking stop failure (%s) for %s "
 417                       "because unknown service can be considered stopped",
 418                       error->name, crm_str(op->rsc));
 419             services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 420             return;
 421         }
 422 
 423         services__set_result(op, PCMK_OCF_NOT_INSTALLED,
 424                              PCMK_EXEC_NOT_INSTALLED, "Upstart job not found");
 425 
 426     } else if (pcmk__str_eq(op->action, "start", pcmk__str_casei)
 427                && strstr(error->name, UPSTART_06_API ".Error.AlreadyStarted")) {
 428         crm_trace("Masking start failure (%s) for %s "
 429                   "because already started resource is OK",
 430                   error->name, crm_str(op->rsc));
 431         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 432         return;
 433     }
 434 
 435     crm_err("DBus request for %s of Upstart job %s for resource %s failed: %s",
 436             op->action, op->agent, crm_str(op->rsc), error->message);
 437 }
 438 
 439 /*!
 440  * \internal
 441  * \brief Process the completion of an asynchronous job start, stop, or restart
 442  *
 443  * \param[in] pending    If not NULL, DBus call associated with request
 444  * \param[in] user_data  Action that was executed
 445  */
 446 static void
 447 job_method_complete(DBusPendingCall *pending, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 448 {
 449     DBusError error;
 450     DBusMessage *reply = NULL;
 451     svc_action_t *op = user_data;
 452 
 453     // Grab the reply
 454     if (pending != NULL) {
 455         reply = dbus_pending_call_steal_reply(pending);
 456     }
 457 
 458     // Determine result
 459     dbus_error_init(&error);
 460     if (pcmk_dbus_find_error(pending, reply, &error)) {
 461         set_result_from_method_error(op, &error);
 462         dbus_error_free(&error);
 463 
 464     } else if (pcmk__str_eq(op->action, "stop", pcmk__str_none)) {
 465         // Call has no return value
 466         crm_debug("DBus request for stop of %s succeeded", crm_str(op->rsc));
 467         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 468 
 469     } else if (!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH,
 470                                      __func__, __LINE__)) {
 471         crm_warn("DBus request for %s of %s succeeded but "
 472                  "return type was unexpected", op->action, crm_str(op->rsc));
 473         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 474 
 475     } else {
 476         const char *path = NULL;
 477 
 478         dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &path,
 479                               DBUS_TYPE_INVALID);
 480         crm_debug("DBus request for %s of %s using %s succeeded",
 481                   op->action, crm_str(op->rsc), path);
 482         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 483     }
 484 
 485     // The call is no longer pending
 486     CRM_LOG_ASSERT(pending == op->opaque->pending);
 487     services_set_op_pending(op, NULL);
 488 
 489     // Finalize action
 490     services__finalize_async_op(op);
 491     if (reply != NULL) {
 492         dbus_message_unref(reply);
 493     }
 494 }
 495 
 496 /*!
 497  * \internal
 498  * \brief Execute an Upstart action
 499  *
 500  * \param[in] op  Action to execute
 501  *
 502  * \return Standard Pacemaker return code
 503  * \retval EBUSY          Recurring operation could not be initiated
 504  * \retval pcmk_rc_error  Synchronous action failed
 505  * \retval pcmk_rc_ok     Synchronous action succeeded, or asynchronous action
 506  *                        should not be freed (because it already was or is
 507  *                        pending)
 508  *
 509  * \note If the return value for an asynchronous action is not pcmk_rc_ok, the
 510  *       caller is responsible for freeing the action.
 511  */
 512 int
 513 services__execute_upstart(svc_action_t *op)
     /* [previous][next][first][last][top][bottom][index][help] */
 514 {
 515     char *job = NULL;
 516     int arg_wait = TRUE;
 517     const char *arg_env = "pacemaker=1";
 518     const char *action = op->action;
 519 
 520     DBusError error;
 521     DBusMessage *msg = NULL;
 522     DBusMessage *reply = NULL;
 523     DBusMessageIter iter, array_iter;
 524 
 525     CRM_ASSERT(op != NULL);
 526 
 527     if ((op->action == NULL) || (op->agent == NULL)) {
 528         services__set_result(op, PCMK_OCF_NOT_CONFIGURED, PCMK_EXEC_ERROR_FATAL,
 529                              "Bug in action caller");
 530         goto cleanup;
 531     }
 532 
 533     if (!upstart_init()) {
 534         services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
 535                              "No DBus connection");
 536         goto cleanup;
 537     }
 538 
 539     if (pcmk__str_eq(op->action, "meta-data", pcmk__str_casei)) {
 540         op->stdout_data = upstart_job_metadata(op->agent);
 541         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 542         goto cleanup;
 543     }
 544 
 545     if (!object_path_for_job(op->agent, &job, op->timeout)) {
 546         if (pcmk__str_eq(action, "stop", pcmk__str_none)) {
 547             services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 548         } else {
 549             services__set_result(op, PCMK_OCF_NOT_INSTALLED,
 550                                  PCMK_EXEC_NOT_INSTALLED,
 551                                  "Upstart job not found");
 552         }
 553         goto cleanup;
 554     }
 555 
 556     if (job == NULL) {
 557         // Shouldn't normally be possible -- maybe a memory error
 558         op->rc = PCMK_OCF_UNKNOWN_ERROR;
 559         op->status = PCMK_EXEC_ERROR;
 560         goto cleanup;
 561     }
 562 
 563     if (pcmk__strcase_any_of(op->action, "monitor", "status", NULL)) {
 564         DBusPendingCall *pending = NULL;
 565         char *state = NULL;
 566         char *path = get_first_instance(job, op->timeout);
 567 
 568         services__set_result(op, PCMK_OCF_NOT_RUNNING, PCMK_EXEC_DONE,
 569                              "No Upstart job instances found");
 570         if (path == NULL) {
 571             goto cleanup;
 572         }
 573         state = pcmk_dbus_get_property(upstart_proxy, BUS_NAME, path,
 574                                        UPSTART_06_API ".Instance", "state",
 575                                        op->synchronous? NULL : parse_status_result,
 576                                        op,
 577                                        op->synchronous? NULL : &pending,
 578                                        op->timeout);
 579         free(path);
 580 
 581         if (op->synchronous) {
 582             parse_status_result("state", state, op);
 583             free(state);
 584 
 585         } else if (pending == NULL) {
 586             services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
 587                                  "Could not get job state from DBus");
 588 
 589         } else { // Successfully initiated async op
 590             free(job);
 591             services_set_op_pending(op, pending);
 592             services_add_inflight_op(op);
 593             return pcmk_rc_ok;
 594         }
 595 
 596         goto cleanup;
 597 
 598     } else if (pcmk__str_eq(action, "start", pcmk__str_none)) {
 599         action = "Start";
 600 
 601     } else if (pcmk__str_eq(action, "stop", pcmk__str_none)) {
 602         action = "Stop";
 603 
 604     } else if (pcmk__str_eq(action, "restart", pcmk__str_none)) {
 605         action = "Restart";
 606 
 607     } else {
 608         services__set_result(op, PCMK_OCF_UNIMPLEMENT_FEATURE,
 609                              PCMK_EXEC_ERROR_HARD,
 610                              "Action not implemented for Upstart resources");
 611         goto cleanup;
 612     }
 613 
 614     // Initialize rc/status in case called functions don't set them
 615     services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_DONE,
 616                          "Bug in service library");
 617 
 618     crm_debug("Calling %s for %s on %s", action, crm_str(op->rsc), job);
 619 
 620     msg = dbus_message_new_method_call(BUS_NAME, // target for the method call
 621                                        job, // object to call on
 622                                        UPSTART_JOB_IFACE, // interface to call on
 623                                        action); // method name
 624     CRM_ASSERT(msg != NULL);
 625 
 626     dbus_message_iter_init_append (msg, &iter);
 627     CRM_LOG_ASSERT(dbus_message_iter_open_container(&iter,
 628                                                     DBUS_TYPE_ARRAY,
 629                                                     DBUS_TYPE_STRING_AS_STRING,
 630                                                     &array_iter));
 631     CRM_LOG_ASSERT(dbus_message_iter_append_basic(&array_iter,
 632                                                   DBUS_TYPE_STRING, &arg_env));
 633     CRM_LOG_ASSERT(dbus_message_iter_close_container(&iter, &array_iter));
 634     CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &arg_wait,
 635                                             DBUS_TYPE_INVALID));
 636 
 637     if (!(op->synchronous)) {
 638         DBusPendingCall *pending = pcmk_dbus_send(msg, upstart_proxy,
 639                                                   job_method_complete, op,
 640                                                   op->timeout);
 641 
 642         if (pending == NULL) {
 643             services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
 644                                  "Unable to send DBus message");
 645             goto cleanup;
 646 
 647         } else { // Successfully initiated async op
 648             free(job);
 649             services_set_op_pending(op, pending);
 650             services_add_inflight_op(op);
 651             return pcmk_rc_ok;
 652         }
 653     }
 654 
 655     // Synchronous call
 656 
 657     dbus_error_init(&error);
 658     reply = pcmk_dbus_send_recv(msg, upstart_proxy, &error, op->timeout);
 659 
 660     if (dbus_error_is_set(&error)) {
 661         set_result_from_method_error(op, &error);
 662         dbus_error_free(&error);
 663 
 664     } else if (pcmk__str_eq(op->action, "stop", pcmk__str_none)) {
 665         // DBus call does not return a value
 666         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 667 
 668     } else if (!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH,
 669                                      __func__, __LINE__)) {
 670         crm_warn("Call to %s passed but return type was unexpected", op->action);
 671         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 672 
 673     } else {
 674         const char *path = NULL;
 675 
 676         dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &path,
 677                               DBUS_TYPE_INVALID);
 678         crm_info("Call to %s passed: %s", op->action, path);
 679         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 680     }
 681 
 682 cleanup:
 683     free(job);
 684     if (msg != NULL) {
 685         dbus_message_unref(msg);
 686     }
 687     if (reply != NULL) {
 688         dbus_message_unref(reply);
 689     }
 690 
 691     if (op->synchronous) {
 692         return (op->rc == PCMK_OCF_OK)? pcmk_rc_ok : pcmk_rc_error;
 693     } else {
 694         return services__finalize_async_op(op);
 695     }
 696 }

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