pacemaker  1.1.14-70404b0
Scalable High-Availability cluster resource manager
utils.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2019 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 #include <dlfcn.h>
12 
13 #ifndef _GNU_SOURCE
14 # define _GNU_SOURCE
15 #endif
16 
17 #include <sys/param.h>
18 #include <sys/types.h>
19 #include <sys/wait.h>
20 #include <sys/stat.h>
21 #include <sys/utsname.h>
22 
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <limits.h>
28 #include <ctype.h>
29 #include <pwd.h>
30 #include <time.h>
31 #include <libgen.h>
32 #include <signal.h>
33 
34 #include <qb/qbdefs.h>
35 
36 #include <crm/crm.h>
37 #include <crm/lrmd.h>
38 #include <crm/services.h>
39 #include <crm/msg_xml.h>
40 #include <crm/cib/internal.h>
41 #include <crm/common/xml.h>
42 #include <crm/common/util.h>
43 #include <crm/common/ipc.h>
44 #include <crm/common/iso8601.h>
45 #include <crm/common/mainloop.h>
46 #include <crm/attrd.h>
47 #include <libxml2/libxml/relaxng.h>
48 
49 #ifndef MAXLINE
50 # define MAXLINE 512
51 #endif
52 
53 #ifdef HAVE_GETOPT_H
54 # include <getopt.h>
55 #endif
56 
57 #ifndef PW_BUFFER_LEN
58 # define PW_BUFFER_LEN 500
59 #endif
60 
61 CRM_TRACE_INIT_DATA(common);
62 
63 gboolean crm_config_error = FALSE;
64 gboolean crm_config_warning = FALSE;
65 char *crm_system_name = NULL;
66 
71 
72 static struct crm_option *crm_long_options = NULL;
73 static const char *crm_app_description = NULL;
74 static char *crm_short_options = NULL;
75 static const char *crm_app_usage = NULL;
76 
77 int
78 crm_exit(int rc)
79 {
81 
82 #if HAVE_LIBXML2
83  crm_trace("cleaning up libxml");
85 #endif
86 
87  crm_trace("exit %d", rc);
88  qb_log_fini();
89 
90  free(crm_short_options);
91  free(crm_system_name);
92 
93  exit(ABS(rc)); /* Always exit with a positive value so that it can be passed to crm_error
94  *
95  * Otherwise the system wraps it around and people
96  * have to jump through hoops figuring out what the
97  * error was
98  */
99  return rc; /* Can never happen, but allows return crm_exit(rc)
100  * where "return rc" was used previously - which
101  * keeps compilers happy.
102  */
103 }
104 
105 gboolean
106 check_time(const char *value)
107 {
108  if (crm_get_msec(value) < 5000) {
109  return FALSE;
110  }
111  return TRUE;
112 }
113 
114 gboolean
115 check_timer(const char *value)
116 {
117  if (crm_get_msec(value) < 0) {
118  return FALSE;
119  }
120  return TRUE;
121 }
122 
123 gboolean
124 check_boolean(const char *value)
125 {
126  int tmp = FALSE;
127 
128  if (crm_str_to_boolean(value, &tmp) != 1) {
129  return FALSE;
130  }
131  return TRUE;
132 }
133 
134 gboolean
135 check_number(const char *value)
136 {
137  errno = 0;
138  if (value == NULL) {
139  return FALSE;
140 
141  } else if (safe_str_eq(value, MINUS_INFINITY_S)) {
142 
143  } else if (safe_str_eq(value, INFINITY_S)) {
144 
145  } else {
146  crm_int_helper(value, NULL);
147  }
148 
149  if (errno != 0) {
150  return FALSE;
151  }
152  return TRUE;
153 }
154 
155 gboolean
156 check_quorum(const char *value)
157 {
158  if (safe_str_eq(value, "stop")) {
159  return TRUE;
160 
161  } else if (safe_str_eq(value, "freeze")) {
162  return TRUE;
163 
164  } else if (safe_str_eq(value, "ignore")) {
165  return TRUE;
166 
167  } else if (safe_str_eq(value, "suicide")) {
168  return TRUE;
169  }
170  return FALSE;
171 }
172 
173 gboolean
174 check_script(const char *value)
175 {
176  struct stat st;
177 
178  if(safe_str_eq(value, "/dev/null")) {
179  return TRUE;
180  }
181 
182  if(stat(value, &st) != 0) {
183  crm_err("Script %s does not exist", value);
184  return FALSE;
185  }
186 
187  if(S_ISREG(st.st_mode) == 0) {
188  crm_err("Script %s is not a regular file", value);
189  return FALSE;
190  }
191 
192  if( (st.st_mode & (S_IXUSR | S_IXGRP )) == 0) {
193  crm_err("Script %s is not executable", value);
194  return FALSE;
195  }
196 
197  return TRUE;
198 }
199 
200 gboolean
201 check_utilization(const char *value)
202 {
203  char *end = NULL;
204  long number = strtol(value, &end, 10);
205 
206  if(end && end[0] != '%') {
207  return FALSE;
208  } else if(number < 0) {
209  return FALSE;
210  }
211 
212  return TRUE;
213 }
214 
215 int
216 char2score(const char *score)
217 {
218  int score_f = 0;
219 
220  if (score == NULL) {
221 
222  } else if (safe_str_eq(score, MINUS_INFINITY_S)) {
223  score_f = -node_score_infinity;
224 
225  } else if (safe_str_eq(score, INFINITY_S)) {
226  score_f = node_score_infinity;
227 
228  } else if (safe_str_eq(score, "+" INFINITY_S)) {
229  score_f = node_score_infinity;
230 
231  } else if (safe_str_eq(score, "red")) {
232  score_f = node_score_red;
233 
234  } else if (safe_str_eq(score, "yellow")) {
235  score_f = node_score_yellow;
236 
237  } else if (safe_str_eq(score, "green")) {
238  score_f = node_score_green;
239 
240  } else {
241  score_f = crm_parse_int(score, NULL);
242  if (score_f > 0 && score_f > node_score_infinity) {
243  score_f = node_score_infinity;
244 
245  } else if (score_f < 0 && score_f < -node_score_infinity) {
246  score_f = -node_score_infinity;
247  }
248  }
249 
250  return score_f;
251 }
252 
253 char *
254 score2char_stack(int score, char *buf, size_t len)
255 {
256  if (score >= node_score_infinity) {
257  strncpy(buf, INFINITY_S, 9);
258  } else if (score <= -node_score_infinity) {
259  strncpy(buf, MINUS_INFINITY_S , 10);
260  } else {
261  return crm_itoa_stack(score, buf, len);
262  }
263 
264  return buf;
265 }
266 
267 char *
268 score2char(int score)
269 {
270  if (score >= node_score_infinity) {
271  return strdup(INFINITY_S);
272 
273  } else if (score <= -node_score_infinity) {
274  return strdup("-" INFINITY_S);
275  }
276  return crm_itoa(score);
277 }
278 
279 const char *
280 cluster_option(GHashTable * options, gboolean(*validate) (const char *),
281  const char *name, const char *old_name, const char *def_value)
282 {
283  const char *value = NULL;
284 
285  CRM_ASSERT(name != NULL);
286 
287  if (options != NULL) {
288  value = g_hash_table_lookup(options, name);
289  }
290 
291  if (value == NULL && old_name && options != NULL) {
292  value = g_hash_table_lookup(options, old_name);
293  if (value != NULL) {
294  crm_config_warn("Using deprecated name '%s' for"
295  " cluster option '%s'", old_name, name);
296  g_hash_table_insert(options, strdup(name), strdup(value));
297  value = g_hash_table_lookup(options, old_name);
298  }
299  }
300 
301  if (value == NULL) {
302  crm_trace("Using default value '%s' for cluster option '%s'", def_value, name);
303 
304  if (options == NULL) {
305  return def_value;
306 
307  } else if(def_value == NULL) {
308  return def_value;
309  }
310 
311  g_hash_table_insert(options, strdup(name), strdup(def_value));
312  value = g_hash_table_lookup(options, name);
313  }
314 
315  if (validate && validate(value) == FALSE) {
316  crm_config_err("Value '%s' for cluster option '%s' is invalid."
317  " Defaulting to %s", value, name, def_value);
318  g_hash_table_replace(options, strdup(name), strdup(def_value));
319  value = g_hash_table_lookup(options, name);
320  }
321 
322  return value;
323 }
324 
325 const char *
326 get_cluster_pref(GHashTable * options, pe_cluster_option * option_list, int len, const char *name)
327 {
328  int lpc = 0;
329  const char *value = NULL;
330  gboolean found = FALSE;
331 
332  for (lpc = 0; lpc < len; lpc++) {
333  if (safe_str_eq(name, option_list[lpc].name)) {
334  found = TRUE;
335  value = cluster_option(options,
336  option_list[lpc].is_valid,
337  option_list[lpc].name,
338  option_list[lpc].alt_name, option_list[lpc].default_value);
339  }
340  }
341  CRM_CHECK(found, crm_err("No option named: %s", name));
342  return value;
343 }
344 
345 void
346 config_metadata(const char *name, const char *version, const char *desc_short,
347  const char *desc_long, pe_cluster_option * option_list, int len)
348 {
349  int lpc = 0;
350 
351  fprintf(stdout, "<?xml version=\"1.0\"?>"
352  "<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n"
353  "<resource-agent name=\"%s\">\n"
354  " <version>%s</version>\n"
355  " <longdesc lang=\"en\">%s</longdesc>\n"
356  " <shortdesc lang=\"en\">%s</shortdesc>\n"
357  " <parameters>\n", name, version, desc_long, desc_short);
358 
359  for (lpc = 0; lpc < len; lpc++) {
360  if (option_list[lpc].description_long == NULL && option_list[lpc].description_short == NULL) {
361  continue;
362  }
363  fprintf(stdout, " <parameter name=\"%s\" unique=\"0\">\n"
364  " <shortdesc lang=\"en\">%s</shortdesc>\n"
365  " <content type=\"%s\" default=\"%s\"/>\n"
366  " <longdesc lang=\"en\">%s%s%s</longdesc>\n"
367  " </parameter>\n",
368  option_list[lpc].name,
369  option_list[lpc].description_short,
370  option_list[lpc].type,
371  option_list[lpc].default_value,
372  option_list[lpc].description_long ? option_list[lpc].
373  description_long : option_list[lpc].description_short,
374  option_list[lpc].values ? " Allowed values: " : "",
375  option_list[lpc].values ? option_list[lpc].values : "");
376  }
377  fprintf(stdout, " </parameters>\n</resource-agent>\n");
378 }
379 
380 void
381 verify_all_options(GHashTable * options, pe_cluster_option * option_list, int len)
382 {
383  int lpc = 0;
384 
385  for (lpc = 0; lpc < len; lpc++) {
386  cluster_option(options,
387  option_list[lpc].is_valid,
388  option_list[lpc].name,
389  option_list[lpc].alt_name, option_list[lpc].default_value);
390  }
391 }
392 
393 char *
394 crm_concat(const char *prefix, const char *suffix, char join)
395 {
396  int len = 0;
397  char *new_str = NULL;
398 
399  CRM_ASSERT(prefix != NULL);
400  CRM_ASSERT(suffix != NULL);
401  len = strlen(prefix) + strlen(suffix) + 2;
402 
403  new_str = malloc(len);
404  if(new_str) {
405  sprintf(new_str, "%s%c%s", prefix, join, suffix);
406  new_str[len - 1] = 0;
407  }
408  return new_str;
409 }
410 
411 char *
412 generate_hash_key(const char *crm_msg_reference, const char *sys)
413 {
414  char *hash_key = crm_concat(sys ? sys : "none", crm_msg_reference, '_');
415 
416  crm_trace("created hash key: (%s)", hash_key);
417  return hash_key;
418 }
419 
420 
421 char *
422 crm_itoa_stack(int an_int, char *buffer, size_t len)
423 {
424  if (buffer != NULL) {
425  snprintf(buffer, len, "%d", an_int);
426  }
427 
428  return buffer;
429 }
430 
431 char *
432 crm_itoa(int an_int)
433 {
434  int len = 32;
435  char *buffer = NULL;
436 
437  buffer = malloc(len + 1);
438  if (buffer != NULL) {
439  snprintf(buffer, len, "%d", an_int);
440  }
441 
442  return buffer;
443 }
444 
445 int
446 crm_user_lookup(const char *name, uid_t * uid, gid_t * gid)
447 {
448  int rc = -1;
449  char *buffer = NULL;
450  struct passwd pwd;
451  struct passwd *pwentry = NULL;
452 
453  buffer = calloc(1, PW_BUFFER_LEN);
454  getpwnam_r(name, &pwd, buffer, PW_BUFFER_LEN, &pwentry);
455  if (pwentry) {
456  rc = 0;
457  if (uid) {
458  *uid = pwentry->pw_uid;
459  }
460  if (gid) {
461  *gid = pwentry->pw_gid;
462  }
463  crm_trace("Cluster user %s has uid=%d gid=%d", name, pwentry->pw_uid, pwentry->pw_gid);
464 
465  } else {
466  crm_err("Cluster user %s does not exist", name);
467  }
468 
469  free(buffer);
470  return rc;
471 }
472 
473 static int
474 crm_version_helper(const char *text, char **end_text)
475 {
476  int atoi_result = -1;
477 
478  CRM_ASSERT(end_text != NULL);
479 
480  errno = 0;
481 
482  if (text != NULL && text[0] != 0) {
483  atoi_result = (int)strtol(text, end_text, 10);
484 
485  if (errno == EINVAL) {
486  crm_err("Conversion of '%s' %c failed", text, text[0]);
487  atoi_result = -1;
488  }
489  }
490  return atoi_result;
491 }
492 
493 /*
494  * version1 < version2 : -1
495  * version1 = version2 : 0
496  * version1 > version2 : 1
497  */
498 int
499 compare_version(const char *version1, const char *version2)
500 {
501  int rc = 0;
502  int lpc = 0;
503  char *ver1_copy = NULL, *ver2_copy = NULL;
504  char *rest1 = NULL, *rest2 = NULL;
505 
506  if (version1 == NULL && version2 == NULL) {
507  return 0;
508  } else if (version1 == NULL) {
509  return -1;
510  } else if (version2 == NULL) {
511  return 1;
512  }
513 
514  ver1_copy = strdup(version1);
515  ver2_copy = strdup(version2);
516  rest1 = ver1_copy;
517  rest2 = ver2_copy;
518 
519  while (1) {
520  int digit1 = 0;
521  int digit2 = 0;
522 
523  lpc++;
524 
525  if (rest1 == rest2) {
526  break;
527  }
528 
529  if (rest1 != NULL) {
530  digit1 = crm_version_helper(rest1, &rest1);
531  }
532 
533  if (rest2 != NULL) {
534  digit2 = crm_version_helper(rest2, &rest2);
535  }
536 
537  if (digit1 < digit2) {
538  rc = -1;
539  break;
540 
541  } else if (digit1 > digit2) {
542  rc = 1;
543  break;
544  }
545 
546  if (rest1 != NULL && rest1[0] == '.') {
547  rest1++;
548  }
549  if (rest1 != NULL && rest1[0] == 0) {
550  rest1 = NULL;
551  }
552 
553  if (rest2 != NULL && rest2[0] == '.') {
554  rest2++;
555  }
556  if (rest2 != NULL && rest2[0] == 0) {
557  rest2 = NULL;
558  }
559  }
560 
561  free(ver1_copy);
562  free(ver2_copy);
563 
564  if (rc == 0) {
565  crm_trace("%s == %s (%d)", version1, version2, lpc);
566  } else if (rc < 0) {
567  crm_trace("%s < %s (%d)", version1, version2, lpc);
568  } else if (rc > 0) {
569  crm_trace("%s > %s (%d)", version1, version2, lpc);
570  }
571 
572  return rc;
573 }
574 
575 gboolean do_stderr = FALSE;
576 
577 void
579 {
580  free(data);
581 }
582 
583 #include <sys/types.h>
584 /* #include <stdlib.h> */
585 /* #include <limits.h> */
586 
587 long long
588 crm_int_helper(const char *text, char **end_text)
589 {
590  long long result = -1;
591  char *local_end_text = NULL;
592  int saved_errno = 0;
593 
594  errno = 0;
595 
596  if (text != NULL) {
597 #ifdef ANSI_ONLY
598  if (end_text != NULL) {
599  result = strtol(text, end_text, 10);
600  } else {
601  result = strtol(text, &local_end_text, 10);
602  }
603 #else
604  if (end_text != NULL) {
605  result = strtoll(text, end_text, 10);
606  } else {
607  result = strtoll(text, &local_end_text, 10);
608  }
609 #endif
610 
611  saved_errno = errno;
612 /* CRM_CHECK(errno != EINVAL); */
613  if (errno == EINVAL) {
614  crm_err("Conversion of %s failed", text);
615  result = -1;
616 
617  } else if (errno == ERANGE) {
618  crm_err("Conversion of %s was clipped: %lld", text, result);
619 
620  } else if (errno != 0) {
621  crm_perror(LOG_ERR, "Conversion of %s failed:", text);
622  }
623 
624  if (local_end_text != NULL && local_end_text[0] != '\0') {
625  crm_err("Characters left over after parsing '%s': '%s'", text, local_end_text);
626  }
627 
628  errno = saved_errno;
629  }
630  return result;
631 }
632 
633 int
634 crm_parse_int(const char *text, const char *default_text)
635 {
636  int atoi_result = -1;
637 
638  if (text != NULL) {
639  atoi_result = crm_int_helper(text, NULL);
640  if (errno == 0) {
641  return atoi_result;
642  }
643  }
644 
645  if (default_text != NULL) {
646  atoi_result = crm_int_helper(default_text, NULL);
647  if (errno == 0) {
648  return atoi_result;
649  }
650 
651  } else {
652  crm_err("No default conversion value supplied");
653  }
654 
655  return -1;
656 }
657 
658 gboolean
659 safe_str_neq(const char *a, const char *b)
660 {
661  if (a == b) {
662  return FALSE;
663 
664  } else if (a == NULL || b == NULL) {
665  return TRUE;
666 
667  } else if (strcasecmp(a, b) == 0) {
668  return FALSE;
669  }
670  return TRUE;
671 }
672 
673 gboolean
674 crm_is_true(const char *s)
675 {
676  gboolean ret = FALSE;
677 
678  if (s != NULL) {
679  crm_str_to_boolean(s, &ret);
680  }
681  return ret;
682 }
683 
684 int
685 crm_str_to_boolean(const char *s, int *ret)
686 {
687  if (s == NULL) {
688  return -1;
689 
690  } else if (strcasecmp(s, "true") == 0
691  || strcasecmp(s, "on") == 0
692  || strcasecmp(s, "yes") == 0 || strcasecmp(s, "y") == 0 || strcasecmp(s, "1") == 0) {
693  *ret = TRUE;
694  return 1;
695 
696  } else if (strcasecmp(s, "false") == 0
697  || strcasecmp(s, "off") == 0
698  || strcasecmp(s, "no") == 0 || strcasecmp(s, "n") == 0 || strcasecmp(s, "0") == 0) {
699  *ret = FALSE;
700  return 1;
701  }
702  return -1;
703 }
704 
705 #ifndef NUMCHARS
706 # define NUMCHARS "0123456789."
707 #endif
708 
709 #ifndef WHITESPACE
710 # define WHITESPACE " \t\n\r\f"
711 #endif
712 
713 unsigned long long
714 crm_get_interval(const char *input)
715 {
716  unsigned long long msec = 0;
717 
718  if (input == NULL) {
719  return msec;
720 
721  } else if (input[0] != 'P') {
722  long long tmp = crm_get_msec(input);
723 
724  if(tmp > 0) {
725  msec = tmp;
726  }
727 
728  } else {
729  crm_time_t *interval = crm_time_parse_duration(input);
730 
731  msec = 1000 * crm_time_get_seconds(interval);
732  crm_time_free(interval);
733  }
734 
735  return msec;
736 }
737 
738 long long
739 crm_get_msec(const char *input)
740 {
741  const char *cp = input;
742  const char *units;
743  long long multiplier = 1000;
744  long long divisor = 1;
745  long long msec = -1;
746  char *end_text = NULL;
747 
748  /* double dret; */
749 
750  if (input == NULL) {
751  return msec;
752  }
753 
754  cp += strspn(cp, WHITESPACE);
755  units = cp + strspn(cp, NUMCHARS);
756  units += strspn(units, WHITESPACE);
757 
758  if (strchr(NUMCHARS, *cp) == NULL) {
759  return msec;
760  }
761 
762  if (strncasecmp(units, "ms", 2) == 0 || strncasecmp(units, "msec", 4) == 0) {
763  multiplier = 1;
764  divisor = 1;
765  } else if (strncasecmp(units, "us", 2) == 0 || strncasecmp(units, "usec", 4) == 0) {
766  multiplier = 1;
767  divisor = 1000;
768  } else if (strncasecmp(units, "s", 1) == 0 || strncasecmp(units, "sec", 3) == 0) {
769  multiplier = 1000;
770  divisor = 1;
771  } else if (strncasecmp(units, "m", 1) == 0 || strncasecmp(units, "min", 3) == 0) {
772  multiplier = 60 * 1000;
773  divisor = 1;
774  } else if (strncasecmp(units, "h", 1) == 0 || strncasecmp(units, "hr", 2) == 0) {
775  multiplier = 60 * 60 * 1000;
776  divisor = 1;
777  } else if (*units != EOS && *units != '\n' && *units != '\r') {
778  return msec;
779  }
780 
781  msec = crm_int_helper(cp, &end_text);
782  if (msec > LLONG_MAX/multiplier) {
783  /* arithmetics overflow while multiplier/divisor mutually exclusive */
784  return LLONG_MAX;
785  }
786  msec *= multiplier;
787  msec /= divisor;
788  /* dret += 0.5; */
789  /* msec = (long long)dret; */
790  return msec;
791 }
792 
793 char *
794 generate_op_key(const char *rsc_id, const char *op_type, int interval)
795 {
796  int len = 35;
797  char *op_id = NULL;
798 
799  CRM_CHECK(rsc_id != NULL, return NULL);
800  CRM_CHECK(op_type != NULL, return NULL);
801 
802  len += strlen(op_type);
803  len += strlen(rsc_id);
804  op_id = malloc(len);
805  CRM_CHECK(op_id != NULL, return NULL);
806  sprintf(op_id, "%s_%s_%d", rsc_id, op_type, interval);
807  return op_id;
808 }
809 
810 gboolean
811 parse_op_key(const char *key, char **rsc_id, char **op_type, int *interval)
812 {
813  char *notify = NULL;
814  char *mutable_key = NULL;
815  char *mutable_key_ptr = NULL;
816  int len = 0, offset = 0, ch = 0;
817 
818  CRM_CHECK(key != NULL, return FALSE);
819 
820  *interval = 0;
821  len = strlen(key);
822  offset = len - 1;
823 
824  crm_trace("Source: %s", key);
825 
826  while (offset > 0 && isdigit(key[offset])) {
827  int digits = len - offset;
828 
829  ch = key[offset] - '0';
830  CRM_CHECK(ch < 10, return FALSE);
831  CRM_CHECK(ch >= 0, return FALSE);
832  while (digits > 1) {
833  digits--;
834  ch = ch * 10;
835  }
836  *interval += ch;
837  offset--;
838  }
839 
840  crm_trace(" Interval: %d", *interval);
841  CRM_CHECK(key[offset] == '_', return FALSE);
842 
843  mutable_key = strdup(key);
844  mutable_key[offset] = 0;
845  offset--;
846 
847  while (offset > 0 && key[offset] != '_') {
848  offset--;
849  }
850 
851  CRM_CHECK(key[offset] == '_', free(mutable_key);
852  return FALSE);
853 
854  mutable_key_ptr = mutable_key + offset + 1;
855 
856  crm_trace(" Action: %s", mutable_key_ptr);
857 
858  *op_type = strdup(mutable_key_ptr);
859 
860  mutable_key[offset] = 0;
861  offset--;
862 
863  CRM_CHECK(mutable_key != mutable_key_ptr, free(mutable_key);
864  return FALSE);
865 
866  notify = strstr(mutable_key, "_post_notify");
867  if (notify && safe_str_eq(notify, "_post_notify")) {
868  notify[0] = 0;
869  }
870 
871  notify = strstr(mutable_key, "_pre_notify");
872  if (notify && safe_str_eq(notify, "_pre_notify")) {
873  notify[0] = 0;
874  }
875 
876  crm_trace(" Resource: %s", mutable_key);
877  *rsc_id = mutable_key;
878 
879  return TRUE;
880 }
881 
882 char *
883 generate_notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
884 {
885  int len = 12;
886  char *op_id = NULL;
887 
888  CRM_CHECK(rsc_id != NULL, return NULL);
889  CRM_CHECK(op_type != NULL, return NULL);
890  CRM_CHECK(notify_type != NULL, return NULL);
891 
892  len += strlen(op_type);
893  len += strlen(rsc_id);
894  len += strlen(notify_type);
895  if(len > 0) {
896  op_id = malloc(len);
897  }
898  if (op_id != NULL) {
899  sprintf(op_id, "%s_%s_notify_%s_0", rsc_id, notify_type, op_type);
900  }
901  return op_id;
902 }
903 
904 char *
905 generate_transition_magic_v202(const char *transition_key, int op_status)
906 {
907  int len = 80;
908  char *fail_state = NULL;
909 
910  CRM_CHECK(transition_key != NULL, return NULL);
911 
912  len += strlen(transition_key);
913 
914  fail_state = malloc(len);
915  if (fail_state != NULL) {
916  snprintf(fail_state, len, "%d:%s", op_status, transition_key);
917  }
918  return fail_state;
919 }
920 
921 char *
922 generate_transition_magic(const char *transition_key, int op_status, int op_rc)
923 {
924  int len = 80;
925  char *fail_state = NULL;
926 
927  CRM_CHECK(transition_key != NULL, return NULL);
928 
929  len += strlen(transition_key);
930 
931  fail_state = malloc(len);
932  if (fail_state != NULL) {
933  snprintf(fail_state, len, "%d:%d;%s", op_status, op_rc, transition_key);
934  }
935  return fail_state;
936 }
937 
938 gboolean
939 decode_transition_magic(const char *magic, char **uuid, int *transition_id, int *action_id,
940  int *op_status, int *op_rc, int *target_rc)
941 {
942  int res = 0;
943  char *key = NULL;
944  gboolean result = TRUE;
945 
946  CRM_CHECK(magic != NULL, return FALSE);
947  CRM_CHECK(op_rc != NULL, return FALSE);
948  CRM_CHECK(op_status != NULL, return FALSE);
949 
950  key = calloc(1, strlen(magic) + 1);
951  res = sscanf(magic, "%d:%d;%s", op_status, op_rc, key);
952  if (res != 3) {
953  crm_warn("Only found %d items in: '%s'", res, magic);
954  free(key);
955  return FALSE;
956  }
957 
958  CRM_CHECK(decode_transition_key(key, uuid, transition_id, action_id, target_rc), result = FALSE);
959 
960  free(key);
961  return result;
962 }
963 
964 char *
965 generate_transition_key(int transition_id, int action_id, int target_rc, const char *node)
966 {
967  int len = 40;
968  char *fail_state = NULL;
969 
970  CRM_CHECK(node != NULL, return NULL);
971 
972  len += strlen(node);
973 
974  fail_state = malloc(len);
975  if (fail_state != NULL) {
976  snprintf(fail_state, len, "%d:%d:%d:%-*s", action_id, transition_id, target_rc, 36, node);
977  }
978  return fail_state;
979 }
980 
981 gboolean
982 decode_transition_key(const char *key, char **uuid, int *transition_id, int *action_id,
983  int *target_rc)
984 {
985  int res = 0;
986  gboolean done = FALSE;
987 
988  CRM_CHECK(uuid != NULL, return FALSE);
989  CRM_CHECK(target_rc != NULL, return FALSE);
990  CRM_CHECK(action_id != NULL, return FALSE);
991  CRM_CHECK(transition_id != NULL, return FALSE);
992 
993  *uuid = calloc(1, 37);
994  res = sscanf(key, "%d:%d:%d:%36s", action_id, transition_id, target_rc, *uuid);
995  switch (res) {
996  case 4:
997  /* Post Pacemaker 0.6 */
998  done = TRUE;
999  break;
1000  case 3:
1001  case 2:
1002  /* this can be tricky - the UUID might start with an integer */
1003 
1004  /* Until Pacemaker 0.6 */
1005  done = TRUE;
1006  *target_rc = -1;
1007  res = sscanf(key, "%d:%d:%36s", action_id, transition_id, *uuid);
1008  if (res == 2) {
1009  *action_id = -1;
1010  res = sscanf(key, "%d:%36s", transition_id, *uuid);
1011  CRM_CHECK(res == 2, done = FALSE);
1012 
1013  } else if (res != 3) {
1014  CRM_CHECK(res == 3, done = FALSE);
1015  }
1016  break;
1017 
1018  case 1:
1019  /* Prior to Heartbeat 2.0.8 */
1020  done = TRUE;
1021  *action_id = -1;
1022  *target_rc = -1;
1023  res = sscanf(key, "%d:%36s", transition_id, *uuid);
1024  CRM_CHECK(res == 2, done = FALSE);
1025  break;
1026  default:
1027  crm_crit("Unhandled sscanf result (%d) for %s", res, key);
1028  }
1029 
1030  if (strlen(*uuid) != 36) {
1031  crm_warn("Bad UUID (%s) in sscanf result (%d) for %s", *uuid, res, key);
1032  }
1033 
1034  if (done == FALSE) {
1035  crm_err("Cannot decode '%s' rc=%d", key, res);
1036 
1037  free(*uuid);
1038  *uuid = NULL;
1039  *target_rc = -1;
1040  *action_id = -1;
1041  *transition_id = -1;
1042  }
1043 
1044  return done;
1045 }
1046 
1047 void
1048 filter_action_parameters(xmlNode * param_set, const char *version)
1049 {
1050  char *key = NULL;
1051  char *timeout = NULL;
1052  char *interval = NULL;
1053 
1054  const char *attr_filter[] = {
1055  XML_ATTR_ID,
1058  };
1059 
1060  gboolean do_delete = FALSE;
1061  int lpc = 0;
1062  static int meta_len = 0;
1063 
1064  if (meta_len == 0) {
1065  meta_len = strlen(CRM_META);
1066  }
1067 
1068  if (param_set == NULL) {
1069  return;
1070  }
1071 
1072  for (lpc = 0; lpc < DIMOF(attr_filter); lpc++) {
1073  xml_remove_prop(param_set, attr_filter[lpc]);
1074  }
1075 
1077  interval = crm_element_value_copy(param_set, key);
1078  free(key);
1079 
1081  timeout = crm_element_value_copy(param_set, key);
1082 
1083  if (param_set) {
1084  xmlAttrPtr xIter = param_set->properties;
1085 
1086  while (xIter) {
1087  const char *prop_name = (const char *)xIter->name;
1088 
1089  xIter = xIter->next;
1090  do_delete = FALSE;
1091  if (strncasecmp(prop_name, CRM_META, meta_len) == 0) {
1092  do_delete = TRUE;
1093  }
1094 
1095  if (do_delete) {
1096  xml_remove_prop(param_set, prop_name);
1097  }
1098  }
1099  }
1100 
1101  if (crm_get_msec(interval) > 0 && compare_version(version, "1.0.8") > 0) {
1102  /* Re-instate the operation's timeout value */
1103  if (timeout != NULL) {
1104  crm_xml_add(param_set, key, timeout);
1105  }
1106  }
1107 
1108  free(interval);
1109  free(timeout);
1110  free(key);
1111 }
1112 
1113 extern bool crm_is_daemon;
1114 
1115 /* coverity[+kill] */
1116 void
1117 crm_abort(const char *file, const char *function, int line,
1118  const char *assert_condition, gboolean do_core, gboolean do_fork)
1119 {
1120  int rc = 0;
1121  int pid = 0;
1122  int status = 0;
1123 
1124  /* Implied by the parent's error logging below */
1125  /* crm_write_blackbox(0); */
1126 
1127  if(crm_is_daemon == FALSE) {
1128  /* This is a command line tool - do not fork */
1129 
1130  /* crm_add_logfile(NULL); * Record it to a file? */
1131  crm_enable_stderr(TRUE); /* Make sure stderr is enabled so we can tell the caller */
1132  do_fork = FALSE; /* Just crash if needed */
1133  }
1134 
1135  if (do_core == FALSE) {
1136  crm_err("%s: Triggered assert at %s:%d : %s", function, file, line, assert_condition);
1137  return;
1138 
1139  } else if (do_fork) {
1140  pid = fork();
1141 
1142  } else {
1143  crm_err("%s: Triggered fatal assert at %s:%d : %s", function, file, line, assert_condition);
1144  }
1145 
1146  if (pid == -1) {
1147  crm_crit("%s: Cannot create core for non-fatal assert at %s:%d : %s",
1148  function, file, line, assert_condition);
1149  return;
1150 
1151  } else if(pid == 0) {
1152  /* Child process */
1153  abort();
1154  return;
1155  }
1156 
1157  /* Parent process */
1158  crm_err("%s: Forked child %d to record non-fatal assert at %s:%d : %s",
1159  function, pid, file, line, assert_condition);
1160  crm_write_blackbox(SIGTRAP, NULL);
1161 
1162  do {
1163  rc = waitpid(pid, &status, 0);
1164  if(rc == pid) {
1165  return; /* Job done */
1166  }
1167 
1168  } while(errno == EINTR);
1169 
1170  if (errno == ECHILD) {
1171  /* crm_mon does this */
1172  crm_trace("Cannot wait on forked child %d - SIGCHLD is probably set to SIG_IGN", pid);
1173  return;
1174  }
1175  crm_perror(LOG_ERR, "Cannot wait on forked child %d", pid);
1176 }
1177 
1178 int
1179 crm_pid_active(long pid, const char *daemon)
1180 {
1181  static int last_asked_pid = 0; /* log spam prevention */
1182 #if SUPPORT_PROCFS
1183  static int have_proc_pid = 0;
1184 #else
1185  static int have_proc_pid = -1;
1186 #endif
1187  int rc = 0;
1188 
1189  if (have_proc_pid == 0) {
1190  /* evaluation of /proc/PID/exe applicability via self-introspection */
1191  char proc_path[PATH_MAX], exe_path[PATH_MAX];
1192  snprintf(proc_path, sizeof(proc_path), "/proc/%lu/exe",
1193  (long unsigned int) getpid());
1194  have_proc_pid = 1;
1195  if (readlink(proc_path, exe_path, sizeof(exe_path) - 1) < 0) {
1196  have_proc_pid = -1;
1197  }
1198  }
1199 
1200  if (pid <= 0) {
1201  return -1;
1202 
1203  } else if ((rc = kill(pid, 0)) < 0 && errno == ESRCH) {
1204  return 0; /* no such PID detected */
1205 
1206  } else if (rc < 0 && have_proc_pid == -1) {
1207  if (last_asked_pid != pid) {
1208  crm_info("Cannot examine PID %ld: %s", pid, strerror(errno));
1209  last_asked_pid = pid;
1210  }
1211  return -2; /* errno != ESRCH */
1212 
1213  } else if (rc == 0 && (daemon == NULL || have_proc_pid == -1)) {
1214  return 1; /* kill as the only indicator, cannot double check */
1215 
1216  } else {
1217  /* make sure PID hasn't been reused by another process
1218  XXX: might still be just a zombie, which could confuse decisions */
1219  bool checked_through_kill = (rc == 0);
1220  char proc_path[PATH_MAX], exe_path[PATH_MAX], myexe_path[PATH_MAX];
1221 
1222  snprintf(proc_path, sizeof(proc_path), "/proc/%ld/exe", pid);
1223 
1224  rc = readlink(proc_path, exe_path, sizeof(exe_path) - 1);
1225  if ((rc < 0) && (errno == EACCES)) {
1226  if (last_asked_pid != pid) {
1227  crm_info("Could not read from %s: %s", proc_path,
1228  strerror(errno));
1229  last_asked_pid = pid;
1230  }
1231  return checked_through_kill ? 1 : -2;
1232  } else if (rc < 0) {
1233  if (last_asked_pid != pid) {
1234  crm_err("Could not read from %s: %s (%d)", proc_path,
1235  strerror(errno), errno);
1236  last_asked_pid = pid;
1237  }
1238  return 0; /* most likely errno == ENOENT */
1239  }
1240  exe_path[rc] = '\0';
1241 
1242  if (daemon[0] != '/') {
1243  rc = snprintf(myexe_path, sizeof(myexe_path), CRM_DAEMON_DIR"/%s",
1244  daemon);
1245  } else {
1246  rc = snprintf(myexe_path, sizeof(myexe_path), "%s", daemon);
1247  }
1248 
1249  if (rc > 0 && rc < sizeof(myexe_path) && !strcmp(exe_path, myexe_path)) {
1250  return 1;
1251  }
1252  }
1253 
1254  return 0;
1255 }
1256 
1257 #define LOCKSTRLEN 11
1258 
1259 int
1260 crm_read_pidfile(const char *filename)
1261 {
1262  int fd;
1263  long pid = -1;
1264  char buf[LOCKSTRLEN + 1];
1265 
1266  if ((fd = open(filename, O_RDONLY)) < 0) {
1267  goto bail;
1268  }
1269 
1270  if (read(fd, buf, sizeof(buf)) < 1) {
1271  goto bail;
1272  }
1273 
1274  if (sscanf(buf, "%lu", &pid) > 0) {
1275  if (pid <= 0) {
1276  pid = -ESRCH;
1277  }
1278  }
1279 
1280  bail:
1281  if (fd >= 0) {
1282  close(fd);
1283  }
1284  return pid;
1285 }
1286 
1287 int
1288 crm_pidfile_inuse(const char *filename, long mypid, const char *daemon)
1289 {
1290  long pid = 0;
1291  struct stat sbuf;
1292  char buf[LOCKSTRLEN + 1];
1293  int rc = -ENOENT, fd = 0;
1294 
1295  if ((fd = open(filename, O_RDONLY)) >= 0) {
1296  if (fstat(fd, &sbuf) >= 0 && sbuf.st_size < LOCKSTRLEN) {
1297  sleep(2); /* if someone was about to create one,
1298  * give'm a sec to do so
1299  */
1300  }
1301  if (read(fd, buf, sizeof(buf)) > 0) {
1302  if (sscanf(buf, "%lu", &pid) > 0) {
1303  crm_trace("Got pid %lu from %s\n", pid, filename);
1304  if (pid <= 1) {
1305  /* Invalid pid */
1306  rc = -ENOENT;
1307  unlink(filename);
1308 
1309  } else if (mypid && pid == mypid) {
1310  /* In use by us */
1311  rc = pcmk_ok;
1312 
1313  } else if (crm_pid_active(pid, daemon) == FALSE) {
1314  /* Contains a stale value */
1315  unlink(filename);
1316  rc = -ENOENT;
1317 
1318  } else if (mypid && pid != mypid) {
1319  /* locked by existing process - give up */
1320  rc = -EEXIST;
1321  }
1322  }
1323  }
1324  close(fd);
1325  }
1326  return rc;
1327 }
1328 
1329 static int
1330 crm_lock_pidfile(const char *filename, const char *name)
1331 {
1332  long mypid = 0;
1333  int fd = 0, rc = 0;
1334  char buf[LOCKSTRLEN + 1];
1335 
1336  mypid = (unsigned long)getpid();
1337 
1338  rc = crm_pidfile_inuse(filename, 0, name);
1339  if (rc == -ENOENT) {
1340  /* exists but the process is not active */
1341 
1342  } else if (rc != pcmk_ok) {
1343  /* locked by existing process - give up */
1344  return rc;
1345  }
1346 
1347  if ((fd = open(filename, O_CREAT | O_WRONLY | O_EXCL, 0644)) < 0) {
1348  /* Hmmh, why did we fail? Anyway, nothing we can do about it */
1349  return -errno;
1350  }
1351 
1352  snprintf(buf, sizeof(buf), "%*lu\n", LOCKSTRLEN - 1, mypid);
1353  rc = write(fd, buf, LOCKSTRLEN);
1354  close(fd);
1355 
1356  if (rc != LOCKSTRLEN) {
1357  crm_perror(LOG_ERR, "Incomplete write to %s", filename);
1358  return -errno;
1359  }
1360 
1361  return crm_pidfile_inuse(filename, mypid, name);
1362 }
1363 
1364 void
1365 crm_make_daemon(const char *name, gboolean daemonize, const char *pidfile)
1366 {
1367  int rc;
1368  long pid;
1369  const char *devnull = "/dev/null";
1370 
1371  if (daemonize == FALSE) {
1372  return;
1373  }
1374 
1375  /* Check before we even try... */
1376  rc = crm_pidfile_inuse(pidfile, 1, name);
1377  if(rc < pcmk_ok && rc != -ENOENT) {
1378  pid = crm_read_pidfile(pidfile);
1379  crm_err("%s: already running [pid %ld in %s]", name, pid, pidfile);
1380  printf("%s: already running [pid %ld in %s]\n", name, pid, pidfile);
1381  crm_exit(rc);
1382  }
1383 
1384  pid = fork();
1385  if (pid < 0) {
1386  fprintf(stderr, "%s: could not start daemon\n", name);
1387  crm_perror(LOG_ERR, "fork");
1388  crm_exit(EINVAL);
1389 
1390  } else if (pid > 0) {
1391  crm_exit(pcmk_ok);
1392  }
1393 
1394  rc = crm_lock_pidfile(pidfile, name);
1395  if(rc < pcmk_ok) {
1396  crm_err("Could not lock '%s' for %s: %s (%d)", pidfile, name, pcmk_strerror(rc), rc);
1397  printf("Could not lock '%s' for %s: %s (%d)\n", pidfile, name, pcmk_strerror(rc), rc);
1398  crm_exit(rc);
1399  }
1400 
1401  umask(S_IWGRP | S_IWOTH | S_IROTH);
1402 
1403  close(STDIN_FILENO);
1404  (void)open(devnull, O_RDONLY); /* Stdin: fd 0 */
1405  close(STDOUT_FILENO);
1406  (void)open(devnull, O_WRONLY); /* Stdout: fd 1 */
1407  close(STDERR_FILENO);
1408  (void)open(devnull, O_WRONLY); /* Stderr: fd 2 */
1409 }
1410 
1411 char *
1413 {
1414  int len;
1415 
1416  if (str == NULL) {
1417  return str;
1418  }
1419 
1420  for (len = strlen(str) - 1; len >= 0 && str[len] == '\n'; len--) {
1421  str[len] = '\0';
1422  }
1423 
1424  return str;
1425 }
1426 
1427 gboolean
1428 crm_str_eq(const char *a, const char *b, gboolean use_case)
1429 {
1430  if (use_case) {
1431  return g_strcmp0(a, b) == 0;
1432 
1433  /* TODO - Figure out which calls, if any, really need to be case independent */
1434  } else if (a == b) {
1435  return TRUE;
1436 
1437  } else if (a == NULL || b == NULL) {
1438  /* shouldn't be comparing NULLs */
1439  return FALSE;
1440 
1441  } else if (strcasecmp(a, b) == 0) {
1442  return TRUE;
1443  }
1444  return FALSE;
1445 }
1446 
1447 char *
1448 crm_meta_name(const char *field)
1449 {
1450  int lpc = 0;
1451  int max = 0;
1452  char *crm_name = NULL;
1453 
1454  CRM_CHECK(field != NULL, return NULL);
1455  crm_name = crm_concat(CRM_META, field, '_');
1456 
1457  /* Massage the names so they can be used as shell variables */
1458  max = strlen(crm_name);
1459  for (; lpc < max; lpc++) {
1460  switch (crm_name[lpc]) {
1461  case '-':
1462  crm_name[lpc] = '_';
1463  break;
1464  }
1465  }
1466  return crm_name;
1467 }
1468 
1469 const char *
1470 crm_meta_value(GHashTable * hash, const char *field)
1471 {
1472  char *key = NULL;
1473  const char *value = NULL;
1474 
1475  key = crm_meta_name(field);
1476  if (key) {
1477  value = g_hash_table_lookup(hash, key);
1478  free(key);
1479  }
1480 
1481  return value;
1482 }
1483 
1484 static struct option *
1485 crm_create_long_opts(struct crm_option *long_options)
1486 {
1487  struct option *long_opts = NULL;
1488 
1489 #ifdef HAVE_GETOPT_H
1490  int index = 0, lpc = 0;
1491 
1492  /*
1493  * A previous, possibly poor, choice of '?' as the short form of --help
1494  * means that getopt_long() returns '?' for both --help and for "unknown option"
1495  *
1496  * This dummy entry allows us to differentiate between the two in crm_get_option()
1497  * and exit with the correct error code
1498  */
1499  long_opts = realloc_safe(long_opts, (index + 1) * sizeof(struct option));
1500  long_opts[index].name = "__dummmy__";
1501  long_opts[index].has_arg = 0;
1502  long_opts[index].flag = 0;
1503  long_opts[index].val = '_';
1504  index++;
1505 
1506  for (lpc = 0; long_options[lpc].name != NULL; lpc++) {
1507  if (long_options[lpc].name[0] == '-') {
1508  continue;
1509  }
1510 
1511  long_opts = realloc_safe(long_opts, (index + 1) * sizeof(struct option));
1512  /*fprintf(stderr, "Creating %d %s = %c\n", index,
1513  * long_options[lpc].name, long_options[lpc].val); */
1514  long_opts[index].name = long_options[lpc].name;
1515  long_opts[index].has_arg = long_options[lpc].has_arg;
1516  long_opts[index].flag = long_options[lpc].flag;
1517  long_opts[index].val = long_options[lpc].val;
1518  index++;
1519  }
1520 
1521  /* Now create the list terminator */
1522  long_opts = realloc_safe(long_opts, (index + 1) * sizeof(struct option));
1523  long_opts[index].name = NULL;
1524  long_opts[index].has_arg = 0;
1525  long_opts[index].flag = 0;
1526  long_opts[index].val = 0;
1527 #endif
1528 
1529  return long_opts;
1530 }
1531 
1532 void
1533 crm_set_options(const char *short_options, const char *app_usage, struct crm_option *long_options,
1534  const char *app_desc)
1535 {
1536  if (short_options) {
1537  crm_short_options = strdup(short_options);
1538 
1539  } else if (long_options) {
1540  int lpc = 0;
1541  int opt_string_len = 0;
1542  char *local_short_options = NULL;
1543 
1544  for (lpc = 0; long_options[lpc].name != NULL; lpc++) {
1545  if (long_options[lpc].val && long_options[lpc].val != '-' && long_options[lpc].val < UCHAR_MAX) {
1546  local_short_options = realloc_safe(local_short_options, opt_string_len + 4);
1547  local_short_options[opt_string_len++] = long_options[lpc].val;
1548  /* getopt(3) says: Two colons mean an option takes an optional arg; */
1549  if (long_options[lpc].has_arg == optional_argument) {
1550  local_short_options[opt_string_len++] = ':';
1551  }
1552  if (long_options[lpc].has_arg >= required_argument) {
1553  local_short_options[opt_string_len++] = ':';
1554  }
1555  local_short_options[opt_string_len] = 0;
1556  }
1557  }
1558  crm_short_options = local_short_options;
1559  crm_trace("Generated short option string: '%s'", local_short_options);
1560  }
1561 
1562  if (long_options) {
1563  crm_long_options = long_options;
1564  }
1565  if (app_desc) {
1566  crm_app_description = app_desc;
1567  }
1568  if (app_usage) {
1569  crm_app_usage = app_usage;
1570  }
1571 }
1572 
1573 int
1574 crm_get_option(int argc, char **argv, int *index)
1575 {
1576  return crm_get_option_long(argc, argv, index, NULL);
1577 }
1578 
1579 int
1580 crm_get_option_long(int argc, char **argv, int *index, const char **longname)
1581 {
1582 #ifdef HAVE_GETOPT_H
1583  static struct option *long_opts = NULL;
1584 
1585  if (long_opts == NULL && crm_long_options) {
1586  long_opts = crm_create_long_opts(crm_long_options);
1587  }
1588 
1589  *index = 0;
1590  if (long_opts) {
1591  int flag = getopt_long(argc, argv, crm_short_options, long_opts, index);
1592 
1593  switch (flag) {
1594  case 0:
1595  if (long_opts[*index].val) {
1596  return long_opts[*index].val;
1597  } else if (longname) {
1598  *longname = long_opts[*index].name;
1599  } else {
1600  crm_notice("Unhandled option --%s", long_opts[*index].name);
1601  return flag;
1602  }
1603  case -1: /* End of option processing */
1604  break;
1605  case ':':
1606  crm_trace("Missing argument");
1607  crm_help('?', 1);
1608  break;
1609  case '?':
1610  crm_help('?', *index ? 0 : 1);
1611  break;
1612  }
1613  return flag;
1614  }
1615 #endif
1616 
1617  if (crm_short_options) {
1618  return getopt(argc, argv, crm_short_options);
1619  }
1620 
1621  return -1;
1622 }
1623 
1624 int
1625 crm_help(char cmd, int exit_code)
1626 {
1627  int i = 0;
1628  FILE *stream = (exit_code ? stderr : stdout);
1629 
1630  if (cmd == 'v' || cmd == '$') {
1631  fprintf(stream, "Pacemaker %s\n", PACEMAKER_VERSION);
1632  fprintf(stream, "Written by Andrew Beekhof\n");
1633  goto out;
1634  }
1635 
1636  if (cmd == '!') {
1637  fprintf(stream, "Pacemaker %s (Build: %s): %s\n", PACEMAKER_VERSION, BUILD_VERSION, CRM_FEATURES);
1638  goto out;
1639  }
1640 
1641  fprintf(stream, "%s - %s\n", crm_system_name, crm_app_description);
1642 
1643  if (crm_app_usage) {
1644  fprintf(stream, "Usage: %s %s\n", crm_system_name, crm_app_usage);
1645  }
1646 
1647  if (crm_long_options) {
1648  fprintf(stream, "Options:\n");
1649  for (i = 0; crm_long_options[i].name != NULL; i++) {
1650  if (crm_long_options[i].flags & pcmk_option_hidden) {
1651 
1652  } else if (crm_long_options[i].flags & pcmk_option_paragraph) {
1653  fprintf(stream, "%s\n\n", crm_long_options[i].desc);
1654 
1655  } else if (crm_long_options[i].flags & pcmk_option_example) {
1656  fprintf(stream, "\t#%s\n\n", crm_long_options[i].desc);
1657 
1658  } else if (crm_long_options[i].val == '-' && crm_long_options[i].desc) {
1659  fprintf(stream, "%s\n", crm_long_options[i].desc);
1660 
1661  } else {
1662  /* is val printable as char ? */
1663  if (crm_long_options[i].val && crm_long_options[i].val <= UCHAR_MAX) {
1664  fprintf(stream, " -%c,", crm_long_options[i].val);
1665  } else {
1666  fputs(" ", stream);
1667  }
1668  fprintf(stream, " --%s%s\t%s\n", crm_long_options[i].name,
1669  crm_long_options[i].has_arg == optional_argument ? "[=value]" :
1670  crm_long_options[i].has_arg == required_argument ? "=value" : "",
1671  crm_long_options[i].desc ? crm_long_options[i].desc : "");
1672  }
1673  }
1674 
1675  } else if (crm_short_options) {
1676  fprintf(stream, "Usage: %s - %s\n", crm_system_name, crm_app_description);
1677  for (i = 0; crm_short_options[i] != 0; i++) {
1678  int has_arg = no_argument /* 0 */;
1679 
1680  if (crm_short_options[i + 1] == ':') {
1681  if (crm_short_options[i + 2] == ':')
1682  has_arg = optional_argument /* 2 */;
1683  else
1684  has_arg = required_argument /* 1 */;
1685  }
1686 
1687  fprintf(stream, " -%c %s\n", crm_short_options[i],
1688  has_arg == optional_argument ? "[value]" :
1689  has_arg == required_argument ? "{value}" : "");
1690  i += has_arg;
1691  }
1692  }
1693 
1694  fprintf(stream, "\nReport bugs to %s\n", PACKAGE_BUGREPORT);
1695 
1696  out:
1697  return crm_exit(exit_code);
1698 }
1699 
1700 void cib_ipc_servers_init(qb_ipcs_service_t **ipcs_ro,
1701  qb_ipcs_service_t **ipcs_rw,
1702  qb_ipcs_service_t **ipcs_shm,
1703  struct qb_ipcs_service_handlers *ro_cb,
1704  struct qb_ipcs_service_handlers *rw_cb)
1705 {
1706  *ipcs_ro = mainloop_add_ipc_server(cib_channel_ro, QB_IPC_NATIVE, ro_cb);
1707  *ipcs_rw = mainloop_add_ipc_server(cib_channel_rw, QB_IPC_NATIVE, rw_cb);
1708  *ipcs_shm = mainloop_add_ipc_server(cib_channel_shm, QB_IPC_SHM, rw_cb);
1709 
1710  if (*ipcs_ro == NULL || *ipcs_rw == NULL || *ipcs_shm == NULL) {
1711  crm_err("Failed to create cib servers: exiting and inhibiting respawn.");
1712  crm_warn("Verify pacemaker and pacemaker_remote are not both enabled.");
1714  }
1715 }
1716 
1717 void cib_ipc_servers_destroy(qb_ipcs_service_t *ipcs_ro,
1718  qb_ipcs_service_t *ipcs_rw,
1719  qb_ipcs_service_t *ipcs_shm)
1720 {
1721  qb_ipcs_destroy(ipcs_ro);
1722  qb_ipcs_destroy(ipcs_rw);
1723  qb_ipcs_destroy(ipcs_shm);
1724 }
1725 
1726 qb_ipcs_service_t *
1727 crmd_ipc_server_init(struct qb_ipcs_service_handlers *cb)
1728 {
1729  return mainloop_add_ipc_server(CRM_SYSTEM_CRMD, QB_IPC_NATIVE, cb);
1730 }
1731 
1732 void
1733 attrd_ipc_server_init(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb)
1734 {
1735  *ipcs = mainloop_add_ipc_server(T_ATTRD, QB_IPC_NATIVE, cb);
1736 
1737  if (*ipcs == NULL) {
1738  crm_err("Failed to create attrd servers: exiting and inhibiting respawn.");
1739  crm_warn("Verify pacemaker and pacemaker_remote are not both enabled.");
1741  }
1742 }
1743 
1744 void
1745 stonith_ipc_server_init(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb)
1746 {
1747  *ipcs = mainloop_add_ipc_server("stonith-ng", QB_IPC_NATIVE, cb);
1748 
1749  if (*ipcs == NULL) {
1750  crm_err("Failed to create stonith-ng servers: exiting and inhibiting respawn.");
1751  crm_warn("Verify pacemaker and pacemaker_remote are not both enabled.");
1753  }
1754 }
1755 
1756 int
1757 attrd_update_delegate(crm_ipc_t * ipc, char command, const char *host, const char *name,
1758  const char *value, const char *section, const char *set, const char *dampen,
1759  const char *user_name, int options)
1760 {
1761  int rc = -ENOTCONN;
1762  int max = 5;
1763  xmlNode *update = create_xml_node(NULL, __FUNCTION__);
1764 
1765  static gboolean connected = TRUE;
1766  static crm_ipc_t *local_ipc = NULL;
1767  static enum crm_ipc_flags flags = crm_ipc_flags_none;
1768 
1769  if (ipc == NULL && local_ipc == NULL) {
1770  local_ipc = crm_ipc_new(T_ATTRD, 0);
1771  flags |= crm_ipc_client_response;
1772  connected = FALSE;
1773  }
1774 
1775  if (ipc == NULL) {
1776  ipc = local_ipc;
1777  }
1778 
1779  /* remap common aliases */
1780  if (safe_str_eq(section, "reboot")) {
1781  section = XML_CIB_TAG_STATUS;
1782 
1783  } else if (safe_str_eq(section, "forever")) {
1784  section = XML_CIB_TAG_NODES;
1785  }
1786 
1787  crm_xml_add(update, F_TYPE, T_ATTRD);
1789 
1790  if (name == NULL && command == 'U') {
1791  command = 'R';
1792  }
1793 
1794  switch (command) {
1795  case 'u':
1797  crm_xml_add(update, F_ATTRD_REGEX, name);
1798  break;
1799  case 'D':
1800  case 'U':
1801  case 'v':
1803  crm_xml_add(update, F_ATTRD_ATTRIBUTE, name);
1804  break;
1805  case 'R':
1807  break;
1808  case 'Q':
1810  crm_xml_add(update, F_ATTRD_ATTRIBUTE, name);
1811  break;
1812  case 'C':
1814  break;
1815  }
1816 
1817  crm_xml_add(update, F_ATTRD_VALUE, value);
1818  crm_xml_add(update, F_ATTRD_DAMPEN, dampen);
1819  crm_xml_add(update, F_ATTRD_SECTION, section);
1820  crm_xml_add(update, F_ATTRD_HOST, host);
1821  crm_xml_add(update, F_ATTRD_SET, set);
1822  crm_xml_add_int(update, F_ATTRD_IS_REMOTE, is_set(options, attrd_opt_remote));
1823  crm_xml_add_int(update, F_ATTRD_IS_PRIVATE, is_set(options, attrd_opt_private));
1824 #if ENABLE_ACL
1825  if (user_name) {
1826  crm_xml_add(update, F_ATTRD_USER, user_name);
1827  }
1828 #endif
1829 
1830  while (max > 0) {
1831  if (connected == FALSE) {
1832  crm_info("Connecting to cluster... %d retries remaining", max);
1833  connected = crm_ipc_connect(ipc);
1834  }
1835 
1836  if (connected) {
1837  rc = crm_ipc_send(ipc, update, flags, 0, NULL);
1838  } else {
1839  crm_perror(LOG_INFO, "Connection to cluster attribute manager failed");
1840  }
1841 
1842  if (ipc != local_ipc) {
1843  break;
1844 
1845  } else if (rc > 0) {
1846  break;
1847 
1848  } else if (rc == -EAGAIN || rc == -EALREADY) {
1849  sleep(5 - max);
1850  max--;
1851 
1852  } else {
1853  crm_ipc_close(ipc);
1854  connected = FALSE;
1855  sleep(5 - max);
1856  max--;
1857  }
1858  }
1859 
1860  free_xml(update);
1861  if (rc > 0) {
1862  crm_debug("Sent update: %s=%s for %s", name, value, host ? host : "localhost");
1863  rc = pcmk_ok;
1864 
1865  } else {
1866  crm_debug("Could not send update %s=%s for %s: %s (%d)", name, value,
1867  host ? host : "localhost", pcmk_strerror(rc), rc);
1868  }
1869  return rc;
1870 }
1871 
1872 #define FAKE_TE_ID "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
1873 static void
1874 append_digest(lrmd_event_data_t * op, xmlNode * update, const char *version, const char *magic,
1875  int level)
1876 {
1877  /* this will enable us to later determine that the
1878  * resource's parameters have changed and we should force
1879  * a restart
1880  */
1881  char *digest = NULL;
1882  xmlNode *args_xml = NULL;
1883 
1884  if (op->params == NULL) {
1885  return;
1886  }
1887 
1888  args_xml = create_xml_node(NULL, XML_TAG_PARAMS);
1889  g_hash_table_foreach(op->params, hash2field, args_xml);
1890  filter_action_parameters(args_xml, version);
1891  digest = calculate_operation_digest(args_xml, version);
1892 
1893 #if 0
1894  if (level < get_crm_log_level()
1895  && op->interval == 0 && crm_str_eq(op->op_type, CRMD_ACTION_START, TRUE)) {
1896  char *digest_source = dump_xml_unformatted(args_xml);
1897 
1898  do_crm_log(level, "Calculated digest %s for %s (%s). Source: %s\n",
1899  digest, ID(update), magic, digest_source);
1900  free(digest_source);
1901  }
1902 #endif
1903  crm_xml_add(update, XML_LRM_ATTR_OP_DIGEST, digest);
1904 
1905  free_xml(args_xml);
1906  free(digest);
1907 }
1908 
1909 int
1911 {
1912  int rc = 0;
1913 
1914  if (op && op->user_data) {
1915  int dummy = 0;
1916  char *uuid = NULL;
1917 
1918  decode_transition_key(op->user_data, &uuid, &dummy, &dummy, &rc);
1919  free(uuid);
1920  }
1921  return rc;
1922 }
1923 
1924 gboolean
1926 {
1927  switch (op->op_status) {
1928  case PCMK_LRM_OP_CANCELLED:
1929  case PCMK_LRM_OP_PENDING:
1930  return FALSE;
1931  break;
1932 
1934  case PCMK_LRM_OP_TIMEOUT:
1935  case PCMK_LRM_OP_ERROR:
1936  return TRUE;
1937  break;
1938 
1939  default:
1940  if (target_rc != op->rc) {
1941  return TRUE;
1942  }
1943  }
1944 
1945  return FALSE;
1946 }
1947 
1948 xmlNode *
1949 create_operation_update(xmlNode * parent, lrmd_event_data_t * op, const char * caller_version,
1950  int target_rc, const char * node, const char * origin, int level)
1951 {
1952  char *key = NULL;
1953  char *magic = NULL;
1954  char *op_id = NULL;
1955  char *op_id_additional = NULL;
1956  char *local_user_data = NULL;
1957  const char *exit_reason = NULL;
1958 
1959  xmlNode *xml_op = NULL;
1960  const char *task = NULL;
1961  gboolean dc_munges_migrate_ops = (compare_version(caller_version, "3.0.3") < 0);
1962  gboolean dc_needs_unique_ops = (compare_version(caller_version, "3.0.6") < 0);
1963 
1964  CRM_CHECK(op != NULL, return NULL);
1965  do_crm_log(level, "%s: Updating resource %s after %s op %s (interval=%d)",
1966  origin, op->rsc_id, op->op_type, services_lrm_status_str(op->op_status),
1967  op->interval);
1968 
1969  crm_trace("DC version: %s", caller_version);
1970 
1971  task = op->op_type;
1972  /* remap the task name under various scenarios
1973  * this makes life easier for the PE when trying determine the current state
1974  */
1975  if (crm_str_eq(task, "reload", TRUE)) {
1976  if (op->op_status == PCMK_LRM_OP_DONE) {
1977  task = CRMD_ACTION_START;
1978  } else {
1979  task = CRMD_ACTION_STATUS;
1980  }
1981 
1982  } else if (dc_munges_migrate_ops && crm_str_eq(task, CRMD_ACTION_MIGRATE, TRUE)) {
1983  /* if the migrate_from fails it will have enough info to do the right thing */
1984  if (op->op_status == PCMK_LRM_OP_DONE) {
1985  task = CRMD_ACTION_STOP;
1986  } else {
1987  task = CRMD_ACTION_STATUS;
1988  }
1989 
1990  } else if (dc_munges_migrate_ops
1991  && op->op_status == PCMK_LRM_OP_DONE
1992  && crm_str_eq(task, CRMD_ACTION_MIGRATED, TRUE)) {
1993  task = CRMD_ACTION_START;
1994  }
1995 
1996  key = generate_op_key(op->rsc_id, task, op->interval);
1997  if (dc_needs_unique_ops && op->interval > 0) {
1998  op_id = strdup(key);
1999 
2000  } else if (crm_str_eq(task, CRMD_ACTION_NOTIFY, TRUE)) {
2001  const char *n_type = crm_meta_value(op->params, "notify_type");
2002  const char *n_task = crm_meta_value(op->params, "notify_operation");
2003 
2004  CRM_LOG_ASSERT(n_type != NULL);
2005  CRM_LOG_ASSERT(n_task != NULL);
2006  op_id = generate_notify_key(op->rsc_id, n_type, n_task);
2007 
2008  /* these are not yet allowed to fail */
2010  op->rc = 0;
2011 
2012  } else if (did_rsc_op_fail(op, target_rc)) {
2013  op_id = generate_op_key(op->rsc_id, "last_failure", 0);
2014  if (op->interval == 0) {
2015  /* Ensure 'last' gets updated too in case recording-pending="true" */
2016  op_id_additional = generate_op_key(op->rsc_id, "last", 0);
2017  }
2018  exit_reason = op->exit_reason;
2019 
2020  } else if (op->interval > 0) {
2021  op_id = strdup(key);
2022 
2023  } else {
2024  op_id = generate_op_key(op->rsc_id, "last", 0);
2025  }
2026 
2027  again:
2028  xml_op = find_entity(parent, XML_LRM_TAG_RSC_OP, op_id);
2029  if (xml_op == NULL) {
2030  xml_op = create_xml_node(parent, XML_LRM_TAG_RSC_OP);
2031  }
2032 
2033  if (op->user_data == NULL) {
2034  crm_debug("Generating fake transition key for:"
2035  " %s_%s_%d %d from %s",
2036  op->rsc_id, op->op_type, op->interval, op->call_id, origin);
2037  local_user_data = generate_transition_key(-1, op->call_id, target_rc, FAKE_TE_ID);
2038  op->user_data = local_user_data;
2039  }
2040 
2041  if(magic == NULL) {
2042  magic = generate_transition_magic(op->user_data, op->op_status, op->rc);
2043  }
2044 
2045  crm_xml_add(xml_op, XML_ATTR_ID, op_id);
2046  crm_xml_add(xml_op, XML_LRM_ATTR_TASK_KEY, key);
2047  crm_xml_add(xml_op, XML_LRM_ATTR_TASK, task);
2048  crm_xml_add(xml_op, XML_ATTR_ORIGIN, origin);
2049  crm_xml_add(xml_op, XML_ATTR_CRM_VERSION, caller_version);
2051  crm_xml_add(xml_op, XML_ATTR_TRANSITION_MAGIC, magic);
2052  crm_xml_add(xml_op, XML_LRM_ATTR_EXIT_REASON, exit_reason);
2053  crm_xml_add(xml_op, XML_LRM_ATTR_TARGET, node); /* For context during triage */
2054 
2056  crm_xml_add_int(xml_op, XML_LRM_ATTR_RC, op->rc);
2059 
2060  if (compare_version("2.1", caller_version) <= 0) {
2061  if (op->t_run || op->t_rcchange || op->exec_time || op->queue_time) {
2062  crm_trace("Timing data (%s_%s_%d): last=%lu change=%lu exec=%lu queue=%lu",
2063  op->rsc_id, op->op_type, op->interval,
2064  op->t_run, op->t_rcchange, op->exec_time, op->queue_time);
2065 
2066  if (op->interval == 0) {
2067  /* The values are the same for non-recurring ops */
2070 
2071  } else if(op->t_rcchange) {
2072  /* last-run is not accurate for recurring ops */
2074 
2075  } else {
2076  /* ...but is better than nothing otherwise */
2078  }
2079 
2082  }
2083  }
2084 
2085  if (crm_str_eq(op->op_type, CRMD_ACTION_MIGRATE, TRUE)
2086  || crm_str_eq(op->op_type, CRMD_ACTION_MIGRATED, TRUE)) {
2087  /*
2088  * Record migrate_source and migrate_target always for migrate ops.
2089  */
2090  const char *name = XML_LRM_ATTR_MIGRATE_SOURCE;
2091 
2092  crm_xml_add(xml_op, name, crm_meta_value(op->params, name));
2093 
2095  crm_xml_add(xml_op, name, crm_meta_value(op->params, name));
2096  }
2097 
2098  append_digest(op, xml_op, caller_version, magic, LOG_DEBUG);
2099 
2100  if (op_id_additional) {
2101  free(op_id);
2102  op_id = op_id_additional;
2103  op_id_additional = NULL;
2104  goto again;
2105  }
2106 
2107  if (local_user_data) {
2108  free(local_user_data);
2109  op->user_data = NULL;
2110  }
2111  free(magic);
2112  free(op_id);
2113  free(key);
2114  return xml_op;
2115 }
2116 
2117 bool
2118 pcmk_acl_required(const char *user)
2119 {
2120 #if ENABLE_ACL
2121  if(user == NULL || strlen(user) == 0) {
2122  crm_trace("no user set");
2123  return FALSE;
2124 
2125  } else if (strcmp(user, CRM_DAEMON_USER) == 0) {
2126  return FALSE;
2127 
2128  } else if (strcmp(user, "root") == 0) {
2129  return FALSE;
2130  }
2131  crm_trace("acls required for %s", user);
2132  return TRUE;
2133 #else
2134  crm_trace("acls not supported");
2135  return FALSE;
2136 #endif
2137 }
2138 
2139 #if ENABLE_ACL
2140 char *
2141 uid2username(uid_t uid)
2142 {
2143  struct passwd *pwent = getpwuid(uid);
2144 
2145  if (pwent == NULL) {
2146  crm_perror(LOG_ERR, "Cannot get password entry of uid: %d", uid);
2147  return NULL;
2148 
2149  } else {
2150  return strdup(pwent->pw_name);
2151  }
2152 }
2153 
2154 const char *
2155 crm_acl_get_set_user(xmlNode * request, const char *field, const char *peer_user)
2156 {
2157  /* field is only checked for backwards compatibility */
2158  static const char *effective_user = NULL;
2159  const char *requested_user = NULL;
2160  const char *user = NULL;
2161 
2162  if(effective_user == NULL) {
2163  effective_user = uid2username(geteuid());
2164  }
2165 
2166  requested_user = crm_element_value(request, XML_ACL_TAG_USER);
2167  if(requested_user == NULL) {
2168  requested_user = crm_element_value(request, field);
2169  }
2170 
2171  if (is_privileged(effective_user) == FALSE) {
2172  /* We're not running as a privileged user, set or overwrite any existing value for $XML_ACL_TAG_USER */
2173  user = effective_user;
2174 
2175  } else if(peer_user == NULL && requested_user == NULL) {
2176  /* No user known or requested, use 'effective_user' and make sure one is set for the request */
2177  user = effective_user;
2178 
2179  } else if(peer_user == NULL) {
2180  /* No user known, trusting 'requested_user' */
2181  user = requested_user;
2182 
2183  } else if (is_privileged(peer_user) == FALSE) {
2184  /* The peer is not a privileged user, set or overwrite any existing value for $XML_ACL_TAG_USER */
2185  user = peer_user;
2186 
2187  } else if (requested_user == NULL) {
2188  /* Even if we're privileged, make sure there is always a value set */
2189  user = peer_user;
2190 
2191  } else {
2192  /* Legal delegation to 'requested_user' */
2193  user = requested_user;
2194  }
2195 
2196  /* Yes, pointer comparision */
2197  if(user != crm_element_value(request, XML_ACL_TAG_USER)) {
2198  crm_xml_add(request, XML_ACL_TAG_USER, user);
2199  }
2200 
2201  if(field != NULL && user != crm_element_value(request, field)) {
2202  crm_xml_add(request, field, user);
2203  }
2204 
2205  return requested_user;
2206 }
2207 
2208 void
2209 determine_request_user(const char *user, xmlNode * request, const char *field)
2210 {
2211  /* Get our internal validation out of the way first */
2212  CRM_CHECK(user != NULL && request != NULL && field != NULL, return);
2213 
2214  /* If our peer is a privileged user, we might be doing something on behalf of someone else */
2215  if (is_privileged(user) == FALSE) {
2216  /* We're not a privileged user, set or overwrite any existing value for $field */
2217  crm_xml_replace(request, field, user);
2218 
2219  } else if (crm_element_value(request, field) == NULL) {
2220  /* Even if we're privileged, make sure there is always a value set */
2221  crm_xml_replace(request, field, user);
2222 
2223 /* } else { Legal delegation */
2224  }
2225 
2226  crm_trace("Processing msg as user '%s'", crm_element_value(request, field));
2227 }
2228 #endif
2229 
2230 /*
2231  * This re-implements g_str_hash as it was prior to glib2-2.28:
2232  *
2233  * http://git.gnome.org/browse/glib/commit/?id=354d655ba8a54b754cb5a3efb42767327775696c
2234  *
2235  * Note that the new g_str_hash is presumably a *better* hash (it's actually
2236  * a correct implementation of DJB's hash), but we need to preserve existing
2237  * behaviour, because the hash key ultimately determines the "sort" order
2238  * when iterating through GHashTables, which affects allocation of scores to
2239  * clone instances when iterating through rsc->allowed_nodes. It (somehow)
2240  * also appears to have some minor impact on the ordering of a few
2241  * pseudo_event IDs in the transition graph.
2242  */
2243 guint
2244 g_str_hash_traditional(gconstpointer v)
2245 {
2246  const signed char *p;
2247  guint32 h = 0;
2248 
2249  for (p = v; *p != '\0'; p++)
2250  h = (h << 5) - h + *p;
2251 
2252  return h;
2253 }
2254 
2255 guint
2256 crm_strcase_hash(gconstpointer v)
2257 {
2258  const signed char *p;
2259  guint32 h = 0;
2260 
2261  for (p = v; *p != '\0'; p++)
2262  h = (h << 5) - h + g_ascii_tolower(*p);
2263 
2264  return h;
2265 }
2266 
2267 void *
2268 find_library_function(void **handle, const char *lib, const char *fn, gboolean fatal)
2269 {
2270  char *error;
2271  void *a_function;
2272 
2273  if (*handle == NULL) {
2274  *handle = dlopen(lib, RTLD_LAZY);
2275  }
2276 
2277  if (!(*handle)) {
2278  crm_err("%sCould not open %s: %s", fatal ? "Fatal: " : "", lib, dlerror());
2279  if (fatal) {
2281  }
2282  return NULL;
2283  }
2284 
2285  a_function = dlsym(*handle, fn);
2286  if ((error = dlerror()) != NULL) {
2287  crm_err("%sCould not find %s in %s: %s", fatal ? "Fatal: " : "", fn, lib, error);
2288  if (fatal) {
2290  }
2291  }
2292 
2293  return a_function;
2294 }
2295 
2296 char *
2297 add_list_element(char *list, const char *value)
2298 {
2299  int len = 0;
2300  int last = 0;
2301 
2302  if (value == NULL) {
2303  return list;
2304  }
2305  if (list) {
2306  last = strlen(list);
2307  }
2308  len = last + 2; /* +1 space, +1 EOS */
2309  len += strlen(value);
2310  list = realloc_safe(list, len);
2311  sprintf(list + last, " %s", value);
2312  return list;
2313 }
2314 
2315 void *
2316 convert_const_pointer(const void *ptr)
2317 {
2318  /* Worst function ever */
2319  return (void *)ptr;
2320 }
2321 
2322 #ifdef HAVE_UUID_UUID_H
2323 # include <uuid/uuid.h>
2324 #endif
2325 
2326 char *
2328 {
2329  unsigned char uuid[16];
2330  char *buffer = malloc(37); /* Including NUL byte */
2331 
2332  uuid_generate(uuid);
2333  uuid_unparse(uuid, buffer);
2334  return buffer;
2335 }
2336 
2337 #include <md5.h>
2338 
2339 char *
2340 crm_md5sum(const char *buffer)
2341 {
2342  int lpc = 0, len = 0;
2343  char *digest = NULL;
2344  unsigned char raw_digest[MD5_DIGEST_SIZE];
2345 
2346  if (buffer == NULL) {
2347  buffer = "";
2348  }
2349  len = strlen(buffer);
2350 
2351  crm_trace("Beginning digest of %d bytes", len);
2352  digest = malloc(2 * MD5_DIGEST_SIZE + 1);
2353  if(digest) {
2354  md5_buffer(buffer, len, raw_digest);
2355  for (lpc = 0; lpc < MD5_DIGEST_SIZE; lpc++) {
2356  sprintf(digest + (2 * lpc), "%02x", raw_digest[lpc]);
2357  }
2358  digest[(2 * MD5_DIGEST_SIZE)] = 0;
2359  crm_trace("Digest %s.", digest);
2360 
2361  } else {
2362  crm_err("Could not create digest");
2363  }
2364  return digest;
2365 }
2366 
2367 #include <time.h>
2368 #include <bzlib.h>
2369 
2370 bool
2371 crm_compress_string(const char *data, int length, int max, char **result, unsigned int *result_len)
2372 {
2373  int rc;
2374  char *compressed = NULL;
2375  char *uncompressed = strdup(data);
2376  struct timespec after_t;
2377  struct timespec before_t;
2378 
2379  if(max == 0) {
2380  max = (length * 1.1) + 600; /* recomended size */
2381  }
2382 
2383 #ifdef CLOCK_MONOTONIC
2384  clock_gettime(CLOCK_MONOTONIC, &before_t);
2385 #endif
2386 
2387  /* coverity[returned_null] Ignore */
2388  compressed = malloc(max);
2389 
2390  *result_len = max;
2391  rc = BZ2_bzBuffToBuffCompress(compressed, result_len, uncompressed, length, CRM_BZ2_BLOCKS, 0,
2392  CRM_BZ2_WORK);
2393 
2394  free(uncompressed);
2395 
2396  if (rc != BZ_OK) {
2397  crm_err("Compression of %d bytes failed: %s (%d)", length, bz2_strerror(rc), rc);
2398  free(compressed);
2399  return FALSE;
2400  }
2401 
2402 #ifdef CLOCK_MONOTONIC
2403  clock_gettime(CLOCK_MONOTONIC, &after_t);
2404 
2405  crm_info("Compressed %d bytes into %d (ratio %d:1) in %dms",
2406  length, *result_len, length / (*result_len),
2407  (after_t.tv_sec - before_t.tv_sec) * 1000 + (after_t.tv_nsec -
2408  before_t.tv_nsec) / 1000000);
2409 #else
2410  crm_info("Compressed %d bytes into %d (ratio %d:1)",
2411  length, *result_len, length / (*result_len));
2412 #endif
2413 
2414  *result = compressed;
2415  return TRUE;
2416 }
2417 
2418 #ifdef HAVE_GNUTLS_GNUTLS_H
2419 void
2420 crm_gnutls_global_init(void)
2421 {
2422  signal(SIGPIPE, SIG_IGN);
2423  gnutls_global_init();
2424 }
2425 #endif
2426 
Services API.
#define T_ATTRD
Definition: msg_xml.h:50
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:164
#define XML_RSC_OP_LAST_CHANGE
Definition: msg_xml.h:278
void * find_library_function(void **handle, const char *lib, const char *fn, gboolean fatal)
Definition: utils.c:2268
void verify_all_options(GHashTable *options, pe_cluster_option *option_list, int len)
Definition: utils.c:381
#define F_ATTRD_VALUE
Definition: crm_internal.h:298
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, int *interval)
Definition: utils.c:811
void crm_write_blackbox(int nsig, struct qb_log_callsite *callsite)
Definition: logging.c:407
bool crm_ipc_connect(crm_ipc_t *client)
Establish an IPC connection to a Pacemaker component.
Definition: ipc.c:795
A dumping ground.
#define F_TYPE
Definition: msg_xml.h:34
long long crm_get_msec(const char *input)
Definition: utils.c:739
int crm_get_option_long(int argc, char **argv, int *index, const char **longname)
Definition: utils.c:1580
#define crm_notice(fmt, args...)
Definition: logging.h:250
int crm_user_lookup(const char *name, uid_t *uid, gid_t *gid)
Definition: utils.c:446
#define CRMD_ACTION_MIGRATED
Definition: crm.h:148
gboolean do_stderr
Definition: utils.c:575
int attrd_update_delegate(crm_ipc_t *ipc, char command, const char *host, const char *name, const char *value, const char *section, const char *set, const char *dampen, const char *user_name, int options)
Definition: utils.c:1757
void crm_enable_stderr(int enable)
Definition: logging.c:890
void * convert_const_pointer(const void *ptr)
Definition: utils.c:2316
bool crm_compress_string(const char *data, int length, int max, char **result, unsigned int *result_len)
Definition: utils.c:2371
#define crm_crit(fmt, args...)
Definition: logging.h:247
gboolean check_utilization(const char *value)
Definition: utils.c:201
#define INFINITY
Definition: crm.h:77
const char * user_data
Definition: lrmd.h:186
const char * crm_meta_value(GHashTable *hash, const char *field)
Definition: utils.c:1470
const char * rsc_id
Definition: lrmd.h:182
#define XML_ATTR_TRANSITION_MAGIC
Definition: msg_xml.h:346
void cib_ipc_servers_destroy(qb_ipcs_service_t *ipcs_ro, qb_ipcs_service_t *ipcs_rw, qb_ipcs_service_t *ipcs_shm)
Definition: utils.c:1717
void attrd_ipc_server_init(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb)
Definition: utils.c:1733
char * crm_concat(const char *prefix, const char *suffix, char join)
Definition: utils.c:394
struct crm_time_s crm_time_t
Definition: iso8601.h:37
const char * pcmk_strerror(int rc)
Definition: logging.c:1113
int node_score_infinity
Definition: utils.c:70
gboolean check_time(const char *value)
Definition: utils.c:106
#define crm_config_err(fmt...)
Definition: crm_internal.h:290
#define F_ATTRD_HOST
Definition: crm_internal.h:305
unsigned int queue_time
Definition: lrmd.h:212
void crm_make_daemon(const char *name, gboolean daemonize, const char *pidfile)
Definition: utils.c:1365
void crm_xml_cleanup(void)
Definition: xml.c:5358
gboolean decode_transition_key(const char *key, char **uuid, int *transition_id, int *action_id, int *target_rc)
Definition: utils.c:982
#define F_ATTRD_REGEX
Definition: crm_internal.h:296
#define pcmk_ok
Definition: error.h:42
void g_hash_destroy_str(gpointer data)
Definition: utils.c:578
#define CRMD_ACTION_NOTIFY
Definition: crm.h:161
void cib_ipc_servers_init(qb_ipcs_service_t **ipcs_ro, qb_ipcs_service_t **ipcs_rw, qb_ipcs_service_t **ipcs_shm, struct qb_ipcs_service_handlers *ro_cb, struct qb_ipcs_service_handlers *rw_cb)
Definition: utils.c:1700
char * crm_md5sum(const char *buffer)
Definition: utils.c:2340
xmlNode * find_entity(xmlNode *parent, const char *node_name, const char *id)
Definition: xml.c:2473
#define XML_RSC_OP_T_EXEC
Definition: msg_xml.h:280
char * generate_transition_key(int transition_id, int action_id, int target_rc, const char *node)
Definition: utils.c:965
#define F_ATTRD_USER
Definition: crm_internal.h:307
#define XML_LRM_ATTR_INTERVAL
Definition: msg_xml.h:256
gboolean safe_str_neq(const char *a, const char *b)
Definition: utils.c:659
gboolean crm_config_warning
Definition: utils.c:64
int crm_help(char cmd, int exit_code)
Definition: utils.c:1625
#define XML_LRM_ATTR_OP_DIGEST
Definition: msg_xml.h:271
#define XML_ATTR_TIMEOUT
Definition: msg_xml.h:94
#define ATTRD_OP_UPDATE
Definition: crm_internal.h:313
void mainloop_cleanup(void)
Definition: mainloop.c:407
int node_score_red
Definition: utils.c:67
char * crm_element_value_copy(xmlNode *data, const char *name)
Definition: xml.c:4031
Local Resource Manager.
unsigned int t_rcchange
Definition: lrmd.h:208
crm_time_t * crm_time_parse_duration(const char *duration_str)
Definition: iso8601.c:830
AIS_Host host
Definition: internal.h:52
#define MINUS_INFINITY_S
Definition: crm.h:75
#define F_ATTRD_SECTION
Definition: crm_internal.h:302
char * crm_itoa_stack(int an_int, char *buffer, size_t len)
Definition: utils.c:422
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:150
void crm_set_options(const char *short_options, const char *app_usage, struct crm_option *long_options, const char *app_desc)
Definition: utils.c:1533
uint32_t pid
Definition: internal.h:49
enum ocf_exitcode rc
Definition: lrmd.h:200
const char * get_cluster_pref(GHashTable *options, pe_cluster_option *option_list, int len, const char *name)
Definition: utils.c:326
char * crm_system_name
Definition: utils.c:65
#define cib_channel_rw
Definition: internal.h:80
char * strerror(int errnum)
#define XML_RSC_OP_T_QUEUE
Definition: msg_xml.h:281
#define XML_CIB_TAG_NODES
Definition: msg_xml.h:158
#define PACEMAKER_VERSION
Definition: config.h:523
#define attrd_opt_private
Definition: attrd.h:25
#define F_ATTRD_SET
Definition: crm_internal.h:299
#define ATTRD_OP_REFRESH
Definition: crm_internal.h:315
int crm_pidfile_inuse(const char *filename, long mypid, const char *daemon)
Definition: utils.c:1288
Wrappers for and extensions to glib mainloop.
char version[256]
Definition: plugin.c:84
void config_metadata(const char *name, const char *version, const char *desc_short, const char *desc_long, pe_cluster_option *option_list, int len)
Definition: utils.c:346
const char * crm_xml_replace(xmlNode *node, const char *name, const char *value)
Definition: xml.c:2741
#define CRM_BZ2_WORK
Definition: xml.h:49
#define ATTRD_OP_PEER_REMOVE
Definition: crm_internal.h:312
bool pcmk_acl_required(const char *user)
Definition: utils.c:2118
guint g_str_hash_traditional(gconstpointer v)
Definition: utils.c:2244
unsigned int exec_time
Definition: lrmd.h:210
void stonith_ipc_server_init(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb)
Definition: utils.c:1745
#define XML_ATTR_ORIGIN
Definition: msg_xml.h:95
#define CRMD_ACTION_START
Definition: crm.h:150
xmlNode * create_operation_update(xmlNode *parent, lrmd_event_data_t *op, const char *caller_version, int target_rc, const char *node, const char *origin, int level)
Definition: utils.c:1949
char * crm_meta_name(const char *field)
Definition: utils.c:1448
gboolean check_quorum(const char *value)
Definition: utils.c:156
#define XML_LRM_ATTR_TASK_KEY
Definition: msg_xml.h:258
#define XML_LRM_ATTR_TASK
Definition: msg_xml.h:257
void hash2field(gpointer key, gpointer value, gpointer user_data)
Definition: xml.c:5008
#define CRMD_ACTION_STOP
Definition: crm.h:153
void * params
Definition: lrmd.h:219
#define PW_BUFFER_LEN
Definition: utils.c:58
char * calculate_operation_digest(xmlNode *local_cib, const char *version)
Calculate and return digest of XML operation.
Definition: digest.c:175
#define crm_warn(fmt, args...)
Definition: logging.h:249
op_status
Definition: services.h:120
int crm_pid_active(long pid, const char *daemon)
Definition: utils.c:1179
int daemon(int nochdir, int noclose)
const char * exit_reason
Definition: lrmd.h:228
#define F_ATTRD_ATTRIBUTE
Definition: crm_internal.h:295
char * generate_hash_key(const char *crm_msg_reference, const char *sys)
Definition: utils.c:412
uint64_t flags
Definition: remote.c:121
#define crm_debug(fmt, args...)
Definition: logging.h:253
void determine_request_user(const char *user, xmlNode *request, const char *field)
bool crm_is_daemon
Definition: logging.c:49
struct crm_ipc_s crm_ipc_t
Definition: ipc.h:61
Utility functions.
#define F_ATTRD_IS_PRIVATE
Definition: crm_internal.h:301
#define XML_ATTR_ID
Definition: msg_xml.h:100
#define CRM_DAEMON_DIR
Definition: config.h:41
char * score2char(int score)
Definition: utils.c:268
#define BUILD_VERSION
Definition: config.h:23
#define LOCKSTRLEN
Definition: utils.c:1257
#define pcmk_option_example
Definition: crm_internal.h:74
unsigned long long crm_get_interval(const char *input)
Definition: utils.c:714
#define INFINITY_S
Definition: crm.h:74
gboolean did_rsc_op_fail(lrmd_event_data_t *op, int target_rc)
Definition: utils.c:1925
#define crm_trace(fmt, args...)
Definition: logging.h:254
#define do_crm_log(level, fmt, args...)
Log a message.
Definition: logging.h:129
const char * cluster_option(GHashTable *options, gboolean(*validate)(const char *), const char *name, const char *old_name, const char *def_value)
Definition: utils.c:280
#define pcmk_option_paragraph
Definition: crm_internal.h:73
#define NUMCHARS
Definition: utils.c:706
int node_score_yellow
Definition: utils.c:69
Wrappers for and extensions to libxml2.
ISO_8601 Date handling.
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:2793
const char * crm_element_value(xmlNode *data, const char *name)
Definition: xml.c:5839
long long crm_int_helper(const char *text, char **end_text)
Definition: utils.c:588
char * crm_itoa(int an_int)
Definition: utils.c:432
gboolean crm_is_true(const char *s)
Definition: utils.c:674
#define CRM_DAEMON_USER
Definition: config.h:47
int crm_exit(int rc)
Definition: utils.c:78
#define F_ATTRD_TASK
Definition: crm_internal.h:297
#define F_ATTRD_IS_REMOTE
Definition: crm_internal.h:300
#define XML_LRM_ATTR_MIGRATE_TARGET
Definition: msg_xml.h:284
char * crm_generate_uuid(void)
Definition: utils.c:2327
#define XML_LRM_ATTR_EXIT_REASON
Definition: msg_xml.h:276
#define F_ORIG
Definition: msg_xml.h:22
void free_xml(xmlNode *child)
Definition: xml.c:2848
#define EOS
Definition: crm.h:40
#define attrd_opt_remote
Definition: attrd.h:24
void filter_action_parameters(xmlNode *param_set, const char *version)
Definition: utils.c:1048
int * flag
Definition: crm_internal.h:86
int node_score_green
Definition: utils.c:68
CRM_TRACE_INIT_DATA(common)
const char * op_type
Definition: lrmd.h:184
#define WHITESPACE
Definition: utils.c:710
gboolean decode_transition_magic(const char *magic, char **uuid, int *transition_id, int *action_id, int *op_status, int *op_rc, int *target_rc)
Definition: utils.c:939
#define cib_channel_shm
Definition: internal.h:81
#define CRM_SYSTEM_CRMD
Definition: crm.h:84
long long int crm_time_get_seconds(crm_time_t *dt)
Definition: iso8601.c:269
#define DAEMON_RESPAWN_STOP
Definition: crm.h:67
int compare_version(const char *version1, const char *version2)
Definition: utils.c:499
unsigned int t_run
Definition: lrmd.h:206
gboolean check_script(const char *value)
Definition: utils.c:174
#define crm_config_warn(fmt...)
Definition: crm_internal.h:291
#define XML_ATTR_TRANSITION_KEY
Definition: msg_xml.h:347
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Definition: xml.c:2695
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Definition: xml.c:2783
unsigned int get_crm_log_level(void)
Definition: logging.c:920
#define ATTRD_OP_QUERY
Definition: crm_internal.h:314
void crm_abort(const char *file, const char *function, int line, const char *assert_condition, gboolean do_core, gboolean do_fork)
Definition: utils.c:1117
char * generate_notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
Definition: utils.c:883
gboolean check_timer(const char *value)
Definition: utils.c:115
#define crm_perror(level, fmt, args...)
Log a system error message.
Definition: logging.h:226
#define CRM_META
Definition: crm.h:55
char * generate_transition_magic_v202(const char *transition_key, int op_status)
Definition: utils.c:905
int char2score(const char *score)
Definition: utils.c:216
#define crm_err(fmt, args...)
Definition: logging.h:248
#define FAKE_TE_ID
Definition: utils.c:1872
int crm_parse_int(const char *text, const char *default_text)
Definition: utils.c:634
int crm_ipc_send(crm_ipc_t *client, xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Definition: ipc.c:1148
const char * bz2_strerror(int rc)
Definition: logging.c:1176
gboolean check_number(const char *value)
Definition: utils.c:135
void xml_remove_prop(xmlNode *obj, const char *name)
Definition: xml.c:4043
int rsc_op_expected_rc(lrmd_event_data_t *op)
Definition: utils.c:1910
crm_ipc_t * crm_ipc_new(const char *name, size_t max_size)
Definition: ipc.c:765
#define F_ATTRD_DAMPEN
Definition: crm_internal.h:303
char * dump_xml_unformatted(xmlNode *msg)
Definition: xml.c:3987
#define DIMOF(a)
Definition: crm.h:41
#define XML_LRM_ATTR_CALLID
Definition: msg_xml.h:270
#define CRMD_ACTION_MIGRATE
Definition: crm.h:147
#define CRM_ASSERT(expr)
Definition: error.h:35
char data[0]
Definition: internal.h:58
#define XML_LRM_ATTR_OPSTATUS
Definition: msg_xml.h:268
#define XML_ATTR_CRM_VERSION
Definition: msg_xml.h:83
#define pcmk_option_hidden
Definition: crm_internal.h:72
int crm_get_option(int argc, char **argv, int *index)
Definition: utils.c:1574
char * generate_op_key(const char *rsc_id, const char *op_type, int interval)
Definition: utils.c:794
#define XML_LRM_ATTR_RC
Definition: msg_xml.h:269
#define MD5_DIGEST_SIZE
Definition: md5.h:26
void * md5_buffer(const char *buffer, size_t len, void *resblock)
Definition: md5.c:210
Wrappers for and extensions to libqb IPC.
#define PACKAGE_BUGREPORT
Definition: config.h:529
int crm_read_pidfile(const char *filename)
Definition: utils.c:1260
#define XML_CIB_TAG_STATUS
Definition: msg_xml.h:156
char * generate_transition_magic(const char *transition_key, int op_status, int op_rc)
Definition: utils.c:922
int crm_str_to_boolean(const char *s, int *ret)
Definition: utils.c:685
const char * crm_acl_get_set_user(xmlNode *request, const char *field, const char *peer_user)
gboolean crm_config_error
Definition: utils.c:63
#define CRM_BZ2_BLOCKS
Definition: xml.h:48
#define XML_LRM_ATTR_TARGET
Definition: msg_xml.h:259
#define XML_LRM_TAG_RSC_OP
Definition: msg_xml.h:232
#define XML_RSC_OP_LAST_RUN
Definition: msg_xml.h:279
#define ID(x)
Definition: msg_xml.h:408
#define XML_ACL_TAG_USER
Definition: msg_xml.h:357
#define safe_str_eq(a, b)
Definition: util.h:74
qb_ipcs_service_t * mainloop_add_ipc_server(const char *name, enum qb_ipc_type type, struct qb_ipcs_service_handlers *callbacks)
Definition: mainloop.c:585
#define XML_LRM_ATTR_MIGRATE_SOURCE
Definition: msg_xml.h:283
#define CRM_FEATURES
Definition: config.h:53
gboolean check_boolean(const char *value)
Definition: utils.c:124
crm_ipc_flags
Definition: ipc.h:41
void crm_ipc_close(crm_ipc_t *client)
Definition: ipc.c:863
char * crm_strip_trailing_newline(char *str)
Definition: utils.c:1412
#define XML_TAG_PARAMS
Definition: msg_xml.h:176
#define crm_info(fmt, args...)
Definition: logging.h:251
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
Definition: utils.c:1428
char * uid2username(uid_t uid)
#define cib_channel_ro
Definition: internal.h:79
char * score2char_stack(int score, char *buf, size_t len)
Definition: utils.c:254
qb_ipcs_service_t * crmd_ipc_server_init(struct qb_ipcs_service_handlers *cb)
Definition: utils.c:1727
const char * name
Definition: crm_internal.h:79
enum crm_ais_msg_types type
Definition: internal.h:51
char * add_list_element(char *list, const char *value)
Definition: utils.c:2297
guint crm_strcase_hash(gconstpointer v)
Definition: utils.c:2256
#define CRMD_ACTION_STATUS
Definition: crm.h:164
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:115