diff --git a/devel/Makefile.am b/devel/Makefile.am index 27237be980..bdfca76069 100644 --- a/devel/Makefile.am +++ b/devel/Makefile.am @@ -1,59 +1,68 @@ # # Copyright 2020 the Pacemaker project contributors # # The version control history for this file may have further details. # # This source code is licensed under the GNU General Public License version 2 # or later (GPLv2+) WITHOUT ANY WARRANTY. # EXTRA_SCRIPTS = coccinelle/test/testrunner.sh EXTRA_DIST = $(EXTRA_SCRIPTS) \ coccinelle/ref-passed-variables-inited.cocci \ coccinelle/string-any-of.cocci \ coccinelle/string-empty.cocci \ coccinelle/string-null-matches.cocci \ coccinelle/string-replacements.cocci \ coccinelle/test/ref-passed-variables-inited.input.c \ coccinelle/test/ref-passed-variables-inited.output # Coccinelle is a tool that takes special patch-like files (called semantic patches) and # applies them throughout a source tree. This is useful when refactoring, changing APIs, # catching dangerous or incorrect code, and other similar tasks. It's not especially # easy to write a semantic patch but most users should only be concerned about running # the target and inspecting the results. # # Documentation (including examples, which are the most useful): # http://coccinelle.lip6.fr/documentation.php # # Run the "make cocci" target to just output what would be done, or "make cocci-inplace" # to apply the changes to the source tree. # # COCCI_FILES may be set on the command line, if you want to test just a single file # while it's under development. Otherwise, it is a list of all the files that are ready # to be run. # # ref-passed-variables-inited.cocci seems to be returning some false positives around # GHashTableIters, so it is disabled for the moment. COCCI_FILES ?= coccinelle/string-any-of.cocci \ coccinelle/string-empty.cocci \ coccinelle/string-null-matches.cocci +# Any file in this list is allowed to use any of the pcmk__ internal functions. +# Coccinelle can use any transformation that depends on "internal" to rewrite +# code to use the internal functions. +MAY_USE_INTERNAL_FILES = $(shell find .. -path "../lib/*.c" -o -path "../tools/*.c" -o -path "../daemons/*.c" -o -path '../include/pcmki/*h' -o -name '*internal.h') + +# And then any file in this list is public API, which may not use internal +# functions. Thus, only those transformations that do not depend on "internal" +# may be applied. +OTHER_FILES = $(shell find ../include -name '*h' -a \! -name '*internal.h' -a \! -path '../include/pcmki/*') + cocci: - for f in $(COCCI_FILES); do \ - for d in daemons include lib tools; do \ - test $$d = "include" \ - && spatch $(_SPATCH_FLAGS) --include-headers --local-includes \ - --preprocess --sp-file $$f --dir ../$$d \ - || spatch $(_SPATCH_FLAGS) --local-includes \ - --preprocess --sp-file $$f --dir ../$$d; \ - done; \ + for cf in $(COCCI_FILES); do \ + for f in $(MAY_USE_INTERNAL_FILES); do \ + spatch $(_SPATCH_FLAGS) -D internal --very-quiet --local-includes --preprocess --sp-file $$cf $$f; \ + done ; \ + for f in $(OTHER_FILES); do \ + spatch $(_SPATCH_FLAGS) --very-quiet --local-includes --preprocess --sp-file $$cf $$f; \ + done ; \ done cocci-inplace: $(MAKE) $(AM_MAKEFLAGS) _SPATCH_FLAGS=--in-place cocci cocci-test: for f in coccinelle/test/*.c; do \ coccinelle/test/testrunner.sh $$f; \ done diff --git a/devel/coccinelle/ref-passed-variables-inited.cocci b/devel/coccinelle/ref-passed-variables-inited.cocci index 1cc28efea8..0d19ff756d 100644 --- a/devel/coccinelle/ref-passed-variables-inited.cocci +++ b/devel/coccinelle/ref-passed-variables-inited.cocci @@ -1,48 +1,50 @@ /* * Copyright 2019-2020 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU General Public License version 2 * or later (GPLv2+) WITHOUT ANY WARRANTY. * * * We require each local variable that * * - is passed to a function through a dereference (suggesting it serves * possibly also or merely as one of the output value propagators seperate * from actual return value if employed at all) and * * - is then subsequently reused (possibly naively expecting it will always * have been initialized (in said function at latest) further in its scope, * * to _always_ be assuredly initialized to some determined value, so as to * prevent a risk of accidentally accessing unspecified value subsequent * to the return from the considered function, which might not have set * that variable at all, lest it would touch it at all. */ +virtual internal + @ref_passed_variables_inited exists@ identifier f_init, f_consume, var; type T; expression E, E_propagate; @@ T - var + var /*FIXME:initialize me*/ ; ... when != var = E f_init(..., &var, ...) ... when != var = E ( return var; | f_consume(..., var, ...) | E_propagate = var | &var | *var ) diff --git a/devel/coccinelle/string-any-of.cocci b/devel/coccinelle/string-any-of.cocci index d63ad2e0a5..ef1a2e96dd 100644 --- a/devel/coccinelle/string-any-of.cocci +++ b/devel/coccinelle/string-any-of.cocci @@ -1,74 +1,76 @@ /* * Copyright 2020 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU General Public License version 2 * or later (GPLv2+) WITHOUT ANY WARRANTY. * * Catch string comparisons where the pcmk__str_any_of function could be used * instead. Note that we are only catching uses involving identifiers (not * expressions), but I think this is probably fine - we are likely not using * the same expression multiple times in a single line of code. If some are * found, it's easy enough to add another block here. */ -@ any_of_1 @ +virtual internal + +@ any_of_1 depends on internal @ expression test_str, str, new_str; identifier I =~ "pcmk__str_none"; @@ - pcmk__str_eq(test_str, str, I) || pcmk__str_eq(test_str, new_str, I) + pcmk__str_any_of(test_str, str, new_str, NULL) -@ any_of_2 @ +@ any_of_2 depends on internal @ expression test_str, str, new_str; identifier I =~ "pcmk__str_casei"; @@ - pcmk__str_eq(test_str, str, I) || pcmk__str_eq(test_str, new_str, I) + pcmk__strcase_any_of(test_str, str, new_str, NULL) -@ any_of_3 @ +@ any_of_3 depends on internal @ expression test_str, new_str; expression list strs; identifier I =~ "pcmk__str_none"; @@ - pcmk__str_any_of(test_str, strs, NULL) || pcmk__str_eq(test_str, new_str, I) + pcmk__str_any_of(test_str, strs, new_str, NULL) -@ any_of_4 @ +@ any_of_4 depends on internal @ expression test_str, new_str; expression list strs; identifier I =~ "pcmk__str_casei"; @@ - pcmk__strcase_any_of(test_str, strs, NULL) || pcmk__str_eq(test_str, new_str, I) + pcmk__strcase_any_of(test_str, strs, new_str, NULL) -@ none_of_1 @ +@ none_of_1 depends on internal @ expression test_str, str, new_str; identifier I =~ "pcmk__str_none"; @@ - !pcmk__str_eq(test_str, str, I) && !pcmk__str_eq(test_str, new_str, I) + !pcmk__str_any_of(test_str, str, new_str, NULL) -@ none_of_2 @ +@ none_of_2 depends on internal @ expression test_str, str, new_str; identifier I =~ "pcmk__str_casei"; @@ - !pcmk__str_eq(test_str, str, I) && !pcmk__str_eq(test_str, new_str, I) + !pcmk__strcase_any_of(test_str, str, new_str, NULL) -@ none_of_3 @ +@ none_of_3 depends on internal @ expression test_str, new_str; expression list strs; identifier I =~ "pcmk__str_none"; @@ - !pcmk__str_any_of(test_str, strs, NULL) && !pcmk__str_eq(test_str, new_str, I) + !pcmk__str_any_of(test_str, strs, new_str, NULL) -@ none_of_4 @ +@ none_of_4 depends on internal @ expression test_str, new_str; expression list strs; identifier I =~ "pcmk__str_casei"; @@ - !pcmk__strcase_any_of(test_str, strs, NULL) && !pcmk__str_eq(test_str, new_str, I) + !pcmk__strcase_any_of(test_str, strs, new_str, NULL) diff --git a/devel/coccinelle/string-empty.cocci b/devel/coccinelle/string-empty.cocci index 7abd558794..d51f69ca8a 100644 --- a/devel/coccinelle/string-empty.cocci +++ b/devel/coccinelle/string-empty.cocci @@ -1,28 +1,30 @@ /* * Copyright 2020 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU General Public License version 2 * or later (GPLv2+) WITHOUT ANY WARRANTY. * * Catch string comparisons where the pcmk__str_empty function could be used * instead. Note that we are only catching uses involving identifiers (not * expressions), but I think this is probably fine - we are likely not using * the same expression multiple times in a single line of code. If some are * found, it's easy enough to add another block here. */ -@ string_empty @ +virtual internal + +@ string_empty depends on internal @ identifier I; @@ ( - (I == NULL) || (strlen(I) == 0) + pcmk__str_empty(I) | - (I == NULL) || !strlen(I) + pcmk__str_empty(I) | - (I == NULL) || (I[0] == 0) + pcmk__str_empty(I) ) diff --git a/devel/coccinelle/string-null-matches.cocci b/devel/coccinelle/string-null-matches.cocci index 00b0b26bc4..b5471f694d 100644 --- a/devel/coccinelle/string-null-matches.cocci +++ b/devel/coccinelle/string-null-matches.cocci @@ -1,72 +1,74 @@ /* * Copyright 2020 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU General Public License version 2 * or later (GPLv2+) WITHOUT ANY WARRANTY. * * Catch places where a string can either be NULL or can match some other * string. In these cases, passing the right flag to pcmk__str_eq will get * the same result but without having to do the NULL comparison manually. */ -@ string_null_matches_1 @ +virtual internal + +@ string_null_matches_1 depends on internal @ expression E1, E2; @@ - ((E1 == NULL) || crm_str_eq(E1, E2, TRUE)) + pcmk__str_eq(E1, E2, pcmk__str_null_matches) -@ string_null_matches_2 @ +@ string_null_matches_2 depends on internal @ expression E1, E2; @@ - ((E1 == NULL) || crm_str_eq(E2, E1, TRUE)) + pcmk__str_eq(E1, E2, pcmk__str_null_matches) -@ string_null_matches_3 @ +@ string_null_matches_3 depends on internal @ expression E1, E2; @@ - ((E1 == NULL) || safe_str_eq(E1, E2)) + pcmk__str_eq(E1, E2, pcmk__str_null_matches|pcmk__str_casei) -@ string_null_matches_4 @ +@ string_null_matches_4 depends on internal @ expression E1, E2; @@ - ((E1 == NULL) || safe_str_eq(E2, E1)) + pcmk__str_eq(E1, E2, pcmk__str_null_matches|pcmk__str_casei) -@ string_null_matches_5 @ +@ string_null_matches_5 depends on internal @ expression E1, E2; @@ - ((E1 == NULL) || strcmp(E1, E2) == 0) + pcmk__str_eq(E1, E2, pcmk__str_null_matches) -@ string_null_matches_6 @ +@ string_null_matches_6 depends on internal @ expression E1, E2; @@ - ((E1 == NULL) || strcmp(E2, E1) == 0) + pcmk__str_eq(E1, E2, pcmk__str_null_matches) -@ string_null_matches_7 @ +@ string_null_matches_7 depends on internal @ expression E1, E2; @@ - ((E1 == NULL) || !strcmp(E1, E2)) + pcmk__str_eq(E1, E2, pcmk__str_null_matches) -@ string_null_matches_8 @ +@ string_null_matches_8 depends on internal @ expression E1, E2; @@ - ((E1 == NULL) || !strcmp(E2, E1)) + pcmk__str_eq(E1, E2, pcmk__str_null_matches) -@ string_null_matches_9 @ +@ string_null_matches_9 depends on internal @ expression E1, E2; @@ - ((E1 != NULL) && strcmp(E1, E2) != 0) + !pcmk__str_eq(E1, E2, pcmk__str_null_matches) -@ string_null_matches_10 @ +@ string_null_matches_10 depends on internal @ expression E1, E2; @@ - ((E1 != NULL) && strcmp(E2, E1) != 0) + !pcmk__str_eq(E1, E2, pcmk__str_null_matches) diff --git a/devel/coccinelle/string-replacements.cocci b/devel/coccinelle/string-replacements.cocci index f05f246ba6..86f81df77a 100644 --- a/devel/coccinelle/string-replacements.cocci +++ b/devel/coccinelle/string-replacements.cocci @@ -1,56 +1,58 @@ /* * Copyright 2020 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU General Public License version 2 * or later (GPLv2+) WITHOUT ANY WARRANTY. * * Catch string comparisons where the pcmk__str_eq function could be used * instead. Note that we are only catching uses involving identifiers (not * expressions), but I think this is probably fine - we are likely not using * the same expression multiple times in a single line of code. If some are * found, it's easy enough to add another block here. */ -@ safe_str_neq_replacement @ +virtual internal + +@ safe_str_neq_replacement depends on internal @ expression E1, E2; @@ - safe_str_neq(E1, E2) + !pcmk__str_eq(E1, E2, pcmk__str_casei) -@ safe_str_eq_replacement_1 @ +@ safe_str_eq_replacement_1 depends on internal @ expression E1, E2; @@ - safe_str_eq(E1, E2) + pcmk__str_eq(E1, E2, pcmk__str_casei) -@ safe_str_eq_replacement_2 @ +@ safe_str_eq_replacement_2 depends on internal @ expression E1, E2; @@ - safe_str_eq(E1, E2) == FALSE + !pcmk__str_eq(E1, E2, pcmk__str_casei) -@ crm_str_eq_replacement_1 @ +@ crm_str_eq_replacement_1 depends on internal @ expression E1, E2; @@ - crm_str_eq(E1, E2, TRUE) + pcmk__str_eq(E1, E2, pcmk__str_none) -@ crm_str_eq_replacement_2 @ +@ crm_str_eq_replacement_2 depends on internal @ expression E1, E2; @@ - crm_str_eq(E1, E2, FALSE) + pcmk__str_eq(E1, E2, pcmk__str_casei) -@ crm_str_eq_replacement_3 @ +@ crm_str_eq_replacement_3 depends on internal @ expression E1, E2; @@ - crm_str_eq(E1, E2, TRUE) == FALSE + !pcmk__str_eq(E1, E2, pcmk__str_none) -@ crm_str_eq_replacement_4 @ +@ crm_str_eq_replacement_4 depends on internal @ expression E1, E2; @@ - crm_str_eq(E1, E2, FALSE) == FALSE + !pcmk__str_eq(E1, E2, pcmk__str_casei) diff --git a/include/crm/services.h b/include/crm/services.h index 9ae08ff7f2..d47803d5e3 100644 --- a/include/crm/services.h +++ b/include/crm/services.h @@ -1,439 +1,432 @@ /* * Copyright 2010-2020 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #ifndef __PCMK_SERVICES__ # define __PCMK_SERVICES__ #ifdef __cplusplus extern "C" { #endif /** * \file * \brief Services API * \ingroup core */ # include # include # include # include # include # include # ifndef OCF_ROOT_DIR # define OCF_ROOT_DIR "/usr/lib/ocf" # endif # ifndef LSB_ROOT_DIR # define LSB_ROOT_DIR "/etc/init.d" # endif /* TODO: Autodetect these two ?*/ # ifndef SYSTEMCTL # define SYSTEMCTL "/bin/systemctl" # endif /* Known resource classes */ #define PCMK_RESOURCE_CLASS_OCF "ocf" #define PCMK_RESOURCE_CLASS_SERVICE "service" #define PCMK_RESOURCE_CLASS_LSB "lsb" #define PCMK_RESOURCE_CLASS_SYSTEMD "systemd" #define PCMK_RESOURCE_CLASS_UPSTART "upstart" #define PCMK_RESOURCE_CLASS_NAGIOS "nagios" #define PCMK_RESOURCE_CLASS_STONITH "stonith" /* This is the string passed in the OCF_EXIT_REASON_PREFIX environment variable. * The stderr output that occurs after this prefix is encountered is considered * the exit reason for a completed operation. */ #define PCMK_OCF_REASON_PREFIX "ocf-exit-reason:" // Agent version to use if agent doesn't specify one #define PCMK_DEFAULT_AGENT_VERSION "0.1" enum lsb_exitcode { PCMK_LSB_OK = 0, PCMK_LSB_UNKNOWN_ERROR = 1, PCMK_LSB_INVALID_PARAM = 2, PCMK_LSB_UNIMPLEMENT_FEATURE = 3, PCMK_LSB_INSUFFICIENT_PRIV = 4, PCMK_LSB_NOT_INSTALLED = 5, PCMK_LSB_NOT_CONFIGURED = 6, PCMK_LSB_NOT_RUNNING = 7, }; /* The return codes for the status operation are not the same for other * operatios - go figure */ enum lsb_status_exitcode { PCMK_LSB_STATUS_OK = 0, PCMK_LSB_STATUS_VAR_PID = 1, PCMK_LSB_STATUS_VAR_LOCK = 2, PCMK_LSB_STATUS_NOT_RUNNING = 3, PCMK_LSB_STATUS_UNKNOWN = 4, /* custom codes should be in the 150-199 range reserved for application use */ PCMK_LSB_STATUS_NOT_INSTALLED = 150, PCMK_LSB_STATUS_INSUFFICIENT_PRIV = 151, }; /* Uniform exit codes * Everything is mapped to its OCF equivalent so that Pacemaker only deals with one set of codes */ enum ocf_exitcode { PCMK_OCF_OK = 0, PCMK_OCF_UNKNOWN_ERROR = 1, PCMK_OCF_INVALID_PARAM = 2, PCMK_OCF_UNIMPLEMENT_FEATURE = 3, PCMK_OCF_INSUFFICIENT_PRIV = 4, PCMK_OCF_NOT_INSTALLED = 5, PCMK_OCF_NOT_CONFIGURED = 6, PCMK_OCF_NOT_RUNNING = 7, /* End of overlap with LSB */ PCMK_OCF_RUNNING_MASTER = 8, PCMK_OCF_FAILED_MASTER = 9, /* 150-199 reserved for application use */ PCMK_OCF_CONNECTION_DIED = 189, // Deprecated (see PCMK_LRM_OP_NOT_CONNECTED) PCMK_OCF_DEGRADED = 190, /* Active resource that is no longer 100% functional */ PCMK_OCF_DEGRADED_MASTER = 191, /* Promoted resource that is no longer 100% functional */ PCMK_OCF_EXEC_ERROR = 192, /* Generic problem invoking the agent */ PCMK_OCF_UNKNOWN = 193, /* State of the service is unknown - used for recording in-flight operations */ PCMK_OCF_SIGNAL = 194, PCMK_OCF_NOT_SUPPORTED = 195, PCMK_OCF_PENDING = 196, PCMK_OCF_CANCELLED = 197, PCMK_OCF_TIMEOUT = 198, PCMK_OCF_OTHER_ERROR = 199, /* Keep the same codes as PCMK_LSB */ }; enum op_status { PCMK_LRM_OP_UNKNOWN = -2, PCMK_LRM_OP_PENDING = -1, PCMK_LRM_OP_DONE, PCMK_LRM_OP_CANCELLED, PCMK_LRM_OP_TIMEOUT, PCMK_LRM_OP_NOTSUPPORTED, PCMK_LRM_OP_ERROR, PCMK_LRM_OP_ERROR_HARD, PCMK_LRM_OP_ERROR_FATAL, PCMK_LRM_OP_NOT_INSTALLED, PCMK_LRM_OP_NOT_CONNECTED, PCMK_LRM_OP_INVALID, }; enum nagios_exitcode { NAGIOS_STATE_OK = 0, NAGIOS_STATE_WARNING = 1, NAGIOS_STATE_CRITICAL = 2, NAGIOS_STATE_UNKNOWN = 3, NAGIOS_STATE_DEPENDENT = 4, NAGIOS_INSUFFICIENT_PRIV = 100, NAGIOS_NOT_INSTALLED = 101, }; enum svc_action_flags { /* On timeout, only kill pid, do not kill entire pid group */ SVC_ACTION_LEAVE_GROUP = 0x01, SVC_ACTION_NON_BLOCKED = 0x02, }; typedef struct svc_action_private_s svc_action_private_t; typedef struct svc_action_s { char *id; char *rsc; char *action; guint interval_ms; char *standard; char *provider; char *agent; int timeout; GHashTable *params; /* used for setting up environment for ocf-ra & alert agents and to be sent via stdin for fence-agents */ int rc; int pid; int cancel; int status; int sequence; int expected_rc; int synchronous; enum svc_action_flags flags; char *stderr_data; char *stdout_data; /*! * Data stored by the creator of the action. * * This may be used to hold data that is needed later on by a callback, * for example. */ void *cb_data; svc_action_private_t *opaque; } svc_action_t; /** * \brief Get a list of files or directories in a given path * * \param[in] root full path to a directory to read * \param[in] files return list of files if TRUE or directories if FALSE * \param[in] executable if TRUE and files is TRUE, only return executable files * * \return a list of what was found. The list items are char *. * \note It is the caller's responsibility to free the result with g_list_free_full(list, free). */ GList *get_directory_list(const char *root, gboolean files, gboolean executable); /** * Get a list of services * * \return a list of services. The list items are gchar *. This list _must_ * be destroyed using g_list_free_full(list, free). */ GList *services_list(void); /** * \brief Get a list of providers * * \param[in] standard list providers of this standard (e.g. ocf, lsb, etc.) * * \return a list of providers as char * list items (or NULL if standard does not support providers) * \note The caller is responsible for freeing the result using g_list_free_full(list, free). */ GList *resources_list_providers(const char *standard); /** * \brief Get a list of resource agents * * \param[in] standard list agents using this standard (e.g. ocf, lsb, etc.) (or NULL for all) * \param[in] provider list agents from this provider (or NULL for all) * * \return a list of resource agents. The list items are char *. * \note The caller is responsible for freeing the result using g_list_free_full(list, free). */ GList *resources_list_agents(const char *standard, const char *provider); /** * Get list of available standards * * \return a list of resource standards. The list items are char *. This list _must_ * be destroyed using g_list_free_full(list, free). */ GList *resources_list_standards(void); /** * Does the given standard, provider, and agent describe a resource that can exist? * * \param[in] standard Which class of agent does the resource belong to? * \param[in] provider What provides the agent (NULL for most standards)? * \param[in] agent What is the name of the agent? * * \return A boolean */ gboolean resources_agent_exists(const char *standard, const char *provider, const char *agent); svc_action_t *services_action_create(const char *name, const char *action, guint interval_ms, int timeout /* ms */); /** * \brief Create a new resource action * * \param[in] name Name of resource * \param[in] standard Resource agent standard (ocf, lsb, etc.) * \param[in] provider Resource agent provider * \param[in] agent Resource agent name * \param[in] action action (start, stop, monitor, etc.) * \param[in] interval_ms How often to repeat this action (if 0, execute once) * \param[in] timeout Consider action failed if it does not complete in this many milliseconds * \param[in] params Action parameters * * \return newly allocated action instance * * \post After the call, 'params' is owned, and later free'd by the svc_action_t result * \note The caller is responsible for freeing the return value using * services_action_free(). */ svc_action_t *resources_action_create(const char *name, const char *standard, const char *provider, const char *agent, const char *action, guint interval_ms, int timeout /* ms */, GHashTable *params, enum svc_action_flags flags); /** * Kick a recurring action so it is scheduled immediately for re-execution */ gboolean services_action_kick(const char *name, const char *action, guint interval_ms); const char *resources_find_service_class(const char *agent); /** * Utilize services API to execute an arbitrary command. * * This API has useful infrastructure in place to be able to run a command * in the background and get notified via a callback when the command finishes. * * \param[in] exec command to execute * \param[in] args arguments to the command, NULL terminated * * \return a svc_action_t object, used to pass to the execute function * (services_action_sync() or services_action_async()) and is * provided to the callback. */ svc_action_t *services_action_create_generic(const char *exec, const char *args[]); void services_action_cleanup(svc_action_t * op); void services_action_free(svc_action_t * op); int services_action_user(svc_action_t *op, const char *user); gboolean services_action_sync(svc_action_t * op); /** * Run an action asynchronously. * * \param[in] op services action data * \param[in] action_callback callback for when the action completes * \param[in] action_fork_callback callback for when action forked successfully * * \retval TRUE succesfully started execution * \retval FALSE failed to start execution, no callback will be received */ gboolean services_action_async_fork_notify(svc_action_t * op, void (*action_callback) (svc_action_t *), void (*action_fork_callback) (svc_action_t *)); gboolean services_action_async(svc_action_t * op, void (*action_callback) (svc_action_t *)); gboolean services_action_cancel(const char *name, const char *action, guint interval_ms); /* functions for alert agents */ svc_action_t *services_alert_create(const char *id, const char *exec, int timeout, GHashTable *params, int sequence, void *cb_data); gboolean services_alert_async(svc_action_t *action, void (*cb)(svc_action_t *op)); static inline const char *services_lrm_status_str(enum op_status status) { switch (status) { case PCMK_LRM_OP_PENDING: return "pending"; case PCMK_LRM_OP_DONE:return "complete"; case PCMK_LRM_OP_CANCELLED:return "Cancelled"; case PCMK_LRM_OP_TIMEOUT:return "Timed Out"; case PCMK_LRM_OP_NOTSUPPORTED:return "NOT SUPPORTED"; case PCMK_LRM_OP_ERROR:return "Error"; case PCMK_LRM_OP_NOT_INSTALLED:return "Not installed"; case PCMK_LRM_OP_NOT_CONNECTED:return "No executor connection"; case PCMK_LRM_OP_INVALID:return "Cannot execute now"; default:return "UNKNOWN!"; } } static inline const char *services_ocf_exitcode_str(enum ocf_exitcode code) { switch (code) { case PCMK_OCF_OK: return "ok"; case PCMK_OCF_UNKNOWN_ERROR: return "error"; case PCMK_OCF_INVALID_PARAM: return "invalid parameter"; case PCMK_OCF_UNIMPLEMENT_FEATURE: return "unimplemented feature"; case PCMK_OCF_INSUFFICIENT_PRIV: return "insufficient privileges"; case PCMK_OCF_NOT_INSTALLED: return "not installed"; case PCMK_OCF_NOT_CONFIGURED: return "not configured"; case PCMK_OCF_NOT_RUNNING: return "not running"; case PCMK_OCF_RUNNING_MASTER: return "master"; case PCMK_OCF_FAILED_MASTER: return "master (failed)"; case PCMK_OCF_SIGNAL: return "OCF_SIGNAL"; case PCMK_OCF_NOT_SUPPORTED: return "OCF_NOT_SUPPORTED"; case PCMK_OCF_PENDING: return "OCF_PENDING"; case PCMK_OCF_CANCELLED: return "OCF_CANCELLED"; case PCMK_OCF_TIMEOUT: return "OCF_TIMEOUT"; case PCMK_OCF_OTHER_ERROR: return "OCF_OTHER_ERROR"; case PCMK_OCF_DEGRADED: return "OCF_DEGRADED"; case PCMK_OCF_DEGRADED_MASTER: return "OCF_DEGRADED_MASTER"; default: return "unknown"; } } /** * \brief Get OCF equivalent of LSB exit code * * \param[in] action LSB action that produced exit code * \param[in] lsb_exitcode Exit code of LSB action * * \return PCMK_OCF_* constant that corresponds to LSB exit code */ static inline enum ocf_exitcode services_get_ocf_exitcode(const char *action, int lsb_exitcode) { /* For non-status actions, LSB and OCF share error code meaning <= 7 */ - if (action) { - /* Note: This conditional is broken up into two parts so it's not flagged - * by coccinelle as something that could be condensed into a call to - * pcmk__str_any_of. We can't use that here because it's an internal - * function and this is a public header. - */ - if (strcmp(action, "status") && strcmp(action, "monitor")) { - if ((lsb_exitcode < 0) || (lsb_exitcode > PCMK_LSB_NOT_RUNNING)) { - return PCMK_OCF_UNKNOWN_ERROR; - } - return (enum ocf_exitcode)lsb_exitcode; + if (action && strcmp(action, "status") && strcmp(action, "monitor")) { + if ((lsb_exitcode < 0) || (lsb_exitcode > PCMK_LSB_NOT_RUNNING)) { + return PCMK_OCF_UNKNOWN_ERROR; } + return (enum ocf_exitcode)lsb_exitcode; } /* status has different return codes */ switch (lsb_exitcode) { case PCMK_LSB_STATUS_OK: return PCMK_OCF_OK; case PCMK_LSB_STATUS_NOT_INSTALLED: return PCMK_OCF_NOT_INSTALLED; case PCMK_LSB_STATUS_INSUFFICIENT_PRIV: return PCMK_OCF_INSUFFICIENT_PRIV; case PCMK_LSB_STATUS_VAR_PID: case PCMK_LSB_STATUS_VAR_LOCK: case PCMK_LSB_STATUS_NOT_RUNNING: return PCMK_OCF_NOT_RUNNING; } return PCMK_OCF_UNKNOWN_ERROR; } # ifdef __cplusplus } # endif #endif /* __PCMK_SERVICES__ */