Coverage Report

Created: 2026-08-14 06:23

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