root/lib/services/services_lsb.c

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

DEFINITIONS

This source file includes following definitions.
  1. lsb_meta_helper_get_value
  2. services__get_lsb_metadata
  3. services__list_lsb_agents
  4. services__lsb_agent_exists
  5. services__lsb_prepare
  6. services__lsb2ocf
  7. services_action_create
  8. services_list

   1 /*
   2  * Copyright 2010-2023 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 #ifndef _GNU_SOURCE
  13 #  define _GNU_SOURCE
  14 #endif
  15 
  16 #include <stdio.h>
  17 #include <errno.h>
  18 #include <sys/stat.h>
  19 
  20 #include <crm/crm.h>
  21 #include <crm/services.h>
  22 #include "services_private.h"
  23 #include "services_lsb.h"
  24 
  25 #define lsb_metadata_template  \
  26     "<?xml version='1.0'?>\n"                                           \
  27     "<!DOCTYPE resource-agent SYSTEM 'ra-api-1.dtd'>\n"                 \
  28     "<resource-agent name='%s' version='" PCMK_DEFAULT_AGENT_VERSION "'>\n" \
  29     "  <version>1.0</version>\n"                                        \
  30     "  <longdesc lang='en'>\n"                                          \
  31     "%s"                                                                \
  32     "  </longdesc>\n"                                                   \
  33     "  <shortdesc lang='en'>%s</shortdesc>\n"                           \
  34     "  <parameters>\n"                                                  \
  35     "  </parameters>\n"                                                 \
  36     "  <actions>\n"                                                     \
  37     "    <action name='meta-data'    timeout='5' />\n"                  \
  38     "    <action name='start'        timeout='15' />\n"                 \
  39     "    <action name='stop'         timeout='15' />\n"                 \
  40     "    <action name='status'       timeout='15' />\n"                 \
  41     "    <action name='restart'      timeout='15' />\n"                 \
  42     "    <action name='force-reload' timeout='15' />\n"                 \
  43     "    <action name='monitor'      timeout='15' interval='15' />\n"   \
  44     "  </actions>\n"                                                    \
  45     "  <special tag='LSB'>\n"                                           \
  46     "    <Provides>%s</Provides>\n"                                     \
  47     "    <Required-Start>%s</Required-Start>\n"                         \
  48     "    <Required-Stop>%s</Required-Stop>\n"                           \
  49     "    <Should-Start>%s</Should-Start>\n"                             \
  50     "    <Should-Stop>%s</Should-Stop>\n"                               \
  51     "    <Default-Start>%s</Default-Start>\n"                           \
  52     "    <Default-Stop>%s</Default-Stop>\n"                             \
  53     "  </special>\n"                                                    \
  54     "</resource-agent>\n"
  55 
  56 /* See "Comment Conventions for Init Scripts" in the LSB core specification at:
  57  * http://refspecs.linuxfoundation.org/lsb.shtml
  58  */
  59 #define LSB_INITSCRIPT_INFOBEGIN_TAG "### BEGIN INIT INFO"
  60 #define LSB_INITSCRIPT_INFOEND_TAG "### END INIT INFO"
  61 #define PROVIDES    "# Provides:"
  62 #define REQ_START   "# Required-Start:"
  63 #define REQ_STOP    "# Required-Stop:"
  64 #define SHLD_START  "# Should-Start:"
  65 #define SHLD_STOP   "# Should-Stop:"
  66 #define DFLT_START  "# Default-Start:"
  67 #define DFLT_STOP   "# Default-Stop:"
  68 #define SHORT_DSCR  "# Short-Description:"
  69 #define DESCRIPTION "# Description:"
  70 
  71 #define lsb_meta_helper_free_value(m)           \
  72     do {                                        \
  73         if ((m) != NULL) {                      \
  74             xmlFree(m);                         \
  75             (m) = NULL;                         \
  76         }                                       \
  77     } while(0)
  78 
  79 /*!
  80  * \internal
  81  * \brief Grab an LSB header value
  82  *
  83  * \param[in]     line    Line read from LSB init script
  84  * \param[in,out] value   If not set, will be set to XML-safe copy of value
  85  * \param[in]     prefix  Set value if line starts with this pattern
  86  *
  87  * \return TRUE if value was set, FALSE otherwise
  88  */
  89 static inline gboolean
  90 lsb_meta_helper_get_value(const char *line, char **value, const char *prefix)
     /* [previous][next][first][last][top][bottom][index][help] */
  91 {
  92     if (!*value && pcmk__starts_with(line, prefix)) {
  93         *value = (char *)xmlEncodeEntitiesReentrant(NULL, BAD_CAST line+strlen(prefix));
  94         return TRUE;
  95     }
  96     return FALSE;
  97 }
  98 
  99 int
 100 services__get_lsb_metadata(const char *type, char **output)
     /* [previous][next][first][last][top][bottom][index][help] */
 101 {
 102     char ra_pathname[PATH_MAX] = { 0, };
 103     FILE *fp = NULL;
 104     char buffer[1024] = { 0, };
 105     char *provides = NULL;
 106     char *req_start = NULL;
 107     char *req_stop = NULL;
 108     char *shld_start = NULL;
 109     char *shld_stop = NULL;
 110     char *dflt_start = NULL;
 111     char *dflt_stop = NULL;
 112     char *s_dscrpt = NULL;
 113     char *xml_l_dscrpt = NULL;
 114     bool in_header = FALSE;
 115 
 116     if (type[0] == '/') {
 117         snprintf(ra_pathname, sizeof(ra_pathname), "%s", type);
 118     } else {
 119         snprintf(ra_pathname, sizeof(ra_pathname), "%s/%s",
 120                  PCMK__LSB_INIT_DIR, type);
 121     }
 122 
 123     crm_trace("Looking into %s", ra_pathname);
 124     fp = fopen(ra_pathname, "r");
 125     if (fp == NULL) {
 126         return -errno;
 127     }
 128 
 129     /* Enter into the LSB-compliant comment block */
 130     while (fgets(buffer, sizeof(buffer), fp)) {
 131 
 132         // Ignore lines up to and including the block delimiter
 133         if (pcmk__starts_with(buffer, LSB_INITSCRIPT_INFOBEGIN_TAG)) {
 134             in_header = TRUE;
 135             continue;
 136         }
 137         if (!in_header) {
 138             continue;
 139         }
 140 
 141         /* Assume each of the following eight arguments contain one line */
 142         if (lsb_meta_helper_get_value(buffer, &provides, PROVIDES)) {
 143             continue;
 144         }
 145         if (lsb_meta_helper_get_value(buffer, &req_start, REQ_START)) {
 146             continue;
 147         }
 148         if (lsb_meta_helper_get_value(buffer, &req_stop, REQ_STOP)) {
 149             continue;
 150         }
 151         if (lsb_meta_helper_get_value(buffer, &shld_start, SHLD_START)) {
 152             continue;
 153         }
 154         if (lsb_meta_helper_get_value(buffer, &shld_stop, SHLD_STOP)) {
 155             continue;
 156         }
 157         if (lsb_meta_helper_get_value(buffer, &dflt_start, DFLT_START)) {
 158             continue;
 159         }
 160         if (lsb_meta_helper_get_value(buffer, &dflt_stop, DFLT_STOP)) {
 161             continue;
 162         }
 163         if (lsb_meta_helper_get_value(buffer, &s_dscrpt, SHORT_DSCR)) {
 164             continue;
 165         }
 166 
 167         /* Long description may cross multiple lines */
 168         if ((xml_l_dscrpt == NULL) // haven't already found long description
 169             && pcmk__starts_with(buffer, DESCRIPTION)) {
 170             bool processed_line = TRUE;
 171             GString *desc = g_string_sized_new(2048);
 172 
 173             // Get remainder of description line itself
 174             g_string_append(desc, buffer + sizeof(DESCRIPTION) - 1);
 175 
 176             // Read any continuation lines of the description
 177             buffer[0] = '\0';
 178             while (fgets(buffer, sizeof(buffer), fp)) {
 179                 if (pcmk__starts_with(buffer, "#  ")
 180                     || pcmk__starts_with(buffer, "#\t")) {
 181                     /* '#' followed by a tab or more than one space indicates a
 182                      * continuation of the long description.
 183                      */
 184                     g_string_append(desc, buffer + 1);
 185                 } else {
 186                     /* This line is not part of the long description,
 187                      * so continue with normal processing.
 188                      */
 189                     processed_line = FALSE;
 190                     break;
 191                 }
 192             }
 193 
 194             // Make long description safe to use in XML
 195             xml_l_dscrpt =
 196                 (char *) xmlEncodeEntitiesReentrant(NULL,
 197                                                     (pcmkXmlStr) desc->str);
 198             g_string_free(desc, TRUE);
 199 
 200             if (processed_line) {
 201                 // We grabbed the line into the long description
 202                 continue;
 203             }
 204         }
 205 
 206         // Stop if we leave the header block
 207         if (pcmk__starts_with(buffer, LSB_INITSCRIPT_INFOEND_TAG)) {
 208             break;
 209         }
 210         if (buffer[0] != '#') {
 211             break;
 212         }
 213     }
 214     fclose(fp);
 215 
 216     *output = crm_strdup_printf(lsb_metadata_template, type,
 217                                 (xml_l_dscrpt? xml_l_dscrpt : type),
 218                                 (s_dscrpt? s_dscrpt : type),
 219                                 (provides? provides : ""),
 220                                 (req_start? req_start : ""),
 221                                 (req_stop? req_stop : ""),
 222                                 (shld_start? shld_start : ""),
 223                                 (shld_stop? shld_stop : ""),
 224                                 (dflt_start? dflt_start : ""),
 225                                 (dflt_stop? dflt_stop : ""));
 226 
 227     lsb_meta_helper_free_value(xml_l_dscrpt);
 228     lsb_meta_helper_free_value(s_dscrpt);
 229     lsb_meta_helper_free_value(provides);
 230     lsb_meta_helper_free_value(req_start);
 231     lsb_meta_helper_free_value(req_stop);
 232     lsb_meta_helper_free_value(shld_start);
 233     lsb_meta_helper_free_value(shld_stop);
 234     lsb_meta_helper_free_value(dflt_start);
 235     lsb_meta_helper_free_value(dflt_stop);
 236 
 237     crm_trace("Created fake metadata: %llu",
 238               (unsigned long long) strlen(*output));
 239     return pcmk_ok;
 240 }
 241 
 242 GList *
 243 services__list_lsb_agents(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 244 {
 245     return services_os_get_directory_list(PCMK__LSB_INIT_DIR, TRUE, TRUE);
 246 }
 247 
 248 bool
 249 services__lsb_agent_exists(const char *agent)
     /* [previous][next][first][last][top][bottom][index][help] */
 250 {
 251     bool rc = FALSE;
 252     struct stat st;
 253     char *path = pcmk__full_path(agent, PCMK__LSB_INIT_DIR);
 254 
 255     rc = (stat(path, &st) == 0);
 256     free(path);
 257     return rc;
 258 }
 259 
 260 /*!
 261  * \internal
 262  * \brief Prepare an LSB action
 263  *
 264  * \param[in,out] op  Action to prepare
 265  *
 266  * \return Standard Pacemaker return code
 267  */
 268 int
 269 services__lsb_prepare(svc_action_t *op)
     /* [previous][next][first][last][top][bottom][index][help] */
 270 {
 271     op->opaque->exec = pcmk__full_path(op->agent, PCMK__LSB_INIT_DIR);
 272     op->opaque->args[0] = strdup(op->opaque->exec);
 273     op->opaque->args[1] = strdup(op->action);
 274     if ((op->opaque->args[0] == NULL) || (op->opaque->args[1] == NULL)) {
 275         return ENOMEM;
 276     }
 277     return pcmk_rc_ok;
 278 }
 279 
 280 /*!
 281  * \internal
 282  * \brief Map an LSB result to a standard OCF result
 283  *
 284  * \param[in] action       Action that result is for
 285  * \param[in] exit_status  LSB agent exit status
 286  *
 287  * \return Standard OCF result
 288  */
 289 enum ocf_exitcode
 290 services__lsb2ocf(const char *action, int exit_status)
     /* [previous][next][first][last][top][bottom][index][help] */
 291 {
 292     // For non-status actions, LSB and OCF share error codes <= 7
 293     if (!pcmk__str_any_of(action, PCMK_ACTION_STATUS, PCMK_ACTION_MONITOR,
 294                           NULL)) {
 295         if ((exit_status < 0) || (exit_status > PCMK_LSB_NOT_RUNNING)) {
 296             return PCMK_OCF_UNKNOWN_ERROR;
 297         }
 298         return (enum ocf_exitcode) exit_status;
 299     }
 300 
 301     // LSB status actions have their own codes
 302     switch (exit_status) {
 303         case PCMK_LSB_STATUS_OK:
 304             return PCMK_OCF_OK;
 305 
 306         case PCMK_LSB_STATUS_NOT_INSTALLED:
 307             return PCMK_OCF_NOT_INSTALLED;
 308 
 309         case PCMK_LSB_STATUS_INSUFFICIENT_PRIV:
 310             return PCMK_OCF_INSUFFICIENT_PRIV;
 311 
 312         case PCMK_LSB_STATUS_VAR_PID:
 313         case PCMK_LSB_STATUS_VAR_LOCK:
 314         case PCMK_LSB_STATUS_NOT_RUNNING:
 315             return PCMK_OCF_NOT_RUNNING;
 316 
 317         default:
 318             return PCMK_OCF_UNKNOWN_ERROR;
 319     }
 320 }
 321 
 322 // Deprecated functions kept only for backward API compatibility
 323 // LCOV_EXCL_START
 324 
 325 #include <crm/services_compat.h>
 326 
 327 svc_action_t *
 328 services_action_create(const char *name, const char *action,
     /* [previous][next][first][last][top][bottom][index][help] */
 329                        guint interval_ms, int timeout)
 330 {
 331     return resources_action_create(name, PCMK_RESOURCE_CLASS_LSB, NULL, name,
 332                                    action, interval_ms, timeout, NULL, 0);
 333 }
 334 
 335 GList *
 336 services_list(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 337 {
 338     return resources_list_agents(PCMK_RESOURCE_CLASS_LSB, NULL);
 339 }
 340 
 341 // LCOV_EXCL_STOP
 342 // End deprecated API

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