pacemaker 2.1.4-dc6eb4362e
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
89static inline gboolean
90lsb_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
101int
102services__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);
234 lsb_meta_helper_free_value(shld_start);
236 lsb_meta_helper_free_value(dflt_start);
238
239 crm_trace("Created fake metadata: %llu",
240 (unsigned long long) strlen(*output));
241 return pcmk_ok;
242}
243
244GList *
246{
248}
249
250bool
252{
253 bool rc = FALSE;
254 struct stat st;
256
257 rc = (stat(path, &st) == 0);
258 free(path);
259 return rc;
260}
261
270int
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
291enum ocf_exitcode
292services__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)) {
298 }
299 return (enum ocf_exitcode) exit_status;
300 }
301
302 // LSB status actions have their own codes
303 switch (exit_status) {
305 return PCMK_OCF_OK;
306
309
312
317
318 default:
320 }
321}
322
323// Deprecated functions kept only for backward API compatibility
324// LCOV_EXCL_START
325
326#include <crm/services_compat.h>
327
329services_action_create(const char *name, const char *action,
330 guint interval_ms, int timeout)
331{
333 action, interval_ms, timeout, NULL, 0);
334}
335
336GList *
338{
340}
341
342// LCOV_EXCL_STOP
343// End deprecated API
const char * path
Definition: cib.c:26
const char * name
Definition: cib.c:24
char * pcmk__full_path(const char *filename, const char *dirname)
Duplicate a file path, inserting a prefix if not absolute.
Definition: io.c:627
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define PCMK__LSB_INIT_DIR
Definition: config.h:543
enum crm_ais_msg_types type
Definition: cpg.c:3
A dumping ground.
#define crm_trace(fmt, args...)
Definition: logging.h:364
unsigned int timeout
Definition: pcmk_fence.c:31
stonith_t * st
Definition: pcmk_fence.c:27
const char * action
Definition: pcmk_fence.c:29
ocf_exitcode
Exit status codes for resource agents.
Definition: results.h:161
@ PCMK_OCF_INSUFFICIENT_PRIV
Insufficient privileges.
Definition: results.h:166
@ PCMK_OCF_NOT_INSTALLED
Dependencies not available locally.
Definition: results.h:167
@ PCMK_OCF_UNKNOWN_ERROR
Unspecified error.
Definition: results.h:163
@ PCMK_OCF_NOT_RUNNING
Service safely stopped.
Definition: results.h:169
@ PCMK_OCF_OK
Success.
Definition: results.h:162
@ pcmk_rc_ok
Definition: results.h:146
#define pcmk_ok
Definition: results.h:68
Services API.
GList * resources_list_agents(const char *standard, const char *provider)
Get a list of resource agents.
Definition: services.c:1119
@ PCMK_LSB_STATUS_NOT_INSTALLED
Definition: services.h:79
@ PCMK_LSB_STATUS_OK
Definition: services.h:72
@ PCMK_LSB_STATUS_VAR_PID
Definition: services.h:73
@ PCMK_LSB_STATUS_INSUFFICIENT_PRIV
Definition: services.h:80
@ PCMK_LSB_STATUS_VAR_LOCK
Definition: services.h:74
@ PCMK_LSB_STATUS_NOT_RUNNING
Definition: services.h:75
@ PCMK_LSB_NOT_RUNNING
Definition: services.h:65
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 PCMK_RESOURCE_CLASS_LSB
Definition: services.h:41
Deprecated services API.
GList * services_os_get_directory_list(const char *root, gboolean files, gboolean executable)
#define DESC_MAX
Definition: services_lsb.c:99
#define SHORT_DSCR
Definition: services_lsb.c:68
#define DFLT_START
Definition: services_lsb.c:66
GList * services_list(void)
Definition: services_lsb.c:337
svc_action_t * services_action_create(const char *name, const char *action, guint interval_ms, int timeout)
Definition: services_lsb.c:329
#define lsb_meta_helper_free_value(m)
Definition: services_lsb.c:71
#define DESCRIPTION
Definition: services_lsb.c:69
#define REQ_START
Definition: services_lsb.c:62
#define lsb_metadata_template
Definition: services_lsb.c:25
#define SHLD_START
Definition: services_lsb.c:64
int services__lsb_prepare(svc_action_t *op)
Definition: services_lsb.c:271
#define PROVIDES
Definition: services_lsb.c:61
#define DFLT_STOP
Definition: services_lsb.c:67
#define REQ_STOP
Definition: services_lsb.c:63
#define SHLD_STOP
Definition: services_lsb.c:65
GList * services__list_lsb_agents(void)
Definition: services_lsb.c:245
#define LSB_INITSCRIPT_INFOEND_TAG
Definition: services_lsb.c:60
#define LSB_INITSCRIPT_INFOBEGIN_TAG
Definition: services_lsb.c:59
bool services__lsb_agent_exists(const char *agent)
Definition: services_lsb.c:251
enum ocf_exitcode services__lsb2ocf(const char *action, int exit_status)
Definition: services_lsb.c:292
int services__get_lsb_metadata(const char *type, char **output)
Definition: services_lsb.c:102
bool pcmk__starts_with(const char *str, const char *prefix)
Check whether a string starts with a certain sequence.
Definition: strings.c:484
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:955
char * args[MAX_ARGC]
Object for executing external actions.
Definition: services.h:121
char * agent
Resource agent name for resource actions, otherwise NULL.
Definition: services.h:143
char * action
Name of action being executed for resource actions, otherwise NULL.
Definition: services.h:131
svc_action_private_t * opaque
This field should be treated as internal to Pacemaker.
Definition: services.h:181