Coverage Report

Created: 2025-11-26 06:09

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