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