pacemaker  2.1.8-3980678f03
Scalable High-Availability cluster resource manager
services_lsb.c
Go to the documentation of this file.
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 
93 static inline gboolean
94 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  if ((*value == NULL) && pcmk__starts_with(line, prefix)) {
100  *value = pcmk__xml_escape(line + strlen(prefix), pcmk__xml_escape_text);
101  return TRUE;
102  }
103  return FALSE;
104 }
105 
106 int
107 services__get_lsb_metadata(const char *type, char **output)
108 {
109  char ra_pathname[PATH_MAX] = { 0, };
110  FILE *fp = NULL;
111  char buffer[1024] = { 0, };
112  gchar *provides = NULL;
113  gchar *required_start = NULL;
114  gchar *required_stop = NULL;
115  gchar *should_start = NULL;
116  gchar *should_stop = NULL;
117  gchar *default_start = NULL;
118  gchar *default_stop = NULL;
119  gchar *short_desc = NULL;
120  gchar *long_desc = NULL;
121  bool in_header = FALSE;
122 
123  if (type[0] == '/') {
124  snprintf(ra_pathname, sizeof(ra_pathname), "%s", type);
125  } else {
126  snprintf(ra_pathname, sizeof(ra_pathname), "%s/%s",
128  }
129 
130  crm_trace("Looking into %s", ra_pathname);
131  fp = fopen(ra_pathname, "r");
132  if (fp == NULL) {
133  return -errno;
134  }
135 
136  /* Enter into the LSB-compliant comment block */
137  while (fgets(buffer, sizeof(buffer), fp)) {
138 
139  // Ignore lines up to and including the block delimiter
141  in_header = TRUE;
142  continue;
143  }
144  if (!in_header) {
145  continue;
146  }
147 
148  /* Assume each of the following eight arguments contain one line */
149  if (lsb_meta_helper_get_value(buffer, &provides, PROVIDES)) {
150  continue;
151  }
152  if (lsb_meta_helper_get_value(buffer, &required_start,
153  REQUIRED_START)) {
154  continue;
155  }
156  if (lsb_meta_helper_get_value(buffer, &required_stop, REQUIRED_STOP)) {
157  continue;
158  }
159  if (lsb_meta_helper_get_value(buffer, &should_start, SHOULD_START)) {
160  continue;
161  }
162  if (lsb_meta_helper_get_value(buffer, &should_stop, SHOULD_STOP)) {
163  continue;
164  }
165  if (lsb_meta_helper_get_value(buffer, &default_start, DEFAULT_START)) {
166  continue;
167  }
168  if (lsb_meta_helper_get_value(buffer, &default_stop, DEFAULT_STOP)) {
169  continue;
170  }
171  if (lsb_meta_helper_get_value(buffer, &short_desc, SHORT_DESC)) {
172  continue;
173  }
174 
175  /* Long description may cross multiple lines */
176  if ((long_desc == NULL) // Haven't already found long description
177  && pcmk__starts_with(buffer, DESCRIPTION)) {
178  bool processed_line = TRUE;
179  GString *desc = g_string_sized_new(2048);
180 
181  // Get remainder of description line itself
182  g_string_append(desc, buffer + sizeof(DESCRIPTION) - 1);
183 
184  // Read any continuation lines of the description
185  buffer[0] = '\0';
186  while (fgets(buffer, sizeof(buffer), fp)) {
187  if (pcmk__starts_with(buffer, "# ")
188  || 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  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  processed_line = FALSE;
198  break;
199  }
200  }
201 
202  // Make long description safe to use in XML
203  long_desc = pcmk__xml_escape(desc->str, pcmk__xml_escape_text);
204  g_string_free(desc, TRUE);
205 
206  if (processed_line) {
207  // We grabbed the line into the long description
208  continue;
209  }
210  }
211 
212  // Stop if we leave the header block
214  break;
215  }
216  if (buffer[0] != '#') {
217  break;
218  }
219  }
220  fclose(fp);
221 
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  g_free(long_desc);
234  g_free(short_desc);
235  g_free(provides);
236  g_free(required_start);
237  g_free(required_stop);
238  g_free(should_start);
239  g_free(should_stop);
240  g_free(default_start);
241  g_free(default_stop);
242  return pcmk_ok;
243 }
244 
245 GList *
247 {
249 }
250 
251 bool
252 services__lsb_agent_exists(const char *agent)
253 {
254  bool rc = FALSE;
255  struct stat st;
256  char *path = pcmk__full_path(agent, PCMK__LSB_INIT_DIR);
257 
258  rc = (stat(path, &st) == 0);
259  free(path);
260  return rc;
261 }
262 
271 int
273 {
275  op->opaque->args[0] = strdup(op->opaque->exec);
276  op->opaque->args[1] = strdup(op->action);
277  if ((op->opaque->args[0] == NULL) || (op->opaque->args[1] == NULL)) {
278  return ENOMEM;
279  }
280  return pcmk_rc_ok;
281 }
282 
292 enum ocf_exitcode
293 services__lsb2ocf(const char *action, int exit_status)
294 {
295  // For non-status actions, LSB and OCF share error codes <= 7
297  NULL)) {
298  if ((exit_status < 0) || (exit_status > PCMK_LSB_NOT_RUNNING)) {
299  return PCMK_OCF_UNKNOWN_ERROR;
300  }
301  return (enum ocf_exitcode) exit_status;
302  }
303 
304  // LSB status actions have their own codes
305  switch (exit_status) {
306  case PCMK_LSB_STATUS_OK:
307  return PCMK_OCF_OK;
308 
310  return PCMK_OCF_NOT_INSTALLED;
311 
314 
318  return PCMK_OCF_NOT_RUNNING;
319 
320  default:
321  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 {
335  action, interval_ms, timeout, NULL, 0);
336 }
337 
338 GList *
340 {
342 }
343 
344 // LCOV_EXCL_STOP
345 // End deprecated API
Services API.
#define REQUIRED_STOP
Definition: services_lsb.c:75
A dumping ground.
ocf_exitcode
Exit status codes for resource agents.
Definition: results.h:177
char * pcmk__xml_escape(const char *text, enum pcmk__xml_escape_type type)
Definition: xml.c:1110
#define LSB_INITSCRIPT_INFOEND_TAG
Definition: services_lsb.c:72
const char * name
Definition: cib.c:26
#define SHORT_DESC
Definition: services_lsb.c:80
#define PCMK_ACTION_MONITOR
Definition: actions.h:60
#define DEFAULT_START
Definition: services_lsb.c:78
Service safely stopped.
Definition: results.h:190
GList * services_os_get_directory_list(const char *root, gboolean files, gboolean executable)
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, GHashTable *params, enum svc_action_flags flags)
Create a new resource action.
Definition: services.c:335
#define DESCRIPTION
Definition: services_lsb.c:81
enum crm_ais_msg_types type
Definition: cpg.c:51
#define REQUIRED_START
Definition: services_lsb.c:74
const char * action
Definition: pcmk_fence.c:30
#define SHOULD_STOP
Definition: services_lsb.c:77
int services__get_lsb_metadata(const char *type, char **output)
Definition: services_lsb.c:107
#define PCMK_ACTION_STATUS
Definition: actions.h:73
GList * services__list_lsb_agents(void)
Definition: services_lsb.c:246
stonith_t * st
Definition: pcmk_fence.c:28
svc_action_private_t * opaque
This field should be treated as internal to Pacemaker.
Definition: services.h:182
svc_action_t * services_action_create(const char *name, const char *action, guint interval_ms, int timeout)
Definition: services_lsb.c:331
#define crm_trace(fmt, args...)
Definition: logging.h:404
#define LSB_INITSCRIPT_INFOBEGIN_TAG
Definition: services_lsb.c:71
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
Object for executing external actions.
Definition: services.h:122
Insufficient privileges.
Definition: results.h:185
char * agent
Resource agent name for resource actions, otherwise NULL.
Definition: services.h:144
Wrappers for and extensions to libxml2.
int services__lsb_prepare(svc_action_t *op)
Definition: services_lsb.c:272
char * pcmk__full_path(const char *filename, const char *dirname)
Duplicate a file path, inserting a prefix if not absolute.
Definition: io.c:634
Deprecated services API.
Dependencies not available locally.
Definition: results.h:186
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1050
Unspecified error.
Definition: results.h:181
enum ocf_exitcode services__lsb2ocf(const char *action, int exit_status)
Definition: services_lsb.c:293
char * args[MAX_ARGC]
char * action
Name of action being executed for resource actions, otherwise NULL.
Definition: services.h:132
#define PCMK__LSB_INIT_DIR
Definition: config.h:565
const char * path
Definition: cib.c:28
Success.
Definition: results.h:178
GList * services_list(void)
Definition: services_lsb.c:339
#define PROVIDES
Definition: services_lsb.c:73
#define PCMK_RESOURCE_CLASS_LSB
Definition: agents.h:29
#define SHOULD_START
Definition: services_lsb.c:76
#define lsb_metadata_template
Definition: services_lsb.c:27
GList * resources_list_agents(const char *standard, const char *provider)
Get a list of resource agents.
Definition: services.c:1117
#define pcmk_ok
Definition: results.h:69
bool pcmk__starts_with(const char *str, const char *prefix)
Check whether a string starts with a certain sequence.
Definition: strings.c:556
#define DEFAULT_STOP
Definition: services_lsb.c:79
unsigned int timeout
Definition: pcmk_fence.c:32
bool services__lsb_agent_exists(const char *agent)
Definition: services_lsb.c:252