pacemaker  2.1.0-7c3f660
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
strings.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2021 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 #ifndef _GNU_SOURCE
13 # define _GNU_SOURCE
14 #endif
15 
16 #include <regex.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <ctype.h>
21 #include <float.h> // DBL_MIN
22 #include <limits.h>
23 #include <math.h> // fabs()
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);
206  *result = PCMK__PARSE_DBL_DEFAULT;
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 (fabs(*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
244  *result = PCMK__PARSE_DBL_DEFAULT;
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;
253  *result = PCMK__PARSE_DBL_DEFAULT;
254 
255  crm_debug("Could not parse floating-point value from '%s' (using "
256  "%.1f instead): No digits found", text,
258 
259  } else if (fabs(*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 
345 #ifndef NUMCHARS
346 # define NUMCHARS "0123456789."
347 #endif
348 
349 #ifndef WHITESPACE
350 # define WHITESPACE " \t\n\r\f"
351 #endif
352 
362 long long
363 crm_get_msec(const char *input)
364 {
365  const char *num_start = NULL;
366  const char *units;
367  long long multiplier = 1000;
368  long long divisor = 1;
369  long long msec = PCMK__PARSE_INT_DEFAULT;
370  size_t num_len = 0;
371  char *end_text = NULL;
372 
373  if (input == NULL) {
375  }
376 
377  num_start = input + strspn(input, WHITESPACE);
378  num_len = strspn(num_start, NUMCHARS);
379  if (num_len < 1) {
381  }
382  units = num_start + num_len;
383  units += strspn(units, WHITESPACE);
384 
385  if (!strncasecmp(units, "ms", 2) || !strncasecmp(units, "msec", 4)) {
386  multiplier = 1;
387  divisor = 1;
388  } else if (!strncasecmp(units, "us", 2) || !strncasecmp(units, "usec", 4)) {
389  multiplier = 1;
390  divisor = 1000;
391  } else if (!strncasecmp(units, "s", 1) || !strncasecmp(units, "sec", 3)) {
392  multiplier = 1000;
393  divisor = 1;
394  } else if (!strncasecmp(units, "m", 1) || !strncasecmp(units, "min", 3)) {
395  multiplier = 60 * 1000;
396  divisor = 1;
397  } else if (!strncasecmp(units, "h", 1) || !strncasecmp(units, "hr", 2)) {
398  multiplier = 60 * 60 * 1000;
399  divisor = 1;
400  } else if ((*units != '\0') && (*units != '\n') && (*units != '\r')) {
402  }
403 
404  scan_ll(num_start, &msec, PCMK__PARSE_INT_DEFAULT, &end_text);
405  if (msec > (LLONG_MAX / multiplier)) {
406  // Arithmetics overflow while multiplier/divisor mutually exclusive
407  return LLONG_MAX;
408  }
409  msec *= multiplier;
410  msec /= divisor;
411  return msec;
412 }
413 
414 gboolean
415 crm_is_true(const char *s)
416 {
417  gboolean ret = FALSE;
418 
419  if (s != NULL) {
420  crm_str_to_boolean(s, &ret);
421  }
422  return ret;
423 }
424 
425 int
426 crm_str_to_boolean(const char *s, int *ret)
427 {
428  if (s == NULL) {
429  return -1;
430 
431  } else if (strcasecmp(s, "true") == 0
432  || strcasecmp(s, "on") == 0
433  || strcasecmp(s, "yes") == 0 || strcasecmp(s, "y") == 0 || strcasecmp(s, "1") == 0) {
434  *ret = TRUE;
435  return 1;
436 
437  } else if (strcasecmp(s, "false") == 0
438  || strcasecmp(s, "off") == 0
439  || strcasecmp(s, "no") == 0 || strcasecmp(s, "n") == 0 || strcasecmp(s, "0") == 0) {
440  *ret = FALSE;
441  return 1;
442  }
443  return -1;
444 }
445 
454 char *
455 pcmk__trim(char *str)
456 {
457  int len;
458 
459  if (str == NULL) {
460  return str;
461  }
462 
463  for (len = strlen(str) - 1; len >= 0 && str[len] == '\n'; len--) {
464  str[len] = '\0';
465  }
466 
467  return str;
468 }
469 
482 bool
483 pcmk__starts_with(const char *str, const char *prefix)
484 {
485  const char *s = str;
486  const char *p = prefix;
487 
488  if (!s || !p) {
489  return false;
490  }
491  while (*s && *p) {
492  if (*s++ != *p++) {
493  return false;
494  }
495  }
496  return (*p == 0);
497 }
498 
499 static inline bool
500 ends_with(const char *s, const char *match, bool as_extension)
501 {
502  if (pcmk__str_empty(match)) {
503  return true;
504  } else if (s == NULL) {
505  return false;
506  } else {
507  size_t slen, mlen;
508 
509  /* Besides as_extension, we could also check
510  !strchr(&match[1], match[0]) but that would be inefficient.
511  */
512  if (as_extension) {
513  s = strrchr(s, match[0]);
514  return (s == NULL)? false : !strcmp(s, match);
515  }
516 
517  mlen = strlen(match);
518  slen = strlen(s);
519  return ((slen >= mlen) && !strcmp(s + slen - mlen, match));
520  }
521 }
522 
534 bool
535 pcmk__ends_with(const char *s, const char *match)
536 {
537  return ends_with(s, match, false);
538 }
539 
561 bool
562 pcmk__ends_with_ext(const char *s, const char *match)
563 {
564  return ends_with(s, match, true);
565 }
566 
586 static guint
587 pcmk__str_hash(gconstpointer v)
588 {
589  const signed char *p;
590  guint32 h = 0;
591 
592  for (p = v; *p != '\0'; p++)
593  h = (h << 5) - h + *p;
594 
595  return h;
596 }
597 
609 GHashTable *
610 pcmk__strkey_table(GDestroyNotify key_destroy_func,
611  GDestroyNotify value_destroy_func)
612 {
613  return g_hash_table_new_full(pcmk__str_hash, g_str_equal,
614  key_destroy_func, value_destroy_func);
615 }
616 
617 /* used with hash tables where case does not matter */
618 static gboolean
619 pcmk__strcase_equal(gconstpointer a, gconstpointer b)
620 {
621  return pcmk__str_eq((const char *)a, (const char *)b, pcmk__str_casei);
622 }
623 
624 static guint
625 pcmk__strcase_hash(gconstpointer v)
626 {
627  const signed char *p;
628  guint32 h = 0;
629 
630  for (p = v; *p != '\0'; p++)
631  h = (h << 5) - h + g_ascii_tolower(*p);
632 
633  return h;
634 }
635 
647 GHashTable *
648 pcmk__strikey_table(GDestroyNotify key_destroy_func,
649  GDestroyNotify value_destroy_func)
650 {
651  return g_hash_table_new_full(pcmk__strcase_hash, pcmk__strcase_equal,
652  key_destroy_func, value_destroy_func);
653 }
654 
655 static void
656 copy_str_table_entry(gpointer key, gpointer value, gpointer user_data)
657 {
658  if (key && value && user_data) {
659  g_hash_table_insert((GHashTable*)user_data, strdup(key), strdup(value));
660  }
661 }
662 
673 GHashTable *
674 pcmk__str_table_dup(GHashTable *old_table)
675 {
676  GHashTable *new_table = NULL;
677 
678  if (old_table) {
679  new_table = pcmk__strkey_table(free, free);
680  g_hash_table_foreach(old_table, copy_str_table_entry, new_table);
681  }
682  return new_table;
683 }
684 
701 void
702 pcmk__add_separated_word(char **list, size_t *len, const char *word,
703  const char *separator)
704 {
705  size_t orig_len, new_len;
706 
707  CRM_ASSERT(list != NULL);
708 
709  if (pcmk__str_empty(word)) {
710  return;
711  }
712 
713  // Use provided length, or calculate it if not available
714  orig_len = (len != NULL)? *len : ((*list == NULL)? 0 : strlen(*list));
715 
716  // Don't add a separator before the first word in the list
717  if (orig_len == 0) {
718  separator = "";
719 
720  // Default to space-separated
721  } else if (separator == NULL) {
722  separator = " ";
723  }
724 
725  new_len = orig_len + strlen(separator) + strlen(word);
726  if (len != NULL) {
727  *len = new_len;
728  }
729 
730  // +1 for null terminator
731  *list = pcmk__realloc(*list, new_len + 1);
732  sprintf(*list + orig_len, "%s%s", separator, word);
733 }
734 
747 int
748 pcmk__compress(const char *data, unsigned int length, unsigned int max,
749  char **result, unsigned int *result_len)
750 {
751  int rc;
752  char *compressed = NULL;
753  char *uncompressed = strdup(data);
754 #ifdef CLOCK_MONOTONIC
755  struct timespec after_t;
756  struct timespec before_t;
757 #endif
758 
759  if (max == 0) {
760  max = (length * 1.01) + 601; // Size guaranteed to hold result
761  }
762 
763 #ifdef CLOCK_MONOTONIC
764  clock_gettime(CLOCK_MONOTONIC, &before_t);
765 #endif
766 
767  compressed = calloc((size_t) max, sizeof(char));
768  CRM_ASSERT(compressed);
769 
770  *result_len = max;
771  rc = BZ2_bzBuffToBuffCompress(compressed, result_len, uncompressed, length,
773  free(uncompressed);
774  if (rc != BZ_OK) {
775  crm_err("Compression of %d bytes failed: %s " CRM_XS " bzerror=%d",
776  length, bz2_strerror(rc), rc);
777  free(compressed);
778  return pcmk_rc_error;
779  }
780 
781 #ifdef CLOCK_MONOTONIC
782  clock_gettime(CLOCK_MONOTONIC, &after_t);
783 
784  crm_trace("Compressed %d bytes into %d (ratio %d:1) in %.0fms",
785  length, *result_len, length / (*result_len),
786  (after_t.tv_sec - before_t.tv_sec) * 1000 +
787  (after_t.tv_nsec - before_t.tv_nsec) / 1e6);
788 #else
789  crm_trace("Compressed %d bytes into %d (ratio %d:1)",
790  length, *result_len, length / (*result_len));
791 #endif
792 
793  *result = compressed;
794  return pcmk_rc_ok;
795 }
796 
797 char *
798 crm_strdup_printf(char const *format, ...)
799 {
800  va_list ap;
801  int len = 0;
802  char *string = NULL;
803 
804  va_start(ap, format);
805  len = vasprintf (&string, format, ap);
806  CRM_ASSERT(len > 0);
807  va_end(ap);
808  return string;
809 }
810 
811 int
812 pcmk__parse_ll_range(const char *srcstring, long long *start, long long *end)
813 {
814  char *remainder = NULL;
815 
816  CRM_ASSERT(start != NULL && end != NULL);
817 
818  *start = PCMK__PARSE_INT_DEFAULT;
820 
821  crm_trace("Attempting to decode: [%s]", srcstring);
822  if (pcmk__str_empty(srcstring) || !strcmp(srcstring, "-")) {
823  return pcmk_rc_unknown_format;
824  }
825 
826  /* String starts with a dash, so this is either a range with
827  * no beginning or garbage.
828  * */
829  if (*srcstring == '-') {
830  int rc = scan_ll(srcstring+1, end, PCMK__PARSE_INT_DEFAULT, &remainder);
831 
832  if (rc != pcmk_rc_ok || *remainder != '\0') {
833  return pcmk_rc_unknown_format;
834  } else {
835  return pcmk_rc_ok;
836  }
837  }
838 
839  if (scan_ll(srcstring, start, PCMK__PARSE_INT_DEFAULT,
840  &remainder) != pcmk_rc_ok) {
841  return pcmk_rc_unknown_format;
842  }
843 
844  if (*remainder && *remainder == '-') {
845  if (*(remainder+1)) {
846  char *more_remainder = NULL;
847  int rc = scan_ll(remainder+1, end, PCMK__PARSE_INT_DEFAULT,
848  &more_remainder);
849 
850  if (rc != pcmk_rc_ok || *more_remainder != '\0') {
851  return pcmk_rc_unknown_format;
852  }
853  }
854  } else if (*remainder && *remainder != '-') {
855  *start = PCMK__PARSE_INT_DEFAULT;
856  return pcmk_rc_unknown_format;
857  } else {
858  /* The input string contained only one number. Set start and end
859  * to the same value and return pcmk_rc_ok. This gives the caller
860  * a way to tell this condition apart from a range with no end.
861  */
862  *end = *start;
863  }
864 
865  return pcmk_rc_ok;
866 }
867 
880 gboolean
881 pcmk__str_in_list(GList *lst, const gchar *s)
882 {
883  if (lst == NULL) {
884  return FALSE;
885  }
886 
887  if (strcmp(lst->data, "*") == 0 && lst->next == NULL) {
888  return TRUE;
889  }
890 
891  return g_list_find_custom(lst, s, (GCompareFunc) strcmp) != NULL;
892 }
893 
894 static bool
895 str_any_of(bool casei, const char *s, va_list args)
896 {
897  bool rc = false;
898 
899  if (s != NULL) {
900  while (1) {
901  const char *ele = va_arg(args, const char *);
902 
903  if (ele == NULL) {
904  break;
905  } else if (pcmk__str_eq(s, ele,
906  casei? pcmk__str_casei : pcmk__str_none)) {
907  rc = true;
908  break;
909  }
910  }
911  }
912  return rc;
913 }
914 
928 bool
929 pcmk__strcase_any_of(const char *s, ...)
930 {
931  va_list ap;
932  bool rc;
933 
934  va_start(ap, s);
935  rc = str_any_of(true, s, ap);
936  va_end(ap);
937  return rc;
938 }
939 
952 bool
953 pcmk__str_any_of(const char *s, ...)
954 {
955  va_list ap;
956  bool rc;
957 
958  va_start(ap, s);
959  rc = str_any_of(false, s, ap);
960  va_end(ap);
961  return rc;
962 }
963 
975 bool
977 {
978  bool rc = false;
979  va_list ap;
980 
981  /*
982  * Passing a char to va_start() can generate compiler warnings,
983  * so ch is declared as an int.
984  */
985  va_start(ap, ch);
986 
987  while (1) {
988  const char *ele = va_arg(ap, const char *);
989 
990  if (ele == NULL) {
991  break;
992  } else if (strchr(ele, ch) != NULL) {
993  rc = true;
994  break;
995  }
996  }
997 
998  va_end(ap);
999  return rc;
1000 }
1001 
1018 int
1019 pcmk__numeric_strcasecmp(const char *s1, const char *s2)
1020 {
1021  while (*s1 && *s2) {
1022  if (isdigit(*s1) && isdigit(*s2)) {
1023  // If node names contain a number, sort numerically
1024 
1025  char *end1 = NULL;
1026  char *end2 = NULL;
1027  long num1 = strtol(s1, &end1, 10);
1028  long num2 = strtol(s2, &end2, 10);
1029 
1030  // allow ordering e.g. 007 > 7
1031  size_t len1 = end1 - s1;
1032  size_t len2 = end2 - s2;
1033 
1034  if (num1 < num2) {
1035  return -1;
1036  } else if (num1 > num2) {
1037  return 1;
1038  } else if (len1 < len2) {
1039  return -1;
1040  } else if (len1 > len2) {
1041  return 1;
1042  }
1043  s1 = end1;
1044  s2 = end2;
1045  } else {
1046  // Compare non-digits case-insensitively
1047  int lower1 = tolower(*s1);
1048  int lower2 = tolower(*s2);
1049 
1050  if (lower1 < lower2) {
1051  return -1;
1052  } else if (lower1 > lower2) {
1053  return 1;
1054  }
1055  ++s1;
1056  ++s2;
1057  }
1058  }
1059  if (!*s1 && *s2) {
1060  return -1;
1061  } else if (*s1 && !*s2) {
1062  return 1;
1063  }
1064  return 0;
1065 }
1066 
1067 /*
1068  * \brief Sort strings.
1069  *
1070  * This is your one-stop function for string comparison. By default, this
1071  * function works like g_strcmp0. That is, like strcmp but a NULL string
1072  * sorts before a non-NULL string.
1073  *
1074  * Behavior can be changed with various flags:
1075  *
1076  * - pcmk__str_regex - The second string is a regular expression that the
1077  * first string will be matched against.
1078  * - pcmk__str_casei - By default, comparisons are done taking case into
1079  * account. This flag makes comparisons case-insensitive.
1080  * This can be combined with pcmk__str_regex.
1081  * - pcmk__str_null_matches - If one string is NULL and the other is not,
1082  * still return 0.
1083  *
1084  * \param[in] s1 First string to compare
1085  * \param[in] s2 Second string to compare, or a regular expression to
1086  * match if pcmk__str_regex is set
1087  * \param[in] flags A bitfield of pcmk__str_flags to modify operation
1088  *
1089  * \retval -1 \p s1 is NULL or comes before \p s2
1090  * \retval 0 \p s1 and \p s2 are equal, or \p s1 is found in \p s2 if
1091  * pcmk__str_regex is set
1092  * \retval 1 \p s2 is NULL or \p s1 comes after \p s2, or if \p s2
1093  * is an invalid regular expression, or \p s1 was not found
1094  * in \p s2 if pcmk__str_regex is set.
1095  */
1096 int
1097 pcmk__strcmp(const char *s1, const char *s2, uint32_t flags)
1098 {
1099  /* If this flag is set, the second string is a regex. */
1100  if (pcmk_is_set(flags, pcmk__str_regex)) {
1101  regex_t *r_patt = calloc(1, sizeof(regex_t));
1102  int reg_flags = REG_EXTENDED | REG_NOSUB;
1103  int regcomp_rc = 0;
1104  int rc = 0;
1105 
1106  if (s1 == NULL || s2 == NULL) {
1107  free(r_patt);
1108  return 1;
1109  }
1110 
1111  if (pcmk_is_set(flags, pcmk__str_casei)) {
1112  reg_flags |= REG_ICASE;
1113  }
1114  regcomp_rc = regcomp(r_patt, s2, reg_flags);
1115  if (regcomp_rc != 0) {
1116  rc = 1;
1117  crm_err("Bad regex '%s' for update: %s", s2, strerror(regcomp_rc));
1118  } else {
1119  rc = regexec(r_patt, s1, 0, NULL, 0);
1120 
1121  if (rc != 0) {
1122  rc = 1;
1123  }
1124  }
1125 
1126  regfree(r_patt);
1127  free(r_patt);
1128  return rc;
1129  }
1130 
1131  /* If the strings are the same pointer, return 0 immediately. */
1132  if (s1 == s2) {
1133  return 0;
1134  }
1135 
1136  /* If this flag is set, return 0 if either (or both) of the input strings
1137  * are NULL. If neither one is NULL, we need to continue and compare
1138  * them normally.
1139  */
1140  if (pcmk_is_set(flags, pcmk__str_null_matches)) {
1141  if (s1 == NULL || s2 == NULL) {
1142  return 0;
1143  }
1144  }
1145 
1146  /* Handle the cases where one is NULL and the str_null_matches flag is not set.
1147  * A NULL string always sorts to the beginning.
1148  */
1149  if (s1 == NULL) {
1150  return -1;
1151  } else if (s2 == NULL) {
1152  return 1;
1153  }
1154 
1155  if (pcmk_is_set(flags, pcmk__str_casei)) {
1156  return strcasecmp(s1, s2);
1157  } else {
1158  return strcmp(s1, s2);
1159  }
1160 }
1161 
1162 // Deprecated functions kept only for backward API compatibility
1163 
1164 #include <crm/common/util_compat.h>
1165 
1166 gboolean
1167 safe_str_neq(const char *a, const char *b)
1168 {
1169  if (a == b) {
1170  return FALSE;
1171 
1172  } else if (a == NULL || b == NULL) {
1173  return TRUE;
1174 
1175  } else if (strcasecmp(a, b) == 0) {
1176  return FALSE;
1177  }
1178  return TRUE;
1179 }
1180 
1181 gboolean
1182 crm_str_eq(const char *a, const char *b, gboolean use_case)
1183 {
1184  if (use_case) {
1185  return g_strcmp0(a, b) == 0;
1186 
1187  /* TODO - Figure out which calls, if any, really need to be case independent */
1188  } else if (a == b) {
1189  return TRUE;
1190 
1191  } else if (a == NULL || b == NULL) {
1192  /* shouldn't be comparing NULLs */
1193  return FALSE;
1194 
1195  } else if (strcasecmp(a, b) == 0) {
1196  return TRUE;
1197  }
1198  return FALSE;
1199 }
1200 
1201 char *
1202 crm_itoa_stack(int an_int, char *buffer, size_t len)
1203 {
1204  if (buffer != NULL) {
1205  snprintf(buffer, len, "%d", an_int);
1206  }
1207  return buffer;
1208 }
1209 
1210 guint
1211 g_str_hash_traditional(gconstpointer v)
1212 {
1213  return pcmk__str_hash(v);
1214 }
1215 
1216 gboolean
1217 crm_strcase_equal(gconstpointer a, gconstpointer b)
1218 {
1219  return pcmk__strcase_equal(a, b);
1220 }
1221 
1222 guint
1223 crm_strcase_hash(gconstpointer v)
1224 {
1225  return pcmk__strcase_hash(v);
1226 }
1227 
1228 GHashTable *
1229 crm_str_table_dup(GHashTable *old_table)
1230 {
1231  return pcmk__str_table_dup(old_table);
1232 }
1233 
1234 long long
1235 crm_parse_ll(const char *text, const char *default_text)
1236 {
1237  long long result;
1238 
1239  if (text == NULL) {
1240  text = default_text;
1241  if (text == NULL) {
1242  crm_err("No default conversion value supplied");
1243  errno = EINVAL;
1244  return PCMK__PARSE_INT_DEFAULT;
1245  }
1246  }
1247  scan_ll(text, &result, PCMK__PARSE_INT_DEFAULT, NULL);
1248  return result;
1249 }
1250 
1251 int
1252 crm_parse_int(const char *text, const char *default_text)
1253 {
1254  long long result = crm_parse_ll(text, default_text);
1255 
1256  if (result < INT_MIN) {
1257  // If errno is ERANGE, crm_parse_ll() has already logged a message
1258  if (errno != ERANGE) {
1259  crm_err("Conversion of %s was clipped: %lld", text, result);
1260  errno = ERANGE;
1261  }
1262  return INT_MIN;
1263 
1264  } else if (result > INT_MAX) {
1265  // If errno is ERANGE, crm_parse_ll() has already logged a message
1266  if (errno != ERANGE) {
1267  crm_err("Conversion of %s was clipped: %lld", text, result);
1268  errno = ERANGE;
1269  }
1270  return INT_MAX;
1271  }
1272 
1273  return (int) result;
1274 }
1275 
1276 char *
1278 {
1279  return pcmk__trim(str);
1280 }
1281 
1282 int
1283 pcmk_numeric_strcasecmp(const char *s1, const char *s2)
1284 {
1285  return pcmk__numeric_strcasecmp(s1, s2);
1286 }
1287 
1288 // End deprecated API
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:218
void pcmk__add_separated_word(char **list, size_t *len, const char *word, const char *separator)
Definition: strings.c:702
const char * bz2_strerror(int rc)
Definition: results.c:726
char data[0]
Definition: cpg.c:55
bool pcmk__char_in_any_str(int ch,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:976
int pcmk__scan_min_int(const char *text, int *result, int minimum)
Definition: strings.c:127
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:929
gboolean pcmk__str_in_list(GList *lst, const gchar *s)
Definition: strings.c:881
char * crm_itoa_stack(int an_int, char *buf, size_t len)
Definition: strings.c:1202
guint crm_strcase_hash(gconstpointer v)
Definition: strings.c:1223
long long crm_get_msec(const char *input)
Parse a time+units string and return milliseconds equivalent.
Definition: strings.c:363
int crm_parse_int(const char *text, const char *default_text)
Definition: strings.c:1252
#define PCMK__PARSE_DBL_DEFAULT
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:420
char * strerror(int errnum)
bool pcmk__ends_with(const char *s, const char *match)
Definition: strings.c:535
#define CRM_BZ2_WORK
Definition: xml.h:46
#define PCMK__PARSE_INT_DEFAULT
int pcmk__scan_ll(const char *text, long long *result, long long default_value)
Definition: strings.c:97
#define crm_warn(fmt, args...)
Definition: logging.h:351
int pcmk__scan_port(const char *text, int *port)
Definition: strings.c:161
int pcmk__guint_from_hash(GHashTable *table, const char *key, guint default_val, guint *result)
Definition: strings.c:311
int rc
Definition: pcmk_fence.c:35
#define crm_debug(fmt, args...)
Definition: logging.h:355
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
Definition: strings.c:1182
guint g_str_hash_traditional(gconstpointer v)
Definition: strings.c:1211
#define crm_trace(fmt, args...)
Definition: logging.h:356
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:114
int pcmk__compress(const char *data, unsigned int length, unsigned int max, char **result, unsigned int *result_len)
Definition: strings.c:748
bool pcmk__str_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:953
int pcmk__scan_double(const char *text, double *result, const char *default_text, char **end_text)
Definition: strings.c:199
int pcmk_numeric_strcasecmp(const char *s1, const char *s2)
Definition: strings.c:1283
#define CRM_XS
Definition: logging.h:54
int crm_str_to_boolean(const char *s, int *ret)
Definition: strings.c:426
long long crm_parse_ll(const char *text, const char *default_text)
Definition: strings.c:1235
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:610
#define crm_err(fmt, args...)
Definition: logging.h:350
#define CRM_ASSERT(expr)
Definition: results.h:42
GHashTable * pcmk__str_table_dup(GHashTable *old_table)
Definition: strings.c:674
gboolean safe_str_neq(const char *a, const char *b)
Definition: strings.c:1167
int pcmk__strcmp(const char *s1, const char *s2, uint32_t flags)
Definition: strings.c:1097
int pcmk__numeric_strcasecmp(const char *s1, const char *s2)
Definition: strings.c:1019
int pcmk__parse_ll_range(const char *srcstring, long long *start, long long *end)
Definition: strings.c:812
gboolean crm_strcase_equal(gconstpointer a, gconstpointer b)
Definition: strings.c:1217
gboolean crm_is_true(const char *s)
Definition: strings.c:415
bool pcmk__starts_with(const char *str, const char *prefix)
Check whether a string starts with a certain sequence.
Definition: strings.c:483
#define CRM_BZ2_BLOCKS
Definition: xml.h:45
char * pcmk__trim(char *str)
Definition: strings.c:455
char * crm_strip_trailing_newline(char *str)
Definition: strings.c:1277
GHashTable * crm_str_table_dup(GHashTable *old_table)
Definition: strings.c:1229
#define WHITESPACE
Definition: strings.c:350
Deprecated Pacemaker utilities.
bool pcmk__ends_with_ext(const char *s, const char *match)
Definition: strings.c:562
#define NUMCHARS
Definition: strings.c:346
uint64_t flags
Definition: remote.c:149
GHashTable * pcmk__strikey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:648