LCOV - code coverage report
Current view: top level - fencing - st_rhcs.c (source / functions) Hit Total Coverage
Test: Pacemaker code coverage Lines: 0 146 0.0 %
Date: 2024-05-07 11:09:47 Functions: 0 6 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright 2004-2024 the Pacemaker project contributors
       3             :  *
       4             :  * The version control history for this file may have further details.
       5             :  *
       6             :  * This source code is licensed under the GNU Lesser General Public License
       7             :  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
       8             :  */
       9             : 
      10             : #include <crm_internal.h>
      11             : 
      12             : #include <stdio.h>
      13             : #include <string.h>
      14             : #include <sys/stat.h>
      15             : #include <glib.h>
      16             : #include <dirent.h>
      17             : 
      18             : #include <crm/crm.h>
      19             : #include <crm/common/xml.h>
      20             : #include <crm/stonith-ng.h>
      21             : #include <crm/fencing/internal.h>
      22             : 
      23             : #include "fencing_private.h"
      24             : 
      25             : #define RH_STONITH_PREFIX "fence_"
      26             : 
      27             : /*!
      28             :  * \internal
      29             :  * \brief Add available RHCS-compatible agents to a list
      30             :  *
      31             :  * \param[in,out]  List to add to
      32             :  *
      33             :  * \return Number of agents added
      34             :  */
      35             : int
      36           0 : stonith__list_rhcs_agents(stonith_key_value_t **devices)
      37             : {
      38             :     // Essentially: ls -1 @sbin_dir@/fence_*
      39             : 
      40           0 :     int count = 0, i;
      41             :     struct dirent **namelist;
      42           0 :     const int file_num = scandir(PCMK__FENCE_BINDIR, &namelist, 0, alphasort);
      43             : 
      44             : #if _POSIX_C_SOURCE < 200809L && !(defined(O_SEARCH) || defined(O_PATH))
      45             :     char buffer[FILENAME_MAX + 1];
      46             : #elif defined(O_SEARCH)
      47             :     const int dirfd = open(PCMK__FENCE_BINDIR, O_SEARCH);
      48             : #else
      49           0 :     const int dirfd = open(PCMK__FENCE_BINDIR, O_PATH);
      50             : #endif
      51             : 
      52           0 :     for (i = 0; i < file_num; i++) {
      53             :         struct stat prop;
      54             : 
      55           0 :         if (pcmk__starts_with(namelist[i]->d_name, RH_STONITH_PREFIX)) {
      56             : #if _POSIX_C_SOURCE < 200809L && !(defined(O_SEARCH) || defined(O_PATH))
      57             :             snprintf(buffer, sizeof(buffer), "%s/%s", PCMK__FENCE_BINDIR,
      58             :                      namelist[i]->d_name);
      59             :             if (stat(buffer, &prop) == 0 && S_ISREG(prop.st_mode)) {
      60             : #else
      61           0 :             if (dirfd == -1) {
      62           0 :                 if (i == 0) {
      63           0 :                     crm_notice("Problem with listing %s directory"
      64             :                                CRM_XS "errno=%d", RH_STONITH_PREFIX, errno);
      65             :                 }
      66           0 :                 free(namelist[i]);
      67           0 :                 continue;
      68             :             }
      69             :             /* note: we can possibly prevent following symlinks here,
      70             :                      which may be a good idea, but fall on the nose when
      71             :                      these agents are moved elsewhere & linked back */
      72           0 :             if (fstatat(dirfd, namelist[i]->d_name, &prop, 0) == 0
      73           0 :                     && S_ISREG(prop.st_mode)) {
      74             : #endif
      75           0 :                 *devices = stonith_key_value_add(*devices, NULL,
      76           0 :                                                  namelist[i]->d_name);
      77           0 :                 count++;
      78             :             }
      79             :         }
      80           0 :         free(namelist[i]);
      81             :     }
      82           0 :     if (file_num > 0) {
      83           0 :         free(namelist);
      84             :     }
      85             : #if _POSIX_C_SOURCE >= 200809L || defined(O_SEARCH) || defined(O_PATH)
      86           0 :     if (dirfd >= 0) {
      87           0 :         close(dirfd);
      88             :     }
      89             : #endif
      90           0 :     return count;
      91             : }
      92             : 
      93             : static void
      94           0 : stonith_rhcs_parameter_not_required(xmlNode *metadata, const char *parameter)
      95             : {
      96           0 :     char *xpath = NULL;
      97           0 :     xmlXPathObject *xpathObj = NULL;
      98             : 
      99           0 :     CRM_CHECK(metadata != NULL, return);
     100           0 :     CRM_CHECK(parameter != NULL, return);
     101             : 
     102           0 :     xpath = crm_strdup_printf("//" PCMK_XE_PARAMETER "[@" PCMK_XA_NAME "='%s']",
     103             :                               parameter);
     104             :     /* Fudge metadata so that the parameter isn't required in config
     105             :      * Pacemaker handles and adds it */
     106           0 :     xpathObj = xpath_search(metadata, xpath);
     107           0 :     if (numXpathResults(xpathObj) > 0) {
     108           0 :         xmlNode *tmp = getXpathResult(xpathObj, 0);
     109             : 
     110           0 :         crm_xml_add(tmp, "required", "0");
     111             :     }
     112           0 :     freeXpathObject(xpathObj);
     113           0 :     free(xpath);
     114             : }
     115             : 
     116             : /*!
     117             :  * \brief Execute RHCS-compatible agent's metadata action
     118             :  *
     119             :  * \param[in]  agent        Agent to execute
     120             :  * \param[in]  timeout_sec  Action timeout
     121             :  * \param[out] metadata     Where to store output xmlNode (or NULL to ignore)
     122             :  */
     123             : static int
     124           0 : stonith__rhcs_get_metadata(const char *agent, int timeout_sec,
     125             :                            xmlNode **metadata)
     126             : {
     127           0 :     xmlNode *xml = NULL;
     128           0 :     xmlNode *actions = NULL;
     129           0 :     xmlXPathObject *xpathObj = NULL;
     130           0 :     stonith_action_t *action = stonith__action_create(agent,
     131             :                                                       PCMK_ACTION_METADATA,
     132             :                                                       NULL, 0, timeout_sec,
     133             :                                                       NULL, NULL, NULL);
     134           0 :     int rc = stonith__execute(action);
     135           0 :     pcmk__action_result_t *result = stonith__action_result(action);
     136             : 
     137           0 :     if (result == NULL) {
     138           0 :         if (rc < 0) {
     139           0 :             crm_warn("Could not execute metadata action for %s: %s "
     140             :                      CRM_XS " rc=%d", agent, pcmk_strerror(rc), rc);
     141             :         }
     142           0 :         stonith__destroy_action(action);
     143           0 :         return rc;
     144             :     }
     145             : 
     146           0 :     if (result->execution_status != PCMK_EXEC_DONE) {
     147           0 :         crm_warn("Could not execute metadata action for %s: %s",
     148             :                  agent, pcmk_exec_status_str(result->execution_status));
     149           0 :         rc = pcmk_rc2legacy(stonith__result2rc(result));
     150           0 :         stonith__destroy_action(action);
     151           0 :         return rc;
     152             :     }
     153             : 
     154           0 :     if (!pcmk__result_ok(result)) {
     155           0 :         crm_warn("Metadata action for %s returned error code %d",
     156             :                  agent, result->exit_status);
     157           0 :         rc = pcmk_rc2legacy(stonith__result2rc(result));
     158           0 :         stonith__destroy_action(action);
     159           0 :         return rc;
     160             :     }
     161             : 
     162           0 :     if (result->action_stdout == NULL) {
     163           0 :         crm_warn("Metadata action for %s returned no data", agent);
     164           0 :         stonith__destroy_action(action);
     165           0 :         return -ENODATA;
     166             :     }
     167             : 
     168           0 :     xml = pcmk__xml_parse(result->action_stdout);
     169           0 :     stonith__destroy_action(action);
     170             : 
     171           0 :     if (xml == NULL) {
     172           0 :         crm_warn("Metadata for %s is invalid", agent);
     173           0 :         return -pcmk_err_schema_validation;
     174             :     }
     175             : 
     176           0 :     xpathObj = xpath_search(xml, "//" PCMK_XE_ACTIONS);
     177           0 :     if (numXpathResults(xpathObj) > 0) {
     178           0 :         actions = getXpathResult(xpathObj, 0);
     179             :     }
     180           0 :     freeXpathObject(xpathObj);
     181             : 
     182             :     // Add start and stop (implemented by pacemaker, not agent) to meta-data
     183           0 :     xpathObj = xpath_search(xml,
     184             :                             "//" PCMK_XE_ACTION
     185             :                             "[@" PCMK_XA_NAME "='" PCMK_ACTION_STOP "']");
     186           0 :     if (numXpathResults(xpathObj) <= 0) {
     187           0 :         xmlNode *tmp = NULL;
     188           0 :         const char *timeout_str = NULL;
     189             : 
     190           0 :         timeout_str = pcmk__readable_interval(PCMK_DEFAULT_ACTION_TIMEOUT_MS);
     191             : 
     192           0 :         tmp = pcmk__xe_create(actions, PCMK_XE_ACTION);
     193           0 :         crm_xml_add(tmp, PCMK_XA_NAME, PCMK_ACTION_STOP);
     194           0 :         crm_xml_add(tmp, PCMK_META_TIMEOUT, timeout_str);
     195             : 
     196           0 :         tmp = pcmk__xe_create(actions, PCMK_XE_ACTION);
     197           0 :         crm_xml_add(tmp, PCMK_XA_NAME, PCMK_ACTION_START);
     198           0 :         crm_xml_add(tmp, PCMK_META_TIMEOUT, timeout_str);
     199             :     }
     200           0 :     freeXpathObject(xpathObj);
     201             : 
     202             :     // Fudge metadata so parameters are not required in config (pacemaker adds them)
     203           0 :     stonith_rhcs_parameter_not_required(xml, "action");
     204           0 :     stonith_rhcs_parameter_not_required(xml, "plug");
     205           0 :     stonith_rhcs_parameter_not_required(xml, "port");
     206             : 
     207           0 :     if (metadata) {
     208           0 :         *metadata = xml;
     209             : 
     210             :     } else {
     211           0 :         free_xml(xml);
     212             :     }
     213             : 
     214           0 :     return pcmk_ok;
     215             : }
     216             : 
     217             : /*!
     218             :  * \brief Retrieve metadata for RHCS-compatible fence agent
     219             :  *
     220             :  * \param[in]  agent        Agent to execute
     221             :  * \param[in]  timeout_sec  Action timeout
     222             :  * \param[out] output       Where to store action output (or NULL to ignore)
     223             :  */
     224             : int
     225           0 : stonith__rhcs_metadata(const char *agent, int timeout_sec, char **output)
     226             : {
     227           0 :     GString *buffer = NULL;
     228           0 :     xmlNode *xml = NULL;
     229             : 
     230           0 :     int rc = stonith__rhcs_get_metadata(agent, timeout_sec, &xml);
     231             : 
     232           0 :     if (rc != pcmk_ok) {
     233           0 :         goto done;
     234             :     }
     235             : 
     236           0 :     buffer = g_string_sized_new(1024);
     237           0 :     pcmk__xml_string(xml, pcmk__xml_fmt_pretty|pcmk__xml_fmt_text, buffer, 0);
     238             : 
     239           0 :     if (pcmk__str_empty(buffer->str)) {
     240           0 :         rc = -pcmk_err_schema_validation;
     241           0 :         goto done;
     242             :     }
     243             : 
     244           0 :     if (output != NULL) {
     245           0 :         pcmk__str_update(output, buffer->str);
     246             :     }
     247             : 
     248           0 : done:
     249           0 :     if (buffer != NULL) {
     250           0 :         g_string_free(buffer, TRUE);
     251             :     }
     252           0 :     free_xml(xml);
     253           0 :     return rc;
     254             : }
     255             : 
     256             : bool
     257           0 : stonith__agent_is_rhcs(const char *agent)
     258             : {
     259             :     struct stat prop;
     260           0 :     char *buffer = crm_strdup_printf(PCMK__FENCE_BINDIR "/%s", agent);
     261           0 :     int rc = stat(buffer, &prop);
     262             : 
     263           0 :     free(buffer);
     264           0 :     return (rc >= 0) && S_ISREG(prop.st_mode);
     265             : }
     266             : 
     267             : int
     268           0 : stonith__rhcs_validate(stonith_t *st, int call_options, const char *target,
     269             :                        const char *agent, GHashTable *params,
     270             :                        const char * host_arg, int timeout,
     271             :                        char **output, char **error_output)
     272             : {
     273           0 :     int rc = pcmk_ok;
     274           0 :     int remaining_timeout = timeout;
     275           0 :     xmlNode *metadata = NULL;
     276           0 :     stonith_action_t *action = NULL;
     277           0 :     pcmk__action_result_t *result = NULL;
     278             : 
     279           0 :     if (host_arg == NULL) {
     280           0 :         time_t start_time = time(NULL);
     281             : 
     282           0 :         rc = stonith__rhcs_get_metadata(agent, remaining_timeout, &metadata);
     283             : 
     284           0 :         if (rc == pcmk_ok) {
     285           0 :             uint32_t device_flags = 0;
     286             : 
     287           0 :             stonith__device_parameter_flags(&device_flags, agent, metadata);
     288           0 :             if (pcmk_is_set(device_flags, st_device_supports_parameter_port)) {
     289           0 :                 host_arg = "port";
     290             : 
     291           0 :             } else if (pcmk_is_set(device_flags,
     292             :                                    st_device_supports_parameter_plug)) {
     293           0 :                 host_arg = "plug";
     294             :             }
     295             :         }
     296             : 
     297           0 :         free_xml(metadata);
     298             : 
     299           0 :         remaining_timeout -= time(NULL) - start_time;
     300             : 
     301           0 :         if (rc == -ETIME || remaining_timeout <= 0 ) {
     302           0 :             return -ETIME;
     303             :         }
     304             : 
     305           0 :     } else if (pcmk__str_eq(host_arg, PCMK_VALUE_NONE, pcmk__str_casei)) {
     306           0 :         host_arg = NULL;
     307             :     }
     308             : 
     309           0 :     action = stonith__action_create(agent, PCMK_ACTION_VALIDATE_ALL, target, 0,
     310             :                                     remaining_timeout, params, NULL, host_arg);
     311             : 
     312           0 :     rc = stonith__execute(action);
     313           0 :     result = stonith__action_result(action);
     314             : 
     315           0 :     if (result != NULL) {
     316           0 :         rc = pcmk_rc2legacy(stonith__result2rc(result));
     317             : 
     318             :         // Take ownership of output so stonith__destroy_action() doesn't free it
     319           0 :         if (output != NULL) {
     320           0 :             *output = result->action_stdout;
     321           0 :             result->action_stdout = NULL;
     322             :         }
     323           0 :         if (error_output != NULL) {
     324           0 :             *error_output = result->action_stderr;
     325           0 :             result->action_stderr = NULL;
     326             :         }
     327             :     }
     328           0 :     stonith__destroy_action(action);
     329           0 :     return rc;
     330             : }

Generated by: LCOV version 1.14