/src/pacemaker/lib/common/strings.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2004-2026 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 <stdarg.h> // va_list, etc. |
14 | | #include <stdbool.h> |
15 | | #include <stdio.h> |
16 | | #include <string.h> |
17 | | #include <stdlib.h> |
18 | | #include <ctype.h> |
19 | | #include <float.h> // DBL_MIN |
20 | | #include <limits.h> |
21 | | #include <bzlib.h> |
22 | | #include <sys/types.h> |
23 | | |
24 | | /*! |
25 | | * \internal |
26 | | * \brief Scan a long long integer from a string |
27 | | * |
28 | | * \param[in] text String to scan |
29 | | * \param[out] result If not NULL, where to store scanned value |
30 | | * \param[in] default_value Value to use if text is NULL or invalid |
31 | | * \param[out] end_text If not NULL, where to store pointer to first |
32 | | * non-integer character |
33 | | * |
34 | | * \return Standard Pacemaker return code (\c pcmk_rc_ok on success, |
35 | | * \c pcmk_rc_bad_input on failed string conversion due to invalid |
36 | | * input, or \c ERANGE if outside long long range) |
37 | | * \note Sets \c errno on error |
38 | | */ |
39 | | static int |
40 | | scan_ll(const char *text, long long *result, long long default_value, |
41 | | char **end_text) |
42 | 1.59k | { |
43 | 1.59k | long long local_result = default_value; |
44 | 1.59k | char *local_end_text = NULL; |
45 | 1.59k | int rc = pcmk_rc_ok; |
46 | | |
47 | 1.59k | errno = 0; |
48 | 1.59k | if (text != NULL) { |
49 | 1.59k | local_result = strtoll(text, &local_end_text, 10); |
50 | 1.59k | if (errno == ERANGE) { |
51 | 4 | rc = errno; |
52 | 4 | pcmk__debug("Integer parsed from '%s' was clipped to %lld", text, |
53 | 4 | local_result); |
54 | | |
55 | 1.59k | } else if (local_end_text == text) { |
56 | 914 | rc = pcmk_rc_bad_input; |
57 | 914 | local_result = default_value; |
58 | 914 | pcmk__debug("Could not parse integer from '%s' (using %lld " |
59 | 914 | "instead): No digits found", |
60 | 914 | text, default_value); |
61 | | |
62 | 914 | } else if (errno != 0) { |
63 | 0 | rc = errno; |
64 | 0 | local_result = default_value; |
65 | 0 | pcmk__debug("Could not parse integer from '%s' (using %lld " |
66 | 0 | "instead): %s", |
67 | 0 | text, default_value, pcmk_rc_str(rc)); |
68 | 0 | } |
69 | | |
70 | 1.59k | if ((end_text == NULL) && !pcmk__str_empty(local_end_text)) { |
71 | 0 | pcmk__debug("Characters left over after parsing '%s': '%s'", |
72 | 0 | text, local_end_text); |
73 | 0 | } |
74 | 1.59k | errno = rc; |
75 | 1.59k | } |
76 | 1.59k | if (end_text != NULL) { |
77 | 1.59k | *end_text = local_end_text; |
78 | 1.59k | } |
79 | 1.59k | if (result != NULL) { |
80 | 1.59k | *result = local_result; |
81 | 1.59k | } |
82 | 1.59k | return rc; |
83 | 1.59k | } |
84 | | |
85 | | /*! |
86 | | * \internal |
87 | | * \brief Scan a long long integer value from a string |
88 | | * |
89 | | * \param[in] text The string to scan (may be NULL) |
90 | | * \param[out] result Where to store result (or NULL to ignore) |
91 | | * \param[in] default_value Value to use if text is NULL or invalid |
92 | | * |
93 | | * \return Standard Pacemaker return code |
94 | | */ |
95 | | int |
96 | | pcmk__scan_ll(const char *text, long long *result, long long default_value) |
97 | 0 | { |
98 | 0 | long long local_result = default_value; |
99 | 0 | int rc = scan_ll(text, &local_result, default_value, NULL); |
100 | |
|
101 | 0 | if (result != NULL) { |
102 | 0 | *result = local_result; |
103 | 0 | } |
104 | 0 | return rc; |
105 | 0 | } |
106 | | |
107 | | /*! |
108 | | * \internal |
109 | | * \brief Scan an integer value from a string, constrained to a minimum |
110 | | * |
111 | | * \param[in] text The string to scan (may be NULL) |
112 | | * \param[out] result Where to store result (or NULL to ignore) |
113 | | * \param[in] minimum Value to use as default and minimum |
114 | | * |
115 | | * \return Standard Pacemaker return code |
116 | | * \note If the value is larger than the maximum integer, EOVERFLOW will be |
117 | | * returned and \p result will be set to the maximum integer. |
118 | | */ |
119 | | int |
120 | | pcmk__scan_min_int(const char *text, int *result, int minimum) |
121 | 0 | { |
122 | 0 | int rc; |
123 | 0 | long long result_ll; |
124 | |
|
125 | 0 | rc = pcmk__scan_ll(text, &result_ll, (long long) minimum); |
126 | |
|
127 | 0 | if (result_ll < (long long) minimum) { |
128 | 0 | pcmk__warn("Clipped '%s' to minimum acceptable value %d", text, |
129 | 0 | minimum); |
130 | 0 | result_ll = (long long) minimum; |
131 | |
|
132 | 0 | } else if (result_ll > INT_MAX) { |
133 | 0 | pcmk__warn("Clipped '%s' to maximum integer %d", text, INT_MAX); |
134 | 0 | result_ll = (long long) INT_MAX; |
135 | 0 | rc = EOVERFLOW; |
136 | 0 | } |
137 | |
|
138 | 0 | if (result != NULL) { |
139 | 0 | *result = (int) result_ll; |
140 | 0 | } |
141 | 0 | return rc; |
142 | 0 | } |
143 | | |
144 | | /*! |
145 | | * \internal |
146 | | * \brief Scan a TCP port number from a string |
147 | | * |
148 | | * \param[in] text The string to scan |
149 | | * \param[out] port Where to store result (or NULL to ignore) |
150 | | * |
151 | | * \return Standard Pacemaker return code |
152 | | * \note \p port will be -1 if \p text is NULL or invalid |
153 | | */ |
154 | | int |
155 | | pcmk__scan_port(const char *text, int *port) |
156 | 0 | { |
157 | 0 | long long port_ll; |
158 | 0 | int rc = pcmk__scan_ll(text, &port_ll, -1LL); |
159 | |
|
160 | 0 | if (rc != pcmk_rc_ok) { |
161 | 0 | pcmk__warn("'%s' is not a valid port: %s", text, pcmk_rc_str(rc)); |
162 | |
|
163 | 0 | } else if ((text != NULL) // wasn't default or invalid |
164 | 0 | && ((port_ll < 0LL) || (port_ll > 65535LL))) { |
165 | 0 | pcmk__warn("Ignoring port specification '%s' not in valid range " |
166 | 0 | "(0-65535)", |
167 | 0 | text); |
168 | 0 | rc = (port_ll < 0LL)? pcmk_rc_before_range : pcmk_rc_after_range; |
169 | 0 | port_ll = -1LL; |
170 | 0 | } |
171 | 0 | if (port != NULL) { |
172 | 0 | *port = (int) port_ll; |
173 | 0 | } |
174 | 0 | return rc; |
175 | 0 | } |
176 | | |
177 | | /*! |
178 | | * \internal |
179 | | * \brief Scan a double-precision floating-point value from a string |
180 | | * |
181 | | * \param[in] text The string to parse |
182 | | * \param[out] result Parsed value on success, or |
183 | | * \c PCMK__PARSE_DBL_DEFAULT on error |
184 | | * \param[in] default_text Default string to parse if \p text is |
185 | | * \c NULL |
186 | | * \param[out] end_text If not \c NULL, where to store a pointer |
187 | | * to the position immediately after the |
188 | | * value |
189 | | * |
190 | | * \return Standard Pacemaker return code (\c pcmk_rc_ok on success, |
191 | | * \c EINVAL on failed string conversion due to invalid input, |
192 | | * \c EOVERFLOW on arithmetic overflow, \c pcmk_rc_underflow |
193 | | * on arithmetic underflow, or \c errno from \c strtod() on |
194 | | * other parse errors) |
195 | | */ |
196 | | int |
197 | | pcmk__scan_double(const char *text, double *result, const char *default_text, |
198 | | char **end_text) |
199 | 0 | { |
200 | 0 | int rc = pcmk_rc_ok; |
201 | 0 | char *local_end_text = NULL; |
202 | |
|
203 | 0 | pcmk__assert(result != NULL); |
204 | 0 | *result = PCMK__PARSE_DBL_DEFAULT; |
205 | |
|
206 | 0 | text = (text != NULL) ? text : default_text; |
207 | |
|
208 | 0 | if (text == NULL) { |
209 | 0 | rc = EINVAL; |
210 | 0 | pcmk__debug("No text and no default conversion value supplied"); |
211 | |
|
212 | 0 | } else { |
213 | 0 | errno = 0; |
214 | 0 | *result = strtod(text, &local_end_text); |
215 | |
|
216 | 0 | if (errno == ERANGE) { |
217 | | /* |
218 | | * Overflow: strtod() returns +/- HUGE_VAL and sets errno to |
219 | | * ERANGE |
220 | | * |
221 | | * Underflow: strtod() returns "a value whose magnitude is |
222 | | * no greater than the smallest normalized |
223 | | * positive" double. Whether ERANGE is set is |
224 | | * implementation-defined. |
225 | | */ |
226 | 0 | const char *over_under; |
227 | |
|
228 | 0 | if (QB_ABS(*result) > DBL_MIN) { |
229 | 0 | rc = EOVERFLOW; |
230 | 0 | over_under = "over"; |
231 | 0 | } else { |
232 | 0 | rc = pcmk_rc_underflow; |
233 | 0 | over_under = "under"; |
234 | 0 | } |
235 | |
|
236 | 0 | pcmk__debug("Floating-point value parsed from '%s' would %sflow " |
237 | 0 | "(using %g instead)", |
238 | 0 | text, over_under, *result); |
239 | |
|
240 | 0 | } else if (errno != 0) { |
241 | 0 | rc = errno; |
242 | | // strtod() set *result = 0 on parse failure |
243 | 0 | *result = PCMK__PARSE_DBL_DEFAULT; |
244 | |
|
245 | 0 | pcmk__debug("Could not parse floating-point value from '%s' (using " |
246 | 0 | "%.1f instead): %s", |
247 | 0 | text, PCMK__PARSE_DBL_DEFAULT, pcmk_rc_str(rc)); |
248 | |
|
249 | 0 | } else if (local_end_text == text) { |
250 | | // errno == 0, but nothing was parsed |
251 | 0 | rc = EINVAL; |
252 | 0 | *result = PCMK__PARSE_DBL_DEFAULT; |
253 | |
|
254 | 0 | pcmk__debug("Could not parse floating-point value from '%s' (using " |
255 | 0 | "%.1f instead): No digits found", |
256 | 0 | text, PCMK__PARSE_DBL_DEFAULT); |
257 | |
|
258 | 0 | } else if (QB_ABS(*result) <= DBL_MIN) { |
259 | | /* |
260 | | * errno == 0 and text was parsed, but value might have |
261 | | * underflowed. |
262 | | * |
263 | | * ERANGE might not be set for underflow. Check magnitude |
264 | | * of *result, but also make sure the input number is not |
265 | | * actually zero (0 <= DBL_MIN is not underflow). |
266 | | * |
267 | | * This check must come last. A parse failure in strtod() |
268 | | * also sets *result == 0, so a parse failure would match |
269 | | * this test condition prematurely. |
270 | | */ |
271 | 0 | for (const char *p = text; p != local_end_text; p++) { |
272 | 0 | if (strchr("0.eE", *p) == NULL) { |
273 | 0 | rc = pcmk_rc_underflow; |
274 | 0 | pcmk__debug("Floating-point value parsed from '%s' would " |
275 | 0 | "underflow (using %g instead)", text, *result); |
276 | 0 | break; |
277 | 0 | } |
278 | 0 | } |
279 | |
|
280 | 0 | } else { |
281 | 0 | pcmk__trace("Floating-point value parsed successfully from '%s': " |
282 | 0 | "%g", |
283 | 0 | text, *result); |
284 | 0 | } |
285 | | |
286 | 0 | if ((end_text == NULL) && !pcmk__str_empty(local_end_text)) { |
287 | 0 | pcmk__debug("Characters left over after parsing '%s': '%s'", text, |
288 | 0 | local_end_text); |
289 | 0 | } |
290 | 0 | } |
291 | | |
292 | 0 | if (end_text != NULL) { |
293 | 0 | *end_text = local_end_text; |
294 | 0 | } |
295 | |
|
296 | 0 | return rc; |
297 | 0 | } |
298 | | |
299 | | /*! |
300 | | * \internal |
301 | | * \brief Parse an <tt>unsigned int</tt> from a string stored in a hash table |
302 | | * |
303 | | * \param[in] table Hash table to search |
304 | | * \param[in] key Hash table key to use to retrieve string |
305 | | * \param[in] default_val What to use if key has no entry in table |
306 | | * \param[out] result If not NULL, where to store parsed integer |
307 | | * |
308 | | * \return Standard Pacemaker return code |
309 | | */ |
310 | | int |
311 | | pcmk__uint_from_hash(GHashTable *table, const char *key, |
312 | | unsigned int default_val, unsigned int *result) |
313 | 0 | { |
314 | 0 | const char *value; |
315 | 0 | long long value_ll; |
316 | 0 | int rc = pcmk_rc_ok; |
317 | |
|
318 | 0 | CRM_CHECK((table != NULL) && (key != NULL), return EINVAL); |
319 | | |
320 | 0 | if (result != NULL) { |
321 | 0 | *result = default_val; |
322 | 0 | } |
323 | |
|
324 | 0 | value = g_hash_table_lookup(table, key); |
325 | 0 | if (value == NULL) { |
326 | 0 | return pcmk_rc_ok; |
327 | 0 | } |
328 | | |
329 | 0 | rc = pcmk__scan_ll(value, &value_ll, 0LL); |
330 | 0 | if (rc != pcmk_rc_ok) { |
331 | 0 | pcmk__warn("Using default (%u) for %s because '%s' is not a valid " |
332 | 0 | "integer: %s", |
333 | 0 | default_val, key, value, pcmk_rc_str(rc)); |
334 | 0 | return rc; |
335 | 0 | } |
336 | | |
337 | 0 | if ((value_ll < 0) || (value_ll > UINT_MAX)) { |
338 | 0 | pcmk__warn("Using default (%u) for %s because '%s' is not in valid " |
339 | 0 | "range", |
340 | 0 | default_val, key, value); |
341 | 0 | return ERANGE; |
342 | 0 | } |
343 | | |
344 | 0 | if (result != NULL) { |
345 | 0 | *result = (unsigned int) value_ll; |
346 | 0 | } |
347 | 0 | return pcmk_rc_ok; |
348 | 0 | } |
349 | | |
350 | | /*! |
351 | | * \brief Parse milliseconds from a Pacemaker interval specification |
352 | | * |
353 | | * \param[in] input Pacemaker time interval specification (a bare number |
354 | | * of seconds; a number with a unit, optionally with |
355 | | * whitespace before and/or after the number; or an ISO |
356 | | * 8601 duration) (can be \c NULL) |
357 | | * \param[out] result_ms Where to store milliseconds equivalent of \p input on |
358 | | * success (limited to the range of an unsigned integer), |
359 | | * or 0 if \p input is \c NULL or invalid |
360 | | * |
361 | | * \return Standard Pacemaker return code |
362 | | */ |
363 | | int |
364 | | pcmk_parse_interval_spec(const char *input, unsigned int *result_ms) |
365 | 1.24k | { |
366 | 1.24k | long long msec = PCMK__PARSE_INT_DEFAULT; |
367 | 1.24k | int rc = pcmk_rc_ok; |
368 | | |
369 | 1.24k | if (input == NULL) { |
370 | 0 | msec = 0; |
371 | 0 | goto done; |
372 | 0 | } |
373 | | |
374 | 1.24k | if (input[0] == 'P') { |
375 | 890 | crm_time_t *period_s = pcmk__time_parse_duration(input); |
376 | | |
377 | 890 | if (period_s != NULL) { |
378 | 546 | msec = pcmk__time_get_seconds(period_s); |
379 | 546 | msec = QB_MIN(msec, UINT_MAX / 1000) * 1000; |
380 | 546 | free(period_s); |
381 | 546 | } |
382 | | |
383 | 890 | } else { |
384 | 353 | rc = pcmk__parse_ms(input, &msec); |
385 | 353 | } |
386 | | |
387 | 1.24k | if (msec < 0) { |
388 | 739 | pcmk__warn("Using 0 instead of invalid interval specification '%s'", |
389 | 739 | input); |
390 | 739 | msec = 0; |
391 | | |
392 | 739 | if (rc == pcmk_rc_ok) { |
393 | | // Preserve any error from pcmk__parse_ms() |
394 | 670 | rc = EINVAL; |
395 | 670 | } |
396 | 739 | } |
397 | | |
398 | 1.24k | done: |
399 | 1.24k | if (result_ms != NULL) { |
400 | 1.24k | *result_ms = (msec >= UINT_MAX)? UINT_MAX : (unsigned int) msec; |
401 | 1.24k | } |
402 | 1.24k | return rc; |
403 | 1.24k | } |
404 | | |
405 | | /*! |
406 | | * \internal |
407 | | * \brief Create a hash of a string suitable for use with GHashTable |
408 | | * |
409 | | * \param[in] v String to hash |
410 | | * |
411 | | * \return A hash of \p v compatible with g_str_hash() before glib 2.28 |
412 | | * \note glib changed their hash implementation: |
413 | | * |
414 | | * https://gitlab.gnome.org/GNOME/glib/commit/354d655ba8a54b754cb5a3efb42767327775696c |
415 | | * |
416 | | * Note that the new g_str_hash is presumably a *better* hash (it's actually |
417 | | * a correct implementation of DJB's hash), but we need to preserve existing |
418 | | * behaviour, because the hash key ultimately determines the "sort" order |
419 | | * when iterating through GHashTables, which affects allocation of scores to |
420 | | * clone instances when iterating through allowed nodes. It (somehow) also |
421 | | * appears to have some minor impact on the ordering of a few pseudo_event IDs |
422 | | * in the transition graph. |
423 | | */ |
424 | | static unsigned int |
425 | | pcmk__str_hash(const void *v) |
426 | 0 | { |
427 | 0 | const signed char *p; |
428 | 0 | guint32 h = 0; |
429 | |
|
430 | 0 | for (p = v; *p != '\0'; p++) |
431 | 0 | h = (h << 5) - h + *p; |
432 | |
|
433 | 0 | return h; |
434 | 0 | } |
435 | | |
436 | | /*! |
437 | | * \internal |
438 | | * \brief Create a hash table with case-sensitive strings as keys |
439 | | * |
440 | | * \param[in] key_destroy_func Function to free a key |
441 | | * \param[in] value_destroy_func Function to free a value |
442 | | * |
443 | | * \return Newly allocated hash table |
444 | | * \note It is the caller's responsibility to free the result, using |
445 | | * g_hash_table_destroy(). |
446 | | */ |
447 | | GHashTable * |
448 | | pcmk__strkey_table(GDestroyNotify key_destroy_func, |
449 | | GDestroyNotify value_destroy_func) |
450 | 0 | { |
451 | 0 | return g_hash_table_new_full(pcmk__str_hash, g_str_equal, |
452 | 0 | key_destroy_func, value_destroy_func); |
453 | 0 | } |
454 | | |
455 | | /*! |
456 | | * \internal |
457 | | * \brief Insert string copies into a hash table as key and value |
458 | | * |
459 | | * \param[in,out] table Hash table to add to |
460 | | * \param[in] name String to add a copy of as key |
461 | | * \param[in] value String to add a copy of as value |
462 | | * |
463 | | * \note This asserts on invalid arguments or memory allocation failure. |
464 | | */ |
465 | | void |
466 | | pcmk__insert_dup(GHashTable *table, const char *name, const char *value) |
467 | 0 | { |
468 | 0 | pcmk__assert((table != NULL) && (name != NULL)); |
469 | |
|
470 | 0 | g_hash_table_insert(table, pcmk__str_copy(name), pcmk__str_copy(value)); |
471 | 0 | } |
472 | | |
473 | | /* used with hash tables where case does not matter */ |
474 | | static gboolean |
475 | | pcmk__strcase_equal(const void *a, const void *b) |
476 | 0 | { |
477 | 0 | return pcmk__str_eq((const char *)a, (const char *)b, pcmk__str_casei); |
478 | 0 | } |
479 | | |
480 | | static unsigned int |
481 | | pcmk__strcase_hash(const void *v) |
482 | 0 | { |
483 | 0 | const signed char *p; |
484 | 0 | guint32 h = 0; |
485 | |
|
486 | 0 | for (p = v; *p != '\0'; p++) |
487 | 0 | h = (h << 5) - h + g_ascii_tolower(*p); |
488 | |
|
489 | 0 | return h; |
490 | 0 | } |
491 | | |
492 | | /*! |
493 | | * \internal |
494 | | * \brief Create a hash table with case-insensitive strings as keys |
495 | | * |
496 | | * \param[in] key_destroy_func Function to free a key |
497 | | * \param[in] value_destroy_func Function to free a value |
498 | | * |
499 | | * \return Newly allocated hash table |
500 | | * \note It is the caller's responsibility to free the result, using |
501 | | * g_hash_table_destroy(). |
502 | | */ |
503 | | GHashTable * |
504 | | pcmk__strikey_table(GDestroyNotify key_destroy_func, |
505 | | GDestroyNotify value_destroy_func) |
506 | 0 | { |
507 | 0 | return g_hash_table_new_full(pcmk__strcase_hash, pcmk__strcase_equal, |
508 | 0 | key_destroy_func, value_destroy_func); |
509 | 0 | } |
510 | | |
511 | | static void |
512 | | copy_str_table_entry(void *key, void *value, void *user_data) |
513 | 0 | { |
514 | 0 | if (key && value && user_data) { |
515 | 0 | pcmk__insert_dup((GHashTable *) user_data, |
516 | 0 | (const char *) key, (const char *) value); |
517 | 0 | } |
518 | 0 | } |
519 | | |
520 | | /*! |
521 | | * \internal |
522 | | * \brief Copy a hash table that uses dynamically allocated strings |
523 | | * |
524 | | * \param[in,out] old_table Hash table to duplicate |
525 | | * |
526 | | * \return New hash table with copies of everything in \p old_table |
527 | | * \note This assumes the hash table uses dynamically allocated strings -- that |
528 | | * is, both the key and value free functions are free(). |
529 | | */ |
530 | | GHashTable * |
531 | | pcmk__str_table_dup(GHashTable *old_table) |
532 | 0 | { |
533 | 0 | GHashTable *new_table = NULL; |
534 | |
|
535 | 0 | if (old_table) { |
536 | 0 | new_table = pcmk__strkey_table(free, free); |
537 | 0 | g_hash_table_foreach(old_table, copy_str_table_entry, new_table); |
538 | 0 | } |
539 | 0 | return new_table; |
540 | 0 | } |
541 | | |
542 | | /*! |
543 | | * \internal |
544 | | * \brief Add a word to a string list of words |
545 | | * |
546 | | * \param[in,out] list Pointer to current string list (may not be \p NULL) |
547 | | * \param[in] init_size \p list will be initialized to at least this size, |
548 | | * if it needs initialization (if 0, use GLib's default |
549 | | * initial string size) |
550 | | * \param[in] word String to add to \p list (\p list will be |
551 | | * unchanged if this is \p NULL or the empty string) |
552 | | * \param[in] separator String to separate words in \p list |
553 | | * |
554 | | * \note \p word may contain \p separator, though that would be a bad idea if |
555 | | * the string needs to be parsed later. |
556 | | */ |
557 | | void |
558 | | pcmk__add_separated_word(GString **list, size_t init_size, const char *word, |
559 | | const char *separator) |
560 | 0 | { |
561 | 0 | pcmk__assert((list != NULL) && (separator != NULL)); |
562 | |
|
563 | 0 | if (pcmk__str_empty(word)) { |
564 | 0 | return; |
565 | 0 | } |
566 | | |
567 | 0 | if (*list == NULL) { |
568 | 0 | if (init_size > 0) { |
569 | 0 | *list = g_string_sized_new(init_size); |
570 | 0 | } else { |
571 | 0 | *list = g_string_new(NULL); |
572 | 0 | } |
573 | 0 | } |
574 | |
|
575 | 0 | if ((*list)->len > 0) { |
576 | | // Don't add a separator before the first word in the list |
577 | 0 | g_string_append(*list, separator); |
578 | 0 | } |
579 | 0 | g_string_append(*list, word); |
580 | 0 | } |
581 | | |
582 | | /*! |
583 | | * \internal |
584 | | * \brief Compress data |
585 | | * |
586 | | * \param[in] data Data to compress |
587 | | * \param[in] length Number of characters of data to compress |
588 | | * \param[out] result Where to store newly allocated compressed result |
589 | | * \param[out] result_len Where to store actual compressed length of result |
590 | | * |
591 | | * \return Standard Pacemaker return code |
592 | | */ |
593 | | int |
594 | | pcmk__compress(const char *data, size_t length, char **result, size_t *result_len) |
595 | 0 | { |
596 | 0 | size_t max = (length * 1.01) + 601; // Max size of the compressed result |
597 | 0 | unsigned int dest_len = 0; // Where bz2 should store the actual size |
598 | 0 | int rc = pcmk_rc_ok; |
599 | 0 | char *compressed = NULL; |
600 | 0 | char *uncompressed = NULL; |
601 | | |
602 | | /* Did the max calculation overflow? */ |
603 | 0 | if (max < length) { |
604 | 0 | return EINVAL; |
605 | 0 | } |
606 | | |
607 | | /* BZ2_bzBuffToBuffCompress wants unsigned ints, not size_t. This function |
608 | | * takes size_t arguments to simplify checking in its callers. Make sure |
609 | | * we're not passing BZ2_bzBuffToBuffCompress something that's too large. |
610 | | */ |
611 | 0 | #if (SIZE_MAX > UINT_MAX) |
612 | 0 | if (max > UINT_MAX) { |
613 | 0 | return EINVAL; |
614 | 0 | } |
615 | 0 | #endif |
616 | | |
617 | 0 | compressed = pcmk__assert_alloc(max, sizeof(char)); |
618 | 0 | uncompressed = pcmk__str_copy(data); |
619 | |
|
620 | 0 | dest_len = max; |
621 | 0 | rc = BZ2_bzBuffToBuffCompress(compressed, &dest_len, uncompressed, length, |
622 | 0 | PCMK__BZ2_BLOCKS, 0, PCMK__BZ2_WORK); |
623 | 0 | *result_len = dest_len; |
624 | |
|
625 | 0 | rc = pcmk__bzlib2rc(rc); |
626 | |
|
627 | 0 | free(uncompressed); |
628 | |
|
629 | 0 | if (rc != pcmk_rc_ok) { |
630 | 0 | pcmk__err("Compression of %zu bytes failed: %s " QB_XS " rc=%d", length, |
631 | 0 | pcmk_rc_str(rc), rc); |
632 | 0 | free(compressed); |
633 | 0 | return rc; |
634 | 0 | } |
635 | | |
636 | 0 | pcmk__trace("Compressed %zu bytes into %zu", length, *result_len); |
637 | | |
638 | 0 | *result = compressed; |
639 | 0 | return pcmk_rc_ok; |
640 | 0 | } |
641 | | |
642 | | /*! |
643 | | * \internal |
644 | | * \brief Parse a boolean value from a string |
645 | | * |
646 | | * Valid input strings (case-insensitive) are as follows: |
647 | | * * \c PCMK_VALUE_TRUE, \c "on", \c "yes", \c "y", or \c "1" for \c true |
648 | | * * \c PCMK_VALUE_FALSE, \c PCMK_VALUE_OFF, \c "no", \c "n", or \c "0" for |
649 | | * \c false |
650 | | * |
651 | | * \param[in] input Input string |
652 | | * \param[out] result Where to store result (can be \c NULL; unchanged on |
653 | | * error) |
654 | | * |
655 | | * \retval Standard Pacemaker return code |
656 | | */ |
657 | | int |
658 | | pcmk__parse_bool(const char *input, bool *result) |
659 | 0 | { |
660 | 0 | bool local_result = false; |
661 | |
|
662 | 0 | CRM_CHECK(input != NULL, return EINVAL); |
663 | | |
664 | 0 | if (pcmk__strcase_any_of(input, PCMK_VALUE_TRUE, "on", "yes", "y", "1", |
665 | 0 | NULL)) { |
666 | 0 | local_result = true; |
667 | |
|
668 | 0 | } else if (pcmk__strcase_any_of(input, PCMK_VALUE_FALSE, PCMK_VALUE_OFF, |
669 | 0 | "no", "n", "0", NULL)) { |
670 | 0 | local_result = false; |
671 | |
|
672 | 0 | } else { |
673 | 0 | return pcmk_rc_bad_input; |
674 | 0 | } |
675 | | |
676 | 0 | if (result != NULL) { |
677 | 0 | *result = local_result; |
678 | 0 | } |
679 | 0 | return pcmk_rc_ok; |
680 | 0 | } |
681 | | |
682 | | /*! |
683 | | * \internal |
684 | | * \brief Parse a range specification string |
685 | | * |
686 | | * A valid range specification string can be in any of the following forms, |
687 | | * where \c "X", \c "Y", and \c "Z" are nonnegative integers that fit into a |
688 | | * <tt>long long</tt> variable: |
689 | | * * "X-Y" |
690 | | * * "X-" |
691 | | * * "-Y" |
692 | | * * "Z" |
693 | | * |
694 | | * In the list above, \c "X" is the start value and \c "Y" is the end value of |
695 | | * the range. Either the start value or the end value, but not both, can be |
696 | | * empty. \c "Z", a single integer with no \c '-' character, is both the start |
697 | | * value and the end value of its range. |
698 | | * |
699 | | * If the start value or end value is empty, then the parsed result stored in |
700 | | * \p *start or \p *end (respectively) is \c PCMK__PARSE_INT_DEFAULT after a |
701 | | * successful parse. |
702 | | * |
703 | | * If the specification string consists of only a single number, then the same |
704 | | * value is stored in both \p *start and \p *end on a successful parse. |
705 | | * |
706 | | * \param[in] text String to parse |
707 | | * \param[out] start Where to store start value (can be \c NULL) |
708 | | * \param[out] end Where to store end value (can be \c NULL) |
709 | | * |
710 | | * \return Standard Pacemaker return code |
711 | | * |
712 | | * \note The values stored in \p *start and \p *end are undefined if the return |
713 | | * value is not \c pcmk_rc_ok. |
714 | | */ |
715 | | int |
716 | | pcmk__parse_ll_range(const char *text, long long *start, long long *end) |
717 | 0 | { |
718 | 0 | int rc = pcmk_rc_ok; |
719 | 0 | long long local_start = 0; |
720 | 0 | long long local_end = 0; |
721 | 0 | gchar **split = NULL; |
722 | 0 | unsigned int length = 0; |
723 | 0 | const char *start_s = NULL; |
724 | 0 | const char *end_s = NULL; |
725 | | |
726 | | // Do not free |
727 | 0 | char *remainder = NULL; |
728 | |
|
729 | 0 | if (start == NULL) { |
730 | 0 | start = &local_start; |
731 | 0 | } |
732 | 0 | if (end == NULL) { |
733 | 0 | end = &local_end; |
734 | 0 | } |
735 | 0 | *start = PCMK__PARSE_INT_DEFAULT; |
736 | 0 | *end = PCMK__PARSE_INT_DEFAULT; |
737 | |
|
738 | 0 | if (pcmk__str_empty(text)) { |
739 | 0 | rc = ENODATA; |
740 | 0 | goto done; |
741 | 0 | } |
742 | | |
743 | 0 | split = g_strsplit(text, "-", 2); |
744 | 0 | length = g_strv_length(split); |
745 | 0 | start_s = split[0]; |
746 | 0 | if (length == 2) { |
747 | 0 | end_s = split[1]; |
748 | 0 | } |
749 | |
|
750 | 0 | if (pcmk__str_empty(start_s) && pcmk__str_empty(end_s)) { |
751 | 0 | rc = pcmk_rc_bad_input; |
752 | 0 | goto done; |
753 | 0 | } |
754 | | |
755 | 0 | if (!pcmk__str_empty(start_s)) { |
756 | 0 | rc = scan_ll(start_s, start, PCMK__PARSE_INT_DEFAULT, &remainder); |
757 | 0 | if (rc != pcmk_rc_ok) { |
758 | 0 | goto done; |
759 | 0 | } |
760 | 0 | if (!pcmk__str_empty(remainder)) { |
761 | 0 | rc = pcmk_rc_bad_input; |
762 | 0 | goto done; |
763 | 0 | } |
764 | 0 | } |
765 | | |
766 | 0 | if (length == 1) { |
767 | | // String contains only a single number, which is both start and end |
768 | 0 | *end = *start; |
769 | 0 | goto done; |
770 | 0 | } |
771 | | |
772 | 0 | if (!pcmk__str_empty(end_s)) { |
773 | 0 | rc = scan_ll(end_s, end, PCMK__PARSE_INT_DEFAULT, &remainder); |
774 | |
|
775 | 0 | if ((rc == pcmk_rc_ok) && !pcmk__str_empty(remainder)) { |
776 | 0 | rc = pcmk_rc_bad_input; |
777 | 0 | } |
778 | 0 | } |
779 | |
|
780 | 0 | done: |
781 | 0 | g_strfreev(split); |
782 | 0 | return rc; |
783 | 0 | } |
784 | | |
785 | | /*! |
786 | | * \internal |
787 | | * \brief Get multiplier and divisor corresponding to given units string |
788 | | * |
789 | | * Multiplier and divisor convert from a number of seconds to an equivalent |
790 | | * number of the unit described by the units string. |
791 | | * |
792 | | * \param[in] units String describing a unit of time (may be empty, |
793 | | * \c "s", \c "sec", \c "ms", \c "msec", \c "us", |
794 | | * \c "usec", \c "m", \c "min", \c "h", or \c "hr") |
795 | | * \param[out] multiplier Number of units in one second, if unit is smaller |
796 | | * than one second, or 1 otherwise (unchanged on error) |
797 | | * \param[out] divisor Number of seconds in one unit, if unit is larger |
798 | | * than one second, or 1 otherwise (unchanged on error) |
799 | | * |
800 | | * \return Standard Pacemaker return code |
801 | | */ |
802 | | static int |
803 | | get_multiplier_divisor(const char *units, long long *multiplier, |
804 | | long long *divisor) |
805 | 682 | { |
806 | | /* @COMPAT Use exact comparisons. Currently, we match too liberally, and the |
807 | | * second strncasecmp() in each case is redundant. |
808 | | */ |
809 | 682 | if ((*units == '\0') |
810 | 590 | || (strncasecmp(units, "s", 1) == 0) |
811 | 562 | || (strncasecmp(units, "sec", 3) == 0)) { |
812 | 120 | *multiplier = 1000; |
813 | 120 | *divisor = 1; |
814 | | |
815 | 562 | } else if ((strncasecmp(units, "ms", 2) == 0) |
816 | 494 | || (strncasecmp(units, "msec", 4) == 0)) { |
817 | 68 | *multiplier = 1; |
818 | 68 | *divisor = 1; |
819 | | |
820 | 494 | } else if ((strncasecmp(units, "us", 2) == 0) |
821 | 446 | || (strncasecmp(units, "usec", 4) == 0)) { |
822 | 48 | *multiplier = 1; |
823 | 48 | *divisor = 1000; |
824 | | |
825 | 446 | } else if ((strncasecmp(units, "m", 1) == 0) |
826 | 400 | || (strncasecmp(units, "min", 3) == 0)) { |
827 | 46 | *multiplier = 60 * 1000; |
828 | 46 | *divisor = 1; |
829 | | |
830 | 400 | } else if ((strncasecmp(units, "h", 1) == 0) |
831 | 288 | || (strncasecmp(units, "hr", 2) == 0)) { |
832 | 288 | *multiplier = 60 * 60 * 1000; |
833 | 288 | *divisor = 1; |
834 | | |
835 | 288 | } else { |
836 | | // Invalid units |
837 | 112 | return pcmk_rc_bad_input; |
838 | 112 | } |
839 | | |
840 | 570 | return pcmk_rc_ok; |
841 | 682 | } |
842 | | |
843 | | /*! |
844 | | * \internal |
845 | | * \brief Parse a time and units string into a milliseconds value |
846 | | * |
847 | | * \param[in] input String with a nonnegative number and optional unit |
848 | | * (optionally with whitespace before and/or after the |
849 | | * number). If absent, the unit defaults to seconds. |
850 | | * \param[out] result Where to store result in milliseconds (unchanged on error |
851 | | * except \c ERANGE) |
852 | | * |
853 | | * \return Standard Pacemaker return code |
854 | | */ |
855 | | int |
856 | | pcmk__parse_ms(const char *input, long long *result) |
857 | 1.59k | { |
858 | 1.59k | long long local_result = 0; |
859 | 1.59k | char *units = NULL; // Do not free; will point to part of input |
860 | 1.59k | long long multiplier = 1000; |
861 | 1.59k | long long divisor = 1; |
862 | 1.59k | int rc = pcmk_rc_ok; |
863 | | |
864 | 1.59k | CRM_CHECK(input != NULL, return EINVAL); |
865 | | |
866 | 1.59k | rc = scan_ll(input, &local_result, 0, &units); |
867 | 1.59k | if ((rc == pcmk_rc_ok) || (rc == ERANGE)) { |
868 | 682 | int units_rc = pcmk_rc_ok; |
869 | | |
870 | | /* If the number is a decimal, scan_ll() reads only the integer part. |
871 | | * Skip any remaining digits or decimal characters. |
872 | | * |
873 | | * @COMPAT Well-formed and malformed decimals are both accepted inputs. |
874 | | * For example, "3.14 ms" and "3.1.4 ms" are treated the same as "3ms" |
875 | | * and parsed successfully. At a compatibility break, decide if this is |
876 | | * still desired. |
877 | | */ |
878 | 1.30k | for (; isdigit(*units) || (*units == '.'); units++); |
879 | | |
880 | | // Skip any additional whitespace after the number |
881 | 682 | for (; isspace(*units); units++); |
882 | | |
883 | | // Validate units and get conversion constants |
884 | 682 | units_rc = get_multiplier_divisor(units, &multiplier, &divisor); |
885 | 682 | if (units_rc != pcmk_rc_ok) { |
886 | 112 | rc = units_rc; |
887 | 112 | } |
888 | 682 | } |
889 | | |
890 | 1.59k | if (rc == ERANGE) { |
891 | 4 | pcmk__warn("'%s' will be clipped to %lld", input, local_result); |
892 | | |
893 | | /* Continue through rest of body before returning ERANGE |
894 | | * |
895 | | * @COMPAT Improve handling of overflow. Units won't necessarily be |
896 | | * respected right now, for one thing. |
897 | | */ |
898 | | |
899 | 1.59k | } else if (rc != pcmk_rc_ok) { |
900 | 1.02k | pcmk__warn("'%s' is not a valid time duration: %s", input, |
901 | 1.02k | pcmk_rc_str(rc)); |
902 | 1.02k | return rc; |
903 | 1.02k | } |
904 | | |
905 | 570 | if (result == NULL) { |
906 | 0 | return rc; |
907 | 0 | } |
908 | | |
909 | | // Apply units, capping at LLONG_MAX |
910 | 570 | if (local_result > (LLONG_MAX / multiplier)) { |
911 | 126 | *result = LLONG_MAX; |
912 | 444 | } else if (local_result < (LLONG_MIN / multiplier)) { |
913 | 4 | *result = LLONG_MIN; |
914 | 440 | } else { |
915 | 440 | *result = (local_result * multiplier) / divisor; |
916 | 440 | } |
917 | | |
918 | 570 | return rc; |
919 | 570 | } |
920 | | |
921 | | /*! |
922 | | * \internal |
923 | | * \brief Data for \c cmp_str_in_list() |
924 | | */ |
925 | | struct str_in_list_data { |
926 | | const char *str; |
927 | | uint32_t flags; |
928 | | }; |
929 | | |
930 | | /*! |
931 | | * \internal |
932 | | * \brief Call \c pcmk__strcmp() against an element of a \c GList |
933 | | * |
934 | | * \param[in] a List element (a string) |
935 | | * \param[in] b String to compare against \p and the flags for comparison (a |
936 | | * (<tt>struct str_in_list_data</tt>) |
937 | | * |
938 | | * \return A negative integer if \p a comes before \p b->str, a positive integer |
939 | | * if \p a comes after \p b->str, or 0 if \p a is equal to \p b->str |
940 | | * (according to \p b->flags) |
941 | | */ |
942 | | static int |
943 | | cmp_str_in_list(const void *a, const void *b) |
944 | 0 | { |
945 | 0 | const char *element = a; |
946 | 0 | const struct str_in_list_data *data = b; |
947 | |
|
948 | 0 | return pcmk__strcmp(element, data->str, data->flags); |
949 | 0 | } |
950 | | |
951 | | /*! |
952 | | * \internal |
953 | | * \brief Find a string in a list of strings |
954 | | * |
955 | | * \param[in] str String to search for |
956 | | * \param[in] list List to search |
957 | | * \param[in] flags Group of <tt>enum pcmk__str_flags</tt> to pass to |
958 | | * \c pcmk__str_eq() |
959 | | * |
960 | | * \return \c true if \p str is in \p list, or \c false otherwise |
961 | | */ |
962 | | bool |
963 | | pcmk__str_in_list(const char *str, const GList *list, uint32_t flags) |
964 | 0 | { |
965 | 0 | const struct str_in_list_data data = { |
966 | 0 | .str = str, |
967 | 0 | .flags = flags, |
968 | 0 | }; |
969 | |
|
970 | 0 | return (g_list_find_custom((GList *) list, &data, cmp_str_in_list) != NULL); |
971 | 0 | } |
972 | | |
973 | | /*! |
974 | | * \internal |
975 | | * \brief Check whether a string is in an array of <tt>gchar *</tt> |
976 | | * |
977 | | * \param[in] strv <tt>NULL</tt>-terminated array of strings to search |
978 | | * \param[in] str String to search for |
979 | | * |
980 | | * \return \c true if \p str is an element of \p strv, or \c false otherwise |
981 | | */ |
982 | | bool |
983 | | pcmk__g_strv_contains(char **strv, const char *str) |
984 | 0 | { |
985 | | // @COMPAT Replace with calls to g_strv_contains() when we require glib 2.44 |
986 | 0 | CRM_CHECK((strv != NULL) && (str != NULL), return false); |
987 | | |
988 | 0 | for (; *strv != NULL; strv++) { |
989 | 0 | if (pcmk__str_eq(*strv, str, pcmk__str_none)) { |
990 | 0 | return true; |
991 | 0 | } |
992 | 0 | } |
993 | | |
994 | 0 | return false; |
995 | 0 | } |
996 | | |
997 | | static bool |
998 | | str_any_of(const char *s, va_list args, uint32_t flags) |
999 | 177 | { |
1000 | 177 | if (s == NULL) { |
1001 | 0 | return false; |
1002 | 0 | } |
1003 | | |
1004 | 528 | while (1) { |
1005 | 528 | const char *ele = va_arg(args, const char *); |
1006 | | |
1007 | 528 | if (ele == NULL) { |
1008 | 175 | break; |
1009 | 353 | } else if (pcmk__str_eq(s, ele, flags)) { |
1010 | 2 | return true; |
1011 | 2 | } |
1012 | 528 | } |
1013 | | |
1014 | 175 | return false; |
1015 | 177 | } |
1016 | | |
1017 | | /*! |
1018 | | * \internal |
1019 | | * \brief Is a string a member of a list of strings? |
1020 | | * |
1021 | | * \param[in] s String to search for in \p ... |
1022 | | * \param[in] ... Strings to compare \p s against. The final string |
1023 | | * must be NULL. |
1024 | | * |
1025 | | * \note The comparison is done case-insensitively. The function name is |
1026 | | * meant to be reminiscent of strcasecmp. |
1027 | | * |
1028 | | * \return \c true if \p s is in \p ..., or \c false otherwise |
1029 | | */ |
1030 | | bool |
1031 | | pcmk__strcase_any_of(const char *s, ...) |
1032 | 0 | { |
1033 | 0 | va_list ap; |
1034 | 0 | bool rc; |
1035 | |
|
1036 | 0 | va_start(ap, s); |
1037 | 0 | rc = str_any_of(s, ap, pcmk__str_casei); |
1038 | 0 | va_end(ap); |
1039 | 0 | return rc; |
1040 | 0 | } |
1041 | | |
1042 | | /*! |
1043 | | * \internal |
1044 | | * \brief Is a string a member of a list of strings? |
1045 | | * |
1046 | | * \param[in] s String to search for in \p ... |
1047 | | * \param[in] ... Strings to compare \p s against. The final string |
1048 | | * must be NULL. |
1049 | | * |
1050 | | * \note The comparison is done taking case into account. |
1051 | | * |
1052 | | * \return \c true if \p s is in \p ..., or \c false otherwise |
1053 | | */ |
1054 | | bool |
1055 | | pcmk__str_any_of(const char *s, ...) |
1056 | 177 | { |
1057 | 177 | va_list ap; |
1058 | 177 | bool rc; |
1059 | | |
1060 | 177 | va_start(ap, s); |
1061 | 177 | rc = str_any_of(s, ap, pcmk__str_none); |
1062 | 177 | va_end(ap); |
1063 | 177 | return rc; |
1064 | 177 | } |
1065 | | |
1066 | | /*! |
1067 | | * \internal |
1068 | | * \brief Sort strings, with numeric portions sorted numerically |
1069 | | * |
1070 | | * Sort two strings case-insensitively like strcasecmp(), but with any numeric |
1071 | | * portions of the string sorted numerically. This is particularly useful for |
1072 | | * node names (for example, "node10" will sort higher than "node9" but lower |
1073 | | * than "remotenode9"). |
1074 | | * |
1075 | | * \param[in] s1 First string to compare (must not be NULL) |
1076 | | * \param[in] s2 Second string to compare (must not be NULL) |
1077 | | * |
1078 | | * \retval -1 \p s1 comes before \p s2 |
1079 | | * \retval 0 \p s1 and \p s2 are equal |
1080 | | * \retval 1 \p s1 comes after \p s2 |
1081 | | */ |
1082 | | int |
1083 | | pcmk__numeric_strcasecmp(const char *s1, const char *s2) |
1084 | 1.24k | { |
1085 | 1.24k | pcmk__assert((s1 != NULL) && (s2 != NULL)); |
1086 | | |
1087 | 105k | while (*s1 && *s2) { |
1088 | 104k | if (isdigit(*s1) && isdigit(*s2)) { |
1089 | | // If node names contain a number, sort numerically |
1090 | | |
1091 | 22.7k | char *end1 = NULL; |
1092 | 22.7k | char *end2 = NULL; |
1093 | 22.7k | long num1 = strtol(s1, &end1, 10); |
1094 | 22.7k | long num2 = strtol(s2, &end2, 10); |
1095 | | |
1096 | | // allow ordering e.g. 007 > 7 |
1097 | 22.7k | size_t len1 = end1 - s1; |
1098 | 22.7k | size_t len2 = end2 - s2; |
1099 | | |
1100 | 22.7k | if (num1 < num2) { |
1101 | 0 | return -1; |
1102 | 22.7k | } else if (num1 > num2) { |
1103 | 0 | return 1; |
1104 | 22.7k | } else if (len1 < len2) { |
1105 | 0 | return -1; |
1106 | 22.7k | } else if (len1 > len2) { |
1107 | 0 | return 1; |
1108 | 0 | } |
1109 | 22.7k | s1 = end1; |
1110 | 22.7k | s2 = end2; |
1111 | 81.9k | } else { |
1112 | | // Compare non-digits case-insensitively |
1113 | 81.9k | int lower1 = tolower(*s1); |
1114 | 81.9k | int lower2 = tolower(*s2); |
1115 | | |
1116 | 81.9k | if (lower1 < lower2) { |
1117 | 0 | return -1; |
1118 | 81.9k | } else if (lower1 > lower2) { |
1119 | 0 | return 1; |
1120 | 0 | } |
1121 | 81.9k | ++s1; |
1122 | 81.9k | ++s2; |
1123 | 81.9k | } |
1124 | 104k | } |
1125 | 1.24k | if (!*s1 && *s2) { |
1126 | 0 | return -1; |
1127 | 1.24k | } else if (*s1 && !*s2) { |
1128 | 0 | return 1; |
1129 | 0 | } |
1130 | 1.24k | return 0; |
1131 | 1.24k | } |
1132 | | |
1133 | | /*! |
1134 | | * \internal |
1135 | | * \brief Sort strings. |
1136 | | * |
1137 | | * This is your one-stop function for string comparison. By default, this |
1138 | | * function works like \p g_strcmp0. That is, like \p strcmp but a \p NULL |
1139 | | * string sorts before a non-<tt>NULL</tt> string. |
1140 | | * |
1141 | | * The \p pcmk__str_none flag produces the default behavior. Behavior can be |
1142 | | * changed with various flags: |
1143 | | * |
1144 | | * - \p pcmk__str_regex - The second string is a regular expression that the |
1145 | | * first string will be matched against. |
1146 | | * - \p pcmk__str_casei - By default, comparisons are done taking case into |
1147 | | * account. This flag makes comparisons case- |
1148 | | * insensitive. This can be combined with |
1149 | | * \p pcmk__str_regex. |
1150 | | * - \p pcmk__str_null_matches - If one string is \p NULL and the other is not, |
1151 | | * still return \p 0. |
1152 | | * - \p pcmk__str_star_matches - If one string is \p "*" and the other is not, |
1153 | | * still return \p 0. |
1154 | | * |
1155 | | * \param[in] s1 First string to compare |
1156 | | * \param[in] s2 Second string to compare, or a regular expression to |
1157 | | * match if \p pcmk__str_regex is set |
1158 | | * \param[in] flags A bitfield of \p pcmk__str_flags to modify operation |
1159 | | * |
1160 | | * \retval negative \p s1 is \p NULL or comes before \p s2 |
1161 | | * \retval 0 \p s1 and \p s2 are equal, or \p s1 is found in \p s2 if |
1162 | | * \c pcmk__str_regex is set |
1163 | | * \retval positive \p s2 is \p NULL or \p s1 comes after \p s2, or \p s2 |
1164 | | * is an invalid regular expression, or \p s1 was not found |
1165 | | * in \p s2 if \p pcmk__str_regex is set. |
1166 | | */ |
1167 | | int |
1168 | | pcmk__strcmp(const char *s1, const char *s2, uint32_t flags) |
1169 | 530 | { |
1170 | | /* If this flag is set, the second string is a regex. */ |
1171 | 530 | if (pcmk__is_set(flags, pcmk__str_regex)) { |
1172 | 0 | regex_t r_patt; |
1173 | 0 | int reg_flags = REG_EXTENDED | REG_NOSUB; |
1174 | 0 | int regcomp_rc = 0; |
1175 | 0 | int rc = 0; |
1176 | |
|
1177 | 0 | if (s1 == NULL || s2 == NULL) { |
1178 | 0 | return 1; |
1179 | 0 | } |
1180 | | |
1181 | 0 | if (pcmk__is_set(flags, pcmk__str_casei)) { |
1182 | 0 | reg_flags |= REG_ICASE; |
1183 | 0 | } |
1184 | 0 | regcomp_rc = regcomp(&r_patt, s2, reg_flags); |
1185 | 0 | if (regcomp_rc != 0) { |
1186 | 0 | rc = 1; |
1187 | 0 | pcmk__err("Bad regex '%s' for update: %s", s2, |
1188 | 0 | strerror(regcomp_rc)); |
1189 | 0 | } else { |
1190 | 0 | rc = regexec(&r_patt, s1, 0, NULL, 0); |
1191 | 0 | regfree(&r_patt); |
1192 | 0 | if (rc != 0) { |
1193 | 0 | rc = 1; |
1194 | 0 | } |
1195 | 0 | } |
1196 | 0 | return rc; |
1197 | 0 | } |
1198 | | |
1199 | | /* If the strings are the same pointer, return 0 immediately. */ |
1200 | 530 | if (s1 == s2) { |
1201 | 0 | return 0; |
1202 | 0 | } |
1203 | | |
1204 | | /* If this flag is set, return 0 if either (or both) of the input strings |
1205 | | * are NULL. If neither one is NULL, we need to continue and compare |
1206 | | * them normally. |
1207 | | */ |
1208 | 530 | if (pcmk__is_set(flags, pcmk__str_null_matches)) { |
1209 | 0 | if (s1 == NULL || s2 == NULL) { |
1210 | 0 | return 0; |
1211 | 0 | } |
1212 | 0 | } |
1213 | | |
1214 | | /* Handle the cases where one is NULL and the str_null_matches flag is not set. |
1215 | | * A NULL string always sorts to the beginning. |
1216 | | */ |
1217 | 530 | if (s1 == NULL) { |
1218 | 0 | return -1; |
1219 | 530 | } else if (s2 == NULL) { |
1220 | 0 | return 1; |
1221 | 0 | } |
1222 | | |
1223 | | /* If this flag is set, return 0 if either (or both) of the input strings |
1224 | | * are "*". If neither one is, we need to continue and compare them |
1225 | | * normally. |
1226 | | */ |
1227 | 530 | if (pcmk__is_set(flags, pcmk__str_star_matches)) { |
1228 | 0 | if (strcmp(s1, "*") == 0 || strcmp(s2, "*") == 0) { |
1229 | 0 | return 0; |
1230 | 0 | } |
1231 | 0 | } |
1232 | | |
1233 | 530 | if (pcmk__is_set(flags, pcmk__str_casei)) { |
1234 | 0 | return strcasecmp(s1, s2); |
1235 | 530 | } else { |
1236 | 530 | return strcmp(s1, s2); |
1237 | 530 | } |
1238 | 530 | } |
1239 | | |
1240 | | /*! |
1241 | | * \internal |
1242 | | * \brief Copy a string, asserting on failure |
1243 | | * |
1244 | | * \param[in] file File where \p function is located |
1245 | | * \param[in] function Calling function |
1246 | | * \param[in] line Line within \p file |
1247 | | * \param[in] str String to copy (can be \c NULL) |
1248 | | * |
1249 | | * \return Newly allocated copy of \p str, or \c NULL if \p str is \c NULL |
1250 | | * |
1251 | | * \note The caller is responsible for freeing the return value using \c free(). |
1252 | | */ |
1253 | | char * |
1254 | | pcmk__str_copy_as(const char *file, const char *function, uint32_t line, |
1255 | | const char *str) |
1256 | 143 | { |
1257 | 143 | if (str != NULL) { |
1258 | 143 | char *result = strdup(str); |
1259 | | |
1260 | 143 | if (result == NULL) { |
1261 | 0 | crm_abort(file, function, line, "Out of memory", FALSE, TRUE); |
1262 | 0 | crm_exit(CRM_EX_OSERR); |
1263 | 0 | } |
1264 | 143 | return result; |
1265 | 143 | } |
1266 | 0 | return NULL; |
1267 | 143 | } |
1268 | | |
1269 | | /*! |
1270 | | * \internal |
1271 | | * \brief Update a dynamically allocated string with a new value |
1272 | | * |
1273 | | * Given a dynamically allocated string and a new value for it, if the string |
1274 | | * is different from the new value, free the string and replace it with either a |
1275 | | * newly allocated duplicate of the value or NULL as appropriate. |
1276 | | * |
1277 | | * \param[in,out] str Pointer to dynamically allocated string |
1278 | | * \param[in] value New value to duplicate (or NULL) |
1279 | | * |
1280 | | * \note The caller remains responsibile for freeing \p *str. |
1281 | | */ |
1282 | | void |
1283 | | pcmk__str_update(char **str, const char *value) |
1284 | 0 | { |
1285 | 0 | if ((str != NULL) && !pcmk__str_eq(*str, value, pcmk__str_none)) { |
1286 | 0 | free(*str); |
1287 | 0 | *str = pcmk__str_copy(value); |
1288 | 0 | } |
1289 | 0 | } |
1290 | | |
1291 | | /*! |
1292 | | * \internal |
1293 | | * \brief Print to an allocated string using \c printf()-style formatting |
1294 | | * |
1295 | | * This is like \c asprintf() but asserts on any error. The return value cannot |
1296 | | * be \c NULL, but it may be an empty string, depending on the format string and |
1297 | | * variadic arguments. |
1298 | | * |
1299 | | * \param[in] format \c printf() format string |
1300 | | * \param[in] ... \c printf() format arguments |
1301 | | * |
1302 | | * \return Newly allocated string (guaranteed not to be \c NULL). |
1303 | | * |
1304 | | * \note The caller is responsible for freeing the return value using \c free(). |
1305 | | */ |
1306 | | char * |
1307 | | pcmk__assert_asprintf(const char *format, ...) |
1308 | 169 | { |
1309 | 169 | char *result = NULL; |
1310 | 169 | va_list ap; |
1311 | | |
1312 | 169 | va_start(ap, format); |
1313 | 169 | pcmk__assert(vasprintf(&result, format, ap) >= 0); |
1314 | 169 | va_end(ap); |
1315 | | |
1316 | 169 | return result; |
1317 | 169 | } |
1318 | | |
1319 | | /*! |
1320 | | * \internal |
1321 | | * \brief Append a list of strings to a destination \p GString |
1322 | | * |
1323 | | * \param[in,out] buffer Where to append the strings (must not be \p NULL) |
1324 | | * \param[in] ... A <tt>NULL</tt>-terminated list of strings |
1325 | | * |
1326 | | * \note This tends to be more efficient than a single call to |
1327 | | * \p g_string_append_printf(). |
1328 | | */ |
1329 | | void |
1330 | | pcmk__g_strcat(GString *buffer, ...) |
1331 | 0 | { |
1332 | 0 | va_list ap; |
1333 | |
|
1334 | 0 | pcmk__assert(buffer != NULL); |
1335 | 0 | va_start(ap, buffer); |
1336 | |
|
1337 | 0 | while (true) { |
1338 | 0 | const char *ele = va_arg(ap, const char *); |
1339 | |
|
1340 | 0 | if (ele == NULL) { |
1341 | 0 | break; |
1342 | 0 | } |
1343 | 0 | g_string_append(buffer, ele); |
1344 | 0 | } |
1345 | 0 | va_end(ap); |
1346 | 0 | } |
1347 | | |
1348 | | // Deprecated functions kept only for backward API compatibility |
1349 | | // LCOV_EXCL_START |
1350 | | |
1351 | | #include <crm/common/strings_compat.h> |
1352 | | |
1353 | | long long |
1354 | | crm_get_msec(const char *input) |
1355 | 0 | { |
1356 | 0 | char *units = NULL; // Do not free; will point to part of input |
1357 | 0 | long long multiplier = 1000; |
1358 | 0 | long long divisor = 1; |
1359 | 0 | long long msec = PCMK__PARSE_INT_DEFAULT; |
1360 | 0 | int rc = pcmk_rc_ok; |
1361 | |
|
1362 | 0 | if (input == NULL) { |
1363 | 0 | return PCMK__PARSE_INT_DEFAULT; |
1364 | 0 | } |
1365 | | |
1366 | | // Skip initial whitespace |
1367 | 0 | while (isspace(*input)) { |
1368 | 0 | input++; |
1369 | 0 | } |
1370 | |
|
1371 | 0 | rc = scan_ll(input, &msec, PCMK__PARSE_INT_DEFAULT, &units); |
1372 | |
|
1373 | 0 | if ((rc == ERANGE) && (msec > 0)) { |
1374 | 0 | pcmk__warn("'%s' will be clipped to %lld", input, msec); |
1375 | |
|
1376 | 0 | } else if ((rc != pcmk_rc_ok) || (msec < 0)) { |
1377 | 0 | pcmk__warn("'%s' is not a valid time duration: %s", input, |
1378 | 0 | ((rc == pcmk_rc_ok)? "Negative" : pcmk_rc_str(rc))); |
1379 | 0 | return PCMK__PARSE_INT_DEFAULT; |
1380 | 0 | } |
1381 | | |
1382 | | /* If the number is a decimal, scan_ll() reads only the integer part. Skip |
1383 | | * any remaining digits or decimal characters. |
1384 | | * |
1385 | | * @COMPAT Well-formed and malformed decimals are both accepted inputs. For |
1386 | | * example, "3.14 ms" and "3.1.4 ms" are treated the same as "3ms" and |
1387 | | * parsed successfully. At a compatibility break, decide if this is still |
1388 | | * desired. |
1389 | | */ |
1390 | 0 | while (isdigit(*units) || (*units == '.')) { |
1391 | 0 | units++; |
1392 | 0 | } |
1393 | | |
1394 | | // Skip any additional whitespace after the number |
1395 | 0 | while (isspace(*units)) { |
1396 | 0 | units++; |
1397 | 0 | } |
1398 | | |
1399 | | /* @COMPAT Use exact comparisons. Currently, we match too liberally, and the |
1400 | | * second strncasecmp() in each case is redundant. |
1401 | | */ |
1402 | 0 | if ((*units == '\0') |
1403 | 0 | || (strncasecmp(units, "s", 1) == 0) |
1404 | 0 | || (strncasecmp(units, "sec", 3) == 0)) { |
1405 | 0 | multiplier = 1000; |
1406 | 0 | divisor = 1; |
1407 | |
|
1408 | 0 | } else if ((strncasecmp(units, "ms", 2) == 0) |
1409 | 0 | || (strncasecmp(units, "msec", 4) == 0)) { |
1410 | 0 | multiplier = 1; |
1411 | 0 | divisor = 1; |
1412 | |
|
1413 | 0 | } else if ((strncasecmp(units, "us", 2) == 0) |
1414 | 0 | || (strncasecmp(units, "usec", 4) == 0)) { |
1415 | 0 | multiplier = 1; |
1416 | 0 | divisor = 1000; |
1417 | |
|
1418 | 0 | } else if ((strncasecmp(units, "m", 1) == 0) |
1419 | 0 | || (strncasecmp(units, "min", 3) == 0)) { |
1420 | 0 | multiplier = 60 * 1000; |
1421 | 0 | divisor = 1; |
1422 | |
|
1423 | 0 | } else if ((strncasecmp(units, "h", 1) == 0) |
1424 | 0 | || (strncasecmp(units, "hr", 2) == 0)) { |
1425 | 0 | multiplier = 60 * 60 * 1000; |
1426 | 0 | divisor = 1; |
1427 | |
|
1428 | 0 | } else { |
1429 | | // Invalid units |
1430 | 0 | return PCMK__PARSE_INT_DEFAULT; |
1431 | 0 | } |
1432 | | |
1433 | | // Apply units, capping at LLONG_MAX |
1434 | 0 | if (msec > (LLONG_MAX / multiplier)) { |
1435 | 0 | return LLONG_MAX; |
1436 | 0 | } |
1437 | 0 | return (msec * multiplier) / divisor; |
1438 | 0 | } |
1439 | | |
1440 | | gboolean |
1441 | | crm_is_true(const char *s) |
1442 | 0 | { |
1443 | 0 | gboolean ret = FALSE; |
1444 | |
|
1445 | 0 | return (crm_str_to_boolean(s, &ret) < 0)? FALSE : ret; |
1446 | 0 | } |
1447 | | |
1448 | | int |
1449 | | crm_str_to_boolean(const char *s, int *ret) |
1450 | 0 | { |
1451 | 0 | if (s == NULL) { |
1452 | 0 | return -1; |
1453 | 0 | } |
1454 | | |
1455 | 0 | if (pcmk__strcase_any_of(s, PCMK_VALUE_TRUE, "on", "yes", "y", "1", NULL)) { |
1456 | 0 | if (ret != NULL) { |
1457 | 0 | *ret = TRUE; |
1458 | 0 | } |
1459 | 0 | return 1; |
1460 | 0 | } |
1461 | | |
1462 | 0 | if (pcmk__strcase_any_of(s, PCMK_VALUE_FALSE, PCMK_VALUE_OFF, "no", "n", |
1463 | 0 | "0", NULL)) { |
1464 | 0 | if (ret != NULL) { |
1465 | 0 | *ret = FALSE; |
1466 | 0 | } |
1467 | 0 | return 1; |
1468 | 0 | } |
1469 | 0 | return -1; |
1470 | 0 | } |
1471 | | |
1472 | | char * |
1473 | | crm_strdup_printf(char const *format, ...) |
1474 | 0 | { |
1475 | 0 | va_list ap; |
1476 | 0 | int len = 0; |
1477 | 0 | char *string = NULL; |
1478 | |
|
1479 | 0 | va_start(ap, format); |
1480 | 0 | len = vasprintf(&string, format, ap); |
1481 | 0 | pcmk__assert(len > 0); |
1482 | | va_end(ap); |
1483 | 0 | return string; |
1484 | 0 | } |
1485 | | |
1486 | | // LCOV_EXCL_STOP |
1487 | | // End deprecated API |