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

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

Generated by: LCOV version 1.14