pacemaker  2.0.2-debe490
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
utils.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2019 the Pacemaker project contributors
3  *
4  * The version control history for this file may have further details.
5  *
6  * This source code is licensed under the GNU Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 #include <dlfcn.h>
12 
13 #ifndef _GNU_SOURCE
14 # define _GNU_SOURCE
15 #endif
16 
17 #include <sys/types.h>
18 #include <sys/wait.h>
19 #include <sys/stat.h>
20 #include <sys/utsname.h>
21 
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <limits.h>
27 #include <pwd.h>
28 #include <time.h>
29 #include <libgen.h>
30 #include <signal.h>
31 
32 #include <qb/qbdefs.h>
33 
34 #include <crm/crm.h>
35 #include <crm/services.h>
36 #include <crm/msg_xml.h>
37 #include <crm/cib/internal.h>
38 #include <crm/common/xml.h>
39 #include <crm/common/util.h>
40 #include <crm/common/ipc.h>
41 #include <crm/common/iso8601.h>
42 #include <crm/common/mainloop.h>
43 #include <libxml2/libxml/relaxng.h>
44 
45 #ifndef MAXLINE
46 # define MAXLINE 512
47 #endif
48 
49 #ifdef HAVE_GETOPT_H
50 # include <getopt.h>
51 #endif
52 
53 #ifndef PW_BUFFER_LEN
54 # define PW_BUFFER_LEN 500
55 #endif
56 
57 CRM_TRACE_INIT_DATA(common);
58 
59 gboolean crm_config_error = FALSE;
60 gboolean crm_config_warning = FALSE;
61 char *crm_system_name = NULL;
62 
66 
67 static struct crm_option *crm_long_options = NULL;
68 static const char *crm_app_description = NULL;
69 static char *crm_short_options = NULL;
70 static const char *crm_app_usage = NULL;
71 
72 gboolean
73 check_time(const char *value)
74 {
75  if (crm_get_msec(value) < 5000) {
76  return FALSE;
77  }
78  return TRUE;
79 }
80 
81 gboolean
82 check_timer(const char *value)
83 {
84  if (crm_get_msec(value) < 0) {
85  return FALSE;
86  }
87  return TRUE;
88 }
89 
90 gboolean
91 check_boolean(const char *value)
92 {
93  int tmp = FALSE;
94 
95  if (crm_str_to_boolean(value, &tmp) != 1) {
96  return FALSE;
97  }
98  return TRUE;
99 }
100 
101 gboolean
102 check_number(const char *value)
103 {
104  errno = 0;
105  if (value == NULL) {
106  return FALSE;
107 
108  } else if (safe_str_eq(value, CRM_MINUS_INFINITY_S)) {
109 
110  } else if (safe_str_eq(value, CRM_INFINITY_S)) {
111 
112  } else {
113  crm_int_helper(value, NULL);
114  }
115 
116  if (errno != 0) {
117  return FALSE;
118  }
119  return TRUE;
120 }
121 
122 gboolean
123 check_positive_number(const char* value)
124 {
125  if (safe_str_eq(value, CRM_INFINITY_S) || (crm_int_helper(value, NULL))) {
126  return TRUE;
127  }
128  return FALSE;
129 }
130 
131 gboolean
132 check_quorum(const char *value)
133 {
134  if (safe_str_eq(value, "stop")) {
135  return TRUE;
136 
137  } else if (safe_str_eq(value, "freeze")) {
138  return TRUE;
139 
140  } else if (safe_str_eq(value, "ignore")) {
141  return TRUE;
142 
143  } else if (safe_str_eq(value, "suicide")) {
144  return TRUE;
145  }
146  return FALSE;
147 }
148 
149 gboolean
150 check_script(const char *value)
151 {
152  struct stat st;
153 
154  if(safe_str_eq(value, "/dev/null")) {
155  return TRUE;
156  }
157 
158  if(stat(value, &st) != 0) {
159  crm_err("Script %s does not exist", value);
160  return FALSE;
161  }
162 
163  if(S_ISREG(st.st_mode) == 0) {
164  crm_err("Script %s is not a regular file", value);
165  return FALSE;
166  }
167 
168  if( (st.st_mode & (S_IXUSR | S_IXGRP )) == 0) {
169  crm_err("Script %s is not executable", value);
170  return FALSE;
171  }
172 
173  return TRUE;
174 }
175 
176 gboolean
177 check_utilization(const char *value)
178 {
179  char *end = NULL;
180  long number = strtol(value, &end, 10);
181 
182  if(end && end[0] != '%') {
183  return FALSE;
184  } else if(number < 0) {
185  return FALSE;
186  }
187 
188  return TRUE;
189 }
190 
191 void
193 {
194  free(crm_short_options);
195  crm_short_options = NULL;
196 }
197 
198 int
199 char2score(const char *score)
200 {
201  int score_f = 0;
202 
203  if (score == NULL) {
204 
205  } else if (safe_str_eq(score, CRM_MINUS_INFINITY_S)) {
206  score_f = -CRM_SCORE_INFINITY;
207 
208  } else if (safe_str_eq(score, CRM_INFINITY_S)) {
209  score_f = CRM_SCORE_INFINITY;
210 
211  } else if (safe_str_eq(score, CRM_PLUS_INFINITY_S)) {
212  score_f = CRM_SCORE_INFINITY;
213 
214  } else if (safe_str_eq(score, "red")) {
215  score_f = node_score_red;
216 
217  } else if (safe_str_eq(score, "yellow")) {
218  score_f = node_score_yellow;
219 
220  } else if (safe_str_eq(score, "green")) {
221  score_f = node_score_green;
222 
223  } else {
224  score_f = crm_parse_int(score, NULL);
225  if (score_f > 0 && score_f > CRM_SCORE_INFINITY) {
226  score_f = CRM_SCORE_INFINITY;
227 
228  } else if (score_f < 0 && score_f < -CRM_SCORE_INFINITY) {
229  score_f = -CRM_SCORE_INFINITY;
230  }
231  }
232 
233  return score_f;
234 }
235 
236 char *
237 score2char_stack(int score, char *buf, size_t len)
238 {
239  if (score >= CRM_SCORE_INFINITY) {
240  strncpy(buf, CRM_INFINITY_S, 9);
241  } else if (score <= -CRM_SCORE_INFINITY) {
242  strncpy(buf, CRM_MINUS_INFINITY_S , 10);
243  } else {
244  return crm_itoa_stack(score, buf, len);
245  }
246 
247  return buf;
248 }
249 
250 char *
251 score2char(int score)
252 {
253  if (score >= CRM_SCORE_INFINITY) {
254  return strdup(CRM_INFINITY_S);
255 
256  } else if (score <= -CRM_SCORE_INFINITY) {
257  return strdup(CRM_MINUS_INFINITY_S);
258  }
259  return crm_itoa(score);
260 }
261 
262 const char *
263 cluster_option(GHashTable * options, gboolean(*validate) (const char *),
264  const char *name, const char *old_name, const char *def_value)
265 {
266  const char *value = NULL;
267  char *new_value = NULL;
268 
269  CRM_ASSERT(name != NULL);
270 
271  if (options) {
272  value = g_hash_table_lookup(options, name);
273 
274  if ((value == NULL) && old_name) {
275  value = g_hash_table_lookup(options, old_name);
276  if (value != NULL) {
277  crm_config_warn("Support for legacy name '%s' for cluster option '%s'"
278  " is deprecated and will be removed in a future release",
279  old_name, name);
280 
281  // Inserting copy with current name ensures we only warn once
282  new_value = strdup(value);
283  g_hash_table_insert(options, strdup(name), new_value);
284  value = new_value;
285  }
286  }
287 
288  if (value && validate && (validate(value) == FALSE)) {
289  crm_config_err("Resetting cluster option '%s' to default: value '%s' is invalid",
290  name, value);
291  value = NULL;
292  }
293 
294  if (value) {
295  return value;
296  }
297  }
298 
299  // No value found, use default
300  value = def_value;
301 
302  if (value == NULL) {
303  crm_trace("No value or default provided for cluster option '%s'",
304  name);
305  return NULL;
306  }
307 
308  if (validate) {
309  CRM_CHECK(validate(value) != FALSE,
310  crm_err("Bug: default value for cluster option '%s' is invalid", name);
311  return NULL);
312  }
313 
314  crm_trace("Using default value '%s' for cluster option '%s'",
315  value, name);
316  if (options) {
317  new_value = strdup(value);
318  g_hash_table_insert(options, strdup(name), new_value);
319  value = new_value;
320  }
321  return value;
322 }
323 
324 const char *
325 get_cluster_pref(GHashTable * options, pe_cluster_option * option_list, int len, const char *name)
326 {
327  const char *value = NULL;
328 
329  for (int lpc = 0; lpc < len; lpc++) {
330  if (safe_str_eq(name, option_list[lpc].name)) {
331  value = cluster_option(options,
332  option_list[lpc].is_valid,
333  option_list[lpc].name,
334  option_list[lpc].alt_name,
335  option_list[lpc].default_value);
336  return value;
337  }
338  }
339  CRM_CHECK(FALSE, crm_err("Bug: looking for unknown option '%s'", name));
340  return NULL;
341 }
342 
343 void
344 config_metadata(const char *name, const char *version, const char *desc_short,
345  const char *desc_long, pe_cluster_option * option_list, int len)
346 {
347  int lpc = 0;
348 
349  fprintf(stdout, "<?xml version=\"1.0\"?>"
350  "<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n"
351  "<resource-agent name=\"%s\">\n"
352  " <version>%s</version>\n"
353  " <longdesc lang=\"en\">%s</longdesc>\n"
354  " <shortdesc lang=\"en\">%s</shortdesc>\n"
355  " <parameters>\n", name, version, desc_long, desc_short);
356 
357  for (lpc = 0; lpc < len; lpc++) {
358  if (option_list[lpc].description_long == NULL && option_list[lpc].description_short == NULL) {
359  continue;
360  }
361  fprintf(stdout, " <parameter name=\"%s\" unique=\"0\">\n"
362  " <shortdesc lang=\"en\">%s</shortdesc>\n"
363  " <content type=\"%s\" default=\"%s\"/>\n"
364  " <longdesc lang=\"en\">%s%s%s</longdesc>\n"
365  " </parameter>\n",
366  option_list[lpc].name,
367  option_list[lpc].description_short,
368  option_list[lpc].type,
369  option_list[lpc].default_value,
370  option_list[lpc].description_long ? option_list[lpc].
371  description_long : option_list[lpc].description_short,
372  option_list[lpc].values ? " Allowed values: " : "",
373  option_list[lpc].values ? option_list[lpc].values : "");
374  }
375  fprintf(stdout, " </parameters>\n</resource-agent>\n");
376 }
377 
378 void
379 verify_all_options(GHashTable * options, pe_cluster_option * option_list, int len)
380 {
381  int lpc = 0;
382 
383  for (lpc = 0; lpc < len; lpc++) {
384  cluster_option(options,
385  option_list[lpc].is_valid,
386  option_list[lpc].name,
387  option_list[lpc].alt_name, option_list[lpc].default_value);
388  }
389 }
390 
391 char *
392 generate_hash_key(const char *crm_msg_reference, const char *sys)
393 {
394  char *hash_key = crm_concat(sys ? sys : "none", crm_msg_reference, '_');
395 
396  crm_trace("created hash key: (%s)", hash_key);
397  return hash_key;
398 }
399 
400 
401 int
402 crm_user_lookup(const char *name, uid_t * uid, gid_t * gid)
403 {
404  int rc = pcmk_ok;
405  char *buffer = NULL;
406  struct passwd pwd;
407  struct passwd *pwentry = NULL;
408 
409  buffer = calloc(1, PW_BUFFER_LEN);
410  rc = getpwnam_r(name, &pwd, buffer, PW_BUFFER_LEN, &pwentry);
411  if (pwentry) {
412  if (uid) {
413  *uid = pwentry->pw_uid;
414  }
415  if (gid) {
416  *gid = pwentry->pw_gid;
417  }
418  crm_trace("User %s has uid=%d gid=%d", name, pwentry->pw_uid, pwentry->pw_gid);
419 
420  } else {
421  rc = rc? -rc : -EINVAL;
422  crm_info("User %s lookup: %s", name, pcmk_strerror(rc));
423  }
424 
425  free(buffer);
426  return rc;
427 }
428 
429 static int
430 crm_version_helper(const char *text, const char **end_text)
431 {
432  int atoi_result = -1;
433 
434  CRM_ASSERT(end_text != NULL);
435 
436  errno = 0;
437 
438  if (text != NULL && text[0] != 0) {
439  /* seemingly sacrificing const-correctness -- because while strtol
440  doesn't modify the input, it doesn't want to artificially taint the
441  "end_text" pointer-to-pointer-to-first-char-in-string with constness
442  in case the input wasn't actually constant -- by semantic definition
443  not a single character will get modified so it shall be perfectly
444  safe to make compiler happy with dropping "const" qualifier here */
445  atoi_result = (int) strtol(text, (char **) end_text, 10);
446 
447  if (errno == EINVAL) {
448  crm_err("Conversion of '%s' %c failed", text, text[0]);
449  atoi_result = -1;
450  }
451  }
452  return atoi_result;
453 }
454 
455 /*
456  * version1 < version2 : -1
457  * version1 = version2 : 0
458  * version1 > version2 : 1
459  */
460 int
461 compare_version(const char *version1, const char *version2)
462 {
463  int rc = 0;
464  int lpc = 0;
465  const char *ver1_iter, *ver2_iter;
466 
467  if (version1 == NULL && version2 == NULL) {
468  return 0;
469  } else if (version1 == NULL) {
470  return -1;
471  } else if (version2 == NULL) {
472  return 1;
473  }
474 
475  ver1_iter = version1;
476  ver2_iter = version2;
477 
478  while (1) {
479  int digit1 = 0;
480  int digit2 = 0;
481 
482  lpc++;
483 
484  if (ver1_iter == ver2_iter) {
485  break;
486  }
487 
488  if (ver1_iter != NULL) {
489  digit1 = crm_version_helper(ver1_iter, &ver1_iter);
490  }
491 
492  if (ver2_iter != NULL) {
493  digit2 = crm_version_helper(ver2_iter, &ver2_iter);
494  }
495 
496  if (digit1 < digit2) {
497  rc = -1;
498  break;
499 
500  } else if (digit1 > digit2) {
501  rc = 1;
502  break;
503  }
504 
505  if (ver1_iter != NULL && *ver1_iter == '.') {
506  ver1_iter++;
507  }
508  if (ver1_iter != NULL && *ver1_iter == '\0') {
509  ver1_iter = NULL;
510  }
511 
512  if (ver2_iter != NULL && *ver2_iter == '.') {
513  ver2_iter++;
514  }
515  if (ver2_iter != NULL && *ver2_iter == 0) {
516  ver2_iter = NULL;
517  }
518  }
519 
520  if (rc == 0) {
521  crm_trace("%s == %s (%d)", version1, version2, lpc);
522  } else if (rc < 0) {
523  crm_trace("%s < %s (%d)", version1, version2, lpc);
524  } else if (rc > 0) {
525  crm_trace("%s > %s (%d)", version1, version2, lpc);
526  }
527 
528  return rc;
529 }
530 
531 gboolean do_stderr = FALSE;
532 
533 #ifndef NUMCHARS
534 # define NUMCHARS "0123456789."
535 #endif
536 
537 #ifndef WHITESPACE
538 # define WHITESPACE " \t\n\r\f"
539 #endif
540 
541 guint
542 crm_parse_interval_spec(const char *input)
543 {
544  long long msec = 0;
545 
546  if (input == NULL) {
547  return 0;
548 
549  } else if (input[0] != 'P') {
550  long long tmp = crm_get_msec(input);
551 
552  if(tmp > 0) {
553  msec = tmp;
554  }
555 
556  } else {
557  crm_time_t *period_s = crm_time_parse_duration(input);
558 
559  msec = 1000 * crm_time_get_seconds(period_s);
560  crm_time_free(period_s);
561  }
562 
563  return (msec <= 0)? 0 : ((msec >= G_MAXUINT)? G_MAXUINT : (guint) msec);
564 }
565 
566 long long
567 crm_get_msec(const char *input)
568 {
569  const char *cp = input;
570  const char *units;
571  long long multiplier = 1000;
572  long long divisor = 1;
573  long long msec = -1;
574  char *end_text = NULL;
575 
576  /* double dret; */
577 
578  if (input == NULL) {
579  return msec;
580  }
581 
582  cp += strspn(cp, WHITESPACE);
583  units = cp + strspn(cp, NUMCHARS);
584  units += strspn(units, WHITESPACE);
585 
586  if (strchr(NUMCHARS, *cp) == NULL) {
587  return msec;
588  }
589 
590  if (strncasecmp(units, "ms", 2) == 0 || strncasecmp(units, "msec", 4) == 0) {
591  multiplier = 1;
592  divisor = 1;
593  } else if (strncasecmp(units, "us", 2) == 0 || strncasecmp(units, "usec", 4) == 0) {
594  multiplier = 1;
595  divisor = 1000;
596  } else if (strncasecmp(units, "s", 1) == 0 || strncasecmp(units, "sec", 3) == 0) {
597  multiplier = 1000;
598  divisor = 1;
599  } else if (strncasecmp(units, "m", 1) == 0 || strncasecmp(units, "min", 3) == 0) {
600  multiplier = 60 * 1000;
601  divisor = 1;
602  } else if (strncasecmp(units, "h", 1) == 0 || strncasecmp(units, "hr", 2) == 0) {
603  multiplier = 60 * 60 * 1000;
604  divisor = 1;
605  } else if (*units != EOS && *units != '\n' && *units != '\r') {
606  return msec;
607  }
608 
609  msec = crm_int_helper(cp, &end_text);
610  if (msec > LLONG_MAX/multiplier) {
611  /* arithmetics overflow while multiplier/divisor mutually exclusive */
612  return LLONG_MAX;
613  }
614  msec *= multiplier;
615  msec /= divisor;
616  /* dret += 0.5; */
617  /* msec = (long long)dret; */
618  return msec;
619 }
620 
621 extern bool crm_is_daemon;
622 
623 /* coverity[+kill] */
624 void
625 crm_abort(const char *file, const char *function, int line,
626  const char *assert_condition, gboolean do_core, gboolean do_fork)
627 {
628  int rc = 0;
629  int pid = 0;
630  int status = 0;
631 
632  /* Implied by the parent's error logging below */
633  /* crm_write_blackbox(0); */
634 
635  if(crm_is_daemon == FALSE) {
636  /* This is a command line tool - do not fork */
637 
638  /* crm_add_logfile(NULL); * Record it to a file? */
639  crm_enable_stderr(TRUE); /* Make sure stderr is enabled so we can tell the caller */
640  do_fork = FALSE; /* Just crash if needed */
641  }
642 
643  if (do_core == FALSE) {
644  crm_err("%s: Triggered assert at %s:%d : %s", function, file, line, assert_condition);
645  return;
646 
647  } else if (do_fork) {
648  pid = fork();
649 
650  } else {
651  crm_err("%s: Triggered fatal assert at %s:%d : %s", function, file, line, assert_condition);
652  }
653 
654  if (pid == -1) {
655  crm_crit("%s: Cannot create core for non-fatal assert at %s:%d : %s",
656  function, file, line, assert_condition);
657  return;
658 
659  } else if(pid == 0) {
660  /* Child process */
661  abort();
662  return;
663  }
664 
665  /* Parent process */
666  crm_err("%s: Forked child %d to record non-fatal assert at %s:%d : %s",
667  function, pid, file, line, assert_condition);
668  crm_write_blackbox(SIGTRAP, NULL);
669 
670  do {
671  rc = waitpid(pid, &status, 0);
672  if(rc == pid) {
673  return; /* Job done */
674  }
675 
676  } while(errno == EINTR);
677 
678  if (errno == ECHILD) {
679  /* crm_mon does this */
680  crm_trace("Cannot wait on forked child %d - SIGCHLD is probably set to SIG_IGN", pid);
681  return;
682  }
683  crm_perror(LOG_ERR, "Cannot wait on forked child %d", pid);
684 }
685 
686 void
687 crm_make_daemon(const char *name, gboolean daemonize, const char *pidfile)
688 {
689  int rc;
690  long pid;
691  const char *devnull = "/dev/null";
692 
693  if (daemonize == FALSE) {
694  return;
695  }
696 
697  /* Check before we even try... */
698  rc = crm_pidfile_inuse(pidfile, 1, name);
699  if(rc < pcmk_ok && rc != -ENOENT) {
700  pid = crm_read_pidfile(pidfile);
701  crm_err("%s: already running [pid %ld in %s]", name, pid, pidfile);
702  printf("%s: already running [pid %ld in %s]\n", name, pid, pidfile);
704  }
705 
706  pid = fork();
707  if (pid < 0) {
708  fprintf(stderr, "%s: could not start daemon\n", name);
709  crm_perror(LOG_ERR, "fork");
711 
712  } else if (pid > 0) {
714  }
715 
716  rc = crm_lock_pidfile(pidfile, name);
717  if(rc < pcmk_ok) {
718  crm_err("Could not lock '%s' for %s: %s (%d)", pidfile, name, pcmk_strerror(rc), rc);
719  printf("Could not lock '%s' for %s: %s (%d)\n", pidfile, name, pcmk_strerror(rc), rc);
721  }
722 
723  umask(S_IWGRP | S_IWOTH | S_IROTH);
724 
725  close(STDIN_FILENO);
726  (void)open(devnull, O_RDONLY); /* Stdin: fd 0 */
727  close(STDOUT_FILENO);
728  (void)open(devnull, O_WRONLY); /* Stdout: fd 1 */
729  close(STDERR_FILENO);
730  (void)open(devnull, O_WRONLY); /* Stderr: fd 2 */
731 }
732 
733 char *
734 crm_meta_name(const char *field)
735 {
736  int lpc = 0;
737  int max = 0;
738  char *crm_name = NULL;
739 
740  CRM_CHECK(field != NULL, return NULL);
741  crm_name = crm_concat(CRM_META, field, '_');
742 
743  /* Massage the names so they can be used as shell variables */
744  max = strlen(crm_name);
745  for (; lpc < max; lpc++) {
746  switch (crm_name[lpc]) {
747  case '-':
748  crm_name[lpc] = '_';
749  break;
750  }
751  }
752  return crm_name;
753 }
754 
755 const char *
756 crm_meta_value(GHashTable * hash, const char *field)
757 {
758  char *key = NULL;
759  const char *value = NULL;
760 
761  key = crm_meta_name(field);
762  if (key) {
763  value = g_hash_table_lookup(hash, key);
764  free(key);
765  }
766 
767  return value;
768 }
769 
770 static struct option *
771 crm_create_long_opts(struct crm_option *long_options)
772 {
773  struct option *long_opts = NULL;
774 
775 #ifdef HAVE_GETOPT_H
776  int index = 0, lpc = 0;
777 
778  /*
779  * A previous, possibly poor, choice of '?' as the short form of --help
780  * means that getopt_long() returns '?' for both --help and for "unknown option"
781  *
782  * This dummy entry allows us to differentiate between the two in crm_get_option()
783  * and exit with the correct error code
784  */
785  long_opts = realloc_safe(long_opts, (index + 1) * sizeof(struct option));
786  long_opts[index].name = "__dummmy__";
787  long_opts[index].has_arg = 0;
788  long_opts[index].flag = 0;
789  long_opts[index].val = '_';
790  index++;
791 
792  for (lpc = 0; long_options[lpc].name != NULL; lpc++) {
793  if (long_options[lpc].name[0] == '-') {
794  continue;
795  }
796 
797  long_opts = realloc_safe(long_opts, (index + 1) * sizeof(struct option));
798  /*fprintf(stderr, "Creating %d %s = %c\n", index,
799  * long_options[lpc].name, long_options[lpc].val); */
800  long_opts[index].name = long_options[lpc].name;
801  long_opts[index].has_arg = long_options[lpc].has_arg;
802  long_opts[index].flag = long_options[lpc].flag;
803  long_opts[index].val = long_options[lpc].val;
804  index++;
805  }
806 
807  /* Now create the list terminator */
808  long_opts = realloc_safe(long_opts, (index + 1) * sizeof(struct option));
809  long_opts[index].name = NULL;
810  long_opts[index].has_arg = 0;
811  long_opts[index].flag = 0;
812  long_opts[index].val = 0;
813 #endif
814 
815  return long_opts;
816 }
817 
818 void
819 crm_set_options(const char *short_options, const char *app_usage, struct crm_option *long_options,
820  const char *app_desc)
821 {
822  if (short_options) {
823  crm_short_options = strdup(short_options);
824 
825  } else if (long_options) {
826  int lpc = 0;
827  int opt_string_len = 0;
828  char *local_short_options = NULL;
829 
830  for (lpc = 0; long_options[lpc].name != NULL; lpc++) {
831  if (long_options[lpc].val && long_options[lpc].val != '-' && long_options[lpc].val < UCHAR_MAX) {
832  local_short_options = realloc_safe(local_short_options, opt_string_len + 4);
833  local_short_options[opt_string_len++] = long_options[lpc].val;
834  /* getopt(3) says: Two colons mean an option takes an optional arg; */
835  if (long_options[lpc].has_arg == optional_argument) {
836  local_short_options[opt_string_len++] = ':';
837  }
838  if (long_options[lpc].has_arg >= required_argument) {
839  local_short_options[opt_string_len++] = ':';
840  }
841  local_short_options[opt_string_len] = 0;
842  }
843  }
844  crm_short_options = local_short_options;
845  crm_trace("Generated short option string: '%s'", local_short_options);
846  }
847 
848  if (long_options) {
849  crm_long_options = long_options;
850  }
851  if (app_desc) {
852  crm_app_description = app_desc;
853  }
854  if (app_usage) {
855  crm_app_usage = app_usage;
856  }
857 }
858 
859 int
860 crm_get_option(int argc, char **argv, int *index)
861 {
862  return crm_get_option_long(argc, argv, index, NULL);
863 }
864 
865 int
866 crm_get_option_long(int argc, char **argv, int *index, const char **longname)
867 {
868 #ifdef HAVE_GETOPT_H
869  static struct option *long_opts = NULL;
870 
871  if (long_opts == NULL && crm_long_options) {
872  long_opts = crm_create_long_opts(crm_long_options);
873  }
874 
875  *index = 0;
876  if (long_opts) {
877  int flag = getopt_long(argc, argv, crm_short_options, long_opts, index);
878 
879  switch (flag) {
880  case 0:
881  if (long_opts[*index].val) {
882  return long_opts[*index].val;
883  } else if (longname) {
884  *longname = long_opts[*index].name;
885  } else {
886  crm_notice("Unhandled option --%s", long_opts[*index].name);
887  return flag;
888  }
889  case -1: /* End of option processing */
890  break;
891  case ':':
892  crm_trace("Missing argument");
893  crm_help('?', CRM_EX_USAGE);
894  break;
895  case '?':
896  crm_help('?', (*index? CRM_EX_OK : CRM_EX_USAGE));
897  break;
898  }
899  return flag;
900  }
901 #endif
902 
903  if (crm_short_options) {
904  return getopt(argc, argv, crm_short_options);
905  }
906 
907  return -1;
908 }
909 
910 void
911 crm_help(char cmd, crm_exit_t exit_code)
912 {
913  int i = 0;
914  FILE *stream = (exit_code ? stderr : stdout);
915 
916  if (cmd == 'v' || cmd == '$') {
917  fprintf(stream, "Pacemaker %s\n", PACEMAKER_VERSION);
918  fprintf(stream, "Written by Andrew Beekhof\n");
919  goto out;
920  }
921 
922  if (cmd == '!') {
923  fprintf(stream, "Pacemaker %s (Build: %s): %s\n", PACEMAKER_VERSION, BUILD_VERSION, CRM_FEATURES);
924  goto out;
925  }
926 
927  fprintf(stream, "%s - %s\n", crm_system_name, crm_app_description);
928 
929  if (crm_app_usage) {
930  fprintf(stream, "Usage: %s %s\n", crm_system_name, crm_app_usage);
931  }
932 
933  if (crm_long_options) {
934  fprintf(stream, "Options:\n");
935  for (i = 0; crm_long_options[i].name != NULL; i++) {
936  if (crm_long_options[i].flags & pcmk_option_hidden) {
937 
938  } else if (crm_long_options[i].flags & pcmk_option_paragraph) {
939  fprintf(stream, "%s\n\n", crm_long_options[i].desc);
940 
941  } else if (crm_long_options[i].flags & pcmk_option_example) {
942  fprintf(stream, "\t#%s\n\n", crm_long_options[i].desc);
943 
944  } else if (crm_long_options[i].val == '-' && crm_long_options[i].desc) {
945  fprintf(stream, "%s\n", crm_long_options[i].desc);
946 
947  } else {
948  /* is val printable as char ? */
949  if (crm_long_options[i].val && crm_long_options[i].val <= UCHAR_MAX) {
950  fprintf(stream, " -%c,", crm_long_options[i].val);
951  } else {
952  fputs(" ", stream);
953  }
954  fprintf(stream, " --%s%s\t%s\n", crm_long_options[i].name,
955  crm_long_options[i].has_arg == optional_argument ? "[=value]" :
956  crm_long_options[i].has_arg == required_argument ? "=value" : "",
957  crm_long_options[i].desc ? crm_long_options[i].desc : "");
958  }
959  }
960 
961  } else if (crm_short_options) {
962  fprintf(stream, "Usage: %s - %s\n", crm_system_name, crm_app_description);
963  for (i = 0; crm_short_options[i] != 0; i++) {
964  int has_arg = no_argument /* 0 */;
965 
966  if (crm_short_options[i + 1] == ':') {
967  if (crm_short_options[i + 2] == ':')
968  has_arg = optional_argument /* 2 */;
969  else
970  has_arg = required_argument /* 1 */;
971  }
972 
973  fprintf(stream, " -%c %s\n", crm_short_options[i],
974  has_arg == optional_argument ? "[value]" :
975  has_arg == required_argument ? "{value}" : "");
976  i += has_arg;
977  }
978  }
979 
980  fprintf(stream, "\nReport bugs to %s\n", PACKAGE_BUGREPORT);
981 
982  out:
983  crm_exit(exit_code);
984  while(1); // above does not return
985 }
986 
987 void cib_ipc_servers_init(qb_ipcs_service_t **ipcs_ro,
988  qb_ipcs_service_t **ipcs_rw,
989  qb_ipcs_service_t **ipcs_shm,
990  struct qb_ipcs_service_handlers *ro_cb,
991  struct qb_ipcs_service_handlers *rw_cb)
992 {
993  *ipcs_ro = mainloop_add_ipc_server(CIB_CHANNEL_RO, QB_IPC_NATIVE, ro_cb);
994  *ipcs_rw = mainloop_add_ipc_server(CIB_CHANNEL_RW, QB_IPC_NATIVE, rw_cb);
995  *ipcs_shm = mainloop_add_ipc_server(CIB_CHANNEL_SHM, QB_IPC_SHM, rw_cb);
996 
997  if (*ipcs_ro == NULL || *ipcs_rw == NULL || *ipcs_shm == NULL) {
998  crm_err("Failed to create the CIB manager: exiting and inhibiting respawn");
999  crm_warn("Verify pacemaker and pacemaker_remote are not both enabled");
1001  }
1002 }
1003 
1004 void cib_ipc_servers_destroy(qb_ipcs_service_t *ipcs_ro,
1005  qb_ipcs_service_t *ipcs_rw,
1006  qb_ipcs_service_t *ipcs_shm)
1007 {
1008  qb_ipcs_destroy(ipcs_ro);
1009  qb_ipcs_destroy(ipcs_rw);
1010  qb_ipcs_destroy(ipcs_shm);
1011 }
1012 
1013 qb_ipcs_service_t *
1014 crmd_ipc_server_init(struct qb_ipcs_service_handlers *cb)
1015 {
1016  return mainloop_add_ipc_server(CRM_SYSTEM_CRMD, QB_IPC_NATIVE, cb);
1017 }
1018 
1019 void
1020 attrd_ipc_server_init(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb)
1021 {
1022  *ipcs = mainloop_add_ipc_server(T_ATTRD, QB_IPC_NATIVE, cb);
1023 
1024  if (*ipcs == NULL) {
1025  crm_err("Failed to create pacemaker-attrd server: exiting and inhibiting respawn");
1026  crm_warn("Verify pacemaker and pacemaker_remote are not both enabled.");
1028  }
1029 }
1030 
1031 void
1032 stonith_ipc_server_init(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb)
1033 {
1034  *ipcs = mainloop_add_ipc_server("stonith-ng", QB_IPC_NATIVE, cb);
1035 
1036  if (*ipcs == NULL) {
1037  crm_err("Failed to create fencer: exiting and inhibiting respawn.");
1038  crm_warn("Verify pacemaker and pacemaker_remote are not both enabled.");
1040  }
1041 }
1042 
1043 void *
1044 find_library_function(void **handle, const char *lib, const char *fn, gboolean fatal)
1045 {
1046  char *error;
1047  void *a_function;
1048 
1049  if (*handle == NULL) {
1050  *handle = dlopen(lib, RTLD_LAZY);
1051  }
1052 
1053  if (!(*handle)) {
1054  crm_err("%sCould not open %s: %s", fatal ? "Fatal: " : "", lib, dlerror());
1055  if (fatal) {
1057  }
1058  return NULL;
1059  }
1060 
1061  a_function = dlsym(*handle, fn);
1062  if (a_function == NULL) {
1063  error = dlerror();
1064  crm_err("%sCould not find %s in %s: %s", fatal ? "Fatal: " : "", fn, lib, error);
1065  if (fatal) {
1067  }
1068  }
1069 
1070  return a_function;
1071 }
1072 
1073 #ifdef HAVE_UUID_UUID_H
1074 # include <uuid/uuid.h>
1075 #endif
1076 
1077 char *
1079 {
1080  unsigned char uuid[16];
1081  char *buffer = malloc(37); /* Including NUL byte */
1082 
1083  uuid_generate(uuid);
1084  uuid_unparse(uuid, buffer);
1085  return buffer;
1086 }
1087 
1099 const char *
1100 pcmk_message_name(const char *name)
1101 {
1102  if (name == NULL) {
1103  return "unknown";
1104 
1105  } else if (!strcmp(name, "pacemaker-attrd")) {
1106  return "attrd";
1107 
1108  } else if (!strcmp(name, "pacemaker-based")) {
1109  return CRM_SYSTEM_CIB;
1110 
1111  } else if (!strcmp(name, "pacemaker-controld")) {
1112  return CRM_SYSTEM_CRMD;
1113 
1114  } else if (!strcmp(name, "pacemaker-execd")) {
1115  return CRM_SYSTEM_LRMD;
1116 
1117  } else if (!strcmp(name, "pacemaker-fenced")) {
1118  return "stonith-ng";
1119 
1120  } else if (!strcmp(name, "pacemaker-schedulerd")) {
1121  return CRM_SYSTEM_PENGINE;
1122 
1123  } else {
1124  return name;
1125  }
1126 }
1127 
1135 bool
1136 crm_is_daemon_name(const char *name)
1137 {
1138  name = pcmk_message_name(name);
1139  return (!strcmp(name, CRM_SYSTEM_CRMD)
1140  || !strcmp(name, CRM_SYSTEM_STONITHD)
1141  || !strcmp(name, "stonith-ng")
1142  || !strcmp(name, "attrd")
1143  || !strcmp(name, CRM_SYSTEM_CIB)
1144  || !strcmp(name, CRM_SYSTEM_MCP)
1145  || !strcmp(name, CRM_SYSTEM_DC)
1146  || !strcmp(name, CRM_SYSTEM_TENGINE)
1147  || !strcmp(name, CRM_SYSTEM_LRMD));
1148 }
1149 
1150 #include <md5.h>
1151 
1152 char *
1153 crm_md5sum(const char *buffer)
1154 {
1155  int lpc = 0, len = 0;
1156  char *digest = NULL;
1157  unsigned char raw_digest[MD5_DIGEST_SIZE];
1158 
1159  if (buffer == NULL) {
1160  buffer = "";
1161  }
1162  len = strlen(buffer);
1163 
1164  crm_trace("Beginning digest of %d bytes", len);
1165  digest = malloc(2 * MD5_DIGEST_SIZE + 1);
1166  if(digest) {
1167  md5_buffer(buffer, len, raw_digest);
1168  for (lpc = 0; lpc < MD5_DIGEST_SIZE; lpc++) {
1169  sprintf(digest + (2 * lpc), "%02x", raw_digest[lpc]);
1170  }
1171  digest[(2 * MD5_DIGEST_SIZE)] = 0;
1172  crm_trace("Digest %s.", digest);
1173 
1174  } else {
1175  crm_err("Could not create digest");
1176  }
1177  return digest;
1178 }
1179 
1180 #ifdef HAVE_GNUTLS_GNUTLS_H
1181 void
1182 crm_gnutls_global_init(void)
1183 {
1184  signal(SIGPIPE, SIG_IGN);
1185  gnutls_global_init();
1186 }
1187 #endif
1188 
1194 char *
1196 {
1197  struct utsname hostinfo;
1198 
1199  return (uname(&hostinfo) < 0)? NULL : strdup(hostinfo.nodename);
1200 }
Services API.
#define T_ATTRD
Definition: msg_xml.h:46
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:156
char uname[MAX_NAME]
Definition: internal.h:87
void crm_write_blackbox(int nsig, struct qb_log_callsite *callsite)
Definition: logging.c:457
A dumping ground.
void * find_library_function(void **handle, const char *lib, const char *fn, int fatal)
#define crm_notice(fmt, args...)
Definition: logging.h:242
const char * pcmk_strerror(int rc)
Definition: results.c:188
gboolean do_stderr
Definition: utils.c:531
void crm_enable_stderr(int enable)
Definition: logging.c:949
bool crm_is_daemon_name(const char *name)
Check whether a string represents a cluster daemon name.
Definition: utils.c:1136
#define crm_crit(fmt, args...)
Definition: logging.h:239
char * crm_generate_uuid(void)
Definition: utils.c:1078
#define CIB_CHANNEL_SHM
Definition: internal.h:71
int crm_lock_pidfile(const char *filename, const char *name)
Definition: pid.c:168
_Noreturn crm_exit_t crm_exit(crm_exit_t rc)
Definition: results.c:476
#define CIB_CHANNEL_RO
Definition: internal.h:69
struct crm_time_s crm_time_t
Definition: iso8601.h:32
#define crm_config_err(fmt...)
Definition: crm_internal.h:179
long long crm_int_helper(const char *text, char **end_text)
Definition: strings.c:34
int char2score(const char *score)
Definition: utils.c:199
long long crm_get_msec(const char *input)
Definition: utils.c:567
void crm_make_daemon(const char *name, gboolean daemonize, const char *pidfile)
Definition: utils.c:687
char * score2char_stack(int score, char *buf, size_t len)
Definition: utils.c:237
const char * crm_meta_value(GHashTable *hash, const char *field)
Definition: utils.c:756
void stonith_ipc_server_init(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb)
Definition: utils.c:1032
int crm_parse_int(const char *text, const char *default_text)
Parse an integer value from a string.
Definition: strings.c:110
crm_time_t * crm_time_parse_duration(const char *duration_str)
Definition: iso8601.c:816
char * crm_system_name
Definition: utils.c:61
enum crm_exit_e crm_exit_t
int crm_user_lookup(const char *name, uid_t *uid, gid_t *gid)
Definition: utils.c:402
uint32_t pid
Definition: internal.h:83
void crm_set_options(const char *short_options, const char *usage, struct crm_option *long_options, const char *app_desc)
Definition: utils.c:819
guint crm_parse_interval_spec(const char *input)
Definition: utils.c:542
gboolean check_number(const char *value)
Definition: utils.c:102
#define PACEMAKER_VERSION
Definition: config.h:514
#define CRM_SCORE_INFINITY
Definition: crm.h:59
Wrappers for and extensions to glib mainloop.
char * crm_meta_name(const char *field)
Definition: utils.c:734
#define CRM_SYSTEM_DC
Definition: crm.h:76
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:987
#define CRM_SYSTEM_MCP
Definition: crm.h:85
#define CRM_TRACE_INIT_DATA(name)
Definition: logging.h:111
gboolean crm_config_error
Definition: utils.c:59
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:344
#define PW_BUFFER_LEN
Definition: utils.c:54
#define crm_warn(fmt, args...)
Definition: logging.h:241
void crm_args_fini(void)
Definition: utils.c:192
const char * pcmk_message_name(const char *name)
Get name to be used as identifier for cluster messages.
Definition: utils.c:1100
Utility functions.
#define BUILD_VERSION
Definition: config.h:8
#define pcmk_option_example
Definition: crm_internal.h:59
gboolean check_quorum(const char *value)
Definition: utils.c:132
#define crm_trace(fmt, args...)
Definition: logging.h:246
#define pcmk_option_paragraph
Definition: crm_internal.h:58
#define CRM_SYSTEM_PENGINE
Definition: crm.h:82
#define NUMCHARS
Definition: utils.c:534
#define CRM_MINUS_INFINITY_S
Definition: crm.h:62
Wrappers for and extensions to libxml2.
ISO_8601 Date handling.
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:1004
gboolean check_positive_number(const char *value)
Definition: utils.c:123
long crm_pidfile_inuse(const char *filename, long mypid, const char *daemon)
Definition: pid.c:141
gboolean check_time(const char *value)
Definition: utils.c:73
gboolean check_boolean(const char *value)
Definition: utils.c:91
#define CIB_CHANNEL_RW
Definition: internal.h:70
#define EOS
Definition: crm.h:34
char * crm_itoa_stack(int an_int, char *buf, size_t len)
Definition: strings.c:24
int crm_get_option_long(int argc, char **argv, int *index, const char **longname)
Definition: utils.c:866
int * flag
Definition: crm_internal.h:71
#define WHITESPACE
Definition: utils.c:538
#define CRM_SYSTEM_CRMD
Definition: crm.h:80
long long int crm_time_get_seconds(crm_time_t *dt)
Definition: iso8601.c:255
#define crm_config_warn(fmt...)
Definition: crm_internal.h:180
void attrd_ipc_server_init(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb)
Definition: utils.c:1020
#define CRM_SYSTEM_STONITHD
Definition: crm.h:84
int crm_str_to_boolean(const char *s, int *ret)
Definition: strings.c:183
qb_ipcs_service_t * crmd_ipc_server_init(struct qb_ipcs_service_handlers *cb)
Definition: utils.c:1014
#define CRM_SYSTEM_CIB
Definition: crm.h:79
#define CRM_SYSTEM_TENGINE
Definition: crm.h:83
const char * cluster_option(GHashTable *options, gboolean(*validate)(const char *), const char *name, const char *old_name, const char *def_value)
Definition: utils.c:263
#define crm_perror(level, fmt, args...)
Log a system error message.
Definition: logging.h:218
gboolean check_script(const char *value)
Definition: utils.c:150
#define CRM_META
Definition: crm.h:49
#define crm_err(fmt, args...)
Definition: logging.h:240
#define CRM_ASSERT(expr)
Definition: results.h:42
#define CRM_INFINITY_S
Definition: crm.h:60
gboolean check_utilization(const char *value)
Definition: utils.c:177
gboolean crm_config_warning
Definition: utils.c:60
int compare_version(const char *version1, const char *version2)
Definition: utils.c:461
#define CRM_SYSTEM_LRMD
Definition: crm.h:81
int node_score_red
Definition: utils.c:63
void verify_all_options(GHashTable *options, pe_cluster_option *option_list, int len)
Definition: utils.c:379
#define pcmk_option_hidden
Definition: crm_internal.h:57
_Noreturn void crm_help(char cmd, crm_exit_t exit_code)
Definition: utils.c:911
#define pcmk_ok
Definition: results.h:57
#define MD5_DIGEST_SIZE
Definition: md5.h:30
void * md5_buffer(const char *buffer, size_t len, void *resblock)
Definition: md5.c:227
Wrappers for and extensions to libqb IPC.
char * generate_hash_key(const char *crm_msg_reference, const char *sys)
Definition: utils.c:392
#define PACKAGE_BUGREPORT
Definition: config.h:520
#define CRM_PLUS_INFINITY_S
Definition: crm.h:61
char * crm_md5sum(const char *buffer)
Definition: utils.c:1153
gboolean check_timer(const char *value)
Definition: utils.c:82
int crm_get_option(int argc, char **argv, int *index)
Definition: utils.c:860
bool crm_is_daemon
Definition: logging.c:40
char * pcmk_hostname(void)
Get the local hostname.
Definition: utils.c:1195
#define safe_str_eq(a, b)
Definition: util.h:59
int node_score_green
Definition: utils.c:64
qb_ipcs_service_t * mainloop_add_ipc_server(const char *name, enum qb_ipc_type type, struct qb_ipcs_service_handlers *callbacks)
Definition: mainloop.c:642
void crm_abort(const char *file, const char *function, int line, const char *condition, gboolean do_core, gboolean do_fork)
Definition: utils.c:625
const char * get_cluster_pref(GHashTable *options, pe_cluster_option *option_list, int len, const char *name)
Definition: utils.c:325
#define CRM_FEATURES
Definition: config.h:35
int node_score_yellow
Definition: utils.c:65
#define crm_info(fmt, args...)
Definition: logging.h:243
uint32_t version
Definition: remote.c:146
long crm_read_pidfile(const char *filename)
Definition: pid.c:103
uint64_t flags
Definition: remote.c:148
const char * name
Definition: crm_internal.h:64
enum crm_ais_msg_types type
Definition: internal.h:85
char * score2char(int score)
Definition: utils.c:251
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:101