12#if defined(HAVE_UCRED) || defined(HAVE_SOCKPEERCRED)
13#include <sys/socket.h>
14#elif defined(HAVE_GETPEERUCRED)
29static int is_ipc_provider_expected(qb_ipcc_connection_t *qb_ipc,
int sock,
30 uid_t refuid, gid_t refgid, pid_t *gotpid,
31 uid_t *gotuid, gid_t *gotgid);
57 (*api)->server = server;
96 if ((*api)->cmds == NULL) {
103 if ((*api)->ipc == NULL) {
110 if ((*api)->cmds->new_data != NULL) {
111 if ((*api)->cmds->new_data(*api) !=
pcmk_rc_ok) {
124 if ((api != NULL) && (api->
cmds != NULL)) {
147 if ((api != NULL) && (api->
cb != NULL)) {
148 api->
cb(api, event_type, status, event_data, api->
user_data);
161ipc_post_disconnect(gpointer user_data)
188 free_daemon_specific_data(api);
189 crm_trace(
"Freeing IPC API object after disconnect");
202 bool free_on_disconnect =
false;
209 if (api->
ipc != NULL) {
224 if (!free_on_disconnect) {
225 free_daemon_specific_data(api);
244 return for_log?
"Pacemaker" : NULL;
249 return pcmk__s(
name,
"Pacemaker");
319 if (buffer == NULL) {
320 crm_warn(
"Empty message received from %s IPC",
327 crm_warn(
"Malformed message received from %s IPC",
332 more = call_api_dispatch(api, msg);
355dispatch_ipc_source_data(
const char *buffer, ssize_t length, gpointer user_data)
360 dispatch_ipc_data(buffer, api);
386 struct pollfd pollfd = { 0, };
394 crm_debug(
"Could not obtain file descriptor for %s IPC: %s",
399 pollfd.events = POLLIN;
400 rc = poll(&pollfd, 1, timeout_ms);
405 return (errno == EAGAIN)? ENOMEM : errno;
406 }
else if (rc == 0) {
443 .dispatch = dispatch_ipc_source_data,
444 .destroy = ipc_post_disconnect,
452 crm_debug(
"Connected to %s IPC (attached to main loop)",
469 crm_debug(
"Connected to %s IPC (without main loop)",
491 int remaining = attempts;
495 if (rc == ECONNREFUSED) {
500 }
while (rc == ECONNREFUSED && remaining >= 0);
522 if ((api == NULL) || (attempts < 1)) {
526 if (api->
ipc == NULL) {
528 if (api->
ipc == NULL) {
540 crm_debug(
"Attempting connection to %s (up to %d time%s)",
542 for (
int remaining = attempts - 1; remaining >= 0; --remaining) {
543 switch (dispatch_type) {
545 rc = connect_with_main_loop(api);
550 rc = connect_without_main_loop(api);
554 if ((remaining == 0) || ((rc != EAGAIN) && (rc != EALREADY))) {
560 crm_debug(
"Re-attempting connection to %s (%d attempt%s remaining)",
592 crm_err(
"Connection to %s failed: %s",
612 if ((api == NULL) || (api->
ipc == NULL)) {
642 ipc_post_disconnect(api);
687 xmlNode *reply = NULL;
690 if ((api == NULL) || (api->
ipc == NULL) || (request == NULL)) {
697 && (api->
cmds != NULL)
712 }
else if (rc == 0) {
718 bool more = call_api_dispatch(api, reply);
727 }
else if (rc == -ENOMSG || rc ==
pcmk_ok) {
738 }
else if (rc == EINPROGRESS) {
771create_purge_node_request(
const pcmk_ipc_api_t *api,
const char *node_name,
774 xmlNode *request = NULL;
828 xmlNode *request = NULL;
833 if ((node_name == NULL) && (nodeid == 0)) {
837 request = create_purge_node_request(api, node_name, nodeid);
838 if (request == NULL) {
844 crm_debug(
"%s peer cache purge of node %s[%lu]: rc=%d",
845 pcmk_ipc_name(api,
true), node_name, (
unsigned long) nodeid, rc);
858 qb_ipcc_connection_t *ipc;
882 if (client == NULL) {
883 crm_err(
"Could not create IPC connection: %s", strerror(errno));
887 client->server_name = strdup(
name);
888 if (client->server_name == NULL) {
889 crm_err(
"Could not create %s IPC connection: %s",
890 name, strerror(errno));
895 client->buffer = NULL;
897 client->pfd.events = POLLIN;
898 client->pfd.revents = 0;
925 ipc->need_reply = FALSE;
927 if (ipc->ipc == NULL) {
931 rc = qb_ipcc_fd_get(ipc->ipc, &ipc->pfd.fd);
944 rc = is_ipc_provider_expected(ipc->ipc, ipc->pfd.fd, cl_uid, cl_gid,
945 &found_pid, &found_uid, &found_gid);
948 crm_info(
"%s IPC provider authentication failed: process %lld has "
949 "uid %lld (expected %lld) and gid %lld (expected %lld)",
952 (
long long) found_uid, (
long long) cl_uid,
953 (
long long) found_gid, (
long long) cl_gid);
967 qb_ipcc_connection_t *ipc = client->ipc;
970 qb_ipcc_disconnect(ipc);
979 if (client->ipc && qb_ipcc_is_connected(client->ipc)) {
980 crm_notice(
"Destroying active %s IPC connection",
981 client->server_name);
992 crm_trace(
"Destroying inactive %s IPC connection",
993 client->server_name);
996 if (client->buffer != NULL) {
1000 free(client->server_name);
1017 if ((ipc == NULL) || (fd == NULL)) {
1020 if ((ipc->ipc == NULL) || (ipc->pfd.fd < 0)) {
1033 crm_err(
"Could not obtain file descriptor for %s IPC",
1034 ((client == NULL)?
"unspecified" : client->server_name));
1046 if (client == NULL) {
1050 }
else if (client->ipc == NULL) {
1054 }
else if (client->pfd.fd < 0) {
1059 rc = qb_ipcc_is_connected(client->ipc);
1061 client->pfd.fd = -EINVAL;
1084 client->pfd.revents = 0;
1085 rc = poll(&(client->pfd), 1, 0);
1086 return (rc < 0)? -errno : rc;
1092 guint8 *buffer = NULL;
1095 pcmk__assert((client != NULL) && (client->ipc != NULL));
1100 ssize_t bytes = qb_ipcc_event_recv(client->ipc, buffer,
1106 crm_trace(
"No message received from %s IPC: %s",
1107 client->server_name, strerror(-bytes));
1110 crm_err(
"Connection to %s IPC failed", client->server_name);
1113 }
else if (bytes == -EAGAIN) {
1120 crm_trace(
"Message size does not match header");
1126 crm_trace(
"Received %s IPC event %" PRId32
" size=%" PRIu32
" rc=%zu",
1127 client->server_name, header->
qb.id, header->
qb.size,
1143 if (client->buffer->len > 0) {
1158 if (client->buffer != NULL) {
1159 g_byte_array_free(client->buffer, TRUE);
1160 client->buffer = NULL;
1168 CRM_CHECK(client->buffer != NULL,
return NULL);
1178 if (client->buffer == NULL) {
1183 return header->
flags;
1190 return client->server_name;
1195internal_ipc_get_reply(
crm_ipc_t *client,
int request_id,
int ms_timeout,
1196 ssize_t *bytes, xmlNode **reply)
1198 guint8 *buffer = NULL;
1201 int32_t qb_timeout = -1;
1205 if (ms_timeout > 0) {
1211 crm_trace(
"Expecting reply to %s IPC message %d", client->server_name,
1217 guint8 *
data = NULL;
1218 xmlNode *xml = NULL;
1227 crm_err(
"%s IPC provider disconnected while waiting for message %d",
1228 client->server_name, request_id);
1235 crm_trace(
"Message size does not match header");
1240 reply_id = hdr->
qb.id;
1242 if (reply_id == request_id) {
1258 if (reply_id < request_id) {
1259 crm_err(
"Discarding old reply %d (need %d)", reply_id, request_id);
1261 }
else if (reply_id > request_id) {
1262 crm_err(
"Discarding newer reply %d (need %d)", reply_id, request_id);
1266 }
while (time(NULL) <
timeout || (
timeout == 0 && *bytes == -EAGAIN));
1268 if (client->buffer->len > 0) {
1269 crm_trace(
"Received %u-byte reply %d to %s IPC %d: %.100s",
1270 client->buffer->len, reply_id, client->server_name,
1273 if (reply != NULL) {
1276 }
else if (*bytes < 0) {
1278 crm_trace(
"No reply to %s IPC %d: %s " QB_XS
" rc=%d",
1279 client->server_name, request_id,
pcmk_rc_str(rc), rc);
1298discard_old_replies(
crm_ipc_t *client, int32_t ms_timeout)
1310 crm_warn(
"Sending %s IPC disabled until pending reply received",
1311 client->server_name);
1323 crm_notice(
"Sending %s IPC re-enabled after pending reply received",
1324 client->server_name);
1325 client->need_reply = FALSE;
1328 crm_warn(
"Sending %s IPC disabled until multipart IPC message "
1329 "reply received", client->server_name);
1357 ssize_t sent_bytes = 0;
1358 struct iovec *iov = NULL;
1359 static uint32_t
id = 0;
1361 GString *iov_buffer = NULL;
1364 if (client == NULL) {
1365 crm_notice(
"Can't send IPC request without connection (bug?): %.100s",
1371 crm_notice(
"Can't send %s IPC requests: Connection closed",
1372 client->server_name);
1376 if (ms_timeout == 0) {
1384 if (client->need_reply) {
1385 int discard_rc = discard_old_replies(client, ms_timeout);
1395 iov_buffer = g_string_sized_new(1024);
1405 crm_warn(
"Couldn't prepare %s IPC request: %s " QB_XS
" rc=%d",
1407 g_string_free(iov_buffer, TRUE);
1411 header = iov[0].iov_base;
1421 crm_trace(
"Sending %s IPC request %" PRId32
" (%spart %" PRIu16
") of "
1422 "%" PRId32
" bytes using %dms timeout",
1423 client->server_name, header->
qb.id, is_end ?
"final " :
"",
1424 index, header->
qb.size, ms_timeout);
1425 crm_trace(
"Text = %s", (
char *) iov[1].iov_base);
1427 crm_trace(
"Sending %s IPC request %" PRId32
" of %" PRId32
" bytes "
1428 "using %dms timeout",
1429 client->server_name, header->
qb.id, header->
qb.size,
1431 crm_trace(
"Text = %s", (
char *) iov[1].iov_base);
1435 if (ms_timeout > 0) {
1440 qb_rc = qb_ipcc_sendv(client->ipc, iov, 2);
1441 }
while ((qb_rc == -EAGAIN) && ((
timeout == 0) || (time(NULL) <
timeout)));
1457 sent_bytes += qb_rc;
1458 rc = (int) sent_bytes;
1466 sent_bytes += qb_rc;
1476 crm_trace(
"Not waiting for reply to %s IPC request %d",
1477 client->server_name, header->
qb.id);
1482 rc = internal_ipc_get_reply(client, header->
qb.id, ms_timeout, &bytes, reply);
1492 if (ms_timeout > 0) {
1499 client->need_reply = TRUE;
1505 crm_notice(
"Couldn't send %s IPC request %d: Connection closed "
1506 QB_XS
" rc=%d", client->server_name, header->
qb.id, rc);
1508 }
else if (rc == -ETIMEDOUT) {
1509 crm_warn(
"%s IPC request %d failed: %s after %dms " QB_XS
" rc=%d",
1514 }
else if (rc <= 0) {
1515 crm_warn(
"%s IPC request %d failed: %s " QB_XS
" rc=%d",
1516 client->server_name, header->
qb.id,
1520 g_string_free(iov_buffer, TRUE);
1544is_ipc_provider_expected(qb_ipcc_connection_t *qb_ipc,
int sock,
1545 uid_t refuid, gid_t refgid,
1546 pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
1548 int rc = EOPNOTSUPP;
1549 pid_t found_pid = 0;
1550 uid_t found_uid = 0;
1551 gid_t found_gid = 0;
1553#ifdef HAVE_QB_IPCC_AUTH_GET
1554 if (qb_ipc != NULL) {
1555 rc = qb_ipcc_auth_get(qb_ipc, &found_pid, &found_uid, &found_gid);
1566 socklen_t ucred_len =
sizeof(ucred);
1568 if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &ucred, &ucred_len) < 0) {
1570 }
else if (ucred_len !=
sizeof(ucred)) {
1573 found_pid = ucred.pid;
1574 found_uid = ucred.uid;
1575 found_gid = ucred.gid;
1581#ifdef HAVE_SOCKPEERCRED
1583 struct sockpeercred sockpeercred;
1584 socklen_t sockpeercred_len =
sizeof(sockpeercred);
1586 if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED,
1587 &sockpeercred, &sockpeercred_len) < 0) {
1589 }
else if (sockpeercred_len !=
sizeof(sockpeercred)) {
1592 found_pid = sockpeercred.pid;
1593 found_uid = sockpeercred.uid;
1594 found_gid = sockpeercred.gid;
1600#ifdef HAVE_GETPEEREID
1601 if (getpeereid(sock, &found_uid, &found_gid) < 0) {
1609#ifdef HAVE_GETPEERUCRED
1611 ucred_t *ucred = NULL;
1613 if (getpeerucred(sock, &ucred) < 0) {
1616 found_pid = ucred_getpid(ucred);
1617 found_uid = ucred_geteuid(ucred);
1618 found_gid = ucred_getegid(ucred);
1628 if (gotpid != NULL) {
1629 *gotpid = found_pid;
1631 if (gotuid != NULL) {
1632 *gotuid = found_uid;
1634 if (gotgid != NULL) {
1635 *gotgid = found_gid;
1637 if ((found_uid != 0) && (found_uid != refuid) && (found_gid != refgid)) {
1645 pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
1647 int ret = is_ipc_provider_expected(NULL, sock, refuid, refgid,
1648 gotpid, gotuid, gotgid);
1662 gid_t refgid, pid_t *gotpid)
1664 static char last_asked_name[PATH_MAX / 2] =
"";
1669 pid_t found_pid = 0; uid_t found_uid = 0; gid_t found_gid = 0;
1670 qb_ipcc_connection_t *c;
1671#ifdef HAVE_QB_IPCC_CONNECT_ASYNC
1672 struct pollfd pollfd = { 0, };
1675 c = qb_ipcc_connect_async(
name, 0,
1678 c = qb_ipcc_connect(
name, 0);
1681 crm_info(
"Could not connect to %s IPC: %s",
name, strerror(errno));
1685#ifdef HAVE_QB_IPCC_CONNECT_ASYNC
1686 pollfd.events = POLLIN;
1688 poll_rc = poll(&pollfd, 1, 2000);
1689 }
while ((poll_rc == -1) && (errno == EINTR));
1696 if (qb_ipcc_connect_continue(c) != 0) {
1698 (poll_rc == 0)?
"timeout":strerror(errno));
1705 qb_rc = qb_ipcc_fd_get(c, &fd);
1708 crm_err(
"Could not get fd from %s IPC: %s " QB_XS
" rc=%d",
1713 auth_rc = is_ipc_provider_expected(c, fd, refuid, refgid,
1714 &found_pid, &found_uid, &found_gid);
1716 crm_err(
"Daemon (IPC %s) effectively blocked with unauthorized"
1717 " process %lld (uid: %lld, gid: %lld)",
1719 (
long long) found_uid, (
long long) found_gid);
1726 crm_err(
"Could not get peer credentials from %s IPC: %s "
1731 if (gotpid != NULL) {
1732 *gotpid = found_pid;
1736 if ((found_uid != refuid || found_gid != refgid)
1737 && strncmp(last_asked_name,
name,
sizeof(last_asked_name))) {
1738 if ((found_uid == 0) && (refuid != 0)) {
1739 crm_warn(
"Daemon (IPC %s) runs as root, whereas the expected"
1740 " credentials are %lld:%lld, hazard of violating"
1741 " the least privilege principle",
1742 name, (
long long) refuid, (
long long) refgid);
1744 crm_notice(
"Daemon (IPC %s) runs as %lld:%lld, whereas the"
1745 " expected credentials are %lld:%lld, which may"
1746 " mean a different set of privileges than expected",
1747 name, (
long long) found_uid, (
long long) found_gid,
1748 (
long long) refuid, (
long long) refgid);
1750 memccpy(last_asked_name,
name,
'\0',
sizeof(last_asked_name));
1755 qb_ipcc_disconnect(c);
1773 if ((client != NULL) && (client->ipc == NULL)) {
1774 errno = (rc > 0)? rc : ENOTCONN;
1775 crm_debug(
"Could not establish %s IPC connection: %s (%d)",
1778 crm_err(
"%s IPC provider authentication failed",
1779 (client == NULL)?
"Pacemaker" : client->server_name);
1780 errno = ECONNABORTED;
1782 crm_err(
"Could not verify authenticity of %s IPC provider",
1783 (client == NULL)?
"Pacemaker" : client->server_name);
int pcmk__add_mainloop_ipc(crm_ipc_t *ipc, int priority, void *userdata, const struct ipc_client_callbacks *callbacks, mainloop_io_t **source)
Connect to IPC and add it as a main loop source.
guint pcmk__timeout_ms2s(guint timeout_ms)
void pcmk__sleep_ms(unsigned int ms)
#define pcmk__assert_alloc(nmemb, size)
int pcmk_daemon_user(uid_t *uid, gid_t *gid)
Get user and group IDs of pacemaker daemon user.
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
#define CRM_OP_RM_NODE_CACHE
#define PCMK__ATTRD_CMD_PEER_REMOVE
struct pcmk__ipc_header_s pcmk__ipc_header_t
G_GNUC_INTERNAL pcmk__ipc_methods_t * pcmk__attrd_api_methods(void)
G_GNUC_INTERNAL pcmk__ipc_methods_t * pcmk__pacemakerd_api_methods(void)
G_GNUC_INTERNAL bool pcmk__valid_ipc_header(const pcmk__ipc_header_t *header)
G_GNUC_INTERNAL pcmk__ipc_methods_t * pcmk__controld_api_methods(void)
G_GNUC_INTERNAL pcmk__ipc_methods_t * pcmk__schedulerd_api_methods(void)
IPC interface to Pacemaker daemons.
void(* pcmk_ipc_callback_t)(pcmk_ipc_api_t *api, enum pcmk_ipc_event event_type, crm_exit_t status, void *event_data, void *user_data)
Callback function type for Pacemaker daemon IPC APIs.
unsigned int crm_ipc_default_buffer_size(void)
Return pacemaker's IPC buffer size.
@ crm_ipc_multipart
This is a multi-part IPC message.
@ crm_ipc_client_response
A response is expected in reply.
@ crm_ipc_proxied
ALL replies to proxied connections need to be sent as events
@ crm_ipc_multipart_end
This is the end of a multi-part IPC message.
void pcmk_free_ipc_event(struct iovec *event)
Free an I/O vector created by pcmk__ipc_prepare_iov()
pcmk_ipc_event
Possible event types that an IPC event callback can be called for.
@ pcmk_ipc_event_disconnect
Termination of IPC connection.
pcmk_ipc_server
Available IPC interfaces.
@ pcmk_ipc_schedulerd
Scheduler.
@ pcmk_ipc_based
CIB manager.
@ pcmk_ipc_execd
Executor.
@ pcmk_ipc_pacemakerd
Launcher.
@ pcmk_ipc_attrd
Attribute manager.
@ pcmk_ipc_controld
Controller.
pcmk_ipc_dispatch
How IPC replies should be dispatched.
@ pcmk_ipc_dispatch_sync
Sending a command will wait for any reply.
@ pcmk_ipc_dispatch_poll
Caller will poll and dispatch IPC.
@ pcmk_ipc_dispatch_main
Attach IPC to GMainLoop for dispatch.
struct crm_ipc_s crm_ipc_t
int pcmk_poll_ipc(const pcmk_ipc_api_t *api, int timeout_ms)
Check whether an IPC connection has data available (without main loop)
void crm_ipc_destroy(crm_ipc_t *client)
int pcmk__connect_generic_ipc(crm_ipc_t *ipc)
void pcmk_disconnect_ipc(pcmk_ipc_api_t *api)
Disconnect an IPC API instance.
const char * crm_ipc_name(crm_ipc_t *client)
int pcmk__ipc_fd(crm_ipc_t *ipc, int *fd)
int crm_ipc_send(crm_ipc_t *client, const xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Send an IPC XML message.
int pcmk_connect_ipc(pcmk_ipc_api_t *api, enum pcmk_ipc_dispatch dispatch_type)
Connect to a Pacemaker daemon via IPC.
long crm_ipc_read(crm_ipc_t *client)
void pcmk__ipc_free_client_buffer(crm_ipc_t *client)
int crm_ipc_get_fd(crm_ipc_t *client)
int pcmk__send_ipc_request(pcmk_ipc_api_t *api, const xmlNode *request)
int crm_ipc_ready(crm_ipc_t *client)
Check whether an IPC connection is ready to be read.
void pcmk__call_ipc_callback(pcmk_ipc_api_t *api, enum pcmk_ipc_event event_type, crm_exit_t status, void *event_data)
int pcmk__connect_ipc(pcmk_ipc_api_t *api, enum pcmk_ipc_dispatch dispatch_type, int attempts)
bool crm_ipc_connected(crm_ipc_t *client)
bool crm_ipc_connect(crm_ipc_t *client)
const char * pcmk_ipc_name(const pcmk_ipc_api_t *api, bool for_log)
Get the IPC name used with an IPC API connection.
int crm_ipc_is_authentic_process(int sock, uid_t refuid, gid_t refgid, pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
Check the authenticity of the IPC socket peer process (legacy)
void crm_ipc_close(crm_ipc_t *client)
void pcmk_free_ipc_api(pcmk_ipc_api_t *api)
Free the contents of an IPC API object.
int pcmk__ipc_is_authentic_process_active(const char *name, uid_t refuid, gid_t refgid, pid_t *gotpid)
int pcmk__connect_ipc_retry_conrefused(pcmk_ipc_api_t *api, enum pcmk_ipc_dispatch dispatch_type, int attempts)
uint32_t crm_ipc_buffer_flags(crm_ipc_t *client)
int pcmk_new_ipc_api(pcmk_ipc_api_t **api, enum pcmk_ipc_server server)
Create a new object for using Pacemaker daemon IPC.
const char * crm_ipc_buffer(crm_ipc_t *client)
bool pcmk_ipc_is_connected(pcmk_ipc_api_t *api)
Check whether an IPC API connection is active.
void pcmk_dispatch_ipc(pcmk_ipc_api_t *api)
Dispatch available messages on an IPC connection (without main loop)
crm_ipc_t * crm_ipc_new(const char *name, size_t max_size)
Create a new (legacy) object for using Pacemaker daemon IPC.
int pcmk_ipc_purge_node(pcmk_ipc_api_t *api, const char *node_name, uint32_t nodeid)
Ask a Pacemaker daemon to purge a node from its peer cache.
void pcmk_register_ipc_callback(pcmk_ipc_api_t *api, pcmk_ipc_callback_t cb, void *user_data)
Register a callback for IPC API events.
Deprecated Pacemaker IPC APIs.
#define PCMK__SPECIAL_PID_AS_0(p)
int pcmk__ipc_msg_append(GByteArray **buffer, guint8 *data)
int pcmk__ipc_prepare_iov(uint32_t request, const GString *message, uint16_t index, struct iovec **result, ssize_t *bytes)
#define pcmk__set_ipc_flags(ipc_flags, ipc_name, flags_to_set)
#define PCMK__SPECIAL_PID
#define pcmk__clear_ipc_flags(ipc_flags, ipc_name, flags_to_clear)
#define crm_info(fmt, args...)
void crm_write_blackbox(int nsig, const struct qb_log_callsite *callsite)
#define crm_warn(fmt, args...)
#define CRM_LOG_ASSERT(expr)
#define crm_notice(fmt, args...)
#define CRM_CHECK(expr, failure_action)
#define crm_debug(fmt, args...)
#define crm_err(fmt, args...)
#define crm_log_xml_trace(xml, text)
#define crm_trace(fmt, args...)
#define crm_log_xml_notice(xml, text)
struct mainloop_io_s mainloop_io_t
void mainloop_del_ipc_client(mainloop_io_t *client)
#define pcmk__new_request(server, sender_system, recipient_node, recipient_system, task, data)
#define PCMK__VALUE_ATTRD
const char * pcmk_strerror(int rc)
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
@ CRM_EX_DISCONNECT
Lost connection to something.
@ pcmk_rc_ipc_unauthorized
@ pcmk_rc_ipc_unresponsive
int pcmk_rc2legacy(int rc)
int pcmk_legacy2rc(int legacy_rc)
enum crm_exit_e crm_exit_t
Exit status codes for tools and daemons.
#define pcmk__assert(expr)
const char * pcmk__server_log_name(enum pcmk_ipc_server server)
const char * pcmk__server_ipc_name(enum pcmk_ipc_server server)
#define pcmk__plural_s(i)
bool(* reply_expected)(pcmk_ipc_api_t *api, const xmlNode *request)
void(* free_data)(void *api_data)
bool(* dispatch)(pcmk_ipc_api_t *api, xmlNode *msg)
void(* post_disconnect)(pcmk_ipc_api_t *api)
int(* post_connect)(pcmk_ipc_api_t *api)
enum pcmk_ipc_dispatch dispatch_type
mainloop_io_t * mainloop_io
pcmk__ipc_methods_t * cmds
enum pcmk_ipc_server server
Wrappers for and extensions to libxml2.
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
const char * crm_xml_add_ll(xmlNode *node, const char *name, long long value)
Create an XML attribute with specified name and long long int value.
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
void pcmk__xe_set_bool_attr(xmlNodePtr node, const char *name, bool value)
void pcmk__xml_free(xmlNode *xml)
void pcmk__xml_string(const xmlNode *data, uint32_t options, GString *buffer, int depth)
xmlNode * pcmk__xml_parse(const char *input)
#define PCMK__XA_ATTR_HOST_ID
#define PCMK__XA_ATTR_HOST