diff --git a/tools/Makefile.am b/tools/Makefile.am index e3486b6570..c822a8c287 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -1,167 +1,168 @@ # # Copyright 2004-2019 the Pacemaker project contributors # # The version control history for this file may have further details. # # This source code is licensed under the GNU General Public License version 2 # or later (GPLv2+) WITHOUT ANY WARRANTY. # include $(top_srcdir)/mk/common.mk if BUILD_SYSTEMD systemdsystemunit_DATA = crm_mon.service endif noinst_HEADERS = crm_mon.h crm_resource.h crm_resource_controller.h pcmkdir = $(datadir)/$(PACKAGE) pcmk_DATA = report.common report.collector sbin_SCRIPTS = crm_report crm_standby crm_master crm_failcount if BUILD_CIBSECRETS sbin_SCRIPTS += cibsecret endif noinst_SCRIPTS = pcmk_simtimes EXTRA_DIST = crm_diff.8.inc \ + crm_error.8.inc \ crm_mon.sysconfig \ crm_mon.8.inc \ crm_node.8.inc \ crm_rule.8.inc \ crm_simulate.8.inc \ fix-manpages \ stonith_admin.8.inc sbin_PROGRAMS = attrd_updater \ cibadmin \ crmadmin \ crm_simulate \ crm_attribute \ crm_diff \ crm_error \ crm_mon \ crm_node \ crm_resource \ crm_rule \ crm_shadow \ crm_verify \ crm_ticket \ iso8601 \ stonith_admin if BUILD_SERVICELOG sbin_PROGRAMS += notifyServicelogEvent endif if BUILD_OPENIPMI_SERVICELOG sbin_PROGRAMS += ipmiservicelogd endif ## SOURCES # A few tools are just thin wrappers around crm_attribute. # This makes their help get updated when crm_attribute changes # (see mk/common.mk). MAN8DEPS = crm_attribute crmadmin_SOURCES = crmadmin.c crmadmin_LDADD = $(top_builddir)/lib/pengine/libpe_status.la \ $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/common/libcrmcommon.la crm_error_SOURCES = crm_error.c crm_error_LDADD = $(top_builddir)/lib/common/libcrmcommon.la cibadmin_SOURCES = cibadmin.c cibadmin_LDADD = $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/common/libcrmcommon.la crm_shadow_SOURCES = crm_shadow.c crm_shadow_LDADD = $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/common/libcrmcommon.la crm_node_SOURCES = crm_node.c crm_node_LDADD = $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/common/libcrmcommon.la crm_simulate_SOURCES = crm_simulate.c crm_simulate_LDADD = $(top_builddir)/lib/pengine/libpe_status.la \ $(top_builddir)/lib/pacemaker/libpacemaker.la \ $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/common/libcrmcommon.la crm_diff_SOURCES = crm_diff.c crm_diff_LDADD = $(top_builddir)/lib/common/libcrmcommon.la crm_mon_SOURCES = crm_mon.c crm_mon_curses.c crm_mon_print.c crm_mon_runtime.c crm_mon_xml.c crm_mon_LDADD = $(top_builddir)/lib/pengine/libpe_status.la \ $(top_builddir)/lib/fencing/libstonithd.la \ $(top_builddir)/lib/pacemaker/libpacemaker.la \ $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/common/libcrmcommon.la \ $(CURSESLIBS) crm_verify_SOURCES = crm_verify.c crm_verify_LDADD = $(top_builddir)/lib/pengine/libpe_status.la \ $(top_builddir)/lib/pacemaker/libpacemaker.la \ $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/common/libcrmcommon.la crm_attribute_SOURCES = crm_attribute.c crm_attribute_LDADD = $(top_builddir)/lib/cluster/libcrmcluster.la \ $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/common/libcrmcommon.la crm_resource_SOURCES = crm_resource.c \ crm_resource_ban.c \ crm_resource_controller.c \ crm_resource_print.c \ crm_resource_runtime.c crm_resource_LDADD = $(top_builddir)/lib/pengine/libpe_rules.la \ $(top_builddir)/lib/fencing/libstonithd.la \ $(top_builddir)/lib/lrmd/liblrmd.la \ $(top_builddir)/lib/services/libcrmservice.la \ $(top_builddir)/lib/pengine/libpe_status.la \ $(top_builddir)/lib/pacemaker/libpacemaker.la \ $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/common/libcrmcommon.la crm_rule_SOURCES = crm_rule.c crm_rule_LDADD = $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/pengine/libpe_rules.la \ $(top_builddir)/lib/pengine/libpe_status.la \ $(top_builddir)/lib/common/libcrmcommon.la iso8601_SOURCES = iso8601.c iso8601_LDADD = $(top_builddir)/lib/common/libcrmcommon.la attrd_updater_SOURCES = attrd_updater.c attrd_updater_LDADD = $(top_builddir)/lib/common/libcrmcommon.la crm_ticket_SOURCES = crm_ticket.c crm_ticket_LDADD = $(top_builddir)/lib/pengine/libpe_rules.la \ $(top_builddir)/lib/pengine/libpe_status.la \ $(top_builddir)/lib/pacemaker/libpacemaker.la \ $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/common/libcrmcommon.la stonith_admin_SOURCES = stonith_admin.c stonith_admin_LDADD = $(top_builddir)/lib/pacemaker/libpacemaker.la \ $(top_builddir)/lib/cib/libcib.la \ $(top_builddir)/lib/pengine/libpe_status.la \ $(top_builddir)/lib/fencing/libstonithd.la \ $(top_builddir)/lib/common/libcrmcommon.la if BUILD_SERVICELOG notifyServicelogEvent_SOURCES = notifyServicelogEvent.c notifyServicelogEvent_CFLAGS = $(SERVICELOG_CFLAGS) notifyServicelogEvent_LDADD = $(top_builddir)/lib/common/libcrmcommon.la $(SERVICELOG_LIBS) endif if BUILD_OPENIPMI_SERVICELOG ipmiservicelogd_SOURCES = ipmiservicelogd.c ipmiservicelogd_CFLAGS = $(OPENIPMI_SERVICELOG_CFLAGS) $(SERVICELOG_CFLAGS) ipmiservicelogd_LDFLAGS = $(top_builddir)/lib/common/libcrmcommon.la $(OPENIPMI_SERVICELOG_LIBS) $(SERVICELOG_LIBS) endif CLEANFILES = $(man8_MANS) diff --git a/tools/crm_error.8.inc b/tools/crm_error.8.inc new file mode 100644 index 0000000000..7ef0440207 --- /dev/null +++ b/tools/crm_error.8.inc @@ -0,0 +1,5 @@ +[synopsis] +crm_error [options] -- [...] + +/Pacemaker error code/ +.SH OPTIONS diff --git a/tools/crm_error.c b/tools/crm_error.c index 9407a4590d..00d59f8e31 100644 --- a/tools/crm_error.c +++ b/tools/crm_error.c @@ -1,159 +1,148 @@ /* * Copyright 2012-2020 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU General Public License version 2 * or later (GPLv2+) WITHOUT ANY WARRANTY. */ #include +#include #include -static pcmk__cli_option_t long_options[] = { - // long option, argument type, storage, short option, description, flags - { - "help", no_argument, NULL, '?', - "\tThis text", pcmk__option_default - }, - { - "version", no_argument, NULL, '$', - "\tVersion information", pcmk__option_default - }, - { - "verbose", no_argument, NULL, 'V', - "\tIncrease debug output", pcmk__option_default - }, - { - "name", no_argument, NULL, 'n', - "\tShow error's name with its description (useful for looking for " - "sources of the error in source code)", - pcmk__option_default - }, - { - "list", no_argument, NULL, 'l', - "\tShow all known errors", pcmk__option_default - }, - { - "exit", no_argument, NULL, 'X', - "\tInterpret as exit code rather than legacy function return value", - pcmk__option_default - }, - { - "rc", no_argument, NULL, 'r', - "\tInterpret as return code rather than legacy function return value", - pcmk__option_default - }, - { 0, 0, 0, 0 } -}; +#define SUMMARY "crm_error - display name or description of a Pacemaker error code" + +struct { + gboolean as_exit_code; + gboolean as_rc; + gboolean with_name; + gboolean do_list; +} options; -static bool as_exit_code = false; -static bool as_rc = false; +static GOptionEntry entries[] = { + { "name", 'n', 0, G_OPTION_ARG_NONE, &options.with_name, + "Show error's name with its description (useful for looking for sources " + "of the error in source code)", + NULL }, + { "list", 'l', 0, G_OPTION_ARG_NONE, &options.do_list, + "Show all known errors", + NULL }, + { "exit", 'X', 0, G_OPTION_ARG_NONE, &options.as_exit_code, + "Interpret as exit code rather than legacy function return value", + NULL }, + { "rc", 'r', 0, G_OPTION_ARG_NONE, &options.as_rc, + "Interpret as return code rather than legacy function return value", + NULL }, + + { NULL } +}; static void get_strings(int rc, const char **name, const char **str) { - if (as_exit_code) { + if (options.as_exit_code) { *str = crm_exit_str((crm_exit_t) rc); *name = crm_exit_name(rc); - } else if (as_rc) { + } else if (options.as_rc) { *str = pcmk_rc_str(rc); *name = pcmk_rc_name(rc); } else { *str = pcmk_strerror(rc); *name = pcmk_errorname(rc); } } + +static GOptionContext * +build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) { + GOptionContext *context = NULL; + + context = pcmk__build_arg_context(args, NULL, group, "-- [...]"); + pcmk__add_main_args(context, entries); + return context; +} + int main(int argc, char **argv) { - int rc = 0; - int lpc = 0; - int flag = 0; - int option_index = 0; - - bool do_list = FALSE; - bool with_name = FALSE; + GError *error = NULL; + GOptionGroup *output_group = NULL; + gchar **processed_args = NULL; + pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY); + GOptionContext *context = build_arg_context(args, &output_group); + int rc = pcmk_rc_ok; + int lpc; const char *name = NULL; const char *desc = NULL; crm_log_cli_init("crm_error"); - pcmk__set_cli_options(NULL, "[options] -- [...]", long_options, - "display name or description of a Pacemaker " - "error code"); - - while (flag >= 0) { - flag = pcmk__next_cli_option(argc, argv, &option_index, NULL); - switch (flag) { - case -1: - break; - case 'V': - crm_bump_log_level(argc, argv); - break; - case '$': - case '?': - pcmk__cli_help(flag, CRM_EX_OK); - break; - case 'n': - with_name = TRUE; - break; - case 'l': - do_list = TRUE; - break; - case 'r': - as_rc = true; - break; - case 'X': - as_exit_code = TRUE; - break; - default: - pcmk__cli_help(flag, CRM_EX_OK); - break; - } + + processed_args = pcmk__cmdline_preproc(argv, "lrnX"); + + if (!g_option_context_parse_strv(context, &processed_args, &error)) { + fprintf(stderr, "%s: %s\n", g_get_prgname(), error->message); + return CRM_EX_USAGE; + } + + for (int i = 0; i < args->verbosity; i++) { + crm_bump_log_level(argc, argv); } - if(do_list) { + if (args->version) { + /* FIXME: When crm_error is converted to use formatted output, this can go. */ + pcmk__cli_help('v', CRM_EX_USAGE); + } + + if (options.do_list) { int start, end, width; // 256 is a hacky magic number that "should" be enough - if (as_rc) { + if (options.as_rc) { start = pcmk_rc_error - 256; end = PCMK_CUSTOM_OFFSET; width = 4; } else { start = 0; end = 256; width = 3; } for (rc = start; rc < end; rc++) { if (rc == (pcmk_rc_error + 1)) { // Values in between are reserved for callers, no use iterating rc = pcmk_rc_ok; } get_strings(rc, &name, &desc); if (!name || !strcmp(name, "Unknown") || !strcmp(name, "CRM_EX_UNKNOWN")) { // Undefined - } else if(with_name) { + } else if(options.with_name) { printf("% .*d: %-26s %s\n", width, rc, name, desc); } else { printf("% .*d: %s\n", width, rc, desc); } } } else { - for (lpc = optind; lpc < argc; lpc++) { - rc = crm_atoi(argv[lpc], NULL); + if (g_strv_length(processed_args) < 2) { + char *help = g_option_context_get_help(context, TRUE, NULL); + fprintf(stderr, "%s", help); + free(help); + return CRM_EX_USAGE; + } + + /* Skip #1 because that's the program name. */ + for (lpc = 1; processed_args[lpc] != NULL; lpc++) { + rc = crm_atoi(processed_args[lpc], NULL); get_strings(rc, &name, &desc); - if (with_name) { + if (options.with_name) { printf("%s - %s\n", name, desc); } else { printf("%s\n", desc); } } } return CRM_EX_OK; }