pacemaker  1.1.16-94ff4df
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules
plugin.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USAA
17  */
18 
19 #include <crm_internal.h>
20 #include <crm/cluster/internal.h>
21 #include <sys/types.h>
22 #include <sys/uio.h>
23 #include <sys/socket.h>
24 #include <sys/un.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <errno.h>
32 #include <signal.h>
33 #include <string.h>
34 
35 #include <corosync/totem/totempg.h>
36 #include <corosync/engine/objdb.h>
37 #include <corosync/engine/config.h>
38 
39 #include <config.h>
40 #include "plugin.h"
41 #include "utils.h"
42 
43 #include <glib.h>
44 
45 #include <sys/resource.h>
46 #include <sys/utsname.h>
47 #include <sys/socket.h>
48 #include <sys/wait.h>
49 #include <sys/stat.h>
50 #include <pthread.h>
51 #include <bzlib.h>
52 #include <pwd.h>
53 
54 struct corosync_api_v1 *pcmk_api = NULL;
55 
58 
59 int use_mgmtd = 0;
60 int plugin_log_level = LOG_DEBUG;
61 char *local_uname = NULL;
63 char *local_cname = NULL;
66 char *ipc_channel_name = NULL;
67 static uint64_t local_born_on = 0;
68 
69 uint64_t membership_seq = 0;
70 pthread_t pcmk_wait_thread;
71 
72 gboolean use_mcp = FALSE;
73 gboolean wait_active = TRUE;
74 gboolean have_reliable_membership_id = FALSE;
75 GHashTable *ipc_client_list = NULL;
76 GHashTable *membership_list = NULL;
77 GHashTable *membership_notify_list = NULL;
78 
79 #define MAX_RESPAWN 100
80 #define LOOPBACK_ID 16777343
81 #define crm_flag_none 0x00000000
82 #define crm_flag_members 0x00000001
83 
84 struct crm_identify_msg_s {
85  cs_ipc_header_request_t header __attribute__ ((aligned(8)));
86  uint32_t id;
87  uint32_t pid;
88  int32_t votes;
90  char uname[256];
91  char version[256];
92  uint64_t born_on;
93 } __attribute__ ((packed));
94 
95 /* *INDENT-OFF* */
96 static crm_child_t pcmk_children[] = {
97  { 0, crm_proc_none, crm_flag_none, 0, 0, FALSE, "none", NULL, NULL, NULL, NULL },
98  { 0, crm_proc_plugin, crm_flag_none, 0, 0, FALSE, "ais", NULL, NULL, NULL, NULL },
99  { 0, crm_proc_lrmd, crm_flag_none, 3, 0, TRUE, "lrmd", NULL, CRM_DAEMON_DIR"/lrmd", NULL, NULL },
100  { 0, crm_proc_cib, crm_flag_members, 1, 0, TRUE, "cib", CRM_DAEMON_USER, CRM_DAEMON_DIR"/cib", NULL, NULL },
101  { 0, crm_proc_crmd, crm_flag_members, 6, 0, TRUE, "crmd", CRM_DAEMON_USER, CRM_DAEMON_DIR"/crmd", NULL, NULL },
102  { 0, crm_proc_attrd, crm_flag_none, 4, 0, TRUE, "attrd", CRM_DAEMON_USER, CRM_DAEMON_DIR"/attrd", NULL, NULL },
103  { 0, crm_proc_stonithd, crm_flag_none, 0, 0, TRUE, "stonithd", NULL, "/bin/false", NULL, NULL },
104  { 0, crm_proc_pe, crm_flag_none, 5, 0, TRUE, "pengine", CRM_DAEMON_USER, CRM_DAEMON_DIR"/pengine", NULL, NULL },
105  { 0, crm_proc_mgmtd, crm_flag_none, 7, 0, TRUE, "mgmtd", NULL, HB_DAEMON_DIR"/mgmtd", NULL, NULL },
106  { 0, crm_proc_stonith_ng, crm_flag_members, 2, 0, TRUE, "stonith-ng", NULL, CRM_DAEMON_DIR"/stonithd", NULL, NULL },
107 };
108 /* *INDENT-ON* */
109 
110 void send_cluster_id(void);
111 int send_plugin_msg_raw(const AIS_Message * ais_msg);
113 gboolean check_message_sanity(const AIS_Message * msg, const char *data);
114 
115 typedef const void ais_void_ptr;
116 int pcmk_shutdown(void);
117 void pcmk_peer_update(enum totem_configuration_type configuration_type,
118  const unsigned int *member_list, size_t member_list_entries,
119  const unsigned int *left_list, size_t left_list_entries,
120  const unsigned int *joined_list, size_t joined_list_entries,
121  const struct memb_ring_id *ring_id);
122 
123 int pcmk_startup(struct corosync_api_v1 *corosync_api);
124 int pcmk_config_init(struct corosync_api_v1 *corosync_api);
125 
126 int pcmk_ipc_exit(void *conn);
127 int pcmk_ipc_connect(void *conn);
128 void pcmk_ipc(void *conn, ais_void_ptr * msg);
129 
130 void pcmk_exec_dump(void);
131 void pcmk_cluster_swab(void *msg);
132 void pcmk_cluster_callback(ais_void_ptr * message, unsigned int nodeid);
133 
134 void pcmk_nodeid(void *conn, ais_void_ptr * msg);
135 void pcmk_nodes(void *conn, ais_void_ptr * msg);
136 void pcmk_notify(void *conn, ais_void_ptr * msg);
137 void pcmk_remove_member(void *conn, ais_void_ptr * msg);
138 void pcmk_quorum(void *conn, ais_void_ptr * msg);
139 
140 void pcmk_cluster_id_swab(void *msg);
141 void pcmk_cluster_id_callback(ais_void_ptr * message, unsigned int nodeid);
142 void ais_remove_peer(char *node_id);
143 void ais_remove_peer_by_name(const char *node_name);
144 
145 static uint32_t
146 get_process_list(void)
147 {
148  int lpc = 0;
149  uint32_t procs = crm_proc_plugin;
150 
151  if (use_mcp) {
152  return 0;
153  }
154 
155  for (lpc = 0; lpc < SIZEOF(pcmk_children); lpc++) {
156  if (pcmk_children[lpc].pid != 0) {
157  procs |= pcmk_children[lpc].flag;
158  }
159  }
160  return procs;
161 }
162 
163 static struct corosync_lib_handler pcmk_lib_service[] = {
164  { /* 0 - crm_class_cluster */
165  .lib_handler_fn = pcmk_ipc,
166  .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED,
167  },
168  { /* 1 - crm_class_members */
169  .lib_handler_fn = pcmk_nodes,
170  .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED,
171  },
172  { /* 2 - crm_class_notify */
173  .lib_handler_fn = pcmk_notify,
174  .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED,
175  },
176  { /* 3 - crm_class_nodeid */
177  .lib_handler_fn = pcmk_nodeid,
178  .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED,
179  },
180  { /* 4 - crm_class_rmpeer */
181  .lib_handler_fn = pcmk_remove_member,
182  .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED,
183  },
184  { /* 5 - crm_class_quorum */
185  .lib_handler_fn = pcmk_quorum,
186  .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED,
187  },
188 };
189 
190 static struct corosync_exec_handler pcmk_exec_service[] = {
191  { /* 0 */
192  .exec_handler_fn = pcmk_cluster_callback,
193  .exec_endian_convert_fn = pcmk_cluster_swab},
194  { /* 1 */
195  .exec_handler_fn = pcmk_cluster_id_callback,
196  .exec_endian_convert_fn = pcmk_cluster_id_swab}
197 };
198 
199 /*
200  * Exports the interface for the service
201  */
202 /* *INDENT-OFF* */
203 struct corosync_service_engine pcmk_service_handler = {
204  .name = (char *)"Pacemaker Cluster Manager "PACEMAKER_VERSION,
205  .id = PCMK_SERVICE_ID,
206  .private_data_size = 0,
207  .flow_control = COROSYNC_LIB_FLOW_CONTROL_NOT_REQUIRED,
208  .allow_inquorate = CS_LIB_ALLOW_INQUORATE,
209  .lib_init_fn = pcmk_ipc_connect,
210  .lib_exit_fn = pcmk_ipc_exit,
211  .exec_init_fn = pcmk_startup,
212  .exec_exit_fn = pcmk_shutdown,
213  .config_init_fn = pcmk_config_init,
214  .priority = 50,
215  .lib_engine = pcmk_lib_service,
216  .lib_engine_count = sizeof (pcmk_lib_service) / sizeof (struct corosync_lib_handler),
217  .exec_engine = pcmk_exec_service,
218  .exec_engine_count = sizeof (pcmk_exec_service) / sizeof (struct corosync_exec_handler),
219  .confchg_fn = pcmk_peer_update,
220  .exec_dump_fn = pcmk_exec_dump,
221 /* void (*sync_init) (void); */
222 /* int (*sync_process) (void); */
223 /* void (*sync_activate) (void); */
224 /* void (*sync_abort) (void); */
225 };
226 
227 
228 /*
229  * Dynamic Loader definition
230  */
231 struct corosync_service_engine *pcmk_get_handler_ver0 (void);
232 
233 struct corosync_service_engine_iface_ver0 pcmk_service_handler_iface = {
234  .corosync_get_service_engine_ver0 = pcmk_get_handler_ver0
235 };
236 
237 static struct lcr_iface openais_pcmk_ver0[2] = {
238  {
239  .name = "pacemaker",
240  .version = 0,
241  .versions_replace = 0,
242  .versions_replace_count = 0,
243  .dependencies = 0,
244  .dependency_count = 0,
245  .constructor = NULL,
246  .destructor = NULL,
247  .interfaces = NULL
248  },
249  {
250  .name = "pacemaker",
251  .version = 1,
252  .versions_replace = 0,
253  .versions_replace_count = 0,
254  .dependencies = 0,
255  .dependency_count = 0,
256  .constructor = NULL,
257  .destructor = NULL,
258  .interfaces = NULL
259  }
260 };
261 
262 static struct lcr_comp pcmk_comp_ver0 = {
263  .iface_count = 2,
264  .ifaces = openais_pcmk_ver0
265 };
266 /* *INDENT-ON* */
267 
268 struct corosync_service_engine *
270 {
271  return (&pcmk_service_handler);
272 }
273 
274 __attribute__ ((constructor))
275 static void
276 register_this_component(void)
277 {
278  lcr_interfaces_set(&openais_pcmk_ver0[0], &pcmk_service_handler_iface);
279  lcr_interfaces_set(&openais_pcmk_ver0[1], &pcmk_service_handler_iface);
280 
281  lcr_component_register(&pcmk_comp_ver0);
282 }
283 
284 static int
285 plugin_has_quorum(void)
286 {
288  return 1;
289  }
290  return 0;
291 }
292 
293 static void
294 update_expected_votes(int value)
295 {
296  if (value < plugin_has_votes) {
297  /* Never drop below the number of connected nodes */
298  ais_info("Cannot update expected quorum votes %d -> %d:"
299  " value cannot be less that the current number of votes",
300  plugin_expected_votes, value);
301 
302  } else if (plugin_expected_votes != value) {
303  ais_info("Expected quorum votes %d -> %d", plugin_expected_votes, value);
304  plugin_expected_votes = value;
305  }
306 }
307 
308 /* Create our own local copy of the config so we can navigate it */
309 static void
310 process_ais_conf(void)
311 {
312  char *value = NULL;
313  gboolean any_log = FALSE;
314  hdb_handle_t top_handle = 0;
315  hdb_handle_t local_handle = 0;
316 
317  ais_info("Reading configure");
318  top_handle = config_find_init(pcmk_api, "logging");
319  local_handle = config_find_next(pcmk_api, "logging", top_handle);
320 
321  get_config_opt(pcmk_api, local_handle, "debug", &value, "on");
322  if (ais_get_boolean(value)) {
323  plugin_log_level = LOG_DEBUG;
324  pcmk_env.debug = "1";
325 
326  } else {
327  plugin_log_level = LOG_INFO;
328  pcmk_env.debug = "0";
329  }
330 
331  get_config_opt(pcmk_api, local_handle, "to_logfile", &value, "off");
332  if (ais_get_boolean(value)) {
333  get_config_opt(pcmk_api, local_handle, "logfile", &value, NULL);
334 
335  if (value == NULL) {
336  ais_err("Logging to a file requested but no log file specified");
337 
338  } else {
339  uid_t pcmk_uid = geteuid();
340  uid_t pcmk_gid = getegid();
341 
342  FILE *logfile = fopen(value, "a");
343 
344  if (logfile) {
345  int ignore = 0;
346  int logfd = fileno(logfile);
347 
348  pcmk_env.logfile = value;
349 
350  /* Ensure the file has the correct permissions */
351  ignore = fchown(logfd, pcmk_uid, pcmk_gid);
352  ignore = fchmod(logfd, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
353 
354  if (ignore < 0) {
355  fprintf(logfile, "Could not set r/w permissions for uid=%d, gid=%d on %s\n",
356  pcmk_uid, pcmk_gid, value);
357 
358  } else {
359  fprintf(logfile, "Set r/w permissions for uid=%d, gid=%d on %s\n",
360  pcmk_uid, pcmk_gid, value);
361  }
362  fflush(logfile);
363  fsync(logfd);
364  fclose(logfile);
365  any_log = TRUE;
366 
367  } else {
368  ais_err("Couldn't create logfile: %s", value);
369  }
370  }
371  }
372 
373  get_config_opt(pcmk_api, local_handle, "to_syslog", &value, "on");
374  if (any_log && ais_get_boolean(value) == FALSE) {
375  ais_info("User configured file based logging and explicitly disabled syslog.");
376  value = "none";
377 
378  } else {
379  if (ais_get_boolean(value) == FALSE) {
380  ais_err
381  ("Please enable some sort of logging, either 'to_file: on' or 'to_syslog: on'.");
382  ais_err("If you use file logging, be sure to also define a value for 'logfile'");
383  }
384  get_config_opt(pcmk_api, local_handle, "syslog_facility", &value, "daemon");
385  }
386  pcmk_env.syslog = value;
387 
388  config_find_done(pcmk_api, local_handle);
389 
390  top_handle = config_find_init(pcmk_api, "quorum");
391  local_handle = config_find_next(pcmk_api, "quorum", top_handle);
392  get_config_opt(pcmk_api, local_handle, "provider", &value, NULL);
393  if (value && ais_str_eq("quorum_cman", value)) {
394  pcmk_env.quorum = "cman";
395  } else {
396  pcmk_env.quorum = "pcmk";
397  }
398 
399  top_handle = config_find_init(pcmk_api, "service");
400  local_handle = config_find_next(pcmk_api, "service", top_handle);
401  while (local_handle) {
402  value = NULL;
403  pcmk_api->object_key_get(local_handle, "name", strlen("name"), (void **)&value, NULL);
404  if (ais_str_eq("pacemaker", value)) {
405  break;
406  }
407  local_handle = config_find_next(pcmk_api, "service", top_handle);
408  }
409 
410  get_config_opt(pcmk_api, local_handle, "ver", &value, "0");
411  if (ais_str_eq(value, "1")) {
412  ais_info("Enabling MCP mode: Use the Pacemaker init script to complete Pacemaker startup");
413  use_mcp = TRUE;
414  }
415 
416  get_config_opt(pcmk_api, local_handle, "clustername", &local_cname, "pcmk");
417  local_cname_len = strlen(local_cname);
418 
419  get_config_opt(pcmk_api, local_handle, "use_logd", &value, "no");
420  pcmk_env.use_logd = value;
421 
422  get_config_opt(pcmk_api, local_handle, "use_mgmtd", &value, "no");
423  if (ais_get_boolean(value) == FALSE) {
424  int lpc = 0;
425 
426  for (; lpc < SIZEOF(pcmk_children); lpc++) {
427  if (crm_proc_mgmtd & pcmk_children[lpc].flag) {
428  /* Disable mgmtd startup */
429  pcmk_children[lpc].start_seq = 0;
430  break;
431  }
432  }
433  }
434 
435  config_find_done(pcmk_api, local_handle);
436 }
437 
438 int
439 pcmk_config_init(struct corosync_api_v1 *unused)
440 {
441  return 0;
442 }
443 
444 static void *
445 pcmk_wait_dispatch(void *arg)
446 {
447  struct timespec waitsleep = {
448  .tv_sec = 1,
449  .tv_nsec = 0
450  };
451 
452  while (wait_active) {
453  int lpc = 0;
454 
455  for (; lpc < SIZEOF(pcmk_children); lpc++) {
456  if (pcmk_children[lpc].pid > 0) {
457  int status;
458  pid_t pid = wait4(pcmk_children[lpc].pid, &status, WNOHANG, NULL);
459 
460  if (pid == 0) {
461  continue;
462 
463  } else if (pid < 0) {
464  ais_perror("Call to wait4(%s) failed", pcmk_children[lpc].name);
465  continue;
466  }
467 
468  /* cleanup */
469  pcmk_children[lpc].pid = 0;
470  pcmk_children[lpc].conn = NULL;
471  pcmk_children[lpc].async_conn = NULL;
472 
473  if (WIFSIGNALED(status)) {
474  int sig = WTERMSIG(status);
475 
476  ais_err("Child process %s terminated with signal %d"
477  " (pid=%d, core=%s)",
478  pcmk_children[lpc].name, sig, pid,
479  WCOREDUMP(status) ? "true" : "false");
480 
481  } else if (WIFEXITED(status)) {
482  int rc = WEXITSTATUS(status);
483 
484  do_ais_log(rc == 0 ? LOG_NOTICE : LOG_ERR,
485  "Child process %s exited (pid=%d, rc=%d)", pcmk_children[lpc].name,
486  pid, rc);
487 
488  if (rc == 100) {
489  ais_notice("Child process %s no longer wishes"
490  " to be respawned", pcmk_children[lpc].name);
491  pcmk_children[lpc].respawn = FALSE;
492  }
493  }
494 
495  /* Broadcast the fact that one of our processes died
496  *
497  * Try to get some logging of the cause out first though
498  * because we're probably about to get fenced
499  *
500  * Potentially do this only if respawn_count > N
501  * to allow for local recovery
502  */
503  send_cluster_id();
504 
505  pcmk_children[lpc].respawn_count += 1;
506  if (pcmk_children[lpc].respawn_count > MAX_RESPAWN) {
507  ais_err("Child respawn count exceeded by %s", pcmk_children[lpc].name);
508  pcmk_children[lpc].respawn = FALSE;
509  }
510  if (pcmk_children[lpc].respawn) {
511  ais_notice("Respawning failed child process: %s", pcmk_children[lpc].name);
512  spawn_child(&(pcmk_children[lpc]));
513  }
514  send_cluster_id();
515  }
516  }
517  sched_yield();
518  nanosleep(&waitsleep, 0);
519  }
520  return 0;
521 }
522 
523 static uint32_t
524 pcmk_update_nodeid(void)
525 {
526  int last = local_nodeid;
527 
528  local_nodeid = pcmk_api->totem_nodeid_get();
529 
530  if (last != local_nodeid) {
531  if (last == 0) {
532  ais_info("Local node id: %u", local_nodeid);
533 
534  } else {
535  char *last_s = NULL;
536 
537  ais_malloc0(last_s, 32);
538  ais_warn("Detected local node id change: %u -> %u", last, local_nodeid);
539  snprintf(last_s, 31, "%u", last);
540  ais_remove_peer(last_s);
541  ais_free(last_s);
542  }
544  }
545 
546  return local_nodeid;
547 }
548 
549 static void
550 build_path(const char *path_c, mode_t mode)
551 {
552  int offset = 1, len = 0;
553  char *path = ais_strdup(path_c);
554 
555  AIS_CHECK(path != NULL, return);
556  for (len = strlen(path); offset < len; offset++) {
557  if (path[offset] == '/') {
558  path[offset] = 0;
559  if (mkdir(path, mode) < 0 && errno != EEXIST) {
560  ais_perror("Could not create directory '%s'", path);
561  break;
562  }
563  path[offset] = '/';
564  }
565  }
566  if (mkdir(path, mode) < 0 && errno != EEXIST) {
567  ais_perror("Could not create directory '%s'", path);
568  }
569  ais_free(path);
570 }
571 
572 int
573 pcmk_startup(struct corosync_api_v1 *init_with)
574 {
575  int rc = 0;
576  int lpc = 0;
577  int start_seq = 1;
578  struct utsname us;
579  struct rlimit cores;
580  static int max = SIZEOF(pcmk_children);
581 
582  uid_t pcmk_uid = 0;
583  gid_t pcmk_gid = 0;
584 
585  uid_t root_uid = -1;
586  uid_t cs_uid = geteuid();
587 
588  pcmk_user_lookup("root", &root_uid, NULL);
589 
590  pcmk_api = init_with;
591 
592  pcmk_env.debug = "0";
593  pcmk_env.logfile = NULL;
594  pcmk_env.use_logd = "false";
595  pcmk_env.syslog = "daemon";
596 
597  if (cs_uid != root_uid) {
598  ais_err("Corosync must be configured to start as 'root',"
599  " otherwise Pacemaker cannot manage services."
600  " Expected %d got %d", root_uid, cs_uid);
601  return -1;
602  }
603 
604  process_ais_conf();
605 
606  membership_list = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, destroy_ais_node);
607  membership_notify_list = g_hash_table_new(g_direct_hash, g_direct_equal);
608  ipc_client_list = g_hash_table_new(g_direct_hash, g_direct_equal);
609 
610  ais_info("CRM: Initialized");
611  log_printf(LOG_INFO, "Logging: Initialized %s\n", __FUNCTION__);
612 
613  rc = getrlimit(RLIMIT_CORE, &cores);
614  if (rc < 0) {
615  ais_perror("Cannot determine current maximum core size.");
616  } else {
617  if (cores.rlim_max == 0 && geteuid() == 0) {
618  cores.rlim_max = RLIM_INFINITY;
619  } else {
620  ais_info("Maximum core file size is: %lu", cores.rlim_max);
621  }
622  cores.rlim_cur = cores.rlim_max;
623 
624  rc = setrlimit(RLIMIT_CORE, &cores);
625  if (rc < 0) {
626  ais_perror("Core file generation will remain disabled."
627  " Core files are an important diagnositic tool,"
628  " please consider enabling them by default.");
629  }
630 #if 0
631  /* system() is not thread-safe, can't call from here
632  * Actually, its a pretty hacky way to try and achieve this anyway
633  */
634  if (system("echo 1 > /proc/sys/kernel/core_uses_pid") != 0) {
635  ais_perror("Could not enable /proc/sys/kernel/core_uses_pid");
636  }
637 #endif
638  }
639 
640  if (pcmk_user_lookup(CRM_DAEMON_USER, &pcmk_uid, &pcmk_gid) < 0) {
641  ais_err("Cluster user %s does not exist, aborting Pacemaker startup", CRM_DAEMON_USER);
642  return TRUE;
643  }
644 
645  rc = mkdir(CRM_STATE_DIR, 0750);
646  rc = chown(CRM_STATE_DIR, pcmk_uid, pcmk_gid);
647 
648  /* Used by stonithd */
649  build_path(HA_STATE_DIR "/heartbeat", 0755);
650 
651  /* Used by RAs - Leave owned by root */
652  build_path(CRM_RSCTMP_DIR, 0755);
653 
654  rc = uname(&us);
655  AIS_ASSERT(rc == 0);
656  local_uname = ais_strdup(us.nodename);
657  local_uname_len = strlen(local_uname);
658 
659  ais_info("Service: %d", PCMK_SERVICE_ID);
660  ais_info("Local hostname: %s", local_uname);
661  pcmk_update_nodeid();
662 
663  if (use_mcp == FALSE) {
664  pthread_create(&pcmk_wait_thread, NULL, pcmk_wait_dispatch, NULL);
665  for (start_seq = 1; start_seq < max; start_seq++) {
666  /* dont start anything with start_seq < 1 */
667  for (lpc = 0; lpc < max; lpc++) {
668  if (start_seq == pcmk_children[lpc].start_seq) {
669  spawn_child(&(pcmk_children[lpc]));
670  }
671  }
672  }
673  }
674  return 0;
675 }
676 
677 /*
678  static void ais_print_node(const char *prefix, struct totem_ip_address *host)
679  {
680  int len = 0;
681  char *buffer = NULL;
682 
683  ais_malloc0(buffer, INET6_ADDRSTRLEN+1);
684 
685  inet_ntop(host->family, host->addr, buffer, INET6_ADDRSTRLEN);
686 
687  len = strlen(buffer);
688  ais_info("%s: %.*s", prefix, len, buffer);
689  ais_free(buffer);
690  }
691 */
692 
693 #if 0
694 /* copied here for reference from exec/totempg.c */
695 char *
696 totempg_ifaces_print(unsigned int nodeid)
697 {
698  static char iface_string[256 * INTERFACE_MAX];
699  char one_iface[64];
700  struct totem_ip_address interfaces[INTERFACE_MAX];
701  char **status;
702  unsigned int iface_count;
703  unsigned int i;
704  int res;
705 
706  iface_string[0] = '\0';
707 
708  res = totempg_ifaces_get(nodeid, interfaces, &status, &iface_count);
709  if (res == -1) {
710  return ("no interface found for nodeid");
711  }
712 
713  for (i = 0; i < iface_count; i++) {
714  sprintf(one_iface, "r(%d) ip(%s), ", i, totemip_print(&interfaces[i]));
715  strcat(iface_string, one_iface);
716  }
717  return (iface_string);
718 }
719 #endif
720 
721 static void
722 ais_mark_unseen_peer_dead(gpointer key, gpointer value, gpointer user_data)
723 {
724  int *changed = user_data;
725  crm_node_t *node = value;
726 
727  if (node->last_seen != membership_seq && ais_str_eq(CRM_NODE_LOST, node->state) == FALSE) {
728  ais_info("Node %s was not seen in the previous transition", node->uname);
729  *changed += update_member(node->id, 0, membership_seq, node->votes,
730  node->processes, node->uname, CRM_NODE_LOST, NULL);
731  }
732 }
733 
734 void
735 pcmk_peer_update(enum totem_configuration_type configuration_type,
736  const unsigned int *member_list, size_t member_list_entries,
737  const unsigned int *left_list, size_t left_list_entries,
738  const unsigned int *joined_list, size_t joined_list_entries,
739  const struct memb_ring_id *ring_id)
740 {
741  int lpc = 0;
742  int changed = 0;
743  int do_update = 0;
744 
745  AIS_ASSERT(ring_id != NULL);
746  switch (configuration_type) {
747  case TOTEM_CONFIGURATION_REGULAR:
748  do_update = 1;
749  break;
750  case TOTEM_CONFIGURATION_TRANSITIONAL:
751  break;
752  }
753 
754  membership_seq = ring_id->seq;
755  ais_notice("%s membership event on ring %lld: memb=%ld, new=%ld, lost=%ld",
756  do_update ? "Stable" : "Transitional", ring_id->seq,
757  (long)member_list_entries, (long)joined_list_entries, (long)left_list_entries);
758 
759  if (do_update == 0) {
760  for (lpc = 0; lpc < joined_list_entries; lpc++) {
761  const char *prefix = "new: ";
762  uint32_t nodeid = joined_list[lpc];
763 
764  ais_info("%s %s %u", prefix, member_uname(nodeid), nodeid);
765  }
766  for (lpc = 0; lpc < member_list_entries; lpc++) {
767  const char *prefix = "memb:";
768  uint32_t nodeid = member_list[lpc];
769 
770  ais_info("%s %s %u", prefix, member_uname(nodeid), nodeid);
771  }
772  for (lpc = 0; lpc < left_list_entries; lpc++) {
773  const char *prefix = "lost:";
774  uint32_t nodeid = left_list[lpc];
775 
776  ais_info("%s %s %u", prefix, member_uname(nodeid), nodeid);
777  }
778  return;
779  }
780 
781  for (lpc = 0; lpc < joined_list_entries; lpc++) {
782  const char *prefix = "NEW: ";
783  uint32_t nodeid = joined_list[lpc];
784  crm_node_t *node = NULL;
785 
786  changed += update_member(nodeid, 0, membership_seq, -1, 0, NULL, CRM_NODE_MEMBER, NULL);
787 
788  ais_info("%s %s %u", prefix, member_uname(nodeid), nodeid);
789 
790  node = g_hash_table_lookup(membership_list, GUINT_TO_POINTER(nodeid));
791  if (node->addr == NULL) {
792  const char *addr = totempg_ifaces_print(nodeid);
793 
794  node->addr = ais_strdup(addr);
795  ais_debug("Node %u has address %s", nodeid, node->addr);
796  }
797  }
798 
799  for (lpc = 0; lpc < member_list_entries; lpc++) {
800  const char *prefix = "MEMB:";
801  uint32_t nodeid = member_list[lpc];
802 
803  changed += update_member(nodeid, 0, membership_seq, -1, 0, NULL, CRM_NODE_MEMBER, NULL);
804 
805  ais_info("%s %s %u", prefix, member_uname(nodeid), nodeid);
806  }
807 
808  for (lpc = 0; lpc < left_list_entries; lpc++) {
809  const char *prefix = "LOST:";
810  uint32_t nodeid = left_list[lpc];
811 
812  changed += update_member(nodeid, 0, membership_seq, -1, 0, NULL, CRM_NODE_LOST, NULL);
813  ais_info("%s %s %u", prefix, member_uname(nodeid), nodeid);
814  }
815 
816  if (changed && joined_list_entries == 0 && left_list_entries == 0) {
817  ais_err("Something strange happened: %d", changed);
818  changed = 0;
819  }
820 
821  ais_trace("Reaping unseen nodes...");
822  g_hash_table_foreach(membership_list, ais_mark_unseen_peer_dead, &changed);
823 
824  if (member_list_entries > 1) {
825  /* Used to set born-on in send_cluster_id())
826  * We need to wait until we have at least one peer since first
827  * membership id is based on the one before we stopped and isn't reliable
828  */
830  }
831 
832  if (changed) {
833  ais_debug("%d nodes changed", changed);
834  pcmk_update_nodeid();
836  }
837 
838  send_cluster_id();
839 }
840 
841 int
842 pcmk_ipc_exit(void *conn)
843 {
844  int lpc = 0;
845  const char *client = NULL;
846  void *async_conn = conn;
847 
848  for (; lpc < SIZEOF(pcmk_children); lpc++) {
849  if (pcmk_children[lpc].conn == conn) {
850  if (wait_active == FALSE) {
851  /* Make sure the shutdown loop exits */
852  pcmk_children[lpc].pid = 0;
853  }
854  pcmk_children[lpc].conn = NULL;
855  pcmk_children[lpc].async_conn = NULL;
856  client = pcmk_children[lpc].name;
857  break;
858  }
859  }
860 
861  g_hash_table_remove(membership_notify_list, async_conn);
862  g_hash_table_remove(ipc_client_list, async_conn);
863 
864  if (client) {
865  do_ais_log(LOG_INFO, "Client %s (conn=%p, async-conn=%p) left", client, conn, async_conn);
866  } else {
867  do_ais_log((LOG_DEBUG + 1), "Client %s (conn=%p, async-conn=%p) left",
868  "unknown-transient", conn, async_conn);
869  }
870 
871  return (0);
872 }
873 
874 int
875 pcmk_ipc_connect(void *conn)
876 {
877  /* Corosync hasn't finished setting up the connection at this point
878  * Sending messages now messes up the protocol!
879  */
880  return (0);
881 }
882 
883 /*
884  * Executive message handlers
885  */
886 void
888 {
889  AIS_Message *ais_msg = msg;
890 
891  ais_trace("Performing endian conversion...");
892  ais_msg->id = swab32(ais_msg->id);
893  ais_msg->size = swab32(ais_msg->size);
894  ais_msg->is_compressed = swab32(ais_msg->is_compressed);
895  ais_msg->compressed_size = swab32(ais_msg->compressed_size);
896 
897  ais_msg->host.id = swab32(ais_msg->host.id);
898  ais_msg->host.pid = swab32(ais_msg->host.pid);
899  ais_msg->host.type = swab32(ais_msg->host.type);
900  ais_msg->host.size = swab32(ais_msg->host.size);
901  ais_msg->host.local = swab32(ais_msg->host.local);
902 
903  ais_msg->sender.id = swab32(ais_msg->sender.id);
904  ais_msg->sender.pid = swab32(ais_msg->sender.pid);
905  ais_msg->sender.type = swab32(ais_msg->sender.type);
906  ais_msg->sender.size = swab32(ais_msg->sender.size);
907  ais_msg->sender.local = swab32(ais_msg->sender.local);
908 
909  ais_msg->header.size = swab32(ais_msg->header.size);
910  ais_msg->header.id = swab32(ais_msg->header.id);
911  ais_msg->header.error = swab32(ais_msg->header.error);
912 }
913 
914 void
915 pcmk_cluster_callback(ais_void_ptr * message, unsigned int nodeid)
916 {
917  const AIS_Message *ais_msg = message;
918 
919  ais_trace("Message from node %u (%s)", nodeid, nodeid == local_nodeid ? "local" : "remote");
920 /* Shouldn't be required...
921  update_member(
922  ais_msg->sender.id, membership_seq, -1, 0, ais_msg->sender.uname, NULL);
923 */
924 
925  if (ais_msg->host.size == 0 || ais_str_eq(ais_msg->host.uname, local_uname)) {
926  route_ais_message(ais_msg, FALSE);
927 
928  } else {
929  ais_trace("Discarding Msg[%d] (dest=%s:%s, from=%s:%s)",
930  ais_msg->id, ais_dest(&(ais_msg->host)),
931  msg_type2text(ais_msg->host.type),
932  ais_dest(&(ais_msg->sender)), msg_type2text(ais_msg->sender.type));
933  }
934 }
935 
936 void
938 {
939  struct crm_identify_msg_s *ais_msg = msg;
940 
941  ais_trace("Performing endian conversion...");
942  ais_msg->id = swab32(ais_msg->id);
943  ais_msg->pid = swab32(ais_msg->pid);
944  ais_msg->votes = swab32(ais_msg->votes);
945  ais_msg->processes = swab32(ais_msg->processes);
946  ais_msg->born_on = swab64(ais_msg->born_on);
947 
948  ais_msg->header.size = swab32(ais_msg->header.size);
949  ais_msg->header.id = swab32(ais_msg->header.id);
950 }
951 
952 void
953 pcmk_cluster_id_callback(ais_void_ptr * message, unsigned int nodeid)
954 {
955  int changed = 0;
956  const struct crm_identify_msg_s *msg = message;
957 
958  if (nodeid != msg->id) {
959  ais_err("Invalid message: Node %u claimed to be node %d", nodeid, msg->id);
960  return;
961  }
962  ais_debug("Node update: %s (%s)", msg->uname, msg->version);
963  changed =
964  update_member(nodeid, msg->born_on, membership_seq, msg->votes, msg->processes, msg->uname,
965  NULL, msg->version);
966 
967  if (changed) {
969  }
970 }
971 
972 struct res_overlay {
973  cs_ipc_header_response_t header __attribute((aligned(8)));
974  char buf[4096];
975 };
976 
977 struct res_overlay *res_overlay = NULL;
978 
979 static void
980 send_ipc_ack(void *conn)
981 {
982  if (res_overlay == NULL) {
983  ais_malloc0(res_overlay, sizeof(struct res_overlay));
984  }
985 
986  res_overlay->header.id = CRM_MESSAGE_IPC_ACK;
987  res_overlay->header.size = sizeof(cs_ipc_header_response_t);
988  res_overlay->header.error = CS_OK;
989  pcmk_api->ipc_response_send(conn, res_overlay, res_overlay->header.size);
990 }
991 
992 /* local callbacks */
993 void
994 pcmk_ipc(void *conn, ais_void_ptr * msg)
995 {
996  AIS_Message *mutable;
997  int type = 0;
998  gboolean transient = TRUE;
999  const AIS_Message *ais_msg = (const AIS_Message *)msg;
1000  void *async_conn = conn;
1001 
1002  ais_trace("Message from client %p", conn);
1003 
1004  if (check_message_sanity(msg, ((const AIS_Message *)msg)->data) == FALSE) {
1005  /* The message is corrupted - ignore */
1006  send_ipc_ack(conn);
1007  msg = NULL;
1008  return;
1009  }
1010 
1011  /* Make a copy of the message here and ACK it
1012  * The message is only valid until a response is sent
1013  * but the response must also be sent _before_ we send anything else
1014  */
1015 
1016  mutable = ais_msg_copy(ais_msg);
1017  AIS_ASSERT(check_message_sanity(mutable, mutable->data));
1018 
1019  type = mutable->sender.type;
1020  ais_trace
1021  ("type: %d local: %d conn: %p host type: %d ais: %d sender pid: %d child pid: %d size: %d",
1022  type, mutable->host.local, pcmk_children[type].conn, mutable->host.type, crm_msg_ais,
1023  mutable->sender.pid, pcmk_children[type].pid, ((int)SIZEOF(pcmk_children)));
1024 
1025  if (type > crm_msg_none && type < SIZEOF(pcmk_children)) {
1026  /* known child process */
1027  transient = FALSE;
1028  }
1029 #if 0
1030  /* If this check fails, the order of pcmk_children probably
1031  * doesn't match that of the crm_ais_msg_types enum
1032  */
1033  AIS_CHECK(transient || mutable->sender.pid == pcmk_children[type].pid,
1034  ais_err("Sender: %d, child[%d]: %d", mutable->sender.pid, type,
1035  pcmk_children[type].pid);
1036  ais_free(mutable);
1037  return);
1038 #endif
1039 
1040  if (transient == FALSE
1041  && type > crm_msg_none
1042  && mutable->host.local
1043  && pcmk_children[type].conn == NULL && mutable->host.type == crm_msg_ais) {
1044  AIS_CHECK(mutable->sender.type != mutable->sender.pid,
1045  ais_err("Pid=%d, type=%d", mutable->sender.pid, mutable->sender.type));
1046 
1047  ais_info("Recorded connection %p for %s/%d",
1048  conn, pcmk_children[type].name, pcmk_children[type].pid);
1049  pcmk_children[type].conn = conn;
1050  pcmk_children[type].async_conn = async_conn;
1051 
1052  /* Make sure they have the latest membership */
1053  if (pcmk_children[type].flags & crm_flag_members) {
1054  char *update = pcmk_generate_membership_data();
1055 
1056  g_hash_table_replace(membership_notify_list, async_conn, async_conn);
1057  ais_info("Sending membership update " U64T " to %s",
1058  membership_seq, pcmk_children[type].name);
1059  send_client_msg(async_conn, crm_class_members, crm_msg_none, update);
1060  }
1061 
1062  } else if (transient) {
1063  AIS_CHECK(mutable->sender.type == mutable->sender.pid,
1064  ais_err("Pid=%d, type=%d", mutable->sender.pid, mutable->sender.type));
1065  g_hash_table_replace(ipc_client_list, async_conn, GUINT_TO_POINTER(mutable->sender.pid));
1066  }
1067 
1068  mutable->sender.id = local_nodeid;
1069  mutable->sender.size = local_uname_len;
1070  memset(mutable->sender.uname, 0, MAX_NAME);
1071  memcpy(mutable->sender.uname, local_uname, mutable->sender.size);
1072 
1073  route_ais_message(mutable, TRUE);
1074  send_ipc_ack(conn);
1075  msg = NULL;
1076  ais_free(mutable);
1077 }
1078 
1079 int
1081 {
1082  int lpc = 0;
1083  static int phase = 0;
1084  static int max_wait = 0;
1085  static time_t next_log = 0;
1086  static int max = SIZEOF(pcmk_children);
1087 
1088  if (use_mcp) {
1089  if (pcmk_children[crm_msg_crmd].conn || pcmk_children[crm_msg_stonith_ng].conn) {
1090  time_t now = time(NULL);
1091 
1092  if (now > next_log) {
1093  next_log = now + 300;
1094  ais_notice
1095  ("Preventing Corosync shutdown. Please ensure Pacemaker is stopped first.");
1096  }
1097  return -1;
1098  }
1099  ais_notice("Unloading Pacemaker plugin");
1100  return 0;
1101  }
1102 
1103  if (phase == 0) {
1104  ais_notice("Shutting down Pacemaker");
1105  phase = max;
1106  }
1107 
1108  wait_active = FALSE; /* stop the wait loop */
1109 
1110  for (; phase > 0; phase--) {
1111  /* dont stop anything with start_seq < 1 */
1112 
1113  for (lpc = max - 1; lpc >= 0; lpc--) {
1114  if (phase != pcmk_children[lpc].start_seq) {
1115  continue;
1116  }
1117 
1118  if (pcmk_children[lpc].pid) {
1119  pid_t pid = 0;
1120  int status = 0;
1121  time_t now = time(NULL);
1122 
1123  if (pcmk_children[lpc].respawn) {
1124  max_wait = 5; /* 5 * 30s = 2.5 minutes... plenty once the crmd is gone */
1125  next_log = now + 30;
1126  pcmk_children[lpc].respawn = FALSE;
1127  stop_child(&(pcmk_children[lpc]), SIGTERM);
1128  }
1129 
1130  pid = wait4(pcmk_children[lpc].pid, &status, WNOHANG, NULL);
1131  if (pid < 0) {
1132  ais_perror("Call to wait4(%s/%d) failed - treating it as stopped",
1133  pcmk_children[lpc].name, pcmk_children[lpc].pid);
1134 
1135  } else if (pid == 0) {
1136  if (now >= next_log) {
1137  max_wait--;
1138  next_log = now + 30;
1139  ais_notice("Still waiting for %s (pid=%d, seq=%d) to terminate...",
1140  pcmk_children[lpc].name, pcmk_children[lpc].pid,
1141  pcmk_children[lpc].start_seq);
1142  if (max_wait <= 0 && phase < pcmk_children[crm_msg_crmd].start_seq) {
1143  ais_err("Child %s taking too long to terminate, sending SIGKILL",
1144  pcmk_children[lpc].name);
1145  stop_child(&(pcmk_children[lpc]), SIGKILL);
1146  }
1147  }
1148  /* Return control to corosync */
1149  return -1;
1150  }
1151  }
1152 
1153  /* cleanup */
1154  ais_notice("%s confirmed stopped", pcmk_children[lpc].name);
1155  pcmk_children[lpc].async_conn = NULL;
1156  pcmk_children[lpc].conn = NULL;
1157  pcmk_children[lpc].pid = 0;
1158  }
1159  }
1160 
1161  send_cluster_id();
1162  ais_notice("Shutdown complete");
1163  /* TODO: Add back the logsys flush call once its written */
1164 
1165  return 0;
1166 }
1167 
1168 struct member_loop_data {
1169  char *string;
1170 };
1171 
1172 static void
1173 member_vote_count_fn(gpointer key, gpointer value, gpointer user_data)
1174 {
1175  crm_node_t *node = value;
1176 
1177  if (ais_str_eq(CRM_NODE_MEMBER, node->state)) {
1178  plugin_has_votes += node->votes;
1179  }
1180 }
1181 
1182 void
1183 member_loop_fn(gpointer key, gpointer value, gpointer user_data)
1184 {
1185  crm_node_t *node = value;
1186  struct member_loop_data *data = user_data;
1187 
1188  ais_trace("Dumping node %u", node->id);
1189  data->string = append_member(data->string, node);
1190 }
1191 
1192 char *
1194 {
1195  int size = 0;
1196  struct member_loop_data data;
1197 
1198  size = 256;
1199  ais_malloc0(data.string, size);
1200 
1201  /* Ensure the list of active processes is up-to-date */
1202  update_member(local_nodeid, 0, 0, -1, get_process_list(), local_uname, CRM_NODE_MEMBER, NULL);
1203 
1204  plugin_has_votes = 0;
1205  g_hash_table_foreach(membership_list, member_vote_count_fn, NULL);
1207  update_expected_votes(plugin_has_votes);
1208  }
1209 
1210  snprintf(data.string, size,
1211  "<nodes id=\"" U64T "\" quorate=\"%s\" expected=\"%u\" actual=\"%u\">",
1212  membership_seq, plugin_has_quorum()? "true" : "false",
1214 
1215  g_hash_table_foreach(membership_list, member_loop_fn, &data);
1216  size = strlen(data.string);
1217  data.string = realloc_safe(data.string, size + 9); /* 9 = </nodes> + nul */
1218  sprintf(data.string + size, "</nodes>");
1219  return data.string;
1220 }
1221 
1222 void
1223 pcmk_nodes(void *conn, ais_void_ptr * msg)
1224 {
1226  void *async_conn = conn;
1227 
1228  /* send the ACK before we send any other messages
1229  * - but after we no longer need to access the message
1230  */
1231  send_ipc_ack(conn);
1232  msg = NULL;
1233 
1234  if (async_conn) {
1235  send_client_msg(async_conn, crm_class_members, crm_msg_none, data);
1236  }
1237  ais_free(data);
1238 }
1239 
1240 void
1241 pcmk_remove_member(void *conn, ais_void_ptr * msg)
1242 {
1243  const AIS_Message *ais_msg = msg;
1244  char *data = get_ais_data(ais_msg);
1245 
1246  send_ipc_ack(conn);
1247  msg = NULL;
1248 
1249  if (data != NULL) {
1250  char *bcast = ais_concat("remove-peer", data, ':');
1251 
1252  send_plugin_msg(crm_msg_ais, NULL, bcast);
1253  ais_info("Sent: %s", bcast);
1254  ais_free(bcast);
1255  }
1256 
1257  ais_free(data);
1258 }
1259 
1260 static void
1261 send_quorum_details(void *conn)
1262 {
1263  int size = 256;
1264  char *data = NULL;
1265 
1266  ais_malloc0(data, size);
1267 
1268  snprintf(data, size, "<quorum id=\"" U64T "\" quorate=\"%s\" expected=\"%u\" actual=\"%u\"/>",
1269  membership_seq, plugin_has_quorum()? "true" : "false",
1271 
1273  ais_free(data);
1274 }
1275 
1276 void
1277 pcmk_quorum(void *conn, ais_void_ptr * msg)
1278 {
1279  char *dummy = NULL;
1280  const AIS_Message *ais_msg = msg;
1281  char *data = get_ais_data(ais_msg);
1282 
1283  send_ipc_ack(conn);
1284  msg = NULL;
1285 
1286  /* Make sure the current number of votes is accurate */
1288  ais_free(dummy);
1289 
1290  /* Calls without data just want the current quorum details */
1291  if (data != NULL && strlen(data) > 0) {
1292  int value = ais_get_int(data, NULL);
1293 
1294  update_expected_votes(value);
1295  }
1296 
1297  send_quorum_details(conn);
1298  ais_free(data);
1299 }
1300 
1301 void
1302 pcmk_notify(void *conn, ais_void_ptr * msg)
1303 {
1304  const AIS_Message *ais_msg = msg;
1305  char *data = get_ais_data(ais_msg);
1306  void *async_conn = conn;
1307 
1308  int enable = 0;
1309  int sender = ais_msg->sender.pid;
1310 
1311  send_ipc_ack(conn);
1312  msg = NULL;
1313 
1314  if (ais_str_eq("true", data)) {
1315  enable = 1;
1316  }
1317 
1318  ais_info("%s node notifications for child %d (%p)",
1319  enable ? "Enabling" : "Disabling", sender, async_conn);
1320  if (enable) {
1321  g_hash_table_replace(membership_notify_list, async_conn, async_conn);
1322  } else {
1323  g_hash_table_remove(membership_notify_list, async_conn);
1324  }
1325  ais_free(data);
1326 }
1327 
1328 void
1329 pcmk_nodeid(void *conn, ais_void_ptr * msg)
1330 {
1331  static int counter = 0;
1332  struct crm_ais_nodeid_resp_s resp;
1333 
1334  ais_trace("Sending local nodeid: %d to %p[%d]", local_nodeid, conn, counter);
1335 
1336  resp.header.id = crm_class_nodeid;
1337  resp.header.size = sizeof(struct crm_ais_nodeid_resp_s);
1338  resp.header.error = CS_OK;
1339  resp.id = local_nodeid;
1340  resp.counter = counter++;
1341  memset(resp.uname, 0, MAX_NAME);
1342  memcpy(resp.uname, local_uname, local_uname_len);
1343  memset(resp.cname, 0, MAX_NAME);
1344  memcpy(resp.cname, local_cname, local_cname_len);
1345 
1346  pcmk_api->ipc_response_send(conn, &resp, resp.header.size);
1347 }
1348 
1349 static gboolean
1350 ghash_send_update(gpointer key, gpointer value, gpointer data)
1351 {
1352  if (send_client_msg(value, crm_class_members, crm_msg_none, data) != 0) {
1353  /* remove it */
1354  return TRUE;
1355  }
1356  return FALSE;
1357 }
1358 
1359 void
1361 {
1362  char *update = pcmk_generate_membership_data();
1363 
1364  ais_info("Sending membership update " U64T " to %d children",
1365  membership_seq, g_hash_table_size(membership_notify_list));
1366 
1367  g_hash_table_foreach_remove(membership_notify_list, ghash_send_update, update);
1368  ais_free(update);
1369 }
1370 
1371 gboolean
1372 check_message_sanity(const AIS_Message * msg, const char *data)
1373 {
1374  gboolean sane = TRUE;
1375  gboolean repaired = FALSE;
1376  int dest = msg->host.type;
1377  int tmp_size = msg->header.size - sizeof(AIS_Message);
1378 
1379  if (sane && msg->header.size == 0) {
1380  ais_err("Message with no size");
1381  sane = FALSE;
1382  }
1383 
1384  if (sane && msg->header.error != CS_OK) {
1385  ais_err("Message header contains an error: %d", msg->header.error);
1386  sane = FALSE;
1387  }
1388 
1389  AIS_CHECK(msg->header.size > sizeof(AIS_Message),
1390  ais_err("Message %d size too small: %d < %llu",
1391  msg->header.id, msg->header.size,
1392  (unsigned long long) sizeof(AIS_Message));
1393  return FALSE);
1394 
1395  if (sane && ais_data_len(msg) != tmp_size) {
1396  ais_warn("Message payload size is incorrect: expected %d, got %d", ais_data_len(msg),
1397  tmp_size);
1398  sane = TRUE;
1399  }
1400 
1401  if (sane && ais_data_len(msg) == 0) {
1402  ais_err("Message with no payload");
1403  sane = FALSE;
1404  }
1405 
1406  if (sane && data && msg->is_compressed == FALSE) {
1407  int str_size = strlen(data) + 1;
1408 
1409  if (ais_data_len(msg) != str_size) {
1410  int lpc = 0;
1411 
1412  ais_err("Message payload is corrupted: expected %d bytes, got %d",
1413  ais_data_len(msg), str_size);
1414  sane = FALSE;
1415  for (lpc = (str_size - 10); lpc < msg->size; lpc++) {
1416  if (lpc < 0) {
1417  lpc = 0;
1418  }
1419  ais_trace("bad_data[%d]: %d / '%c'", lpc, data[lpc], data[lpc]);
1420  }
1421  }
1422  }
1423 
1424  if (sane == FALSE) {
1425  AIS_CHECK(sane,
1426  ais_err
1427  ("Invalid message %d: (dest=%s:%s, from=%s:%s.%d, compressed=%d, size=%d, total=%d)",
1428  msg->id, ais_dest(&(msg->host)), msg_type2text(dest), ais_dest(&(msg->sender)),
1429  msg_type2text(msg->sender.type), msg->sender.pid, msg->is_compressed,
1430  ais_data_len(msg), msg->header.size));
1431 
1432  } else if (repaired) {
1433  ais_err
1434  ("Repaired message %d: (dest=%s:%s, from=%s:%s.%d, compressed=%d, size=%d, total=%d)",
1435  msg->id, ais_dest(&(msg->host)), msg_type2text(dest), ais_dest(&(msg->sender)),
1436  msg_type2text(msg->sender.type), msg->sender.pid, msg->is_compressed,
1437  ais_data_len(msg), msg->header.size);
1438  } else {
1439  ais_trace
1440  ("Verified message %d: (dest=%s:%s, from=%s:%s.%d, compressed=%d, size=%d, total=%d)",
1441  msg->id, ais_dest(&(msg->host)), msg_type2text(dest), ais_dest(&(msg->sender)),
1442  msg_type2text(msg->sender.type), msg->sender.pid, msg->is_compressed,
1443  ais_data_len(msg), msg->header.size);
1444  }
1445  return sane;
1446 }
1447 
1448 static int delivered_transient = 0;
1449 static void
1450 deliver_transient_msg(gpointer key, gpointer value, gpointer user_data)
1451 {
1452  int pid = GPOINTER_TO_INT(value);
1453  AIS_Message *mutable = user_data;
1454 
1455  if (pid == mutable->host.type) {
1456  int rc = send_client_ipc(key, mutable);
1457 
1458  delivered_transient++;
1459 
1460  ais_info("Sent message to %s.%d (rc=%d)", ais_dest(&(mutable->host)), pid, rc);
1461  if (rc != 0) {
1462  ais_warn("Sending message to %s.%d failed (rc=%d)",
1463  ais_dest(&(mutable->host)), pid, rc);
1464  log_ais_message(LOG_DEBUG, mutable);
1465  }
1466  }
1467 }
1468 
1469 gboolean
1470 route_ais_message(const AIS_Message * msg, gboolean local_origin)
1471 {
1472  int rc = 0;
1473  int dest = msg->host.type;
1474  const char *reason = "unknown";
1475  AIS_Message *mutable = ais_msg_copy(msg);
1476  static int service_id = SERVICE_ID_MAKE(PCMK_SERVICE_ID, 0);
1477 
1478  ais_trace("Msg[%d] (dest=%s:%s, from=%s:%s.%d, remote=%s, size=%d)",
1479  mutable->id, ais_dest(&(mutable->host)), msg_type2text(dest),
1480  ais_dest(&(mutable->sender)), msg_type2text(mutable->sender.type),
1481  mutable->sender.pid, local_origin ? "false" : "true", ais_data_len((mutable)));
1482 
1483  if (local_origin == FALSE) {
1484  if (mutable->host.size == 0 || ais_str_eq(local_uname, mutable->host.uname)) {
1485  mutable->host.local = TRUE;
1486  }
1487  }
1488 
1489  if (check_message_sanity(mutable, mutable->data) == FALSE) {
1490  /* Don't send this message to anyone */
1491  rc = 1;
1492  goto bail;
1493  }
1494 
1495  if (mutable->host.local) {
1496  void *conn = NULL;
1497  const char *lookup = NULL;
1498  int children_index = 0;
1499 
1500  if (dest == crm_msg_ais) {
1501  process_ais_message(mutable);
1502  goto bail;
1503 
1504  } else if (dest == crm_msg_lrmd) {
1505  /* lrmd messages are routed via the crm */
1506  dest = crm_msg_crmd;
1507 
1508  } else if (dest == crm_msg_te) {
1509  /* te messages are routed via the crm */
1510  dest = crm_msg_crmd;
1511 
1512  } else if (dest >= SIZEOF(pcmk_children)) {
1513  /* Transient client */
1514 
1515  delivered_transient = 0;
1516  g_hash_table_foreach(ipc_client_list, deliver_transient_msg, mutable);
1517  if (delivered_transient) {
1518  ais_trace("Sent message to %d transient clients: %d", delivered_transient, dest);
1519  goto bail;
1520 
1521  } else {
1522  /* try the crmd */
1523  ais_trace("Sending message to transient client %d via crmd", dest);
1524  dest = crm_msg_crmd;
1525  }
1526 
1527  } else if (dest == 0) {
1528  ais_err("Invalid destination: %d", dest);
1529  log_ais_message(LOG_ERR, mutable);
1530  log_printf(LOG_ERR, "%s", get_ais_data(mutable));
1531  rc = 1;
1532  goto bail;
1533  }
1534 
1535  lookup = msg_type2text(dest);
1536 
1537  if (dest == crm_msg_pe && ais_str_eq(pcmk_children[7].name, lookup)) {
1538  children_index = 7;
1539 
1540  } else {
1541  children_index = dest;
1542  }
1543 
1544  conn = pcmk_children[children_index].async_conn;
1545 
1546  if (mutable->header.id == service_id) {
1547  mutable->header.id = 0; /* reset this back to zero for IPC messages */
1548 
1549  } else if (mutable->header.id != 0) {
1550  ais_err("reset header id back to zero from %d", mutable->header.id);
1551  mutable->header.id = 0; /* reset this back to zero for IPC messages */
1552  }
1553 
1554  reason = "ipc delivery failed";
1555  rc = send_client_ipc(conn, mutable);
1556 
1557  } else if (local_origin) {
1558  /* forward to other hosts */
1559  ais_trace("Forwarding to cluster");
1560  reason = "cluster delivery failed";
1561  rc = send_plugin_msg_raw(mutable);
1562  }
1563 
1564  if (rc != 0) {
1565  ais_warn("Sending message to %s.%s failed: %s (rc=%d)",
1566  ais_dest(&(mutable->host)), msg_type2text(dest), reason, rc);
1567  log_ais_message(LOG_DEBUG, mutable);
1568  }
1569 
1570  bail:
1571  ais_free(mutable);
1572  return rc == 0 ? TRUE : FALSE;
1573 }
1574 
1575 int
1577 {
1578  int rc = 0;
1579  struct iovec iovec;
1580  static uint32_t msg_id = 0;
1581  AIS_Message *mutable = ais_msg_copy(ais_msg);
1582 
1583  AIS_ASSERT(local_nodeid != 0);
1584  AIS_ASSERT(ais_msg->header.size == (sizeof(AIS_Message) + ais_data_len(ais_msg)));
1585 
1586  if (mutable->id == 0) {
1587  msg_id++;
1588  AIS_CHECK(msg_id != 0 /* detect wrap-around */ ,
1589  msg_id++; ais_err("Message ID wrapped around"));
1590  mutable->id = msg_id;
1591  }
1592 
1593  mutable->header.error = CS_OK;
1594  mutable->header.id = SERVICE_ID_MAKE(PCMK_SERVICE_ID, 0);
1595 
1596  mutable->sender.id = local_nodeid;
1597  mutable->sender.size = local_uname_len;
1598  memset(mutable->sender.uname, 0, MAX_NAME);
1599  memcpy(mutable->sender.uname, local_uname, mutable->sender.size);
1600 
1601  iovec.iov_base = (char *)mutable;
1602  iovec.iov_len = mutable->header.size;
1603 
1604  ais_trace("Sending message (size=%u)", (unsigned int)iovec.iov_len);
1605  rc = pcmk_api->totem_mcast(&iovec, 1, TOTEMPG_SAFE);
1606 
1607  if (rc == 0 && mutable->is_compressed == FALSE) {
1608  ais_trace("Message sent: %.80s", mutable->data);
1609  }
1610 
1611  AIS_CHECK(rc == 0, ais_err("Message not sent (%d): %.120s", rc, mutable->data));
1612 
1613  ais_free(mutable);
1614  return rc;
1615 }
1616 
1617 #define min(x,y) (x)<(y)?(x):(y)
1618 
1619 void
1621 {
1622  int rc = 0;
1623  int len = 0;
1624  time_t now = time(NULL);
1625  struct iovec iovec;
1626  struct crm_identify_msg_s *msg = NULL;
1627 
1628  static time_t started = 0;
1629  static uint64_t first_seq = 0;
1630 
1631  AIS_ASSERT(local_nodeid != 0);
1632 
1633  if (started == 0) {
1634  started = now;
1635  first_seq = membership_seq;
1636  }
1637 
1638  if (local_born_on == 0) {
1639  if (started + 15 < now) {
1640  ais_debug("Born-on set to: " U64T " (age)", first_seq);
1641  local_born_on = first_seq;
1642 
1643  } else if (have_reliable_membership_id) {
1644  ais_debug("Born-on set to: " U64T " (peer)", membership_seq);
1645  local_born_on = membership_seq;
1646 
1647  } else {
1648  ais_debug("Leaving born-on unset: " U64T, membership_seq);
1649  }
1650  }
1651 
1652  ais_malloc0(msg, sizeof(struct crm_identify_msg_s));
1653  msg->header.size = sizeof(struct crm_identify_msg_s);
1654 
1655  msg->id = local_nodeid;
1656  /* msg->header.error = CS_OK; */
1657  msg->header.id = SERVICE_ID_MAKE(PCMK_SERVICE_ID, 1);
1658 
1659  len = min(local_uname_len, MAX_NAME - 1);
1660  memset(msg->uname, 0, MAX_NAME);
1661  memcpy(msg->uname, local_uname, len);
1662 
1663  len = min(strlen(VERSION), MAX_NAME - 1);
1664  memset(msg->version, 0, MAX_NAME);
1665  memcpy(msg->version, VERSION, len);
1666 
1667  msg->votes = 1;
1668  msg->pid = getpid();
1669  msg->processes = get_process_list();
1670  msg->born_on = local_born_on;
1671 
1672  ais_debug("Local update: id=%u, born=" U64T ", seq=" U64T "",
1673  local_nodeid, local_born_on, membership_seq);
1674  update_member(local_nodeid, local_born_on, membership_seq, msg->votes, msg->processes, NULL,
1675  NULL, VERSION);
1676 
1677  iovec.iov_base = (char *)msg;
1678  iovec.iov_len = msg->header.size;
1679 
1680  rc = pcmk_api->totem_mcast(&iovec, 1, TOTEMPG_SAFE);
1681 
1682  AIS_CHECK(rc == 0, ais_err("Message not sent (%d)", rc));
1683 
1684  ais_free(msg);
1685 }
1686 
1687 static gboolean
1688 ghash_send_removal(gpointer key, gpointer value, gpointer data)
1689 {
1690  send_quorum_details(value);
1691  if (send_client_msg(value, crm_class_rmpeer, crm_msg_none, data) != 0) {
1692  /* remove it */
1693  return TRUE;
1694  }
1695  return FALSE;
1696 }
1697 
1698 void
1699 ais_remove_peer(char *node_id)
1700 {
1701  uint32_t id = ais_get_int(node_id, NULL);
1702  crm_node_t *node = g_hash_table_lookup(membership_list, GUINT_TO_POINTER(id));
1703 
1704  if (node == NULL) {
1705  ais_info("Peer %u is unknown", id);
1706 
1707  } else if (ais_str_eq(CRM_NODE_MEMBER, node->state)) {
1708  ais_warn("Peer %u/%s is still active", id, node->uname);
1709 
1710  } else if (g_hash_table_remove(membership_list, GUINT_TO_POINTER(id))) {
1712  ais_notice("Removed dead peer %u from the membership list", id);
1713  ais_info("Sending removal of %u to %d children",
1714  id, g_hash_table_size(membership_notify_list));
1715 
1716  g_hash_table_foreach_remove(membership_notify_list, ghash_send_removal, node_id);
1717 
1718  } else {
1719  ais_warn("Peer %u/%s was not removed", id, node->uname);
1720  }
1721 }
1722 
1723 void
1724 ais_remove_peer_by_name(const char *node_name)
1725 {
1726  GHashTableIter iter;
1727  gpointer key = 0;
1728  crm_node_t *node = NULL;
1729  GList *node_list = NULL;
1730 
1731  g_hash_table_iter_init(&iter, membership_list);
1732 
1733  while (g_hash_table_iter_next(&iter, &key, (void **)&node)) {
1734  if (ais_str_eq(node_name, node->uname)) {
1735  uint32_t node_id = GPOINTER_TO_UINT(key);
1736  char *node_id_s = NULL;
1737 
1738  ais_malloc0(node_id_s, 32);
1739  snprintf(node_id_s, 31, "%u", node_id);
1740  node_list = g_list_append(node_list, node_id_s);
1741  }
1742  }
1743 
1744  if (node_list) {
1745  GList *gIter = NULL;
1746 
1747  for (gIter = node_list; gIter != NULL; gIter = gIter->next) {
1748  char *node_id_s = gIter->data;
1749 
1750  ais_remove_peer(node_id_s);
1751  }
1752  g_list_free_full(node_list, free);
1753 
1754  } else {
1755  ais_warn("Peer %s is unkown", node_name);
1756  }
1757 }
1758 
1759 gboolean
1761 {
1762  int len = ais_data_len(msg);
1763  char *data = get_ais_data(msg);
1764 
1765  do_ais_log(LOG_DEBUG,
1766  "Msg[%d] (dest=%s:%s, from=%s:%s.%d, remote=%s, size=%d): %.90s",
1767  msg->id, ais_dest(&(msg->host)), msg_type2text(msg->host.type),
1768  ais_dest(&(msg->sender)), msg_type2text(msg->sender.type),
1769  msg->sender.pid,
1770  msg->sender.uname == local_uname ? "false" : "true", ais_data_len(msg), data);
1771 
1772  if (data && len > 12 && strncmp("remove-peer:", data, 12) == 0) {
1773  char *node = data + 12;
1774 
1776  }
1777 
1778  ais_free(data);
1779  return TRUE;
1780 }
1781 
1782 static void
1783 member_dump_fn(gpointer key, gpointer value, gpointer user_data)
1784 {
1785  crm_node_t *node = value;
1786 
1787  ais_info(" node id:%u, uname=%s state=%s processes=%.16x born=" U64T " seen=" U64T
1788  " addr=%s version=%s", node->id, node->uname ? node->uname : "-unknown-", node->state,
1789  node->processes, node->born, node->last_seen, node->addr ? node->addr : "-unknown-",
1790  node->version ? node->version : "-unknown-");
1791 }
1792 
1793 void
1795 {
1796  /* Called after SIG_USR2 */
1797  process_ais_conf();
1798  ais_info("Local id: %u, uname: %s, born: " U64T, local_nodeid, local_uname, local_born_on);
1799  ais_info("Membership id: " U64T ", quorate: %s, expected: %u, actual: %u",
1800  membership_seq, plugin_has_quorum()? "true" : "false",
1802 
1803  g_hash_table_foreach(membership_list, member_dump_fn, NULL);
1804 }
enum crm_ais_msg_types type
Definition: internal.h:39
#define CRM_RSCTMP_DIR
Definition: config.h:59
uint32_t local_nodeid
Definition: plugin.c:65
#define CRM_NODE_LOST
Definition: cluster.h:43
gboolean is_compressed
Definition: internal.h:48
GHashTable * membership_notify_list
Definition: plugin.c:77
uint32_t size
Definition: internal.h:53
gboolean route_ais_message(const AIS_Message *msg, gboolean local_origin)
Definition: plugin.c:1470
hdb_handle_t config_find_init(struct corosync_api_v1 *config, char *name)
Definition: utils.c:620
#define SIZEOF(a)
Definition: utils.h:65
int pcmk_user_lookup(const char *name, uid_t *uid, gid_t *gid)
Definition: utils.c:755
uint32_t plugin_expected_votes
Definition: plugin.c:57
void pcmk_nodeid(void *conn, ais_void_ptr *msg)
Definition: plugin.c:1329
void pcmk_notify(void *conn, ais_void_ptr *msg)
Definition: plugin.c:1302
uint32_t id
Definition: cluster.h:73
void pcmk_cluster_callback(ais_void_ptr *message, unsigned int nodeid)
Definition: plugin.c:915
long long ais_get_int(const char *text, char **end_text)
Definition: utils.c:712
void log_ais_message(int level, const AIS_Message *msg)
Definition: utils.c:43
uint64_t born
Definition: cluster.h:74
#define ais_notice(fmt, args...)
Definition: utils.h:163
void config_find_done(struct corosync_api_v1 *config, hdb_handle_t local_handle)
Definition: utils.c:652
uint32_t id
Definition: plugin.c:79
uint32_t size
Definition: internal.h:52
char uname[256]
Definition: plugin.c:83
int32_t votes
Definition: plugin.c:81
struct corosync_service_engine * pcmk_get_handler_ver0(void)
Definition: plugin.c:269
char * local_cname
Definition: plugin.c:63
uint32_t id
Definition: internal.h:36
#define VERSION
Definition: config.h:644
void * async_conn
Definition: utils.h:78
pthread_t pcmk_wait_thread
Definition: plugin.c:70
#define AIS_ASSERT(expr)
Definition: utils.h:183
void pcmk_quorum(void *conn, ais_void_ptr *msg)
Definition: plugin.c:1277
char * addr
Definition: cluster.h:87
void ais_remove_peer_by_name(const char *node_name)
Definition: plugin.c:1724
#define ais_perror(fmt, args...)
Definition: utils.h:156
void pcmk_exec_dump(void)
Definition: plugin.c:1794
void pcmk_cluster_id_callback(ais_void_ptr *message, unsigned int nodeid)
Definition: plugin.c:953
void pcmk_nodes(void *conn, ais_void_ptr *msg)
Definition: plugin.c:1223
#define HB_DAEMON_DIR
Definition: config.h:484
#define ais_info(fmt, args...)
Definition: utils.h:164
const char * use_logd
Definition: utils.h:235
#define ais_trace(fmt, args...)
Definition: utils.h:166
struct res_overlay __attribute__
void ais_remove_peer(char *node_id)
Definition: plugin.c:1699
AIS_Host sender
Definition: internal.h:53
int pcmk_config_init(struct corosync_api_v1 *corosync_api)
Definition: plugin.c:439
#define PACEMAKER_VERSION
Definition: config.h:527
#define ais_malloc0(malloc_obj, length)
Definition: utils.h:168
char uname[MAX_NAME]
Definition: internal.h:64
char version[256]
Definition: plugin.c:84
int start_seq
Definition: utils.h:71
gboolean have_reliable_membership_id
Definition: plugin.c:74
#define PCMK_SERVICE_ID
Definition: config.h:554
struct pcmk_env_s pcmk_env
Definition: utils.c:40
int ais_get_boolean(const char *value)
Definition: utils.c:697
int update_member(unsigned int id, uint64_t born, uint64_t seq, int32_t votes, uint32_t procs, const char *uname, const char *state, const char *version)
Definition: utils.c:295
void send_member_notification(void)
Definition: plugin.c:1360
uint32_t processes
Definition: cluster.h:79
int pid
Definition: utils.h:68
struct corosync_api_v1 * pcmk_api
Definition: plugin.c:54
#define ais_free(obj)
Definition: utils.h:176
#define ais_err(fmt, args...)
Definition: utils.h:161
int pcmk_ipc_connect(void *conn)
Definition: plugin.c:875
struct res_overlay * res_overlay
Definition: plugin.c:977
struct corosync_service_engine pcmk_service_handler
Definition: plugin.c:203
int get_config_opt(struct corosync_api_v1 *config, hdb_handle_t object_service_handle, char *key, char **value, const char *fallback)
Definition: utils.c:660
#define CRM_DAEMON_DIR
Definition: config.h:41
int local_cname_len
Definition: plugin.c:64
const void ais_void_ptr
Definition: plugin.c:115
int use_mgmtd
Definition: plugin.c:59
gboolean local
Definition: internal.h:38
#define CRM_MESSAGE_IPC_ACK
Definition: internal.h:26
void send_cluster_id(void)
Definition: plugin.c:1620
int plugin_log_level
Definition: plugin.c:60
int send_plugin_msg(enum crm_ais_msg_types type, const char *host, const char *data)
Definition: utils.c:479
const char * name
Definition: utils.h:74
AIS_Host sender
Definition: internal.h:51
gboolean stop_child(crm_child_t *child, int signal)
Definition: utils.c:252
int respawn_count
Definition: utils.h:72
uint32_t id
Definition: internal.h:47
const char * member_uname(uint32_t id)
Definition: utils.c:374
#define AIS_CHECK(expr, failure_action)
Definition: utils.h:188
#define HA_STATE_DIR
Definition: config.h:481
struct crm_ais_msg_s AIS_Message
Definition: internal.h:33
uint32_t processes
Definition: plugin.c:82
#define ais_data_len(msg)
Definition: internal.h:210
uint32_t size
Definition: internal.h:40
uint32_t pid
Definition: plugin.c:80
struct qb_ipc_response_header cs_ipc_header_response_t
Definition: crm_internal.h:293
#define CRM_NODE_MEMBER
Definition: cluster.h:44
#define CRM_DAEMON_USER
Definition: config.h:47
const char * syslog
Definition: utils.h:233
void member_loop_fn(gpointer key, gpointer value, gpointer user_data)
Definition: plugin.c:1183
void pcmk_peer_update(enum totem_configuration_type configuration_type, const unsigned int *member_list, size_t member_list_entries, const unsigned int *left_list, size_t left_list_entries, const unsigned int *joined_list, size_t joined_list_entries, const struct memb_ring_id *ring_id)
Definition: plugin.c:735
long flag
Definition: utils.h:69
gboolean use_mcp
Definition: plugin.c:72
uint32_t compressed_size
Definition: internal.h:54
char * pcmk_generate_membership_data(void)
Definition: plugin.c:1193
uint32_t counter
Definition: internal.h:50
uint32_t plugin_has_votes
Definition: plugin.c:56
#define ais_debug(fmt, args...)
Definition: utils.h:165
#define MAX_NAME
Definition: crm.h:42
char * ais_concat(const char *prefix, const char *suffix, char join)
Definition: utils.c:604
char * version
Definition: cluster.h:88
void * conn
Definition: utils.h:77
int pcmk_shutdown(void)
Definition: plugin.c:1080
#define crm_flag_members
Definition: plugin.c:82
hdb_handle_t config_find_next(struct corosync_api_v1 *config, char *name, hdb_handle_t top_handle)
Definition: utils.c:633
#define do_ais_log(level, fmt, args...)
Definition: utils.h:144
void destroy_ais_node(gpointer data)
Definition: utils.c:282
#define crm_flag_none
Definition: plugin.c:81
char * local_uname
Definition: plugin.c:61
struct corosync_service_engine_iface_ver0 pcmk_service_handler_iface
Definition: plugin.c:233
gboolean check_message_sanity(const AIS_Message *msg, const char *data)
Definition: plugin.c:1372
#define min(x, y)
Definition: plugin.c:1617
#define INTERFACE_MAX
Definition: internal.h:29
int send_plugin_msg_raw(const AIS_Message *ais_msg)
Definition: plugin.c:1576
char * get_ais_data(const AIS_Message *msg)
Definition: utils.c:454
char cname[MAX_NAME]
Definition: internal.h:65
void pcmk_remove_member(void *conn, ais_void_ptr *msg)
Definition: plugin.c:1241
gboolean wait_active
Definition: plugin.c:73
void pcmk_cluster_id_swab(void *msg)
Definition: plugin.c:937
uint64_t membership_seq
Definition: plugin.c:69
#define ais_warn(fmt, args...)
Definition: utils.h:162
char uname[MAX_NAME]
Definition: internal.h:41
gboolean spawn_child(crm_child_t *child)
Definition: utils.c:136
#define uint32_t
Definition: stdint.in.h:158
#define MAX_RESPAWN
Definition: plugin.c:79
char data[0]
Definition: internal.h:58
void pcmk_ipc(void *conn, ais_void_ptr *msg)
Definition: plugin.c:994
char * state
Definition: cluster.h:84
const char * quorum
Definition: utils.h:236
char * append_member(char *data, crm_node_t *node)
Definition: utils.c:388
#define CRM_STATE_DIR
Definition: config.h:62
uint64_t born_on
Definition: plugin.c:85
#define U64T
Definition: config.h:635
int32_t votes
Definition: cluster.h:78
gboolean process_ais_message(const AIS_Message *msg)
Definition: plugin.c:1760
int send_client_msg(void *conn, enum crm_ais_msg_class class, enum crm_ais_msg_types type, const char *data)
Definition: utils.c:550
uint32_t pid
Definition: internal.h:37
int send_client_ipc(void *conn, const AIS_Message *ais_msg)
Definition: utils.c:527
char * uname
Definition: cluster.h:82
uint64_t last_seen
Definition: cluster.h:75
void pcmk_cluster_swab(void *msg)
Definition: plugin.c:887
int pcmk_startup(struct corosync_api_v1 *corosync_api)
Definition: plugin.c:573
AIS_Host host
Definition: internal.h:50
GHashTable * membership_list
Definition: plugin.c:76
const char * logfile
Definition: utils.h:234
char * ipc_channel_name
Definition: plugin.c:66
int pcmk_ipc_exit(void *conn)
Definition: plugin.c:842
uint64_t flags
Definition: remote.c:121
gboolean respawn
Definition: utils.h:73
enum crm_ais_msg_types type
Definition: internal.h:51
const char * debug
Definition: utils.h:232
#define int32_t
Definition: stdint.in.h:157
GHashTable * ipc_client_list
Definition: plugin.c:75
struct qb_ipc_request_header cs_ipc_header_request_t
Definition: crm_internal.h:292
int local_uname_len
Definition: plugin.c:62