root/lib/fencing/st_rhcs.c

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

DEFINITIONS

This source file includes following definitions.
  1. stonith__list_rhcs_agents
  2. stonith_rhcs_parameter_not_required
  3. stonith__rhcs_get_metadata
  4. stonith__rhcs_metadata
  5. stonith__agent_is_rhcs
  6. stonith__rhcs_validate

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

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