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