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