From 14d0a9eef613a0588bfed8e123dc95dd3a07ffcd Mon Sep 17 00:00:00 2001 From: Peter Rajnoha Date: Tue, 22 Aug 2023 10:54:35 +0200 Subject: [PATCH] report: support printing full column names in report headings Reuse existing report/headings config setting to make it possible to change the type of headings to display: 0 - no headings 1 - column name abbreviations (default and original functionality) 2 - full column names (column names are equal to exact names that -o|--options also accepts to set report output) Also, add '--headings none|abbrev|full|0|1|2' command line option so we are able to select the heading type for each LVM reporting command directly. --- WHATS_NEW | 2 ++ lib/config/config_settings.h | 8 ++++++-- lib/report/report.c | 29 +++++++++++++++++++++++++---- lib/report/report.h | 15 ++++++++++++--- tools/args.h | 6 ++++++ tools/command-lines.in | 6 +++++- tools/command.c | 1 + tools/lvmcmdline.c | 5 +++++ tools/reporter.c | 14 +++++++++++--- tools/tools.h | 1 + tools/vals.h | 1 + 11 files changed, 75 insertions(+), 13 deletions(-) diff --git a/WHATS_NEW b/WHATS_NEW index 1a1190096..438e4675b 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,7 @@ version 2.03.23 - ================================== + Recognize lvm.conf report/headings=2 for full column names in report headings. + Add --headings none|abbrev|full cmd line option to set report headings type. Require writable LV for convertion to vdo pool. Fix return value from lvconvert integrity remove. Preserve UUID for pool metadata spare. diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h index 5e4ec253d..793b5d44d 100644 --- a/lib/config/config_settings.h +++ b/lib/config/config_settings.h @@ -1863,8 +1863,12 @@ cfg(report_buffered_CFG, "buffered", report_CFG_SECTION, CFG_PROFILABLE | CFG_DE "execution. Otherwise, if buffering is not used, each object is\n" "reported as soon as its processing is finished.\n") -cfg(report_headings_CFG, "headings", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_REP_HEADINGS, vsn(1, 0, 0), NULL, 0, NULL, - "Show headings for columns on report.\n") +cfg(report_headings_CFG, "headings", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_REP_HEADINGS, vsn(1, 0, 0), NULL, 0, NULL, + "Format of LVM command's report output headings.\n" + "Accepted values:\n" + " 0 no headings,\n" + " 1 headings with column abbreviations,\n" + " 2 headings with full column names.\n") cfg(report_separator_CFG, "separator", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_REP_SEPARATOR, vsn(1, 0, 0), NULL, 0, NULL, "A separator to use on report after each field.\n") diff --git a/lib/report/report.c b/lib/report/report.c index dbbb369e9..f4bf1e7f4 100644 --- a/lib/report/report.c +++ b/lib/report/report.c @@ -4421,11 +4421,28 @@ static const struct dm_report_field_type _log_fields[] = { #undef SNUM #undef FIELD +report_headings_t report_headings_str_to_type(const char *str) +{ + if (!str || !*str) + return REPORT_HEADINGS_UNKNOWN; + + if (!strcmp(str, "none") || !strcmp(str, "0")) + return REPORT_HEADINGS_NONE; + + if (!strcmp(str, "abbrev") || !strcmp(str, "1")) + return REPORT_HEADINGS_ABBREV; + + if (!strcmp(str, "full") || !strcmp(str, "2")) + return REPORT_HEADINGS_FULL; + + return REPORT_HEADINGS_UNKNOWN; +} + void *report_init(struct cmd_context *cmd, const char *format, const char *keys, report_type_t *report_type, const char *separator, - int aligned, int buffered, int headings, int field_prefixes, - int quoted, int columns_as_rows, const char *selection, - int multiple_output) + int aligned, int buffered, report_headings_t headings, + int field_prefixes, int quoted, int columns_as_rows, + const char *selection, int multiple_output) { uint32_t report_flags = 0; const struct dm_report_object_type *types; @@ -4439,8 +4456,12 @@ void *report_init(struct cmd_context *cmd, const char *format, const char *keys, if (buffered) report_flags |= DM_REPORT_OUTPUT_BUFFERED; - if (headings) + if (headings) { + /* any out of bound headings type value maps to REPORT_HEADINGS_ABBREV */ report_flags |= DM_REPORT_OUTPUT_HEADINGS; + if (headings == REPORT_HEADINGS_FULL) + report_flags |= DM_REPORT_OUTPUT_FIELD_IDS_IN_HEADINGS; + } if (field_prefixes) report_flags |= DM_REPORT_OUTPUT_FIELD_NAME_PREFIX; diff --git a/lib/report/report.h b/lib/report/report.h index 380538ad6..67d7605c3 100644 --- a/lib/report/report.h +++ b/lib/report/report.h @@ -35,6 +35,13 @@ typedef enum { DEVTYPES = 2048 } report_type_t; +typedef enum { + REPORT_HEADINGS_UNKNOWN = -1, + REPORT_HEADINGS_NONE = 0, + REPORT_HEADINGS_ABBREV = 1, + REPORT_HEADINGS_FULL = 2 +} report_headings_t; + /* * The "struct selection_handle" is used only for selection * of items that should be processed further (not for display!). @@ -81,13 +88,15 @@ struct processing_handle; typedef int (*field_report_fn) (struct report_handle * dh, struct field * field, const void *data); +report_headings_t report_headings_str_to_type(const char *str); + int report_format_init(struct cmd_context *cmd); void *report_init(struct cmd_context *cmd, const char *format, const char *keys, report_type_t *report_type, const char *separator, - int aligned, int buffered, int headings, int field_prefixes, - int quoted, int columns_as_rows, const char *selection, - int multiple_output); + int aligned, int buffered, report_headings_t headings, + int field_prefixes, int quoted, int columns_as_rows, + const char *selection, int multiple_output); int report_get_single_selection(struct cmd_context *cmd, report_type_t report_type, const char **selection); void *report_init_for_selection(struct cmd_context *cmd, report_type_t *report_type, const char *selection); diff --git a/tools/args.h b/tools/args.h index 8eefb1d5a..bbb1f4744 100644 --- a/tools/args.h +++ b/tools/args.h @@ -334,6 +334,12 @@ arg(handlemissingpvs_ARG, '\0', "handlemissingpvs", 0, 0, 0, "Allows a polling operation to continue when PVs are missing,\n" "e.g. for repairs due to faulty devices.\n") +arg(headings_ARG, '\0', "headings", headings_VAL, 0, 0, + "Type of headings to use in report output.\n" + "\\fBnone\\fP or \\fB0\\fP: No headings.\n" + "\\fBabbrev\\fP or \\fB1\\fP: Column name abbreviations.\n" + "\\fBfull\\fP or \\fB2\\fP: Full column names.\n") + arg(ignoreadvanced_ARG, '\0', "ignoreadvanced", 0, 0, 0, "Exclude advanced configuration settings from the output.\n") diff --git a/tools/command-lines.in b/tools/command-lines.in index 20aa49667..f660314dd 100644 --- a/tools/command-lines.in +++ b/tools/command-lines.in @@ -210,7 +210,7 @@ OO_ALL: --commandprofile String, --config String, --debug, # options for pvs, lvs, vgs, fullreport # OO_REPORT: --aligned, --all, --binary, --configreport ConfigReport, --foreign, ---ignorelockingfailure, --logonly, +--headings HeadingsType --ignorelockingfailure, --logonly, --nameprefixes, --noheadings, --nosuffix, --options String, --readonly, --reportformat ReportFmt, --rows, --select String, --separator String, --shared, --sort String, @@ -1531,6 +1531,7 @@ OO: --history, --segments, OO_REPORT OP: VG|LV|Tag ... IO: --partial, --ignoreskippedcluster, --trustcache ID: lvs_general +RULE: --noheadings not --headings --- @@ -1644,6 +1645,7 @@ OO: --segments, OO_REPORT OP: PV|Tag ... IO: --partial, --ignoreskippedcluster, --trustcache ID: pvs_general +RULE: --noheadings not --headings --- @@ -1952,6 +1954,7 @@ OO: OO_REPORT OP: VG|Tag ... IO: --partial, --ignoreskippedcluster, --trustcache ID: vgs_general +RULE: --noheadings not --headings --- @@ -2007,6 +2010,7 @@ OO: OO_REPORT OP: VG ... IO: --partial, --ignoreskippedcluster, --trustcache ID: fullreport_general +RULE: --noheadings not --headings lastlog OO: --reportformat ReportFmt, --select String diff --git a/tools/command.c b/tools/command.c index c0373700d..0502db9a3 100644 --- a/tools/command.c +++ b/tools/command.c @@ -126,6 +126,7 @@ static inline int configreport_arg(struct cmd_context *cmd __attribute__((unused static inline int configtype_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; } static inline int repairtype_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; } static inline int dumptype_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; } +static inline int headings_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { return 0; } /* needed to include commands.h when building man page generator */ #define CACHE_VGMETADATA 0x00000001 diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c index 87f829f19..a5f34258e 100644 --- a/tools/lvmcmdline.c +++ b/tools/lvmcmdline.c @@ -1136,6 +1136,11 @@ int dumptype_arg(struct cmd_context *cmd, struct arg_values *av) return 0; } +int headings_arg(struct cmd_context *cmd, struct arg_values *av) +{ + return report_headings_str_to_type(av->value) != REPORT_HEADINGS_UNKNOWN; +} + /* * FIXME: there's been a confusing mixup among: * resizeable, resizable, allocatable, allocation. diff --git a/tools/reporter.c b/tools/reporter.c index 45273c0a4..82b39b212 100644 --- a/tools/reporter.c +++ b/tools/reporter.c @@ -48,9 +48,9 @@ struct report_args { char **argv; dm_report_group_type_t report_group_type; report_type_t report_type; + report_headings_t headings; int aligned; int buffered; - int headings; int field_prefixes; int quoted; int columns_as_rows; @@ -1247,9 +1247,11 @@ out: static int _config_report(struct cmd_context *cmd, struct report_args *args, struct single_report_args *single_args) { + const char *str; + args->aligned = find_config_tree_bool(cmd, report_aligned_CFG, NULL); args->buffered = find_config_tree_bool(cmd, report_buffered_CFG, NULL); - args->headings = find_config_tree_bool(cmd, report_headings_CFG, NULL); + args->headings = find_config_tree_int(cmd, report_headings_CFG, NULL); args->separator = find_config_tree_str(cmd, report_separator_CFG, NULL); args->field_prefixes = find_config_tree_bool(cmd, report_prefixes_CFG, NULL); args->quoted = find_config_tree_bool(cmd, report_quoted_CFG, NULL); @@ -1344,7 +1346,13 @@ static int _config_report(struct cmd_context *cmd, struct report_args *args, str if (arg_is_set(cmd, unbuffered_ARG) && !arg_is_set(cmd, sort_ARG)) args->buffered = 0; if (arg_is_set(cmd, noheadings_ARG)) - args->headings = 0; + args->headings = REPORT_HEADINGS_NONE; + if ((str = arg_str_value(cmd, headings_ARG, NULL))) { + if ((args->headings = report_headings_str_to_type(str)) == REPORT_HEADINGS_UNKNOWN) { + log_error("Unknown --headings value."); + return 0; + } + } if (arg_is_set(cmd, nameprefixes_ARG)) { args->aligned = 0; args->field_prefixes = 1; diff --git a/tools/tools.h b/tools/tools.h index 35841e300..8dfe20043 100644 --- a/tools/tools.h +++ b/tools/tools.h @@ -191,6 +191,7 @@ int configreport_arg(struct cmd_context *cmd __attribute__((unused)), struct arg int configtype_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av); int repairtype_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av); int dumptype_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av); +int headings_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av); /* we use the enums to access the switches */ int arg_is_valid_for_command(const struct cmd_context *cmd, int a); diff --git a/tools/vals.h b/tools/vals.h index 590755a1e..8e1819f6f 100644 --- a/tools/vals.h +++ b/tools/vals.h @@ -143,6 +143,7 @@ val(configreport_VAL, configreport_arg, "ConfigReport", "log|vg|lv|pv|pvseg|seg" val(configtype_VAL, configtype_arg, "ConfigType", "current|default|diff|full|list|missing|new|profilable|profilable-command|profilable-metadata") val(repairtype_VAL, repairtype_arg, "RepairType", "pv_header|metadata|label_header") val(dumptype_VAL, dumptype_arg, "DumpType", "headers|metadata|metadata_all|metadata_search") +val(headings_VAL, headings_arg, "HeadingsType", "none|abbrev|full|0|1|2") /* this should always be last */ val(VAL_COUNT, NULL, NULL, NULL)