This source file includes following definitions.
- services__systemd_prepare
 
- services__systemd2ocf
 
- systemd_new_method
 
- systemd_send
 
- systemd_send_recv
 
- systemd_call_simple_method
 
- systemd_init
 
- systemd_get_property
 
- systemd_cleanup
 
- systemd_unit_extension
 
- systemd_service_name
 
- systemd_daemon_reload_complete
 
- systemd_daemon_reload
 
- set_result_from_method_error
 
- execute_after_loadunit
 
- loadunit_completed
 
- invoke_unit_by_name
 
- sort_str
 
- systemd_unit_listall
 
- systemd_unit_exists
 
- systemd_unit_metadata
 
- process_unit_method_reply
 
- unit_method_complete
 
- create_world_readable
 
- create_override_dir
 
- get_override_filename
 
- systemd_create_override
 
- systemd_remove_override
 
- parse_status_result
 
- invoke_unit_by_path
 
- systemd_timeout_callback
 
- services__execute_systemd
 
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 #include <crm_internal.h>
  11 #include <crm/crm.h>
  12 #include <crm/services.h>
  13 #include <crm/services_internal.h>
  14 #include <crm/common/mainloop.h>
  15 
  16 #include <sys/stat.h>
  17 #include <gio/gio.h>
  18 #include <services_private.h>
  19 #include <systemd.h>
  20 #include <dbus/dbus.h>
  21 #include <pcmk-dbus.h>
  22 
  23 static void invoke_unit_by_path(svc_action_t *op, const char *unit);
  24 
  25 #define BUS_NAME         "org.freedesktop.systemd1"
  26 #define BUS_NAME_MANAGER BUS_NAME ".Manager"
  27 #define BUS_NAME_UNIT    BUS_NAME ".Unit"
  28 #define BUS_PATH         "/org/freedesktop/systemd1"
  29 
  30 
  31 
  32 
  33 
  34 
  35 
  36 
  37 
  38 int
  39 services__systemd_prepare(svc_action_t *op)
     
  40 {
  41     op->opaque->exec = strdup("systemd-dbus");
  42     if (op->opaque->exec == NULL) {
  43         return ENOMEM;
  44     }
  45     return pcmk_rc_ok;
  46 }
  47 
  48 
  49 
  50 
  51 
  52 
  53 
  54 
  55 
  56 enum ocf_exitcode
  57 services__systemd2ocf(int exit_status)
     
  58 {
  59     
  60     return (enum ocf_exitcode) exit_status;
  61 }
  62 
  63 static inline DBusMessage *
  64 systemd_new_method(const char *method)
     
  65 {
  66     crm_trace("Calling: %s on " BUS_NAME_MANAGER, method);
  67     return dbus_message_new_method_call(BUS_NAME, BUS_PATH, BUS_NAME_MANAGER,
  68                                         method);
  69 }
  70 
  71 
  72 
  73 
  74 
  75 static DBusConnection* systemd_proxy = NULL;
  76 
  77 static inline DBusPendingCall *
  78 systemd_send(DBusMessage *msg,
     
  79              void(*done)(DBusPendingCall *pending, void *user_data),
  80              void *user_data, int timeout)
  81 {
  82     return pcmk_dbus_send(msg, systemd_proxy, done, user_data, timeout);
  83 }
  84 
  85 static inline DBusMessage *
  86 systemd_send_recv(DBusMessage *msg, DBusError *error, int timeout)
     
  87 {
  88     return pcmk_dbus_send_recv(msg, systemd_proxy, error, timeout);
  89 }
  90 
  91 
  92 
  93 
  94 
  95 
  96 
  97 
  98 
  99 
 100 
 101 
 102 static DBusMessage *
 103 systemd_call_simple_method(const char *method)
     
 104 {
 105     DBusMessage *msg = systemd_new_method(method);
 106     DBusMessage *reply = NULL;
 107     DBusError error;
 108 
 109     
 110     CRM_CHECK(systemd_proxy, return NULL);
 111 
 112     if (msg == NULL) {
 113         crm_err("Could not create message to send %s to systemd", method);
 114         return NULL;
 115     }
 116 
 117     dbus_error_init(&error);
 118     reply = systemd_send_recv(msg, &error, DBUS_TIMEOUT_USE_DEFAULT);
 119     dbus_message_unref(msg);
 120 
 121     if (dbus_error_is_set(&error)) {
 122         crm_err("Could not send %s to systemd: %s (%s)",
 123                 method, error.message, error.name);
 124         dbus_error_free(&error);
 125         return NULL;
 126 
 127     } else if (reply == NULL) {
 128         crm_err("Could not send %s to systemd: no reply received", method);
 129         return NULL;
 130     }
 131 
 132     return reply;
 133 }
 134 
 135 static gboolean
 136 systemd_init(void)
     
 137 {
 138     static int need_init = 1;
 139     
 140 
 141     if (systemd_proxy
 142         && dbus_connection_get_is_connected(systemd_proxy) == FALSE) {
 143         crm_warn("Connection to System DBus is closed. Reconnecting...");
 144         pcmk_dbus_disconnect(systemd_proxy);
 145         systemd_proxy = NULL;
 146         need_init = 1;
 147     }
 148 
 149     if (need_init) {
 150         need_init = 0;
 151         systemd_proxy = pcmk_dbus_connect();
 152     }
 153     if (systemd_proxy == NULL) {
 154         return FALSE;
 155     }
 156     return TRUE;
 157 }
 158 
 159 static inline char *
 160 systemd_get_property(const char *unit, const char *name,
     
 161                      void (*callback)(const char *name, const char *value, void *userdata),
 162                      void *userdata, DBusPendingCall **pending, int timeout)
 163 {
 164     return systemd_proxy?
 165            pcmk_dbus_get_property(systemd_proxy, BUS_NAME, unit, BUS_NAME_UNIT,
 166                                   name, callback, userdata, pending, timeout)
 167            : NULL;
 168 }
 169 
 170 void
 171 systemd_cleanup(void)
     
 172 {
 173     if (systemd_proxy) {
 174         pcmk_dbus_disconnect(systemd_proxy);
 175         systemd_proxy = NULL;
 176     }
 177 }
 178 
 179 
 180 
 181 
 182 
 183 
 184 
 185 
 186 
 187 
 188 
 189 
 190 
 191 static const char *
 192 systemd_unit_extension(const char *name)
     
 193 {
 194     if (name) {
 195         const char *dot = strrchr(name, '.');
 196 
 197         if (dot && (!strcmp(dot, ".service")
 198                     || !strcmp(dot, ".socket")
 199                     || !strcmp(dot, ".mount")
 200                     || !strcmp(dot, ".timer")
 201                     || !strcmp(dot, ".path"))) {
 202             return dot;
 203         }
 204     }
 205     return NULL;
 206 }
 207 
 208 static char *
 209 systemd_service_name(const char *name, bool add_instance_name)
     
 210 {
 211     const char *dot = NULL;
 212 
 213     if (pcmk__str_empty(name)) {
 214         return NULL;
 215     }
 216 
 217     
 218 
 219 
 220 
 221 
 222 
 223 
 224 
 225 
 226     dot = systemd_unit_extension(name);
 227 
 228     if (dot) {
 229         if (dot != name && *(dot-1) == '@') {
 230             char *s = NULL;
 231 
 232             if (asprintf(&s, "%.*spacemaker%s", (int) (dot-name), name, dot) == -1) {
 233                 
 234                 return strdup(name);
 235             }
 236 
 237             return s;
 238         } else {
 239             return strdup(name);
 240         }
 241 
 242     } else if (add_instance_name && *(name+strlen(name)-1) == '@') {
 243         return crm_strdup_printf("%spacemaker.service", name);
 244 
 245     } else {
 246         return crm_strdup_printf("%s.service", name);
 247     }
 248 }
 249 
 250 static void
 251 systemd_daemon_reload_complete(DBusPendingCall *pending, void *user_data)
     
 252 {
 253     DBusError error;
 254     DBusMessage *reply = NULL;
 255     unsigned int reload_count = GPOINTER_TO_UINT(user_data);
 256 
 257     dbus_error_init(&error);
 258     if(pending) {
 259         reply = dbus_pending_call_steal_reply(pending);
 260     }
 261 
 262     if (pcmk_dbus_find_error(pending, reply, &error)) {
 263         crm_warn("Could not issue systemd reload %d: %s",
 264                  reload_count, error.message);
 265         dbus_error_free(&error);
 266 
 267     } else {
 268         crm_trace("Reload %d complete", reload_count);
 269     }
 270 
 271     if(pending) {
 272         dbus_pending_call_unref(pending);
 273     }
 274     if(reply) {
 275         dbus_message_unref(reply);
 276     }
 277 }
 278 
 279 static bool
 280 systemd_daemon_reload(int timeout)
     
 281 {
 282     static unsigned int reload_count = 0;
 283     DBusMessage *msg = systemd_new_method("Reload");
 284 
 285     reload_count++;
 286     CRM_ASSERT(msg != NULL);
 287     systemd_send(msg, systemd_daemon_reload_complete,
 288                  GUINT_TO_POINTER(reload_count), timeout);
 289     dbus_message_unref(msg);
 290 
 291     return TRUE;
 292 }
 293 
 294 
 295 
 296 
 297 
 298 
 299 
 300 
 301 static void
 302 set_result_from_method_error(svc_action_t *op, const DBusError *error)
     
 303 {
 304     services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
 305                          "Unable to invoke systemd DBus method");
 306 
 307     if (strstr(error->name, "org.freedesktop.systemd1.InvalidName")
 308         || strstr(error->name, "org.freedesktop.systemd1.LoadFailed")
 309         || strstr(error->name, "org.freedesktop.systemd1.NoSuchUnit")) {
 310 
 311         if (pcmk__str_eq(op->action, "stop", pcmk__str_casei)) {
 312             crm_trace("Masking systemd stop failure (%s) for %s "
 313                       "because unknown service can be considered stopped",
 314                       error->name, pcmk__s(op->rsc, "unknown resource"));
 315             services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 316             return;
 317         }
 318 
 319         services__format_result(op, PCMK_OCF_NOT_INSTALLED,
 320                                PCMK_EXEC_NOT_INSTALLED,
 321                                "systemd unit %s not found", op->agent);
 322     }
 323 
 324     crm_info("DBus request for %s of systemd unit %s%s%s failed: %s",
 325              op->action, op->agent,
 326              ((op->rsc == NULL)? "" : " for resource "), pcmk__s(op->rsc, ""),
 327              error->message);
 328 }
 329 
 330 
 331 
 332 
 333 
 334 
 335 
 336 
 337 
 338 
 339 
 340 static const char *
 341 execute_after_loadunit(DBusMessage *reply, svc_action_t *op)
     
 342 {
 343     const char *path = NULL;
 344     DBusError error;
 345 
 346     
 347 
 348 
 349     if (pcmk_dbus_find_error((void *) &path, reply, &error)) {
 350         if (op != NULL) {
 351             set_result_from_method_error(op, &error);
 352         }
 353         dbus_error_free(&error);
 354 
 355     } else if (!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH,
 356                                      __func__, __LINE__)) {
 357         if (op != NULL) {
 358             services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
 359                                  "systemd DBus method had unexpected reply");
 360             crm_info("Could not load systemd unit %s for %s: "
 361                      "DBus reply has unexpected type", op->agent, op->id);
 362         } else {
 363             crm_info("Could not load systemd unit: "
 364                      "DBus reply has unexpected type");
 365         }
 366 
 367     } else {
 368         dbus_message_get_args (reply, NULL,
 369                                DBUS_TYPE_OBJECT_PATH, &path,
 370                                DBUS_TYPE_INVALID);
 371     }
 372 
 373     if (op != NULL) {
 374         if (path != NULL) {
 375             invoke_unit_by_path(op, path);
 376 
 377         } else if (!(op->synchronous)) {
 378             services__format_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
 379                                     "No DBus object found for systemd unit %s",
 380                                     op->agent);
 381             services__finalize_async_op(op);
 382         }
 383     }
 384 
 385     return path;
 386 }
 387 
 388 
 389 
 390 
 391 
 392 
 393 
 394 
 395 static void
 396 loadunit_completed(DBusPendingCall *pending, void *user_data)
     
 397 {
 398     DBusMessage *reply = NULL;
 399     svc_action_t *op = user_data;
 400 
 401     crm_trace("LoadUnit result for %s arrived", op->id);
 402 
 403     
 404     if (pending != NULL) {
 405         reply = dbus_pending_call_steal_reply(pending);
 406     }
 407 
 408     
 409     CRM_LOG_ASSERT(pending == op->opaque->pending);
 410     services_set_op_pending(op, NULL);
 411 
 412     
 413     execute_after_loadunit(reply, user_data);
 414     if (reply != NULL) {
 415         dbus_message_unref(reply);
 416     }
 417 }
 418 
 419 
 420 
 421 
 422 
 423 
 424 
 425 
 426 
 427 
 428 
 429 
 430 
 431 
 432 
 433 
 434 static int
 435 invoke_unit_by_name(const char *arg_name, svc_action_t *op, char **path)
     
 436 {
 437     DBusMessage *msg;
 438     DBusMessage *reply = NULL;
 439     DBusPendingCall *pending = NULL;
 440     char *name = NULL;
 441 
 442     if (!systemd_init()) {
 443         if (op != NULL) {
 444             services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
 445                                  "No DBus connection");
 446         }
 447         return ENOTCONN;
 448     }
 449 
 450     
 451 
 452 
 453 
 454 
 455 
 456 
 457 
 458     msg = systemd_new_method("LoadUnit");
 459     CRM_ASSERT(msg != NULL);
 460 
 461     
 462     name = systemd_service_name(arg_name, op == NULL || pcmk__str_eq(op->action, "meta-data", pcmk__str_none));
 463     CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name,
 464                                             DBUS_TYPE_INVALID));
 465     free(name);
 466 
 467     if ((op == NULL) || op->synchronous) {
 468         
 469         const char *unit = NULL;
 470         int rc = pcmk_rc_ok;
 471 
 472         reply = systemd_send_recv(msg, NULL,
 473                                   (op? op->timeout : DBUS_TIMEOUT_USE_DEFAULT));
 474         dbus_message_unref(msg);
 475 
 476         unit = execute_after_loadunit(reply, op);
 477         if (unit == NULL) {
 478             rc = ENOENT;
 479             if (path != NULL) {
 480                 *path = NULL;
 481             }
 482         } else if (path != NULL) {
 483             *path = strdup(unit);
 484             if (*path == NULL) {
 485                 rc = ENOMEM;
 486             }
 487         }
 488 
 489         if (reply != NULL) {
 490             dbus_message_unref(reply);
 491         }
 492         return rc;
 493     }
 494 
 495     
 496     pending = systemd_send(msg, loadunit_completed, op, op->timeout);
 497     if (pending == NULL) {
 498         services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
 499                              "Unable to send DBus message");
 500         dbus_message_unref(msg);
 501         return ECOMM;
 502     }
 503 
 504     
 505     services__set_result(op, PCMK_OCF_UNKNOWN, PCMK_EXEC_PENDING, NULL);
 506     services_set_op_pending(op, pending);
 507     dbus_message_unref(msg);
 508     return pcmk_rc_ok;
 509 }
 510 
 511 
 512 
 513 
 514 
 515 
 516 
 517 
 518 
 519 
 520 
 521 
 522 
 523 static gint
 524 sort_str(gconstpointer a, gconstpointer b)
     
 525 {
 526     if (!a && !b) {
 527         return 0;
 528     } else if (!a) {
 529         return -1;
 530     } else if (!b) {
 531         return 1;
 532     }
 533     return strcasecmp(a, b);
 534 }
 535 
 536 GList *
 537 systemd_unit_listall(void)
     
 538 {
 539     int nfiles = 0;
 540     GList *units = NULL;
 541     DBusMessageIter args;
 542     DBusMessageIter unit;
 543     DBusMessageIter elem;
 544     DBusMessage *reply = NULL;
 545 
 546     if (systemd_init() == FALSE) {
 547         return NULL;
 548     }
 549 
 550 
 551 
 552 
 553 
 554 
 555 
 556     reply = systemd_call_simple_method("ListUnitFiles");
 557     if (reply == NULL) {
 558         return NULL;
 559     }
 560     if (!dbus_message_iter_init(reply, &args)) {
 561         crm_err("Could not list systemd unit files: systemd reply has no arguments");
 562         dbus_message_unref(reply);
 563         return NULL;
 564     }
 565     if (!pcmk_dbus_type_check(reply, &args, DBUS_TYPE_ARRAY,
 566                               __func__, __LINE__)) {
 567         crm_err("Could not list systemd unit files: systemd reply has invalid arguments");
 568         dbus_message_unref(reply);
 569         return NULL;
 570     }
 571 
 572     dbus_message_iter_recurse(&args, &unit);
 573     for (; dbus_message_iter_get_arg_type(&unit) != DBUS_TYPE_INVALID;
 574         dbus_message_iter_next(&unit)) {
 575 
 576         DBusBasicValue value;
 577         const char *match = NULL;
 578         char *unit_name = NULL;
 579         char *basename = NULL;
 580 
 581         if(!pcmk_dbus_type_check(reply, &unit, DBUS_TYPE_STRUCT, __func__, __LINE__)) {
 582             crm_warn("Skipping systemd reply argument with unexpected type");
 583             continue;
 584         }
 585 
 586         dbus_message_iter_recurse(&unit, &elem);
 587         if(!pcmk_dbus_type_check(reply, &elem, DBUS_TYPE_STRING, __func__, __LINE__)) {
 588             crm_warn("Skipping systemd reply argument with no string");
 589             continue;
 590         }
 591 
 592         dbus_message_iter_get_basic(&elem, &value);
 593         if (value.str == NULL) {
 594             crm_debug("ListUnitFiles reply did not provide a string");
 595             continue;
 596         }
 597         crm_trace("DBus ListUnitFiles listed: %s", value.str);
 598 
 599         match = systemd_unit_extension(value.str);
 600         if (match == NULL) {
 601             
 602             crm_debug("ListUnitFiles entry '%s' is not supported as resource",
 603                       value.str);
 604             continue;
 605         }
 606 
 607         
 608         basename = strrchr(value.str, '/');
 609         if (basename) {
 610             basename = basename + 1;
 611         } else {
 612             basename = value.str;
 613         }
 614 
 615         if (!strcmp(match, ".service")) {
 616             
 617             unit_name = strndup(basename, match - basename);
 618         } else {
 619             unit_name = strdup(basename);
 620         }
 621 
 622         nfiles++;
 623         units = g_list_prepend(units, unit_name);
 624     }
 625 
 626     dbus_message_unref(reply);
 627 
 628     crm_trace("Found %d manageable systemd unit files", nfiles);
 629     units = g_list_sort(units, sort_str);
 630     return units;
 631 }
 632 
 633 gboolean
 634 systemd_unit_exists(const char *name)
     
 635 {
 636     char *path = NULL;
 637     char *state = NULL;
 638 
 639     
 640 
 641 
 642     if ((invoke_unit_by_name(name, NULL, &path) != pcmk_rc_ok)
 643         || (path == NULL)) {
 644         return FALSE;
 645     }
 646 
 647     
 648 
 649 
 650 
 651     state = systemd_get_property(path, "LoadState", NULL, NULL, NULL,
 652                                  DBUS_TIMEOUT_USE_DEFAULT);
 653     free(path);
 654     if (pcmk__str_any_of(state, "loaded", "masked", NULL)) {
 655         free(state);
 656         return TRUE;
 657     }
 658     free(state);
 659     return FALSE;
 660 }
 661 
 662 #define METADATA_FORMAT                                                     \
 663     "<?xml version=\"1.0\"?>\n"                                             \
 664     "<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n"                   \
 665     "<resource-agent name=\"%s\" version=\"" PCMK_DEFAULT_AGENT_VERSION "\">\n" \
 666     "  <version>1.1</version>\n"                                            \
 667     "  <longdesc lang=\"en\">\n"                                            \
 668     "    %s\n"                                                              \
 669     "  </longdesc>\n"                                                       \
 670     "  <shortdesc lang=\"en\">systemd unit file for %s</shortdesc>\n"       \
 671     "  <parameters/>\n"                                                     \
 672     "  <actions>\n"                                                         \
 673     "    <action name=\"start\"     timeout=\"100\" />\n"                   \
 674     "    <action name=\"stop\"      timeout=\"100\" />\n"                   \
 675     "    <action name=\"status\"    timeout=\"100\" />\n"                   \
 676     "    <action name=\"monitor\"   timeout=\"100\" interval=\"60\"/>\n"    \
 677     "    <action name=\"meta-data\" timeout=\"5\"   />\n"                   \
 678     "  </actions>\n"                                                        \
 679     "  <special tag=\"systemd\"/>\n"                                        \
 680     "</resource-agent>\n"
 681 
 682 static char *
 683 systemd_unit_metadata(const char *name, int timeout)
     
 684 {
 685     char *meta = NULL;
 686     char *desc = NULL;
 687     char *path = NULL;
 688 
 689     char *escaped = NULL;
 690 
 691     if (invoke_unit_by_name(name, NULL, &path) == pcmk_rc_ok) {
 692         
 693         desc = systemd_get_property(path, "Description", NULL, NULL, NULL,
 694                                     timeout);
 695     } else {
 696         desc = crm_strdup_printf("Systemd unit file for %s", name);
 697     }
 698 
 699     escaped = crm_xml_escape(desc);
 700 
 701     meta = crm_strdup_printf(METADATA_FORMAT, name, escaped, name);
 702     free(desc);
 703     free(path);
 704     free(escaped);
 705     return meta;
 706 }
 707 
 708 
 709 
 710 
 711 
 712 
 713 
 714 
 715 static void
 716 process_unit_method_reply(DBusMessage *reply, svc_action_t *op)
     
 717 {
 718     DBusError error;
 719 
 720     
 721 
 722 
 723     if (pcmk_dbus_find_error((void *) &error, reply, &error)) {
 724         set_result_from_method_error(op, &error);
 725         dbus_error_free(&error);
 726 
 727     } else if (!pcmk_dbus_type_check(reply, NULL, DBUS_TYPE_OBJECT_PATH,
 728                                      __func__, __LINE__)) {
 729         crm_info("DBus request for %s of %s succeeded but "
 730                  "return type was unexpected",
 731                  op->action, pcmk__s(op->rsc, "unknown resource"));
 732         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE,
 733                              "systemd DBus method had unexpected reply");
 734 
 735     } else {
 736         const char *path = NULL;
 737 
 738         dbus_message_get_args(reply, NULL,
 739                               DBUS_TYPE_OBJECT_PATH, &path,
 740                               DBUS_TYPE_INVALID);
 741         crm_debug("DBus request for %s of %s using %s succeeded",
 742                   op->action, pcmk__s(op->rsc, "unknown resource"), path);
 743         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 744     }
 745 }
 746 
 747 
 748 
 749 
 750 
 751 
 752 
 753 
 754 static void
 755 unit_method_complete(DBusPendingCall *pending, void *user_data)
     
 756 {
 757     DBusMessage *reply = NULL;
 758     svc_action_t *op = user_data;
 759 
 760     crm_trace("Result for %s arrived", op->id);
 761 
 762     
 763     if (pending != NULL) {
 764         reply = dbus_pending_call_steal_reply(pending);
 765     }
 766 
 767     
 768     CRM_LOG_ASSERT(pending == op->opaque->pending);
 769     services_set_op_pending(op, NULL);
 770 
 771     
 772     process_unit_method_reply(reply, op);
 773     services__finalize_async_op(op);
 774     if (reply != NULL) {
 775         dbus_message_unref(reply);
 776     }
 777 }
 778 
 779 #define SYSTEMD_OVERRIDE_ROOT "/run/systemd/system/"
 780 
 781 
 782 
 783 
 784 
 785 
 786 
 787 
 788 
 789 
 790 #define SYSTEMD_OVERRIDE_TEMPLATE                           \
 791     "[Unit]\n"                                              \
 792     "Description=Cluster Controlled %s\n"                   \
 793     "Before=pacemaker.service pacemaker_remote.service\n"   \
 794     "\n"                                                    \
 795     "[Service]\n"                                           \
 796     "Restart=no\n"
 797 
 798 
 799 static FILE *
 800 create_world_readable(const char *filename)
     
 801 {
 802     mode_t orig_umask = umask(S_IWGRP | S_IWOTH);
 803     FILE *fp = fopen(filename, "w");
 804 
 805     umask(orig_umask);
 806     return fp;
 807 }
 808 
 809 static void
 810 create_override_dir(const char *agent)
     
 811 {
 812     char *override_dir = crm_strdup_printf(SYSTEMD_OVERRIDE_ROOT
 813                                            "/%s.service.d", agent);
 814     int rc = pcmk__build_path(override_dir, 0755);
 815 
 816     if (rc != pcmk_rc_ok) {
 817         crm_warn("Could not create systemd override directory %s: %s",
 818                  override_dir, pcmk_rc_str(rc));
 819     }
 820     free(override_dir);
 821 }
 822 
 823 static char *
 824 get_override_filename(const char *agent)
     
 825 {
 826     return crm_strdup_printf(SYSTEMD_OVERRIDE_ROOT
 827                              "/%s.service.d/50-pacemaker.conf", agent);
 828 }
 829 
 830 static void
 831 systemd_create_override(const char *agent, int timeout)
     
 832 {
 833     FILE *file_strm = NULL;
 834     char *override_file = get_override_filename(agent);
 835 
 836     create_override_dir(agent);
 837 
 838     
 839 
 840 
 841     file_strm = create_world_readable(override_file);
 842     if (file_strm == NULL) {
 843         crm_err("Cannot open systemd override file %s for writing",
 844                 override_file);
 845     } else {
 846         char *override = crm_strdup_printf(SYSTEMD_OVERRIDE_TEMPLATE, agent);
 847 
 848         int rc = fprintf(file_strm, "%s\n", override);
 849 
 850         free(override);
 851         if (rc < 0) {
 852             crm_perror(LOG_WARNING, "Cannot write to systemd override file %s",
 853                        override_file);
 854         }
 855         fflush(file_strm);
 856         fclose(file_strm);
 857         systemd_daemon_reload(timeout);
 858     }
 859 
 860     free(override_file);
 861 }
 862 
 863 static void
 864 systemd_remove_override(const char *agent, int timeout)
     
 865 {
 866     char *override_file = get_override_filename(agent);
 867     int rc = unlink(override_file);
 868 
 869     if (rc < 0) {
 870         
 871         crm_perror(LOG_DEBUG, "Cannot remove systemd override file %s",
 872                    override_file);
 873     } else {
 874         systemd_daemon_reload(timeout);
 875     }
 876     free(override_file);
 877 }
 878 
 879 
 880 
 881 
 882 
 883 
 884 
 885 
 886 
 887 
 888 
 889 
 890 static void
 891 parse_status_result(const char *name, const char *state, void *userdata)
     
 892 {
 893     svc_action_t *op = userdata;
 894 
 895     crm_trace("Resource %s has %s='%s'",
 896               pcmk__s(op->rsc, "(unspecified)"), name,
 897               pcmk__s(state, "<null>"));
 898 
 899     if (pcmk__str_eq(state, "active", pcmk__str_none)) {
 900         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 901 
 902     } else if (pcmk__str_eq(state, "reloading", pcmk__str_none)) {
 903         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
 904 
 905     } else if (pcmk__str_eq(state, "activating", pcmk__str_none)) {
 906         services__set_result(op, PCMK_OCF_UNKNOWN, PCMK_EXEC_PENDING, NULL);
 907 
 908     } else if (pcmk__str_eq(state, "deactivating", pcmk__str_none)) {
 909         services__set_result(op, PCMK_OCF_UNKNOWN, PCMK_EXEC_PENDING, NULL);
 910 
 911     } else {
 912         services__set_result(op, PCMK_OCF_NOT_RUNNING, PCMK_EXEC_DONE, state);
 913     }
 914 
 915     if (!(op->synchronous)) {
 916         services_set_op_pending(op, NULL);
 917         services__finalize_async_op(op);
 918     }
 919 }
 920 
 921 
 922 
 923 
 924 
 925 
 926 
 927 
 928 static void
 929 invoke_unit_by_path(svc_action_t *op, const char *unit)
     
 930 {
 931     const char *method = NULL;
 932     DBusMessage *msg = NULL;
 933     DBusMessage *reply = NULL;
 934 
 935     if (pcmk__str_any_of(op->action, "monitor", "status", NULL)) {
 936         DBusPendingCall *pending = NULL;
 937         char *state;
 938 
 939         state = systemd_get_property(unit, "ActiveState",
 940                                      (op->synchronous? NULL : parse_status_result),
 941                                      op, (op->synchronous? NULL : &pending),
 942                                      op->timeout);
 943         if (op->synchronous) {
 944             parse_status_result("ActiveState", state, op);
 945             free(state);
 946 
 947         } else if (pending == NULL) { 
 948             services__format_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
 949                                     "Could not get state for unit %s from DBus",
 950                                     op->agent);
 951             services__finalize_async_op(op);
 952 
 953         } else {
 954             services_set_op_pending(op, pending);
 955         }
 956         return;
 957 
 958     } else if (pcmk__str_eq(op->action, "start", pcmk__str_none)) {
 959         method = "StartUnit";
 960         systemd_create_override(op->agent, op->timeout);
 961 
 962     } else if (pcmk__str_eq(op->action, "stop", pcmk__str_none)) {
 963         method = "StopUnit";
 964         systemd_remove_override(op->agent, op->timeout);
 965 
 966     } else if (pcmk__str_eq(op->action, "restart", pcmk__str_none)) {
 967         method = "RestartUnit";
 968 
 969     } else {
 970         services__format_result(op, PCMK_OCF_UNIMPLEMENT_FEATURE,
 971                                 PCMK_EXEC_ERROR,
 972                                 "Action %s not implemented "
 973                                 "for systemd resources",
 974                                 pcmk__s(op->action, "(unspecified)"));
 975         if (!(op->synchronous)) {
 976             services__finalize_async_op(op);
 977         }
 978         return;
 979     }
 980 
 981     crm_trace("Calling %s for unit path %s%s%s",
 982               method, unit,
 983               ((op->rsc == NULL)? "" : " for resource "), pcmk__s(op->rsc, ""));
 984 
 985     msg = systemd_new_method(method);
 986     CRM_ASSERT(msg != NULL);
 987 
 988     
 989     {
 990         const char *replace_s = "replace";
 991         char *name = systemd_service_name(op->agent, pcmk__str_eq(op->action, "meta-data", pcmk__str_none));
 992 
 993         CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID));
 994         CRM_LOG_ASSERT(dbus_message_append_args(msg, DBUS_TYPE_STRING, &replace_s, DBUS_TYPE_INVALID));
 995 
 996         free(name);
 997     }
 998 
 999     if (op->synchronous) {
1000         reply = systemd_send_recv(msg, NULL, op->timeout);
1001         dbus_message_unref(msg);
1002         process_unit_method_reply(reply, op);
1003         if (reply != NULL) {
1004             dbus_message_unref(reply);
1005         }
1006 
1007     } else {
1008         DBusPendingCall *pending = systemd_send(msg, unit_method_complete, op,
1009                                                 op->timeout);
1010 
1011         dbus_message_unref(msg);
1012         if (pending == NULL) {
1013             services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
1014                                  "Unable to send DBus message");
1015             services__finalize_async_op(op);
1016 
1017         } else {
1018             services_set_op_pending(op, pending);
1019         }
1020     }
1021 }
1022 
1023 static gboolean
1024 systemd_timeout_callback(gpointer p)
     
1025 {
1026     svc_action_t * op = p;
1027 
1028     op->opaque->timerid = 0;
1029     crm_info("%s action for systemd unit %s named '%s' timed out",
1030              op->action, op->agent, op->rsc);
1031     services__format_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_TIMEOUT,
1032                             "%s action for systemd unit %s "
1033                             "did not complete in time", op->action, op->agent);
1034     services__finalize_async_op(op);
1035     return FALSE;
1036 }
1037 
1038 
1039 
1040 
1041 
1042 
1043 
1044 
1045 
1046 
1047 
1048 
1049 
1050 
1051 
1052 
1053 
1054 int
1055 services__execute_systemd(svc_action_t *op)
     
1056 {
1057     CRM_ASSERT(op != NULL);
1058 
1059     if ((op->action == NULL) || (op->agent == NULL)) {
1060         services__set_result(op, PCMK_OCF_NOT_CONFIGURED, PCMK_EXEC_ERROR_FATAL,
1061                              "Bug in action caller");
1062         goto done;
1063     }
1064 
1065     if (!systemd_init()) {
1066         services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
1067                              "No DBus connection");
1068         goto done;
1069     }
1070 
1071     crm_debug("Performing %ssynchronous %s op on systemd unit %s%s%s",
1072               (op->synchronous? "" : "a"), op->action, op->agent,
1073               ((op->rsc == NULL)? "" : " for resource "), pcmk__s(op->rsc, ""));
1074 
1075     if (pcmk__str_eq(op->action, "meta-data", pcmk__str_casei)) {
1076         op->stdout_data = systemd_unit_metadata(op->agent, op->timeout);
1077         services__set_result(op, PCMK_OCF_OK, PCMK_EXEC_DONE, NULL);
1078         goto done;
1079     }
1080 
1081     
1082 
1083 
1084     services__set_result(op, PCMK_OCF_UNKNOWN_ERROR, PCMK_EXEC_ERROR,
1085                          "Bug in service library");
1086 
1087     if (invoke_unit_by_name(op->agent, op, NULL) == pcmk_rc_ok) {
1088         op->opaque->timerid = g_timeout_add(op->timeout + 5000,
1089                                             systemd_timeout_callback, op);
1090         services_add_inflight_op(op);
1091         return pcmk_rc_ok;
1092     }
1093 
1094 done:
1095     if (op->synchronous) {
1096         return (op->rc == PCMK_OCF_OK)? pcmk_rc_ok : pcmk_rc_error;
1097     } else {
1098         return services__finalize_async_op(op);
1099     }
1100 }