pacemaker  1.1.17-b36b869ca8
Scalable High-Availability cluster resource manager
utils.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include <crm_internal.h>
20 #include <dlfcn.h>
21 
22 #ifndef _GNU_SOURCE
23 # define _GNU_SOURCE
24 #endif
25 
26 #include <sys/param.h>
27 #include <sys/types.h>
28 #include <sys/wait.h>
29 #include <sys/stat.h>
30 #include <sys/utsname.h>
31 
32 #include <stdio.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include <limits.h>
37 #include <ctype.h>
38 #include <pwd.h>
39 #include <time.h>
40 #include <libgen.h>
41 #include <signal.h>
42 
43 #include <qb/qbdefs.h>
44 
45 #include <crm/crm.h>
46 #include <crm/lrmd.h>
47 #include <crm/services.h>
48 #include <crm/msg_xml.h>
49 #include <crm/cib/internal.h>
50 #include <crm/common/xml.h>
51 #include <crm/common/util.h>
52 #include <crm/common/ipc.h>
53 #include <crm/common/iso8601.h>
54 #include <crm/common/mainloop.h>
55 #include <libxml2/libxml/relaxng.h>
56 
57 #ifndef MAXLINE
58 # define MAXLINE 512
59 #endif
60 
61 #ifdef HAVE_GETOPT_H
62 # include <getopt.h>
63 #endif
64 
65 #ifndef PW_BUFFER_LEN
66 # define PW_BUFFER_LEN 500
67 #endif
68 
69 CRM_TRACE_INIT_DATA(common);
70 
71 gboolean crm_config_error = FALSE;
72 gboolean crm_config_warning = FALSE;
73 char *crm_system_name = NULL;
74 
79 
80 static struct crm_option *crm_long_options = NULL;
81 static const char *crm_app_description = NULL;
82 static char *crm_short_options = NULL;
83 static const char *crm_app_usage = NULL;
84 
85 int
86 crm_exit(int rc)
87 {
89 
90 #if HAVE_LIBXML2
91  crm_trace("cleaning up libxml");
93 #endif
94 
95  crm_trace("exit %d", rc);
96  qb_log_fini();
97 
98  free(crm_short_options);
99  free(crm_system_name);
100 
101  exit(ABS(rc)); /* Always exit with a positive value so that it can be passed to crm_error
102  *
103  * Otherwise the system wraps it around and people
104  * have to jump through hoops figuring out what the
105  * error was
106  */
107  return rc; /* Can never happen, but allows return crm_exit(rc)
108  * where "return rc" was used previously - which
109  * keeps compilers happy.
110  */
111 }
112 
113 gboolean
114 check_time(const char *value)
115 {
116  if (crm_get_msec(value) < 5000) {
117  return FALSE;
118  }
119  return TRUE;
120 }
121 
122 gboolean
123 check_timer(const char *value)
124 {
125  if (crm_get_msec(value) < 0) {
126  return FALSE;
127  }
128  return TRUE;
129 }
130 
131 gboolean
132 check_boolean(const char *value)
133 {
134  int tmp = FALSE;
135 
136  if (crm_str_to_boolean(value, &tmp) != 1) {
137  return FALSE;
138  }
139  return TRUE;
140 }
141 
142 gboolean
143 check_number(const char *value)
144 {
145  errno = 0;
146  if (value == NULL) {
147  return FALSE;
148 
149  } else if (safe_str_eq(value, MINUS_INFINITY_S)) {
150 
151  } else if (safe_str_eq(value, INFINITY_S)) {
152 
153  } else {
154  crm_int_helper(value, NULL);
155  }
156 
157  if (errno != 0) {
158  return FALSE;
159  }
160  return TRUE;
161 }
162 
163 gboolean
164 check_positive_number(const char* value)
165 {
166  if (safe_str_eq(value, INFINITY_S) || (crm_int_helper(value, NULL))) {
167  return TRUE;
168  }
169  return FALSE;
170 }
171 
172 gboolean
173 check_quorum(const char *value)
174 {
175  if (safe_str_eq(value, "stop")) {
176  return TRUE;
177 
178  } else if (safe_str_eq(value, "freeze")) {
179  return TRUE;
180 
181  } else if (safe_str_eq(value, "ignore")) {
182  return TRUE;
183 
184  } else if (safe_str_eq(value, "suicide")) {
185  return TRUE;
186  }
187  return FALSE;
188 }
189 
190 gboolean
191 check_script(const char *value)
192 {
193  struct stat st;
194 
195  if(safe_str_eq(value, "/dev/null")) {
196  return TRUE;
197  }
198 
199  if(stat(value, &st) != 0) {
200  crm_err("Script %s does not exist", value);
201  return FALSE;
202  }
203 
204  if(S_ISREG(st.st_mode) == 0) {
205  crm_err("Script %s is not a regular file", value);
206  return FALSE;
207  }
208 
209  if( (st.st_mode & (S_IXUSR | S_IXGRP )) == 0) {
210  crm_err("Script %s is not executable", value);
211  return FALSE;
212  }
213 
214  return TRUE;
215 }
216 
217 gboolean
218 check_utilization(const char *value)
219 {
220  char *end = NULL;
221  long number = strtol(value, &end, 10);
222 
223  if(end && end[0] != '%') {
224  return FALSE;
225  } else if(number < 0) {
226  return FALSE;
227  }
228 
229  return TRUE;
230 }
231 
232 int
233 char2score(const char *score)
234 {
235  int score_f = 0;
236 
237  if (score == NULL) {
238 
239  } else if (safe_str_eq(score, MINUS_INFINITY_S)) {
240  score_f = -node_score_infinity;
241 
242  } else if (safe_str_eq(score, INFINITY_S)) {
243  score_f = node_score_infinity;
244 
245  } else if (safe_str_eq(score, "+" INFINITY_S)) {
246  score_f = node_score_infinity;
247 
248  } else if (safe_str_eq(score, "red")) {
249  score_f = node_score_red;
250 
251  } else if (safe_str_eq(score, "yellow")) {
252  score_f = node_score_yellow;
253 
254  } else if (safe_str_eq(score, "green")) {
255  score_f = node_score_green;
256 
257  } else {
258  score_f = crm_parse_int(score, NULL);
259  if (score_f > 0 && score_f > node_score_infinity) {
260  score_f = node_score_infinity;
261 
262  } else if (score_f < 0 && score_f < -node_score_infinity) {
263  score_f = -node_score_infinity;
264  }
265  }
266 
267  return score_f;
268 }
269 
270 char *
271 score2char_stack(int score, char *buf, size_t len)
272 {
273  if (score >= node_score_infinity) {
274  strncpy(buf, INFINITY_S, 9);
275  } else if (score <= -node_score_infinity) {
276  strncpy(buf, MINUS_INFINITY_S , 10);
277  } else {
278  return crm_itoa_stack(score, buf, len);
279  }
280 
281  return buf;
282 }
283 
284 char *
285 score2char(int score)
286 {
287  if (score >= node_score_infinity) {
288  return strdup(INFINITY_S);
289 
290  } else if (score <= -node_score_infinity) {
291  return strdup("-" INFINITY_S);
292  }
293  return crm_itoa(score);
294 }
295 
296 const char *
297 cluster_option(GHashTable * options, gboolean(*validate) (const char *),
298  const char *name, const char *old_name, const char *def_value)
299 {
300  const char *value = NULL;
301 
302  CRM_ASSERT(name != NULL);
303 
304  if (options != NULL) {
305  value = g_hash_table_lookup(options, name);
306  }
307 
308  if (value == NULL && old_name && options != NULL) {
309  value = g_hash_table_lookup(options, old_name);
310  if (value != NULL) {
311  crm_config_warn("Using deprecated name '%s' for"
312  " cluster option '%s'", old_name, name);
313  g_hash_table_insert(options, strdup(name), strdup(value));
314  value = g_hash_table_lookup(options, old_name);
315  }
316  }
317 
318  if (value == NULL) {
319  crm_trace("Using default value '%s' for cluster option '%s'", def_value, name);
320 
321  if (options == NULL) {
322  return def_value;
323 
324  } else if(def_value == NULL) {
325  return def_value;
326  }
327 
328  g_hash_table_insert(options, strdup(name), strdup(def_value));
329  value = g_hash_table_lookup(options, name);
330  }
331 
332  if (validate && validate(value) == FALSE) {
333  crm_config_err("Value '%s' for cluster option '%s' is invalid."
334  " Defaulting to %s", value, name, def_value);
335  g_hash_table_replace(options, strdup(name), strdup(def_value));
336  value = g_hash_table_lookup(options, name);
337  }
338 
339  return value;
340 }
341 
342 const char *
343 get_cluster_pref(GHashTable * options, pe_cluster_option * option_list, int len, const char *name)
344 {
345  int lpc = 0;
346  const char *value = NULL;
347  gboolean found = FALSE;
348 
349  for (lpc = 0; lpc < len; lpc++) {
350  if (safe_str_eq(name, option_list[lpc].name)) {
351  found = TRUE;
352  value = cluster_option(options,
353  option_list[lpc].is_valid,
354  option_list[lpc].name,
355  option_list[lpc].alt_name, option_list[lpc].default_value);
356  }
357  }
358  CRM_CHECK(found, crm_err("No option named: %s", name));
359  return value;
360 }
361 
362 void
363 config_metadata(const char *name, const char *version, const char *desc_short,
364  const char *desc_long, pe_cluster_option * option_list, int len)
365 {
366  int lpc = 0;
367 
368  fprintf(stdout, "<?xml version=\"1.0\"?>"
369  "<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n"
370  "<resource-agent name=\"%s\">\n"
371  " <version>%s</version>\n"
372  " <longdesc lang=\"en\">%s</longdesc>\n"
373  " <shortdesc lang=\"en\">%s</shortdesc>\n"
374  " <parameters>\n", name, version, desc_long, desc_short);
375 
376  for (lpc = 0; lpc < len; lpc++) {
377  if (option_list[lpc].description_long == NULL && option_list[lpc].description_short == NULL) {
378  continue;
379  }
380  fprintf(stdout, " <parameter name=\"%s\" unique=\"0\">\n"
381  " <shortdesc lang=\"en\">%s</shortdesc>\n"
382  " <content type=\"%s\" default=\"%s\"/>\n"
383  " <longdesc lang=\"en\">%s%s%s</longdesc>\n"
384  " </parameter>\n",
385  option_list[lpc].name,
386  option_list[lpc].description_short,
387  option_list[lpc].type,
388  option_list[lpc].default_value,
389  option_list[lpc].description_long ? option_list[lpc].
390  description_long : option_list[lpc].description_short,
391  option_list[lpc].values ? " Allowed values: " : "",
392  option_list[lpc].values ? option_list[lpc].values : "");
393  }
394  fprintf(stdout, " </parameters>\n</resource-agent>\n");
395 }
396 
397 void
398 verify_all_options(GHashTable * options, pe_cluster_option * option_list, int len)
399 {
400  int lpc = 0;
401 
402  for (lpc = 0; lpc < len; lpc++) {
403  cluster_option(options,
404  option_list[lpc].is_valid,
405  option_list[lpc].name,
406  option_list[lpc].alt_name, option_list[lpc].default_value);
407  }
408 }
409 
410 char *
411 generate_hash_key(const char *crm_msg_reference, const char *sys)
412 {
413  char *hash_key = crm_concat(sys ? sys : "none", crm_msg_reference, '_');
414 
415  crm_trace("created hash key: (%s)", hash_key);
416  return hash_key;
417 }
418 
419 
420 int
421 crm_user_lookup(const char *name, uid_t * uid, gid_t * gid)
422 {
423  int rc = -1;
424  char *buffer = NULL;
425  struct passwd pwd;
426  struct passwd *pwentry = NULL;
427 
428  buffer = calloc(1, PW_BUFFER_LEN);
429  getpwnam_r(name, &pwd, buffer, PW_BUFFER_LEN, &pwentry);
430  if (pwentry) {
431  rc = 0;
432  if (uid) {
433  *uid = pwentry->pw_uid;
434  }
435  if (gid) {
436  *gid = pwentry->pw_gid;
437  }
438  crm_trace("Cluster user %s has uid=%d gid=%d", name, pwentry->pw_uid, pwentry->pw_gid);
439 
440  } else {
441  crm_err("Cluster user %s does not exist", name);
442  }
443 
444  free(buffer);
445  return rc;
446 }
447 
448 static int
449 crm_version_helper(const char *text, char **end_text)
450 {
451  int atoi_result = -1;
452 
453  CRM_ASSERT(end_text != NULL);
454 
455  errno = 0;
456 
457  if (text != NULL && text[0] != 0) {
458  atoi_result = (int)strtol(text, end_text, 10);
459 
460  if (errno == EINVAL) {
461  crm_err("Conversion of '%s' %c failed", text, text[0]);
462  atoi_result = -1;
463  }
464  }
465  return atoi_result;
466 }
467 
468 /*
469  * version1 < version2 : -1
470  * version1 = version2 : 0
471  * version1 > version2 : 1
472  */
473 int
474 compare_version(const char *version1, const char *version2)
475 {
476  int rc = 0;
477  int lpc = 0;
478  char *ver1_copy = NULL, *ver2_copy = NULL;
479  char *rest1 = NULL, *rest2 = NULL;
480 
481  if (version1 == NULL && version2 == NULL) {
482  return 0;
483  } else if (version1 == NULL) {
484  return -1;
485  } else if (version2 == NULL) {
486  return 1;
487  }
488 
489  ver1_copy = strdup(version1);
490  ver2_copy = strdup(version2);
491  rest1 = ver1_copy;
492  rest2 = ver2_copy;
493 
494  while (1) {
495  int digit1 = 0;
496  int digit2 = 0;
497 
498  lpc++;
499 
500  if (rest1 == rest2) {
501  break;
502  }
503 
504  if (rest1 != NULL) {
505  digit1 = crm_version_helper(rest1, &rest1);
506  }
507 
508  if (rest2 != NULL) {
509  digit2 = crm_version_helper(rest2, &rest2);
510  }
511 
512  if (digit1 < digit2) {
513  rc = -1;
514  break;
515 
516  } else if (digit1 > digit2) {
517  rc = 1;
518  break;
519  }
520 
521  if (rest1 != NULL && rest1[0] == '.') {
522  rest1++;
523  }
524  if (rest1 != NULL && rest1[0] == 0) {
525  rest1 = NULL;
526  }
527 
528  if (rest2 != NULL && rest2[0] == '.') {
529  rest2++;
530  }
531  if (rest2 != NULL && rest2[0] == 0) {
532  rest2 = NULL;
533  }
534  }
535 
536  free(ver1_copy);
537  free(ver2_copy);
538 
539  if (rc == 0) {
540  crm_trace("%s == %s (%d)", version1, version2, lpc);
541  } else if (rc < 0) {
542  crm_trace("%s < %s (%d)", version1, version2, lpc);
543  } else if (rc > 0) {
544  crm_trace("%s > %s (%d)", version1, version2, lpc);
545  }
546 
547  return rc;
548 }
549 
550 gboolean do_stderr = FALSE;
551 
552 #ifndef NUMCHARS
553 # define NUMCHARS "0123456789."
554 #endif
555 
556 #ifndef WHITESPACE
557 # define WHITESPACE " \t\n\r\f"
558 #endif
559 
560 unsigned long long
561 crm_get_interval(const char *input)
562 {
563  unsigned long long msec = 0;
564 
565  if (input == NULL) {
566  return msec;
567 
568  } else if (input[0] != 'P') {
569  long long tmp = crm_get_msec(input);
570 
571  if(tmp > 0) {
572  msec = tmp;
573  }
574 
575  } else {
576  crm_time_t *interval = crm_time_parse_duration(input);
577 
578  msec = 1000 * crm_time_get_seconds(interval);
579  crm_time_free(interval);
580  }
581 
582  return msec;
583 }
584 
585 long long
586 crm_get_msec(const char *input)
587 {
588  const char *cp = input;
589  const char *units;
590  long long multiplier = 1000;
591  long long divisor = 1;
592  long long msec = -1;
593  char *end_text = NULL;
594 
595  /* double dret; */
596 
597  if (input == NULL) {
598  return msec;
599  }
600 
601  cp += strspn(cp, WHITESPACE);
602  units = cp + strspn(cp, NUMCHARS);
603  units += strspn(units, WHITESPACE);
604 
605  if (strchr(NUMCHARS, *cp) == NULL) {
606  return msec;
607  }
608 
609  if (strncasecmp(units, "ms", 2) == 0 || strncasecmp(units, "msec", 4) == 0) {
610  multiplier = 1;
611  divisor = 1;
612  } else if (strncasecmp(units, "us", 2) == 0 || strncasecmp(units, "usec", 4) == 0) {
613  multiplier = 1;
614  divisor = 1000;
615  } else if (strncasecmp(units, "s", 1) == 0 || strncasecmp(units, "sec", 3) == 0) {
616  multiplier = 1000;
617  divisor = 1;
618  } else if (strncasecmp(units, "m", 1) == 0 || strncasecmp(units, "min", 3) == 0) {
619  multiplier = 60 * 1000;
620  divisor = 1;
621  } else if (strncasecmp(units, "h", 1) == 0 || strncasecmp(units, "hr", 2) == 0) {
622  multiplier = 60 * 60 * 1000;
623  divisor = 1;
624  } else if (*units != EOS && *units != '\n' && *units != '\r') {
625  return msec;
626  }
627 
628  msec = crm_int_helper(cp, &end_text);
629  if (msec > LLONG_MAX/multiplier) {
630  /* arithmetics overflow while multiplier/divisor mutually exclusive */
631  return LLONG_MAX;
632  }
633  msec *= multiplier;
634  msec /= divisor;
635  /* dret += 0.5; */
636  /* msec = (long long)dret; */
637  return msec;
638 }
639 
651 char *
652 generate_op_key(const char *rsc_id, const char *op_type, int interval)
653 {
654  CRM_ASSERT(rsc_id != NULL);
655  CRM_ASSERT(op_type != NULL);
656  CRM_ASSERT(interval >= 0);
657  return crm_strdup_printf("%s_%s_%d", rsc_id, op_type, interval);
658 }
659 
660 gboolean
661 parse_op_key(const char *key, char **rsc_id, char **op_type, int *interval)
662 {
663  char *notify = NULL;
664  char *mutable_key = NULL;
665  char *mutable_key_ptr = NULL;
666  int len = 0, offset = 0, ch = 0;
667 
668  CRM_CHECK(key != NULL, return FALSE);
669 
670  *interval = 0;
671  len = strlen(key);
672  offset = len - 1;
673 
674  crm_trace("Source: %s", key);
675 
676  while (offset > 0 && isdigit(key[offset])) {
677  int digits = len - offset;
678 
679  ch = key[offset] - '0';
680  CRM_CHECK(ch < 10, return FALSE);
681  CRM_CHECK(ch >= 0, return FALSE);
682  while (digits > 1) {
683  digits--;
684  ch = ch * 10;
685  }
686  *interval += ch;
687  offset--;
688  }
689 
690  crm_trace(" Interval: %d", *interval);
691  CRM_CHECK(key[offset] == '_', return FALSE);
692 
693  mutable_key = strdup(key);
694  mutable_key[offset] = 0;
695  offset--;
696 
697  while (offset > 0 && key[offset] != '_') {
698  offset--;
699  }
700 
701  CRM_CHECK(key[offset] == '_', free(mutable_key);
702  return FALSE);
703 
704  mutable_key_ptr = mutable_key + offset + 1;
705 
706  crm_trace(" Action: %s", mutable_key_ptr);
707 
708  *op_type = strdup(mutable_key_ptr);
709 
710  mutable_key[offset] = 0;
711  offset--;
712 
713  CRM_CHECK(mutable_key != mutable_key_ptr, free(mutable_key);
714  return FALSE);
715 
716  notify = strstr(mutable_key, "_post_notify");
717  if (notify && safe_str_eq(notify, "_post_notify")) {
718  notify[0] = 0;
719  }
720 
721  notify = strstr(mutable_key, "_pre_notify");
722  if (notify && safe_str_eq(notify, "_pre_notify")) {
723  notify[0] = 0;
724  }
725 
726  crm_trace(" Resource: %s", mutable_key);
727  *rsc_id = mutable_key;
728 
729  return TRUE;
730 }
731 
732 char *
733 generate_notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
734 {
735  int len = 12;
736  char *op_id = NULL;
737 
738  CRM_CHECK(rsc_id != NULL, return NULL);
739  CRM_CHECK(op_type != NULL, return NULL);
740  CRM_CHECK(notify_type != NULL, return NULL);
741 
742  len += strlen(op_type);
743  len += strlen(rsc_id);
744  len += strlen(notify_type);
745  if(len > 0) {
746  op_id = malloc(len);
747  }
748  if (op_id != NULL) {
749  sprintf(op_id, "%s_%s_notify_%s_0", rsc_id, notify_type, op_type);
750  }
751  return op_id;
752 }
753 
754 char *
755 generate_transition_magic_v202(const char *transition_key, int op_status)
756 {
757  int len = 80;
758  char *fail_state = NULL;
759 
760  CRM_CHECK(transition_key != NULL, return NULL);
761 
762  len += strlen(transition_key);
763 
764  fail_state = malloc(len);
765  if (fail_state != NULL) {
766  snprintf(fail_state, len, "%d:%s", op_status, transition_key);
767  }
768  return fail_state;
769 }
770 
771 char *
772 generate_transition_magic(const char *transition_key, int op_status, int op_rc)
773 {
774  int len = 80;
775  char *fail_state = NULL;
776 
777  CRM_CHECK(transition_key != NULL, return NULL);
778 
779  len += strlen(transition_key);
780 
781  fail_state = malloc(len);
782  if (fail_state != NULL) {
783  snprintf(fail_state, len, "%d:%d;%s", op_status, op_rc, transition_key);
784  }
785  return fail_state;
786 }
787 
788 gboolean
789 decode_transition_magic(const char *magic, char **uuid, int *transition_id, int *action_id,
790  int *op_status, int *op_rc, int *target_rc)
791 {
792  int res = 0;
793  char *key = NULL;
794  gboolean result = TRUE;
795 
796  CRM_CHECK(magic != NULL, return FALSE);
797  CRM_CHECK(op_rc != NULL, return FALSE);
798  CRM_CHECK(op_status != NULL, return FALSE);
799 
800  key = calloc(1, strlen(magic) + 1);
801  res = sscanf(magic, "%d:%d;%s", op_status, op_rc, key);
802  if (res != 3) {
803  crm_warn("Only found %d items in: '%s'", res, magic);
804  free(key);
805  return FALSE;
806  }
807 
808  CRM_CHECK(decode_transition_key(key, uuid, transition_id, action_id, target_rc), result = FALSE);
809 
810  free(key);
811  return result;
812 }
813 
814 char *
815 generate_transition_key(int transition_id, int action_id, int target_rc, const char *node)
816 {
817  int len = 40;
818  char *fail_state = NULL;
819 
820  CRM_CHECK(node != NULL, return NULL);
821 
822  len += strlen(node);
823 
824  fail_state = malloc(len);
825  if (fail_state != NULL) {
826  snprintf(fail_state, len, "%d:%d:%d:%-*s", action_id, transition_id, target_rc, 36, node);
827  }
828  return fail_state;
829 }
830 
831 gboolean
832 decode_transition_key(const char *key, char **uuid, int *transition_id, int *action_id,
833  int *target_rc)
834 {
835  int res = 0;
836  gboolean done = FALSE;
837 
838  CRM_CHECK(uuid != NULL, return FALSE);
839  CRM_CHECK(target_rc != NULL, return FALSE);
840  CRM_CHECK(action_id != NULL, return FALSE);
841  CRM_CHECK(transition_id != NULL, return FALSE);
842 
843  *uuid = calloc(1, 37);
844  res = sscanf(key, "%d:%d:%d:%36s", action_id, transition_id, target_rc, *uuid);
845  switch (res) {
846  case 4:
847  /* Post Pacemaker 0.6 */
848  done = TRUE;
849  break;
850  case 3:
851  case 2:
852  /* this can be tricky - the UUID might start with an integer */
853 
854  /* Until Pacemaker 0.6 */
855  done = TRUE;
856  *target_rc = -1;
857  res = sscanf(key, "%d:%d:%36s", action_id, transition_id, *uuid);
858  if (res == 2) {
859  *action_id = -1;
860  res = sscanf(key, "%d:%36s", transition_id, *uuid);
861  CRM_CHECK(res == 2, done = FALSE);
862 
863  } else if (res != 3) {
864  CRM_CHECK(res == 3, done = FALSE);
865  }
866  break;
867 
868  case 1:
869  /* Prior to Heartbeat 2.0.8 */
870  done = TRUE;
871  *action_id = -1;
872  *target_rc = -1;
873  res = sscanf(key, "%d:%36s", transition_id, *uuid);
874  CRM_CHECK(res == 2, done = FALSE);
875  break;
876  default:
877  crm_crit("Unhandled sscanf result (%d) for %s", res, key);
878  }
879 
880  if (strlen(*uuid) != 36) {
881  crm_warn("Bad UUID (%s) in sscanf result (%d) for %s", *uuid, res, key);
882  }
883 
884  if (done == FALSE) {
885  crm_err("Cannot decode '%s' rc=%d", key, res);
886 
887  free(*uuid);
888  *uuid = NULL;
889  *target_rc = -1;
890  *action_id = -1;
891  *transition_id = -1;
892  }
893 
894  return done;
895 }
896 
897 void
898 filter_action_parameters(xmlNode * param_set, const char *version)
899 {
900  char *key = NULL;
901  char *timeout = NULL;
902  char *interval = NULL;
903 
904  const char *attr_filter[] = {
905  XML_ATTR_ID,
910  "pcmk_external_ip"
911  };
912 
913  gboolean do_delete = FALSE;
914  int lpc = 0;
915  static int meta_len = 0;
916 
917  if (meta_len == 0) {
918  meta_len = strlen(CRM_META);
919  }
920 
921  if (param_set == NULL) {
922  return;
923  }
924 
925  for (lpc = 0; lpc < DIMOF(attr_filter); lpc++) {
926  xml_remove_prop(param_set, attr_filter[lpc]);
927  }
928 
930  interval = crm_element_value_copy(param_set, key);
931  free(key);
932 
934  timeout = crm_element_value_copy(param_set, key);
935 
936  if (param_set) {
937  xmlAttrPtr xIter = param_set->properties;
938 
939  while (xIter) {
940  const char *prop_name = (const char *)xIter->name;
941 
942  xIter = xIter->next;
943  do_delete = FALSE;
944  if (strncasecmp(prop_name, CRM_META, meta_len) == 0) {
945  do_delete = TRUE;
946  }
947 
948  if (do_delete) {
949  xml_remove_prop(param_set, prop_name);
950  }
951  }
952  }
953 
954  if (crm_get_msec(interval) > 0 && compare_version(version, "1.0.8") > 0) {
955  /* Re-instate the operation's timeout value */
956  if (timeout != NULL) {
957  crm_xml_add(param_set, key, timeout);
958  }
959  }
960 
961  free(interval);
962  free(timeout);
963  free(key);
964 }
965 
966 extern bool crm_is_daemon;
967 
968 /* coverity[+kill] */
969 void
970 crm_abort(const char *file, const char *function, int line,
971  const char *assert_condition, gboolean do_core, gboolean do_fork)
972 {
973  int rc = 0;
974  int pid = 0;
975  int status = 0;
976 
977  /* Implied by the parent's error logging below */
978  /* crm_write_blackbox(0); */
979 
980  if(crm_is_daemon == FALSE) {
981  /* This is a command line tool - do not fork */
982 
983  /* crm_add_logfile(NULL); * Record it to a file? */
984  crm_enable_stderr(TRUE); /* Make sure stderr is enabled so we can tell the caller */
985  do_fork = FALSE; /* Just crash if needed */
986  }
987 
988  if (do_core == FALSE) {
989  crm_err("%s: Triggered assert at %s:%d : %s", function, file, line, assert_condition);
990  return;
991 
992  } else if (do_fork) {
993  pid = fork();
994 
995  } else {
996  crm_err("%s: Triggered fatal assert at %s:%d : %s", function, file, line, assert_condition);
997  }
998 
999  if (pid == -1) {
1000  crm_crit("%s: Cannot create core for non-fatal assert at %s:%d : %s",
1001  function, file, line, assert_condition);
1002  return;
1003 
1004  } else if(pid == 0) {
1005  /* Child process */
1006  abort();
1007  return;
1008  }
1009 
1010  /* Parent process */
1011  crm_err("%s: Forked child %d to record non-fatal assert at %s:%d : %s",
1012  function, pid, file, line, assert_condition);
1013  crm_write_blackbox(SIGTRAP, NULL);
1014 
1015  do {
1016  rc = waitpid(pid, &status, 0);
1017  if(rc == pid) {
1018  return; /* Job done */
1019  }
1020 
1021  } while(errno == EINTR);
1022 
1023  if (errno == ECHILD) {
1024  /* crm_mon does this */
1025  crm_trace("Cannot wait on forked child %d - SIGCHLD is probably set to SIG_IGN", pid);
1026  return;
1027  }
1028  crm_perror(LOG_ERR, "Cannot wait on forked child %d", pid);
1029 }
1030 
1031 int
1032 crm_pid_active(long pid, const char *daemon)
1033 {
1034  static int have_proc_pid = 0;
1035 
1036  if(have_proc_pid == 0) {
1037  char proc_path[PATH_MAX], exe_path[PATH_MAX];
1038 
1039  /* check to make sure pid hasn't been reused by another process */
1040  snprintf(proc_path, sizeof(proc_path), "/proc/%lu/exe", (long unsigned int)getpid());
1041 
1042  have_proc_pid = 1;
1043  if(readlink(proc_path, exe_path, PATH_MAX - 1) < 0) {
1044  have_proc_pid = -1;
1045  }
1046  }
1047 
1048  if (pid <= 0) {
1049  return -1;
1050 
1051  } else if (kill(pid, 0) < 0 && errno == ESRCH) {
1052  return 0;
1053 
1054  } else if(daemon == NULL || have_proc_pid == -1) {
1055  return 1;
1056 
1057  } else {
1058  int rc = 0;
1059  char proc_path[PATH_MAX], exe_path[PATH_MAX], myexe_path[PATH_MAX];
1060 
1061  /* check to make sure pid hasn't been reused by another process */
1062  snprintf(proc_path, sizeof(proc_path), "/proc/%lu/exe", pid);
1063 
1064  rc = readlink(proc_path, exe_path, PATH_MAX - 1);
1065  if (rc < 0 && errno == EACCES) {
1066  crm_perror(LOG_INFO, "Could not read from %s", proc_path);
1067  return 1;
1068  } else if (rc < 0) {
1069  crm_perror(LOG_ERR, "Could not read from %s", proc_path);
1070  return 0;
1071  }
1072 
1073 
1074  exe_path[rc] = 0;
1075 
1076  if(daemon[0] != '/') {
1077  rc = snprintf(myexe_path, sizeof(proc_path), CRM_DAEMON_DIR"/%s", daemon);
1078  myexe_path[rc] = 0;
1079  } else {
1080  rc = snprintf(myexe_path, sizeof(proc_path), "%s", daemon);
1081  myexe_path[rc] = 0;
1082  }
1083 
1084  if (strcmp(exe_path, myexe_path) == 0) {
1085  return 1;
1086  }
1087  }
1088 
1089  return 0;
1090 }
1091 
1092 #define LOCKSTRLEN 11
1093 
1094 long
1095 crm_read_pidfile(const char *filename)
1096 {
1097  int fd;
1098  struct stat sbuf;
1099  long pid = -ENOENT;
1100  char buf[LOCKSTRLEN + 1];
1101 
1102  if ((fd = open(filename, O_RDONLY)) < 0) {
1103  goto bail;
1104  }
1105 
1106  if (fstat(fd, &sbuf) >= 0 && sbuf.st_size < LOCKSTRLEN) {
1107  sleep(2); /* if someone was about to create one,
1108  * give'm a sec to do so
1109  */
1110  }
1111 
1112  if (read(fd, buf, sizeof(buf)) < 1) {
1113  goto bail;
1114  }
1115 
1116  if (sscanf(buf, "%lu", &pid) > 0) {
1117  if (pid <= 0) {
1118  pid = -ESRCH;
1119  } else {
1120  crm_trace("Got pid %lu from %s\n", pid, filename);
1121  }
1122  }
1123 
1124  bail:
1125  if (fd >= 0) {
1126  close(fd);
1127  }
1128  return pid;
1129 }
1130 
1131 long
1132 crm_pidfile_inuse(const char *filename, long mypid, const char *daemon)
1133 {
1134  long pid = crm_read_pidfile(filename);
1135 
1136  if (pid < 2) {
1137  /* Invalid pid */
1138  pid = -ENOENT;
1139  unlink(filename);
1140 
1141  } else if (mypid && pid == mypid) {
1142  /* In use by us */
1143  pid = pcmk_ok;
1144 
1145  } else if (crm_pid_active(pid, daemon) == FALSE) {
1146  /* Contains a stale value */
1147  unlink(filename);
1148  pid = -ENOENT;
1149 
1150  } else if (mypid && pid != mypid) {
1151  /* locked by existing process - give up */
1152  pid = -EEXIST;
1153  }
1154 
1155  return pid;
1156 }
1157 
1158 static int
1159 crm_lock_pidfile(const char *filename, const char *name)
1160 {
1161  long mypid = 0;
1162  int fd = 0, rc = 0;
1163  char buf[LOCKSTRLEN + 1];
1164 
1165  mypid = (unsigned long)getpid();
1166 
1167  rc = crm_pidfile_inuse(filename, 0, name);
1168  if (rc == -ENOENT) {
1169  /* exists but the process is not active */
1170 
1171  } else if (rc != pcmk_ok) {
1172  /* locked by existing process - give up */
1173  return rc;
1174  }
1175 
1176  if ((fd = open(filename, O_CREAT | O_WRONLY | O_EXCL, 0644)) < 0) {
1177  /* Hmmh, why did we fail? Anyway, nothing we can do about it */
1178  return -errno;
1179  }
1180 
1181  snprintf(buf, sizeof(buf), "%*lu\n", LOCKSTRLEN - 1, mypid);
1182  rc = write(fd, buf, LOCKSTRLEN);
1183  close(fd);
1184 
1185  if (rc != LOCKSTRLEN) {
1186  crm_perror(LOG_ERR, "Incomplete write to %s", filename);
1187  return -errno;
1188  }
1189 
1190  return crm_pidfile_inuse(filename, mypid, name);
1191 }
1192 
1193 void
1194 crm_make_daemon(const char *name, gboolean daemonize, const char *pidfile)
1195 {
1196  int rc;
1197  long pid;
1198  const char *devnull = "/dev/null";
1199 
1200  if (daemonize == FALSE) {
1201  return;
1202  }
1203 
1204  /* Check before we even try... */
1205  rc = crm_pidfile_inuse(pidfile, 1, name);
1206  if(rc < pcmk_ok && rc != -ENOENT) {
1207  pid = crm_read_pidfile(pidfile);
1208  crm_err("%s: already running [pid %ld in %s]", name, pid, pidfile);
1209  printf("%s: already running [pid %ld in %s]\n", name, pid, pidfile);
1210  crm_exit(rc);
1211  }
1212 
1213  pid = fork();
1214  if (pid < 0) {
1215  fprintf(stderr, "%s: could not start daemon\n", name);
1216  crm_perror(LOG_ERR, "fork");
1217  crm_exit(EINVAL);
1218 
1219  } else if (pid > 0) {
1220  crm_exit(pcmk_ok);
1221  }
1222 
1223  rc = crm_lock_pidfile(pidfile, name);
1224  if(rc < pcmk_ok) {
1225  crm_err("Could not lock '%s' for %s: %s (%d)", pidfile, name, pcmk_strerror(rc), rc);
1226  printf("Could not lock '%s' for %s: %s (%d)\n", pidfile, name, pcmk_strerror(rc), rc);
1227  crm_exit(rc);
1228  }
1229 
1230  umask(S_IWGRP | S_IWOTH | S_IROTH);
1231 
1232  close(STDIN_FILENO);
1233  (void)open(devnull, O_RDONLY); /* Stdin: fd 0 */
1234  close(STDOUT_FILENO);
1235  (void)open(devnull, O_WRONLY); /* Stdout: fd 1 */
1236  close(STDERR_FILENO);
1237  (void)open(devnull, O_WRONLY); /* Stderr: fd 2 */
1238 }
1239 
1240 char *
1241 crm_meta_name(const char *field)
1242 {
1243  int lpc = 0;
1244  int max = 0;
1245  char *crm_name = NULL;
1246 
1247  CRM_CHECK(field != NULL, return NULL);
1248  crm_name = crm_concat(CRM_META, field, '_');
1249 
1250  /* Massage the names so they can be used as shell variables */
1251  max = strlen(crm_name);
1252  for (; lpc < max; lpc++) {
1253  switch (crm_name[lpc]) {
1254  case '-':
1255  crm_name[lpc] = '_';
1256  break;
1257  }
1258  }
1259  return crm_name;
1260 }
1261 
1262 const char *
1263 crm_meta_value(GHashTable * hash, const char *field)
1264 {
1265  char *key = NULL;
1266  const char *value = NULL;
1267 
1268  key = crm_meta_name(field);
1269  if (key) {
1270  value = g_hash_table_lookup(hash, key);
1271  free(key);
1272  }
1273 
1274  return value;
1275 }
1276 
1277 static struct option *
1278 crm_create_long_opts(struct crm_option *long_options)
1279 {
1280  struct option *long_opts = NULL;
1281 
1282 #ifdef HAVE_GETOPT_H
1283  int index = 0, lpc = 0;
1284 
1285  /*
1286  * A previous, possibly poor, choice of '?' as the short form of --help
1287  * means that getopt_long() returns '?' for both --help and for "unknown option"
1288  *
1289  * This dummy entry allows us to differentiate between the two in crm_get_option()
1290  * and exit with the correct error code
1291  */
1292  long_opts = realloc_safe(long_opts, (index + 1) * sizeof(struct option));
1293  long_opts[index].name = "__dummmy__";
1294  long_opts[index].has_arg = 0;
1295  long_opts[index].flag = 0;
1296  long_opts[index].val = '_';
1297  index++;
1298 
1299  for (lpc = 0; long_options[lpc].name != NULL; lpc++) {
1300  if (long_options[lpc].name[0] == '-') {
1301  continue;
1302  }
1303 
1304  long_opts = realloc_safe(long_opts, (index + 1) * sizeof(struct option));
1305  /*fprintf(stderr, "Creating %d %s = %c\n", index,
1306  * long_options[lpc].name, long_options[lpc].val); */
1307  long_opts[index].name = long_options[lpc].name;
1308  long_opts[index].has_arg = long_options[lpc].has_arg;
1309  long_opts[index].flag = long_options[lpc].flag;
1310  long_opts[index].val = long_options[lpc].val;
1311  index++;
1312  }
1313 
1314  /* Now create the list terminator */
1315  long_opts = realloc_safe(long_opts, (index + 1) * sizeof(struct option));
1316  long_opts[index].name = NULL;
1317  long_opts[index].has_arg = 0;
1318  long_opts[index].flag = 0;
1319  long_opts[index].val = 0;
1320 #endif
1321 
1322  return long_opts;
1323 }
1324 
1325 void
1326 crm_set_options(const char *short_options, const char *app_usage, struct crm_option *long_options,
1327  const char *app_desc)
1328 {
1329  if (short_options) {
1330  crm_short_options = strdup(short_options);
1331 
1332  } else if (long_options) {
1333  int lpc = 0;
1334  int opt_string_len = 0;
1335  char *local_short_options = NULL;
1336 
1337  for (lpc = 0; long_options[lpc].name != NULL; lpc++) {
1338  if (long_options[lpc].val && long_options[lpc].val != '-' && long_options[lpc].val < UCHAR_MAX) {
1339  local_short_options = realloc_safe(local_short_options, opt_string_len + 4);
1340  local_short_options[opt_string_len++] = long_options[lpc].val;
1341  /* getopt(3) says: Two colons mean an option takes an optional arg; */
1342  if (long_options[lpc].has_arg == optional_argument) {
1343  local_short_options[opt_string_len++] = ':';
1344  }
1345  if (long_options[lpc].has_arg >= required_argument) {
1346  local_short_options[opt_string_len++] = ':';
1347  }
1348  local_short_options[opt_string_len] = 0;
1349  }
1350  }
1351  crm_short_options = local_short_options;
1352  crm_trace("Generated short option string: '%s'", local_short_options);
1353  }
1354 
1355  if (long_options) {
1356  crm_long_options = long_options;
1357  }
1358  if (app_desc) {
1359  crm_app_description = app_desc;
1360  }
1361  if (app_usage) {
1362  crm_app_usage = app_usage;
1363  }
1364 }
1365 
1366 int
1367 crm_get_option(int argc, char **argv, int *index)
1368 {
1369  return crm_get_option_long(argc, argv, index, NULL);
1370 }
1371 
1372 int
1373 crm_get_option_long(int argc, char **argv, int *index, const char **longname)
1374 {
1375 #ifdef HAVE_GETOPT_H
1376  static struct option *long_opts = NULL;
1377 
1378  if (long_opts == NULL && crm_long_options) {
1379  long_opts = crm_create_long_opts(crm_long_options);
1380  }
1381 
1382  *index = 0;
1383  if (long_opts) {
1384  int flag = getopt_long(argc, argv, crm_short_options, long_opts, index);
1385 
1386  switch (flag) {
1387  case 0:
1388  if (long_opts[*index].val) {
1389  return long_opts[*index].val;
1390  } else if (longname) {
1391  *longname = long_opts[*index].name;
1392  } else {
1393  crm_notice("Unhandled option --%s", long_opts[*index].name);
1394  return flag;
1395  }
1396  case -1: /* End of option processing */
1397  break;
1398  case ':':
1399  crm_trace("Missing argument");
1400  crm_help('?', 1);
1401  break;
1402  case '?':
1403  crm_help('?', *index ? 0 : 1);
1404  break;
1405  }
1406  return flag;
1407  }
1408 #endif
1409 
1410  if (crm_short_options) {
1411  return getopt(argc, argv, crm_short_options);
1412  }
1413 
1414  return -1;
1415 }
1416 
1417 int
1418 crm_help(char cmd, int exit_code)
1419 {
1420  int i = 0;
1421  FILE *stream = (exit_code ? stderr : stdout);
1422 
1423  if (cmd == 'v' || cmd == '$') {
1424  fprintf(stream, "Pacemaker %s\n", PACEMAKER_VERSION);
1425  fprintf(stream, "Written by Andrew Beekhof\n");
1426  goto out;
1427  }
1428 
1429  if (cmd == '!') {
1430  fprintf(stream, "Pacemaker %s (Build: %s): %s\n", PACEMAKER_VERSION, BUILD_VERSION, CRM_FEATURES);
1431  goto out;
1432  }
1433 
1434  fprintf(stream, "%s - %s\n", crm_system_name, crm_app_description);
1435 
1436  if (crm_app_usage) {
1437  fprintf(stream, "Usage: %s %s\n", crm_system_name, crm_app_usage);
1438  }
1439 
1440  if (crm_long_options) {
1441  fprintf(stream, "Options:\n");
1442  for (i = 0; crm_long_options[i].name != NULL; i++) {
1443  if (crm_long_options[i].flags & pcmk_option_hidden) {
1444 
1445  } else if (crm_long_options[i].flags & pcmk_option_paragraph) {
1446  fprintf(stream, "%s\n\n", crm_long_options[i].desc);
1447 
1448  } else if (crm_long_options[i].flags & pcmk_option_example) {
1449  fprintf(stream, "\t#%s\n\n", crm_long_options[i].desc);
1450 
1451  } else if (crm_long_options[i].val == '-' && crm_long_options[i].desc) {
1452  fprintf(stream, "%s\n", crm_long_options[i].desc);
1453 
1454  } else {
1455  /* is val printable as char ? */
1456  if (crm_long_options[i].val && crm_long_options[i].val <= UCHAR_MAX) {
1457  fprintf(stream, " -%c,", crm_long_options[i].val);
1458  } else {
1459  fputs(" ", stream);
1460  }
1461  fprintf(stream, " --%s%s\t%s\n", crm_long_options[i].name,
1462  crm_long_options[i].has_arg == optional_argument ? "[=value]" :
1463  crm_long_options[i].has_arg == required_argument ? "=value" : "",
1464  crm_long_options[i].desc ? crm_long_options[i].desc : "");
1465  }
1466  }
1467 
1468  } else if (crm_short_options) {
1469  fprintf(stream, "Usage: %s - %s\n", crm_system_name, crm_app_description);
1470  for (i = 0; crm_short_options[i] != 0; i++) {
1471  int has_arg = no_argument /* 0 */;
1472 
1473  if (crm_short_options[i + 1] == ':') {
1474  if (crm_short_options[i + 2] == ':')
1475  has_arg = optional_argument /* 2 */;
1476  else
1477  has_arg = required_argument /* 1 */;
1478  }
1479 
1480  fprintf(stream, " -%c %s\n", crm_short_options[i],
1481  has_arg == optional_argument ? "[value]" :
1482  has_arg == required_argument ? "{value}" : "");
1483  i += has_arg;
1484  }
1485  }
1486 
1487  fprintf(stream, "\nReport bugs to %s\n", PACKAGE_BUGREPORT);
1488 
1489  out:
1490  return crm_exit(exit_code);
1491 }
1492 
1493 void cib_ipc_servers_init(qb_ipcs_service_t **ipcs_ro,
1494  qb_ipcs_service_t **ipcs_rw,
1495  qb_ipcs_service_t **ipcs_shm,
1496  struct qb_ipcs_service_handlers *ro_cb,
1497  struct qb_ipcs_service_handlers *rw_cb)
1498 {
1499  *ipcs_ro = mainloop_add_ipc_server(cib_channel_ro, QB_IPC_NATIVE, ro_cb);
1500  *ipcs_rw = mainloop_add_ipc_server(cib_channel_rw, QB_IPC_NATIVE, rw_cb);
1501  *ipcs_shm = mainloop_add_ipc_server(cib_channel_shm, QB_IPC_SHM, rw_cb);
1502 
1503  if (*ipcs_ro == NULL || *ipcs_rw == NULL || *ipcs_shm == NULL) {
1504  crm_err("Failed to create cib servers: exiting and inhibiting respawn.");
1505  crm_warn("Verify pacemaker and pacemaker_remote are not both enabled.");
1507  }
1508 }
1509 
1510 void cib_ipc_servers_destroy(qb_ipcs_service_t *ipcs_ro,
1511  qb_ipcs_service_t *ipcs_rw,
1512  qb_ipcs_service_t *ipcs_shm)
1513 {
1514  qb_ipcs_destroy(ipcs_ro);
1515  qb_ipcs_destroy(ipcs_rw);
1516  qb_ipcs_destroy(ipcs_shm);
1517 }
1518 
1519 qb_ipcs_service_t *
1520 crmd_ipc_server_init(struct qb_ipcs_service_handlers *cb)
1521 {
1522  return mainloop_add_ipc_server(CRM_SYSTEM_CRMD, QB_IPC_NATIVE, cb);
1523 }
1524 
1525 void
1526 attrd_ipc_server_init(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb)
1527 {
1528  *ipcs = mainloop_add_ipc_server(T_ATTRD, QB_IPC_NATIVE, cb);
1529 
1530  if (*ipcs == NULL) {
1531  crm_err("Failed to create attrd servers: exiting and inhibiting respawn.");
1532  crm_warn("Verify pacemaker and pacemaker_remote are not both enabled.");
1534  }
1535 }
1536 
1537 void
1538 stonith_ipc_server_init(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb)
1539 {
1540  *ipcs = mainloop_add_ipc_server("stonith-ng", QB_IPC_NATIVE, cb);
1541 
1542  if (*ipcs == NULL) {
1543  crm_err("Failed to create stonith-ng servers: exiting and inhibiting respawn.");
1544  crm_warn("Verify pacemaker and pacemaker_remote are not both enabled.");
1546  }
1547 }
1548 
1549 #define FAKE_TE_ID "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
1550 static void
1551 append_digest(lrmd_event_data_t * op, xmlNode * update, const char *version, const char *magic,
1552  int level)
1553 {
1554  /* this will enable us to later determine that the
1555  * resource's parameters have changed and we should force
1556  * a restart
1557  */
1558  char *digest = NULL;
1559  xmlNode *args_xml = NULL;
1560 
1561  if (op->params == NULL) {
1562  return;
1563  }
1564 
1565  args_xml = create_xml_node(NULL, XML_TAG_PARAMS);
1566  g_hash_table_foreach(op->params, hash2field, args_xml);
1567  filter_action_parameters(args_xml, version);
1568 #ifdef ENABLE_VERSIONED_ATTRS
1569  crm_summarize_versioned_params(args_xml, op->versioned_params);
1570 #endif
1571  digest = calculate_operation_digest(args_xml, version);
1572 
1573 #if 0
1574  if (level < get_crm_log_level()
1575  && op->interval == 0 && crm_str_eq(op->op_type, CRMD_ACTION_START, TRUE)) {
1576  char *digest_source = dump_xml_unformatted(args_xml);
1577 
1578  do_crm_log(level, "Calculated digest %s for %s (%s). Source: %s\n",
1579  digest, ID(update), magic, digest_source);
1580  free(digest_source);
1581  }
1582 #endif
1583  crm_xml_add(update, XML_LRM_ATTR_OP_DIGEST, digest);
1584 
1585  free_xml(args_xml);
1586  free(digest);
1587 }
1588 
1589 int
1591 {
1592  int rc = 0;
1593 
1594  if (op && op->user_data) {
1595  int dummy = 0;
1596  char *uuid = NULL;
1597 
1598  decode_transition_key(op->user_data, &uuid, &dummy, &dummy, &rc);
1599  free(uuid);
1600  }
1601  return rc;
1602 }
1603 
1604 gboolean
1606 {
1607  switch (op->op_status) {
1608  case PCMK_LRM_OP_CANCELLED:
1609  case PCMK_LRM_OP_PENDING:
1610  return FALSE;
1611  break;
1612 
1614  case PCMK_LRM_OP_TIMEOUT:
1615  case PCMK_LRM_OP_ERROR:
1616  return TRUE;
1617  break;
1618 
1619  default:
1620  if (target_rc != op->rc) {
1621  return TRUE;
1622  }
1623  }
1624 
1625  return FALSE;
1626 }
1627 
1628 xmlNode *
1629 create_operation_update(xmlNode * parent, lrmd_event_data_t * op, const char * caller_version,
1630  int target_rc, const char * node, const char * origin, int level)
1631 {
1632  char *key = NULL;
1633  char *magic = NULL;
1634  char *op_id = NULL;
1635  char *op_id_additional = NULL;
1636  char *local_user_data = NULL;
1637  const char *exit_reason = NULL;
1638 
1639  xmlNode *xml_op = NULL;
1640  const char *task = NULL;
1641  gboolean dc_munges_migrate_ops = (compare_version(caller_version, "3.0.3") < 0);
1642  gboolean dc_needs_unique_ops = (compare_version(caller_version, "3.0.6") < 0);
1643 
1644  CRM_CHECK(op != NULL, return NULL);
1645  do_crm_log(level, "%s: Updating resource %s after %s op %s (interval=%d)",
1646  origin, op->rsc_id, op->op_type, services_lrm_status_str(op->op_status),
1647  op->interval);
1648 
1649  crm_trace("DC version: %s", caller_version);
1650 
1651  task = op->op_type;
1652  /* remap the task name under various scenarios
1653  * this makes life easier for the PE when trying determine the current state
1654  */
1655  if (crm_str_eq(task, "reload", TRUE)) {
1656  if (op->op_status == PCMK_LRM_OP_DONE) {
1657  task = CRMD_ACTION_START;
1658  } else {
1659  task = CRMD_ACTION_STATUS;
1660  }
1661 
1662  } else if (dc_munges_migrate_ops && crm_str_eq(task, CRMD_ACTION_MIGRATE, TRUE)) {
1663  /* if the migrate_from fails it will have enough info to do the right thing */
1664  if (op->op_status == PCMK_LRM_OP_DONE) {
1665  task = CRMD_ACTION_STOP;
1666  } else {
1667  task = CRMD_ACTION_STATUS;
1668  }
1669 
1670  } else if (dc_munges_migrate_ops
1671  && op->op_status == PCMK_LRM_OP_DONE
1672  && crm_str_eq(task, CRMD_ACTION_MIGRATED, TRUE)) {
1673  task = CRMD_ACTION_START;
1674  }
1675 
1676  key = generate_op_key(op->rsc_id, task, op->interval);
1677  if (dc_needs_unique_ops && op->interval > 0) {
1678  op_id = strdup(key);
1679 
1680  } else if (crm_str_eq(task, CRMD_ACTION_NOTIFY, TRUE)) {
1681  const char *n_type = crm_meta_value(op->params, "notify_type");
1682  const char *n_task = crm_meta_value(op->params, "notify_operation");
1683 
1684  CRM_LOG_ASSERT(n_type != NULL);
1685  CRM_LOG_ASSERT(n_task != NULL);
1686  op_id = generate_notify_key(op->rsc_id, n_type, n_task);
1687 
1688  /* these are not yet allowed to fail */
1690  op->rc = 0;
1691 
1692  } else if (did_rsc_op_fail(op, target_rc)) {
1693  op_id = generate_op_key(op->rsc_id, "last_failure", 0);
1694  if (op->interval == 0) {
1695  /* Ensure 'last' gets updated too in case recording-pending="true" */
1696  op_id_additional = generate_op_key(op->rsc_id, "last", 0);
1697  }
1698  exit_reason = op->exit_reason;
1699 
1700  } else if (op->interval > 0) {
1701  op_id = strdup(key);
1702 
1703  } else {
1704  op_id = generate_op_key(op->rsc_id, "last", 0);
1705  }
1706 
1707  again:
1708  xml_op = find_entity(parent, XML_LRM_TAG_RSC_OP, op_id);
1709  if (xml_op == NULL) {
1710  xml_op = create_xml_node(parent, XML_LRM_TAG_RSC_OP);
1711  }
1712 
1713  if (op->user_data == NULL) {
1714  crm_debug("Generating fake transition key for:"
1715  " %s_%s_%d %d from %s",
1716  op->rsc_id, op->op_type, op->interval, op->call_id, origin);
1717  local_user_data = generate_transition_key(-1, op->call_id, target_rc, FAKE_TE_ID);
1718  op->user_data = local_user_data;
1719  }
1720 
1721  if(magic == NULL) {
1722  magic = generate_transition_magic(op->user_data, op->op_status, op->rc);
1723  }
1724 
1725  crm_xml_add(xml_op, XML_ATTR_ID, op_id);
1726  crm_xml_add(xml_op, XML_LRM_ATTR_TASK_KEY, key);
1727  crm_xml_add(xml_op, XML_LRM_ATTR_TASK, task);
1728  crm_xml_add(xml_op, XML_ATTR_ORIGIN, origin);
1729  crm_xml_add(xml_op, XML_ATTR_CRM_VERSION, caller_version);
1731  crm_xml_add(xml_op, XML_ATTR_TRANSITION_MAGIC, magic);
1732  crm_xml_add(xml_op, XML_LRM_ATTR_EXIT_REASON, exit_reason);
1733  crm_xml_add(xml_op, XML_LRM_ATTR_TARGET, node); /* For context during triage */
1734 
1736  crm_xml_add_int(xml_op, XML_LRM_ATTR_RC, op->rc);
1739 
1740  if (compare_version("2.1", caller_version) <= 0) {
1741  if (op->t_run || op->t_rcchange || op->exec_time || op->queue_time) {
1742  crm_trace("Timing data (%s_%s_%d): last=%u change=%u exec=%u queue=%u",
1743  op->rsc_id, op->op_type, op->interval,
1744  op->t_run, op->t_rcchange, op->exec_time, op->queue_time);
1745 
1746  if (op->interval == 0) {
1747  /* The values are the same for non-recurring ops */
1750 
1751  } else if(op->t_rcchange) {
1752  /* last-run is not accurate for recurring ops */
1754 
1755  } else {
1756  /* ...but is better than nothing otherwise */
1758  }
1759 
1762  }
1763  }
1764 
1765  if (crm_str_eq(op->op_type, CRMD_ACTION_MIGRATE, TRUE)
1766  || crm_str_eq(op->op_type, CRMD_ACTION_MIGRATED, TRUE)) {
1767  /*
1768  * Record migrate_source and migrate_target always for migrate ops.
1769  */
1770  const char *name = XML_LRM_ATTR_MIGRATE_SOURCE;
1771 
1772  crm_xml_add(xml_op, name, crm_meta_value(op->params, name));
1773 
1775  crm_xml_add(xml_op, name, crm_meta_value(op->params, name));
1776  }
1777 
1778  append_digest(op, xml_op, caller_version, magic, LOG_DEBUG);
1779 
1780  if (op_id_additional) {
1781  free(op_id);
1782  op_id = op_id_additional;
1783  op_id_additional = NULL;
1784  goto again;
1785  }
1786 
1787  if (local_user_data) {
1788  free(local_user_data);
1789  op->user_data = NULL;
1790  }
1791  free(magic);
1792  free(op_id);
1793  free(key);
1794  return xml_op;
1795 }
1796 
1797 bool
1798 pcmk_acl_required(const char *user)
1799 {
1800 #if ENABLE_ACL
1801  if(user == NULL || strlen(user) == 0) {
1802  crm_trace("no user set");
1803  return FALSE;
1804 
1805  } else if (strcmp(user, CRM_DAEMON_USER) == 0) {
1806  return FALSE;
1807 
1808  } else if (strcmp(user, "root") == 0) {
1809  return FALSE;
1810  }
1811  crm_trace("acls required for %s", user);
1812  return TRUE;
1813 #else
1814  crm_trace("acls not supported");
1815  return FALSE;
1816 #endif
1817 }
1818 
1819 #if ENABLE_ACL
1820 char *
1821 uid2username(uid_t uid)
1822 {
1823  struct passwd *pwent = getpwuid(uid);
1824 
1825  if (pwent == NULL) {
1826  crm_perror(LOG_ERR, "Cannot get password entry of uid: %d", uid);
1827  return NULL;
1828 
1829  } else {
1830  return strdup(pwent->pw_name);
1831  }
1832 }
1833 
1834 const char *
1835 crm_acl_get_set_user(xmlNode * request, const char *field, const char *peer_user)
1836 {
1837  /* field is only checked for backwards compatibility */
1838  static const char *effective_user = NULL;
1839  const char *requested_user = NULL;
1840  const char *user = NULL;
1841 
1842  if(effective_user == NULL) {
1843  effective_user = uid2username(geteuid());
1844  }
1845 
1846  requested_user = crm_element_value(request, XML_ACL_TAG_USER);
1847  if(requested_user == NULL) {
1848  requested_user = crm_element_value(request, field);
1849  }
1850 
1851  if (is_privileged(effective_user) == FALSE) {
1852  /* We're not running as a privileged user, set or overwrite any existing value for $XML_ACL_TAG_USER */
1853  user = effective_user;
1854 
1855  } else if(peer_user == NULL && requested_user == NULL) {
1856  /* No user known or requested, use 'effective_user' and make sure one is set for the request */
1857  user = effective_user;
1858 
1859  } else if(peer_user == NULL) {
1860  /* No user known, trusting 'requested_user' */
1861  user = requested_user;
1862 
1863  } else if (is_privileged(peer_user) == FALSE) {
1864  /* The peer is not a privileged user, set or overwrite any existing value for $XML_ACL_TAG_USER */
1865  user = peer_user;
1866 
1867  } else if (requested_user == NULL) {
1868  /* Even if we're privileged, make sure there is always a value set */
1869  user = peer_user;
1870 
1871  } else {
1872  /* Legal delegation to 'requested_user' */
1873  user = requested_user;
1874  }
1875 
1876  /* Yes, pointer comparision */
1877  if(user != crm_element_value(request, XML_ACL_TAG_USER)) {
1878  crm_xml_add(request, XML_ACL_TAG_USER, user);
1879  }
1880 
1881  if(field != NULL && user != crm_element_value(request, field)) {
1882  crm_xml_add(request, field, user);
1883  }
1884 
1885  return requested_user;
1886 }
1887 
1888 void
1889 determine_request_user(const char *user, xmlNode * request, const char *field)
1890 {
1891  /* Get our internal validation out of the way first */
1892  CRM_CHECK(user != NULL && request != NULL && field != NULL, return);
1893 
1894  /* If our peer is a privileged user, we might be doing something on behalf of someone else */
1895  if (is_privileged(user) == FALSE) {
1896  /* We're not a privileged user, set or overwrite any existing value for $field */
1897  crm_xml_replace(request, field, user);
1898 
1899  } else if (crm_element_value(request, field) == NULL) {
1900  /* Even if we're privileged, make sure there is always a value set */
1901  crm_xml_replace(request, field, user);
1902 
1903 /* } else { Legal delegation */
1904  }
1905 
1906  crm_trace("Processing msg as user '%s'", crm_element_value(request, field));
1907 }
1908 #endif
1909 
1910 void *
1911 find_library_function(void **handle, const char *lib, const char *fn, gboolean fatal)
1912 {
1913  char *error;
1914  void *a_function;
1915 
1916  if (*handle == NULL) {
1917  *handle = dlopen(lib, RTLD_LAZY);
1918  }
1919 
1920  if (!(*handle)) {
1921  crm_err("%sCould not open %s: %s", fatal ? "Fatal: " : "", lib, dlerror());
1922  if (fatal) {
1924  }
1925  return NULL;
1926  }
1927 
1928  a_function = dlsym(*handle, fn);
1929  if (a_function == NULL) {
1930  error = dlerror();
1931  crm_err("%sCould not find %s in %s: %s", fatal ? "Fatal: " : "", fn, lib, error);
1932  if (fatal) {
1934  }
1935  }
1936 
1937  return a_function;
1938 }
1939 
1940 void *
1941 convert_const_pointer(const void *ptr)
1942 {
1943  /* Worst function ever */
1944  return (void *)ptr;
1945 }
1946 
1947 #ifdef HAVE_UUID_UUID_H
1948 # include <uuid/uuid.h>
1949 #endif
1950 
1951 char *
1953 {
1954  unsigned char uuid[16];
1955  char *buffer = malloc(37); /* Including NUL byte */
1956 
1957  uuid_generate(uuid);
1958  uuid_unparse(uuid, buffer);
1959  return buffer;
1960 }
1961 
1969 bool
1970 crm_is_daemon_name(const char *name)
1971 {
1972  return (name &&
1973  (!strcmp(name, CRM_SYSTEM_CRMD)
1974  || !strcmp(name, CRM_SYSTEM_STONITHD)
1975  || !strcmp(name, T_ATTRD)
1976  || !strcmp(name, CRM_SYSTEM_CIB)
1977  || !strcmp(name, CRM_SYSTEM_MCP)
1978  || !strcmp(name, CRM_SYSTEM_DC)
1979  || !strcmp(name, CRM_SYSTEM_TENGINE)
1980  || !strcmp(name, CRM_SYSTEM_LRMD)));
1981 }
1982 
1983 #include <md5.h>
1984 
1985 char *
1986 crm_md5sum(const char *buffer)
1987 {
1988  int lpc = 0, len = 0;
1989  char *digest = NULL;
1990  unsigned char raw_digest[MD5_DIGEST_SIZE];
1991 
1992  if (buffer == NULL) {
1993  buffer = "";
1994  }
1995  len = strlen(buffer);
1996 
1997  crm_trace("Beginning digest of %d bytes", len);
1998  digest = malloc(2 * MD5_DIGEST_SIZE + 1);
1999  if(digest) {
2000  md5_buffer(buffer, len, raw_digest);
2001  for (lpc = 0; lpc < MD5_DIGEST_SIZE; lpc++) {
2002  sprintf(digest + (2 * lpc), "%02x", raw_digest[lpc]);
2003  }
2004  digest[(2 * MD5_DIGEST_SIZE)] = 0;
2005  crm_trace("Digest %s.", digest);
2006 
2007  } else {
2008  crm_err("Could not create digest");
2009  }
2010  return digest;
2011 }
2012 
2013 #ifdef HAVE_GNUTLS_GNUTLS_H
2014 void
2015 crm_gnutls_global_init(void)
2016 {
2017  signal(SIGPIPE, SIG_IGN);
2018  gnutls_global_init();
2019 }
2020 #endif
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:292
void * find_library_function(void **handle, const char *lib, const char *fn, gboolean fatal)
Definition: utils.c:1911
void verify_all_options(GHashTable *options, pe_cluster_option *option_list, int len)
Definition: utils.c:398
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, int *interval)
Definition: utils.c:661
void crm_write_blackbox(int nsig, struct qb_log_callsite *callsite)
Definition: logging.c:423
A dumping ground.
long long crm_get_msec(const char *input)
Definition: utils.c:586
int crm_get_option_long(int argc, char **argv, int *index, const char **longname)
Definition: utils.c:1373
#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:421
#define CRMD_ACTION_MIGRATED
Definition: crm.h:160
gboolean do_stderr
Definition: utils.c:550
void crm_enable_stderr(int enable)
Definition: logging.c:909
void * convert_const_pointer(const void *ptr)
Definition: utils.c:1941
#define crm_crit(fmt, args...)
Definition: logging.h:247
gboolean check_utilization(const char *value)
Definition: utils.c:218
#define INFINITY
Definition: crm.h:83
const char * user_data
Definition: lrmd.h:201
const char * crm_meta_value(GHashTable *hash, const char *field)
Definition: utils.c:1263
const char * rsc_id
Definition: lrmd.h:197
#define XML_ATTR_TRANSITION_MAGIC
Definition: msg_xml.h:372
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:1510
void attrd_ipc_server_init(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb)
Definition: utils.c:1526
struct crm_time_s crm_time_t
Definition: iso8601.h:37
const char * pcmk_strerror(int rc)
Definition: logging.c:1132
int node_score_infinity
Definition: utils.c:78
gboolean check_time(const char *value)
Definition: utils.c:114
#define crm_config_err(fmt...)
Definition: crm_internal.h:258
unsigned int queue_time
Definition: lrmd.h:227
void crm_make_daemon(const char *name, gboolean daemonize, const char *pidfile)
Definition: utils.c:1194
void crm_xml_cleanup(void)
Definition: xml.c:5086
gboolean decode_transition_key(const char *key, char **uuid, int *transition_id, int *action_id, int *target_rc)
Definition: utils.c:832
#define pcmk_ok
Definition: error.h:42
long long crm_int_helper(const char *text, char **end_text)
Definition: strings.c:80
#define CRMD_ACTION_NOTIFY
Definition: crm.h:173
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:1493
char * crm_md5sum(const char *buffer)
Definition: utils.c:1986
xmlNode * find_entity(xmlNode *parent, const char *node_name, const char *id)
Definition: xml.c:2267
#define XML_RSC_OP_T_EXEC
Definition: msg_xml.h:294
bool crm_is_daemon_name(const char *name)
Check whether a string represents a cluster daemon name.
Definition: utils.c:1970
char * generate_transition_key(int transition_id, int action_id, int target_rc, const char *node)
Definition: utils.c:815
#define XML_LRM_ATTR_INTERVAL
Definition: msg_xml.h:271
gboolean crm_config_warning
Definition: utils.c:72
int crm_help(char cmd, int exit_code)
Definition: utils.c:1418
#define XML_LRM_ATTR_OP_DIGEST
Definition: msg_xml.h:285
#define XML_ATTR_TIMEOUT
Definition: msg_xml.h:95
void mainloop_cleanup(void)
Definition: mainloop.c:411
int crm_parse_int(const char *text, const char *default_text)
Definition: strings.c:125
int node_score_red
Definition: utils.c:75
char * crm_element_value_copy(xmlNode *data, const char *name)
Definition: xml.c:3893
Local Resource Manager.
unsigned int t_rcchange
Definition: lrmd.h:223
crm_time_t * crm_time_parse_duration(const char *duration_str)
Definition: iso8601.c:831
#define MINUS_INFINITY_S
Definition: crm.h:81
#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:1326
uint32_t pid
Definition: internal.h:49
enum ocf_exitcode rc
Definition: lrmd.h:215
const char * get_cluster_pref(GHashTable *options, pe_cluster_option *option_list, int len, const char *name)
Definition: utils.c:343
char * crm_system_name
Definition: utils.c:73
#define cib_channel_rw
Definition: internal.h:80
#define XML_RSC_OP_T_QUEUE
Definition: msg_xml.h:295
#define PACEMAKER_VERSION
Definition: config.h:642
Wrappers for and extensions to glib mainloop.
gboolean check_positive_number(const char *value)
Definition: utils.c:164
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:363
long crm_read_pidfile(const char *filename)
Definition: utils.c:1095
#define CRM_SYSTEM_DC
Definition: crm.h:86
const char * crm_xml_replace(xmlNode *node, const char *name, const char *value)
Definition: xml.c:2535
bool pcmk_acl_required(const char *user)
Definition: utils.c:1798
#define CRM_SYSTEM_MCP
Definition: crm.h:95
unsigned int exec_time
Definition: lrmd.h:225
void stonith_ipc_server_init(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb)
Definition: utils.c:1538
#define XML_ATTR_ORIGIN
Definition: msg_xml.h:96
#define CRMD_ACTION_START
Definition: crm.h:162
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:1629
char * crm_meta_name(const char *field)
Definition: utils.c:1241
gboolean check_quorum(const char *value)
Definition: utils.c:173
#define XML_LRM_ATTR_TASK_KEY
Definition: msg_xml.h:273
#define XML_LRM_ATTR_TASK
Definition: msg_xml.h:272
void hash2field(gpointer key, gpointer value, gpointer user_data)
Definition: xml.c:4884
#define CRMD_ACTION_STOP
Definition: crm.h:165
void * params
Definition: lrmd.h:234
#define PW_BUFFER_LEN
Definition: utils.c:66
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:130
int crm_pid_active(long pid, const char *daemon)
Definition: utils.c:1032
int daemon(int nochdir, int noclose)
const char * exit_reason
Definition: lrmd.h:242
char * generate_hash_key(const char *crm_msg_reference, const char *sys)
Definition: utils.c:411
#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
Utility functions.
#define XML_ATTR_ID
Definition: msg_xml.h:101
#define CRM_DAEMON_DIR
Definition: config.h:41
char * score2char(int score)
Definition: utils.c:285
#define BUILD_VERSION
Definition: config.h:23
#define LOCKSTRLEN
Definition: utils.c:1092
#define pcmk_option_example
Definition: crm_internal.h:73
unsigned long long crm_get_interval(const char *input)
Definition: utils.c:561
#define INFINITY_S
Definition: crm.h:80
gboolean did_rsc_op_fail(lrmd_event_data_t *op, int target_rc)
Definition: utils.c:1605
#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:297
#define pcmk_option_paragraph
Definition: crm_internal.h:72
#define NUMCHARS
Definition: utils.c:553
int node_score_yellow
Definition: utils.c:77
Wrappers for and extensions to libxml2.
ISO_8601 Date handling.
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:2587
const char * crm_element_value(xmlNode *data, const char *name)
Definition: xml.c:5134
#define CRM_DAEMON_USER
Definition: config.h:47
int crm_exit(int rc)
Definition: utils.c:86
#define XML_LRM_ATTR_MIGRATE_TARGET
Definition: msg_xml.h:298
char * crm_generate_uuid(void)
Definition: utils.c:1952
#define XML_LRM_ATTR_EXIT_REASON
Definition: msg_xml.h:290
void free_xml(xmlNode *child)
Definition: xml.c:2705
#define EOS
Definition: crm.h:38
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
Definition: strings.c:213
char * crm_itoa_stack(int an_int, char *buf, size_t len)
Definition: strings.c:50
void filter_action_parameters(xmlNode *param_set, const char *version)
Definition: utils.c:898
int * flag
Definition: crm_internal.h:85
int node_score_green
Definition: utils.c:76
CRM_TRACE_INIT_DATA(common)
const char * op_type
Definition: lrmd.h:199
#define WHITESPACE
Definition: utils.c:557
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:789
#define XML_LRM_ATTR_TARGET_UUID
Definition: msg_xml.h:275
#define cib_channel_shm
Definition: internal.h:81
#define CRM_SYSTEM_CRMD
Definition: crm.h:90
long long int crm_time_get_seconds(crm_time_t *dt)
Definition: iso8601.c:270
#define DAEMON_RESPAWN_STOP
Definition: crm.h:65
int compare_version(const char *version1, const char *version2)
Definition: utils.c:474
unsigned int t_run
Definition: lrmd.h:221
gboolean check_script(const char *value)
Definition: utils.c:191
#define crm_config_warn(fmt...)
Definition: crm_internal.h:259
#define XML_ATTR_TRANSITION_KEY
Definition: msg_xml.h:373
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Definition: xml.c:2489
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Definition: xml.c:2577
unsigned int get_crm_log_level(void)
Definition: logging.c:939
#define CRM_SYSTEM_STONITHD
Definition: crm.h:94
int crm_str_to_boolean(const char *s, int *ret)
Definition: strings.c:176
void crm_abort(const char *file, const char *function, int line, const char *assert_condition, gboolean do_core, gboolean do_fork)
Definition: utils.c:970
#define CRM_SYSTEM_CIB
Definition: crm.h:89
char * generate_notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
Definition: utils.c:733
#define CRM_SYSTEM_TENGINE
Definition: crm.h:93
gboolean check_timer(const char *value)
Definition: utils.c:123
long crm_pidfile_inuse(const char *filename, long mypid, const char *daemon)
Definition: utils.c:1132
#define crm_perror(level, fmt, args...)
Log a system error message.
Definition: logging.h:226
#define CRM_META
Definition: crm.h:53
char * generate_transition_magic_v202(const char *transition_key, int op_status)
Definition: utils.c:755
int char2score(const char *score)
Definition: utils.c:233
#define crm_err(fmt, args...)
Definition: logging.h:248
#define FAKE_TE_ID
Definition: utils.c:1549
gboolean check_number(const char *value)
Definition: utils.c:143
void xml_remove_prop(xmlNode *obj, const char *name)
Definition: xml.c:3905
int rsc_op_expected_rc(lrmd_event_data_t *op)
Definition: utils.c:1590
char * dump_xml_unformatted(xmlNode *msg)
Definition: xml.c:3849
#define DIMOF(a)
Definition: crm.h:39
#define XML_LRM_ATTR_CALLID
Definition: msg_xml.h:284
#define CRM_SYSTEM_LRMD
Definition: crm.h:91
#define CRMD_ACTION_MIGRATE
Definition: crm.h:159
#define CRM_ASSERT(expr)
Definition: error.h:35
#define XML_LRM_ATTR_OPSTATUS
Definition: msg_xml.h:282
#define XML_ATTR_CRM_VERSION
Definition: msg_xml.h:84
#define pcmk_option_hidden
Definition: crm_internal.h:71
int crm_get_option(int argc, char **argv, int *index)
Definition: utils.c:1367
char * generate_op_key(const char *rsc_id, const char *op_type, int interval)
Generate an operation key.
Definition: utils.c:652
#define XML_LRM_ATTR_RC
Definition: msg_xml.h:283
#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:648
char * generate_transition_magic(const char *transition_key, int op_status, int op_rc)
Definition: utils.c:772
const char * crm_acl_get_set_user(xmlNode *request, const char *field, const char *peer_user)
gboolean crm_config_error
Definition: utils.c:71
#define XML_LRM_ATTR_TARGET
Definition: msg_xml.h:274
#define XML_LRM_TAG_RSC_OP
Definition: msg_xml.h:242
#define XML_RSC_OP_LAST_RUN
Definition: msg_xml.h:293
char * crm_concat(const char *prefix, const char *suffix, char join)
Definition: strings.c:32
#define ID(x)
Definition: msg_xml.h:434
#define XML_ACL_TAG_USER
Definition: msg_xml.h:383
char * crm_itoa(int an_int)
Definition: strings.c:60
#define safe_str_eq(a, b)
Definition: util.h:64
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:589
char * crm_strdup_printf(char const *format,...) __attribute__((__format__(__printf__
#define XML_LRM_ATTR_MIGRATE_SOURCE
Definition: msg_xml.h:297
#define CRM_FEATURES
Definition: config.h:53
gboolean check_boolean(const char *value)
Definition: utils.c:132
#define XML_TAG_PARAMS
Definition: msg_xml.h:183
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:271
uint64_t flags
Definition: remote.c:156
qb_ipcs_service_t * crmd_ipc_server_init(struct qb_ipcs_service_handlers *cb)
Definition: utils.c:1520
const char * name
Definition: crm_internal.h:78
enum crm_ais_msg_types type
Definition: internal.h:51
#define CRMD_ACTION_STATUS
Definition: crm.h:176
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:116