pacemaker 2.1.5-a3f44794f94
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
99int
100services__get_lsb_metadata(const char *type, char **output)
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",
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
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
208 break;
209 }
210 if (buffer[0] != '#') {
211 break;
212 }
213 }
214 fclose(fp);
215
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);
232 lsb_meta_helper_free_value(shld_start);
234 lsb_meta_helper_free_value(dflt_start);
236
237 crm_trace("Created fake metadata: %llu",
238 (unsigned long long) strlen(*output));
239 return pcmk_ok;
240}
241
242GList *
244{
246}
247
248bool
250{
251 bool rc = FALSE;
252 struct stat st;
254
255 rc = (stat(path, &st) == 0);
256 free(path);
257 return rc;
258}
259
268int
270{
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
289enum ocf_exitcode
290services__lsb2ocf(const char *action, int exit_status)
291{
292 // For non-status actions, LSB and OCF share error codes <= 7
293 if (!pcmk__str_any_of(action, "status", "monitor", NULL)) {
294 if ((exit_status < 0) || (exit_status > PCMK_LSB_NOT_RUNNING)) {
296 }
297 return (enum ocf_exitcode) exit_status;
298 }
299
300 // LSB status actions have their own codes
301 switch (exit_status) {
303 return PCMK_OCF_OK;
304
307
310
315
316 default:
318 }
319}
320
321// Deprecated functions kept only for backward API compatibility
322// LCOV_EXCL_START
323
324#include <crm/services_compat.h>
325
327services_action_create(const char *name, const char *action,
328 guint interval_ms, int timeout)
329{
331 action, interval_ms, timeout, NULL, 0);
332}
333
334GList *
336{
338}
339
340// LCOV_EXCL_STOP
341// End deprecated API
#define PCMK_RESOURCE_CLASS_LSB
Definition: agents.h:29
const char * path
Definition: cib.c:26
const char * name
Definition: cib.c:24
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define PCMK__LSB_INIT_DIR
Definition: config.h:544
enum crm_ais_msg_types type
Definition: cpg.c:3
A dumping ground.
char * pcmk__full_path(const char *filename, const char *dirname)
Duplicate a file path, inserting a prefix if not absolute.
Definition: io.c:628
#define crm_trace(fmt, args...)
Definition: logging.h:365
unsigned int timeout
Definition: pcmk_fence.c:32
stonith_t * st
Definition: pcmk_fence.c:28
const char * action
Definition: pcmk_fence.c:30
ocf_exitcode
Exit status codes for resource agents.
Definition: results.h:163
@ PCMK_OCF_INSUFFICIENT_PRIV
Insufficient privileges.
Definition: results.h:168
@ PCMK_OCF_NOT_INSTALLED
Dependencies not available locally.
Definition: results.h:169
@ PCMK_OCF_UNKNOWN_ERROR
Unspecified error.
Definition: results.h:165
@ PCMK_OCF_NOT_RUNNING
Service safely stopped.
Definition: results.h:171
@ PCMK_OCF_OK
Success.
Definition: results.h:164
@ pcmk_rc_ok
Definition: results.h:148
#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:69
@ PCMK_LSB_STATUS_OK
Definition: services.h:62
@ PCMK_LSB_STATUS_VAR_PID
Definition: services.h:63
@ PCMK_LSB_STATUS_INSUFFICIENT_PRIV
Definition: services.h:70
@ PCMK_LSB_STATUS_VAR_LOCK
Definition: services.h:64
@ PCMK_LSB_STATUS_NOT_RUNNING
Definition: services.h:65
@ PCMK_LSB_NOT_RUNNING
Definition: services.h:57
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
Deprecated services API.
GList * services_os_get_directory_list(const char *root, gboolean files, gboolean executable)
#define SHORT_DSCR
Definition: services_lsb.c:68
#define DFLT_START
Definition: services_lsb.c:66
GList * services_list(void)
Definition: services_lsb.c:335
svc_action_t * services_action_create(const char *name, const char *action, guint interval_ms, int timeout)
Definition: services_lsb.c:327
#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:269
#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:243
#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:249
enum ocf_exitcode services__lsb2ocf(const char *action, int exit_status)
Definition: services_lsb.c:290
int services__get_lsb_metadata(const char *type, char **output)
Definition: services_lsb.c:100
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:952
char * args[MAX_ARGC]
Object for executing external actions.
Definition: services.h:112
char * agent
Resource agent name for resource actions, otherwise NULL.
Definition: services.h:134
char * action
Name of action being executed for resource actions, otherwise NULL.
Definition: services.h:122
svc_action_private_t * opaque
This field should be treated as internal to Pacemaker.
Definition: services.h:172
const xmlChar * pcmkXmlStr
Definition: xml.h:50