pacemaker  2.1.4-dc6eb4362
Scalable High-Availability cluster resource manager
services_lsb.c
Go to the documentation of this file.
1 /*
2  * Copyright 2010-2021 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 
89 static inline gboolean
90 lsb_meta_helper_get_value(const char *line, char **value, const char *prefix)
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 #define DESC_MAX 2048
100 
101 int
102 services__get_lsb_metadata(const char *type, char **output)
103 {
104  char ra_pathname[PATH_MAX] = { 0, };
105  FILE *fp = NULL;
106  char buffer[1024] = { 0, };
107  char *provides = NULL;
108  char *req_start = NULL;
109  char *req_stop = NULL;
110  char *shld_start = NULL;
111  char *shld_stop = NULL;
112  char *dflt_start = NULL;
113  char *dflt_stop = NULL;
114  char *s_dscrpt = NULL;
115  char *xml_l_dscrpt = NULL;
116  int offset = 0;
117  bool in_header = FALSE;
118  char description[DESC_MAX] = { 0, };
119 
120  if (type[0] == '/') {
121  snprintf(ra_pathname, sizeof(ra_pathname), "%s", type);
122  } else {
123  snprintf(ra_pathname, sizeof(ra_pathname), "%s/%s",
125  }
126 
127  crm_trace("Looking into %s", ra_pathname);
128  fp = fopen(ra_pathname, "r");
129  if (fp == NULL) {
130  return -errno;
131  }
132 
133  /* Enter into the LSB-compliant comment block */
134  while (fgets(buffer, sizeof(buffer), fp)) {
135 
136  // Ignore lines up to and including the block delimiter
138  in_header = TRUE;
139  continue;
140  }
141  if (!in_header) {
142  continue;
143  }
144 
145  /* Assume each of the following eight arguments contain one line */
146  if (lsb_meta_helper_get_value(buffer, &provides, PROVIDES)) {
147  continue;
148  }
149  if (lsb_meta_helper_get_value(buffer, &req_start, REQ_START)) {
150  continue;
151  }
152  if (lsb_meta_helper_get_value(buffer, &req_stop, REQ_STOP)) {
153  continue;
154  }
155  if (lsb_meta_helper_get_value(buffer, &shld_start, SHLD_START)) {
156  continue;
157  }
158  if (lsb_meta_helper_get_value(buffer, &shld_stop, SHLD_STOP)) {
159  continue;
160  }
161  if (lsb_meta_helper_get_value(buffer, &dflt_start, DFLT_START)) {
162  continue;
163  }
164  if (lsb_meta_helper_get_value(buffer, &dflt_stop, DFLT_STOP)) {
165  continue;
166  }
167  if (lsb_meta_helper_get_value(buffer, &s_dscrpt, SHORT_DSCR)) {
168  continue;
169  }
170 
171  /* Long description may cross multiple lines */
172  if ((offset == 0) // haven't already found long description
173  && pcmk__starts_with(buffer, DESCRIPTION)) {
174  bool processed_line = TRUE;
175 
176  // Get remainder of description line itself
177  offset += snprintf(description, DESC_MAX, "%s",
178  buffer + strlen(DESCRIPTION));
179 
180  // Read any continuation lines of the description
181  buffer[0] = '\0';
182  while (fgets(buffer, sizeof(buffer), fp)) {
183  if (pcmk__starts_with(buffer, "# ")
184  || pcmk__starts_with(buffer, "#\t")) {
185  /* '#' followed by a tab or more than one space indicates a
186  * continuation of the long description.
187  */
188  offset += snprintf(description + offset, DESC_MAX - offset,
189  "%s", buffer + 1);
190  } else {
191  /* This line is not part of the long description,
192  * so continue with normal processing.
193  */
194  processed_line = FALSE;
195  break;
196  }
197  }
198 
199  // Make long description safe to use in XML
200  xml_l_dscrpt = (char *)xmlEncodeEntitiesReentrant(NULL, BAD_CAST(description));
201 
202  if (processed_line) {
203  // We grabbed the line into the long description
204  continue;
205  }
206  }
207 
208  // Stop if we leave the header block
210  break;
211  }
212  if (buffer[0] != '#') {
213  break;
214  }
215  }
216  fclose(fp);
217 
219  (xml_l_dscrpt? xml_l_dscrpt : type),
220  (s_dscrpt? s_dscrpt : type),
221  (provides? provides : ""),
222  (req_start? req_start : ""),
223  (req_stop? req_stop : ""),
224  (shld_start? shld_start : ""),
225  (shld_stop? shld_stop : ""),
226  (dflt_start? dflt_start : ""),
227  (dflt_stop? dflt_stop : ""));
228 
229  lsb_meta_helper_free_value(xml_l_dscrpt);
230  lsb_meta_helper_free_value(s_dscrpt);
231  lsb_meta_helper_free_value(provides);
232  lsb_meta_helper_free_value(req_start);
233  lsb_meta_helper_free_value(req_stop);
234  lsb_meta_helper_free_value(shld_start);
235  lsb_meta_helper_free_value(shld_stop);
236  lsb_meta_helper_free_value(dflt_start);
237  lsb_meta_helper_free_value(dflt_stop);
238 
239  crm_trace("Created fake metadata: %llu",
240  (unsigned long long) strlen(*output));
241  return pcmk_ok;
242 }
243 
244 GList *
246 {
248 }
249 
250 bool
251 services__lsb_agent_exists(const char *agent)
252 {
253  bool rc = FALSE;
254  struct stat st;
255  char *path = pcmk__full_path(agent, PCMK__LSB_INIT_DIR);
256 
257  rc = (stat(path, &st) == 0);
258  free(path);
259  return rc;
260 }
261 
270 int
272 {
274  op->opaque->args[0] = strdup(op->opaque->exec);
275  op->opaque->args[1] = strdup(op->action);
276  if ((op->opaque->args[0] == NULL) || (op->opaque->args[1] == NULL)) {
277  return ENOMEM;
278  }
279  return pcmk_rc_ok;
280 }
281 
291 enum ocf_exitcode
292 services__lsb2ocf(const char *action, int exit_status)
293 {
294  // For non-status actions, LSB and OCF share error codes <= 7
295  if (!pcmk__str_any_of(action, "status", "monitor", NULL)) {
296  if ((exit_status < 0) || (exit_status > PCMK_LSB_NOT_RUNNING)) {
297  return PCMK_OCF_UNKNOWN_ERROR;
298  }
299  return (enum ocf_exitcode) exit_status;
300  }
301 
302  // LSB status actions have their own codes
303  switch (exit_status) {
304  case PCMK_LSB_STATUS_OK:
305  return PCMK_OCF_OK;
306 
308  return PCMK_OCF_NOT_INSTALLED;
309 
312 
316  return PCMK_OCF_NOT_RUNNING;
317 
318  default:
319  return PCMK_OCF_UNKNOWN_ERROR;
320  }
321 }
322 
323 // Deprecated functions kept only for backward API compatibility
324 // LCOV_EXCL_START
325 
326 #include <crm/services_compat.h>
327 
328 svc_action_t *
329 services_action_create(const char *name, const char *action,
330  guint interval_ms, int timeout)
331 {
333  action, interval_ms, timeout, NULL, 0);
334 }
335 
336 GList *
338 {
340 }
341 
342 // LCOV_EXCL_STOP
343 // End deprecated API
Services API.
#define DFLT_STOP
Definition: services_lsb.c:67
A dumping ground.
ocf_exitcode
Exit status codes for resource agents.
Definition: results.h:161
#define LSB_INITSCRIPT_INFOEND_TAG
Definition: services_lsb.c:60
const char * name
Definition: cib.c:24
Service safely stopped.
Definition: results.h:169
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:69
#define SHORT_DSCR
Definition: services_lsb.c:68
enum crm_ais_msg_types type
Definition: cpg.c:48
const char * action
Definition: pcmk_fence.c:29
#define REQ_STOP
Definition: services_lsb.c:63
#define lsb_meta_helper_free_value(m)
Definition: services_lsb.c:71
int services__get_lsb_metadata(const char *type, char **output)
Definition: services_lsb.c:102
GList * services__list_lsb_agents(void)
Definition: services_lsb.c:245
stonith_t * st
Definition: pcmk_fence.c:27
svc_action_private_t * opaque
This field should be treated as internal to Pacemaker.
Definition: services.h:181
svc_action_t * services_action_create(const char *name, const char *action, guint interval_ms, int timeout)
Definition: services_lsb.c:329
#define DESC_MAX
Definition: services_lsb.c:99
#define crm_trace(fmt, args...)
Definition: logging.h:364
#define LSB_INITSCRIPT_INFOBEGIN_TAG
Definition: services_lsb.c:59
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
Object for executing external actions.
Definition: services.h:121
Insufficient privileges.
Definition: results.h:166
char * agent
Resource agent name for resource actions, otherwise NULL.
Definition: services.h:143
#define DFLT_START
Definition: services_lsb.c:66
int services__lsb_prepare(svc_action_t *op)
Definition: services_lsb.c:271
Deprecated services API.
Dependencies not available locally.
Definition: results.h:167
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:955
#define SHLD_START
Definition: services_lsb.c:64
Unspecified error.
Definition: results.h:163
enum ocf_exitcode services__lsb2ocf(const char *action, int exit_status)
Definition: services_lsb.c:292
char * args[MAX_ARGC]
#define REQ_START
Definition: services_lsb.c:62
char * action
Name of action being executed for resource actions, otherwise NULL.
Definition: services.h:131
#define PCMK_RESOURCE_CLASS_LSB
Definition: services.h:41
#define PCMK__LSB_INIT_DIR
Definition: config.h:546
const char * path
Definition: cib.c:26
Success.
Definition: results.h:162
GList * services_list(void)
Definition: services_lsb.c:337
#define PROVIDES
Definition: services_lsb.c:61
#define lsb_metadata_template
Definition: services_lsb.c:25
GList * resources_list_agents(const char *standard, const char *provider)
Get a list of resource agents.
Definition: services.c:1119
#define pcmk_ok
Definition: results.h:68
bool pcmk__starts_with(const char *str, const char *prefix)
Check whether a string starts with a certain sequence.
Definition: strings.c:484
#define SHLD_STOP
Definition: services_lsb.c:65
char * pcmk__full_path(const char *filename, const char *dirname)
Duplicate a file path, inserting a prefix if not absolute.
Definition: io.c:627
unsigned int timeout
Definition: pcmk_fence.c:31
bool services__lsb_agent_exists(const char *agent)
Definition: services_lsb.c:251