This source file includes following definitions.
- pcmk__cli_help
- pcmk__env_option
- pcmk__set_env_option
- pcmk__env_option_enabled
- pcmk__valid_interval_spec
- pcmk__valid_boolean
- pcmk__valid_number
- pcmk__valid_positive_number
- pcmk__valid_quorum
- pcmk__valid_script
- pcmk__valid_percentage
- cluster_option_value
- pcmk__cluster_option
- add_desc
- pcmk__format_option_metadata
- pcmk__validate_cluster_options
1
2
3
4
5
6
7
8
9
10 #ifndef _GNU_SOURCE
11 # define _GNU_SOURCE
12 #endif
13
14 #include <crm_internal.h>
15
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21
22 #include <crm/crm.h>
23
24 void
25 pcmk__cli_help(char cmd)
26 {
27 if (cmd == 'v' || cmd == '$') {
28 printf("Pacemaker %s\n", PACEMAKER_VERSION);
29 printf("Written by Andrew Beekhof and "
30 "the Pacemaker project contributors\n");
31
32 } else if (cmd == '!') {
33 printf("Pacemaker %s (Build: %s): %s\n", PACEMAKER_VERSION, BUILD_VERSION, CRM_FEATURES);
34 }
35
36 crm_exit(CRM_EX_OK);
37 while(1);
38 }
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 const char *
58 pcmk__env_option(const char *option)
59 {
60 const char *const prefixes[] = {"PCMK_", "HA_"};
61 char env_name[NAME_MAX];
62 const char *value = NULL;
63
64 CRM_CHECK(!pcmk__str_empty(option), return NULL);
65
66 for (int i = 0; i < PCMK__NELEM(prefixes); i++) {
67 int rv = snprintf(env_name, NAME_MAX, "%s%s", prefixes[i], option);
68
69 if (rv < 0) {
70 crm_err("Failed to write %s%s to buffer: %s", prefixes[i], option,
71 strerror(errno));
72 return NULL;
73 }
74
75 if (rv >= sizeof(env_name)) {
76 crm_trace("\"%s%s\" is too long", prefixes[i], option);
77 continue;
78 }
79
80 value = getenv(env_name);
81 if (value != NULL) {
82 crm_trace("Found %s = %s", env_name, value);
83 return value;
84 }
85 }
86
87 crm_trace("Nothing found for %s", option);
88 return NULL;
89 }
90
91
92
93
94
95
96
97
98
99
100 void
101 pcmk__set_env_option(const char *option, const char *value)
102 {
103 const char *const prefixes[] = {"PCMK_", "HA_"};
104 char env_name[NAME_MAX];
105
106 CRM_CHECK(!pcmk__str_empty(option) && (strchr(option, '=') == NULL),
107 return);
108
109 for (int i = 0; i < PCMK__NELEM(prefixes); i++) {
110 int rv = snprintf(env_name, NAME_MAX, "%s%s", prefixes[i], option);
111
112 if (rv < 0) {
113 crm_err("Failed to write %s%s to buffer: %s", prefixes[i], option,
114 strerror(errno));
115 return;
116 }
117
118 if (rv >= sizeof(env_name)) {
119 crm_trace("\"%s%s\" is too long", prefixes[i], option);
120 continue;
121 }
122
123 if (value != NULL) {
124 crm_trace("Setting %s to %s", env_name, value);
125 rv = setenv(env_name, value, 1);
126 } else {
127 crm_trace("Unsetting %s", env_name);
128 rv = unsetenv(env_name);
129 }
130
131 if (rv < 0) {
132 crm_err("Failed to %sset %s: %s", (value != NULL)? "" : "un",
133 env_name, strerror(errno));
134 }
135 }
136 }
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151 bool
152 pcmk__env_option_enabled(const char *daemon, const char *option)
153 {
154 const char *value = pcmk__env_option(option);
155
156 return (value != NULL)
157 && (crm_is_true(value)
158 || ((daemon != NULL) && (strstr(value, daemon) != NULL)));
159 }
160
161
162
163
164
165
166 bool
167 pcmk__valid_interval_spec(const char *value)
168 {
169 (void) crm_parse_interval_spec(value);
170 return errno == 0;
171 }
172
173 bool
174 pcmk__valid_boolean(const char *value)
175 {
176 int tmp;
177
178 return crm_str_to_boolean(value, &tmp) == 1;
179 }
180
181 bool
182 pcmk__valid_number(const char *value)
183 {
184 if (value == NULL) {
185 return false;
186
187 } else if (pcmk_str_is_minus_infinity(value) ||
188 pcmk_str_is_infinity(value)) {
189 return true;
190 }
191
192 return pcmk__scan_ll(value, NULL, 0LL) == pcmk_rc_ok;
193 }
194
195 bool
196 pcmk__valid_positive_number(const char *value)
197 {
198 long long num = 0LL;
199
200 return pcmk_str_is_infinity(value)
201 || ((pcmk__scan_ll(value, &num, 0LL) == pcmk_rc_ok) && (num > 0));
202 }
203
204 bool
205 pcmk__valid_quorum(const char *value)
206 {
207 return pcmk__strcase_any_of(value, "stop", "freeze", "ignore", "demote", "suicide", NULL);
208 }
209
210 bool
211 pcmk__valid_script(const char *value)
212 {
213 struct stat st;
214
215 if (pcmk__str_eq(value, "/dev/null", pcmk__str_casei)) {
216 return true;
217 }
218
219 if (stat(value, &st) != 0) {
220 crm_err("Script %s does not exist", value);
221 return false;
222 }
223
224 if (S_ISREG(st.st_mode) == 0) {
225 crm_err("Script %s is not a regular file", value);
226 return false;
227 }
228
229 if ((st.st_mode & (S_IXUSR | S_IXGRP)) == 0) {
230 crm_err("Script %s is not executable", value);
231 return false;
232 }
233
234 return true;
235 }
236
237 bool
238 pcmk__valid_percentage(const char *value)
239 {
240 char *end = NULL;
241 long number = strtol(value, &end, 10);
242
243 if (end && (end[0] != '%')) {
244 return false;
245 }
246 return number >= 0;
247 }
248
249
250
251
252
253
254
255
256
257
258
259
260
261 static const char *
262 cluster_option_value(GHashTable *options, bool (*validate)(const char *),
263 const char *name, const char *old_name,
264 const char *def_value)
265 {
266 const char *value = NULL;
267 char *new_value = NULL;
268
269 CRM_ASSERT(name != NULL);
270
271 if (options) {
272 value = g_hash_table_lookup(options, name);
273
274 if ((value == NULL) && old_name) {
275 value = g_hash_table_lookup(options, old_name);
276 if (value != NULL) {
277 pcmk__config_warn("Support for legacy name '%s' for cluster "
278 "option '%s' is deprecated and will be "
279 "removed in a future release",
280 old_name, name);
281
282
283 new_value = strdup(value);
284 g_hash_table_insert(options, strdup(name), new_value);
285 value = new_value;
286 }
287 }
288
289 if (value && validate && (validate(value) == FALSE)) {
290 pcmk__config_err("Using default value for cluster option '%s' "
291 "because '%s' is invalid", name, value);
292 value = NULL;
293 }
294
295 if (value) {
296 return value;
297 }
298 }
299
300
301 value = def_value;
302
303 if (value == NULL) {
304 crm_trace("No value or default provided for cluster option '%s'",
305 name);
306 return NULL;
307 }
308
309 if (validate) {
310 CRM_CHECK(validate(value) != FALSE,
311 crm_err("Bug: default value for cluster option '%s' is invalid", name);
312 return NULL);
313 }
314
315 crm_trace("Using default value '%s' for cluster option '%s'",
316 value, name);
317 if (options) {
318 new_value = strdup(value);
319 g_hash_table_insert(options, strdup(name), new_value);
320 value = new_value;
321 }
322 return value;
323 }
324
325
326
327
328
329
330
331
332
333
334
335
336 const char *
337 pcmk__cluster_option(GHashTable *options,
338 const pcmk__cluster_option_t *option_list,
339 int len, const char *name)
340 {
341 const char *value = NULL;
342
343 for (int lpc = 0; lpc < len; lpc++) {
344 if (pcmk__str_eq(name, option_list[lpc].name, pcmk__str_casei)) {
345 value = cluster_option_value(options, option_list[lpc].is_valid,
346 option_list[lpc].name,
347 option_list[lpc].alt_name,
348 option_list[lpc].default_value);
349 return value;
350 }
351 }
352 CRM_CHECK(FALSE, crm_err("Bug: looking for unknown option '%s'", name));
353 return NULL;
354 }
355
356
357
358
359
360
361
362
363
364
365
366
367 static void
368 add_desc(GString *s, const char *tag, const char *desc, const char *values,
369 const char *spaces)
370 {
371 char *escaped_en = crm_xml_escape(desc);
372
373 if (spaces != NULL) {
374 g_string_append(s, spaces);
375 }
376 pcmk__g_strcat(s, "<", tag, " lang=\"en\">", escaped_en, NULL);
377
378 if (values != NULL) {
379 pcmk__g_strcat(s, " Allowed values: ", values, NULL);
380 }
381 pcmk__g_strcat(s, "</", tag, ">\n", NULL);
382
383 #ifdef ENABLE_NLS
384 {
385 static const char *locale = NULL;
386
387 char *localized = crm_xml_escape(_(desc));
388
389 if (strcmp(escaped_en, localized) != 0) {
390 if (locale == NULL) {
391 locale = strtok(setlocale(LC_ALL, NULL), "_");
392 }
393
394 if (spaces != NULL) {
395 g_string_append(s, spaces);
396 }
397 pcmk__g_strcat(s, "<", tag, " lang=\"", locale, "\">", localized,
398 NULL);
399
400 if (values != NULL) {
401 pcmk__g_strcat(s, _(" Allowed values: "), _(values), NULL);
402 }
403 pcmk__g_strcat(s, "</", tag, ">\n", NULL);
404 }
405 free(localized);
406 }
407 #endif
408
409 free(escaped_en);
410 }
411
412 gchar *
413 pcmk__format_option_metadata(const char *name, const char *desc_short,
414 const char *desc_long,
415 pcmk__cluster_option_t *option_list, int len)
416 {
417
418 GString *s = g_string_sized_new(13000);
419
420 pcmk__g_strcat(s,
421 "<?xml version=\"1.0\"?>\n"
422 "<resource-agent name=\"", name, "\" "
423 "version=\"" PACEMAKER_VERSION "\">\n"
424 " <version>" PCMK_OCF_VERSION "</version>\n", NULL);
425
426 add_desc(s, "longdesc", desc_long, NULL, " ");
427 add_desc(s, "shortdesc", desc_short, NULL, " ");
428
429 g_string_append(s, " <parameters>\n");
430
431 for (int lpc = 0; lpc < len; lpc++) {
432 const char *opt_name = option_list[lpc].name;
433 const char *opt_type = option_list[lpc].type;
434 const char *opt_values = option_list[lpc].values;
435 const char *opt_default = option_list[lpc].default_value;
436 const char *opt_desc_short = option_list[lpc].description_short;
437 const char *opt_desc_long = option_list[lpc].description_long;
438
439
440 CRM_ASSERT((opt_desc_short != NULL) || (opt_desc_long != NULL));
441
442 if (opt_desc_short == NULL) {
443 opt_desc_short = opt_desc_long;
444 } else if (opt_desc_long == NULL) {
445 opt_desc_long = opt_desc_short;
446 }
447
448
449 CRM_ASSERT(opt_type != NULL);
450
451 pcmk__g_strcat(s, " <parameter name=\"", opt_name, "\">\n", NULL);
452
453 add_desc(s, "longdesc", opt_desc_long, opt_values, " ");
454 add_desc(s, "shortdesc", opt_desc_short, NULL, " ");
455
456 pcmk__g_strcat(s, " <content type=\"", opt_type, "\"", NULL);
457 if (opt_default != NULL) {
458 pcmk__g_strcat(s, " default=\"", opt_default, "\"", NULL);
459 }
460
461 if ((opt_values != NULL) && (strcmp(opt_type, "select") == 0)) {
462 char *str = strdup(opt_values);
463 const char *delim = ", ";
464 char *ptr = strtok(str, delim);
465
466 g_string_append(s, ">\n");
467
468 while (ptr != NULL) {
469 pcmk__g_strcat(s, " <option value=\"", ptr, "\" />\n",
470 NULL);
471 ptr = strtok(NULL, delim);
472 }
473 g_string_append_printf(s, " </content>\n");
474 free(str);
475
476 } else {
477 g_string_append(s, "/>\n");
478 }
479
480 g_string_append(s, " </parameter>\n");
481 }
482 g_string_append(s, " </parameters>\n</resource-agent>\n");
483
484 return g_string_free(s, FALSE);
485 }
486
487 void
488 pcmk__validate_cluster_options(GHashTable *options,
489 pcmk__cluster_option_t *option_list, int len)
490 {
491 for (int lpc = 0; lpc < len; lpc++) {
492 cluster_option_value(options, option_list[lpc].is_valid,
493 option_list[lpc].name,
494 option_list[lpc].alt_name,
495 option_list[lpc].default_value);
496 }
497 }