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