| |
| |
| |
| |
| |
| |
| |
| |
| |
| #include <crm_internal.h> |
| #include <stdarg.h> |
| #include <stdlib.h> |
| #include <crm/crm.h> |
| #include <crm/common/curses_internal.h> |
| #include <crm/common/output.h> |
| #include <crm/stonith-ng.h> |
| #include <crm/fencing/internal.h> |
| #include <crm/pengine/internal.h> |
| #include <glib.h> |
| |
| #include "crm_mon.h" |
| |
| #if CURSES_ENABLED |
| |
| GOptionEntry crm_mon_curses_output_entries[] = { |
| { NULL } |
| }; |
| |
| typedef struct curses_list_data_s { |
| unsigned int len; |
| char *singular_noun; |
| char *plural_noun; |
| } curses_list_data_t; |
| |
| typedef struct private_data_s { |
| GQueue *parent_q; |
| } private_data_t; |
| |
| static void |
| curses_free_priv(pcmk__output_t *out) { |
| private_data_t *priv = out->priv; |
| |
| if (priv == NULL) { |
| return; |
| } |
| |
| g_queue_free(priv->parent_q); |
| free(priv); |
| } |
| |
| static bool |
| curses_init(pcmk__output_t *out) { |
| private_data_t *priv = NULL; |
| |
| |
| if (out->priv != NULL) { |
| return true; |
| } else { |
| out->priv = calloc(1, sizeof(private_data_t)); |
| if (out->priv == NULL) { |
| return false; |
| } |
| |
| priv = out->priv; |
| } |
| |
| priv->parent_q = g_queue_new(); |
| |
| initscr(); |
| cbreak(); |
| noecho(); |
| |
| return true; |
| } |
| |
| static void |
| curses_finish(pcmk__output_t *out, crm_exit_t exit_status, bool print, void **copy_dest) { |
| echo(); |
| nocbreak(); |
| endwin(); |
| } |
| |
| static void |
| curses_reset(pcmk__output_t *out) { |
| CRM_ASSERT(out != NULL); |
| |
| curses_free_priv(out); |
| curses_init(out); |
| } |
| |
| static void |
| curses_subprocess_output(pcmk__output_t *out, int exit_status, |
| const char *proc_stdout, const char *proc_stderr) { |
| if (proc_stdout != NULL) { |
| printw("%s\n", proc_stdout); |
| } |
| |
| if (proc_stderr != NULL) { |
| printw("%s\n", proc_stderr); |
| } |
| |
| clrtoeol(); |
| refresh(); |
| } |
| |
| |
| |
| |
| static void |
| curses_ver(pcmk__output_t *out, bool extended) { |
| if (extended) { |
| printf("Pacemaker %s (Build: %s): %s\n", PACEMAKER_VERSION, BUILD_VERSION, CRM_FEATURES); |
| } else { |
| printf("Pacemaker %s\n", PACEMAKER_VERSION); |
| printf("Written by Andrew Beekhof\n"); |
| } |
| } |
| |
| G_GNUC_PRINTF(2, 3) |
| static void |
| curses_error(pcmk__output_t *out, const char *format, ...) { |
| va_list ap; |
| |
| |
| |
| |
| va_start(ap, format); |
| vw_printw(stdscr, format, ap); |
| va_end(ap); |
| |
| |
| addch('\n'); |
| |
| clrtoeol(); |
| refresh(); |
| sleep(2); |
| } |
| |
| G_GNUC_PRINTF(2, 3) |
| static void |
| curses_info(pcmk__output_t *out, const char *format, ...) { |
| va_list ap; |
| |
| |
| |
| |
| va_start(ap, format); |
| vw_printw(stdscr, format, ap); |
| va_end(ap); |
| |
| |
| addch('\n'); |
| |
| clrtoeol(); |
| refresh(); |
| } |
| |
| static void |
| curses_output_xml(pcmk__output_t *out, const char *name, const char *buf) { |
| private_data_t *priv = out->priv; |
| |
| CRM_ASSERT(priv != NULL); |
| curses_indented_printf(out, "%s", buf); |
| } |
| |
| G_GNUC_PRINTF(4, 5) |
| static void |
| curses_begin_list(pcmk__output_t *out, const char *singular_noun, const char *plural_noun, |
| const char *format, ...) { |
| private_data_t *priv = out->priv; |
| curses_list_data_t *new_list = NULL; |
| va_list ap; |
| |
| CRM_ASSERT(priv != NULL); |
| |
| va_start(ap, format); |
| |
| curses_indented_vprintf(out, format, ap); |
| printw(":\n"); |
| |
| va_end(ap); |
| |
| new_list = calloc(1, sizeof(curses_list_data_t)); |
| new_list->len = 0; |
| new_list->singular_noun = singular_noun == NULL ? NULL : strdup(singular_noun); |
| new_list->plural_noun = plural_noun == NULL ? NULL : strdup(plural_noun); |
| |
| g_queue_push_tail(priv->parent_q, new_list); |
| } |
| |
| G_GNUC_PRINTF(3, 4) |
| static void |
| curses_list_item(pcmk__output_t *out, const char *id, const char *format, ...) { |
| private_data_t *priv = out->priv; |
| va_list ap; |
| |
| CRM_ASSERT(priv != NULL); |
| |
| va_start(ap, format); |
| |
| if (id != NULL) { |
| curses_indented_printf(out, "%s: ", id); |
| vw_printw(stdscr, format, ap); |
| } else { |
| curses_indented_vprintf(out, format, ap); |
| } |
| |
| addch('\n'); |
| va_end(ap); |
| |
| out->increment_list(out); |
| } |
| |
| static void |
| curses_increment_list(pcmk__output_t *out) { |
| private_data_t *priv = out->priv; |
| gpointer tail; |
| |
| CRM_ASSERT(priv != NULL); |
| tail = g_queue_peek_tail(priv->parent_q); |
| CRM_ASSERT(tail != NULL); |
| ((curses_list_data_t *) tail)->len++; |
| } |
| |
| static void |
| curses_end_list(pcmk__output_t *out) { |
| private_data_t *priv = out->priv; |
| curses_list_data_t *node = NULL; |
| |
| CRM_ASSERT(priv != NULL); |
| node = g_queue_pop_tail(priv->parent_q); |
| |
| if (node->singular_noun != NULL && node->plural_noun != NULL) { |
| if (node->len == 1) { |
| curses_indented_printf(out, "%d %s found\n", node->len, node->singular_noun); |
| } else { |
| curses_indented_printf(out, "%d %s found\n", node->len, node->plural_noun); |
| } |
| } |
| |
| free(node); |
| } |
| |
| pcmk__output_t * |
| crm_mon_mk_curses_output(char **argv) { |
| pcmk__output_t *retval = calloc(1, sizeof(pcmk__output_t)); |
| |
| if (retval == NULL) { |
| return NULL; |
| } |
| |
| retval->fmt_name = "console"; |
| retval->request = argv == NULL ? NULL : g_strjoinv(" ", argv); |
| retval->supports_quiet = true; |
| |
| retval->init = curses_init; |
| retval->free_priv = curses_free_priv; |
| retval->finish = curses_finish; |
| retval->reset = curses_reset; |
| |
| retval->register_message = pcmk__register_message; |
| retval->message = pcmk__call_message; |
| |
| retval->subprocess_output = curses_subprocess_output; |
| retval->version = curses_ver; |
| retval->err = curses_error; |
| retval->info = curses_info; |
| retval->output_xml = curses_output_xml; |
| |
| retval->begin_list = curses_begin_list; |
| retval->list_item = curses_list_item; |
| retval->increment_list = curses_increment_list; |
| retval->end_list = curses_end_list; |
| |
| return retval; |
| } |
| |
| G_GNUC_PRINTF(2, 0) |
| void |
| curses_indented_vprintf(pcmk__output_t *out, const char *format, va_list args) { |
| int level = 0; |
| private_data_t *priv = out->priv; |
| |
| CRM_ASSERT(priv != NULL); |
| |
| level = g_queue_get_length(priv->parent_q); |
| |
| for (int i = 0; i < level; i++) { |
| printw(" "); |
| } |
| |
| if (level > 0) { |
| printw("* "); |
| } |
| |
| vw_printw(stdscr, format, args); |
| |
| clrtoeol(); |
| refresh(); |
| } |
| |
| G_GNUC_PRINTF(2, 3) |
| void |
| curses_indented_printf(pcmk__output_t *out, const char *format, ...) { |
| va_list ap; |
| |
| va_start(ap, format); |
| curses_indented_vprintf(out, format, ap); |
| va_end(ap); |
| } |
| |
| PCMK__OUTPUT_ARGS("stonith-event", "struct stonith_history_t *", "gboolean", "gboolean") |
| static int |
| stonith_event_console(pcmk__output_t *out, va_list args) { |
| stonith_history_t *event = va_arg(args, stonith_history_t *); |
| gboolean full_history = va_arg(args, gboolean); |
| gboolean later_succeeded = va_arg(args, gboolean); |
| |
| crm_time_t *crm_when = crm_time_new(NULL); |
| char *buf = NULL; |
| |
| crm_time_set_timet(crm_when, &(event->completed)); |
| buf = crm_time_as_string(crm_when, crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone); |
| |
| switch (event->state) { |
| case st_failed: |
| curses_indented_printf(out, "%s of %s failed: delegate=%s, client=%s, origin=%s, %s='%s'%s\n", |
| stonith_action_str(event->action), event->target, |
| event->delegate ? event->delegate : "", |
| event->client, event->origin, |
| full_history ? "completed" : "last-failed", buf, |
| later_succeeded ? " (a later attempt succeeded)" : ""); |
| break; |
| |
| case st_done: |
| curses_indented_printf(out, "%s of %s successful: delegate=%s, client=%s, origin=%s, %s='%s'\n", |
| stonith_action_str(event->action), event->target, |
| event->delegate ? event->delegate : "", |
| event->client, event->origin, |
| full_history ? "completed" : "last-successful", buf); |
| break; |
| |
| default: |
| curses_indented_printf(out, "%s of %s pending: client=%s, origin=%s\n", |
| stonith_action_str(event->action), event->target, |
| event->client, event->origin); |
| break; |
| } |
| |
| free(buf); |
| crm_time_free(crm_when); |
| return pcmk_rc_ok; |
| } |
| |
| PCMK__OUTPUT_ARGS("maint-mode") |
| static int |
| cluster_maint_mode_console(pcmk__output_t *out, va_list args) { |
| printw("\n *** Resource management is DISABLED ***"); |
| printw("\n The cluster will not attempt to start, stop or recover services"); |
| printw("\n"); |
| clrtoeol(); |
| refresh(); |
| return pcmk_rc_ok; |
| } |
| |
| static pcmk__message_entry_t fmt_functions[] = { |
| { "ban", "console", pe__ban_text }, |
| { "bundle", "console", pe__bundle_text }, |
| { "clone", "console", pe__clone_text }, |
| { "cluster-counts", "console", pe__cluster_counts_text }, |
| { "cluster-dc", "console", pe__cluster_dc_text }, |
| { "cluster-options", "console", pe__cluster_options_text }, |
| { "cluster-stack", "console", pe__cluster_stack_text }, |
| { "cluster-summary", "console", pe__cluster_summary }, |
| { "cluster-times", "console", pe__cluster_times_text }, |
| { "failed-action", "console", pe__failed_action_text }, |
| { "failed-fencing-history", "console", stonith__failed_history }, |
| { "fencing-history", "console", stonith__history }, |
| { "full-fencing-history", "console", stonith__full_history }, |
| { "group", "console", pe__group_text }, |
| { "maint-mode", "console", cluster_maint_mode_console }, |
| { "node", "console", pe__node_text }, |
| { "node-attribute", "console", pe__node_attribute_text }, |
| { "node-list", "console", pe__node_list_text }, |
| { "op-history", "console", pe__op_history_text }, |
| { "pending-fencing-actions", "console", stonith__pending_actions }, |
| { "primitive", "console", pe__resource_text }, |
| { "resource-history", "console", pe__resource_history_text }, |
| { "stonith-event", "console", stonith_event_console }, |
| { "ticket", "console", pe__ticket_text }, |
| |
| { NULL, NULL, NULL } |
| }; |
| |
| void |
| crm_mon_register_messages(pcmk__output_t *out) { |
| pcmk__register_messages(out, fmt_functions); |
| } |
| |
| #else |
| |
| pcmk__output_t * |
| crm_mon_mk_curses_output(char **argv) { |
| |
| return pcmk__mk_text_output(argv); |
| } |
| |
| G_GNUC_PRINTF(2, 0) |
| void |
| curses_indented_vprintf(pcmk__output_t *out, const char *format, va_list args) { |
| return; |
| } |
| |
| G_GNUC_PRINTF(2, 3) |
| void |
| curses_indented_printf(pcmk__output_t *out, const char *format, ...) { |
| return; |
| } |
| |
| void |
| crm_mon_register_messages(pcmk__output_t *out) { |
| return; |
| } |
| |
| #endif |