pacemaker 2.1.1-77db578727
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
ipc_client.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2021 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11
12#if defined(US_AUTH_PEERCRED_UCRED) || defined(US_AUTH_PEERCRED_SOCKPEERCRED)
13# ifdef US_AUTH_PEERCRED_UCRED
14# ifndef _GNU_SOURCE
15# define _GNU_SOURCE
16# endif
17# endif
18# include <sys/socket.h>
19#elif defined(US_AUTH_GETPEERUCRED)
20# include <ucred.h>
21#endif
22
23#include <stdio.h>
24#include <sys/types.h>
25#include <errno.h>
26#include <bzlib.h>
27
28#include <crm/crm.h> /* indirectly: pcmk_err_generic */
29#include <crm/msg_xml.h>
30#include <crm/common/ipc.h>
32#include "crmcommon_private.h"
33
46int
48{
49 if (api == NULL) {
50 return EINVAL;
51 }
52
53 *api = calloc(1, sizeof(pcmk_ipc_api_t));
54 if (*api == NULL) {
55 return errno;
56 }
57
58 (*api)->server = server;
59 if (pcmk_ipc_name(*api, false) == NULL) {
61 *api = NULL;
62 return EOPNOTSUPP;
63 }
64
65 (*api)->ipc_size_max = 0;
66
67 // Set server methods and max_size (if not default)
68 switch (server) {
69 case pcmk_ipc_attrd:
70 break;
71
72 case pcmk_ipc_based:
73 (*api)->ipc_size_max = 512 * 1024; // 512KB
74 break;
75
77 (*api)->cmds = pcmk__controld_api_methods();
78 break;
79
80 case pcmk_ipc_execd:
81 break;
82
83 case pcmk_ipc_fenced:
84 break;
85
87 (*api)->cmds = pcmk__pacemakerd_api_methods();
88 break;
89
91 // @TODO max_size could vary by client, maybe take as argument?
92 (*api)->ipc_size_max = 5 * 1024 * 1024; // 5MB
93 break;
94 }
95 if ((*api)->cmds == NULL) {
97 *api = NULL;
98 return ENOMEM;
99 }
100
101 (*api)->ipc = crm_ipc_new(pcmk_ipc_name(*api, false),
102 (*api)->ipc_size_max);
103 if ((*api)->ipc == NULL) {
104 pcmk_free_ipc_api(*api);
105 *api = NULL;
106 return ENOMEM;
107 }
108
109 // If daemon API has its own data to track, allocate it
110 if ((*api)->cmds->new_data != NULL) {
111 if ((*api)->cmds->new_data(*api) != pcmk_rc_ok) {
112 pcmk_free_ipc_api(*api);
113 *api = NULL;
114 return ENOMEM;
115 }
116 }
117 crm_trace("Created %s API IPC object", pcmk_ipc_name(*api, true));
118 return pcmk_rc_ok;
119}
120
121static void
122free_daemon_specific_data(pcmk_ipc_api_t *api)
123{
124 if ((api != NULL) && (api->cmds != NULL)) {
125 if ((api->cmds->free_data != NULL) && (api->api_data != NULL)) {
126 api->cmds->free_data(api->api_data);
127 api->api_data = NULL;
128 }
129 free(api->cmds);
130 api->cmds = NULL;
131 }
132}
133
143void
145 crm_exit_t status, void *event_data)
146{
147 if ((api != NULL) && (api->cb != NULL)) {
148 api->cb(api, event_type, status, event_data, api->user_data);
149 }
150}
151
160static void
161ipc_post_disconnect(gpointer user_data)
162{
163 pcmk_ipc_api_t *api = user_data;
164
165 crm_info("Disconnected from %s IPC API", pcmk_ipc_name(api, true));
166
167 // Perform any daemon-specific handling needed
168 if ((api->cmds != NULL) && (api->cmds->post_disconnect != NULL)) {
169 api->cmds->post_disconnect(api);
170 }
171
172 // Call client's registered event callback
174 NULL);
175
176 /* If this is being called from a running main loop, mainloop_gio_destroy()
177 * will free ipc and mainloop_io immediately after calling this function.
178 * If this is called from a stopped main loop, these will leak, so the best
179 * practice is to close the connection before stopping the main loop.
180 */
181 api->ipc = NULL;
182 api->mainloop_io = NULL;
183
184 if (api->free_on_disconnect) {
185 /* pcmk_free_ipc_api() has already been called, but did not free api
186 * or api->cmds because this function needed them. Do that now.
187 */
188 free_daemon_specific_data(api);
189 crm_trace("Freeing IPC API object after disconnect");
190 free(api);
191 }
192}
193
199void
201{
202 bool free_on_disconnect = false;
203
204 if (api == NULL) {
205 return;
206 }
207 crm_debug("Releasing %s IPC API", pcmk_ipc_name(api, true));
208
209 if (api->ipc != NULL) {
210 if (api->mainloop_io != NULL) {
211 /* We need to keep the api pointer itself around, because it is the
212 * user data for the IPC client destroy callback. That will be
213 * triggered by the pcmk_disconnect_ipc() call below, but it might
214 * happen later in the main loop (if still running).
215 *
216 * This flag tells the destroy callback to free the object. It can't
217 * do that unconditionally, because the application might call this
218 * function after a disconnect that happened by other means.
219 */
220 free_on_disconnect = api->free_on_disconnect = true;
221 }
222 pcmk_disconnect_ipc(api); // Frees api if free_on_disconnect is true
223 }
224 if (!free_on_disconnect) {
225 free_daemon_specific_data(api);
226 crm_trace("Freeing IPC API object");
227 free(api);
228 }
229}
230
240const char *
241pcmk_ipc_name(pcmk_ipc_api_t *api, bool for_log)
242{
243 if (api == NULL) {
244 return for_log? "Pacemaker" : NULL;
245 }
246 switch (api->server) {
247 case pcmk_ipc_attrd:
248 return for_log? "attribute manager" : NULL /* T_ATTRD */;
249
250 case pcmk_ipc_based:
251 return for_log? "CIB manager" : NULL /* PCMK__SERVER_BASED_RW */;
252
254 return for_log? "controller" : CRM_SYSTEM_CRMD;
255
256 case pcmk_ipc_execd:
257 return for_log? "executor" : NULL /* CRM_SYSTEM_LRMD */;
258
259 case pcmk_ipc_fenced:
260 return for_log? "fencer" : NULL /* "stonith-ng" */;
261
263 return for_log? "launcher" : CRM_SYSTEM_MCP;
264
266 return for_log? "scheduler" : NULL /* CRM_SYSTEM_PENGINE */;
267
268 default:
269 return for_log? "Pacemaker" : NULL;
270 }
271}
272
280bool
282{
283 return (api != NULL) && crm_ipc_connected(api->ipc);
284}
285
296static void
297call_api_dispatch(pcmk_ipc_api_t *api, xmlNode *message)
298{
299 crm_log_xml_trace(message, "ipc-received");
300 if ((api->cmds != NULL) && (api->cmds->dispatch != NULL)) {
301 api->cmds->dispatch(api, message);
302 }
303}
304
317static int
318dispatch_ipc_data(const char *buffer, ssize_t length, gpointer user_data)
319{
320 pcmk_ipc_api_t *api = user_data;
321 xmlNode *msg;
322
323 CRM_CHECK(api != NULL, return 0);
324
325 if (buffer == NULL) {
326 crm_warn("Empty message received from %s IPC",
327 pcmk_ipc_name(api, true));
328 return 0;
329 }
330
331 msg = string2xml(buffer);
332 if (msg == NULL) {
333 crm_warn("Malformed message received from %s IPC",
334 pcmk_ipc_name(api, true));
335 return 0;
336 }
337 call_api_dispatch(api, msg);
338 free_xml(msg);
339 return 0;
340}
341
360int
361pcmk_poll_ipc(pcmk_ipc_api_t *api, int timeout_ms)
362{
363 int rc;
364 struct pollfd pollfd = { 0, };
365
366 if ((api == NULL) || (api->dispatch_type != pcmk_ipc_dispatch_poll)) {
367 return EINVAL;
368 }
369 pollfd.fd = crm_ipc_get_fd(api->ipc);
370 pollfd.events = POLLIN;
371 rc = poll(&pollfd, 1, timeout_ms);
372 if (rc < 0) {
373 return errno;
374 } else if (rc == 0) {
375 return EAGAIN;
376 }
377 return pcmk_rc_ok;
378}
379
390void
392{
393 if (api == NULL) {
394 return;
395 }
396 while (crm_ipc_ready(api->ipc) > 0) {
397 if (crm_ipc_read(api->ipc) > 0) {
398 dispatch_ipc_data(crm_ipc_buffer(api->ipc), 0, api);
399 }
400 }
401}
402
403// \return Standard Pacemaker return code
404static int
405connect_with_main_loop(pcmk_ipc_api_t *api)
406{
407 int rc;
408
409 struct ipc_client_callbacks callbacks = {
410 .dispatch = dispatch_ipc_data,
411 .destroy = ipc_post_disconnect,
412 };
413
414 rc = pcmk__add_mainloop_ipc(api->ipc, G_PRIORITY_DEFAULT, api,
415 &callbacks, &(api->mainloop_io));
416 if (rc != pcmk_rc_ok) {
417 return rc;
418 }
419 crm_debug("Connected to %s IPC (attached to main loop)",
420 pcmk_ipc_name(api, true));
421 /* After this point, api->mainloop_io owns api->ipc, so api->ipc
422 * should not be explicitly freed.
423 */
424 return pcmk_rc_ok;
425}
426
427// \return Standard Pacemaker return code
428static int
429connect_without_main_loop(pcmk_ipc_api_t *api)
430{
431 int rc;
432
433 if (!crm_ipc_connect(api->ipc)) {
434 rc = errno;
435 crm_ipc_close(api->ipc);
436 return rc;
437 }
438 crm_debug("Connected to %s IPC (without main loop)",
439 pcmk_ipc_name(api, true));
440 return pcmk_rc_ok;
441}
442
451int
453{
454 int rc = pcmk_rc_ok;
455
456 if (api == NULL) {
457 crm_err("Cannot connect to uninitialized API object");
458 return EINVAL;
459 }
460
461 if (api->ipc == NULL) {
462 api->ipc = crm_ipc_new(pcmk_ipc_name(api, false),
463 api->ipc_size_max);
464 if (api->ipc == NULL) {
465 crm_err("Failed to re-create IPC API");
466 return ENOMEM;
467 }
468 }
469
470 if (crm_ipc_connected(api->ipc)) {
471 crm_trace("Already connected to %s IPC API", pcmk_ipc_name(api, true));
472 return pcmk_rc_ok;
473 }
474
475 api->dispatch_type = dispatch_type;
476 switch (dispatch_type) {
478 rc = connect_with_main_loop(api);
479 break;
480
483 rc = connect_without_main_loop(api);
484 break;
485 }
486 if (rc != pcmk_rc_ok) {
487 return rc;
488 }
489
490 if ((api->cmds != NULL) && (api->cmds->post_connect != NULL)) {
491 rc = api->cmds->post_connect(api);
492 if (rc != pcmk_rc_ok) {
493 crm_ipc_close(api->ipc);
494 }
495 }
496 return rc;
497}
498
510void
512{
513 if ((api == NULL) || (api->ipc == NULL)) {
514 return;
515 }
516 switch (api->dispatch_type) {
518 {
519 mainloop_io_t *mainloop_io = api->mainloop_io;
520
521 // Make sure no code with access to api can use these again
522 api->mainloop_io = NULL;
523 api->ipc = NULL;
524
525 mainloop_del_ipc_client(mainloop_io);
526 // After this point api might have already been freed
527 }
528 break;
529
532 {
533 crm_ipc_t *ipc = api->ipc;
534
535 // Make sure no code with access to api can use ipc again
536 api->ipc = NULL;
537
538 // This should always be the case already, but to be safe
539 api->free_on_disconnect = false;
540
541 crm_ipc_destroy(ipc);
542 ipc_post_disconnect(api);
543 }
544 break;
545 }
546}
547
560void
562 void *user_data)
563{
564 if (api == NULL) {
565 return;
566 }
567 api->cb = cb;
568 api->user_data = user_data;
569}
570
583int
585{
586 int rc;
587 xmlNode *reply = NULL;
589
590 if ((api == NULL) || (api->ipc == NULL) || (request == NULL)) {
591 return EINVAL;
592 }
593 crm_log_xml_trace(request, "ipc-sent");
594
595 // Synchronous dispatch requires waiting for a reply
597 && (api->cmds != NULL)
598 && (api->cmds->reply_expected != NULL)
599 && (api->cmds->reply_expected(api, request))) {
601 }
602
603 // The 0 here means a default timeout of 5 seconds
604 rc = crm_ipc_send(api->ipc, request, flags, 0, &reply);
605
606 if (rc < 0) {
607 return pcmk_legacy2rc(rc);
608 } else if (rc == 0) {
609 return ENODATA;
610 }
611
612 // With synchronous dispatch, we dispatch any reply now
613 if (reply != NULL) {
614 call_api_dispatch(api, reply);
615 free_xml(reply);
616 }
617 return pcmk_rc_ok;
618}
619
642static xmlNode *
643create_purge_node_request(pcmk_ipc_api_t *api, const char *node_name,
644 uint32_t nodeid)
645{
646 xmlNode *request = NULL;
647 const char *client = crm_system_name? crm_system_name : "client";
648
649 switch (api->server) {
650 case pcmk_ipc_attrd:
651 request = create_xml_node(NULL, __func__);
652 crm_xml_add(request, F_TYPE, T_ATTRD);
655 crm_xml_add(request, PCMK__XA_ATTR_NODE_NAME, node_name);
656 if (nodeid > 0) {
657 crm_xml_add_int(request, PCMK__XA_ATTR_NODE_ID, (int) nodeid);
658 }
659 break;
660
662 case pcmk_ipc_fenced:
664 request = create_request(CRM_OP_RM_NODE_CACHE, NULL, NULL,
665 pcmk_ipc_name(api, false), client, NULL);
666 if (nodeid > 0) {
667 crm_xml_set_id(request, "%lu", (unsigned long) nodeid);
668 }
669 crm_xml_add(request, XML_ATTR_UNAME, node_name);
670 break;
671
672 case pcmk_ipc_based:
673 case pcmk_ipc_execd:
675 break;
676 }
677 return request;
678}
679
691int
692pcmk_ipc_purge_node(pcmk_ipc_api_t *api, const char *node_name, uint32_t nodeid)
693{
694 int rc = 0;
695 xmlNode *request = NULL;
696
697 if (api == NULL) {
698 return EINVAL;
699 }
700 if ((node_name == NULL) && (nodeid == 0)) {
701 return EINVAL;
702 }
703
704 request = create_purge_node_request(api, node_name, nodeid);
705 if (request == NULL) {
706 return EOPNOTSUPP;
707 }
708 rc = pcmk__send_ipc_request(api, request);
709 free_xml(request);
710
711 crm_debug("%s peer cache purge of node %s[%lu]: rc=%d",
712 pcmk_ipc_name(api, true), node_name, (unsigned long) nodeid, rc);
713 return rc;
714}
715
716/*
717 * Generic IPC API (to eventually be deprecated as public API and made internal)
718 */
719
720struct crm_ipc_s {
721 struct pollfd pfd;
722 unsigned int max_buf_size; // maximum bytes we can send or receive over IPC
723 unsigned int buf_size; // size of allocated buffer
724 int msg_size;
725 int need_reply;
726 char *buffer;
727 char *server_name; // server IPC name being connected to
728 qb_ipcc_connection_t *ipc;
729};
730
744crm_ipc_t *
745crm_ipc_new(const char *name, size_t max_size)
746{
747 crm_ipc_t *client = NULL;
748
749 client = calloc(1, sizeof(crm_ipc_t));
750 if (client == NULL) {
751 crm_err("Could not create IPC connection: %s", strerror(errno));
752 return NULL;
753 }
754
755 client->server_name = strdup(name);
756 if (client->server_name == NULL) {
757 crm_err("Could not create %s IPC connection: %s",
758 name, strerror(errno));
759 free(client);
760 return NULL;
761 }
762 client->buf_size = pcmk__ipc_buffer_size(max_size);
763 client->buffer = malloc(client->buf_size);
764 if (client->buffer == NULL) {
765 crm_err("Could not create %s IPC connection: %s",
766 name, strerror(errno));
767 free(client->server_name);
768 free(client);
769 return NULL;
770 }
771
772 /* Clients initiating connection pick the max buf size */
773 client->max_buf_size = client->buf_size;
774
775 client->pfd.fd = -1;
776 client->pfd.events = POLLIN;
777 client->pfd.revents = 0;
778
779 return client;
780}
781
791bool
793{
794 uid_t cl_uid = 0;
795 gid_t cl_gid = 0;
796 pid_t found_pid = 0; uid_t found_uid = 0; gid_t found_gid = 0;
797 int rv;
798
799 client->need_reply = FALSE;
800 client->ipc = qb_ipcc_connect(client->server_name, client->buf_size);
801
802 if (client->ipc == NULL) {
803 crm_debug("Could not establish %s IPC connection: %s (%d)",
804 client->server_name, pcmk_strerror(errno), errno);
805 return FALSE;
806 }
807
808 client->pfd.fd = crm_ipc_get_fd(client);
809 if (client->pfd.fd < 0) {
810 rv = errno;
811 /* message already omitted */
812 crm_ipc_close(client);
813 errno = rv;
814 return FALSE;
815 }
816
817 rv = pcmk_daemon_user(&cl_uid, &cl_gid);
818 if (rv < 0) {
819 /* message already omitted */
820 crm_ipc_close(client);
821 errno = -rv;
822 return FALSE;
823 }
824
825 if ((rv = pcmk__crm_ipc_is_authentic_process(client->ipc, client->pfd.fd, cl_uid, cl_gid,
826 &found_pid, &found_uid,
827 &found_gid)) == pcmk_rc_ipc_unauthorized) {
828 crm_err("%s IPC provider authentication failed: process %lld has "
829 "uid %lld (expected %lld) and gid %lld (expected %lld)",
830 client->server_name,
831 (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
832 (long long) found_uid, (long long) cl_uid,
833 (long long) found_gid, (long long) cl_gid);
834 crm_ipc_close(client);
835 errno = ECONNABORTED;
836 return FALSE;
837
838 } else if (rv != pcmk_rc_ok) {
839 crm_perror(LOG_ERR, "Could not verify authenticity of %s IPC provider",
840 client->server_name);
841 crm_ipc_close(client);
842 if (rv > 0) {
843 errno = rv;
844 } else {
845 errno = ENOTCONN;
846 }
847 return FALSE;
848 }
849
850 qb_ipcc_context_set(client->ipc, client);
851
852 client->max_buf_size = qb_ipcc_get_buffer_size(client->ipc);
853 if (client->max_buf_size > client->buf_size) {
854 free(client->buffer);
855 client->buffer = calloc(1, client->max_buf_size);
856 client->buf_size = client->max_buf_size;
857 }
858 return TRUE;
859}
860
861void
863{
864 if (client) {
865 if (client->ipc) {
866 qb_ipcc_connection_t *ipc = client->ipc;
867
868 client->ipc = NULL;
869 qb_ipcc_disconnect(ipc);
870 }
871 }
872}
873
874void
876{
877 if (client) {
878 if (client->ipc && qb_ipcc_is_connected(client->ipc)) {
879 crm_notice("Destroying active %s IPC connection",
880 client->server_name);
881 /* The next line is basically unsafe
882 *
883 * If this connection was attached to mainloop and mainloop is active,
884 * the 'disconnected' callback will end up back here and we'll end
885 * up free'ing the memory twice - something that can still happen
886 * even without this if we destroy a connection and it closes before
887 * we call exit
888 */
889 /* crm_ipc_close(client); */
890 } else {
891 crm_trace("Destroying inactive %s IPC connection",
892 client->server_name);
893 }
894 free(client->buffer);
895 free(client->server_name);
896 free(client);
897 }
898}
899
900int
902{
903 int fd = 0;
904
905 if (client && client->ipc && (qb_ipcc_fd_get(client->ipc, &fd) == 0)) {
906 return fd;
907 }
908 errno = EINVAL;
909 crm_perror(LOG_ERR, "Could not obtain file descriptor for %s IPC",
910 (client? client->server_name : "unspecified"));
911 return -errno;
912}
913
914bool
916{
917 bool rc = FALSE;
918
919 if (client == NULL) {
920 crm_trace("No client");
921 return FALSE;
922
923 } else if (client->ipc == NULL) {
924 crm_trace("No connection");
925 return FALSE;
926
927 } else if (client->pfd.fd < 0) {
928 crm_trace("Bad descriptor");
929 return FALSE;
930 }
931
932 rc = qb_ipcc_is_connected(client->ipc);
933 if (rc == FALSE) {
934 client->pfd.fd = -EINVAL;
935 }
936 return rc;
937}
938
946int
948{
949 int rc;
950
951 CRM_ASSERT(client != NULL);
952
953 if (crm_ipc_connected(client) == FALSE) {
954 return -ENOTCONN;
955 }
956
957 client->pfd.revents = 0;
958 rc = poll(&(client->pfd), 1, 0);
959 return (rc < 0)? -errno : rc;
960}
961
962// \return Standard Pacemaker return code
963static int
964crm_ipc_decompress(crm_ipc_t * client)
965{
966 pcmk__ipc_header_t *header = (pcmk__ipc_header_t *)(void*)client->buffer;
967
968 if (header->size_compressed) {
969 int rc = 0;
970 unsigned int size_u = 1 + header->size_uncompressed;
971 /* never let buf size fall below our max size required for ipc reads. */
972 unsigned int new_buf_size = QB_MAX((sizeof(pcmk__ipc_header_t) + size_u), client->max_buf_size);
973 char *uncompressed = calloc(1, new_buf_size);
974
975 crm_trace("Decompressing message data %u bytes into %u bytes",
976 header->size_compressed, size_u);
977
978 rc = BZ2_bzBuffToBuffDecompress(uncompressed + sizeof(pcmk__ipc_header_t), &size_u,
979 client->buffer + sizeof(pcmk__ipc_header_t), header->size_compressed, 1, 0);
980
981 if (rc != BZ_OK) {
982 crm_err("Decompression failed: %s " CRM_XS " bzerror=%d",
983 bz2_strerror(rc), rc);
984 free(uncompressed);
985 return EILSEQ;
986 }
987
988 /*
989 * This assert no longer holds true. For an identical msg, some clients may
990 * require compression, and others may not. If that same msg (event) is sent
991 * to multiple clients, it could result in some clients receiving a compressed
992 * msg even though compression was not explicitly required for them.
993 *
994 * CRM_ASSERT((header->size_uncompressed + sizeof(pcmk__ipc_header_t)) >= ipc_buffer_max);
995 */
996 CRM_ASSERT(size_u == header->size_uncompressed);
997
998 memcpy(uncompressed, client->buffer, sizeof(pcmk__ipc_header_t)); /* Preserve the header */
999 header = (pcmk__ipc_header_t *)(void*)uncompressed;
1000
1001 free(client->buffer);
1002 client->buf_size = new_buf_size;
1003 client->buffer = uncompressed;
1004 }
1005
1006 CRM_ASSERT(client->buffer[sizeof(pcmk__ipc_header_t) + header->size_uncompressed - 1] == 0);
1007 return pcmk_rc_ok;
1008}
1009
1010long
1012{
1013 pcmk__ipc_header_t *header = NULL;
1014
1015 CRM_ASSERT(client != NULL);
1016 CRM_ASSERT(client->ipc != NULL);
1017 CRM_ASSERT(client->buffer != NULL);
1018
1019 client->buffer[0] = 0;
1020 client->msg_size = qb_ipcc_event_recv(client->ipc, client->buffer,
1021 client->buf_size, 0);
1022 if (client->msg_size >= 0) {
1023 int rc = crm_ipc_decompress(client);
1024
1025 if (rc != pcmk_rc_ok) {
1026 return pcmk_rc2legacy(rc);
1027 }
1028
1029 header = (pcmk__ipc_header_t *)(void*)client->buffer;
1030 if (!pcmk__valid_ipc_header(header)) {
1031 return -EBADMSG;
1032 }
1033
1034 crm_trace("Received %s IPC event %d size=%u rc=%d text='%.100s'",
1035 client->server_name, header->qb.id, header->qb.size,
1036 client->msg_size,
1037 client->buffer + sizeof(pcmk__ipc_header_t));
1038
1039 } else {
1040 crm_trace("No message received from %s IPC: %s",
1041 client->server_name, pcmk_strerror(client->msg_size));
1042 }
1043
1044 if (crm_ipc_connected(client) == FALSE || client->msg_size == -ENOTCONN) {
1045 crm_err("Connection to %s IPC failed", client->server_name);
1046 }
1047
1048 if (header) {
1049 /* Data excluding the header */
1050 return header->size_uncompressed;
1051 }
1052 return -ENOMSG;
1053}
1054
1055const char *
1057{
1058 CRM_ASSERT(client != NULL);
1059 return client->buffer + sizeof(pcmk__ipc_header_t);
1060}
1061
1062uint32_t
1064{
1065 pcmk__ipc_header_t *header = NULL;
1066
1067 CRM_ASSERT(client != NULL);
1068 if (client->buffer == NULL) {
1069 return 0;
1070 }
1071
1072 header = (pcmk__ipc_header_t *)(void*)client->buffer;
1073 return header->flags;
1074}
1075
1076const char *
1078{
1079 CRM_ASSERT(client != NULL);
1080 return client->server_name;
1081}
1082
1083// \return Standard Pacemaker return code
1084static int
1085internal_ipc_get_reply(crm_ipc_t *client, int request_id, int ms_timeout,
1086 ssize_t *bytes)
1087{
1088 time_t timeout = time(NULL) + 1 + (ms_timeout / 1000);
1089 int rc = pcmk_rc_ok;
1090
1091 /* get the reply */
1092 crm_trace("Waiting on reply to %s IPC message %d",
1093 client->server_name, request_id);
1094 do {
1095
1096 *bytes = qb_ipcc_recv(client->ipc, client->buffer, client->buf_size, 1000);
1097 if (*bytes > 0) {
1098 pcmk__ipc_header_t *hdr = NULL;
1099
1100 rc = crm_ipc_decompress(client);
1101 if (rc != pcmk_rc_ok) {
1102 return rc;
1103 }
1104
1105 hdr = (pcmk__ipc_header_t *)(void*)client->buffer;
1106 if (hdr->qb.id == request_id) {
1107 /* Got it */
1108 break;
1109 } else if (hdr->qb.id < request_id) {
1110 xmlNode *bad = string2xml(crm_ipc_buffer(client));
1111
1112 crm_err("Discarding old reply %d (need %d)", hdr->qb.id, request_id);
1113 crm_log_xml_notice(bad, "OldIpcReply");
1114
1115 } else {
1116 xmlNode *bad = string2xml(crm_ipc_buffer(client));
1117
1118 crm_err("Discarding newer reply %d (need %d)", hdr->qb.id, request_id);
1119 crm_log_xml_notice(bad, "ImpossibleReply");
1120 CRM_ASSERT(hdr->qb.id <= request_id);
1121 }
1122 } else if (crm_ipc_connected(client) == FALSE) {
1123 crm_err("%s IPC provider disconnected while waiting for message %d",
1124 client->server_name, request_id);
1125 break;
1126 }
1127
1128 } while (time(NULL) < timeout);
1129
1130 if (*bytes < 0) {
1131 rc = (int) -*bytes; // System errno
1132 }
1133 return rc;
1134}
1135
1149int
1150crm_ipc_send(crm_ipc_t * client, xmlNode * message, enum crm_ipc_flags flags, int32_t ms_timeout,
1151 xmlNode ** reply)
1152{
1153 int rc = 0;
1154 ssize_t qb_rc = 0;
1155 ssize_t bytes = 0;
1156 struct iovec *iov;
1157 static uint32_t id = 0;
1158 static int factor = 8;
1159 pcmk__ipc_header_t *header;
1160
1161 if (client == NULL) {
1162 crm_notice("Can't send IPC request without connection (bug?): %.100s",
1163 message);
1164 return -ENOTCONN;
1165
1166 } else if (crm_ipc_connected(client) == FALSE) {
1167 /* Don't even bother */
1168 crm_notice("Can't send %s IPC requests: Connection closed",
1169 client->server_name);
1170 return -ENOTCONN;
1171 }
1172
1173 if (ms_timeout == 0) {
1174 ms_timeout = 5000;
1175 }
1176
1177 if (client->need_reply) {
1178 qb_rc = qb_ipcc_recv(client->ipc, client->buffer, client->buf_size, ms_timeout);
1179 if (qb_rc < 0) {
1180 crm_warn("Sending %s IPC disabled until pending reply received",
1181 client->server_name);
1182 return -EALREADY;
1183
1184 } else {
1185 crm_notice("Sending %s IPC re-enabled after pending reply received",
1186 client->server_name);
1187 client->need_reply = FALSE;
1188 }
1189 }
1190
1191 id++;
1192 CRM_LOG_ASSERT(id != 0); /* Crude wrap-around detection */
1193 rc = pcmk__ipc_prepare_iov(id, message, client->max_buf_size, &iov, &bytes);
1194 if (rc != pcmk_rc_ok) {
1195 crm_warn("Couldn't prepare %s IPC request: %s " CRM_XS " rc=%d",
1196 client->server_name, pcmk_rc_str(rc), rc);
1197 return pcmk_rc2legacy(rc);
1198 }
1199
1200 header = iov[0].iov_base;
1201 pcmk__set_ipc_flags(header->flags, client->server_name, flags);
1202
1204 /* Don't look for a synchronous response */
1206 }
1207
1208 if(header->size_compressed) {
1209 if(factor < 10 && (client->max_buf_size / 10) < (bytes / factor)) {
1210 crm_notice("Compressed message exceeds %d0%% of configured IPC "
1211 "limit (%u bytes); consider setting PCMK_ipc_buffer to "
1212 "%u or higher",
1213 factor, client->max_buf_size, 2 * client->max_buf_size);
1214 factor++;
1215 }
1216 }
1217
1218 crm_trace("Sending %s IPC request %d of %u bytes using %dms timeout",
1219 client->server_name, header->qb.id, header->qb.size, ms_timeout);
1220
1221 if ((ms_timeout > 0) || !pcmk_is_set(flags, crm_ipc_client_response)) {
1222
1223 time_t timeout = time(NULL) + 1 + (ms_timeout / 1000);
1224
1225 do {
1226 /* @TODO Is this check really needed? Won't qb_ipcc_sendv() return
1227 * an error if it's not connected?
1228 */
1229 if (!crm_ipc_connected(client)) {
1230 goto send_cleanup;
1231 }
1232
1233 qb_rc = qb_ipcc_sendv(client->ipc, iov, 2);
1234 } while ((qb_rc == -EAGAIN) && (time(NULL) < timeout));
1235
1236 rc = (int) qb_rc; // Negative of system errno, or bytes sent
1237 if (qb_rc <= 0) {
1238 goto send_cleanup;
1239
1241 crm_trace("Not waiting for reply to %s IPC request %d",
1242 client->server_name, header->qb.id);
1243 goto send_cleanup;
1244 }
1245
1246 rc = internal_ipc_get_reply(client, header->qb.id, ms_timeout, &bytes);
1247 if (rc != pcmk_rc_ok) {
1248 /* We didn't get the reply in time, so disable future sends for now.
1249 * The only alternative would be to close the connection since we
1250 * don't know how to detect and discard out-of-sequence replies.
1251 *
1252 * @TODO Implement out-of-sequence detection
1253 */
1254 client->need_reply = TRUE;
1255 }
1256 rc = (int) bytes; // Negative system errno, or size of reply received
1257
1258 } else {
1259 // No timeout, and client response needed
1260 do {
1261 qb_rc = qb_ipcc_sendv_recv(client->ipc, iov, 2, client->buffer,
1262 client->buf_size, -1);
1263 } while ((qb_rc == -EAGAIN) && crm_ipc_connected(client));
1264 rc = (int) qb_rc; // Negative system errno, or size of reply received
1265 }
1266
1267 if (rc > 0) {
1268 pcmk__ipc_header_t *hdr = (pcmk__ipc_header_t *)(void*)client->buffer;
1269
1270 crm_trace("Received %d-byte reply %d to %s IPC %d: %.100s",
1271 rc, hdr->qb.id, client->server_name, header->qb.id,
1272 crm_ipc_buffer(client));
1273
1274 if (reply) {
1275 *reply = string2xml(crm_ipc_buffer(client));
1276 }
1277
1278 } else {
1279 crm_trace("No reply to %s IPC %d: rc=%d",
1280 client->server_name, header->qb.id, rc);
1281 }
1282
1283 send_cleanup:
1284 if (crm_ipc_connected(client) == FALSE) {
1285 crm_notice("Couldn't send %s IPC request %d: Connection closed "
1286 CRM_XS " rc=%d", client->server_name, header->qb.id, rc);
1287
1288 } else if (rc == -ETIMEDOUT) {
1289 crm_warn("%s IPC request %d failed: %s after %dms " CRM_XS " rc=%d",
1290 client->server_name, header->qb.id, pcmk_strerror(rc),
1291 ms_timeout, rc);
1292 crm_write_blackbox(0, NULL);
1293
1294 } else if (rc <= 0) {
1295 crm_warn("%s IPC request %d failed: %s " CRM_XS " rc=%d",
1296 client->server_name, header->qb.id,
1297 ((rc == 0)? "No bytes sent" : pcmk_strerror(rc)), rc);
1298 }
1299
1301 return rc;
1302}
1303
1304int
1305pcmk__crm_ipc_is_authentic_process(qb_ipcc_connection_t *qb_ipc, int sock, uid_t refuid, gid_t refgid,
1306 pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
1307{
1308 int ret = 0;
1309 pid_t found_pid = 0; uid_t found_uid = 0; gid_t found_gid = 0;
1310#if defined(US_AUTH_PEERCRED_UCRED)
1311 struct ucred ucred;
1312 socklen_t ucred_len = sizeof(ucred);
1313#endif
1314
1315#ifdef HAVE_QB_IPCC_AUTH_GET
1316 if (qb_ipc && !qb_ipcc_auth_get(qb_ipc, &found_pid, &found_uid, &found_gid)) {
1317 goto do_checks;
1318 }
1319#endif
1320
1321#if defined(US_AUTH_PEERCRED_UCRED)
1322 if (!getsockopt(sock, SOL_SOCKET, SO_PEERCRED,
1323 &ucred, &ucred_len)
1324 && ucred_len == sizeof(ucred)) {
1325 found_pid = ucred.pid; found_uid = ucred.uid; found_gid = ucred.gid;
1326
1327#elif defined(US_AUTH_PEERCRED_SOCKPEERCRED)
1328 struct sockpeercred sockpeercred;
1329 socklen_t sockpeercred_len = sizeof(sockpeercred);
1330
1331 if (!getsockopt(sock, SOL_SOCKET, SO_PEERCRED,
1332 &sockpeercred, &sockpeercred_len)
1333 && sockpeercred_len == sizeof(sockpeercred_len)) {
1334 found_pid = sockpeercred.pid;
1335 found_uid = sockpeercred.uid; found_gid = sockpeercred.gid;
1336
1337#elif defined(US_AUTH_GETPEEREID)
1338 if (!getpeereid(sock, &found_uid, &found_gid)) {
1339 found_pid = PCMK__SPECIAL_PID; /* cannot obtain PID (FreeBSD) */
1340
1341#elif defined(US_AUTH_GETPEERUCRED)
1342 ucred_t *ucred;
1343 if (!getpeerucred(sock, &ucred)) {
1344 errno = 0;
1345 found_pid = ucred_getpid(ucred);
1346 found_uid = ucred_geteuid(ucred); found_gid = ucred_getegid(ucred);
1347 ret = -errno;
1348 ucred_free(ucred);
1349 if (ret) {
1350 return (ret < 0) ? ret : -pcmk_err_generic;
1351 }
1352
1353#else
1354# error "No way to authenticate a Unix socket peer"
1355 errno = 0;
1356 if (0) {
1357#endif
1358#ifdef HAVE_QB_IPCC_AUTH_GET
1359 do_checks:
1360#endif
1361 if (gotpid != NULL) {
1362 *gotpid = found_pid;
1363 }
1364 if (gotuid != NULL) {
1365 *gotuid = found_uid;
1366 }
1367 if (gotgid != NULL) {
1368 *gotgid = found_gid;
1369 }
1370 if (found_uid == 0 || found_uid == refuid || found_gid == refgid) {
1371 ret = 0;
1372 } else {
1374 }
1375 } else {
1376 ret = (errno > 0) ? errno : pcmk_rc_error;
1377 }
1378 return ret;
1379}
1380
1381int
1382crm_ipc_is_authentic_process(int sock, uid_t refuid, gid_t refgid,
1383 pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
1384{
1385 int ret = pcmk__crm_ipc_is_authentic_process(NULL, sock, refuid, refgid,
1386 gotpid, gotuid, gotgid);
1387
1388 /* The old function had some very odd return codes*/
1389 if (ret == 0) {
1390 return 1;
1391 } else if (ret == pcmk_rc_ipc_unauthorized) {
1392 return 0;
1393 } else {
1394 return pcmk_rc2legacy(ret);
1395 }
1396}
1397
1398int
1400 gid_t refgid, pid_t *gotpid)
1401{
1402 static char last_asked_name[PATH_MAX / 2] = ""; /* log spam prevention */
1403 int fd;
1405 int auth_rc = 0;
1406 int32_t qb_rc;
1407 pid_t found_pid = 0; uid_t found_uid = 0; gid_t found_gid = 0;
1408 qb_ipcc_connection_t *c;
1409
1410 c = qb_ipcc_connect(name, 0);
1411 if (c == NULL) {
1412 crm_info("Could not connect to %s IPC: %s", name, strerror(errno));
1414 goto bail;
1415 }
1416
1417 qb_rc = qb_ipcc_fd_get(c, &fd);
1418 if (qb_rc != 0) {
1419 rc = (int) -qb_rc; // System errno
1420 crm_err("Could not get fd from %s IPC: %s " CRM_XS " rc=%d",
1421 name, pcmk_rc_str(rc), rc);
1422 goto bail;
1423 }
1424
1425 auth_rc = pcmk__crm_ipc_is_authentic_process(c, fd, refuid, refgid, &found_pid,
1426 &found_uid, &found_gid);
1427 if (auth_rc == pcmk_rc_ipc_unauthorized) {
1428 crm_err("Daemon (IPC %s) effectively blocked with unauthorized"
1429 " process %lld (uid: %lld, gid: %lld)",
1430 name, (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
1431 (long long) found_uid, (long long) found_gid);
1433 goto bail;
1434 }
1435
1436 if (auth_rc != pcmk_rc_ok) {
1437 rc = auth_rc;
1438 crm_err("Could not get peer credentials from %s IPC: %s "
1439 CRM_XS " rc=%d", name, pcmk_rc_str(rc), rc);
1440 goto bail;
1441 }
1442
1443 if (gotpid != NULL) {
1444 *gotpid = found_pid;
1445 }
1446
1447 rc = pcmk_rc_ok;
1448 if ((found_uid != refuid || found_gid != refgid)
1449 && strncmp(last_asked_name, name, sizeof(last_asked_name))) {
1450 if ((found_uid == 0) && (refuid != 0)) {
1451 crm_warn("Daemon (IPC %s) runs as root, whereas the expected"
1452 " credentials are %lld:%lld, hazard of violating"
1453 " the least privilege principle",
1454 name, (long long) refuid, (long long) refgid);
1455 } else {
1456 crm_notice("Daemon (IPC %s) runs as %lld:%lld, whereas the"
1457 " expected credentials are %lld:%lld, which may"
1458 " mean a different set of privileges than expected",
1459 name, (long long) found_uid, (long long) found_gid,
1460 (long long) refuid, (long long) refgid);
1461 }
1462 memccpy(last_asked_name, name, '\0', sizeof(last_asked_name));
1463 }
1464
1465bail:
1466 if (c != NULL) {
1467 qb_ipcc_disconnect(c);
1468 }
1469 return rc;
1470}
int pcmk__add_mainloop_ipc(crm_ipc_t *ipc, int priority, void *userdata, struct ipc_client_callbacks *callbacks, mainloop_io_t **source)
Connect to IPC and add it as a main loop source.
Definition mainloop.c:893
uint64_t flags
Definition remote.c:3
int pcmk_daemon_user(uid_t *uid, gid_t *gid)
Get user and group IDs of pacemaker daemon user.
Definition utils.c:169
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:114
A dumping ground.
#define CRM_SYSTEM_CRMD
Definition crm.h:106
#define CRM_SYSTEM_MCP
Definition crm.h:111
#define CRM_OP_RM_NODE_CACHE
Definition crm.h:159
char * crm_system_name
Definition utils.c:54
#define PCMK__XA_ATTR_NODE_NAME
#define PCMK__ATTRD_CMD_PEER_REMOVE
#define PCMK__XA_ATTR_NODE_ID
#define PCMK__XA_TASK
struct pcmk__ipc_header_s pcmk__ipc_header_t
G_GNUC_INTERNAL unsigned int pcmk__ipc_buffer_size(unsigned int max)
Definition ipc_common.c:31
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)
Definition ipc_common.c:81
G_GNUC_INTERNAL pcmk__ipc_methods_t * pcmk__controld_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.
Definition ipc.h:110
#define create_request(task, xml_data, host_to, sys_to, sys_from, uuid_from)
Definition ipc.h:42
crm_ipc_flags
Definition ipc.h:144
@ crm_ipc_flags_none
Definition ipc.h:145
@ crm_ipc_client_response
Definition ipc.h:150
@ crm_ipc_proxied
Definition ipc.h:149
void pcmk_free_ipc_event(struct iovec *event)
Free an I/O vector created by pcmk__ipc_prepare_iov()
Definition ipc_server.c:280
pcmk_ipc_event
Possible event types that an IPC event callback can be called for.
Definition ipc.h:79
@ pcmk_ipc_event_disconnect
Termination of IPC connection.
Definition ipc.h:81
pcmk_ipc_server
Available IPC interfaces.
Definition ipc.h:68
@ pcmk_ipc_schedulerd
Scheduler.
Definition ipc.h:75
@ pcmk_ipc_based
CIB manager.
Definition ipc.h:70
@ pcmk_ipc_execd
Executor.
Definition ipc.h:72
@ pcmk_ipc_pacemakerd
Launcher.
Definition ipc.h:74
@ pcmk_ipc_attrd
Attribute manager.
Definition ipc.h:69
@ pcmk_ipc_controld
Controller.
Definition ipc.h:71
@ pcmk_ipc_fenced
Fencer.
Definition ipc.h:73
pcmk_ipc_dispatch
How IPC replies should be dispatched.
Definition ipc.h:87
@ pcmk_ipc_dispatch_sync
Sending a command will wait for any reply.
Definition ipc.h:90
@ pcmk_ipc_dispatch_poll
Caller will poll and dispatch IPC.
Definition ipc.h:89
@ pcmk_ipc_dispatch_main
Attach IPC to GMainLoop for dispatch.
Definition ipc.h:88
struct crm_ipc_s crm_ipc_t
Definition ipc.h:162
void crm_ipc_destroy(crm_ipc_t *client)
Definition ipc_client.c:875
int crm_ipc_send(crm_ipc_t *client, xmlNode *message, enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
Send an IPC XML message.
void pcmk_disconnect_ipc(pcmk_ipc_api_t *api)
Disconnect an IPC API instance.
Definition ipc_client.c:511
const char * crm_ipc_name(crm_ipc_t *client)
int pcmk_connect_ipc(pcmk_ipc_api_t *api, enum pcmk_ipc_dispatch dispatch_type)
Connect to a Pacemaker daemon via IPC.
Definition ipc_client.c:452
int pcmk__send_ipc_request(pcmk_ipc_api_t *api, xmlNode *request)
Definition ipc_client.c:584
const char * pcmk_ipc_name(pcmk_ipc_api_t *api, bool for_log)
Get the IPC name used with an IPC API connection.
Definition ipc_client.c:241
long crm_ipc_read(crm_ipc_t *client)
int crm_ipc_get_fd(crm_ipc_t *client)
Definition ipc_client.c:901
int crm_ipc_ready(crm_ipc_t *client)
Check whether an IPC connection is ready to be read.
Definition ipc_client.c:947
void pcmk__call_ipc_callback(pcmk_ipc_api_t *api, enum pcmk_ipc_event event_type, crm_exit_t status, void *event_data)
Definition ipc_client.c:144
bool crm_ipc_connected(crm_ipc_t *client)
Definition ipc_client.c:915
bool crm_ipc_connect(crm_ipc_t *client)
Establish an IPC connection to a Pacemaker component.
Definition ipc_client.c:792
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)
Definition ipc_client.c:862
void pcmk_free_ipc_api(pcmk_ipc_api_t *api)
Free the contents of an IPC API object.
Definition ipc_client.c:200
int pcmk__ipc_is_authentic_process_active(const char *name, uid_t refuid, gid_t refgid, pid_t *gotpid)
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.
Definition ipc_client.c:47
int pcmk__crm_ipc_is_authentic_process(qb_ipcc_connection_t *qb_ipc, 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.
int pcmk_poll_ipc(pcmk_ipc_api_t *api, int timeout_ms)
Check whether an IPC connection has data available (without main loop)
Definition ipc_client.c:361
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.
Definition ipc_client.c:281
void pcmk_dispatch_ipc(pcmk_ipc_api_t *api)
Dispatch available messages on an IPC connection (without main loop)
Definition ipc_client.c:391
crm_ipc_t * crm_ipc_new(const char *name, size_t max_size)
Create a new (legacy) object for using Pacemaker daemon IPC.
Definition ipc_client.c:745
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.
Definition ipc_client.c:692
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.
Definition ipc_client.c:561
#define PCMK__SPECIAL_PID_AS_0(p)
#define pcmk__set_ipc_flags(ipc_flags, ipc_name, flags_to_set)
int pcmk__ipc_prepare_iov(uint32_t request, xmlNode *message, uint32_t max_send_size, struct iovec **result, ssize_t *bytes)
Definition ipc_server.c:586
#define PCMK__SPECIAL_PID
#define pcmk__clear_ipc_flags(ipc_flags, ipc_name, flags_to_clear)
#define crm_info(fmt, args...)
Definition logging.h:353
#define crm_warn(fmt, args...)
Definition logging.h:351
#define CRM_XS
Definition logging.h:54
#define CRM_LOG_ASSERT(expr)
Definition logging.h:202
#define crm_notice(fmt, args...)
Definition logging.h:352
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition logging.h:301
#define CRM_CHECK(expr, failure_action)
Definition logging.h:218
void crm_write_blackbox(int nsig, struct qb_log_callsite *callsite)
Definition logging.c:468
#define crm_debug(fmt, args...)
Definition logging.h:355
#define crm_err(fmt, args...)
Definition logging.h:350
#define crm_log_xml_trace(xml, text)
Definition logging.h:364
#define crm_trace(fmt, args...)
Definition logging.h:356
#define crm_log_xml_notice(xml, text)
Definition logging.h:361
struct mainloop_io_s mainloop_io_t
Definition mainloop.h:32
void mainloop_del_ipc_client(mainloop_io_t *client)
Definition mainloop.c:960
#define XML_ATTR_UNAME
Definition msg_xml.h:151
#define T_ATTRD
Definition msg_xml.h:79
#define F_ORIG
Definition msg_xml.h:51
#define F_TYPE
Definition msg_xml.h:63
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
Definition nvpair.c:432
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition nvpair.c:324
unsigned int timeout
Definition pcmk_fence.c:32
char * name
Definition pcmk_fence.c:31
int rc
Definition pcmk_fence.c:35
#define ENODATA
char * strerror(int errnum)
const char * bz2_strerror(int rc)
Definition results.c:726
const char * pcmk_strerror(int rc)
Definition results.c:58
#define pcmk_err_generic
Definition results.h:70
#define CRM_ASSERT(expr)
Definition results.h:42
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition results.c:420
@ CRM_EX_DISCONNECT
Definition results.h:248
@ pcmk_rc_ok
Definition results.h:142
@ pcmk_rc_ipc_unauthorized
Definition results.h:120
@ pcmk_rc_error
Definition results.h:138
@ pcmk_rc_ipc_unresponsive
Definition results.h:119
int pcmk_rc2legacy(int rc)
Definition results.c:437
int pcmk_legacy2rc(int legacy_rc)
Definition results.c:450
enum crm_exit_e crm_exit_t
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Dispatch function for an IPC connection used as mainloop source.
Definition mainloop.h:83
struct qb_ipc_response_header qb
void(* free_data)(void *api_data)
void(* post_disconnect)(pcmk_ipc_api_t *api)
void(* dispatch)(pcmk_ipc_api_t *api, xmlNode *msg)
bool(* reply_expected)(pcmk_ipc_api_t *api, xmlNode *request)
int(* post_connect)(pcmk_ipc_api_t *api)
enum pcmk_ipc_dispatch dispatch_type
mainloop_io_t * mainloop_io
pcmk__ipc_methods_t * cmds
pcmk_ipc_callback_t cb
enum pcmk_ipc_server server
void crm_xml_set_id(xmlNode *xml, const char *format,...) G_GNUC_PRINTF(2
xmlNode * string2xml(const char *input)
Definition xml.c:868
void free_xml(xmlNode *child)
Definition xml.c:823
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition xml.c:696