pacemaker  3.0.0-d8340737c4
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_internal.h>
11 
12 #include <regex.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <stdlib.h>
16 #include <ctype.h>
17 #include <float.h> // DBL_MIN
18 #include <limits.h>
19 #include <bzlib.h>
20 #include <sys/types.h>
21 
37 static int
38 scan_ll(const char *text, long long *result, long long default_value,
39  char **end_text)
40 {
41  long long local_result = default_value;
42  char *local_end_text = NULL;
43  int rc = pcmk_rc_ok;
44 
45  errno = 0;
46  if (text != NULL) {
47  local_result = strtoll(text, &local_end_text, 10);
48  if (errno == ERANGE) {
49  rc = errno;
50  crm_debug("Integer parsed from '%s' was clipped to %lld",
51  text, local_result);
52 
53  } else if (local_end_text == text) {
54  rc = pcmk_rc_bad_input;
55  local_result = default_value;
56  crm_debug("Could not parse integer from '%s' (using %lld instead): "
57  "No digits found", text, default_value);
58 
59  } else if (errno != 0) {
60  rc = errno;
61  local_result = default_value;
62  crm_debug("Could not parse integer from '%s' (using %lld instead): "
63  "%s", text, default_value, pcmk_rc_str(rc));
64  }
65 
66  if ((end_text == NULL) && !pcmk__str_empty(local_end_text)) {
67  crm_debug("Characters left over after parsing '%s': '%s'",
68  text, local_end_text);
69  }
70  errno = rc;
71  }
72  if (end_text != NULL) {
73  *end_text = local_end_text;
74  }
75  if (result != NULL) {
76  *result = local_result;
77  }
78  return rc;
79 }
80 
91 int
92 pcmk__scan_ll(const char *text, long long *result, long long default_value)
93 {
94  long long local_result = default_value;
95  int rc = scan_ll(text, &local_result, default_value, NULL);
96 
97  if (result != NULL) {
98  *result = local_result;
99  }
100  return rc;
101 }
102 
115 int
116 pcmk__scan_min_int(const char *text, int *result, int minimum)
117 {
118  int rc;
119  long long result_ll;
120 
121  rc = pcmk__scan_ll(text, &result_ll, (long long) minimum);
122 
123  if (result_ll < (long long) minimum) {
124  crm_warn("Clipped '%s' to minimum acceptable value %d", text, minimum);
125  result_ll = (long long) minimum;
126 
127  } else if (result_ll > INT_MAX) {
128  crm_warn("Clipped '%s' to maximum integer %d", text, INT_MAX);
129  result_ll = (long long) INT_MAX;
130  rc = EOVERFLOW;
131  }
132 
133  if (result != NULL) {
134  *result = (int) result_ll;
135  }
136  return rc;
137 }
138 
149 int
150 pcmk__scan_port(const char *text, int *port)
151 {
152  long long port_ll;
153  int rc = pcmk__scan_ll(text, &port_ll, -1LL);
154 
155  if (rc != pcmk_rc_ok) {
156  crm_warn("'%s' is not a valid port: %s", text, pcmk_rc_str(rc));
157 
158  } else if ((text != NULL) // wasn't default or invalid
159  && ((port_ll < 0LL) || (port_ll > 65535LL))) {
160  crm_warn("Ignoring port specification '%s' "
161  "not in valid range (0-65535)", text);
162  rc = (port_ll < 0LL)? pcmk_rc_before_range : pcmk_rc_after_range;
163  port_ll = -1LL;
164  }
165  if (port != NULL) {
166  *port = (int) port_ll;
167  }
168  return rc;
169 }
170 
190 int
191 pcmk__scan_double(const char *text, double *result, const char *default_text,
192  char **end_text)
193 {
194  int rc = pcmk_rc_ok;
195  char *local_end_text = NULL;
196 
197  pcmk__assert(result != NULL);
199 
200  text = (text != NULL) ? text : default_text;
201 
202  if (text == NULL) {
203  rc = EINVAL;
204  crm_debug("No text and no default conversion value supplied");
205 
206  } else {
207  errno = 0;
208  *result = strtod(text, &local_end_text);
209 
210  if (errno == ERANGE) {
211  /*
212  * Overflow: strtod() returns +/- HUGE_VAL and sets errno to
213  * ERANGE
214  *
215  * Underflow: strtod() returns "a value whose magnitude is
216  * no greater than the smallest normalized
217  * positive" double. Whether ERANGE is set is
218  * implementation-defined.
219  */
220  const char *over_under;
221 
222  if (QB_ABS(*result) > DBL_MIN) {
223  rc = EOVERFLOW;
224  over_under = "over";
225  } else {
226  rc = pcmk_rc_underflow;
227  over_under = "under";
228  }
229 
230  crm_debug("Floating-point value parsed from '%s' would %sflow "
231  "(using %g instead)", text, over_under, *result);
232 
233  } else if (errno != 0) {
234  rc = errno;
235  // strtod() set *result = 0 on parse failure
237 
238  crm_debug("Could not parse floating-point value from '%s' (using "
239  "%.1f instead): %s", text, PCMK__PARSE_DBL_DEFAULT,
240  pcmk_rc_str(rc));
241 
242  } else if (local_end_text == text) {
243  // errno == 0, but nothing was parsed
244  rc = EINVAL;
246 
247  crm_debug("Could not parse floating-point value from '%s' (using "
248  "%.1f instead): No digits found", text,
250 
251  } else if (QB_ABS(*result) <= DBL_MIN) {
252  /*
253  * errno == 0 and text was parsed, but value might have
254  * underflowed.
255  *
256  * ERANGE might not be set for underflow. Check magnitude
257  * of *result, but also make sure the input number is not
258  * actually zero (0 <= DBL_MIN is not underflow).
259  *
260  * This check must come last. A parse failure in strtod()
261  * also sets *result == 0, so a parse failure would match
262  * this test condition prematurely.
263  */
264  for (const char *p = text; p != local_end_text; p++) {
265  if (strchr("0.eE", *p) == NULL) {
266  rc = pcmk_rc_underflow;
267  crm_debug("Floating-point value parsed from '%s' would "
268  "underflow (using %g instead)", text, *result);
269  break;
270  }
271  }
272 
273  } else {
274  crm_trace("Floating-point value parsed successfully from "
275  "'%s': %g", text, *result);
276  }
277 
278  if ((end_text == NULL) && !pcmk__str_empty(local_end_text)) {
279  crm_debug("Characters left over after parsing '%s': '%s'",
280  text, local_end_text);
281  }
282  }
283 
284  if (end_text != NULL) {
285  *end_text = local_end_text;
286  }
287 
288  return rc;
289 }
290 
302 int
303 pcmk__guint_from_hash(GHashTable *table, const char *key, guint default_val,
304  guint *result)
305 {
306  const char *value;
307  long long value_ll;
308  int rc = pcmk_rc_ok;
309 
310  CRM_CHECK((table != NULL) && (key != NULL), return EINVAL);
311 
312  if (result != NULL) {
313  *result = default_val;
314  }
315 
316  value = g_hash_table_lookup(table, key);
317  if (value == NULL) {
318  return pcmk_rc_ok;
319  }
320 
321  rc = pcmk__scan_ll(value, &value_ll, 0LL);
322  if (rc != pcmk_rc_ok) {
323  crm_warn("Using default (%u) for %s because '%s' is not a "
324  "valid integer: %s", default_val, key, value, pcmk_rc_str(rc));
325  return rc;
326  }
327 
328  if ((value_ll < 0) || (value_ll > G_MAXUINT)) {
329  crm_warn("Using default (%u) for %s because '%s' is not in valid range",
330  default_val, key, value);
331  return ERANGE;
332  }
333 
334  if (result != NULL) {
335  *result = (guint) value_ll;
336  }
337  return pcmk_rc_ok;
338 }
339 
350 long long
351 crm_get_msec(const char *input)
352 {
353  char *units = NULL; // Do not free; will point to part of input
354  long long multiplier = 1000;
355  long long divisor = 1;
356  long long msec = PCMK__PARSE_INT_DEFAULT;
357  int rc = pcmk_rc_ok;
358 
359  if (input == NULL) {
361  }
362 
363  // Skip initial whitespace
364  while (isspace(*input)) {
365  input++;
366  }
367 
368  rc = scan_ll(input, &msec, PCMK__PARSE_INT_DEFAULT, &units);
369 
370  if ((rc == ERANGE) && (msec > 0)) {
371  crm_warn("'%s' will be clipped to %lld", input, msec);
372 
373  } else if ((rc != pcmk_rc_ok) || (msec < 0)) {
374  crm_warn("'%s' is not a valid time duration: %s",
375  input, ((rc == pcmk_rc_ok)? "Negative" : pcmk_rc_str(rc)));
377  }
378 
379  /* If the number is a decimal, scan_ll() reads only the integer part. Skip
380  * any remaining digits or decimal characters.
381  *
382  * @COMPAT Well-formed and malformed decimals are both accepted inputs. For
383  * example, "3.14 ms" and "3.1.4 ms" are treated the same as "3ms" and
384  * parsed successfully. At a compatibility break, decide if this is still
385  * desired.
386  */
387  while (isdigit(*units) || (*units == '.')) {
388  units++;
389  }
390 
391  // Skip any additional whitespace after the number
392  while (isspace(*units)) {
393  units++;
394  }
395 
396  /* @COMPAT Use exact comparisons. Currently, we match too liberally, and the
397  * second strncasecmp() in each case is redundant.
398  */
399  if ((*units == '\0')
400  || (strncasecmp(units, "s", 1) == 0)
401  || (strncasecmp(units, "sec", 3) == 0)) {
402  multiplier = 1000;
403  divisor = 1;
404 
405  } else if ((strncasecmp(units, "ms", 2) == 0)
406  || (strncasecmp(units, "msec", 4) == 0)) {
407  multiplier = 1;
408  divisor = 1;
409 
410  } else if ((strncasecmp(units, "us", 2) == 0)
411  || (strncasecmp(units, "usec", 4) == 0)) {
412  multiplier = 1;
413  divisor = 1000;
414 
415  } else if ((strncasecmp(units, "m", 1) == 0)
416  || (strncasecmp(units, "min", 3) == 0)) {
417  multiplier = 60 * 1000;
418  divisor = 1;
419 
420  } else if ((strncasecmp(units, "h", 1) == 0)
421  || (strncasecmp(units, "hr", 2) == 0)) {
422  multiplier = 60 * 60 * 1000;
423  divisor = 1;
424 
425  } else {
426  // Invalid units
428  }
429 
430  // Apply units, capping at LLONG_MAX
431  if (msec > (LLONG_MAX / multiplier)) {
432  return LLONG_MAX;
433  }
434  return (msec * multiplier) / divisor;
435 }
436 
451 int
452 pcmk_parse_interval_spec(const char *input, guint *result_ms)
453 {
454  long long msec = PCMK__PARSE_INT_DEFAULT;
455  int rc = pcmk_rc_ok;
456 
457  if (input == NULL) {
458  msec = 0;
459  goto done;
460  }
461 
462  if (input[0] == 'P') {
464 
465  if (period_s != NULL) {
466  msec = crm_time_get_seconds(period_s);
467  msec = QB_MIN(msec, G_MAXUINT / 1000) * 1000;
468  crm_time_free(period_s);
469  }
470 
471  } else {
472  msec = crm_get_msec(input);
473  }
474 
475  if (msec < 0) {
476  crm_warn("Using 0 instead of invalid interval specification '%s'",
477  input);
478  msec = 0;
479  rc = EINVAL;
480  }
481 
482 done:
483  if (result_ms != NULL) {
484  *result_ms = (msec >= G_MAXUINT)? G_MAXUINT : (guint) msec;
485  }
486  return rc;
487 }
488 
489 gboolean
490 crm_is_true(const char *s)
491 {
492  gboolean ret = FALSE;
493 
494  return (crm_str_to_boolean(s, &ret) < 0)? FALSE : ret;
495 }
496 
497 int
498 crm_str_to_boolean(const char *s, int *ret)
499 {
500  if (s == NULL) {
501  return -1;
502  }
503 
504  if (pcmk__strcase_any_of(s, PCMK_VALUE_TRUE, "on", "yes", "y", "1", NULL)) {
505  if (ret != NULL) {
506  *ret = TRUE;
507  }
508  return 1;
509  }
510 
512  "0", NULL)) {
513  if (ret != NULL) {
514  *ret = FALSE;
515  }
516  return 1;
517  }
518  return -1;
519 }
520 
529 char *
530 pcmk__trim(char *str)
531 {
532  int len;
533 
534  if (str == NULL) {
535  return str;
536  }
537 
538  for (len = strlen(str) - 1; len >= 0 && str[len] == '\n'; len--) {
539  str[len] = '\0';
540  }
541 
542  return str;
543 }
544 
557 bool
558 pcmk__starts_with(const char *str, const char *prefix)
559 {
560  const char *s = str;
561  const char *p = prefix;
562 
563  if (!s || !p) {
564  return false;
565  }
566  while (*s && *p) {
567  if (*s++ != *p++) {
568  return false;
569  }
570  }
571  return (*p == 0);
572 }
573 
574 static inline bool
575 ends_with(const char *s, const char *match, bool as_extension)
576 {
577  if (pcmk__str_empty(match)) {
578  return true;
579  } else if (s == NULL) {
580  return false;
581  } else {
582  size_t slen, mlen;
583 
584  /* Besides as_extension, we could also check
585  !strchr(&match[1], match[0]) but that would be inefficient.
586  */
587  if (as_extension) {
588  s = strrchr(s, match[0]);
589  return (s == NULL)? false : !strcmp(s, match);
590  }
591 
592  mlen = strlen(match);
593  slen = strlen(s);
594  return ((slen >= mlen) && !strcmp(s + slen - mlen, match));
595  }
596 }
597 
609 bool
610 pcmk__ends_with(const char *s, const char *match)
611 {
612  return ends_with(s, match, false);
613 }
614 
636 bool
637 pcmk__ends_with_ext(const char *s, const char *match)
638 {
639  return ends_with(s, match, true);
640 }
641 
661 static guint
662 pcmk__str_hash(gconstpointer v)
663 {
664  const signed char *p;
665  guint32 h = 0;
666 
667  for (p = v; *p != '\0'; p++)
668  h = (h << 5) - h + *p;
669 
670  return h;
671 }
672 
684 GHashTable *
685 pcmk__strkey_table(GDestroyNotify key_destroy_func,
686  GDestroyNotify value_destroy_func)
687 {
688  return g_hash_table_new_full(pcmk__str_hash, g_str_equal,
689  key_destroy_func, value_destroy_func);
690 }
691 
702 void
703 pcmk__insert_dup(GHashTable *table, const char *name, const char *value)
704 {
705  pcmk__assert((table != NULL) && (name != NULL));
706 
707  g_hash_table_insert(table, pcmk__str_copy(name), pcmk__str_copy(value));
708 }
709 
710 /* used with hash tables where case does not matter */
711 static gboolean
712 pcmk__strcase_equal(gconstpointer a, gconstpointer b)
713 {
714  return pcmk__str_eq((const char *)a, (const char *)b, pcmk__str_casei);
715 }
716 
717 static guint
718 pcmk__strcase_hash(gconstpointer v)
719 {
720  const signed char *p;
721  guint32 h = 0;
722 
723  for (p = v; *p != '\0'; p++)
724  h = (h << 5) - h + g_ascii_tolower(*p);
725 
726  return h;
727 }
728 
740 GHashTable *
741 pcmk__strikey_table(GDestroyNotify key_destroy_func,
742  GDestroyNotify value_destroy_func)
743 {
744  return g_hash_table_new_full(pcmk__strcase_hash, pcmk__strcase_equal,
745  key_destroy_func, value_destroy_func);
746 }
747 
748 static void
749 copy_str_table_entry(gpointer key, gpointer value, gpointer user_data)
750 {
751  if (key && value && user_data) {
752  pcmk__insert_dup((GHashTable *) user_data,
753  (const char *) key, (const char *) value);
754  }
755 }
756 
767 GHashTable *
768 pcmk__str_table_dup(GHashTable *old_table)
769 {
770  GHashTable *new_table = NULL;
771 
772  if (old_table) {
773  new_table = pcmk__strkey_table(free, free);
774  g_hash_table_foreach(old_table, copy_str_table_entry, new_table);
775  }
776  return new_table;
777 }
778 
795 void
796 pcmk__add_separated_word(GString **list, size_t init_size, const char *word,
797  const char *separator)
798 {
799  pcmk__assert(list != NULL);
800 
801  if (pcmk__str_empty(word)) {
802  return;
803  }
804 
805  if (*list == NULL) {
806  if (init_size > 0) {
807  *list = g_string_sized_new(init_size);
808  } else {
809  *list = g_string_new(NULL);
810  }
811  }
812 
813  if ((*list)->len == 0) {
814  // Don't add a separator before the first word in the list
815  separator = "";
816 
817  } else if (separator == NULL) {
818  // Default to space-separated
819  separator = " ";
820  }
821 
822  g_string_append(*list, separator);
823  g_string_append(*list, word);
824 }
825 
838 int
839 pcmk__compress(const char *data, unsigned int length, unsigned int max,
840  char **result, unsigned int *result_len)
841 {
842  int rc;
843  char *compressed = NULL;
844  char *uncompressed = strdup(data);
845 #ifdef CLOCK_MONOTONIC
846  struct timespec after_t;
847  struct timespec before_t;
848 #endif
849 
850  if (max == 0) {
851  max = (length * 1.01) + 601; // Size guaranteed to hold result
852  }
853 
854 #ifdef CLOCK_MONOTONIC
855  clock_gettime(CLOCK_MONOTONIC, &before_t);
856 #endif
857 
858  compressed = pcmk__assert_alloc((size_t) max, sizeof(char));
859 
860  *result_len = max;
861  rc = BZ2_bzBuffToBuffCompress(compressed, result_len, uncompressed, length,
863  rc = pcmk__bzlib2rc(rc);
864 
865  free(uncompressed);
866 
867  if (rc != pcmk_rc_ok) {
868  crm_err("Compression of %d bytes failed: %s " QB_XS " rc=%d",
869  length, pcmk_rc_str(rc), rc);
870  free(compressed);
871  return rc;
872  }
873 
874 #ifdef CLOCK_MONOTONIC
875  clock_gettime(CLOCK_MONOTONIC, &after_t);
876 
877  crm_trace("Compressed %d bytes into %d (ratio %d:1) in %.0fms",
878  length, *result_len, length / (*result_len),
879  (after_t.tv_sec - before_t.tv_sec) * 1000 +
880  (after_t.tv_nsec - before_t.tv_nsec) / 1e6);
881 #else
882  crm_trace("Compressed %d bytes into %d (ratio %d:1)",
883  length, *result_len, length / (*result_len));
884 #endif
885 
886  *result = compressed;
887  return pcmk_rc_ok;
888 }
889 
890 char *
891 crm_strdup_printf(char const *format, ...)
892 {
893  va_list ap;
894  int len = 0;
895  char *string = NULL;
896 
897  va_start(ap, format);
898  len = vasprintf(&string, format, ap);
899  pcmk__assert(len > 0);
900  va_end(ap);
901  return string;
902 }
903 
904 int
905 pcmk__parse_ll_range(const char *srcstring, long long *start, long long *end)
906 {
907  char *remainder = NULL;
908  int rc = pcmk_rc_ok;
909 
910  pcmk__assert((start != NULL) && (end != NULL));
911 
912  *start = PCMK__PARSE_INT_DEFAULT;
914 
915  crm_trace("Attempting to decode: [%s]", srcstring);
916  if (pcmk__str_eq(srcstring, "", pcmk__str_null_matches)) {
917  return ENODATA;
918  } else if (pcmk__str_eq(srcstring, "-", pcmk__str_none)) {
919  return pcmk_rc_bad_input;
920  }
921 
922  /* String starts with a dash, so this is either a range with
923  * no beginning or garbage.
924  * */
925  if (*srcstring == '-') {
926  int rc = scan_ll(srcstring+1, end, PCMK__PARSE_INT_DEFAULT, &remainder);
927 
928  if ((rc == pcmk_rc_ok) && (*remainder != '\0')) {
929  rc = pcmk_rc_bad_input;
930  }
931  return rc;
932  }
933 
934  rc = scan_ll(srcstring, start, PCMK__PARSE_INT_DEFAULT, &remainder);
935  if (rc != pcmk_rc_ok) {
936  return rc;
937  }
938 
939  if (*remainder && *remainder == '-') {
940  if (*(remainder+1)) {
941  char *more_remainder = NULL;
942  int rc = scan_ll(remainder+1, end, PCMK__PARSE_INT_DEFAULT,
943  &more_remainder);
944 
945  if (rc != pcmk_rc_ok) {
946  return rc;
947  } else if (*more_remainder != '\0') {
948  return pcmk_rc_bad_input;
949  }
950  }
951  } else if (*remainder && *remainder != '-') {
952  *start = PCMK__PARSE_INT_DEFAULT;
953  return pcmk_rc_bad_input;
954  } else {
955  /* The input string contained only one number. Set start and end
956  * to the same value and return pcmk_rc_ok. This gives the caller
957  * a way to tell this condition apart from a range with no end.
958  */
959  *end = *start;
960  }
961 
962  return pcmk_rc_ok;
963 }
964 
981 gboolean
982 pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
983 {
984  for (const GList *ele = lst; ele != NULL; ele = ele->next) {
985  if (pcmk__str_eq(s, ele->data, flags)) {
986  return TRUE;
987  }
988  }
989 
990  return FALSE;
991 }
992 
993 static bool
994 str_any_of(const char *s, va_list args, uint32_t flags)
995 {
996  if (s == NULL) {
998  }
999 
1000  while (1) {
1001  const char *ele = va_arg(args, const char *);
1002 
1003  if (ele == NULL) {
1004  break;
1005  } else if (pcmk__str_eq(s, ele, flags)) {
1006  return true;
1007  }
1008  }
1009 
1010  return false;
1011 }
1012 
1026 bool
1027 pcmk__strcase_any_of(const char *s, ...)
1028 {
1029  va_list ap;
1030  bool rc;
1031 
1032  va_start(ap, s);
1033  rc = str_any_of(s, ap, pcmk__str_casei);
1034  va_end(ap);
1035  return rc;
1036 }
1037 
1050 bool
1051 pcmk__str_any_of(const char *s, ...)
1052 {
1053  va_list ap;
1054  bool rc;
1055 
1056  va_start(ap, s);
1057  rc = str_any_of(s, ap, pcmk__str_none);
1058  va_end(ap);
1059  return rc;
1060 }
1061 
1078 int
1079 pcmk__numeric_strcasecmp(const char *s1, const char *s2)
1080 {
1081  pcmk__assert((s1 != NULL) && (s2 != NULL));
1082 
1083  while (*s1 && *s2) {
1084  if (isdigit(*s1) && isdigit(*s2)) {
1085  // If node names contain a number, sort numerically
1086 
1087  char *end1 = NULL;
1088  char *end2 = NULL;
1089  long num1 = strtol(s1, &end1, 10);
1090  long num2 = strtol(s2, &end2, 10);
1091 
1092  // allow ordering e.g. 007 > 7
1093  size_t len1 = end1 - s1;
1094  size_t len2 = end2 - s2;
1095 
1096  if (num1 < num2) {
1097  return -1;
1098  } else if (num1 > num2) {
1099  return 1;
1100  } else if (len1 < len2) {
1101  return -1;
1102  } else if (len1 > len2) {
1103  return 1;
1104  }
1105  s1 = end1;
1106  s2 = end2;
1107  } else {
1108  // Compare non-digits case-insensitively
1109  int lower1 = tolower(*s1);
1110  int lower2 = tolower(*s2);
1111 
1112  if (lower1 < lower2) {
1113  return -1;
1114  } else if (lower1 > lower2) {
1115  return 1;
1116  }
1117  ++s1;
1118  ++s2;
1119  }
1120  }
1121  if (!*s1 && *s2) {
1122  return -1;
1123  } else if (*s1 && !*s2) {
1124  return 1;
1125  }
1126  return 0;
1127 }
1128 
1163 int
1164 pcmk__strcmp(const char *s1, const char *s2, uint32_t flags)
1165 {
1166  /* If this flag is set, the second string is a regex. */
1168  regex_t r_patt;
1169  int reg_flags = REG_EXTENDED | REG_NOSUB;
1170  int regcomp_rc = 0;
1171  int rc = 0;
1172 
1173  if (s1 == NULL || s2 == NULL) {
1174  return 1;
1175  }
1176 
1178  reg_flags |= REG_ICASE;
1179  }
1180  regcomp_rc = regcomp(&r_patt, s2, reg_flags);
1181  if (regcomp_rc != 0) {
1182  rc = 1;
1183  crm_err("Bad regex '%s' for update: %s", s2, strerror(regcomp_rc));
1184  } else {
1185  rc = regexec(&r_patt, s1, 0, NULL, 0);
1186  regfree(&r_patt);
1187  if (rc != 0) {
1188  rc = 1;
1189  }
1190  }
1191  return rc;
1192  }
1193 
1194  /* If the strings are the same pointer, return 0 immediately. */
1195  if (s1 == s2) {
1196  return 0;
1197  }
1198 
1199  /* If this flag is set, return 0 if either (or both) of the input strings
1200  * are NULL. If neither one is NULL, we need to continue and compare
1201  * them normally.
1202  */
1204  if (s1 == NULL || s2 == NULL) {
1205  return 0;
1206  }
1207  }
1208 
1209  /* Handle the cases where one is NULL and the str_null_matches flag is not set.
1210  * A NULL string always sorts to the beginning.
1211  */
1212  if (s1 == NULL) {
1213  return -1;
1214  } else if (s2 == NULL) {
1215  return 1;
1216  }
1217 
1218  /* If this flag is set, return 0 if either (or both) of the input strings
1219  * are "*". If neither one is, we need to continue and compare them
1220  * normally.
1221  */
1223  if (strcmp(s1, "*") == 0 || strcmp(s2, "*") == 0) {
1224  return 0;
1225  }
1226  }
1227 
1229  return strcasecmp(s1, s2);
1230  } else {
1231  return strcmp(s1, s2);
1232  }
1233 }
1234 
1248 char *
1249 pcmk__str_copy_as(const char *file, const char *function, uint32_t line,
1250  const char *str)
1251 {
1252  if (str != NULL) {
1253  char *result = strdup(str);
1254 
1255  if (result == NULL) {
1256  crm_abort(file, function, line, "Out of memory", FALSE, TRUE);
1258  }
1259  return result;
1260  }
1261  return NULL;
1262 }
1263 
1277 void
1278 pcmk__str_update(char **str, const char *value)
1279 {
1280  if ((str != NULL) && !pcmk__str_eq(*str, value, pcmk__str_none)) {
1281  free(*str);
1282  *str = pcmk__str_copy(value);
1283  }
1284 }
1285 
1296 void
1297 pcmk__g_strcat(GString *buffer, ...)
1298 {
1299  va_list ap;
1300 
1301  pcmk__assert(buffer != NULL);
1302  va_start(ap, buffer);
1303 
1304  while (true) {
1305  const char *ele = va_arg(ap, const char *);
1306 
1307  if (ele == NULL) {
1308  break;
1309  }
1310  g_string_append(buffer, ele);
1311  }
1312  va_end(ap);
1313 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:213
bool pcmk__starts_with(const char *str, const char *prefix)
Check whether a string starts with a certain sequence.
Definition: strings.c:558
char data[0]
Definition: cpg.c:58
char * crm_strdup_printf(char const *format,...)
Definition: strings.c:891
_Noreturn crm_exit_t crm_exit(crm_exit_t rc)
Definition: results.c:1044
#define PCMK_VALUE_FALSE
Definition: options.h:153
const char * name
Definition: cib.c:26
struct crm_time_s crm_time_t
Definition: iso8601.h:32
void crm_abort(const char *file, const char *function, int line, const char *condition, gboolean do_core, gboolean do_fork)
Definition: results.c:215
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:685
#define PCMK__PARSE_DBL_DEFAULT
int pcmk__scan_port(const char *text, int *port)
Definition: strings.c:150
int pcmk__scan_ll(const char *text, long long *result, long long default_value)
Definition: strings.c:92
int pcmk__numeric_strcasecmp(const char *s1, const char *s2)
Definition: strings.c:1079
bool pcmk__str_any_of(const char *s,...)
Definition: strings.c:1051
crm_time_t * crm_time_parse_duration(const char *duration_str)
Parse a time duration from an ISO 8601 duration specification.
Definition: iso8601.c:1121
int pcmk__scan_double(const char *text, double *result, const char *default_text, char **end_text)
Definition: strings.c:191
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:609
void pcmk__str_update(char **str, const char *value)
Definition: strings.c:1278
#define PCMK__PARSE_INT_DEFAULT
#define crm_warn(fmt, args...)
Definition: logging.h:362
int pcmk__guint_from_hash(GHashTable *table, const char *key, guint default_val, guint *result)
Definition: strings.c:303
#define crm_debug(fmt, args...)
Definition: logging.h:370
void pcmk__add_separated_word(GString **list, size_t init_size, const char *word, const char *separator)
Definition: strings.c:796
int pcmk__parse_ll_range(const char *srcstring, long long *start, long long *end)
Definition: strings.c:905
External (OS/environmental) problem.
Definition: results.h:252
int pcmk__compress(const char *data, unsigned int length, unsigned int max, char **result, unsigned int *result_len)
Definition: strings.c:839
#define crm_trace(fmt, args...)
Definition: logging.h:372
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:80
void pcmk__insert_dup(GHashTable *table, const char *name, const char *value)
Definition: strings.c:703
long long crm_get_msec(const char *input)
Parse a time+units string and return milliseconds equivalent.
Definition: strings.c:351
#define PCMK_VALUE_TRUE
Definition: options.h:218
int pcmk__scan_min_int(const char *text, int *result, int minimum)
Definition: strings.c:116
GHashTable * pcmk__str_table_dup(GHashTable *old_table)
Definition: strings.c:768
int pcmk_parse_interval_spec(const char *input, guint *result_ms)
Parse milliseconds from a Pacemaker interval specification.
Definition: strings.c:452
long long crm_time_get_seconds(const crm_time_t *dt)
Definition: iso8601.c:331
#define pcmk__str_copy(str)
int crm_str_to_boolean(const char *s, int *ret)
Definition: strings.c:498
#define pcmk__assert(expr)
int pcmk__strcmp(const char *s1, const char *s2, uint32_t flags)
Definition: strings.c:1164
GHashTable * pcmk__strikey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:741
#define CRM_BZ2_BLOCKS
Definition: xml_io.h:33
gboolean crm_is_true(const char *s)
Definition: strings.c:490
bool pcmk__ends_with_ext(const char *s, const char *match)
Definition: strings.c:637
int pcmk__bzlib2rc(int bz2)
Map a bz2 return code to the most similar Pacemaker return code.
Definition: results.c:1014
#define ENODATA
Definition: portability.h:61
pcmk__action_result_t result
Definition: pcmk_fence.c:37
#define crm_err(fmt, args...)
Definition: logging.h:359
xmlNode * input
#define PCMK_VALUE_OFF
Definition: options.h:184
void pcmk__g_strcat(GString *buffer,...)
Definition: strings.c:1297
char * pcmk__str_copy_as(const char *file, const char *function, uint32_t line, const char *str)
Definition: strings.c:1249
gboolean pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
Definition: strings.c:982
char * pcmk__trim(char *str)
Definition: strings.c:530
#define pcmk__assert_alloc(nmemb, size)
Definition: internal.h:257
#define CRM_BZ2_WORK
Definition: xml_io.h:34
bool pcmk__ends_with(const char *s, const char *match)
Definition: strings.c:610
uint64_t flags
Definition: remote.c:211
bool pcmk__strcase_any_of(const char *s,...)
Definition: strings.c:1027
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:150