pacemaker  1.1.24-3850484742
Scalable High-Availability cluster resource manager
strings.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include <crm_internal.h>
20 
21 #ifndef _GNU_SOURCE
22 # define _GNU_SOURCE
23 #endif
24 
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <limits.h>
29 #include <bzlib.h>
30 #include <sys/types.h>
31 
32 char *
33 crm_concat(const char *prefix, const char *suffix, char join)
34 {
35  int len = 0;
36  char *new_str = NULL;
37 
38  CRM_ASSERT(prefix != NULL);
39  CRM_ASSERT(suffix != NULL);
40  len = strlen(prefix) + strlen(suffix) + 2;
41 
42  new_str = malloc(len);
43  if(new_str) {
44  sprintf(new_str, "%s%c%s", prefix, join, suffix);
45  new_str[len - 1] = 0;
46  }
47  return new_str;
48 }
49 
50 char *
51 crm_itoa_stack(int an_int, char *buffer, size_t len)
52 {
53  if (buffer != NULL) {
54  snprintf(buffer, len, "%d", an_int);
55  }
56 
57  return buffer;
58 }
59 
60 char *
61 crm_itoa(int an_int)
62 {
63  int len = 32;
64  char *buffer = NULL;
65 
66  buffer = malloc(len + 1);
67  if (buffer != NULL) {
68  snprintf(buffer, len, "%d", an_int);
69  }
70 
71  return buffer;
72 }
73 
74 void
76 {
77  free(data);
78 }
79 
80 long long
81 crm_int_helper(const char *text, char **end_text)
82 {
83  long long result = -1;
84  char *local_end_text = NULL;
85  int saved_errno = 0;
86 
87  errno = 0;
88 
89  if (text != NULL) {
90 #ifdef ANSI_ONLY
91  if (end_text != NULL) {
92  result = strtol(text, end_text, 10);
93  } else {
94  result = strtol(text, &local_end_text, 10);
95  }
96 #else
97  if (end_text != NULL) {
98  result = strtoll(text, end_text, 10);
99  } else {
100  result = strtoll(text, &local_end_text, 10);
101  }
102 #endif
103 
104  saved_errno = errno;
105  if (errno == EINVAL) {
106  crm_err("Conversion of %s failed", text);
107  result = -1;
108 
109  } else if (errno == ERANGE) {
110  crm_err("Conversion of %s was clipped: %lld", text, result);
111 
112  } else if (errno != 0) {
113  crm_perror(LOG_ERR, "Conversion of %s failed", text);
114  }
115 
116  if (local_end_text != NULL && local_end_text[0] != '\0') {
117  crm_err("Characters left over after parsing '%s': '%s'", text, local_end_text);
118  }
119 
120  errno = saved_errno;
121  }
122  return result;
123 }
124 
133 long long
134 crm_parse_ll(const char *text, const char *default_text)
135 {
136  if (text == NULL) {
137  text = default_text;
138  if (text == NULL) {
139  crm_err("No default conversion value supplied");
140  errno = EINVAL;
141  return -1;
142  }
143  }
144  return crm_int_helper(text, NULL);
145 }
146 
156 int
157 crm_parse_int(const char *text, const char *default_text)
158 {
159  long long result = crm_parse_ll(text, default_text);
160 
161  if (result < INT_MIN) {
162  // If errno is ERANGE, crm_parse_ll() has already logged a message
163  if (errno != ERANGE) {
164  crm_err("Conversion of %s was clipped: %lld", text, result);
165  errno = ERANGE;
166  }
167  return INT_MIN;
168 
169  } else if (result > INT_MAX) {
170  // If errno is ERANGE, crm_parse_ll() has already logged a message
171  if (errno != ERANGE) {
172  crm_err("Conversion of %s was clipped: %lld", text, result);
173  errno = ERANGE;
174  }
175  return INT_MAX;
176  }
177 
178  return (int) result;
179 }
180 
181 gboolean
182 safe_str_neq(const char *a, const char *b)
183 {
184  if (a == b) {
185  return FALSE;
186 
187  } else if (a == NULL || b == NULL) {
188  return TRUE;
189 
190  } else if (strcasecmp(a, b) == 0) {
191  return FALSE;
192  }
193  return TRUE;
194 }
195 
196 gboolean
197 crm_is_true(const char *s)
198 {
199  gboolean ret = FALSE;
200 
201  if (s != NULL) {
202  crm_str_to_boolean(s, &ret);
203  }
204  return ret;
205 }
206 
207 int
208 crm_str_to_boolean(const char *s, int *ret)
209 {
210  if (s == NULL) {
211  return -1;
212 
213  } else if (strcasecmp(s, "true") == 0
214  || strcasecmp(s, "on") == 0
215  || strcasecmp(s, "yes") == 0 || strcasecmp(s, "y") == 0 || strcasecmp(s, "1") == 0) {
216  *ret = TRUE;
217  return 1;
218 
219  } else if (strcasecmp(s, "false") == 0
220  || strcasecmp(s, "off") == 0
221  || strcasecmp(s, "no") == 0 || strcasecmp(s, "n") == 0 || strcasecmp(s, "0") == 0) {
222  *ret = FALSE;
223  return 1;
224  }
225  return -1;
226 }
227 
228 char *
230 {
231  int len;
232 
233  if (str == NULL) {
234  return str;
235  }
236 
237  for (len = strlen(str) - 1; len >= 0 && str[len] == '\n'; len--) {
238  str[len] = '\0';
239  }
240 
241  return str;
242 }
243 
244 gboolean
245 crm_str_eq(const char *a, const char *b, gboolean use_case)
246 {
247  if (use_case) {
248  return g_strcmp0(a, b) == 0;
249 
250  /* TODO - Figure out which calls, if any, really need to be case independent */
251  } else if (a == b) {
252  return TRUE;
253 
254  } else if (a == NULL || b == NULL) {
255  /* shouldn't be comparing NULLs */
256  return FALSE;
257 
258  } else if (strcasecmp(a, b) == 0) {
259  return TRUE;
260  }
261  return FALSE;
262 }
263 
264 static inline const char * null2emptystr(const char *);
265 static inline const char *
266 null2emptystr(const char *input)
267 {
268  return (input == NULL) ? "" : input;
269 }
270 
283 bool
284 crm_starts_with(const char *str, const char *prefix)
285 {
286  const char *s = str;
287  const char *p = prefix;
288 
289  if (!s || !p) {
290  return FALSE;
291  }
292  while (*s && *p) {
293  if (*s++ != *p++) {
294  return FALSE;
295  }
296  }
297  return (*p == 0);
298 }
299 
300 static inline int crm_ends_with_internal(const char *, const char *, gboolean);
301 static inline int
302 crm_ends_with_internal(const char *s, const char *match, gboolean as_extension)
303 {
304  if ((s == NULL) || (match == NULL)) {
305  return 0;
306  } else {
307  size_t slen, mlen;
308 
309  if (match[0] != '\0'
310  && (as_extension /* following commented out for inefficiency:
311  || strchr(&match[1], match[0]) == NULL */))
312  return !strcmp(null2emptystr(strrchr(s, match[0])), match);
313 
314  if ((mlen = strlen(match)) == 0)
315  return 1;
316  slen = strlen(s);
317  return ((slen >= mlen) && !strcmp(s + slen - mlen, match));
318  }
319 }
320 
333 gboolean
334 crm_ends_with(const char *s, const char *match)
335 {
336  return crm_ends_with_internal(s, match, FALSE);
337 }
338 
362 gboolean
363 crm_ends_with_ext(const char *s, const char *match)
364 {
365  return crm_ends_with_internal(s, match, TRUE);
366 }
367 
368 /*
369  * This re-implements g_str_hash as it was prior to glib2-2.28:
370  *
371  * http://git.gnome.org/browse/glib/commit/?id=354d655ba8a54b754cb5a3efb42767327775696c
372  *
373  * Note that the new g_str_hash is presumably a *better* hash (it's actually
374  * a correct implementation of DJB's hash), but we need to preserve existing
375  * behaviour, because the hash key ultimately determines the "sort" order
376  * when iterating through GHashTables, which affects allocation of scores to
377  * clone instances when iterating through rsc->allowed_nodes. It (somehow)
378  * also appears to have some minor impact on the ordering of a few
379  * pseudo_event IDs in the transition graph.
380  */
381 guint
382 g_str_hash_traditional(gconstpointer v)
383 {
384  const signed char *p;
385  guint32 h = 0;
386 
387  for (p = v; *p != '\0'; p++)
388  h = (h << 5) - h + *p;
389 
390  return h;
391 }
392 
393 guint
394 crm_strcase_hash(gconstpointer v)
395 {
396  const signed char *p;
397  guint32 h = 0;
398 
399  for (p = v; *p != '\0'; p++)
400  h = (h << 5) - h + g_ascii_tolower(*p);
401 
402  return h;
403 }
404 
405 static void
406 copy_str_table_entry(gpointer key, gpointer value, gpointer user_data)
407 {
408  if (key && value && user_data) {
409  g_hash_table_insert((GHashTable*)user_data, strdup(key), strdup(value));
410  }
411 }
412 
413 GHashTable *
414 crm_str_table_dup(GHashTable *old_table)
415 {
416  GHashTable *new_table = NULL;
417 
418  if (old_table) {
419  new_table = crm_str_table_new();
420  g_hash_table_foreach(old_table, copy_str_table_entry, new_table);
421  }
422  return new_table;
423 }
424 
425 char *
426 add_list_element(char *list, const char *value)
427 {
428  int len = 0;
429  int last = 0;
430 
431  if (value == NULL) {
432  return list;
433  }
434  if (list) {
435  last = strlen(list);
436  }
437  len = last + 2; /* +1 space, +1 EOS */
438  len += strlen(value);
439  list = realloc_safe(list, len);
440  sprintf(list + last, " %s", value);
441  return list;
442 }
443 
444 bool
445 crm_compress_string(const char *data, int length, int max, char **result, unsigned int *result_len)
446 {
447  int rc;
448  char *compressed = NULL;
449  char *uncompressed = strdup(data);
450  struct timespec after_t;
451  struct timespec before_t;
452 
453  if(max == 0) {
454  max = (length * 1.1) + 600; /* recommended size */
455  }
456 
457 #ifdef CLOCK_MONOTONIC
458  clock_gettime(CLOCK_MONOTONIC, &before_t);
459 #endif
460 
461  /* coverity[returned_null] Ignore */
462  compressed = malloc(max);
463 
464  *result_len = max;
465  rc = BZ2_bzBuffToBuffCompress(compressed, result_len, uncompressed, length, CRM_BZ2_BLOCKS, 0,
466  CRM_BZ2_WORK);
467 
468  free(uncompressed);
469 
470  if (rc != BZ_OK) {
471  crm_err("Compression of %d bytes failed: %s (%d)", length, bz2_strerror(rc), rc);
472  free(compressed);
473  return FALSE;
474  }
475 
476 #ifdef CLOCK_MONOTONIC
477  clock_gettime(CLOCK_MONOTONIC, &after_t);
478 
479  crm_trace("Compressed %d bytes into %d (ratio %d:1) in %.0fms",
480  length, *result_len, length / (*result_len),
481  difftime (after_t.tv_sec, before_t.tv_sec) * 1000 +
482  (after_t.tv_nsec - before_t.tv_nsec) / 1e6);
483 #else
484  crm_trace("Compressed %d bytes into %d (ratio %d:1)",
485  length, *result_len, length / (*result_len));
486 #endif
487 
488  *result = compressed;
489  return TRUE;
490 }
491 
503 gint
504 crm_alpha_sort(gconstpointer a, gconstpointer b)
505 {
506  if (!a && !b) {
507  return 0;
508  } else if (!a) {
509  return -1;
510  } else if (!b) {
511  return 1;
512  }
513  return strcasecmp(a, b);
514 }
bool crm_compress_string(const char *data, int length, int max, char **result, unsigned int *result_len)
Definition: strings.c:445
long long crm_int_helper(const char *text, char **end_text)
Definition: strings.c:81
gboolean crm_ends_with(const char *s, const char *match)
Definition: strings.c:334
guint g_str_hash_traditional(gconstpointer v)
Definition: strings.c:382
#define CRM_BZ2_WORK
Definition: xml.h:40
#define crm_trace(fmt, args...)
Definition: logging.h:280
char * add_list_element(char *list, const char *value)
Definition: strings.c:426
gboolean crm_ends_with_ext(const char *s, const char *match)
Definition: strings.c:363
gint crm_alpha_sort(gconstpointer a, gconstpointer b)
Compare two strings alphabetically (case-insensitive)
Definition: strings.c:504
void g_hash_destroy_str(gpointer data)
Definition: strings.c:75
char * crm_itoa_stack(int an_int, char *buffer, size_t len)
Definition: strings.c:51
int crm_str_to_boolean(const char *s, int *ret)
Definition: strings.c:208
char * crm_strip_trailing_newline(char *str)
Definition: strings.c:229
gboolean crm_is_true(const char *s)
Definition: strings.c:197
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
Definition: strings.c:245
int crm_parse_int(const char *text, const char *default_text)
Parse an integer value from a string.
Definition: strings.c:157
long long crm_parse_ll(const char *text, const char *default_text)
Parse a long long integer value from a string.
Definition: strings.c:134
#define crm_perror(level, fmt, args...)
Log a system error message.
Definition: logging.h:252
#define crm_err(fmt, args...)
Definition: logging.h:274
const char * bz2_strerror(int rc)
Definition: logging.c:1390
char * crm_itoa(int an_int)
Definition: strings.c:61
bool crm_starts_with(const char *str, const char *prefix)
Check whether a string starts with a certain sequence.
Definition: strings.c:284
#define CRM_ASSERT(expr)
Definition: error.h:20
char data[0]
Definition: internal.h:86
gboolean safe_str_neq(const char *a, const char *b)
Definition: strings.c:182
guint crm_strcase_hash(gconstpointer v)
Definition: strings.c:394
char * crm_concat(const char *prefix, const char *suffix, char join)
Definition: strings.c:33
#define CRM_BZ2_BLOCKS
Definition: xml.h:39
GHashTable * crm_str_table_dup(GHashTable *old_table)
Definition: strings.c:414