diff --git a/exec/main.c b/exec/main.c index ba8e06e1..61bcd3d9 100644 --- a/exec/main.c +++ b/exec/main.c @@ -1,1424 +1,1424 @@ /* * Copyright (c) 2002-2006 MontaVista Software, Inc. * Copyright (c) 2006-2012 Red Hat, Inc. * * All rights reserved. * * Author: Steven Dake (sdake@redhat.com) * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the MontaVista Software, Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ /** * \mainpage Corosync * * This is the doxygen generated developer documentation for the Corosync * project. For more information about Corosync, please see the project * web site, corosync.org. * * \section license License * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the MontaVista Software, Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "quorum.h" #include "totemsrp.h" #include "logconfig.h" #include "totemconfig.h" #include "main.h" #include "sync.h" #include "timer.h" #include "util.h" #include "apidef.h" #include "service.h" #include "schedwrk.h" #ifdef HAVE_SMALL_MEMORY_FOOTPRINT #define IPC_LOGSYS_SIZE 1024*64 #else #define IPC_LOGSYS_SIZE 8192*128 #endif LOGSYS_DECLARE_SYSTEM ("corosync", LOGSYS_MODE_OUTPUT_STDERR | LOGSYS_MODE_OUTPUT_SYSLOG, LOG_DAEMON, LOG_INFO); LOGSYS_DECLARE_SUBSYS ("MAIN"); #define SERVER_BACKLOG 5 static int sched_priority = 0; static unsigned int service_count = 32; static struct totem_logging_configuration totem_logging_configuration; static struct corosync_api_v1 *api = NULL; static int sync_in_process = 1; static qb_loop_t *corosync_poll_handle; struct sched_param global_sched_param; static corosync_timer_handle_t corosync_stats_timer_handle; static const char *corosync_lock_file = LOCALSTATEDIR"/run/corosync.pid"; static int ip_version = AF_INET; qb_loop_t *cs_poll_handle_get (void) { return (corosync_poll_handle); } int cs_poll_dispatch_add (qb_loop_t * handle, int fd, int events, void *data, int (*dispatch_fn) (int fd, int revents, void *data)) { return qb_loop_poll_add(handle, QB_LOOP_MED, fd, events, data, dispatch_fn); } int cs_poll_dispatch_delete(qb_loop_t * handle, int fd) { return qb_loop_poll_del(handle, fd); } void corosync_state_dump (void) { int i; for (i = 0; i < SERVICES_COUNT_MAX; i++) { if (corosync_service[i] && corosync_service[i]->exec_dump_fn) { corosync_service[i]->exec_dump_fn (); } } } static void corosync_blackbox_write_to_file (void) { char fname[PATH_MAX]; char fdata_fname[PATH_MAX]; char time_str[PATH_MAX]; struct tm cur_time_tm; time_t cur_time_t; ssize_t res; cur_time_t = time(NULL); localtime_r(&cur_time_t, &cur_time_tm); strftime(time_str, PATH_MAX, "%Y-%m-%dT%H:%M:%S", &cur_time_tm); snprintf(fname, PATH_MAX, "%s/fdata-%s-%lld", get_run_dir(), time_str, (long long int)getpid()); if ((res = qb_log_blackbox_write_to_file(fname)) < 0) { LOGSYS_PERROR(-res, LOGSYS_LEVEL_ERROR, "Can't store blackbox file"); } snprintf(fdata_fname, sizeof(fdata_fname), "%s/fdata", get_run_dir()); unlink(fdata_fname); if (symlink(fname, fdata_fname) == -1) { log_printf(LOGSYS_LEVEL_ERROR, "Can't create symlink to '%s' for corosync blackbox file '%s'", fname, fdata_fname); } } static void unlink_all_completed (void) { api->timer_delete (corosync_stats_timer_handle); qb_loop_stop (corosync_poll_handle); icmap_fini(); } void corosync_shutdown_request (void) { corosync_service_unlink_all (api, unlink_all_completed); } static int32_t sig_diag_handler (int num, void *data) { corosync_state_dump (); return 0; } static int32_t sig_exit_handler (int num, void *data) { log_printf(LOGSYS_LEVEL_NOTICE, "Node was shut down by a signal"); corosync_service_unlink_all (api, unlink_all_completed); return 0; } static void sigsegv_handler (int num) { (void)signal (SIGSEGV, SIG_DFL); corosync_blackbox_write_to_file (); qb_log_fini(); raise (SIGSEGV); } /* * QB wrapper for real signal handler */ static int32_t sig_segv_handler (int num, void *data) { sigsegv_handler(num); return 0; } static void sigabrt_handler (int num) { (void)signal (SIGABRT, SIG_DFL); corosync_blackbox_write_to_file (); qb_log_fini(); raise (SIGABRT); } /* * QB wrapper for real signal handler */ static int32_t sig_abrt_handler (int num, void *data) { sigabrt_handler(num); return 0; } #define LOCALHOST_IP inet_addr("127.0.0.1") static void *corosync_group_handle; static struct totempg_group corosync_group = { .group = "a", .group_len = 1 }; static void serialize_lock (void) { } static void serialize_unlock (void) { } static void corosync_sync_completed (void) { log_printf (LOGSYS_LEVEL_NOTICE, "Completed service synchronization, ready to provide service."); sync_in_process = 0; cs_ipcs_sync_state_changed(sync_in_process); cs_ipc_allow_connections(1); /* * Inform totem to start using new message queue again */ totempg_trans_ack(); } static int corosync_sync_callbacks_retrieve ( int service_id, struct sync_callbacks *callbacks) { if (corosync_service[service_id] == NULL) { return (-1); } if (callbacks == NULL) { return (0); } callbacks->name = corosync_service[service_id]->name; callbacks->sync_init = corosync_service[service_id]->sync_init; callbacks->sync_process = corosync_service[service_id]->sync_process; callbacks->sync_activate = corosync_service[service_id]->sync_activate; callbacks->sync_abort = corosync_service[service_id]->sync_abort; return (0); } static struct memb_ring_id corosync_ring_id; static void member_object_joined (unsigned int nodeid) { char member_ip[ICMAP_KEYNAME_MAXLEN]; char member_join_count[ICMAP_KEYNAME_MAXLEN]; char member_status[ICMAP_KEYNAME_MAXLEN]; snprintf(member_ip, ICMAP_KEYNAME_MAXLEN, "runtime.totem.pg.mrp.srp.members.%u.ip", nodeid); snprintf(member_join_count, ICMAP_KEYNAME_MAXLEN, "runtime.totem.pg.mrp.srp.members.%u.join_count", nodeid); snprintf(member_status, ICMAP_KEYNAME_MAXLEN, "runtime.totem.pg.mrp.srp.members.%u.status", nodeid); if (icmap_get(member_ip, NULL, NULL, NULL) == CS_OK) { icmap_inc(member_join_count); icmap_set_string(member_status, "joined"); } else { icmap_set_string(member_ip, (char*)api->totem_ifaces_print (nodeid)); icmap_set_uint32(member_join_count, 1); icmap_set_string(member_status, "joined"); } log_printf (LOGSYS_LEVEL_DEBUG, "Member joined: %s", api->totem_ifaces_print (nodeid)); } static void member_object_left (unsigned int nodeid) { char member_status[ICMAP_KEYNAME_MAXLEN]; snprintf(member_status, ICMAP_KEYNAME_MAXLEN, "runtime.totem.pg.mrp.srp.members.%u.status", nodeid); icmap_set_string(member_status, "left"); log_printf (LOGSYS_LEVEL_DEBUG, "Member left: %s", api->totem_ifaces_print (nodeid)); } static void confchg_fn ( 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) { int i; int abort_activate = 0; if (sync_in_process == 1) { abort_activate = 1; } sync_in_process = 1; cs_ipcs_sync_state_changed(sync_in_process); memcpy (&corosync_ring_id, ring_id, sizeof (struct memb_ring_id)); for (i = 0; i < left_list_entries; i++) { member_object_left (left_list[i]); } for (i = 0; i < joined_list_entries; i++) { member_object_joined (joined_list[i]); } /* * Call configuration change for all services */ for (i = 0; i < service_count; i++) { if (corosync_service[i] && corosync_service[i]->confchg_fn) { corosync_service[i]->confchg_fn (configuration_type, member_list, member_list_entries, left_list, left_list_entries, joined_list, joined_list_entries, ring_id); } } if (abort_activate) { sync_abort (); } if (configuration_type == TOTEM_CONFIGURATION_TRANSITIONAL) { sync_save_transitional (member_list, member_list_entries, ring_id); } if (configuration_type == TOTEM_CONFIGURATION_REGULAR) { sync_start (member_list, member_list_entries, ring_id); } } static void priv_drop (void) { return; /* TODO: we are still not dropping privs */ } static void corosync_tty_detach (void) { int devnull; /* * Disconnect from TTY if this is not a debug run */ switch (fork ()) { case -1: corosync_exit_error (COROSYNC_DONE_FORK); break; case 0: /* * child which is disconnected, run this process */ break; default: exit (0); break; } /* Create new session */ (void)setsid(); /* * Map stdin/out/err to /dev/null. */ devnull = open("/dev/null", O_RDWR); if (devnull == -1) { corosync_exit_error (COROSYNC_DONE_STD_TO_NULL_REDIR); } if (dup2(devnull, 0) < 0 || dup2(devnull, 1) < 0 || dup2(devnull, 2) < 0) { close(devnull); corosync_exit_error (COROSYNC_DONE_STD_TO_NULL_REDIR); } close(devnull); } static void corosync_mlockall (void) { int res; struct rlimit rlimit; rlimit.rlim_cur = RLIM_INFINITY; rlimit.rlim_max = RLIM_INFINITY; #ifndef RLIMIT_MEMLOCK #define RLIMIT_MEMLOCK RLIMIT_VMEM #endif setrlimit (RLIMIT_MEMLOCK, &rlimit); res = mlockall (MCL_CURRENT | MCL_FUTURE); if (res == -1) { LOGSYS_PERROR (errno, LOGSYS_LEVEL_WARNING, "Could not lock memory of service to avoid page faults"); }; } static void corosync_totem_stats_updater (void *data) { totempg_stats_t * stats; uint32_t total_mtt_rx_token; uint32_t total_backlog_calc; uint32_t total_token_holdtime; int t, prev; int32_t token_count; stats = api->totem_get_stats(); icmap_set_uint32("runtime.totem.pg.msg_reserved", stats->msg_reserved); icmap_set_uint32("runtime.totem.pg.msg_queue_avail", stats->msg_queue_avail); icmap_set_uint64("runtime.totem.pg.srp.orf_token_tx", stats->srp->orf_token_tx); icmap_set_uint64("runtime.totem.pg.srp.orf_token_rx", stats->srp->orf_token_rx); icmap_set_uint64("runtime.totem.pg.srp.memb_merge_detect_tx", stats->srp->memb_merge_detect_tx); icmap_set_uint64("runtime.totem.pg.srp.memb_merge_detect_rx", stats->srp->memb_merge_detect_rx); icmap_set_uint64("runtime.totem.pg.srp.memb_join_tx", stats->srp->memb_join_tx); icmap_set_uint64("runtime.totem.pg.srp.memb_join_rx", stats->srp->memb_join_rx); icmap_set_uint64("runtime.totem.pg.srp.mcast_tx", stats->srp->mcast_tx); icmap_set_uint64("runtime.totem.pg.srp.mcast_retx", stats->srp->mcast_retx); icmap_set_uint64("runtime.totem.pg.srp.mcast_rx", stats->srp->mcast_rx); icmap_set_uint64("runtime.totem.pg.srp.memb_commit_token_tx", stats->srp->memb_commit_token_tx); icmap_set_uint64("runtime.totem.pg.srp.memb_commit_token_rx", stats->srp->memb_commit_token_rx); icmap_set_uint64("runtime.totem.pg.srp.token_hold_cancel_tx", stats->srp->token_hold_cancel_tx); icmap_set_uint64("runtime.totem.pg.srp.token_hold_cancel_rx", stats->srp->token_hold_cancel_rx); icmap_set_uint64("runtime.totem.pg.srp.operational_entered", stats->srp->operational_entered); icmap_set_uint64("runtime.totem.pg.srp.operational_token_lost", stats->srp->operational_token_lost); icmap_set_uint64("runtime.totem.pg.srp.gather_entered", stats->srp->gather_entered); icmap_set_uint64("runtime.totem.pg.srp.gather_token_lost", stats->srp->gather_token_lost); icmap_set_uint64("runtime.totem.pg.srp.commit_entered", stats->srp->commit_entered); icmap_set_uint64("runtime.totem.pg.srp.commit_token_lost", stats->srp->commit_token_lost); icmap_set_uint64("runtime.totem.pg.srp.recovery_entered", stats->srp->recovery_entered); icmap_set_uint64("runtime.totem.pg.srp.recovery_token_lost", stats->srp->recovery_token_lost); icmap_set_uint64("runtime.totem.pg.srp.consensus_timeouts", stats->srp->consensus_timeouts); icmap_set_uint64("runtime.totem.pg.srp.rx_msg_dropped", stats->srp->rx_msg_dropped); icmap_set_uint32("runtime.totem.pg.srp.continuous_gather", stats->srp->continuous_gather); icmap_set_uint32("runtime.totem.pg.srp.continuous_sendmsg_failures", stats->srp->continuous_sendmsg_failures); icmap_set_uint8("runtime.totem.pg.srp.firewall_enabled_or_nic_failure", stats->srp->continuous_gather > MAX_NO_CONT_GATHER ? 1 : 0); if (stats->srp->continuous_gather > MAX_NO_CONT_GATHER || stats->srp->continuous_sendmsg_failures > MAX_NO_CONT_SENDMSG_FAILURES) { log_printf (LOGSYS_LEVEL_WARNING, "Totem is unable to form a cluster because of an " "operating system or network fault. The most common " "cause of this message is that the local firewall is " "configured improperly."); icmap_set_uint8("runtime.totem.pg.srp.firewall_enabled_or_nic_failure", 1); } else { icmap_set_uint8("runtime.totem.pg.srp.firewall_enabled_or_nic_failure", 0); } total_mtt_rx_token = 0; total_token_holdtime = 0; total_backlog_calc = 0; token_count = 0; t = stats->srp->latest_token; while (1) { if (t == 0) prev = TOTEM_TOKEN_STATS_MAX - 1; else prev = t - 1; if (prev == stats->srp->earliest_token) break; /* if tx == 0, then dropped token (not ours) */ if (stats->srp->token[t].tx != 0 || (stats->srp->token[t].rx - stats->srp->token[prev].rx) > 0 ) { total_mtt_rx_token += (stats->srp->token[t].rx - stats->srp->token[prev].rx); total_token_holdtime += (stats->srp->token[t].tx - stats->srp->token[t].rx); total_backlog_calc += stats->srp->token[t].backlog_calc; token_count++; } t = prev; } if (token_count) { icmap_set_uint32("runtime.totem.pg.srp.mtt_rx_token", (total_mtt_rx_token / token_count)); icmap_set_uint32("runtime.totem.pg.srp.avg_token_workload", (total_token_holdtime / token_count)); icmap_set_uint32("runtime.totem.pg.srp.avg_backlog_calc", (total_backlog_calc / token_count)); } cs_ipcs_stats_update(); api->timer_add_duration (1500 * MILLI_2_NANO_SECONDS, NULL, corosync_totem_stats_updater, &corosync_stats_timer_handle); } static void corosync_totem_stats_init (void) { icmap_set_uint32("runtime.totem.pg.srp.mtt_rx_token", 0); icmap_set_uint32("runtime.totem.pg.srp.avg_token_workload", 0); icmap_set_uint32("runtime.totem.pg.srp.avg_backlog_calc", 0); /* start stats timer */ api->timer_add_duration (1500 * MILLI_2_NANO_SECONDS, NULL, corosync_totem_stats_updater, &corosync_stats_timer_handle); } static void deliver_fn ( unsigned int nodeid, const void *msg, unsigned int msg_len, int endian_conversion_required) { const struct qb_ipc_request_header *header; int32_t service; int32_t fn_id; uint32_t id; header = msg; if (endian_conversion_required) { id = swab32 (header->id); } else { id = header->id; } /* * Call the proper executive handler */ service = id >> 16; fn_id = id & 0xffff; if (!corosync_service[service]) { return; } if (fn_id >= corosync_service[service]->exec_engine_count) { log_printf(LOGSYS_LEVEL_WARNING, "discarded unknown message %d for service %d (max id %d)", fn_id, service, corosync_service[service]->exec_engine_count); return; } icmap_fast_inc(service_stats_rx[service][fn_id]); if (endian_conversion_required) { assert(corosync_service[service]->exec_engine[fn_id].exec_endian_convert_fn != NULL); corosync_service[service]->exec_engine[fn_id].exec_endian_convert_fn ((void *)msg); } corosync_service[service]->exec_engine[fn_id].exec_handler_fn (msg, nodeid); } int main_mcast ( const struct iovec *iovec, unsigned int iov_len, unsigned int guarantee) { const struct qb_ipc_request_header *req = iovec->iov_base; int32_t service; int32_t fn_id; service = req->id >> 16; fn_id = req->id & 0xffff; if (corosync_service[service]) { icmap_fast_inc(service_stats_tx[service][fn_id]); } return (totempg_groups_mcast_joined (corosync_group_handle, iovec, iov_len, guarantee)); } static void corosync_ring_id_create_or_load ( struct memb_ring_id *memb_ring_id, const struct totem_ip_address *addr) { int fd; int res = 0; char filename[PATH_MAX]; snprintf (filename, sizeof(filename), "%s/ringid_%s", get_run_dir(), totemip_print (addr)); fd = open (filename, O_RDONLY, 0700); /* * If file can be opened and read, read the ring id */ if (fd != -1) { res = read (fd, &memb_ring_id->seq, sizeof (uint64_t)); close (fd); } /* * If file could not be opened or read, create a new ring id */ if ((fd == -1) || (res != sizeof (uint64_t))) { memb_ring_id->seq = 0; umask(0); fd = open (filename, O_CREAT|O_RDWR, 0700); if (fd != -1) { res = write (fd, &memb_ring_id->seq, sizeof (uint64_t)); close (fd); if (res == -1) { LOGSYS_PERROR (errno, LOGSYS_LEVEL_ERROR, "Couldn't write ringid file '%s'", filename); corosync_exit_error (COROSYNC_DONE_STORE_RINGID); } } else { LOGSYS_PERROR (errno, LOGSYS_LEVEL_ERROR, "Couldn't create ringid file '%s'", filename); corosync_exit_error (COROSYNC_DONE_STORE_RINGID); } } totemip_copy(&memb_ring_id->rep, addr); assert (!totemip_zero_check(&memb_ring_id->rep)); } static void corosync_ring_id_store ( const struct memb_ring_id *memb_ring_id, const struct totem_ip_address *addr) { char filename[PATH_MAX]; int fd; int res; snprintf (filename, sizeof(filename), "%s/ringid_%s", get_run_dir(), totemip_print (addr)); fd = open (filename, O_WRONLY, 0700); if (fd == -1) { fd = open (filename, O_CREAT|O_RDWR, 0700); } if (fd == -1) { LOGSYS_PERROR(errno, LOGSYS_LEVEL_ERROR, "Couldn't store new ring id %llx to stable storage", memb_ring_id->seq); corosync_exit_error (COROSYNC_DONE_STORE_RINGID); } log_printf (LOGSYS_LEVEL_DEBUG, "Storing new sequence id for ring %llx", memb_ring_id->seq); res = write (fd, &memb_ring_id->seq, sizeof(memb_ring_id->seq)); close (fd); if (res != sizeof(memb_ring_id->seq)) { LOGSYS_PERROR(errno, LOGSYS_LEVEL_ERROR, "Couldn't store new ring id %llx to stable storage", memb_ring_id->seq); corosync_exit_error (COROSYNC_DONE_STORE_RINGID); } } static qb_loop_timer_handle recheck_the_q_level_timer; void corosync_recheck_the_q_level(void *data) { totempg_check_q_level(corosync_group_handle); if (cs_ipcs_q_level_get() == TOTEM_Q_LEVEL_CRITICAL) { qb_loop_timer_add(cs_poll_handle_get(), QB_LOOP_MED, 1*QB_TIME_NS_IN_MSEC, NULL, corosync_recheck_the_q_level, &recheck_the_q_level_timer); } } struct sending_allowed_private_data_struct { int reserved_msgs; }; int corosync_sending_allowed ( unsigned int service, unsigned int id, const void *msg, void *sending_allowed_private_data) { struct sending_allowed_private_data_struct *pd = (struct sending_allowed_private_data_struct *)sending_allowed_private_data; struct iovec reserve_iovec; struct qb_ipc_request_header *header = (struct qb_ipc_request_header *)msg; int sending_allowed; reserve_iovec.iov_base = (char *)header; reserve_iovec.iov_len = header->size; pd->reserved_msgs = totempg_groups_joined_reserve ( corosync_group_handle, &reserve_iovec, 1); if (pd->reserved_msgs == -1) { return -EINVAL; } sending_allowed = QB_FALSE; if (corosync_quorum_is_quorate() == 1 || corosync_service[service]->allow_inquorate == CS_LIB_ALLOW_INQUORATE) { // we are quorate // now check flow control if (corosync_service[service]->lib_engine[id].flow_control == CS_LIB_FLOW_CONTROL_NOT_REQUIRED) { sending_allowed = QB_TRUE; } else if (pd->reserved_msgs && sync_in_process == 0) { sending_allowed = QB_TRUE; } else if (pd->reserved_msgs == 0) { return -ENOBUFS; } else /* (sync_in_process) */ { return -EINPROGRESS; } } else { return -EHOSTUNREACH; } return (sending_allowed); } void corosync_sending_allowed_release (void *sending_allowed_private_data) { struct sending_allowed_private_data_struct *pd = (struct sending_allowed_private_data_struct *)sending_allowed_private_data; if (pd->reserved_msgs == -1) { return; } totempg_groups_joined_release (pd->reserved_msgs); } int message_source_is_local (const mar_message_source_t *source) { int ret = 0; assert (source != NULL); if (source->nodeid == totempg_my_nodeid_get ()) { ret = 1; } return ret; } void message_source_set ( mar_message_source_t *source, void *conn) { assert ((source != NULL) && (conn != NULL)); memset (source, 0, sizeof (mar_message_source_t)); source->nodeid = totempg_my_nodeid_get (); source->conn = conn; } struct scheduler_pause_timeout_data { struct totem_config *totem_config; qb_loop_timer_handle handle; unsigned long long tv_prev; unsigned long long max_tv_diff; }; static void timer_function_scheduler_timeout (void *data) { struct scheduler_pause_timeout_data *timeout_data = (struct scheduler_pause_timeout_data *)data; unsigned long long tv_current; unsigned long long tv_diff; tv_current = qb_util_nano_current_get (); if (timeout_data->tv_prev == 0) { /* * Initial call -> just pretent everything is ok */ timeout_data->tv_prev = tv_current; timeout_data->max_tv_diff = 0; } tv_diff = tv_current - timeout_data->tv_prev; timeout_data->tv_prev = tv_current; if (tv_diff > timeout_data->max_tv_diff) { log_printf (LOGSYS_LEVEL_WARNING, "Corosync main process was not scheduled for %0.4f ms " "(threshold is %0.4f ms). Consider token timeout increase.", (float)tv_diff / QB_TIME_NS_IN_MSEC, (float)timeout_data->max_tv_diff / QB_TIME_NS_IN_MSEC); } /* * Set next threshold, because token_timeout can change */ timeout_data->max_tv_diff = timeout_data->totem_config->token_timeout * QB_TIME_NS_IN_MSEC * 0.8; qb_loop_timer_add (corosync_poll_handle, QB_LOOP_MED, timeout_data->totem_config->token_timeout * QB_TIME_NS_IN_MSEC / 3, timeout_data, timer_function_scheduler_timeout, &timeout_data->handle); } static void corosync_setscheduler (void) { #if defined(HAVE_PTHREAD_SETSCHEDPARAM) && defined(HAVE_SCHED_GET_PRIORITY_MAX) && defined(HAVE_SCHED_SETSCHEDULER) int res; sched_priority = sched_get_priority_max (SCHED_RR); if (sched_priority != -1) { global_sched_param.sched_priority = sched_priority; res = sched_setscheduler (0, SCHED_RR, &global_sched_param); if (res == -1) { LOGSYS_PERROR(errno, LOGSYS_LEVEL_WARNING, "Could not set SCHED_RR at priority %d", global_sched_param.sched_priority); global_sched_param.sched_priority = 0; #ifdef HAVE_QB_LOG_THREAD_PRIORITY_SET qb_log_thread_priority_set (SCHED_OTHER, 0); #endif } else { /* * Turn on SCHED_RR in logsys system */ #ifdef HAVE_QB_LOG_THREAD_PRIORITY_SET res = qb_log_thread_priority_set (SCHED_RR, sched_priority); #else res = -1; #endif if (res == -1) { log_printf (LOGSYS_LEVEL_ERROR, "Could not set logsys thread priority." " Can't continue because of priority inversions."); corosync_exit_error (COROSYNC_DONE_LOGSETUP); } } } else { LOGSYS_PERROR (errno, LOGSYS_LEVEL_WARNING, "Could not get maximum scheduler priority"); sched_priority = 0; } #else log_printf(LOGSYS_LEVEL_WARNING, "The Platform is missing process priority setting features. Leaving at default."); #endif } /* The basename man page contains scary warnings about thread-safety and portability, hence this */ static const char *corosync_basename(const char *file_name) { char *base; base = strrchr (file_name, '/'); if (base) { return base + 1; } return file_name; } static void _logsys_log_printf(int level, int subsys, const char *function_name, const char *file_name, int file_line, const char *format, ...) __attribute__((format(printf, 6, 7))); static void _logsys_log_printf(int level, int subsys, const char *function_name, const char *file_name, int file_line, const char *format, ...) { va_list ap; va_start(ap, format); qb_log_from_external_source_va(function_name, corosync_basename(file_name), format, level, file_line, subsys, ap); va_end(ap); } static void fplay_key_change_notify_fn ( int32_t event, const char *key_name, struct icmap_notify_value new_val, struct icmap_notify_value old_val, void *user_data) { if (strcmp(key_name, "runtime.blackbox.dump_flight_data") == 0) { fprintf(stderr,"Writetofile\n"); corosync_blackbox_write_to_file (); } if (strcmp(key_name, "runtime.blackbox.dump_state") == 0) { fprintf(stderr,"statefump\n"); corosync_state_dump (); } } static void corosync_fplay_control_init (void) { icmap_track_t track = NULL; icmap_set_string("runtime.blackbox.dump_flight_data", "no"); icmap_set_string("runtime.blackbox.dump_state", "no"); icmap_track_add("runtime.blackbox.dump_flight_data", ICMAP_TRACK_ADD | ICMAP_TRACK_DELETE | ICMAP_TRACK_MODIFY, fplay_key_change_notify_fn, NULL, &track); icmap_track_add("runtime.blackbox.dump_state", ICMAP_TRACK_ADD | ICMAP_TRACK_DELETE | ICMAP_TRACK_MODIFY, fplay_key_change_notify_fn, NULL, &track); } /* * Set RO flag for keys, which ether doesn't make sense to change by user (statistic) * or which when changed are not reflected by runtime (totem.crypto_cipher, ...). * * Also some RO keys cannot be determined in this stage, so they are set later in * other functions (like nodelist.local_node_pos, ...) */ static void set_icmap_ro_keys_flag (void) { /* * Set RO flag for all keys of internal configuration and runtime statistics */ icmap_set_ro_access("internal_configuration.", CS_TRUE, CS_TRUE); icmap_set_ro_access("runtime.connections.", CS_TRUE, CS_TRUE); icmap_set_ro_access("runtime.totem.", CS_TRUE, CS_TRUE); icmap_set_ro_access("runtime.services.", CS_TRUE, CS_TRUE); icmap_set_ro_access("runtime.config.", CS_TRUE, CS_TRUE); icmap_set_ro_access("uidgid.config.", CS_TRUE, CS_TRUE); /* * Set RO flag for constrete keys of configuration which can't be changed * during runtime */ icmap_set_ro_access("totem.crypto_cipher", CS_FALSE, CS_TRUE); icmap_set_ro_access("totem.crypto_hash", CS_FALSE, CS_TRUE); icmap_set_ro_access("totem.secauth", CS_FALSE, CS_TRUE); icmap_set_ro_access("totem.ip_version", CS_FALSE, CS_TRUE); icmap_set_ro_access("totem.rrp_mode", CS_FALSE, CS_TRUE); icmap_set_ro_access("totem.transport", CS_FALSE, CS_TRUE); icmap_set_ro_access("totem.cluster_name", CS_FALSE, CS_TRUE); icmap_set_ro_access("totem.netmtu", CS_FALSE, CS_TRUE); icmap_set_ro_access("totem.threads", CS_FALSE, CS_TRUE); icmap_set_ro_access("totem.version", CS_FALSE, CS_TRUE); icmap_set_ro_access("totem.nodeid", CS_FALSE, CS_TRUE); icmap_set_ro_access("totem.clear_node_high_bit", CS_FALSE, CS_TRUE); icmap_set_ro_access("qb.ipc_type", CS_FALSE, CS_TRUE); icmap_set_ro_access("config.reload_in_progress", CS_FALSE, CS_TRUE); icmap_set_ro_access("config.totemconfig_reload_in_progress", CS_FALSE, CS_TRUE); } static void main_service_ready (void) { int res; /* * This must occur after totempg is initialized because "this_ip" must be set */ res = corosync_service_defaults_link_and_init (api); if (res == -1) { log_printf (LOGSYS_LEVEL_ERROR, "Could not initialize default services"); corosync_exit_error (COROSYNC_DONE_INIT_SERVICES); } cs_ipcs_init(); corosync_totem_stats_init (); corosync_fplay_control_init (); sync_init ( corosync_sync_callbacks_retrieve, corosync_sync_completed); } static enum e_corosync_done corosync_flock (const char *lockfile, pid_t pid) { struct flock lock; enum e_corosync_done err; char pid_s[17]; int fd_flag; int lf; err = COROSYNC_DONE_EXIT; lf = open (lockfile, O_WRONLY | O_CREAT, 0640); if (lf == -1) { log_printf (LOGSYS_LEVEL_ERROR, "Corosync Executive couldn't create lock file."); return (COROSYNC_DONE_ACQUIRE_LOCK); } retry_fcntl: lock.l_type = F_WRLCK; lock.l_start = 0; lock.l_whence = SEEK_SET; lock.l_len = 0; if (fcntl (lf, F_SETLK, &lock) == -1) { switch (errno) { case EINTR: goto retry_fcntl; break; case EAGAIN: case EACCES: log_printf (LOGSYS_LEVEL_ERROR, "Another Corosync instance is already running."); err = COROSYNC_DONE_ALREADY_RUNNING; goto error_close; break; default: log_printf (LOGSYS_LEVEL_ERROR, "Corosync Executive couldn't acquire lock. Error was %s", strerror(errno)); err = COROSYNC_DONE_ACQUIRE_LOCK; goto error_close; break; } } if (ftruncate (lf, 0) == -1) { log_printf (LOGSYS_LEVEL_ERROR, "Corosync Executive couldn't truncate lock file. Error was %s", strerror (errno)); err = COROSYNC_DONE_ACQUIRE_LOCK; goto error_close_unlink; } memset (pid_s, 0, sizeof (pid_s)); snprintf (pid_s, sizeof (pid_s) - 1, "%u\n", pid); retry_write: if (write (lf, pid_s, strlen (pid_s)) != strlen (pid_s)) { if (errno == EINTR) { goto retry_write; } else { log_printf (LOGSYS_LEVEL_ERROR, "Corosync Executive couldn't write pid to lock file. " "Error was %s", strerror (errno)); err = COROSYNC_DONE_ACQUIRE_LOCK; goto error_close_unlink; } } if ((fd_flag = fcntl (lf, F_GETFD, 0)) == -1) { log_printf (LOGSYS_LEVEL_ERROR, "Corosync Executive couldn't get close-on-exec flag from lock file. " "Error was %s", strerror (errno)); err = COROSYNC_DONE_ACQUIRE_LOCK; goto error_close_unlink; } fd_flag |= FD_CLOEXEC; if (fcntl (lf, F_SETFD, fd_flag) == -1) { log_printf (LOGSYS_LEVEL_ERROR, "Corosync Executive couldn't set close-on-exec flag to lock file. " "Error was %s", strerror (errno)); err = COROSYNC_DONE_ACQUIRE_LOCK; goto error_close_unlink; } return (err); error_close_unlink: unlink (lockfile); error_close: close (lf); return (err); } int main (int argc, char **argv, char **envp) { const char *error_string; struct totem_config totem_config; int res, ch; int background, setprio, testonly; struct stat stat_out; enum e_corosync_done flock_err; uint64_t totem_config_warnings; struct scheduler_pause_timeout_data scheduler_pause_timeout_data; /* default configuration */ background = 1; setprio = 1; testonly = 0; while ((ch = getopt (argc, argv, "fprtv")) != EOF) { switch (ch) { case 'f': background = 0; break; case 'p': setprio = 0; break; case 'r': setprio = 1; break; case 't': testonly = 1; break; case 'v': printf ("Corosync Cluster Engine, version '%s'\n", VERSION); printf ("Copyright (c) 2006-2009 Red Hat, Inc.\n"); logsys_system_fini(); return EXIT_SUCCESS; break; default: fprintf(stderr, \ "usage:\n"\ " -f : Start application in foreground.\n"\ " -p : Do not set process priority.\n"\ - " -t : Test configuration and exit.\n"\ " -r : Set round robin realtime scheduling (default).\n"\ + " -t : Test configuration and exit.\n"\ " -v : Display version and SVN revision of Corosync and exit.\n"); logsys_system_fini(); return EXIT_FAILURE; } } /* * Set round robin realtime scheduling with priority 99 * Lock all memory to avoid page faults which may interrupt * application healthchecking */ if (setprio) { corosync_setscheduler (); } corosync_mlockall (); /* * Other signals are registered later via qb_loop_signal_add */ (void)signal (SIGSEGV, sigsegv_handler); (void)signal (SIGABRT, sigabrt_handler); #if MSG_NOSIGNAL != 0 (void)signal (SIGPIPE, SIG_IGN); #endif if (icmap_init() != CS_OK) { log_printf (LOGSYS_LEVEL_ERROR, "Corosync Executive couldn't initialize configuration component."); corosync_exit_error (COROSYNC_DONE_ICMAP); } set_icmap_ro_keys_flag(); /* * Initialize the corosync_api_v1 definition */ api = apidef_get (); res = coroparse_configparse(icmap_get_global_map(), &error_string); if (res == -1) { log_printf (LOGSYS_LEVEL_ERROR, "%s", error_string); corosync_exit_error (COROSYNC_DONE_MAINCONFIGREAD); } res = corosync_log_config_read (&error_string); if (res == -1) { /* * if we are here, we _must_ flush the logsys queue * and try to inform that we couldn't read the config. * this is a desperate attempt before certain death * and there is no guarantee that we can print to stderr * nor that logsys is sending the messages where we expect. */ log_printf (LOGSYS_LEVEL_ERROR, "%s", error_string); fprintf(stderr, "%s", error_string); syslog (LOGSYS_LEVEL_ERROR, "%s", error_string); corosync_exit_error (COROSYNC_DONE_LOGCONFIGREAD); } if (!testonly) { log_printf (LOGSYS_LEVEL_NOTICE, "Corosync Cluster Engine ('%s'): started and ready to provide service.", VERSION); log_printf (LOGSYS_LEVEL_INFO, "Corosync built-in features:" PACKAGE_FEATURES ""); } /* * Make sure required directory is present */ res = stat (get_run_dir(), &stat_out); if ((res == -1) || (res == 0 && !S_ISDIR(stat_out.st_mode))) { log_printf (LOGSYS_LEVEL_ERROR, "Required directory not present %s. Please create it.", get_run_dir()); corosync_exit_error (COROSYNC_DONE_DIR_NOT_PRESENT); } res = chdir(get_run_dir()); if (res == -1) { log_printf (LOGSYS_LEVEL_ERROR, "Cannot chdir to run directory %s. " "Please make sure it has correct context and rights.", get_run_dir()); corosync_exit_error (COROSYNC_DONE_DIR_NOT_PRESENT); } res = totem_config_read (&totem_config, &error_string, &totem_config_warnings); if (res == -1) { log_printf (LOGSYS_LEVEL_ERROR, "%s", error_string); corosync_exit_error (COROSYNC_DONE_MAINCONFIGREAD); } if (totem_config_warnings & TOTEM_CONFIG_WARNING_MEMBERS_IGNORED) { log_printf (LOGSYS_LEVEL_WARNING, "member section is used together with nodelist. Members ignored."); } if (totem_config_warnings & TOTEM_CONFIG_WARNING_MEMBERS_DEPRECATED) { log_printf (LOGSYS_LEVEL_WARNING, "member section is deprecated."); } if (totem_config_warnings & TOTEM_CONFIG_WARNING_TOTEM_NODEID_IGNORED) { log_printf (LOGSYS_LEVEL_WARNING, "nodeid appears both in totem section and nodelist. Nodelist one is used."); } if (totem_config_warnings != 0) { log_printf (LOGSYS_LEVEL_WARNING, "Please migrate config file to nodelist."); } res = totem_config_keyread (&totem_config, &error_string); if (res == -1) { log_printf (LOGSYS_LEVEL_ERROR, "%s", error_string); corosync_exit_error (COROSYNC_DONE_MAINCONFIGREAD); } res = totem_config_validate (&totem_config, &error_string); if (res == -1) { log_printf (LOGSYS_LEVEL_ERROR, "%s", error_string); corosync_exit_error (COROSYNC_DONE_MAINCONFIGREAD); } if (testonly) { corosync_exit_error (COROSYNC_DONE_EXIT); } ip_version = totem_config.ip_version; totem_config.totem_memb_ring_id_create_or_load = corosync_ring_id_create_or_load; totem_config.totem_memb_ring_id_store = corosync_ring_id_store; totem_config.totem_logging_configuration = totem_logging_configuration; totem_config.totem_logging_configuration.log_subsys_id = _logsys_subsys_create("TOTEM", "totem," "totemmrp.c,totemrrp.c,totemip.c,totemconfig.c,totemcrypto.c,totemsrp.c," "totempg.c,totemiba.c,totemudp.c,totemudpu.c,totemnet.c,totemknet.c"); totem_config.totem_logging_configuration.log_level_security = LOGSYS_LEVEL_WARNING; totem_config.totem_logging_configuration.log_level_error = LOGSYS_LEVEL_ERROR; totem_config.totem_logging_configuration.log_level_warning = LOGSYS_LEVEL_WARNING; totem_config.totem_logging_configuration.log_level_notice = LOGSYS_LEVEL_NOTICE; totem_config.totem_logging_configuration.log_level_debug = LOGSYS_LEVEL_DEBUG; totem_config.totem_logging_configuration.log_level_trace = LOGSYS_LEVEL_TRACE; totem_config.totem_logging_configuration.log_printf = _logsys_log_printf; logsys_config_apply(); /* * Now we are fully initialized. */ if (background) { corosync_tty_detach (); } corosync_poll_handle = qb_loop_create (); memset(&scheduler_pause_timeout_data, 0, sizeof(scheduler_pause_timeout_data)); scheduler_pause_timeout_data.totem_config = &totem_config; timer_function_scheduler_timeout (&scheduler_pause_timeout_data); qb_loop_signal_add(corosync_poll_handle, QB_LOOP_LOW, SIGUSR2, NULL, sig_diag_handler, NULL); qb_loop_signal_add(corosync_poll_handle, QB_LOOP_HIGH, SIGINT, NULL, sig_exit_handler, NULL); qb_loop_signal_add(corosync_poll_handle, QB_LOOP_HIGH, SIGSEGV, NULL, sig_segv_handler, NULL); qb_loop_signal_add(corosync_poll_handle, QB_LOOP_HIGH, SIGABRT, NULL, sig_abrt_handler, NULL); qb_loop_signal_add(corosync_poll_handle, QB_LOOP_HIGH, SIGQUIT, NULL, sig_exit_handler, NULL); qb_loop_signal_add(corosync_poll_handle, QB_LOOP_HIGH, SIGTERM, NULL, sig_exit_handler, NULL); if (logsys_thread_start() != 0) { log_printf (LOGSYS_LEVEL_ERROR, "Can't initialize log thread"); corosync_exit_error (COROSYNC_DONE_LOGCONFIGREAD); } if ((flock_err = corosync_flock (corosync_lock_file, getpid ())) != COROSYNC_DONE_EXIT) { corosync_exit_error (flock_err); } /* * if totempg_initialize doesn't have root priveleges, it cannot * bind to a specific interface. This only matters if * there is more then one interface in a system, so * in this case, only a warning is printed */ /* * Join multicast group and setup delivery * and configuration change functions */ totempg_initialize ( corosync_poll_handle, &totem_config); totempg_service_ready_register ( main_service_ready); totempg_groups_initialize ( &corosync_group_handle, deliver_fn, confchg_fn); totempg_groups_join ( corosync_group_handle, &corosync_group, 1); /* * Drop root privleges to user 'corosync' * TODO: Don't really need full root capabilities; * needed capabilities are: * CAP_NET_RAW (bindtodevice) * CAP_SYS_NICE (setscheduler) * CAP_IPC_LOCK (mlockall) */ priv_drop (); schedwrk_init ( serialize_lock, serialize_unlock); /* * Start main processing loop */ qb_loop_run (corosync_poll_handle); /* * Exit was requested */ totempg_finalize (); /* * free the loop resources */ qb_loop_destroy (corosync_poll_handle); /* * free up the icmap */ /* * Remove pid lock file */ unlink (corosync_lock_file); corosync_exit_error (COROSYNC_DONE_EXIT); return EXIT_SUCCESS; } diff --git a/man/corosync-cfgtool.8 b/man/corosync-cfgtool.8 index 6df86518..b190766e 100644 --- a/man/corosync-cfgtool.8 +++ b/man/corosync-cfgtool.8 @@ -1,80 +1,74 @@ .\" .\" * Copyright (C) 2010 Red Hat, Inc. .\" * .\" * All rights reserved. .\" * .\" * Author: Angus Salkeld .\" * .\" * This software licensed under BSD license, the text of which follows: .\" * .\" * Redistribution and use in source and binary forms, with or without .\" * modification, are permitted provided that the following conditions are met: .\" * .\" * - Redistributions of source code must retain the above copyright notice, .\" * this list of conditions and the following disclaimer. .\" * - Redistributions in binary form must reproduce the above copyright notice, .\" * this list of conditions and the following disclaimer in the documentation .\" * and/or other materials provided with the distribution. .\" * - Neither the name of the MontaVista Software, Inc. nor the names of its .\" * contributors may be used to endorse or promote products derived from this .\" * software without specific prior written permission. .\" * .\" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" .\" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE .\" * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR .\" * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF .\" * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN .\" * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) .\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF .\" * THE POSSIBILITY OF SUCH DAMAGE. .\" */ .TH "COROSYNC-CFGTOOL" "8" "2010-05-30" "" "" .SH "NAME" corosync-cfgtool \- An administrative tool for corosync. .SH "SYNOPSIS" -.B corosync\-cfgtool [\-i] [IP_address] [\-s] [\-r] [\-l] [\-u] [\-H] [service_name] [\-v] [version] [\-k] [nodeid] [\-a] [nodeid] +.B corosync\-cfgtool [\-i IP_address] [\-s] [\-r] [\-R] [\-k nodeid] [\-a nodeid] [\-h] [\-H] .SH "DESCRIPTION" .B corosync\-cfgtool A tool for displaying and configuring active parameters within corosync. .SH "OPTIONS" -.TP -.B -h -Print basic usage. .TP .B -i Finds only information about the specified interface IP address. .TP .B -s Displays the status of the current rings on this node. If any interfaces are faulty, 1 is returned by the binary. If all interfaces are active 0 is returned to the shell. .TP .B -r Reset redundant ring state cluster wide after a fault to re-enable redundant ring operation. .TP -.B -l -Load a service identified by "service_name". -.TP -.B -u -Unload a service identified by "service_name". -.TP -.B -a -Display the IP address(es) of a node. +.B -R +Tell all instances of corosync in this cluster to reload corosync.conf. .TP .B -k Kill a node identified by node id. .TP -.B -R -Tell all instances of corosync in this cluster to reload corosync.conf +.B -a +Display the IP address(es) of a node. +.TP +.B -h +Print basic usage. .TP .B -H Shutdown corosync cleanly on this node. .SH "SEE ALSO" .BR corosync_overview (8), .SH "AUTHOR" Angus Salkeld .PP diff --git a/man/corosync-cmapctl.8 b/man/corosync-cmapctl.8 index 661137ce..ed97fadc 100644 --- a/man/corosync-cmapctl.8 +++ b/man/corosync-cmapctl.8 @@ -1,85 +1,85 @@ .\"/* .\" * Copyright (C) 2010 Red Hat, Inc. .\" * .\" * All rights reserved. .\" * .\" * Author: Angus Salkeld .\" * .\" * This software licensed under BSD license, the text of which follows: .\" * .\" * Redistribution and use in source and binary forms, with or without .\" * modification, are permitted provided that the following conditions are met: .\" * .\" * - Redistributions of source code must retain the above copyright notice, .\" * this list of conditions and the following disclaimer. .\" * - Redistributions in binary form must reproduce the above copyright notice, .\" * this list of conditions and the following disclaimer in the documentation .\" * and/or other materials provided with the distribution. .\" * - Neither the name of the MontaVista Software, Inc. nor the names of its .\" * contributors may be used to endorse or promote products derived from this .\" * software without specific prior written permission. .\" * .\" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" .\" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE .\" * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR .\" * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF .\" * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN .\" * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) .\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF .\" * THE POSSIBILITY OF SUCH DAMAGE. .\" */ .TH COROSYNC-CMAP 8 2012-01-23 .SH NAME corosync-cmapctl: \- A tool for accessing the object database. .SH DESCRIPTION -usage: corosync\-cmapctl [\-b] [\-dghsTtp] [params...] +usage: corosync\-cmapctl [\-b] [\-DdghsTt] [\-p filename] [params...] .HP \fB\-b\fR show binary values .SS "Set key:" .IP corosync\-cmapctl \fB\-s\fR key_name type value .IP where type is one of ([i|u][8|16|32|64] | flt | dbl | str | bin) for bin, value is file name (or \- for stdin) .SS "Load settings from a file:" .IP corosync\-cmapctl \fB\-p\fR filename .IP the format of the file is: [^[^]][ ] .IP Keys prefixed with single caret ('^') are deleted (see \fB\-d\fR). .IP Keys (actually prefixes) prefixed with double caret ('^^') are deleted by prefix (see \fB\-D\fR). .IP and are optional (not checked) in above cases. .IP Other keys are set (see \fB\-s\fR) so both and are required. .SS "Delete key:" .IP corosync\-cmapctl \fB\-d\fR key_name... .SS "Delete multiple keys with prefix:" .IP corosync\-cmapctl \fB\-D\fR key_prefix... .SS "Get key:" .IP corosync\-cmapctl [\-b] \fB\-g\fR key_name... .SS "Display all keys:" .IP corosync\-cmapctl [\-b] .SS "Display keys with prefix key_name:" .IP corosync\-cmapctl [\-b] key_name... .SS "Track changes on keys with key_name:" .IP corosync\-cmapctl [\-b] \fB\-t\fR key_name .SS "Track changes on keys with key prefix:" .IP corosync\-cmapctl [\-b] \fB\-T\fR key_prefix .SH "SEE ALSO" .BR cmap_overview (8), .BR cmap_keys (8) diff --git a/man/corosync-cpgtool.8 b/man/corosync-cpgtool.8 index 8ef32d1d..3a62752b 100644 --- a/man/corosync-cpgtool.8 +++ b/man/corosync-cpgtool.8 @@ -1,85 +1,85 @@ .\"/* .\" * Copyright (C) 2010 Red Hat, Inc. .\" * .\" * All rights reserved. .\" * .\" * Author: Angus Salkeld .\" * .\" * This software licensed under BSD license, the text of which follows: .\" * .\" * Redistribution and use in source and binary forms, with or without .\" * modification, are permitted provided that the following conditions are met: .\" * .\" * - Redistributions of source code must retain the above copyright notice, .\" * this list of conditions and the following disclaimer. .\" * - Redistributions in binary form must reproduce the above copyright notice, .\" * this list of conditions and the following disclaimer in the documentation .\" * and/or other materials provided with the distribution. .\" * - Neither the name of the MontaVista Software, Inc. nor the names of its .\" * contributors may be used to endorse or promote products derived from this .\" * software without specific prior written permission. .\" * .\" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" .\" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE .\" * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR .\" * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF .\" * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN .\" * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) .\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF .\" * THE POSSIBILITY OF SUCH DAMAGE. .\" */ .TH COROSYNC-CPGTOOL 8 2010-05-30 .SH NAME corosync-cpgtool \- A tool for displaying cpg groups and members. .SH SYNOPSIS .B "corosync-cpgtool [\-d delimiter] [\-e] [\-n] [\-h]" .SH DESCRIPTION .B corosync-cpgtool A tool for displaying cpg groups and members. .SH OPTIONS .TP -.B -h -Display this help. -.TP .B -d Delimiter between fields. .TP .B -e -Don't escape unprintable characters in group name +Don't escape unprintable characters in group name. .TP .B -n Display only all existing group names. +.TP +.B -h +Display this help. .SH EXAMPLES .TP Display the groups and process that belong to those cpg groups. $ corosync-cpgtool .br Group Name PID Node ID .br example-group .br 2515 191146176 (192.168.100.11) .br 2471 207923392 (192.168.100.12) .TP Get a comma-delimited list. $ corosync-cpgtool -d "," .br GRP_NAME,PID,NODEID .br example-group,2515,191146176 .br example-group,2471,207923392 .TP Just get the group names $ corosync-cpgtool -n .br example-group .SH SEE ALSO .BR corosync_overview (8), .SH AUTHOR Angus Salkeld .PP diff --git a/man/corosync-keygen.8 b/man/corosync-keygen.8 index 5aaae933..ed04620d 100644 --- a/man/corosync-keygen.8 +++ b/man/corosync-keygen.8 @@ -1,98 +1,101 @@ .\"/* .\" * Copyright (C) 2010 Red Hat, Inc. .\" * .\" * All rights reserved. .\" * .\" * Author: Angus Salkeld .\" * .\" * This software licensed under BSD license, the text of which follows: .\" * .\" * Redistribution and use in source and binary forms, with or without .\" * modification, are permitted provided that the following conditions are met: .\" * .\" * - Redistributions of source code must retain the above copyright notice, .\" * this list of conditions and the following disclaimer. .\" * - Redistributions in binary form must reproduce the above copyright notice, .\" * this list of conditions and the following disclaimer in the documentation .\" * and/or other materials provided with the distribution. .\" * - Neither the name of the MontaVista Software, Inc. nor the names of its .\" * contributors may be used to endorse or promote products derived from this .\" * software without specific prior written permission. .\" * .\" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" .\" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE .\" * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR .\" * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF .\" * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN .\" * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) .\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF .\" * THE POSSIBILITY OF SUCH DAMAGE. .\" */ .TH COROSYNC-KEYGEN 8 2010-05-30 .SH NAME corosync-keygen \- Generate an authentication key for Corosync. .SH SYNOPSIS -.B "corosync-keygen [\-k ] [\-l]" +.B "corosync-keygen [\-k ] [\-l] [\-h]" .SH DESCRIPTION If you want to configure corosync to use cryptographic techniques to ensure authenticity and privacy of the messages, you will need to generate a private key. .PP .B corosync-keygen creates this key and writes it to /etc/corosync/authkey or to file specified by -k option. .PP This private key must be copied to every processor in the cluster. If the private key isn't the same for every node, those nodes with nonmatching private keys will not be able to join the same configuration. .PP Copy the key to some security transportable storage or use ssh to transmit the key from node to node. Then install the key with the command: .PP unix#: install -D --group=0 --owner=0 --mode=0400 /path_to_authkey/authkey /etc/corosync/authkey .PP If a message "Invalid digest" appears from the corosync executive, the keys are not consistent between processors. .PP .B Note: corosync-keygen will ask for user input to assist in generating entropy unless the -l option is used. .SH OPTIONS .TP .B -k This specifies the fully qualified path to the shared key to create. .br The default is /etc/corosync/authkey. .TP .B -l Use a less secure random data source that will not require user input to help generate entropy. This may be useful when this utility is used from a script or hardware random number generator is not available (f.e. in virtual machine). +.TP +.B -h +Print basic usage. .SH EXAMPLES .TP Generate the key. .PP # corosync-keygen .br Corosync Cluster Engine Authentication key generator. .br Gathering 1024 bits for key from /dev/random. .br Press keys on your keyboard to generate entropy. .br .PP $ corosync-keygen -l -k /tmp/authkey .br Corosync Cluster Engine Authentication key generator. .br Writing corosync key to /tmp/authkey. .br .SH SEE ALSO .BR corosync_overview (8), .BR corosync.conf (5), .SH AUTHOR Angus Salkeld .PP diff --git a/man/corosync-notifyd.8 b/man/corosync-notifyd.8 index 822d1387..40d8d796 100644 --- a/man/corosync-notifyd.8 +++ b/man/corosync-notifyd.8 @@ -1,145 +1,145 @@ .\"/* .\" * Copyright (C) 2010 Red Hat, Inc. .\" * .\" * All rights reserved. .\" * .\" * Author: Angus Salkeld .\" * .\" * This software licensed under BSD license, the text of which follows: .\" * .\" * Redistribution and use in source and binary forms, with or without .\" * modification, are permitted provided that the following conditions are met: .\" * .\" * - Redistributions of source code must retain the above copyright notice, .\" * this list of conditions and the following disclaimer. .\" * - Redistributions in binary form must reproduce the above copyright notice, .\" * this list of conditions and the following disclaimer in the documentation .\" * and/or other materials provided with the distribution. .\" * - Neither the name of Red Hat, Inc. nor the names of its .\" * contributors may be used to endorse or promote products derived from this .\" * software without specific prior written permission. .\" * .\" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" .\" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE .\" * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR .\" * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF .\" * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN .\" * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) .\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF .\" * THE POSSIBILITY OF SUCH DAMAGE. .\" */ .TH COROSYNC-NOTIFYD 8 2011-01-14 .SH NAME corosync-notifyd \- Listen for important corosync events and send dbus and/or snmp traps. .SH SYNOPSIS -.B "corosync-notifyd [\-f] [\-l] [\-o] [\-s] [\-m] [manager] [\-d] [-h]" +.B "corosync-notifyd [\-f] [\-l] [\-o] [\-s] [\-m manager] [\-d] [-h]" .SH DESCRIPTION .B corosync-notifyd uses corosync API to listen for important cluster events and can log them, generate dbus signals or generate snmp traps. .SH OPTIONS .TP .B -f Start application in foreground. .TP .B -l Log all events. .TP .B -o Print events to stdout (turns on -l). .TP .B -s Send SNMP traps on all events. .TP .B -m -Set the SNMP manager address. +Set the SNMP Manager IP address (defaults to localhost). .TP .B -d Send DBUS signals on all events. .TP .B -h -Print this help +Print this help. .SH EXAMPLES .br $ corosync-notifyd -o .br corosync-notifyd[18505]: troll[23374016] corosync-notify:18505:12 is now connected to corosync .br corosync-notifyd[18505]: troll[23374016] corosync-notify:18505:13 is now disconnected from corosync .br corosync-notifyd[18505]: troll[23374016] is now quorate .br corosync-notifyd[18505]: r2[1550100672] ip:192.168.100.92 joined .br corosync-notifyd[18505]: r2[1550100672] ip:192.168.100.92 left .br .br $ corosync-notifyd -d .br Note this output below is from "dbus-monitor --system" .br signal sender=:1.216 -> dest=(null destination) serial=2 path=/com/redhat/cluster/corosync; interface=com.redhat.cluster.corosync; member=ConnectionStateChange .br string "troll" .br uint32 23374016 .br string "corosync-notify:18900:12" .br string "connected" .br signal sender=:1.216 -> dest=(null destination) serial=3 path=/com/redhat/cluster/corosync; interface=com.redhat.cluster.corosync; member=ConnectionStateChange .br string "troll" .br uint32 23374016 .br string "corosync-notify:18900:13" .br string "disconnected" .br signal sender=:1.216 -> dest=(null destination) serial=4 path=/com/redhat/cluster/corosync; interface=com.redhat.cluster.corosync; member=QorumStateChange .br string "troll" .br uint32 23374016 .br string "quorate" .br signal sender=:1.216 -> dest=(null destination) serial=5 path=/com/redhat/cluster/corosync; interface=com.redhat.cluster.corosync; member=NodeStateChange .br string "r2" .br uint32 1550100672 .br string "192.168.100.92" .br string "joined" .br signal sender=:1.216 -> dest=(null destination) serial=6 path=/com/redhat/cluster/corosync; interface=com.redhat.cluster.corosync; member=NodeStateChange .br string "r2" .br uint32 1550100672 .br string "192.168.100.92" .br string "left" .SH SEE ALSO .BR corosync (8), .BR corosync-cmapctl (8), .BR dbus-monitor (1), .SH AUTHOR Angus Salkeld .PP diff --git a/man/corosync-quorumtool.8 b/man/corosync-quorumtool.8 index 9707a70c..88264b06 100644 --- a/man/corosync-quorumtool.8 +++ b/man/corosync-quorumtool.8 @@ -1,87 +1,93 @@ .\"/* .\" * Copyright (C) 2010,2014 Red Hat, Inc. .\" * .\" * All rights reserved. .\" * .\" * Author: Angus Salkeld .\" * .\" * This software licensed under BSD license, the text of which follows: .\" * .\" * Redistribution and use in source and binary forms, with or without .\" * modification, are permitted provided that the following conditions are met: .\" * .\" * - Redistributions of source code must retain the above copyright notice, .\" * this list of conditions and the following disclaimer. .\" * - Redistributions in binary form must reproduce the above copyright notice, .\" * this list of conditions and the following disclaimer in the documentation .\" * and/or other materials provided with the distribution. .\" * - Neither the name of the MontaVista Software, Inc. nor the names of its .\" * contributors may be used to endorse or promote products derived from this .\" * software without specific prior written permission. .\" * .\" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" .\" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE .\" * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR .\" * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF .\" * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN .\" * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) .\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF .\" * THE POSSIBILITY OF SUCH DAMAGE. .\" */ .TH COROSYNC-QUORUMTOOL 8 2012-01-12 .SH NAME corosync-quorumtool \- Set and display quorum settings. .SH SYNOPSIS -.B "corosync-quorumtool [\-s] [\-m] [\-l] [\-p] [\-v votes] [\-n nodeid] [\-e expected] [\-h] [\-i] [\-o ] [\-V]" +.B "corosync-quorumtool [\-s] [\-m] [\-l] [\-p] [\-v votes] [\-n nodeid] [\-e expected] [\-H] [\-i] [\-o ] [\-f] [\-h] [\-V]" .SH DESCRIPTION Display the current state of quorum in the cluster and set vote quorum options. .SH OPTIONS .TP .B -s show quorum status .TP .B -m constantly monitor quorum status .TP .B -l list nodes .TP +.B -p +when used with -s or -l, generates machine parsable output +.TP .B -v change the number of votes for a node * .TP .B -n optional nodeid of node for -v .TP .B -e change expected votes for the cluster * .TP .B -H show nodeids in hexadecimal rather than decimal .TP .B -i show node IP addresses instead of the resolved name .TP .B -p when used with -s or -l, generates machine parsable output .TP .B -o Orders the output of the nodes list. By default or with -oa nodes are listed in IP address order: as they come from corosync. -on will order the nodes based on their name, and -oi will order them based on their node ID. .TP +.B -f +forcefully unregister a quorum device *DANGEROUS* * +.TP .B -h (if no other argument) show this help text .TP .B -V show version and exit .PP * Starred items only work if votequorum is the quorum provider for corosync .SH SEE ALSO .BR corosync_overview (8), .BR votequorum_overview (8), .SH AUTHOR Angus Salkeld .PP diff --git a/man/corosync.8 b/man/corosync.8 index b5451ade..89ab771b 100644 --- a/man/corosync.8 +++ b/man/corosync.8 @@ -1,68 +1,68 @@ .\"/* .\" * Copyright (C) 2010 Red Hat, Inc. .\" * .\" * All rights reserved. .\" * .\" * Author: Angus Salkeld .\" * .\" * This software licensed under BSD license, the text of which follows: .\" * .\" * Redistribution and use in source and binary forms, with or without .\" * modification, are permitted provided that the following conditions are met: .\" * .\" * - Redistributions of source code must retain the above copyright notice, .\" * this list of conditions and the following disclaimer. .\" * - Redistributions in binary form must reproduce the above copyright notice, .\" * this list of conditions and the following disclaimer in the documentation .\" * and/or other materials provided with the distribution. .\" * - Neither the name of the MontaVista Software, Inc. nor the names of its .\" * contributors may be used to endorse or promote products derived from this .\" * software without specific prior written permission. .\" * .\" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" .\" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE .\" * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR .\" * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF .\" * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN .\" * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) .\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF .\" * THE POSSIBILITY OF SUCH DAMAGE. .\" */ .TH COROSYNC 8 2010-05-30 .SH NAME corosync \- The Corosync Cluster Engine. .SH SYNOPSIS -.B "corosync [\-f] [\-p] [\-r] [\-v]" +.B "corosync [\-f] [\-p] [\-r] [\-t] [\-v]" .SH DESCRIPTION .B corosync Corosync provides clustering infrastructure such as membership, messaging and quorum. .SH OPTIONS .TP .B -f Start application in foreground. .TP .B -p Do not set process priority. .TP .B -r Set round robin realtime scheduling (default). .TP .B -t Test configuration and then exit. .TP .B -v Display version and SVN revision of Corosync and exit. .SH SEE ALSO .BR corosync_overview (8), .BR corosync.conf (5), .BR cpg_overview (8), .BR votequorum_overview (8), .BR sam_overview (8), .BR cmap_overview (8), .BR quorum_overview (8) .SH AUTHOR Angus Salkeld .PP diff --git a/tools/corosync-cfgtool.c b/tools/corosync-cfgtool.c index 94ffce46..201977b2 100644 --- a/tools/corosync-cfgtool.c +++ b/tools/corosync-cfgtool.c @@ -1,318 +1,321 @@ /* * Copyright (c) 2006-2013 Red Hat, Inc. * * All rights reserved. * * Author: Steven Dake * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the MontaVista Software, Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define cs_repeat(result, max, code) \ do { \ int counter = 0; \ do { \ result = code; \ if (result == CS_ERR_TRY_AGAIN) { \ sleep(1); \ counter++; \ } else { \ break; \ } \ } while (counter < max); \ } while (0) static int ringstatusget_do (char *interface_name) { cs_error_t result; corosync_cfg_handle_t handle; unsigned int interface_count; char **interface_names; char **interface_status; unsigned int i; unsigned int nodeid; int rc = 0; printf ("Printing ring status.\n"); result = corosync_cfg_initialize (&handle, NULL); if (result != CS_OK) { printf ("Could not initialize corosync configuration API error %d\n", result); exit (1); } result = corosync_cfg_local_get(handle, &nodeid); if (result != CS_OK) { printf ("Could not get the local node id, the error is: %d\n", result); } else { printf ("Local node ID %u\n", nodeid); } result = corosync_cfg_ring_status_get (handle, &interface_names, &interface_status, &interface_count); if (result != CS_OK) { printf ("Could not get the ring status, the error is: %d\n", result); } else { for (i = 0; i < interface_count; i++) { if ( (interface_name && (interface_name[0]=='\0' || strcasecmp (interface_name, interface_names[i]) == 0)) || !interface_name ) { printf ("RING ID %d\n", i); printf ("\tid\t= %s\n", interface_names[i]); printf ("\tstatus\t= %s\n", interface_status[i]); if (strstr(interface_status[i], "FAULTY")) { rc = 1; } } } for (i = 0; i < interface_count; i++) { free(interface_status[i]); free(interface_names[i]); } free(interface_status); free(interface_names); } (void)corosync_cfg_finalize (handle); return rc; } static void ringreenable_do (void) { cs_error_t result; corosync_cfg_handle_t handle; printf ("Re-enabling all failed rings.\n"); result = corosync_cfg_initialize (&handle, NULL); if (result != CS_OK) { printf ("Could not initialize corosync configuration API error %d\n", result); exit (1); } result = corosync_cfg_ring_reenable (handle); if (result != CS_OK) { printf ("Could not re-enable ring error %d\n", result); } (void)corosync_cfg_finalize (handle); } static int reload_config_do (void) { cs_error_t result; corosync_cfg_handle_t handle; int rc; rc = 0; printf ("Reloading corosync.conf...\n"); result = corosync_cfg_initialize (&handle, NULL); if (result != CS_OK) { printf ("Could not initialize corosync configuration API error %s\n", cs_strerror(result)); exit (1); } result = corosync_cfg_reload_config (handle); if (result != CS_OK) { printf ("Could not reload configuration. Error %s\n", cs_strerror(result)); rc = (int)result; } else { printf ("Done\n"); } (void)corosync_cfg_finalize (handle); return (rc); } static void shutdown_do(void) { cs_error_t result; corosync_cfg_handle_t handle; corosync_cfg_callbacks_t callbacks; callbacks.corosync_cfg_shutdown_callback = NULL; result = corosync_cfg_initialize (&handle, &callbacks); if (result != CS_OK) { printf ("Could not initialize corosync configuration API error %d\n", result); exit (1); } printf ("Shutting down corosync\n"); cs_repeat(result, 30, corosync_cfg_try_shutdown (handle, COROSYNC_CFG_SHUTDOWN_FLAG_REQUEST)); if (result != CS_OK) { printf ("Could not shutdown (error = %d)\n", result); } (void)corosync_cfg_finalize (handle); } static void showaddrs_do(int nodeid) { cs_error_t result; corosync_cfg_handle_t handle; corosync_cfg_callbacks_t callbacks; int numaddrs; int i; corosync_cfg_node_address_t addrs[INTERFACE_MAX]; result = corosync_cfg_initialize (&handle, &callbacks); if (result != CS_OK) { printf ("Could not initialize corosync configuration API error %d\n", result); exit (1); } if (corosync_cfg_get_node_addrs(handle, nodeid, INTERFACE_MAX, &numaddrs, addrs) == CS_OK) { for (i=0; iss_family == AF_INET6) saddr = &sin6->sin6_addr; else saddr = &sin->sin_addr; inet_ntop(ss->ss_family, saddr, buf, sizeof(buf)); if (i != 0) { printf(" "); } printf("%s", buf); } printf("\n"); } (void)corosync_cfg_finalize (handle); } static void killnode_do(unsigned int nodeid) { cs_error_t result; corosync_cfg_handle_t handle; printf ("Killing node %d\n", nodeid); result = corosync_cfg_initialize (&handle, NULL); if (result != CS_OK) { printf ("Could not initialize corosync configuration API error %d\n", result); exit (1); } result = corosync_cfg_kill_node (handle, nodeid, "Killed by corosync-cfgtool"); if (result != CS_OK) { printf ("Could not kill node (error = %d)\n", result); } (void)corosync_cfg_finalize (handle); } static void usage_do (void) { - printf ("corosync-cfgtool [-i ] -s] [-r] [-H] [service_name] [-k] [nodeid] [-a] [nodeid]\n\n"); + printf ("corosync-cfgtool [-i ] [-s] [-r] [-R] [-k nodeid] [-a nodeid] [-h] [-H]\n\n"); printf ("A tool for displaying and configuring active parameters within corosync.\n"); printf ("options:\n"); + printf ("\t-i\tFinds only information about the specified interface IP address.\n"); printf ("\t-s\tDisplays the status of the current rings on this node.\n"); printf ("\t-r\tReset redundant ring state cluster wide after a fault to\n"); printf ("\t\tre-enable redundant ring operation.\n"); - printf ("\t-a\tDisplay the IP address(es) of a node\n"); + printf ("\t-R\tTell all instances of corosync in this cluster to reload corosync.conf.\n"); printf ("\t-k\tKill a node identified by node id.\n"); - printf ("\t-R\tReload corosync.conf on all nodes.\n"); + printf ("\t-a\tDisplay the IP address(es) of a node\n"); + printf ("\t-h\tPrint basic usage.\n"); printf ("\t-H\tShutdown corosync cleanly on this node.\n"); } int main (int argc, char *argv[]) { const char *options = "i:srRk:a:hH"; int opt; unsigned int nodeid; char interface_name[128] = ""; int rc=0; if (argc == 1) { usage_do (); } while ( (opt = getopt(argc, argv, options)) != -1 ) { switch (opt) { case 'i': strncpy(interface_name, optarg, sizeof(interface_name)); interface_name[sizeof(interface_name) - 1] = '\0'; break; case 's': rc = ringstatusget_do (interface_name); break; case 'R': rc = reload_config_do (); break; case 'r': ringreenable_do (); break; case 'k': nodeid = atoi (optarg); killnode_do(nodeid); break; case 'H': shutdown_do(); break; case 'a': - showaddrs_do( atoi(optarg) ); + nodeid = atoi (optarg); + showaddrs_do(nodeid); break; case 'h': usage_do(); break; } } return (rc); } diff --git a/tools/corosync-cmapctl.c b/tools/corosync-cmapctl.c index d31a73d1..af0aa142 100644 --- a/tools/corosync-cmapctl.c +++ b/tools/corosync-cmapctl.c @@ -1,878 +1,878 @@ /* * Copyright (c) 2011-2012 Red Hat, Inc. * * All rights reserved. * * Author: Jan Friesse (jfriesse@redhat.com) * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the Red Hat, Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include "../lib/util.h" #ifndef INFTIM #define INFTIM -1 #endif #define MAX_TRY_AGAIN 10 enum user_action { ACTION_GET, ACTION_SET, ACTION_DELETE, ACTION_DELETE_PREFIX, ACTION_PRINT_ALL, ACTION_PRINT_PREFIX, ACTION_TRACK, ACTION_LOAD, }; struct name_to_type_item { const char *name; cmap_value_types_t type; }; struct name_to_type_item name_to_type[] = { {"i8", CMAP_VALUETYPE_INT8}, {"u8", CMAP_VALUETYPE_UINT8}, {"i16", CMAP_VALUETYPE_INT16}, {"u16", CMAP_VALUETYPE_UINT16}, {"i32", CMAP_VALUETYPE_INT32}, {"u32", CMAP_VALUETYPE_UINT32}, {"i64", CMAP_VALUETYPE_INT64}, {"u64", CMAP_VALUETYPE_UINT64}, {"flt", CMAP_VALUETYPE_FLOAT}, {"dbl", CMAP_VALUETYPE_DOUBLE}, {"str", CMAP_VALUETYPE_STRING}, {"bin", CMAP_VALUETYPE_BINARY}}; int show_binary = 0; static int convert_name_to_type(const char *name) { int i; for (i = 0; i < sizeof(name_to_type) / sizeof(*name_to_type); i++) { if (strcmp(name, name_to_type[i].name) == 0) { return (name_to_type[i].type); } } return (-1); } static int print_help(void) { printf("\n"); - printf("usage: corosync-cmapctl [-b] [-dghsTtp] [params...]\n"); + printf("usage: corosync-cmapctl [-b] [-DdghsTt] [-p filename] [params...]\n"); printf("\n"); printf(" -b show binary values\n"); printf("\n"); printf("Set key:\n"); printf(" corosync-cmapctl -s key_name type value\n"); printf("\n"); printf(" where type is one of ([i|u][8|16|32|64] | flt | dbl | str | bin)\n"); printf(" for bin, value is file name (or - for stdin)\n"); printf("\n"); printf("Load settings from a file:\n"); printf(" corosync-cmapctl -p filename\n"); printf("\n"); printf(" the format of the file is:\n"); printf(" [^[^]][ ]\n"); printf(" Keys prefixed with single caret ('^') are deleted (see -d).\n"); printf(" Keys (actually prefixes) prefixed with double caret ('^^') are deleted by prefix (see -D).\n"); printf(" and are optional (not checked) in above cases.\n"); printf(" Other keys are set (see -s) so both and are required.\n"); printf("\n"); printf("Delete key:\n"); printf(" corosync-cmapctl -d key_name...\n"); printf("\n"); printf("Delete multiple keys with prefix:\n"); printf(" corosync-cmapctl -D key_prefix...\n"); printf("\n"); printf("Get key:\n"); printf(" corosync-cmapctl [-b] -g key_name...\n"); printf("\n"); printf("Display all keys:\n"); printf(" corosync-cmapctl [-b]\n"); printf("\n"); printf("Display keys with prefix key_name:\n"); printf(" corosync-cmapctl [-b] key_name...\n"); printf("\n"); printf("Track changes on keys with key_name:\n"); printf(" corosync-cmapctl [-b] -t key_name\n"); printf("\n"); printf("Track changes on keys with key prefix:\n"); printf(" corosync-cmapctl [-b] -T key_prefix\n"); printf("\n"); return (0); } static void print_binary_key (char *value, size_t value_len) { size_t i; char c; for (i = 0; i < value_len; i++) { c = value[i]; if (c >= ' ' && c < 0x7f && c != '\\') { fputc (c, stdout); } else { if (c == '\\') { printf ("\\\\"); } else { printf ("\\x%02X", c); } } } } static void print_key(cmap_handle_t handle, const char *key_name, size_t value_len, const void *value, cmap_value_types_t type) { char *str; char *bin_value = NULL; cs_error_t err; int8_t i8; uint8_t u8; int16_t i16; uint16_t u16; int32_t i32; uint32_t u32; int64_t i64; uint64_t u64; float flt; double dbl; int end_loop; int no_retries; size_t bin_value_len; end_loop = 0; no_retries = 0; err = CS_OK; while (!end_loop) { switch (type) { case CMAP_VALUETYPE_INT8: if (value == NULL) { err = cmap_get_int8(handle, key_name, &i8); } else { i8 = *((int8_t *)value); } break; case CMAP_VALUETYPE_INT16: if (value == NULL) { err = cmap_get_int16(handle, key_name, &i16); } else { i16 = *((int16_t *)value); } break; case CMAP_VALUETYPE_INT32: if (value == NULL) { err = cmap_get_int32(handle, key_name, &i32); } else { i32 = *((int32_t *)value); } break; case CMAP_VALUETYPE_INT64: if (value == NULL) { err = cmap_get_int64(handle, key_name, &i64); } else { i64 = *((int64_t *)value); } break; case CMAP_VALUETYPE_UINT8: if (value == NULL) { err = cmap_get_uint8(handle, key_name, &u8); } else { u8 = *((uint8_t *)value); } break; case CMAP_VALUETYPE_UINT16: if (value == NULL) { err = cmap_get_uint16(handle, key_name, &u16); } else { u16 = *((uint16_t *)value); } break; case CMAP_VALUETYPE_UINT32: if (value == NULL) { err = cmap_get_uint32(handle, key_name, &u32); } else { u32 = *((uint32_t *)value); } break; case CMAP_VALUETYPE_UINT64: if (value == NULL) { err = cmap_get_uint64(handle, key_name, &u64); } else { u64 = *((uint64_t *)value); } break; case CMAP_VALUETYPE_FLOAT: if (value == NULL) { err = cmap_get_float(handle, key_name, &flt); } else { flt = *((float *)value); } break; case CMAP_VALUETYPE_DOUBLE: if (value == NULL) { err = cmap_get_double(handle, key_name, &dbl); } else { dbl = *((double *)value); } break; case CMAP_VALUETYPE_STRING: if (value == NULL) { err = cmap_get_string(handle, key_name, &str); } else { str = (char *)value; } break; case CMAP_VALUETYPE_BINARY: if (show_binary) { if (value == NULL) { bin_value = malloc(value_len); if (bin_value == NULL) { fprintf(stderr, "Can't alloc memory\n"); exit(EXIT_FAILURE); } bin_value_len = value_len; err = cmap_get(handle, key_name, bin_value, &bin_value_len, NULL); } else { bin_value = (char *)value; } } break; } if (err == CS_OK) { end_loop = 1; } else if (err == CS_ERR_TRY_AGAIN) { sleep(1); no_retries++; if (no_retries > MAX_TRY_AGAIN) { end_loop = 1; } } else { end_loop = 1; } }; if (err != CS_OK) { fprintf(stderr, "Can't get value of %s. Error %s\n", key_name, cs_strerror(err)); return ; } printf("%s (", key_name); switch (type) { case CMAP_VALUETYPE_INT8: printf("%s) = %"PRId8, "i8", i8); break; case CMAP_VALUETYPE_UINT8: printf("%s) = %"PRIu8, "u8", u8); break; case CMAP_VALUETYPE_INT16: printf("%s) = %"PRId16, "i16", i16); break; case CMAP_VALUETYPE_UINT16: printf("%s) = %"PRIu16, "u16", u16); break; case CMAP_VALUETYPE_INT32: printf("%s) = %"PRId32, "i32", i32); break; case CMAP_VALUETYPE_UINT32: printf("%s) = %"PRIu32, "u32", u32); break; case CMAP_VALUETYPE_INT64: printf("%s) = %"PRId64, "i64", i64); break; case CMAP_VALUETYPE_UINT64: printf("%s) = %"PRIu64, "u64", u64); break; case CMAP_VALUETYPE_FLOAT: printf("%s) = %f", "flt", flt); break; case CMAP_VALUETYPE_DOUBLE: printf("%s) = %lf", "dbl", dbl); break; case CMAP_VALUETYPE_STRING: printf("%s) = %s", "str", str); if (value == NULL) { free(str); } break; case CMAP_VALUETYPE_BINARY: printf("%s)", "bin"); if (show_binary) { printf(" = "); if (bin_value) { print_binary_key(bin_value, value_len); if (value == NULL) { free(bin_value); } } else { printf("*empty*"); } } break; } printf("\n"); } static void print_iter(cmap_handle_t handle, const char *prefix) { cmap_iter_handle_t iter_handle; char key_name[CMAP_KEYNAME_MAXLEN + 1]; size_t value_len; cmap_value_types_t type; cs_error_t err; err = cmap_iter_init(handle, prefix, &iter_handle); if (err != CS_OK) { fprintf (stderr, "Failed to initialize iteration. Error %s\n", cs_strerror(err)); exit (EXIT_FAILURE); } while ((err = cmap_iter_next(handle, iter_handle, key_name, &value_len, &type)) == CS_OK) { print_key(handle, key_name, value_len, NULL, type); } cmap_iter_finalize(handle, iter_handle); } static void delete_with_prefix(cmap_handle_t handle, const char *prefix) { cmap_iter_handle_t iter_handle; char key_name[CMAP_KEYNAME_MAXLEN + 1]; size_t value_len; cmap_value_types_t type; cs_error_t err; cs_error_t err2; err = cmap_iter_init(handle, prefix, &iter_handle); if (err != CS_OK) { fprintf (stderr, "Failed to initialize iteration. Error %s\n", cs_strerror(err)); exit (EXIT_FAILURE); } while ((err = cmap_iter_next(handle, iter_handle, key_name, &value_len, &type)) == CS_OK) { err2 = cmap_delete(handle, key_name); if (err2 != CS_OK) { fprintf(stderr, "Can't delete key %s. Error %s\n", key_name, cs_strerror(err2)); } } cmap_iter_finalize(handle, iter_handle); } static void cmap_notify_fn( cmap_handle_t cmap_handle, cmap_track_handle_t cmap_track_handle, int32_t event, const char *key_name, struct cmap_notify_value new_val, struct cmap_notify_value old_val, void *user_data) { switch (event) { case CMAP_TRACK_ADD: printf("create> "); print_key(cmap_handle, key_name, new_val.len, new_val.data, new_val.type); break; case CMAP_TRACK_DELETE: printf("delete> "); print_key(cmap_handle, key_name, old_val.len, old_val.data, old_val.type); break; case CMAP_TRACK_MODIFY: printf("modify> "); print_key(cmap_handle, key_name, new_val.len, new_val.data, new_val.type); break; default: printf("unknown change> "); break; } } static void add_track(cmap_handle_t handle, const char *key_name, int prefix) { cmap_track_handle_t track_handle; int32_t track_type; cs_error_t err; track_type = CMAP_TRACK_ADD | CMAP_TRACK_DELETE | CMAP_TRACK_MODIFY; if (prefix) { track_type |= CMAP_TRACK_PREFIX; } err = cmap_track_add(handle, key_name, track_type, cmap_notify_fn, NULL, &track_handle); if (err != CS_OK) { fprintf(stderr, "Failed to add tracking function. Error %s\n", cs_strerror(err)); exit (EXIT_FAILURE); } } static void track_changes(cmap_handle_t handle) { struct pollfd pfd[2]; int cmap_fd; cs_error_t err; int poll_res; char inbuf[3]; int quit = CS_FALSE; err = cmap_fd_get(handle, &cmap_fd); if (err != CS_OK) { fprintf(stderr, "Failed to get file handle. Error %s\n", cs_strerror(err)); exit (EXIT_FAILURE); } pfd[0].fd = cmap_fd; pfd[1].fd = STDIN_FILENO; pfd[0].events = pfd[1].events = POLLIN; printf("Type \"q\" to finish\n"); do { pfd[0].revents = pfd[1].revents = 0; poll_res = poll(pfd, 2, INFTIM); if (poll_res == -1) { perror("poll"); } if (pfd[1].revents & POLLIN) { if (fgets(inbuf, sizeof(inbuf), stdin) == NULL) { quit = CS_TRUE; } else if (strncmp(inbuf, "q", 1) == 0) { quit = CS_TRUE; } } if (pfd[0].revents & POLLIN) { err = cmap_dispatch(handle, CS_DISPATCH_ALL); if (err != CS_OK) { fprintf(stderr, "Dispatch error %s\n", cs_strerror(err)); quit = CS_TRUE; } } } while (poll_res > 0 && !quit); } static cs_error_t set_key_bin(cmap_handle_t handle, const char *key_name, const char *fname) { FILE *f; char *val; char buf[4096]; size_t size; size_t readed; size_t pos; cs_error_t err; if (strcmp(fname, "-") == 0) { f = stdin; } else { f = fopen(fname, "rb"); if (f == NULL) { perror("Can't open input file"); exit(EXIT_FAILURE); } } val = NULL; size = 0; pos = 0; while ((readed = fread(buf, 1, sizeof(buf), f)) != 0) { size += readed; if ((val = realloc(val, size)) == NULL) { fprintf(stderr, "Can't alloc memory\n"); exit (EXIT_FAILURE); } memcpy(val + pos, buf, readed); pos += readed; } if (f != stdin) { fclose(f); } err = cmap_set(handle, key_name, val, size, CMAP_VALUETYPE_BINARY); free(val); return (err); } static void set_key(cmap_handle_t handle, const char *key_name, const char *key_type_s, const char *key_value_s) { int64_t i64; uint64_t u64; double dbl; float flt; cs_error_t err = CS_OK; int scanf_res = 0; cmap_value_types_t type; if (convert_name_to_type(key_type_s) == -1) { fprintf(stderr, "Unknown type %s\n", key_type_s); exit (EXIT_FAILURE); } type = convert_name_to_type(key_type_s); switch (type) { case CMAP_VALUETYPE_INT8: case CMAP_VALUETYPE_INT16: case CMAP_VALUETYPE_INT32: case CMAP_VALUETYPE_INT64: scanf_res = sscanf(key_value_s, "%"PRId64, &i64); break; case CMAP_VALUETYPE_UINT8: case CMAP_VALUETYPE_UINT16: case CMAP_VALUETYPE_UINT32: case CMAP_VALUETYPE_UINT64: scanf_res = sscanf(key_value_s, "%"PRIu64, &u64); break; case CMAP_VALUETYPE_FLOAT: scanf_res = sscanf(key_value_s, "%f", &flt); break; case CMAP_VALUETYPE_DOUBLE: scanf_res = sscanf(key_value_s, "%lf", &dbl); break; case CMAP_VALUETYPE_STRING: case CMAP_VALUETYPE_BINARY: /* * Do nothing */ scanf_res = 1; break; } if (scanf_res != 1) { fprintf(stderr, "%s is not valid %s type value\n", key_value_s, key_type_s); exit(EXIT_FAILURE); } /* * We have parsed value, so insert value */ switch (type) { case CMAP_VALUETYPE_INT8: if (i64 > INT8_MAX || i64 < INT8_MIN) { fprintf(stderr, "%s is not valid i8 integer\n", key_value_s); exit(EXIT_FAILURE); } err = cmap_set_int8(handle, key_name, i64); break; case CMAP_VALUETYPE_INT16: if (i64 > INT16_MAX || i64 < INT16_MIN) { fprintf(stderr, "%s is not valid i16 integer\n", key_value_s); exit(EXIT_FAILURE); } err = cmap_set_int16(handle, key_name, i64); break; case CMAP_VALUETYPE_INT32: if (i64 > INT32_MAX || i64 < INT32_MIN) { fprintf(stderr, "%s is not valid i32 integer\n", key_value_s); exit(EXIT_FAILURE); } err = cmap_set_int32(handle, key_name, i64); break; case CMAP_VALUETYPE_INT64: err = cmap_set_int64(handle, key_name, i64); break; case CMAP_VALUETYPE_UINT8: if (u64 > UINT8_MAX) { fprintf(stderr, "%s is not valid u8 integer\n", key_value_s); exit(EXIT_FAILURE); } err = cmap_set_uint8(handle, key_name, u64); break; case CMAP_VALUETYPE_UINT16: if (u64 > UINT16_MAX) { fprintf(stderr, "%s is not valid u16 integer\n", key_value_s); exit(EXIT_FAILURE); } err = cmap_set_uint16(handle, key_name, u64); break; case CMAP_VALUETYPE_UINT32: if (u64 > UINT32_MAX) { fprintf(stderr, "%s is not valid u32 integer\n", key_value_s); exit(EXIT_FAILURE); } err = cmap_set_uint32(handle, key_name, u64); break; case CMAP_VALUETYPE_UINT64: err = cmap_set_uint64(handle, key_name, u64); break; case CMAP_VALUETYPE_FLOAT: err = cmap_set_float(handle, key_name, flt); break; case CMAP_VALUETYPE_DOUBLE: err = cmap_set_double(handle, key_name, dbl); break; case CMAP_VALUETYPE_STRING: err = cmap_set_string(handle, key_name, key_value_s); break; case CMAP_VALUETYPE_BINARY: err = set_key_bin(handle, key_name, key_value_s); break; } if (err != CS_OK) { fprintf (stderr, "Failed to set key %s. Error %s\n", key_name, cs_strerror(err)); exit (EXIT_FAILURE); } } static void read_in_config_file(cmap_handle_t handle, char * filename) { int ignore; int c; FILE* fh; char buf[1024]; char * line; char *key_name; char *key_type_s; char *key_value_s; fh = fopen(filename, "r"); if (fh == NULL) { perror ("Couldn't open file."); return; } while (fgets (buf, 1024, fh) != NULL) { /* find the first real character, if it is * a '#' then ignore this line. * else process. * if no real characters then also ignore. */ ignore = 1; for (c = 0; c < 1024; c++) { if (isblank (buf[c])) { continue; } if (buf[c] == '#' || buf[c] == '\n') { ignore = 1; break; } ignore = 0; line = &buf[c]; break; } if (ignore == 1) { continue; } /* * should be: * [^[^]][ ] */ key_name = strtok(line, " \n"); if (key_name && *key_name == '^') { key_name++; if (*key_name == '^') { key_name++; delete_with_prefix(handle, key_name); } else { cs_error_t err; err = cmap_delete(handle, key_name); if (err != CS_OK) { fprintf(stderr, "Can't delete key %s. Error %s\n", key_name, cs_strerror(err)); } } } else { key_type_s = strtok(NULL, " \n"); key_value_s = strtok(NULL, " \n"); set_key(handle, key_name, key_type_s, key_value_s); } } fclose (fh); } int main(int argc, char *argv[]) { enum user_action action; int c; cs_error_t err; cmap_handle_t handle; int i; size_t value_len; cmap_value_types_t type; int track_prefix; int no_retries; char * settings_file = NULL; action = ACTION_PRINT_PREFIX; track_prefix = 1; while ((c = getopt(argc, argv, "hgsdDtTbp:")) != -1) { switch (c) { case 'h': return print_help(); break; case 'b': show_binary++; break; case 'g': action = ACTION_GET; break; case 's': action = ACTION_SET; break; case 'd': action = ACTION_DELETE; break; case 'D': action = ACTION_DELETE_PREFIX; break; case 'p': settings_file = optarg; action = ACTION_LOAD; break; case 't': action = ACTION_TRACK; track_prefix = 0; break; case 'T': action = ACTION_TRACK; break; case '?': return (EXIT_FAILURE); break; default: action = ACTION_PRINT_PREFIX; break; } } if (argc == 1 || (argc == 2 && show_binary)) { action = ACTION_PRINT_ALL; } argc -= optind; argv += optind; if (argc == 0 && action != ACTION_LOAD && action != ACTION_PRINT_ALL) { fprintf(stderr, "Expected key after options\n"); return (EXIT_FAILURE); } no_retries = 0; while ((err = cmap_initialize(&handle)) == CS_ERR_TRY_AGAIN && no_retries++ < MAX_TRY_AGAIN) { sleep(1); } if (err != CS_OK) { fprintf (stderr, "Failed to initialize the cmap API. Error %s\n", cs_strerror(err)); exit (EXIT_FAILURE); } switch (action) { case ACTION_PRINT_ALL: print_iter(handle, NULL); break; case ACTION_PRINT_PREFIX: for (i = 0; i < argc; i++) { print_iter(handle, argv[i]); } break; case ACTION_GET: for (i = 0; i < argc; i++) { err = cmap_get(handle, argv[i], NULL, &value_len, &type); if (err == CS_OK) { print_key(handle, argv[i], value_len, NULL, type); } else { fprintf(stderr, "Can't get key %s. Error %s\n", argv[i], cs_strerror(err)); } } break; case ACTION_DELETE: for (i = 0; i < argc; i++) { err = cmap_delete(handle, argv[i]); if (err != CS_OK) { fprintf(stderr, "Can't delete key %s. Error %s\n", argv[i], cs_strerror(err)); } } break; case ACTION_DELETE_PREFIX: for (i = 0; i < argc; i++) { delete_with_prefix(handle, argv[i]); } break; case ACTION_LOAD: read_in_config_file(handle, settings_file); break; case ACTION_TRACK: for (i = 0; i < argc; i++) { add_track(handle, argv[i], track_prefix); } track_changes(handle); break; case ACTION_SET: if (argc < 3) { fprintf(stderr, "At least 3 parameters are expected for set\n"); return (EXIT_FAILURE); } set_key(handle, argv[0], argv[1], argv[2]); break; } err = cmap_finalize(handle); if (err != CS_OK) { fprintf (stderr, "Failed to finalize the cmap API. Error %s\n", cs_strerror(err)); exit (EXIT_FAILURE); } return (0); } diff --git a/tools/corosync-cpgtool.c b/tools/corosync-cpgtool.c index 719d10b6..a5fc118b 100644 --- a/tools/corosync-cpgtool.c +++ b/tools/corosync-cpgtool.c @@ -1,271 +1,271 @@ /* * Copyright (c) 2009-2011 Red Hat, Inc. * * All rights reserved. * * Author: Jan Friesse * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the MontaVista Software, Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static corosync_cfg_handle_t cfg_handle; static cpg_handle_t cpg_handle; typedef enum { OPER_NAMES_ONLY = 1, OPER_FULL_OUTPUT = 2, } operation_t; static void fprint_addrs(FILE *f, int nodeid) { int numaddrs; int i; corosync_cfg_node_address_t addrs[INTERFACE_MAX]; if (corosync_cfg_get_node_addrs(cfg_handle, nodeid, INTERFACE_MAX, &numaddrs, addrs) == CS_OK) { for (i=0; iss_family == AF_INET6) saddr = &sin6->sin6_addr; else saddr = &sin->sin_addr; inet_ntop(ss->ss_family, saddr, buf, sizeof(buf)); if (i != 0) { fprintf(f, " "); } fprintf(f, "%s", buf); } } } static void fprint_group (FILE *f, int escape, const struct cpg_name *group) { int i; char c; for (i = 0; i < group->length; i++) { c = group->value[i]; if (!escape || (c >= ' ' && c < 0x7f && c != '\\')) { fputc (c, f); } else { if (c == '\\') fprintf (f, "\\\\"); else fprintf (f, "\\x%02X", c); } } } static int display_groups (char delimiter, int escape) { cs_error_t res; cpg_iteration_handle_t iter_handle; struct cpg_iteration_description_t description; res = cpg_iteration_initialize (cpg_handle, CPG_ITERATION_NAME_ONLY, NULL, &iter_handle); if (res != CS_OK) { fprintf (stderr, "Cannot initialize cpg iterator error %d\n", res); return 0; } while ((res = cpg_iteration_next (iter_handle, &description)) == CS_OK) { fprint_group (stdout, escape, &description.group); fputc ((delimiter ? delimiter : '\n'), stdout); } if (delimiter) putc ('\n', stdout); cpg_iteration_finalize (iter_handle); return 1; } static inline int group_name_compare ( const struct cpg_name *g1, const struct cpg_name *g2) { return (g1->length == g2->length? memcmp (g1->value, g2->value, g1->length): g1->length - g2->length); } static int display_groups_with_members (char delimiter, int escape) { cs_error_t res; cpg_iteration_handle_t iter_handle; struct cpg_iteration_description_t description; struct cpg_name old_group; res = cpg_iteration_initialize (cpg_handle, CPG_ITERATION_ALL, NULL, &iter_handle); if (res != CS_OK) { fprintf (stderr, "Cannot initialize cpg iterator error %d\n", res); return 0; } memset (&old_group, 0, sizeof (struct cpg_name)); if (delimiter) { fprintf (stdout, "GRP_NAME%cPID%cNODEID\n", delimiter, delimiter); } else { fprintf (stdout, "Group Name\t%10s\t%10s\n", "PID", "Node ID"); } while ((res = cpg_iteration_next (iter_handle, &description)) == CS_OK) { if (!delimiter && group_name_compare (&old_group, &description.group) != 0) { fprint_group (stdout, escape, &description.group); fprintf (stdout, "\n"); memcpy (&old_group, &description.group, sizeof (struct cpg_name)); } if (!delimiter) { fprintf (stdout, "\t\t%10u\t%10u (", description.pid, description.nodeid); fprint_addrs (stdout, description.nodeid); fprintf (stdout, ")\n"); } else { fprint_group (stdout, escape, &description.group); fprintf (stdout, "%c%u%c%u\n", delimiter, description.pid, delimiter, description.nodeid); } } if (res != CS_ERR_NO_SECTIONS) { fprintf (stderr, "cpg iteration error %d\n", res); return 0; } cpg_iteration_finalize (iter_handle); return 1; } static void usage_do (const char *prog_name) { printf ("%s [-d delimiter] [-e] [-n] [-h]\n\n", prog_name); printf ("A tool for displaying cpg groups and members.\n"); printf ("options:\n"); printf ("\t-d\tDelimiter between fields.\n"); - printf ("\t-e\tDon't escape unprintable characters in group name\n"); + printf ("\t-e\tDon't escape unprintable characters in group name.\n"); printf ("\t-n\tDisplay only all existing group names.\n"); printf ("\t-h\tDisplay this help.\n"); } int main (int argc, char *argv[]) { const char *options = "hd:ne"; int opt; const char *prog_name = basename(argv[0]); char delimiter = 0; int escape = 1; operation_t operation = OPER_FULL_OUTPUT; int result; while ( (opt = getopt(argc, argv, options)) != -1 ) { switch (opt) { case 'd': if (strlen (optarg) > 0) { delimiter = optarg[0]; } break; case 'n': operation = OPER_NAMES_ONLY; break; case 'e': escape = 0; break; case 'h': usage_do (prog_name); return (EXIT_SUCCESS); break; case '?': case ':': return (EXIT_FAILURE); break; } } result = cpg_initialize (&cpg_handle, NULL); if (result != CS_OK) { fprintf (stderr, "Could not initialize corosync cpg API error %d\n", result); return (EXIT_FAILURE); } result = corosync_cfg_initialize (&cfg_handle, NULL); if (result != CS_OK) { fprintf (stderr, "Could not initialize corosync configuration API error %d\n", result); return (EXIT_FAILURE); } switch (operation) { case OPER_NAMES_ONLY: result = display_groups (delimiter, escape); break; case OPER_FULL_OUTPUT: result = display_groups_with_members (delimiter, escape); break; } cpg_finalize (cpg_handle); corosync_cfg_finalize (cfg_handle); return (result ? EXIT_SUCCESS : EXIT_FAILURE); } diff --git a/tools/corosync-keygen.c b/tools/corosync-keygen.c index 668d6e93..695ed31e 100644 --- a/tools/corosync-keygen.c +++ b/tools/corosync-keygen.c @@ -1,161 +1,162 @@ /* * Copyright (c) 2004 MontaVista Software, Inc. * Copyright (c) 2005-2011 Red Hat, Inc. * * All rights reserved. * * Author: Steven Dake (sdake@redhat.com) * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the MontaVista Software, Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #define DEFAULT_KEYFILE COROSYSCONFDIR "/authkey" static const char usage[] = - "Usage: corosync-keygen [-k ] [-l]\n" + "Usage: corosync-keygen [-k ] [-l] [-h]\n" " -k / --key-file= - Write to the specified keyfile\n" " instead of the default " DEFAULT_KEYFILE ".\n" " -l / --less-secure - Use a less secure random number source\n" " (/dev/urandom) that is guaranteed not to require user\n" " input for entropy. This can be used when this\n" - " application is used from a script.\n"; + " application is used from a script.\n" + " -h / --help - Print basic usage.\n"; int main (int argc, char *argv[]) { int authkey_fd; int random_fd; char *keyfile = NULL; unsigned char key[128]; ssize_t res; ssize_t bytes_read; int c; int option_index; int less_secure = 0; static struct option long_options[] = { { "key-file", required_argument, NULL, 'k' }, { "less-secure", no_argument, NULL, 'l' }, { "help", no_argument, NULL, 'h' }, { 0, 0, NULL, 0 }, }; while ((c = getopt_long (argc, argv, "k:lh", long_options, &option_index)) != -1) { switch (c) { case 'k': keyfile = optarg; break; case 'l': less_secure = 1; break; case 'h': printf ("%s\n", usage); exit(0); break; default: printf ("Error parsing command line options.\n"); exit (1); } } printf ("Corosync Cluster Engine Authentication key generator.\n"); if (!keyfile) { keyfile = (char *)DEFAULT_KEYFILE; } if (less_secure) { printf ("Gathering %lu bits for key from /dev/urandom.\n", (unsigned long)(sizeof (key) * 8)); random_fd = open ("/dev/urandom", O_RDONLY); } else { printf ("Gathering %lu bits for key from /dev/random.\n", (unsigned long)(sizeof (key) * 8)); printf ("Press keys on your keyboard to generate entropy.\n"); random_fd = open ("/dev/random", O_RDONLY); } if (random_fd == -1) { err (1, "Failed to open random source"); } /* * Read random data */ bytes_read = 0; retry_read: res = read (random_fd, &key[bytes_read], sizeof (key) - bytes_read); if (res == -1) { err (1, "Could not read /dev/random"); } bytes_read += res; if (bytes_read != sizeof (key)) { printf ("Press keys on your keyboard to generate entropy (bits = %d).\n", (int)(bytes_read * 8)); goto retry_read; } close (random_fd); /* * Open key */ authkey_fd = open (keyfile, O_CREAT|O_WRONLY, 0600); if (authkey_fd == -1) { err (2, "Could not create %s", keyfile); } if (fchmod (authkey_fd, 0400)) { err (3, "Failed to set key file permissions to 0400"); } printf ("Writing corosync key to %s.\n", keyfile); /* * Write key */ res = write (authkey_fd, key, sizeof (key)); if (res != sizeof (key)) { err (4, "Could not write %s", keyfile); } if (close (authkey_fd)) { err (5, "Could not close %s", keyfile); } return (0); } diff --git a/tools/corosync-notifyd.c b/tools/corosync-notifyd.c index 4688ed7a..bd16208d 100644 --- a/tools/corosync-notifyd.c +++ b/tools/corosync-notifyd.c @@ -1,1222 +1,1222 @@ /* * Copyright (c) 2011-2012 Red Hat, Inc. * * All rights reserved. * * Author: Angus Salkeld * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the MontaVista Software, Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * generic declarations */ enum { CS_NTF_LOG, CS_NTF_STDOUT, CS_NTF_SNMP, CS_NTF_DBUS, CS_NTF_FG, CS_NTF_MAX, }; static int conf[CS_NTF_MAX]; static int32_t _cs_is_quorate = 0; typedef void (*node_membership_fn_t)(char *nodename, uint32_t nodeid, char *state, char* ip); typedef void (*node_quorum_fn_t)(char *nodename, uint32_t nodeid, const char *state); typedef void (*application_connection_fn_t)(char *nodename, uint32_t nodeid, char *app_name, const char *state); typedef void (*rrp_faulty_fn_t)(char *nodename, uint32_t nodeid, uint32_t iface_no, const char *state); struct notify_callbacks { node_membership_fn_t node_membership_fn; node_quorum_fn_t node_quorum_fn; application_connection_fn_t application_connection_fn; rrp_faulty_fn_t rrp_faulty_fn; }; #define MAX_NOTIFIERS 5 static int num_notifiers = 0; static struct notify_callbacks notifiers[MAX_NOTIFIERS]; static uint32_t local_nodeid = 0; static char local_nodename[CS_MAX_NAME_LENGTH]; static qb_loop_t *main_loop; static quorum_handle_t quorum_handle; static void _cs_node_membership_event(char *nodename, uint32_t nodeid, char *state, char* ip); static void _cs_node_quorum_event(const char *state); static void _cs_application_connection_event(char *app_name, const char *state); static void _cs_rrp_faulty_event(uint32_t iface_no, const char *state); #ifdef HAVE_DBUS #include /* * dbus */ #define DBUS_CS_NAME "org.corosync" #define DBUS_CS_IFACE "org.corosync" #define DBUS_CS_PATH "/org/corosync" static DBusConnection *db = NULL; static char _err[512]; static int err_set = 0; static void _cs_dbus_init(void); #endif /* HAVE_DBUS */ #ifdef ENABLE_SNMP #include #include #include #include #include #include #include enum snmp_node_status { SNMP_NODE_STATUS_UNKNOWN = 0, SNMP_NODE_STATUS_JOINED = 1, SNMP_NODE_STATUS_LEFT = 2 }; #define SNMP_OID_COROSYNC "1.3.6.1.4.1.35488" #define SNMP_OID_OBJECT_ROOT SNMP_OID_COROSYNC ".1" #define SNMP_OID_OBJECT_NODE_NAME SNMP_OID_OBJECT_ROOT ".1" #define SNMP_OID_OBJECT_NODE_ID SNMP_OID_OBJECT_ROOT ".2" #define SNMP_OID_OBJECT_NODE_STATUS SNMP_OID_OBJECT_ROOT ".3" #define SNMP_OID_OBJECT_NODE_ADDR SNMP_OID_OBJECT_ROOT ".4" #define SNMP_OID_OBJECT_RINGSEQ SNMP_OID_OBJECT_ROOT ".20" #define SNMP_OID_OBJECT_QUORUM SNMP_OID_OBJECT_ROOT ".21" #define SNMP_OID_OBJECT_APP_NAME SNMP_OID_OBJECT_ROOT ".40" #define SNMP_OID_OBJECT_APP_STATUS SNMP_OID_OBJECT_ROOT ".41" #define SNMP_OID_OBJECT_RRP_IFACE_NO SNMP_OID_OBJECT_ROOT ".60" #define SNMP_OID_OBJECT_RRP_STATUS SNMP_OID_OBJECT_ROOT ".61" #define SNMP_OID_TRAPS_ROOT SNMP_OID_COROSYNC ".0" #define SNMP_OID_TRAPS_NODE SNMP_OID_TRAPS_ROOT ".1" #define SNMP_OID_TRAPS_QUORUM SNMP_OID_TRAPS_ROOT ".2" #define SNMP_OID_TRAPS_APP SNMP_OID_TRAPS_ROOT ".3" #define SNMP_OID_TRAPS_RRP SNMP_OID_TRAPS_ROOT ".4" #define CS_TIMESTAMP_STR_LEN 20 static const char *local_host = "localhost"; #endif /* ENABLE_SNMP */ static char snmp_manager_buf[CS_MAX_NAME_LENGTH]; static char *snmp_manager = NULL; #define CMAP_MAX_RETRIES 10 /* * cmap */ static cmap_handle_t cmap_handle; static int32_t _cs_ip_to_hostname(char* ip, char* name_out) { struct sockaddr_in sa; int rc; if (strchr(ip, ':') == NULL) { sa.sin_family = AF_INET; } else { sa.sin_family = AF_INET6; } rc = inet_pton(sa.sin_family, ip, &sa.sin_addr); if (rc == 0) { return -EINVAL; } rc = getnameinfo((struct sockaddr*)&sa, sizeof(sa), name_out, CS_MAX_NAME_LENGTH, NULL, 0, 0); if (rc != 0) { qb_log(LOG_ERR, 0, "error looking up %s : %s", ip, gai_strerror(rc)); return -EINVAL; } return 0; } static void _cs_cmap_members_key_changed ( cmap_handle_t cmap_handle_c, cmap_track_handle_t cmap_track_handle, int32_t event, const char *key_name, struct cmap_notify_value new_value, struct cmap_notify_value old_value, void *user_data) { char nodename[CS_MAX_NAME_LENGTH]; char* open_bracket = NULL; char* close_bracket = NULL; int res; uint32_t nodeid; char *ip_str; char tmp_key[CMAP_KEYNAME_MAXLEN]; cs_error_t err; int no_retries; if (event != CMAP_TRACK_ADD && event != CMAP_TRACK_MODIFY) { return ; } res = sscanf(key_name, "runtime.totem.pg.mrp.srp.members.%u.%s", &nodeid, tmp_key); if (res != 2) return ; if (strcmp(tmp_key, "status") != 0) { return ; } snprintf(tmp_key, CMAP_KEYNAME_MAXLEN, "runtime.totem.pg.mrp.srp.members.%u.ip", nodeid); no_retries = 0; while ((err = cmap_get_string(cmap_handle, tmp_key, &ip_str)) == CS_ERR_TRY_AGAIN && no_retries++ < CMAP_MAX_RETRIES) { sleep(1); } if (err != CS_OK) { return ; } /* * We want the ip out of: "r(0) ip(192.168.100.92)" */ open_bracket = strrchr(ip_str, '('); open_bracket++; close_bracket = strrchr(open_bracket, ')'); *close_bracket = '\0'; _cs_ip_to_hostname(open_bracket, nodename); _cs_node_membership_event(nodename, nodeid, (char *)new_value.data, open_bracket); free(ip_str); } static void _cs_cmap_connections_key_changed ( cmap_handle_t cmap_handle_c, cmap_track_handle_t cmap_track_handle, int32_t event, const char *key_name, struct cmap_notify_value new_value, struct cmap_notify_value old_value, void *user_data) { char obj_name[CS_MAX_NAME_LENGTH]; char conn_str[CMAP_KEYNAME_MAXLEN]; char tmp_key[CMAP_KEYNAME_MAXLEN]; int res; res = sscanf(key_name, "runtime.connections.%[^.].%s", conn_str, tmp_key); if (res != 2) { return ; } if (strcmp(tmp_key, "service_id") != 0) { return ; } snprintf(obj_name, CS_MAX_NAME_LENGTH, "%s", conn_str); if (event == CMAP_TRACK_ADD) { _cs_application_connection_event(obj_name, "connected"); } if (event == CMAP_TRACK_DELETE) { _cs_application_connection_event(obj_name, "disconnected"); } } static void _cs_cmap_rrp_faulty_key_changed ( cmap_handle_t cmap_handle_c, cmap_track_handle_t cmap_track_handle, int32_t event, const char *key_name, struct cmap_notify_value new_value, struct cmap_notify_value old_value, void *user_data) { uint32_t iface_no; char tmp_key[CMAP_KEYNAME_MAXLEN]; int res; int no_retries; uint8_t faulty; cs_error_t err; res = sscanf(key_name, "runtime.totem.pg.mrp.rrp.%u.%s", &iface_no, tmp_key); if (res != 2) { return ; } if (strcmp(tmp_key, "faulty") != 0) { return ; } no_retries = 0; while ((err = cmap_get_uint8(cmap_handle, key_name, &faulty)) == CS_ERR_TRY_AGAIN && no_retries++ < CMAP_MAX_RETRIES) { sleep(1); } if (err != CS_OK) { return ; } if (faulty) { _cs_rrp_faulty_event(iface_no, "faulty"); } else { _cs_rrp_faulty_event(iface_no, "operational"); } } static int _cs_cmap_dispatch(int fd, int revents, void *data) { cs_error_t err; err = cmap_dispatch(cmap_handle, CS_DISPATCH_ONE); if (err != CS_OK && err != CS_ERR_TRY_AGAIN && err != CS_ERR_TIMEOUT && err != CS_ERR_QUEUE_FULL) { qb_log(LOG_ERR, "Could not dispatch cmap events. Error %u", err); qb_loop_stop(main_loop); return -1; } return 0; } static void _cs_quorum_notification(quorum_handle_t handle, uint32_t quorate, uint64_t ring_seq, uint32_t view_list_entries, uint32_t *view_list) { if (_cs_is_quorate == quorate) { return; } _cs_is_quorate = quorate; if (quorate) { _cs_node_quorum_event("quorate"); } else { _cs_node_quorum_event("not quorate"); } } static int _cs_quorum_dispatch(int fd, int revents, void *data) { cs_error_t err; err = quorum_dispatch(quorum_handle, CS_DISPATCH_ONE); if (err != CS_OK && err != CS_ERR_TRY_AGAIN && err != CS_ERR_TIMEOUT && err != CS_ERR_QUEUE_FULL) { qb_log(LOG_ERR, "Could not dispatch quorum events. Error %u", err); qb_loop_stop(main_loop); return -1; } return 0; } static void _cs_quorum_init(void) { cs_error_t rc; uint32_t quorum_type; int fd; quorum_callbacks_t quorum_callbacks = { .quorum_notify_fn = _cs_quorum_notification, }; rc = quorum_initialize (&quorum_handle, &quorum_callbacks, &quorum_type); if (rc != CS_OK) { qb_log(LOG_ERR, "Could not connect to corosync(quorum)"); return; } quorum_fd_get(quorum_handle, &fd); qb_loop_poll_add(main_loop, QB_LOOP_MED, fd, POLLIN|POLLNVAL, NULL, _cs_quorum_dispatch); rc = quorum_trackstart(quorum_handle, CS_TRACK_CHANGES); if (rc != CS_OK) { qb_log(LOG_ERR, "Could not start tracking"); return; } } static void _cs_quorum_finalize(void) { quorum_finalize (quorum_handle); } #ifdef HAVE_DBUS /* * dbus notifications */ static void _cs_dbus_auto_flush(void) { dbus_connection_ref(db); while (dbus_connection_get_dispatch_status(db) == DBUS_DISPATCH_DATA_REMAINS) { dbus_connection_dispatch(db); } while (dbus_connection_has_messages_to_send(db)) { dbus_connection_flush(db); } dbus_connection_unref(db); } static void _cs_dbus_release(void) { DBusError err; if (!db) return; dbus_error_init(&err); dbus_bus_release_name(db, DBUS_CS_NAME, &err); dbus_error_free(&err); dbus_connection_unref(db); db = NULL; } static void _cs_dbus_node_quorum_event(char *nodename, uint32_t nodeid, const char *state) { DBusMessage *msg = NULL; if (err_set) { qb_log(LOG_ERR, "%s", _err); err_set = 0; } if (!db) { goto out_free; } if (dbus_connection_get_is_connected(db) != TRUE) { err_set = 1; snprintf(_err, sizeof(_err), "DBus connection lost"); _cs_dbus_release(); goto out_unlock; } _cs_dbus_auto_flush(); if (!(msg = dbus_message_new_signal(DBUS_CS_PATH, DBUS_CS_IFACE, "QuorumStateChange"))) { qb_log(LOG_ERR, "error creating dbus signal"); goto out_unlock; } if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &nodename, DBUS_TYPE_UINT32, &nodeid, DBUS_TYPE_STRING, &state, DBUS_TYPE_INVALID)) { qb_log(LOG_ERR, "error adding args to quorum signal"); goto out_unlock; } dbus_connection_send(db, msg, NULL); out_unlock: if (msg) { dbus_message_unref(msg); } out_free: return; } static void _cs_dbus_node_membership_event(char *nodename, uint32_t nodeid, char *state, char* ip) { DBusMessage *msg = NULL; if (err_set) { qb_log(LOG_ERR, "%s", _err); err_set = 0; } if (!db) { goto out_free; } if (dbus_connection_get_is_connected(db) != TRUE) { err_set = 1; snprintf(_err, sizeof(_err), "DBus connection lost"); _cs_dbus_release(); goto out_unlock; } _cs_dbus_auto_flush(); if (!(msg = dbus_message_new_signal(DBUS_CS_PATH, DBUS_CS_IFACE, "NodeStateChange"))) { qb_log(LOG_ERR, "error creating NodeStateChange signal"); goto out_unlock; } if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &nodename, DBUS_TYPE_UINT32, &nodeid, DBUS_TYPE_STRING, &ip, DBUS_TYPE_STRING, &state, DBUS_TYPE_INVALID)) { qb_log(LOG_ERR, "error adding args to NodeStateChange signal"); goto out_unlock; } dbus_connection_send(db, msg, NULL); out_unlock: if (msg) { dbus_message_unref(msg); } out_free: return; } static void _cs_dbus_application_connection_event(char *nodename, uint32_t nodeid, char *app_name, const char *state) { DBusMessage *msg = NULL; if (err_set) { qb_log(LOG_ERR, "%s", _err); err_set = 0; } if (!db) { goto out_free; } if (dbus_connection_get_is_connected(db) != TRUE) { err_set = 1; snprintf(_err, sizeof(_err), "DBus connection lost"); _cs_dbus_release(); goto out_unlock; } _cs_dbus_auto_flush(); if (!(msg = dbus_message_new_signal(DBUS_CS_PATH, DBUS_CS_IFACE, "ConnectionStateChange"))) { qb_log(LOG_ERR, "error creating ConnectionStateChange signal"); goto out_unlock; } if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &nodename, DBUS_TYPE_UINT32, &nodeid, DBUS_TYPE_STRING, &app_name, DBUS_TYPE_STRING, &state, DBUS_TYPE_INVALID)) { qb_log(LOG_ERR, "error adding args to ConnectionStateChange signal"); goto out_unlock; } dbus_connection_send(db, msg, NULL); out_unlock: if (msg) { dbus_message_unref(msg); } out_free: return; } static void _cs_dbus_rrp_faulty_event(char *nodename, uint32_t nodeid, uint32_t iface_no, const char *state) { DBusMessage *msg = NULL; if (err_set) { qb_log(LOG_ERR, "%s", _err); err_set = 0; } if (!db) { goto out_free; } if (dbus_connection_get_is_connected(db) != TRUE) { err_set = 1; snprintf(_err, sizeof(_err), "DBus connection lost"); _cs_dbus_release(); goto out_unlock; } _cs_dbus_auto_flush(); if (!(msg = dbus_message_new_signal(DBUS_CS_PATH, DBUS_CS_IFACE, "QuorumStateChange"))) { qb_log(LOG_ERR, "error creating dbus signal"); goto out_unlock; } if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &nodename, DBUS_TYPE_UINT32, &nodeid, DBUS_TYPE_UINT32, &iface_no, DBUS_TYPE_STRING, &state, DBUS_TYPE_INVALID)) { qb_log(LOG_ERR, "error adding args to rrp signal"); goto out_unlock; } dbus_connection_send(db, msg, NULL); out_unlock: if (msg) { dbus_message_unref(msg); } out_free: return; } static void _cs_dbus_init(void) { DBusConnection *dbc = NULL; DBusError err; dbus_error_init(&err); dbc = dbus_bus_get(DBUS_BUS_SYSTEM, &err); if (!dbc) { snprintf(_err, sizeof(_err), "dbus_bus_get: %s", err.message); err_set = 1; dbus_error_free(&err); return; } dbus_connection_set_exit_on_disconnect(dbc, FALSE); db = dbc; notifiers[num_notifiers].node_membership_fn = _cs_dbus_node_membership_event; notifiers[num_notifiers].node_quorum_fn = _cs_dbus_node_quorum_event; notifiers[num_notifiers].application_connection_fn = _cs_dbus_application_connection_event; notifiers[num_notifiers].rrp_faulty_fn = _cs_dbus_rrp_faulty_event; num_notifiers++; } #endif /* HAVE_DBUS */ #ifdef ENABLE_SNMP static netsnmp_session *snmp_init (const char *target) { static netsnmp_session *session = NULL; #ifndef NETSNMPV54 char default_port[128]; snprintf (default_port, sizeof (default_port), "%s:162", target); #endif if (session) { return (session); } if (target == NULL) { return NULL; } session = malloc (sizeof (netsnmp_session)); snmp_sess_init (session); session->version = SNMP_VERSION_2c; session->callback = NULL; session->callback_magic = NULL; session = snmp_add(session, #ifdef NETSNMPV54 netsnmp_transport_open_client ("snmptrap", target), #else netsnmp_tdomain_transport (default_port, 0, "udp"), #endif NULL, NULL); if (session == NULL) { qb_log(LOG_ERR, 0, "Could not create snmp transport"); } return (session); } static inline void add_field ( netsnmp_pdu *trap_pdu, u_char asn_type, const char *prefix, void *value, size_t value_size) { oid _oid[MAX_OID_LEN]; size_t _oid_len = MAX_OID_LEN; if (snmp_parse_oid(prefix, _oid, &_oid_len)) { snmp_pdu_add_variable (trap_pdu, _oid, _oid_len, asn_type, (u_char *) value, value_size); } } static void _cs_snmp_node_membership_event(char *nodename, uint32_t nodeid, char *state, char* ip) { int ret; char csysuptime[CS_TIMESTAMP_STR_LEN]; static oid snmptrap_oid[] = { 1,3,6,1,6,3,1,1,4,1,0 }; static oid sysuptime_oid[] = { 1,3,6,1,2,1,1,3,0 }; time_t now = time (NULL); netsnmp_pdu *trap_pdu; netsnmp_session *session = snmp_init (snmp_manager); if (session == NULL) { qb_log(LOG_NOTICE, "Failed to init SNMP session."); return ; } trap_pdu = snmp_pdu_create (SNMP_MSG_TRAP2); if (!trap_pdu) { qb_log(LOG_NOTICE, "Failed to create SNMP notification."); return ; } /* send uptime */ snprintf (csysuptime, CS_TIMESTAMP_STR_LEN, "%ld", now); snmp_add_var (trap_pdu, sysuptime_oid, sizeof (sysuptime_oid) / sizeof (oid), 't', csysuptime); snmp_add_var (trap_pdu, snmptrap_oid, sizeof (snmptrap_oid) / sizeof (oid), 'o', SNMP_OID_TRAPS_NODE); /* Add extries to the trap */ add_field (trap_pdu, ASN_OCTET_STR, SNMP_OID_OBJECT_NODE_NAME, (void*)nodename, strlen (nodename)); add_field (trap_pdu, ASN_UNSIGNED, SNMP_OID_OBJECT_NODE_ID, (void*)&nodeid, sizeof (nodeid)); add_field (trap_pdu, ASN_OCTET_STR, SNMP_OID_OBJECT_NODE_ADDR, (void*)ip, strlen (ip)); add_field (trap_pdu, ASN_OCTET_STR, SNMP_OID_OBJECT_NODE_STATUS, (void*)state, strlen (state)); /* Send and cleanup */ ret = snmp_send (session, trap_pdu); if (ret == 0) { /* error */ qb_log(LOG_ERR, "Could not send SNMP trap"); snmp_free_pdu (trap_pdu); } } static void _cs_snmp_node_quorum_event(char *nodename, uint32_t nodeid, const char *state) { int ret; char csysuptime[20]; static oid snmptrap_oid[] = { 1,3,6,1,6,3,1,1,4,1,0 }; static oid sysuptime_oid[] = { 1,3,6,1,2,1,1,3,0 }; time_t now = time (NULL); netsnmp_pdu *trap_pdu; netsnmp_session *session = snmp_init (snmp_manager); if (session == NULL) { qb_log(LOG_NOTICE, "Failed to init SNMP session."); return ; } trap_pdu = snmp_pdu_create (SNMP_MSG_TRAP2); if (!trap_pdu) { qb_log(LOG_NOTICE, "Failed to create SNMP notification."); return ; } /* send uptime */ sprintf (csysuptime, "%ld", now); snmp_add_var (trap_pdu, sysuptime_oid, sizeof (sysuptime_oid) / sizeof (oid), 't', csysuptime); snmp_add_var (trap_pdu, snmptrap_oid, sizeof (snmptrap_oid) / sizeof (oid), 'o', SNMP_OID_TRAPS_QUORUM); /* Add extries to the trap */ add_field (trap_pdu, ASN_OCTET_STR, SNMP_OID_OBJECT_NODE_NAME, (void*)nodename, strlen (nodename)); add_field (trap_pdu, ASN_UNSIGNED, SNMP_OID_OBJECT_NODE_ID, (void*)&nodeid, sizeof (nodeid)); add_field (trap_pdu, ASN_OCTET_STR, SNMP_OID_OBJECT_QUORUM, (void*)state, strlen (state)); /* Send and cleanup */ ret = snmp_send (session, trap_pdu); if (ret == 0) { /* error */ qb_log(LOG_ERR, "Could not send SNMP trap"); snmp_free_pdu (trap_pdu); } } static void _cs_snmp_rrp_faulty_event(char *nodename, uint32_t nodeid, uint32_t iface_no, const char *state) { int ret; char csysuptime[20]; static oid snmptrap_oid[] = { 1,3,6,1,6,3,1,1,4,1,0 }; static oid sysuptime_oid[] = { 1,3,6,1,2,1,1,3,0 }; time_t now = time (NULL); netsnmp_pdu *trap_pdu; netsnmp_session *session = snmp_init (snmp_manager); if (session == NULL) { qb_log(LOG_NOTICE, "Failed to init SNMP session."); return ; } trap_pdu = snmp_pdu_create (SNMP_MSG_TRAP2); if (!trap_pdu) { qb_log(LOG_NOTICE, "Failed to create SNMP notification."); return ; } /* send uptime */ sprintf (csysuptime, "%ld", now); snmp_add_var (trap_pdu, sysuptime_oid, sizeof (sysuptime_oid) / sizeof (oid), 't', csysuptime); snmp_add_var (trap_pdu, snmptrap_oid, sizeof (snmptrap_oid) / sizeof (oid), 'o', SNMP_OID_TRAPS_RRP); /* Add extries to the trap */ add_field (trap_pdu, ASN_OCTET_STR, SNMP_OID_OBJECT_NODE_NAME, (void*)nodename, strlen (nodename)); add_field (trap_pdu, ASN_UNSIGNED, SNMP_OID_OBJECT_NODE_ID, (void*)&nodeid, sizeof (nodeid)); add_field (trap_pdu, ASN_INTEGER, SNMP_OID_OBJECT_RRP_IFACE_NO, (void*)&iface_no, sizeof (iface_no)); add_field (trap_pdu, ASN_OCTET_STR, SNMP_OID_OBJECT_RRP_STATUS, (void*)state, strlen (state)); /* Send and cleanup */ ret = snmp_send (session, trap_pdu); if (ret == 0) { /* error */ qb_log(LOG_ERR, "Could not send SNMP trap"); snmp_free_pdu (trap_pdu); } } static void _cs_snmp_init(void) { if (snmp_manager == NULL) { snmp_manager = (char*)local_host; } notifiers[num_notifiers].node_membership_fn = _cs_snmp_node_membership_event; notifiers[num_notifiers].node_quorum_fn = _cs_snmp_node_quorum_event; notifiers[num_notifiers].application_connection_fn = NULL; notifiers[num_notifiers].rrp_faulty_fn = _cs_snmp_rrp_faulty_event; num_notifiers++; } #endif /* ENABLE_SNMP */ static void _cs_syslog_node_membership_event(char *nodename, uint32_t nodeid, char *state, char* ip) { qb_log(LOG_NOTICE, "%s[%d] ip:%s %s", nodename, nodeid, ip, state); } static void _cs_syslog_node_quorum_event(char *nodename, uint32_t nodeid, const char *state) { if (strcmp(state, "quorate") == 0) { qb_log(LOG_NOTICE, "%s[%d] is now %s", nodename, nodeid, state); } else { qb_log(LOG_NOTICE, "%s[%d] has lost quorum", nodename, nodeid); } } static void _cs_syslog_application_connection_event(char *nodename, uint32_t nodeid, char* app_name, const char *state) { if (strcmp(state, "connected") == 0) { qb_log(LOG_NOTICE, "%s[%d] %s is now %s to corosync", nodename, nodeid, app_name, state); } else { qb_log(LOG_NOTICE, "%s[%d] %s is now %s from corosync", nodename, nodeid, app_name, state); } } static void _cs_syslog_rrp_faulty_event(char *nodename, uint32_t nodeid, uint32_t iface_no, const char *state) { qb_log(LOG_NOTICE, "%s[%d] interface %u is now %s", nodename, nodeid, iface_no, state); } static void _cs_node_membership_event(char *nodename, uint32_t nodeid, char *state, char* ip) { int i; for (i = 0; i < num_notifiers; i++) { if (notifiers[i].node_membership_fn) { notifiers[i].node_membership_fn(nodename, nodeid, state, ip); } } } static void _cs_local_node_info_get(char **nodename, uint32_t *nodeid) { cs_error_t rc; corosync_cfg_handle_t cfg_handle; if (local_nodeid == 0) { rc = corosync_cfg_initialize(&cfg_handle, NULL); if (rc != CS_OK) { syslog (LOG_ERR, "Failed to initialize the cfg API. Error %d\n", rc); exit (EXIT_FAILURE); } rc = corosync_cfg_local_get (cfg_handle, &local_nodeid); corosync_cfg_finalize(cfg_handle); if (rc != CS_OK) { local_nodeid = 0; strncpy(local_nodename, "localhost", sizeof (local_nodename)); local_nodename[sizeof (local_nodename) - 1] = '\0'; } else { gethostname(local_nodename, CS_MAX_NAME_LENGTH); } } *nodeid = local_nodeid; *nodename = local_nodename; } static void _cs_node_quorum_event(const char *state) { int i; char *nodename; uint32_t nodeid; _cs_local_node_info_get(&nodename, &nodeid); for (i = 0; i < num_notifiers; i++) { if (notifiers[i].node_quorum_fn) { notifiers[i].node_quorum_fn(nodename, nodeid, state); } } } static void _cs_application_connection_event(char *app_name, const char *state) { int i; char *nodename; uint32_t nodeid; _cs_local_node_info_get(&nodename, &nodeid); for (i = 0; i < num_notifiers; i++) { if (notifiers[i].application_connection_fn) { notifiers[i].application_connection_fn(nodename, nodeid, app_name, state); } } } static void _cs_rrp_faulty_event(uint32_t iface_no, const char *state) { int i; char *nodename; uint32_t nodeid; _cs_local_node_info_get(&nodename, &nodeid); for (i = 0; i < num_notifiers; i++) { if (notifiers[i].rrp_faulty_fn) { notifiers[i].rrp_faulty_fn(nodename, nodeid, iface_no, state); } } } static int32_t sig_exit_handler(int32_t num, void *data) { qb_loop_stop(main_loop); return 0; } static void _cs_cmap_init(void) { cs_error_t rc; int cmap_fd = 0; cmap_track_handle_t track_handle; rc = cmap_initialize (&cmap_handle); if (rc != CS_OK) { qb_log(LOG_ERR, "Failed to initialize the cmap API. Error %d", rc); exit (EXIT_FAILURE); } cmap_fd_get(cmap_handle, &cmap_fd); qb_loop_poll_add(main_loop, QB_LOOP_MED, cmap_fd, POLLIN|POLLNVAL, NULL, _cs_cmap_dispatch); rc = cmap_track_add(cmap_handle, "runtime.connections.", CMAP_TRACK_ADD | CMAP_TRACK_DELETE | CMAP_TRACK_PREFIX, _cs_cmap_connections_key_changed, NULL, &track_handle); if (rc != CS_OK) { qb_log(LOG_ERR, "Failed to track the connections key. Error %d", rc); exit (EXIT_FAILURE); } rc = cmap_track_add(cmap_handle, "runtime.totem.pg.mrp.srp.members.", CMAP_TRACK_ADD | CMAP_TRACK_MODIFY | CMAP_TRACK_PREFIX, _cs_cmap_members_key_changed, NULL, &track_handle); if (rc != CS_OK) { qb_log(LOG_ERR, "Failed to track the members key. Error %d", rc); exit (EXIT_FAILURE); } rc = cmap_track_add(cmap_handle, "runtime.totem.pg.mrp.rrp.", CMAP_TRACK_ADD | CMAP_TRACK_MODIFY | CMAP_TRACK_PREFIX, _cs_cmap_rrp_faulty_key_changed, NULL, &track_handle); if (rc != CS_OK) { qb_log(LOG_ERR, "Failed to track the rrp key. Error %d", rc); exit (EXIT_FAILURE); } } static void _cs_cmap_finalize(void) { cmap_finalize (cmap_handle); } static void _cs_check_config(void) { if (conf[CS_NTF_LOG] == QB_FALSE && conf[CS_NTF_STDOUT] == QB_FALSE && conf[CS_NTF_SNMP] == QB_FALSE && conf[CS_NTF_DBUS] == QB_FALSE) { qb_log(LOG_ERR, "no event type enabled, see corosync-notifyd -h, exiting."); exit(EXIT_FAILURE); } #ifndef ENABLE_SNMP if (conf[CS_NTF_SNMP]) { qb_log(LOG_ERR, "Not compiled with SNMP support enabled, exiting."); exit(EXIT_FAILURE); } #endif #ifndef HAVE_DBUS if (conf[CS_NTF_DBUS]) { qb_log(LOG_ERR, "Not compiled with DBus support enabled, exiting."); exit(EXIT_FAILURE); } #endif if (conf[CS_NTF_STDOUT] && !conf[CS_NTF_FG]) { qb_log(LOG_ERR, "configured to print to stdout and run in the background, exiting"); exit(EXIT_FAILURE); } if (conf[CS_NTF_SNMP] && conf[CS_NTF_DBUS]) { qb_log(LOG_ERR, "configured to send snmp traps and dbus signals - are you sure?."); } } static void _cs_usage(void) { fprintf(stderr, "usage:\n"\ " -f : Start application in foreground.\n"\ " -l : Log all events.\n"\ " -o : Print events to stdout (turns on -l).\n"\ " -s : Send SNMP traps on all events.\n"\ - " -m : SNMP Manager IP address (defaults to localhost).\n"\ + " -m : Set the SNMP Manager IP address (defaults to localhost).\n"\ " -d : Send DBUS signals on all events.\n"\ - " -h : Print this help\n\n"); + " -h : Print this help.\n\n"); } int main(int argc, char *argv[]) { int ch; conf[CS_NTF_FG] = QB_FALSE; conf[CS_NTF_LOG] = QB_FALSE; conf[CS_NTF_STDOUT] = QB_FALSE; conf[CS_NTF_SNMP] = QB_FALSE; conf[CS_NTF_DBUS] = QB_FALSE; while ((ch = getopt (argc, argv, "floshdm:")) != EOF) { switch (ch) { case 'f': conf[CS_NTF_FG] = QB_TRUE; break; case 'l': conf[CS_NTF_LOG] = QB_TRUE; break; case 'm': conf[CS_NTF_SNMP] = QB_TRUE; strncpy(snmp_manager_buf, optarg, sizeof (snmp_manager_buf)); snmp_manager_buf[sizeof (snmp_manager_buf) - 1] = '\0'; snmp_manager = snmp_manager_buf; break; case 'o': conf[CS_NTF_LOG] = QB_TRUE; conf[CS_NTF_STDOUT] = QB_TRUE; break; case 's': conf[CS_NTF_SNMP] = QB_TRUE; break; case 'd': conf[CS_NTF_DBUS] = QB_TRUE; break; case 'h': default: _cs_usage(); return EXIT_FAILURE; } } qb_log_init("notifyd", LOG_DAEMON, LOG_INFO); if (conf[CS_NTF_STDOUT]) { qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD, QB_LOG_FILTER_FILE, "*", LOG_DEBUG); qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, conf[CS_NTF_STDOUT]); } _cs_check_config(); if (!conf[CS_NTF_FG]) { if (daemon(0, 0) < 0) { perror("daemon() failed"); return EXIT_FAILURE; } } num_notifiers = 0; if (conf[CS_NTF_LOG]) { notifiers[num_notifiers].node_membership_fn = _cs_syslog_node_membership_event; notifiers[num_notifiers].node_quorum_fn = _cs_syslog_node_quorum_event; notifiers[num_notifiers].application_connection_fn = _cs_syslog_application_connection_event; notifiers[num_notifiers].rrp_faulty_fn = _cs_syslog_rrp_faulty_event; num_notifiers++; } main_loop = qb_loop_create(); _cs_cmap_init(); _cs_quorum_init(); #ifdef HAVE_DBUS if (conf[CS_NTF_DBUS]) { _cs_dbus_init(); } #endif /* HAVE_DBUS */ #ifdef ENABLE_SNMP if (conf[CS_NTF_SNMP]) { _cs_snmp_init(); } #endif /* ENABLE_SNMP */ qb_loop_signal_add(main_loop, QB_LOOP_HIGH, SIGINT, NULL, sig_exit_handler, NULL); qb_loop_signal_add(main_loop, QB_LOOP_HIGH, SIGQUIT, NULL, sig_exit_handler, NULL); qb_loop_signal_add(main_loop, QB_LOOP_HIGH, SIGTERM, NULL, sig_exit_handler, NULL); qb_loop_run(main_loop); #ifdef HAVE_DBUS if (conf[CS_NTF_DBUS]) { _cs_dbus_release(); } #endif /* HAVE_DBUS */ _cs_quorum_finalize(); _cs_cmap_finalize(); return 0; } diff --git a/tools/corosync-quorumtool.c b/tools/corosync-quorumtool.c index ea5ca28a..5fa937d0 100644 --- a/tools/corosync-quorumtool.c +++ b/tools/corosync-quorumtool.c @@ -1,989 +1,990 @@ /* * Copyright (c) 2009-2014 Red Hat, Inc. * * All rights reserved. * * Authors: Christine Caulfield * Fabio M. Di Nitto (fdinitto@redhat.com) * * This software licensed under BSD license, the text of which follows: * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the Red Hat Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include typedef enum { NODEID_FORMAT_DECIMAL, NODEID_FORMAT_HEX } nodeid_format_t; typedef enum { ADDRESS_FORMAT_NAME, ADDRESS_FORMAT_IP } name_format_t; typedef enum { CMD_UNKNOWN, CMD_SHOWNODES, CMD_SHOWSTATUS, CMD_SETVOTES, CMD_SETEXPECTED, CMD_MONITOR, CMD_UNREGISTER_QDEVICE } command_t; typedef enum { SORT_ADDR, SORT_NODEID, SORT_NODENAME } sorttype_t; /* * global vars */ /* * cmap bits */ static cmap_handle_t cmap_handle; /* * quorum bits */ static void quorum_notification_fn( quorum_handle_t handle, uint32_t quorate, uint64_t ring_id, uint32_t view_list_entries, uint32_t *view_list); static quorum_handle_t q_handle; static uint32_t q_type; static quorum_callbacks_t q_callbacks = { .quorum_notify_fn = quorum_notification_fn }; /* * quorum call back vars */ /* Containing struct to keep votequorum & normal quorum bits together */ typedef struct { struct votequorum_info *vq_info; /* Might be NULL if votequorum not present */ char *name; /* Might be IP address or NULL */ int node_id; /* Always present */ } view_list_entry_t; static view_list_entry_t *g_view_list; static uint32_t g_quorate; static uint64_t g_ring_id; static uint32_t g_ring_id_rep_node; static uint32_t g_view_list_entries; static uint32_t g_called; static uint32_t g_vq_called; /* * votequorum bits */ static void votequorum_notification_fn( votequorum_handle_t handle, uint64_t context, votequorum_ring_id_t ring_id, uint32_t node_list_entries, uint32_t node_list[]); static votequorum_handle_t v_handle; static votequorum_callbacks_t v_callbacks = { .votequorum_quorum_notify_fn = NULL, .votequorum_expectedvotes_notify_fn = NULL, .votequorum_nodelist_notify_fn = votequorum_notification_fn, }; static uint32_t our_nodeid = 0; /* * cfg bits */ static corosync_cfg_handle_t c_handle; static corosync_cfg_callbacks_t c_callbacks = { .corosync_cfg_shutdown_callback = NULL }; /* * global */ static int machine_parsable = 0; static void show_usage(const char *name) { printf("usage: \n"); printf("%s \n", name); printf("\n"); printf(" options:\n"); printf("\n"); printf(" -s show quorum status\n"); - printf(" -m monitor quorum status\n"); + printf(" -m constantly monitor quorum status\n"); printf(" -l list nodes\n"); printf(" -p when used with -s or -l, generates machine parsable output\n"); printf(" -v change the number of votes for a node (*)\n"); - printf(" -n optional nodeid of node for -v (*)\n"); + printf(" -n optional nodeid of node for -v\n"); printf(" -e change expected votes for the cluster (*)\n"); printf(" -H show nodeids in hexadecimal rather than decimal\n"); printf(" -i show node IP addresses instead of the resolved name\n"); - printf(" -o order by [a] IP address (default), [i] nodeid,\n"); + printf(" -p when used with -s or -l, generates machine parsable output\n"); + printf(" -o order by [a] IP address (default), [n] name, [i] nodeid\n"); printf(" -f forcefully unregister a quorum device *DANGEROUS* (*)\n"); printf(" -h show this help text\n"); printf(" -V show version and exit\n"); printf("\n"); printf(" (*) Starred items only work if votequorum is the quorum provider for corosync\n"); printf("\n"); } static int get_quorum_type(char *quorum_type, size_t quorum_type_len) { int err; char *str = NULL; if ((!quorum_type) || (quorum_type_len <= 0)) { return -1; } if (q_type == QUORUM_FREE) { return -1; } if ((err = cmap_get_string(cmap_handle, "quorum.provider", &str)) != CS_OK) { goto out; } if (!str) { return -1; } strncpy(quorum_type, str, quorum_type_len - 1); free(str); return 0; out: return err; } /* * Returns 1 if 'votequorum' is active. The called then knows that * votequorum calls should work and can provide extra information */ static int using_votequorum(void) { char quorumtype[256]; int using_voteq; memset(quorumtype, 0, sizeof(quorumtype)); if (get_quorum_type(quorumtype, sizeof(quorumtype))) { return -1; } if (strcmp(quorumtype, "corosync_votequorum") == 0) { using_voteq = 1; } else { using_voteq = 0; } return using_voteq; } static int set_votes(uint32_t nodeid, int votes) { int err; if ((err=votequorum_setvotes(v_handle, nodeid, votes)) != CS_OK) { fprintf(stderr, "Unable to set votes %d for nodeid: %u: %s\n", votes, nodeid, cs_strerror(err)); } return err==CS_OK?0:err; } static int set_expected(int expected_votes) { int err; if ((err=votequorum_setexpected(v_handle, expected_votes)) != CS_OK) { fprintf(stderr, "Unable to set expected votes: %s\n", cs_strerror(err)); } return err==CS_OK?0:err; } /* * node name by nodelist */ static const char *node_name_by_nodelist(uint32_t nodeid) { cmap_iter_handle_t iter; char key_name[CMAP_KEYNAME_MAXLEN]; char tmp_key[CMAP_KEYNAME_MAXLEN]; static char ret_buf[_POSIX_HOST_NAME_MAX]; char *str = NULL; uint32_t node_pos, cur_nodeid; int res = 0; if (cmap_iter_init(cmap_handle, "nodelist.node.", &iter) != CS_OK) { return ""; } memset(ret_buf, 0, sizeof(ret_buf)); while ((cmap_iter_next(cmap_handle, iter, key_name, NULL, NULL)) == CS_OK) { res = sscanf(key_name, "nodelist.node.%u.%s", &node_pos, tmp_key); if (res != 2) { continue; } if (strcmp(tmp_key, "ring0_addr") != 0) { continue; } snprintf(tmp_key, CMAP_KEYNAME_MAXLEN, "nodelist.node.%u.nodeid", node_pos); if (cmap_get_uint32(cmap_handle, tmp_key, &cur_nodeid) != CS_OK) { continue; } if (cur_nodeid != nodeid) { continue; } snprintf(tmp_key, CMAP_KEYNAME_MAXLEN, "nodelist.node.%u.ring0_addr", node_pos); if (cmap_get_string(cmap_handle, tmp_key, &str) != CS_OK) { continue; } if (!str) { continue; } strncpy(ret_buf, str, sizeof(ret_buf) - 1); free(str); break; } cmap_iter_finalize(cmap_handle, iter); return ret_buf; } /* * This resolves the first address assigned to a node * and returns the name or IP address. Use cfgtool if you need more information. */ static const char *node_name(uint32_t nodeid, name_format_t name_format) { int err; int numaddrs; corosync_cfg_node_address_t addrs[INTERFACE_MAX]; static char buf[INET6_ADDRSTRLEN]; const char *nodelist_name = NULL; socklen_t addrlen; struct sockaddr_storage *ss; if (name_format == ADDRESS_FORMAT_NAME) { nodelist_name = node_name_by_nodelist(nodeid); } if ((nodelist_name) && (strlen(nodelist_name) > 0)) { return nodelist_name; } err = corosync_cfg_get_node_addrs(c_handle, nodeid, INTERFACE_MAX, &numaddrs, addrs); if (err != CS_OK) { fprintf(stderr, "Unable to get node address for nodeid %u: %s\n", nodeid, cs_strerror(err)); return ""; } ss = (struct sockaddr_storage *)addrs[0].address; if (ss->ss_family == AF_INET6) { addrlen = sizeof(struct sockaddr_in6); } else { addrlen = sizeof(struct sockaddr_in); } if (!getnameinfo( (struct sockaddr *)addrs[0].address, addrlen, buf, sizeof(buf), NULL, 0, (name_format == ADDRESS_FORMAT_IP)?NI_NUMERICHOST:0)) { return buf; } return ""; } static void votequorum_notification_fn( votequorum_handle_t handle, uint64_t context, votequorum_ring_id_t ring_id, uint32_t node_list_entries, uint32_t node_list[]) { g_ring_id_rep_node = ring_id.nodeid; g_vq_called = 1; } static void quorum_notification_fn( quorum_handle_t handle, uint32_t quorate, uint64_t ring_id, uint32_t view_list_entries, uint32_t *view_list) { int i; g_called = 1; g_quorate = quorate; g_ring_id = ring_id; g_view_list_entries = view_list_entries; if (g_view_list) { free(g_view_list); } g_view_list = malloc(sizeof(view_list_entry_t) * view_list_entries); if (g_view_list) { for (i=0; i< view_list_entries; i++) { g_view_list[i].node_id = view_list[i]; g_view_list[i].name = NULL; g_view_list[i].vq_info = NULL; } } } static void print_string_padded(const char *buf) { int len, delta; len = strlen(buf); delta = 10 - len; while (delta > 0) { printf(" "); delta--; } printf("%s ", buf); } static void print_uint32_padded(uint32_t value) { char buf[12]; snprintf(buf, sizeof(buf) - 1, "%u", value); print_string_padded(buf); } /* for qsort */ static int compare_nodeids(const void *one, const void *two) { const view_list_entry_t *info1 = one; const view_list_entry_t *info2 = two; if (info1->node_id == info2->node_id) { return 0; } if (info1->node_id > info2->node_id) { return 1; } return -1; } static int compare_nodenames(const void *one, const void *two) { const view_list_entry_t *info1 = one; const view_list_entry_t *info2 = two; return strcmp(info1->name, info2->name); } static void display_nodes_data(nodeid_format_t nodeid_format, name_format_t name_format, sorttype_t sort_type) { int i, display_qdevice = 0; unsigned int our_flags = 0; struct votequorum_info info[g_view_list_entries]; /* * cache node info because we need to parse them twice */ if (v_handle) { for (i=0; i < g_view_list_entries; i++) { if (votequorum_getinfo(v_handle, g_view_list[i].node_id, &info[i]) != CS_OK) { printf("Unable to get node %u info\n", g_view_list[i].node_id); } g_view_list[i].vq_info = &info[i]; if (info[i].flags & VOTEQUORUM_INFO_QDEVICE_REGISTERED) { display_qdevice = 1; } } } /* * Get node names */ for (i=0; i < g_view_list_entries; i++) { g_view_list[i].name = strdup(node_name(g_view_list[i].node_id, name_format)); } printf("\nMembership information\n"); printf("----------------------\n"); print_string_padded("Nodeid"); if (v_handle) { print_string_padded("Votes"); if ((display_qdevice) || (machine_parsable)) { print_string_padded("Qdevice"); } } printf("Name\n"); /* corosync sends them already sorted by address */ if (sort_type == SORT_NODEID) { qsort(g_view_list, g_view_list_entries, sizeof(view_list_entry_t), compare_nodeids); } if (sort_type == SORT_NODENAME) { qsort(g_view_list, g_view_list_entries, sizeof(view_list_entry_t), compare_nodenames); } for (i=0; i < g_view_list_entries; i++) { if (nodeid_format == NODEID_FORMAT_DECIMAL) { print_uint32_padded(g_view_list[i].node_id); } else { printf("0x%08x ", g_view_list[i].node_id); } if (v_handle) { int votes = -1; votes = info[i].node_votes; print_uint32_padded(votes); if ((display_qdevice) || (machine_parsable)) { if (info[i].flags & VOTEQUORUM_INFO_QDEVICE_REGISTERED) { char buf[10]; snprintf(buf, sizeof(buf) - 1, "%s,%s,%s", info[i].flags & VOTEQUORUM_INFO_QDEVICE_ALIVE?"A":"NA", info[i].flags & VOTEQUORUM_INFO_QDEVICE_CAST_VOTE?"V":"NV", info[i].flags & VOTEQUORUM_INFO_QDEVICE_MASTER_WINS?"MW":"NMW"); print_string_padded(buf); } else { print_string_padded("NR"); } } } printf("%s", g_view_list[i].name); if (g_view_list[i].node_id == our_nodeid) { printf(" (local)"); our_flags = info[i].flags; } printf("\n"); } if (g_view_list_entries) { for (i=0; i < g_view_list_entries; i++) { free(g_view_list[i].name); } free(g_view_list); g_view_list = NULL; } if (display_qdevice) { if (nodeid_format == NODEID_FORMAT_DECIMAL) { print_uint32_padded(VOTEQUORUM_QDEVICE_NODEID); } else { printf("0x%08x ", VOTEQUORUM_QDEVICE_NODEID); } /* If the quorum device is inactive on this node then show votes as 0 so that the display is not confusing */ if (our_flags & VOTEQUORUM_INFO_QDEVICE_CAST_VOTE) { print_uint32_padded(info[0].qdevice_votes); } else { print_uint32_padded(0); } printf(" %s", info[0].qdevice_name); if (our_flags & VOTEQUORUM_INFO_QDEVICE_CAST_VOTE) { printf("\n"); } else { printf(" (votes %d)\n", info[0].qdevice_votes); } } } static int display_quorum_data(int is_quorate, nodeid_format_t nodeid_format, name_format_t name_format, sorttype_t sort_type, int loop) { struct votequorum_info info; int err; char quorumtype[256]; time_t t; memset(quorumtype, 0, sizeof(quorumtype)); printf("Quorum information\n"); printf("------------------\n"); time(&t); printf("Date: %s", ctime((const time_t *)&t)); if (get_quorum_type(quorumtype, sizeof(quorumtype))) { strncpy(quorumtype, "Not configured", sizeof(quorumtype) - 1); } printf("Quorum provider: %s\n", quorumtype); printf("Nodes: %d\n", g_view_list_entries); if (nodeid_format == NODEID_FORMAT_DECIMAL) { printf("Node ID: %u\n", our_nodeid); } else { printf("Node ID: 0x%08x\n", our_nodeid); } if (v_handle) { printf("Ring ID: %d/%" PRIu64 "\n", g_ring_id_rep_node, g_ring_id); } else { printf("Ring ID: %" PRIu64 "\n", g_ring_id); } printf("Quorate: %s\n", is_quorate?"Yes":"No"); if (!v_handle) { return CS_OK; } err=votequorum_getinfo(v_handle, our_nodeid, &info); if ((err == CS_OK) || (err == CS_ERR_NOT_EXIST)) { printf("\nVotequorum information\n"); printf("----------------------\n"); printf("Expected votes: %d\n", info.node_expected_votes); printf("Highest expected: %d\n", info.highest_expected); printf("Total votes: %d\n", info.total_votes); printf("Quorum: %d %s\n", info.quorum, info.flags & VOTEQUORUM_INFO_QUORATE?" ":"Activity blocked"); printf("Flags: "); if (info.flags & VOTEQUORUM_INFO_TWONODE) printf("2Node "); if (info.flags & VOTEQUORUM_INFO_QUORATE) printf("Quorate "); if (info.flags & VOTEQUORUM_INFO_WAIT_FOR_ALL) printf("WaitForAll "); if (info.flags & VOTEQUORUM_INFO_LAST_MAN_STANDING) printf("LastManStanding "); if (info.flags & VOTEQUORUM_INFO_AUTO_TIE_BREAKER) printf("AutoTieBreaker "); if (info.flags & VOTEQUORUM_INFO_ALLOW_DOWNSCALE) printf("AllowDownscale "); if (info.flags & VOTEQUORUM_INFO_QDEVICE_REGISTERED) printf("Qdevice "); printf("\n"); } else { fprintf(stderr, "Unable to get node info: %s\n", cs_strerror(err)); } display_nodes_data(nodeid_format, name_format, sort_type); return err; } /* * return 1 if quorate * 0 if not quorate * -1 on error */ static int show_status(nodeid_format_t nodeid_format, name_format_t name_format, sorttype_t sort_type) { int is_quorate; int err; err=quorum_getquorate(q_handle, &is_quorate); if (err != CS_OK) { fprintf(stderr, "Unable to get cluster quorate status: %s\n", cs_strerror(err)); goto quorum_err; } err=quorum_trackstart(q_handle, CS_TRACK_CURRENT); if (err != CS_OK) { fprintf(stderr, "Unable to start quorum status tracking: %s\n", cs_strerror(err)); goto quorum_err; } g_called = 0; while (g_called == 0 && err == CS_OK) { err = quorum_dispatch(q_handle, CS_DISPATCH_ONE); if (err != CS_OK) { fprintf(stderr, "Unable to dispatch quorum status: %s\n", cs_strerror(err)); } } if (quorum_trackstop(q_handle) != CS_OK) { fprintf(stderr, "Unable to stop quorum status tracking: %s\n", cs_strerror(err)); } if (using_votequorum()) { if ( (err=votequorum_trackstart(v_handle, 0LL, CS_TRACK_CURRENT)) != CS_OK) { fprintf(stderr, "Unable to start votequorum status tracking: %s\n", cs_strerror(err)); goto quorum_err; } g_vq_called = 0; while (g_vq_called == 0 && err == CS_OK) { err = votequorum_dispatch(v_handle, CS_DISPATCH_ONE); if (err != CS_OK) { fprintf(stderr, "Unable to dispatch votequorum status: %s\n", cs_strerror(err)); } } } quorum_err: if (err != CS_OK) { return -1; } err = display_quorum_data(is_quorate, nodeid_format, name_format, sort_type, 0); if (err != CS_OK) { return -1; } return is_quorate; } static int monitor_status(nodeid_format_t nodeid_format, name_format_t name_format, sorttype_t sort_type) { int err; int loop = 0; if (q_type == QUORUM_FREE) { printf("\nQuorum is not configured - cannot monitor\n"); return show_status(nodeid_format, name_format, sort_type); } err=quorum_trackstart(q_handle, CS_TRACK_CHANGES); if (err != CS_OK) { fprintf(stderr, "Unable to start quorum status tracking: %s\n", cs_strerror(err)); goto quorum_err; } if (using_votequorum()) { if ( (err=votequorum_trackstart(v_handle, 0LL, CS_TRACK_CHANGES)) != CS_OK) { fprintf(stderr, "Unable to start votequorum status tracking: %s\n", cs_strerror(err)); goto quorum_err; } } while (1) { err = quorum_dispatch(q_handle, CS_DISPATCH_ONE); if (err != CS_OK) { fprintf(stderr, "Unable to dispatch quorum status: %s\n", cs_strerror(err)); goto quorum_err; } if (using_votequorum()) { g_vq_called = 0; while (!g_vq_called) { err = votequorum_dispatch(v_handle, CS_DISPATCH_ONE); if (err != CS_OK) { fprintf(stderr, "Unable to dispatch votequorum status: %s\n", cs_strerror(err)); goto quorum_err; } } } err = display_quorum_data(g_quorate, nodeid_format, name_format, sort_type, loop); printf("\n"); loop = 1; if (err != CS_OK) { fprintf(stderr, "Unable to display quorum data: %s\n", cs_strerror(err)); goto quorum_err; } } quorum_err: return -1; } static int show_nodes(nodeid_format_t nodeid_format, name_format_t name_format, sorttype_t sort_type) { int err; int result = EXIT_FAILURE; err = quorum_trackstart(q_handle, CS_TRACK_CURRENT); if (err != CS_OK) { fprintf(stderr, "Unable to start quorum status tracking: %s\n", cs_strerror(err)); goto err_exit; } g_called = 0; while (g_called == 0) { err = quorum_dispatch(q_handle, CS_DISPATCH_ONE); if (err != CS_OK) { fprintf(stderr, "Unable to dispatch quorum status: %s\n", cs_strerror(err)); goto err_exit; } } display_nodes_data(nodeid_format, name_format, sort_type); result = EXIT_SUCCESS; err_exit: return result; } static int unregister_qdevice(void) { int err; struct votequorum_info info; err = votequorum_getinfo(v_handle, our_nodeid, &info); if (err != CS_OK) { fprintf(stderr, "Unable to get quorum device info: %s\n", cs_strerror(err)); return -1; } if (!(info.flags & VOTEQUORUM_INFO_QDEVICE_REGISTERED)) { return 0; } err = votequorum_qdevice_unregister(v_handle, info.qdevice_name); if (err != CS_OK) { fprintf(stderr, "Unable to unregister quorum device: %s\n", cs_strerror(err)); return -1; } return 0; } /* * return -1 on error * 0 if OK */ static int init_all(void) { cmap_handle = 0; q_handle = 0; v_handle = 0; c_handle = 0; if (cmap_initialize(&cmap_handle) != CS_OK) { fprintf(stderr, "Cannot initialize CMAP service\n"); cmap_handle = 0; goto out; } if (quorum_initialize(&q_handle, &q_callbacks, &q_type) != CS_OK) { fprintf(stderr, "Cannot initialize QUORUM service\n"); q_handle = 0; goto out; } if (corosync_cfg_initialize(&c_handle, &c_callbacks) != CS_OK) { fprintf(stderr, "Cannot initialise CFG service\n"); c_handle = 0; goto out; } if (using_votequorum() <= 0) { return 0; } if (votequorum_initialize(&v_handle, &v_callbacks) != CS_OK) { fprintf(stderr, "Cannot initialise VOTEQUORUM service\n"); v_handle = 0; goto out; } if (cmap_get_uint32(cmap_handle, "runtime.votequorum.this_node_id", &our_nodeid) != CS_OK) { fprintf(stderr, "Unable to retrieve this_node_id\n"); goto out; } return 0; out: return -1; } static void close_all(void) { if (cmap_handle) { cmap_finalize(cmap_handle); } if (q_handle) { quorum_finalize(q_handle); } if (c_handle) { corosync_cfg_finalize(c_handle); } if (v_handle) { votequorum_finalize(v_handle); } } int main (int argc, char *argv[]) { const char *options = "VHslpmfe:v:hin:o:"; char *endptr; int opt; int votes = 0; int ret = 0; uint32_t nodeid = 0; uint32_t nodeid_set = 0; nodeid_format_t nodeid_format = NODEID_FORMAT_DECIMAL; name_format_t address_format = ADDRESS_FORMAT_NAME; command_t command_opt = CMD_SHOWSTATUS; sorttype_t sort_opt = SORT_ADDR; char sortchar; long int l; if (init_all()) { close_all(); exit(1); } while ( (opt = getopt(argc, argv, options)) != -1 ) { switch (opt) { case 'f': if (using_votequorum() > 0) { command_opt = CMD_UNREGISTER_QDEVICE; } else { fprintf(stderr, "You cannot unregister quorum device, corosync is not using votequorum\n"); exit(2); } break; case 's': command_opt = CMD_SHOWSTATUS; break; case 'm': command_opt = CMD_MONITOR; break; case 'i': address_format = ADDRESS_FORMAT_IP; break; case 'H': nodeid_format = NODEID_FORMAT_HEX; break; case 'l': command_opt = CMD_SHOWNODES; break; case 'p': machine_parsable = 1; break; case 'e': if (using_votequorum() > 0) { votes = strtol(optarg, &endptr, 0); if ((votes == 0 && endptr == optarg) || votes <= 0) { fprintf(stderr, "New expected votes value was not valid, try a positive number\n"); } else { command_opt = CMD_SETEXPECTED; } } else { fprintf(stderr, "You cannot change expected votes, corosync is not using votequorum\n"); exit(2); } break; case 'n': l = strtol(optarg, &endptr, 0); if ((l == 0 && endptr == optarg) || l < 0) { fprintf(stderr, "The nodeid was not valid, try a positive number\n"); exit(2); } nodeid = l; nodeid_set = 1; break; case 'v': if (using_votequorum() > 0) { votes = strtol(optarg, &endptr, 0); if ((votes == 0 && endptr == optarg) || votes < 0) { fprintf(stderr, "New votes value was not valid, try a positive number or zero\n"); exit(2); } else { command_opt = CMD_SETVOTES; } } else { fprintf(stderr, "You cannot change node votes, corosync is not using votequorum\n"); exit(2); } break; case 'o': sortchar = optarg[0]; switch (sortchar) { case 'a': sort_opt = SORT_ADDR; break; case 'i': sort_opt = SORT_NODEID; break; case 'n': sort_opt = SORT_NODENAME; break; default: fprintf(stderr, "Invalid ordering option. valid orders are a(address), i(node ID) or n(name)\n"); exit(2); break; } break; case 'V': printf("corosync-quorumtool version: %s\n", VERSION); exit(0); case ':': case 'h': case '?': default: command_opt = CMD_UNKNOWN; break; } } switch (command_opt) { case CMD_UNKNOWN: show_usage(argv[0]); ret = -1; break; case CMD_SHOWNODES: ret = show_nodes(nodeid_format, address_format, sort_opt); break; case CMD_SHOWSTATUS: ret = show_status(nodeid_format, address_format, sort_opt); break; case CMD_SETVOTES: if (!nodeid_set) { nodeid = our_nodeid; } ret = set_votes(nodeid, votes); break; case CMD_SETEXPECTED: ret = set_expected(votes); break; case CMD_MONITOR: ret = monitor_status(nodeid_format, address_format, sort_opt); break; case CMD_UNREGISTER_QDEVICE: ret = unregister_qdevice(); break; } close_all(); return (ret); }