From 8c0bc83d11fb89e1fb0e263519a9c15d5a2e6481 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sat, 11 Apr 2026 09:42:31 -0700 Subject: [PATCH 01/99] Refactor: libcrmcommon: Clarify days_in_month_year() Signed-off-by: Reid Wahl --- lib/common/iso8601.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index f7a37384c44..6acf9e371d9 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -92,12 +92,8 @@ is_leap_year(int year) && (((year % 100) != 0) || (year % 400 == 0)); } -// Jan-Dec plus Feb of leap years -static int month_days[13] = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 29 -}; - /*! + * \internal * \brief Return number of days in given month of given year * * \param[in] month Ordinal month (1-12) @@ -108,12 +104,18 @@ static int month_days[13] = { static int days_in_month_year(int month, int year) { + static const int month_days[12] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + if ((month < 1) || (month > 12) || (year < 1)) { return 0; } + if ((month == 2) && is_leap_year(year)) { - month = 13; + return month_days[1] + 1; } + return month_days[month - 1]; } From de848bcda44667ebec9d5d88a4b9360499d318cb Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sat, 11 Apr 2026 17:19:44 -0700 Subject: [PATCH 02/99] Refactor: libcrmcommon: Use g_date_get_days_in_month() Signed-off-by: Reid Wahl --- lib/common/iso8601.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 6acf9e371d9..eaf08ab940a 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -104,19 +104,31 @@ is_leap_year(int year) static int days_in_month_year(int month, int year) { - static const int month_days[12] = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 - }; + if (!g_date_valid_month(month)) { + return 0; + } - if ((month < 1) || (month > 12) || (year < 1)) { + if (year < 1) { return 0; } - if ((month == 2) && is_leap_year(year)) { - return month_days[1] + 1; + /* @COMPAT Remove this fallback when we can ensure that the year argument is + * always in the range 1 to 9999. g_date_get_days_in_month() takes a + * GDateYear, which is defined as guint16. + */ + if (year > UINT16_MAX) { + static const int month_days[12] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + + if ((month == 2) && is_leap_year(year)) { + return month_days[1] + 1; + } + + return month_days[month - 1]; } - return month_days[month - 1]; + return g_date_get_days_in_month(month, year); } /*! From 233e6a68acaaa2cd59020c6c61f66e4035d1fd7c Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 12 Apr 2026 00:54:57 -0700 Subject: [PATCH 03/99] Log: libcrmcommon: Drop unhelpful trace logs from crm_time_add_months() Signed-off-by: Reid Wahl --- lib/common/iso8601.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index eaf08ab940a..e79513e2359 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1806,8 +1806,6 @@ crm_time_add_months(crm_time_t * a_time, int extra) uint32_t y, m, d, dmax; crm_time_get_gregorian(a_time, &y, &m, &d); - pcmk__trace("Adding %d months to %.4" PRIu32 "-%.2" PRIu32 "-%.2" PRIu32, - extra, y, m, d); if (extra > 0) { for (lpc = extra; lpc > 0; lpc--) { @@ -1833,13 +1831,8 @@ crm_time_add_months(crm_time_t * a_time, int extra) d = dmax; } - pcmk__trace("Calculated %.4" PRIu32 "-%.2" PRIu32 "-%.2" PRIu32, y, m, d); - a_time->years = y; a_time->days = get_ordinal_days(y, m, d); - - crm_time_get_gregorian(a_time, &y, &m, &d); - pcmk__trace("Got %.4" PRIu32 "-%.2" PRIu32 "-%.2" PRIu32, y, m, d); } void From e073dec02179c9837f411f7a646b35b96cdc7188 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 12 Apr 2026 00:57:41 -0700 Subject: [PATCH 04/99] Refactor: libcrmcommon: Rename a_time and value variables in crm_time.c To match header. Also rename lpc to i in crm_time_add_months(). Signed-off-by: Reid Wahl --- lib/common/iso8601.c | 108 +++++++++++++++++++++---------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index e79513e2359..50cbcf5b610 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1732,83 +1732,81 @@ crm_time_compare(const crm_time_t *a, const crm_time_t *b) /*! * \brief Add a given number of seconds to a date/time or duration * - * \param[in,out] a_time Date/time or duration to add seconds to - * \param[in] extra Number of seconds to add + * \param[in,out] dt Date/time or duration to add seconds to + * \param[in] value Number of seconds to add */ void -crm_time_add_seconds(crm_time_t *a_time, int extra) +crm_time_add_seconds(crm_time_t *dt, int value) { - int days = extra / SECONDS_IN_DAY; + int days = value / SECONDS_IN_DAY; - pcmk__assert(a_time != NULL); + pcmk__assert(dt != NULL); - pcmk__trace("Adding %d seconds (including %d whole day%s) to %d", extra, - days, pcmk__plural_s(days), a_time->seconds); + pcmk__trace("Adding %d seconds (including %d whole day%s) to %d", value, + days, pcmk__plural_s(days), dt->seconds); - a_time->seconds += extra % SECONDS_IN_DAY; + dt->seconds += value % SECONDS_IN_DAY; // Check whether the addition crossed a day boundary - if (a_time->seconds > SECONDS_IN_DAY) { + if (dt->seconds > SECONDS_IN_DAY) { ++days; - a_time->seconds -= SECONDS_IN_DAY; + dt->seconds -= SECONDS_IN_DAY; - } else if (a_time->seconds < 0) { + } else if (dt->seconds < 0) { --days; - a_time->seconds += SECONDS_IN_DAY; + dt->seconds += SECONDS_IN_DAY; } - crm_time_add_days(a_time, days); + crm_time_add_days(dt, days); } /*! * \brief Add days to a date/time * - * \param[in,out] a_time Time to modify - * \param[in] extra Number of days to add (may be negative to subtract) + * \param[in,out] dt Time to modify + * \param[in] value Number of days to add (may be negative to subtract) */ void -crm_time_add_days(crm_time_t *a_time, int extra) +crm_time_add_days(crm_time_t *dt, int value) { - pcmk__assert(a_time != NULL); + pcmk__assert(dt != NULL); - pcmk__trace("Adding %d days to %.4d-%.3d", extra, a_time->years, - a_time->days); + pcmk__trace("Adding %d days to %.4d-%.3d", value, dt->years, dt->days); - if (extra > 0) { - while ((a_time->days + (long long) extra) > year_days(a_time->years)) { - if (a_time->years == INT_MAX) { + if (value > 0) { + while ((dt->days + (long long) value) > year_days(dt->years)) { + if (dt->years == INT_MAX) { // Clip to latest we can handle - a_time->days = year_days(a_time->years); + dt->days = year_days(dt->years); return; } - extra -= year_days(a_time->years); - a_time->years++; + value -= year_days(dt->years); + dt->years++; } - } else if (extra < 0) { - const int min_days = a_time->duration? 0 : 1; + } else if (value < 0) { + const int min_days = dt->duration? 0 : 1; - while ((a_time->days + (long long) extra) < min_days) { - if (a_time->years <= 1) { - a_time->days = 1; // Clip to earliest we can handle (no BCE) + while ((dt->days + (long long) value) < min_days) { + if (dt->years <= 1) { + dt->days = 1; // Clip to earliest we can handle (no BCE) return; } - a_time->years--; - extra += year_days(a_time->years); + dt->years--; + value += year_days(dt->years); } } - a_time->days += extra; + dt->days += value; } void -crm_time_add_months(crm_time_t * a_time, int extra) +crm_time_add_months(crm_time_t *dt, int value) { - int lpc; uint32_t y, m, d, dmax; - crm_time_get_gregorian(a_time, &y, &m, &d); + crm_time_get_gregorian(dt, &y, &m, &d); - if (extra > 0) { - for (lpc = extra; lpc > 0; lpc--) { + if (value > 0) { + for (int i = value; i > 0; i--) { m++; if (m == 13) { m = 1; @@ -1816,7 +1814,7 @@ crm_time_add_months(crm_time_t * a_time, int extra) } } } else { - for (lpc = extra; lpc < 0; lpc++) { + for (int i = value; i < 0; i++) { m--; if (m == 0) { m = 12; @@ -1831,39 +1829,41 @@ crm_time_add_months(crm_time_t * a_time, int extra) d = dmax; } - a_time->years = y; - a_time->days = get_ordinal_days(y, m, d); + dt->years = y; + dt->days = get_ordinal_days(y, m, d); } void -crm_time_add_minutes(crm_time_t * a_time, int extra) +crm_time_add_minutes(crm_time_t *dt, int value) { - crm_time_add_seconds(a_time, extra * SECONDS_IN_MINUTE); + crm_time_add_seconds(dt, value * SECONDS_IN_MINUTE); } void -crm_time_add_hours(crm_time_t * a_time, int extra) +crm_time_add_hours(crm_time_t *dt, int value) { - crm_time_add_seconds(a_time, extra * SECONDS_IN_HOUR); + crm_time_add_seconds(dt, value * SECONDS_IN_HOUR); } void -crm_time_add_weeks(crm_time_t * a_time, int extra) +crm_time_add_weeks(crm_time_t *dt, int value) { - crm_time_add_days(a_time, extra * 7); + crm_time_add_days(dt, value * 7); } void -crm_time_add_years(crm_time_t * a_time, int extra) +crm_time_add_years(crm_time_t *dt, int value) { - pcmk__assert(a_time != NULL); + pcmk__assert(dt != NULL); + + if ((value > 0) && ((dt->years + (long long) value) > INT_MAX)) { + dt->years = INT_MAX; + + } else if ((value < 0) && ((dt->years + (long long) value) < 1)) { + dt->years = 1; // Clip to earliest we can handle (no BCE) - if ((extra > 0) && ((a_time->years + (long long) extra) > INT_MAX)) { - a_time->years = INT_MAX; - } else if ((extra < 0) && ((a_time->years + (long long) extra) < 1)) { - a_time->years = 1; // Clip to earliest we can handle (no BCE) } else { - a_time->years += extra; + dt->years += value; } } From ad3e8685f12be883d07e7725343e1deb537195dc Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 12 Apr 2026 01:03:42 -0700 Subject: [PATCH 05/99] Refactor: libcrmcommon: Rename ymd variables in crm_time_add_months() Signed-off-by: Reid Wahl --- lib/common/iso8601.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 50cbcf5b610..f7c1f0f4c32 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1801,36 +1801,40 @@ crm_time_add_days(crm_time_t *dt, int value) void crm_time_add_months(crm_time_t *dt, int value) { - uint32_t y, m, d, dmax; + uint32_t year = 0; + uint32_t month = 0; + uint32_t day = 0; + int days_in_month = 0; - crm_time_get_gregorian(dt, &y, &m, &d); + crm_time_get_gregorian(dt, &year, &month, &day); if (value > 0) { for (int i = value; i > 0; i--) { - m++; - if (m == 13) { - m = 1; - y++; + month++; + if (month == 13) { + month = 1; + year++; } } } else { for (int i = value; i < 0; i++) { - m--; - if (m == 0) { - m = 12; - y--; + month--; + if (month == 0) { + month = 12; + year--; } } } - dmax = days_in_month_year(m, y); - if (dmax < d) { - /* Preserve day-of-month unless the month doesn't have enough days */ - d = dmax; + days_in_month = days_in_month_year(month, year); + + if (days_in_month < day) { + // Preserve day-of-month unless the month doesn't have enough days + day = days_in_month; } - dt->years = y; - dt->days = get_ordinal_days(y, m, d); + dt->years = year; + dt->days = get_ordinal_days(year, month, day); } void From a254b90fe5c0aad7c074725cfeebd5dbdebc160b Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 12 Apr 2026 01:20:42 -0700 Subject: [PATCH 06/99] Refactor: libcrmcommon: Assert before dereferencing in iso8601.c Signed-off-by: Reid Wahl --- lib/common/iso8601.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index f7c1f0f4c32..c2238980eb2 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -677,6 +677,8 @@ int crm_time_get_timeofday(const crm_time_t *dt, uint32_t *h, uint32_t *m, uint32_t *s) { + pcmk__assert((dt != NULL) && (h != NULL) && (m != NULL) && (s != NULL)); + seconds_to_hms(dt->seconds, h, m, s); return TRUE; } @@ -735,6 +737,8 @@ crm_time_get_gregorian(const crm_time_t *dt, uint32_t *y, uint32_t *m, int months = 0; int days = dt->days; + pcmk__assert((dt != NULL) && (y != NULL) && (m != NULL) && (d != NULL)); + if(dt->years != 0) { for (months = 1; months <= 12 && days > 0; months++) { int mdays = days_in_month_year(months, dt->years); @@ -765,6 +769,8 @@ crm_time_get_gregorian(const crm_time_t *dt, uint32_t *y, uint32_t *m, int crm_time_get_ordinal(const crm_time_t *dt, uint32_t *y, uint32_t *d) { + pcmk__assert((dt != NULL) && (y != NULL) && (d != NULL)); + *y = dt->years; *d = dt->days; return TRUE; @@ -775,13 +781,17 @@ pcmk__time_get_ywd(const crm_time_t *dt, uint32_t *y, uint32_t *w, uint32_t *d) { // Based on ISO week date: https://en.wikipedia.org/wiki/ISO_week_date int year_num = 0; - int jan1 = jan1_day_of_week(dt->years); + int jan1 = 0; int h = -1; + pcmk__assert((dt != NULL) && (y != NULL) && (w != NULL) && (d != NULL)); + if (dt->days <= 0) { return; } + jan1 = jan1_day_of_week(dt->years); + /* 6. Find the Weekday for Y M D */ h = dt->days + jan1 - 1; *d = 1 + ((h - 1) % 7); @@ -2340,6 +2350,8 @@ int crm_time_get_isoweek(const crm_time_t *dt, uint32_t *y, uint32_t *w, uint32_t *d) { + pcmk__assert((dt != NULL) && (y != NULL) && (w != NULL) && (d != NULL)); + CRM_CHECK(dt->days > 0, return FALSE); pcmk__time_get_ywd(dt, y, w, d); return TRUE; From 7f5bbf6a775251e1118bc990e524f76bd1651f87 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sat, 11 Apr 2026 12:45:45 -0700 Subject: [PATCH 07/99] Refactor: libcrmcommon: Improve variable names in get_ordinal_days() Signed-off-by: Reid Wahl --- lib/common/iso8601.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index c2238980eb2..17d5f23322e 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -135,26 +135,27 @@ days_in_month_year(int month, int year) * \internal * \brief Get ordinal day number of year corresponding to given date * - * \param[in] y Year - * \param[in] m Month (1-12) - * \param[in] d Day of month (1-31) + * \param[in] year Year + * \param[in] month Month (1-12) + * \param[in] day Day of month (1-31) * - * \return Day number of year \p y corresponding to month \p m and day \p d, - * or 0 for invalid arguments + * \return Day number of year \p year corresponding to month \p month and day + * \p day, or 0 for invalid arguments */ static int -get_ordinal_days(uint32_t y, uint32_t m, uint32_t d) +get_ordinal_days(uint32_t year, uint32_t month, uint32_t day) { - int result = 0; + int prev_month_days = 0; - CRM_CHECK((y > 0) && (y <= INT_MAX) && (m >= 1) && (m <= 12) - && (d >= 1) && (d <= 31), return 0); + CRM_CHECK((year >= 1) && (year <= INT_MAX) + && (month >= 1) && (month <= 12) + && (day >= 1) && (day <= 31), return 0); - result = d; - for (int lpc = 1; lpc < m; lpc++) { - result += days_in_month_year(lpc, y); + for (int i = 1; i < month; i++) { + prev_month_days += days_in_month_year(i, year); } - return result; + + return prev_month_days + day; } static int From dc6c7956203cfe82f3bc7634675a32cfc4cb752c Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sat, 11 Apr 2026 17:44:41 -0700 Subject: [PATCH 08/99] Refactor: libcrmcommon: Drop redundant check from parse_int() The caller already skips 'T' characters. Signed-off-by: Reid Wahl --- lib/common/iso8601.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 17d5f23322e..2937b0f81b3 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1088,25 +1088,25 @@ static int parse_int(const char *str, int *result) { unsigned int lpc; - int offset = (str[0] == 'T')? 1 : 0; + int offset = 0; bool negate = false; *result = 0; // @TODO This cannot handle combinations of these characters - switch (str[offset]) { + switch (str[0]) { case '.': case ',': return 0; // Fractions are not supported case '-': negate = true; - offset++; + offset = 1; break; case '+': case ':': - offset++; + offset = 1; break; default: @@ -1122,7 +1122,7 @@ parse_int(const char *str, int *result) *result = *result * 10 + digit; } if (negate) { - *result = 0 - *result; + *result = -*result; } return (lpc > 0)? offset : 0; } From 89675adc5c37ed2b8142690f9e5a9d71e04d1d95 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sat, 11 Apr 2026 21:05:31 -0700 Subject: [PATCH 09/99] Refactor: libcrmcommon: Functionizing parsing a duration element This makes crm_time_parse_duration() a little bit less convoluted. Signed-off-by: Reid Wahl --- cts/cli/regression.dates.exp | 4 +- cts/cts-cli.in | 3 +- lib/common/iso8601.c | 224 +++++++++++++++++++---------------- 3 files changed, 129 insertions(+), 102 deletions(-) diff --git a/cts/cli/regression.dates.exp b/cts/cli/regression.dates.exp index a3b4a9c07d4..d1aa4ba1794 100644 --- a/cts/cli/regression.dates.exp +++ b/cts/cli/regression.dates.exp @@ -69,12 +69,12 @@ iso8601: Invalid interval specified: 2019-01-01 00:00:00Z/P =#=#=#= End test: Invalid period - [2019-01-01 00:00:00Z/P] - Invalid parameter (2) =#=#=#= * Passed: iso8601 - Invalid period - [2019-01-01 00:00:00Z/P] =#=#=#= Begin test: Invalid period - [P1Z/2019-02-20 00:00:00Z] =#=#=#= -crm_time_parse_duration error: 'P1Z/2019-02-20 00:00:00Z' is not a valid ISO 8601 time duration because 'Z' is not a valid time unit +parse_duration_element error: 'P1Z/2019-02-20 00:00:00Z' is not a valid ISO 8601 time duration because 'Z' is not a valid time unit iso8601: Invalid interval specified: P1Z/2019-02-20 00:00:00Z =#=#=#= End test: Invalid period - [P1Z/2019-02-20 00:00:00Z] - Invalid parameter (2) =#=#=#= * Passed: iso8601 - Invalid period - [P1Z/2019-02-20 00:00:00Z] =#=#=#= Begin test: Invalid period - [P1YM/2019-02-20 00:00:00Z] =#=#=#= -crm_time_parse_duration error: 'P1YM/2019-02-20 00:00:00Z' is not a valid ISO 8601 time duration because no valid integer at 'M/2019-02-20 00:00:00Z' +parse_duration_element error: 'P1YM/2019-02-20 00:00:00Z' is not a valid ISO 8601 duration because no valid integer at 'M/2019-02-20 00:00:00Z' iso8601: Invalid interval specified: P1YM/2019-02-20 00:00:00Z =#=#=#= End test: Invalid period - [P1YM/2019-02-20 00:00:00Z] - Invalid parameter (2) =#=#=#= * Passed: iso8601 - Invalid period - [P1YM/2019-02-20 00:00:00Z] diff --git a/cts/cts-cli.in b/cts/cts-cli.in index eadb6a69ba1..5c2546b6862 100644 --- a/cts/cts-cli.in +++ b/cts/cts-cli.in @@ -9,7 +9,7 @@ # We know this is a very long file. # pylint: disable=too-many-lines -__copyright__ = "Copyright 2024-2025 the Pacemaker project contributors" +__copyright__ = "Copyright 2024-2026 the Pacemaker project contributors" __license__ = "GNU General Public License version 2 or later (GPLv2+) WITHOUT ANY WARRANTY" import argparse @@ -261,6 +261,7 @@ def sanitize_output(s): (r'last_update time=".*"', r'last_update time=""'), (r' last-rc-change=[\'"][-+A-Za-z0-9: ]*[\'"],?', r''), (r'\(parse_date@.*\.c:[0-9]+\)', r'parse_date'), + (r'\(parse_duration_element@.*\.c:[0-9]+\)', r'parse_duration_element'), (r'\((pcmk__.*)@.*\.c:[0-9]+\)', r'\1'), (r'.*Relax-NG validity error : ', r''), (r'request=".*cibadmin', r'request="cibadmin'), diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 2937b0f81b3..77398ca7715 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1127,6 +1127,128 @@ parse_int(const char *str, int *result) return (lpc > 0)? offset : 0; } +/*! + * \internal + * \brief Parse an element of an ISO 8601 duration string + * + * \param[in,out] element Element to parse (within \p duration_s) + * \param[in] duration_s Full duration string (for logging only) + * \param[in,out] duration Where to add result of parsing \p element + * \param[in] as_time If \c true, \c 'M' indicates minutes; otherwise, + * it indicates months + * + * \return Standard Pacemaker return code + * + * \note On successful return, \p element points to the unit designator of the + * element just parsed. This is a bit confusing but will suffice for now. + * \note \p as_time is set to \c true if the caller has encountered a \c 'T' + * already while parsing \p duration_s. + */ +static int +parse_duration_element(const char **element, const char *duration_s, + crm_time_t *duration, bool as_time) +{ + int value = 0; + int consumed = 0; + long long result = 0; + const char *start = *element; + + // Component must begin with an integer + consumed = parse_int(*element, &value); + if (consumed == 0) { + pcmk__err("'%s' is not a valid ISO 8601 duration because no valid " + "integer at '%s'", duration_s, *element); + return pcmk_rc_bad_input; + } + + *element += consumed; + + // A unit designator must be next (we're not strict about the order) + switch (**element) { + case 'Y': + duration->years = value; + break; + + case 'M': + if (!as_time) { // Months + duration->months = value; + + } else { // Minutes + result = duration->seconds + (value * 60LL); + if ((result < INT_MIN) || (result > INT_MAX)) { + pcmk__err("'%s' is not a valid ISO 8601 time duration " + "because integer at '%s' is too %s", duration_s, + start, ((result > 0)? "large" : "small")); + return pcmk_rc_bad_input; + } + + duration->seconds = (int) result; + } + + break; + + case 'W': + result = duration->days + (value * 7LL); + if ((result < INT_MIN) || (result > INT_MAX)) { + pcmk__err("'%s' is not a valid ISO 8601 time duration because " + "integer at '%s' is too %s", duration_s, start, + ((result > 0)? "large" : "small")); + return pcmk_rc_bad_input; + } + + duration->days = (int) result; + break; + + case 'D': + result = duration->days + (long long) value; + if ((result < INT_MIN) || (result > INT_MAX)) { + pcmk__err("'%s' is not a valid ISO 8601 time duration because " + "integer at '%s' is too %s", duration_s, start, + ((result > 0)? "large" : "small")); + return pcmk_rc_bad_input; + } + + duration->days = (int) result; + break; + + case 'H': + result = duration->seconds + ((long long) value * SECONDS_IN_HOUR); + if ((result < INT_MIN) || (result > INT_MAX)) { + pcmk__err("'%s' is not a valid ISO 8601 time duration because " + "integer at '%s' is too %s", duration_s, start, + ((result > 0)? "large" : "small")); + return pcmk_rc_bad_input; + } + + duration->seconds = (int) result; + break; + + case 'S': + result = duration->seconds + (long long) value; + if ((result < INT_MIN) || (result > INT_MAX)) { + pcmk__err("'%s' is not a valid ISO 8601 time duration because " + "integer at '%s' is too %s", duration_s, start, + ((result > 0)? "large" : "small")); + return pcmk_rc_bad_input; + } + + duration->seconds = (int) result; + break; + + case '\0': + pcmk__err("'%s' is not a valid ISO 8601 time duration because " + "no units after %d", duration_s, value); + return pcmk_rc_bad_input; + + default: + pcmk__err("'%s' is not a valid ISO 8601 time duration because " + "'%c' is not a valid time unit", duration_s, **element); + return pcmk_rc_bad_input; + } + + return pcmk_rc_ok; +} + /*! * \brief Parse a time duration from an ISO 8601 duration specification * @@ -1167,9 +1289,6 @@ crm_time_parse_duration(const char *period_s) current[0] && (current[0] != '/') && !isspace(current[0]); ++current) { - int an_int = 0, rc; - long long result = 0LL; - if (current[0] == 'T') { /* A 'T' separates year/month/day from hour/minute/seconds. We don't * require it strictly, but just use it to differentiate month from @@ -1179,104 +1298,11 @@ crm_time_parse_duration(const char *period_s) continue; } - // An integer must be next - rc = parse_int(current, &an_int); - if (rc == 0) { - pcmk__err("'%s' is not a valid ISO 8601 time duration because no " - "valid integer at '%s'", - period_s, current); + // current points to last character of current element on success + if (parse_duration_element(¤t, period_s, diff, + is_time) != pcmk_rc_ok) { goto invalid; } - current += rc; - - // A time unit must be next (we're not strict about the order) - switch (current[0]) { - case 'Y': - diff->years = an_int; - break; - - case 'M': - if (!is_time) { // Months - diff->months = an_int; - } else { // Minutes - result = diff->seconds + an_int * 60LL; - if ((result < INT_MIN) || (result > INT_MAX)) { - pcmk__err("'%s' is not a valid ISO 8601 time duration " - "because integer at '%s' is too %s", - period_s, (current - rc), - ((result > 0)? "large" : "small")); - goto invalid; - } else { - diff->seconds = (int) result; - } - } - - break; - - case 'W': - result = diff->days + an_int * 7LL; - if ((result < INT_MIN) || (result > INT_MAX)) { - pcmk__err("'%s' is not a valid ISO 8601 time duration " - "because integer at '%s' is too %s", - period_s, (current - rc), - ((result > 0)? "large" : "small")); - goto invalid; - } else { - diff->days = (int) result; - } - break; - - case 'D': - result = diff->days + (long long) an_int; - if ((result < INT_MIN) || (result > INT_MAX)) { - pcmk__err("'%s' is not a valid ISO 8601 time duration " - "because integer at '%s' is too %s", - period_s, (current - rc), - ((result > 0)? "large" : "small")); - goto invalid; - } else { - diff->days = (int) result; - } - break; - - case 'H': - result = diff->seconds + ((long long) an_int * SECONDS_IN_HOUR); - if ((result < INT_MIN) || (result > INT_MAX)) { - pcmk__err("'%s' is not a valid ISO 8601 time duration " - "because integer at '%s' is too %s", - period_s, (current - rc), - ((result > 0)? "large" : "small")); - goto invalid; - } else { - diff->seconds = (int) result; - } - break; - - case 'S': - result = diff->seconds + (long long) an_int; - if ((result < INT_MIN) || (result > INT_MAX)) { - pcmk__err("'%s' is not a valid ISO 8601 time duration " - "because integer at '%s' is too %s", - period_s, (current - rc), - ((result > 0)? "large" : "small")); - goto invalid; - } else { - diff->seconds = (int) result; - } - break; - - case '\0': - pcmk__err("'%s' is not a valid ISO 8601 time duration because " - "no units after %d", - period_s, an_int); - goto invalid; - - default: - pcmk__err("'%s' is not a valid ISO 8601 time duration because " - "'%c' is not a valid time unit", - period_s, current[0]); - goto invalid; - } } if (!crm_time_is_defined(diff)) { From 5d4ca39067eb946f309cf84612d7453f00561527 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sat, 11 Apr 2026 21:32:31 -0700 Subject: [PATCH 10/99] Refactor: libcrmcommon: Drop some nesting in parse_duration_element() Signed-off-by: Reid Wahl --- lib/common/iso8601.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 77398ca7715..d0787608104 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1167,25 +1167,25 @@ parse_duration_element(const char **element, const char *duration_s, switch (**element) { case 'Y': duration->years = value; - break; + return pcmk_rc_ok; case 'M': if (!as_time) { // Months duration->months = value; + return pcmk_rc_ok; + } - } else { // Minutes - result = duration->seconds + (value * 60LL); - if ((result < INT_MIN) || (result > INT_MAX)) { - pcmk__err("'%s' is not a valid ISO 8601 time duration " - "because integer at '%s' is too %s", duration_s, - start, ((result > 0)? "large" : "small")); - return pcmk_rc_bad_input; - } - - duration->seconds = (int) result; + // Minutes + result = duration->seconds + (value * 60LL); + if ((result < INT_MIN) || (result > INT_MAX)) { + pcmk__err("'%s' is not a valid ISO 8601 time duration because " + "integer at '%s' is too %s", duration_s, start, + ((result > 0)? "large" : "small")); + return pcmk_rc_bad_input; } - break; + duration->seconds = (int) result; + return pcmk_rc_ok; case 'W': result = duration->days + (value * 7LL); @@ -1197,7 +1197,7 @@ parse_duration_element(const char **element, const char *duration_s, } duration->days = (int) result; - break; + return pcmk_rc_ok; case 'D': result = duration->days + (long long) value; @@ -1209,7 +1209,7 @@ parse_duration_element(const char **element, const char *duration_s, } duration->days = (int) result; - break; + return pcmk_rc_ok; case 'H': result = duration->seconds + ((long long) value * SECONDS_IN_HOUR); @@ -1221,7 +1221,7 @@ parse_duration_element(const char **element, const char *duration_s, } duration->seconds = (int) result; - break; + return pcmk_rc_ok; case 'S': result = duration->seconds + (long long) value; @@ -1233,7 +1233,7 @@ parse_duration_element(const char **element, const char *duration_s, } duration->seconds = (int) result; - break; + return pcmk_rc_ok; case '\0': pcmk__err("'%s' is not a valid ISO 8601 time duration because " @@ -1245,8 +1245,6 @@ parse_duration_element(const char **element, const char *duration_s, "'%c' is not a valid time unit", duration_s, **element); return pcmk_rc_bad_input; } - - return pcmk_rc_ok; } /*! From d45db96828948b3f7ca4205011e986a33b672b8a Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sat, 11 Apr 2026 21:51:50 -0700 Subject: [PATCH 11/99] Log: libcrmcommon: Improve no-units message in parse_duration_element() It's clearer to show the original string value than the parsed integer. Signed-off-by: Reid Wahl --- lib/common/iso8601.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index d0787608104..90db847de36 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1236,8 +1236,8 @@ parse_duration_element(const char **element, const char *duration_s, return pcmk_rc_ok; case '\0': - pcmk__err("'%s' is not a valid ISO 8601 time duration because " - "no units after %d", duration_s, value); + pcmk__err("'%s' is not a valid ISO 8601 duration because no units " + "after %s", duration_s, start); return pcmk_rc_bad_input; default: From d6db32b46f5303125c49231436468cd48692937e Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sat, 11 Apr 2026 21:43:42 -0700 Subject: [PATCH 12/99] Log: libcrmcommon: Simplify overflow logging in parse_duration_element() It's incorrect to say that a particular integer is too large or too small, in the way we were doing. In the lax way we're parsing durations, multiple elements with the same designator may occur. Also, elements with different designators can add to the same field of the crm_time_t object. So multiple elements, none of which are too large or too small on their own, can sum to a value that overflows the size of an int. Reduce duplication and simplify the log messages on overflow. Signed-off-by: Reid Wahl --- cts/cli/regression.dates.exp | 2 +- lib/common/iso8601.c | 34 ++++++++++++---------------------- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/cts/cli/regression.dates.exp b/cts/cli/regression.dates.exp index d1aa4ba1794..1e4119c666d 100644 --- a/cts/cli/regression.dates.exp +++ b/cts/cli/regression.dates.exp @@ -69,7 +69,7 @@ iso8601: Invalid interval specified: 2019-01-01 00:00:00Z/P =#=#=#= End test: Invalid period - [2019-01-01 00:00:00Z/P] - Invalid parameter (2) =#=#=#= * Passed: iso8601 - Invalid period - [2019-01-01 00:00:00Z/P] =#=#=#= Begin test: Invalid period - [P1Z/2019-02-20 00:00:00Z] =#=#=#= -parse_duration_element error: 'P1Z/2019-02-20 00:00:00Z' is not a valid ISO 8601 time duration because 'Z' is not a valid time unit +parse_duration_element error: 'P1Z/2019-02-20 00:00:00Z' is not a valid ISO 8601 duration because 'Z' is not a valid time unit iso8601: Invalid interval specified: P1Z/2019-02-20 00:00:00Z =#=#=#= End test: Invalid period - [P1Z/2019-02-20 00:00:00Z] - Invalid parameter (2) =#=#=#= * Passed: iso8601 - Invalid period - [P1Z/2019-02-20 00:00:00Z] diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 90db847de36..3bcb9755fe4 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1178,10 +1178,7 @@ parse_duration_element(const char **element, const char *duration_s, // Minutes result = duration->seconds + (value * 60LL); if ((result < INT_MIN) || (result > INT_MAX)) { - pcmk__err("'%s' is not a valid ISO 8601 time duration because " - "integer at '%s' is too %s", duration_s, start, - ((result > 0)? "large" : "small")); - return pcmk_rc_bad_input; + break; } duration->seconds = (int) result; @@ -1190,10 +1187,7 @@ parse_duration_element(const char **element, const char *duration_s, case 'W': result = duration->days + (value * 7LL); if ((result < INT_MIN) || (result > INT_MAX)) { - pcmk__err("'%s' is not a valid ISO 8601 time duration because " - "integer at '%s' is too %s", duration_s, start, - ((result > 0)? "large" : "small")); - return pcmk_rc_bad_input; + break; } duration->days = (int) result; @@ -1202,10 +1196,7 @@ parse_duration_element(const char **element, const char *duration_s, case 'D': result = duration->days + (long long) value; if ((result < INT_MIN) || (result > INT_MAX)) { - pcmk__err("'%s' is not a valid ISO 8601 time duration because " - "integer at '%s' is too %s", duration_s, start, - ((result > 0)? "large" : "small")); - return pcmk_rc_bad_input; + break; } duration->days = (int) result; @@ -1214,10 +1205,7 @@ parse_duration_element(const char **element, const char *duration_s, case 'H': result = duration->seconds + ((long long) value * SECONDS_IN_HOUR); if ((result < INT_MIN) || (result > INT_MAX)) { - pcmk__err("'%s' is not a valid ISO 8601 time duration because " - "integer at '%s' is too %s", duration_s, start, - ((result > 0)? "large" : "small")); - return pcmk_rc_bad_input; + break; } duration->seconds = (int) result; @@ -1226,10 +1214,7 @@ parse_duration_element(const char **element, const char *duration_s, case 'S': result = duration->seconds + (long long) value; if ((result < INT_MIN) || (result > INT_MAX)) { - pcmk__err("'%s' is not a valid ISO 8601 time duration because " - "integer at '%s' is too %s", duration_s, start, - ((result > 0)? "large" : "small")); - return pcmk_rc_bad_input; + break; } duration->seconds = (int) result; @@ -1241,10 +1226,15 @@ parse_duration_element(const char **element, const char *duration_s, return pcmk_rc_bad_input; default: - pcmk__err("'%s' is not a valid ISO 8601 time duration because " - "'%c' is not a valid time unit", duration_s, **element); + pcmk__err("'%s' is not a valid ISO 8601 duration because '%c' is " + "not a valid time unit", duration_s, **element); return pcmk_rc_bad_input; } + + pcmk__err("'%s' could not be parsed as an ISO 8601 duration because the " + "the parsed value for one or more time units is too large", + duration_s); + return pcmk_rc_bad_input; } /*! From fd3dace889036962e8f7a3900a1c0d3c24a8b5ae Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sat, 11 Apr 2026 23:30:00 -0700 Subject: [PATCH 13/99] Low: libcrmcommon: Improve crm_time_get_seconds() for durations There's no "right" way to do this, and it should be exceedingly rare that our users specify years or months as part of a duration. But since we unfortunately support a ISO 8601 duration-like syntax in a wide variety of contexts, we should handle it sanely. Hopefully we can deprecate and drop it sometime. Signed-off-by: Reid Wahl --- lib/common/iso8601.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 3bcb9755fe4..8e70755f04f 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -688,7 +688,8 @@ long long crm_time_get_seconds(const crm_time_t *dt) { crm_time_t *utc = NULL; - long long in_seconds = 0; + long long days = 0; + long long seconds = 0; if (dt == NULL) { return 0; @@ -699,29 +700,31 @@ crm_time_get_seconds(const crm_time_t *dt) dt = utc; } - // @TODO We should probably use <= if dt is a duration - for (int i = 1; i < dt->years; i++) { - long long dmax = year_days(i); + if (dt->duration) { + /* Assume 365-day years and 30-day months. The correct number of days in + * years and months varies depending on the start date to which the + * duration will be applied, which is unknown. + */ + days = (365 * (long long) dt->years) + + (30 * (long long) dt->months) + + dt->days; - in_seconds += SECONDS_IN_DAY * dmax; - } + } else { + // The months field can be set only for durations, so ignore it here + for (int i = 1; i < dt->years; i++) { + days += year_days(i); + } - /* utc->months can be set only for durations. By definition, the value - * varies depending on the (unknown) start date to which the duration will - * be applied. Assume 30-day months so that something vaguely sane happens - * in this case. - */ - if (dt->months > 0) { - in_seconds += SECONDS_IN_DAY * 30 * (long long) (dt->months); + // This is probably always true + if (dt->days > 0) { + days += dt->days - 1; + } } - if (dt->days > 0) { - in_seconds += SECONDS_IN_DAY * (long long) (dt->days - 1); - } - in_seconds += dt->seconds; + seconds = dt->seconds + (SECONDS_IN_DAY * days); crm_time_free(utc); - return in_seconds; + return seconds; } #define EPOCH_SECONDS 62135596800ULL /* Calculated using crm_time_get_seconds() */ From a940eb9875c1503cfd2a706b7c755f67e72f0ac8 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 12 Apr 2026 11:25:11 -0700 Subject: [PATCH 14/99] Refactor: libcrmcommon: Use g_date_is_leap_year() The pcmk__time_valid_year() function will be used outside this file soon. Signed-off-by: Reid Wahl --- include/crm/common/iso8601_internal.h | 1 + lib/common/iso8601.c | 26 ++++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/include/crm/common/iso8601_internal.h b/include/crm/common/iso8601_internal.h index f8817ff0d5c..473b876cc4a 100644 --- a/include/crm/common/iso8601_internal.h +++ b/include/crm/common/iso8601_internal.h @@ -27,6 +27,7 @@ extern "C" { #endif +bool pcmk__time_valid_year(int year); void pcmk__time_get_ywd(const crm_time_t *dt, uint32_t *y, uint32_t *w, uint32_t *d); char *pcmk__time_format_hr(const char *format, const crm_time_t *dt, int usec); diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 8e70755f04f..4f28e0c7516 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -85,11 +85,33 @@ crm_time_new_undefined(void) return pcmk__assert_alloc(1, sizeof(crm_time_t)); } +/*! + * \internal + * \brief Check whether a year is positive and representable by four digits + * + * \param[in] year Year + * + * \return \c true if \p year is between 1 and 9999 (inclusive), or \c false + * otherwise + */ +bool +pcmk__time_valid_year(int year) +{ + return (year >= 1) && (year <= 9999); +} + static bool is_leap_year(int year) { - return ((year % 4) == 0) - && (((year % 100) != 0) || (year % 400 == 0)); + /* @COMPAT Remove this fallback when we can ensure that the year argument is + * always in the range 1 to 9999. + */ + if (!pcmk__time_valid_year(year)) { + return ((year % 4) == 0) + && (((year % 100) != 0) || (year % 400 == 0)); + } + + return g_date_is_leap_year(year); } /*! From a76eb5f4e3687051d5683d2fa364ed857f72ce94 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 12 Apr 2026 11:23:53 -0700 Subject: [PATCH 15/99] Doc: libcrmcommon: Address FIXME comment about GLib version The reason for the deprecation warning regardless of installed version, is that we define GLIB_VERSION_MIN_REQUIRED and GLIB_VERSION_MAX_ALLOWED as GLIB_VERSION_2_42. So we are strictly bound to the 2.42 API. However, when we can use version 2.58 or later, we're better off using g_time_zone_new_offset(). This avoids the need to convert the offset to a string. Signed-off-by: Reid Wahl --- lib/common/iso8601.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 4f28e0c7516..3adc4d02cb8 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1986,16 +1986,7 @@ get_g_date_time(const struct tm *tm, int offset) CRM_LOG_ASSERT(QB_ABS(offset) <= SECONDS_IN_DAY); } - /* @FIXME @COMPAT As of glib 2.68, g_time_zone_new() is deprecated in favor - * of g_time_zone_new_identifier(). However, calling - * g_time_zone_new_identifier() results in compiler warnings, even on a - * system with glib 2.84 installed. It is unclear why. - * - * The *_new_identifier() function was added (and the *_new() function - * deprecated) in version 2.68. They have the same signature. Ideally, we - * would choose which function to call here and below based the installed - * glib version using a CPP guard. - */ + // @COMPAT Starting in GLib 2.58, we can use g_time_zone_new_offset() tz = g_time_zone_new(offset_s); dt = g_date_time_new(tz, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); From 9c32aa3ceabb12fd8c29a785f6ea5e6ff0c50ac3 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 12 Apr 2026 11:47:27 -0700 Subject: [PATCH 16/99] Refactor: libcrmcommon: New offset_text() Allocate a new string for readability, even though we know the exact string length in advance and were previously taking advantage of that in order to use a static buffer. Signed-off-by: Reid Wahl --- lib/common/iso8601.c | 50 +++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 3adc4d02cb8..780e786d72c 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1945,6 +1945,22 @@ ha_get_tm_time(struct tm *target, const crm_time_t *source) mktime(target); } +static char * +offset_text(int offset) +{ + uint32_t hours = 0; + uint32_t minutes = 0; + uint32_t seconds = 0; + + // If offset is out of range, default to NULL + CRM_CHECK(QB_ABS(offset) <= SECONDS_IN_DAY, return NULL); + + seconds_to_hms(offset, &hours, &minutes, &seconds); + + return pcmk__assert_asprintf("%c%02" PRIu32 ":%02" PRIu32, + ((offset >= 0)? '+' : '-'), hours, minutes); +} + /*! * \internal * \brief Convert a struct tm to a \c GDateTime @@ -1962,35 +1978,25 @@ static GDateTime * get_g_date_time(const struct tm *tm, int offset) { // Accept an offset argument in case tm lacks a tm_gmtoff member - char buf[sizeof("+hh:mm")] = { '\0', }; - const char *offset_s = NULL; - + char *offset_s = offset_text(offset); GTimeZone *tz = NULL; GDateTime *dt = NULL; - if (QB_ABS(offset) <= SECONDS_IN_DAY) { - uint32_t hours = 0; - uint32_t minutes = 0; - uint32_t seconds = 0; - int rc = 0; - - seconds_to_hms(offset, &hours, &minutes, &seconds); - - rc = snprintf(buf, sizeof(buf), "%c%02" PRIu32 ":%02" PRIu32, - ((offset >= 0)? '+' : '-'), hours, minutes); - pcmk__assert(rc == (sizeof(buf) - 1)); - offset_s = buf; - - } else { - // offset out of range; use NULL as offset_s - CRM_LOG_ASSERT(QB_ABS(offset) <= SECONDS_IN_DAY); - } - // @COMPAT Starting in GLib 2.58, we can use g_time_zone_new_offset() tz = g_time_zone_new(offset_s); + if (tz == NULL) { + goto done; + } + dt = g_date_time_new(tz, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); - g_time_zone_unref(tz); + +done: + free(offset_s); + + if (tz != NULL) { + g_time_zone_unref(tz); + } return dt; } From d202fb9b2825c3ff706f853f27ee9e32f7429151 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 12 Apr 2026 11:57:29 -0700 Subject: [PATCH 17/99] Refactor: libcrmcommon: seconds_to_hms() accepts NULL seconds This isn't really in keeping with the function name. However, some callers care only about the resulting hours and minutes, so this is more convenient than requiring those callers to pass dummy seconds output variables. Signed-off-by: Reid Wahl --- lib/common/iso8601.c | 49 ++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 780e786d72c..0676614ed59 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -336,21 +336,36 @@ parse_offset(const char *offset_str, int *offset) return true; } +/*! + * \internal + * \brief Convert seconds to hours, minutes, and seconds + * + * The resulting minutes and seconds are in the range [0, 59]. Accordingly, the + * number of hours is \p seconds_i divided by \c SECONDS_IN_HOUR. + * + * \param[in] seconds_i Seconds to convert + * \param[out] hours Where to store hours + * \param[out] minutes Where to store minutes + * \param[out] seconds If not \c NULL, where to store seconds + */ static void -seconds_to_hms(int seconds, uint32_t *h, uint32_t *m, uint32_t *s) +seconds_to_hms(int seconds_i, uint32_t *hours, uint32_t *minutes, + uint32_t *seconds) { - int hours = 0; - int minutes = 0; + int hours_i = 0; + int minutes_i = 0; - hours = seconds / SECONDS_IN_HOUR; - seconds %= SECONDS_IN_HOUR; + hours_i = seconds_i / SECONDS_IN_HOUR; + seconds_i %= SECONDS_IN_HOUR; - minutes = seconds / SECONDS_IN_MINUTE; - seconds %= SECONDS_IN_MINUTE; + minutes_i = seconds_i / SECONDS_IN_MINUTE; + seconds_i %= SECONDS_IN_MINUTE; - *h = (uint32_t) QB_ABS(hours); - *m = (uint32_t) QB_ABS(minutes); - *s = (uint32_t) QB_ABS(seconds); + *hours = (uint32_t) QB_ABS(hours_i); + *minutes = (uint32_t) QB_ABS(minutes_i); + if (seconds != NULL) { + *seconds = (uint32_t) QB_ABS(seconds_i); + } } /*! @@ -366,7 +381,8 @@ seconds_to_hms(int seconds, uint32_t *h, uint32_t *m, uint32_t *s) static bool parse_time(const char *time_str, crm_time_t *a_time) { - uint32_t h, m, s; + uint32_t h = 0; + uint32_t m = 0; const char *offset_s = NULL; tzset(); @@ -394,7 +410,7 @@ parse_time(const char *time_str, crm_time_t *a_time) return false; } - seconds_to_hms(a_time->offset, &h, &m, &s); + seconds_to_hms(a_time->offset, &h, &m, NULL); pcmk__trace("Got tz: %c%2." PRIu32 ":%.2" PRIu32, (a_time->offset < 0)? '-' : '+', h, m); @@ -1078,7 +1094,7 @@ time_as_string_common(const crm_time_t *dt, int usec, uint32_t flags) if (pcmk__is_set(flags, crm_time_log_with_timezone) && (dt->offset != 0)) { - seconds_to_hms(dt->offset, &h, &m, &s); + seconds_to_hms(dt->offset, &h, &m, NULL); g_string_append_printf(buf, " %c%.2" PRIu32 ":%.2" PRIu32, ((dt->offset < 0)? '-' : '+'), h, m); @@ -1950,12 +1966,11 @@ offset_text(int offset) { uint32_t hours = 0; uint32_t minutes = 0; - uint32_t seconds = 0; // If offset is out of range, default to NULL CRM_CHECK(QB_ABS(offset) <= SECONDS_IN_DAY, return NULL); - seconds_to_hms(offset, &hours, &minutes, &seconds); + seconds_to_hms(offset, &hours, &minutes, NULL); return pcmk__assert_asprintf("%c%02" PRIu32 ":%02" PRIu32, ((offset >= 0)? '+' : '-'), hours, minutes); @@ -2324,9 +2339,7 @@ crm_time_days_in_month(int month, int year) int crm_time_get_timezone(const crm_time_t *dt, uint32_t *h, uint32_t *m) { - uint32_t s; - - seconds_to_hms(dt->seconds, h, m, &s); + seconds_to_hms(dt->seconds, h, m, NULL); return TRUE; } From 6489138ba7f88c12c9c2408ce8c957c1485fe9e4 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Mon, 13 Apr 2026 16:19:30 -0700 Subject: [PATCH 18/99] Refactor: tools: Drop redundant else in crm_rule.c crm_time_new(NULL) always returns non-NULL. Signed-off-by: Reid Wahl --- tools/crm_rule.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/tools/crm_rule.c b/tools/crm_rule.c index bf22b197c3b..cead4a1c328 100644 --- a/tools/crm_rule.c +++ b/tools/crm_rule.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2025 the Pacemaker project contributors + * Copyright 2019-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -158,17 +158,9 @@ main(int argc, char **argv) /* Set up some defaults. */ rule_date = crm_time_new(options.date); if (rule_date == NULL) { - if (options.date != NULL) { - exit_code = CRM_EX_DATAERR; - g_set_error(&error, PCMK__EXITC_ERROR, exit_code, - "Invalid date specified: '%s'", options.date); - - } else { - // Should never happen - exit_code = CRM_EX_OSERR; - g_set_error(&error, PCMK__EXITC_ERROR, exit_code, - "No --date given and can't determine current date"); - } + exit_code = CRM_EX_DATAERR; + g_set_error(&error, PCMK__EXITC_ERROR, exit_code, + "Invalid date specified: '%s'", options.date); goto done; } From f12cb5f12d1844a7f7d81a13c93832b3c819a5c3 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 16 Apr 2026 08:14:06 -0700 Subject: [PATCH 19/99] Refactor: libcrmcommon: Remove some nesting in set_effective_date() Signed-off-by: Reid Wahl --- lib/pacemaker/pcmk_simulate.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/lib/pacemaker/pcmk_simulate.c b/lib/pacemaker/pcmk_simulate.c index 647c2342257..467f1f15d03 100644 --- a/lib/pacemaker/pcmk_simulate.c +++ b/lib/pacemaker/pcmk_simulate.c @@ -498,31 +498,34 @@ static void set_effective_date(pcmk_scheduler_t *scheduler, bool print_original, const char *use_date) { + static const uint32_t flags = crm_time_log_date|crm_time_log_timeofday; + pcmk__output_t *out = scheduler->priv->out; time_t original_date = 0; pcmk__assert(out != NULL); - pcmk__xe_get_time(scheduler->input, PCMK_XA_EXECUTION_DATE, - &original_date); - if (use_date) { scheduler->priv->now = crm_time_new(use_date); out->info(out, "Setting effective cluster time: %s", use_date); pcmk__time_log(LOG_NOTICE, "Pretending 'now' is", scheduler->priv->now, - crm_time_log_date|crm_time_log_timeofday); + flags); + return; + } - } else if (original_date != 0) { - scheduler->priv->now = pcmk__copy_timet(original_date); + pcmk__xe_get_time(scheduler->input, PCMK_XA_EXECUTION_DATE, + &original_date); + if (original_date == 0) { + return; + } - if (print_original) { - char *when = crm_time_as_string(scheduler->priv->now, - crm_time_log_date - |crm_time_log_timeofday); + scheduler->priv->now = pcmk__copy_timet(original_date); - out->info(out, "Using the original execution date of: %s", when); - free(when); - } + if (print_original) { + char *when = crm_time_as_string(scheduler->priv->now, flags); + + out->info(out, "Using the original execution date of: %s", when); + free(when); } } From 938e2361378b5201c12f927fa92cfcb5247fbcbd Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 17 Apr 2026 05:32:44 -0700 Subject: [PATCH 20/99] Refactor: libpacemaker: Improve validation in set_effective_date() Check whether parsing was successful, not whether the value was 0 (which is technically a valid value: epoch). Signed-off-by: Reid Wahl --- lib/pacemaker/pcmk_simulate.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/pacemaker/pcmk_simulate.c b/lib/pacemaker/pcmk_simulate.c index 467f1f15d03..7e093f12050 100644 --- a/lib/pacemaker/pcmk_simulate.c +++ b/lib/pacemaker/pcmk_simulate.c @@ -513,9 +513,8 @@ set_effective_date(pcmk_scheduler_t *scheduler, bool print_original, return; } - pcmk__xe_get_time(scheduler->input, PCMK_XA_EXECUTION_DATE, - &original_date); - if (original_date == 0) { + if (pcmk__xe_get_time(scheduler->input, PCMK_XA_EXECUTION_DATE, + &original_date) != pcmk_rc_ok) { return; } From b5a1e81fca1f1c61d55882cad6b8119ef3a730b3 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sat, 25 Apr 2026 19:41:54 -0700 Subject: [PATCH 21/99] Refactor: libcrmcommon: Cast -1 to time_t for comparison Signed-off-by: Reid Wahl --- lib/common/tls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common/tls.c b/lib/common/tls.c index babb8b9b20e..3ba6aa94661 100644 --- a/lib/common/tls.c +++ b/lib/common/tls.c @@ -466,7 +466,7 @@ pcmk__tls_check_cert_expiration(gnutls_session_t session) expiry = gnutls_x509_crt_get_expiration_time(cert); - if (expiry != -1) { + if (expiry != (time_t) -1) { time_t now = time(NULL); /* If the cert is going to expire within ~ one month (30 days), log it */ From cbeba228610479765d630917d1c5068c2e2ce737 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 26 Apr 2026 23:31:55 -0700 Subject: [PATCH 22/99] Test: cts-cli: Test out-of-range year in interval specification The spec with year 10000 is valid for now. Note that years get scanned as uint32_t, so -1 becomes UINT32_MAX. I expect that number to be platform-independent. Signed-off-by: Reid Wahl --- cts/cli/regression.dates.exp | 24 ++++++++++++++++++++++++ cts/cts-cli.in | 3 +++ 2 files changed, 27 insertions(+) diff --git a/cts/cli/regression.dates.exp b/cts/cli/regression.dates.exp index 1e4119c666d..ce4ad538492 100644 --- a/cts/cli/regression.dates.exp +++ b/cts/cli/regression.dates.exp @@ -78,6 +78,16 @@ parse_duration_element error: 'P1YM/2019-02-20 00:00:00Z' is not a valid ISO 86 iso8601: Invalid interval specified: P1YM/2019-02-20 00:00:00Z =#=#=#= End test: Invalid period - [P1YM/2019-02-20 00:00:00Z] - Invalid parameter (2) =#=#=#= * Passed: iso8601 - Invalid period - [P1YM/2019-02-20 00:00:00Z] +=#=#=#= Begin test: Invalid period - [0000-10-01T00:00:00Z/P1M] =#=#=#= +parse_date error: '0000-10-01T00:00:00Z/P1M' is not a valid ISO 8601 date/time specification because '0' is not a valid year +iso8601: Invalid interval specified: 0000-10-01T00:00:00Z/P1M +=#=#=#= End test: Invalid period - [0000-10-01T00:00:00Z/P1M] - Invalid parameter (2) =#=#=#= +* Passed: iso8601 - Invalid period - [0000-10-01T00:00:00Z/P1M] +=#=#=#= Begin test: Invalid period - [-0001-10-01T00:00:00Z/P1M] =#=#=#= +parse_date error: '-0001-10-01T00:00:00Z/P1M' is not a valid ISO 8601 date/time specification because '4294967295' is not a valid year +iso8601: Invalid interval specified: -0001-10-01T00:00:00Z/P1M +=#=#=#= End test: Invalid period - [-0001-10-01T00:00:00Z/P1M] - Invalid parameter (2) =#=#=#= +* Passed: iso8601 - Invalid period - [-0001-10-01T00:00:00Z/P1M] =#=#=#= Begin test: '2005-040/2005-043' period =#=#=#= Period: 2005-02-09 00:00:00Z to 2005-02-12 00:00:00Z =#=#=#= End test: '2005-040/2005-043' period - OK (0) =#=#=#= @@ -92,6 +102,20 @@ Period: 2005-02-09 00:00:00Z to 2005-02-12 00:00:00Z =#=#=#= End test: '2005-040/2005-043' period (XML) - OK (0) =#=#=#= * Passed: iso8601 - '2005-040/2005-043' period (XML) +=#=#=#= Begin test: '10000-10-01T00:00:00Z/P1M' period =#=#=#= +Period: 10000-10-01 00:00:00Z to 10000-11-01 00:00:00Z +=#=#=#= End test: '10000-10-01T00:00:00Z/P1M' period - OK (0) =#=#=#= +* Passed: iso8601 - '10000-10-01T00:00:00Z/P1M' period +=#=#=#= Begin test: '10000-10-01T00:00:00Z/P1M' period (XML) =#=#=#= + + + 10000-10-01 00:00:00Z + 10000-11-01 00:00:00Z + + + +=#=#=#= End test: '10000-10-01T00:00:00Z/P1M' period (XML) - OK (0) =#=#=#= +* Passed: iso8601 - '10000-10-01T00:00:00Z/P1M' period (XML) =#=#=#= Begin test: 2014-01-01 00:30:00 - 1 Hour =#=#=#= Date: 2014-01-01 00:30:00Z Duration: -3600 seconds (1 hour) diff --git a/cts/cts-cli.in b/cts/cts-cli.in index 5c2546b6862..fe607546026 100644 --- a/cts/cts-cli.in +++ b/cts/cts-cli.in @@ -1116,6 +1116,8 @@ class DatesRegressionTest(RegressionTest): "2019-01-01 00:00:00Z/P", # Duration with no values "P1Z/2019-02-20 00:00:00Z", # Invalid duration unit "P1YM/2019-02-20 00:00:00Z", # No number for duration unit + "0000-10-01T00:00:00Z/P1M", # Zero year + "-0001-10-01T00:00:00Z/P1M", # Negative year ] # Ensure invalid period specifications are rejected @@ -1140,6 +1142,7 @@ class DatesRegressionTest(RegressionTest): return invalid_period_tests + [ make_test_group("'2005-040/2005-043' period", "iso8601 -p '2005-040/2005-043'"), + make_test_group("'10000-10-01T00:00:00Z/P1M' period", "iso8601 -p '10000-10-01T00:00:00Z/P1M'"), Test("2014-01-01 00:30:00 - 1 Hour", "iso8601 -d '2014-01-01 00:30:00Z' -D P-1H -E '2013-12-31 23:30:00Z'"), Test("Valid date - Feb 29 in leap year", From 93354332e607f6a11a56a791a3bf10ede4a2d052 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Mon, 27 Apr 2026 02:33:01 -0700 Subject: [PATCH 23/99] Feature: libcrmcommon: crm_time_parse_period requires years in [1, 9999] ...for the start and end of a period. This is a behavioral change but shouldn't affect any reasonable cluster configurations. Use of the iso8601 CLI tool or of the crm_time_parse_period() function directly will be affected, for dates with year >= 10000. ISO 8601 only guarantees support for years up to four digits. Year 0 is treated as 1 BCE. However, we consider year 0 invalid. The goal is to move to using GLib's GDateTime internally. 0001-01-1 to 9999-12-31 is the supported range for GDateTime. Signed-off-by: Reid Wahl --- cts/cli/regression.dates.exp | 19 +++++-------------- cts/cts-cli.in | 2 +- lib/common/iso8601.c | 19 +++++++++++++++---- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/cts/cli/regression.dates.exp b/cts/cli/regression.dates.exp index ce4ad538492..fcb093907c2 100644 --- a/cts/cli/regression.dates.exp +++ b/cts/cli/regression.dates.exp @@ -88,6 +88,11 @@ parse_date error: '-0001-10-01T00:00:00Z/P1M' is not a valid ISO 8601 date/time iso8601: Invalid interval specified: -0001-10-01T00:00:00Z/P1M =#=#=#= End test: Invalid period - [-0001-10-01T00:00:00Z/P1M] - Invalid parameter (2) =#=#=#= * Passed: iso8601 - Invalid period - [-0001-10-01T00:00:00Z/P1M] +=#=#=#= Begin test: Invalid period - [10000-10-01T00:00:00Z/P1M] =#=#=#= +crm_time_parse_period error: 'P1M' is not a valid ISO 8601 time period because the start is invalid (must be between 0001-01-01T00:00:00 and 9999-12-31T23:59:59) +iso8601: Invalid interval specified: 10000-10-01T00:00:00Z/P1M +=#=#=#= End test: Invalid period - [10000-10-01T00:00:00Z/P1M] - Invalid parameter (2) =#=#=#= +* Passed: iso8601 - Invalid period - [10000-10-01T00:00:00Z/P1M] =#=#=#= Begin test: '2005-040/2005-043' period =#=#=#= Period: 2005-02-09 00:00:00Z to 2005-02-12 00:00:00Z =#=#=#= End test: '2005-040/2005-043' period - OK (0) =#=#=#= @@ -102,20 +107,6 @@ Period: 2005-02-09 00:00:00Z to 2005-02-12 00:00:00Z =#=#=#= End test: '2005-040/2005-043' period (XML) - OK (0) =#=#=#= * Passed: iso8601 - '2005-040/2005-043' period (XML) -=#=#=#= Begin test: '10000-10-01T00:00:00Z/P1M' period =#=#=#= -Period: 10000-10-01 00:00:00Z to 10000-11-01 00:00:00Z -=#=#=#= End test: '10000-10-01T00:00:00Z/P1M' period - OK (0) =#=#=#= -* Passed: iso8601 - '10000-10-01T00:00:00Z/P1M' period -=#=#=#= Begin test: '10000-10-01T00:00:00Z/P1M' period (XML) =#=#=#= - - - 10000-10-01 00:00:00Z - 10000-11-01 00:00:00Z - - - -=#=#=#= End test: '10000-10-01T00:00:00Z/P1M' period (XML) - OK (0) =#=#=#= -* Passed: iso8601 - '10000-10-01T00:00:00Z/P1M' period (XML) =#=#=#= Begin test: 2014-01-01 00:30:00 - 1 Hour =#=#=#= Date: 2014-01-01 00:30:00Z Duration: -3600 seconds (1 hour) diff --git a/cts/cts-cli.in b/cts/cts-cli.in index fe607546026..7be19a78dcf 100644 --- a/cts/cts-cli.in +++ b/cts/cts-cli.in @@ -1118,6 +1118,7 @@ class DatesRegressionTest(RegressionTest): "P1YM/2019-02-20 00:00:00Z", # No number for duration unit "0000-10-01T00:00:00Z/P1M", # Zero year "-0001-10-01T00:00:00Z/P1M", # Negative year + "10000-10-01T00:00:00Z/P1M", # Year greater than 9999 ] # Ensure invalid period specifications are rejected @@ -1142,7 +1143,6 @@ class DatesRegressionTest(RegressionTest): return invalid_period_tests + [ make_test_group("'2005-040/2005-043' period", "iso8601 -p '2005-040/2005-043'"), - make_test_group("'10000-10-01T00:00:00Z/P1M' period", "iso8601 -p '10000-10-01T00:00:00Z/P1M'"), Test("2014-01-01 00:30:00 - 1 Hour", "iso8601 -d '2014-01-01 00:30:00Z' -D P-1H -E '2013-12-31 23:30:00Z'"), Test("Valid date - Feb 29 in leap year", diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 0676614ed59..b47b423c77d 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -55,6 +55,9 @@ #define HOURS_IN_DAY 24 #define SECONDS_IN_DAY (SECONDS_IN_HOUR * HOURS_IN_DAY) +#define BEGIN_VALID_RANGE_S "0001-01-01T00:00:00" +#define END_VALID_RANGE_S "9999-12-31T23:59:59" + /*! * \internal * \brief Validate a seconds/microseconds tuple @@ -1426,16 +1429,24 @@ crm_time_parse_period(const char *period_str) period->end = crm_time_add(period->start, period->diff); } - if (!valid_time(period->start)) { + if (!pcmk__time_valid_year(period->start->years) + || !valid_time(period->start)) { + pcmk__err("'%s' is not a valid ISO 8601 time period because the start " - "is invalid", period_str); + "is invalid (must be between " BEGIN_VALID_RANGE_S " and " + END_VALID_RANGE_S ")", period_str); goto invalid; } - if (!valid_time(period->end)) { + + if (!pcmk__time_valid_year(period->end->years) + || !valid_time(period->end)) { + pcmk__err("'%s' is not a valid ISO 8601 time period because the end is " - "invalid", period_str); + "invalid (must be between " BEGIN_VALID_RANGE_S " and " + END_VALID_RANGE_S ")", period_str); goto invalid; } + return period; invalid: From 540aafd9e2df568f767d794162ffed4974d4e1d6 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Mon, 27 Apr 2026 02:56:47 -0700 Subject: [PATCH 24/99] Refactor: tools: iso8601 output function doesn't use crm_time_period_t Instead, pass the start and end fields. This is an incremental step toward getting rid of crm_time_period_t. Signed-off-by: Reid Wahl --- tools/iso8601.c | 57 ++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/tools/iso8601.c b/tools/iso8601.c index d8d0a1a7f8a..1803bd149be 100644 --- a/tools/iso8601.c +++ b/tools/iso8601.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2025 the Pacemaker project contributors + * Copyright 2005-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -215,65 +215,67 @@ duration_ends_xml(pcmk__output_t *out, va_list args) return pcmk_rc_ok; } -PCMK__OUTPUT_ARGS("period", "crm_time_period_t *", "int") +PCMK__OUTPUT_ARGS("period", "crm_time_t *", "crm_time_t *", "int") static int period_default(pcmk__output_t *out, va_list args) { - crm_time_period_t *period = va_arg(args, crm_time_period_t *); + const crm_time_t *start = va_arg(args, crm_time_t *); + const crm_time_t *end = va_arg(args, crm_time_t *); int opts = va_arg(args, int); - char *start = NULL; - char *end = NULL; + char *start_s = NULL; + char *end_s = NULL; opts |= crm_time_log_date | crm_time_log_timeofday; - start = crm_time_as_string(period->start, opts); - if (start == NULL) { + start_s = crm_time_as_string(start, opts); + if (start_s == NULL) { return pcmk_rc_no_output; } - end = crm_time_as_string(period->end, opts); - if (end == NULL) { - free(start); + end_s = crm_time_as_string(end, opts); + if (end_s == NULL) { + free(start_s); return pcmk_rc_no_output; } - out->info(out, "Period: %s to %s", start, end); + out->info(out, "Period: %s to %s", start_s, end_s); - free(start); - free(end); + free(start_s); + free(end_s); return pcmk_rc_ok; } -PCMK__OUTPUT_ARGS("period", "crm_time_period_t *", "int") +PCMK__OUTPUT_ARGS("period", "crm_time_t *", "crm_time_t *", "int") static int period_xml(pcmk__output_t *out, va_list args) { - crm_time_period_t *period = va_arg(args, crm_time_period_t *); + const crm_time_t *start = va_arg(args, crm_time_t *); + const crm_time_t *end = va_arg(args, crm_time_t *); int opts = va_arg(args, int); - char *start = NULL; - char *end = NULL; + char *start_s = NULL; + char *end_s = NULL; opts |= crm_time_log_date | crm_time_log_timeofday; - start = crm_time_as_string(period->start, opts); - if (start == NULL) { + start_s = crm_time_as_string(start, opts); + if (start_s == NULL) { return pcmk_rc_no_output; } - end = crm_time_as_string(period->end, opts); - if (end == NULL) { - free(start); + end_s = crm_time_as_string(end, opts); + if (end_s == NULL) { + free(start_s); return pcmk_rc_no_output; } pcmk__output_xml_create_parent(out, PCMK_XE_PERIOD, NULL); - pcmk__output_create_xml_text_node(out, PCMK_XE_START, start); - pcmk__output_create_xml_text_node(out, PCMK_XE_END, end); + pcmk__output_create_xml_text_node(out, PCMK_XE_START, start_s); + pcmk__output_create_xml_text_node(out, PCMK_XE_END, end_s); - free(start); - free(end); + free(start_s); + free(end_s); return pcmk_rc_ok; } @@ -398,7 +400,8 @@ main(int argc, char **argv) goto done; } - out->message(out, "period", period, options.print_options); + out->message(out, "period", period->start, period->end, + options.print_options); crm_time_free_period(period); } From 404cf1e1553137cda2b64d2d71430a8a1c7b2fbe Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Mon, 27 Apr 2026 03:05:22 -0700 Subject: [PATCH 25/99] Refactor: tools: Drop crm_time_period_t from iso8601 CLI tool This copies the crm_time_parse_period() logic to a static function in the tool. The plan is to deprecate the public API function and the data type itself. This temporarily exposes valid_time() internally without changing the name. The plan is to pull pcmk__time_valid_year() into the validity check soon. This also temporarily defines {BEGIN,END}_VALID_RANGE_S in tools/iso8601.c. Signed-off-by: Reid Wahl --- cts/cli/regression.dates.exp | 8 +-- cts/cts-cli.in | 2 +- include/crm/common/iso8601_internal.h | 2 + lib/common/iso8601.c | 2 +- tools/iso8601.c | 100 ++++++++++++++++++++++++-- 5 files changed, 103 insertions(+), 11 deletions(-) diff --git a/cts/cli/regression.dates.exp b/cts/cli/regression.dates.exp index fcb093907c2..b72d92ae688 100644 --- a/cts/cli/regression.dates.exp +++ b/cts/cli/regression.dates.exp @@ -1,10 +1,10 @@ =#=#=#= Begin test: Invalid period - [] =#=#=#= -crm_time_parse_period error: No ISO 8601 time period given +parse_period error: No ISO 8601 time period given iso8601: Invalid interval specified: =#=#=#= End test: Invalid period - [] - Invalid parameter (2) =#=#=#= * Passed: iso8601 - Invalid period - [] =#=#=#= Begin test: Invalid period - [2019-01-01 00:00:00Z] =#=#=#= -crm_time_parse_period error: '2019-01-01 00:00:00Z' is not a valid ISO 8601 time period because it has no duration or ending time +parse_period error: '2019-01-01 00:00:00Z' is not a valid ISO 8601 time period because it has no duration or ending time iso8601: Invalid interval specified: 2019-01-01 00:00:00Z =#=#=#= End test: Invalid period - [2019-01-01 00:00:00Z] - Invalid parameter (2) =#=#=#= * Passed: iso8601 - Invalid period - [2019-01-01 00:00:00Z] @@ -14,7 +14,7 @@ iso8601: Invalid interval specified: 2019-01-01 00:00:00Z/ =#=#=#= End test: Invalid period - [2019-01-01 00:00:00Z/] - Invalid parameter (2) =#=#=#= * Passed: iso8601 - Invalid period - [2019-01-01 00:00:00Z/] =#=#=#= Begin test: Invalid period - [PT2S/P1M] =#=#=#= -crm_time_parse_period error: 'PT2S/P1M' is not a valid ISO 8601 time period because it has two durations +parse_period error: 'PT2S/P1M' is not a valid ISO 8601 time period because it has two durations iso8601: Invalid interval specified: PT2S/P1M =#=#=#= End test: Invalid period - [PT2S/P1M] - Invalid parameter (2) =#=#=#= * Passed: iso8601 - Invalid period - [PT2S/P1M] @@ -89,7 +89,7 @@ iso8601: Invalid interval specified: -0001-10-01T00:00:00Z/P1M =#=#=#= End test: Invalid period - [-0001-10-01T00:00:00Z/P1M] - Invalid parameter (2) =#=#=#= * Passed: iso8601 - Invalid period - [-0001-10-01T00:00:00Z/P1M] =#=#=#= Begin test: Invalid period - [10000-10-01T00:00:00Z/P1M] =#=#=#= -crm_time_parse_period error: 'P1M' is not a valid ISO 8601 time period because the start is invalid (must be between 0001-01-01T00:00:00 and 9999-12-31T23:59:59) +parse_period error: 'P1M' is not a valid ISO 8601 time period because the start is invalid (must be between 0001-01-01T00:00:00 and 9999-12-31T23:59:59) iso8601: Invalid interval specified: 10000-10-01T00:00:00Z/P1M =#=#=#= End test: Invalid period - [10000-10-01T00:00:00Z/P1M] - Invalid parameter (2) =#=#=#= * Passed: iso8601 - Invalid period - [10000-10-01T00:00:00Z/P1M] diff --git a/cts/cts-cli.in b/cts/cts-cli.in index 7be19a78dcf..8f557ce4b45 100644 --- a/cts/cts-cli.in +++ b/cts/cts-cli.in @@ -252,7 +252,6 @@ def sanitize_output(s): (r'crm_feature_set="[^"]*" ', r''), (r'@crm_feature_set=[0-9.]+, ', r''), (r'\(crm_time_parse_duration@.*\.c:[0-9]+\)', r'crm_time_parse_duration'), - (r'\(crm_time_parse_period@.*\.c:[0-9]+\)', r'crm_time_parse_period'), (r'\(parse_hms@.*\.c:[0-9]+\)', r'parse_hms'), (re.escape(cts_cli_data), r'CTS_CLI_DATA'), (r' default="[^"]*"', r' default=""'), @@ -262,6 +261,7 @@ def sanitize_output(s): (r' last-rc-change=[\'"][-+A-Za-z0-9: ]*[\'"],?', r''), (r'\(parse_date@.*\.c:[0-9]+\)', r'parse_date'), (r'\(parse_duration_element@.*\.c:[0-9]+\)', r'parse_duration_element'), + (r'\(parse_period@.*\.c:[0-9]+\)', r'parse_period'), (r'\((pcmk__.*)@.*\.c:[0-9]+\)', r'\1'), (r'.*Relax-NG validity error : ', r''), (r'request=".*cibadmin', r'request="cibadmin'), diff --git a/include/crm/common/iso8601_internal.h b/include/crm/common/iso8601_internal.h index 473b876cc4a..883c3b89859 100644 --- a/include/crm/common/iso8601_internal.h +++ b/include/crm/common/iso8601_internal.h @@ -64,6 +64,8 @@ struct crm_time_s { bool duration; }; +bool valid_time(const crm_time_t *dt); + #ifdef __cplusplus } #endif diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index b47b423c77d..d78bc45276e 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -434,7 +434,7 @@ parse_time(const char *time_str, crm_time_t *a_time) * \return \c true if days and seconds are valid given the year, or \c false * otherwise */ -static bool +bool valid_time(const crm_time_t *dt) { return (dt != NULL) diff --git a/tools/iso8601.c b/tools/iso8601.c index 1803bd149be..50377f33c0c 100644 --- a/tools/iso8601.c +++ b/tools/iso8601.c @@ -34,6 +34,8 @@ struct { } options; #define INDENT " " +#define BEGIN_VALID_RANGE_S "0001-01-01T00:00:00" +#define END_VALID_RANGE_S "9999-12-31T23:59:59" static gboolean date_now_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) { @@ -279,6 +281,93 @@ period_xml(pcmk__output_t *out, va_list args) return pcmk_rc_ok; } +static int +parse_period(const char *period_str, crm_time_t **start, crm_time_t **end) +{ + const char *original = period_str; + crm_time_t *diff = NULL; + + if (pcmk__str_empty(period_str)) { + pcmk__err("No ISO 8601 time period given"); + goto invalid; + } + + tzset(); + + if (period_str[0] == 'P') { + diff = crm_time_parse_duration(period_str); + if (diff == NULL) { + goto invalid; + } + } else { + *start = crm_time_new(period_str); + if (*start == NULL) { + goto invalid; + } + } + + period_str = strchr(original, '/'); + if (period_str != NULL) { + ++period_str; + if (period_str[0] == 'P') { + if (diff != NULL) { + pcmk__err("'%s' is not a valid ISO 8601 time period because it " + "has two durations", original); + goto invalid; + } + diff = crm_time_parse_duration(period_str); + if (diff == NULL) { + goto invalid; + } + } else { + *end = crm_time_new(period_str); + if (*end == NULL) { + goto invalid; + } + } + + } else if (diff != NULL) { + // Only duration given, assume start is now + *start = pcmk__copy_timet(time(NULL)); + + } else { + // Only start given + pcmk__err("'%s' is not a valid ISO 8601 time period because it has no " + "duration or ending time", original); + goto invalid; + } + + if (*start == NULL) { + *start = crm_time_subtract(*end, diff); + + } else if (*end == NULL) { + *end = crm_time_add(*start, diff); + } + + if (!pcmk__time_valid_year((*start)->years) || !valid_time(*start)) { + pcmk__err("'%s' is not a valid ISO 8601 time period because the start " + "is invalid (must be between " BEGIN_VALID_RANGE_S " and " + END_VALID_RANGE_S ")", period_str); + goto invalid; + } + + if (!pcmk__time_valid_year((*end)->years) || !valid_time(*end)) { + pcmk__err("'%s' is not a valid ISO 8601 time period because the end is " + "invalid (must be between " BEGIN_VALID_RANGE_S " and " + END_VALID_RANGE_S ")", period_str); + goto invalid; + } + + crm_time_free(diff); + return pcmk_rc_ok; + +invalid: + crm_time_free(diff); + crm_time_free(*start); + crm_time_free(*end); + return EINVAL; +} + static GOptionContext * build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) { @@ -391,18 +480,19 @@ main(int argc, char **argv) } if (options.period_s) { - crm_time_period_t *period = crm_time_parse_period(options.period_s); + crm_time_t *start = NULL; + crm_time_t *end = NULL; - if (period == NULL) { + if (parse_period(options.period_s, &start, &end) != pcmk_rc_ok) { exit_code = CRM_EX_INVALID_PARAM; g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Invalid interval specified: %s", options.period_s); goto done; } - out->message(out, "period", period->start, period->end, - options.print_options); - crm_time_free_period(period); + out->message(out, "period", start, end, options.print_options); + crm_time_free(start); + crm_time_free(end); } if (date_time && duration) { From e7c59462d37a8ccb912c276a1ecc8ad91d2774ed Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Mon, 27 Apr 2026 03:12:21 -0700 Subject: [PATCH 26/99] API: libcrmcommon: Deprecate crm_time_parse_period() (Note: we've often been using the term "period" to refer to an ISO 8601 interval.) There doesn't seem to be a very good use case for this function. Perhaps after querying a time period/interval XML attribute from the CIB, a user could parse it with this function. But a scenario where that's useful seems pretty contrived. It appears we don't use ISO 8601 intervals for any piece of the configuration or for any implementation detail. pcmk_parse_interval_spec() actually parses a duration, not an interval. The implementation is also incomplete and incorrect. So I see no reason to keep this. Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 1 - include/crm/common/iso8601_compat.h | 5 +- lib/common/fuzzers/iso8601_fuzzer.c | 7 +- lib/common/iso8601.c | 194 +++++++++++++--------------- 4 files changed, 97 insertions(+), 110 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 8d3939603c5..74b317e85ec 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -82,7 +82,6 @@ char *crm_time_as_string(const crm_time_t *dt, int flags); crm_time_t *crm_time_parse_duration(const char *duration_str); crm_time_t *crm_time_calculate_duration(const crm_time_t *dt, const crm_time_t *value); -crm_time_period_t *crm_time_parse_period(const char *period_str); void crm_time_free_period(crm_time_period_t *period); int crm_time_compare(const crm_time_t *a, const crm_time_t *b); diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index 69d551ee451..a4a1cbd1190 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2025 the Pacemaker project contributors + * Copyright 2004-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -66,6 +66,9 @@ void crm_time_log_alias(int log_level, const char *file, const char *function, int line, const char *prefix, const crm_time_t *date_time, int flags); +//! \deprecated Do not use +crm_time_period_t *crm_time_parse_period(const char *period_str); + #ifdef __cplusplus } #endif diff --git a/lib/common/fuzzers/iso8601_fuzzer.c b/lib/common/fuzzers/iso8601_fuzzer.c index 668f74a7d00..e7c0ecb5b41 100644 --- a/lib/common/fuzzers/iso8601_fuzzer.c +++ b/lib/common/fuzzers/iso8601_fuzzer.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 the Pacemaker project contributors + * Copyright 2024-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -21,8 +21,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { char *ns = NULL; - crm_time_period_t *period = NULL; - struct timespec tv = { 0, }; crm_time_t *now = NULL; char *result = NULL; @@ -34,9 +32,6 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) ns = pcmk__assert_alloc(size + 1, sizeof(char)); memcpy(ns, data, size); - period = crm_time_parse_period(ns); - crm_time_free_period(period); - qb_util_timespec_from_epoch_get(&tv); now = pcmk__copy_timet(tv.tv_sec); result = pcmk__time_format_hr(ns, now, diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index d78bc45276e..66af517729e 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1353,108 +1353,6 @@ crm_time_parse_duration(const char *period_s) return NULL; } -/*! - * \brief Parse a time period from an ISO 8601 interval specification - * - * \param[in] period_str ISO 8601 interval specification (start/end, - * start/duration, or duration/end) - * - * \return New time period object on success, NULL (and set errno) otherwise - * \note The caller is responsible for freeing the result using - * crm_time_free_period(). - */ -crm_time_period_t * -crm_time_parse_period(const char *period_str) -{ - const char *original = period_str; - crm_time_period_t *period = NULL; - - if (pcmk__str_empty(period_str)) { - pcmk__err("No ISO 8601 time period given"); - goto invalid; - } - - tzset(); - period = pcmk__assert_alloc(1, sizeof(crm_time_period_t)); - - if (period_str[0] == 'P') { - period->diff = crm_time_parse_duration(period_str); - if (period->diff == NULL) { - goto invalid; - } - } else { - period->start = parse_date(period_str); - if (period->start == NULL) { - goto invalid; - } - } - - period_str = strchr(original, '/'); - if (period_str != NULL) { - ++period_str; - if (period_str[0] == 'P') { - if (period->diff != NULL) { - pcmk__err("'%s' is not a valid ISO 8601 time period because it " - "has two durations", - original); - goto invalid; - } - period->diff = crm_time_parse_duration(period_str); - if (period->diff == NULL) { - goto invalid; - } - } else { - period->end = parse_date(period_str); - if (period->end == NULL) { - goto invalid; - } - } - - } else if (period->diff != NULL) { - // Only duration given, assume start is now - period->start = pcmk__copy_timet(time(NULL)); - - } else { - // Only start given - pcmk__err("'%s' is not a valid ISO 8601 time period because it has no " - "duration or ending time", - original); - goto invalid; - } - - if (period->start == NULL) { - period->start = crm_time_subtract(period->end, period->diff); - - } else if (period->end == NULL) { - period->end = crm_time_add(period->start, period->diff); - } - - if (!pcmk__time_valid_year(period->start->years) - || !valid_time(period->start)) { - - pcmk__err("'%s' is not a valid ISO 8601 time period because the start " - "is invalid (must be between " BEGIN_VALID_RANGE_S " and " - END_VALID_RANGE_S ")", period_str); - goto invalid; - } - - if (!pcmk__time_valid_year(period->end->years) - || !valid_time(period->end)) { - - pcmk__err("'%s' is not a valid ISO 8601 time period because the end is " - "invalid (must be between " BEGIN_VALID_RANGE_S " and " - END_VALID_RANGE_S ")", period_str); - goto invalid; - } - - return period; - -invalid: - errno = EINVAL; - crm_time_free_period(period); - return NULL; -} - /*! * \brief Free a dynamically allocated time period object * @@ -2427,5 +2325,97 @@ crm_time_log_alias(int log_level, const char *file, const char *function, prefix, date_time, flags); } +crm_time_period_t * +crm_time_parse_period(const char *period_str) +{ + const char *original = period_str; + crm_time_period_t *period = NULL; + + if (pcmk__str_empty(period_str)) { + pcmk__err("No ISO 8601 time period given"); + goto invalid; + } + + tzset(); + period = pcmk__assert_alloc(1, sizeof(crm_time_period_t)); + + if (period_str[0] == 'P') { + period->diff = crm_time_parse_duration(period_str); + if (period->diff == NULL) { + goto invalid; + } + } else { + period->start = parse_date(period_str); + if (period->start == NULL) { + goto invalid; + } + } + + period_str = strchr(original, '/'); + if (period_str != NULL) { + ++period_str; + if (period_str[0] == 'P') { + if (period->diff != NULL) { + pcmk__err("'%s' is not a valid ISO 8601 time period because it " + "has two durations", + original); + goto invalid; + } + period->diff = crm_time_parse_duration(period_str); + if (period->diff == NULL) { + goto invalid; + } + } else { + period->end = parse_date(period_str); + if (period->end == NULL) { + goto invalid; + } + } + + } else if (period->diff != NULL) { + // Only duration given, assume start is now + period->start = pcmk__copy_timet(time(NULL)); + + } else { + // Only start given + pcmk__err("'%s' is not a valid ISO 8601 time period because it has no " + "duration or ending time", + original); + goto invalid; + } + + if (period->start == NULL) { + period->start = crm_time_subtract(period->end, period->diff); + + } else if (period->end == NULL) { + period->end = crm_time_add(period->start, period->diff); + } + + if (!pcmk__time_valid_year(period->start->years) + || !valid_time(period->start)) { + + pcmk__err("'%s' is not a valid ISO 8601 time period because the start " + "is invalid (must be between " BEGIN_VALID_RANGE_S " and " + END_VALID_RANGE_S ")", period_str); + goto invalid; + } + + if (!pcmk__time_valid_year(period->end->years) + || !valid_time(period->end)) { + + pcmk__err("'%s' is not a valid ISO 8601 time period because the end is " + "invalid (must be between " BEGIN_VALID_RANGE_S " and " + END_VALID_RANGE_S ")", period_str); + goto invalid; + } + + return period; + +invalid: + errno = EINVAL; + crm_time_free_period(period); + return NULL; +} + // LCOV_EXCL_STOP // End deprecated API From 88f6a0f6066852014fa6113aaf81378e028ef358 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Mon, 27 Apr 2026 03:23:22 -0700 Subject: [PATCH 27/99] API: libcrmcommon: Deprecate crm_time_free_period() There is no longer a constructor for crm_time_period_t and no reason to create one. Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 1 - include/crm/common/iso8601_compat.h | 3 +++ lib/common/iso8601.c | 27 +++++++++++---------------- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 74b317e85ec..534ab05d815 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -82,7 +82,6 @@ char *crm_time_as_string(const crm_time_t *dt, int flags); crm_time_t *crm_time_parse_duration(const char *duration_str); crm_time_t *crm_time_calculate_duration(const crm_time_t *dt, const crm_time_t *value); -void crm_time_free_period(crm_time_period_t *period); int crm_time_compare(const crm_time_t *a, const crm_time_t *b); diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index a4a1cbd1190..1e46ad5db3f 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -66,6 +66,9 @@ void crm_time_log_alias(int log_level, const char *file, const char *function, int line, const char *prefix, const crm_time_t *date_time, int flags); +//! \deprecated Do not use +void crm_time_free_period(crm_time_period_t *period); + //! \deprecated Do not use crm_time_period_t *crm_time_parse_period(const char *period_str); diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 66af517729e..635b2b04bf4 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1353,22 +1353,6 @@ crm_time_parse_duration(const char *period_s) return NULL; } -/*! - * \brief Free a dynamically allocated time period object - * - * \param[in,out] period Time period to free - */ -void -crm_time_free_period(crm_time_period_t *period) -{ - if (period) { - crm_time_free(period->start); - crm_time_free(period->end); - crm_time_free(period->diff); - free(period); - } -} - /*! * \internal * \brief Set one time object to another if the other is earlier @@ -2325,6 +2309,17 @@ crm_time_log_alias(int log_level, const char *file, const char *function, prefix, date_time, flags); } +void +crm_time_free_period(crm_time_period_t *period) +{ + if (period) { + crm_time_free(period->start); + crm_time_free(period->end); + crm_time_free(period->diff); + free(period); + } +} + crm_time_period_t * crm_time_parse_period(const char *period_str) { From 4fa39636f4675f87ab75553c6d0415d156be5837 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Mon, 27 Apr 2026 03:25:02 -0700 Subject: [PATCH 28/99] API: libcrmcommon: Deprecate crm_time_period_t Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 10 ---------- include/crm/common/iso8601_compat.h | 7 +++++++ 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 534ab05d815..469a577cfc8 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -38,16 +38,6 @@ extern "C" { */ typedef struct crm_time_s crm_time_t; -/*! - * \deprecated Use \c crm_time_period_t instead of - * struct crm_time_period_s. - */ -typedef struct crm_time_period_s { - crm_time_t *start; - crm_time_t *end; - crm_time_t *diff; -} crm_time_period_t; - /* Creates a new date/time object conforming to ISO 8601, for example: * Ordinal: 2010-01 12:00:00 +10:00 * Gregorian: 2010-01-01 12:00:00 +10:00 diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index 1e46ad5db3f..fa83f4a2c36 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -29,6 +29,13 @@ extern "C" { * release. */ +//! \deprecated Do not use +typedef struct crm_time_period_s { + crm_time_t *start; + crm_time_t *end; + crm_time_t *diff; +} crm_time_period_t; + //! \deprecated Do not use bool crm_time_leapyear(int year); From 9f2af21e5137251381c7c1233ed1a49fdafed91f Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Mon, 13 Apr 2026 16:21:09 -0700 Subject: [PATCH 29/99] Feature: tools: crm_rule requires dates to have year between 1 and 9999 ISO 8601 guarantees support only for years in this range (representable by four digits). We want to move to using GDateTime, which requires dates to be in this range. Signed-off-by: Reid Wahl --- tools/crm_rule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/crm_rule.c b/tools/crm_rule.c index cead4a1c328..51e9e8758b3 100644 --- a/tools/crm_rule.c +++ b/tools/crm_rule.c @@ -157,7 +157,7 @@ main(int argc, char **argv) /* Set up some defaults. */ rule_date = crm_time_new(options.date); - if (rule_date == NULL) { + if ((rule_date == NULL) || !pcmk__time_valid_year(rule_date->years)) { exit_code = CRM_EX_DATAERR; g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Invalid date specified: '%s'", options.date); From 6d0d1757140eb885c07a9c3110e9cab0e192b504 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 10:31:29 -0700 Subject: [PATCH 30/99] API: libcrmcommon: Deprecate crm_time_calculate_duration() Pacemaker should not be used for general-purpose date/time manipulation. There's no need to calculate a duration (as the difference between two crm_time_t objects) for the purpose of administering Pacemaker. Where Pacemaker uses durations, it parses them directly from strings. A crm_time_t object can be displayed as a string if desired, and then a user can compare two strings through whatever method they desire. Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 2 -- include/crm/common/iso8601_compat.h | 3 +++ lib/common/iso8601.c | 12 ++++++------ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 469a577cfc8..48c3ac9cc55 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -70,8 +70,6 @@ char *crm_time_as_string(const crm_time_t *dt, int flags); #define crm_time_usecs 0x400 crm_time_t *crm_time_parse_duration(const char *duration_str); -crm_time_t *crm_time_calculate_duration(const crm_time_t *dt, - const crm_time_t *value); int crm_time_compare(const crm_time_t *a, const crm_time_t *b); diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index fa83f4a2c36..124f44018a7 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -79,6 +79,9 @@ void crm_time_free_period(crm_time_period_t *period); //! \deprecated Do not use crm_time_period_t *crm_time_parse_period(const char *period_str); +//! \deprecated Do not use +crm_time_t *crm_time_calculate_duration(const crm_time_t *dt, + const crm_time_t *value); #ifdef __cplusplus } #endif diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 635b2b04bf4..5e10d5809cc 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1634,12 +1634,6 @@ subtract_time(const crm_time_t *dt1, const crm_time_t *dt2, bool as_duration) return result; } -crm_time_t * -crm_time_calculate_duration(const crm_time_t *dt, const crm_time_t *value) -{ - return subtract_time(dt, value, true); -} - crm_time_t * crm_time_subtract(const crm_time_t *dt, const crm_time_t *value) { @@ -2412,5 +2406,11 @@ crm_time_parse_period(const char *period_str) return NULL; } +crm_time_t * +crm_time_calculate_duration(const crm_time_t *dt, const crm_time_t *value) +{ + return subtract_time(dt, value, true); +} + // LCOV_EXCL_STOP // End deprecated API From 3db87082f86130e9e8e94ae41432f7bd760badee Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 10:45:20 -0700 Subject: [PATCH 31/99] Refactor: libcrmcommon: New pcmk__time_parse_duration() To replace crm_time_parse_duration(). Signed-off-by: Reid Wahl --- cts/cli/regression.dates.exp | 2 +- cts/cts-cli.in | 1 - include/crm/common/iso8601_internal.h | 2 + lib/common/iso8601.c | 35 ++++-- lib/common/strings.c | 4 +- lib/common/tests/iso8601/Makefile.am | 2 +- .../iso8601/crm_time_parse_duration_test.c | 110 ------------------ .../iso8601/pcmk__time_parse_duration_test.c | 110 ++++++++++++++++++ tools/crm_resource_ban.c | 2 +- tools/iso8601.c | 6 +- 10 files changed, 148 insertions(+), 126 deletions(-) delete mode 100644 lib/common/tests/iso8601/crm_time_parse_duration_test.c create mode 100644 lib/common/tests/iso8601/pcmk__time_parse_duration_test.c diff --git a/cts/cli/regression.dates.exp b/cts/cli/regression.dates.exp index b72d92ae688..bb0378ab81d 100644 --- a/cts/cli/regression.dates.exp +++ b/cts/cli/regression.dates.exp @@ -64,7 +64,7 @@ iso8601: Invalid interval specified: P1Y/2019-02-29 00:00:00Z =#=#=#= End test: Invalid period - [P1Y/2019-02-29 00:00:00Z] - Invalid parameter (2) =#=#=#= * Passed: iso8601 - Invalid period - [P1Y/2019-02-29 00:00:00Z] =#=#=#= Begin test: Invalid period - [2019-01-01 00:00:00Z/P] =#=#=#= -crm_time_parse_duration error: 'P' is not a valid ISO 8601 time duration because nothing follows 'P' +pcmk__time_parse_duration error: 'P' is not a valid ISO 8601 time duration because nothing follows 'P' iso8601: Invalid interval specified: 2019-01-01 00:00:00Z/P =#=#=#= End test: Invalid period - [2019-01-01 00:00:00Z/P] - Invalid parameter (2) =#=#=#= * Passed: iso8601 - Invalid period - [2019-01-01 00:00:00Z/P] diff --git a/cts/cts-cli.in b/cts/cts-cli.in index 8f557ce4b45..b111a6055b7 100644 --- a/cts/cts-cli.in +++ b/cts/cts-cli.in @@ -251,7 +251,6 @@ def sanitize_output(s): (r'(duration = TRUE; + diff->duration = true; return diff; invalid: + /* @COMPAT Setting errno is required only for backward compatibility with + * crm_time_parse_duration() + */ crm_time_free(diff); errno = EINVAL; return NULL; } +/*! + * \brief Parse a time duration from an ISO 8601 duration specification + * + * \param[in] period_s ISO 8601 duration specification (optionally followed by + * whitespace, after which the rest of the string will be + * ignored) + * + * \return New time object on success, NULL (and set errno) otherwise + * \note It is the caller's responsibility to return the result using + * crm_time_free(). + */ +crm_time_t * +crm_time_parse_duration(const char *period_s) +{ + return pcmk__time_parse_duration(period_s); +} + /*! * \internal * \brief Set one time object to another if the other is earlier @@ -2329,7 +2350,7 @@ crm_time_parse_period(const char *period_str) period = pcmk__assert_alloc(1, sizeof(crm_time_period_t)); if (period_str[0] == 'P') { - period->diff = crm_time_parse_duration(period_str); + period->diff = pcmk__time_parse_duration(period_str); if (period->diff == NULL) { goto invalid; } @@ -2350,7 +2371,7 @@ crm_time_parse_period(const char *period_str) original); goto invalid; } - period->diff = crm_time_parse_duration(period_str); + period->diff = pcmk__time_parse_duration(period_str); if (period->diff == NULL) { goto invalid; } diff --git a/lib/common/strings.c b/lib/common/strings.c index a920a899e3c..997395002ca 100644 --- a/lib/common/strings.c +++ b/lib/common/strings.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2025 the Pacemaker project contributors + * Copyright 2004-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -372,7 +372,7 @@ pcmk_parse_interval_spec(const char *input, guint *result_ms) } if (input[0] == 'P') { - crm_time_t *period_s = crm_time_parse_duration(input); + crm_time_t *period_s = pcmk__time_parse_duration(input); if (period_s != NULL) { msec = crm_time_get_seconds(period_s); diff --git a/lib/common/tests/iso8601/Makefile.am b/lib/common/tests/iso8601/Makefile.am index 92ac3b5b273..8dd1ef06f48 100644 --- a/lib/common/tests/iso8601/Makefile.am +++ b/lib/common/tests/iso8601/Makefile.am @@ -15,10 +15,10 @@ include $(top_srcdir)/mk/unittest.mk check_PROGRAMS = crm_time_add_days_test check_PROGRAMS += crm_time_add_seconds_test check_PROGRAMS += crm_time_add_years_test -check_PROGRAMS += crm_time_parse_duration_test check_PROGRAMS += pcmk__add_time_from_xml_test check_PROGRAMS += pcmk__readable_interval_test check_PROGRAMS += pcmk__set_time_if_earlier_test check_PROGRAMS += pcmk__time_format_hr_test +check_PROGRAMS += pcmk__time_parse_duration_test TESTS = $(check_PROGRAMS) diff --git a/lib/common/tests/iso8601/crm_time_parse_duration_test.c b/lib/common/tests/iso8601/crm_time_parse_duration_test.c deleted file mode 100644 index 58015e82422..00000000000 --- a/lib/common/tests/iso8601/crm_time_parse_duration_test.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2024 the Pacemaker project contributors - * - * The version control history for this file may have further details. - * - * This source code is licensed under the GNU General Public License version 2 - * or later (GPLv2+) WITHOUT ANY WARRANTY. - */ - -#include - -#include - -#include -#include "crmcommon_private.h" - -static void -empty_arg(void **state) -{ - assert_null(crm_time_parse_duration(NULL)); - assert_null(crm_time_parse_duration("")); -} - -static void -invalid_arg(void **state) -{ - // Valid except doesn't start with P - assert_null(crm_time_parse_duration("X3Y6M4DT12H30M5S")); - - // Illegal character after P - assert_null(crm_time_parse_duration("P")); - assert_null(crm_time_parse_duration("P 3Y6M4DT12H30M5S")); - assert_null(crm_time_parse_duration("PX3Y6M4DT12H30M5S")); - - // Missing or invalid units - assert_null(crm_time_parse_duration("P3Y6M4DT12H30M5")); - assert_null(crm_time_parse_duration("P3Y6M4DT12H30M5X")); - assert_null(crm_time_parse_duration("P3X6M4DT12H30M5S")); - assert_null(crm_time_parse_duration("PT")); - assert_null(crm_time_parse_duration("P/")); - -#if 0 - // @TODO The current implementation treats these as valid - - // Units out of order - assert_null(crm_time_parse_duration("P6M3Y4DT12H30M5S")); - assert_null(crm_time_parse_duration("P6M3DT12HY430M5S")); - - // Same unit specified multiple times - assert_null(crm_time_parse_duration("P6Y4M3D1MT12H30M5S")); - - // Weeks mixed with other units - assert_null(crm_time_parse_duration("P6Y4M3W3D1MT12H30M5S")); - assert_null(crm_time_parse_duration("P3WT12H30M5S")); -#endif -} - -static void -overflow(void **state) -{ - // Too large - assert_null(crm_time_parse_duration("P2147483648Y6M4DT12H30M5S")); - assert_null(crm_time_parse_duration("P3Y2147483648M4DT12H30M5S")); - assert_null(crm_time_parse_duration("P3Y6M2147483648DT12H30M5S")); - assert_null(crm_time_parse_duration("P3Y6M4DT2147483648H30M5S")); - assert_null(crm_time_parse_duration("P3Y6M4DT12H2147483648M5S")); - assert_null(crm_time_parse_duration("P3Y6M4DT12H30MP2147483648S")); - - // Too small - assert_null(crm_time_parse_duration("P-2147483648Y6M4DT12H30M5S")); - assert_null(crm_time_parse_duration("P3Y-2147483648M4DT12H30M5S")); - assert_null(crm_time_parse_duration("P3Y6M-2147483648DT12H30M5S")); - assert_null(crm_time_parse_duration("P3Y6M4DT-2147483648H30M5S")); - assert_null(crm_time_parse_duration("P3Y6M4DT12H-2147483648M5S")); - assert_null(crm_time_parse_duration("P3Y6M4DT12H30MP-2147483648S")); -} - -static void -valid_arg(void **state) -{ - // @TODO Check result value - assert_non_null(crm_time_parse_duration("P3Y6M4DT12H30M5S")); - assert_non_null(crm_time_parse_duration("P3Y6M4DT12H30M-5S")); - assert_non_null(crm_time_parse_duration("P3Y6M4DT12H-30M5S")); - assert_non_null(crm_time_parse_duration("P3Y6M4DT-12H30M5S")); - assert_non_null(crm_time_parse_duration("P3Y6M-4DT12H30M5S")); - assert_non_null(crm_time_parse_duration("P3Y-6M4DT12H30M5S")); - assert_non_null(crm_time_parse_duration("P3Y6M4DT12H30M")); - assert_non_null(crm_time_parse_duration("P3Y6M4D")); - assert_non_null(crm_time_parse_duration("P1M")); // 1 month - assert_non_null(crm_time_parse_duration("PT1M")); // 1 minute - assert_non_null(crm_time_parse_duration("P7W")); - -#if 0 - // @TODO Current implementation can't handle these cases - - // Fractional value for last unit - assert_non_null(crm_time_parse_duration("P3Y6M4DT12H30.5M")); - assert_non_null(crm_time_parse_duration("P3Y6M4DT12H30,5M")); - - // P--
T:: format - assert_non_null(crm_time_parse_duration("P0003-02-01T11:10:09"); -#endif -} - -PCMK__UNIT_TEST(NULL, NULL, - cmocka_unit_test(empty_arg), - cmocka_unit_test(invalid_arg), - cmocka_unit_test(overflow), - cmocka_unit_test(valid_arg)); diff --git a/lib/common/tests/iso8601/pcmk__time_parse_duration_test.c b/lib/common/tests/iso8601/pcmk__time_parse_duration_test.c new file mode 100644 index 00000000000..76acc590741 --- /dev/null +++ b/lib/common/tests/iso8601/pcmk__time_parse_duration_test.c @@ -0,0 +1,110 @@ +/* + * Copyright 2024-2026 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include + +#include + +#include +#include "crmcommon_private.h" + +static void +empty_arg(void **state) +{ + assert_null(pcmk__time_parse_duration(NULL)); + assert_null(pcmk__time_parse_duration("")); +} + +static void +invalid_arg(void **state) +{ + // Valid except doesn't start with P + assert_null(pcmk__time_parse_duration("X3Y6M4DT12H30M5S")); + + // Illegal character after P + assert_null(pcmk__time_parse_duration("P")); + assert_null(pcmk__time_parse_duration("P 3Y6M4DT12H30M5S")); + assert_null(pcmk__time_parse_duration("PX3Y6M4DT12H30M5S")); + + // Missing or invalid units + assert_null(pcmk__time_parse_duration("P3Y6M4DT12H30M5")); + assert_null(pcmk__time_parse_duration("P3Y6M4DT12H30M5X")); + assert_null(pcmk__time_parse_duration("P3X6M4DT12H30M5S")); + assert_null(pcmk__time_parse_duration("PT")); + assert_null(pcmk__time_parse_duration("P/")); + +#if 0 + // @TODO The current implementation treats these as valid + + // Units out of order + assert_null(pcmk__time_parse_duration("P6M3Y4DT12H30M5S")); + assert_null(pcmk__time_parse_duration("P6M3DT12HY430M5S")); + + // Same unit specified multiple times + assert_null(pcmk__time_parse_duration("P6Y4M3D1MT12H30M5S")); + + // Weeks mixed with other units + assert_null(pcmk__time_parse_duration("P6Y4M3W3D1MT12H30M5S")); + assert_null(pcmk__time_parse_duration("P3WT12H30M5S")); +#endif +} + +static void +overflow(void **state) +{ + // Too large + assert_null(pcmk__time_parse_duration("P2147483648Y6M4DT12H30M5S")); + assert_null(pcmk__time_parse_duration("P3Y2147483648M4DT12H30M5S")); + assert_null(pcmk__time_parse_duration("P3Y6M2147483648DT12H30M5S")); + assert_null(pcmk__time_parse_duration("P3Y6M4DT2147483648H30M5S")); + assert_null(pcmk__time_parse_duration("P3Y6M4DT12H2147483648M5S")); + assert_null(pcmk__time_parse_duration("P3Y6M4DT12H30MP2147483648S")); + + // Too small + assert_null(pcmk__time_parse_duration("P-2147483648Y6M4DT12H30M5S")); + assert_null(pcmk__time_parse_duration("P3Y-2147483648M4DT12H30M5S")); + assert_null(pcmk__time_parse_duration("P3Y6M-2147483648DT12H30M5S")); + assert_null(pcmk__time_parse_duration("P3Y6M4DT-2147483648H30M5S")); + assert_null(pcmk__time_parse_duration("P3Y6M4DT12H-2147483648M5S")); + assert_null(pcmk__time_parse_duration("P3Y6M4DT12H30MP-2147483648S")); +} + +static void +valid_arg(void **state) +{ + // @TODO Check result value + assert_non_null(pcmk__time_parse_duration("P3Y6M4DT12H30M5S")); + assert_non_null(pcmk__time_parse_duration("P3Y6M4DT12H30M-5S")); + assert_non_null(pcmk__time_parse_duration("P3Y6M4DT12H-30M5S")); + assert_non_null(pcmk__time_parse_duration("P3Y6M4DT-12H30M5S")); + assert_non_null(pcmk__time_parse_duration("P3Y6M-4DT12H30M5S")); + assert_non_null(pcmk__time_parse_duration("P3Y-6M4DT12H30M5S")); + assert_non_null(pcmk__time_parse_duration("P3Y6M4DT12H30M")); + assert_non_null(pcmk__time_parse_duration("P3Y6M4D")); + assert_non_null(pcmk__time_parse_duration("P1M")); // 1 month + assert_non_null(pcmk__time_parse_duration("PT1M")); // 1 minute + assert_non_null(pcmk__time_parse_duration("P7W")); + +#if 0 + // @TODO Current implementation can't handle these cases + + // Fractional value for last unit + assert_non_null(pcmk__time_parse_duration("P3Y6M4DT12H30.5M")); + assert_non_null(pcmk__time_parse_duration("P3Y6M4DT12H30,5M")); + + // P--
T:: format + assert_non_null(pcmk__time_parse_duration("P0003-02-01T11:10:09"); +#endif +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(empty_arg), + cmocka_unit_test(invalid_arg), + cmocka_unit_test(overflow), + cmocka_unit_test(valid_arg)); diff --git a/tools/crm_resource_ban.c b/tools/crm_resource_ban.c index e52268b4335..a83bee1e89c 100644 --- a/tools/crm_resource_ban.c +++ b/tools/crm_resource_ban.c @@ -31,7 +31,7 @@ parse_cli_lifetime(pcmk__output_t *out, const char *move_lifetime) return NULL; } - duration = crm_time_parse_duration(move_lifetime); + duration = pcmk__time_parse_duration(move_lifetime); if (duration == NULL) { out->err(out, "Invalid duration specified: %s\n" "Please refer to https://en.wikipedia.org/wiki/ISO_8601#Durations " diff --git a/tools/iso8601.c b/tools/iso8601.c index 50377f33c0c..fc5bed4c0ce 100644 --- a/tools/iso8601.c +++ b/tools/iso8601.c @@ -295,7 +295,7 @@ parse_period(const char *period_str, crm_time_t **start, crm_time_t **end) tzset(); if (period_str[0] == 'P') { - diff = crm_time_parse_duration(period_str); + diff = pcmk__time_parse_duration(period_str); if (diff == NULL) { goto invalid; } @@ -315,7 +315,7 @@ parse_period(const char *period_str, crm_time_t **start, crm_time_t **end) "has two durations", original); goto invalid; } - diff = crm_time_parse_duration(period_str); + diff = pcmk__time_parse_duration(period_str); if (diff == NULL) { goto invalid; } @@ -467,7 +467,7 @@ main(int argc, char **argv) } if (options.duration_s) { - duration = crm_time_parse_duration(options.duration_s); + duration = pcmk__time_parse_duration(options.duration_s); if (duration == NULL) { exit_code = CRM_EX_INVALID_PARAM; From 2e523def6870258f597baa4c393208db971f1141 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 13:32:45 -0700 Subject: [PATCH 32/99] API: libcrmcommon: Deprecate crm_time_parse_duration() Pacemaker parses durations from strings in a few places. However, there is no need for external code to do this for the purpose of administering Pacemaker. Pacemaker should not be used for general-purpose date/time manipulation. Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 2 -- include/crm/common/iso8601_compat.h | 4 ++++ lib/common/iso8601.c | 23 ++++++----------------- 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 48c3ac9cc55..ccf9369090a 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -69,8 +69,6 @@ char *crm_time_as_string(const crm_time_t *dt, int flags); #define crm_time_epoch 0x200 #define crm_time_usecs 0x400 -crm_time_t *crm_time_parse_duration(const char *duration_str); - int crm_time_compare(const crm_time_t *a, const crm_time_t *b); int crm_time_get_timeofday(const crm_time_t *dt, uint32_t *h, uint32_t *m, diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index 124f44018a7..b823a530d83 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -82,6 +82,10 @@ crm_time_period_t *crm_time_parse_period(const char *period_str); //! \deprecated Do not use crm_time_t *crm_time_calculate_duration(const crm_time_t *dt, const crm_time_t *value); + +//! \deprecated Do not use +crm_time_t *crm_time_parse_duration(const char *duration_str); + #ifdef __cplusplus } #endif diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 611966c88ed..76b01a04099 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1357,23 +1357,6 @@ pcmk__time_parse_duration(const char *period_s) return NULL; } -/*! - * \brief Parse a time duration from an ISO 8601 duration specification - * - * \param[in] period_s ISO 8601 duration specification (optionally followed by - * whitespace, after which the rest of the string will be - * ignored) - * - * \return New time object on success, NULL (and set errno) otherwise - * \note It is the caller's responsibility to return the result using - * crm_time_free(). - */ -crm_time_t * -crm_time_parse_duration(const char *period_s) -{ - return pcmk__time_parse_duration(period_s); -} - /*! * \internal * \brief Set one time object to another if the other is earlier @@ -2433,5 +2416,11 @@ crm_time_calculate_duration(const crm_time_t *dt, const crm_time_t *value) return subtract_time(dt, value, true); } +crm_time_t * +crm_time_parse_duration(const char *period_s) +{ + return pcmk__time_parse_duration(period_s); +} + // LCOV_EXCL_STOP // End deprecated API From d2120d70747d9bdac904034e01e93026d70fd5fd Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 17:34:32 -0700 Subject: [PATCH 33/99] Refactor: libcrmcommon: Clean up includes in scheduler.h Add a couple of missing includes elsewhere, since they break otherwise. Signed-off-by: Reid Wahl --- include/crm/common/scheduler.h | 18 ++++++------------ include/crm/pengine/status.h | 4 ++-- include/pacemaker.h | 3 ++- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/include/crm/common/scheduler.h b/include/crm/common/scheduler.h index 5e347ff00bf..b01f970a32b 100644 --- a/include/crm/common/scheduler.h +++ b/include/crm/common/scheduler.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2025 the Pacemaker project contributors + * Copyright 2004-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -10,19 +10,13 @@ #ifndef PCMK__CRM_COMMON_SCHEDULER__H #define PCMK__CRM_COMMON_SCHEDULER__H -#include -#include // time_t -#include // xmlNode -#include // guint, GList, GHashTable +#include // bool +#include // uint64_t -#include // crm_time_t +#include // GList +#include // xmlNode -#include -#include -#include -#include -#include -#include +#include // pcmk_node_t, pcmk_scheduler_t #ifdef __cplusplus extern "C" { diff --git a/include/crm/pengine/status.h b/include/crm/pengine/status.h index 8d7722c72b0..d46428b6870 100644 --- a/include/crm/pengine/status.h +++ b/include/crm/pengine/status.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2025 the Pacemaker project contributors + * Copyright 2004-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -12,7 +12,7 @@ # include // gboolean # include // bool -# include +# include // pe_find # include // pcmk_node_t, pcmk_resource_t, etc. # include diff --git a/include/pacemaker.h b/include/pacemaker.h index b2bbff4b047..299cf73b698 100644 --- a/include/pacemaker.h +++ b/include/pacemaker.h @@ -1,5 +1,5 @@ /* - * Copyright 2019-2025 the Pacemaker project contributors + * Copyright 2019-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -16,6 +16,7 @@ # include # include +# include // crm_time_t # include # include From 2691e4b1161643fe63be3b52a63cc42449ca00b5 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 17:42:55 -0700 Subject: [PATCH 34/99] Refactor: various: Drop crm_time_new_undefined() internally Signed-off-by: Reid Wahl --- lib/common/iso8601.c | 10 +++++----- .../tests/iso8601/pcmk__set_time_if_earlier_test.c | 4 ++-- lib/common/tests/rules/pcmk__evaluate_condition_test.c | 4 ++-- lib/common/tests/rules/pcmk_evaluate_rule_test.c | 10 +++++----- .../tests/xml_element/pcmk__xe_get_datetime_test.c | 4 ++-- lib/pacemaker/pcmk_sched_location.c | 2 +- lib/pengine/utils.c | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 76b01a04099..9a710d6ac78 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -482,7 +482,7 @@ parse_date(const char *date_str) goto parse_time_segment; } - dt = crm_time_new_undefined(); + dt = pcmk__assert_alloc(1, sizeof(crm_time_t)); if ((strncasecmp(PCMK__VALUE_EPOCH, date_str, 5) == 0) && ((date_str[5] == '\0') @@ -640,7 +640,7 @@ copy_time_to_utc(const crm_time_t *dt) pcmk__assert(dt != NULL); - utc = crm_time_new_undefined(); + utc = pcmk__assert_alloc(1, sizeof(crm_time_t)); utc->years = dt->years; utc->days = dt->days; utc->seconds = dt->seconds; @@ -1316,7 +1316,7 @@ pcmk__time_parse_duration(const char *period_s) goto invalid; } - diff = crm_time_new_undefined(); + diff = pcmk__assert_alloc(1, sizeof(crm_time_t)); for (const char *current = period_s + 1; current[0] && (current[0] != '/') && !isspace(current[0]); @@ -1387,7 +1387,7 @@ pcmk__set_time_if_earlier(crm_time_t *target, const crm_time_t *source) crm_time_t * pcmk_copy_time(const crm_time_t *source) { - crm_time_t *target = crm_time_new_undefined(); + crm_time_t *target = pcmk__assert_alloc(1, sizeof(crm_time_t)); *target = *source; return target; @@ -1408,7 +1408,7 @@ crm_time_t * pcmk__copy_timet(time_t source_sec) { const struct tm *source = localtime(&source_sec); - crm_time_t *target = crm_time_new_undefined(); + crm_time_t *target = pcmk__assert_alloc(1, sizeof(crm_time_t)); int h_offset = 0; int m_offset = 0; diff --git a/lib/common/tests/iso8601/pcmk__set_time_if_earlier_test.c b/lib/common/tests/iso8601/pcmk__set_time_if_earlier_test.c index c4bf0140825..79821c3de2e 100644 --- a/lib/common/tests/iso8601/pcmk__set_time_if_earlier_test.c +++ b/lib/common/tests/iso8601/pcmk__set_time_if_earlier_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 the Pacemaker project contributors + * Copyright 2024-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -36,7 +36,7 @@ static void target_undefined(void **state) { crm_time_t *source = crm_time_new("2024-01-01 00:29:59 +01:00"); - crm_time_t *target = crm_time_new_undefined(); + crm_time_t *target = pcmk__assert_alloc(1, sizeof(crm_time_t)); pcmk__set_time_if_earlier(target, source); assert_int_equal(crm_time_compare(target, source), 0); diff --git a/lib/common/tests/rules/pcmk__evaluate_condition_test.c b/lib/common/tests/rules/pcmk__evaluate_condition_test.c index be0931a0267..7327ad01fc9 100644 --- a/lib/common/tests/rules/pcmk__evaluate_condition_test.c +++ b/lib/common/tests/rules/pcmk__evaluate_condition_test.c @@ -42,7 +42,7 @@ static void null_invalid(void **state) { xmlNode *xml = NULL; - crm_time_t *next_change = crm_time_new_undefined(); + crm_time_t *next_change = pcmk__assert_alloc(1, sizeof(crm_time_t)); assert_int_equal(pcmk__evaluate_condition(NULL, NULL, next_change), EINVAL); @@ -63,7 +63,7 @@ static void invalid_expression(void **state) { xmlNode *xml = pcmk__xml_parse(EXPR_INVALID); - crm_time_t *next_change = crm_time_new_undefined(); + crm_time_t *next_change = pcmk__assert_alloc(1, sizeof(crm_time_t)); assert_int_equal(pcmk__evaluate_condition(xml, &rule_input, next_change), pcmk_rc_unpack_error); diff --git a/lib/common/tests/rules/pcmk_evaluate_rule_test.c b/lib/common/tests/rules/pcmk_evaluate_rule_test.c index 0a028076c58..f0ce9d23b49 100644 --- a/lib/common/tests/rules/pcmk_evaluate_rule_test.c +++ b/lib/common/tests/rules/pcmk_evaluate_rule_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 the Pacemaker project contributors + * Copyright 2024-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -43,7 +43,7 @@ static void null_invalid(void **state) { xmlNode *xml = NULL; - crm_time_t *next_change = crm_time_new_undefined(); + crm_time_t *next_change = pcmk__assert_alloc(1, sizeof(crm_time_t)); assert_int_equal(pcmk_evaluate_rule(NULL, NULL, next_change), EINVAL); @@ -69,7 +69,7 @@ static void id_missing(void **state) { xmlNode *xml = pcmk__xml_parse(RULE_OP_MISSING_ID); - crm_time_t *next_change = crm_time_new_undefined(); + crm_time_t *next_change = pcmk__assert_alloc(1, sizeof(crm_time_t)); assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, next_change), pcmk_rc_unpack_error); @@ -85,7 +85,7 @@ good_idref(void **state) { xmlNode *parent_xml = pcmk__xml_parse(RULE_IDREF_PARENT); xmlNode *rule_xml = pcmk__xe_create(parent_xml, PCMK_XE_RULE); - crm_time_t *next_change = crm_time_new_undefined(); + crm_time_t *next_change = pcmk__assert_alloc(1, sizeof(crm_time_t)); pcmk__xe_set(rule_xml, PCMK_XA_ID_REF, "r"); assert_int_equal(pcmk_evaluate_rule(rule_xml, &rule_input, next_change), @@ -100,7 +100,7 @@ bad_idref(void **state) { xmlNode *parent_xml = pcmk__xml_parse(RULE_IDREF_PARENT); xmlNode *rule_xml = pcmk__xe_create(parent_xml, PCMK_XE_RULE); - crm_time_t *next_change = crm_time_new_undefined(); + crm_time_t *next_change = pcmk__assert_alloc(1, sizeof(crm_time_t)); pcmk__xe_set(rule_xml, PCMK_XA_ID_REF, "x"); assert_int_equal(pcmk_evaluate_rule(rule_xml, &rule_input, next_change), diff --git a/lib/common/tests/xml_element/pcmk__xe_get_datetime_test.c b/lib/common/tests/xml_element/pcmk__xe_get_datetime_test.c index bad68bffbf1..c488d3f7243 100644 --- a/lib/common/tests/xml_element/pcmk__xe_get_datetime_test.c +++ b/lib/common/tests/xml_element/pcmk__xe_get_datetime_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 the Pacemaker project contributors + * Copyright 2024-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -51,7 +51,7 @@ static void nonnull_time_invalid(void **state) { xmlNode *xml = pcmk__xml_parse(REFERENCE_XML); - crm_time_t *t = crm_time_new_undefined(); + crm_time_t *t = pcmk__assert_alloc(1, sizeof(crm_time_t)); assert_int_equal(pcmk__xe_get_datetime(xml, ATTR_PRESENT, &t), EINVAL); diff --git a/lib/pacemaker/pcmk_sched_location.c b/lib/pacemaker/pcmk_sched_location.c index 8415dc2c131..bcd0bb51306 100644 --- a/lib/pacemaker/pcmk_sched_location.c +++ b/lib/pacemaker/pcmk_sched_location.c @@ -362,7 +362,7 @@ unpack_rsc_location(xmlNode *xml_obj, pcmk_resource_t *rsc, location->role_filter = role; } else { - crm_time_t *next_change = crm_time_new_undefined(); + crm_time_t *next_change = pcmk__assert_alloc(1, sizeof(crm_time_t)); xmlNode *rule_xml = pcmk__xe_first_child(xml_obj, PCMK_XE_RULE, NULL, NULL); pcmk_rule_input_t rule_input = { diff --git a/lib/pengine/utils.c b/lib/pengine/utils.c index 7906fbe6305..e4ca2bd9334 100644 --- a/lib/pengine/utils.c +++ b/lib/pengine/utils.c @@ -709,7 +709,7 @@ pe__unpack_dataset_nvpairs(const xmlNode *xml_obj, const char *set_name, return; } - next_change = crm_time_new_undefined(); + next_change = pcmk__assert_alloc(1, sizeof(crm_time_t)); pcmk__unpack_nvpair_blocks(xml_obj, set_name, always_first, rule_input, hash, next_change, scheduler->input->doc); From a07781e3df92abd8651ca22c5c7b118a373bb466 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 18:05:05 -0700 Subject: [PATCH 35/99] API: libcrmcommon: Deprecate crm_time_new_undefined() Use crm_time_new() to create a new crm_time_t object from a string (or NULL to use the current time). There is no need for external callers to create an uninitialized object and then set the fields (such as years) later. Pacemaker should not be used for general-purpose date/time manipulation. pcmk_evaluate_rule() can take an uninitialized (undefined) crm_time_t object as the next_change argument and update it as appropriate. However, that argument is for use by the scheduler, not for external callers. Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 1 - include/crm/common/iso8601_compat.h | 3 +++ lib/common/iso8601.c | 20 ++++++-------------- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index ccf9369090a..b01c4836d86 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -52,7 +52,6 @@ typedef struct crm_time_s crm_time_t; * A timezone of 'Z' denotes UTC time */ crm_time_t *crm_time_new(const char *string); -crm_time_t *crm_time_new_undefined(void); void crm_time_free(crm_time_t * dt); bool crm_time_is_defined(const crm_time_t *t); diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index b823a530d83..112674aadbe 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -86,6 +86,9 @@ crm_time_t *crm_time_calculate_duration(const crm_time_t *dt, //! \deprecated Do not use crm_time_t *crm_time_parse_duration(const char *duration_str); +//! \deprecated Do not use +crm_time_t *crm_time_new_undefined(void); + #ifdef __cplusplus } #endif diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 9a710d6ac78..73f947bb9fc 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -74,20 +74,6 @@ ((QB_ABS(usec) < QB_TIME_US_IN_SEC) \ && (((sec) == 0) || ((usec) == 0) || (((sec) < 0) == ((usec) < 0)))) -/*! - * \brief Allocate memory for an uninitialized time object - * - * \return Newly allocated time object (guaranteed not to be \c NULL) - * - * \note The caller is responsible for freeing the return value using - * \c crm_time_free(). - */ -crm_time_t * -crm_time_new_undefined(void) -{ - return pcmk__assert_alloc(1, sizeof(crm_time_t)); -} - /*! * \internal * \brief Check whether a year is positive and representable by four digits @@ -2422,5 +2408,11 @@ crm_time_parse_duration(const char *period_s) return pcmk__time_parse_duration(period_s); } +crm_time_t * +crm_time_new_undefined(void) +{ + return pcmk__assert_alloc(1, sizeof(crm_time_t)); +} + // LCOV_EXCL_STOP // End deprecated API From 3c2b2825df9a279fa7fc6af40ab07fe5a8280c52 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 18:15:09 -0700 Subject: [PATCH 36/99] Refactor: libcrmcommon: New pcmk__time_is_initialized() To replace crm_time_is_defined(). Signed-off-by: Reid Wahl --- include/crm/common/iso8601_internal.h | 1 + lib/common/iso8601.c | 30 +++++++++++++++++++++------ lib/pacemaker/pcmk_sched_location.c | 2 +- lib/pengine/utils.c | 2 +- 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/include/crm/common/iso8601_internal.h b/include/crm/common/iso8601_internal.h index ac12844de7e..93b5ca5d354 100644 --- a/include/crm/common/iso8601_internal.h +++ b/include/crm/common/iso8601_internal.h @@ -28,6 +28,7 @@ extern "C" { #endif bool pcmk__time_valid_year(int year); +bool pcmk__time_is_initialized(const crm_time_t *dt); void pcmk__time_get_ywd(const crm_time_t *dt, uint32_t *y, uint32_t *w, uint32_t *d); char *pcmk__time_format_hr(const char *format, const crm_time_t *dt, int usec); diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 73f947bb9fc..47001c57ece 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -655,6 +655,26 @@ crm_time_new(const char *date_time) return parse_date(date_time); } +/*! + * \brief Check whether a time object has been initialized yet + * + * \param[in] dt Time object to check + * + * \return \c true if time object has been initialized, or \c false otherwise + */ +bool +pcmk__time_is_initialized(const crm_time_t *dt) +{ + // Any nonzero member indicates something has been done to dt + return (dt != NULL) + && ((dt->years != 0) + || (dt->months != 0) + || (dt->days != 0) + || (dt->seconds != 0) + || (dt->offset != 0) + || (dt->duration)); +} + /*! * \brief Check whether a time object has been initialized yet * @@ -665,9 +685,7 @@ crm_time_new(const char *date_time) bool crm_time_is_defined(const crm_time_t *t) { - // Any nonzero member indicates something has been done to t - return (t != NULL) && (t->years || t->months || t->days || t->seconds - || t->offset || t->duration); + return pcmk__time_is_initialized(t); } void @@ -987,7 +1005,7 @@ time_as_string_common(const crm_time_t *dt, int usec, uint32_t flags) GString *buf = NULL; char *result = NULL; - if (!crm_time_is_defined(dt)) { + if (!pcmk__time_is_initialized(dt)) { return pcmk__str_copy(""); } @@ -1324,7 +1342,7 @@ pcmk__time_parse_duration(const char *period_s) } } - if (!crm_time_is_defined(diff)) { + if (!pcmk__time_is_initialized(diff)) { pcmk__err("'%s' is not a valid ISO 8601 time duration because no " "amounts and units given", period_s); @@ -1359,7 +1377,7 @@ pcmk__set_time_if_earlier(crm_time_t *target, const crm_time_t *source) if ((target == NULL) || (source == NULL) - || (crm_time_is_defined(target) + || (pcmk__time_is_initialized(target) && (crm_time_compare(source, target) >= 0))) { return; diff --git a/lib/pacemaker/pcmk_sched_location.c b/lib/pacemaker/pcmk_sched_location.c index bcd0bb51306..e5e48b9bc60 100644 --- a/lib/pacemaker/pcmk_sched_location.c +++ b/lib/pacemaker/pcmk_sched_location.c @@ -379,7 +379,7 @@ unpack_rsc_location(xmlNode *xml_obj, pcmk_resource_t *rsc, /* If there is a point in the future when the evaluation of a rule will * change, make sure the scheduler is re-run by that time. */ - if (crm_time_is_defined(next_change)) { + if (pcmk__time_is_initialized(next_change)) { time_t t = (time_t) crm_time_get_seconds_since_epoch(next_change); pcmk__update_recheck_time(t, rsc->priv->scheduler, diff --git a/lib/pengine/utils.c b/lib/pengine/utils.c index e4ca2bd9334..0237af6def0 100644 --- a/lib/pengine/utils.c +++ b/lib/pengine/utils.c @@ -713,7 +713,7 @@ pe__unpack_dataset_nvpairs(const xmlNode *xml_obj, const char *set_name, pcmk__unpack_nvpair_blocks(xml_obj, set_name, always_first, rule_input, hash, next_change, scheduler->input->doc); - if (crm_time_is_defined(next_change)) { + if (pcmk__time_is_initialized(next_change)) { time_t recheck = (time_t) crm_time_get_seconds_since_epoch(next_change); pcmk__update_recheck_time(recheck, scheduler, "rule evaluation"); From e5a3ea03e37923ac56eb2286bc29192cffd700c2 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 18:17:00 -0700 Subject: [PATCH 37/99] API: libcrmcommon: Deprecate crm_time_is_defined() External callers should always be using crm_time_new() to create a crm_time_t object. Such objects will be initialized ("defined"). Pacemaker does not return crm_time_t objects via public API functions, except as an output argument of pcmk_evaluate_rule(). However, that argument is for use by the scheduler, not for external callers. Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 1 - include/crm/common/iso8601_compat.h | 3 +++ lib/common/iso8601.c | 19 ++++++------------- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index b01c4836d86..e0426665dc0 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,7 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); void crm_time_free(crm_time_t * dt); -bool crm_time_is_defined(const crm_time_t *t); char *crm_time_as_string(const crm_time_t *dt, int flags); #define crm_time_log_date 0x001 diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index 112674aadbe..05889f933bb 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -89,6 +89,9 @@ crm_time_t *crm_time_parse_duration(const char *duration_str); //! \deprecated Do not use crm_time_t *crm_time_new_undefined(void); +//! \deprecated Do not use +bool crm_time_is_defined(const crm_time_t *t); + #ifdef __cplusplus } #endif diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 47001c57ece..8a5362799a6 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -675,19 +675,6 @@ pcmk__time_is_initialized(const crm_time_t *dt) || (dt->duration)); } -/*! - * \brief Check whether a time object has been initialized yet - * - * \param[in] t Time object to check - * - * \return \c true if time object has been initialized, \c false otherwise - */ -bool -crm_time_is_defined(const crm_time_t *t) -{ - return pcmk__time_is_initialized(t); -} - void crm_time_free(crm_time_t * dt) { @@ -2432,5 +2419,11 @@ crm_time_new_undefined(void) return pcmk__assert_alloc(1, sizeof(crm_time_t)); } +bool +crm_time_is_defined(const crm_time_t *t) +{ + return pcmk__time_is_initialized(t); +} + // LCOV_EXCL_STOP // End deprecated API From 0a72341d0ab0a2789ae03eea63a2928d87c01b88 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 18:27:20 -0700 Subject: [PATCH 38/99] Refactor: libcrmcommon: New pcmk__time_text() To replace crm_time_as_string(). Signed-off-by: Reid Wahl --- include/crm/common/iso8601_internal.h | 1 + lib/common/iso8601.c | 21 ++++++++++++++--- lib/pacemaker/pcmk_simulate.c | 2 +- tools/crm_resource_ban.c | 4 ++-- tools/iso8601.c | 33 +++++++++++++++------------ 5 files changed, 40 insertions(+), 21 deletions(-) diff --git a/include/crm/common/iso8601_internal.h b/include/crm/common/iso8601_internal.h index 93b5ca5d354..fc61b5e3782 100644 --- a/include/crm/common/iso8601_internal.h +++ b/include/crm/common/iso8601_internal.h @@ -31,6 +31,7 @@ bool pcmk__time_valid_year(int year); bool pcmk__time_is_initialized(const crm_time_t *dt); void pcmk__time_get_ywd(const crm_time_t *dt, uint32_t *y, uint32_t *w, uint32_t *d); +char *pcmk__time_text(const crm_time_t *dt, int flags); char *pcmk__time_format_hr(const char *format, const crm_time_t *dt, int usec); char *pcmk__epoch2str(const time_t *source, uint32_t flags); char *pcmk__timespec2str(const struct timespec *ts, uint32_t flags); diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 8a5362799a6..27441a1412d 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -689,7 +689,7 @@ pcmk__time_log_as(const char *file, const char *function, int line, uint8_t level, const char *prefix, const crm_time_t *dt, uint32_t flags) { - char *date_s = crm_time_as_string(dt, flags); + char *date_s = pcmk__time_text(dt, flags); if (prefix != NULL) { char *old = date_s; @@ -1104,6 +1104,21 @@ time_as_string_common(const crm_time_t *dt, int usec, uint32_t flags) return result; } +/*! + * \internal + * \brief Get a string representation of a \c crm_time_t object + * + * \param[in] dt Time to convert to string + * \param[in] flags Group of \c crm_time_* string format options + * + * \note The caller is responsible for freeing the return value using \c free(). + */ +char * +pcmk__time_text(const crm_time_t *dt, int flags) +{ + return time_as_string_common(dt, 0, flags); +} + /*! * \brief Get a string representation of a \p crm_time_t object * @@ -1115,7 +1130,7 @@ time_as_string_common(const crm_time_t *dt, int usec, uint32_t flags) char * crm_time_as_string(const crm_time_t *dt, int flags) { - return time_as_string_common(dt, 0, flags); + return pcmk__time_text(dt, flags); } // Parse an ISO 8601 numeric value and return number of characters consumed @@ -2098,7 +2113,7 @@ pcmk__epoch2str(const time_t *source, uint32_t flags) } dt = pcmk__copy_timet(epoch_time); - result = crm_time_as_string(dt, flags); + result = pcmk__time_text(dt, flags); crm_time_free(dt); return result; diff --git a/lib/pacemaker/pcmk_simulate.c b/lib/pacemaker/pcmk_simulate.c index 7e093f12050..18bb0dcbacd 100644 --- a/lib/pacemaker/pcmk_simulate.c +++ b/lib/pacemaker/pcmk_simulate.c @@ -521,7 +521,7 @@ set_effective_date(pcmk_scheduler_t *scheduler, bool print_original, scheduler->priv->now = pcmk__copy_timet(original_date); if (print_original) { - char *when = crm_time_as_string(scheduler->priv->now, flags); + char *when = pcmk__time_text(scheduler->priv->now, flags); out->info(out, "Using the original execution date of: %s", when); free(when); diff --git a/tools/crm_resource_ban.c b/tools/crm_resource_ban.c index a83bee1e89c..d7a594bc45c 100644 --- a/tools/crm_resource_ban.c +++ b/tools/crm_resource_ban.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2025 the Pacemaker project contributors + * Copyright 2004-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -53,7 +53,7 @@ parse_cli_lifetime(pcmk__output_t *out, const char *move_lifetime) pcmk__time_log(LOG_INFO, "now ", now, time_flags); pcmk__time_log(LOG_INFO, "later ", later, time_flags); pcmk__time_log(LOG_INFO, "duration", duration, duration_flags); - later_s = crm_time_as_string(later, time_flags); + later_s = pcmk__time_text(later, time_flags); out->info(out, "Migration will take effect until: %s", later_s); crm_time_free(duration); diff --git a/tools/iso8601.c b/tools/iso8601.c index fc5bed4c0ce..ec4db392419 100644 --- a/tools/iso8601.c +++ b/tools/iso8601.c @@ -127,7 +127,7 @@ date_default(pcmk__output_t *out, va_list args) char *date_s = NULL; opts |= crm_time_log_date | crm_time_log_timeofday; - date_s = crm_time_as_string(date, opts); + date_s = pcmk__time_text(date, opts); out->info(out, "%s: %s", prefix, date_s); @@ -146,7 +146,7 @@ date_xml(pcmk__output_t *out, va_list args) char *date_s = NULL; opts |= crm_time_log_date | crm_time_log_timeofday; - date_s = crm_time_as_string(date, opts); + date_s = pcmk__time_text(date, opts); pcmk__output_create_xml_text_node(out, PCMK_XE_DATE, date_s); free(date_s); @@ -160,7 +160,7 @@ duration_default(pcmk__output_t *out, va_list args) crm_time_t *time = va_arg(args, crm_time_t *); int opts = va_arg(args, int); - char *date_s = crm_time_as_string(time, opts | crm_time_log_duration); + char *date_s = pcmk__time_text(time, opts|crm_time_log_duration); out->info(out, "Duration: %s", date_s); @@ -175,7 +175,7 @@ duration_xml(pcmk__output_t *out, va_list args) crm_time_t *time = va_arg(args, crm_time_t *); int opts = va_arg(args, int); - char *date_s = crm_time_as_string(time, opts | crm_time_log_duration); + char *date_s = pcmk__time_text(time, opts|crm_time_log_duration); pcmk__output_create_xml_text_node(out, PCMK_XE_DURATION, date_s); free(date_s); @@ -192,7 +192,7 @@ duration_ends_default(pcmk__output_t *out, va_list args) char *date_s = NULL; opts |= crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone; - date_s = crm_time_as_string(time, opts); + date_s = pcmk__time_text(time, opts); out->info(out, "Duration ends at: %s", date_s); @@ -210,7 +210,7 @@ duration_ends_xml(pcmk__output_t *out, va_list args) char *date_s = NULL; opts |= crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone; - date_s = crm_time_as_string(time, opts); + date_s = pcmk__time_text(time, opts); pcmk__output_create_xml_text_node(out, PCMK_XE_DURATION_ENDS, date_s); free(date_s); @@ -230,12 +230,12 @@ period_default(pcmk__output_t *out, va_list args) opts |= crm_time_log_date | crm_time_log_timeofday; - start_s = crm_time_as_string(start, opts); + start_s = pcmk__time_text(start, opts); if (start_s == NULL) { return pcmk_rc_no_output; } - end_s = crm_time_as_string(end, opts); + end_s = pcmk__time_text(end, opts); if (end_s == NULL) { free(start_s); return pcmk_rc_no_output; @@ -261,12 +261,12 @@ period_xml(pcmk__output_t *out, va_list args) opts |= crm_time_log_date | crm_time_log_timeofday; - start_s = crm_time_as_string(start, opts); + start_s = pcmk__time_text(start, opts); if (start_s == NULL) { return pcmk_rc_no_output; } - end_s = crm_time_as_string(end, opts); + end_s = pcmk__time_text(end, opts); if (end_s == NULL) { free(start_s); return pcmk_rc_no_output; @@ -509,9 +509,10 @@ main(int argc, char **argv) out->message(out, "duration_ends", later, options.print_options); if (options.expected_s) { - char *dt_s = crm_time_as_string(later, - options.print_options | crm_time_log_date | - crm_time_log_timeofday); + char *dt_s = pcmk__time_text(later, + options.print_options + |crm_time_log_date + |crm_time_log_timeofday); if (!pcmk__str_eq(options.expected_s, dt_s, pcmk__str_casei)) { exit_code = CRM_EX_ERROR; goto done; @@ -521,8 +522,10 @@ main(int argc, char **argv) crm_time_free(later); } else if (date_time && options.expected_s) { - char *dt_s = crm_time_as_string(date_time, - options.print_options | crm_time_log_date | crm_time_log_timeofday); + char *dt_s = pcmk__time_text(date_time, + options.print_options + |crm_time_log_date + |crm_time_log_timeofday); if (!pcmk__str_eq(options.expected_s, dt_s, pcmk__str_casei)) { exit_code = CRM_EX_ERROR; From 48ae97af82554591315fba2d7e0cd5fafc7a4cd1 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 18:28:04 -0700 Subject: [PATCH 39/99] API: libcrmcommon: Deprecate crm_time_as_string() Pacemaker should not be used for general-purpose date/time manipulation. It also does not return crm_time_t objects (except in the case of pcmk_evaluate_rule(), as discussed in previous commit messages). So external callers have no need to convert a crm_time_t to a string representation. Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 2 -- include/crm/common/iso8601_compat.h | 3 +++ lib/common/iso8601.c | 20 ++++++-------------- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index e0426665dc0..07e20d1301b 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,8 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); void crm_time_free(crm_time_t * dt); -char *crm_time_as_string(const crm_time_t *dt, int flags); - #define crm_time_log_date 0x001 #define crm_time_log_timeofday 0x002 #define crm_time_log_with_timezone 0x004 diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index 05889f933bb..282637248d7 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -92,6 +92,9 @@ crm_time_t *crm_time_new_undefined(void); //! \deprecated Do not use bool crm_time_is_defined(const crm_time_t *t); +//! \deprecated Do not use +char *crm_time_as_string(const crm_time_t *dt, int flags); + #ifdef __cplusplus } #endif diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 27441a1412d..c5c948df577 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1119,20 +1119,6 @@ pcmk__time_text(const crm_time_t *dt, int flags) return time_as_string_common(dt, 0, flags); } -/*! - * \brief Get a string representation of a \p crm_time_t object - * - * \param[in] dt Time to convert to string - * \param[in] flags Group of \p crm_time_* string format options - * - * \note The caller is responsible for freeing the return value using \p free(). - */ -char * -crm_time_as_string(const crm_time_t *dt, int flags) -{ - return pcmk__time_text(dt, flags); -} - // Parse an ISO 8601 numeric value and return number of characters consumed static int parse_int(const char *str, int *result) @@ -2440,5 +2426,11 @@ crm_time_is_defined(const crm_time_t *t) return pcmk__time_is_initialized(t); } +char * +crm_time_as_string(const crm_time_t *dt, int flags) +{ + return pcmk__time_text(dt, flags); +} + // LCOV_EXCL_STOP // End deprecated API From 7b28de59700f7b6106f84ca463fd581eb6a59295 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 18:33:41 -0700 Subject: [PATCH 40/99] Refactor: libcrmcommon: New pcmk__time_fmt_date flag To replace crm_time_log_date. Signed-off-by: Reid Wahl --- include/crm/common/iso8601_internal.h | 7 +++++++ lib/common/iso8601.c | 10 +++++----- lib/common/tls.c | 5 +++-- lib/fencing/st_output.c | 4 ++-- lib/pacemaker/pcmk_output.c | 8 ++++---- lib/pacemaker/pcmk_simulate.c | 2 +- lib/pengine/pe_output.c | 2 +- tools/crm_resource_ban.c | 2 +- tools/iso8601.c | 20 ++++++++++++-------- 9 files changed, 36 insertions(+), 24 deletions(-) diff --git a/include/crm/common/iso8601_internal.h b/include/crm/common/iso8601_internal.h index fc61b5e3782..3f63cf19289 100644 --- a/include/crm/common/iso8601_internal.h +++ b/include/crm/common/iso8601_internal.h @@ -27,6 +27,13 @@ extern "C" { #endif +/* @COMPAT These must be kept in line with the deprecated crm_time_* flags until + * those are removed + */ +enum pcmk__time_fmt_flags { + pcmk__time_fmt_date = (UINT32_C(1) << 0), +}; + bool pcmk__time_valid_year(int year); bool pcmk__time_is_initialized(const crm_time_t *dt); void pcmk__time_get_ywd(const crm_time_t *dt, uint32_t *y, uint32_t *w, diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index c5c948df577..c3f6d1975a9 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -440,7 +440,7 @@ valid_time(const crm_time_t *dt) static crm_time_t * parse_date(const char *date_str) { - const uint32_t flags = crm_time_log_date|crm_time_log_timeofday; + const uint32_t flags = pcmk__time_fmt_date|crm_time_log_timeofday; const char *time_s = NULL; crm_time_t *dt = NULL; @@ -619,7 +619,7 @@ parse_date(const char *date_str) static crm_time_t * copy_time_to_utc(const crm_time_t *dt) { - const uint32_t flags = crm_time_log_date + const uint32_t flags = pcmk__time_fmt_date |crm_time_log_timeofday |crm_time_log_with_timezone; crm_time_t *utc = NULL; @@ -1034,7 +1034,7 @@ time_as_string_common(const crm_time_t *dt, int usec, uint32_t flags) // As readable string - if (pcmk__is_set(flags, crm_time_log_date)) { + if (pcmk__is_set(flags, pcmk__time_fmt_date)) { if (pcmk__is_set(flags, crm_time_weeks)) { // YYYY-WW-D if (dt->days > 0) { uint32_t y = 0; @@ -1359,7 +1359,7 @@ pcmk__time_parse_duration(const char *period_s) void pcmk__set_time_if_earlier(crm_time_t *target, const crm_time_t *source) { - const int flags = crm_time_log_date + const int flags = pcmk__time_fmt_date |crm_time_log_timeofday |crm_time_log_with_timezone; @@ -2241,7 +2241,7 @@ crm_time_january1_weekday(int year) void crm_time_set(crm_time_t *target, const crm_time_t *source) { - const uint32_t flags = crm_time_log_date + const uint32_t flags = pcmk__time_fmt_date |crm_time_log_timeofday |crm_time_log_with_timezone; diff --git a/lib/common/tls.c b/lib/common/tls.c index 3ba6aa94661..f9bab37348d 100644 --- a/lib/common/tls.c +++ b/lib/common/tls.c @@ -27,7 +27,7 @@ #include // QB_XS #include -#include // crm_time_free, crm_time_log_date +#include // crm_time_* #include // CRM_CHECK #include // pcmk_rc_* @@ -474,7 +474,8 @@ pcmk__tls_check_cert_expiration(gnutls_session_t session) crm_time_t *expiry_t = pcmk__copy_timet(expiry); pcmk__time_log(LOG_WARNING, "TLS certificate will expire on", - expiry_t, crm_time_log_date|crm_time_log_timeofday); + expiry_t, + pcmk__time_fmt_date|crm_time_log_timeofday); crm_time_free(expiry_t); } } diff --git a/lib/fencing/st_output.c b/lib/fencing/st_output.c index 0f68ed2ad74..d666a01fcd7 100644 --- a/lib/fencing/st_output.c +++ b/lib/fencing/st_output.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2025 the Pacemaker project contributors + * Copyright 2019-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -41,7 +41,7 @@ timespec_string(time_t sec, long nsec, bool show_usec) { }; return pcmk__timespec2str(&ts, - crm_time_log_date + pcmk__time_fmt_date |crm_time_log_timeofday |crm_time_log_with_timezone |(show_usec? crm_time_usecs : 0)); diff --git a/lib/pacemaker/pcmk_output.c b/lib/pacemaker/pcmk_output.c index 48e13538eb8..a1cf3193ec4 100644 --- a/lib/pacemaker/pcmk_output.c +++ b/lib/pacemaker/pcmk_output.c @@ -1,5 +1,5 @@ /* - * Copyright 2019-2025 the Pacemaker project contributors + * Copyright 2019-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -736,7 +736,7 @@ pacemakerd_health(pcmk__output_t *out, va_list args) if (last_updated != 0) { last_updated_s = pcmk__epoch2str(&last_updated, - crm_time_log_date + pcmk__time_fmt_date |crm_time_log_timeofday |crm_time_log_with_timezone); } @@ -777,7 +777,7 @@ pacemakerd_health_html(pcmk__output_t *out, va_list args) if (last_updated != 0) { last_updated_s = pcmk__epoch2str(&last_updated, - crm_time_log_date + pcmk__time_fmt_date |crm_time_log_timeofday |crm_time_log_with_timezone); } @@ -841,7 +841,7 @@ pacemakerd_health_xml(pcmk__output_t *out, va_list args) if (last_updated != 0) { last_updated_s = pcmk__epoch2str(&last_updated, - crm_time_log_date + pcmk__time_fmt_date |crm_time_log_timeofday |crm_time_log_with_timezone); } diff --git a/lib/pacemaker/pcmk_simulate.c b/lib/pacemaker/pcmk_simulate.c index 18bb0dcbacd..ae888326d50 100644 --- a/lib/pacemaker/pcmk_simulate.c +++ b/lib/pacemaker/pcmk_simulate.c @@ -498,7 +498,7 @@ static void set_effective_date(pcmk_scheduler_t *scheduler, bool print_original, const char *use_date) { - static const uint32_t flags = crm_time_log_date|crm_time_log_timeofday; + static const uint32_t flags = pcmk__time_fmt_date|crm_time_log_timeofday; pcmk__output_t *out = scheduler->priv->out; time_t original_date = 0; diff --git a/lib/pengine/pe_output.c b/lib/pengine/pe_output.c index 7b43314937e..290478eeee5 100644 --- a/lib/pengine/pe_output.c +++ b/lib/pengine/pe_output.c @@ -1648,7 +1648,7 @@ failed_action_xml(pcmk__output_t *out, va_list args) { guint interval_ms = 0; char *interval_ms_s = NULL; char *rc_change = pcmk__epoch2str(&epoch, - crm_time_log_date + pcmk__time_fmt_date |crm_time_log_timeofday |crm_time_log_with_timezone); diff --git a/tools/crm_resource_ban.c b/tools/crm_resource_ban.c index d7a594bc45c..093a08e6607 100644 --- a/tools/crm_resource_ban.c +++ b/tools/crm_resource_ban.c @@ -24,7 +24,7 @@ parse_cli_lifetime(pcmk__output_t *out, const char *move_lifetime) crm_time_t *now = NULL; crm_time_t *later = NULL; crm_time_t *duration = NULL; - const uint32_t duration_flags = crm_time_log_date|crm_time_log_timeofday; + const uint32_t duration_flags = pcmk__time_fmt_date|crm_time_log_timeofday; const uint32_t time_flags = duration_flags|crm_time_log_with_timezone; if (move_lifetime == NULL) { diff --git a/tools/iso8601.c b/tools/iso8601.c index ec4db392419..fec74a14dc8 100644 --- a/tools/iso8601.c +++ b/tools/iso8601.c @@ -126,7 +126,7 @@ date_default(pcmk__output_t *out, va_list args) char *date_s = NULL; - opts |= crm_time_log_date | crm_time_log_timeofday; + opts |= pcmk__time_fmt_date|crm_time_log_timeofday; date_s = pcmk__time_text(date, opts); out->info(out, "%s: %s", prefix, date_s); @@ -145,7 +145,7 @@ date_xml(pcmk__output_t *out, va_list args) char *date_s = NULL; - opts |= crm_time_log_date | crm_time_log_timeofday; + opts |= pcmk__time_fmt_date|crm_time_log_timeofday; date_s = pcmk__time_text(date, opts); pcmk__output_create_xml_text_node(out, PCMK_XE_DATE, date_s); @@ -191,7 +191,9 @@ duration_ends_default(pcmk__output_t *out, va_list args) char *date_s = NULL; - opts |= crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone; + opts |= pcmk__time_fmt_date + |crm_time_log_timeofday + |crm_time_log_with_timezone; date_s = pcmk__time_text(time, opts); out->info(out, "Duration ends at: %s", date_s); @@ -209,7 +211,9 @@ duration_ends_xml(pcmk__output_t *out, va_list args) char *date_s = NULL; - opts |= crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone; + opts |= pcmk__time_fmt_date + |crm_time_log_timeofday + |crm_time_log_with_timezone; date_s = pcmk__time_text(time, opts); pcmk__output_create_xml_text_node(out, PCMK_XE_DURATION_ENDS, date_s); @@ -228,7 +232,7 @@ period_default(pcmk__output_t *out, va_list args) char *start_s = NULL; char *end_s = NULL; - opts |= crm_time_log_date | crm_time_log_timeofday; + opts |= pcmk__time_fmt_date|crm_time_log_timeofday; start_s = pcmk__time_text(start, opts); if (start_s == NULL) { @@ -259,7 +263,7 @@ period_xml(pcmk__output_t *out, va_list args) char *start_s = NULL; char *end_s = NULL; - opts |= crm_time_log_date | crm_time_log_timeofday; + opts |= pcmk__time_fmt_date|crm_time_log_timeofday; start_s = pcmk__time_text(start, opts); if (start_s == NULL) { @@ -511,7 +515,7 @@ main(int argc, char **argv) if (options.expected_s) { char *dt_s = pcmk__time_text(later, options.print_options - |crm_time_log_date + |pcmk__time_fmt_date |crm_time_log_timeofday); if (!pcmk__str_eq(options.expected_s, dt_s, pcmk__str_casei)) { exit_code = CRM_EX_ERROR; @@ -524,7 +528,7 @@ main(int argc, char **argv) } else if (date_time && options.expected_s) { char *dt_s = pcmk__time_text(date_time, options.print_options - |crm_time_log_date + |pcmk__time_fmt_date |crm_time_log_timeofday); if (!pcmk__str_eq(options.expected_s, dt_s, pcmk__str_casei)) { From 063772b3622bbac88342d30af0a620c83ed59a13 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 18:37:29 -0700 Subject: [PATCH 41/99] API: libcrmcommon: Deprecate crm_time_log_date Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 1 - include/crm/common/iso8601_compat.h | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 07e20d1301b..ac6c5dd2c74 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,7 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); void crm_time_free(crm_time_t * dt); -#define crm_time_log_date 0x001 #define crm_time_log_timeofday 0x002 #define crm_time_log_with_timezone 0x004 #define crm_time_log_duration 0x008 diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index 282637248d7..70108907147 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -29,6 +29,9 @@ extern "C" { * release. */ +//! \deprecated Do not use +#define crm_time_log_date 0x001 + //! \deprecated Do not use typedef struct crm_time_period_s { crm_time_t *start; From a4ff3132c45a9fd72ae698cbb51a0b1f72778a2b Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 18:43:47 -0700 Subject: [PATCH 42/99] Refactor: libcrmcommon: New pcmk__time_fmt_time To replace crm_time_log_timeofday. Signed-off-by: Reid Wahl --- include/crm/common/iso8601_internal.h | 1 + lib/common/iso8601.c | 10 +++++----- lib/common/tls.c | 3 +-- lib/fencing/st_output.c | 2 +- lib/pacemaker/pcmk_output.c | 6 +++--- lib/pacemaker/pcmk_simulate.c | 2 +- lib/pengine/pe_output.c | 2 +- tools/crm_resource_ban.c | 2 +- tools/iso8601.c | 20 ++++++++------------ 9 files changed, 22 insertions(+), 26 deletions(-) diff --git a/include/crm/common/iso8601_internal.h b/include/crm/common/iso8601_internal.h index 3f63cf19289..04546bae9fb 100644 --- a/include/crm/common/iso8601_internal.h +++ b/include/crm/common/iso8601_internal.h @@ -32,6 +32,7 @@ extern "C" { */ enum pcmk__time_fmt_flags { pcmk__time_fmt_date = (UINT32_C(1) << 0), + pcmk__time_fmt_time = (UINT32_C(1) << 1), }; bool pcmk__time_valid_year(int year); diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index c3f6d1975a9..b92f1800787 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -440,7 +440,7 @@ valid_time(const crm_time_t *dt) static crm_time_t * parse_date(const char *date_str) { - const uint32_t flags = pcmk__time_fmt_date|crm_time_log_timeofday; + const uint32_t flags = pcmk__time_fmt_date|pcmk__time_fmt_time; const char *time_s = NULL; crm_time_t *dt = NULL; @@ -620,7 +620,7 @@ static crm_time_t * copy_time_to_utc(const crm_time_t *dt) { const uint32_t flags = pcmk__time_fmt_date - |crm_time_log_timeofday + |pcmk__time_fmt_time |crm_time_log_with_timezone; crm_time_t *utc = NULL; @@ -1068,7 +1068,7 @@ time_as_string_common(const crm_time_t *dt, int usec, uint32_t flags) } } - if (pcmk__is_set(flags, crm_time_log_timeofday)) { + if (pcmk__is_set(flags, pcmk__time_fmt_time)) { uint32_t h = 0, m = 0, s = 0; if (buf->len > 0) { @@ -1360,7 +1360,7 @@ void pcmk__set_time_if_earlier(crm_time_t *target, const crm_time_t *source) { const int flags = pcmk__time_fmt_date - |crm_time_log_timeofday + |pcmk__time_fmt_time |crm_time_log_with_timezone; if ((target == NULL) @@ -2242,7 +2242,7 @@ void crm_time_set(crm_time_t *target, const crm_time_t *source) { const uint32_t flags = pcmk__time_fmt_date - |crm_time_log_timeofday + |pcmk__time_fmt_time |crm_time_log_with_timezone; pcmk__trace("target=%p, source=%p", target, source); diff --git a/lib/common/tls.c b/lib/common/tls.c index f9bab37348d..1d834a59812 100644 --- a/lib/common/tls.c +++ b/lib/common/tls.c @@ -474,8 +474,7 @@ pcmk__tls_check_cert_expiration(gnutls_session_t session) crm_time_t *expiry_t = pcmk__copy_timet(expiry); pcmk__time_log(LOG_WARNING, "TLS certificate will expire on", - expiry_t, - pcmk__time_fmt_date|crm_time_log_timeofday); + expiry_t, pcmk__time_fmt_date|pcmk__time_fmt_time); crm_time_free(expiry_t); } } diff --git a/lib/fencing/st_output.c b/lib/fencing/st_output.c index d666a01fcd7..2573659cfa2 100644 --- a/lib/fencing/st_output.c +++ b/lib/fencing/st_output.c @@ -42,7 +42,7 @@ timespec_string(time_t sec, long nsec, bool show_usec) { return pcmk__timespec2str(&ts, pcmk__time_fmt_date - |crm_time_log_timeofday + |pcmk__time_fmt_time |crm_time_log_with_timezone |(show_usec? crm_time_usecs : 0)); } diff --git a/lib/pacemaker/pcmk_output.c b/lib/pacemaker/pcmk_output.c index a1cf3193ec4..12d0cd5148d 100644 --- a/lib/pacemaker/pcmk_output.c +++ b/lib/pacemaker/pcmk_output.c @@ -737,7 +737,7 @@ pacemakerd_health(pcmk__output_t *out, va_list args) if (last_updated != 0) { last_updated_s = pcmk__epoch2str(&last_updated, pcmk__time_fmt_date - |crm_time_log_timeofday + |pcmk__time_fmt_time |crm_time_log_with_timezone); } @@ -778,7 +778,7 @@ pacemakerd_health_html(pcmk__output_t *out, va_list args) if (last_updated != 0) { last_updated_s = pcmk__epoch2str(&last_updated, pcmk__time_fmt_date - |crm_time_log_timeofday + |pcmk__time_fmt_time |crm_time_log_with_timezone); } @@ -842,7 +842,7 @@ pacemakerd_health_xml(pcmk__output_t *out, va_list args) if (last_updated != 0) { last_updated_s = pcmk__epoch2str(&last_updated, pcmk__time_fmt_date - |crm_time_log_timeofday + |pcmk__time_fmt_time |crm_time_log_with_timezone); } diff --git a/lib/pacemaker/pcmk_simulate.c b/lib/pacemaker/pcmk_simulate.c index ae888326d50..7f318b3cfcb 100644 --- a/lib/pacemaker/pcmk_simulate.c +++ b/lib/pacemaker/pcmk_simulate.c @@ -498,7 +498,7 @@ static void set_effective_date(pcmk_scheduler_t *scheduler, bool print_original, const char *use_date) { - static const uint32_t flags = pcmk__time_fmt_date|crm_time_log_timeofday; + static const uint32_t flags = pcmk__time_fmt_date|pcmk__time_fmt_time; pcmk__output_t *out = scheduler->priv->out; time_t original_date = 0; diff --git a/lib/pengine/pe_output.c b/lib/pengine/pe_output.c index 290478eeee5..64cc85decd6 100644 --- a/lib/pengine/pe_output.c +++ b/lib/pengine/pe_output.c @@ -1649,7 +1649,7 @@ failed_action_xml(pcmk__output_t *out, va_list args) { char *interval_ms_s = NULL; char *rc_change = pcmk__epoch2str(&epoch, pcmk__time_fmt_date - |crm_time_log_timeofday + |pcmk__time_fmt_time |crm_time_log_with_timezone); pcmk__xe_get_guint(xml_op, PCMK_META_INTERVAL, &interval_ms); diff --git a/tools/crm_resource_ban.c b/tools/crm_resource_ban.c index 093a08e6607..89f2b14cc9a 100644 --- a/tools/crm_resource_ban.c +++ b/tools/crm_resource_ban.c @@ -24,7 +24,7 @@ parse_cli_lifetime(pcmk__output_t *out, const char *move_lifetime) crm_time_t *now = NULL; crm_time_t *later = NULL; crm_time_t *duration = NULL; - const uint32_t duration_flags = pcmk__time_fmt_date|crm_time_log_timeofday; + const uint32_t duration_flags = pcmk__time_fmt_date|pcmk__time_fmt_time; const uint32_t time_flags = duration_flags|crm_time_log_with_timezone; if (move_lifetime == NULL) { diff --git a/tools/iso8601.c b/tools/iso8601.c index fec74a14dc8..09fdd6b38ba 100644 --- a/tools/iso8601.c +++ b/tools/iso8601.c @@ -126,7 +126,7 @@ date_default(pcmk__output_t *out, va_list args) char *date_s = NULL; - opts |= pcmk__time_fmt_date|crm_time_log_timeofday; + opts |= pcmk__time_fmt_date|pcmk__time_fmt_time; date_s = pcmk__time_text(date, opts); out->info(out, "%s: %s", prefix, date_s); @@ -145,7 +145,7 @@ date_xml(pcmk__output_t *out, va_list args) char *date_s = NULL; - opts |= pcmk__time_fmt_date|crm_time_log_timeofday; + opts |= pcmk__time_fmt_date|pcmk__time_fmt_time; date_s = pcmk__time_text(date, opts); pcmk__output_create_xml_text_node(out, PCMK_XE_DATE, date_s); @@ -191,9 +191,7 @@ duration_ends_default(pcmk__output_t *out, va_list args) char *date_s = NULL; - opts |= pcmk__time_fmt_date - |crm_time_log_timeofday - |crm_time_log_with_timezone; + opts |= pcmk__time_fmt_date|pcmk__time_fmt_time|crm_time_log_with_timezone; date_s = pcmk__time_text(time, opts); out->info(out, "Duration ends at: %s", date_s); @@ -211,9 +209,7 @@ duration_ends_xml(pcmk__output_t *out, va_list args) char *date_s = NULL; - opts |= pcmk__time_fmt_date - |crm_time_log_timeofday - |crm_time_log_with_timezone; + opts |= pcmk__time_fmt_date|pcmk__time_fmt_time|crm_time_log_with_timezone; date_s = pcmk__time_text(time, opts); pcmk__output_create_xml_text_node(out, PCMK_XE_DURATION_ENDS, date_s); @@ -232,7 +228,7 @@ period_default(pcmk__output_t *out, va_list args) char *start_s = NULL; char *end_s = NULL; - opts |= pcmk__time_fmt_date|crm_time_log_timeofday; + opts |= pcmk__time_fmt_date|pcmk__time_fmt_time; start_s = pcmk__time_text(start, opts); if (start_s == NULL) { @@ -263,7 +259,7 @@ period_xml(pcmk__output_t *out, va_list args) char *start_s = NULL; char *end_s = NULL; - opts |= pcmk__time_fmt_date|crm_time_log_timeofday; + opts |= pcmk__time_fmt_date|pcmk__time_fmt_time; start_s = pcmk__time_text(start, opts); if (start_s == NULL) { @@ -516,7 +512,7 @@ main(int argc, char **argv) char *dt_s = pcmk__time_text(later, options.print_options |pcmk__time_fmt_date - |crm_time_log_timeofday); + |pcmk__time_fmt_time); if (!pcmk__str_eq(options.expected_s, dt_s, pcmk__str_casei)) { exit_code = CRM_EX_ERROR; goto done; @@ -529,7 +525,7 @@ main(int argc, char **argv) char *dt_s = pcmk__time_text(date_time, options.print_options |pcmk__time_fmt_date - |crm_time_log_timeofday); + |pcmk__time_fmt_time); if (!pcmk__str_eq(options.expected_s, dt_s, pcmk__str_casei)) { exit_code = CRM_EX_ERROR; From aa85aef3396c22b8276e1fcd25d6ca51fcb2030e Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 18:44:38 -0700 Subject: [PATCH 43/99] API: libcrmcommon: Deprecate crm_time_log_timeofday Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 1 - include/crm/common/iso8601_compat.h | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index ac6c5dd2c74..570e9de045b 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,7 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); void crm_time_free(crm_time_t * dt); -#define crm_time_log_timeofday 0x002 #define crm_time_log_with_timezone 0x004 #define crm_time_log_duration 0x008 diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index 70108907147..dc60ec7b94f 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -32,6 +32,9 @@ extern "C" { //! \deprecated Do not use #define crm_time_log_date 0x001 +//! \deprecated Do not use +#define crm_time_log_timeofday 0x002 + //! \deprecated Do not use typedef struct crm_time_period_s { crm_time_t *start; From 5dd68a3b26cd46d19eecb29944331843699fafe4 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 18:47:01 -0700 Subject: [PATCH 44/99] Refactor: libcrmcommon: New pcmk__time_fmt_timezone To replace crm_time_log_with_timezone. Signed-off-by: Reid Wahl --- include/crm/common/iso8601_internal.h | 1 + lib/common/iso8601.c | 12 +++++------- lib/fencing/st_output.c | 2 +- lib/pacemaker/pcmk_output.c | 6 +++--- lib/pengine/pe_output.c | 2 +- tools/crm_resource_ban.c | 2 +- tools/iso8601.c | 6 +++--- 7 files changed, 15 insertions(+), 16 deletions(-) diff --git a/include/crm/common/iso8601_internal.h b/include/crm/common/iso8601_internal.h index 04546bae9fb..60e716c03aa 100644 --- a/include/crm/common/iso8601_internal.h +++ b/include/crm/common/iso8601_internal.h @@ -33,6 +33,7 @@ extern "C" { enum pcmk__time_fmt_flags { pcmk__time_fmt_date = (UINT32_C(1) << 0), pcmk__time_fmt_time = (UINT32_C(1) << 1), + pcmk__time_fmt_timezone = (UINT32_C(1) << 2), }; bool pcmk__time_valid_year(int year); diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index b92f1800787..56bf014a5c1 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -621,7 +621,7 @@ copy_time_to_utc(const crm_time_t *dt) { const uint32_t flags = pcmk__time_fmt_date |pcmk__time_fmt_time - |crm_time_log_with_timezone; + |pcmk__time_fmt_timezone; crm_time_t *utc = NULL; pcmk__assert(dt != NULL); @@ -1027,7 +1027,7 @@ time_as_string_common(const crm_time_t *dt, int usec, uint32_t flags) } // Convert to UTC if local timezone was not requested - if ((dt->offset != 0) && !pcmk__is_set(flags, crm_time_log_with_timezone)) { + if ((dt->offset != 0) && !pcmk__is_set(flags, pcmk__time_fmt_timezone)) { utc = copy_time_to_utc(dt); dt = utc; } @@ -1085,9 +1085,7 @@ time_as_string_common(const crm_time_t *dt, int usec, uint32_t flags) } } - if (pcmk__is_set(flags, crm_time_log_with_timezone) - && (dt->offset != 0)) { - + if (pcmk__is_set(flags, pcmk__time_fmt_timezone) && (dt->offset != 0)) { seconds_to_hms(dt->offset, &h, &m, NULL); g_string_append_printf(buf, " %c%.2" PRIu32 ":%.2" PRIu32, ((dt->offset < 0)? '-' : '+'), h, m); @@ -1361,7 +1359,7 @@ pcmk__set_time_if_earlier(crm_time_t *target, const crm_time_t *source) { const int flags = pcmk__time_fmt_date |pcmk__time_fmt_time - |crm_time_log_with_timezone; + |pcmk__time_fmt_timezone; if ((target == NULL) || (source == NULL) @@ -2243,7 +2241,7 @@ crm_time_set(crm_time_t *target, const crm_time_t *source) { const uint32_t flags = pcmk__time_fmt_date |pcmk__time_fmt_time - |crm_time_log_with_timezone; + |pcmk__time_fmt_timezone; pcmk__trace("target=%p, source=%p", target, source); diff --git a/lib/fencing/st_output.c b/lib/fencing/st_output.c index 2573659cfa2..e854b7c011b 100644 --- a/lib/fencing/st_output.c +++ b/lib/fencing/st_output.c @@ -43,7 +43,7 @@ timespec_string(time_t sec, long nsec, bool show_usec) { return pcmk__timespec2str(&ts, pcmk__time_fmt_date |pcmk__time_fmt_time - |crm_time_log_with_timezone + |pcmk__time_fmt_timezone |(show_usec? crm_time_usecs : 0)); } diff --git a/lib/pacemaker/pcmk_output.c b/lib/pacemaker/pcmk_output.c index 12d0cd5148d..9095754e9f6 100644 --- a/lib/pacemaker/pcmk_output.c +++ b/lib/pacemaker/pcmk_output.c @@ -738,7 +738,7 @@ pacemakerd_health(pcmk__output_t *out, va_list args) last_updated_s = pcmk__epoch2str(&last_updated, pcmk__time_fmt_date |pcmk__time_fmt_time - |crm_time_log_with_timezone); + |pcmk__time_fmt_timezone); } rc = out->info(out, "Status of %s: '%s' (last updated %s)", @@ -779,7 +779,7 @@ pacemakerd_health_html(pcmk__output_t *out, va_list args) last_updated_s = pcmk__epoch2str(&last_updated, pcmk__time_fmt_date |pcmk__time_fmt_time - |crm_time_log_with_timezone); + |pcmk__time_fmt_timezone); } msg = pcmk__assert_asprintf("Status of %s: '%s' (last updated %s)", @@ -843,7 +843,7 @@ pacemakerd_health_xml(pcmk__output_t *out, va_list args) last_updated_s = pcmk__epoch2str(&last_updated, pcmk__time_fmt_date |pcmk__time_fmt_time - |crm_time_log_with_timezone); + |pcmk__time_fmt_timezone); } pcmk__output_create_xml_node(out, PCMK_XE_PACEMAKERD, diff --git a/lib/pengine/pe_output.c b/lib/pengine/pe_output.c index 64cc85decd6..ff2828a765e 100644 --- a/lib/pengine/pe_output.c +++ b/lib/pengine/pe_output.c @@ -1650,7 +1650,7 @@ failed_action_xml(pcmk__output_t *out, va_list args) { char *rc_change = pcmk__epoch2str(&epoch, pcmk__time_fmt_date |pcmk__time_fmt_time - |crm_time_log_with_timezone); + |pcmk__time_fmt_timezone); pcmk__xe_get_guint(xml_op, PCMK_META_INTERVAL, &interval_ms); interval_ms_s = pcmk__assert_asprintf("%u", interval_ms); diff --git a/tools/crm_resource_ban.c b/tools/crm_resource_ban.c index 89f2b14cc9a..f169660a85c 100644 --- a/tools/crm_resource_ban.c +++ b/tools/crm_resource_ban.c @@ -25,7 +25,7 @@ parse_cli_lifetime(pcmk__output_t *out, const char *move_lifetime) crm_time_t *later = NULL; crm_time_t *duration = NULL; const uint32_t duration_flags = pcmk__time_fmt_date|pcmk__time_fmt_time; - const uint32_t time_flags = duration_flags|crm_time_log_with_timezone; + const uint32_t time_flags = duration_flags|pcmk__time_fmt_timezone; if (move_lifetime == NULL) { return NULL; diff --git a/tools/iso8601.c b/tools/iso8601.c index 09fdd6b38ba..0a553228230 100644 --- a/tools/iso8601.c +++ b/tools/iso8601.c @@ -55,7 +55,7 @@ modifier_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError } else if (pcmk__str_any_of(option_name, "--epoch", "-S", NULL)) { options.print_options |= crm_time_epoch; } else if (pcmk__str_any_of(option_name, "--local", "-L", NULL)) { - options.print_options |= crm_time_log_with_timezone; + options.print_options |= pcmk__time_fmt_timezone; } else if (pcmk__str_any_of(option_name, "--ordinal", "-O", NULL)) { options.print_options |= crm_time_ordinal; } else if (pcmk__str_any_of(option_name, "--week", "-W", NULL)) { @@ -191,7 +191,7 @@ duration_ends_default(pcmk__output_t *out, va_list args) char *date_s = NULL; - opts |= pcmk__time_fmt_date|pcmk__time_fmt_time|crm_time_log_with_timezone; + opts |= pcmk__time_fmt_date|pcmk__time_fmt_time|pcmk__time_fmt_timezone; date_s = pcmk__time_text(time, opts); out->info(out, "Duration ends at: %s", date_s); @@ -209,7 +209,7 @@ duration_ends_xml(pcmk__output_t *out, va_list args) char *date_s = NULL; - opts |= pcmk__time_fmt_date|pcmk__time_fmt_time|crm_time_log_with_timezone; + opts |= pcmk__time_fmt_date|pcmk__time_fmt_time|pcmk__time_fmt_timezone; date_s = pcmk__time_text(time, opts); pcmk__output_create_xml_text_node(out, PCMK_XE_DURATION_ENDS, date_s); From d5379fdb915d7fd049d5d82a5026572b4146e26e Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 18:47:29 -0700 Subject: [PATCH 45/99] API: libcrmcommon: Deprecate crm_time_log_with_timezone Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 1 - include/crm/common/iso8601_compat.h | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 570e9de045b..214ed30abbc 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,7 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); void crm_time_free(crm_time_t * dt); -#define crm_time_log_with_timezone 0x004 #define crm_time_log_duration 0x008 #define crm_time_ordinal 0x010 diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index dc60ec7b94f..784371b1e75 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -35,6 +35,9 @@ extern "C" { //! \deprecated Do not use #define crm_time_log_timeofday 0x002 +//! \deprecated Do not use +#define crm_time_log_with_timezone 0x004 + //! \deprecated Do not use typedef struct crm_time_period_s { crm_time_t *start; From 02a69e582ad0fc4a1ce1ca03ee9622e10befab19 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 18:49:53 -0700 Subject: [PATCH 46/99] Refactor: libcrmcommon: New pcmk__time_fmt_duration To replace crm_time_log_duration. Signed-off-by: Reid Wahl --- include/crm/common/iso8601_internal.h | 3 +++ lib/common/iso8601.c | 2 +- tools/iso8601.c | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/crm/common/iso8601_internal.h b/include/crm/common/iso8601_internal.h index 60e716c03aa..160b9a5d747 100644 --- a/include/crm/common/iso8601_internal.h +++ b/include/crm/common/iso8601_internal.h @@ -34,6 +34,9 @@ enum pcmk__time_fmt_flags { pcmk__time_fmt_date = (UINT32_C(1) << 0), pcmk__time_fmt_time = (UINT32_C(1) << 1), pcmk__time_fmt_timezone = (UINT32_C(1) << 2), + + // @COMPAT Nothing sets this internally except tools/iso8601.c (deprecated) + pcmk__time_fmt_duration = (UINT32_C(1) << 3), }; bool pcmk__time_valid_year(int year); diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 56bf014a5c1..6fe785d11fc 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1004,7 +1004,7 @@ time_as_string_common(const crm_time_t *dt, int usec, uint32_t flags) * These never depend on time zone. */ - if (pcmk__is_set(flags, crm_time_log_duration)) { + if (pcmk__is_set(flags, pcmk__time_fmt_duration)) { duration_as_string(dt, usec, pcmk__is_set(flags, crm_time_usecs), buf); goto done; } diff --git a/tools/iso8601.c b/tools/iso8601.c index 0a553228230..b5bf6bde081 100644 --- a/tools/iso8601.c +++ b/tools/iso8601.c @@ -160,7 +160,7 @@ duration_default(pcmk__output_t *out, va_list args) crm_time_t *time = va_arg(args, crm_time_t *); int opts = va_arg(args, int); - char *date_s = pcmk__time_text(time, opts|crm_time_log_duration); + char *date_s = pcmk__time_text(time, opts|pcmk__time_fmt_duration); out->info(out, "Duration: %s", date_s); @@ -175,7 +175,7 @@ duration_xml(pcmk__output_t *out, va_list args) crm_time_t *time = va_arg(args, crm_time_t *); int opts = va_arg(args, int); - char *date_s = pcmk__time_text(time, opts|crm_time_log_duration); + char *date_s = pcmk__time_text(time, opts|pcmk__time_fmt_duration); pcmk__output_create_xml_text_node(out, PCMK_XE_DURATION, date_s); free(date_s); From c48c4df2e986d6d285c303f9bef534997869fea1 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 18:50:22 -0700 Subject: [PATCH 47/99] API: libcrmcommon: Deprecate crm_time_log_duration Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 2 -- include/crm/common/iso8601_compat.h | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 214ed30abbc..ae7ce172ca9 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,8 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); void crm_time_free(crm_time_t * dt); -#define crm_time_log_duration 0x008 - #define crm_time_ordinal 0x010 #define crm_time_weeks 0x020 #define crm_time_seconds 0x100 diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index 784371b1e75..a0f839fb792 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -38,6 +38,9 @@ extern "C" { //! \deprecated Do not use #define crm_time_log_with_timezone 0x004 +//! \deprecated Do not use +#define crm_time_log_duration 0x008 + //! \deprecated Do not use typedef struct crm_time_period_s { crm_time_t *start; From 0bafb59c772f690223d3f0e91417b09cc1676d64 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 18:51:40 -0700 Subject: [PATCH 48/99] Refactor: libcrmcommon: New pcmk__time_fmt_ordinal To replace crm_time_ordinal. Signed-off-by: Reid Wahl --- include/crm/common/iso8601_internal.h | 3 +++ lib/common/iso8601.c | 2 +- tools/iso8601.c | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/crm/common/iso8601_internal.h b/include/crm/common/iso8601_internal.h index 160b9a5d747..0fdb1a3c3c2 100644 --- a/include/crm/common/iso8601_internal.h +++ b/include/crm/common/iso8601_internal.h @@ -37,6 +37,9 @@ enum pcmk__time_fmt_flags { // @COMPAT Nothing sets this internally except tools/iso8601.c (deprecated) pcmk__time_fmt_duration = (UINT32_C(1) << 3), + + // @COMPAT Nothing sets this internally except tools/iso8601.c (deprecated) + pcmk__time_fmt_ordinal = (UINT32_C(1) << 4), }; bool pcmk__time_valid_year(int year); diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 6fe785d11fc..c95520bd913 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1047,7 +1047,7 @@ time_as_string_common(const crm_time_t *dt, int usec, uint32_t flags) y, w, d); } - } else if (pcmk__is_set(flags, crm_time_ordinal)) { // YYYY-DDD + } else if (pcmk__is_set(flags, pcmk__time_fmt_ordinal)) { // YYYY-DDD uint32_t y = 0; uint32_t d = 0; diff --git a/tools/iso8601.c b/tools/iso8601.c index b5bf6bde081..e5b950c66e2 100644 --- a/tools/iso8601.c +++ b/tools/iso8601.c @@ -57,7 +57,7 @@ modifier_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError } else if (pcmk__str_any_of(option_name, "--local", "-L", NULL)) { options.print_options |= pcmk__time_fmt_timezone; } else if (pcmk__str_any_of(option_name, "--ordinal", "-O", NULL)) { - options.print_options |= crm_time_ordinal; + options.print_options |= pcmk__time_fmt_ordinal; } else if (pcmk__str_any_of(option_name, "--week", "-W", NULL)) { options.print_options |= crm_time_weeks; } From 709477035e9792fb82f8901c4db275456ee8ce47 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 18:52:11 -0700 Subject: [PATCH 49/99] API: libcrmcommon: Deprecate crm_time_ordinal Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 1 - include/crm/common/iso8601_compat.h | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index ae7ce172ca9..44e618195c1 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,7 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); void crm_time_free(crm_time_t * dt); -#define crm_time_ordinal 0x010 #define crm_time_weeks 0x020 #define crm_time_seconds 0x100 #define crm_time_epoch 0x200 diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index a0f839fb792..4d1dc5271bd 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -41,6 +41,9 @@ extern "C" { //! \deprecated Do not use #define crm_time_log_duration 0x008 +//! \deprecated Do not use +#define crm_time_ordinal 0x010 + //! \deprecated Do not use typedef struct crm_time_period_s { crm_time_t *start; From c1cff6330b852d35d6179503fcb1895e1562b26f Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 18:54:04 -0700 Subject: [PATCH 50/99] Refactor: libcrmcommon: New pcmk__time_fmt_weeks To replace crm_time_weeks. Signed-off-by: Reid Wahl --- include/crm/common/iso8601_internal.h | 3 +++ lib/common/iso8601.c | 2 +- tools/iso8601.c | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/crm/common/iso8601_internal.h b/include/crm/common/iso8601_internal.h index 0fdb1a3c3c2..ba3646b3d8a 100644 --- a/include/crm/common/iso8601_internal.h +++ b/include/crm/common/iso8601_internal.h @@ -40,6 +40,9 @@ enum pcmk__time_fmt_flags { // @COMPAT Nothing sets this internally except tools/iso8601.c (deprecated) pcmk__time_fmt_ordinal = (UINT32_C(1) << 4), + + // @COMPAT Nothing sets this internally except tools/iso8601.c (deprecated) + pcmk__time_fmt_weeks = (UINT32_C(1) << 5), }; bool pcmk__time_valid_year(int year); diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index c95520bd913..4d2f65195f9 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1035,7 +1035,7 @@ time_as_string_common(const crm_time_t *dt, int usec, uint32_t flags) // As readable string if (pcmk__is_set(flags, pcmk__time_fmt_date)) { - if (pcmk__is_set(flags, crm_time_weeks)) { // YYYY-WW-D + if (pcmk__is_set(flags, pcmk__time_fmt_weeks)) { // YYYY-WW-D if (dt->days > 0) { uint32_t y = 0; uint32_t w = 0; diff --git a/tools/iso8601.c b/tools/iso8601.c index e5b950c66e2..34f845377e7 100644 --- a/tools/iso8601.c +++ b/tools/iso8601.c @@ -59,7 +59,7 @@ modifier_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError } else if (pcmk__str_any_of(option_name, "--ordinal", "-O", NULL)) { options.print_options |= pcmk__time_fmt_ordinal; } else if (pcmk__str_any_of(option_name, "--week", "-W", NULL)) { - options.print_options |= crm_time_weeks; + options.print_options |= pcmk__time_fmt_weeks; } return TRUE; From 26f882dbc8881367e178b3801b300bb5be39ead2 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 18:54:26 -0700 Subject: [PATCH 51/99] API: libcrmcommon: Deprecate crm_time_weeks Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 1 - include/crm/common/iso8601_compat.h | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 44e618195c1..1fac69d4a77 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,7 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); void crm_time_free(crm_time_t * dt); -#define crm_time_weeks 0x020 #define crm_time_seconds 0x100 #define crm_time_epoch 0x200 #define crm_time_usecs 0x400 diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index 4d1dc5271bd..29af2fea30a 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -44,6 +44,9 @@ extern "C" { //! \deprecated Do not use #define crm_time_ordinal 0x010 +//! \deprecated Do not use +#define crm_time_weeks 0x020 + //! \deprecated Do not use typedef struct crm_time_period_s { crm_time_t *start; From 6ef57d00b9166b1bd9406e039b5a5dfb333fe307 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 18:56:33 -0700 Subject: [PATCH 52/99] Refactor: libcrmcommon: New pcmk__time_fmt_seconds To replace crm_time_seconds. Signed-off-by: Reid Wahl --- include/crm/common/iso8601_internal.h | 3 +++ lib/common/iso8601.c | 4 ++-- tools/iso8601.c | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/crm/common/iso8601_internal.h b/include/crm/common/iso8601_internal.h index ba3646b3d8a..aa141c4ae3e 100644 --- a/include/crm/common/iso8601_internal.h +++ b/include/crm/common/iso8601_internal.h @@ -43,6 +43,9 @@ enum pcmk__time_fmt_flags { // @COMPAT Nothing sets this internally except tools/iso8601.c (deprecated) pcmk__time_fmt_weeks = (UINT32_C(1) << 5), + + // @COMPAT Nothing sets this internally except tools/iso8601.c (deprecated) + pcmk__time_fmt_seconds = (UINT32_C(1) << 8), }; bool pcmk__time_valid_year(int year); diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 4d2f65195f9..da6a6f84ef4 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1009,10 +1009,10 @@ time_as_string_common(const crm_time_t *dt, int usec, uint32_t flags) goto done; } - if (pcmk__any_flags_set(flags, crm_time_seconds|crm_time_epoch)) { + if (pcmk__any_flags_set(flags, pcmk__time_fmt_seconds|crm_time_epoch)) { long long seconds = 0; - if (pcmk__is_set(flags, crm_time_seconds)) { + if (pcmk__is_set(flags, pcmk__time_fmt_seconds)) { seconds = crm_time_get_seconds(dt); } else { seconds = crm_time_get_seconds_since_epoch(dt); diff --git a/tools/iso8601.c b/tools/iso8601.c index 34f845377e7..5be9613ed14 100644 --- a/tools/iso8601.c +++ b/tools/iso8601.c @@ -51,7 +51,7 @@ date_now_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError static gboolean modifier_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) { if (pcmk__str_any_of(option_name, "--seconds", "-s", NULL)) { - options.print_options |= crm_time_seconds; + options.print_options |= pcmk__time_fmt_seconds; } else if (pcmk__str_any_of(option_name, "--epoch", "-S", NULL)) { options.print_options |= crm_time_epoch; } else if (pcmk__str_any_of(option_name, "--local", "-L", NULL)) { From f6166d74f579edb9446decd98b04f3ef80da245b Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 18:57:07 -0700 Subject: [PATCH 53/99] API: libcrmcommon: Deprecate crm_time_seconds Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 1 - include/crm/common/iso8601_compat.h | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 1fac69d4a77..744dd1d2117 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,7 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); void crm_time_free(crm_time_t * dt); -#define crm_time_seconds 0x100 #define crm_time_epoch 0x200 #define crm_time_usecs 0x400 diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index 29af2fea30a..3085a52c0f3 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -47,6 +47,9 @@ extern "C" { //! \deprecated Do not use #define crm_time_weeks 0x020 +//! \deprecated Do not use +#define crm_time_seconds 0x100 + //! \deprecated Do not use typedef struct crm_time_period_s { crm_time_t *start; From 6bc12fa1fde0aaeee134aab340b167c42c53b64c Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 18:58:17 -0700 Subject: [PATCH 54/99] Refactor: libcrmcommon: New pcmk__time_fmt_epoch To replace crm_time_epoch. Signed-off-by: Reid Wahl --- include/crm/common/iso8601_internal.h | 3 +++ lib/common/iso8601.c | 3 ++- tools/iso8601.c | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/crm/common/iso8601_internal.h b/include/crm/common/iso8601_internal.h index aa141c4ae3e..1394e6baeff 100644 --- a/include/crm/common/iso8601_internal.h +++ b/include/crm/common/iso8601_internal.h @@ -46,6 +46,9 @@ enum pcmk__time_fmt_flags { // @COMPAT Nothing sets this internally except tools/iso8601.c (deprecated) pcmk__time_fmt_seconds = (UINT32_C(1) << 8), + + // @COMPAT Nothing sets this internally except tools/iso8601.c (deprecated) + pcmk__time_fmt_epoch = (UINT32_C(1) << 9), }; bool pcmk__time_valid_year(int year); diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index da6a6f84ef4..9abbba5d1d2 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1009,7 +1009,8 @@ time_as_string_common(const crm_time_t *dt, int usec, uint32_t flags) goto done; } - if (pcmk__any_flags_set(flags, pcmk__time_fmt_seconds|crm_time_epoch)) { + if (pcmk__any_flags_set(flags, + pcmk__time_fmt_seconds|pcmk__time_fmt_epoch)) { long long seconds = 0; if (pcmk__is_set(flags, pcmk__time_fmt_seconds)) { diff --git a/tools/iso8601.c b/tools/iso8601.c index 5be9613ed14..a9366436a63 100644 --- a/tools/iso8601.c +++ b/tools/iso8601.c @@ -53,7 +53,7 @@ modifier_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError if (pcmk__str_any_of(option_name, "--seconds", "-s", NULL)) { options.print_options |= pcmk__time_fmt_seconds; } else if (pcmk__str_any_of(option_name, "--epoch", "-S", NULL)) { - options.print_options |= crm_time_epoch; + options.print_options |= pcmk__time_fmt_epoch; } else if (pcmk__str_any_of(option_name, "--local", "-L", NULL)) { options.print_options |= pcmk__time_fmt_timezone; } else if (pcmk__str_any_of(option_name, "--ordinal", "-O", NULL)) { From b27ba53df2fa25d7f54911ccd6282a2f40c3740d Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 18:58:40 -0700 Subject: [PATCH 55/99] API: libcrmcommon: Deprecate crm_time_epoch Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 1 - include/crm/common/iso8601_compat.h | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 744dd1d2117..9a7192d0fb4 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,7 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); void crm_time_free(crm_time_t * dt); -#define crm_time_epoch 0x200 #define crm_time_usecs 0x400 int crm_time_compare(const crm_time_t *a, const crm_time_t *b); diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index 3085a52c0f3..5c7b4471616 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -50,6 +50,9 @@ extern "C" { //! \deprecated Do not use #define crm_time_seconds 0x100 +//! \deprecated Do not use +#define crm_time_epoch 0x200 + //! \deprecated Do not use typedef struct crm_time_period_s { crm_time_t *start; From 1183df5932a9dcbd033499bbd0400e4e68dbe12d Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 19:01:59 -0700 Subject: [PATCH 56/99] Refactor: libcrmcommon: New pcmk__time_fmt_usecs To replace crm_time_usecs. Signed-off-by: Reid Wahl --- include/crm/common/iso8601_internal.h | 2 ++ lib/common/iso8601.c | 11 ++++++----- lib/fencing/st_output.c | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/include/crm/common/iso8601_internal.h b/include/crm/common/iso8601_internal.h index 1394e6baeff..39019a3bc60 100644 --- a/include/crm/common/iso8601_internal.h +++ b/include/crm/common/iso8601_internal.h @@ -49,6 +49,8 @@ enum pcmk__time_fmt_flags { // @COMPAT Nothing sets this internally except tools/iso8601.c (deprecated) pcmk__time_fmt_epoch = (UINT32_C(1) << 9), + + pcmk__time_fmt_usecs = (UINT32_C(1) << 10), }; bool pcmk__time_valid_year(int year); diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 9abbba5d1d2..2745a09477f 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1005,7 +1005,8 @@ time_as_string_common(const crm_time_t *dt, int usec, uint32_t flags) */ if (pcmk__is_set(flags, pcmk__time_fmt_duration)) { - duration_as_string(dt, usec, pcmk__is_set(flags, crm_time_usecs), buf); + duration_as_string(dt, usec, pcmk__is_set(flags, pcmk__time_fmt_usecs), + buf); goto done; } @@ -1019,7 +1020,7 @@ time_as_string_common(const crm_time_t *dt, int usec, uint32_t flags) seconds = crm_time_get_seconds_since_epoch(dt); } - if (pcmk__is_set(flags, crm_time_usecs)) { + if (pcmk__is_set(flags, pcmk__time_fmt_usecs)) { sec_usec_as_string(seconds, usec, buf); } else { g_string_append_printf(buf, "%lld", seconds); @@ -1081,7 +1082,7 @@ time_as_string_common(const crm_time_t *dt, int usec, uint32_t flags) "%.2" PRIu32 ":%.2" PRIu32 ":%.2" PRIu32, h, m, s); - if (pcmk__is_set(flags, crm_time_usecs)) { + if (pcmk__is_set(flags, pcmk__time_fmt_usecs)) { g_string_append_printf(buf, ".%06" PRIu32, QB_ABS(usec)); } } @@ -2109,8 +2110,8 @@ pcmk__epoch2str(const time_t *source, uint32_t flags) * \brief Return a human-friendly string corresponding to seconds-and- * nanoseconds value * - * Time is shown with microsecond resolution if \p crm_time_usecs is in \p - * flags. + * Time is shown with microsecond resolution if \c pcmk__time_fmt_usecs is in + * \p flags. * * \param[in] ts Time in seconds and nanoseconds (or \p NULL for current * time) diff --git a/lib/fencing/st_output.c b/lib/fencing/st_output.c index e854b7c011b..d779b993a65 100644 --- a/lib/fencing/st_output.c +++ b/lib/fencing/st_output.c @@ -44,7 +44,7 @@ timespec_string(time_t sec, long nsec, bool show_usec) { pcmk__time_fmt_date |pcmk__time_fmt_time |pcmk__time_fmt_timezone - |(show_usec? crm_time_usecs : 0)); + |(show_usec? pcmk__time_fmt_usecs : 0)); } /*! From 033c4ba22e9f0ca834e9b4d90f52681da6c1b14f Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 19:02:23 -0700 Subject: [PATCH 57/99] API: libcrmcommon: Deprecate crm_time_usecs Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 2 -- include/crm/common/iso8601_compat.h | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 9a7192d0fb4..66aa47e93f0 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,8 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); void crm_time_free(crm_time_t * dt); -#define crm_time_usecs 0x400 - int crm_time_compare(const crm_time_t *a, const crm_time_t *b); int crm_time_get_timeofday(const crm_time_t *dt, uint32_t *h, uint32_t *m, diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index 5c7b4471616..5065d58da5d 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -53,6 +53,9 @@ extern "C" { //! \deprecated Do not use #define crm_time_epoch 0x200 +//! \deprecated Do not use +#define crm_time_usecs 0x400 + //! \deprecated Do not use typedef struct crm_time_period_s { crm_time_t *start; From 2b97bc381d779797177b57f98cdbd410f67a8894 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 19:06:37 -0700 Subject: [PATCH 58/99] Refactor: libcrmcommon: New pcmk__time_compare() To replace crm_time_compare(). Signed-off-by: Reid Wahl --- include/crm/common/iso8601_internal.h | 2 ++ lib/common/iso8601.c | 10 +++++-- lib/common/rules.c | 8 +++--- .../tests/iso8601/crm_time_add_days_test.c | 4 +-- .../tests/iso8601/crm_time_add_seconds_test.c | 4 +-- .../tests/iso8601/crm_time_add_years_test.c | 4 +-- .../iso8601/pcmk__add_time_from_xml_test.c | 26 +++++++++---------- .../iso8601/pcmk__set_time_if_earlier_test.c | 8 +++--- .../nvpair/pcmk__unpack_nvpair_blocks_test.c | 2 +- .../rules/pcmk__evaluate_condition_test.c | 2 +- .../pcmk__evaluate_date_expression_test.c | 4 +-- .../tests/rules/pcmk__unpack_duration_test.c | 4 +-- .../xml_element/pcmk__xe_get_datetime_test.c | 2 +- tools/crm_resource_ban.c | 2 +- 14 files changed, 45 insertions(+), 37 deletions(-) diff --git a/include/crm/common/iso8601_internal.h b/include/crm/common/iso8601_internal.h index 39019a3bc60..be5a117644a 100644 --- a/include/crm/common/iso8601_internal.h +++ b/include/crm/common/iso8601_internal.h @@ -66,6 +66,8 @@ const char *pcmk__readable_interval(guint interval_ms); crm_time_t *pcmk__time_parse_duration(const char *period_s); crm_time_t *pcmk__copy_timet(time_t source_sec); +int pcmk__time_compare(const crm_time_t *a, const crm_time_t *b); + void pcmk__time_log_as(const char *file, const char *function, int line, uint8_t level, const char *prefix, const crm_time_t *dt, uint32_t flags); diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 2745a09477f..1534f8de52e 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1366,7 +1366,7 @@ pcmk__set_time_if_earlier(crm_time_t *target, const crm_time_t *source) if ((target == NULL) || (source == NULL) || (pcmk__time_is_initialized(target) - && (crm_time_compare(source, target) >= 0))) { + && (pcmk__time_compare(source, target) >= 0))) { return; } @@ -1650,7 +1650,7 @@ crm_time_subtract(const crm_time_t *dt, const crm_time_t *value) } int -crm_time_compare(const crm_time_t *a, const crm_time_t *b) +pcmk__time_compare(const crm_time_t *a, const crm_time_t *b) { int rc = 0; crm_time_t *t1 = NULL; @@ -1678,6 +1678,12 @@ crm_time_compare(const crm_time_t *a, const crm_time_t *b) return rc; } +int +crm_time_compare(const crm_time_t *a, const crm_time_t *b) +{ + return pcmk__time_compare(a, b); +} + /*! * \brief Add a given number of seconds to a date/time or duration * diff --git a/lib/common/rules.c b/lib/common/rules.c index 9a7bff73ae5..981e0a03124 100644 --- a/lib/common/rules.c +++ b/lib/common/rules.c @@ -332,7 +332,7 @@ evaluate_in_range(const xmlNode *date_expression, const char *id, } } - if ((start != NULL) && (crm_time_compare(now, start) < 0)) { + if ((start != NULL) && (pcmk__time_compare(now, start) < 0)) { pcmk__set_time_if_earlier(next_change, start); crm_time_free(start); crm_time_free(end); @@ -340,7 +340,7 @@ evaluate_in_range(const xmlNode *date_expression, const char *id, } if (end != NULL) { - if (crm_time_compare(now, end) > 0) { + if (pcmk__time_compare(now, end) > 0) { crm_time_free(start); crm_time_free(end); return pcmk_rc_after_range; @@ -392,7 +392,7 @@ evaluate_gt(const xmlNode *date_expression, const char *id, return pcmk_rc_unpack_error; } - if (crm_time_compare(now, start) > 0) { + if (pcmk__time_compare(now, start) > 0) { crm_time_free(start); return pcmk_rc_within_range; } @@ -437,7 +437,7 @@ evaluate_lt(const xmlNode *date_expression, const char *id, return pcmk_rc_unpack_error; } - if (crm_time_compare(now, end) < 0) { + if (pcmk__time_compare(now, end) < 0) { pcmk__set_time_if_earlier(next_change, end); crm_time_free(end); return pcmk_rc_within_range; diff --git a/lib/common/tests/iso8601/crm_time_add_days_test.c b/lib/common/tests/iso8601/crm_time_add_days_test.c index c9ad3616d78..b7995355b48 100644 --- a/lib/common/tests/iso8601/crm_time_add_days_test.c +++ b/lib/common/tests/iso8601/crm_time_add_days_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 the Pacemaker project contributors + * Copyright 2024-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -27,7 +27,7 @@ assert_add_days(const char *orig_date_time, int days, assert_non_null(expected); crm_time_add_days(orig, days); - assert_int_equal(crm_time_compare(orig, expected), 0); + assert_int_equal(pcmk__time_compare(orig, expected), 0); crm_time_free(orig); crm_time_free(expected); diff --git a/lib/common/tests/iso8601/crm_time_add_seconds_test.c b/lib/common/tests/iso8601/crm_time_add_seconds_test.c index 4315d7dcb5d..6cb957e689b 100644 --- a/lib/common/tests/iso8601/crm_time_add_seconds_test.c +++ b/lib/common/tests/iso8601/crm_time_add_seconds_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 the Pacemaker project contributors + * Copyright 2024-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -27,7 +27,7 @@ assert_add_seconds(const char *orig_date_time, int seconds, assert_non_null(expected); crm_time_add_seconds(orig, seconds); - assert_int_equal(crm_time_compare(orig, expected), 0); + assert_int_equal(pcmk__time_compare(orig, expected), 0); crm_time_free(orig); crm_time_free(expected); diff --git a/lib/common/tests/iso8601/crm_time_add_years_test.c b/lib/common/tests/iso8601/crm_time_add_years_test.c index 8ea6b4d1c46..35831673cdb 100644 --- a/lib/common/tests/iso8601/crm_time_add_years_test.c +++ b/lib/common/tests/iso8601/crm_time_add_years_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 the Pacemaker project contributors + * Copyright 2024-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -27,7 +27,7 @@ assert_add_years(const char *orig_date_time, int years, assert_non_null(expected); crm_time_add_years(orig, years); - assert_int_equal(crm_time_compare(orig, expected), 0); + assert_int_equal(pcmk__time_compare(orig, expected), 0); crm_time_free(orig); crm_time_free(expected); diff --git a/lib/common/tests/iso8601/pcmk__add_time_from_xml_test.c b/lib/common/tests/iso8601/pcmk__add_time_from_xml_test.c index fa7f6ab183e..ebea2842ab6 100644 --- a/lib/common/tests/iso8601/pcmk__add_time_from_xml_test.c +++ b/lib/common/tests/iso8601/pcmk__add_time_from_xml_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 the Pacemaker project contributors + * Copyright 2024-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -45,7 +45,7 @@ null_xml_ok(void **state) assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_years, NULL), pcmk_rc_ok); - assert_int_equal(crm_time_compare(t, reference), 0); + assert_int_equal(pcmk__time_compare(t, reference), 0); crm_time_free(t); crm_time_free(reference); @@ -70,7 +70,7 @@ missing_attr(void **state) assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_months, xml), pcmk_rc_ok); - assert_int_equal(crm_time_compare(t, reference), 0); + assert_int_equal(pcmk__time_compare(t, reference), 0); crm_time_free(t); crm_time_free(reference); @@ -86,7 +86,7 @@ invalid_attr(void **state) assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_years, xml), pcmk_rc_unpack_error); - assert_int_equal(crm_time_compare(t, reference), 0); + assert_int_equal(pcmk__time_compare(t, reference), 0); crm_time_free(t); crm_time_free(reference); @@ -102,12 +102,12 @@ out_of_range_attr(void **state) xml = pcmk__xml_parse(YEARS_TOO_BIG); assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_years, xml), ERANGE); - assert_int_equal(crm_time_compare(t, reference), 0); + assert_int_equal(pcmk__time_compare(t, reference), 0); pcmk__xml_free(xml); xml = pcmk__xml_parse(YEARS_TOO_SMALL); assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_years, xml), ERANGE); - assert_int_equal(crm_time_compare(t, reference), 0); + assert_int_equal(pcmk__time_compare(t, reference), 0); pcmk__xml_free(xml); crm_time_free(t); @@ -123,7 +123,7 @@ add_years(void **state) assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_years, xml), pcmk_rc_ok); - assert_int_equal(crm_time_compare(t, reference), 0); + assert_int_equal(pcmk__time_compare(t, reference), 0); crm_time_free(t); crm_time_free(reference); @@ -139,7 +139,7 @@ add_months(void **state) assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_months, xml), pcmk_rc_ok); - assert_int_equal(crm_time_compare(t, reference), 0); + assert_int_equal(pcmk__time_compare(t, reference), 0); crm_time_free(t); crm_time_free(reference); @@ -155,7 +155,7 @@ add_weeks(void **state) assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_weeks, xml), pcmk_rc_ok); - assert_int_equal(crm_time_compare(t, reference), 0); + assert_int_equal(pcmk__time_compare(t, reference), 0); crm_time_free(t); crm_time_free(reference); @@ -171,7 +171,7 @@ add_days(void **state) assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_days, xml), pcmk_rc_ok); - assert_int_equal(crm_time_compare(t, reference), 0); + assert_int_equal(pcmk__time_compare(t, reference), 0); crm_time_free(t); crm_time_free(reference); @@ -187,7 +187,7 @@ add_hours(void **state) assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_hours, xml), pcmk_rc_ok); - assert_int_equal(crm_time_compare(t, reference), 0); + assert_int_equal(pcmk__time_compare(t, reference), 0); crm_time_free(t); crm_time_free(reference); @@ -203,7 +203,7 @@ add_minutes(void **state) assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_minutes, xml), pcmk_rc_ok); - assert_int_equal(crm_time_compare(t, reference), 0); + assert_int_equal(pcmk__time_compare(t, reference), 0); crm_time_free(t); crm_time_free(reference); @@ -219,7 +219,7 @@ add_seconds(void **state) assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_seconds, xml), pcmk_rc_ok); - assert_int_equal(crm_time_compare(t, reference), 0); + assert_int_equal(pcmk__time_compare(t, reference), 0); crm_time_free(t); crm_time_free(reference); diff --git a/lib/common/tests/iso8601/pcmk__set_time_if_earlier_test.c b/lib/common/tests/iso8601/pcmk__set_time_if_earlier_test.c index 79821c3de2e..86d82cb8bab 100644 --- a/lib/common/tests/iso8601/pcmk__set_time_if_earlier_test.c +++ b/lib/common/tests/iso8601/pcmk__set_time_if_earlier_test.c @@ -26,7 +26,7 @@ null_ok(void **state) // Shouldn't assert, crash, or change target pcmk__set_time_if_earlier(target, NULL); - assert_int_equal(crm_time_compare(target, target_copy), 0); + assert_int_equal(pcmk__time_compare(target, target_copy), 0); crm_time_free(target); crm_time_free(target_copy); @@ -39,7 +39,7 @@ target_undefined(void **state) crm_time_t *target = pcmk__assert_alloc(1, sizeof(crm_time_t)); pcmk__set_time_if_earlier(target, source); - assert_int_equal(crm_time_compare(target, source), 0); + assert_int_equal(pcmk__time_compare(target, source), 0); crm_time_free(source); crm_time_free(target); @@ -52,7 +52,7 @@ source_earlier(void **state) crm_time_t *target = crm_time_new("2024-01-01 00:30:00 +01:00"); pcmk__set_time_if_earlier(target, source); - assert_int_equal(crm_time_compare(target, source), 0); + assert_int_equal(pcmk__time_compare(target, source), 0); crm_time_free(source); crm_time_free(target); @@ -66,7 +66,7 @@ source_later(void **state) crm_time_t *target_copy = pcmk_copy_time(target); pcmk__set_time_if_earlier(target, source); - assert_int_equal(crm_time_compare(target, target_copy), 0); + assert_int_equal(pcmk__time_compare(target, target_copy), 0); crm_time_free(source); crm_time_free(target); diff --git a/lib/common/tests/nvpair/pcmk__unpack_nvpair_blocks_test.c b/lib/common/tests/nvpair/pcmk__unpack_nvpair_blocks_test.c index 6bea483f134..c2e9e7a9e9a 100644 --- a/lib/common/tests/nvpair/pcmk__unpack_nvpair_blocks_test.c +++ b/lib/common/tests/nvpair/pcmk__unpack_nvpair_blocks_test.c @@ -144,7 +144,7 @@ rule_fails(void **state) assert_string_equal(g_hash_table_lookup(values, "name1"), "3"); assert_string_equal(g_hash_table_lookup(values, "name2"), "3"); assert_string_equal(g_hash_table_lookup(values, "name3"), "3"); - assert_int_equal(crm_time_compare(next_change, expected_next_change), 0); + assert_int_equal(pcmk__time_compare(next_change, expected_next_change), 0); pcmk__xml_free(xml); crm_time_free(now); diff --git a/lib/common/tests/rules/pcmk__evaluate_condition_test.c b/lib/common/tests/rules/pcmk__evaluate_condition_test.c index 7327ad01fc9..32d1ab23048 100644 --- a/lib/common/tests/rules/pcmk__evaluate_condition_test.c +++ b/lib/common/tests/rules/pcmk__evaluate_condition_test.c @@ -130,7 +130,7 @@ date_expression(void **state) rule_input.now = now; assert_int_equal(pcmk__evaluate_condition(xml, &rule_input, next_change), pcmk_rc_before_range); - assert_int_equal(crm_time_compare(next_change, reference), 0); + assert_int_equal(pcmk__time_compare(next_change, reference), 0); rule_input.now = NULL; crm_time_free(reference); diff --git a/lib/common/tests/rules/pcmk__evaluate_date_expression_test.c b/lib/common/tests/rules/pcmk__evaluate_date_expression_test.c index cfb6bdbf7f5..bed8fc3e998 100644 --- a/lib/common/tests/rules/pcmk__evaluate_date_expression_test.c +++ b/lib/common/tests/rules/pcmk__evaluate_date_expression_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2024-2025 the Pacemaker project contributors + * Copyright 2024-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -52,7 +52,7 @@ assert_date_expression(const xmlNode *xml, const char *now_s, if (check_next_change) { crm_time_t *reference = crm_time_new(reference_s); - assert_int_equal(crm_time_compare(next_change, reference), 0); + assert_int_equal(pcmk__time_compare(next_change, reference), 0); crm_time_free(reference); crm_time_free(next_change); } diff --git a/lib/common/tests/rules/pcmk__unpack_duration_test.c b/lib/common/tests/rules/pcmk__unpack_duration_test.c index 2eba68e24e7..978dd8d1bab 100644 --- a/lib/common/tests/rules/pcmk__unpack_duration_test.c +++ b/lib/common/tests/rules/pcmk__unpack_duration_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 the Pacemaker project contributors + * Copyright 2024-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -99,7 +99,7 @@ all_valid(void **state) crm_time_t *reference = crm_time_new("2025-03-21 16:01:01"); assert_int_equal(pcmk__unpack_duration(duration, start, &end), pcmk_rc_ok); - assert_int_equal(crm_time_compare(end, reference), 0); + assert_int_equal(pcmk__time_compare(end, reference), 0); crm_time_free(start); crm_time_free(end); diff --git a/lib/common/tests/xml_element/pcmk__xe_get_datetime_test.c b/lib/common/tests/xml_element/pcmk__xe_get_datetime_test.c index c488d3f7243..34c4103abd9 100644 --- a/lib/common/tests/xml_element/pcmk__xe_get_datetime_test.c +++ b/lib/common/tests/xml_element/pcmk__xe_get_datetime_test.c @@ -79,7 +79,7 @@ attr_valid(void **state) crm_time_t *reference = crm_time_new(REFERENCE_ISO8601); assert_int_equal(pcmk__xe_get_datetime(xml, ATTR_PRESENT, &t), pcmk_rc_ok); - assert_int_equal(crm_time_compare(t, reference), 0); + assert_int_equal(pcmk__time_compare(t, reference), 0); crm_time_free(t); crm_time_free(reference); diff --git a/tools/crm_resource_ban.c b/tools/crm_resource_ban.c index f169660a85c..656cb17cf4e 100644 --- a/tools/crm_resource_ban.c +++ b/tools/crm_resource_ban.c @@ -496,7 +496,7 @@ cli_resource_clear_all_expired(xmlNode *root, cib_t *cib_conn, const char *rsc, continue; // Treat as unexpired } - if (crm_time_compare(now, end) == 1) { + if (pcmk__time_compare(now, end) > 0) { xmlNode *fragment = NULL; xmlNode *location = NULL; From a764bec3f8b18b937adf211ee61f43af2ac40d3b Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 19:07:17 -0700 Subject: [PATCH 59/99] API: libcrmcommon: Deprecate crm_time_compare() Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 2 -- include/crm/common/iso8601_compat.h | 3 +++ lib/common/iso8601.c | 12 ++++++------ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 66aa47e93f0..daa4ea7a1fe 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,8 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); void crm_time_free(crm_time_t * dt); -int crm_time_compare(const crm_time_t *a, const crm_time_t *b); - int crm_time_get_timeofday(const crm_time_t *dt, uint32_t *h, uint32_t *m, uint32_t *s); int crm_time_get_gregorian(const crm_time_t *dt, uint32_t *y, uint32_t *m, diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index 5065d58da5d..48050685f08 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -122,6 +122,9 @@ bool crm_time_is_defined(const crm_time_t *t); //! \deprecated Do not use char *crm_time_as_string(const crm_time_t *dt, int flags); +//! \deprecated Do not use +int crm_time_compare(const crm_time_t *a, const crm_time_t *b); + #ifdef __cplusplus } #endif diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 1534f8de52e..0091c709157 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1678,12 +1678,6 @@ pcmk__time_compare(const crm_time_t *a, const crm_time_t *b) return rc; } -int -crm_time_compare(const crm_time_t *a, const crm_time_t *b) -{ - return pcmk__time_compare(a, b); -} - /*! * \brief Add a given number of seconds to a date/time or duration * @@ -2438,5 +2432,11 @@ crm_time_as_string(const crm_time_t *dt, int flags) return pcmk__time_text(dt, flags); } +int +crm_time_compare(const crm_time_t *a, const crm_time_t *b) +{ + return pcmk__time_compare(a, b); +} + // LCOV_EXCL_STOP // End deprecated API From 3cc9ba86d8040564b79dc0c336fb67929546be15 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 21:19:11 -0700 Subject: [PATCH 60/99] Refactor: libcrmcommon: Ignore crm_time_get_timeofday() return value It's always TRUE. Signed-off-by: Reid Wahl --- lib/common/iso8601.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 0091c709157..8ec3e331a10 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1077,14 +1077,12 @@ time_as_string_common(const crm_time_t *dt, int usec, uint32_t flags) g_string_append_c(buf, ' '); } - if (crm_time_get_timeofday(dt, &h, &m, &s)) { - g_string_append_printf(buf, - "%.2" PRIu32 ":%.2" PRIu32 ":%.2" PRIu32, - h, m, s); + crm_time_get_timeofday(dt, &h, &m, &s); + g_string_append_printf(buf, "%.2" PRIu32 ":%.2" PRIu32 ":%.2" PRIu32, + h, m, s); - if (pcmk__is_set(flags, pcmk__time_fmt_usecs)) { - g_string_append_printf(buf, ".%06" PRIu32, QB_ABS(usec)); - } + if (pcmk__is_set(flags, pcmk__time_fmt_usecs)) { + g_string_append_printf(buf, ".%06" PRIu32, QB_ABS(usec)); } if (pcmk__is_set(flags, pcmk__time_fmt_timezone) && (dt->offset != 0)) { From 19ab05c36672b32669ded3058e3003cb1f42238f Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 19:15:22 -0700 Subject: [PATCH 61/99] Refactor: libcrmcommon: New pcmk__time_get_timeofday() To replace crm_time_get_timeofday(). Signed-off-by: Reid Wahl --- lib/common/crmcommon_private.h | 4 ++++ lib/common/iso8601.c | 16 ++++++++++++---- lib/common/rules.c | 4 ++-- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/lib/common/crmcommon_private.h b/lib/common/crmcommon_private.h index 58add461801..49be4f208e8 100644 --- a/lib/common/crmcommon_private.h +++ b/lib/common/crmcommon_private.h @@ -203,6 +203,10 @@ enum pcmk__time_component { pcmk__time_seconds, }; +G_GNUC_INTERNAL +void pcmk__time_get_timeofday(const crm_time_t *dt, uint32_t *hour, + uint32_t *minute, uint32_t *second); + G_GNUC_INTERNAL const char *pcmk__time_component_attr(enum pcmk__time_component component); diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 8ec3e331a10..a925a2a3044 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -706,13 +706,21 @@ pcmk__time_log_as(const char *file, const char *function, int line, free(date_s); } +void +pcmk__time_get_timeofday(const crm_time_t *dt, uint32_t *hour, + uint32_t *minute, uint32_t *second) +{ + pcmk__assert((dt != NULL) && (hour != NULL) && (minute != NULL) + && (second != NULL)); + + seconds_to_hms(dt->seconds, hour, minute, second); +} + int crm_time_get_timeofday(const crm_time_t *dt, uint32_t *h, uint32_t *m, uint32_t *s) { - pcmk__assert((dt != NULL) && (h != NULL) && (m != NULL) && (s != NULL)); - - seconds_to_hms(dt->seconds, h, m, s); + pcmk__time_get_timeofday(dt, h, m, s); return TRUE; } @@ -1077,7 +1085,7 @@ time_as_string_common(const crm_time_t *dt, int usec, uint32_t flags) g_string_append_c(buf, ' '); } - crm_time_get_timeofday(dt, &h, &m, &s); + pcmk__time_get_timeofday(dt, &h, &m, &s); g_string_append_printf(buf, "%.2" PRIu32 ":%.2" PRIu32 ":%.2" PRIu32, h, m, s); diff --git a/lib/common/rules.c b/lib/common/rules.c index 981e0a03124..78167a790e9 100644 --- a/lib/common/rules.c +++ b/lib/common/rules.c @@ -188,8 +188,8 @@ pcmk__evaluate_date_spec(const xmlNode *date_spec, const crm_time_t *now) &(ranges[2].value)); // Hour, minute, second - crm_time_get_timeofday(now, &(ranges[3].value), &(ranges[4].value), - &(ranges[5].value)); + pcmk__time_get_timeofday(now, &(ranges[3].value), &(ranges[4].value), + &(ranges[5].value)); // Year (redundant) and day of year crm_time_get_ordinal(now, &(ranges[0].value), &(ranges[6].value)); From a207d49bace2cf6db0165fc41a8f21fde2b8169d Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 22:09:33 -0700 Subject: [PATCH 62/99] API: libcrmcommon: Deprecate crm_time_get_timeofday() External callers have no need to inspect a crm_time_t object. Pacemaker should not be used for general-purpose date/time manipulation. Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 2 -- include/crm/common/iso8601_compat.h | 4 ++++ lib/common/iso8601.c | 16 ++++++++-------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index daa4ea7a1fe..102e90b38cf 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,8 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); void crm_time_free(crm_time_t * dt); -int crm_time_get_timeofday(const crm_time_t *dt, uint32_t *h, uint32_t *m, - uint32_t *s); int crm_time_get_gregorian(const crm_time_t *dt, uint32_t *y, uint32_t *m, uint32_t *d); int crm_time_get_ordinal(const crm_time_t *dt, uint32_t *y, uint32_t *d); diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index 48050685f08..4ef54e01541 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -125,6 +125,10 @@ char *crm_time_as_string(const crm_time_t *dt, int flags); //! \deprecated Do not use int crm_time_compare(const crm_time_t *a, const crm_time_t *b); +//! \deprecated Do not use +int crm_time_get_timeofday(const crm_time_t *dt, uint32_t *h, uint32_t *m, + uint32_t *s); + #ifdef __cplusplus } #endif diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index a925a2a3044..482447bdbc5 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -716,14 +716,6 @@ pcmk__time_get_timeofday(const crm_time_t *dt, uint32_t *hour, seconds_to_hms(dt->seconds, hour, minute, second); } -int -crm_time_get_timeofday(const crm_time_t *dt, uint32_t *h, uint32_t *m, - uint32_t *s) -{ - pcmk__time_get_timeofday(dt, h, m, s); - return TRUE; -} - long long crm_time_get_seconds(const crm_time_t *dt) { @@ -2444,5 +2436,13 @@ crm_time_compare(const crm_time_t *a, const crm_time_t *b) return pcmk__time_compare(a, b); } +int +crm_time_get_timeofday(const crm_time_t *dt, uint32_t *h, uint32_t *m, + uint32_t *s) +{ + pcmk__time_get_timeofday(dt, h, m, s); + return TRUE; +} + // LCOV_EXCL_STOP // End deprecated API From f740769ed7edf62851e090569f18fe779f90b884 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 22:13:36 -0700 Subject: [PATCH 63/99] Refactor: libcrmcommon: Ignore crm_time_get_gregorian() return value It always returns TRUE. Signed-off-by: Reid Wahl --- lib/common/iso8601.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 482447bdbc5..5da153697c8 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1062,11 +1062,10 @@ time_as_string_common(const crm_time_t *dt, int usec, uint32_t flags) uint32_t m = 0; uint32_t d = 0; - if (crm_time_get_gregorian(dt, &y, &m, &d)) { - g_string_append_printf(buf, - "%.4" PRIu32 "-%.2" PRIu32 "-%.2" PRIu32, - y, m, d); - } + crm_time_get_gregorian(dt, &y, &m, &d); + g_string_append_printf(buf, + "%.4" PRIu32 "-%.2" PRIu32 "-%.2" PRIu32, + y, m, d); } } From 13e3fff924ccae63843663d8f6d58d0ebb02d1af Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 22:22:06 -0700 Subject: [PATCH 64/99] Refactor: libcrmcommon: New pcmk__time_get_ymd() To replace crm_time_get_gregorian(). Signed-off-by: Reid Wahl --- lib/common/crmcommon_private.h | 4 ++++ lib/common/iso8601.c | 28 +++++++++++++++++----------- lib/common/rules.c | 4 ++-- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/lib/common/crmcommon_private.h b/lib/common/crmcommon_private.h index 49be4f208e8..0654bf2ae01 100644 --- a/lib/common/crmcommon_private.h +++ b/lib/common/crmcommon_private.h @@ -207,6 +207,10 @@ G_GNUC_INTERNAL void pcmk__time_get_timeofday(const crm_time_t *dt, uint32_t *hour, uint32_t *minute, uint32_t *second); +G_GNUC_INTERNAL +void pcmk__time_get_ymd(const crm_time_t *dt, uint32_t *year, uint32_t *month, + uint32_t *day); + G_GNUC_INTERNAL const char *pcmk__time_component_attr(enum pcmk__time_component component); diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 5da153697c8..0445d315846 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -766,14 +766,15 @@ crm_time_get_seconds_since_epoch(const crm_time_t *dt) return (dt == NULL)? 0 : (crm_time_get_seconds(dt) - EPOCH_SECONDS); } -int -crm_time_get_gregorian(const crm_time_t *dt, uint32_t *y, uint32_t *m, - uint32_t *d) +void +pcmk__time_get_ymd(const crm_time_t *dt, uint32_t *year, uint32_t *month, + uint32_t *day) { int months = 0; int days = dt->days; - pcmk__assert((dt != NULL) && (y != NULL) && (m != NULL) && (d != NULL)); + pcmk__assert((dt != NULL) && (year != NULL) && (month != NULL) + && (day != NULL)); if(dt->years != 0) { for (months = 1; months <= 12 && days > 0; months++) { @@ -794,11 +795,16 @@ crm_time_get_gregorian(const crm_time_t *dt, uint32_t *y, uint32_t *m, /* This is a duration not including months, still don't convert the days field */ } - *y = dt->years; - *m = months; - *d = days; - pcmk__trace("%.4d-%.3d -> %.4d-%.2d-%.2d", dt->years, dt->days, dt->years, - months, days); + *year = dt->years; + *month = months; + *day = days; +} + +int +crm_time_get_gregorian(const crm_time_t *dt, uint32_t *y, uint32_t *m, + uint32_t *d) +{ + pcmk__time_get_ymd(dt, y, m, d); return TRUE; } @@ -1062,7 +1068,7 @@ time_as_string_common(const crm_time_t *dt, int usec, uint32_t flags) uint32_t m = 0; uint32_t d = 0; - crm_time_get_gregorian(dt, &y, &m, &d); + pcmk__time_get_ymd(dt, &y, &m, &d); g_string_append_printf(buf, "%.4" PRIu32 "-%.2" PRIu32 "-%.2" PRIu32, y, m, d); @@ -1752,7 +1758,7 @@ crm_time_add_months(crm_time_t *dt, int value) uint32_t day = 0; int days_in_month = 0; - crm_time_get_gregorian(dt, &year, &month, &day); + pcmk__time_get_ymd(dt, &year, &month, &day); if (value > 0) { for (int i = value; i > 0; i--) { diff --git a/lib/common/rules.c b/lib/common/rules.c index 78167a790e9..2e8519840c7 100644 --- a/lib/common/rules.c +++ b/lib/common/rules.c @@ -184,8 +184,8 @@ pcmk__evaluate_date_spec(const xmlNode *date_spec, const crm_time_t *now) } // Year, month, day - crm_time_get_gregorian(now, &(ranges[0].value), &(ranges[1].value), - &(ranges[2].value)); + pcmk__time_get_ymd(now, &(ranges[0].value), &(ranges[1].value), + &(ranges[2].value)); // Hour, minute, second pcmk__time_get_timeofday(now, &(ranges[3].value), &(ranges[4].value), From 65279c9683ebe0f8ea26e5d82eb1e9ea836e98c2 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 22:22:51 -0700 Subject: [PATCH 65/99] API: libcrmcommon: Deprecate crm_time_get_gregorian() External callers have no need to inspect a crm_time_t object. Pacemaker should not be used for general-purpose date/time manipulation. Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 2 -- include/crm/common/iso8601_compat.h | 4 ++++ lib/common/iso8601.c | 16 ++++++++-------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 102e90b38cf..814c2942140 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,8 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); void crm_time_free(crm_time_t * dt); -int crm_time_get_gregorian(const crm_time_t *dt, uint32_t *y, uint32_t *m, - uint32_t *d); int crm_time_get_ordinal(const crm_time_t *dt, uint32_t *y, uint32_t *d); /* Time in seconds since 0000-01-01 00:00:00Z */ diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index 4ef54e01541..0ebed008dc4 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -129,6 +129,10 @@ int crm_time_compare(const crm_time_t *a, const crm_time_t *b); int crm_time_get_timeofday(const crm_time_t *dt, uint32_t *h, uint32_t *m, uint32_t *s); +//! \deprecated Do not use +int crm_time_get_gregorian(const crm_time_t *dt, uint32_t *y, uint32_t *m, + uint32_t *d); + #ifdef __cplusplus } #endif diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 0445d315846..22532e24cd1 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -800,14 +800,6 @@ pcmk__time_get_ymd(const crm_time_t *dt, uint32_t *year, uint32_t *month, *day = days; } -int -crm_time_get_gregorian(const crm_time_t *dt, uint32_t *y, uint32_t *m, - uint32_t *d) -{ - pcmk__time_get_ymd(dt, y, m, d); - return TRUE; -} - int crm_time_get_ordinal(const crm_time_t *dt, uint32_t *y, uint32_t *d) { @@ -2449,5 +2441,13 @@ crm_time_get_timeofday(const crm_time_t *dt, uint32_t *h, uint32_t *m, return TRUE; } +int +crm_time_get_gregorian(const crm_time_t *dt, uint32_t *y, uint32_t *m, + uint32_t *d) +{ + pcmk__time_get_ymd(dt, y, m, d); + return TRUE; +} + // LCOV_EXCL_STOP // End deprecated API From df5742c54c85deae287b35d45e323a8cb6958804 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 22:29:18 -0700 Subject: [PATCH 66/99] Refactor: libcrmcommon: Drop crm_time_get_ordinal() internally Signed-off-by: Reid Wahl --- lib/common/iso8601.c | 7 +------ lib/common/rules.c | 4 ++-- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 22532e24cd1..0a2611ff079 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1048,12 +1048,7 @@ time_as_string_common(const crm_time_t *dt, int usec, uint32_t flags) } } else if (pcmk__is_set(flags, pcmk__time_fmt_ordinal)) { // YYYY-DDD - uint32_t y = 0; - uint32_t d = 0; - - if (crm_time_get_ordinal(dt, &y, &d)) { - g_string_append_printf(buf, "%" PRIu32 "-%.3" PRIu32, y, d); - } + g_string_append_printf(buf, "%d-%.3d", dt->years, dt->days); } else { // YYYY-MM-DD uint32_t y = 0; diff --git a/lib/common/rules.c b/lib/common/rules.c index 2e8519840c7..3b49c3962b9 100644 --- a/lib/common/rules.c +++ b/lib/common/rules.c @@ -191,8 +191,8 @@ pcmk__evaluate_date_spec(const xmlNode *date_spec, const crm_time_t *now) pcmk__time_get_timeofday(now, &(ranges[3].value), &(ranges[4].value), &(ranges[5].value)); - // Year (redundant) and day of year - crm_time_get_ordinal(now, &(ranges[0].value), &(ranges[6].value)); + // Day of year + ranges[6].value = now->days; // Week year, week of week year, day of week pcmk__time_get_ywd(now, &(ranges[7].value), &(ranges[8].value), From ce187d862710f5d46a299c846988c1919f93b83f Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 22:30:20 -0700 Subject: [PATCH 67/99] API: libcrmcommon: Deprecate crm_time_get_ordinal() External callers have no need to inspect a crm_time_t object. Pacemaker should not be used for general-purpose date/time manipulation. Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 2 -- include/crm/common/iso8601_compat.h | 3 +++ lib/common/iso8601.c | 20 ++++++++++---------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 814c2942140..01c8a5b1418 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,8 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); void crm_time_free(crm_time_t * dt); -int crm_time_get_ordinal(const crm_time_t *dt, uint32_t *y, uint32_t *d); - /* Time in seconds since 0000-01-01 00:00:00Z */ long long crm_time_get_seconds(const crm_time_t *dt); diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index 0ebed008dc4..c4c62a51d04 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -133,6 +133,9 @@ int crm_time_get_timeofday(const crm_time_t *dt, uint32_t *h, uint32_t *m, int crm_time_get_gregorian(const crm_time_t *dt, uint32_t *y, uint32_t *m, uint32_t *d); +//! \deprecated Do not use +int crm_time_get_ordinal(const crm_time_t *dt, uint32_t *y, uint32_t *d); + #ifdef __cplusplus } #endif diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 0a2611ff079..4bbb3105f8e 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -800,16 +800,6 @@ pcmk__time_get_ymd(const crm_time_t *dt, uint32_t *year, uint32_t *month, *day = days; } -int -crm_time_get_ordinal(const crm_time_t *dt, uint32_t *y, uint32_t *d) -{ - pcmk__assert((dt != NULL) && (y != NULL) && (d != NULL)); - - *y = dt->years; - *d = dt->days; - return TRUE; -} - void pcmk__time_get_ywd(const crm_time_t *dt, uint32_t *y, uint32_t *w, uint32_t *d) { @@ -2444,5 +2434,15 @@ crm_time_get_gregorian(const crm_time_t *dt, uint32_t *y, uint32_t *m, return TRUE; } +int +crm_time_get_ordinal(const crm_time_t *dt, uint32_t *y, uint32_t *d) +{ + pcmk__assert((dt != NULL) && (y != NULL) && (d != NULL)); + + *y = dt->years; + *d = dt->days; + return TRUE; +} + // LCOV_EXCL_STOP // End deprecated API From 217d4439c21a8ac69e249ea4a4ec9ece61d399c7 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 22:34:48 -0700 Subject: [PATCH 68/99] Refactor: libcrmcommon: New pcmk__time_get_seconds() To replace crm_time_get_seconds(). Signed-off-by: Reid Wahl --- include/crm/common/iso8601_internal.h | 1 + lib/common/iso8601.c | 15 +++++++++++---- lib/common/strings.c | 2 +- lib/pengine/pe_actions.c | 2 +- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/include/crm/common/iso8601_internal.h b/include/crm/common/iso8601_internal.h index be5a117644a..41d591fdb11 100644 --- a/include/crm/common/iso8601_internal.h +++ b/include/crm/common/iso8601_internal.h @@ -55,6 +55,7 @@ enum pcmk__time_fmt_flags { bool pcmk__time_valid_year(int year); bool pcmk__time_is_initialized(const crm_time_t *dt); +long long pcmk__time_get_seconds(const crm_time_t *dt); void pcmk__time_get_ywd(const crm_time_t *dt, uint32_t *y, uint32_t *w, uint32_t *d); char *pcmk__time_text(const crm_time_t *dt, int flags); diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 4bbb3105f8e..c2dacb1aa38 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -716,8 +716,9 @@ pcmk__time_get_timeofday(const crm_time_t *dt, uint32_t *hour, seconds_to_hms(dt->seconds, hour, minute, second); } +// Time in seconds since 0000-01-01 00:00:00Z long long -crm_time_get_seconds(const crm_time_t *dt) +pcmk__time_get_seconds(const crm_time_t *dt) { crm_time_t *utc = NULL; long long days = 0; @@ -759,11 +760,17 @@ crm_time_get_seconds(const crm_time_t *dt) return seconds; } -#define EPOCH_SECONDS 62135596800ULL /* Calculated using crm_time_get_seconds() */ +long long +crm_time_get_seconds(const crm_time_t *dt) +{ + return pcmk__time_get_seconds(dt); +} + +#define EPOCH_SECONDS 62135596800ULL // Calculated using pcmk__time_get_seconds long long crm_time_get_seconds_since_epoch(const crm_time_t *dt) { - return (dt == NULL)? 0 : (crm_time_get_seconds(dt) - EPOCH_SECONDS); + return (dt == NULL)? 0 : (pcmk__time_get_seconds(dt) - EPOCH_SECONDS); } void @@ -1003,7 +1010,7 @@ time_as_string_common(const crm_time_t *dt, int usec, uint32_t flags) long long seconds = 0; if (pcmk__is_set(flags, pcmk__time_fmt_seconds)) { - seconds = crm_time_get_seconds(dt); + seconds = pcmk__time_get_seconds(dt); } else { seconds = crm_time_get_seconds_since_epoch(dt); } diff --git a/lib/common/strings.c b/lib/common/strings.c index 997395002ca..4e2b3054da7 100644 --- a/lib/common/strings.c +++ b/lib/common/strings.c @@ -375,7 +375,7 @@ pcmk_parse_interval_spec(const char *input, guint *result_ms) crm_time_t *period_s = pcmk__time_parse_duration(input); if (period_s != NULL) { - msec = crm_time_get_seconds(period_s); + msec = pcmk__time_get_seconds(period_s); msec = QB_MIN(msec, G_MAXUINT / 1000) * 1000; crm_time_free(period_s); } diff --git a/lib/pengine/pe_actions.c b/lib/pengine/pe_actions.c index d71c800cf04..ba550a42016 100644 --- a/lib/pengine/pe_actions.c +++ b/lib/pengine/pe_actions.c @@ -572,7 +572,7 @@ unpack_interval_origin(const char *value, const xmlNode *xml_obj, } // Get seconds since origin (negative if origin is in the future) - result = crm_time_get_seconds(now) - crm_time_get_seconds(origin); + result = pcmk__time_get_seconds(now) - pcmk__time_get_seconds(origin); crm_time_free(origin); // Calculate seconds from closest interval to now From 5c9d48bff82c887e283c81fd94e1de47fbc6b468 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 22:36:11 -0700 Subject: [PATCH 69/99] API: libcrmcommon: Deprecate crm_time_get_seconds() External callers have no need to inspect a crm_time_t object. Pacemaker should not be used for general-purpose date/time manipulation. Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 3 --- include/crm/common/iso8601_compat.h | 3 +++ lib/common/iso8601.c | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 01c8a5b1418..2d2b4566602 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,9 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); void crm_time_free(crm_time_t * dt); -/* Time in seconds since 0000-01-01 00:00:00Z */ -long long crm_time_get_seconds(const crm_time_t *dt); - /* Time in seconds since 1970-01-01 00:00:00Z */ long long crm_time_get_seconds_since_epoch(const crm_time_t *dt); diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index c4c62a51d04..3c08c6b3388 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -136,6 +136,9 @@ int crm_time_get_gregorian(const crm_time_t *dt, uint32_t *y, uint32_t *m, //! \deprecated Do not use int crm_time_get_ordinal(const crm_time_t *dt, uint32_t *y, uint32_t *d); +//! \deprecated Do not use +long long crm_time_get_seconds(const crm_time_t *dt); + #ifdef __cplusplus } #endif diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index c2dacb1aa38..ea93f74431f 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -760,12 +760,6 @@ pcmk__time_get_seconds(const crm_time_t *dt) return seconds; } -long long -crm_time_get_seconds(const crm_time_t *dt) -{ - return pcmk__time_get_seconds(dt); -} - #define EPOCH_SECONDS 62135596800ULL // Calculated using pcmk__time_get_seconds long long crm_time_get_seconds_since_epoch(const crm_time_t *dt) @@ -2451,5 +2445,11 @@ crm_time_get_ordinal(const crm_time_t *dt, uint32_t *y, uint32_t *d) return TRUE; } +long long +crm_time_get_seconds(const crm_time_t *dt) +{ + return pcmk__time_get_seconds(dt); +} + // LCOV_EXCL_STOP // End deprecated API From 776bdbf3bf3d078d3ecb8ca3d649635049223eae Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 22:37:49 -0700 Subject: [PATCH 70/99] Refactor: libcrmcommon: Make pcmk__time_get_ywd() library-private Signed-off-by: Reid Wahl --- include/crm/common/iso8601_internal.h | 2 -- lib/common/crmcommon_private.h | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/crm/common/iso8601_internal.h b/include/crm/common/iso8601_internal.h index 41d591fdb11..c55e33b3623 100644 --- a/include/crm/common/iso8601_internal.h +++ b/include/crm/common/iso8601_internal.h @@ -56,8 +56,6 @@ enum pcmk__time_fmt_flags { bool pcmk__time_valid_year(int year); bool pcmk__time_is_initialized(const crm_time_t *dt); long long pcmk__time_get_seconds(const crm_time_t *dt); -void pcmk__time_get_ywd(const crm_time_t *dt, uint32_t *y, uint32_t *w, - uint32_t *d); char *pcmk__time_text(const crm_time_t *dt, int flags); char *pcmk__time_format_hr(const char *format, const crm_time_t *dt, int usec); char *pcmk__epoch2str(const time_t *source, uint32_t flags); diff --git a/lib/common/crmcommon_private.h b/lib/common/crmcommon_private.h index 0654bf2ae01..adabc816961 100644 --- a/lib/common/crmcommon_private.h +++ b/lib/common/crmcommon_private.h @@ -211,6 +211,10 @@ G_GNUC_INTERNAL void pcmk__time_get_ymd(const crm_time_t *dt, uint32_t *year, uint32_t *month, uint32_t *day); +G_GNUC_INTERNAL +void pcmk__time_get_ywd(const crm_time_t *dt, uint32_t *y, uint32_t *w, + uint32_t *d); + G_GNUC_INTERNAL const char *pcmk__time_component_attr(enum pcmk__time_component component); From 01a8ef4f4e7fd6127d9942e72ddfc710a36dfa6c Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 22:43:34 -0700 Subject: [PATCH 71/99] Refactor: libcrmcommon: New pcmk__time_to_unix() To replace crm_time_get_seconds_since_epoch(). The name "pcmk__time_to_unix()" is chosen in order to align with g_date_time_to_unix(), which we plan to adopt eventually. Signed-off-by: Reid Wahl --- include/crm/common/iso8601_internal.h | 1 + lib/common/iso8601.c | 11 +++++++++-- lib/common/scheduler.c | 2 +- lib/pacemaker/pcmk_sched_location.c | 2 +- lib/pengine/utils.c | 2 +- 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/include/crm/common/iso8601_internal.h b/include/crm/common/iso8601_internal.h index c55e33b3623..5f908c31e76 100644 --- a/include/crm/common/iso8601_internal.h +++ b/include/crm/common/iso8601_internal.h @@ -56,6 +56,7 @@ enum pcmk__time_fmt_flags { bool pcmk__time_valid_year(int year); bool pcmk__time_is_initialized(const crm_time_t *dt); long long pcmk__time_get_seconds(const crm_time_t *dt); +long long pcmk__time_to_unix(const crm_time_t *dt); char *pcmk__time_text(const crm_time_t *dt, int flags); char *pcmk__time_format_hr(const char *format, const crm_time_t *dt, int usec); char *pcmk__epoch2str(const time_t *source, uint32_t flags); diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index ea93f74431f..c4316961b0c 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -761,12 +761,19 @@ pcmk__time_get_seconds(const crm_time_t *dt) } #define EPOCH_SECONDS 62135596800ULL // Calculated using pcmk__time_get_seconds +// Time in seconds since 1970-01-01 00:00:00Z long long -crm_time_get_seconds_since_epoch(const crm_time_t *dt) +pcmk__time_to_unix(const crm_time_t *dt) { return (dt == NULL)? 0 : (pcmk__time_get_seconds(dt) - EPOCH_SECONDS); } +long long +crm_time_get_seconds_since_epoch(const crm_time_t *dt) +{ + return pcmk__time_to_unix(dt); +} + void pcmk__time_get_ymd(const crm_time_t *dt, uint32_t *year, uint32_t *month, uint32_t *day) @@ -1006,7 +1013,7 @@ time_as_string_common(const crm_time_t *dt, int usec, uint32_t flags) if (pcmk__is_set(flags, pcmk__time_fmt_seconds)) { seconds = pcmk__time_get_seconds(dt); } else { - seconds = crm_time_get_seconds_since_epoch(dt); + seconds = pcmk__time_to_unix(dt); } if (pcmk__is_set(flags, pcmk__time_fmt_usecs)) { diff --git a/lib/common/scheduler.c b/lib/common/scheduler.c index 44d14df455e..2b97c126be4 100644 --- a/lib/common/scheduler.c +++ b/lib/common/scheduler.c @@ -285,7 +285,7 @@ pcmk__scheduler_epoch_time(pcmk_scheduler_t *scheduler) pcmk__trace("Scheduler 'now' set to current time"); scheduler->priv->now = crm_time_new(NULL); } - return crm_time_get_seconds_since_epoch(scheduler->priv->now); + return pcmk__time_to_unix(scheduler->priv->now); } /*! diff --git a/lib/pacemaker/pcmk_sched_location.c b/lib/pacemaker/pcmk_sched_location.c index e5e48b9bc60..2977a8da8c4 100644 --- a/lib/pacemaker/pcmk_sched_location.c +++ b/lib/pacemaker/pcmk_sched_location.c @@ -380,7 +380,7 @@ unpack_rsc_location(xmlNode *xml_obj, pcmk_resource_t *rsc, * change, make sure the scheduler is re-run by that time. */ if (pcmk__time_is_initialized(next_change)) { - time_t t = (time_t) crm_time_get_seconds_since_epoch(next_change); + time_t t = (time_t) pcmk__time_to_unix(next_change); pcmk__update_recheck_time(t, rsc->priv->scheduler, "location rule evaluation"); diff --git a/lib/pengine/utils.c b/lib/pengine/utils.c index 0237af6def0..3e77412e256 100644 --- a/lib/pengine/utils.c +++ b/lib/pengine/utils.c @@ -714,7 +714,7 @@ pe__unpack_dataset_nvpairs(const xmlNode *xml_obj, const char *set_name, hash, next_change, scheduler->input->doc); if (pcmk__time_is_initialized(next_change)) { - time_t recheck = (time_t) crm_time_get_seconds_since_epoch(next_change); + time_t recheck = (time_t) pcmk__time_to_unix(next_change); pcmk__update_recheck_time(recheck, scheduler, "rule evaluation"); } From d7b34132b8bd5abbbdd6b6f890e382ab225a1826 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 22:45:11 -0700 Subject: [PATCH 72/99] API: libcrmcommon: Deprecate crm_time_get_seconds_since_epoch() External callers have no need to inspect a crm_time_t object. Pacemaker should not be used for general-purpose date/time manipulation. Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 3 --- include/crm/common/iso8601_compat.h | 3 +++ lib/common/iso8601.c | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 2d2b4566602..3f494d9ba1e 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,9 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); void crm_time_free(crm_time_t * dt); -/* Time in seconds since 1970-01-01 00:00:00Z */ -long long crm_time_get_seconds_since_epoch(const crm_time_t *dt); - /* Returns a new time object */ crm_time_t *pcmk_copy_time(const crm_time_t *source); crm_time_t *crm_time_add(const crm_time_t *dt, const crm_time_t *value); diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index 3c08c6b3388..78a60718052 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -139,6 +139,9 @@ int crm_time_get_ordinal(const crm_time_t *dt, uint32_t *y, uint32_t *d); //! \deprecated Do not use long long crm_time_get_seconds(const crm_time_t *dt); +//! \deprecated Do not use +long long crm_time_get_seconds_since_epoch(const crm_time_t *dt); + #ifdef __cplusplus } #endif diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index c4316961b0c..a15ae88a5db 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -768,12 +768,6 @@ pcmk__time_to_unix(const crm_time_t *dt) return (dt == NULL)? 0 : (pcmk__time_get_seconds(dt) - EPOCH_SECONDS); } -long long -crm_time_get_seconds_since_epoch(const crm_time_t *dt) -{ - return pcmk__time_to_unix(dt); -} - void pcmk__time_get_ymd(const crm_time_t *dt, uint32_t *year, uint32_t *month, uint32_t *day) @@ -2458,5 +2452,11 @@ crm_time_get_seconds(const crm_time_t *dt) return pcmk__time_get_seconds(dt); } +long long +crm_time_get_seconds_since_epoch(const crm_time_t *dt) +{ + return pcmk__time_to_unix(dt); +} + // LCOV_EXCL_STOP // End deprecated API From aef4bea873dfa1e7708b6e2e9f3c180c90b413ff Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 22:54:04 -0700 Subject: [PATCH 73/99] Refactor: various: Drop crm_time_free() internally It's equivalent to free(). There are no dynamically allocated fields within crm_time_t. Signed-off-by: Reid Wahl --- daemons/controld/controld_control.c | 2 +- daemons/controld/controld_remote_proxy.c | 2 +- lib/cib/cib_utils.c | 2 +- lib/common/alerts.c | 2 +- lib/common/fuzzers/iso8601_fuzzer.c | 2 +- lib/common/iso8601.c | 34 +++++++------- lib/common/rules.c | 28 ++++++------ lib/common/scheduler.c | 2 +- lib/common/strings.c | 2 +- .../tests/iso8601/crm_time_add_days_test.c | 4 +- .../tests/iso8601/crm_time_add_seconds_test.c | 4 +- .../tests/iso8601/crm_time_add_years_test.c | 4 +- .../iso8601/pcmk__add_time_from_xml_test.c | 44 +++++++++---------- .../iso8601/pcmk__set_time_if_earlier_test.c | 18 ++++---- .../nvpair/pcmk__unpack_nvpair_block_test.c | 2 +- .../nvpair/pcmk__unpack_nvpair_blocks_test.c | 20 ++++----- .../rules/pcmk__evaluate_condition_test.c | 10 ++--- .../pcmk__evaluate_date_expression_test.c | 10 ++--- .../rules/pcmk__evaluate_date_spec_test.c | 6 +-- .../tests/rules/pcmk__unpack_duration_test.c | 16 +++---- .../tests/rules/pcmk_evaluate_rule_test.c | 8 ++-- .../xml_element/pcmk__xe_get_datetime_test.c | 6 +-- lib/common/tls.c | 2 +- lib/common/xml_element.c | 2 +- lib/lrmd/lrmd_alerts.c | 4 +- lib/pacemaker/pcmk_sched_location.c | 2 +- lib/pengine/pe_actions.c | 2 +- lib/pengine/status.c | 2 +- lib/pengine/utils.c | 2 +- tools/crm_resource_ban.c | 14 +++--- tools/crm_rule.c | 2 +- tools/iso8601.c | 18 ++++---- 32 files changed, 138 insertions(+), 140 deletions(-) diff --git a/daemons/controld/controld_control.c b/daemons/controld/controld_control.c index 69cc4906c69..753dcca544c 100644 --- a/daemons/controld/controld_control.c +++ b/daemons/controld/controld_control.c @@ -630,7 +630,7 @@ config_query_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void g_hash_table_destroy(config_hash); bail: - crm_time_free(now); + free(now); } /*! diff --git a/daemons/controld/controld_remote_proxy.c b/daemons/controld/controld_remote_proxy.c index 876c439fe1c..6871783dcc2 100644 --- a/daemons/controld/controld_remote_proxy.c +++ b/daemons/controld/controld_remote_proxy.c @@ -272,7 +272,7 @@ remote_config_check(xmlNode *msg, int call_id, int rc, xmlNode *output, lrmd__validate_remote_settings(lrmd, config_hash); g_hash_table_destroy(config_hash); - crm_time_free(now); + free(now); } /*! diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index 709a799c538..e24def378e9 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -146,7 +146,7 @@ read_config(GHashTable *options, xmlNode *current_cib) pcmk__unpack_nvpair_blocks(config, PCMK_XE_CLUSTER_PROPERTY_SET, PCMK_VALUE_CIB_BOOTSTRAP_OPTIONS, &rule_input, options, NULL, config->doc); - crm_time_free(now); + free(now); } static bool diff --git a/lib/common/alerts.c b/lib/common/alerts.c index 6906c74059d..86cf61c77b6 100644 --- a/lib/common/alerts.c +++ b/lib/common/alerts.c @@ -155,7 +155,7 @@ unpack_alert_options(xmlNode *xml, pcmk__alert_t *entry, guint *max_timeout) pcmk__unpack_nvpair_blocks(xml, PCMK_XE_META_ATTRIBUTES, NULL, &rule_input, config_hash, NULL, xml->doc); - crm_time_free(now); + free(now); value = g_hash_table_lookup(config_hash, PCMK_META_ENABLED); if ((value != NULL) && !pcmk__is_true(value)) { diff --git a/lib/common/fuzzers/iso8601_fuzzer.c b/lib/common/fuzzers/iso8601_fuzzer.c index e7c0ecb5b41..60b93d67eee 100644 --- a/lib/common/fuzzers/iso8601_fuzzer.c +++ b/lib/common/fuzzers/iso8601_fuzzer.c @@ -36,7 +36,7 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) now = pcmk__copy_timet(tv.tv_sec); result = pcmk__time_format_hr(ns, now, (int) (tv.tv_nsec / QB_TIME_NS_IN_USEC)); - crm_time_free(now); + free(now); free(result); free(ns); diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index a15ae88a5db..aa8afebda75 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -610,7 +610,7 @@ parse_date(const char *date_str) return dt; invalid: - crm_time_free(dt); + free(dt); errno = EINVAL; return NULL; } @@ -756,7 +756,7 @@ pcmk__time_get_seconds(const crm_time_t *dt) seconds = dt->seconds + (SECONDS_IN_DAY * days); - crm_time_free(utc); + free(utc); return seconds; } @@ -1080,7 +1080,7 @@ time_as_string_common(const crm_time_t *dt, int usec, uint32_t flags) } done: - crm_time_free(utc); + free(utc); result = pcmk__str_copy(buf->str); g_string_free(buf, TRUE); return result; @@ -1264,8 +1264,7 @@ parse_duration_element(const char **element, const char *duration_s, * ignored) * * \return New time object on success, or \cNULL (and set \c errno) otherwise - * \note It is the caller's responsibility to free the result using - * \c crm_time_free(). + * \note It is the caller's responsibility to free the result using \c free(). */ crm_time_t * pcmk__time_parse_duration(const char *period_s) @@ -1326,7 +1325,7 @@ pcmk__time_parse_duration(const char *period_s) /* @COMPAT Setting errno is required only for backward compatibility with * crm_time_parse_duration() */ - crm_time_free(diff); + free(diff); errno = EINVAL; return NULL; } @@ -1375,8 +1374,7 @@ pcmk_copy_time(const crm_time_t *source) * * \return Newly allocated \c crm_time_t object representing \p source_sec * - * \note The caller is responsible for freeing the return value using - * \c crm_time_free(). + * \note The caller is responsible for freeing the return value using \c free(). */ crm_time_t * pcmk__copy_timet(time_t source_sec) @@ -1442,7 +1440,7 @@ crm_time_add(const crm_time_t *dt, const crm_time_t *value) crm_time_add_days(answer, utc->days); crm_time_add_seconds(answer, utc->seconds); - crm_time_free(utc); + free(utc); return answer; } @@ -1608,7 +1606,7 @@ subtract_time(const crm_time_t *dt1, const crm_time_t *dt2, bool as_duration) } crm_time_add_seconds(result, -utc->seconds); - crm_time_free(utc); + free(utc); return result; } @@ -1655,8 +1653,8 @@ pcmk__time_compare(const crm_time_t *a, const crm_time_t *b) do_cmp_field(t1, t2, days); do_cmp_field(t1, t2, seconds); - crm_time_free(t1); - crm_time_free(t2); + free(t1); + free(t2); return rc; } @@ -2083,7 +2081,7 @@ pcmk__epoch2str(const time_t *source, uint32_t flags) dt = pcmk__copy_timet(epoch_time); result = pcmk__time_text(dt, flags); - crm_time_free(dt); + free(dt); return result; } @@ -2119,7 +2117,7 @@ pcmk__timespec2str(const struct timespec *ts, uint32_t flags) dt = pcmk__copy_timet(ts->tv_sec); result = time_as_string_common(dt, ts->tv_nsec / QB_TIME_NS_IN_USEC, flags); - crm_time_free(dt); + free(dt); return result; } @@ -2258,7 +2256,7 @@ crm_time_set_timet(crm_time_t *target, const time_t *source_sec) source = pcmk__copy_timet(*source_sec); *target = *source; - crm_time_free(source); + free(source); } int @@ -2285,9 +2283,9 @@ void crm_time_free_period(crm_time_period_t *period) { if (period) { - crm_time_free(period->start); - crm_time_free(period->end); - crm_time_free(period->diff); + free(period->start); + free(period->end); + free(period->diff); free(period); } } diff --git a/lib/common/rules.c b/lib/common/rules.c index 3b49c3962b9..7327bffba0d 100644 --- a/lib/common/rules.c +++ b/lib/common/rules.c @@ -220,7 +220,7 @@ pcmk__evaluate_date_spec(const xmlNode *date_spec, const crm_time_t *now) parent_id, id, \ pcmk__time_component_attr(component), \ pcmk_rc_str(rc)); \ - g_clear_pointer(end, crm_time_free); \ + g_clear_pointer(end, free); \ return rc; \ } \ } while (0) @@ -235,7 +235,7 @@ pcmk__evaluate_date_spec(const xmlNode *date_spec, const crm_time_t *now) * initially) * * \return Standard Pacemaker return code - * \note The caller is responsible for freeing \p *end using crm_time_free(). + * \note The caller is responsible for freeing \p *end using \c free(). */ int pcmk__unpack_duration(const xmlNode *duration, const crm_time_t *start, @@ -302,7 +302,7 @@ evaluate_in_range(const xmlNode *date_expression, const char *id, &end) != pcmk_rc_ok) { pcmk__config_err("Treating " PCMK_XE_DATE_EXPRESSION " %s as not " "passing because " PCMK_XA_END " is invalid", id); - crm_time_free(start); + free(start); return pcmk_rc_unpack_error; } @@ -326,7 +326,7 @@ evaluate_in_range(const xmlNode *date_expression, const char *id, pcmk__config_err("Treating " PCMK_XE_DATE_EXPRESSION " %s as not passing because duration " "is invalid", id); - crm_time_free(start); + free(start); return rc; } } @@ -334,15 +334,15 @@ evaluate_in_range(const xmlNode *date_expression, const char *id, if ((start != NULL) && (pcmk__time_compare(now, start) < 0)) { pcmk__set_time_if_earlier(next_change, start); - crm_time_free(start); - crm_time_free(end); + free(start); + free(end); return pcmk_rc_before_range; } if (end != NULL) { if (pcmk__time_compare(now, end) > 0) { - crm_time_free(start); - crm_time_free(end); + free(start); + free(end); return pcmk_rc_after_range; } @@ -353,8 +353,8 @@ evaluate_in_range(const xmlNode *date_expression, const char *id, } } - crm_time_free(start); - crm_time_free(end); + free(start); + free(end); return pcmk_rc_within_range; } @@ -393,14 +393,14 @@ evaluate_gt(const xmlNode *date_expression, const char *id, } if (pcmk__time_compare(now, start) > 0) { - crm_time_free(start); + free(start); return pcmk_rc_within_range; } // Evaluation doesn't change until second after start time crm_time_add_seconds(start, 1); pcmk__set_time_if_earlier(next_change, start); - crm_time_free(start); + free(start); return pcmk_rc_before_range; } @@ -439,11 +439,11 @@ evaluate_lt(const xmlNode *date_expression, const char *id, if (pcmk__time_compare(now, end) < 0) { pcmk__set_time_if_earlier(next_change, end); - crm_time_free(end); + free(end); return pcmk_rc_within_range; } - crm_time_free(end); + free(end); return pcmk_rc_after_range; } diff --git a/lib/common/scheduler.c b/lib/common/scheduler.c index 2b97c126be4..ce798d4ef2f 100644 --- a/lib/common/scheduler.c +++ b/lib/common/scheduler.c @@ -105,7 +105,7 @@ pcmk_reset_scheduler(pcmk_scheduler_t *scheduler) // Do not reset local_node_name or out - g_clear_pointer(&scheduler->priv->now, crm_time_free); + g_clear_pointer(&scheduler->priv->now, free); g_clear_pointer(&scheduler->priv->options, g_hash_table_destroy); scheduler->priv->fence_action = NULL; diff --git a/lib/common/strings.c b/lib/common/strings.c index 4e2b3054da7..db014ad44ed 100644 --- a/lib/common/strings.c +++ b/lib/common/strings.c @@ -377,7 +377,7 @@ pcmk_parse_interval_spec(const char *input, guint *result_ms) if (period_s != NULL) { msec = pcmk__time_get_seconds(period_s); msec = QB_MIN(msec, G_MAXUINT / 1000) * 1000; - crm_time_free(period_s); + free(period_s); } } else { diff --git a/lib/common/tests/iso8601/crm_time_add_days_test.c b/lib/common/tests/iso8601/crm_time_add_days_test.c index b7995355b48..21b1106e796 100644 --- a/lib/common/tests/iso8601/crm_time_add_days_test.c +++ b/lib/common/tests/iso8601/crm_time_add_days_test.c @@ -29,8 +29,8 @@ assert_add_days(const char *orig_date_time, int days, crm_time_add_days(orig, days); assert_int_equal(pcmk__time_compare(orig, expected), 0); - crm_time_free(orig); - crm_time_free(expected); + free(orig); + free(expected); } static void diff --git a/lib/common/tests/iso8601/crm_time_add_seconds_test.c b/lib/common/tests/iso8601/crm_time_add_seconds_test.c index 6cb957e689b..2b6d02733a5 100644 --- a/lib/common/tests/iso8601/crm_time_add_seconds_test.c +++ b/lib/common/tests/iso8601/crm_time_add_seconds_test.c @@ -29,8 +29,8 @@ assert_add_seconds(const char *orig_date_time, int seconds, crm_time_add_seconds(orig, seconds); assert_int_equal(pcmk__time_compare(orig, expected), 0); - crm_time_free(orig); - crm_time_free(expected); + free(orig); + free(expected); } static void diff --git a/lib/common/tests/iso8601/crm_time_add_years_test.c b/lib/common/tests/iso8601/crm_time_add_years_test.c index 35831673cdb..f0fa451accb 100644 --- a/lib/common/tests/iso8601/crm_time_add_years_test.c +++ b/lib/common/tests/iso8601/crm_time_add_years_test.c @@ -29,8 +29,8 @@ assert_add_years(const char *orig_date_time, int years, crm_time_add_years(orig, years); assert_int_equal(pcmk__time_compare(orig, expected), 0); - crm_time_free(orig); - crm_time_free(expected); + free(orig); + free(expected); } static void diff --git a/lib/common/tests/iso8601/pcmk__add_time_from_xml_test.c b/lib/common/tests/iso8601/pcmk__add_time_from_xml_test.c index ebea2842ab6..4fd5a252b72 100644 --- a/lib/common/tests/iso8601/pcmk__add_time_from_xml_test.c +++ b/lib/common/tests/iso8601/pcmk__add_time_from_xml_test.c @@ -47,8 +47,8 @@ null_xml_ok(void **state) pcmk_rc_ok); assert_int_equal(pcmk__time_compare(t, reference), 0); - crm_time_free(t); - crm_time_free(reference); + free(t); + free(reference); } static void @@ -72,8 +72,8 @@ missing_attr(void **state) pcmk_rc_ok); assert_int_equal(pcmk__time_compare(t, reference), 0); - crm_time_free(t); - crm_time_free(reference); + free(t); + free(reference); pcmk__xml_free(xml); } @@ -88,8 +88,8 @@ invalid_attr(void **state) pcmk_rc_unpack_error); assert_int_equal(pcmk__time_compare(t, reference), 0); - crm_time_free(t); - crm_time_free(reference); + free(t); + free(reference); pcmk__xml_free(xml); } @@ -110,8 +110,8 @@ out_of_range_attr(void **state) assert_int_equal(pcmk__time_compare(t, reference), 0); pcmk__xml_free(xml); - crm_time_free(t); - crm_time_free(reference); + free(t); + free(reference); } static void @@ -125,8 +125,8 @@ add_years(void **state) pcmk_rc_ok); assert_int_equal(pcmk__time_compare(t, reference), 0); - crm_time_free(t); - crm_time_free(reference); + free(t); + free(reference); pcmk__xml_free(xml); } @@ -141,8 +141,8 @@ add_months(void **state) pcmk_rc_ok); assert_int_equal(pcmk__time_compare(t, reference), 0); - crm_time_free(t); - crm_time_free(reference); + free(t); + free(reference); pcmk__xml_free(xml); } @@ -157,8 +157,8 @@ add_weeks(void **state) pcmk_rc_ok); assert_int_equal(pcmk__time_compare(t, reference), 0); - crm_time_free(t); - crm_time_free(reference); + free(t); + free(reference); pcmk__xml_free(xml); } @@ -173,8 +173,8 @@ add_days(void **state) pcmk_rc_ok); assert_int_equal(pcmk__time_compare(t, reference), 0); - crm_time_free(t); - crm_time_free(reference); + free(t); + free(reference); pcmk__xml_free(xml); } @@ -189,8 +189,8 @@ add_hours(void **state) pcmk_rc_ok); assert_int_equal(pcmk__time_compare(t, reference), 0); - crm_time_free(t); - crm_time_free(reference); + free(t); + free(reference); pcmk__xml_free(xml); } @@ -205,8 +205,8 @@ add_minutes(void **state) pcmk_rc_ok); assert_int_equal(pcmk__time_compare(t, reference), 0); - crm_time_free(t); - crm_time_free(reference); + free(t); + free(reference); pcmk__xml_free(xml); } @@ -221,8 +221,8 @@ add_seconds(void **state) pcmk_rc_ok); assert_int_equal(pcmk__time_compare(t, reference), 0); - crm_time_free(t); - crm_time_free(reference); + free(t); + free(reference); pcmk__xml_free(xml); } diff --git a/lib/common/tests/iso8601/pcmk__set_time_if_earlier_test.c b/lib/common/tests/iso8601/pcmk__set_time_if_earlier_test.c index 86d82cb8bab..6197a3b4a24 100644 --- a/lib/common/tests/iso8601/pcmk__set_time_if_earlier_test.c +++ b/lib/common/tests/iso8601/pcmk__set_time_if_earlier_test.c @@ -28,8 +28,8 @@ null_ok(void **state) pcmk__set_time_if_earlier(target, NULL); assert_int_equal(pcmk__time_compare(target, target_copy), 0); - crm_time_free(target); - crm_time_free(target_copy); + free(target); + free(target_copy); } static void @@ -41,8 +41,8 @@ target_undefined(void **state) pcmk__set_time_if_earlier(target, source); assert_int_equal(pcmk__time_compare(target, source), 0); - crm_time_free(source); - crm_time_free(target); + free(source); + free(target); } static void @@ -54,8 +54,8 @@ source_earlier(void **state) pcmk__set_time_if_earlier(target, source); assert_int_equal(pcmk__time_compare(target, source), 0); - crm_time_free(source); - crm_time_free(target); + free(source); + free(target); } static void @@ -68,9 +68,9 @@ source_later(void **state) pcmk__set_time_if_earlier(target, source); assert_int_equal(pcmk__time_compare(target, target_copy), 0); - crm_time_free(source); - crm_time_free(target); - crm_time_free(target_copy); + free(source); + free(target); + free(target_copy); } PCMK__UNIT_TEST(NULL, NULL, diff --git a/lib/common/tests/nvpair/pcmk__unpack_nvpair_block_test.c b/lib/common/tests/nvpair/pcmk__unpack_nvpair_block_test.c index bfb34e03378..8198cef841b 100644 --- a/lib/common/tests/nvpair/pcmk__unpack_nvpair_block_test.c +++ b/lib/common/tests/nvpair/pcmk__unpack_nvpair_block_test.c @@ -127,7 +127,7 @@ with_rules(void **state) assert_unpack_nvpair_block("" XML_NVPAIRS_2 XML_FAILING_RULE "", &unpack_data, 2, "1", "1", NULL); - crm_time_free(now); + free(now); g_hash_table_destroy(unpack_data.values); } diff --git a/lib/common/tests/nvpair/pcmk__unpack_nvpair_blocks_test.c b/lib/common/tests/nvpair/pcmk__unpack_nvpair_blocks_test.c index c2e9e7a9e9a..aea10f42125 100644 --- a/lib/common/tests/nvpair/pcmk__unpack_nvpair_blocks_test.c +++ b/lib/common/tests/nvpair/pcmk__unpack_nvpair_blocks_test.c @@ -74,8 +74,8 @@ null_xml(void **state) &rule_input, values, next_change, NULL); assert_int_equal(g_hash_table_size(values), 0); g_hash_table_destroy(values); - crm_time_free(now); - crm_time_free(next_change); + free(now); + free(next_change); } static void @@ -94,8 +94,8 @@ null_table(void **state) "id1", &rule_input, NULL, next_change, xml->doc)); pcmk__xml_free(xml); - crm_time_free(next_change); - crm_time_free(now); + free(next_change); + free(now); } static void @@ -118,8 +118,8 @@ rule_passes(void **state) assert_string_equal(g_hash_table_lookup(values, "name3"), "3"); pcmk__xml_free(xml); - crm_time_free(next_change); - crm_time_free(now); + free(next_change); + free(now); g_hash_table_destroy(values); } @@ -147,9 +147,9 @@ rule_fails(void **state) assert_int_equal(pcmk__time_compare(next_change, expected_next_change), 0); pcmk__xml_free(xml); - crm_time_free(now); - crm_time_free(next_change); - crm_time_free(expected_next_change); + free(now); + free(next_change); + free(expected_next_change); g_hash_table_destroy(values); } @@ -185,7 +185,7 @@ element_name(void **state) assert_string_equal(g_hash_table_lookup(values, "name3"), "3"); pcmk__xml_free(xml); - crm_time_free(now); + free(now); g_hash_table_destroy(values); } diff --git a/lib/common/tests/rules/pcmk__evaluate_condition_test.c b/lib/common/tests/rules/pcmk__evaluate_condition_test.c index 32d1ab23048..2a09b190596 100644 --- a/lib/common/tests/rules/pcmk__evaluate_condition_test.c +++ b/lib/common/tests/rules/pcmk__evaluate_condition_test.c @@ -53,7 +53,7 @@ null_invalid(void **state) assert_int_equal(pcmk__evaluate_condition(NULL, &rule_input, next_change), EINVAL); - crm_time_free(next_change); + free(next_change); } @@ -68,7 +68,7 @@ invalid_expression(void **state) assert_int_equal(pcmk__evaluate_condition(xml, &rule_input, next_change), pcmk_rc_unpack_error); - crm_time_free(next_change); + free(next_change); pcmk__xml_free(xml); } @@ -133,9 +133,9 @@ date_expression(void **state) assert_int_equal(pcmk__time_compare(next_change, reference), 0); rule_input.now = NULL; - crm_time_free(reference); - crm_time_free(next_change); - crm_time_free(now); + free(reference); + free(next_change); + free(now); } #define EXPR_RESOURCE \ diff --git a/lib/common/tests/rules/pcmk__evaluate_date_expression_test.c b/lib/common/tests/rules/pcmk__evaluate_date_expression_test.c index bed8fc3e998..042fcaabad6 100644 --- a/lib/common/tests/rules/pcmk__evaluate_date_expression_test.c +++ b/lib/common/tests/rules/pcmk__evaluate_date_expression_test.c @@ -47,14 +47,14 @@ assert_date_expression(const xmlNode *xml, const char *now_s, now = crm_time_new(now_s); assert_int_equal(pcmk__evaluate_date_expression(xml, now, next_change), reference_rc); - crm_time_free(now); + free(now); if (check_next_change) { crm_time_t *reference = crm_time_new(reference_s); assert_int_equal(pcmk__time_compare(next_change, reference), 0); - crm_time_free(reference); - crm_time_free(next_change); + free(reference); + free(next_change); } } @@ -73,7 +73,7 @@ null_invalid(void **state) assert_int_equal(pcmk__evaluate_date_expression(xml, NULL, NULL), EINVAL); assert_int_equal(pcmk__evaluate_date_expression(NULL, t, NULL), EINVAL); - crm_time_free(t); + free(t); pcmk__xml_free(xml); } @@ -237,7 +237,7 @@ range_missing(void **state) assert_int_equal(pcmk__evaluate_date_expression(xml, t, NULL), pcmk_rc_unpack_error); - crm_time_free(t); + free(t); pcmk__xml_free(xml); } diff --git a/lib/common/tests/rules/pcmk__evaluate_date_spec_test.c b/lib/common/tests/rules/pcmk__evaluate_date_spec_test.c index 8522f30be8b..08d9ff3a5d2 100644 --- a/lib/common/tests/rules/pcmk__evaluate_date_spec_test.c +++ b/lib/common/tests/rules/pcmk__evaluate_date_spec_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2020-2024 the Pacemaker project contributors + * Copyright 2020-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -24,7 +24,7 @@ run_one_test(const char *t, const char *x, int expected) assert_int_equal(pcmk__evaluate_date_spec(xml, tm), expected); - crm_time_free(tm); + free(tm); pcmk__xml_free(xml); } @@ -40,7 +40,7 @@ null_invalid(void **state) assert_int_equal(pcmk__evaluate_date_spec(xml, NULL), EINVAL); assert_int_equal(pcmk__evaluate_date_spec(NULL, tm), EINVAL); - crm_time_free(tm); + free(tm); pcmk__xml_free(xml); } diff --git a/lib/common/tests/rules/pcmk__unpack_duration_test.c b/lib/common/tests/rules/pcmk__unpack_duration_test.c index 978dd8d1bab..fba62996741 100644 --- a/lib/common/tests/rules/pcmk__unpack_duration_test.c +++ b/lib/common/tests/rules/pcmk__unpack_duration_test.c @@ -42,7 +42,7 @@ null_invalid(void **state) assert_int_equal(pcmk__unpack_duration(NULL, start, &end), EINVAL); assert_int_equal(pcmk__unpack_duration(NULL, NULL, &end), EINVAL); - crm_time_free(start); + free(start); pcmk__xml_free(duration); } @@ -55,8 +55,8 @@ nonnull_end_invalid(void **state) assert_int_equal(pcmk__unpack_duration(duration, start, &end), EINVAL); - crm_time_free(start); - crm_time_free(end); + free(start); + free(end); pcmk__xml_free(duration); } @@ -71,7 +71,7 @@ no_id(void **state) pcmk_rc_unpack_error); assert_null(end); - crm_time_free(start); + free(start); pcmk__xml_free(duration); } @@ -86,7 +86,7 @@ years_invalid(void **state) pcmk_rc_unpack_error); assert_null(end); - crm_time_free(start); + free(start); pcmk__xml_free(duration); } @@ -101,9 +101,9 @@ all_valid(void **state) assert_int_equal(pcmk__unpack_duration(duration, start, &end), pcmk_rc_ok); assert_int_equal(pcmk__time_compare(end, reference), 0); - crm_time_free(start); - crm_time_free(end); - crm_time_free(reference); + free(start); + free(end); + free(reference); pcmk__xml_free(duration); } diff --git a/lib/common/tests/rules/pcmk_evaluate_rule_test.c b/lib/common/tests/rules/pcmk_evaluate_rule_test.c index f0ce9d23b49..072bbf92c15 100644 --- a/lib/common/tests/rules/pcmk_evaluate_rule_test.c +++ b/lib/common/tests/rules/pcmk_evaluate_rule_test.c @@ -55,7 +55,7 @@ null_invalid(void **state) assert_int_equal(pcmk_evaluate_rule(NULL, &rule_input, next_change), EINVAL); - crm_time_free(next_change); + free(next_change); } #define RULE_OP_MISSING_ID \ @@ -74,7 +74,7 @@ id_missing(void **state) assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, next_change), pcmk_rc_unpack_error); - crm_time_free(next_change); + free(next_change); pcmk__xml_free(xml); } @@ -91,7 +91,7 @@ good_idref(void **state) assert_int_equal(pcmk_evaluate_rule(rule_xml, &rule_input, next_change), pcmk_rc_ok); - crm_time_free(next_change); + free(next_change); pcmk__xml_free(parent_xml); } @@ -106,7 +106,7 @@ bad_idref(void **state) assert_int_equal(pcmk_evaluate_rule(rule_xml, &rule_input, next_change), pcmk_rc_unpack_error); - crm_time_free(next_change); + free(next_change); pcmk__xml_free(parent_xml); } diff --git a/lib/common/tests/xml_element/pcmk__xe_get_datetime_test.c b/lib/common/tests/xml_element/pcmk__xe_get_datetime_test.c index 34c4103abd9..9c2b60b6ad9 100644 --- a/lib/common/tests/xml_element/pcmk__xe_get_datetime_test.c +++ b/lib/common/tests/xml_element/pcmk__xe_get_datetime_test.c @@ -55,7 +55,7 @@ nonnull_time_invalid(void **state) assert_int_equal(pcmk__xe_get_datetime(xml, ATTR_PRESENT, &t), EINVAL); - crm_time_free(t); + free(t); pcmk__xml_free(xml); } @@ -81,8 +81,8 @@ attr_valid(void **state) assert_int_equal(pcmk__xe_get_datetime(xml, ATTR_PRESENT, &t), pcmk_rc_ok); assert_int_equal(pcmk__time_compare(t, reference), 0); - crm_time_free(t); - crm_time_free(reference); + free(t); + free(reference); pcmk__xml_free(xml); } diff --git a/lib/common/tls.c b/lib/common/tls.c index 1d834a59812..19906924aff 100644 --- a/lib/common/tls.c +++ b/lib/common/tls.c @@ -475,7 +475,7 @@ pcmk__tls_check_cert_expiration(gnutls_session_t session) pcmk__time_log(LOG_WARNING, "TLS certificate will expire on", expiry_t, pcmk__time_fmt_date|pcmk__time_fmt_time); - crm_time_free(expiry_t); + free(expiry_t); } } diff --git a/lib/common/xml_element.c b/lib/common/xml_element.c index 91adf14ff80..c8aeba83689 100644 --- a/lib/common/xml_element.c +++ b/lib/common/xml_element.c @@ -1455,7 +1455,7 @@ pcmk__xe_set_timeval(xmlNode *xml, const char *sec_attr, const char *usec_attr, * (\p *t must be NULL initially) * * \return Standard Pacemaker return code - * \note The caller is responsible for freeing \p *t using crm_time_free(). + * \note The caller is responsible for freeing \p *t using \c free(). */ int pcmk__xe_get_datetime(const xmlNode *xml, const char *attr, crm_time_t **t) diff --git a/lib/lrmd/lrmd_alerts.c b/lib/lrmd/lrmd_alerts.c index 3fba9d47bd1..eeea294d0a5 100644 --- a/lib/lrmd/lrmd_alerts.c +++ b/lib/lrmd/lrmd_alerts.c @@ -1,5 +1,5 @@ /* - * Copyright 2015-2025 the Pacemaker project contributors + * Copyright 2015-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -184,7 +184,7 @@ exec_alert_list(lrmd_t *lrmd, const GList *alert_list, } } - crm_time_free(now_dt); + free(now_dt); if (any_failure) { return (any_success? -1 : -2); diff --git a/lib/pacemaker/pcmk_sched_location.c b/lib/pacemaker/pcmk_sched_location.c index 2977a8da8c4..2f20a79af24 100644 --- a/lib/pacemaker/pcmk_sched_location.c +++ b/lib/pacemaker/pcmk_sched_location.c @@ -385,7 +385,7 @@ unpack_rsc_location(xmlNode *xml_obj, pcmk_resource_t *rsc, pcmk__update_recheck_time(t, rsc->priv->scheduler, "location rule evaluation"); } - crm_time_free(next_change); + free(next_change); } } diff --git a/lib/pengine/pe_actions.c b/lib/pengine/pe_actions.c index ba550a42016..a1a38ee9bac 100644 --- a/lib/pengine/pe_actions.c +++ b/lib/pengine/pe_actions.c @@ -573,7 +573,7 @@ unpack_interval_origin(const char *value, const xmlNode *xml_obj, // Get seconds since origin (negative if origin is in the future) result = pcmk__time_get_seconds(now) - pcmk__time_get_seconds(origin); - crm_time_free(origin); + free(origin); // Calculate seconds from closest interval to now result = result % interval_sec; diff --git a/lib/pengine/status.c b/lib/pengine/status.c index c7da06f45ea..af33aff69b0 100644 --- a/lib/pengine/status.c +++ b/lib/pengine/status.c @@ -320,7 +320,7 @@ cleanup_calculations(pcmk_scheduler_t *scheduler) pcmk__free_param_checks(scheduler); g_list_free(scheduler->priv->stop_needed); - crm_time_free(scheduler->priv->now); + free(scheduler->priv->now); pcmk__xml_free(scheduler->input); pcmk__xml_free(scheduler->priv->failed); pcmk__xml_free(scheduler->priv->graph); diff --git a/lib/pengine/utils.c b/lib/pengine/utils.c index 3e77412e256..31bf393a537 100644 --- a/lib/pengine/utils.c +++ b/lib/pengine/utils.c @@ -718,7 +718,7 @@ pe__unpack_dataset_nvpairs(const xmlNode *xml_obj, const char *set_name, pcmk__update_recheck_time(recheck, scheduler, "rule evaluation"); } - crm_time_free(next_change); + free(next_change); } bool diff --git a/tools/crm_resource_ban.c b/tools/crm_resource_ban.c index 656cb17cf4e..f87e3309950 100644 --- a/tools/crm_resource_ban.c +++ b/tools/crm_resource_ban.c @@ -45,8 +45,8 @@ parse_cli_lifetime(pcmk__output_t *out, const char *move_lifetime) out->err(out, "Unable to add %s to current time\n" "Please report to " PACKAGE_BUGREPORT " as possible bug", move_lifetime); - crm_time_free(now); - crm_time_free(duration); + free(now); + free(duration); return NULL; } @@ -56,9 +56,9 @@ parse_cli_lifetime(pcmk__output_t *out, const char *move_lifetime) later_s = pcmk__time_text(later, time_flags); out->info(out, "Migration will take effect until: %s", later_s); - crm_time_free(duration); - crm_time_free(later); - crm_time_free(now); + free(duration); + free(later); + free(now); return later_s; } @@ -516,7 +516,7 @@ cli_resource_clear_all_expired(xmlNode *root, cib_t *cib_conn, const char *rsc, pcmk__xml_free(fragment); } - crm_time_free(end); + free(end); } done: @@ -524,6 +524,6 @@ cli_resource_clear_all_expired(xmlNode *root, cib_t *cib_conn, const char *rsc, g_string_free(buf, TRUE); } xmlXPathFreeObject(xpathObj); - crm_time_free(now); + free(now); return rc; } diff --git a/tools/crm_rule.c b/tools/crm_rule.c index 51e9e8758b3..b660331198b 100644 --- a/tools/crm_rule.c +++ b/tools/crm_rule.c @@ -204,7 +204,7 @@ main(int argc, char **argv) g_strfreev(processed_args); pcmk__free_arg_context(context); - crm_time_free(rule_date); + free(rule_date); pcmk__xml_free(input); pcmk__output_and_clear_error(&error, out); diff --git a/tools/iso8601.c b/tools/iso8601.c index a9366436a63..a1de22191b3 100644 --- a/tools/iso8601.c +++ b/tools/iso8601.c @@ -358,13 +358,13 @@ parse_period(const char *period_str, crm_time_t **start, crm_time_t **end) goto invalid; } - crm_time_free(diff); + free(diff); return pcmk_rc_ok; invalid: - crm_time_free(diff); - crm_time_free(*start); - crm_time_free(*end); + free(diff); + free(*start); + free(*end); return EINVAL; } @@ -491,8 +491,8 @@ main(int argc, char **argv) } out->message(out, "period", start, end, options.print_options); - crm_time_free(start); - crm_time_free(end); + free(start); + free(end); } if (date_time && duration) { @@ -519,7 +519,7 @@ main(int argc, char **argv) } free(dt_s); } - crm_time_free(later); + free(later); } else if (date_time && options.expected_s) { char *dt_s = pcmk__time_text(date_time, @@ -535,8 +535,8 @@ main(int argc, char **argv) } done: - crm_time_free(date_time); - crm_time_free(duration); + free(date_time); + free(duration); g_strfreev(processed_args); pcmk__free_arg_context(context); From 1b5ea9eea6997f26632f6c97c52d3055dbe5bddd Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 22:55:07 -0700 Subject: [PATCH 74/99] API: libcrmcommon: Deprecate crm_time_free() Use free() instead. Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 1 - include/crm/common/iso8601_compat.h | 3 +++ lib/common/iso8601.c | 15 ++++++--------- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 3f494d9ba1e..d2c0bffc397 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -52,7 +52,6 @@ typedef struct crm_time_s crm_time_t; * A timezone of 'Z' denotes UTC time */ crm_time_t *crm_time_new(const char *string); -void crm_time_free(crm_time_t * dt); /* Returns a new time object */ crm_time_t *pcmk_copy_time(const crm_time_t *source); diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index 78a60718052..0b068aec27a 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -142,6 +142,9 @@ long long crm_time_get_seconds(const crm_time_t *dt); //! \deprecated Do not use long long crm_time_get_seconds_since_epoch(const crm_time_t *dt); +//! \deprecated Use \c free() instead +void crm_time_free(crm_time_t *dt); + #ifdef __cplusplus } #endif diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index aa8afebda75..c13f317ee3f 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -675,15 +675,6 @@ pcmk__time_is_initialized(const crm_time_t *dt) || (dt->duration)); } -void -crm_time_free(crm_time_t * dt) -{ - if (dt == NULL) { - return; - } - free(dt); -} - void pcmk__time_log_as(const char *file, const char *function, int line, uint8_t level, const char *prefix, const crm_time_t *dt, @@ -2456,5 +2447,11 @@ crm_time_get_seconds_since_epoch(const crm_time_t *dt) return pcmk__time_to_unix(dt); } +void +crm_time_free(crm_time_t *dt) +{ + free(dt); +} + // LCOV_EXCL_STOP // End deprecated API From a909bd98d4eb6aa22fca7087d050b9225cdf4db7 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 22:58:42 -0700 Subject: [PATCH 75/99] Refactor: libcrmcommon: New pcmk__time_copy() To replace pcmk_copy_time(). Signed-off-by: Reid Wahl --- include/crm/common/iso8601_internal.h | 3 +++ lib/common/iso8601.c | 18 ++++++++++++------ lib/common/rules.c | 2 +- .../iso8601/pcmk__add_time_from_xml_test.c | 8 ++++---- .../iso8601/pcmk__set_time_if_earlier_test.c | 4 ++-- lib/pacemaker/pcmk_scheduler.c | 6 +++--- 6 files changed, 25 insertions(+), 16 deletions(-) diff --git a/include/crm/common/iso8601_internal.h b/include/crm/common/iso8601_internal.h index 5f908c31e76..5c32fa1f47d 100644 --- a/include/crm/common/iso8601_internal.h +++ b/include/crm/common/iso8601_internal.h @@ -54,6 +54,9 @@ enum pcmk__time_fmt_flags { }; bool pcmk__time_valid_year(int year); + +crm_time_t *pcmk__time_copy(const crm_time_t *source); + bool pcmk__time_is_initialized(const crm_time_t *dt); long long pcmk__time_get_seconds(const crm_time_t *dt); long long pcmk__time_to_unix(const crm_time_t *dt); diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index c13f317ee3f..6a56b727151 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -655,6 +655,15 @@ crm_time_new(const char *date_time) return parse_date(date_time); } +crm_time_t * +pcmk__time_copy(const crm_time_t *source) +{ + crm_time_t *target = pcmk__assert_alloc(1, sizeof(crm_time_t)); + + *target = *source; + return target; +} + /*! * \brief Check whether a time object has been initialized yet * @@ -1351,10 +1360,7 @@ pcmk__set_time_if_earlier(crm_time_t *target, const crm_time_t *source) crm_time_t * pcmk_copy_time(const crm_time_t *source) { - crm_time_t *target = pcmk__assert_alloc(1, sizeof(crm_time_t)); - - *target = *source; - return target; + return pcmk__time_copy(source); } /*! @@ -1423,7 +1429,7 @@ crm_time_add(const crm_time_t *dt, const crm_time_t *value) return NULL; } - answer = pcmk_copy_time(dt); + answer = pcmk__time_copy(dt); utc = copy_time_to_utc(value); crm_time_add_years(answer, utc->years); @@ -1566,7 +1572,7 @@ subtract_time(const crm_time_t *dt1, const crm_time_t *dt2, bool as_duration) return NULL; } - result = (as_duration? copy_time_to_utc(dt1) : pcmk_copy_time(dt1)); + result = (as_duration? copy_time_to_utc(dt1) : pcmk__time_copy(dt1)); result->duration = as_duration; utc = copy_time_to_utc(dt2); diff --git a/lib/common/rules.c b/lib/common/rules.c index 7327bffba0d..d209e6d085a 100644 --- a/lib/common/rules.c +++ b/lib/common/rules.c @@ -258,7 +258,7 @@ pcmk__unpack_duration(const xmlNode *duration, const crm_time_t *start, return pcmk_rc_unpack_error; } - *end = pcmk_copy_time(start); + *end = pcmk__time_copy(start); ADD_COMPONENT(pcmk__time_years); ADD_COMPONENT(pcmk__time_months); diff --git a/lib/common/tests/iso8601/pcmk__add_time_from_xml_test.c b/lib/common/tests/iso8601/pcmk__add_time_from_xml_test.c index 4fd5a252b72..0f9be77060d 100644 --- a/lib/common/tests/iso8601/pcmk__add_time_from_xml_test.c +++ b/lib/common/tests/iso8601/pcmk__add_time_from_xml_test.c @@ -41,7 +41,7 @@ static void null_xml_ok(void **state) { crm_time_t *t = crm_time_new("2024-01-01 15:00:00"); - crm_time_t *reference = pcmk_copy_time(t); + crm_time_t *reference = pcmk__time_copy(t); assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_years, NULL), pcmk_rc_ok); @@ -65,7 +65,7 @@ static void missing_attr(void **state) { crm_time_t *t = crm_time_new("2024-01-01 15:00:00"); - crm_time_t *reference = pcmk_copy_time(t); + crm_time_t *reference = pcmk__time_copy(t); xmlNode *xml = pcmk__xml_parse(YEARS_INVALID); assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_months, xml), @@ -81,7 +81,7 @@ static void invalid_attr(void **state) { crm_time_t *t = crm_time_new("2024-01-01 15:00:00"); - crm_time_t *reference = pcmk_copy_time(t); + crm_time_t *reference = pcmk__time_copy(t); xmlNode *xml = pcmk__xml_parse(YEARS_INVALID); assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_years, xml), @@ -97,7 +97,7 @@ static void out_of_range_attr(void **state) { crm_time_t *t = crm_time_new("2024-01-01 15:00:00"); - crm_time_t *reference = pcmk_copy_time(t); + crm_time_t *reference = pcmk__time_copy(t); xmlNode *xml = NULL; xml = pcmk__xml_parse(YEARS_TOO_BIG); diff --git a/lib/common/tests/iso8601/pcmk__set_time_if_earlier_test.c b/lib/common/tests/iso8601/pcmk__set_time_if_earlier_test.c index 6197a3b4a24..27b48fb9c5b 100644 --- a/lib/common/tests/iso8601/pcmk__set_time_if_earlier_test.c +++ b/lib/common/tests/iso8601/pcmk__set_time_if_earlier_test.c @@ -18,7 +18,7 @@ static void null_ok(void **state) { crm_time_t *target = crm_time_new("2024-01-01 00:30:00 +01:00"); - crm_time_t *target_copy = pcmk_copy_time(target); + crm_time_t *target_copy = pcmk__time_copy(target); // Should do nothing (just checking it doesn't assert or crash) pcmk__set_time_if_earlier(NULL, NULL); @@ -63,7 +63,7 @@ source_later(void **state) { crm_time_t *source = crm_time_new("2024-01-01 00:31:00 +01:00"); crm_time_t *target = crm_time_new("2024-01-01 00:30:00 +01:00"); - crm_time_t *target_copy = pcmk_copy_time(target); + crm_time_t *target_copy = pcmk__time_copy(target); pcmk__set_time_if_earlier(target, source); assert_int_equal(pcmk__time_compare(target, target_copy), 0); diff --git a/lib/pacemaker/pcmk_scheduler.c b/lib/pacemaker/pcmk_scheduler.c index c0d5ccd9e4e..2368485c6a9 100644 --- a/lib/pacemaker/pcmk_scheduler.c +++ b/lib/pacemaker/pcmk_scheduler.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2025 the Pacemaker project contributors + * Copyright 2004-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -834,8 +834,8 @@ pcmk__init_scheduler(pcmk__output_t *out, xmlNodePtr input, const crm_time_t *da // Make our own copy of the given crm_time_t object; otherwise // cluster_status() populates with the current time if (date != NULL) { - // pcmk_copy_time() guarantees non-NULL - new_scheduler->priv->now = pcmk_copy_time(date); + // pcmk__time_copy() guarantees non-NULL + new_scheduler->priv->now = pcmk__time_copy(date); } // Unpack everything From 42676ad689085c0569f7f03742a2209daa9884f9 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 23:02:05 -0700 Subject: [PATCH 76/99] API: libcrmcommon: Deprecate pcmk_copy_time() External callers have no need to copy a crm_time_t object. Pacemaker should not be used for general-purpose date/time manipulation. Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 1 - include/crm/common/iso8601_compat.h | 3 +++ lib/common/iso8601.c | 12 ++++++------ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index d2c0bffc397..27faaeda521 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,7 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); /* Returns a new time object */ -crm_time_t *pcmk_copy_time(const crm_time_t *source); crm_time_t *crm_time_add(const crm_time_t *dt, const crm_time_t *value); crm_time_t *crm_time_subtract(const crm_time_t *dt, const crm_time_t *value); diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index 0b068aec27a..407d04e9799 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -145,6 +145,9 @@ long long crm_time_get_seconds_since_epoch(const crm_time_t *dt); //! \deprecated Use \c free() instead void crm_time_free(crm_time_t *dt); +//! \deprecated Do not use +crm_time_t *pcmk_copy_time(const crm_time_t *source); + #ifdef __cplusplus } #endif diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 6a56b727151..4010b349749 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1357,12 +1357,6 @@ pcmk__set_time_if_earlier(crm_time_t *target, const crm_time_t *source) pcmk__time_log(LOG_TRACE, "target", target, flags); } -crm_time_t * -pcmk_copy_time(const crm_time_t *source) -{ - return pcmk__time_copy(source); -} - /*! * \internal * \brief Convert a \c time_t time to a \c crm_time_t time @@ -2459,5 +2453,11 @@ crm_time_free(crm_time_t *dt) free(dt); } +crm_time_t * +pcmk_copy_time(const crm_time_t *source) +{ + return pcmk__time_copy(source); +} + // LCOV_EXCL_STOP // End deprecated API From 84c17b087778df31a64984d2f9ec46a394a60961 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 23:06:45 -0700 Subject: [PATCH 77/99] Refactor: libcrmcommon: New pcmk__time_add() To replace crm_time_add(). Signed-off-by: Reid Wahl --- include/crm/common/iso8601_internal.h | 1 + lib/common/iso8601.c | 20 ++++++++++++++------ tools/crm_resource_ban.c | 2 +- tools/iso8601.c | 4 ++-- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/include/crm/common/iso8601_internal.h b/include/crm/common/iso8601_internal.h index 5c32fa1f47d..d43b0c18d24 100644 --- a/include/crm/common/iso8601_internal.h +++ b/include/crm/common/iso8601_internal.h @@ -68,6 +68,7 @@ const char *pcmk__readable_interval(guint interval_ms); crm_time_t *pcmk__time_parse_duration(const char *period_s); crm_time_t *pcmk__copy_timet(time_t source_sec); +crm_time_t *pcmk__time_add(const crm_time_t *dt, const crm_time_t *value); int pcmk__time_compare(const crm_time_t *a, const crm_time_t *b); diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 4010b349749..e265af539aa 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1413,15 +1413,12 @@ pcmk__copy_timet(time_t source_sec) } crm_time_t * -crm_time_add(const crm_time_t *dt, const crm_time_t *value) +pcmk__time_add(const crm_time_t *dt, const crm_time_t *value) { crm_time_t *utc = NULL; crm_time_t *answer = NULL; - if ((dt == NULL) || (value == NULL)) { - errno = EINVAL; - return NULL; - } + pcmk__assert((dt != NULL) && (value != NULL)); answer = pcmk__time_copy(dt); utc = copy_time_to_utc(value); @@ -1435,6 +1432,17 @@ crm_time_add(const crm_time_t *dt, const crm_time_t *value) return answer; } +crm_time_t * +crm_time_add(const crm_time_t *dt, const crm_time_t *value) +{ + if ((dt == NULL) || (value == NULL)) { + errno = EINVAL; + return NULL; + } + + return pcmk__time_add(dt, value); +} + /*! * \internal * \brief Return the XML attribute name corresponding to a time component @@ -2344,7 +2352,7 @@ crm_time_parse_period(const char *period_str) period->start = crm_time_subtract(period->end, period->diff); } else if (period->end == NULL) { - period->end = crm_time_add(period->start, period->diff); + period->end = pcmk__time_add(period->start, period->diff); } if (!pcmk__time_valid_year(period->start->years) diff --git a/tools/crm_resource_ban.c b/tools/crm_resource_ban.c index f87e3309950..264c5ee1d2a 100644 --- a/tools/crm_resource_ban.c +++ b/tools/crm_resource_ban.c @@ -40,7 +40,7 @@ parse_cli_lifetime(pcmk__output_t *out, const char *move_lifetime) } now = crm_time_new(NULL); - later = crm_time_add(now, duration); + later = pcmk__time_add(now, duration); if (later == NULL) { out->err(out, "Unable to add %s to current time\n" "Please report to " PACKAGE_BUGREPORT " as possible bug", diff --git a/tools/iso8601.c b/tools/iso8601.c index a1de22191b3..fa4c209cb84 100644 --- a/tools/iso8601.c +++ b/tools/iso8601.c @@ -341,7 +341,7 @@ parse_period(const char *period_str, crm_time_t **start, crm_time_t **end) *start = crm_time_subtract(*end, diff); } else if (*end == NULL) { - *end = crm_time_add(*start, diff); + *end = pcmk__time_add(*start, diff); } if (!pcmk__time_valid_year((*start)->years) || !valid_time(*start)) { @@ -496,7 +496,7 @@ main(int argc, char **argv) } if (date_time && duration) { - crm_time_t *later = crm_time_add(date_time, duration); + crm_time_t *later = pcmk__time_add(date_time, duration); if (later == NULL) { exit_code = CRM_EX_SOFTWARE; From 1211b756eac842ad26045a6bd313000b8f69fedf Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 23:08:31 -0700 Subject: [PATCH 78/99] API: libcrmcommon: Deprecate crm_time_add() External callers have no need to add to a crm_time_t object. Pacemaker should not be used for general-purpose date/time manipulation. Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 1 - include/crm/common/iso8601_compat.h | 3 +++ lib/common/iso8601.c | 22 +++++++++++----------- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 27faaeda521..bd05e121a6c 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,7 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); /* Returns a new time object */ -crm_time_t *crm_time_add(const crm_time_t *dt, const crm_time_t *value); crm_time_t *crm_time_subtract(const crm_time_t *dt, const crm_time_t *value); /* All crm_time_add_... functions support negative values */ diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index 407d04e9799..ef358931563 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -148,6 +148,9 @@ void crm_time_free(crm_time_t *dt); //! \deprecated Do not use crm_time_t *pcmk_copy_time(const crm_time_t *source); +//! \deprecated Do not use +crm_time_t *crm_time_add(const crm_time_t *dt, const crm_time_t *value); + #ifdef __cplusplus } #endif diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index e265af539aa..a34df91f07b 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1432,17 +1432,6 @@ pcmk__time_add(const crm_time_t *dt, const crm_time_t *value) return answer; } -crm_time_t * -crm_time_add(const crm_time_t *dt, const crm_time_t *value) -{ - if ((dt == NULL) || (value == NULL)) { - errno = EINVAL; - return NULL; - } - - return pcmk__time_add(dt, value); -} - /*! * \internal * \brief Return the XML attribute name corresponding to a time component @@ -2467,5 +2456,16 @@ pcmk_copy_time(const crm_time_t *source) return pcmk__time_copy(source); } +crm_time_t * +crm_time_add(const crm_time_t *dt, const crm_time_t *value) +{ + if ((dt == NULL) || (value == NULL)) { + errno = EINVAL; + return NULL; + } + + return pcmk__time_add(dt, value); +} + // LCOV_EXCL_STOP // End deprecated API From e2b29f5f582192474d1e7e573b7105be5158e2e5 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 23:12:49 -0700 Subject: [PATCH 79/99] Refactor: libcrmcommon: New pcmk__time_subtract() To replace crm_time_subtract(). Signed-off-by: Reid Wahl --- include/crm/common/iso8601_internal.h | 1 + lib/common/iso8601.c | 25 +++++++++++++++++++------ tools/iso8601.c | 2 +- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/include/crm/common/iso8601_internal.h b/include/crm/common/iso8601_internal.h index d43b0c18d24..b902b3af36f 100644 --- a/include/crm/common/iso8601_internal.h +++ b/include/crm/common/iso8601_internal.h @@ -69,6 +69,7 @@ const char *pcmk__readable_interval(guint interval_ms); crm_time_t *pcmk__time_parse_duration(const char *period_s); crm_time_t *pcmk__copy_timet(time_t source_sec); crm_time_t *pcmk__time_add(const crm_time_t *dt, const crm_time_t *value); +crm_time_t *pcmk__time_subtract(const crm_time_t *dt, const crm_time_t *value); int pcmk__time_compare(const crm_time_t *a, const crm_time_t *b); diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index a34df91f07b..efa3ec4248b 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1558,10 +1558,7 @@ subtract_time(const crm_time_t *dt1, const crm_time_t *dt2, bool as_duration) crm_time_t *result = NULL; crm_time_t *utc = NULL; - if ((dt1 == NULL) || (dt2 == NULL)) { - errno = EINVAL; - return NULL; - } + pcmk__assert((dt1 != NULL) && (dt2 != NULL)); result = (as_duration? copy_time_to_utc(dt1) : pcmk__time_copy(dt1)); result->duration = as_duration; @@ -1599,11 +1596,22 @@ subtract_time(const crm_time_t *dt1, const crm_time_t *dt2, bool as_duration) } crm_time_t * -crm_time_subtract(const crm_time_t *dt, const crm_time_t *value) +pcmk__time_subtract(const crm_time_t *dt, const crm_time_t *value) { return subtract_time(dt, value, false); } +crm_time_t * +crm_time_subtract(const crm_time_t *dt, const crm_time_t *value) +{ + if ((dt == NULL) || (value == NULL)) { + errno = EINVAL; + return NULL; + } + + return pcmk__time_subtract(dt, value); +} + #define do_cmp_field(l, r, field) \ if(rc == 0) { \ if(l->field > r->field) { \ @@ -2338,7 +2346,7 @@ crm_time_parse_period(const char *period_str) } if (period->start == NULL) { - period->start = crm_time_subtract(period->end, period->diff); + period->start = pcmk__time_subtract(period->end, period->diff); } else if (period->end == NULL) { period->end = pcmk__time_add(period->start, period->diff); @@ -2373,6 +2381,11 @@ crm_time_parse_period(const char *period_str) crm_time_t * crm_time_calculate_duration(const crm_time_t *dt, const crm_time_t *value) { + if ((dt == NULL) || (value == NULL)) { + errno = EINVAL; + return NULL; + } + return subtract_time(dt, value, true); } diff --git a/tools/iso8601.c b/tools/iso8601.c index fa4c209cb84..bb91d076832 100644 --- a/tools/iso8601.c +++ b/tools/iso8601.c @@ -338,7 +338,7 @@ parse_period(const char *period_str, crm_time_t **start, crm_time_t **end) } if (*start == NULL) { - *start = crm_time_subtract(*end, diff); + *start = pcmk__time_subtract(*end, diff); } else if (*end == NULL) { *end = pcmk__time_add(*start, diff); From f40d14cb850fd6d886ea5bef6cf842d088fe4eff Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 23:13:57 -0700 Subject: [PATCH 80/99] API: libcrmcommon: Deprecate crm_time_subtract() External callers have no need to subtract from a crm_time_t object. Pacemaker should not be used for general-purpose date/time manipulation. Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 3 --- include/crm/common/iso8601_compat.h | 3 +++ lib/common/iso8601.c | 22 +++++++++++----------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index bd05e121a6c..601ea683750 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -53,9 +53,6 @@ typedef struct crm_time_s crm_time_t; */ crm_time_t *crm_time_new(const char *string); -/* Returns a new time object */ -crm_time_t *crm_time_subtract(const crm_time_t *dt, const crm_time_t *value); - /* All crm_time_add_... functions support negative values */ void crm_time_add_seconds(crm_time_t * dt, int value); void crm_time_add_minutes(crm_time_t * dt, int value); diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index ef358931563..964a7fcf2ff 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -151,6 +151,9 @@ crm_time_t *pcmk_copy_time(const crm_time_t *source); //! \deprecated Do not use crm_time_t *crm_time_add(const crm_time_t *dt, const crm_time_t *value); +//! \deprecated Do not use +crm_time_t *crm_time_subtract(const crm_time_t *dt, const crm_time_t *value); + #ifdef __cplusplus } #endif diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index efa3ec4248b..964abd2ee5d 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1601,17 +1601,6 @@ pcmk__time_subtract(const crm_time_t *dt, const crm_time_t *value) return subtract_time(dt, value, false); } -crm_time_t * -crm_time_subtract(const crm_time_t *dt, const crm_time_t *value) -{ - if ((dt == NULL) || (value == NULL)) { - errno = EINVAL; - return NULL; - } - - return pcmk__time_subtract(dt, value); -} - #define do_cmp_field(l, r, field) \ if(rc == 0) { \ if(l->field > r->field) { \ @@ -2480,5 +2469,16 @@ crm_time_add(const crm_time_t *dt, const crm_time_t *value) return pcmk__time_add(dt, value); } +crm_time_t * +crm_time_subtract(const crm_time_t *dt, const crm_time_t *value) +{ + if ((dt == NULL) || (value == NULL)) { + errno = EINVAL; + return NULL; + } + + return pcmk__time_subtract(dt, value); +} + // LCOV_EXCL_STOP // End deprecated API From 5a035c2e6ae42528283ed4354d304bcfd74117fe Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 23:19:12 -0700 Subject: [PATCH 81/99] Refactor: libcrmcommon: New pcmk__time_add_seconds() To replace crm_time_add_seconds(). Signed-off-by: Reid Wahl --- lib/common/crmcommon_private.h | 3 + lib/common/iso8601.c | 64 +++++++++++-------- lib/common/rules.c | 4 +- lib/common/tests/iso8601/Makefile.am | 2 +- ...s_test.c => pcmk__time_add_seconds_test.c} | 6 +- 5 files changed, 47 insertions(+), 32 deletions(-) rename lib/common/tests/iso8601/{crm_time_add_seconds_test.c => pcmk__time_add_seconds_test.c} (97%) diff --git a/lib/common/crmcommon_private.h b/lib/common/crmcommon_private.h index adabc816961..55e58a50c8c 100644 --- a/lib/common/crmcommon_private.h +++ b/lib/common/crmcommon_private.h @@ -203,6 +203,9 @@ enum pcmk__time_component { pcmk__time_seconds, }; +G_GNUC_INTERNAL +void pcmk__time_add_seconds(crm_time_t *dt, int value); + G_GNUC_INTERNAL void pcmk__time_get_timeofday(const crm_time_t *dt, uint32_t *hour, uint32_t *minute, uint32_t *second); diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 964abd2ee5d..8da37b1dfbd 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -615,6 +615,35 @@ parse_date(const char *date_str) return NULL; } +/*! + * \internal + * \brief Add a given number of seconds to a date/time or duration + * + * \param[in,out] dt Date/time or duration to add seconds to + * \param[in] value Number of seconds to add + */ +void +pcmk__time_add_seconds(crm_time_t *dt, int value) +{ + int days = value / SECONDS_IN_DAY; + + pcmk__assert(dt != NULL); + + dt->seconds += value % SECONDS_IN_DAY; + + // Check whether the addition crossed a day boundary + if (dt->seconds > SECONDS_IN_DAY) { + ++days; + dt->seconds -= SECONDS_IN_DAY; + + } else if (dt->seconds < 0) { + --days; + dt->seconds += SECONDS_IN_DAY; + } + + crm_time_add_days(dt, days); +} + // Return value is guaranteed not to be NULL static crm_time_t * copy_time_to_utc(const crm_time_t *dt) @@ -633,7 +662,7 @@ copy_time_to_utc(const crm_time_t *dt) utc->offset = 0; if (dt->offset != 0) { - crm_time_add_seconds(utc, -dt->offset); + pcmk__time_add_seconds(utc, -dt->offset); } else { // Durations (the only things that can include months) never have a TZ @@ -1426,7 +1455,7 @@ pcmk__time_add(const crm_time_t *dt, const crm_time_t *value) crm_time_add_years(answer, utc->years); crm_time_add_months(answer, utc->months); crm_time_add_days(answer, utc->days); - crm_time_add_seconds(answer, utc->seconds); + pcmk__time_add_seconds(answer, utc->seconds); free(utc); return answer; @@ -1504,7 +1533,7 @@ component_fn(enum pcmk__time_component component) return crm_time_add_minutes; case pcmk__time_seconds: - return crm_time_add_seconds; + return pcmk__time_add_seconds; default: return NULL; @@ -1586,10 +1615,10 @@ subtract_time(const crm_time_t *dt1, const crm_time_t *dt2, bool as_duration) crm_time_add_days(result, -utc->days); if (utc->seconds == INT_MIN) { - crm_time_add_seconds(result, -1); + pcmk__time_add_seconds(result, -1); utc->seconds++; } - crm_time_add_seconds(result, -utc->seconds); + pcmk__time_add_seconds(result, -utc->seconds); free(utc); return result; @@ -1652,26 +1681,7 @@ pcmk__time_compare(const crm_time_t *a, const crm_time_t *b) void crm_time_add_seconds(crm_time_t *dt, int value) { - int days = value / SECONDS_IN_DAY; - - pcmk__assert(dt != NULL); - - pcmk__trace("Adding %d seconds (including %d whole day%s) to %d", value, - days, pcmk__plural_s(days), dt->seconds); - - dt->seconds += value % SECONDS_IN_DAY; - - // Check whether the addition crossed a day boundary - if (dt->seconds > SECONDS_IN_DAY) { - ++days; - dt->seconds -= SECONDS_IN_DAY; - - } else if (dt->seconds < 0) { - --days; - dt->seconds += SECONDS_IN_DAY; - } - - crm_time_add_days(dt, days); + pcmk__time_add_seconds(dt, value); } /*! @@ -1754,13 +1764,13 @@ crm_time_add_months(crm_time_t *dt, int value) void crm_time_add_minutes(crm_time_t *dt, int value) { - crm_time_add_seconds(dt, value * SECONDS_IN_MINUTE); + pcmk__time_add_seconds(dt, value * SECONDS_IN_MINUTE); } void crm_time_add_hours(crm_time_t *dt, int value) { - crm_time_add_seconds(dt, value * SECONDS_IN_HOUR); + pcmk__time_add_seconds(dt, value * SECONDS_IN_HOUR); } void diff --git a/lib/common/rules.c b/lib/common/rules.c index d209e6d085a..2950b2f8018 100644 --- a/lib/common/rules.c +++ b/lib/common/rules.c @@ -348,7 +348,7 @@ evaluate_in_range(const xmlNode *date_expression, const char *id, // Evaluation doesn't change until second after end if (next_change != NULL) { - crm_time_add_seconds(end, 1); + pcmk__time_add_seconds(end, 1); pcmk__set_time_if_earlier(next_change, end); } } @@ -398,7 +398,7 @@ evaluate_gt(const xmlNode *date_expression, const char *id, } // Evaluation doesn't change until second after start time - crm_time_add_seconds(start, 1); + pcmk__time_add_seconds(start, 1); pcmk__set_time_if_earlier(next_change, start); free(start); return pcmk_rc_before_range; diff --git a/lib/common/tests/iso8601/Makefile.am b/lib/common/tests/iso8601/Makefile.am index 8dd1ef06f48..c320fb59ca8 100644 --- a/lib/common/tests/iso8601/Makefile.am +++ b/lib/common/tests/iso8601/Makefile.am @@ -13,11 +13,11 @@ include $(top_srcdir)/mk/unittest.mk # Add "_test" to the end of all test program names to simplify .gitignore. check_PROGRAMS = crm_time_add_days_test -check_PROGRAMS += crm_time_add_seconds_test check_PROGRAMS += crm_time_add_years_test check_PROGRAMS += pcmk__add_time_from_xml_test check_PROGRAMS += pcmk__readable_interval_test check_PROGRAMS += pcmk__set_time_if_earlier_test +check_PROGRAMS += pcmk__time_add_seconds_test check_PROGRAMS += pcmk__time_format_hr_test check_PROGRAMS += pcmk__time_parse_duration_test diff --git a/lib/common/tests/iso8601/crm_time_add_seconds_test.c b/lib/common/tests/iso8601/pcmk__time_add_seconds_test.c similarity index 97% rename from lib/common/tests/iso8601/crm_time_add_seconds_test.c rename to lib/common/tests/iso8601/pcmk__time_add_seconds_test.c index 2b6d02733a5..9cf91ffb641 100644 --- a/lib/common/tests/iso8601/crm_time_add_seconds_test.c +++ b/lib/common/tests/iso8601/pcmk__time_add_seconds_test.c @@ -16,6 +16,8 @@ #include +#include "crmcommon_private.h" // pcmk__time_add_seconds + static void assert_add_seconds(const char *orig_date_time, int seconds, const char *expected_date_time) @@ -26,7 +28,7 @@ assert_add_seconds(const char *orig_date_time, int seconds, assert_non_null(orig); assert_non_null(expected); - crm_time_add_seconds(orig, seconds); + pcmk__time_add_seconds(orig, seconds); assert_int_equal(pcmk__time_compare(orig, expected), 0); free(orig); @@ -36,7 +38,7 @@ assert_add_seconds(const char *orig_date_time, int seconds, static void invalid_argument(void **state) { - pcmk__assert_asserts(crm_time_add_seconds(NULL, 1)); + pcmk__assert_asserts(pcmk__time_add_seconds(NULL, 1)); } static void From f95140c491a9259f6ba73ceb4cbf48e9a1f3aa30 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 23:20:13 -0700 Subject: [PATCH 82/99] API: libcrmcommon: Deprecate crm_time_add_seconds() External callers have no need to add seconds to a crm_time_t object. Pacemaker should not be used for general-purpose date/time manipulation. Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 1 - include/crm/common/iso8601_compat.h | 3 +++ lib/common/iso8601.c | 18 ++++++------------ 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 601ea683750..2dcfbbeb7e6 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,7 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); /* All crm_time_add_... functions support negative values */ -void crm_time_add_seconds(crm_time_t * dt, int value); void crm_time_add_minutes(crm_time_t * dt, int value); void crm_time_add_hours(crm_time_t * dt, int value); void crm_time_add_days(crm_time_t * dt, int value); diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index 964a7fcf2ff..ffe2d1c5136 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -154,6 +154,9 @@ crm_time_t *crm_time_add(const crm_time_t *dt, const crm_time_t *value); //! \deprecated Do not use crm_time_t *crm_time_subtract(const crm_time_t *dt, const crm_time_t *value); +//! \deprecated Do not use +void crm_time_add_seconds(crm_time_t *dt, int value); + #ifdef __cplusplus } #endif diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 8da37b1dfbd..60dcf6e4ed1 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1672,18 +1672,6 @@ pcmk__time_compare(const crm_time_t *a, const crm_time_t *b) return rc; } -/*! - * \brief Add a given number of seconds to a date/time or duration - * - * \param[in,out] dt Date/time or duration to add seconds to - * \param[in] value Number of seconds to add - */ -void -crm_time_add_seconds(crm_time_t *dt, int value) -{ - pcmk__time_add_seconds(dt, value); -} - /*! * \brief Add days to a date/time * @@ -2490,5 +2478,11 @@ crm_time_subtract(const crm_time_t *dt, const crm_time_t *value) return pcmk__time_subtract(dt, value); } +void +crm_time_add_seconds(crm_time_t *dt, int value) +{ + pcmk__time_add_seconds(dt, value); +} + // LCOV_EXCL_STOP // End deprecated API From 6346c49669d93be354a925b68251ca38ea650d58 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 23:23:11 -0700 Subject: [PATCH 83/99] API: libcrmcommon: Deprecate crm_time_add_minutes() External callers have no need to add minutes to a crm_time_t object. Pacemaker should not be used for general-purpose date/time manipulation. Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 1 - include/crm/common/iso8601_compat.h | 3 +++ lib/common/iso8601.c | 20 +++++++++++++------- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 2dcfbbeb7e6..18b4be84b75 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,7 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); /* All crm_time_add_... functions support negative values */ -void crm_time_add_minutes(crm_time_t * dt, int value); void crm_time_add_hours(crm_time_t * dt, int value); void crm_time_add_days(crm_time_t * dt, int value); void crm_time_add_weeks(crm_time_t * dt, int value); diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index ffe2d1c5136..54c058f4f69 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -157,6 +157,9 @@ crm_time_t *crm_time_subtract(const crm_time_t *dt, const crm_time_t *value); //! \deprecated Do not use void crm_time_add_seconds(crm_time_t *dt, int value); +//! \deprecated Do not use +void crm_time_add_minutes(crm_time_t *dt, int value); + #ifdef __cplusplus } #endif diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 60dcf6e4ed1..07006f871ec 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1500,6 +1500,12 @@ pcmk__time_component_attr(enum pcmk__time_component component) } } +static void +add_minutes(crm_time_t *dt, int value) +{ + pcmk__time_add_seconds(dt, value * SECONDS_IN_MINUTE); +} + typedef void (*component_fn_t)(crm_time_t *, int); /*! @@ -1530,7 +1536,7 @@ component_fn(enum pcmk__time_component component) return crm_time_add_hours; case pcmk__time_minutes: - return crm_time_add_minutes; + return add_minutes; case pcmk__time_seconds: return pcmk__time_add_seconds; @@ -1749,12 +1755,6 @@ crm_time_add_months(crm_time_t *dt, int value) dt->days = get_ordinal_days(year, month, day); } -void -crm_time_add_minutes(crm_time_t *dt, int value) -{ - pcmk__time_add_seconds(dt, value * SECONDS_IN_MINUTE); -} - void crm_time_add_hours(crm_time_t *dt, int value) { @@ -2484,5 +2484,11 @@ crm_time_add_seconds(crm_time_t *dt, int value) pcmk__time_add_seconds(dt, value); } +void +crm_time_add_minutes(crm_time_t *dt, int value) +{ + add_minutes(dt, value); +} + // LCOV_EXCL_STOP // End deprecated API From 1a8503c20b89f7311030d7f28caf2bde8e7cebde Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 23:25:08 -0700 Subject: [PATCH 84/99] API: libcrmcommon: Deprecate crm_time_add_hours() External callers have no need to add hours to a crm_time_t object. Pacemaker should not be used for general-purpose date/time manipulation. Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 1 - include/crm/common/iso8601_compat.h | 3 +++ lib/common/iso8601.c | 20 +++++++++++++------- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 18b4be84b75..330f0439c51 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,7 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); /* All crm_time_add_... functions support negative values */ -void crm_time_add_hours(crm_time_t * dt, int value); void crm_time_add_days(crm_time_t * dt, int value); void crm_time_add_weeks(crm_time_t * dt, int value); void crm_time_add_months(crm_time_t * dt, int value); diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index 54c058f4f69..3d1c02981f6 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -160,6 +160,9 @@ void crm_time_add_seconds(crm_time_t *dt, int value); //! \deprecated Do not use void crm_time_add_minutes(crm_time_t *dt, int value); +//! \deprecated Do not use +void crm_time_add_hours(crm_time_t *dt, int value); + #ifdef __cplusplus } #endif diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 07006f871ec..025eb7d7190 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1500,6 +1500,12 @@ pcmk__time_component_attr(enum pcmk__time_component component) } } +static void +add_hours(crm_time_t *dt, int value) +{ + pcmk__time_add_seconds(dt, value * SECONDS_IN_HOUR); +} + static void add_minutes(crm_time_t *dt, int value) { @@ -1533,7 +1539,7 @@ component_fn(enum pcmk__time_component component) return crm_time_add_days; case pcmk__time_hours: - return crm_time_add_hours; + return add_hours; case pcmk__time_minutes: return add_minutes; @@ -1755,12 +1761,6 @@ crm_time_add_months(crm_time_t *dt, int value) dt->days = get_ordinal_days(year, month, day); } -void -crm_time_add_hours(crm_time_t *dt, int value) -{ - pcmk__time_add_seconds(dt, value * SECONDS_IN_HOUR); -} - void crm_time_add_weeks(crm_time_t *dt, int value) { @@ -2490,5 +2490,11 @@ crm_time_add_minutes(crm_time_t *dt, int value) add_minutes(dt, value); } +void +crm_time_add_hours(crm_time_t *dt, int value) +{ + add_hours(dt, value); +} + // LCOV_EXCL_STOP // End deprecated API From 14f0516053506aa4f12184a69b85928fff1cc522 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 23:31:56 -0700 Subject: [PATCH 85/99] Refactor: libcrmcommon: New pcmk__time_add_days() To replace crm_time_add_days(). Signed-off-by: Reid Wahl --- lib/common/crmcommon_private.h | 3 + lib/common/iso8601.c | 87 +++++++++++-------- lib/common/tests/iso8601/Makefile.am | 4 +- ...days_test.c => pcmk__time_add_days_test.c} | 6 +- 4 files changed, 58 insertions(+), 42 deletions(-) rename lib/common/tests/iso8601/{crm_time_add_days_test.c => pcmk__time_add_days_test.c} (97%) diff --git a/lib/common/crmcommon_private.h b/lib/common/crmcommon_private.h index 55e58a50c8c..edd19e4f105 100644 --- a/lib/common/crmcommon_private.h +++ b/lib/common/crmcommon_private.h @@ -203,6 +203,9 @@ enum pcmk__time_component { pcmk__time_seconds, }; +G_GNUC_INTERNAL +void pcmk__time_add_days(crm_time_t *dt, int value); + G_GNUC_INTERNAL void pcmk__time_add_seconds(crm_time_t *dt, int value); diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 025eb7d7190..4167432f650 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -357,6 +357,43 @@ seconds_to_hms(int seconds_i, uint32_t *hours, uint32_t *minutes, } } +/*! + * \internal + * \brief Add days to a date/time + * + * \param[in,out] dt Time to modify + * \param[in] value Number of days to add (may be negative to subtract) + */ +void +pcmk__time_add_days(crm_time_t *dt, int value) +{ + pcmk__assert(dt != NULL); + + if (value > 0) { + while ((dt->days + (long long) value) > year_days(dt->years)) { + if (dt->years == INT_MAX) { + // Clip to latest we can handle + dt->days = year_days(dt->years); + return; + } + value -= year_days(dt->years); + dt->years++; + } + } else if (value < 0) { + const int min_days = dt->duration? 0 : 1; + + while ((dt->days + (long long) value) < min_days) { + if (dt->years <= 1) { + dt->days = 1; // Clip to earliest we can handle (no BCE) + return; + } + dt->years--; + value += year_days(dt->years); + } + } + dt->days += value; +} + /*! * \internal * \brief Parse the time portion of an ISO 8601 date/time string @@ -406,7 +443,7 @@ parse_time(const char *time_str, crm_time_t *a_time) if (a_time->seconds == SECONDS_IN_DAY) { // 24:00:00 == 00:00:00 of next day a_time->seconds = 0; - crm_time_add_days(a_time, 1); + pcmk__time_add_days(a_time, 1); } return true; } @@ -571,15 +608,15 @@ parse_date(const char *date_str) year, jan1, week, day, date_str); dt->years = year; - crm_time_add_days(dt, (week - 1) * 7); + pcmk__time_add_days(dt, (week - 1) * 7); if (jan1 <= 4) { - crm_time_add_days(dt, 1 - jan1); + pcmk__time_add_days(dt, 1 - jan1); } else { - crm_time_add_days(dt, 8 - jan1); + pcmk__time_add_days(dt, 8 - jan1); } - crm_time_add_days(dt, day); + pcmk__time_add_days(dt, day); } goto parse_time_segment; } @@ -641,7 +678,7 @@ pcmk__time_add_seconds(crm_time_t *dt, int value) dt->seconds += SECONDS_IN_DAY; } - crm_time_add_days(dt, days); + pcmk__time_add_days(dt, days); } // Return value is guaranteed not to be NULL @@ -1454,7 +1491,7 @@ pcmk__time_add(const crm_time_t *dt, const crm_time_t *value) crm_time_add_years(answer, utc->years); crm_time_add_months(answer, utc->months); - crm_time_add_days(answer, utc->days); + pcmk__time_add_days(answer, utc->days); pcmk__time_add_seconds(answer, utc->seconds); free(utc); @@ -1536,7 +1573,7 @@ component_fn(enum pcmk__time_component component) return crm_time_add_weeks; case pcmk__time_days: - return crm_time_add_days; + return pcmk__time_add_days; case pcmk__time_hours: return add_hours; @@ -1621,10 +1658,10 @@ subtract_time(const crm_time_t *dt1, const crm_time_t *dt2, bool as_duration) crm_time_add_months(result, -utc->months); if (utc->days == INT_MIN) { - crm_time_add_days(result, -1); + pcmk__time_add_days(result, -1); utc->days++; } - crm_time_add_days(result, -utc->days); + pcmk__time_add_days(result, -utc->days); if (utc->seconds == INT_MIN) { pcmk__time_add_seconds(result, -1); @@ -1693,33 +1730,7 @@ pcmk__time_compare(const crm_time_t *a, const crm_time_t *b) void crm_time_add_days(crm_time_t *dt, int value) { - pcmk__assert(dt != NULL); - - pcmk__trace("Adding %d days to %.4d-%.3d", value, dt->years, dt->days); - - if (value > 0) { - while ((dt->days + (long long) value) > year_days(dt->years)) { - if (dt->years == INT_MAX) { - // Clip to latest we can handle - dt->days = year_days(dt->years); - return; - } - value -= year_days(dt->years); - dt->years++; - } - } else if (value < 0) { - const int min_days = dt->duration? 0 : 1; - - while ((dt->days + (long long) value) < min_days) { - if (dt->years <= 1) { - dt->days = 1; // Clip to earliest we can handle (no BCE) - return; - } - dt->years--; - value += year_days(dt->years); - } - } - dt->days += value; + pcmk__time_add_days(dt, value); } void @@ -1764,7 +1775,7 @@ crm_time_add_months(crm_time_t *dt, int value) void crm_time_add_weeks(crm_time_t *dt, int value) { - crm_time_add_days(dt, value * 7); + pcmk__time_add_days(dt, value * 7); } void diff --git a/lib/common/tests/iso8601/Makefile.am b/lib/common/tests/iso8601/Makefile.am index c320fb59ca8..873accf45f0 100644 --- a/lib/common/tests/iso8601/Makefile.am +++ b/lib/common/tests/iso8601/Makefile.am @@ -12,11 +12,11 @@ include $(top_srcdir)/mk/tap.mk include $(top_srcdir)/mk/unittest.mk # Add "_test" to the end of all test program names to simplify .gitignore. -check_PROGRAMS = crm_time_add_days_test -check_PROGRAMS += crm_time_add_years_test +check_PROGRAMS = crm_time_add_years_test check_PROGRAMS += pcmk__add_time_from_xml_test check_PROGRAMS += pcmk__readable_interval_test check_PROGRAMS += pcmk__set_time_if_earlier_test +check_PROGRAMS += pcmk__time_add_days_test check_PROGRAMS += pcmk__time_add_seconds_test check_PROGRAMS += pcmk__time_format_hr_test check_PROGRAMS += pcmk__time_parse_duration_test diff --git a/lib/common/tests/iso8601/crm_time_add_days_test.c b/lib/common/tests/iso8601/pcmk__time_add_days_test.c similarity index 97% rename from lib/common/tests/iso8601/crm_time_add_days_test.c rename to lib/common/tests/iso8601/pcmk__time_add_days_test.c index 21b1106e796..6efaab17d43 100644 --- a/lib/common/tests/iso8601/crm_time_add_days_test.c +++ b/lib/common/tests/iso8601/pcmk__time_add_days_test.c @@ -16,6 +16,8 @@ #include +#include "crmcommon_private.h" // pcmk__time_add_days + static void assert_add_days(const char *orig_date_time, int days, const char *expected_date_time) @@ -26,7 +28,7 @@ assert_add_days(const char *orig_date_time, int days, assert_non_null(orig); assert_non_null(expected); - crm_time_add_days(orig, days); + pcmk__time_add_days(orig, days); assert_int_equal(pcmk__time_compare(orig, expected), 0); free(orig); @@ -36,7 +38,7 @@ assert_add_days(const char *orig_date_time, int days, static void invalid_argument(void **state) { - pcmk__assert_asserts(crm_time_add_days(NULL, 1)); + pcmk__assert_asserts(pcmk__time_add_days(NULL, 1)); } static void From b043bbfa07273d7d2442b7a2e5ba863e3341abdd Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 30 Apr 2026 23:33:34 -0700 Subject: [PATCH 86/99] API: libcrmcommon: Deprecate crm_time_add_days() External callers have no need to add days to a crm_time_t object. Pacemaker should not be used for general-purpose date/time manipulation. Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 1 - include/crm/common/iso8601_compat.h | 3 +++ lib/common/iso8601.c | 18 ++++++------------ 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 330f0439c51..bc94822a33d 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,7 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); /* All crm_time_add_... functions support negative values */ -void crm_time_add_days(crm_time_t * dt, int value); void crm_time_add_weeks(crm_time_t * dt, int value); void crm_time_add_months(crm_time_t * dt, int value); void crm_time_add_years(crm_time_t * dt, int value); diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index 3d1c02981f6..a1871dd5049 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -163,6 +163,9 @@ void crm_time_add_minutes(crm_time_t *dt, int value); //! \deprecated Do not use void crm_time_add_hours(crm_time_t *dt, int value); +//! \deprecated Do not use +void crm_time_add_days(crm_time_t *dt, int value); + #ifdef __cplusplus } #endif diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 4167432f650..d49d79edb11 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1721,18 +1721,6 @@ pcmk__time_compare(const crm_time_t *a, const crm_time_t *b) return rc; } -/*! - * \brief Add days to a date/time - * - * \param[in,out] dt Time to modify - * \param[in] value Number of days to add (may be negative to subtract) - */ -void -crm_time_add_days(crm_time_t *dt, int value) -{ - pcmk__time_add_days(dt, value); -} - void crm_time_add_months(crm_time_t *dt, int value) { @@ -2507,5 +2495,11 @@ crm_time_add_hours(crm_time_t *dt, int value) add_hours(dt, value); } +void +crm_time_add_days(crm_time_t *dt, int value) +{ + pcmk__time_add_days(dt, value); +} + // LCOV_EXCL_STOP // End deprecated API From 00b14d5e1fdd6924419a8aba4fe5619335805c82 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 1 May 2026 00:24:14 -0700 Subject: [PATCH 87/99] API: libcrmcommon: Deprecate crm_time_add_weeks() External callers have no need to add weeks to a crm_time_t object. Pacemaker should not be used for general-purpose date/time manipulation. Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 1 - include/crm/common/iso8601_compat.h | 3 +++ lib/common/iso8601.c | 21 +++++++++++++-------- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index bc94822a33d..665b65952bb 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,7 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); /* All crm_time_add_... functions support negative values */ -void crm_time_add_weeks(crm_time_t * dt, int value); void crm_time_add_months(crm_time_t * dt, int value); void crm_time_add_years(crm_time_t * dt, int value); diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index a1871dd5049..3234869a386 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -166,6 +166,9 @@ void crm_time_add_hours(crm_time_t *dt, int value); //! \deprecated Do not use void crm_time_add_days(crm_time_t *dt, int value); +//! \deprecated Do not use +void crm_time_add_weeks(crm_time_t *dt, int value); + #ifdef __cplusplus } #endif diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index d49d79edb11..363a8494d5f 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1537,6 +1537,12 @@ pcmk__time_component_attr(enum pcmk__time_component component) } } +static void +add_weeks(crm_time_t *dt, int value) +{ + pcmk__time_add_days(dt, value * 7); +} + static void add_hours(crm_time_t *dt, int value) { @@ -1570,7 +1576,7 @@ component_fn(enum pcmk__time_component component) return crm_time_add_months; case pcmk__time_weeks: - return crm_time_add_weeks; + return add_weeks; case pcmk__time_days: return pcmk__time_add_days; @@ -1587,7 +1593,6 @@ component_fn(enum pcmk__time_component component) default: return NULL; } - } /*! @@ -1760,12 +1765,6 @@ crm_time_add_months(crm_time_t *dt, int value) dt->days = get_ordinal_days(year, month, day); } -void -crm_time_add_weeks(crm_time_t *dt, int value) -{ - pcmk__time_add_days(dt, value * 7); -} - void crm_time_add_years(crm_time_t *dt, int value) { @@ -2501,5 +2500,11 @@ crm_time_add_days(crm_time_t *dt, int value) pcmk__time_add_days(dt, value); } +void +crm_time_add_weeks(crm_time_t *dt, int value) +{ + add_weeks(dt, value); +} + // LCOV_EXCL_STOP // End deprecated API From ed56b7de81b7eb63e954e2ebf2356d3599bb97b8 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 1 May 2026 00:32:47 -0700 Subject: [PATCH 88/99] API: libcrmcommon: Deprecate crm_time_add_months() External callers have no need to add months to a crm_time_t object. Pacemaker should not be used for general-purpose date/time manipulation. Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 1 - include/crm/common/iso8601_compat.h | 3 + lib/common/iso8601.c | 92 +++++++++++++++-------------- 3 files changed, 52 insertions(+), 44 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 665b65952bb..9bf76f8a6a8 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -54,7 +54,6 @@ typedef struct crm_time_s crm_time_t; crm_time_t *crm_time_new(const char *string); /* All crm_time_add_... functions support negative values */ -void crm_time_add_months(crm_time_t * dt, int value); void crm_time_add_years(crm_time_t * dt, int value); #ifdef __cplusplus diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index 3234869a386..fb1cb89f95b 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -169,6 +169,9 @@ void crm_time_add_days(crm_time_t *dt, int value); //! \deprecated Do not use void crm_time_add_weeks(crm_time_t *dt, int value); +//! \deprecated Do not use +void crm_time_add_months(crm_time_t *dt, int value); + #ifdef __cplusplus } #endif diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 363a8494d5f..e48356946b2 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1478,6 +1478,45 @@ pcmk__copy_timet(time_t source_sec) return target; } +static void +add_months(crm_time_t *dt, int value) +{ + uint32_t year = 0; + uint32_t month = 0; + uint32_t day = 0; + int days_in_month = 0; + + pcmk__time_get_ymd(dt, &year, &month, &day); + + if (value > 0) { + for (int i = value; i > 0; i--) { + month++; + if (month == 13) { + month = 1; + year++; + } + } + } else { + for (int i = value; i < 0; i++) { + month--; + if (month == 0) { + month = 12; + year--; + } + } + } + + days_in_month = days_in_month_year(month, year); + + if (days_in_month < day) { + // Preserve day-of-month unless the month doesn't have enough days + day = days_in_month; + } + + dt->years = year; + dt->days = get_ordinal_days(year, month, day); +} + crm_time_t * pcmk__time_add(const crm_time_t *dt, const crm_time_t *value) { @@ -1490,7 +1529,7 @@ pcmk__time_add(const crm_time_t *dt, const crm_time_t *value) utc = copy_time_to_utc(value); crm_time_add_years(answer, utc->years); - crm_time_add_months(answer, utc->months); + add_months(answer, utc->months); pcmk__time_add_days(answer, utc->days); pcmk__time_add_seconds(answer, utc->seconds); @@ -1573,7 +1612,7 @@ component_fn(enum pcmk__time_component component) return crm_time_add_years; case pcmk__time_months: - return crm_time_add_months; + return add_months; case pcmk__time_weeks: return add_weeks; @@ -1657,10 +1696,10 @@ subtract_time(const crm_time_t *dt1, const crm_time_t *dt2, bool as_duration) crm_time_add_years(result, -utc->years); if (utc->months == INT_MIN) { - crm_time_add_months(result, -1); + add_months(result, -1); utc->months++; } - crm_time_add_months(result, -utc->months); + add_months(result, -utc->months); if (utc->days == INT_MIN) { pcmk__time_add_days(result, -1); @@ -1726,45 +1765,6 @@ pcmk__time_compare(const crm_time_t *a, const crm_time_t *b) return rc; } -void -crm_time_add_months(crm_time_t *dt, int value) -{ - uint32_t year = 0; - uint32_t month = 0; - uint32_t day = 0; - int days_in_month = 0; - - pcmk__time_get_ymd(dt, &year, &month, &day); - - if (value > 0) { - for (int i = value; i > 0; i--) { - month++; - if (month == 13) { - month = 1; - year++; - } - } - } else { - for (int i = value; i < 0; i++) { - month--; - if (month == 0) { - month = 12; - year--; - } - } - } - - days_in_month = days_in_month_year(month, year); - - if (days_in_month < day) { - // Preserve day-of-month unless the month doesn't have enough days - day = days_in_month; - } - - dt->years = year; - dt->days = get_ordinal_days(year, month, day); -} - void crm_time_add_years(crm_time_t *dt, int value) { @@ -2506,5 +2506,11 @@ crm_time_add_weeks(crm_time_t *dt, int value) add_weeks(dt, value); } +void +crm_time_add_months(crm_time_t *dt, int value) +{ + add_months(dt, value); +} + // LCOV_EXCL_STOP // End deprecated API From d7aca018517a80a70546e1015f8f5258f54ca082 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 1 May 2026 00:38:26 -0700 Subject: [PATCH 89/99] Refactor: libcrmcommon: New pcmk__time_add_years() To replace crm_time_add_years(). Signed-off-by: Reid Wahl --- lib/common/crmcommon_private.h | 3 ++ lib/common/iso8601.c | 38 +++++++++++-------- lib/common/tests/iso8601/Makefile.am | 4 +- ...ars_test.c => pcmk__time_add_years_test.c} | 6 ++- 4 files changed, 31 insertions(+), 20 deletions(-) rename lib/common/tests/iso8601/{crm_time_add_years_test.c => pcmk__time_add_years_test.c} (92%) diff --git a/lib/common/crmcommon_private.h b/lib/common/crmcommon_private.h index edd19e4f105..b25e487cb04 100644 --- a/lib/common/crmcommon_private.h +++ b/lib/common/crmcommon_private.h @@ -231,6 +231,9 @@ int pcmk__add_time_from_xml(crm_time_t *t, enum pcmk__time_component component, G_GNUC_INTERNAL void pcmk__set_time_if_earlier(crm_time_t *target, const crm_time_t *source); +G_GNUC_INTERNAL +void pcmk__time_add_years(crm_time_t *dt, int value); + /* * IPC diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index e48356946b2..0f760e730f2 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1423,6 +1423,22 @@ pcmk__set_time_if_earlier(crm_time_t *target, const crm_time_t *source) pcmk__time_log(LOG_TRACE, "target", target, flags); } +void +pcmk__time_add_years(crm_time_t *dt, int value) +{ + pcmk__assert(dt != NULL); + + if ((value > 0) && ((dt->years + (long long) value) > INT_MAX)) { + dt->years = INT_MAX; + + } else if ((value < 0) && ((dt->years + (long long) value) < 1)) { + dt->years = 1; // Clip to earliest we can handle (no BCE) + + } else { + dt->years += value; + } +} + /*! * \internal * \brief Convert a \c time_t time to a \c crm_time_t time @@ -1445,7 +1461,7 @@ pcmk__copy_timet(time_t source_sec) if (source->tm_year > 0) { // Years since 1900 target->years = 1900; - crm_time_add_years(target, source->tm_year); + pcmk__time_add_years(target, source->tm_year); } if (source->tm_yday >= 0) { @@ -1528,7 +1544,7 @@ pcmk__time_add(const crm_time_t *dt, const crm_time_t *value) answer = pcmk__time_copy(dt); utc = copy_time_to_utc(value); - crm_time_add_years(answer, utc->years); + pcmk__time_add_years(answer, utc->years); add_months(answer, utc->months); pcmk__time_add_days(answer, utc->days); pcmk__time_add_seconds(answer, utc->seconds); @@ -1609,7 +1625,7 @@ component_fn(enum pcmk__time_component component) { switch (component) { case pcmk__time_years: - return crm_time_add_years; + return pcmk__time_add_years; case pcmk__time_months: return add_months; @@ -1690,10 +1706,10 @@ subtract_time(const crm_time_t *dt1, const crm_time_t *dt2, bool as_duration) // Avoid overflow when negating INT_MIN in calculations below if (utc->years == INT_MIN) { - crm_time_add_years(result, -1); + pcmk__time_add_years(result, -1); utc->years++; } - crm_time_add_years(result, -utc->years); + pcmk__time_add_years(result, -utc->years); if (utc->months == INT_MIN) { add_months(result, -1); @@ -1768,17 +1784,7 @@ pcmk__time_compare(const crm_time_t *a, const crm_time_t *b) void crm_time_add_years(crm_time_t *dt, int value) { - pcmk__assert(dt != NULL); - - if ((value > 0) && ((dt->years + (long long) value) > INT_MAX)) { - dt->years = INT_MAX; - - } else if ((value < 0) && ((dt->years + (long long) value) < 1)) { - dt->years = 1; // Clip to earliest we can handle (no BCE) - - } else { - dt->years += value; - } + pcmk__time_add_years(dt, value); } static void diff --git a/lib/common/tests/iso8601/Makefile.am b/lib/common/tests/iso8601/Makefile.am index 873accf45f0..77e947fa7bf 100644 --- a/lib/common/tests/iso8601/Makefile.am +++ b/lib/common/tests/iso8601/Makefile.am @@ -12,12 +12,12 @@ include $(top_srcdir)/mk/tap.mk include $(top_srcdir)/mk/unittest.mk # Add "_test" to the end of all test program names to simplify .gitignore. -check_PROGRAMS = crm_time_add_years_test -check_PROGRAMS += pcmk__add_time_from_xml_test +check_PROGRAMS = pcmk__add_time_from_xml_test check_PROGRAMS += pcmk__readable_interval_test check_PROGRAMS += pcmk__set_time_if_earlier_test check_PROGRAMS += pcmk__time_add_days_test check_PROGRAMS += pcmk__time_add_seconds_test +check_PROGRAMS += pcmk__time_add_years_test check_PROGRAMS += pcmk__time_format_hr_test check_PROGRAMS += pcmk__time_parse_duration_test diff --git a/lib/common/tests/iso8601/crm_time_add_years_test.c b/lib/common/tests/iso8601/pcmk__time_add_years_test.c similarity index 92% rename from lib/common/tests/iso8601/crm_time_add_years_test.c rename to lib/common/tests/iso8601/pcmk__time_add_years_test.c index f0fa451accb..c4110c04c69 100644 --- a/lib/common/tests/iso8601/crm_time_add_years_test.c +++ b/lib/common/tests/iso8601/pcmk__time_add_years_test.c @@ -16,6 +16,8 @@ #include +#include "crmcommon_private.h" // pcmk__time_add_days + static void assert_add_years(const char *orig_date_time, int years, const char *expected_date_time) @@ -26,7 +28,7 @@ assert_add_years(const char *orig_date_time, int years, assert_non_null(orig); assert_non_null(expected); - crm_time_add_years(orig, years); + pcmk__time_add_years(orig, years); assert_int_equal(pcmk__time_compare(orig, expected), 0); free(orig); @@ -36,7 +38,7 @@ assert_add_years(const char *orig_date_time, int years, static void invalid_argument(void **state) { - pcmk__assert_asserts(crm_time_add_years(NULL, 1)); + pcmk__assert_asserts(pcmk__time_add_years(NULL, 1)); } static void From c7ef9b79e8012598a9fa829edfaf4233576a5ca7 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 1 May 2026 00:39:29 -0700 Subject: [PATCH 90/99] API: libcrmcommon: Deprecate crm_time_add_years() External callers have no need to add years to a crm_time_t object. Pacemaker should not be used for general-purpose date/time manipulation. Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 3 --- include/crm/common/iso8601_compat.h | 3 +++ lib/common/iso8601.c | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index 9bf76f8a6a8..c34af98d331 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -53,9 +53,6 @@ typedef struct crm_time_s crm_time_t; */ crm_time_t *crm_time_new(const char *string); -/* All crm_time_add_... functions support negative values */ -void crm_time_add_years(crm_time_t * dt, int value); - #ifdef __cplusplus } #endif diff --git a/include/crm/common/iso8601_compat.h b/include/crm/common/iso8601_compat.h index fb1cb89f95b..5ef6f6915b2 100644 --- a/include/crm/common/iso8601_compat.h +++ b/include/crm/common/iso8601_compat.h @@ -172,6 +172,9 @@ void crm_time_add_weeks(crm_time_t *dt, int value); //! \deprecated Do not use void crm_time_add_months(crm_time_t *dt, int value); +//! \deprecated Do not use +void crm_time_add_years(crm_time_t *dt, int value); + #ifdef __cplusplus } #endif diff --git a/lib/common/iso8601.c b/lib/common/iso8601.c index 0f760e730f2..e5eeb1114e0 100644 --- a/lib/common/iso8601.c +++ b/lib/common/iso8601.c @@ -1781,12 +1781,6 @@ pcmk__time_compare(const crm_time_t *a, const crm_time_t *b) return rc; } -void -crm_time_add_years(crm_time_t *dt, int value) -{ - pcmk__time_add_years(dt, value); -} - static void ha_get_tm_time(struct tm *target, const crm_time_t *source) { @@ -2518,5 +2512,11 @@ crm_time_add_months(crm_time_t *dt, int value) add_months(dt, value); } +void +crm_time_add_years(crm_time_t *dt, int value) +{ + pcmk__time_add_years(dt, value); +} + // LCOV_EXCL_STOP // End deprecated API From 13cd9e7fd33fe3e16047081065473cd4e7ac3547 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 1 May 2026 00:41:57 -0700 Subject: [PATCH 91/99] Refactor: libcrmcommon: Drop unused includes from iso8601.h Signed-off-by: Reid Wahl --- include/crm/common/iso8601.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/include/crm/common/iso8601.h b/include/crm/common/iso8601.h index c34af98d331..caf807b08f6 100644 --- a/include/crm/common/iso8601.h +++ b/include/crm/common/iso8601.h @@ -10,11 +10,6 @@ #ifndef PCMK__CRM_COMMON_ISO8601__H #define PCMK__CRM_COMMON_ISO8601__H -#include -#include // bool -#include // uint32_t -#include - #ifdef __cplusplus extern "C" { #endif From e5821e71bf66eea3c279982d3fad2994611196f5 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 10 May 2026 07:39:12 -0700 Subject: [PATCH 92/99] Refactor: libcrmcommon: New pcmk__evaluate_rule() To replace pcmk_evaluate_rule(). Signed-off-by: Reid Wahl --- include/crm/common/rules_internal.h | 6 ++- lib/common/nvpair.c | 4 +- lib/common/rules.c | 24 +++++++++-- lib/common/tests/rules/Makefile.am | 2 +- ...rule_test.c => pcmk__evaluate_rule_test.c} | 42 +++++++++---------- lib/pacemaker/pcmk_sched_location.c | 4 +- lib/pengine/rules_compat.c | 6 +-- 7 files changed, 53 insertions(+), 35 deletions(-) rename lib/common/tests/rules/{pcmk_evaluate_rule_test.c => pcmk__evaluate_rule_test.c} (88%) diff --git a/include/crm/common/rules_internal.h b/include/crm/common/rules_internal.h index 91ea703febf..a00f38f2f10 100644 --- a/include/crm/common/rules_internal.h +++ b/include/crm/common/rules_internal.h @@ -15,10 +15,11 @@ #define PCMK__CRM_COMMON_RULES_INTERNAL__H #include // regmatch_t + #include // xmlNode -#include // enum expression_type, etc. #include // crm_time_t +#include // enum expression_type, etc. #ifdef __cplusplus extern "C" { @@ -41,6 +42,9 @@ int pcmk__evaluate_date_expression(const xmlNode *date_expression, int pcmk__evaluate_condition(xmlNode *expr, const pcmk_rule_input_t *rule_input, crm_time_t *next_change); +int pcmk__evaluate_rule(xmlNode *rule, const pcmk_rule_input_t *rule_input, + crm_time_t *next_change); + #ifdef __cplusplus } #endif diff --git a/lib/common/nvpair.c b/lib/common/nvpair.c index b1510b93e12..8a9414c539b 100644 --- a/lib/common/nvpair.c +++ b/lib/common/nvpair.c @@ -456,8 +456,8 @@ pcmk__unpack_nvpair_block(gpointer data, gpointer user_data) rule_xml = pcmk__xe_first_child(pair, PCMK_XE_RULE, NULL, NULL); if ((rule_xml != NULL) - && (pcmk_evaluate_rule(rule_xml, &(unpack_data->rule_input), - unpack_data->next_change) != pcmk_rc_ok)) { + && (pcmk__evaluate_rule(rule_xml, &unpack_data->rule_input, + unpack_data->next_change) != pcmk_rc_ok)) { return; } diff --git a/lib/common/rules.c b/lib/common/rules.c index 2950b2f8018..d4a932a9369 100644 --- a/lib/common/rules.c +++ b/lib/common/rules.c @@ -1259,7 +1259,7 @@ pcmk__evaluate_condition(xmlNode *condition, switch (pcmk__condition_type(condition)) { case pcmk__condition_rule: - return pcmk_evaluate_rule(condition, rule_input, next_change); + return pcmk__evaluate_rule(condition, rule_input, next_change); case pcmk__condition_attribute: case pcmk__condition_location: @@ -1290,6 +1290,7 @@ pcmk__evaluate_condition(xmlNode *condition, } /*! + * \internal * \brief Evaluate a single rule, including all its conditions * * \param[in,out] rule XML containing a rule definition or its id-ref @@ -1300,8 +1301,8 @@ pcmk__evaluate_condition(xmlNode *condition, * satisfied, some other value if it is not) */ int -pcmk_evaluate_rule(xmlNode *rule, const pcmk_rule_input_t *rule_input, - crm_time_t *next_change) +pcmk__evaluate_rule(xmlNode *rule, const pcmk_rule_input_t *rule_input, + crm_time_t *next_change) { bool empty = true; int rc = pcmk_rc_ok; @@ -1373,3 +1374,20 @@ pcmk_evaluate_rule(xmlNode *rule, const pcmk_rule_input_t *rule_input, ((rc == pcmk_rc_ok)? "" : "not ")); return rc; } + +/*! + * \brief Evaluate a single rule, including all its conditions + * + * \param[in,out] rule XML containing a rule definition or its id-ref + * \param[in] rule_input Values used to evaluate rule criteria + * \param[out] next_change If not NULL, set to when evaluation will change + * + * \return Standard Pacemaker return code (\c pcmk_rc_ok if the rule is + * satisfied, some other value if it is not) + */ +int +pcmk_evaluate_rule(xmlNode *rule, const pcmk_rule_input_t *rule_input, + crm_time_t *next_change) +{ + return pcmk__evaluate_rule(rule, rule_input, next_change); +} diff --git a/lib/common/tests/rules/Makefile.am b/lib/common/tests/rules/Makefile.am index 57fbd067ba3..343960f35ad 100644 --- a/lib/common/tests/rules/Makefile.am +++ b/lib/common/tests/rules/Makefile.am @@ -19,12 +19,12 @@ check_PROGRAMS += pcmk__evaluate_date_spec_test check_PROGRAMS += pcmk__evaluate_condition_test check_PROGRAMS += pcmk__evaluate_op_expression_test check_PROGRAMS += pcmk__evaluate_rsc_expression_test +check_PROGRAMS += pcmk__evaluate_rule_test check_PROGRAMS += pcmk__parse_combine_test check_PROGRAMS += pcmk__parse_comparison_test check_PROGRAMS += pcmk__parse_source_test check_PROGRAMS += pcmk__parse_type_test check_PROGRAMS += pcmk__replace_submatches_test check_PROGRAMS += pcmk__unpack_duration_test -check_PROGRAMS += pcmk_evaluate_rule_test TESTS = $(check_PROGRAMS) diff --git a/lib/common/tests/rules/pcmk_evaluate_rule_test.c b/lib/common/tests/rules/pcmk__evaluate_rule_test.c similarity index 88% rename from lib/common/tests/rules/pcmk_evaluate_rule_test.c rename to lib/common/tests/rules/pcmk__evaluate_rule_test.c index 072bbf92c15..b8dd891bbe2 100644 --- a/lib/common/tests/rules/pcmk_evaluate_rule_test.c +++ b/lib/common/tests/rules/pcmk__evaluate_rule_test.c @@ -45,14 +45,13 @@ null_invalid(void **state) xmlNode *xml = NULL; crm_time_t *next_change = pcmk__assert_alloc(1, sizeof(crm_time_t)); - assert_int_equal(pcmk_evaluate_rule(NULL, NULL, next_change), - EINVAL); + assert_int_equal(pcmk__evaluate_rule(NULL, NULL, next_change), EINVAL); xml = pcmk__xml_parse(RULE_OP); - assert_int_equal(pcmk_evaluate_rule(xml, NULL, next_change), EINVAL); + assert_int_equal(pcmk__evaluate_rule(xml, NULL, next_change), EINVAL); pcmk__xml_free(xml); - assert_int_equal(pcmk_evaluate_rule(NULL, &rule_input, next_change), + assert_int_equal(pcmk__evaluate_rule(NULL, &rule_input, next_change), EINVAL); free(next_change); @@ -71,7 +70,7 @@ id_missing(void **state) xmlNode *xml = pcmk__xml_parse(RULE_OP_MISSING_ID); crm_time_t *next_change = pcmk__assert_alloc(1, sizeof(crm_time_t)); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, next_change), + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, next_change), pcmk_rc_unpack_error); free(next_change); @@ -88,7 +87,7 @@ good_idref(void **state) crm_time_t *next_change = pcmk__assert_alloc(1, sizeof(crm_time_t)); pcmk__xe_set(rule_xml, PCMK_XA_ID_REF, "r"); - assert_int_equal(pcmk_evaluate_rule(rule_xml, &rule_input, next_change), + assert_int_equal(pcmk__evaluate_rule(rule_xml, &rule_input, next_change), pcmk_rc_ok); free(next_change); @@ -103,7 +102,7 @@ bad_idref(void **state) crm_time_t *next_change = pcmk__assert_alloc(1, sizeof(crm_time_t)); pcmk__xe_set(rule_xml, PCMK_XA_ID_REF, "x"); - assert_int_equal(pcmk_evaluate_rule(rule_xml, &rule_input, next_change), + assert_int_equal(pcmk__evaluate_rule(rule_xml, &rule_input, next_change), pcmk_rc_unpack_error); free(next_change); @@ -118,8 +117,7 @@ empty_default(void **state) // Currently acceptable xmlNode *xml = pcmk__xml_parse(RULE_EMPTY); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), - pcmk_rc_ok); + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); pcmk__xml_free(xml); } @@ -134,8 +132,7 @@ empty_and(void **state) // Currently acceptable xmlNode *xml = pcmk__xml_parse(RULE_EMPTY_AND); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), - pcmk_rc_ok); + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); pcmk__xml_free(xml); } @@ -149,8 +146,7 @@ empty_or(void **state) { xmlNode *xml = pcmk__xml_parse(RULE_EMPTY_OR); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), - pcmk_rc_ok); + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); pcmk__xml_free(xml); } @@ -170,7 +166,7 @@ default_boolean_op(void **state) // Defaults to PCMK_VALUE_AND xmlNode *xml = pcmk__xml_parse(RULE_DEFAULT_BOOLEAN_OP); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_op_unsatisfied); pcmk__xml_free(xml); @@ -191,7 +187,7 @@ invalid_boolean_op(void **state) { xmlNode *xml = pcmk__xml_parse(RULE_INVALID_BOOLEAN_OP); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_unpack_error); pcmk__xml_free(xml); @@ -212,7 +208,7 @@ and_passes(void **state) { xmlNode *xml = pcmk__xml_parse(RULE_AND_PASSES); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); pcmk__xml_free(xml); } @@ -229,7 +225,7 @@ lonely_and_passes(void **state) { xmlNode *xml = pcmk__xml_parse(RULE_LONELY_AND); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); pcmk__xml_free(xml); } @@ -249,7 +245,7 @@ and_one_fails(void **state) { xmlNode *xml = pcmk__xml_parse(RULE_AND_ONE_FAILS); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_op_unsatisfied); pcmk__xml_free(xml); @@ -270,7 +266,7 @@ and_two_fail(void **state) { xmlNode *xml = pcmk__xml_parse(RULE_AND_TWO_FAIL); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_op_unsatisfied); pcmk__xml_free(xml); @@ -291,7 +287,7 @@ or_one_passes(void **state) { xmlNode *xml = pcmk__xml_parse(RULE_OR_ONE_PASSES); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); pcmk__xml_free(xml); } @@ -311,7 +307,7 @@ or_two_pass(void **state) { xmlNode *xml = pcmk__xml_parse(RULE_OR_TWO_PASS); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); pcmk__xml_free(xml); } @@ -329,7 +325,7 @@ lonely_or_passes(void **state) { xmlNode *xml = pcmk__xml_parse(RULE_LONELY_OR); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok); pcmk__xml_free(xml); } @@ -349,7 +345,7 @@ or_fails(void **state) { xmlNode *xml = pcmk__xml_parse(RULE_OR_FAILS); - assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), + assert_int_equal(pcmk__evaluate_rule(xml, &rule_input, NULL), pcmk_rc_op_unsatisfied); pcmk__xml_free(xml); diff --git a/lib/pacemaker/pcmk_sched_location.c b/lib/pacemaker/pcmk_sched_location.c index 2f20a79af24..330c243781e 100644 --- a/lib/pacemaker/pcmk_sched_location.c +++ b/lib/pacemaker/pcmk_sched_location.c @@ -269,8 +269,8 @@ generate_location_rule(pcmk_resource_t *rsc, xmlNode *rule_xml, rule_input->rsc_params = pe_rsc_params(rsc, node, rsc->priv->scheduler); - if (pcmk_evaluate_rule(rule_xml, rule_input, - next_change) != pcmk_rc_ok) { + if (pcmk__evaluate_rule(rule_xml, rule_input, + next_change) != pcmk_rc_ok) { continue; } diff --git a/lib/pengine/rules_compat.c b/lib/pengine/rules_compat.c index 43fce159391..258839e4c5e 100644 --- a/lib/pengine/rules_compat.c +++ b/lib/pengine/rules_compat.c @@ -14,11 +14,11 @@ #include // xmlNode #include +#include // pcmk__evaluate_rule, etc. #include // crm_time_t #include // enum rsc_role_e - -#include #include // pcmk_rule_input_t, etc. +#include // Deprecated functions kept only for backward API compatibility // LCOV_EXCL_START @@ -34,7 +34,7 @@ test_rule(xmlNode * rule, GHashTable * node_hash, enum rsc_role_e role, crm_time .now = now, }; - return pcmk_evaluate_rule(rule, &rule_input, NULL) == pcmk_rc_ok; + return pcmk__evaluate_rule(rule, &rule_input, NULL) == pcmk_rc_ok; } /*! From dd3ce6a9a0baea391f10f465a05b009aa0e87bd6 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 10 May 2026 11:04:01 -0700 Subject: [PATCH 93/99] API: libcrmcommon: Deprecate pcmk_evaluate_rule() There doesn't seem to be much use case for this. We could come up with a contrived use case: a user wants to find out whether a rule will evaluate to true or false under some combination of current date/time, node attributes, resource parameters, etc. The user might want to test a rule that's already in the configuration or one that they're considering adding. However, we have pcmk_check_rule() and pcmk_check_rules(), which serve a similar but more limited purpose. Given an input CIB, a date/time object, and one or more rule IDs (for rules in the input CIB), those functions determine whether the rules woudl evaluate to true or false at the given date/time. Those functions can replace arbitrary calls to pcmk_evaluate_rule(). Instead of setting up your own pcmk_rule_input_t object for pcmk_evaluate_rule(), create the input CIB so that it contains the desired node attributes, resource parameters, etc. Then pass that input CIB and a date/time object to pcmk_check_rule(s)(). Some of the documentation for the pcmk_rule_input_t struct is a bit vague for external users. More importantly, it will be nice to be able to change the implementation without affecting any external users. Signed-off-by: Reid Wahl --- include/crm/common/Makefile.am | 1 + include/crm/common/rules.h | 8 +++--- include/crm/common/rules_compat.h | 39 ++++++++++++++++++++++++++++++ include/crm/pengine/rules_compat.h | 2 +- lib/common/rules.c | 18 ++++++-------- 5 files changed, 53 insertions(+), 15 deletions(-) create mode 100644 include/crm/common/rules_compat.h diff --git a/include/crm/common/Makefile.am b/include/crm/common/Makefile.am index cf66a79f240..06e6bdf2bdd 100644 --- a/include/crm/common/Makefile.am +++ b/include/crm/common/Makefile.am @@ -39,6 +39,7 @@ header_HEADERS += results.h header_HEADERS += results_compat.h header_HEADERS += roles.h header_HEADERS += rules.h +header_HEADERS += rules_compat.h header_HEADERS += scheduler.h header_HEADERS += scheduler_types.h header_HEADERS += schemas.h diff --git a/include/crm/common/rules.h b/include/crm/common/rules.h index ec311011878..24da65c1006 100644 --- a/include/crm/common/rules.h +++ b/include/crm/common/rules.h @@ -13,7 +13,6 @@ #include // regmatch_t #include // guint, GHashTable -#include // xmlNode #include // crm_time_t @@ -109,11 +108,12 @@ typedef struct pcmk_rule_input { int rsc_id_nmatches; } pcmk_rule_input_t; -int pcmk_evaluate_rule(xmlNode *rule, const pcmk_rule_input_t *rule_input, - crm_time_t *next_change); - #ifdef __cplusplus } #endif +#if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1) +#include +#endif + #endif // PCMK__CRM_COMMON_RULES__H diff --git a/include/crm/common/rules_compat.h b/include/crm/common/rules_compat.h new file mode 100644 index 00000000000..6ce9d23c0ae --- /dev/null +++ b/include/crm/common/rules_compat.h @@ -0,0 +1,39 @@ +/* + * Copyright 2004-2026 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU Lesser General Public License + * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. + */ + +#ifndef PCMK__CRM_COMMON_RULES_COMPAT__H +#define PCMK__CRM_COMMON_RULES_COMPAT__H + +#include // xmlNode + +#include // crm_time_t +#include // pcmk_rule_input_t + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \file + * \brief Deprecated Pacemaker rules API + * \ingroup core + * \deprecated Do not include this header directly. The nvpair APIs in this + * header, and the header itself, will be removed in a future + * release. + */ + +//! \deprecated Do not use +int pcmk_evaluate_rule(xmlNode *rule, const pcmk_rule_input_t *rule_input, + crm_time_t *next_change); + +#ifdef __cplusplus +} +#endif + +#endif // PCMK__CRM_COMMON_RULES_COMPAT__H diff --git a/include/crm/pengine/rules_compat.h b/include/crm/pengine/rules_compat.h index 4112075f33e..036bf0b4d89 100644 --- a/include/crm/pengine/rules_compat.h +++ b/include/crm/pengine/rules_compat.h @@ -30,7 +30,7 @@ extern "C" { */ // @COMPAT sbd's configure script checks for this (as of at least 1.5.2) -//! \deprecated Use pcmk_evaluate_rule() instead +//! \deprecated Do not use gboolean test_rule(xmlNode *rule, GHashTable *node_hash, enum rsc_role_e role, crm_time_t *now); diff --git a/lib/common/rules.c b/lib/common/rules.c index d4a932a9369..79e51cb51d4 100644 --- a/lib/common/rules.c +++ b/lib/common/rules.c @@ -1375,19 +1375,17 @@ pcmk__evaluate_rule(xmlNode *rule, const pcmk_rule_input_t *rule_input, return rc; } -/*! - * \brief Evaluate a single rule, including all its conditions - * - * \param[in,out] rule XML containing a rule definition or its id-ref - * \param[in] rule_input Values used to evaluate rule criteria - * \param[out] next_change If not NULL, set to when evaluation will change - * - * \return Standard Pacemaker return code (\c pcmk_rc_ok if the rule is - * satisfied, some other value if it is not) - */ +// Deprecated functions kept only for backward API compatibility +// LCOV_EXCL_START + +#include // pcmk_evaluate_rule + int pcmk_evaluate_rule(xmlNode *rule, const pcmk_rule_input_t *rule_input, crm_time_t *next_change) { return pcmk__evaluate_rule(rule, rule_input, next_change); } + +// LCOV_EXCL_STOP +// End deprecated API From 119fe2be8f2adad3870914015e7a46093c810141 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 10 May 2026 11:58:42 -0700 Subject: [PATCH 94/99] Refactor: libcrmcommon: New pcmk__rule_input_t To replace pcmk_rule_input_t. Also add a conversion function, so that we can change the internal pcmk__rule_input_t definition later. Signed-off-by: Reid Wahl --- include/crm/common/rules_internal.h | 56 +++++++++++++++++++++++++++++ lib/common/rules.c | 31 ++++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/include/crm/common/rules_internal.h b/include/crm/common/rules_internal.h index a00f38f2f10..8aaa1e95a7b 100644 --- a/include/crm/common/rules_internal.h +++ b/include/crm/common/rules_internal.h @@ -16,6 +16,7 @@ #include // regmatch_t +#include // GHashTable #include // xmlNode #include // crm_time_t @@ -31,6 +32,61 @@ enum pcmk__combine { pcmk__combine_or, }; +/*! + * \internal + * \brief Data used to evaluate a rule (any \c NULL items are ignored) + */ +typedef struct { + // Used to evaluate date expressions + const crm_time_t *now; //!< Current time to use for rule evaluation + + // Used to evaluate resource type expressions + const char *rsc_standard; //!< Resource standard that rule applies to + const char *rsc_provider; //!< Resource provider that rule applies to + const char *rsc_agent; //!< Resource agent that rule applies to + + // Used to evaluate operation type expressions + const char *op_name; //!< Operation name that rule applies to + unsigned int op_interval_ms; //!< Operation interval that rule applies to + + // Remaining members are used to evaluate node attribute expressions + + /*! + * Node attributes for rule evaluation purposes + * + * \note Though not const, this is used only with \c g_hash_table_lookup(). + */ + GHashTable *node_attrs; + + // Remaining members are used only within location constraint rules + + /*! + * Resource parameters that can be used as the reference value source + * + * \note Though not const, this is used only with \c g_hash_table_lookup(). + */ + GHashTable *rsc_params; + + /*! + * Resource meta-attributes that can be used as the reference value source + * + * \note Though not const, this is used only with \c g_hash_table_lookup(). + */ + GHashTable *rsc_meta; + + //! Resource ID to compare against a location constraint's resource pattern + const char *rsc_id; + + //! Resource pattern submatches (as set by \c regexec()) for \c rsc_id + const regmatch_t *rsc_id_submatches; + + //! Number of entries in rsc_id_submatches + int rsc_id_nmatches; +} pcmk__rule_input_t; + +void pcmk__rule_input_convert(const pcmk_rule_input_t *source, + pcmk__rule_input_t *target); + enum expression_type pcmk__condition_type(const xmlNode *condition); char *pcmk__replace_submatches(const char *string, const char *match, const regmatch_t submatches[], int nmatches); diff --git a/lib/common/rules.c b/lib/common/rules.c index 79e51cb51d4..b65793f4e0f 100644 --- a/lib/common/rules.c +++ b/lib/common/rules.c @@ -65,6 +65,37 @@ pcmk__condition_type(const xmlNode *condition) return pcmk__condition_attribute; } +/*! + * \internal + * \brief Convert a \c pcmk_rule_input_t to a \c pcmk__rule_input_t + * + * \param[in] source Source object + * \param[out] target Target object + */ +void +pcmk__rule_input_convert(const pcmk_rule_input_t *source, + pcmk__rule_input_t *target) +{ + /* @COMPAT Drop this function when pcmk_rule_input_t is dropped. It exists + * purely for as a helper for deprecated API. + */ + pcmk__assert((source != NULL) && (target != NULL)); + + // Non-numeric fields are const and are shared between source and target + target->now = source->now; + target->rsc_standard = source->rsc_standard; + target->rsc_provider = source->rsc_provider; + target->rsc_agent = source->rsc_agent; + target->op_name = source->op_name; + target->op_interval_ms = source->op_interval_ms; + target->node_attrs = source->node_attrs; + target->rsc_params = source->rsc_params; + target->rsc_meta = source->rsc_meta; + target->rsc_id = source->rsc_id; + target->rsc_id_submatches = source->rsc_id_submatches; + target->rsc_id_nmatches = source->rsc_id_nmatches; +} + /*! * \internal * \brief Get parent XML element's ID for logging purposes From 6121efd377e5dc3dc19fe82dddbdd8b37eb89613 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 10 May 2026 12:26:26 -0700 Subject: [PATCH 95/99] Refactor: libcrmcommon: pcmk__evaluate_rule() takes pcmk__rule_input_t This requires changing the helper functions too, some of which are non-static. However, doing this for pcmk__evaluate_rule() and all its helpers at the same time, turned out to be cleaner than doing them one by one. Signed-off-by: Reid Wahl --- include/crm/common/rules_internal.h | 5 ++-- lib/common/crmcommon_private.h | 7 +++--- lib/common/nvpair.c | 5 +++- lib/common/rules.c | 24 ++++++++++++------- .../pcmk__evaluate_attr_expression_test.c | 9 ++++--- .../rules/pcmk__evaluate_condition_test.c | 2 +- .../rules/pcmk__evaluate_op_expression_test.c | 4 ++-- .../pcmk__evaluate_rsc_expression_test.c | 4 ++-- .../tests/rules/pcmk__evaluate_rule_test.c | 2 +- lib/pacemaker/pcmk_sched_location.c | 7 +++--- lib/pengine/rules_compat.c | 2 +- 11 files changed, 42 insertions(+), 29 deletions(-) diff --git a/include/crm/common/rules_internal.h b/include/crm/common/rules_internal.h index 8aaa1e95a7b..966f27888e9 100644 --- a/include/crm/common/rules_internal.h +++ b/include/crm/common/rules_internal.h @@ -95,10 +95,11 @@ enum pcmk__combine pcmk__parse_combine(const char *combine); int pcmk__evaluate_date_expression(const xmlNode *date_expression, const crm_time_t *now, crm_time_t *next_change); -int pcmk__evaluate_condition(xmlNode *expr, const pcmk_rule_input_t *rule_input, +int pcmk__evaluate_condition(xmlNode *expr, + const pcmk__rule_input_t *rule_input, crm_time_t *next_change); -int pcmk__evaluate_rule(xmlNode *rule, const pcmk_rule_input_t *rule_input, +int pcmk__evaluate_rule(xmlNode *rule, const pcmk__rule_input_t *rule_input, crm_time_t *next_change); #ifdef __cplusplus diff --git a/lib/common/crmcommon_private.h b/lib/common/crmcommon_private.h index b25e487cb04..cfffcaf977c 100644 --- a/lib/common/crmcommon_private.h +++ b/lib/common/crmcommon_private.h @@ -28,7 +28,6 @@ #include // crm_time_t #include // mainloop_io_t #include // crm_exit_t -#include // pcmk_rule_input_t #ifdef __cplusplus extern "C" { @@ -448,15 +447,15 @@ int pcmk__evaluate_date_spec(const xmlNode *date_spec, const crm_time_t *now); G_GNUC_INTERNAL int pcmk__evaluate_attr_expression(const xmlNode *expression, - const pcmk_rule_input_t *rule_input); + const pcmk__rule_input_t *rule_input); G_GNUC_INTERNAL int pcmk__evaluate_rsc_expression(const xmlNode *expr, - const pcmk_rule_input_t *rule_input); + const pcmk__rule_input_t *rule_input); G_GNUC_INTERNAL int pcmk__evaluate_op_expression(const xmlNode *expr, - const pcmk_rule_input_t *rule_input); + const pcmk__rule_input_t *rule_input); /* diff --git a/lib/common/nvpair.c b/lib/common/nvpair.c index 8a9414c539b..fc4bd366271 100644 --- a/lib/common/nvpair.c +++ b/lib/common/nvpair.c @@ -448,6 +448,7 @@ pcmk__unpack_nvpair_block(gpointer data, gpointer user_data) { xmlNode *pair = data; pcmk__nvpair_unpack_t *unpack_data = user_data; + pcmk__rule_input_t new_input = { NULL, }; xmlNode *rule_xml = NULL; @@ -455,8 +456,10 @@ pcmk__unpack_nvpair_block(gpointer data, gpointer user_data) && (unpack_data->values != NULL)); rule_xml = pcmk__xe_first_child(pair, PCMK_XE_RULE, NULL, NULL); + pcmk__rule_input_convert(&unpack_data->rule_input, &new_input); + if ((rule_xml != NULL) - && (pcmk__evaluate_rule(rule_xml, &unpack_data->rule_input, + && (pcmk__evaluate_rule(rule_xml, &new_input, unpack_data->next_change) != pcmk_rc_ok)) { return; } diff --git a/lib/common/rules.c b/lib/common/rules.c index b65793f4e0f..982957340e5 100644 --- a/lib/common/rules.c +++ b/lib/common/rules.c @@ -946,7 +946,7 @@ evaluate_attr_comparison(const char *actual, const char *reference, */ static const char * value_from_source(const char *value, enum pcmk__reference_source source, - const pcmk_rule_input_t *rule_input) + const pcmk__rule_input_t *rule_input) { GHashTable *table = NULL; @@ -984,7 +984,7 @@ value_from_source(const char *value, enum pcmk__reference_source source, */ int pcmk__evaluate_attr_expression(const xmlNode *expression, - const pcmk_rule_input_t *rule_input) + const pcmk__rule_input_t *rule_input) { const char *id = NULL; const char *op = NULL; @@ -1138,7 +1138,7 @@ pcmk__evaluate_attr_expression(const xmlNode *expression, */ int pcmk__evaluate_rsc_expression(const xmlNode *rsc_expression, - const pcmk_rule_input_t *rule_input) + const pcmk__rule_input_t *rule_input) { const char *id = NULL; const char *standard = NULL; @@ -1207,7 +1207,7 @@ pcmk__evaluate_rsc_expression(const xmlNode *rsc_expression, */ int pcmk__evaluate_op_expression(const xmlNode *op_expression, - const pcmk_rule_input_t *rule_input) + const pcmk__rule_input_t *rule_input) { const char *id = NULL; const char *name = NULL; @@ -1280,10 +1280,9 @@ pcmk__evaluate_op_expression(const xmlNode *op_expression, */ int pcmk__evaluate_condition(xmlNode *condition, - const pcmk_rule_input_t *rule_input, + const pcmk__rule_input_t *rule_input, crm_time_t *next_change) { - if ((condition == NULL) || (rule_input == NULL)) { return EINVAL; } @@ -1315,7 +1314,7 @@ pcmk__evaluate_condition(xmlNode *condition, pcmk__config_err("Treating rule condition %s as not passing " "because %s is not a valid condition type", pcmk__s(pcmk__xe_id(condition), "without ID"), - (const char *) condition->name); + condition->name); return pcmk_rc_unpack_error; } } @@ -1332,7 +1331,7 @@ pcmk__evaluate_condition(xmlNode *condition, * satisfied, some other value if it is not) */ int -pcmk__evaluate_rule(xmlNode *rule, const pcmk_rule_input_t *rule_input, +pcmk__evaluate_rule(xmlNode *rule, const pcmk__rule_input_t *rule_input, crm_time_t *next_change) { bool empty = true; @@ -1415,7 +1414,14 @@ int pcmk_evaluate_rule(xmlNode *rule, const pcmk_rule_input_t *rule_input, crm_time_t *next_change) { - return pcmk__evaluate_rule(rule, rule_input, next_change); + pcmk__rule_input_t new_input = { NULL, }; + + if (rule_input == NULL) { + return EINVAL; + } + + pcmk__rule_input_convert(rule_input, &new_input); + return pcmk__evaluate_rule(rule, &new_input, next_change); } // LCOV_EXCL_STOP diff --git a/lib/common/tests/rules/pcmk__evaluate_attr_expression_test.c b/lib/common/tests/rules/pcmk__evaluate_attr_expression_test.c index b229893aa59..01813dd0d9f 100644 --- a/lib/common/tests/rules/pcmk__evaluate_attr_expression_test.c +++ b/lib/common/tests/rules/pcmk__evaluate_attr_expression_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 the Pacemaker project contributors + * Copyright 2024-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -10,10 +10,13 @@ #include #include + #include -#include +#include // pcmk__rule_*, pcmk__xml_*, etc. #include +#include // PCMK_XA_*, PCMK_XE_*, etc. + #include "crmcommon_private.h" /* @@ -27,7 +30,7 @@ static const regmatch_t submatches[] = { { .rm_so = 7, .rm_eo = 12 }, // %1 = "north" }; -static pcmk_rule_input_t rule_input = { +static pcmk__rule_input_t rule_input = { // These are the only members used to evaluate attribute expressions // Used to replace submatches in attribute name diff --git a/lib/common/tests/rules/pcmk__evaluate_condition_test.c b/lib/common/tests/rules/pcmk__evaluate_condition_test.c index 2a09b190596..40965ee32d8 100644 --- a/lib/common/tests/rules/pcmk__evaluate_condition_test.c +++ b/lib/common/tests/rules/pcmk__evaluate_condition_test.c @@ -19,7 +19,7 @@ * Shared data */ -static pcmk_rule_input_t rule_input = { +static pcmk__rule_input_t rule_input = { .rsc_standard = PCMK_RESOURCE_CLASS_OCF, .rsc_provider = "heartbeat", .rsc_agent = "IPaddr2", diff --git a/lib/common/tests/rules/pcmk__evaluate_op_expression_test.c b/lib/common/tests/rules/pcmk__evaluate_op_expression_test.c index e04497f22f2..40de0f30e00 100644 --- a/lib/common/tests/rules/pcmk__evaluate_op_expression_test.c +++ b/lib/common/tests/rules/pcmk__evaluate_op_expression_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 the Pacemaker project contributors + * Copyright 2024-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -20,7 +20,7 @@ * Shared data */ -static pcmk_rule_input_t rule_input = { +static pcmk__rule_input_t rule_input = { // These are the only members used to evaluate operation expressions .op_name = PCMK_ACTION_MONITOR, .op_interval_ms = 10000, diff --git a/lib/common/tests/rules/pcmk__evaluate_rsc_expression_test.c b/lib/common/tests/rules/pcmk__evaluate_rsc_expression_test.c index e1d24853e5c..025aad58e0b 100644 --- a/lib/common/tests/rules/pcmk__evaluate_rsc_expression_test.c +++ b/lib/common/tests/rules/pcmk__evaluate_rsc_expression_test.c @@ -1,5 +1,5 @@ /* - * Copyright 2024 the Pacemaker project contributors + * Copyright 2024-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -20,7 +20,7 @@ * Shared data */ -static pcmk_rule_input_t rule_input = { +static pcmk__rule_input_t rule_input = { // These are the only members used to evaluate resource expressions .rsc_standard = PCMK_RESOURCE_CLASS_OCF, .rsc_provider = "heartbeat", diff --git a/lib/common/tests/rules/pcmk__evaluate_rule_test.c b/lib/common/tests/rules/pcmk__evaluate_rule_test.c index b8dd891bbe2..96c53fc3266 100644 --- a/lib/common/tests/rules/pcmk__evaluate_rule_test.c +++ b/lib/common/tests/rules/pcmk__evaluate_rule_test.c @@ -19,7 +19,7 @@ * Shared data */ -static pcmk_rule_input_t rule_input = { +static pcmk__rule_input_t rule_input = { .rsc_standard = PCMK_RESOURCE_CLASS_OCF, .rsc_provider = "heartbeat", .rsc_agent = "IPaddr2", diff --git a/lib/pacemaker/pcmk_sched_location.c b/lib/pacemaker/pcmk_sched_location.c index 330c243781e..b5da4bb859c 100644 --- a/lib/pacemaker/pcmk_sched_location.c +++ b/lib/pacemaker/pcmk_sched_location.c @@ -70,7 +70,7 @@ parse_location_role(const char *role_spec, enum rsc_role_e *role) */ static const char * score_attribute_name(const xmlNode *rule_xml, char **allocated, - const pcmk_rule_input_t *rule_input) + const pcmk__rule_input_t *rule_input) { const char *name = NULL; @@ -191,7 +191,8 @@ score_from_attr(const char *constraint_id, const char *attr_name, static bool generate_location_rule(pcmk_resource_t *rsc, xmlNode *rule_xml, const char *discovery, crm_time_t *next_change, - pcmk_rule_input_t *rule_input, const char *constraint_id) + pcmk__rule_input_t *rule_input, + const char *constraint_id) { const char *rule_id = NULL; const char *score_attr = NULL; @@ -365,7 +366,7 @@ unpack_rsc_location(xmlNode *xml_obj, pcmk_resource_t *rsc, crm_time_t *next_change = pcmk__assert_alloc(1, sizeof(crm_time_t)); xmlNode *rule_xml = pcmk__xe_first_child(xml_obj, PCMK_XE_RULE, NULL, NULL); - pcmk_rule_input_t rule_input = { + pcmk__rule_input_t rule_input = { .now = rsc->priv->scheduler->priv->now, .rsc_meta = rsc->priv->meta, .rsc_id = rsc_id_match, diff --git a/lib/pengine/rules_compat.c b/lib/pengine/rules_compat.c index 258839e4c5e..02571e9cfab 100644 --- a/lib/pengine/rules_compat.c +++ b/lib/pengine/rules_compat.c @@ -29,7 +29,7 @@ gboolean test_rule(xmlNode * rule, GHashTable * node_hash, enum rsc_role_e role, crm_time_t * now) { - pcmk_rule_input_t rule_input = { + pcmk__rule_input_t rule_input = { .node_attrs = node_hash, .now = now, }; From 1e43f427fd3891453cfcd4141b652025e4dd17bf Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 10 May 2026 14:10:05 -0700 Subject: [PATCH 96/99] Refactor: libcrmcommon: pcmk__nvpair_unpack_t pcmk__rule_input_t field Instead of pcmk_rule_input_t. Signed-off-by: Reid Wahl --- include/crm/common/nvpair_internal.h | 4 ++-- lib/common/nvpair.c | 7 ++----- lib/pengine/rules_compat.c | 7 ++++++- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/include/crm/common/nvpair_internal.h b/include/crm/common/nvpair_internal.h index d0582ad953f..27d88059761 100644 --- a/include/crm/common/nvpair_internal.h +++ b/include/crm/common/nvpair_internal.h @@ -18,8 +18,8 @@ #include // gboolean, gpointer, GHashTable #include // xmlNode -#include // pcmk_rule_input_t #include // crm_time_t +#include // pcmk__rule_input_t #include // pcmk__str_eq(), etc. #ifdef __cplusplus @@ -31,7 +31,7 @@ typedef struct { GHashTable *values; // Where to put name/value pairs const char *first_id; // Block with this XML ID should sort first xmlDoc *doc; // XML document to use for resolving IDREFs - pcmk_rule_input_t rule_input; // Data used to evaluate rules + pcmk__rule_input_t rule_input; // Data used to evaluate rules /* Whether each block's values should overwrite any existing ones * diff --git a/lib/common/nvpair.c b/lib/common/nvpair.c index fc4bd366271..856258ff5ef 100644 --- a/lib/common/nvpair.c +++ b/lib/common/nvpair.c @@ -448,7 +448,6 @@ pcmk__unpack_nvpair_block(gpointer data, gpointer user_data) { xmlNode *pair = data; pcmk__nvpair_unpack_t *unpack_data = user_data; - pcmk__rule_input_t new_input = { NULL, }; xmlNode *rule_xml = NULL; @@ -456,10 +455,8 @@ pcmk__unpack_nvpair_block(gpointer data, gpointer user_data) && (unpack_data->values != NULL)); rule_xml = pcmk__xe_first_child(pair, PCMK_XE_RULE, NULL, NULL); - pcmk__rule_input_convert(&unpack_data->rule_input, &new_input); - if ((rule_xml != NULL) - && (pcmk__evaluate_rule(rule_xml, &new_input, + && (pcmk__evaluate_rule(rule_xml, &unpack_data->rule_input, unpack_data->next_change) != pcmk_rc_ok)) { return; } @@ -513,7 +510,7 @@ pcmk__unpack_nvpair_blocks(const xmlNode *xml, const char *element_name, data.doc = doc; if (rule_input != NULL) { - data.rule_input = *rule_input; + pcmk__rule_input_convert(rule_input, &data.rule_input); } blocks = g_list_sort_with_data(blocks, pcmk__cmp_nvpair_blocks, &data); diff --git a/lib/pengine/rules_compat.c b/lib/pengine/rules_compat.c index 02571e9cfab..3462c9537d7 100644 --- a/lib/pengine/rules_compat.c +++ b/lib/pengine/rules_compat.c @@ -79,6 +79,7 @@ pe_eval_nvpairs(xmlNode *top, const xmlNode *xml_obj, const char *set_name, crm_time_t *next_change) { GList *pairs = NULL; + pcmk_rule_input_t tmp_input = { NULL, }; pcmk__nvpair_unpack_t data = { .values = hash, .first_id = always_first, @@ -96,7 +97,11 @@ pe_eval_nvpairs(xmlNode *top, const xmlNode *xml_obj, const char *set_name, } data.doc = xml_obj->doc; - map_rule_input(&(data.rule_input), rule_data); + + map_rule_input(&tmp_input, rule_data); + if (rule_data != NULL) { + pcmk__rule_input_convert(&tmp_input, &data.rule_input); + } pairs = g_list_sort_with_data(pairs, pcmk__cmp_nvpair_blocks, &data); g_list_foreach(pairs, pcmk__unpack_nvpair_block, &data); From 673f27afb982254f858be3453d813a35c3e7120e Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 10 May 2026 14:17:09 -0700 Subject: [PATCH 97/99] Refactor: libcrmcommon: pcmk__unpack_nvpair_blocks() pcmk__rule_input_t Instead of pcmk_rule_input_t. Signed-off-by: Reid Wahl --- daemons/controld/controld_control.c | 2 +- daemons/controld/controld_remote_proxy.c | 3 +-- include/crm/common/nvpair_internal.h | 2 +- lib/cib/cib_utils.c | 2 +- lib/common/alerts.c | 2 +- lib/common/nvpair.c | 12 +++++++++--- .../tests/nvpair/pcmk__unpack_nvpair_blocks_test.c | 10 +++++----- lib/pengine/utils.c | 4 +++- 8 files changed, 22 insertions(+), 15 deletions(-) diff --git a/daemons/controld/controld_control.c b/daemons/controld/controld_control.c index 753dcca544c..2e7b071f268 100644 --- a/daemons/controld/controld_control.c +++ b/daemons/controld/controld_control.c @@ -541,7 +541,7 @@ config_query_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void crm_time_t *now = crm_time_new(NULL); xmlNode *crmconfig = NULL; xmlNode *alerts = NULL; - pcmk_rule_input_t rule_input = { + pcmk__rule_input_t rule_input = { .now = now, }; diff --git a/daemons/controld/controld_remote_proxy.c b/daemons/controld/controld_remote_proxy.c index 6871783dcc2..7f019e6638d 100644 --- a/daemons/controld/controld_remote_proxy.c +++ b/daemons/controld/controld_remote_proxy.c @@ -29,7 +29,6 @@ #include // pcmk_unpack_nvpair_blocks #include // PCMK_VALUE_CIB_BOOTSTRAP_OPTIONS #include // pcmk_ok, pcmk_rc_*, pcmk_strerror -#include // pcmk_rule_input_t #include // PCMK_XA_*, PCMK_XE_*, etc. #include // crm_system_name #include // lrmd_t @@ -244,7 +243,7 @@ remote_config_check(xmlNode *msg, int call_id, int rc, xmlNode *output, lrmd_t *lrmd = user_data; GHashTable *config_hash = NULL; crm_time_t *now = NULL; - pcmk_rule_input_t rule_input = { NULL, }; + pcmk__rule_input_t rule_input = { NULL, }; if (rc != pcmk_ok) { pcmk__err("Query resulted in an error: %s", pcmk_strerror(rc)); diff --git a/include/crm/common/nvpair_internal.h b/include/crm/common/nvpair_internal.h index 27d88059761..f334a2d2a07 100644 --- a/include/crm/common/nvpair_internal.h +++ b/include/crm/common/nvpair_internal.h @@ -51,7 +51,7 @@ void pcmk__unpack_nvpair_block(gpointer data, gpointer user_data); void pcmk__unpack_nvpair_blocks(const xmlNode *xml, const char *element_name, const char *first_id, - const pcmk_rule_input_t *rule_input, + const pcmk__rule_input_t *rule_input, GHashTable *values, crm_time_t *next_change, xmlDoc *doc); diff --git a/lib/cib/cib_utils.c b/lib/cib/cib_utils.c index e24def378e9..076ed67434e 100644 --- a/lib/cib/cib_utils.c +++ b/lib/cib/cib_utils.c @@ -133,7 +133,7 @@ static void read_config(GHashTable *options, xmlNode *current_cib) { crm_time_t *now = NULL; - pcmk_rule_input_t rule_input = { 0, }; + pcmk__rule_input_t rule_input = { NULL, }; xmlNode *config = pcmk_find_cib_element(current_cib, PCMK_XE_CRM_CONFIG); if (config == NULL) { diff --git a/lib/common/alerts.c b/lib/common/alerts.c index 86cf61c77b6..77e5bbbd8d3 100644 --- a/lib/common/alerts.c +++ b/lib/common/alerts.c @@ -149,7 +149,7 @@ unpack_alert_options(xmlNode *xml, pcmk__alert_t *entry, guint *max_timeout) const char *value = NULL; int rc = pcmk_rc_ok; - pcmk_rule_input_t rule_input = { + pcmk__rule_input_t rule_input = { .now = now, }; diff --git a/lib/common/nvpair.c b/lib/common/nvpair.c index 856258ff5ef..5df48b4d1a4 100644 --- a/lib/common/nvpair.c +++ b/lib/common/nvpair.c @@ -487,7 +487,7 @@ pcmk__unpack_nvpair_block(gpointer data, gpointer user_data) void pcmk__unpack_nvpair_blocks(const xmlNode *xml, const char *element_name, const char *first_id, - const pcmk_rule_input_t *rule_input, + const pcmk__rule_input_t *rule_input, GHashTable *values, crm_time_t *next_change, xmlDoc *doc) { @@ -510,7 +510,7 @@ pcmk__unpack_nvpair_blocks(const xmlNode *xml, const char *element_name, data.doc = doc; if (rule_input != NULL) { - pcmk__rule_input_convert(rule_input, &data.rule_input); + data.rule_input = *rule_input; } blocks = g_list_sort_with_data(blocks, pcmk__cmp_nvpair_blocks, &data); @@ -738,11 +738,17 @@ pcmk_unpack_nvpair_blocks(const xmlNode *xml, const char *element_name, const pcmk_rule_input_t *rule_input, GHashTable *values, crm_time_t *next_change) { + pcmk__rule_input_t new_input = { NULL, }; + if (xml == NULL) { return; } - pcmk__unpack_nvpair_blocks(xml, element_name, first_id, rule_input, values, + if (rule_input != NULL) { + pcmk__rule_input_convert(rule_input, &new_input); + } + + pcmk__unpack_nvpair_blocks(xml, element_name, first_id, &new_input, values, next_change, xml->doc); } diff --git a/lib/common/tests/nvpair/pcmk__unpack_nvpair_blocks_test.c b/lib/common/tests/nvpair/pcmk__unpack_nvpair_blocks_test.c index aea10f42125..5adb15296e1 100644 --- a/lib/common/tests/nvpair/pcmk__unpack_nvpair_blocks_test.c +++ b/lib/common/tests/nvpair/pcmk__unpack_nvpair_blocks_test.c @@ -65,7 +65,7 @@ null_xml(void **state) GHashTable *values = pcmk__strkey_table(free, free); crm_time_t *now = crm_time_new("2024-01-01 15:00:00"); crm_time_t *next_change = crm_time_new("2024-01-01 20:00:00"); - pcmk_rule_input_t rule_input = { + pcmk__rule_input_t rule_input = { .now = now, }; @@ -84,7 +84,7 @@ null_table(void **state) xmlNode *xml = pcmk__xml_parse(XML_BLOCKS); crm_time_t *now = crm_time_new("2024-01-01 15:00:00"); crm_time_t *next_change = crm_time_new("2024-01-01 20:00:00"); - pcmk_rule_input_t rule_input = { + pcmk__rule_input_t rule_input = { .now = now, }; @@ -105,7 +105,7 @@ rule_passes(void **state) crm_time_t *now = crm_time_new("2024-11-06 15:00:00"); crm_time_t *next_change = crm_time_new("2024-11-06 20:00:00"); GHashTable *values = pcmk__strkey_table(free, free); - pcmk_rule_input_t rule_input = { + pcmk__rule_input_t rule_input = { .now = now, }; @@ -131,7 +131,7 @@ rule_fails(void **state) crm_time_t *next_change = crm_time_new("2024-11-05 20:00:00"); crm_time_t *expected_next_change = crm_time_new("2024-11-05 00:00:01"); GHashTable *values = pcmk__strkey_table(free, free); - pcmk_rule_input_t rule_input = { + pcmk__rule_input_t rule_input = { .now = now, }; @@ -159,7 +159,7 @@ element_name(void **state) xmlNode *xml = pcmk__xml_parse(XML_BLOCKS); crm_time_t *now = crm_time_new("2024-11-06 15:00:00"); GHashTable *values = pcmk__strkey_table(free, free); - pcmk_rule_input_t rule_input = { + pcmk__rule_input_t rule_input = { .now = now, }; diff --git a/lib/pengine/utils.c b/lib/pengine/utils.c index 31bf393a537..1949a275c09 100644 --- a/lib/pengine/utils.c +++ b/lib/pengine/utils.c @@ -697,6 +697,7 @@ pe__unpack_dataset_nvpairs(const xmlNode *xml_obj, const char *set_name, pcmk_scheduler_t *scheduler) { crm_time_t *next_change = NULL; + pcmk__rule_input_t new_input = { NULL, }; CRM_CHECK((set_name != NULL) && (rule_input != NULL) && (hash != NULL) && (scheduler != NULL), return); @@ -709,8 +710,9 @@ pe__unpack_dataset_nvpairs(const xmlNode *xml_obj, const char *set_name, return; } + pcmk__rule_input_convert(rule_input, &new_input); next_change = pcmk__assert_alloc(1, sizeof(crm_time_t)); - pcmk__unpack_nvpair_blocks(xml_obj, set_name, always_first, rule_input, + pcmk__unpack_nvpair_blocks(xml_obj, set_name, always_first, &new_input, hash, next_change, scheduler->input->doc); if (pcmk__time_is_initialized(next_change)) { From 6eb671425a303a590190b901d6c2166ac44d8ced Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 10 May 2026 14:23:59 -0700 Subject: [PATCH 98/99] Refactor: libpe_status: pe__unpack_dataset_nvpairs() pcmk__rule_input_t Instead of pcmk_rule_input_t. Signed-off-by: Reid Wahl --- include/crm/pengine/internal.h | 2 +- lib/pengine/complex.c | 8 ++++---- lib/pengine/pe_actions.c | 4 ++-- lib/pengine/unpack.c | 4 ++-- lib/pengine/utils.c | 6 ++---- tools/crm_resource.c | 2 +- 6 files changed, 12 insertions(+), 14 deletions(-) diff --git a/include/crm/pengine/internal.h b/include/crm/pengine/internal.h index e27d41cc0cd..e749d5b249e 100644 --- a/include/crm/pengine/internal.h +++ b/include/crm/pengine/internal.h @@ -338,7 +338,7 @@ bool pe__shutdown_requested(const pcmk_node_t *node); void pe__register_messages(pcmk__output_t *out); void pe__unpack_dataset_nvpairs(const xmlNode *xml_obj, const char *set_name, - const pcmk_rule_input_t *rule_input, + const pcmk__rule_input_t *rule_input, GHashTable *hash, const char *always_first, pcmk_scheduler_t *scheduler); diff --git a/lib/pengine/complex.c b/lib/pengine/complex.c index 60c97f9572c..fe6b89544a8 100644 --- a/lib/pengine/complex.c +++ b/lib/pengine/complex.c @@ -132,7 +132,7 @@ dup_attr(gpointer key, gpointer value, gpointer user_data) static void expand_parents_fixed_nvpairs(const pcmk_resource_t *rsc, - const pcmk_rule_input_t *rule_input, + const pcmk__rule_input_t *rule_input, GHashTable *meta_hash, pcmk_scheduler_t *scheduler) { GHashTable *parent_orig_meta = pcmk__strkey_table(free, free); @@ -168,7 +168,7 @@ void get_meta_attributes(GHashTable *meta_hash, const pcmk_resource_t *rsc, pcmk_node_t *node, pcmk_scheduler_t *scheduler) { - pcmk_rule_input_t rule_input = { NULL, }; + pcmk__rule_input_t rule_input = { NULL, }; CRM_CHECK((meta_hash != NULL) && (rsc != NULL) && (scheduler != NULL), return); @@ -227,7 +227,7 @@ void get_rsc_attributes(GHashTable *instance_attrs, const pcmk_resource_t *rsc, const pcmk_node_t *node, pcmk_scheduler_t *scheduler) { - pcmk_rule_input_t rule_input = { + pcmk__rule_input_t rule_input = { .now = NULL, }; @@ -681,7 +681,7 @@ pe__unpack_resource(xmlNode *xml_obj, pcmk_resource_t **rsc, bool remote_node = false; pcmk__resource_private_t *rsc_private = NULL; - pcmk_rule_input_t rule_input = { + pcmk__rule_input_t rule_input = { .now = NULL, }; diff --git a/lib/pengine/pe_actions.c b/lib/pengine/pe_actions.c index a1a38ee9bac..ac66567dc07 100644 --- a/lib/pengine/pe_actions.c +++ b/lib/pengine/pe_actions.c @@ -249,7 +249,7 @@ pcmk__unpack_action_rsc_params(const xmlNode *action_xml, { GHashTable *params = pcmk__strkey_table(free, free); - const pcmk_rule_input_t rule_input = { + const pcmk__rule_input_t rule_input = { .now = scheduler->priv->now, .node_attrs = node_attrs, }; @@ -685,7 +685,7 @@ pcmk__unpack_action_meta(pcmk_resource_t *rsc, const pcmk_node_t *node, const char *timeout_spec = NULL; const char *str = NULL; - const pcmk_rule_input_t rule_input = { + const pcmk__rule_input_t rule_input = { /* Node attributes are not set because node expressions are not allowed * for meta-attributes */ diff --git a/lib/pengine/unpack.c b/lib/pengine/unpack.c index 1430a58a146..0db6448d6cc 100644 --- a/lib/pengine/unpack.c +++ b/lib/pengine/unpack.c @@ -221,7 +221,7 @@ unpack_config(xmlNode *config, pcmk_scheduler_t *scheduler) const char *value = NULL; GHashTable *config_hash = pcmk__strkey_table(free, free); - const pcmk_rule_input_t rule_input = { + const pcmk__rule_input_t rule_input = { .now = scheduler->priv->now, }; @@ -4963,7 +4963,7 @@ add_node_attrs(const xmlNode *xml_obj, pcmk_node_t *node, bool overwrite, { const char *cluster_name = NULL; const char *dc_id = pcmk__xe_get(scheduler->input, PCMK_XA_DC_UUID); - const pcmk_rule_input_t rule_input = { + const pcmk__rule_input_t rule_input = { .now = scheduler->priv->now, }; diff --git a/lib/pengine/utils.c b/lib/pengine/utils.c index 1949a275c09..83c4d56cc7f 100644 --- a/lib/pengine/utils.c +++ b/lib/pengine/utils.c @@ -692,12 +692,11 @@ pe__shutdown_requested(const pcmk_node_t *node) */ void pe__unpack_dataset_nvpairs(const xmlNode *xml_obj, const char *set_name, - const pcmk_rule_input_t *rule_input, + const pcmk__rule_input_t *rule_input, GHashTable *hash, const char *always_first, pcmk_scheduler_t *scheduler) { crm_time_t *next_change = NULL; - pcmk__rule_input_t new_input = { NULL, }; CRM_CHECK((set_name != NULL) && (rule_input != NULL) && (hash != NULL) && (scheduler != NULL), return); @@ -710,9 +709,8 @@ pe__unpack_dataset_nvpairs(const xmlNode *xml_obj, const char *set_name, return; } - pcmk__rule_input_convert(rule_input, &new_input); next_change = pcmk__assert_alloc(1, sizeof(crm_time_t)); - pcmk__unpack_nvpair_blocks(xml_obj, set_name, always_first, &new_input, + pcmk__unpack_nvpair_blocks(xml_obj, set_name, always_first, rule_input, hash, next_change, scheduler->input->doc); if (pcmk__time_is_initialized(next_change)) { diff --git a/tools/crm_resource.c b/tools/crm_resource.c index 8e655d1f6e3..fbbfc104cdf 100644 --- a/tools/crm_resource.c +++ b/tools/crm_resource.c @@ -1445,7 +1445,7 @@ handle_get_param(pcmk_resource_t *rsc, pcmk_node_t *node, cib_t *cib_conn, value = pcmk__xe_get(rsc->priv->xml, options.prop_name); } else { - const pcmk_rule_input_t rule_input = { + const pcmk__rule_input_t rule_input = { .now = scheduler->priv->now, }; From 2793520a0b6f485eb48b9b0ff214b8644859febc Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Mon, 11 May 2026 22:16:30 -0700 Subject: [PATCH 99/99] API: libcrmcommon: Deprecate pcmk_rule_input_t It's only used by deprecated functions now. Signed-off-by: Reid Wahl --- include/crm/common/nvpair_compat.h | 8 ++-- include/crm/common/rules.h | 54 --------------------------- include/crm/common/rules_compat.h | 16 +++++++- include/crm/common/rules_internal.h | 9 +++-- lib/common/nvpair.c | 1 + lib/common/rules.c | 57 +++++++++++++---------------- lib/pengine/rules_compat.c | 2 +- 7 files changed, 52 insertions(+), 95 deletions(-) diff --git a/include/crm/common/nvpair_compat.h b/include/crm/common/nvpair_compat.h index 88c4fd250b5..db9510f0d5f 100644 --- a/include/crm/common/nvpair_compat.h +++ b/include/crm/common/nvpair_compat.h @@ -10,11 +10,11 @@ #ifndef PCMK__CRM_COMMON_NVPAIR_COMPAT__H #define PCMK__CRM_COMMON_NVPAIR_COMPAT__H -#include // GHashTable, gpointer, GSList -#include // xmlNode +#include // GHashTable, gpointer, GSList +#include // xmlNode -#include // crm_time_t -#include // pcmk_rule_input_t +#include // crm_time_t +#include // pcmk_rule_input_t #ifdef __cplusplus extern "C" { diff --git a/include/crm/common/rules.h b/include/crm/common/rules.h index 24da65c1006..15f432e1bc3 100644 --- a/include/crm/common/rules.h +++ b/include/crm/common/rules.h @@ -54,60 +54,6 @@ enum expression_type { }; //!@} -/*! - * \brief Data used to evaluate a rule (any \c NULL items are ignored) - * - * \deprecated Use \c pcmk_rule_input_t instead of - * struct pcmk_rule_input. - */ -typedef struct pcmk_rule_input { - // Used to evaluate date expressions - const crm_time_t *now; //!< Current time for rule evaluation purposes - - // Used to evaluate resource type expressions - const char *rsc_standard; //!< Resource standard that rule applies to - const char *rsc_provider; //!< Resource provider that rule applies to - const char *rsc_agent; //!< Resource agent that rule applies to - - // Used to evaluate operation type expressions - const char *op_name; //!< Operation name that rule applies to - guint op_interval_ms; //!< Operation interval that rule applies to - - // Remaining members are used to evaluate node attribute expressions - - /*! - * Node attributes for rule evaluation purposes - * - * \note Though not const, this is used only with g_hash_table_lookup(). - */ - GHashTable *node_attrs; - - // Remaining members are used only within location constraint rules - - /*! - * Resource parameters that can be used as the reference value source - * - * \note Though not const, this is used only with g_hash_table_lookup(). - */ - GHashTable *rsc_params; - - /*! - * Resource meta-attributes that can be used as the reference value source - * - * \note Though not const, this is used only with g_hash_table_lookup(). - */ - GHashTable *rsc_meta; - - //! Resource ID to compare against a location constraint's resource pattern - const char *rsc_id; - - //! Resource pattern submatches (as set by regexec()) for rsc_id - const regmatch_t *rsc_id_submatches; - - //! Number of entries in rsc_id_submatches - int rsc_id_nmatches; -} pcmk_rule_input_t; - #ifdef __cplusplus } #endif diff --git a/include/crm/common/rules_compat.h b/include/crm/common/rules_compat.h index 6ce9d23c0ae..a3deb76ea20 100644 --- a/include/crm/common/rules_compat.h +++ b/include/crm/common/rules_compat.h @@ -13,7 +13,6 @@ #include // xmlNode #include // crm_time_t -#include // pcmk_rule_input_t #ifdef __cplusplus extern "C" { @@ -28,6 +27,21 @@ extern "C" { * release. */ +typedef struct pcmk_rule_input { + const crm_time_t *now; + const char *rsc_standard; + const char *rsc_provider; + const char *rsc_agent; + const char *op_name; + guint op_interval_ms; + GHashTable *node_attrs; + GHashTable *rsc_params; + GHashTable *rsc_meta; + const char *rsc_id; + const regmatch_t *rsc_id_submatches; + int rsc_id_nmatches; +} pcmk_rule_input_t; + //! \deprecated Do not use int pcmk_evaluate_rule(xmlNode *rule, const pcmk_rule_input_t *rule_input, crm_time_t *next_change); diff --git a/include/crm/common/rules_internal.h b/include/crm/common/rules_internal.h index 966f27888e9..8eccc37572f 100644 --- a/include/crm/common/rules_internal.h +++ b/include/crm/common/rules_internal.h @@ -84,9 +84,6 @@ typedef struct { int rsc_id_nmatches; } pcmk__rule_input_t; -void pcmk__rule_input_convert(const pcmk_rule_input_t *source, - pcmk__rule_input_t *target); - enum expression_type pcmk__condition_type(const xmlNode *condition); char *pcmk__replace_submatches(const char *string, const char *match, const regmatch_t submatches[], int nmatches); @@ -102,6 +99,12 @@ int pcmk__evaluate_condition(xmlNode *expr, int pcmk__evaluate_rule(xmlNode *rule, const pcmk__rule_input_t *rule_input, crm_time_t *next_change); +// Redeclare because the definition is in rules_compat.h +typedef struct pcmk_rule_input pcmk_rule_input_t; + +void pcmk__rule_input_convert(const pcmk_rule_input_t *source, + pcmk__rule_input_t *target); + #ifdef __cplusplus } #endif diff --git a/lib/common/nvpair.c b/lib/common/nvpair.c index 5df48b4d1a4..dd3a0479a82 100644 --- a/lib/common/nvpair.c +++ b/lib/common/nvpair.c @@ -665,6 +665,7 @@ pcmk__cmp_nvpair_blocks(gconstpointer a, gconstpointer b, gpointer user_data) // LCOV_EXCL_START #include +#include // pcmk_rule_input_t static gint pcmk__compare_nvpair(gconstpointer a, gconstpointer b) diff --git a/lib/common/rules.c b/lib/common/rules.c index 982957340e5..afb5074cc4f 100644 --- a/lib/common/rules.c +++ b/lib/common/rules.c @@ -65,37 +65,6 @@ pcmk__condition_type(const xmlNode *condition) return pcmk__condition_attribute; } -/*! - * \internal - * \brief Convert a \c pcmk_rule_input_t to a \c pcmk__rule_input_t - * - * \param[in] source Source object - * \param[out] target Target object - */ -void -pcmk__rule_input_convert(const pcmk_rule_input_t *source, - pcmk__rule_input_t *target) -{ - /* @COMPAT Drop this function when pcmk_rule_input_t is dropped. It exists - * purely for as a helper for deprecated API. - */ - pcmk__assert((source != NULL) && (target != NULL)); - - // Non-numeric fields are const and are shared between source and target - target->now = source->now; - target->rsc_standard = source->rsc_standard; - target->rsc_provider = source->rsc_provider; - target->rsc_agent = source->rsc_agent; - target->op_name = source->op_name; - target->op_interval_ms = source->op_interval_ms; - target->node_attrs = source->node_attrs; - target->rsc_params = source->rsc_params; - target->rsc_meta = source->rsc_meta; - target->rsc_id = source->rsc_id; - target->rsc_id_submatches = source->rsc_id_submatches; - target->rsc_id_nmatches = source->rsc_id_nmatches; -} - /*! * \internal * \brief Get parent XML element's ID for logging purposes @@ -1408,7 +1377,31 @@ pcmk__evaluate_rule(xmlNode *rule, const pcmk__rule_input_t *rule_input, // Deprecated functions kept only for backward API compatibility // LCOV_EXCL_START -#include // pcmk_evaluate_rule +#include // pcmk_rule_input_t + +void +pcmk__rule_input_convert(const pcmk_rule_input_t *source, + pcmk__rule_input_t *target) +{ + /* @COMPAT Drop this function when pcmk_rule_input_t is dropped. It exists + * purely for as a helper for deprecated API. + */ + pcmk__assert((source != NULL) && (target != NULL)); + + // Non-numeric fields are const and are shared between source and target + target->now = source->now; + target->rsc_standard = source->rsc_standard; + target->rsc_provider = source->rsc_provider; + target->rsc_agent = source->rsc_agent; + target->op_name = source->op_name; + target->op_interval_ms = source->op_interval_ms; + target->node_attrs = source->node_attrs; + target->rsc_params = source->rsc_params; + target->rsc_meta = source->rsc_meta; + target->rsc_id = source->rsc_id; + target->rsc_id_submatches = source->rsc_id_submatches; + target->rsc_id_nmatches = source->rsc_id_nmatches; +} int pcmk_evaluate_rule(xmlNode *rule, const pcmk_rule_input_t *rule_input, diff --git a/lib/pengine/rules_compat.c b/lib/pengine/rules_compat.c index 3462c9537d7..02057759eba 100644 --- a/lib/pengine/rules_compat.c +++ b/lib/pengine/rules_compat.c @@ -17,12 +17,12 @@ #include // pcmk__evaluate_rule, etc. #include // crm_time_t #include // enum rsc_role_e -#include // pcmk_rule_input_t, etc. #include // Deprecated functions kept only for backward API compatibility // LCOV_EXCL_START +#include // pcmk_rule_input_t #include #include