pacemaker  2.1.8-3980678f03
Scalable High-Availability cluster resource manager
strings.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2024 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/common/results.h"
11 #include <crm_internal.h>
12 
13 #ifndef _GNU_SOURCE
14 # define _GNU_SOURCE
15 #endif
16 
17 #include <regex.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <ctype.h>
22 #include <float.h> // DBL_MIN
23 #include <limits.h>
24 #include <bzlib.h>
25 #include <sys/types.h>
26 
42 static int
43 scan_ll(const char *text, long long *result, long long default_value,
44  char **end_text)
45 {
46  long long local_result = default_value;
47  char *local_end_text = NULL;
48  int rc = pcmk_rc_ok;
49 
50  errno = 0;
51  if (text != NULL) {
52  local_result = strtoll(text, &local_end_text, 10);
53  if (errno == ERANGE) {
54  rc = EOVERFLOW;
55  crm_warn("Integer parsed from '%s' was clipped to %lld",
56  text, local_result);
57 
58  } else if (errno != 0) {
59  rc = errno;
60  local_result = default_value;
61  crm_warn("Could not parse integer from '%s' (using %lld instead): "
62  "%s", text, default_value, pcmk_rc_str(rc));
63 
64  } else if (local_end_text == text) {
65  rc = EINVAL;
66  local_result = default_value;
67  crm_warn("Could not parse integer from '%s' (using %lld instead): "
68  "No digits found", text, default_value);
69  }
70 
71  if ((end_text == NULL) && !pcmk__str_empty(local_end_text)) {
72  crm_warn("Characters left over after parsing '%s': '%s'",
73  text, local_end_text);
74  }
75  errno = rc;
76  }
77  if (end_text != NULL) {
78  *end_text = local_end_text;
79  }
80  if (result != NULL) {
81  *result = local_result;
82  }
83  return rc;
84 }
85 
96 int
97 pcmk__scan_ll(const char *text, long long *result, long long default_value)
98 {
99  long long local_result = default_value;
100  int rc = pcmk_rc_ok;
101 
102  if (text != NULL) {
103  rc = scan_ll(text, &local_result, default_value, NULL);
104  if (rc != pcmk_rc_ok) {
105  local_result = default_value;
106  }
107  }
108  if (result != NULL) {
109  *result = local_result;
110  }
111  return rc;
112 }
113 
126 int
127 pcmk__scan_min_int(const char *text, int *result, int minimum)
128 {
129  int rc;
130  long long result_ll;
131 
132  rc = pcmk__scan_ll(text, &result_ll, (long long) minimum);
133 
134  if (result_ll < (long long) minimum) {
135  crm_warn("Clipped '%s' to minimum acceptable value %d", text, minimum);
136  result_ll = (long long) minimum;
137 
138  } else if (result_ll > INT_MAX) {
139  crm_warn("Clipped '%s' to maximum integer %d", text, INT_MAX);
140  result_ll = (long long) INT_MAX;
141  rc = EOVERFLOW;
142  }
143 
144  if (result != NULL) {
145  *result = (int) result_ll;
146  }
147  return rc;
148 }
149 
160 int
161 pcmk__scan_port(const char *text, int *port)
162 {
163  long long port_ll;
164  int rc = pcmk__scan_ll(text, &port_ll, -1LL);
165 
166  if ((text != NULL) && (rc == pcmk_rc_ok) // wasn't default or invalid
167  && ((port_ll < 0LL) || (port_ll > 65535LL))) {
168  crm_warn("Ignoring port specification '%s' "
169  "not in valid range (0-65535)", text);
170  rc = (port_ll < 0LL)? pcmk_rc_before_range : pcmk_rc_after_range;
171  port_ll = -1LL;
172  }
173  if (port != NULL) {
174  *port = (int) port_ll;
175  }
176  return rc;
177 }
178 
198 int
199 pcmk__scan_double(const char *text, double *result, const char *default_text,
200  char **end_text)
201 {
202  int rc = pcmk_rc_ok;
203  char *local_end_text = NULL;
204 
205  CRM_ASSERT(result != NULL);
207 
208  text = (text != NULL) ? text : default_text;
209 
210  if (text == NULL) {
211  rc = EINVAL;
212  crm_debug("No text and no default conversion value supplied");
213 
214  } else {
215  errno = 0;
216  *result = strtod(text, &local_end_text);
217 
218  if (errno == ERANGE) {
219  /*
220  * Overflow: strtod() returns +/- HUGE_VAL and sets errno to
221  * ERANGE
222  *
223  * Underflow: strtod() returns "a value whose magnitude is
224  * no greater than the smallest normalized
225  * positive" double. Whether ERANGE is set is
226  * implementation-defined.
227  */
228  const char *over_under;
229 
230  if (QB_ABS(*result) > DBL_MIN) {
231  rc = EOVERFLOW;
232  over_under = "over";
233  } else {
234  rc = pcmk_rc_underflow;
235  over_under = "under";
236  }
237 
238  crm_debug("Floating-point value parsed from '%s' would %sflow "
239  "(using %g instead)", text, over_under, *result);
240 
241  } else if (errno != 0) {
242  rc = errno;
243  // strtod() set *result = 0 on parse failure
245 
246  crm_debug("Could not parse floating-point value from '%s' (using "
247  "%.1f instead): %s", text, PCMK__PARSE_DBL_DEFAULT,
248  pcmk_rc_str(rc));
249 
250  } else if (local_end_text == text) {
251  // errno == 0, but nothing was parsed
252  rc = EINVAL;
254 
255  crm_debug("Could not parse floating-point value from '%s' (using "
256  "%.1f instead): No digits found", text,
258 
259  } else if (QB_ABS(*result) <= DBL_MIN) {
260  /*
261  * errno == 0 and text was parsed, but value might have
262  * underflowed.
263  *
264  * ERANGE might not be set for underflow. Check magnitude
265  * of *result, but also make sure the input number is not
266  * actually zero (0 <= DBL_MIN is not underflow).
267  *
268  * This check must come last. A parse failure in strtod()
269  * also sets *result == 0, so a parse failure would match
270  * this test condition prematurely.
271  */
272  for (const char *p = text; p != local_end_text; p++) {
273  if (strchr("0.eE", *p) == NULL) {
274  rc = pcmk_rc_underflow;
275  crm_debug("Floating-point value parsed from '%s' would "
276  "underflow (using %g instead)", text, *result);
277  break;
278  }
279  }
280 
281  } else {
282  crm_trace("Floating-point value parsed successfully from "
283  "'%s': %g", text, *result);
284  }
285 
286  if ((end_text == NULL) && !pcmk__str_empty(local_end_text)) {
287  crm_debug("Characters left over after parsing '%s': '%s'",
288  text, local_end_text);
289  }
290  }
291 
292  if (end_text != NULL) {
293  *end_text = local_end_text;
294  }
295 
296  return rc;
297 }
298 
310 int
311 pcmk__guint_from_hash(GHashTable *table, const char *key, guint default_val,
312  guint *result)
313 {
314  const char *value;
315  long long value_ll;
316  int rc = pcmk_rc_ok;
317 
318  CRM_CHECK((table != NULL) && (key != NULL), return EINVAL);
319 
320  if (result != NULL) {
321  *result = default_val;
322  }
323 
324  value = g_hash_table_lookup(table, key);
325  if (value == NULL) {
326  return pcmk_rc_ok;
327  }
328 
329  rc = pcmk__scan_ll(value, &value_ll, 0LL);
330  if (rc != pcmk_rc_ok) {
331  return rc;
332  }
333 
334  if ((value_ll < 0) || (value_ll > G_MAXUINT)) {
335  crm_warn("Could not parse non-negative integer from %s", value);
336  return ERANGE;
337  }
338 
339  if (result != NULL) {
340  *result = (guint) value_ll;
341  }
342  return pcmk_rc_ok;
343 }
344 
355 long long
356 crm_get_msec(const char *input)
357 {
358  char *units = NULL; // Do not free; will point to part of input
359  long long multiplier = 1000;
360  long long divisor = 1;
361  long long msec = PCMK__PARSE_INT_DEFAULT;
362 
363  if (input == NULL) {
365  }
366 
367  // Skip initial whitespace
368  while (isspace(*input)) {
369  input++;
370  }
371 
372  // Reject negative and unparsable inputs
373  scan_ll(input, &msec, -1, &units);
374  if (msec < 0) {
376  }
377 
378  /* If the number is a decimal, scan_ll() reads only the integer part. Skip
379  * any remaining digits or decimal characters.
380  *
381  * @COMPAT Well-formed and malformed decimals are both accepted inputs. For
382  * example, "3.14 ms" and "3.1.4 ms" are treated the same as "3ms" and
383  * parsed successfully. At a compatibility break, decide if this is still
384  * desired.
385  */
386  while (isdigit(*units) || (*units == '.')) {
387  units++;
388  }
389 
390  // Skip any additional whitespace after the number
391  while (isspace(*units)) {
392  units++;
393  }
394 
395  /* @COMPAT Use exact comparisons. Currently, we match too liberally, and the
396  * second strncasecmp() in each case is redundant.
397  */
398  if ((*units == '\0')
399  || (strncasecmp(units, "s", 1) == 0)
400  || (strncasecmp(units, "sec", 3) == 0)) {
401  multiplier = 1000;
402  divisor = 1;
403 
404  } else if ((strncasecmp(units, "ms", 2) == 0)
405  || (strncasecmp(units, "msec", 4) == 0)) {
406  multiplier = 1;
407  divisor = 1;
408 
409  } else if ((strncasecmp(units, "us", 2) == 0)
410  || (strncasecmp(units, "usec", 4) == 0)) {
411  multiplier = 1;
412  divisor = 1000;
413 
414  } else if ((strncasecmp(units, "m", 1) == 0)
415  || (strncasecmp(units, "min", 3) == 0)) {
416  multiplier = 60 * 1000;
417  divisor = 1;
418 
419  } else if ((strncasecmp(units, "h", 1) == 0)
420  || (strncasecmp(units, "hr", 2) == 0)) {
421  multiplier = 60 * 60 * 1000;
422  divisor = 1;
423 
424  } else {
425  // Invalid units
427  }
428 
429  // Apply units, capping at LLONG_MAX
430  if (msec > (LLONG_MAX / multiplier)) {
431  return LLONG_MAX;
432  }
433  return (msec * multiplier) / divisor;
434 }
435 
450 int
451 pcmk_parse_interval_spec(const char *input, guint *result_ms)
452 {
453  long long msec = PCMK__PARSE_INT_DEFAULT;
454  int rc = pcmk_rc_ok;
455 
456  if (input == NULL) {
457  msec = 0;
458  goto done;
459  }
460 
461  if (input[0] == 'P') {
463 
464  if (period_s != NULL) {
465  msec = 1000 * crm_time_get_seconds(period_s);
466  crm_time_free(period_s);
467  }
468 
469  } else {
470  msec = crm_get_msec(input);
471  }
472 
473  if (msec == PCMK__PARSE_INT_DEFAULT) {
474  crm_warn("Using 0 instead of invalid interval specification '%s'",
475  input);
476  msec = 0;
477  rc = EINVAL;
478  }
479 
480 done:
481  if (result_ms != NULL) {
482  *result_ms = (msec >= G_MAXUINT)? G_MAXUINT : (guint) msec;
483  }
484  return rc;
485 }
486 
487 gboolean
488 crm_is_true(const char *s)
489 {
490  gboolean ret = FALSE;
491 
492  return (crm_str_to_boolean(s, &ret) < 0)? FALSE : ret;
493 }
494 
495 int
496 crm_str_to_boolean(const char *s, int *ret)
497 {
498  if (s == NULL) {
499  return -1;
500  }
501 
502  if (pcmk__strcase_any_of(s, PCMK_VALUE_TRUE, "on", "yes", "y", "1", NULL)) {
503  if (ret != NULL) {
504  *ret = TRUE;
505  }
506  return 1;
507  }
508 
509  if (pcmk__strcase_any_of(s, PCMK_VALUE_FALSE, "off", "no", "n", "0",
510  NULL)) {
511  if (ret != NULL) {
512  *ret = FALSE;
513  }
514  return 1;
515  }
516  return -1;
517 }
518 
527 char *
528 pcmk__trim(char *str)
529 {
530  int len;
531 
532  if (str == NULL) {
533  return str;
534  }
535 
536  for (len = strlen(str) - 1; len >= 0 && str[len] == '\n'; len--) {
537  str[len] = '\0';
538  }
539 
540  return str;
541 }
542 
555 bool
556 pcmk__starts_with(const char *str, const char *prefix)
557 {
558  const char *s = str;
559  const char *p = prefix;
560 
561  if (!s || !p) {
562  return false;
563  }
564  while (*s && *p) {
565  if (*s++ != *p++) {
566  return false;
567  }
568  }
569  return (*p == 0);
570 }
571 
572 static inline bool
573 ends_with(const char *s, const char *match, bool as_extension)
574 {
575  if (pcmk__str_empty(match)) {
576  return true;
577  } else if (s == NULL) {
578  return false;
579  } else {
580  size_t slen, mlen;
581 
582  /* Besides as_extension, we could also check
583  !strchr(&match[1], match[0]) but that would be inefficient.
584  */
585  if (as_extension) {
586  s = strrchr(s, match[0]);
587  return (s == NULL)? false : !strcmp(s, match);
588  }
589 
590  mlen = strlen(match);
591  slen = strlen(s);
592  return ((slen >= mlen) && !strcmp(s + slen - mlen, match));
593  }
594 }
595 
607 bool
608 pcmk__ends_with(const char *s, const char *match)
609 {
610  return ends_with(s, match, false);
611 }
612 
634 bool
635 pcmk__ends_with_ext(const char *s, const char *match)
636 {
637  return ends_with(s, match, true);
638 }
639 
659 static guint
660 pcmk__str_hash(gconstpointer v)
661 {
662  const signed char *p;
663  guint32 h = 0;
664 
665  for (p = v; *p != '\0'; p++)
666  h = (h << 5) - h + *p;
667 
668  return h;
669 }
670 
682 GHashTable *
683 pcmk__strkey_table(GDestroyNotify key_destroy_func,
684  GDestroyNotify value_destroy_func)
685 {
686  return g_hash_table_new_full(pcmk__str_hash, g_str_equal,
687  key_destroy_func, value_destroy_func);
688 }
689 
700 void
701 pcmk__insert_dup(GHashTable *table, const char *name, const char *value)
702 {
703  CRM_ASSERT((table != NULL) && (name != NULL));
704 
705  g_hash_table_insert(table, pcmk__str_copy(name), pcmk__str_copy(value));
706 }
707 
708 /* used with hash tables where case does not matter */
709 static gboolean
710 pcmk__strcase_equal(gconstpointer a, gconstpointer b)
711 {
712  return pcmk__str_eq((const char *)a, (const char *)b, pcmk__str_casei);
713 }
714 
715 static guint
716 pcmk__strcase_hash(gconstpointer v)
717 {
718  const signed char *p;
719  guint32 h = 0;
720 
721  for (p = v; *p != '\0'; p++)
722  h = (h << 5) - h + g_ascii_tolower(*p);
723 
724  return h;
725 }
726 
738 GHashTable *
739 pcmk__strikey_table(GDestroyNotify key_destroy_func,
740  GDestroyNotify value_destroy_func)
741 {
742  return g_hash_table_new_full(pcmk__strcase_hash, pcmk__strcase_equal,
743  key_destroy_func, value_destroy_func);
744 }
745 
746 static void
747 copy_str_table_entry(gpointer key, gpointer value, gpointer user_data)
748 {
749  if (key && value && user_data) {
750  pcmk__insert_dup((GHashTable *) user_data,
751  (const char *) key, (const char *) value);
752  }
753 }
754 
765 GHashTable *
766 pcmk__str_table_dup(GHashTable *old_table)
767 {
768  GHashTable *new_table = NULL;
769 
770  if (old_table) {
771  new_table = pcmk__strkey_table(free, free);
772  g_hash_table_foreach(old_table, copy_str_table_entry, new_table);
773  }
774  return new_table;
775 }
776 
793 void
794 pcmk__add_separated_word(GString **list, size_t init_size, const char *word,
795  const char *separator)
796 {
797  CRM_ASSERT(list != NULL);
798 
799  if (pcmk__str_empty(word)) {
800  return;
801  }
802 
803  if (*list == NULL) {
804  if (init_size > 0) {
805  *list = g_string_sized_new(init_size);
806  } else {
807  *list = g_string_new(NULL);
808  }
809  }
810 
811  if ((*list)->len == 0) {
812  // Don't add a separator before the first word in the list
813  separator = "";
814 
815  } else if (separator == NULL) {
816  // Default to space-separated
817  separator = " ";
818  }
819 
820  g_string_append(*list, separator);
821  g_string_append(*list, word);
822 }
823 
836 int
837 pcmk__compress(const char *data, unsigned int length, unsigned int max,
838  char **result, unsigned int *result_len)
839 {
840  int rc;
841  char *compressed = NULL;
842  char *uncompressed = strdup(data);
843 #ifdef CLOCK_MONOTONIC
844  struct timespec after_t;
845  struct timespec before_t;
846 #endif
847 
848  if (max == 0) {
849  max = (length * 1.01) + 601; // Size guaranteed to hold result
850  }
851 
852 #ifdef CLOCK_MONOTONIC
853  clock_gettime(CLOCK_MONOTONIC, &before_t);
854 #endif
855 
856  compressed = pcmk__assert_alloc((size_t) max, sizeof(char));
857 
858  *result_len = max;
859  rc = BZ2_bzBuffToBuffCompress(compressed, result_len, uncompressed, length,
861  rc = pcmk__bzlib2rc(rc);
862 
863  free(uncompressed);
864 
865  if (rc != pcmk_rc_ok) {
866  crm_err("Compression of %d bytes failed: %s " CRM_XS " rc=%d",
867  length, pcmk_rc_str(rc), rc);
868  free(compressed);
869  return rc;
870  }
871 
872 #ifdef CLOCK_MONOTONIC
873  clock_gettime(CLOCK_MONOTONIC, &after_t);
874 
875  crm_trace("Compressed %d bytes into %d (ratio %d:1) in %.0fms",
876  length, *result_len, length / (*result_len),
877  (after_t.tv_sec - before_t.tv_sec) * 1000 +
878  (after_t.tv_nsec - before_t.tv_nsec) / 1e6);
879 #else
880  crm_trace("Compressed %d bytes into %d (ratio %d:1)",
881  length, *result_len, length / (*result_len));
882 #endif
883 
884  *result = compressed;
885  return pcmk_rc_ok;
886 }
887 
888 char *
889 crm_strdup_printf(char const *format, ...)
890 {
891  va_list ap;
892  int len = 0;
893  char *string = NULL;
894 
895  va_start(ap, format);
896  len = vasprintf (&string, format, ap);
897  CRM_ASSERT(len > 0);
898  va_end(ap);
899  return string;
900 }
901 
902 int
903 pcmk__parse_ll_range(const char *srcstring, long long *start, long long *end)
904 {
905  char *remainder = NULL;
906  int rc = pcmk_rc_ok;
907 
908  CRM_ASSERT(start != NULL && end != NULL);
909 
910  *start = PCMK__PARSE_INT_DEFAULT;
912 
913  crm_trace("Attempting to decode: [%s]", srcstring);
914  if (pcmk__str_eq(srcstring, "", pcmk__str_null_matches)) {
915  return ENODATA;
916  } else if (pcmk__str_eq(srcstring, "-", pcmk__str_none)) {
917  return pcmk_rc_bad_input;
918  }
919 
920  /* String starts with a dash, so this is either a range with
921  * no beginning or garbage.
922  * */
923  if (*srcstring == '-') {
924  int rc = scan_ll(srcstring+1, end, PCMK__PARSE_INT_DEFAULT, &remainder);
925 
926  if (rc != pcmk_rc_ok || *remainder != '\0') {
927  return pcmk_rc_bad_input;
928  } else {
929  return pcmk_rc_ok;
930  }
931  }
932 
933  rc = scan_ll(srcstring, start, PCMK__PARSE_INT_DEFAULT, &remainder);
934  if (rc != pcmk_rc_ok) {
935  return rc;
936  }
937 
938  if (*remainder && *remainder == '-') {
939  if (*(remainder+1)) {
940  char *more_remainder = NULL;
941  int rc = scan_ll(remainder+1, end, PCMK__PARSE_INT_DEFAULT,
942  &more_remainder);
943 
944  if (rc != pcmk_rc_ok) {
945  return rc;
946  } else if (*more_remainder != '\0') {
947  return pcmk_rc_bad_input;
948  }
949  }
950  } else if (*remainder && *remainder != '-') {
951  *start = PCMK__PARSE_INT_DEFAULT;
952  return pcmk_rc_bad_input;
953  } else {
954  /* The input string contained only one number. Set start and end
955  * to the same value and return pcmk_rc_ok. This gives the caller
956  * a way to tell this condition apart from a range with no end.
957  */
958  *end = *start;
959  }
960 
961  return pcmk_rc_ok;
962 }
963 
980 gboolean
981 pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
982 {
983  for (const GList *ele = lst; ele != NULL; ele = ele->next) {
984  if (pcmk__str_eq(s, ele->data, flags)) {
985  return TRUE;
986  }
987  }
988 
989  return FALSE;
990 }
991 
992 static bool
993 str_any_of(const char *s, va_list args, uint32_t flags)
994 {
995  if (s == NULL) {
997  }
998 
999  while (1) {
1000  const char *ele = va_arg(args, const char *);
1001 
1002  if (ele == NULL) {
1003  break;
1004  } else if (pcmk__str_eq(s, ele, flags)) {
1005  return true;
1006  }
1007  }
1008 
1009  return false;
1010 }
1011 
1025 bool
1026 pcmk__strcase_any_of(const char *s, ...)
1027 {
1028  va_list ap;
1029  bool rc;
1030 
1031  va_start(ap, s);
1032  rc = str_any_of(s, ap, pcmk__str_casei);
1033  va_end(ap);
1034  return rc;
1035 }
1036 
1049 bool
1050 pcmk__str_any_of(const char *s, ...)
1051 {
1052  va_list ap;
1053  bool rc;
1054 
1055  va_start(ap, s);
1056  rc = str_any_of(s, ap, pcmk__str_none);
1057  va_end(ap);
1058  return rc;
1059 }
1060 
1077 int
1078 pcmk__numeric_strcasecmp(const char *s1, const char *s2)
1079 {
1080  CRM_ASSERT((s1 != NULL) && (s2 != NULL));
1081 
1082  while (*s1 && *s2) {
1083  if (isdigit(*s1) && isdigit(*s2)) {
1084  // If node names contain a number, sort numerically
1085 
1086  char *end1 = NULL;
1087  char *end2 = NULL;
1088  long num1 = strtol(s1, &end1, 10);
1089  long num2 = strtol(s2, &end2, 10);
1090 
1091  // allow ordering e.g. 007 > 7
1092  size_t len1 = end1 - s1;
1093  size_t len2 = end2 - s2;
1094 
1095  if (num1 < num2) {
1096  return -1;
1097  } else if (num1 > num2) {
1098  return 1;
1099  } else if (len1 < len2) {
1100  return -1;
1101  } else if (len1 > len2) {
1102  return 1;
1103  }
1104  s1 = end1;
1105  s2 = end2;
1106  } else {
1107  // Compare non-digits case-insensitively
1108  int lower1 = tolower(*s1);
1109  int lower2 = tolower(*s2);
1110 
1111  if (lower1 < lower2) {
1112  return -1;
1113  } else if (lower1 > lower2) {
1114  return 1;
1115  }
1116  ++s1;
1117  ++s2;
1118  }
1119  }
1120  if (!*s1 && *s2) {
1121  return -1;
1122  } else if (*s1 && !*s2) {
1123  return 1;
1124  }
1125  return 0;
1126 }
1127 
1162 int
1163 pcmk__strcmp(const char *s1, const char *s2, uint32_t flags)
1164 {
1165  /* If this flag is set, the second string is a regex. */
1167  regex_t r_patt;
1168  int reg_flags = REG_EXTENDED | REG_NOSUB;
1169  int regcomp_rc = 0;
1170  int rc = 0;
1171 
1172  if (s1 == NULL || s2 == NULL) {
1173  return 1;
1174  }
1175 
1177  reg_flags |= REG_ICASE;
1178  }
1179  regcomp_rc = regcomp(&r_patt, s2, reg_flags);
1180  if (regcomp_rc != 0) {
1181  rc = 1;
1182  crm_err("Bad regex '%s' for update: %s", s2, strerror(regcomp_rc));
1183  } else {
1184  rc = regexec(&r_patt, s1, 0, NULL, 0);
1185  regfree(&r_patt);
1186  if (rc != 0) {
1187  rc = 1;
1188  }
1189  }
1190  return rc;
1191  }
1192 
1193  /* If the strings are the same pointer, return 0 immediately. */
1194  if (s1 == s2) {
1195  return 0;
1196  }
1197 
1198  /* If this flag is set, return 0 if either (or both) of the input strings
1199  * are NULL. If neither one is NULL, we need to continue and compare
1200  * them normally.
1201  */
1203  if (s1 == NULL || s2 == NULL) {
1204  return 0;
1205  }
1206  }
1207 
1208  /* Handle the cases where one is NULL and the str_null_matches flag is not set.
1209  * A NULL string always sorts to the beginning.
1210  */
1211  if (s1 == NULL) {
1212  return -1;
1213  } else if (s2 == NULL) {
1214  return 1;
1215  }
1216 
1217  /* If this flag is set, return 0 if either (or both) of the input strings
1218  * are "*". If neither one is, we need to continue and compare them
1219  * normally.
1220  */
1222  if (strcmp(s1, "*") == 0 || strcmp(s2, "*") == 0) {
1223  return 0;
1224  }
1225  }
1226 
1228  return strcasecmp(s1, s2);
1229  } else {
1230  return strcmp(s1, s2);
1231  }
1232 }
1233 
1247 char *
1248 pcmk__str_copy_as(const char *file, const char *function, uint32_t line,
1249  const char *str)
1250 {
1251  if (str != NULL) {
1252  char *result = strdup(str);
1253 
1254  if (result == NULL) {
1255  crm_abort(file, function, line, "Out of memory", FALSE, TRUE);
1257  }
1258  return result;
1259  }
1260  return NULL;
1261 }
1262 
1276 void
1277 pcmk__str_update(char **str, const char *value)
1278 {
1279  if ((str != NULL) && !pcmk__str_eq(*str, value, pcmk__str_none)) {
1280  free(*str);
1281  *str = pcmk__str_copy(value);
1282  }
1283 }
1284 
1295 void
1296 pcmk__g_strcat(GString *buffer, ...)
1297 {
1298  va_list ap;
1299 
1300  CRM_ASSERT(buffer != NULL);
1301  va_start(ap, buffer);
1302 
1303  while (true) {
1304  const char *ele = va_arg(ap, const char *);
1305 
1306  if (ele == NULL) {
1307  break;
1308  }
1309  g_string_append(buffer, ele);
1310  }
1311  va_end(ap);
1312 }
1313 
1314 // Deprecated functions kept only for backward API compatibility
1315 // LCOV_EXCL_START
1316 
1317 #include <crm/common/util_compat.h>
1318 
1319 gboolean
1320 safe_str_neq(const char *a, const char *b)
1321 {
1322  if (a == b) {
1323  return FALSE;
1324 
1325  } else if (a == NULL || b == NULL) {
1326  return TRUE;
1327 
1328  } else if (strcasecmp(a, b) == 0) {
1329  return FALSE;
1330  }
1331  return TRUE;
1332 }
1333 
1334 gboolean
1335 crm_str_eq(const char *a, const char *b, gboolean use_case)
1336 {
1337  if (use_case) {
1338  return g_strcmp0(a, b) == 0;
1339 
1340  /* TODO - Figure out which calls, if any, really need to be case independent */
1341  } else if (a == b) {
1342  return TRUE;
1343 
1344  } else if (a == NULL || b == NULL) {
1345  /* shouldn't be comparing NULLs */
1346  return FALSE;
1347 
1348  } else if (strcasecmp(a, b) == 0) {
1349  return TRUE;
1350  }
1351  return FALSE;
1352 }
1353 
1354 char *
1355 crm_itoa_stack(int an_int, char *buffer, size_t len)
1356 {
1357  if (buffer != NULL) {
1358  snprintf(buffer, len, "%d", an_int);
1359  }
1360  return buffer;
1361 }
1362 
1363 guint
1364 g_str_hash_traditional(gconstpointer v)
1365 {
1366  return pcmk__str_hash(v);
1367 }
1368 
1369 gboolean
1370 crm_strcase_equal(gconstpointer a, gconstpointer b)
1371 {
1372  return pcmk__strcase_equal(a, b);
1373 }
1374 
1375 guint
1376 crm_strcase_hash(gconstpointer v)
1377 {
1378  return pcmk__strcase_hash(v);
1379 }
1380 
1381 GHashTable *
1382 crm_str_table_dup(GHashTable *old_table)
1383 {
1384  return pcmk__str_table_dup(old_table);
1385 }
1386 
1387 long long
1388 crm_parse_ll(const char *text, const char *default_text)
1389 {
1390  long long result;
1391 
1392  if (text == NULL) {
1393  text = default_text;
1394  if (text == NULL) {
1395  crm_err("No default conversion value supplied");
1396  errno = EINVAL;
1397  return PCMK__PARSE_INT_DEFAULT;
1398  }
1399  }
1400  scan_ll(text, &result, PCMK__PARSE_INT_DEFAULT, NULL);
1401  return result;
1402 }
1403 
1404 int
1405 crm_parse_int(const char *text, const char *default_text)
1406 {
1407  long long result = crm_parse_ll(text, default_text);
1408 
1409  if (result < INT_MIN) {
1410  // If errno is ERANGE, crm_parse_ll() has already logged a message
1411  if (errno != ERANGE) {
1412  crm_err("Conversion of %s was clipped: %lld", text, result);
1413  errno = ERANGE;
1414  }
1415  return INT_MIN;
1416 
1417  } else if (result > INT_MAX) {
1418  // If errno is ERANGE, crm_parse_ll() has already logged a message
1419  if (errno != ERANGE) {
1420  crm_err("Conversion of %s was clipped: %lld", text, result);
1421  errno = ERANGE;
1422  }
1423  return INT_MAX;
1424  }
1425 
1426  return (int) result;
1427 }
1428 
1429 char *
1431 {
1432  return pcmk__trim(str);
1433 }
1434 
1435 int
1436 pcmk_numeric_strcasecmp(const char *s1, const char *s2)
1437 {
1438  return pcmk__numeric_strcasecmp(s1, s2);
1439 }
1440 
1441 // LCOV_EXCL_STOP
1442 // End deprecated API
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:245
bool pcmk__starts_with(const char *str, const char *prefix)
Check whether a string starts with a certain sequence.
Definition: strings.c:556
char data[0]
Definition: cpg.c:58
char * crm_strdup_printf(char const *format,...)
Definition: strings.c:889
_Noreturn crm_exit_t crm_exit(crm_exit_t rc)
Definition: results.c:936
#define PCMK_VALUE_FALSE
Definition: options.h:152
int pcmk_numeric_strcasecmp(const char *s1, const char *s2)
Definition: strings.c:1436
const char * name
Definition: cib.c:26
struct crm_time_s crm_time_t
Definition: iso8601.h:32
guint g_str_hash_traditional(gconstpointer v)
Definition: strings.c:1364
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:683
#define PCMK__PARSE_DBL_DEFAULT
int pcmk__scan_port(const char *text, int *port)
Definition: strings.c:161
int pcmk__scan_ll(const char *text, long long *result, long long default_value)
Definition: strings.c:97
int pcmk__numeric_strcasecmp(const char *s1, const char *s2)
Definition: strings.c:1078
bool pcmk__str_any_of(const char *s,...)
Definition: strings.c:1050
crm_time_t * crm_time_parse_duration(const char *duration_str)
Parse a time duration from an ISO 8601 duration specification.
Definition: iso8601.c:1086
int pcmk__scan_double(const char *text, double *result, const char *default_text, char **end_text)
Definition: strings.c:199
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:501
void pcmk__str_update(char **str, const char *value)
Definition: strings.c:1277
#define PCMK__PARSE_INT_DEFAULT
#define crm_warn(fmt, args...)
Definition: logging.h:394
int pcmk__guint_from_hash(GHashTable *table, const char *key, guint default_val, guint *result)
Definition: strings.c:311
#define crm_debug(fmt, args...)
Definition: logging.h:402
void pcmk__add_separated_word(GString **list, size_t init_size, const char *word, const char *separator)
Definition: strings.c:794
int pcmk__parse_ll_range(const char *srcstring, long long *start, long long *end)
Definition: strings.c:903
External (OS/environmental) problem.
Definition: results.h:276
int pcmk__compress(const char *data, unsigned int length, unsigned int max, char **result, unsigned int *result_len)
Definition: strings.c:837
#define crm_trace(fmt, args...)
Definition: logging.h:404
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:98
void pcmk__insert_dup(GHashTable *table, const char *name, const char *value)
Definition: strings.c:701
long long crm_get_msec(const char *input)
Parse a time+units string and return milliseconds equivalent.
Definition: strings.c:356
#define PCMK_VALUE_TRUE
Definition: options.h:215
int pcmk__scan_min_int(const char *text, int *result, int minimum)
Definition: strings.c:127
GHashTable * pcmk__str_table_dup(GHashTable *old_table)
Definition: strings.c:766
int pcmk_parse_interval_spec(const char *input, guint *result_ms)
Parse milliseconds from a Pacemaker interval specification.
Definition: strings.c:451
long long crm_time_get_seconds(const crm_time_t *dt)
Definition: iso8601.c:316
char * crm_itoa_stack(int an_int, char *buffer, size_t len)
Definition: strings.c:1355
#define pcmk__str_copy(str)
Function and executable result codes.
int crm_str_to_boolean(const char *s, int *ret)
Definition: strings.c:496
#define CRM_XS
Definition: logging.h:56
char * crm_strip_trailing_newline(char *str)
Definition: strings.c:1430
int pcmk__strcmp(const char *s1, const char *s2, uint32_t flags)
Definition: strings.c:1163
GHashTable * pcmk__strikey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:739
#define CRM_BZ2_BLOCKS
Definition: xml_io.h:33
gboolean crm_is_true(const char *s)
Definition: strings.c:488
bool pcmk__ends_with_ext(const char *s, const char *match)
Definition: strings.c:635
int pcmk__bzlib2rc(int bz2)
Map a bz2 return code to the most similar Pacemaker return code.
Definition: results.c:906
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
Definition: strings.c:1335
int crm_parse_int(const char *text, const char *default_text)
Definition: strings.c:1405
#define ENODATA
Definition: portability.h:106
long long crm_parse_ll(const char *text, const char *default_text)
Definition: strings.c:1388
pcmk__action_result_t result
Definition: pcmk_fence.c:35
#define crm_err(fmt, args...)
Definition: logging.h:391
#define CRM_ASSERT(expr)
Definition: results.h:42
Deprecated Pacemaker utilities.
xmlNode * input
gboolean crm_strcase_equal(gconstpointer a, gconstpointer b)
Definition: strings.c:1370
void pcmk__g_strcat(GString *buffer,...)
Definition: strings.c:1296
char * pcmk__str_copy_as(const char *file, const char *function, uint32_t line, const char *str)
Definition: strings.c:1248
gboolean pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
Definition: strings.c:981
gboolean safe_str_neq(const char *a, const char *b)
Definition: strings.c:1320
guint crm_strcase_hash(gconstpointer v)
Definition: strings.c:1376
GHashTable * crm_str_table_dup(GHashTable *old_table)
Definition: strings.c:1382
char * pcmk__trim(char *str)
Definition: strings.c:528
void crm_abort(const char *file, const char *function, int line, const char *condition, gboolean do_core, gboolean do_fork)
Definition: utils.c:356
#define pcmk__assert_alloc(nmemb, size)
Definition: internal.h:297
#define CRM_BZ2_WORK
Definition: xml_io.h:34
bool pcmk__ends_with(const char *s, const char *match)
Definition: strings.c:608
uint64_t flags
Definition: remote.c:215
bool pcmk__strcase_any_of(const char *s,...)
Definition: strings.c:1026
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:150