pacemaker  1.1.16-94ff4df
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 generate_hash_key(const char *crm_msg_reference, const char *sys)
404 {
405  char *hash_key = crm_concat(sys ? sys : "none", crm_msg_reference, '_');
406 
407  crm_trace("created hash key: (%s)", hash_key);
408  return hash_key;
409 }
410 
411 
412 int
413 crm_user_lookup(const char *name, uid_t * uid, gid_t * gid)
414 {
415  int rc = -1;
416  char *buffer = NULL;
417  struct passwd pwd;
418  struct passwd *pwentry = NULL;
419 
420  buffer = calloc(1, PW_BUFFER_LEN);
421  getpwnam_r(name, &pwd, buffer, PW_BUFFER_LEN, &pwentry);
422  if (pwentry) {
423  rc = 0;
424  if (uid) {
425  *uid = pwentry->pw_uid;
426  }
427  if (gid) {
428  *gid = pwentry->pw_gid;
429  }
430  crm_trace("Cluster user %s has uid=%d gid=%d", name, pwentry->pw_uid, pwentry->pw_gid);
431 
432  } else {
433  crm_err("Cluster user %s does not exist", name);
434  }
435 
436  free(buffer);
437  return rc;
438 }
439 
440 static int
441 crm_version_helper(const char *text, char **end_text)
442 {
443  int atoi_result = -1;
444 
445  CRM_ASSERT(end_text != NULL);
446 
447  errno = 0;
448 
449  if (text != NULL && text[0] != 0) {
450  atoi_result = (int)strtol(text, end_text, 10);
451 
452  if (errno == EINVAL) {
453  crm_err("Conversion of '%s' %c failed", text, text[0]);
454  atoi_result = -1;
455  }
456  }
457  return atoi_result;
458 }
459 
460 /*
461  * version1 < version2 : -1
462  * version1 = version2 : 0
463  * version1 > version2 : 1
464  */
465 int
466 compare_version(const char *version1, const char *version2)
467 {
468  int rc = 0;
469  int lpc = 0;
470  char *ver1_copy = NULL, *ver2_copy = NULL;
471  char *rest1 = NULL, *rest2 = NULL;
472 
473  if (version1 == NULL && version2 == NULL) {
474  return 0;
475  } else if (version1 == NULL) {
476  return -1;
477  } else if (version2 == NULL) {
478  return 1;
479  }
480 
481  ver1_copy = strdup(version1);
482  ver2_copy = strdup(version2);
483  rest1 = ver1_copy;
484  rest2 = ver2_copy;
485 
486  while (1) {
487  int digit1 = 0;
488  int digit2 = 0;
489 
490  lpc++;
491 
492  if (rest1 == rest2) {
493  break;
494  }
495 
496  if (rest1 != NULL) {
497  digit1 = crm_version_helper(rest1, &rest1);
498  }
499 
500  if (rest2 != NULL) {
501  digit2 = crm_version_helper(rest2, &rest2);
502  }
503 
504  if (digit1 < digit2) {
505  rc = -1;
506  break;
507 
508  } else if (digit1 > digit2) {
509  rc = 1;
510  break;
511  }
512 
513  if (rest1 != NULL && rest1[0] == '.') {
514  rest1++;
515  }
516  if (rest1 != NULL && rest1[0] == 0) {
517  rest1 = NULL;
518  }
519 
520  if (rest2 != NULL && rest2[0] == '.') {
521  rest2++;
522  }
523  if (rest2 != NULL && rest2[0] == 0) {
524  rest2 = NULL;
525  }
526  }
527 
528  free(ver1_copy);
529  free(ver2_copy);
530 
531  if (rc == 0) {
532  crm_trace("%s == %s (%d)", version1, version2, lpc);
533  } else if (rc < 0) {
534  crm_trace("%s < %s (%d)", version1, version2, lpc);
535  } else if (rc > 0) {
536  crm_trace("%s > %s (%d)", version1, version2, lpc);
537  }
538 
539  return rc;
540 }
541 
542 gboolean do_stderr = FALSE;
543 
544 #ifndef NUMCHARS
545 # define NUMCHARS "0123456789."
546 #endif
547 
548 #ifndef WHITESPACE
549 # define WHITESPACE " \t\n\r\f"
550 #endif
551 
552 unsigned long long
553 crm_get_interval(const char *input)
554 {
555  unsigned long long msec = 0;
556 
557  if (input == NULL) {
558  return msec;
559 
560  } else if (input[0] != 'P') {
561  long long tmp = crm_get_msec(input);
562 
563  if(tmp > 0) {
564  msec = tmp;
565  }
566 
567  } else {
568  crm_time_t *interval = crm_time_parse_duration(input);
569 
570  msec = 1000 * crm_time_get_seconds(interval);
571  crm_time_free(interval);
572  }
573 
574  return msec;
575 }
576 
577 long long
578 crm_get_msec(const char *input)
579 {
580  const char *cp = input;
581  const char *units;
582  long long multiplier = 1000;
583  long long divisor = 1;
584  long long msec = -1;
585  char *end_text = NULL;
586 
587  /* double dret; */
588 
589  if (input == NULL) {
590  return msec;
591  }
592 
593  cp += strspn(cp, WHITESPACE);
594  units = cp + strspn(cp, NUMCHARS);
595  units += strspn(units, WHITESPACE);
596 
597  if (strchr(NUMCHARS, *cp) == NULL) {
598  return msec;
599  }
600 
601  if (strncasecmp(units, "ms", 2) == 0 || strncasecmp(units, "msec", 4) == 0) {
602  multiplier = 1;
603  divisor = 1;
604  } else if (strncasecmp(units, "us", 2) == 0 || strncasecmp(units, "usec", 4) == 0) {
605  multiplier = 1;
606  divisor = 1000;
607  } else if (strncasecmp(units, "s", 1) == 0 || strncasecmp(units, "sec", 3) == 0) {
608  multiplier = 1000;
609  divisor = 1;
610  } else if (strncasecmp(units, "m", 1) == 0 || strncasecmp(units, "min", 3) == 0) {
611  multiplier = 60 * 1000;
612  divisor = 1;
613  } else if (strncasecmp(units, "h", 1) == 0 || strncasecmp(units, "hr", 2) == 0) {
614  multiplier = 60 * 60 * 1000;
615  divisor = 1;
616  } else if (*units != EOS && *units != '\n' && *units != '\r') {
617  return msec;
618  }
619 
620  msec = crm_int_helper(cp, &end_text);
621  if (msec > LLONG_MAX/multiplier) {
622  /* arithmetics overflow while multiplier/divisor mutually exclusive */
623  return LLONG_MAX;
624  }
625  msec *= multiplier;
626  msec /= divisor;
627  /* dret += 0.5; */
628  /* msec = (long long)dret; */
629  return msec;
630 }
631 
632 char *
633 generate_op_key(const char *rsc_id, const char *op_type, int interval)
634 {
635  int len = 35;
636  char *op_id = NULL;
637 
638  CRM_CHECK(rsc_id != NULL, return NULL);
639  CRM_CHECK(op_type != NULL, return NULL);
640 
641  len += strlen(op_type);
642  len += strlen(rsc_id);
643  op_id = malloc(len);
644  CRM_CHECK(op_id != NULL, return NULL);
645  sprintf(op_id, "%s_%s_%d", rsc_id, op_type, interval);
646  return op_id;
647 }
648 
649 gboolean
650 parse_op_key(const char *key, char **rsc_id, char **op_type, int *interval)
651 {
652  char *notify = NULL;
653  char *mutable_key = NULL;
654  char *mutable_key_ptr = NULL;
655  int len = 0, offset = 0, ch = 0;
656 
657  CRM_CHECK(key != NULL, return FALSE);
658 
659  *interval = 0;
660  len = strlen(key);
661  offset = len - 1;
662 
663  crm_trace("Source: %s", key);
664 
665  while (offset > 0 && isdigit(key[offset])) {
666  int digits = len - offset;
667 
668  ch = key[offset] - '0';
669  CRM_CHECK(ch < 10, return FALSE);
670  CRM_CHECK(ch >= 0, return FALSE);
671  while (digits > 1) {
672  digits--;
673  ch = ch * 10;
674  }
675  *interval += ch;
676  offset--;
677  }
678 
679  crm_trace(" Interval: %d", *interval);
680  CRM_CHECK(key[offset] == '_', return FALSE);
681 
682  mutable_key = strdup(key);
683  mutable_key[offset] = 0;
684  offset--;
685 
686  while (offset > 0 && key[offset] != '_') {
687  offset--;
688  }
689 
690  CRM_CHECK(key[offset] == '_', free(mutable_key);
691  return FALSE);
692 
693  mutable_key_ptr = mutable_key + offset + 1;
694 
695  crm_trace(" Action: %s", mutable_key_ptr);
696 
697  *op_type = strdup(mutable_key_ptr);
698 
699  mutable_key[offset] = 0;
700  offset--;
701 
702  CRM_CHECK(mutable_key != mutable_key_ptr, free(mutable_key);
703  return FALSE);
704 
705  notify = strstr(mutable_key, "_post_notify");
706  if (notify && safe_str_eq(notify, "_post_notify")) {
707  notify[0] = 0;
708  }
709 
710  notify = strstr(mutable_key, "_pre_notify");
711  if (notify && safe_str_eq(notify, "_pre_notify")) {
712  notify[0] = 0;
713  }
714 
715  crm_trace(" Resource: %s", mutable_key);
716  *rsc_id = mutable_key;
717 
718  return TRUE;
719 }
720 
721 char *
722 generate_notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
723 {
724  int len = 12;
725  char *op_id = NULL;
726 
727  CRM_CHECK(rsc_id != NULL, return NULL);
728  CRM_CHECK(op_type != NULL, return NULL);
729  CRM_CHECK(notify_type != NULL, return NULL);
730 
731  len += strlen(op_type);
732  len += strlen(rsc_id);
733  len += strlen(notify_type);
734  if(len > 0) {
735  op_id = malloc(len);
736  }
737  if (op_id != NULL) {
738  sprintf(op_id, "%s_%s_notify_%s_0", rsc_id, notify_type, op_type);
739  }
740  return op_id;
741 }
742 
743 char *
744 generate_transition_magic_v202(const char *transition_key, int op_status)
745 {
746  int len = 80;
747  char *fail_state = NULL;
748 
749  CRM_CHECK(transition_key != NULL, return NULL);
750 
751  len += strlen(transition_key);
752 
753  fail_state = malloc(len);
754  if (fail_state != NULL) {
755  snprintf(fail_state, len, "%d:%s", op_status, transition_key);
756  }
757  return fail_state;
758 }
759 
760 char *
761 generate_transition_magic(const char *transition_key, int op_status, int op_rc)
762 {
763  int len = 80;
764  char *fail_state = NULL;
765 
766  CRM_CHECK(transition_key != NULL, return NULL);
767 
768  len += strlen(transition_key);
769 
770  fail_state = malloc(len);
771  if (fail_state != NULL) {
772  snprintf(fail_state, len, "%d:%d;%s", op_status, op_rc, transition_key);
773  }
774  return fail_state;
775 }
776 
777 gboolean
778 decode_transition_magic(const char *magic, char **uuid, int *transition_id, int *action_id,
779  int *op_status, int *op_rc, int *target_rc)
780 {
781  int res = 0;
782  char *key = NULL;
783  gboolean result = TRUE;
784 
785  CRM_CHECK(magic != NULL, return FALSE);
786  CRM_CHECK(op_rc != NULL, return FALSE);
787  CRM_CHECK(op_status != NULL, return FALSE);
788 
789  key = calloc(1, strlen(magic) + 1);
790  res = sscanf(magic, "%d:%d;%s", op_status, op_rc, key);
791  if (res != 3) {
792  crm_warn("Only found %d items in: '%s'", res, magic);
793  free(key);
794  return FALSE;
795  }
796 
797  CRM_CHECK(decode_transition_key(key, uuid, transition_id, action_id, target_rc), result = FALSE);
798 
799  free(key);
800  return result;
801 }
802 
803 char *
804 generate_transition_key(int transition_id, int action_id, int target_rc, const char *node)
805 {
806  int len = 40;
807  char *fail_state = NULL;
808 
809  CRM_CHECK(node != NULL, return NULL);
810 
811  len += strlen(node);
812 
813  fail_state = malloc(len);
814  if (fail_state != NULL) {
815  snprintf(fail_state, len, "%d:%d:%d:%-*s", action_id, transition_id, target_rc, 36, node);
816  }
817  return fail_state;
818 }
819 
820 gboolean
821 decode_transition_key(const char *key, char **uuid, int *transition_id, int *action_id,
822  int *target_rc)
823 {
824  int res = 0;
825  gboolean done = FALSE;
826 
827  CRM_CHECK(uuid != NULL, return FALSE);
828  CRM_CHECK(target_rc != NULL, return FALSE);
829  CRM_CHECK(action_id != NULL, return FALSE);
830  CRM_CHECK(transition_id != NULL, return FALSE);
831 
832  *uuid = calloc(1, 37);
833  res = sscanf(key, "%d:%d:%d:%36s", action_id, transition_id, target_rc, *uuid);
834  switch (res) {
835  case 4:
836  /* Post Pacemaker 0.6 */
837  done = TRUE;
838  break;
839  case 3:
840  case 2:
841  /* this can be tricky - the UUID might start with an integer */
842 
843  /* Until Pacemaker 0.6 */
844  done = TRUE;
845  *target_rc = -1;
846  res = sscanf(key, "%d:%d:%36s", action_id, transition_id, *uuid);
847  if (res == 2) {
848  *action_id = -1;
849  res = sscanf(key, "%d:%36s", transition_id, *uuid);
850  CRM_CHECK(res == 2, done = FALSE);
851 
852  } else if (res != 3) {
853  CRM_CHECK(res == 3, done = FALSE);
854  }
855  break;
856 
857  case 1:
858  /* Prior to Heartbeat 2.0.8 */
859  done = TRUE;
860  *action_id = -1;
861  *target_rc = -1;
862  res = sscanf(key, "%d:%36s", transition_id, *uuid);
863  CRM_CHECK(res == 2, done = FALSE);
864  break;
865  default:
866  crm_crit("Unhandled sscanf result (%d) for %s", res, key);
867  }
868 
869  if (strlen(*uuid) != 36) {
870  crm_warn("Bad UUID (%s) in sscanf result (%d) for %s", *uuid, res, key);
871  }
872 
873  if (done == FALSE) {
874  crm_err("Cannot decode '%s' rc=%d", key, res);
875 
876  free(*uuid);
877  *uuid = NULL;
878  *target_rc = -1;
879  *action_id = -1;
880  *transition_id = -1;
881  }
882 
883  return done;
884 }
885 
886 void
887 filter_action_parameters(xmlNode * param_set, const char *version)
888 {
889  char *key = NULL;
890  char *timeout = NULL;
891  char *interval = NULL;
892 
893  const char *attr_filter[] = {
894  XML_ATTR_ID,
897  };
898 
899  gboolean do_delete = FALSE;
900  int lpc = 0;
901  static int meta_len = 0;
902 
903  if (meta_len == 0) {
904  meta_len = strlen(CRM_META);
905  }
906 
907  if (param_set == NULL) {
908  return;
909  }
910 
911  for (lpc = 0; lpc < DIMOF(attr_filter); lpc++) {
912  xml_remove_prop(param_set, attr_filter[lpc]);
913  }
914 
916  interval = crm_element_value_copy(param_set, key);
917  free(key);
918 
920  timeout = crm_element_value_copy(param_set, key);
921 
922  if (param_set) {
923  xmlAttrPtr xIter = param_set->properties;
924 
925  while (xIter) {
926  const char *prop_name = (const char *)xIter->name;
927 
928  xIter = xIter->next;
929  do_delete = FALSE;
930  if (strncasecmp(prop_name, CRM_META, meta_len) == 0) {
931  do_delete = TRUE;
932  }
933 
934  if (do_delete) {
935  xml_remove_prop(param_set, prop_name);
936  }
937  }
938  }
939 
940  if (crm_get_msec(interval) > 0 && compare_version(version, "1.0.8") > 0) {
941  /* Re-instate the operation's timeout value */
942  if (timeout != NULL) {
943  crm_xml_add(param_set, key, timeout);
944  }
945  }
946 
947  free(interval);
948  free(timeout);
949  free(key);
950 }
951 
952 extern bool crm_is_daemon;
953 
954 /* coverity[+kill] */
955 void
956 crm_abort(const char *file, const char *function, int line,
957  const char *assert_condition, gboolean do_core, gboolean do_fork)
958 {
959  int rc = 0;
960  int pid = 0;
961  int status = 0;
962 
963  /* Implied by the parent's error logging below */
964  /* crm_write_blackbox(0); */
965 
966  if(crm_is_daemon == FALSE) {
967  /* This is a command line tool - do not fork */
968 
969  /* crm_add_logfile(NULL); * Record it to a file? */
970  crm_enable_stderr(TRUE); /* Make sure stderr is enabled so we can tell the caller */
971  do_fork = FALSE; /* Just crash if needed */
972  }
973 
974  if (do_core == FALSE) {
975  crm_err("%s: Triggered assert at %s:%d : %s", function, file, line, assert_condition);
976  return;
977 
978  } else if (do_fork) {
979  pid = fork();
980 
981  } else {
982  crm_err("%s: Triggered fatal assert at %s:%d : %s", function, file, line, assert_condition);
983  }
984 
985  if (pid == -1) {
986  crm_crit("%s: Cannot create core for non-fatal assert at %s:%d : %s",
987  function, file, line, assert_condition);
988  return;
989 
990  } else if(pid == 0) {
991  /* Child process */
992  abort();
993  return;
994  }
995 
996  /* Parent process */
997  crm_err("%s: Forked child %d to record non-fatal assert at %s:%d : %s",
998  function, pid, file, line, assert_condition);
999  crm_write_blackbox(SIGTRAP, NULL);
1000 
1001  do {
1002  rc = waitpid(pid, &status, 0);
1003  if(rc == pid) {
1004  return; /* Job done */
1005  }
1006 
1007  } while(errno == EINTR);
1008 
1009  if (errno == ECHILD) {
1010  /* crm_mon does this */
1011  crm_trace("Cannot wait on forked child %d - SIGCHLD is probably set to SIG_IGN", pid);
1012  return;
1013  }
1014  crm_perror(LOG_ERR, "Cannot wait on forked child %d", pid);
1015 }
1016 
1017 int
1018 crm_pid_active(long pid, const char *daemon)
1019 {
1020  static int have_proc_pid = 0;
1021 
1022  if(have_proc_pid == 0) {
1023  char proc_path[PATH_MAX], exe_path[PATH_MAX];
1024 
1025  /* check to make sure pid hasn't been reused by another process */
1026  snprintf(proc_path, sizeof(proc_path), "/proc/%lu/exe", (long unsigned int)getpid());
1027 
1028  have_proc_pid = 1;
1029  if(readlink(proc_path, exe_path, PATH_MAX - 1) < 0) {
1030  have_proc_pid = -1;
1031  }
1032  }
1033 
1034  if (pid <= 0) {
1035  return -1;
1036 
1037  } else if (kill(pid, 0) < 0 && errno == ESRCH) {
1038  return 0;
1039 
1040  } else if(daemon == NULL || have_proc_pid == -1) {
1041  return 1;
1042 
1043  } else {
1044  int rc = 0;
1045  char proc_path[PATH_MAX], exe_path[PATH_MAX], myexe_path[PATH_MAX];
1046 
1047  /* check to make sure pid hasn't been reused by another process */
1048  snprintf(proc_path, sizeof(proc_path), "/proc/%lu/exe", pid);
1049 
1050  rc = readlink(proc_path, exe_path, PATH_MAX - 1);
1051  if (rc < 0 && errno == EACCES) {
1052  crm_perror(LOG_INFO, "Could not read from %s", proc_path);
1053  return 1;
1054  } else if (rc < 0) {
1055  crm_perror(LOG_ERR, "Could not read from %s", proc_path);
1056  return 0;
1057  }
1058 
1059 
1060  exe_path[rc] = 0;
1061 
1062  if(daemon[0] != '/') {
1063  rc = snprintf(myexe_path, sizeof(proc_path), CRM_DAEMON_DIR"/%s", daemon);
1064  myexe_path[rc] = 0;
1065  } else {
1066  rc = snprintf(myexe_path, sizeof(proc_path), "%s", daemon);
1067  myexe_path[rc] = 0;
1068  }
1069 
1070  if (strcmp(exe_path, myexe_path) == 0) {
1071  return 1;
1072  }
1073  }
1074 
1075  return 0;
1076 }
1077 
1078 #define LOCKSTRLEN 11
1079 
1080 long
1081 crm_read_pidfile(const char *filename)
1082 {
1083  int fd;
1084  struct stat sbuf;
1085  long pid = -ENOENT;
1086  char buf[LOCKSTRLEN + 1];
1087 
1088  if ((fd = open(filename, O_RDONLY)) < 0) {
1089  goto bail;
1090  }
1091 
1092  if (fstat(fd, &sbuf) >= 0 && sbuf.st_size < LOCKSTRLEN) {
1093  sleep(2); /* if someone was about to create one,
1094  * give'm a sec to do so
1095  */
1096  }
1097 
1098  if (read(fd, buf, sizeof(buf)) < 1) {
1099  goto bail;
1100  }
1101 
1102  if (sscanf(buf, "%lu", &pid) > 0) {
1103  if (pid <= 0) {
1104  pid = -ESRCH;
1105  } else {
1106  crm_trace("Got pid %lu from %s\n", pid, filename);
1107  }
1108  }
1109 
1110  bail:
1111  if (fd >= 0) {
1112  close(fd);
1113  }
1114  return pid;
1115 }
1116 
1117 long
1118 crm_pidfile_inuse(const char *filename, long mypid, const char *daemon)
1119 {
1120  long pid = crm_read_pidfile(filename);
1121 
1122  if (pid < 2) {
1123  /* Invalid pid */
1124  pid = -ENOENT;
1125  unlink(filename);
1126 
1127  } else if (mypid && pid == mypid) {
1128  /* In use by us */
1129  pid = pcmk_ok;
1130 
1131  } else if (crm_pid_active(pid, daemon) == FALSE) {
1132  /* Contains a stale value */
1133  unlink(filename);
1134  pid = -ENOENT;
1135 
1136  } else if (mypid && pid != mypid) {
1137  /* locked by existing process - give up */
1138  pid = -EEXIST;
1139  }
1140 
1141  return pid;
1142 }
1143 
1144 static int
1145 crm_lock_pidfile(const char *filename, const char *name)
1146 {
1147  long mypid = 0;
1148  int fd = 0, rc = 0;
1149  char buf[LOCKSTRLEN + 1];
1150 
1151  mypid = (unsigned long)getpid();
1152 
1153  rc = crm_pidfile_inuse(filename, 0, name);
1154  if (rc == -ENOENT) {
1155  /* exists but the process is not active */
1156 
1157  } else if (rc != pcmk_ok) {
1158  /* locked by existing process - give up */
1159  return rc;
1160  }
1161 
1162  if ((fd = open(filename, O_CREAT | O_WRONLY | O_EXCL, 0644)) < 0) {
1163  /* Hmmh, why did we fail? Anyway, nothing we can do about it */
1164  return -errno;
1165  }
1166 
1167  snprintf(buf, sizeof(buf), "%*lu\n", LOCKSTRLEN - 1, mypid);
1168  rc = write(fd, buf, LOCKSTRLEN);
1169  close(fd);
1170 
1171  if (rc != LOCKSTRLEN) {
1172  crm_perror(LOG_ERR, "Incomplete write to %s", filename);
1173  return -errno;
1174  }
1175 
1176  return crm_pidfile_inuse(filename, mypid, name);
1177 }
1178 
1179 void
1180 crm_make_daemon(const char *name, gboolean daemonize, const char *pidfile)
1181 {
1182  int rc;
1183  long pid;
1184  const char *devnull = "/dev/null";
1185 
1186  if (daemonize == FALSE) {
1187  return;
1188  }
1189 
1190  /* Check before we even try... */
1191  rc = crm_pidfile_inuse(pidfile, 1, name);
1192  if(rc < pcmk_ok && rc != -ENOENT) {
1193  pid = crm_read_pidfile(pidfile);
1194  crm_err("%s: already running [pid %ld in %s]", name, pid, pidfile);
1195  printf("%s: already running [pid %ld in %s]\n", name, pid, pidfile);
1196  crm_exit(rc);
1197  }
1198 
1199  pid = fork();
1200  if (pid < 0) {
1201  fprintf(stderr, "%s: could not start daemon\n", name);
1202  crm_perror(LOG_ERR, "fork");
1203  crm_exit(EINVAL);
1204 
1205  } else if (pid > 0) {
1206  crm_exit(pcmk_ok);
1207  }
1208 
1209  rc = crm_lock_pidfile(pidfile, name);
1210  if(rc < pcmk_ok) {
1211  crm_err("Could not lock '%s' for %s: %s (%d)", pidfile, name, pcmk_strerror(rc), rc);
1212  printf("Could not lock '%s' for %s: %s (%d)\n", pidfile, name, pcmk_strerror(rc), rc);
1213  crm_exit(rc);
1214  }
1215 
1216  umask(S_IWGRP | S_IWOTH | S_IROTH);
1217 
1218  close(STDIN_FILENO);
1219  (void)open(devnull, O_RDONLY); /* Stdin: fd 0 */
1220  close(STDOUT_FILENO);
1221  (void)open(devnull, O_WRONLY); /* Stdout: fd 1 */
1222  close(STDERR_FILENO);
1223  (void)open(devnull, O_WRONLY); /* Stderr: fd 2 */
1224 }
1225 
1226 char *
1227 crm_meta_name(const char *field)
1228 {
1229  int lpc = 0;
1230  int max = 0;
1231  char *crm_name = NULL;
1232 
1233  CRM_CHECK(field != NULL, return NULL);
1234  crm_name = crm_concat(CRM_META, field, '_');
1235 
1236  /* Massage the names so they can be used as shell variables */
1237  max = strlen(crm_name);
1238  for (; lpc < max; lpc++) {
1239  switch (crm_name[lpc]) {
1240  case '-':
1241  crm_name[lpc] = '_';
1242  break;
1243  }
1244  }
1245  return crm_name;
1246 }
1247 
1248 const char *
1249 crm_meta_value(GHashTable * hash, const char *field)
1250 {
1251  char *key = NULL;
1252  const char *value = NULL;
1253 
1254  key = crm_meta_name(field);
1255  if (key) {
1256  value = g_hash_table_lookup(hash, key);
1257  free(key);
1258  }
1259 
1260  return value;
1261 }
1262 
1263 static struct option *
1264 crm_create_long_opts(struct crm_option *long_options)
1265 {
1266  struct option *long_opts = NULL;
1267 
1268 #ifdef HAVE_GETOPT_H
1269  int index = 0, lpc = 0;
1270 
1271  /*
1272  * A previous, possibly poor, choice of '?' as the short form of --help
1273  * means that getopt_long() returns '?' for both --help and for "unknown option"
1274  *
1275  * This dummy entry allows us to differentiate between the two in crm_get_option()
1276  * and exit with the correct error code
1277  */
1278  long_opts = realloc_safe(long_opts, (index + 1) * sizeof(struct option));
1279  long_opts[index].name = "__dummmy__";
1280  long_opts[index].has_arg = 0;
1281  long_opts[index].flag = 0;
1282  long_opts[index].val = '_';
1283  index++;
1284 
1285  for (lpc = 0; long_options[lpc].name != NULL; lpc++) {
1286  if (long_options[lpc].name[0] == '-') {
1287  continue;
1288  }
1289 
1290  long_opts = realloc_safe(long_opts, (index + 1) * sizeof(struct option));
1291  /*fprintf(stderr, "Creating %d %s = %c\n", index,
1292  * long_options[lpc].name, long_options[lpc].val); */
1293  long_opts[index].name = long_options[lpc].name;
1294  long_opts[index].has_arg = long_options[lpc].has_arg;
1295  long_opts[index].flag = long_options[lpc].flag;
1296  long_opts[index].val = long_options[lpc].val;
1297  index++;
1298  }
1299 
1300  /* Now create the list terminator */
1301  long_opts = realloc_safe(long_opts, (index + 1) * sizeof(struct option));
1302  long_opts[index].name = NULL;
1303  long_opts[index].has_arg = 0;
1304  long_opts[index].flag = 0;
1305  long_opts[index].val = 0;
1306 #endif
1307 
1308  return long_opts;
1309 }
1310 
1311 void
1312 crm_set_options(const char *short_options, const char *app_usage, struct crm_option *long_options,
1313  const char *app_desc)
1314 {
1315  if (short_options) {
1316  crm_short_options = strdup(short_options);
1317 
1318  } else if (long_options) {
1319  int lpc = 0;
1320  int opt_string_len = 0;
1321  char *local_short_options = NULL;
1322 
1323  for (lpc = 0; long_options[lpc].name != NULL; lpc++) {
1324  if (long_options[lpc].val && long_options[lpc].val != '-' && long_options[lpc].val < UCHAR_MAX) {
1325  local_short_options = realloc_safe(local_short_options, opt_string_len + 4);
1326  local_short_options[opt_string_len++] = long_options[lpc].val;
1327  /* getopt(3) says: Two colons mean an option takes an optional arg; */
1328  if (long_options[lpc].has_arg == optional_argument) {
1329  local_short_options[opt_string_len++] = ':';
1330  }
1331  if (long_options[lpc].has_arg >= required_argument) {
1332  local_short_options[opt_string_len++] = ':';
1333  }
1334  local_short_options[opt_string_len] = 0;
1335  }
1336  }
1337  crm_short_options = local_short_options;
1338  crm_trace("Generated short option string: '%s'", local_short_options);
1339  }
1340 
1341  if (long_options) {
1342  crm_long_options = long_options;
1343  }
1344  if (app_desc) {
1345  crm_app_description = app_desc;
1346  }
1347  if (app_usage) {
1348  crm_app_usage = app_usage;
1349  }
1350 }
1351 
1352 int
1353 crm_get_option(int argc, char **argv, int *index)
1354 {
1355  return crm_get_option_long(argc, argv, index, NULL);
1356 }
1357 
1358 int
1359 crm_get_option_long(int argc, char **argv, int *index, const char **longname)
1360 {
1361 #ifdef HAVE_GETOPT_H
1362  static struct option *long_opts = NULL;
1363 
1364  if (long_opts == NULL && crm_long_options) {
1365  long_opts = crm_create_long_opts(crm_long_options);
1366  }
1367 
1368  *index = 0;
1369  if (long_opts) {
1370  int flag = getopt_long(argc, argv, crm_short_options, long_opts, index);
1371 
1372  switch (flag) {
1373  case 0:
1374  if (long_opts[*index].val) {
1375  return long_opts[*index].val;
1376  } else if (longname) {
1377  *longname = long_opts[*index].name;
1378  } else {
1379  crm_notice("Unhandled option --%s", long_opts[*index].name);
1380  return flag;
1381  }
1382  case -1: /* End of option processing */
1383  break;
1384  case ':':
1385  crm_trace("Missing argument");
1386  crm_help('?', 1);
1387  break;
1388  case '?':
1389  crm_help('?', *index ? 0 : 1);
1390  break;
1391  }
1392  return flag;
1393  }
1394 #endif
1395 
1396  if (crm_short_options) {
1397  return getopt(argc, argv, crm_short_options);
1398  }
1399 
1400  return -1;
1401 }
1402 
1403 int
1404 crm_help(char cmd, int exit_code)
1405 {
1406  int i = 0;
1407  FILE *stream = (exit_code ? stderr : stdout);
1408 
1409  if (cmd == 'v' || cmd == '$') {
1410  fprintf(stream, "Pacemaker %s\n", PACEMAKER_VERSION);
1411  fprintf(stream, "Written by Andrew Beekhof\n");
1412  goto out;
1413  }
1414 
1415  if (cmd == '!') {
1416  fprintf(stream, "Pacemaker %s (Build: %s): %s\n", PACEMAKER_VERSION, BUILD_VERSION, CRM_FEATURES);
1417  goto out;
1418  }
1419 
1420  fprintf(stream, "%s - %s\n", crm_system_name, crm_app_description);
1421 
1422  if (crm_app_usage) {
1423  fprintf(stream, "Usage: %s %s\n", crm_system_name, crm_app_usage);
1424  }
1425 
1426  if (crm_long_options) {
1427  fprintf(stream, "Options:\n");
1428  for (i = 0; crm_long_options[i].name != NULL; i++) {
1429  if (crm_long_options[i].flags & pcmk_option_hidden) {
1430 
1431  } else if (crm_long_options[i].flags & pcmk_option_paragraph) {
1432  fprintf(stream, "%s\n\n", crm_long_options[i].desc);
1433 
1434  } else if (crm_long_options[i].flags & pcmk_option_example) {
1435  fprintf(stream, "\t#%s\n\n", crm_long_options[i].desc);
1436 
1437  } else if (crm_long_options[i].val == '-' && crm_long_options[i].desc) {
1438  fprintf(stream, "%s\n", crm_long_options[i].desc);
1439 
1440  } else {
1441  /* is val printable as char ? */
1442  if (crm_long_options[i].val && crm_long_options[i].val <= UCHAR_MAX) {
1443  fprintf(stream, " -%c,", crm_long_options[i].val);
1444  } else {
1445  fputs(" ", stream);
1446  }
1447  fprintf(stream, " --%s%s\t%s\n", crm_long_options[i].name,
1448  crm_long_options[i].has_arg == optional_argument ? "[=value]" :
1449  crm_long_options[i].has_arg == required_argument ? "=value" : "",
1450  crm_long_options[i].desc ? crm_long_options[i].desc : "");
1451  }
1452  }
1453 
1454  } else if (crm_short_options) {
1455  fprintf(stream, "Usage: %s - %s\n", crm_system_name, crm_app_description);
1456  for (i = 0; crm_short_options[i] != 0; i++) {
1457  int has_arg = no_argument /* 0 */;
1458 
1459  if (crm_short_options[i + 1] == ':') {
1460  if (crm_short_options[i + 2] == ':')
1461  has_arg = optional_argument /* 2 */;
1462  else
1463  has_arg = required_argument /* 1 */;
1464  }
1465 
1466  fprintf(stream, " -%c %s\n", crm_short_options[i],
1467  has_arg == optional_argument ? "[value]" :
1468  has_arg == required_argument ? "{value}" : "");
1469  i += has_arg;
1470  }
1471  }
1472 
1473  fprintf(stream, "\nReport bugs to %s\n", PACKAGE_BUGREPORT);
1474 
1475  out:
1476  return crm_exit(exit_code);
1477 }
1478 
1479 void cib_ipc_servers_init(qb_ipcs_service_t **ipcs_ro,
1480  qb_ipcs_service_t **ipcs_rw,
1481  qb_ipcs_service_t **ipcs_shm,
1482  struct qb_ipcs_service_handlers *ro_cb,
1483  struct qb_ipcs_service_handlers *rw_cb)
1484 {
1485  *ipcs_ro = mainloop_add_ipc_server(cib_channel_ro, QB_IPC_NATIVE, ro_cb);
1486  *ipcs_rw = mainloop_add_ipc_server(cib_channel_rw, QB_IPC_NATIVE, rw_cb);
1487  *ipcs_shm = mainloop_add_ipc_server(cib_channel_shm, QB_IPC_SHM, rw_cb);
1488 
1489  if (*ipcs_ro == NULL || *ipcs_rw == NULL || *ipcs_shm == NULL) {
1490  crm_err("Failed to create cib servers: exiting and inhibiting respawn.");
1491  crm_warn("Verify pacemaker and pacemaker_remote are not both enabled.");
1493  }
1494 }
1495 
1496 void cib_ipc_servers_destroy(qb_ipcs_service_t *ipcs_ro,
1497  qb_ipcs_service_t *ipcs_rw,
1498  qb_ipcs_service_t *ipcs_shm)
1499 {
1500  qb_ipcs_destroy(ipcs_ro);
1501  qb_ipcs_destroy(ipcs_rw);
1502  qb_ipcs_destroy(ipcs_shm);
1503 }
1504 
1505 qb_ipcs_service_t *
1506 crmd_ipc_server_init(struct qb_ipcs_service_handlers *cb)
1507 {
1508  return mainloop_add_ipc_server(CRM_SYSTEM_CRMD, QB_IPC_NATIVE, cb);
1509 }
1510 
1511 void
1512 attrd_ipc_server_init(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb)
1513 {
1514  *ipcs = mainloop_add_ipc_server(T_ATTRD, QB_IPC_NATIVE, cb);
1515 
1516  if (*ipcs == NULL) {
1517  crm_err("Failed to create attrd servers: exiting and inhibiting respawn.");
1518  crm_warn("Verify pacemaker and pacemaker_remote are not both enabled.");
1520  }
1521 }
1522 
1523 void
1524 stonith_ipc_server_init(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb)
1525 {
1526  *ipcs = mainloop_add_ipc_server("stonith-ng", QB_IPC_NATIVE, cb);
1527 
1528  if (*ipcs == NULL) {
1529  crm_err("Failed to create stonith-ng servers: exiting and inhibiting respawn.");
1530  crm_warn("Verify pacemaker and pacemaker_remote are not both enabled.");
1532  }
1533 }
1534 
1535 int
1536 attrd_update_delegate(crm_ipc_t * ipc, char command, const char *host, const char *name,
1537  const char *value, const char *section, const char *set, const char *dampen,
1538  const char *user_name, int options)
1539 {
1540  int rc = -ENOTCONN;
1541  int max = 5;
1542  const char *task = NULL;
1543  const char *name_as = NULL;
1544  const char *display_host = (host ? host : "localhost");
1545  const char *display_command = NULL; /* for commands without name/value */
1546  xmlNode *update = create_xml_node(NULL, __FUNCTION__);
1547 
1548  static gboolean connected = TRUE;
1549  static crm_ipc_t *local_ipc = NULL;
1550  static enum crm_ipc_flags flags = crm_ipc_flags_none;
1551 
1552  if (ipc == NULL && local_ipc == NULL) {
1553  local_ipc = crm_ipc_new(T_ATTRD, 0);
1554  flags |= crm_ipc_client_response;
1555  connected = FALSE;
1556  }
1557 
1558  if (ipc == NULL) {
1559  ipc = local_ipc;
1560  }
1561 
1562  /* remap common aliases */
1563  if (safe_str_eq(section, "reboot")) {
1564  section = XML_CIB_TAG_STATUS;
1565 
1566  } else if (safe_str_eq(section, "forever")) {
1567  section = XML_CIB_TAG_NODES;
1568  }
1569 
1570  crm_xml_add(update, F_TYPE, T_ATTRD);
1571  crm_xml_add(update, F_ORIG, crm_system_name?crm_system_name:"unknown");
1572 
1573  if (name == NULL && command == 'U') {
1574  command = 'R';
1575  }
1576 
1577  switch (command) {
1578  case 'u':
1579  task = ATTRD_OP_UPDATE;
1580  name_as = F_ATTRD_REGEX;
1581  break;
1582  case 'D':
1583  case 'U':
1584  case 'v':
1585  task = ATTRD_OP_UPDATE;
1586  name_as = F_ATTRD_ATTRIBUTE;
1587  break;
1588  case 'R':
1589  task = ATTRD_OP_REFRESH;
1590  display_command = "refresh";
1591  break;
1592  case 'B':
1593  task = ATTRD_OP_UPDATE_BOTH;
1594  name_as = F_ATTRD_ATTRIBUTE;
1595  break;
1596  case 'Y':
1597  task = ATTRD_OP_UPDATE_DELAY;
1598  name_as = F_ATTRD_ATTRIBUTE;
1599  break;
1600  case 'Q':
1601  task = ATTRD_OP_QUERY;
1602  name_as = F_ATTRD_ATTRIBUTE;
1603  break;
1604  case 'C':
1605  task = ATTRD_OP_PEER_REMOVE;
1606  display_command = "purge";
1607  break;
1608  }
1609 
1610  if (name_as != NULL) {
1611  if (name == NULL) {
1612  rc = -EINVAL;
1613  goto done;
1614  }
1615  crm_xml_add(update, name_as, name);
1616  }
1617 
1618  crm_xml_add(update, F_ATTRD_TASK, task);
1619  crm_xml_add(update, F_ATTRD_VALUE, value);
1620  crm_xml_add(update, F_ATTRD_DAMPEN, dampen);
1621  crm_xml_add(update, F_ATTRD_SECTION, section);
1622  crm_xml_add(update, F_ATTRD_HOST, host);
1623  crm_xml_add(update, F_ATTRD_SET, set);
1624  crm_xml_add_int(update, F_ATTRD_IS_REMOTE, is_set(options, attrd_opt_remote));
1625  crm_xml_add_int(update, F_ATTRD_IS_PRIVATE, is_set(options, attrd_opt_private));
1626 #if ENABLE_ACL
1627  if (user_name) {
1628  crm_xml_add(update, F_ATTRD_USER, user_name);
1629  }
1630 #endif
1631 
1632  while (max > 0) {
1633  if (connected == FALSE) {
1634  crm_info("Connecting to cluster... %d retries remaining", max);
1635  connected = crm_ipc_connect(ipc);
1636  }
1637 
1638  if (connected) {
1639  rc = crm_ipc_send(ipc, update, flags, 0, NULL);
1640  } else {
1641  crm_perror(LOG_INFO, "Connection to cluster attribute manager failed");
1642  }
1643 
1644  if (ipc != local_ipc) {
1645  break;
1646 
1647  } else if (rc > 0) {
1648  break;
1649 
1650  } else if (rc == -EAGAIN || rc == -EALREADY) {
1651  sleep(5 - max);
1652  max--;
1653 
1654  } else {
1655  crm_ipc_close(ipc);
1656  connected = FALSE;
1657  sleep(5 - max);
1658  max--;
1659  }
1660  }
1661 
1662 done:
1663  free_xml(update);
1664  if (rc > 0) {
1665  rc = pcmk_ok;
1666  }
1667 
1668  if (display_command) {
1669  crm_debug("Asked attrd to %s %s: %s (%d)",
1670  display_command, display_host, pcmk_strerror(rc), rc);
1671  } else {
1672  crm_debug("Asked attrd to update %s=%s for %s: %s (%d)",
1673  name, value, display_host, pcmk_strerror(rc), rc);
1674  }
1675  return rc;
1676 }
1677 
1678 #define FAKE_TE_ID "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
1679 static void
1680 append_digest(lrmd_event_data_t * op, xmlNode * update, const char *version, const char *magic,
1681  int level)
1682 {
1683  /* this will enable us to later determine that the
1684  * resource's parameters have changed and we should force
1685  * a restart
1686  */
1687  char *digest = NULL;
1688  xmlNode *args_xml = NULL;
1689 
1690  if (op->params == NULL) {
1691  return;
1692  }
1693 
1694  args_xml = create_xml_node(NULL, XML_TAG_PARAMS);
1695  g_hash_table_foreach(op->params, hash2field, args_xml);
1696  filter_action_parameters(args_xml, version);
1697  digest = calculate_operation_digest(args_xml, version);
1698 
1699 #if 0
1700  if (level < get_crm_log_level()
1701  && op->interval == 0 && crm_str_eq(op->op_type, CRMD_ACTION_START, TRUE)) {
1702  char *digest_source = dump_xml_unformatted(args_xml);
1703 
1704  do_crm_log(level, "Calculated digest %s for %s (%s). Source: %s\n",
1705  digest, ID(update), magic, digest_source);
1706  free(digest_source);
1707  }
1708 #endif
1709  crm_xml_add(update, XML_LRM_ATTR_OP_DIGEST, digest);
1710 
1711  free_xml(args_xml);
1712  free(digest);
1713 }
1714 
1715 int
1717 {
1718  int rc = 0;
1719 
1720  if (op && op->user_data) {
1721  int dummy = 0;
1722  char *uuid = NULL;
1723 
1724  decode_transition_key(op->user_data, &uuid, &dummy, &dummy, &rc);
1725  free(uuid);
1726  }
1727  return rc;
1728 }
1729 
1730 gboolean
1732 {
1733  switch (op->op_status) {
1734  case PCMK_LRM_OP_CANCELLED:
1735  case PCMK_LRM_OP_PENDING:
1736  return FALSE;
1737  break;
1738 
1740  case PCMK_LRM_OP_TIMEOUT:
1741  case PCMK_LRM_OP_ERROR:
1742  return TRUE;
1743  break;
1744 
1745  default:
1746  if (target_rc != op->rc) {
1747  return TRUE;
1748  }
1749  }
1750 
1751  return FALSE;
1752 }
1753 
1754 xmlNode *
1755 create_operation_update(xmlNode * parent, lrmd_event_data_t * op, const char * caller_version,
1756  int target_rc, const char * node, const char * origin, int level)
1757 {
1758  char *key = NULL;
1759  char *magic = NULL;
1760  char *op_id = NULL;
1761  char *op_id_additional = NULL;
1762  char *local_user_data = NULL;
1763  const char *exit_reason = NULL;
1764 
1765  xmlNode *xml_op = NULL;
1766  const char *task = NULL;
1767  gboolean dc_munges_migrate_ops = (compare_version(caller_version, "3.0.3") < 0);
1768  gboolean dc_needs_unique_ops = (compare_version(caller_version, "3.0.6") < 0);
1769 
1770  CRM_CHECK(op != NULL, return NULL);
1771  do_crm_log(level, "%s: Updating resource %s after %s op %s (interval=%d)",
1772  origin, op->rsc_id, op->op_type, services_lrm_status_str(op->op_status),
1773  op->interval);
1774 
1775  crm_trace("DC version: %s", caller_version);
1776 
1777  task = op->op_type;
1778  /* remap the task name under various scenarios
1779  * this makes life easier for the PE when trying determine the current state
1780  */
1781  if (crm_str_eq(task, "reload", TRUE)) {
1782  if (op->op_status == PCMK_LRM_OP_DONE) {
1783  task = CRMD_ACTION_START;
1784  } else {
1785  task = CRMD_ACTION_STATUS;
1786  }
1787 
1788  } else if (dc_munges_migrate_ops && crm_str_eq(task, CRMD_ACTION_MIGRATE, TRUE)) {
1789  /* if the migrate_from fails it will have enough info to do the right thing */
1790  if (op->op_status == PCMK_LRM_OP_DONE) {
1791  task = CRMD_ACTION_STOP;
1792  } else {
1793  task = CRMD_ACTION_STATUS;
1794  }
1795 
1796  } else if (dc_munges_migrate_ops
1797  && op->op_status == PCMK_LRM_OP_DONE
1798  && crm_str_eq(task, CRMD_ACTION_MIGRATED, TRUE)) {
1799  task = CRMD_ACTION_START;
1800  }
1801 
1802  key = generate_op_key(op->rsc_id, task, op->interval);
1803  if (dc_needs_unique_ops && op->interval > 0) {
1804  op_id = strdup(key);
1805 
1806  } else if (crm_str_eq(task, CRMD_ACTION_NOTIFY, TRUE)) {
1807  const char *n_type = crm_meta_value(op->params, "notify_type");
1808  const char *n_task = crm_meta_value(op->params, "notify_operation");
1809 
1810  CRM_LOG_ASSERT(n_type != NULL);
1811  CRM_LOG_ASSERT(n_task != NULL);
1812  op_id = generate_notify_key(op->rsc_id, n_type, n_task);
1813 
1814  /* these are not yet allowed to fail */
1816  op->rc = 0;
1817 
1818  } else if (did_rsc_op_fail(op, target_rc)) {
1819  op_id = generate_op_key(op->rsc_id, "last_failure", 0);
1820  if (op->interval == 0) {
1821  /* Ensure 'last' gets updated too in case recording-pending="true" */
1822  op_id_additional = generate_op_key(op->rsc_id, "last", 0);
1823  }
1824  exit_reason = op->exit_reason;
1825 
1826  } else if (op->interval > 0) {
1827  op_id = strdup(key);
1828 
1829  } else {
1830  op_id = generate_op_key(op->rsc_id, "last", 0);
1831  }
1832 
1833  again:
1834  xml_op = find_entity(parent, XML_LRM_TAG_RSC_OP, op_id);
1835  if (xml_op == NULL) {
1836  xml_op = create_xml_node(parent, XML_LRM_TAG_RSC_OP);
1837  }
1838 
1839  if (op->user_data == NULL) {
1840  crm_debug("Generating fake transition key for:"
1841  " %s_%s_%d %d from %s",
1842  op->rsc_id, op->op_type, op->interval, op->call_id, origin);
1843  local_user_data = generate_transition_key(-1, op->call_id, target_rc, FAKE_TE_ID);
1844  op->user_data = local_user_data;
1845  }
1846 
1847  if(magic == NULL) {
1848  magic = generate_transition_magic(op->user_data, op->op_status, op->rc);
1849  }
1850 
1851  crm_xml_add(xml_op, XML_ATTR_ID, op_id);
1852  crm_xml_add(xml_op, XML_LRM_ATTR_TASK_KEY, key);
1853  crm_xml_add(xml_op, XML_LRM_ATTR_TASK, task);
1854  crm_xml_add(xml_op, XML_ATTR_ORIGIN, origin);
1855  crm_xml_add(xml_op, XML_ATTR_CRM_VERSION, caller_version);
1857  crm_xml_add(xml_op, XML_ATTR_TRANSITION_MAGIC, magic);
1858  crm_xml_add(xml_op, XML_LRM_ATTR_EXIT_REASON, exit_reason);
1859  crm_xml_add(xml_op, XML_LRM_ATTR_TARGET, node); /* For context during triage */
1860 
1862  crm_xml_add_int(xml_op, XML_LRM_ATTR_RC, op->rc);
1865 
1866  if (compare_version("2.1", caller_version) <= 0) {
1867  if (op->t_run || op->t_rcchange || op->exec_time || op->queue_time) {
1868  crm_trace("Timing data (%s_%s_%d): last=%u change=%u exec=%u queue=%u",
1869  op->rsc_id, op->op_type, op->interval,
1870  op->t_run, op->t_rcchange, op->exec_time, op->queue_time);
1871 
1872  if (op->interval == 0) {
1873  /* The values are the same for non-recurring ops */
1876 
1877  } else if(op->t_rcchange) {
1878  /* last-run is not accurate for recurring ops */
1880 
1881  } else {
1882  /* ...but is better than nothing otherwise */
1884  }
1885 
1888  }
1889  }
1890 
1891  if (crm_str_eq(op->op_type, CRMD_ACTION_MIGRATE, TRUE)
1892  || crm_str_eq(op->op_type, CRMD_ACTION_MIGRATED, TRUE)) {
1893  /*
1894  * Record migrate_source and migrate_target always for migrate ops.
1895  */
1896  const char *name = XML_LRM_ATTR_MIGRATE_SOURCE;
1897 
1898  crm_xml_add(xml_op, name, crm_meta_value(op->params, name));
1899 
1901  crm_xml_add(xml_op, name, crm_meta_value(op->params, name));
1902  }
1903 
1904  append_digest(op, xml_op, caller_version, magic, LOG_DEBUG);
1905 
1906  if (op_id_additional) {
1907  free(op_id);
1908  op_id = op_id_additional;
1909  op_id_additional = NULL;
1910  goto again;
1911  }
1912 
1913  if (local_user_data) {
1914  free(local_user_data);
1915  op->user_data = NULL;
1916  }
1917  free(magic);
1918  free(op_id);
1919  free(key);
1920  return xml_op;
1921 }
1922 
1923 bool
1924 pcmk_acl_required(const char *user)
1925 {
1926 #if ENABLE_ACL
1927  if(user == NULL || strlen(user) == 0) {
1928  crm_trace("no user set");
1929  return FALSE;
1930 
1931  } else if (strcmp(user, CRM_DAEMON_USER) == 0) {
1932  return FALSE;
1933 
1934  } else if (strcmp(user, "root") == 0) {
1935  return FALSE;
1936  }
1937  crm_trace("acls required for %s", user);
1938  return TRUE;
1939 #else
1940  crm_trace("acls not supported");
1941  return FALSE;
1942 #endif
1943 }
1944 
1945 #if ENABLE_ACL
1946 char *
1947 uid2username(uid_t uid)
1948 {
1949  struct passwd *pwent = getpwuid(uid);
1950 
1951  if (pwent == NULL) {
1952  crm_perror(LOG_ERR, "Cannot get password entry of uid: %d", uid);
1953  return NULL;
1954 
1955  } else {
1956  return strdup(pwent->pw_name);
1957  }
1958 }
1959 
1960 const char *
1961 crm_acl_get_set_user(xmlNode * request, const char *field, const char *peer_user)
1962 {
1963  /* field is only checked for backwards compatibility */
1964  static const char *effective_user = NULL;
1965  const char *requested_user = NULL;
1966  const char *user = NULL;
1967 
1968  if(effective_user == NULL) {
1969  effective_user = uid2username(geteuid());
1970  }
1971 
1972  requested_user = crm_element_value(request, XML_ACL_TAG_USER);
1973  if(requested_user == NULL) {
1974  requested_user = crm_element_value(request, field);
1975  }
1976 
1977  if (is_privileged(effective_user) == FALSE) {
1978  /* We're not running as a privileged user, set or overwrite any existing value for $XML_ACL_TAG_USER */
1979  user = effective_user;
1980 
1981  } else if(peer_user == NULL && requested_user == NULL) {
1982  /* No user known or requested, use 'effective_user' and make sure one is set for the request */
1983  user = effective_user;
1984 
1985  } else if(peer_user == NULL) {
1986  /* No user known, trusting 'requested_user' */
1987  user = requested_user;
1988 
1989  } else if (is_privileged(peer_user) == FALSE) {
1990  /* The peer is not a privileged user, set or overwrite any existing value for $XML_ACL_TAG_USER */
1991  user = peer_user;
1992 
1993  } else if (requested_user == NULL) {
1994  /* Even if we're privileged, make sure there is always a value set */
1995  user = peer_user;
1996 
1997  } else {
1998  /* Legal delegation to 'requested_user' */
1999  user = requested_user;
2000  }
2001 
2002  /* Yes, pointer comparision */
2003  if(user != crm_element_value(request, XML_ACL_TAG_USER)) {
2004  crm_xml_add(request, XML_ACL_TAG_USER, user);
2005  }
2006 
2007  if(field != NULL && user != crm_element_value(request, field)) {
2008  crm_xml_add(request, field, user);
2009  }
2010 
2011  return requested_user;
2012 }
2013 
2014 void
2015 determine_request_user(const char *user, xmlNode * request, const char *field)
2016 {
2017  /* Get our internal validation out of the way first */
2018  CRM_CHECK(user != NULL && request != NULL && field != NULL, return);
2019 
2020  /* If our peer is a privileged user, we might be doing something on behalf of someone else */
2021  if (is_privileged(user) == FALSE) {
2022  /* We're not a privileged user, set or overwrite any existing value for $field */
2023  crm_xml_replace(request, field, user);
2024 
2025  } else if (crm_element_value(request, field) == NULL) {
2026  /* Even if we're privileged, make sure there is always a value set */
2027  crm_xml_replace(request, field, user);
2028 
2029 /* } else { Legal delegation */
2030  }
2031 
2032  crm_trace("Processing msg as user '%s'", crm_element_value(request, field));
2033 }
2034 #endif
2035 
2036 void *
2037 find_library_function(void **handle, const char *lib, const char *fn, gboolean fatal)
2038 {
2039  char *error;
2040  void *a_function;
2041 
2042  if (*handle == NULL) {
2043  *handle = dlopen(lib, RTLD_LAZY);
2044  }
2045 
2046  if (!(*handle)) {
2047  crm_err("%sCould not open %s: %s", fatal ? "Fatal: " : "", lib, dlerror());
2048  if (fatal) {
2050  }
2051  return NULL;
2052  }
2053 
2054  a_function = dlsym(*handle, fn);
2055  if (a_function == NULL) {
2056  error = dlerror();
2057  crm_err("%sCould not find %s in %s: %s", fatal ? "Fatal: " : "", fn, lib, error);
2058  if (fatal) {
2060  }
2061  }
2062 
2063  return a_function;
2064 }
2065 
2066 void *
2067 convert_const_pointer(const void *ptr)
2068 {
2069  /* Worst function ever */
2070  return (void *)ptr;
2071 }
2072 
2073 #ifdef HAVE_UUID_UUID_H
2074 # include <uuid/uuid.h>
2075 #endif
2076 
2077 char *
2079 {
2080  unsigned char uuid[16];
2081  char *buffer = malloc(37); /* Including NUL byte */
2082 
2083  uuid_generate(uuid);
2084  uuid_unparse(uuid, buffer);
2085  return buffer;
2086 }
2087 
2088 #include <md5.h>
2089 
2090 char *
2091 crm_md5sum(const char *buffer)
2092 {
2093  int lpc = 0, len = 0;
2094  char *digest = NULL;
2095  unsigned char raw_digest[MD5_DIGEST_SIZE];
2096 
2097  if (buffer == NULL) {
2098  buffer = "";
2099  }
2100  len = strlen(buffer);
2101 
2102  crm_trace("Beginning digest of %d bytes", len);
2103  digest = malloc(2 * MD5_DIGEST_SIZE + 1);
2104  if(digest) {
2105  md5_buffer(buffer, len, raw_digest);
2106  for (lpc = 0; lpc < MD5_DIGEST_SIZE; lpc++) {
2107  sprintf(digest + (2 * lpc), "%02x", raw_digest[lpc]);
2108  }
2109  digest[(2 * MD5_DIGEST_SIZE)] = 0;
2110  crm_trace("Digest %s.", digest);
2111 
2112  } else {
2113  crm_err("Could not create digest");
2114  }
2115  return digest;
2116 }
2117 
2118 #ifdef HAVE_GNUTLS_GNUTLS_H
2119 void
2120 crm_gnutls_global_init(void)
2121 {
2122  signal(SIGPIPE, SIG_IGN);
2123  gnutls_global_init();
2124 }
2125 #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:283
void * find_library_function(void **handle, const char *lib, const char *fn, gboolean fatal)
Definition: utils.c:2037
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:264
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, int *interval)
Definition: utils.c:650
void crm_write_blackbox(int nsig, struct qb_log_callsite *callsite)
Definition: logging.c:419
bool crm_ipc_connect(crm_ipc_t *client)
Establish an IPC connection to a Pacemaker component.
Definition: ipc.c:798
A dumping ground.
#define F_TYPE
Definition: msg_xml.h:34
long long crm_get_msec(const char *input)
Definition: utils.c:578
int crm_get_option_long(int argc, char **argv, int *index, const char **longname)
Definition: utils.c:1359
#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:413
#define CRMD_ACTION_MIGRATED
Definition: crm.h:156
gboolean do_stderr
Definition: utils.c:542
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:1536
void crm_enable_stderr(int enable)
Definition: logging.c:905
void * convert_const_pointer(const void *ptr)
Definition: utils.c:2067
#define crm_crit(fmt, args...)
Definition: logging.h:247
gboolean check_utilization(const char *value)
Definition: utils.c:210
#define INFINITY
Definition: crm.h:83
const char * user_data
Definition: lrmd.h:196
const char * crm_meta_value(GHashTable *hash, const char *field)
Definition: utils.c:1249
const char * rsc_id
Definition: lrmd.h:192
#define XML_ATTR_TRANSITION_MAGIC
Definition: msg_xml.h:361
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:1496
void attrd_ipc_server_init(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb)
Definition: utils.c:1512
struct crm_time_s crm_time_t
Definition: iso8601.h:37
const char * pcmk_strerror(int rc)
Definition: logging.c:1128
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:256
#define F_ATTRD_HOST
Definition: crm_internal.h:271
unsigned int queue_time
Definition: lrmd.h:222
void crm_make_daemon(const char *name, gboolean daemonize, const char *pidfile)
Definition: utils.c:1180
void crm_xml_cleanup(void)
Definition: xml.c:4939
gboolean decode_transition_key(const char *key, char **uuid, int *transition_id, int *action_id, int *target_rc)
Definition: utils.c:821
#define F_ATTRD_REGEX
Definition: crm_internal.h:262
#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:169
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:1479
char * crm_md5sum(const char *buffer)
Definition: utils.c:2091
xmlNode * find_entity(xmlNode *parent, const char *node_name, const char *id)
Definition: xml.c:2212
#define XML_RSC_OP_T_EXEC
Definition: msg_xml.h:285
char * generate_transition_key(int transition_id, int action_id, int target_rc, const char *node)
Definition: utils.c:804
#define F_ATTRD_USER
Definition: crm_internal.h:273
#define XML_LRM_ATTR_INTERVAL
Definition: msg_xml.h:262
gboolean crm_config_warning
Definition: utils.c:73
int crm_help(char cmd, int exit_code)
Definition: utils.c:1404
#define XML_LRM_ATTR_OP_DIGEST
Definition: msg_xml.h:276
#define XML_ATTR_TIMEOUT
Definition: msg_xml.h:94
#define ATTRD_OP_UPDATE
Definition: crm_internal.h:279
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:76
char * crm_element_value_copy(xmlNode *data, const char *name)
Definition: xml.c:3770
Local Resource Manager.
unsigned int t_rcchange
Definition: lrmd.h:218
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:81
#define F_ATTRD_SECTION
Definition: crm_internal.h:268
#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:1312
uint32_t pid
Definition: internal.h:49
enum ocf_exitcode rc
Definition: lrmd.h:210
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:286
#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:265
#define ATTRD_OP_REFRESH
Definition: crm_internal.h:283
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
long crm_read_pidfile(const char *filename)
Definition: utils.c:1081
const char * crm_xml_replace(xmlNode *node, const char *name, const char *value)
Definition: xml.c:2480
#define ATTRD_OP_PEER_REMOVE
Definition: crm_internal.h:278
bool pcmk_acl_required(const char *user)
Definition: utils.c:1924
unsigned int exec_time
Definition: lrmd.h:220
void stonith_ipc_server_init(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb)
Definition: utils.c:1524
#define XML_ATTR_ORIGIN
Definition: msg_xml.h:95
#define CRMD_ACTION_START
Definition: crm.h:158
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:1755
char * crm_meta_name(const char *field)
Definition: utils.c:1227
gboolean check_quorum(const char *value)
Definition: utils.c:165
#define XML_LRM_ATTR_TASK_KEY
Definition: msg_xml.h:264
#define XML_LRM_ATTR_TASK
Definition: msg_xml.h:263
void hash2field(gpointer key, gpointer value, gpointer user_data)
Definition: xml.c:4742
#define CRMD_ACTION_STOP
Definition: crm.h:161
void * params
Definition: lrmd.h:229
#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:1018
int daemon(int nochdir, int noclose)
const char * exit_reason
Definition: lrmd.h:237
#define F_ATTRD_ATTRIBUTE
Definition: crm_internal.h:261
char * generate_hash_key(const char *crm_msg_reference, const char *sys)
Definition: utils.c:403
#define ATTRD_OP_UPDATE_BOTH
Definition: crm_internal.h:280
#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:267
#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:1078
#define pcmk_option_example
Definition: crm_internal.h:73
unsigned long long crm_get_interval(const char *input)
Definition: utils.c:553
#define INFINITY_S
Definition: crm.h:80
gboolean did_rsc_op_fail(lrmd_event_data_t *op, int target_rc)
Definition: utils.c:1731
#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:72
#define NUMCHARS
Definition: utils.c:545
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:2532
const char * crm_element_value(xmlNode *data, const char *name)
Definition: xml.c:4987
#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:263
#define F_ATTRD_IS_REMOTE
Definition: crm_internal.h:266
#define XML_LRM_ATTR_MIGRATE_TARGET
Definition: msg_xml.h:289
char * crm_generate_uuid(void)
Definition: utils.c:2078
#define XML_LRM_ATTR_EXIT_REASON
Definition: msg_xml.h:281
#define F_ORIG
Definition: msg_xml.h:22
void free_xml(xmlNode *child)
Definition: xml.c:2587
#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
#define attrd_opt_remote
Definition: attrd.h:24
void filter_action_parameters(xmlNode *param_set, const char *version)
Definition: utils.c:887
int * flag
Definition: crm_internal.h:85
int node_score_green
Definition: utils.c:77
CRM_TRACE_INIT_DATA(common)
const char * op_type
Definition: lrmd.h:194
#define WHITESPACE
Definition: utils.c:549
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:778
#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:269
#define DAEMON_RESPAWN_STOP
Definition: crm.h:65
int compare_version(const char *version1, const char *version2)
Definition: utils.c:466
unsigned int t_run
Definition: lrmd.h:216
gboolean check_script(const char *value)
Definition: utils.c:183
#define crm_config_warn(fmt...)
Definition: crm_internal.h:257
#define XML_ATTR_TRANSITION_KEY
Definition: msg_xml.h:362
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Definition: xml.c:2434
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Definition: xml.c:2522
unsigned int get_crm_log_level(void)
Definition: logging.c:935
#define ATTRD_OP_QUERY
Definition: crm_internal.h:282
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:956
char * generate_notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
Definition: utils.c:722
gboolean check_timer(const char *value)
Definition: utils.c:124
long crm_pidfile_inuse(const char *filename, long mypid, const char *daemon)
Definition: utils.c:1118
#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:744
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:1678
int crm_ipc_send(crm_ipc_t *client, xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Definition: ipc.c:1124
gboolean check_number(const char *value)
Definition: utils.c:144
void xml_remove_prop(xmlNode *obj, const char *name)
Definition: xml.c:3782
int rsc_op_expected_rc(lrmd_event_data_t *op)
Definition: utils.c:1716
crm_ipc_t * crm_ipc_new(const char *name, size_t max_size)
Definition: ipc.c:770
#define F_ATTRD_DAMPEN
Definition: crm_internal.h:269
char * dump_xml_unformatted(xmlNode *msg)
Definition: xml.c:3726
#define DIMOF(a)
Definition: crm.h:39
#define XML_LRM_ATTR_CALLID
Definition: msg_xml.h:275
#define CRMD_ACTION_MIGRATE
Definition: crm.h:155
#define CRM_ASSERT(expr)
Definition: error.h:35
#define XML_LRM_ATTR_OPSTATUS
Definition: msg_xml.h:273
#define XML_ATTR_CRM_VERSION
Definition: msg_xml.h:83
#define pcmk_option_hidden
Definition: crm_internal.h:71
int crm_get_option(int argc, char **argv, int *index)
Definition: utils.c:1353
char * generate_op_key(const char *rsc_id, const char *op_type, int interval)
Definition: utils.c:633
#define XML_LRM_ATTR_RC
Definition: msg_xml.h:274
#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
#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:761
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 XML_LRM_ATTR_TARGET
Definition: msg_xml.h:265
#define XML_LRM_TAG_RSC_OP
Definition: msg_xml.h:235
#define XML_RSC_OP_LAST_RUN
Definition: msg_xml.h:284
char * crm_concat(const char *prefix, const char *suffix, char join)
Definition: strings.c:32
#define ID(x)
Definition: msg_xml.h:423
#define XML_ACL_TAG_USER
Definition: msg_xml.h:372
char * crm_itoa(int an_int)
Definition: strings.c:60
#define safe_str_eq(a, b)
Definition: util.h:63
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
#define XML_LRM_ATTR_MIGRATE_SOURCE
Definition: msg_xml.h:288
#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:829
#define ATTRD_OP_UPDATE_DELAY
Definition: crm_internal.h:281
#define XML_TAG_PARAMS
Definition: msg_xml.h:179
#define crm_info(fmt, args...)
Definition: logging.h:251
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
uint64_t flags
Definition: remote.c:121
qb_ipcs_service_t * crmd_ipc_server_init(struct qb_ipcs_service_handlers *cb)
Definition: utils.c:1506
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:172
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:115