From 8867d486f850703035739570027c3a356948ee19 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Wed, 22 Jul 2026 17:11:10 -0700 Subject: [PATCH 01/37] Refactor: various: Drop cluster/internal.h includes from .c files Our .c files include crm_internal.h, which includes crm/cluster/internal.h. The explicit include makes sense for header files, since we don't include crm_internal.h there, but not for .c files. Signed-off-by: Reid Wahl --- daemons/attrd/attrd_alerts.c | 1 - daemons/attrd/attrd_cib.c | 1 - daemons/attrd/attrd_corosync.c | 1 - daemons/attrd/attrd_ipc.c | 1 - daemons/attrd/attrd_messages.c | 1 - daemons/attrd/pacemaker-attrd.c | 1 - daemons/based/based_callbacks.c | 1 - daemons/based/based_corosync.c | 1 - daemons/based/based_messages.c | 1 - daemons/based/pacemaker-based.c | 1 - daemons/controld/controld_control.c | 1 - daemons/controld/controld_corosync.c | 1 - daemons/controld/controld_election.c | 1 - daemons/controld/controld_membership.c | 1 - daemons/controld/controld_messages.c | 1 - daemons/fenced/cts-fence-helper.c | 1 - daemons/fenced/fenced_cib.c | 2 -- daemons/fenced/fenced_commands.c | 1 - daemons/fenced/fenced_history.c | 1 - daemons/fenced/fenced_remote.c | 1 - lib/cluster/cluster.c | 1 - lib/cluster/corosync.c | 1 - lib/cluster/cpg.c | 1 - lib/cluster/election.c | 1 - lib/cluster/membership.c | 1 - tools/stonith_admin.c | 1 - 26 files changed, 27 deletions(-) diff --git a/daemons/attrd/attrd_alerts.c b/daemons/attrd/attrd_alerts.c index 9bcbaf4f8f8..a07a0a6e50a 100644 --- a/daemons/attrd/attrd_alerts.c +++ b/daemons/attrd/attrd_alerts.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/daemons/attrd/attrd_cib.c b/daemons/attrd/attrd_cib.c index e33d525fd41..72877d83b86 100644 --- a/daemons/attrd/attrd_cib.c +++ b/daemons/attrd/attrd_cib.c @@ -18,7 +18,6 @@ #include #include #include -#include // pcmk__get_node() #include "pacemaker-attrd.h" diff --git a/daemons/attrd/attrd_corosync.c b/daemons/attrd/attrd_corosync.c index 20519e0911d..b6b9e2e8f23 100644 --- a/daemons/attrd/attrd_corosync.c +++ b/daemons/attrd/attrd_corosync.c @@ -15,7 +15,6 @@ #include #include -#include #include #include #include diff --git a/daemons/attrd/attrd_ipc.c b/daemons/attrd/attrd_ipc.c index 3b0113ccac1..b4ae24b4811 100644 --- a/daemons/attrd/attrd_ipc.c +++ b/daemons/attrd/attrd_ipc.c @@ -17,7 +17,6 @@ #include #include -#include #include #include #include diff --git a/daemons/attrd/attrd_messages.c b/daemons/attrd/attrd_messages.c index ed90865fb18..fe9f9927964 100644 --- a/daemons/attrd/attrd_messages.c +++ b/daemons/attrd/attrd_messages.c @@ -14,7 +14,6 @@ #include -#include // pcmk__get_node() #include #include "pacemaker-attrd.h" diff --git a/daemons/attrd/pacemaker-attrd.c b/daemons/attrd/pacemaker-attrd.c index 1682ba8ba56..b04d9f88e59 100644 --- a/daemons/attrd/pacemaker-attrd.c +++ b/daemons/attrd/pacemaker-attrd.c @@ -24,7 +24,6 @@ #include #include #include -#include #include "pacemaker-attrd.h" diff --git a/daemons/based/based_callbacks.c b/daemons/based/based_callbacks.c index 71679d43275..de1881ff3bd 100644 --- a/daemons/based/based_callbacks.c +++ b/daemons/based/based_callbacks.c @@ -23,7 +23,6 @@ #include // cib_call_options values #include // cib__* -#include // pcmk__cluster_send_message #include // pcmk__s, pcmk__str_eq #include // crm_ipc_*, pcmk_ipc_* #include // CRM_LOG_ASSERT, CRM_CHECK diff --git a/daemons/based/based_corosync.c b/daemons/based/based_corosync.c index cf8fc547d6c..688be5f3a63 100644 --- a/daemons/based/based_corosync.c +++ b/daemons/based/based_corosync.c @@ -20,7 +20,6 @@ #include // SUPPORT_COROSYNC #include // pcmk_cluster_* -#include // pcmk__cluster_*, etc. #include // pcmk__err, pcmk__xml_free, etc. #include // CRM_EX_DISCONNECT, pcmk_rc_ok diff --git a/daemons/based/based_messages.c b/daemons/based/based_messages.c index a77344d92d1..678840d7ae9 100644 --- a/daemons/based/based_messages.c +++ b/daemons/based/based_messages.c @@ -19,7 +19,6 @@ #include // QB_XS #include // PCMK__CIB_REQUEST_UPGRADE -#include // pcmk__cluster_send_message #include // pcmk__info, pcmk__xml_free, etc. #include // pcmk_ipc_server #include // CRM_CHECK diff --git a/daemons/based/pacemaker-based.c b/daemons/based/pacemaker-based.c index 46206af7ffc..218929093b2 100644 --- a/daemons/based/pacemaker-based.c +++ b/daemons/based/pacemaker-based.c @@ -22,7 +22,6 @@ #include // xmlNode #include // CRM_CONFIG_DIR, CRM_DAEMON_USER -#include // pcmk__node_update, etc. #include // PCMK__EXITC_ERROR, pcmk__err, etc. #include // crm_ipc_* #include // crm_log_* diff --git a/daemons/controld/controld_control.c b/daemons/controld/controld_control.c index 0f916edf63b..7a2337ae858 100644 --- a/daemons/controld/controld_control.c +++ b/daemons/controld/controld_control.c @@ -16,7 +16,6 @@ #include #include -#include #include #include diff --git a/daemons/controld/controld_corosync.c b/daemons/controld/controld_corosync.c index e065fcc9ede..f5f9c5b0da1 100644 --- a/daemons/controld/controld_corosync.c +++ b/daemons/controld/controld_corosync.c @@ -18,7 +18,6 @@ #include #include -#include #include #include diff --git a/daemons/controld/controld_election.c b/daemons/controld/controld_election.c index 43d5f0f7e5f..f833da82898 100644 --- a/daemons/controld/controld_election.c +++ b/daemons/controld/controld_election.c @@ -14,7 +14,6 @@ #include #include -#include #include #include diff --git a/daemons/controld/controld_membership.c b/daemons/controld/controld_membership.c index fd33d0827e4..7f32d8df012 100644 --- a/daemons/controld/controld_membership.c +++ b/daemons/controld/controld_membership.c @@ -16,7 +16,6 @@ #include #include -#include #include diff --git a/daemons/controld/controld_messages.c b/daemons/controld/controld_messages.c index 319bd468d45..523f35b40ff 100644 --- a/daemons/controld/controld_messages.c +++ b/daemons/controld/controld_messages.c @@ -18,7 +18,6 @@ #include #include -#include #include #include diff --git a/daemons/fenced/cts-fence-helper.c b/daemons/fenced/cts-fence-helper.c index 2de750c3e1a..f4386ad16b4 100644 --- a/daemons/fenced/cts-fence-helper.c +++ b/daemons/fenced/cts-fence-helper.c @@ -22,7 +22,6 @@ #include #include -#include #include #include diff --git a/daemons/fenced/fenced_cib.c b/daemons/fenced/fenced_cib.c index 803cad11e33..939518e5700 100644 --- a/daemons/fenced/fenced_cib.c +++ b/daemons/fenced/fenced_cib.c @@ -17,8 +17,6 @@ #include #include -#include - #include #include diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c index 9c8f0667b36..9be94a49231 100644 --- a/daemons/fenced/fenced_commands.c +++ b/daemons/fenced/fenced_commands.c @@ -28,7 +28,6 @@ #include #include -#include #include #include diff --git a/daemons/fenced/fenced_history.c b/daemons/fenced/fenced_history.c index 23864f7e2cf..75bac9d36f4 100644 --- a/daemons/fenced/fenced_history.c +++ b/daemons/fenced/fenced_history.c @@ -18,7 +18,6 @@ #include #include -#include #include #include diff --git a/daemons/fenced/fenced_remote.c b/daemons/fenced/fenced_remote.c index 9d59d054e81..394dd4859e3 100644 --- a/daemons/fenced/fenced_remote.c +++ b/daemons/fenced/fenced_remote.c @@ -28,7 +28,6 @@ #include #include -#include #include #include diff --git a/lib/cluster/cluster.c b/lib/cluster/cluster.c index ec2d54a1ae2..692df516dc1 100644 --- a/lib/cluster/cluster.c +++ b/lib/cluster/cluster.c @@ -27,7 +27,6 @@ #include #include -#include #include "crmcluster_private.h" /*! diff --git a/lib/cluster/corosync.c b/lib/cluster/corosync.c index 5b1c9136745..192b9889a98 100644 --- a/lib/cluster/corosync.c +++ b/lib/cluster/corosync.c @@ -28,7 +28,6 @@ #include // QB_XS #include // pcmk_cluster_*, etc. -#include // pcmk__cluster_private_t members #include // pcmk__corosync2rc, pcmk__err, etc. #include // crm_ipc_is_authentic_process #include // CRM_LOG_ASSERT diff --git a/lib/cluster/cpg.c b/lib/cluster/cpg.c index c121a2f9d07..c0fed8a2a19 100644 --- a/lib/cluster/cpg.c +++ b/lib/cluster/cpg.c @@ -28,7 +28,6 @@ #include #include -#include #include #include #include diff --git a/lib/cluster/election.c b/lib/cluster/election.c index db44bfdfccd..40e0f8c5341 100644 --- a/lib/cluster/election.c +++ b/lib/cluster/election.c @@ -17,7 +17,6 @@ #include #include -#include #include #include "crmcluster_private.h" diff --git a/lib/cluster/membership.c b/lib/cluster/membership.c index 14b33ec9fbe..d48d36013a0 100644 --- a/lib/cluster/membership.c +++ b/lib/cluster/membership.c @@ -20,7 +20,6 @@ #include #include -#include #include #include "crmcluster_private.h" diff --git a/tools/stonith_admin.c b/tools/stonith_admin.c index ef8face6f3d..4780ce663c6 100644 --- a/tools/stonith_admin.c +++ b/tools/stonith_admin.c @@ -26,7 +26,6 @@ #include #include -#include #include #include // stonith__register_messages() From 6b63bca76cd90c31f010f8cb248ec6f78ad0cd27 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Wed, 22 Jul 2026 17:18:49 -0700 Subject: [PATCH 02/37] Refactor: various: Don't include cluster/election_internal.h directly Include cluster/internal.h instead. Note that cluster/internal.h is included by crm_internal.h. Signed-off-by: Reid Wahl --- daemons/attrd/attrd_alerts.c | 3 ++- daemons/attrd/attrd_elections.c | 1 - daemons/attrd/pacemaker-attrd.h | 2 +- daemons/controld/controld_control.c | 1 - daemons/controld/controld_election.c | 1 - daemons/controld/controld_fsa.c | 1 - daemons/controld/controld_fsa.h | 3 +-- include/crm/cluster/election_internal.h | 5 +++++ include/crm/cluster/internal.h | 5 +++++ lib/cluster/election.c | 1 - tests/test-headers.sh | 1 + 11 files changed, 15 insertions(+), 9 deletions(-) diff --git a/daemons/attrd/attrd_alerts.c b/daemons/attrd/attrd_alerts.c index a07a0a6e50a..e58629e5dab 100644 --- a/daemons/attrd/attrd_alerts.c +++ b/daemons/attrd/attrd_alerts.c @@ -8,11 +8,12 @@ */ #include + #include #include -#include #include #include + #include "pacemaker-attrd.h" static GList *attrd_alert_list = NULL; diff --git a/daemons/attrd/attrd_elections.c b/daemons/attrd/attrd_elections.c index c48c808fda7..11c2841a94e 100644 --- a/daemons/attrd/attrd_elections.c +++ b/daemons/attrd/attrd_elections.c @@ -12,7 +12,6 @@ #include #include -#include #include #include "pacemaker-attrd.h" diff --git a/daemons/attrd/pacemaker-attrd.h b/daemons/attrd/pacemaker-attrd.h index 8d9b50ad408..b2e94052f39 100644 --- a/daemons/attrd/pacemaker-attrd.h +++ b/daemons/attrd/pacemaker-attrd.h @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include diff --git a/daemons/controld/controld_control.c b/daemons/controld/controld_control.c index 7a2337ae858..5ca16b37986 100644 --- a/daemons/controld/controld_control.c +++ b/daemons/controld/controld_control.c @@ -16,7 +16,6 @@ #include #include -#include #include diff --git a/daemons/controld/controld_election.c b/daemons/controld/controld_election.c index f833da82898..12f33e41b3a 100644 --- a/daemons/controld/controld_election.c +++ b/daemons/controld/controld_election.c @@ -14,7 +14,6 @@ #include #include -#include #include #include diff --git a/daemons/controld/controld_fsa.c b/daemons/controld/controld_fsa.c index b44ca99c55d..786446cc6cd 100644 --- a/daemons/controld/controld_fsa.c +++ b/daemons/controld/controld_fsa.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include diff --git a/daemons/controld/controld_fsa.h b/daemons/controld/controld_fsa.h index 04eeb8156cf..b1ef802f1cf 100644 --- a/daemons/controld/controld_fsa.h +++ b/daemons/controld/controld_fsa.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. * @@ -16,7 +16,6 @@ # include # include # include -# include # include /*! States the controller can be in */ diff --git a/include/crm/cluster/election_internal.h b/include/crm/cluster/election_internal.h index 4825f8e103e..93cecf943e3 100644 --- a/include/crm/cluster/election_internal.h +++ b/include/crm/cluster/election_internal.h @@ -7,6 +7,11 @@ * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ +#ifndef PCMK__INCLUDED_CRM_CLUSTER_INTERNAL_H +#error "Include instead of " \ + "directly" +#endif + #ifndef PCMK__CRM_CLUSTER_ELECTION_INTERNAL__H #define PCMK__CRM_CLUSTER_ELECTION_INTERNAL__H diff --git a/include/crm/cluster/internal.h b/include/crm/cluster/internal.h index aed702eb9a1..85512e27fae 100644 --- a/include/crm/cluster/internal.h +++ b/include/crm/cluster/internal.h @@ -10,6 +10,8 @@ #ifndef PCMK__CRM_CLUSTER_INTERNAL__H #define PCMK__CRM_CLUSTER_INTERNAL__H +#define PCMK__INCLUDED_CRM_CLUSTER_INTERNAL_H + #include #include // uint32_t, uint64_t @@ -18,11 +20,14 @@ #include // enum crm_ipc_server #include +#include #if SUPPORT_COROSYNC #include // cpg_name, cpg_handle_t #endif +#undef PCMK__INCLUDED_CRM_CLUSTER_INTERNAL_H + #ifdef __cplusplus extern "C" { #endif diff --git a/lib/cluster/election.c b/lib/cluster/election.c index 40e0f8c5341..27655d55982 100644 --- a/lib/cluster/election.c +++ b/lib/cluster/election.c @@ -17,7 +17,6 @@ #include #include -#include #include "crmcluster_private.h" #define STORM_INTERVAL 2 /* in seconds */ diff --git a/tests/test-headers.sh b/tests/test-headers.sh index 764431dfca9..d92bf90a8b7 100644 --- a/tests/test-headers.sh +++ b/tests/test-headers.sh @@ -34,6 +34,7 @@ do cat >"$TESTFILE" < #ifndef $PROTECT From a16fb66176b87cdf74a5d096058f78c9ebabec4e Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Wed, 22 Jul 2026 17:23:55 -0700 Subject: [PATCH 03/37] Refactor: various: Drop common/internal.h includes from .c files Our .c files include crm_internal.h, which includes crm/common/internal.h. The explicit include makes sense for header files, since we don't include crm_internal.h there, but not for .c files. Signed-off-by: Reid Wahl --- daemons/based/based_callbacks.c | 1 - daemons/based/based_corosync.c | 1 - daemons/based/based_io.c | 1 - daemons/based/based_ipc.c | 1 - daemons/based/based_messages.c | 1 - daemons/based/based_notify.c | 1 - daemons/based/based_operation.c | 1 - daemons/based/based_remote.c | 1 - daemons/based/based_transaction.c | 1 - daemons/based/pacemaker-based.c | 1 - daemons/controld/controld_remote_proxy.c | 1 - daemons/execd/execd_ipc.c | 1 - daemons/execd/execd_messages.c | 1 - daemons/execd/remoted_proxy.c | 1 - daemons/execd/remoted_tls.c | 1 - lib/cib/cib_remote.c | 1 - lib/cluster/corosync.c | 1 - lib/common/fuzzers/iso8601_fuzzer.c | 3 ++- lib/common/fuzzers/scores_fuzzer.c | 3 ++- lib/common/logging.c | 1 - lib/common/tls.c | 1 - lib/lrmd/lrmd_client.c | 1 - lib/pacemaker/pcmk_acl.c | 1 - tools/cibsecret.c | 1 - tools/crm_resource_runtime.c | 1 - 25 files changed, 4 insertions(+), 25 deletions(-) diff --git a/daemons/based/based_callbacks.c b/daemons/based/based_callbacks.c index de1881ff3bd..cef3d4bcdc3 100644 --- a/daemons/based/based_callbacks.c +++ b/daemons/based/based_callbacks.c @@ -23,7 +23,6 @@ #include // cib_call_options values #include // cib__* -#include // pcmk__s, pcmk__str_eq #include // crm_ipc_*, pcmk_ipc_* #include // CRM_LOG_ASSERT, CRM_CHECK #include // mainloop_* diff --git a/daemons/based/based_corosync.c b/daemons/based/based_corosync.c index 688be5f3a63..134d44a4889 100644 --- a/daemons/based/based_corosync.c +++ b/daemons/based/based_corosync.c @@ -20,7 +20,6 @@ #include // SUPPORT_COROSYNC #include // pcmk_cluster_* -#include // pcmk__err, pcmk__xml_free, etc. #include // CRM_EX_DISCONNECT, pcmk_rc_ok #include "pacemaker-based.h" diff --git a/daemons/based/based_io.c b/daemons/based/based_io.c index 5e6a12153ab..f4d5c5004ff 100644 --- a/daemons/based/based_io.c +++ b/daemons/based/based_io.c @@ -29,7 +29,6 @@ #include // cib_file_* #include // createEmptyCib -#include // pcmk__assert_asprintf, PCMK__XE_*, etc. #include // CRM_CHECK #include // mainloop_* #include // pcmk_legacy2rc, pcmk_rc_* diff --git a/daemons/based/based_ipc.c b/daemons/based/based_ipc.c index 9e32dfdbd5f..42d8998c958 100644 --- a/daemons/based/based_ipc.c +++ b/daemons/based/based_ipc.c @@ -20,7 +20,6 @@ #include // qb_ipcs_* #include // cib_none, cib_sync_call -#include // pcmk__client_*, pcmk__trace, etc. #include // crm_ipc_client_response #include // CRM_CHECK(), CRM_LOG_ASSERT() #include // CRM_EX_PROTOCOL, pcmk_rc_* diff --git a/daemons/based/based_messages.c b/daemons/based/based_messages.c index 678840d7ae9..8dcbf7f5d7f 100644 --- a/daemons/based/based_messages.c +++ b/daemons/based/based_messages.c @@ -19,7 +19,6 @@ #include // QB_XS #include // PCMK__CIB_REQUEST_UPGRADE -#include // pcmk__info, pcmk__xml_free, etc. #include // pcmk_ipc_server #include // CRM_CHECK #include // pcmk_err, pcmk_ok, pcmk_rc* diff --git a/daemons/based/based_notify.c b/daemons/based/based_notify.c index d9dcab67950..47ced2c53d4 100644 --- a/daemons/based/based_notify.c +++ b/daemons/based/based_notify.c @@ -20,7 +20,6 @@ #include // xmlNode #include // QB_XS -#include // pcmk__client_t, etc. #include // pcmk_free_ipc_event #include // CRM_LOG_ASSERT #include // pcmk_rc_* diff --git a/daemons/based/based_operation.c b/daemons/based/based_operation.c index 04d1c5417e8..1608018250f 100644 --- a/daemons/based/based_operation.c +++ b/daemons/based/based_operation.c @@ -12,7 +12,6 @@ #include // NULL #include // cib__* -#include // pcmk__assert, PCMK__NELEM #include "pacemaker-based.h" diff --git a/daemons/based/based_remote.c b/daemons/based/based_remote.c index 7695ea8947b..ad3ac88219f 100644 --- a/daemons/based/based_remote.c +++ b/daemons/based/based_remote.c @@ -27,7 +27,6 @@ #include // QB_XS #include // CRM_DAEMON_GROUP -#include // pcmk__client_t, etc. #include // CRM_CHECK #include // mainloop_* #include // pcmk_rc_* diff --git a/daemons/based/based_transaction.c b/daemons/based/based_transaction.c index 61f84d4b331..22fa18d9ea1 100644 --- a/daemons/based/based_transaction.c +++ b/daemons/based/based_transaction.c @@ -17,7 +17,6 @@ #include // xmlNode #include // cib__* -#include // pcmk__client_t, pcmk__s, pcmk__xe_*, etc. #include // CRM_CHECK #include // pcmk_rc_* diff --git a/daemons/based/pacemaker-based.c b/daemons/based/pacemaker-based.c index 218929093b2..6f114ccfc82 100644 --- a/daemons/based/pacemaker-based.c +++ b/daemons/based/pacemaker-based.c @@ -22,7 +22,6 @@ #include // xmlNode #include // CRM_CONFIG_DIR, CRM_DAEMON_USER -#include // PCMK__EXITC_ERROR, pcmk__err, etc. #include // crm_ipc_* #include // crm_log_* #include // mainloop_add_signal diff --git a/daemons/controld/controld_remote_proxy.c b/daemons/controld/controld_remote_proxy.c index 261e5ac68db..8da874e02b6 100644 --- a/daemons/controld/controld_remote_proxy.c +++ b/daemons/controld/controld_remote_proxy.c @@ -21,7 +21,6 @@ #include // xmlNode #include // cib_* -#include // pcmk__xe_*, pcmk__xml_*, etc. #include // crm_ipc_* #include // crm_time_* #include // CRM_CHECK, crm_log_xml_explicit diff --git a/daemons/execd/execd_ipc.c b/daemons/execd/execd_ipc.c index c8821f51c9e..8d2f489de68 100644 --- a/daemons/execd/execd_ipc.c +++ b/daemons/execd/execd_ipc.c @@ -18,7 +18,6 @@ #include // xmlNode #include // qb_ipcs_connection_t -#include // pcmk__client_t, pcmk__find_client #include // crm_ipc_client_response #include // CRM_CHECK #include // pcmk_rc_*, pcmk_rc_str diff --git a/daemons/execd/execd_messages.c b/daemons/execd/execd_messages.c index 52384cf79be..f67d190e4b3 100644 --- a/daemons/execd/execd_messages.c +++ b/daemons/execd/execd_messages.c @@ -19,7 +19,6 @@ #include // QB_XS #include // CRM_OP_*, CRM_SYSTEM_LRMD -#include // pcmk__process_request, pcmk__xml_free #include // pcmk_exec_status, pcmk_rc_*, pcmk_rc_str #include // LRMD_OP_* diff --git a/daemons/execd/remoted_proxy.c b/daemons/execd/remoted_proxy.c index bc3c9a98838..10213ff180d 100644 --- a/daemons/execd/remoted_proxy.c +++ b/daemons/execd/remoted_proxy.c @@ -19,7 +19,6 @@ #include // qb_ipcs_connection_t #include // QB_XS -#include #include // crm_ipc_flags #include // CRM_CHECK, CRM_LOG_ASSERT #include // pcmk_rc_*, pcmk_rc_str diff --git a/daemons/execd/remoted_tls.c b/daemons/execd/remoted_tls.c index af28efc657c..02dc4984a02 100644 --- a/daemons/execd/remoted_tls.c +++ b/daemons/execd/remoted_tls.c @@ -23,7 +23,6 @@ #include // xmlNode #include // QB_XS -#include #include // CRM_CHECK #include // mainloop_* #include // pcmk_rc_str, pcmk_rc_* diff --git a/lib/cib/cib_remote.c b/lib/cib/cib_remote.c index eab7e5841bc..72624f2d6e1 100644 --- a/lib/cib/cib_remote.c +++ b/lib/cib/cib_remote.c @@ -24,7 +24,6 @@ #include // cib_t, cib_remote_new #include // cib__create_op, cib__extend_transaction -#include #include // mainloop_fd_callbacks #include // pcmk_rc_str, pcmk_rc_* #include // PCMK_XA_*, diff --git a/lib/cluster/corosync.c b/lib/cluster/corosync.c index 192b9889a98..305c9a2ac45 100644 --- a/lib/cluster/corosync.c +++ b/lib/cluster/corosync.c @@ -28,7 +28,6 @@ #include // QB_XS #include // pcmk_cluster_*, etc. -#include // pcmk__corosync2rc, pcmk__err, etc. #include // crm_ipc_is_authentic_process #include // CRM_LOG_ASSERT #include // mainloop_* diff --git a/lib/common/fuzzers/iso8601_fuzzer.c b/lib/common/fuzzers/iso8601_fuzzer.c index e7c0ecb5b41..51e5fcf1c94 100644 --- a/lib/common/fuzzers/iso8601_fuzzer.c +++ b/lib/common/fuzzers/iso8601_fuzzer.c @@ -7,6 +7,8 @@ * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ +#include + #include #include #include @@ -15,7 +17,6 @@ #include // qb_util_timespec_from_epoch_get() #include -#include int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) diff --git a/lib/common/fuzzers/scores_fuzzer.c b/lib/common/fuzzers/scores_fuzzer.c index 3e06cf5fc13..375bba5e0c7 100644 --- a/lib/common/fuzzers/scores_fuzzer.c +++ b/lib/common/fuzzers/scores_fuzzer.c @@ -7,12 +7,13 @@ * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ +#include + #include #include #include #include -#include int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) diff --git a/lib/common/logging.c b/lib/common/logging.c index 96e3b62bae2..c49fda6b360 100644 --- a/lib/common/logging.c +++ b/lib/common/logging.c @@ -31,7 +31,6 @@ #include // LOG_TRACE, qb_log_* #include // CRM_DAEMON_USER, CRM_*_DIR -#include // pcmk__env_*, pcmk__output_*, etc. #include // do_crm_log, CRM_CHECK, etc. #include // crm_signal_handler, mainloop_add_signal #include // PCMK_VALUE_NONE diff --git a/lib/common/tls.c b/lib/common/tls.c index 1d834a59812..b88703d8eb8 100644 --- a/lib/common/tls.c +++ b/lib/common/tls.c @@ -26,7 +26,6 @@ #include // gnutls_x509_* #include // QB_XS -#include #include // crm_time_* #include // CRM_CHECK #include // pcmk_rc_* diff --git a/lib/lrmd/lrmd_client.c b/lib/lrmd/lrmd_client.c index 65b23df8edd..8af18bf14d6 100644 --- a/lib/lrmd/lrmd_client.c +++ b/lib/lrmd/lrmd_client.c @@ -26,7 +26,6 @@ #include // PCMK_DEFAULT_ACTION_TIMEOUT_MS #include // PCMK_RESOURCE_CLASS_STONITH -#include #include // crm_ipc_* #include // CRM_CHECK, CRM_LOG_ASSERT #include // mainloop_set_trigger diff --git a/lib/pacemaker/pcmk_acl.c b/lib/pacemaker/pcmk_acl.c index 5f47e76e2ee..31fa1130f0d 100644 --- a/lib/pacemaker/pcmk_acl.c +++ b/lib/pacemaker/pcmk_acl.c @@ -25,7 +25,6 @@ #include #include -#include #include diff --git a/tools/cibsecret.c b/tools/cibsecret.c index bbf1d318a52..4e520ed0707 100644 --- a/tools/cibsecret.c +++ b/tools/cibsecret.c @@ -25,7 +25,6 @@ #include // xmlChar #include // cib__clean_up_connection, cib__signon_query -#include #include #include // crm_element_value, PCMK_XA_* diff --git a/tools/crm_resource_runtime.c b/tools/crm_resource_runtime.c index 217e3b203e9..6e81367a184 100644 --- a/tools/crm_resource_runtime.c +++ b/tools/crm_resource_runtime.c @@ -27,7 +27,6 @@ #include // PCMK_ACTION_MONITOR #include // pcmk_get_ra_caps, pcmk_ra_cap_* #include // pcmk_cib_xpath_for -#include #include // pcmk_ipc_api_t #include // pcmk_controld_api_* #include // crm_time_new From 7d016f5a3c5ba51eddef62f4c465bdc504ff9089 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sat, 10 Jan 2026 18:25:23 -0800 Subject: [PATCH 04/37] Refactor: based: Clean up shutdown logic And rename based_terminate() to based_quit_main_loop(). The main loop processes events in batches. On each iteration, it checks to see what sources are ready (that is, pending dispatch), and then it dispatches them. It iterates over the list of ready sources and runs each source's callback function, provided the source has not been removed/destroyed. When we call g_main_loop_quit(), we call it from within a source's callback. g_main_loop_quit() ensures that no additional loop iterations will occur. However, any sources that are already in the pending list will still be dispatched. This means that if we quit the main loop, we need to be prepared for any pending source callbacks. This commit handles that by returning early from functions that shouldn't do anything during shutdown, if we're in the process of shutting down (that is, if we've called g_main_loop_quit()). This lets us quit based the same way regardless of the exit code and consolidate cleanup at the end of main(). It also hopefully makes behavior more reliable when we quit the main loop. Previously, if we were quitting with CRM_EX_OK (due to a SIGTERM), we would free based_cib, cib_root, and possibly other important data structures that we generally assume are non-NULL. If some function tried to dereference those when processing pending sources, we might seg fault. Signed-off-by: Reid Wahl --- daemons/based/based_callbacks.c | 9 +++++++ daemons/based/based_corosync.c | 16 +++++++++--- daemons/based/based_io.c | 4 +++ daemons/based/based_remote.c | 5 ++++ daemons/based/pacemaker-based.c | 45 +++++++++++++-------------------- daemons/based/pacemaker-based.h | 2 +- 6 files changed, 49 insertions(+), 32 deletions(-) diff --git a/daemons/based/based_callbacks.c b/daemons/based/based_callbacks.c index cef3d4bcdc3..ddcaa005176 100644 --- a/daemons/based/based_callbacks.c +++ b/daemons/based/based_callbacks.c @@ -67,6 +67,10 @@ digest_timer_cb(void *data) { xmlNode *ping = NULL; + if (based_shutting_down()) { + return G_SOURCE_REMOVE; + } + if (!based_get_local_node_dc()) { // Only the DC sends a ping return G_SOURCE_REMOVE; @@ -694,6 +698,11 @@ based_process_request(xmlNode *request, bool privileged, xmlNode *output = NULL; time_t start_time = 0; + if (based_shutting_down()) { + pcmk__info("Ignoring pending CIB request during shutdown"); + return ENOTCONN; + } + rc = pcmk__xe_get_flags(request, PCMK__XA_CIB_CALLOPT, &call_options, cib_none); if (rc != pcmk_rc_ok) { diff --git a/daemons/based/based_corosync.c b/daemons/based/based_corosync.c index 134d44a4889..6825c9ac64a 100644 --- a/daemons/based/based_corosync.c +++ b/daemons/based/based_corosync.c @@ -9,6 +9,7 @@ #include +#include // PRIu32 #include #include // NULL, size_t #include // uint32_t @@ -57,10 +58,17 @@ static void based_cpg_dispatch(cpg_handle_t handle, const struct cpg_name *group_name, uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len) { - xmlNode *xml = NULL; + char *data = NULL; const char *from = NULL; - char *data = pcmk__cpg_message_data(handle, nodeid, pid, msg, &from); + xmlNode *xml = NULL; + + if (based_shutting_down()) { + pcmk__info("Ignoring CPG message from node %" PRIu32 " during shutdown", + nodeid); + return; + } + data = pcmk__cpg_message_data(handle, nodeid, pid, msg, &from); if (data == NULL) { return; } @@ -86,8 +94,8 @@ based_cpg_destroy(void *user_data) return; } - pcmk__crit("Exiting immediately after losing connection to cluster layer"); - based_terminate(CRM_EX_DISCONNECT); + pcmk__crit("Exiting after losing connection to cluster layer"); + based_quit_main_loop(CRM_EX_DISCONNECT); } #endif diff --git a/daemons/based/based_io.c b/daemons/based/based_io.c index f4d5c5004ff..0a17ea24866 100644 --- a/daemons/based/based_io.c +++ b/daemons/based/based_io.c @@ -92,6 +92,10 @@ write_cib_async(void *user_data) pid_t pid = 0; int blackbox_state = qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_STATE_GET, 0); + if (based_shutting_down()) { + pcmk__info("Skipping CIB write during shutdown"); + } + /* Disable blackbox logging before the fork to avoid two processes writing * to the same shared memory. The disable should not be done in the child, * because this would close shared memory files in the parent. diff --git a/daemons/based/based_remote.c b/daemons/based/based_remote.c index ad3ac88219f..7574cbe9cd5 100644 --- a/daemons/based/based_remote.c +++ b/daemons/based/based_remote.c @@ -564,6 +564,11 @@ cib_remote_listen(void *user_data) .destroy = based_remote_client_destroy, }; + if (based_shutting_down()) { + pcmk__info("Ignoring new remote connection during shutdown"); + return 0; + } + /* accept the connection */ laddr = sizeof(addr); memset(&addr, 0, sizeof(addr)); diff --git a/daemons/based/pacemaker-based.c b/daemons/based/pacemaker-based.c index 6f114ccfc82..c080bc5be13 100644 --- a/daemons/based/pacemaker-based.c +++ b/daemons/based/pacemaker-based.c @@ -227,6 +227,7 @@ static void based_cleanup(void) { based_callbacks_cleanup(); + based_cluster_disconnect(); based_io_cleanup(); based_ipc_cleanup(); based_remote_cleanup(); @@ -237,48 +238,39 @@ based_cleanup(void) /*! * \internal - * \brief Clean up data structures and exit + * \brief Set an exit code and quit the main loop * - * \param[in] exit_status Exit code + * \param[in] ec Exit code */ void -based_terminate(crm_exit_t exit_status) +based_quit_main_loop(crm_exit_t ec) { - shutting_down = true; - based_cleanup(); - - if (exit_status != CRM_EX_OK) { - /* After calling g_main_loop_quit(), sources that have already been - * dispatched are still executed. On error, skip that and exit - * immediately after cleaning up data structures. - * - * @TODO Is this necessary? It would be nice to do the cleanup at the - * end of main(). If so, then one (complicated) option would be to keep - * track of all main loop sources and destroy them so that - * g_main_dispatch() ignores them. - */ - crm_exit(exit_status); + if (shutting_down) { + return; } - based_cluster_disconnect(); + shutting_down = true; + exit_code = ec; // There should be no way to get here without the main loop running CRM_CHECK((mainloop != NULL) && g_main_loop_is_running(mainloop), - crm_exit(exit_status)); + crm_exit(exit_code)); g_main_loop_quit(mainloop); } +/*! + * \internal + * \brief Quit the main loop and set the exit code to \c CRM_EX_OK + * + * \param[in] nsig Ignored + * + * \note This is a main loop signal handler function. + */ static void based_shutdown(int nsig) { - if (based_shutting_down()) { - // Already shutting down - return; - } - - shutting_down = true; - based_terminate(CRM_EX_OK); + based_quit_main_loop(CRM_EX_OK); } int @@ -417,7 +409,6 @@ main(int argc, char **argv) g_strfreev(processed_args); pcmk__free_arg_context(context); - based_cluster_disconnect(); based_cleanup(); pcmk__output_and_clear_error(&error, out); diff --git a/daemons/based/pacemaker-based.h b/daemons/based/pacemaker-based.h index b4c53ded680..7e80a7287ef 100644 --- a/daemons/based/pacemaker-based.h +++ b/daemons/based/pacemaker-based.h @@ -36,6 +36,6 @@ void based_set_local_node_dc(bool value); bool based_shutting_down(void); bool based_stand_alone(void); -void based_terminate(crm_exit_t exit_status); +void based_quit_main_loop(crm_exit_t ec); #endif // PACEMAKER_BASED__H From b0aa2d9c9c0b0e03a902f058b26fa02e18372622 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Wed, 14 Jan 2026 01:35:56 -0800 Subject: [PATCH 05/37] Refactor: based: based_cib should always be non-NULL after init now Signed-off-by: Reid Wahl --- daemons/based/based_callbacks.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/daemons/based/based_callbacks.c b/daemons/based/based_callbacks.c index ddcaa005176..9f62c48f6d6 100644 --- a/daemons/based/based_callbacks.c +++ b/daemons/based/based_callbacks.c @@ -617,14 +617,9 @@ log_op_result(const xmlNode *request, const cib__operation_t *operation, int rc, originator = pcmk__s(originator, "local"); client_name = pcmk__s(client_name, "client"); - /* @FIXME based_cib should always be non-NULL, but that's currently not the - * case during shutdown - */ - if (based_cib != NULL) { - pcmk__xe_get_int(based_cib, PCMK_XA_ADMIN_EPOCH, &admin_epoch); - pcmk__xe_get_int(based_cib, PCMK_XA_EPOCH, &epoch); - pcmk__xe_get_int(based_cib, PCMK_XA_NUM_UPDATES, &num_updates); - } + pcmk__xe_get_int(based_cib, PCMK_XA_ADMIN_EPOCH, &admin_epoch); + pcmk__xe_get_int(based_cib, PCMK_XA_EPOCH, &epoch); + pcmk__xe_get_int(based_cib, PCMK_XA_NUM_UPDATES, &num_updates); do_crm_log(level, "Completed %s operation for section %s: %s (rc=%d, " From 56f7ded697e271a0fee1b218b0523b4b50740548 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 23 Jul 2026 11:05:00 -0700 Subject: [PATCH 06/37] Refactor: controller: Don't set mainloop to NULL in crmd_exit() The comment above the assignment says "Don't re-enter this block." However, that's already impossible thanks to the in_progress static variable. If it's true, we exit at the beginning of the function. If it's false, we set it to true after checking it. That in_progress logic was not present as of commit 0f9b4c1, when the "Don't re-enter" comment was added. Interestingly though, the in_progress logic was added one hour after the "Don't re-enter" and NULL assignment, but the latter were never removed. See commit 716d9d7. Signed-off-by: Reid Wahl --- daemons/controld/controld_control.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/daemons/controld/controld_control.c b/daemons/controld/controld_control.c index 5ca16b37986..9e0c00b7dac 100644 --- a/daemons/controld/controld_control.c +++ b/daemons/controld/controld_control.c @@ -239,9 +239,6 @@ crmd_exit(crm_exit_t exit_code) if (mloop != NULL) { GMainContext *ctx = g_main_loop_get_context(controld_globals.mainloop); - // Don't re-enter this block - controld_globals.mainloop = NULL; - // Try to drain the main loop before closing it for (int i = 0; (i < 10) && g_main_context_pending(ctx); i++) { g_main_context_dispatch(ctx); From 5a224966d694dbd1a31dbf544793c6929bd4ce71 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sat, 10 Jan 2026 19:45:17 -0800 Subject: [PATCH 07/37] Refactor: various: Unref main loop consistently Signed-off-by: Reid Wahl --- daemons/attrd/attrd_utils.c | 2 +- daemons/based/pacemaker-based.c | 1 + daemons/controld/controld_control.c | 1 - daemons/controld/pacemaker-controld.c | 2 ++ daemons/execd/cts-exec-helper.c | 1 + daemons/execd/pacemaker-execd.c | 1 + daemons/fenced/cts-fence-helper.c | 1 + daemons/fenced/pacemaker-fenced.c | 1 + daemons/pacemakerd/pacemakerd.c | 3 ++- daemons/schedulerd/pacemaker-schedulerd.c | 1 + lib/pacemaker/pcmk_fence.c | 1 + tools/crm_resource.c | 4 +--- 12 files changed, 13 insertions(+), 6 deletions(-) diff --git a/daemons/attrd/attrd_utils.c b/daemons/attrd/attrd_utils.c index 3025f197e76..e68550f5774 100644 --- a/daemons/attrd/attrd_utils.c +++ b/daemons/attrd/attrd_utils.c @@ -77,7 +77,6 @@ attrd_shutdown(int nsig) crm_exit(CRM_EX_OK); } else { g_main_loop_quit(mloop); - g_main_loop_unref(mloop); } } @@ -99,6 +98,7 @@ void attrd_run_mainloop(void) { g_main_loop_run(mloop); + g_clear_pointer(&mloop, g_main_loop_unref); } /* strlen("value") */ diff --git a/daemons/based/pacemaker-based.c b/daemons/based/pacemaker-based.c index c080bc5be13..c8976401b9b 100644 --- a/daemons/based/pacemaker-based.c +++ b/daemons/based/pacemaker-based.c @@ -404,6 +404,7 @@ main(int argc, char **argv) pcmk__notice("Pacemaker CIB manager successfully started and accepting " "connections"); g_main_loop_run(mainloop); + g_main_loop_unref(mainloop); done: g_strfreev(processed_args); diff --git a/daemons/controld/controld_control.c b/daemons/controld/controld_control.c index 9e0c00b7dac..d51be7a1018 100644 --- a/daemons/controld/controld_control.c +++ b/daemons/controld/controld_control.c @@ -246,7 +246,6 @@ crmd_exit(crm_exit_t exit_code) // Exit the main loop and free it when we return from this dispatch g_main_loop_quit(mloop); - g_main_loop_unref(mloop); } throttle_fini(); diff --git a/daemons/controld/pacemaker-controld.c b/daemons/controld/pacemaker-controld.c index 58f17e004b1..f202981010c 100644 --- a/daemons/controld/pacemaker-controld.c +++ b/daemons/controld/pacemaker-controld.c @@ -199,6 +199,8 @@ main(int argc, char **argv) // Run mainloop controld_globals.mainloop = g_main_loop_new(NULL, FALSE); g_main_loop_run(controld_globals.mainloop); + g_main_loop_unref(controld_globals.mainloop); + if (pcmk__is_set(controld_globals.fsa_input_register, R_STAYDOWN)) { pcmk__info("Inhibiting automated respawn"); exit_code = CRM_EX_FATAL; diff --git a/daemons/execd/cts-exec-helper.c b/daemons/execd/cts-exec-helper.c index 8508da6ef51..d13f045b10d 100644 --- a/daemons/execd/cts-exec-helper.c +++ b/daemons/execd/cts-exec-helper.c @@ -610,6 +610,7 @@ main(int argc, char **argv) pcmk__info("Starting"); mainloop = g_main_loop_new(NULL, FALSE); g_main_loop_run(mainloop); + g_main_loop_unref(mainloop); done: g_strfreev(processed_args); diff --git a/daemons/execd/pacemaker-execd.c b/daemons/execd/pacemaker-execd.c index 26b780e8e9a..5b38e4fa934 100644 --- a/daemons/execd/pacemaker-execd.c +++ b/daemons/execd/pacemaker-execd.c @@ -439,6 +439,7 @@ main(int argc, char **argv) "accepting connections"); pcmk__notice("OCF resource agent search path is %s", PCMK__OCF_RA_PATH); g_main_loop_run(mainloop); + g_main_loop_unref(mainloop); /* should never get here */ exit_executor(); diff --git a/daemons/fenced/cts-fence-helper.c b/daemons/fenced/cts-fence-helper.c index f4386ad16b4..21cbb7174b8 100644 --- a/daemons/fenced/cts-fence-helper.c +++ b/daemons/fenced/cts-fence-helper.c @@ -605,6 +605,7 @@ mainloop_tests(void) pcmk__info("Starting"); mainloop = g_main_loop_new(NULL, FALSE); g_main_loop_run(mainloop); + g_main_loop_unref(mainloop); } static GOptionContext * diff --git a/daemons/fenced/pacemaker-fenced.c b/daemons/fenced/pacemaker-fenced.c index 531d0738c10..be249badf9e 100644 --- a/daemons/fenced/pacemaker-fenced.c +++ b/daemons/fenced/pacemaker-fenced.c @@ -446,6 +446,7 @@ main(int argc, char **argv) pcmk__notice("Pacemaker fencer successfully started and accepting " "connections"); g_main_loop_run(mainloop); + g_main_loop_unref(mainloop); done: g_strfreev(processed_args); diff --git a/daemons/pacemakerd/pacemakerd.c b/daemons/pacemakerd/pacemakerd.c index 286ff374ae4..48e9b87ecbc 100644 --- a/daemons/pacemakerd/pacemakerd.c +++ b/daemons/pacemakerd/pacemakerd.c @@ -477,10 +477,11 @@ main(int argc, char **argv) pcmk__notice("Pacemaker daemon successfully started and accepting " "connections"); g_main_loop_run(mainloop); + g_main_loop_unref(mainloop); + pacemakerd_ipc_cleanup(); pacemakerd_unregister_handlers(); - g_main_loop_unref(mainloop); #if SUPPORT_COROSYNC cluster_disconnect_cfg(); #endif diff --git a/daemons/schedulerd/pacemaker-schedulerd.c b/daemons/schedulerd/pacemaker-schedulerd.c index e3ce0ca7c4a..67d6bbf8702 100644 --- a/daemons/schedulerd/pacemaker-schedulerd.c +++ b/daemons/schedulerd/pacemaker-schedulerd.c @@ -164,6 +164,7 @@ main(int argc, char **argv) pcmk__notice("Pacemaker scheduler successfully started and accepting " "connections"); g_main_loop_run(mainloop); + g_main_loop_unref(mainloop); done: g_strfreev(options.remainder); diff --git a/lib/pacemaker/pcmk_fence.c b/lib/pacemaker/pcmk_fence.c index b43bb2fd799..bc28e1a1ea9 100644 --- a/lib/pacemaker/pcmk_fence.c +++ b/lib/pacemaker/pcmk_fence.c @@ -222,6 +222,7 @@ pcmk__request_fencing(stonith_t *st, const char *target, const char *action, mainloop = g_main_loop_new(NULL, FALSE); g_main_loop_run(mainloop); + g_main_loop_unref(mainloop); free(async_fence_data.name); diff --git a/tools/crm_resource.c b/tools/crm_resource.c index 750c3d7d2cf..4150824c24a 100644 --- a/tools/crm_resource.c +++ b/tools/crm_resource.c @@ -2379,9 +2379,7 @@ main(int argc, char **argv) cib__clean_up_connection(&cib_conn); pcmk_free_ipc_api(controld_api); pcmk_free_scheduler(scheduler); - if (mainloop != NULL) { - g_main_loop_unref(mainloop); - } + g_clear_pointer(&mainloop, g_main_loop_unref); pcmk__output_and_clear_error(&error, out); From 05166f47ce14aec7e90977b3dda2198917e06254 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sat, 10 Jan 2026 19:55:25 -0800 Subject: [PATCH 08/37] Refactor: attrd: Drop mainloop_destroy_signal() from attrd_shutdown() mainloop_add_signal() adds mainloop_signal_handler() as a "wrapper" handler for the given signal. If the signal is received, mainloop_signal_handler() sets a boolean trigger value to true and returns. This is a lightweight operation. The "wrapped" signal handler gets called in a later main loop iteration. However, this can't happen after we've called attrd_shutdown(). Either we exit immediately or we quit the main loop. In either case, there will be no additional main loop iterations. Note that the controller is a bit different. There, we "drain" the main loop, which may run more loop iterations. So it makes some sense to destroy signal handlers before doing so. Signed-off-by: Reid Wahl --- daemons/attrd/attrd_utils.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/daemons/attrd/attrd_utils.c b/daemons/attrd/attrd_utils.c index e68550f5774..c4648fa6139 100644 --- a/daemons/attrd/attrd_utils.c +++ b/daemons/attrd/attrd_utils.c @@ -57,14 +57,6 @@ attrd_shutdown(int nsig) // Tell various functions not to do anthing shutting_down = true; - // Don't respond to signals while shutting down - mainloop_destroy_signal(SIGTERM); - mainloop_destroy_signal(SIGCHLD); - mainloop_destroy_signal(SIGPIPE); - mainloop_destroy_signal(SIGUSR1); - mainloop_destroy_signal(SIGUSR2); - mainloop_destroy_signal(SIGTRAP); - attrd_free_waitlist(); attrd_free_confirmations(); From 536e4b918db192cdc75bbd51496494fd5923a4a0 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sat, 10 Jan 2026 20:02:29 -0800 Subject: [PATCH 09/37] Refactor: attrd: Assume main loop is running in attrd_shutdown() There are two call sites. * attrd_cpg_destroy: This is called only via the main loop. See pcmk_cluster_set_destroy_fn() and pcmk__cpg_connect(). * attrd_shutdown: We can reach this only through the main loop. It's set up as a main loop signal handler via mainloop_add_signal(). The true signal handler is mainloop_signal_handler(), which sets a main loop trigger to call attrd_shutdown(). That trigger can't do anything unless the main loop is running. Signed-off-by: Reid Wahl --- daemons/attrd/attrd_utils.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/daemons/attrd/attrd_utils.c b/daemons/attrd/attrd_utils.c index c4648fa6139..2428104f058 100644 --- a/daemons/attrd/attrd_utils.c +++ b/daemons/attrd/attrd_utils.c @@ -62,14 +62,11 @@ attrd_shutdown(int nsig) g_clear_pointer(&peer_protocol_vers, g_hash_table_destroy); - if ((mloop == NULL) || !g_main_loop_is_running(mloop)) { - /* If there's no main loop active, just exit. This should be possible - * only if we get SIGTERM in brief windows at start-up and shutdown. - */ - crm_exit(CRM_EX_OK); - } else { - g_main_loop_quit(mloop); - } + // There should be no way to get here without the main loop running + CRM_CHECK((mloop != NULL) && g_main_loop_is_running(mloop), + crm_exit(CRM_EX_OK)); + + g_main_loop_quit(mloop); } /*! From cc1ab8a6874791ca4bc0bf8a866235df17c008ff Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sat, 10 Jan 2026 22:40:34 -0800 Subject: [PATCH 10/37] Refactor: based: Don't init node caches explicitly And assume the cache is already initialized when we call based_peer_callback(). pcmk__corosync_connect() initializes the node caches by calling pcmk__get_node(). Signed-off-by: Reid Wahl --- daemons/based/based_corosync.c | 18 ++---------------- daemons/based/pacemaker-based.c | 1 - 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/daemons/based/based_corosync.c b/daemons/based/based_corosync.c index 6825c9ac64a..81c88b49659 100644 --- a/daemons/based/based_corosync.c +++ b/daemons/based/based_corosync.c @@ -28,29 +28,15 @@ static pcmk_cluster_t *cluster = NULL; static void -based_peer_callback(xmlNode *msg, void *private_data) +based_peer_callback(xmlNode *msg) { - const char *reason = NULL; const char *originator = pcmk__xe_get(msg, PCMK__XA_SRC); - if (pcmk__peer_cache == NULL) { - reason = "membership not established"; - goto bail; - } - if (pcmk__xe_get(msg, PCMK__XA_CIB_CLIENTNAME) == NULL) { pcmk__xe_set(msg, PCMK__XA_CIB_CLIENTNAME, originator); } based_process_request(msg, true, NULL); - return; - - bail: - if (reason) { - const char *op = pcmk__xe_get(msg, PCMK__XA_CIB_OP); - - pcmk__warn("Discarding %s message from %s: %s", op, originator, reason); - } } #if SUPPORT_COROSYNC @@ -80,7 +66,7 @@ based_cpg_dispatch(cpg_handle_t handle, const struct cpg_name *group_name, return; } pcmk__xe_set(xml, PCMK__XA_SRC, from); - based_peer_callback(xml, NULL); + based_peer_callback(xml); pcmk__xml_free(xml); free(data); diff --git a/daemons/based/pacemaker-based.c b/daemons/based/pacemaker-based.c index c8976401b9b..f26cc41fe37 100644 --- a/daemons/based/pacemaker-based.c +++ b/daemons/based/pacemaker-based.c @@ -370,7 +370,6 @@ main(int argc, char **argv) goto done; } - pcmk__cluster_init_node_caches(); based_callbacks_init(); based_io_init(); From 19a6288d9833413ef774356dc8c3ac2266429e44 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sat, 10 Jan 2026 22:44:09 -0800 Subject: [PATCH 11/37] Refactor: based: Drop based_peer_callback() Signed-off-by: Reid Wahl --- daemons/based/based_corosync.c | 21 ++++++++------------- lib/cluster/corosync.c | 3 +++ 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/daemons/based/based_corosync.c b/daemons/based/based_corosync.c index 81c88b49659..a14c99a915f 100644 --- a/daemons/based/based_corosync.c +++ b/daemons/based/based_corosync.c @@ -27,18 +27,6 @@ static pcmk_cluster_t *cluster = NULL; -static void -based_peer_callback(xmlNode *msg) -{ - const char *originator = pcmk__xe_get(msg, PCMK__XA_SRC); - - if (pcmk__xe_get(msg, PCMK__XA_CIB_CLIENTNAME) == NULL) { - pcmk__xe_set(msg, PCMK__XA_CIB_CLIENTNAME, originator); - } - - based_process_request(msg, true, NULL); -} - #if SUPPORT_COROSYNC static void based_cpg_dispatch(cpg_handle_t handle, const struct cpg_name *group_name, @@ -65,8 +53,15 @@ based_cpg_dispatch(cpg_handle_t handle, const struct cpg_name *group_name, free(data); return; } + pcmk__xe_set(xml, PCMK__XA_SRC, from); - based_peer_callback(xml); + + if (pcmk__xe_get(xml, PCMK__XA_CIB_CLIENTNAME) == NULL) { + pcmk__xe_set(xml, PCMK__XA_CIB_CLIENTNAME, + pcmk__xe_get(xml, PCMK__XA_SRC)); + } + + based_process_request(xml, true, NULL); pcmk__xml_free(xml); free(data); diff --git a/lib/cluster/corosync.c b/lib/cluster/corosync.c index 305c9a2ac45..612ff5d3fe3 100644 --- a/lib/cluster/corosync.c +++ b/lib/cluster/corosync.c @@ -459,6 +459,9 @@ pcmk__corosync_quorum_connect(gboolean (*dispatch)(unsigned long long, * \param[in,out] cluster Initialized cluster object to connect * * \return Standard Pacemaker return code + * + * \note This initializes the node caches on success by calling + * \c pcmk__get_node(). */ int pcmk__corosync_connect(pcmk_cluster_t *cluster) From 6d0e08c98475b2151f34f763ab1576312295a200 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 11 Jan 2026 03:19:10 -0800 Subject: [PATCH 12/37] API: libcib: Deprecate cib_query and cib_connected_query This doesn't meaningfully change behavior except in the following ways. If you call the signon() method for a cib_native cib_t object, and you pass cib_query for the type: * The resulting cib_t:state value on success is cib_connected_command. Previously it was cib_connected_query. * The resulting connection can be used for read/write requests. Previously it could only be used for read-only requests. The cib_query (read-only) vs. cib_command (read/write) API was added when the CIB API was first created, in commit 58fdec76 (2004). No rationale was given. All cib_file and cib_remote clients use cib_command unconditionally. Their signon() methods ignore the type argument. Requests that the CIB manager receives via the cluster layer (Corosync) are also given read/write privileges. Read-only connections have been restricted to cib_native clients that sign on with type=cib_query. The asymmetry of cib_native clients vs. cib_remote clients doesn't seem to make sense, and cib_query doesn't seem especially useful. One can make an argument that it promotes safety/least-privilege by allowing a client to ensure that it doesn't modify the CIB. However, this can be achieved with some basic discipline, and it already wasn't available for cib_remote connections. Supporting read-only connections complicates our CIB manager implementation substantially. We will now treat connections created with cib_query the same as those created with cib_command, and this will simplify things by a lot. Signed-off-by: Reid Wahl --- daemons/execd/remoted_schemas.c | 4 ++-- include/crm/cib/cib_types.h | 7 ++++++- lib/cib/cib_native.c | 10 ++++------ python/pacemaker/_cts/patterns.py | 2 +- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/daemons/execd/remoted_schemas.c b/daemons/execd/remoted_schemas.c index da4fece9267..191ed00b854 100644 --- a/daemons/execd/remoted_schemas.c +++ b/daemons/execd/remoted_schemas.c @@ -1,5 +1,5 @@ /* - * Copyright 2023-2025 the Pacemaker project contributors + * Copyright 2023-2026 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -144,7 +144,7 @@ get_schema_files(void) _exit(CRM_EX_OSERR); } - rc = cib->cmds->signon(cib, crm_system_name, cib_query); + rc = cib->cmds->signon(cib, crm_system_name, cib_command); rc = pcmk_legacy2rc(rc); if (rc != pcmk_rc_ok) { pcmk__err("Could not connect to the CIB manager: %s", pcmk_rc_str(rc)); diff --git a/include/crm/cib/cib_types.h b/include/crm/cib/cib_types.h index 41fd6094b87..93ece539aa5 100644 --- a/include/crm/cib/cib_types.h +++ b/include/crm/cib/cib_types.h @@ -41,6 +41,7 @@ enum cib_state { cib_connected_command, // NOTE: sbd (as of at least 1.5.2) uses this value + //! \deprecated Look for \c cib_connected_command instead cib_connected_query, cib_disconnected @@ -50,6 +51,7 @@ enum cib_conn_type { cib_command, // NOTE: sbd (as of at least 1.5.2) uses this value + //! \deprecated Use \c cib_command instead cib_query, cib_no_connection, @@ -138,7 +140,10 @@ typedef struct cib_s cib_t; */ typedef struct cib_api_operations_s { // NOTE: sbd (as of at least 1.5.2) uses this - // @COMPAT At compatibility break, drop name (always use crm_system_name) + /* @COMPAT At a compatibility break, drop name (always use crm_system_name) + * and type (always use cib_command -- cib_file and cib_remote already do + * this). + */ int (*signon) (cib_t *cib, const char *name, enum cib_conn_type type); // NOTE: sbd (as of at least 1.5.2) uses this diff --git a/lib/cib/cib_native.c b/lib/cib/cib_native.c index 39524166492..df36af0fa88 100644 --- a/lib/cib/cib_native.c +++ b/lib/cib/cib_native.c @@ -300,16 +300,14 @@ cib_native_signon(cib_t *cib, const char *name, enum cib_conn_type type) switch (type) { case cib_command: case cib_command_nonblocking: - // @COMPAT cib_command_nonblocking is deprecated since 3.0.2 + case cib_query: + /* @COMPAT cib_command_nonblocking and cib_query are deprecated + * since 3.0.2 + */ cib->state = cib_connected_command; channel = PCMK__SERVER_BASED_RW; break; - case cib_query: - cib->state = cib_connected_query; - channel = PCMK__SERVER_BASED_RO; - break; - default: return -ENOTCONN; } diff --git a/python/pacemaker/_cts/patterns.py b/python/pacemaker/_cts/patterns.py index 4b69cfe9a14..2cff9504969 100644 --- a/python/pacemaker/_cts/patterns.py +++ b/python/pacemaker/_cts/patterns.py @@ -177,7 +177,7 @@ def __init__(self): r"error.*: Operation 'reboot' .* using FencingFail returned ", r"getinfo response error: 1$", r"sbd.* error: inquisitor_child: DEBUG MODE IS ACTIVE", - r"sbd.* pcmk:\s*error:.*Connection to cib_ro.* (failed|closed)", + r"sbd.* pcmk:\s*error:.*Connection to cib_rw.* (failed|closed)", ] self._bad_news = [ From dc7089bd8b99d61d00477ca984cda73fbdd8713c Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 11 Jan 2026 15:19:48 -0800 Subject: [PATCH 13/37] Refactor: remoted: Drop cib_proxy_accept_ro() As of the previous commit, no remote client can connect to the PCMK__SERVER_BASED_RO channel. (cib_native clients now use PCMK__SERVER_BASED_RW unconditionally.) So replace the two separate cib_proxy_accept_*() functions with a single based_proxy_accept(). Keep the two ipcs objects (based_ipcs_ro and based_ipcs_rw) for now, since pcmk__serve_based_ipc() needs both. Their callbacks are the same, however. Signed-off-by: Reid Wahl --- daemons/execd/remoted_proxy.c | 55 +++++++++++++---------------------- 1 file changed, 20 insertions(+), 35 deletions(-) diff --git a/daemons/execd/remoted_proxy.c b/daemons/execd/remoted_proxy.c index 10213ff180d..87c20d2d286 100644 --- a/daemons/execd/remoted_proxy.c +++ b/daemons/execd/remoted_proxy.c @@ -27,10 +27,9 @@ #include "pacemaker-execd.h" // lrmd_server_send_notify -static qb_ipcs_service_t *cib_ro = NULL; -static qb_ipcs_service_t *cib_rw = NULL; - static qb_ipcs_service_t *attrd_ipcs = NULL; +static qb_ipcs_service_t *based_ipcs_ro = NULL; +static qb_ipcs_service_t *based_ipcs_rw = NULL; static qb_ipcs_service_t *controld_ipcs = NULL; static qb_ipcs_service_t *fencer_ipcs = NULL; static qb_ipcs_service_t *pacemakerd_ipcs = NULL; @@ -133,27 +132,21 @@ attrd_proxy_accept(qb_ipcs_connection_t *c, uid_t uid, gid_t gid) } static int32_t -fencer_proxy_accept(qb_ipcs_connection_t *c, uid_t uid, gid_t gid) +based_proxy_accept(qb_ipcs_connection_t *c, uid_t uid, gid_t gid) { - return ipc_proxy_accept(c, uid, gid, "stonith-ng"); -} - -static int32_t -pacemakerd_proxy_accept(qb_ipcs_connection_t *c, uid_t uid, gid_t gid) -{ - return -EREMOTEIO; + return ipc_proxy_accept(c, uid, gid, PCMK__SERVER_BASED_RW); } static int32_t -cib_proxy_accept_rw(qb_ipcs_connection_t *c, uid_t uid, gid_t gid) +fencer_proxy_accept(qb_ipcs_connection_t *c, uid_t uid, gid_t gid) { - return ipc_proxy_accept(c, uid, gid, PCMK__SERVER_BASED_RW); + return ipc_proxy_accept(c, uid, gid, "stonith-ng"); } static int32_t -cib_proxy_accept_ro(qb_ipcs_connection_t *c, uid_t uid, gid_t gid) +pacemakerd_proxy_accept(qb_ipcs_connection_t *c, uid_t uid, gid_t gid) { - return ipc_proxy_accept(c, uid, gid, PCMK__SERVER_BASED_RO); + return -EREMOTEIO; } int @@ -438,6 +431,14 @@ static struct qb_ipcs_service_handlers attrd_proxy_callbacks = { .connection_destroyed = ipc_proxy_destroy }; +static struct qb_ipcs_service_handlers based_proxy_callbacks = { + .connection_accept = based_proxy_accept, + .connection_created = NULL, + .msg_process = ipc_proxy_dispatch, + .connection_closed = ipc_proxy_closed, + .connection_destroyed = ipc_proxy_destroy +}; + static struct qb_ipcs_service_handlers fencer_proxy_callbacks = { .connection_accept = fencer_proxy_accept, .connection_created = NULL, @@ -454,22 +455,6 @@ static struct qb_ipcs_service_handlers pacemakerd_proxy_callbacks = { .connection_destroyed = NULL }; -static struct qb_ipcs_service_handlers cib_proxy_callbacks_ro = { - .connection_accept = cib_proxy_accept_ro, - .connection_created = NULL, - .msg_process = ipc_proxy_dispatch, - .connection_closed = ipc_proxy_closed, - .connection_destroyed = ipc_proxy_destroy -}; - -static struct qb_ipcs_service_handlers cib_proxy_callbacks_rw = { - .connection_accept = cib_proxy_accept_rw, - .connection_created = NULL, - .msg_process = ipc_proxy_dispatch, - .connection_closed = ipc_proxy_closed, - .connection_destroyed = ipc_proxy_destroy -}; - void ipc_proxy_add_provider(pcmk__client_t *ipc_proxy) { @@ -518,9 +503,9 @@ ipc_proxy_init(void) { ipc_clients = pcmk__strkey_table(NULL, NULL); - pcmk__serve_based_ipc(&cib_ro, &cib_rw, &cib_proxy_callbacks_ro, - &cib_proxy_callbacks_rw); pcmk__serve_attrd_ipc(&attrd_ipcs, &attrd_proxy_callbacks); + pcmk__serve_based_ipc(&based_ipcs_ro, &based_ipcs_rw, + &based_proxy_callbacks, &based_proxy_callbacks); pcmk__serve_controld_ipc(&controld_ipcs, &crmd_proxy_callbacks); if (controld_ipcs == NULL) { @@ -539,8 +524,8 @@ ipc_proxy_cleanup(void) g_clear_pointer(&ipc_clients, g_hash_table_destroy); g_clear_pointer(&attrd_ipcs, qb_ipcs_destroy); - g_clear_pointer(&cib_ro, qb_ipcs_destroy); - g_clear_pointer(&cib_rw, qb_ipcs_destroy); + g_clear_pointer(&based_ipcs_ro, qb_ipcs_destroy); + g_clear_pointer(&based_ipcs_rw, qb_ipcs_destroy); g_clear_pointer(&controld_ipcs, qb_ipcs_destroy); g_clear_pointer(&fencer_ipcs, qb_ipcs_destroy); g_clear_pointer(&pacemakerd_ipcs, qb_ipcs_destroy); From 7be7e4fb1018935788234545133d7f62e9c0aaa7 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 11 Jan 2026 15:27:09 -0800 Subject: [PATCH 14/37] Refactor: based: Check for old PCMK__SERVER_BASED_RW instance If there was a PCMK__SERVER_BASED_RO instance, there also should have been a PCMK__SERVER_BASED_RW instance. We're moving toward using PCMK__SERVER_BASED_RW everywhere, so use it here. Signed-off-by: Reid Wahl --- daemons/based/pacemaker-based.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemons/based/pacemaker-based.c b/daemons/based/pacemaker-based.c index f26cc41fe37..9667423b124 100644 --- a/daemons/based/pacemaker-based.c +++ b/daemons/based/pacemaker-based.c @@ -328,7 +328,7 @@ main(int argc, char **argv) crm_log_init(NULL, LOG_INFO, TRUE, FALSE, argc, argv, FALSE); pcmk__notice("Starting Pacemaker CIB manager"); - old_instance = crm_ipc_new(PCMK__SERVER_BASED_RO, 0); + old_instance = crm_ipc_new(PCMK__SERVER_BASED_RW, 0); if (old_instance == NULL) { /* crm_ipc_new() will have already logged an error message with * pcmk__err() From c17d49f589ac20db7e54536b40083030033ed0ca Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 11 Jan 2026 15:01:28 -0800 Subject: [PATCH 15/37] Refactor: based: Make PCMK__SERVER_BASED_RO behave like _RW This affects only proxied connections from older Pacemaker Remote nodes. IPC clients on cluster nodes and on same-version Pacemaker Remote nodes use PCMK__SERVER_BASED_RW unconditionally (as of a recent commit that updated cib_native_signon()). This shouldn't cause any breakages or noticeable changes for existing clients. The capabilities of PCMK__SERVER_BASED_RW were already a proper superset of the capabilities of PCMK__SERVER_BASED_RO. That is, a client connected to the PCMK__SERVER_BASED_RW channel could do anything that a client connected to the PCMK__SERVER_BASED_RO channel can do, but not vice-versa. So nothing that previously worked should break. Signed-off-by: Reid Wahl --- daemons/based/based_ipc.c | 69 ++++++--------------------------------- lib/cib/cib_native.c | 11 ++++--- lib/cib/cib_remote.c | 8 ++--- 3 files changed, 20 insertions(+), 68 deletions(-) diff --git a/daemons/based/based_ipc.c b/daemons/based/based_ipc.c index 42d8998c958..50bdbd4091c 100644 --- a/daemons/based/based_ipc.c +++ b/daemons/based/based_ipc.c @@ -60,17 +60,16 @@ based_ipc_accept(qb_ipcs_connection_t *c, uid_t uid, gid_t gid) * \internal * \brief Handle a message from an IPC connection * - * \param[in,out] c Established IPC connection - * \param[in] data The message data read from the connection - this - * can be a complete IPC message or just a part of - * one if it's very large - * \param[in] privileged If \c true, operations with - * \c cib__op_attr_privileged can be run + * \param[in,out] c Established IPC connection + * \param[in] data The message data read from the connection - this can be + * a complete IPC message or just a part of one if it's + * very large + * \param[in] size Unused * * \return 0 in all cases */ static int32_t -dispatch_common(qb_ipcs_connection_t *c, void *data, bool privileged) +based_ipc_dispatch(qb_ipcs_connection_t *c, void *data, size_t size) { int rc = pcmk_rc_ok; uint32_t id = 0; @@ -87,9 +86,6 @@ dispatch_common(qb_ipcs_connection_t *c, void *data, bool privileged) return 0; } - pcmk__trace("Dispatching %sprivileged request from client %s", - (privileged? "" : "un"), client->id); - rc = pcmk__ipc_msg_append(&client->buffer, data); if (rc == pcmk_rc_ipc_more) { @@ -201,49 +197,13 @@ dispatch_common(qb_ipcs_connection_t *c, void *data, bool privileged) goto cleanup; } - based_process_request(msg, privileged, client); + based_process_request(msg, true, client); cleanup: pcmk__xml_free(msg); return 0; } -/*! - * \internal - * \brief Handle a message from a read-only IPC connection - * - * \param[in,out] c Established IPC connection - * \param[in] data The message data read from the connection - this can be - * a complete IPC message or just a part of one if it's - * very large - * \param[in] size Unused - * - * \return 0 in all cases - */ -static int32_t -based_ipc_dispatch_ro(qb_ipcs_connection_t *c, void *data, size_t size) -{ - return dispatch_common(c, data, false); -} - -/*! - * \internal - * \brief Handle a message from a read/write IPC connection - * - * \param[in,out] c Established IPC connection - * \param[in] data The message data read from the connection - this can be - * a complete IPC message or just a part of one if it's - * very large - * \param[in] size Unused - * - * \return 0 in all cases - */ -static int32_t -based_ipc_dispatch_rw(qb_ipcs_connection_t *c, void *data, size_t size) -{ - return dispatch_common(c, data, true); -} - /*! * \internal * \brief Destroy a client IPC connection @@ -280,18 +240,10 @@ based_ipc_destroy(qb_ipcs_connection_t *c) based_ipc_closed(c); } -static struct qb_ipcs_service_handlers ipc_ro_callbacks = { - .connection_accept = based_ipc_accept, - .connection_created = NULL, - .msg_process = based_ipc_dispatch_ro, - .connection_closed = based_ipc_closed, - .connection_destroyed = based_ipc_destroy, -}; - -static struct qb_ipcs_service_handlers ipc_rw_callbacks = { +static struct qb_ipcs_service_handlers ipc_callbacks = { .connection_accept = based_ipc_accept, .connection_created = NULL, - .msg_process = based_ipc_dispatch_rw, + .msg_process = based_ipc_dispatch, .connection_closed = based_ipc_closed, .connection_destroyed = based_ipc_destroy, }; @@ -303,8 +255,7 @@ static struct qb_ipcs_service_handlers ipc_rw_callbacks = { void based_ipc_init(void) { - pcmk__serve_based_ipc(&ipcs_ro, &ipcs_rw, &ipc_ro_callbacks, - &ipc_rw_callbacks); + pcmk__serve_based_ipc(&ipcs_ro, &ipcs_rw, &ipc_callbacks, &ipc_callbacks); } /*! diff --git a/lib/cib/cib_native.c b/lib/cib/cib_native.c index df36af0fa88..1944f046bd5 100644 --- a/lib/cib/cib_native.c +++ b/lib/cib/cib_native.c @@ -104,9 +104,9 @@ cib_native_perform_op_delegate(cib_t *cib, const char *op, const char *host, goto done; } - /* The only reason we can receive an ACK here is if dispatch_common -> + /* The only reason we can receive an ACK here is if based_ipc_dispatch -> * pcmk__client_data2xml processed something that's not valid XML. - * dispatch_common does not return ACK, unlike other daemons. + * based_ipc_dispatch does not return ACK, unlike other daemons. */ if (pcmk__xe_is(op_reply, PCMK__XE_ACK) && ack_is_failure(op_reply)) { rc = -EPROTO; @@ -339,9 +339,10 @@ cib_native_signon(cib_t *cib, const char *name, enum cib_conn_type type) goto done; } - /* The only reason we can receive an ACK here is if dispatch_common -> - * pcmk__client_data2xml processed something that's not valid XML. - * dispatch_common does not return ACK, unlike other daemons. + /* The only reason we can receive an ACK here is if + * based_ipc_dispatch -> pcmk__client_data2xml processed something + * that's not valid XML. based_ipc_dispatch does not return ACK, unlike + * other daemons. */ if (pcmk__xe_is(reply, PCMK__XE_ACK) && ack_is_failure(reply)) { rc = -EPROTO; diff --git a/lib/cib/cib_remote.c b/lib/cib/cib_remote.c index 72624f2d6e1..9a4a8605e29 100644 --- a/lib/cib/cib_remote.c +++ b/lib/cib/cib_remote.c @@ -172,9 +172,9 @@ cib_remote_perform_op(cib_t *cib, const char *op, const char *host, return -ENOMSG; } - /* The only reason we can receive an ACK here is if dispatch_common -> + /* The only reason we can receive an ACK here is if based_ipc_dispatch -> * pcmk__client_data2xml processed something that's not valid XML. - * dispatch_common does not return ACK, unlike other daemons. + * based_ipc_dispatch does not return ACK, unlike other daemons. */ if (pcmk__xe_is(op_reply, PCMK__XE_ACK) && ack_is_failure(op_reply)) { pcmk__xml_free(op_reply); @@ -526,9 +526,9 @@ cib_tls_signon(cib_t *cib, pcmk__remote_t *connection, gboolean event_channel) goto done; } - /* The only reason we can receive an ACK here is if dispatch_common -> + /* The only reason we can receive an ACK here is if based_ipc_dispatch -> * pcmk__client_data2xml processed something that's not valid XML. - * dispatch_common does not return ACK, unlike other daemons. + * based_ipc_dispatch does not return ACK, unlike other daemons. */ if (pcmk__xe_is(answer, PCMK__XE_ACK) && ack_is_failure(answer)) { rc = -EPROTO; From 60391d9b65cf2d1756afb41a57a707f518bbb617 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 11 Jan 2026 15:41:05 -0800 Subject: [PATCH 16/37] Refactor: based: Drop privileged argument of based_process_request() We always pass true. Signed-off-by: Reid Wahl --- daemons/based/based_callbacks.c | 18 +++++------------- daemons/based/based_callbacks.h | 5 +---- daemons/based/based_corosync.c | 3 +-- daemons/based/based_ipc.c | 3 +-- daemons/based/based_remote.c | 2 +- daemons/based/based_transaction.c | 7 ++----- 6 files changed, 11 insertions(+), 27 deletions(-) diff --git a/daemons/based/based_callbacks.c b/daemons/based/based_callbacks.c index 9f62c48f6d6..f90ac2e66c8 100644 --- a/daemons/based/based_callbacks.c +++ b/daemons/based/based_callbacks.c @@ -656,17 +656,14 @@ send_peer_reply(xmlNode *msg, const char *originator) * \internal * \brief Handle an IPC or CPG message containing a request * - * \param[in,out] request Request XML - * \param[in] privileged If \c true, operations with - * \c cib__op_attr_privileged can be run - * \param[in] client IPC client that sent request (\c NULL if request - * came from CPG) + * \param[in,out] request Request XML + * \param[in] client IPC client that sent request (\c NULL if request came + * from CPG) * * \return Standard Pacemaker return code */ int -based_process_request(xmlNode *request, bool privileged, - const pcmk__client_t *client) +based_process_request(xmlNode *request, const pcmk__client_t *client) { // @TODO: Break into multiple smaller functions uint32_t call_options = cib_none; @@ -795,12 +792,7 @@ based_process_request(xmlNode *request, bool privileged, start_time = time(NULL); - if (!privileged - && pcmk__is_set(operation->flags, cib__op_attr_privileged)) { - - rc = EACCES; - - } else if (!pcmk__is_set(operation->flags, cib__op_attr_modifies)) { + if (!pcmk__is_set(operation->flags, cib__op_attr_modifies)) { rc = cib__perform_op_ro(op_function, request, &based_cib, &output); } else { diff --git a/daemons/based/based_callbacks.h b/daemons/based/based_callbacks.h index 7363e7ab2d6..93565ef1a93 100644 --- a/daemons/based/based_callbacks.h +++ b/daemons/based/based_callbacks.h @@ -10,8 +10,6 @@ #ifndef BASED_CALLBACKS__H #define BASED_CALLBACKS__H -#include - #include // xmlNode #include // pcmk__client_t @@ -19,7 +17,6 @@ void based_callbacks_init(void); void based_callbacks_cleanup(void); -int based_process_request(xmlNode *request, bool privileged, - const pcmk__client_t *client); +int based_process_request(xmlNode *request, const pcmk__client_t *client); #endif // BASED_CALLBACKS__H diff --git a/daemons/based/based_corosync.c b/daemons/based/based_corosync.c index a14c99a915f..2efb71c5706 100644 --- a/daemons/based/based_corosync.c +++ b/daemons/based/based_corosync.c @@ -10,7 +10,6 @@ #include #include // PRIu32 -#include #include // NULL, size_t #include // uint32_t #include // free @@ -61,7 +60,7 @@ based_cpg_dispatch(cpg_handle_t handle, const struct cpg_name *group_name, pcmk__xe_get(xml, PCMK__XA_SRC)); } - based_process_request(xml, true, NULL); + based_process_request(xml, NULL); pcmk__xml_free(xml); free(data); diff --git a/daemons/based/based_ipc.c b/daemons/based/based_ipc.c index 50bdbd4091c..3aad068ce89 100644 --- a/daemons/based/based_ipc.c +++ b/daemons/based/based_ipc.c @@ -10,7 +10,6 @@ #include #include // ECONNREFUSED, ENOMEM -#include #include // NULL, size_t #include // int32_t, uint32_t #include // gid_t, uid_t @@ -197,7 +196,7 @@ based_ipc_dispatch(qb_ipcs_connection_t *c, void *data, size_t size) goto cleanup; } - based_process_request(msg, true, client); + based_process_request(msg, client); cleanup: pcmk__xml_free(msg); diff --git a/daemons/based/based_remote.c b/daemons/based/based_remote.c index 7574cbe9cd5..e91ef7214ef 100644 --- a/daemons/based/based_remote.c +++ b/daemons/based/based_remote.c @@ -392,7 +392,7 @@ cib_handle_remote_msg(pcmk__client_t *client, xmlNode *command) based_update_notify_flags(command, client); } - based_process_request(command, true, client); + based_process_request(command, client); } static int diff --git a/daemons/based/based_transaction.c b/daemons/based/based_transaction.c index 22fa18d9ea1..afe9bc3fbdc 100644 --- a/daemons/based/based_transaction.c +++ b/daemons/based/based_transaction.c @@ -10,7 +10,6 @@ #include #include // EOPNOTSUPP -#include #include // NULL #include // free @@ -79,11 +78,9 @@ process_transaction_requests(xmlNode *transaction, const pcmk__client_t *client, || (host != NULL)) { rc = EOPNOTSUPP; + } else { - /* Commit-transaction is a privileged operation. If we reached - * this point, the request came from a privileged connection. - */ - rc = based_process_request(request, true, client); + rc = based_process_request(request, client); } } From f773a3c5e62ca68dd57c71ec47930b0380d3e6da Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 11 Jan 2026 15:44:07 -0800 Subject: [PATCH 17/37] Refactor: libcib: Drop cib__op_attr_privileged Nothing uses it anymore. Signed-off-by: Reid Wahl --- include/crm/cib/internal.h | 3 --- lib/cib/cib_ops.c | 47 +++++++++++--------------------------- 2 files changed, 13 insertions(+), 37 deletions(-) diff --git a/include/crm/cib/internal.h b/include/crm/cib/internal.h index 98a20b1e49f..99ce4bd359f 100644 --- a/include/crm/cib/internal.h +++ b/include/crm/cib/internal.h @@ -51,9 +51,6 @@ enum cib__op_attr { //! May modify state (of the CIB itself or of the CIB manager) cib__op_attr_modifies = (UINT32_C(1) << 1), - //! Requires privileges - cib__op_attr_privileged = (UINT32_C(1) << 2), - //! Must only be processed locally cib__op_attr_local = (UINT32_C(1) << 3), diff --git a/lib/cib/cib_ops.c b/lib/cib/cib_ops.c index 41ead4081b2..3cef5ff3025 100644 --- a/lib/cib/cib_ops.c +++ b/lib/cib/cib_ops.c @@ -35,56 +35,38 @@ static GHashTable *operation_table = NULL; static const cib__operation_t cib_ops[] = { { - PCMK__CIB_REQUEST_ABS_DELETE, cib__op_abs_delete, - cib__op_attr_modifies|cib__op_attr_privileged + PCMK__CIB_REQUEST_ABS_DELETE, cib__op_abs_delete, cib__op_attr_modifies }, { PCMK__CIB_REQUEST_APPLY_PATCH, cib__op_apply_patch, - cib__op_attr_modifies - |cib__op_attr_privileged - |cib__op_attr_transaction + cib__op_attr_modifies|cib__op_attr_transaction }, { PCMK__CIB_REQUEST_BUMP, cib__op_bump, - cib__op_attr_modifies - |cib__op_attr_privileged - |cib__op_attr_transaction + cib__op_attr_modifies|cib__op_attr_transaction }, { PCMK__CIB_REQUEST_COMMIT_TRANSACT, cib__op_commit_transact, - cib__op_attr_modifies - |cib__op_attr_privileged - |cib__op_attr_replaces - |cib__op_attr_writes_through + cib__op_attr_modifies|cib__op_attr_replaces|cib__op_attr_writes_through }, { PCMK__CIB_REQUEST_CREATE, cib__op_create, - cib__op_attr_modifies - |cib__op_attr_privileged - |cib__op_attr_transaction + cib__op_attr_modifies|cib__op_attr_transaction }, { PCMK__CIB_REQUEST_DELETE, cib__op_delete, - cib__op_attr_modifies - |cib__op_attr_privileged - |cib__op_attr_transaction + cib__op_attr_modifies|cib__op_attr_transaction }, { PCMK__CIB_REQUEST_ERASE, cib__op_erase, - cib__op_attr_modifies - |cib__op_attr_privileged - |cib__op_attr_replaces - |cib__op_attr_transaction + cib__op_attr_modifies|cib__op_attr_replaces|cib__op_attr_transaction }, { - PCMK__CIB_REQUEST_IS_PRIMARY, cib__op_is_primary, - cib__op_attr_privileged + PCMK__CIB_REQUEST_IS_PRIMARY, cib__op_is_primary, cib__op_attr_none }, { PCMK__CIB_REQUEST_MODIFY, cib__op_modify, - cib__op_attr_modifies - |cib__op_attr_privileged - |cib__op_attr_transaction + cib__op_attr_modifies|cib__op_attr_transaction }, { PCMK__CIB_REQUEST_NOOP, cib__op_noop, cib__op_attr_none @@ -95,7 +77,7 @@ static const cib__operation_t cib_ops[] = { { // @COMPAT: Drop cib__op_attr_modifies when we drop legacy mode support PCMK__CIB_REQUEST_PRIMARY, cib__op_primary, - cib__op_attr_modifies|cib__op_attr_privileged|cib__op_attr_local + cib__op_attr_modifies|cib__op_attr_local }, { PCMK__CIB_REQUEST_QUERY, cib__op_query, cib__op_attr_none @@ -103,7 +85,6 @@ static const cib__operation_t cib_ops[] = { { PCMK__CIB_REQUEST_REPLACE, cib__op_replace, cib__op_attr_modifies - |cib__op_attr_privileged |cib__op_attr_replaces |cib__op_attr_writes_through |cib__op_attr_transaction @@ -112,19 +93,17 @@ static const cib__operation_t cib_ops[] = { PCMK__CIB_REQUEST_SCHEMAS, cib__op_schemas, cib__op_attr_local }, { - PCMK__CIB_REQUEST_SECONDARY, cib__op_secondary, - cib__op_attr_privileged|cib__op_attr_local + PCMK__CIB_REQUEST_SECONDARY, cib__op_secondary, cib__op_attr_local }, { - PCMK__CIB_REQUEST_SHUTDOWN, cib__op_shutdown, cib__op_attr_privileged + PCMK__CIB_REQUEST_SHUTDOWN, cib__op_shutdown, cib__op_attr_none }, { - PCMK__CIB_REQUEST_SYNC, cib__op_sync, cib__op_attr_privileged + PCMK__CIB_REQUEST_SYNC, cib__op_sync, cib__op_attr_none }, { PCMK__CIB_REQUEST_UPGRADE, cib__op_upgrade, cib__op_attr_modifies - |cib__op_attr_privileged |cib__op_attr_writes_through |cib__op_attr_transaction }, From d04c2394b461961e7f9a03a0c4579a3eb6786268 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 11 Jan 2026 15:56:47 -0800 Subject: [PATCH 18/37] Refactor: liblrmd: Map proxied PCMK__SERVER_BASED_RO clients to _RW This happens only on the cluster node that is providing an IPC proxy for a Pacemaker Remote client. This way, we'll treat the client as being associated with PCMK__SERVER_BASED_RW in every way. We no longer have anything using PCMK__SERVER_BASED_RO except for this function that maps it to PCMK__SERVER_BASED_RW, and pcmk__parse_server() (which should no longer be receiving PCMK__SERVER_BASED_RO as an argument). Signed-off-by: Reid Wahl --- daemons/controld/controld_remote_proxy.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/daemons/controld/controld_remote_proxy.c b/daemons/controld/controld_remote_proxy.c index 8da874e02b6..16ae3db4f53 100644 --- a/daemons/controld/controld_remote_proxy.c +++ b/daemons/controld/controld_remote_proxy.c @@ -188,6 +188,16 @@ remote_proxy_new(lrmd_t *lrmd, const char *node_name, const char *session_id, return NULL; } + /* @COMPAT Proxied clients from Pacemaker Remote nodes older than version + * 3.0.2 can connect using PCMK__SERVER_BASED_RO. Since we use + * PCMK__SERVER_BASED_RW for everything now, and since no local or same- + * versioned proxied clients can connect to PCMK__SERVER_BASED_RO, just map + * it to PCMK__SERVER_BASED_RW here. + */ + if (pcmk__str_eq(channel, PCMK__SERVER_BASED_RO, pcmk__str_none)) { + channel = PCMK__SERVER_BASED_RW; + } + proxy = pcmk__assert_alloc(1, sizeof(remote_proxy_t)); proxy->node_name = pcmk__str_copy(node_name); From 143926567aeb02031493dfac1419a2666a95700f Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 11 Jan 2026 16:13:27 -0800 Subject: [PATCH 19/37] Refactor: libcrmcommon: pcmk__serve_based_ipc() starts only one server Now that there is no possibility of receiving an IPC client connection (either local or proxied, whether in a rolling upgrade or not) with server name set to PCMK__SERVER_BASED_RO, we don't need to serve anything with that name anymore. _RO already behaved the same as _RW. Signed-off-by: Reid Wahl --- daemons/based/based_ipc.c | 12 ++++------ daemons/execd/remoted_proxy.c | 9 +++----- include/crm/common/ipc_internal.h | 6 ++--- lib/common/ipc_server.c | 23 +++++++------------ lib/common/servers.c | 38 +++++++++++++++++-------------- 5 files changed, 38 insertions(+), 50 deletions(-) diff --git a/daemons/based/based_ipc.c b/daemons/based/based_ipc.c index 3aad068ce89..850a638c525 100644 --- a/daemons/based/based_ipc.c +++ b/daemons/based/based_ipc.c @@ -26,8 +26,7 @@ #include "pacemaker-based.h" -static qb_ipcs_service_t *ipcs_ro = NULL; -static qb_ipcs_service_t *ipcs_rw = NULL; +static qb_ipcs_service_t *ipcs = NULL; /*! * \internal @@ -254,7 +253,7 @@ static struct qb_ipcs_service_handlers ipc_callbacks = { void based_ipc_init(void) { - pcmk__serve_based_ipc(&ipcs_ro, &ipcs_rw, &ipc_callbacks, &ipc_callbacks); + pcmk__serve_based_ipc(&ipcs, &ipc_callbacks); } /*! @@ -264,11 +263,8 @@ based_ipc_init(void) void based_ipc_cleanup(void) { - pcmk__drop_all_clients(ipcs_ro); - g_clear_pointer(&ipcs_ro, qb_ipcs_destroy); - - pcmk__drop_all_clients(ipcs_rw); - g_clear_pointer(&ipcs_rw, qb_ipcs_destroy); + pcmk__drop_all_clients(ipcs); + g_clear_pointer(&ipcs, qb_ipcs_destroy); /* Drop remote clients here because they're part of the IPC client table and * must be dropped before \c pcmk__client_cleanup() diff --git a/daemons/execd/remoted_proxy.c b/daemons/execd/remoted_proxy.c index 87c20d2d286..36f71c0b844 100644 --- a/daemons/execd/remoted_proxy.c +++ b/daemons/execd/remoted_proxy.c @@ -28,8 +28,7 @@ #include "pacemaker-execd.h" // lrmd_server_send_notify static qb_ipcs_service_t *attrd_ipcs = NULL; -static qb_ipcs_service_t *based_ipcs_ro = NULL; -static qb_ipcs_service_t *based_ipcs_rw = NULL; +static qb_ipcs_service_t *based_ipcs = NULL; static qb_ipcs_service_t *controld_ipcs = NULL; static qb_ipcs_service_t *fencer_ipcs = NULL; static qb_ipcs_service_t *pacemakerd_ipcs = NULL; @@ -504,8 +503,7 @@ ipc_proxy_init(void) ipc_clients = pcmk__strkey_table(NULL, NULL); pcmk__serve_attrd_ipc(&attrd_ipcs, &attrd_proxy_callbacks); - pcmk__serve_based_ipc(&based_ipcs_ro, &based_ipcs_rw, - &based_proxy_callbacks, &based_proxy_callbacks); + pcmk__serve_based_ipc(&based_ipcs, &based_proxy_callbacks); pcmk__serve_controld_ipc(&controld_ipcs, &crmd_proxy_callbacks); if (controld_ipcs == NULL) { @@ -524,8 +522,7 @@ ipc_proxy_cleanup(void) g_clear_pointer(&ipc_clients, g_hash_table_destroy); g_clear_pointer(&attrd_ipcs, qb_ipcs_destroy); - g_clear_pointer(&based_ipcs_ro, qb_ipcs_destroy); - g_clear_pointer(&based_ipcs_rw, qb_ipcs_destroy); + g_clear_pointer(&based_ipcs, qb_ipcs_destroy); g_clear_pointer(&controld_ipcs, qb_ipcs_destroy); g_clear_pointer(&fencer_ipcs, qb_ipcs_destroy); g_clear_pointer(&pacemakerd_ipcs, qb_ipcs_destroy); diff --git a/include/crm/common/ipc_internal.h b/include/crm/common/ipc_internal.h index b48a702993a..0b49ab6d517 100644 --- a/include/crm/common/ipc_internal.h +++ b/include/crm/common/ipc_internal.h @@ -250,10 +250,8 @@ void pcmk__serve_pacemakerd_ipc(qb_ipcs_service_t **ipcs, void pcmk__serve_schedulerd_ipc(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb); -void pcmk__serve_based_ipc(qb_ipcs_service_t **ipcs_ro, - qb_ipcs_service_t **ipcs_rw, - struct qb_ipcs_service_handlers *ro_cb, - struct qb_ipcs_service_handlers *rw_cb); +void pcmk__serve_based_ipc(qb_ipcs_service_t **ipcs, + struct qb_ipcs_service_handlers *cb); static inline const char * pcmk__ipc_sys_name(const char *ipc_name, const char *fallback) diff --git a/lib/common/ipc_server.c b/lib/common/ipc_server.c index ec92392918f..ba566d11157 100644 --- a/lib/common/ipc_server.c +++ b/lib/common/ipc_server.c @@ -1061,28 +1061,21 @@ pcmk__ipc_send_ack_as(const char *function, int line, pcmk__client_t *c, * \internal * \brief Add an IPC server to the main loop for the CIB manager API * - * \param[out] ipcs_ro New IPC server for read-only CIB manager API - * \param[out] ipcs_rw New IPC server for read/write CIB manager API - * \param[in] ro_cb IPC callbacks for read-only API - * \param[in] rw_cb IPC callbacks for read/write and shared-memory APIs + * \param[out] ipcs Where to store newly created IPC server + * \param[in] cb IPC callbacks * * \note This function exits fatally on error. */ void -pcmk__serve_based_ipc(qb_ipcs_service_t **ipcs_ro, qb_ipcs_service_t **ipcs_rw, - struct qb_ipcs_service_handlers *ro_cb, - struct qb_ipcs_service_handlers *rw_cb) +pcmk__serve_based_ipc(qb_ipcs_service_t **ipcs, + struct qb_ipcs_service_handlers *cb) { - pcmk__assert((ipcs_ro != NULL) && (*ipcs_ro == NULL) && (ro_cb != NULL) - && (ipcs_rw != NULL) && (*ipcs_rw == NULL) && (rw_cb != NULL)); - - *ipcs_ro = mainloop_add_ipc_server(PCMK__SERVER_BASED_RO, QB_IPC_SHM, - ro_cb); + pcmk__assert((ipcs != NULL) && (*ipcs == NULL) && (cb != NULL)); - *ipcs_rw = mainloop_add_ipc_server(PCMK__SERVER_BASED_RW, QB_IPC_SHM, - rw_cb); + *ipcs = mainloop_add_ipc_server(pcmk__server_ipc_name(pcmk_ipc_based), + QB_IPC_SHM, cb); - if ((*ipcs_ro == NULL) || (*ipcs_rw == NULL)) { + if (*ipcs == NULL) { pcmk__crit("Failed to create %s IPC server; shutting down", pcmk__server_log_name(pcmk_ipc_based)); pcmk__crit("Verify pacemaker and pacemaker_remote are not both " diff --git a/lib/common/servers.c b/lib/common/servers.c index 6a4fdc7405b..e5a6715db2f 100644 --- a/lib/common/servers.c +++ b/lib/common/servers.c @@ -29,66 +29,72 @@ * members, and libqb IPC server endpoints for both the old and new names, and * could drop the old names only after we no longer supported connections with * older nodes. + * + * @TODO It would be easy to use system_names[0] as a server's IPC name. + * Everything would automatically use the new names except for proxied + * connections from *older* Pacemaker Remote nodes. We would just have to map + * the old names to the new names in remote_proxy_new(), the same as we're + * currently mapping PCMK__SERVER_BASED_RO to PCMK__SERVER_BASED_RW there. */ static struct { const char *log_name; // Readable server name for use in logs const char *system_names[2]; // crm_system_name values (subdaemon names) - const char *ipc_names[2]; // libqb IPC names used to contact server + const char *ipc_name; // libqb IPC name used to contact server const char *message_types[3]; // IPC/cluster message types sent to server } server_info[] = { [pcmk_ipc_unknown] = { NULL, { NULL, NULL, }, - { NULL, NULL, }, + NULL, { NULL, NULL, NULL, }, }, [pcmk_ipc_attrd] = { "attribute manager", { PCMK__SERVER_ATTRD, NULL, }, - { PCMK__VALUE_ATTRD, NULL, }, + PCMK__VALUE_ATTRD, { PCMK__VALUE_ATTRD, NULL, NULL, }, }, [pcmk_ipc_based] = { "CIB manager", { PCMK__SERVER_BASED, NULL, }, - { PCMK__SERVER_BASED_RW, PCMK__SERVER_BASED_RO, }, + PCMK__SERVER_BASED_RW, { CRM_SYSTEM_CIB, NULL, NULL, }, }, [pcmk_ipc_controld] = { "controller", { PCMK__SERVER_CONTROLD, NULL, }, - { PCMK__VALUE_CRMD, NULL, }, + PCMK__VALUE_CRMD, { PCMK__VALUE_CRMD, CRM_SYSTEM_DC, CRM_SYSTEM_TENGINE, }, }, [pcmk_ipc_execd] = { "executor", { PCMK__SERVER_EXECD, PCMK__SERVER_REMOTED, }, - { PCMK__VALUE_LRMD, NULL, }, + PCMK__VALUE_LRMD, { PCMK__VALUE_LRMD, NULL, NULL, }, }, [pcmk_ipc_fenced] = { "fencer", { PCMK__SERVER_FENCED, NULL, }, - { PCMK__VALUE_STONITH_NG, NULL, }, + PCMK__VALUE_STONITH_NG, { PCMK__VALUE_STONITH_NG, NULL, NULL, }, }, [pcmk_ipc_pacemakerd] = { "launcher", { PCMK__SERVER_PACEMAKERD, NULL, }, - { CRM_SYSTEM_MCP, NULL, }, + CRM_SYSTEM_MCP, { CRM_SYSTEM_MCP, NULL, NULL, }, }, [pcmk_ipc_schedulerd] = { "scheduler", { PCMK__SERVER_SCHEDULERD, NULL, }, - { CRM_SYSTEM_PENGINE, NULL, }, + CRM_SYSTEM_PENGINE, { CRM_SYSTEM_PENGINE, NULL, NULL, }, }, }; @@ -131,7 +137,7 @@ pcmk__server_log_name(enum pcmk_ipc_server server) /*! * \internal - * \brief Return the (primary) IPC endpoint name for a server + * \brief Return the IPC endpoint name for a server * * \param[in] server Server to get IPC endpoint for * @@ -144,7 +150,7 @@ pcmk__server_ipc_name(enum pcmk_ipc_server server) { CRM_CHECK((server > 0) && (server < PCMK__NELEM(server_info)), return NULL); - return server_info[server].ipc_names[0]; + return server_info[server].ipc_name; } /*! @@ -191,13 +197,11 @@ pcmk__parse_server(const char *text) return server; } } - for (name = 0; - (name < 2) && (server_info[server].ipc_names[name] != NULL); - ++name) { - if (strcmp(text, server_info[server].ipc_names[name]) == 0) { - return server; - } + + if (pcmk__str_eq(text, server_info[server].ipc_name, pcmk__str_none)) { + return server; } + for (name = 0; (name < 3) && (server_info[server].message_types[name] != NULL); ++name) { From 635374ef81cd5529fedaaa7cfb3ef5ecf4524b9d Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 11 Jan 2026 17:49:04 -0800 Subject: [PATCH 20/37] Refactor: based: Standardize based_cpg_dispatch() Make it look like fenced_cpg_dispatch() and attrd_cpg_dispatch(), and have it call a based_peer_message() (structured similarly to fenced_peer_message() and attrd_peer_message()). Not everything is in accordance with my preferences here, but the goal is to make it look as similar as possible to the other daemons. Signed-off-by: Reid Wahl --- daemons/based/based_corosync.c | 87 ++++++++++++++++++++++++++-------- 1 file changed, 66 insertions(+), 21 deletions(-) diff --git a/daemons/based/based_corosync.c b/daemons/based/based_corosync.c index 2efb71c5706..2a7bcbe0071 100644 --- a/daemons/based/based_corosync.c +++ b/daemons/based/based_corosync.c @@ -26,42 +26,87 @@ static pcmk_cluster_t *cluster = NULL; -#if SUPPORT_COROSYNC static void -based_cpg_dispatch(cpg_handle_t handle, const struct cpg_name *group_name, - uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len) +based_peer_message(pcmk__node_status_t *peer, xmlNode *xml) { - char *data = NULL; - const char *from = NULL; - xmlNode *xml = NULL; + int rc = pcmk_rc_ok; if (based_shutting_down()) { - pcmk__info("Ignoring CPG message from node %" PRIu32 " during shutdown", - nodeid); + pcmk__info("Ignoring CPG message from %s[%" PRIu32 "] during shutdown", + peer->name, peer->cluster_layer_id); return; + + } else { + pcmk__request_t request = { + .ipc_client = NULL, + .ipc_id = 0, + .ipc_flags = 0, + .peer = peer->name, + .xml = xml, + .call_options = cib_none, + .result = PCMK__UNKNOWN_RESULT, + }; + + rc = pcmk__xe_get_flags(xml, PCMK__XA_CIB_CALLOPT, + (uint32_t *) &request.call_options, cib_none); + if (rc != pcmk_rc_ok) { + pcmk__warn("Couldn't parse options from request: %s", + pcmk_rc_str(rc)); + } + + request.op = pcmk__xe_get_copy(request.xml, PCMK__XA_CIB_OP); + CRM_CHECK(request.op != NULL, return); + + if (pcmk__is_set(request.call_options, cib_sync_call)) { + pcmk__set_request_flags(&request, pcmk__request_sync); + } + + if (pcmk__xe_get(request.xml, PCMK__XA_CIB_CLIENTNAME) == NULL) { + pcmk__xe_set(request.xml, PCMK__XA_CIB_CLIENTNAME, + pcmk__xe_get(request.xml, PCMK__XA_SRC)); + } + + based_process_request(request.xml, request.ipc_client); + pcmk__reset_request(&request); } +} + +#if SUPPORT_COROSYNC +/*! + * \internal + * \brief Callback for when a peer message is received + * + * \param[in] handle Cluster connection + * \param[in] group_name Group that \p nodeid is a member of + * \param[in] nodeid Peer node that sent \p msg + * \param[in] pid Process that sent \p msg + * \param[in,out] msg Received message + * \param[in] msg_len Length of \p msg + */ +static void +based_cpg_dispatch(cpg_handle_t handle, const struct cpg_name *group_name, + uint32_t nodeid, uint32_t pid, void *msg, size_t msg_len) +{ + xmlNode *xml = NULL; + const char *from = NULL; + char *data = pcmk__cpg_message_data(handle, nodeid, pid, msg, &from); - data = pcmk__cpg_message_data(handle, nodeid, pid, msg, &from); if (data == NULL) { return; } xml = pcmk__xml_parse(data); if (xml == NULL) { - pcmk__err("Invalid XML: '%.120s'", data); - free(data); - return; - } - - pcmk__xe_set(xml, PCMK__XA_SRC, from); - - if (pcmk__xe_get(xml, PCMK__XA_CIB_CLIENTNAME) == NULL) { - pcmk__xe_set(xml, PCMK__XA_CIB_CLIENTNAME, - pcmk__xe_get(xml, PCMK__XA_SRC)); + pcmk__err("Bad message received from %s[%" PRIu32 "]: '%.120s'", from, + nodeid, data); + + } else { + pcmk__xe_set(xml, PCMK__XA_SRC, from); + based_peer_message(pcmk__get_node(nodeid, from, NULL, + pcmk__node_search_cluster_member), + xml); } - based_process_request(xml, NULL); - pcmk__xml_free(xml); free(data); } From 2652d38176a6ef000c3f53eefa6b247a864c71d4 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 23 Jul 2026 15:08:13 -0700 Subject: [PATCH 21/37] Refactor: libcib: Drop unnecessary rc check in cib_native_signon() It's initialized to pcmk_ok, and nothing can change it before we reach this point. (That was not the case when this line was added.) Signed-off-by: Reid Wahl --- lib/cib/cib_native.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cib/cib_native.c b/lib/cib/cib_native.c index 1944f046bd5..d25af9e722d 100644 --- a/lib/cib/cib_native.c +++ b/lib/cib/cib_native.c @@ -288,7 +288,7 @@ cib_native_signon(cib_t *cib, const char *name, enum cib_conn_type type) struct ipc_client_callbacks cib_callbacks = { .dispatch = cib_native_dispatch_internal, - .destroy = cib_native_destroy + .destroy = cib_native_destroy, }; if (name == NULL) { @@ -318,7 +318,7 @@ cib_native_signon(cib_t *cib, const char *name, enum cib_conn_type type) &cib_callbacks); native->ipc = mainloop_get_ipc_client(native->source); - if (rc != pcmk_ok || native->ipc == NULL || !crm_ipc_connected(native->ipc)) { + if ((native->ipc == NULL) || !crm_ipc_connected(native->ipc)) { pcmk__info("Could not connect to CIB manager for %s", name); rc = -ENOTCONN; } From 95611f763d39d8adb2710821bd516f4a91231ce6 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 23 Jul 2026 15:09:22 -0700 Subject: [PATCH 22/37] Refactor: libcib: Unindent some of cib_native_signon() Signed-off-by: Reid Wahl --- lib/cib/cib_native.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/cib/cib_native.c b/lib/cib/cib_native.c index d25af9e722d..3850f008509 100644 --- a/lib/cib/cib_native.c +++ b/lib/cib/cib_native.c @@ -321,13 +321,12 @@ cib_native_signon(cib_t *cib, const char *name, enum cib_conn_type type) if ((native->ipc == NULL) || !crm_ipc_connected(native->ipc)) { pcmk__info("Could not connect to CIB manager for %s", name); rc = -ENOTCONN; + goto done; } - if (rc == pcmk_ok) { - rc = cib__create_op(cib, CRM_OP_REGISTER, NULL, NULL, NULL, - cib_sync_call, NULL, name, &hello); - rc = pcmk_rc2legacy(rc); - } + rc = cib__create_op(cib, CRM_OP_REGISTER, NULL, NULL, NULL, cib_sync_call, + NULL, name, &hello); + rc = pcmk_rc2legacy(rc); if (rc == pcmk_ok) { xmlNode *reply = NULL; From 6279154703a36d23b97eb27ab1066dd6e9878e2a Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 23 Jul 2026 15:12:51 -0700 Subject: [PATCH 23/37] Refactor: libcib: Unindent more of cib_native_signon() Signed-off-by: Reid Wahl --- lib/cib/cib_native.c | 60 +++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/lib/cib/cib_native.c b/lib/cib/cib_native.c index 3850f008509..03685bf7bd3 100644 --- a/lib/cib/cib_native.c +++ b/lib/cib/cib_native.c @@ -285,6 +285,8 @@ cib_native_signon(cib_t *cib, const char *name, enum cib_conn_type type) const char *channel = NULL; cib_native_opaque_t *native = cib->variant_opaque; xmlNode *hello = NULL; + xmlNode *reply = NULL; + const char *msg_type = NULL; struct ipc_client_callbacks cib_callbacks = { .dispatch = cib_native_dispatch_internal, @@ -327,50 +329,44 @@ cib_native_signon(cib_t *cib, const char *name, enum cib_conn_type type) rc = cib__create_op(cib, CRM_OP_REGISTER, NULL, NULL, NULL, cib_sync_call, NULL, name, &hello); rc = pcmk_rc2legacy(rc); + if (rc != pcmk_ok) { + goto done; + } - if (rc == pcmk_ok) { - xmlNode *reply = NULL; - const char *msg_type = NULL; + if (crm_ipc_send(native->ipc, hello, crm_ipc_client_response, -1, + &reply) <= 0) { + rc = -ECOMM; + goto done; + } - if (crm_ipc_send(native->ipc, hello, crm_ipc_client_response, -1, - &reply) <= 0) { - rc = -ECOMM; - goto done; - } + /* The only reason we can receive an ACK here is if based_ipc_dispatch -> + * pcmk__client_data2xml processed something that's not valid XML. + * based_ipc_dispatch does not return ACK, unlike other daemons. + */ + if (pcmk__xe_is(reply, PCMK__XE_ACK) && ack_is_failure(reply)) { + rc = -EPROTO; + goto done; + } - /* The only reason we can receive an ACK here is if - * based_ipc_dispatch -> pcmk__client_data2xml processed something - * that's not valid XML. based_ipc_dispatch does not return ACK, unlike - * other daemons. - */ - if (pcmk__xe_is(reply, PCMK__XE_ACK) && ack_is_failure(reply)) { - rc = -EPROTO; - pcmk__xml_free(reply); - goto done; - } + msg_type = pcmk__xe_get(reply, PCMK__XA_CIB_OP); - msg_type = pcmk__xe_get(reply, PCMK__XA_CIB_OP); + pcmk__log_xml_trace(reply, "reg-reply"); - pcmk__log_xml_trace(reply, "reg-reply"); + if (!pcmk__str_eq(msg_type, CRM_OP_REGISTER, pcmk__str_casei)) { + pcmk__info("Reply to CIB registration message has unknown type '%s'", + msg_type); + rc = -EPROTO; - if (!pcmk__str_eq(msg_type, CRM_OP_REGISTER, pcmk__str_casei)) { - pcmk__info("Reply to CIB registration message has unknown type " - "'%s'", - msg_type); + } else { + native->token = pcmk__xe_get_copy(reply, PCMK__XA_CIB_CLIENTID); + if (native->token == NULL) { rc = -EPROTO; - - } else { - native->token = pcmk__xe_get_copy(reply, PCMK__XA_CIB_CLIENTID); - if (native->token == NULL) { - rc = -EPROTO; - } } - - pcmk__xml_free(reply); } done: pcmk__xml_free(hello); + pcmk__xml_free(reply); if (rc == pcmk_ok) { pcmk__info("Successfully connected to CIB manager for %s", name); From 1b431b7e8d627407bc94b7fe2ad2dc08fd1f68af Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 23 Jul 2026 15:13:54 -0700 Subject: [PATCH 24/37] Refactor: libcib: Unindent one more block of cib_native_signon() Signed-off-by: Reid Wahl --- lib/cib/cib_native.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/cib/cib_native.c b/lib/cib/cib_native.c index 03685bf7bd3..73a34971a78 100644 --- a/lib/cib/cib_native.c +++ b/lib/cib/cib_native.c @@ -348,20 +348,19 @@ cib_native_signon(cib_t *cib, const char *name, enum cib_conn_type type) goto done; } - msg_type = pcmk__xe_get(reply, PCMK__XA_CIB_OP); - pcmk__log_xml_trace(reply, "reg-reply"); + msg_type = pcmk__xe_get(reply, PCMK__XA_CIB_OP); if (!pcmk__str_eq(msg_type, CRM_OP_REGISTER, pcmk__str_casei)) { pcmk__info("Reply to CIB registration message has unknown type '%s'", msg_type); rc = -EPROTO; + goto done; + } - } else { - native->token = pcmk__xe_get_copy(reply, PCMK__XA_CIB_CLIENTID); - if (native->token == NULL) { - rc = -EPROTO; - } + native->token = pcmk__xe_get_copy(reply, PCMK__XA_CIB_CLIENTID); + if (native->token == NULL) { + rc = -EPROTO; } done: From 88c713b0851327cf0e3f15cb0cedca782db61dae Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 23 Jul 2026 15:16:16 -0700 Subject: [PATCH 25/37] Refactor: libcib: Compare CRM_OP_REGISTER case-sensitively Signed-off-by: Reid Wahl --- lib/cib/cib_native.c | 2 +- lib/cib/cib_remote.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cib/cib_native.c b/lib/cib/cib_native.c index 73a34971a78..1355976f6a7 100644 --- a/lib/cib/cib_native.c +++ b/lib/cib/cib_native.c @@ -351,7 +351,7 @@ cib_native_signon(cib_t *cib, const char *name, enum cib_conn_type type) pcmk__log_xml_trace(reply, "reg-reply"); msg_type = pcmk__xe_get(reply, PCMK__XA_CIB_OP); - if (!pcmk__str_eq(msg_type, CRM_OP_REGISTER, pcmk__str_casei)) { + if (!pcmk__str_eq(msg_type, CRM_OP_REGISTER, pcmk__str_none)) { pcmk__info("Reply to CIB registration message has unknown type '%s'", msg_type); rc = -EPROTO; diff --git a/lib/cib/cib_remote.c b/lib/cib/cib_remote.c index 9a4a8605e29..9750e8b69d1 100644 --- a/lib/cib/cib_remote.c +++ b/lib/cib/cib_remote.c @@ -541,7 +541,7 @@ cib_tls_signon(cib_t *cib, pcmk__remote_t *connection, gboolean event_channel) msg_type = pcmk__xe_get(answer, PCMK__XA_CIB_OP); tmp_ticket = pcmk__xe_get(answer, PCMK__XA_CIB_CLIENTID); - if (!pcmk__str_eq(msg_type, CRM_OP_REGISTER, pcmk__str_casei)) { + if (!pcmk__str_eq(msg_type, CRM_OP_REGISTER, pcmk__str_none)) { pcmk__err("Invalid registration message: %s", msg_type); rc = -EPROTO; From e8ceff8807ec9b69d5c0ff0b39810adf12e36eb1 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 23 Jul 2026 15:45:07 -0700 Subject: [PATCH 26/37] Feature: libcib: Ignore name argument of cib_api_operations_t:signon() Instead, always use crm_system_name if set, or fall back to "client" otherwise. All internal callers pass crm_system_name. Further, crm_system_name should always be non-NULL if crm_log_preinit() has been called -- which is always true for internal callers. Up to now, callers have been allowed to pass an arbitrary client name. However, this does not seem to be useful for anything except logging, and certain names may cause Pacemaker daemons to treat requests from the client specially. It seems safer to use crm_system_name unconditionally (falling back to "client" if NULL). Signed-off-by: Reid Wahl --- include/crm/cib/cib_types.h | 7 +++++++ lib/cib/cib_file.c | 15 ++++++++++++--- lib/cib/cib_native.c | 12 +++++++++--- lib/cib/cib_remote.c | 12 +++++++++--- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/include/crm/cib/cib_types.h b/include/crm/cib/cib_types.h index 93ece539aa5..deb9523abe6 100644 --- a/include/crm/cib/cib_types.h +++ b/include/crm/cib/cib_types.h @@ -144,6 +144,13 @@ typedef struct cib_api_operations_s { * and type (always use cib_command -- cib_file and cib_remote already do * this). */ + /*! + * \brief Sign on a client to the CIB API + * + * \param[in,out] cib CIB connection (client) + * \param[in] name Ignored + * \param[in] type Type of CIB connection + */ int (*signon) (cib_t *cib, const char *name, enum cib_conn_type type); // NOTE: sbd (as of at least 1.5.2) uses this diff --git a/lib/cib/cib_file.c b/lib/cib/cib_file.c index da7e6c1b1b8..94a509bd6f8 100644 --- a/lib/cib/cib_file.c +++ b/lib/cib/cib_file.c @@ -521,12 +521,22 @@ load_file_cib(const char *filename, xmlNode **output) return pcmk_ok; } +/*! + * \internal + * \brief Sign on a native client to the CIB API + * + * \param[in,out] cib CIB connection (client) + * \param[in] name Ignored + * \param[in] type Ignored + */ static int file_signon(cib_t *cib, const char *name, enum cib_conn_type type) { int rc = pcmk_ok; file_opaque_t *private = cib->variant_opaque; + name = pcmk__s(crm_system_name, "client"); + if (private->filename == NULL) { rc = -EINVAL; } else { @@ -535,15 +545,14 @@ file_signon(cib_t *cib, const char *name, enum cib_conn_type type) if (rc == pcmk_ok) { pcmk__debug("Opened connection to local file '%s' for %s", - private->filename, pcmk__s(name, "client")); + private->filename, name); cib->state = cib_connected_command; cib->type = cib_command; register_client(cib); } else { pcmk__info("Connection to local file '%s' for %s (client %s) failed: " - "%s", - private->filename, pcmk__s(name, "client"), private->id, + "%s", private->filename, name, private->id, pcmk_strerror(rc)); } return rc; diff --git a/lib/cib/cib_native.c b/lib/cib/cib_native.c index 1355976f6a7..85c2d290229 100644 --- a/lib/cib/cib_native.c +++ b/lib/cib/cib_native.c @@ -278,6 +278,14 @@ cib_native_signoff(cib_t *cib) return pcmk_ok; } +/*! + * \internal + * \brief Sign on a native client to the CIB API + * + * \param[in,out] cib CIB connection (client) + * \param[in] name Ignored + * \param[in] type Type of CIB connection + */ static int cib_native_signon(cib_t *cib, const char *name, enum cib_conn_type type) { @@ -293,9 +301,7 @@ cib_native_signon(cib_t *cib, const char *name, enum cib_conn_type type) .destroy = cib_native_destroy, }; - if (name == NULL) { - name = pcmk__s(crm_system_name, "client"); - } + name = pcmk__s(crm_system_name, "client"); cib->call_timeout = PCMK__IPC_TIMEOUT; diff --git a/lib/cib/cib_remote.c b/lib/cib/cib_remote.c index 9750e8b69d1..039f98872b1 100644 --- a/lib/cib/cib_remote.c +++ b/lib/cib/cib_remote.c @@ -568,15 +568,21 @@ cib_tls_signon(cib_t *cib, pcmk__remote_t *connection, gboolean event_channel) return rc; } +/*! + * \internal + * \brief Sign on a native client to the CIB API + * + * \param[in,out] cib CIB connection (client) + * \param[in] name Ignored + * \param[in] type Ignored + */ static int cib_remote_signon(cib_t *cib, const char *name, enum cib_conn_type type) { int rc = pcmk_ok; cib_remote_opaque_t *private = cib->variant_opaque; - if (name == NULL) { - name = pcmk__s(crm_system_name, "client"); - } + name = pcmk__s(crm_system_name, "client"); if (private->passwd == NULL) { if (private->out == NULL) { From b63210d13ea2ab56779b77ec50b2cb0e063b0377 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 23 Jul 2026 15:57:53 -0700 Subject: [PATCH 27/37] Feature: libcib: Don't set cib_t:type Nothing checks it internally, and there's no apparent use case for anything external to check it. Further, cib_native clients already don't set it at all during signon. cib_file and cib_remote clients set it during signon; all clients set it back to cib_no_connection at signoff. Signed-off-by: Reid Wahl --- lib/cib/cib_client.c | 1 - lib/cib/cib_file.c | 2 -- lib/cib/cib_native.c | 1 - lib/cib/cib_remote.c | 2 -- 4 files changed, 6 deletions(-) diff --git a/lib/cib/cib_client.c b/lib/cib/cib_client.c index 81658f69b6f..9d992975ef2 100644 --- a/lib/cib/cib_client.c +++ b/lib/cib/cib_client.c @@ -618,7 +618,6 @@ cib_new_variant(void) new_cib->call_id = 1; new_cib->variant = cib_undefined; - new_cib->type = cib_no_connection; new_cib->state = cib_disconnected; new_cib->variant_opaque = NULL; new_cib->notify_list = NULL; diff --git a/lib/cib/cib_file.c b/lib/cib/cib_file.c index 94a509bd6f8..182d7a6e1d4 100644 --- a/lib/cib/cib_file.c +++ b/lib/cib/cib_file.c @@ -547,7 +547,6 @@ file_signon(cib_t *cib, const char *name, enum cib_conn_type type) pcmk__debug("Opened connection to local file '%s' for %s", private->filename, name); cib->state = cib_connected_command; - cib->type = cib_command; register_client(cib); } else { @@ -657,7 +656,6 @@ file_signoff(cib_t *cib) pcmk__debug("Disconnecting from the CIB manager"); cib->state = cib_disconnected; - cib->type = cib_no_connection; unregister_client(cib); cib->cmds->end_transaction(cib, false, cib_none); diff --git a/lib/cib/cib_native.c b/lib/cib/cib_native.c index 85c2d290229..e3c139c23da 100644 --- a/lib/cib/cib_native.c +++ b/lib/cib/cib_native.c @@ -273,7 +273,6 @@ cib_native_signoff(cib_t *cib) cib->cmds->end_transaction(cib, false, cib_none); cib->state = cib_disconnected; - cib->type = cib_no_connection; return pcmk_ok; } diff --git a/lib/cib/cib_remote.c b/lib/cib/cib_remote.c index 039f98872b1..3813767e918 100644 --- a/lib/cib/cib_remote.c +++ b/lib/cib/cib_remote.c @@ -612,7 +612,6 @@ cib_remote_signon(cib_t *cib, const char *name, enum cib_conn_type type) pcmk__info("Opened connection to %s:%d for %s", private->server, private->port, name); cib->state = cib_connected_command; - cib->type = cib_command; } else { pcmk__info("Connection to %s:%d for %s failed: %s\n", private->server, @@ -632,7 +631,6 @@ cib_remote_signoff(cib_t *cib) cib->cmds->end_transaction(cib, false, cib_none); cib->state = cib_disconnected; - cib->type = cib_no_connection; return rc; } From cd3ed6eb360cb1bb7a3394b4dc72c385f796c267 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 23 Jul 2026 16:00:56 -0700 Subject: [PATCH 28/37] API: libcib: Deprecate cib_no_connection Signed-off-by: Reid Wahl --- include/crm/cib/cib_types.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/crm/cib/cib_types.h b/include/crm/cib/cib_types.h index deb9523abe6..c239fae878b 100644 --- a/include/crm/cib/cib_types.h +++ b/include/crm/cib/cib_types.h @@ -54,6 +54,7 @@ enum cib_conn_type { //! \deprecated Use \c cib_command instead cib_query, + //! \deprecated Do not use cib_no_connection, //! \deprecated Use \c cib_command instead From f4c78cc80c665274f54f44debeac58b28aaa4793 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 23 Jul 2026 16:05:58 -0700 Subject: [PATCH 29/37] Feature: libcib: Ignore type argument of signon method for native client cib_file and cib_remote clients already ignored the type argument. cib_native clients simply returned an ENOTCONN error if the type was invalid; otherwise, they ignored it. Signed-off-by: Reid Wahl --- include/crm/cib/cib_types.h | 2 +- lib/cib/cib_native.c | 24 ++++-------------------- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/include/crm/cib/cib_types.h b/include/crm/cib/cib_types.h index c239fae878b..85f788c8596 100644 --- a/include/crm/cib/cib_types.h +++ b/include/crm/cib/cib_types.h @@ -150,7 +150,7 @@ typedef struct cib_api_operations_s { * * \param[in,out] cib CIB connection (client) * \param[in] name Ignored - * \param[in] type Type of CIB connection + * \param[in] type Ignored */ int (*signon) (cib_t *cib, const char *name, enum cib_conn_type type); diff --git a/lib/cib/cib_native.c b/lib/cib/cib_native.c index e3c139c23da..aad64ec31f5 100644 --- a/lib/cib/cib_native.c +++ b/lib/cib/cib_native.c @@ -283,13 +283,12 @@ cib_native_signoff(cib_t *cib) * * \param[in,out] cib CIB connection (client) * \param[in] name Ignored - * \param[in] type Type of CIB connection + * \param[in] type Ignored */ static int cib_native_signon(cib_t *cib, const char *name, enum cib_conn_type type) { int rc = pcmk_ok; - const char *channel = NULL; cib_native_opaque_t *native = cib->variant_opaque; xmlNode *hello = NULL; xmlNode *reply = NULL; @@ -303,25 +302,10 @@ cib_native_signon(cib_t *cib, const char *name, enum cib_conn_type type) name = pcmk__s(crm_system_name, "client"); cib->call_timeout = PCMK__IPC_TIMEOUT; + cib->state = cib_connected_command; - switch (type) { - case cib_command: - case cib_command_nonblocking: - case cib_query: - /* @COMPAT cib_command_nonblocking and cib_query are deprecated - * since 3.0.2 - */ - cib->state = cib_connected_command; - channel = PCMK__SERVER_BASED_RW; - break; - - default: - return -ENOTCONN; - } - - pcmk__trace("Connecting %s channel", channel); - - native->source = mainloop_add_ipc_client(channel, G_PRIORITY_HIGH, 0, cib, + native->source = mainloop_add_ipc_client(PCMK__SERVER_BASED_RW, + G_PRIORITY_HIGH, 0, cib, &cib_callbacks); native->ipc = mainloop_get_ipc_client(native->source); From b39196718a57b56e2090f0140fa53bf17c5626d9 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 23 Jul 2026 16:03:11 -0700 Subject: [PATCH 30/37] API: libcib: Deprecate enum cib_conn_type cib_command is the only type we ever use, so this enum is now meaningless. Signed-off-by: Reid Wahl --- include/crm/cib/cib_types.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/crm/cib/cib_types.h b/include/crm/cib/cib_types.h index 85f788c8596..86112f1c7e4 100644 --- a/include/crm/cib/cib_types.h +++ b/include/crm/cib/cib_types.h @@ -47,17 +47,19 @@ enum cib_state { cib_disconnected }; +/*! + * \deprecated Do not use + * + * \note Pass \c cib_command to cib_api_operations_t:signon as long as + * that function and argument exist. + */ enum cib_conn_type { cib_command, // NOTE: sbd (as of at least 1.5.2) uses this value - //! \deprecated Use \c cib_command instead cib_query, - //! \deprecated Do not use cib_no_connection, - - //! \deprecated Use \c cib_command instead cib_command_nonblocking, }; From 97fb8b34fbf2e58a4f9657258b91178ba5f607d5 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 23 Jul 2026 16:10:27 -0700 Subject: [PATCH 31/37] Refactor: libcib: Clean up the end of cib_native_signon() Signed-off-by: Reid Wahl --- lib/cib/cib_native.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/cib/cib_native.c b/lib/cib/cib_native.c index aad64ec31f5..5d15893ed52 100644 --- a/lib/cib/cib_native.c +++ b/lib/cib/cib_native.c @@ -302,7 +302,6 @@ cib_native_signon(cib_t *cib, const char *name, enum cib_conn_type type) name = pcmk__s(crm_system_name, "client"); cib->call_timeout = PCMK__IPC_TIMEOUT; - cib->state = cib_connected_command; native->source = mainloop_add_ipc_client(PCMK__SERVER_BASED_RW, G_PRIORITY_HIGH, 0, cib, @@ -350,20 +349,22 @@ cib_native_signon(cib_t *cib, const char *name, enum cib_conn_type type) native->token = pcmk__xe_get_copy(reply, PCMK__XA_CIB_CLIENTID); if (native->token == NULL) { rc = -EPROTO; + goto done; } + pcmk__info("Successfully connected to CIB manager for %s", name); + cib->state = cib_connected_command; + done: pcmk__xml_free(hello); pcmk__xml_free(reply); - if (rc == pcmk_ok) { - pcmk__info("Successfully connected to CIB manager for %s", name); - return pcmk_ok; + if (rc != pcmk_ok) { + pcmk__info("Connection to CIB manager for %s failed: %s", name, + pcmk_strerror(rc)); + cib_native_signoff(cib); } - pcmk__info("Connection to CIB manager for %s failed: %s", name, - pcmk_strerror(rc)); - cib_native_signoff(cib); return rc; } From adbf9fdc8968ea7ec634b89c994e087d6a729628 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 23 Jul 2026 22:10:05 -0700 Subject: [PATCH 32/37] Refactor: based: goto cleanup consistently in based_ipc_dispatch() Just for future-proofing and consistency. This doesn't fix a bug. Signed-off-by: Reid Wahl --- daemons/based/based_ipc.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/daemons/based/based_ipc.c b/daemons/based/based_ipc.c index 850a638c525..6aad0f64083 100644 --- a/daemons/based/based_ipc.c +++ b/daemons/based/based_ipc.c @@ -78,17 +78,18 @@ based_ipc_dispatch(qb_ipcs_connection_t *c, void *data, size_t size) const char *op = NULL; // Sanity-check, and parse XML from IPC data - CRM_CHECK(client != NULL, return 0); + CRM_CHECK(client != NULL, goto cleanup); + if (data == NULL) { pcmk__debug("No IPC data from PID %d", pcmk__client_pid(c)); - return 0; + goto cleanup; } rc = pcmk__ipc_msg_append(&client->buffer, data); if (rc == pcmk_rc_ipc_more) { /* We haven't read the complete message yet, so just return. */ - return 0; + goto cleanup; } else if (rc == pcmk_rc_ok) { /* We've read the complete message and there's already a header on @@ -109,13 +110,13 @@ based_ipc_dispatch(qb_ipcs_connection_t *c, void *data, size_t size) client->buffer = NULL; } - return 0; + goto cleanup; } if (msg == NULL) { pcmk__debug("Unrecognizable IPC data from PID %d", pcmk__client_pid(c)); pcmk__ipc_send_ack(client, id, flags, NULL, CRM_EX_PROTOCOL); - return 0; + goto cleanup; } if (client->name == NULL) { From 2147d3f8db62158752828beef463ba0d539fe595 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Thu, 23 Jul 2026 22:30:06 -0700 Subject: [PATCH 33/37] Refactor: various: Use pcmk__is_set() and friends in more places Signed-off-by: Reid Wahl --- daemons/based/based_ipc.c | 2 +- daemons/controld/controld_remote_proxy.c | 2 +- daemons/fenced/fenced_history.c | 7 +++--- daemons/fenced/fenced_remote.c | 20 ++++++++++++----- lib/cib/cib_native.c | 9 +++++--- lib/cib/cib_remote.c | 9 ++++---- lib/cluster/membership.c | 2 +- lib/common/io.c | 8 +++++-- lib/common/mainloop.c | 8 ++++--- lib/common/tls.c | 2 +- lib/fencing/st_client.c | 14 +++++++----- lib/services/dbus.c | 28 ++++++++++++++---------- lib/services/services_linux.c | 7 +++--- tools/crm_mon.c | 6 ++--- 14 files changed, 75 insertions(+), 49 deletions(-) diff --git a/daemons/based/based_ipc.c b/daemons/based/based_ipc.c index 6aad0f64083..3f9eaf9c0e2 100644 --- a/daemons/based/based_ipc.c +++ b/daemons/based/based_ipc.c @@ -148,7 +148,7 @@ based_ipc_dispatch(qb_ipcs_connection_t *c, void *data, size_t size) } if (pcmk__is_set(call_options, cib_sync_call)) { - CRM_LOG_ASSERT(flags & crm_ipc_client_response); + CRM_LOG_ASSERT(pcmk__is_set(flags, crm_ipc_client_response)); // If false, the client has two synchronous events in flight CRM_LOG_ASSERT(client->request_id == 0); diff --git a/daemons/controld/controld_remote_proxy.c b/daemons/controld/controld_remote_proxy.c index 16ae3db4f53..5f6cf009a6b 100644 --- a/daemons/controld/controld_remote_proxy.c +++ b/daemons/controld/controld_remote_proxy.c @@ -128,7 +128,7 @@ remote_proxy_dispatch(const char *buffer, ssize_t length, void *userdata) } flags = crm_ipc_buffer_flags(proxy->ipc); - if (flags & crm_ipc_proxied_relay_response) { + if (pcmk__is_set(flags, crm_ipc_proxied_relay_response)) { pcmk__trace("Passing response back to %.8s on %s: %.200s - request id: " "%d", proxy->session_id, proxy->node_name, buffer, proxy->last_request_id); diff --git a/daemons/fenced/fenced_history.c b/daemons/fenced/fenced_history.c index 75bac9d36f4..968de2a5b21 100644 --- a/daemons/fenced/fenced_history.c +++ b/daemons/fenced/fenced_history.c @@ -482,7 +482,8 @@ stonith_fence_history(xmlNode *msg, xmlNode **output, if (dev) { target = pcmk__xe_get(dev, PCMK__XA_ST_TARGET); - if (target && (options & st_opt_cs_nodeid)) { + + if ((target != NULL) && pcmk__is_set(options, st_opt_cs_nodeid)) { int nodeid; pcmk__node_status_t *node = NULL; @@ -496,14 +497,14 @@ stonith_fence_history(xmlNode *msg, xmlNode **output, } } - if (options & st_opt_cleanup) { + if (pcmk__is_set(options, st_opt_cleanup)) { const char *call_id = pcmk__xe_get(msg, PCMK__XA_ST_CALLID); pcmk__trace("Cleaning up operations on %s in %p", target, stonith_remote_op_list); stonith_fence_history_cleanup(target, (call_id != NULL)); - } else if (options & st_opt_broadcast) { + } else if (pcmk__is_set(options, st_opt_broadcast)) { /* there is no clear sign atm for when a history sync is done so send a notification for anything that smells like history-sync diff --git a/daemons/fenced/fenced_remote.c b/daemons/fenced/fenced_remote.c index 394dd4859e3..496a8ede76a 100644 --- a/daemons/fenced/fenced_remote.c +++ b/daemons/fenced/fenced_remote.c @@ -1245,7 +1245,7 @@ create_remote_stonith_op(const char *client, xmlNode *request, gboolean peer) op->replies_expected, pcmk__plural_alt(op->replies_expected, "reply", "replies")); - if (op->call_options & st_opt_cs_nodeid) { + if (pcmk__is_set(op->call_options, st_opt_cs_nodeid)) { int nodeid; pcmk__node_status_t *node = NULL; @@ -1396,7 +1396,7 @@ static peer_device_info_t * find_best_peer(const char *device, remote_fencing_op_t * op, enum find_best_peer_options options) { GList *iter = NULL; - gboolean verified_devices_only = (options & FIND_PEER_VERIFIED_ONLY) ? TRUE : FALSE; + bool verified_devices_only = pcmk__is_set(options, FIND_PEER_VERIFIED_ONLY); if ((device == NULL) && pcmk__is_set(op->call_options, st_opt_topology)) { return NULL; @@ -1409,10 +1409,16 @@ find_best_peer(const char *device, remote_fencing_op_t * op, enum find_best_peer "%x", peer->host, op->target, peer->ndevices, pcmk__plural_s(peer->ndevices), peer->tried, options); - if ((options & FIND_PEER_SKIP_TARGET) && pcmk__str_eq(peer->host, op->target, pcmk__str_casei)) { + + if (pcmk__is_set(options, FIND_PEER_SKIP_TARGET) + && pcmk__str_eq(peer->host, op->target, pcmk__str_casei)) { + continue; } - if ((options & FIND_PEER_TARGET_ONLY) && !pcmk__str_eq(peer->host, op->target, pcmk__str_casei)) { + + if (pcmk__is_set(options, FIND_PEER_TARGET_ONLY) + && !pcmk__str_eq(peer->host, op->target, pcmk__str_casei)) { + continue; } @@ -1722,13 +1728,15 @@ report_timeout_period(remote_fencing_op_t * op, int op_timeout) const char *client_id = NULL; const char *call_id = NULL; - if (op->call_options & st_opt_sync_call) { + if (pcmk__is_set(op->call_options, st_opt_sync_call)) { /* There is no reason to report the timeout for a synchronous call. It * is impossible to use the reported timeout to do anything when the client * is blocking for the response. This update is only important for * async calls that require a callback to report the results in. */ return; - } else if (!op->request) { + } + + if (op->request == NULL) { return; } diff --git a/lib/cib/cib_native.c b/lib/cib/cib_native.c index 5d15893ed52..6fa2d73bf62 100644 --- a/lib/cib/cib_native.c +++ b/lib/cib/cib_native.c @@ -76,7 +76,7 @@ cib_native_perform_op_delegate(cib_t *cib, const char *op, const char *host, return -EINVAL; } - if (call_options & cib_sync_call) { + if (pcmk__is_set(call_options, cib_sync_call)) { pcmk__set_ipc_flags(ipc_flags, "client", crm_ipc_client_response); } @@ -115,7 +115,7 @@ cib_native_perform_op_delegate(cib_t *cib, const char *op, const char *host, pcmk__log_xml_trace(op_reply, "Reply"); - if (!(call_options & cib_sync_call)) { + if (!pcmk__is_set(call_options, cib_sync_call)) { pcmk__trace("Async call, returning %d", cib->call_id); CRM_CHECK(cib->call_id != 0, rc = -ENOMSG; goto done); @@ -133,8 +133,11 @@ cib_native_perform_op_delegate(cib_t *cib, const char *op, const char *host, rc = -EPROTO; } - if (output_data == NULL || (call_options & cib_discard_reply)) { + if ((output_data == NULL) + || pcmk__is_set(call_options, cib_discard_reply)) { + pcmk__trace("Discarding reply"); + } else { *output_data = pcmk__xml_copy(NULL, tmp); } diff --git a/lib/cib/cib_remote.c b/lib/cib/cib_remote.c index 3813767e918..79a8ee30e38 100644 --- a/lib/cib/cib_remote.c +++ b/lib/cib/cib_remote.c @@ -105,18 +105,19 @@ cib_remote_perform_op(cib_t *cib, const char *op, const char *host, } pcmk__trace("Sending %s message to the CIB manager", op); - if (!(call_options & cib_sync_call)) { + if (!pcmk__is_set(call_options, cib_sync_call)) { pcmk__remote_send_xml(&private->callback, op_msg); } else { pcmk__remote_send_xml(&private->command, op_msg); } pcmk__xml_free(op_msg); - if ((call_options & cib_discard_reply)) { + if (pcmk__is_set(call_options, cib_discard_reply)) { pcmk__trace("Discarding reply"); return pcmk_ok; + } - } else if (!(call_options & cib_sync_call)) { + if (!pcmk__is_set(call_options, cib_sync_call)) { return cib->call_id; } @@ -199,7 +200,7 @@ cib_remote_perform_op(cib_t *cib, const char *op, const char *host, if (output_data == NULL) { /* do nothing more */ - } else if (!(call_options & cib_discard_reply)) { + } else if (!pcmk__is_set(call_options, cib_discard_reply)) { xmlNode *tmp = cib__get_calldata(op_reply); if (tmp == NULL) { diff --git a/lib/cluster/membership.c b/lib/cluster/membership.c index d48d36013a0..81ce288005e 100644 --- a/lib/cluster/membership.c +++ b/lib/cluster/membership.c @@ -1128,7 +1128,7 @@ crm_update_peer_proc(const char *source, pcmk__node_status_t *node, changed = TRUE; } - } else if (node->processes & flag) { + } else if (pcmk__is_set(node->processes, flag)) { node->processes = pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE, "Peer process", node->name, node->processes, diff --git a/lib/common/io.c b/lib/common/io.c index 15347e93c50..b8c07970896 100644 --- a/lib/common/io.c +++ b/lib/common/io.c @@ -252,6 +252,7 @@ pcmk__daemon_user_can_write(const char *target_name, struct stat *target_stat) pcmk_rc_str(rc)); return false; } + if (target_stat->st_uid != daemon_uid) { pcmk__notice("%s is not owned by user " CRM_DAEMON_USER " " QB_XS " uid %lld != %lld", @@ -259,13 +260,15 @@ pcmk__daemon_user_can_write(const char *target_name, struct stat *target_stat) (long long) target_stat->st_uid); return false; } - if ((target_stat->st_mode & (S_IRUSR | S_IWUSR)) == 0) { + + if (!pcmk__any_flags_set(target_stat->st_mode, S_IRUSR|S_IWUSR)) { pcmk__notice("%s is not readable and writable by user %s " QB_XS " st_mode=0%lo", target_name, CRM_DAEMON_USER, (unsigned long) target_stat->st_mode); return false; } + return true; } @@ -289,13 +292,14 @@ pcmk__daemon_group_can_write(const char *target_name, struct stat *target_stat) return false; } - if ((target_stat->st_mode & (S_IRGRP | S_IWGRP)) == 0) { + if (!pcmk__any_flags_set(target_stat->st_mode, S_IRGRP|S_IWGRP)) { pcmk__notice("%s is not readable and writable by group %s " QB_XS " st_mode=0%lo", target_name, CRM_DAEMON_GROUP, (unsigned long) target_stat->st_mode); return false; } + return true; } diff --git a/lib/common/mainloop.c b/lib/common/mainloop.c index b3457ff026b..7aee7ae85a7 100644 --- a/lib/common/mainloop.c +++ b/lib/common/mainloop.c @@ -687,7 +687,7 @@ mainloop_gio_callback(GIOChannel *gio, GIOCondition condition, void *data) pcmk__assert(client->fd == g_io_channel_unix_get_fd(gio)); - if (condition & G_IO_IN) { + if (pcmk__is_set(condition, G_IO_IN)) { if (client->ipc) { long read_rc = 0L; int max = 10; @@ -738,12 +738,14 @@ mainloop_gio_callback(GIOChannel *gio, GIOCondition condition, void *data) client->name, client, condition); rc = G_SOURCE_REMOVE; - } else if (condition & (G_IO_HUP | G_IO_NVAL | G_IO_ERR)) { + } else if (pcmk__any_flags_set(condition, + (G_IO_HUP | G_IO_NVAL | G_IO_ERR))) { + pcmk__trace("The connection %s[%p] has been closed (I/O condition=%d)", client->name, client, condition); rc = G_SOURCE_REMOVE; - } else if ((condition & G_IO_IN) == 0) { + } else if (!pcmk__is_set(condition, G_IO_IN)) { /* #define GLIB_SYSDEF_POLLIN =1 #define GLIB_SYSDEF_POLLPRI =2 diff --git a/lib/common/tls.c b/lib/common/tls.c index b88703d8eb8..9d0d5a4474e 100644 --- a/lib/common/tls.c +++ b/lib/common/tls.c @@ -642,7 +642,7 @@ pcmk__cred_file_useable(const char *location, bool *file_exists) return false; } - if ((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0) { + if (pcmk__any_flags_set(sb.st_mode, S_IRWXG|S_IRWXO)) { pcmk__err("Refusing to use PSK credentials file %s because it has " "group and/or other permissions set", location); return false; diff --git a/lib/fencing/st_client.c b/lib/fencing/st_client.c index 33e41d7ff8f..3e2ff23439f 100644 --- a/lib/fencing/st_client.c +++ b/lib/fencing/st_client.c @@ -1388,7 +1388,7 @@ stonith_api_add_callback(stonith_t * stonith, int call_id, int timeout, int opti private->op_callback = callback; } else if (call_id < 0) { // Call failed immediately, so call callback now - if (!(options & st_opt_report_only_success)) { + if (!pcmk__is_set(options, st_opt_report_only_success)) { pcmk__action_result_t result = PCMK__UNKNOWN_RESULT; pcmk__trace("Call failed, calling %s: %s", callback_name, @@ -1405,10 +1405,10 @@ stonith_api_add_callback(stonith_t * stonith, int call_id, int timeout, int opti blob = pcmk__assert_alloc(1, sizeof(stonith_callback_client_t)); blob->id = callback_name; - blob->only_success = (options & st_opt_report_only_success) ? TRUE : FALSE; + blob->only_success = pcmk__is_set(options, st_opt_report_only_success); blob->user_data = user_data; blob->callback = callback; - blob->allow_timeout_updates = (options & st_opt_timeout_updates) ? TRUE : FALSE; + blob->allow_timeout_updates = pcmk__is_set(options, st_opt_timeout_updates); if (timeout > 0) { set_callback_timeout(blob, stonith, call_id, timeout); @@ -1637,7 +1637,7 @@ stonith_send_command(stonith_t * stonith, const char *op, xmlNode * data, xmlNod { enum crm_ipc_flags ipc_flags = crm_ipc_flags_none; - if (call_options & st_opt_sync_call) { + if (pcmk__is_set(call_options, st_opt_sync_call)) { pcmk__set_ipc_flags(ipc_flags, "fencing command", crm_ipc_client_response); } @@ -1660,7 +1660,7 @@ stonith_send_command(stonith_t * stonith, const char *op, xmlNode * data, xmlNod pcmk__log_xml_trace(op_reply, "Reply"); - if (!(call_options & st_opt_sync_call)) { + if (!pcmk__is_set(call_options, st_opt_sync_call)) { pcmk__trace("Async call %d, returning", stonith->call_id); pcmk__xml_free(op_reply); return stonith->call_id; @@ -1677,7 +1677,9 @@ stonith_send_command(stonith_t * stonith, const char *op, xmlNode * data, xmlNod rc = pcmk_rc2legacy(stonith__result2rc(&result)); pcmk__reset_result(&result); - if ((call_options & st_opt_discard_reply) || output_data == NULL) { + if (pcmk__is_set(call_options, st_opt_discard_reply) + || (output_data == NULL)) { + pcmk__trace("Discarding reply"); } else { diff --git a/lib/services/dbus.c b/lib/services/dbus.c index a21da13e599..bd32ab141dd 100644 --- a/lib/services/dbus.c +++ b/lib/services/dbus.c @@ -82,18 +82,19 @@ dispatch_messages(void) static const char* dbus_watch_flags_to_string(int flags) { - const char *watch_type; - - if ((flags & DBUS_WATCH_READABLE) && (flags & DBUS_WATCH_WRITABLE)) { - watch_type = "read/write"; - } else if (flags & DBUS_WATCH_READABLE) { - watch_type = "read"; - } else if (flags & DBUS_WATCH_WRITABLE) { - watch_type = "write"; - } else { - watch_type = "neither read nor write"; + if (pcmk__all_flags_set(flags, DBUS_WATCH_READABLE|DBUS_WATCH_WRITABLE)) { + return "read/write"; + } + + if (pcmk__is_set(flags, DBUS_WATCH_READABLE)) { + return "read"; } - return watch_type; + + if (pcmk__is_set(flags, DBUS_WATCH_WRITABLE)) { + return "write"; + } + + return "neither read nor write"; } /*! @@ -120,7 +121,10 @@ dispatch_fd_data(void *userdata) dbus_watch_get_unix_fd(watch), flags, dbus_watch_flags_to_string(flags)); - if (enabled && (flags & (DBUS_WATCH_READABLE|DBUS_WATCH_WRITABLE))) { + if (enabled + && pcmk__any_flags_set(flags, + DBUS_WATCH_READABLE|DBUS_WATCH_WRITABLE)) { + oom = !dbus_watch_handle(watch, flags); } else if (enabled) { diff --git a/lib/services/services_linux.c b/lib/services/services_linux.c index 6ae1605ebbc..74a02d9dd2c 100644 --- a/lib/services/services_linux.c +++ b/lib/services/services_linux.c @@ -1092,16 +1092,17 @@ wait_for_sync_result(svc_action_t *op, struct sigchld_data_s *data) wait_reason = NULL; if (poll_rc > 0) { - if (fds[0].revents & POLLIN) { + if (pcmk__is_set(fds[0].revents, POLLIN)) { svc_read_output(op->opaque->stdout_fd, op, FALSE); } - if (fds[1].revents & POLLIN) { + if (pcmk__is_set(fds[1].revents, POLLIN)) { svc_read_output(op->opaque->stderr_fd, op, TRUE); } - if ((fds[2].revents & POLLIN) + if (pcmk__is_set(fds[2].revents, POLLIN) && sigchld_received(fds[2].fd, op->pid, data)) { + wait_rc = waitpid(op->pid, &status, WNOHANG); if ((wait_rc > 0) || ((wait_rc < 0) && (errno == ECHILD))) { diff --git a/tools/crm_mon.c b/tools/crm_mon.c index c45a4dfe2a4..2c615249943 100644 --- a/tools/crm_mon.c +++ b/tools/crm_mon.c @@ -1090,7 +1090,7 @@ detect_user_input(GIOChannel *channel, GIOCondition condition, void *user_data) * Exit with an error, otherwise the process would persist in the * background and significantly raise the CPU usage. */ - if ((condition & G_IO_ERR) && (condition & G_IO_HUP)) { + if (pcmk__all_flags_set(condition, G_IO_ERR|G_IO_HUP)) { rc = G_SOURCE_REMOVE; clean_up(CRM_EX_IOERR); } @@ -1098,11 +1098,11 @@ detect_user_input(GIOChannel *channel, GIOCondition condition, void *user_data) /* The connection/fd has been closed. Refresh the screen and remove this * event source hence ignore stdin. */ - if (condition & (G_IO_HUP | G_IO_NVAL)) { + if (pcmk__any_flags_set(condition, G_IO_HUP|G_IO_NVAL)) { rc = G_SOURCE_REMOVE; } - if ((condition & G_IO_IN) == 0) { + if (!pcmk__is_set(condition, G_IO_IN)) { return rc; } From e8c609bf832f185279a25e066d60409b9a7c5a02 Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 24 Jul 2026 00:49:51 -0700 Subject: [PATCH 34/37] Refactor: based: Add extra XML attrs only before based_process_request() We don't use these attrs when processing CRM_OP_REGISTER and PCMK__VALUE_CIB_NOTIFY. Signed-off-by: Reid Wahl --- daemons/based/based_ipc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/daemons/based/based_ipc.c b/daemons/based/based_ipc.c index 3f9eaf9c0e2..759ad3a21cd 100644 --- a/daemons/based/based_ipc.c +++ b/daemons/based/based_ipc.c @@ -157,12 +157,6 @@ based_ipc_dispatch(qb_ipcs_connection_t *c, void *data, size_t size) client->request_id = id; } - pcmk__xe_set(msg, PCMK__XA_CIB_CLIENTID, client->id); - pcmk__xe_set(msg, PCMK__XA_CIB_CLIENTNAME, client->name); - - CRM_LOG_ASSERT(client->user != NULL); - pcmk__update_acl_user(msg, PCMK__XA_CIB_USER, client->user); - pcmk__log_xml_trace(msg, "ipc-request"); op = pcmk__xe_get(msg, PCMK__XA_CIB_OP); @@ -196,6 +190,12 @@ based_ipc_dispatch(qb_ipcs_connection_t *c, void *data, size_t size) goto cleanup; } + pcmk__xe_set(msg, PCMK__XA_CIB_CLIENTID, client->id); + pcmk__xe_set(msg, PCMK__XA_CIB_CLIENTNAME, client->name); + + CRM_LOG_ASSERT(client->user != NULL); + pcmk__update_acl_user(msg, PCMK__XA_CIB_USER, client->user); + based_process_request(msg, client); cleanup: From 5a4a4eff3abd01e37103ddd5bc6270079815904c Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 24 Jul 2026 01:03:41 -0700 Subject: [PATCH 35/37] Low: based: Ignore requests from unregistered clients And set client->name only when dispatching a register request. In practice, this means that a client must call the signon() method before any other methods. Signed-off-by: Reid Wahl --- daemons/based/based_ipc.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/daemons/based/based_ipc.c b/daemons/based/based_ipc.c index 759ad3a21cd..4c680023817 100644 --- a/daemons/based/based_ipc.c +++ b/daemons/based/based_ipc.c @@ -119,16 +119,6 @@ based_ipc_dispatch(qb_ipcs_connection_t *c, void *data, size_t size) goto cleanup; } - if (client->name == NULL) { - const char *value = pcmk__xe_get(msg, PCMK__XA_CIB_CLIENTNAME); - - if (value == NULL) { - client->name = pcmk__itoa(client->pid); - } else { - client->name = pcmk__str_copy(value); - } - } - rc = pcmk__xe_get_flags(msg, PCMK__XA_CIB_CALLOPT, &call_options, cib_none); if (rc != pcmk_rc_ok) { pcmk__warn("Couldn't parse options from request from IPC client %s: %s", @@ -172,9 +162,31 @@ based_ipc_dispatch(qb_ipcs_connection_t *c, void *data, size_t size) pcmk__xe_set(reply, PCMK__XA_CIB_OP, CRM_OP_REGISTER); pcmk__xe_set(reply, PCMK__XA_CIB_CLIENTID, client->id); pcmk__ipc_send_xml(client, id, reply, flags); + pcmk__xml_free(reply); + + if (client->name != NULL) { + /* client->name is set if and only if we've processed a register + * request from the client + */ + pcmk__warn("Received register request from IPC client %s that is " + "already registered", pcmk__client_name(client)); + goto cleanup; + } client->request_id = 0; - pcmk__xml_free(reply); + + client->name = pcmk__xe_get_copy(msg, PCMK__XA_CIB_CLIENTNAME); + if (client->name == NULL) { + // Fall back to PID for logging purposes + client->name = pcmk__itoa(client->pid); + } + + goto cleanup; + } + + if (client->name == NULL) { + pcmk__warn("Ignoring CIB request from unregistered client %s", + pcmk__client_name(client)); goto cleanup; } From fc7061d93c922b34e9b93dbd8449621b8d27c5cb Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Sun, 11 Jan 2026 18:11:38 -0800 Subject: [PATCH 36/37] Refactor: based: Standardize based_ipc_dispatch() Make it look more like fenced_ipc_dispatch() and attrd_ipc_dispatch(). Not everything is in accordance with my preferences here, but the goal is to make it look as similar as possible to the other daemons. Signed-off-by: Reid Wahl --- daemons/based/based_ipc.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/daemons/based/based_ipc.c b/daemons/based/based_ipc.c index 4c680023817..8c885cbfda0 100644 --- a/daemons/based/based_ipc.c +++ b/daemons/based/based_ipc.c @@ -121,9 +121,7 @@ based_ipc_dispatch(qb_ipcs_connection_t *c, void *data, size_t size) rc = pcmk__xe_get_flags(msg, PCMK__XA_CIB_CALLOPT, &call_options, cib_none); if (rc != pcmk_rc_ok) { - pcmk__warn("Couldn't parse options from request from IPC client %s: %s", - client->name, pcmk_rc_str(rc)); - pcmk__log_xml_info(msg, "bad-call-opts"); + pcmk__warn("Couldn't parse options from request: %s", pcmk_rc_str(rc)); } /* Requests with cib_transaction set should not be sent to based directly @@ -147,8 +145,6 @@ based_ipc_dispatch(qb_ipcs_connection_t *c, void *data, size_t size) client->request_id = id; } - pcmk__log_xml_trace(msg, "ipc-request"); - op = pcmk__xe_get(msg, PCMK__XA_CIB_OP); if (pcmk__str_eq(op, CRM_OP_REGISTER, pcmk__str_none)) { @@ -199,16 +195,34 @@ based_ipc_dispatch(qb_ipcs_connection_t *c, void *data, size_t size) } pcmk__ipc_send_ack(client, id, flags, NULL, status); - goto cleanup; - } - pcmk__xe_set(msg, PCMK__XA_CIB_CLIENTID, client->id); - pcmk__xe_set(msg, PCMK__XA_CIB_CLIENTNAME, client->name); + } else { + pcmk__request_t request = { + .ipc_client = client, + .ipc_id = id, + .ipc_flags = flags, + .peer = NULL, + .xml = msg, + .call_options = call_options, + .result = PCMK__UNKNOWN_RESULT, + }; + + request.op = pcmk__xe_get_copy(request.xml, PCMK__XA_CIB_OP); + CRM_CHECK(request.op != NULL, goto cleanup); + + if (pcmk__is_set(request.call_options, cib_sync_call)) { + pcmk__set_request_flags(&request, pcmk__request_sync); + } + + pcmk__xe_set(request.xml, PCMK__XA_CIB_CLIENTID, client->id); + pcmk__xe_set(request.xml, PCMK__XA_CIB_CLIENTNAME, client->name); - CRM_LOG_ASSERT(client->user != NULL); - pcmk__update_acl_user(msg, PCMK__XA_CIB_USER, client->user); + CRM_LOG_ASSERT(client->user != NULL); + pcmk__update_acl_user(request.xml, PCMK__XA_CIB_USER, client->user); - based_process_request(msg, client); + based_process_request(request.xml, request.ipc_client); + pcmk__reset_request(&request); + } cleanup: pcmk__xml_free(msg); From e985f33e76baa6828794cabedd118a00b697548b Mon Sep 17 00:00:00 2001 From: Reid Wahl Date: Fri, 24 Jul 2026 09:52:40 -0700 Subject: [PATCH 37/37] Refactor: libcrmcommon: Assert non-NULL args in pcmk__serve_execd_ipc() Should have been done as part of a6bf06d. Signed-off-by: Reid Wahl --- lib/common/ipc_server.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/common/ipc_server.c b/lib/common/ipc_server.c index ba566d11157..453831ee75a 100644 --- a/lib/common/ipc_server.c +++ b/lib/common/ipc_server.c @@ -1152,6 +1152,8 @@ void pcmk__serve_execd_ipc(qb_ipcs_service_t **ipcs, struct qb_ipcs_service_handlers *cb) { + pcmk__assert((ipcs != NULL) && (*ipcs == NULL) && (cb != NULL)); + *ipcs = mainloop_add_ipc_server(pcmk__server_ipc_name(pcmk_ipc_execd), QB_IPC_SHM, cb);