pacemaker  1.1.18-7fdfbbe
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 (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 <bzlib.h>
29 #include <sys/types.h>
30 
31 char *
32 crm_concat(const char *prefix, const char *suffix, char join)
33 {
34  int len = 0;
35  char *new_str = NULL;
36 
37  CRM_ASSERT(prefix != NULL);
38  CRM_ASSERT(suffix != NULL);
39  len = strlen(prefix) + strlen(suffix) + 2;
40 
41  new_str = malloc(len);
42  if(new_str) {
43  sprintf(new_str, "%s%c%s", prefix, join, suffix);
44  new_str[len - 1] = 0;
45  }
46  return new_str;
47 }
48 
49 char *
50 crm_itoa_stack(int an_int, char *buffer, size_t len)
51 {
52  if (buffer != NULL) {
53  snprintf(buffer, len, "%d", an_int);
54  }
55 
56  return buffer;
57 }
58 
59 char *
60 crm_itoa(int an_int)
61 {
62  int len = 32;
63  char *buffer = NULL;
64 
65  buffer = malloc(len + 1);
66  if (buffer != NULL) {
67  snprintf(buffer, len, "%d", an_int);
68  }
69 
70  return buffer;
71 }
72 
73 void
75 {
76  free(data);
77 }
78 
79 long long
80 crm_int_helper(const char *text, char **end_text)
81 {
82  long long result = -1;
83  char *local_end_text = NULL;
84  int saved_errno = 0;
85 
86  errno = 0;
87 
88  if (text != NULL) {
89 #ifdef ANSI_ONLY
90  if (end_text != NULL) {
91  result = strtol(text, end_text, 10);
92  } else {
93  result = strtol(text, &local_end_text, 10);
94  }
95 #else
96  if (end_text != NULL) {
97  result = strtoll(text, end_text, 10);
98  } else {
99  result = strtoll(text, &local_end_text, 10);
100  }
101 #endif
102 
103  saved_errno = errno;
104  if (errno == EINVAL) {
105  crm_err("Conversion of %s failed", text);
106  result = -1;
107 
108  } else if (errno == ERANGE) {
109  crm_err("Conversion of %s was clipped: %lld", text, result);
110 
111  } else if (errno != 0) {
112  crm_perror(LOG_ERR, "Conversion of %s failed", text);
113  }
114 
115  if (local_end_text != NULL && local_end_text[0] != '\0') {
116  crm_err("Characters left over after parsing '%s': '%s'", text, local_end_text);
117  }
118 
119  errno = saved_errno;
120  }
121  return result;
122 }
123 
124 int
125 crm_parse_int(const char *text, const char *default_text)
126 {
127  int atoi_result = -1;
128 
129  if (text != NULL) {
130  atoi_result = crm_int_helper(text, NULL);
131  if (errno == 0) {
132  return atoi_result;
133  }
134  }
135 
136  if (default_text != NULL) {
137  atoi_result = crm_int_helper(default_text, NULL);
138  if (errno == 0) {
139  return atoi_result;
140  }
141 
142  } else {
143  crm_err("No default conversion value supplied");
144  }
145 
146  return -1;
147 }
148 
149 gboolean
150 safe_str_neq(const char *a, const char *b)
151 {
152  if (a == b) {
153  return FALSE;
154 
155  } else if (a == NULL || b == NULL) {
156  return TRUE;
157 
158  } else if (strcasecmp(a, b) == 0) {
159  return FALSE;
160  }
161  return TRUE;
162 }
163 
164 gboolean
165 crm_is_true(const char *s)
166 {
167  gboolean ret = FALSE;
168 
169  if (s != NULL) {
170  crm_str_to_boolean(s, &ret);
171  }
172  return ret;
173 }
174 
175 int
176 crm_str_to_boolean(const char *s, int *ret)
177 {
178  if (s == NULL) {
179  return -1;
180 
181  } else if (strcasecmp(s, "true") == 0
182  || strcasecmp(s, "on") == 0
183  || strcasecmp(s, "yes") == 0 || strcasecmp(s, "y") == 0 || strcasecmp(s, "1") == 0) {
184  *ret = TRUE;
185  return 1;
186 
187  } else if (strcasecmp(s, "false") == 0
188  || strcasecmp(s, "off") == 0
189  || strcasecmp(s, "no") == 0 || strcasecmp(s, "n") == 0 || strcasecmp(s, "0") == 0) {
190  *ret = FALSE;
191  return 1;
192  }
193  return -1;
194 }
195 
196 char *
198 {
199  int len;
200 
201  if (str == NULL) {
202  return str;
203  }
204 
205  for (len = strlen(str) - 1; len >= 0 && str[len] == '\n'; len--) {
206  str[len] = '\0';
207  }
208 
209  return str;
210 }
211 
212 gboolean
213 crm_str_eq(const char *a, const char *b, gboolean use_case)
214 {
215  if (use_case) {
216  return g_strcmp0(a, b) == 0;
217 
218  /* TODO - Figure out which calls, if any, really need to be case independent */
219  } else if (a == b) {
220  return TRUE;
221 
222  } else if (a == NULL || b == NULL) {
223  /* shouldn't be comparing NULLs */
224  return FALSE;
225 
226  } else if (strcasecmp(a, b) == 0) {
227  return TRUE;
228  }
229  return FALSE;
230 }
231 
232 static inline const char * null2emptystr(const char *);
233 static inline const char *
234 null2emptystr(const char *input)
235 {
236  return (input == NULL) ? "" : input;
237 }
238 
251 bool
252 crm_starts_with(const char *str, const char *prefix)
253 {
254  const char *s = str;
255  const char *p = prefix;
256 
257  if (!s || !p) {
258  return FALSE;
259  }
260  while (*s && *p) {
261  if (*s++ != *p++) {
262  return FALSE;
263  }
264  }
265  return (*p == 0);
266 }
267 
268 static inline int crm_ends_with_internal(const char *, const char *, gboolean);
269 static inline int
270 crm_ends_with_internal(const char *s, const char *match, gboolean as_extension)
271 {
272  if ((s == NULL) || (match == NULL)) {
273  return 0;
274  } else {
275  size_t slen, mlen;
276 
277  if (match[0] != '\0'
278  && (as_extension /* following commented out for inefficiency:
279  || strchr(&match[1], match[0]) == NULL */))
280  return !strcmp(null2emptystr(strrchr(s, match[0])), match);
281 
282  if ((mlen = strlen(match)) == 0)
283  return 1;
284  slen = strlen(s);
285  return ((slen >= mlen) && !strcmp(s + slen - mlen, match));
286  }
287 }
288 
301 gboolean
302 crm_ends_with(const char *s, const char *match)
303 {
304  return crm_ends_with_internal(s, match, FALSE);
305 }
306 
330 gboolean
331 crm_ends_with_ext(const char *s, const char *match)
332 {
333  return crm_ends_with_internal(s, match, TRUE);
334 }
335 
336 /*
337  * This re-implements g_str_hash as it was prior to glib2-2.28:
338  *
339  * http://git.gnome.org/browse/glib/commit/?id=354d655ba8a54b754cb5a3efb42767327775696c
340  *
341  * Note that the new g_str_hash is presumably a *better* hash (it's actually
342  * a correct implementation of DJB's hash), but we need to preserve existing
343  * behaviour, because the hash key ultimately determines the "sort" order
344  * when iterating through GHashTables, which affects allocation of scores to
345  * clone instances when iterating through rsc->allowed_nodes. It (somehow)
346  * also appears to have some minor impact on the ordering of a few
347  * pseudo_event IDs in the transition graph.
348  */
349 guint
350 g_str_hash_traditional(gconstpointer v)
351 {
352  const signed char *p;
353  guint32 h = 0;
354 
355  for (p = v; *p != '\0'; p++)
356  h = (h << 5) - h + *p;
357 
358  return h;
359 }
360 
361 guint
362 crm_strcase_hash(gconstpointer v)
363 {
364  const signed char *p;
365  guint32 h = 0;
366 
367  for (p = v; *p != '\0'; p++)
368  h = (h << 5) - h + g_ascii_tolower(*p);
369 
370  return h;
371 }
372 
373 static void
374 copy_str_table_entry(gpointer key, gpointer value, gpointer user_data)
375 {
376  if (key && value && user_data) {
377  g_hash_table_insert((GHashTable*)user_data, strdup(key), strdup(value));
378  }
379 }
380 
381 GHashTable *
382 crm_str_table_dup(GHashTable *old_table)
383 {
384  GHashTable *new_table = NULL;
385 
386  if (old_table) {
387  new_table = crm_str_table_new();
388  g_hash_table_foreach(old_table, copy_str_table_entry, new_table);
389  }
390  return new_table;
391 }
392 
393 char *
394 add_list_element(char *list, const char *value)
395 {
396  int len = 0;
397  int last = 0;
398 
399  if (value == NULL) {
400  return list;
401  }
402  if (list) {
403  last = strlen(list);
404  }
405  len = last + 2; /* +1 space, +1 EOS */
406  len += strlen(value);
407  list = realloc_safe(list, len);
408  sprintf(list + last, " %s", value);
409  return list;
410 }
411 
412 bool
413 crm_compress_string(const char *data, int length, int max, char **result, unsigned int *result_len)
414 {
415  int rc;
416  char *compressed = NULL;
417  char *uncompressed = strdup(data);
418  struct timespec after_t;
419  struct timespec before_t;
420 
421  if(max == 0) {
422  max = (length * 1.1) + 600; /* recommended size */
423  }
424 
425 #ifdef CLOCK_MONOTONIC
426  clock_gettime(CLOCK_MONOTONIC, &before_t);
427 #endif
428 
429  /* coverity[returned_null] Ignore */
430  compressed = malloc(max);
431 
432  *result_len = max;
433  rc = BZ2_bzBuffToBuffCompress(compressed, result_len, uncompressed, length, CRM_BZ2_BLOCKS, 0,
434  CRM_BZ2_WORK);
435 
436  free(uncompressed);
437 
438  if (rc != BZ_OK) {
439  crm_err("Compression of %d bytes failed: %s (%d)", length, bz2_strerror(rc), rc);
440  free(compressed);
441  return FALSE;
442  }
443 
444 #ifdef CLOCK_MONOTONIC
445  clock_gettime(CLOCK_MONOTONIC, &after_t);
446 
447  crm_trace("Compressed %d bytes into %d (ratio %d:1) in %.0fms",
448  length, *result_len, length / (*result_len),
449  difftime (after_t.tv_sec, before_t.tv_sec) * 1000 +
450  (after_t.tv_nsec - before_t.tv_nsec) / 1e6);
451 #else
452  crm_trace("Compressed %d bytes into %d (ratio %d:1)",
453  length, *result_len, length / (*result_len));
454 #endif
455 
456  *result = compressed;
457  return TRUE;
458 }
459 
471 gint
472 crm_alpha_sort(gconstpointer a, gconstpointer b)
473 {
474  if (!a && !b) {
475  return 0;
476  } else if (!a) {
477  return -1;
478  } else if (!b) {
479  return 1;
480  }
481  return strcasecmp(a, b);
482 }
gboolean safe_str_neq(const char *a, const char *b)
Definition: strings.c:150
guint g_str_hash_traditional(gconstpointer v)
Definition: strings.c:350
long long crm_int_helper(const char *text, char **end_text)
Definition: strings.c:80
int crm_parse_int(const char *text, const char *default_text)
Definition: strings.c:125
bool crm_starts_with(const char *str, const char *prefix)
Check whether a string starts with a certain sequence.
Definition: strings.c:252
#define CRM_BZ2_WORK
Definition: xml.h:49
char * add_list_element(char *list, const char *value)
Definition: strings.c:394
gint crm_alpha_sort(gconstpointer a, gconstpointer b)
Compare two strings alphabetically (case-insensitive)
Definition: strings.c:472
#define crm_trace(fmt, args...)
Definition: logging.h:254
guint crm_strcase_hash(gconstpointer v)
Definition: strings.c:362
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
Definition: strings.c:213
char * crm_itoa_stack(int an_int, char *buf, size_t len)
Definition: strings.c:50
gboolean crm_ends_with_ext(const char *s, const char *match)
Definition: strings.c:331
gboolean crm_ends_with(const char *s, const char *match)
Definition: strings.c:302
bool crm_compress_string(const char *data, int length, int max, char **result, unsigned int *result_len)
Definition: strings.c:413
int crm_str_to_boolean(const char *s, int *ret)
Definition: strings.c:176
#define crm_perror(level, fmt, args...)
Log a system error message.
Definition: logging.h:226
#define crm_err(fmt, args...)
Definition: logging.h:248
const char * bz2_strerror(int rc)
Definition: logging.c:1198
GHashTable * crm_str_table_dup(GHashTable *old_table)
Definition: strings.c:382
#define CRM_ASSERT(expr)
Definition: error.h:35
char data[0]
Definition: internal.h:58
gboolean crm_is_true(const char *s)
Definition: strings.c:165
#define CRM_BZ2_BLOCKS
Definition: xml.h:48
char * crm_strip_trailing_newline(char *str)
Definition: strings.c:197
char * crm_concat(const char *prefix, const char *suffix, char join)
Definition: strings.c:32
char * crm_itoa(int an_int)
Definition: strings.c:60
void g_hash_destroy_str(gpointer data)
Definition: strings.c:74