diff --git a/man/standard-options.xml b/man/standard-options.xml index 64274ce8f31..8ba5b09df85 100644 --- a/man/standard-options.xml +++ b/man/standard-options.xml @@ -52,4 +52,13 @@ Before each file, the filename is printed as a comment. + + + MODE + + Shows output formatted as JSON. Expects one of short (for the + shortest possible output without any redundant whitespace or line breaks), pretty + (for a pretty version of the same, with indentation and line breaks) or off (to turn + off JSON output, the default). + diff --git a/man/systemd-dissect.xml b/man/systemd-dissect.xml index ed2153f765b..fd55fd0bfb3 100644 --- a/man/systemd-dissect.xml +++ b/man/systemd-dissect.xml @@ -162,15 +162,6 @@ operation begins. - - MODE - - Shows output formatted as JSON. Expects one of short (for the - shortest possible output without any redundant whitespace or line breaks), pretty - (for a pretty version of the same, with indentation and line breaks) or off (to turn - off json output). - - @@ -237,6 +228,9 @@ url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable Partitions Specification. + + + diff --git a/man/systemd-repart.xml b/man/systemd-repart.xml index 858b5be66d7..a5a0890c526 100644 --- a/man/systemd-repart.xml +++ b/man/systemd-repart.xml @@ -278,15 +278,6 @@ and graphic illustrating the changes applied. - - MODE - - Shows output formatted as JSON. Expects one of short (for the - shortest possible output without any redundant whitespace or line breaks), pretty - (for a pretty version of the same, with indentation and line breaks) or off (to turn - off json output). - - @@ -321,6 +312,9 @@ + + + diff --git a/man/systemd-sysext.xml b/man/systemd-sysext.xml index e5f2e368998..ad6a401c7a2 100644 --- a/man/systemd-sysext.xml +++ b/man/systemd-sysext.xml @@ -211,14 +211,6 @@ /opt/ hierarchies, but below some specified root directory. - - - - Generate JSON output, instead of human readable tabular output. Takes one of - short, pretty or off in order to control the - output style, or explicitly disabling JSON output. - - @@ -229,6 +221,8 @@ + + diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c index 276cae1b8b5..8a31916ad79 100644 --- a/src/busctl/busctl.c +++ b/src/busctl/busctl.c @@ -239,8 +239,6 @@ static int list_bus_names(int argc, char **argv, void *userdata) { if (r < 0) return log_error_errno(r, "Failed to set columns to display: %m"); - table_set_header(table, arg_legend); - HASHMAP_FOREACH_KEY(v, k, names) { _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; @@ -357,14 +355,7 @@ static int list_bus_names(int argc, char **argv, void *userdata) { return log_error_errno(r, "Failed to fill line: %m"); } - if (arg_json_format_flags & (JSON_FORMAT_OFF|JSON_FORMAT_PRETTY|JSON_FORMAT_PRETTY_AUTO)) - (void) pager_open(arg_pager_flags); - - r = table_print_json(table, NULL, arg_json_format_flags); - if (r < 0) - return table_log_print_error(r); - - return 0; + return table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend); } static void print_subtree(const char *prefix, const char *path, char **l) { @@ -2255,6 +2246,8 @@ static int help(void) { if (r < 0) return log_oom(); + (void) pager_open(arg_pager_flags); + printf("%s [OPTIONS...] COMMAND ...\n\n" "%sIntrospect the D-Bus IPC bus.%s\n" "\nCommands:\n" diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c index c5d161b2b57..9b127d456a9 100644 --- a/src/dissect/dissect.c +++ b/src/dissect/dissect.c @@ -46,6 +46,8 @@ static const char *arg_target = NULL; static DissectImageFlags arg_flags = DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK; static VeritySettings arg_verity_settings = VERITY_SETTINGS_DEFAULT; static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF; +static PagerFlags arg_pager_flags = 0; +static bool arg_legend = true; STATIC_DESTRUCTOR_REGISTER(arg_verity_settings, verity_settings_done); @@ -63,6 +65,8 @@ static int help(void) { "%1$s [OPTIONS...] --copy-to IMAGE [SOURCE] PATH\n\n" "%5$sDissect a file system OS image.%6$s\n\n" "%3$sOptions:%4$s\n" + " --no-pager Do not pipe output into a pager\n" + " --no-legend Do not show the headers and footers\n" " -r --read-only Mount read-only\n" " --fsck=BOOL Run fsck before mounting\n" " --mkdir Make mount directory before mounting, if missing\n" @@ -96,6 +100,8 @@ static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, + ARG_NO_PAGER, + ARG_NO_LEGEND, ARG_DISCARD, ARG_FSCK, ARG_ROOT_HASH, @@ -108,6 +114,8 @@ static int parse_argv(int argc, char *argv[]) { static const struct option options[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, ARG_VERSION }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, { "mount", no_argument, NULL, 'm' }, { "read-only", no_argument, NULL, 'r' }, { "discard", required_argument, NULL, ARG_DISCARD }, @@ -137,6 +145,14 @@ static int parse_argv(int argc, char *argv[]) { case ARG_VERSION: return version(); + case ARG_NO_PAGER: + arg_pager_flags |= PAGER_DISABLE; + break; + + case ARG_NO_LEGEND: + arg_legend = false; + break; + case 'm': arg_action = ACTION_MOUNT; break; @@ -339,6 +355,9 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) { assert(m); assert(d); + if (arg_json_format_flags & (JSON_FORMAT_OFF|JSON_FORMAT_PRETTY|JSON_FORMAT_PRETTY_AUTO)) + (void) pager_open(arg_pager_flags); + if (arg_json_format_flags & JSON_FORMAT_OFF) printf(" Name: %s\n", basename(arg_image)); @@ -482,7 +501,9 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) { } if (arg_json_format_flags & JSON_FORMAT_OFF) { - r = table_print(t, stdout); + (void) table_set_header(t, arg_legend); + + r = table_print(t, NULL); if (r < 0) return table_log_print_error(r); } else { diff --git a/src/home/homectl.c b/src/home/homectl.c index f9c07dfec71..93d322110b5 100644 --- a/src/home/homectl.c +++ b/src/home/homectl.c @@ -113,8 +113,6 @@ static int list_homes(int argc, char *argv[], void *userdata) { _cleanup_(table_unrefp) Table *table = NULL; int r; - (void) pager_open(arg_pager_flags); - r = acquire_bus(&bus); if (r < 0) return r; @@ -175,11 +173,9 @@ static int list_homes(int argc, char *argv[], void *userdata) { if (r < 0) return table_log_sort_error(r); - table_set_header(table, arg_legend); - - r = table_print_json(table, stdout, arg_json_format_flags); + r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend); if (r < 0) - return table_log_print_error(r); + return r; } if (arg_legend && (arg_json_format_flags & JSON_FORMAT_OFF)) { diff --git a/src/partition/repart.c b/src/partition/repart.c index d98051d1349..3de7a052dfe 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -107,6 +107,8 @@ static int arg_pretty = -1; static uint64_t arg_size = UINT64_MAX; static bool arg_size_auto = false; static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF; +static PagerFlags arg_pager_flags = 0; +static bool arg_legend = true; static void *arg_key = NULL; static size_t arg_key_size = 0; static char *arg_tpm2_device = NULL; @@ -1918,11 +1920,7 @@ static int context_dump_partitions(Context *context, const char *node) { return table_log_add_error(r); } - r = table_print_json(t, stdout, arg_json_format_flags); - if (r < 0) - return table_log_print_error(r); - - return 0; + return table_print_with_pager(t, arg_json_format_flags, arg_pager_flags, arg_legend); } static void context_bar_char_process_partition( @@ -3479,6 +3477,8 @@ static int help(void) { "\n%sGrow and add partitions to partition table.%s\n\n" " -h --help Show this help\n" " --version Show package version\n" + " --no-pager Do not pipe output into a pager\n" + " --no-legend Do not show the headers and footers\n" " --dry-run=BOOL Whether to run dry-run operation\n" " --empty=MODE One of refuse, allow, require, force, create; controls\n" " how to handle empty disks lacking partition tables\n" @@ -3510,6 +3510,8 @@ static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, + ARG_NO_PAGER, + ARG_NO_LEGEND, ARG_DRY_RUN, ARG_EMPTY, ARG_DISCARD, @@ -3529,6 +3531,8 @@ static int parse_argv(int argc, char *argv[]) { static const struct option options[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, ARG_VERSION }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, { "dry-run", required_argument, NULL, ARG_DRY_RUN }, { "empty", required_argument, NULL, ARG_EMPTY }, { "discard", required_argument, NULL, ARG_DISCARD }, @@ -3561,6 +3565,14 @@ static int parse_argv(int argc, char *argv[]) { case ARG_VERSION: return version(); + case ARG_NO_PAGER: + arg_pager_flags |= PAGER_DISABLE; + break; + + case ARG_NO_LEGEND: + arg_legend = false; + break; + case ARG_DRY_RUN: r = parse_boolean(optarg); if (r < 0) diff --git a/src/shared/format-table.c b/src/shared/format-table.c index 645e5b9afa1..8b9c81664df 100644 --- a/src/shared/format-table.c +++ b/src/shared/format-table.c @@ -2550,3 +2550,30 @@ int table_print_json(Table *t, FILE *f, JsonFormatFlags flags) { return fflush_and_check(f); } + +int table_print_with_pager( + Table *t, + JsonFormatFlags json_format_flags, + PagerFlags pager_flags, + bool show_header) { + + bool saved_header; + int r; + + assert(t); + + /* A all-in-one solution for showing tables, and turning on a pager first. Also optionally suppresses + * the table header and logs about any error. */ + + if (json_format_flags & (JSON_FORMAT_OFF|JSON_FORMAT_PRETTY|JSON_FORMAT_PRETTY_AUTO)) + (void) pager_open(pager_flags); + + saved_header = t->header; + t->header = show_header; + r = table_print_json(t, stdout, json_format_flags); + t->header = saved_header; + if (r < 0) + return table_log_print_error(r); + + return 0; +} diff --git a/src/shared/format-table.h b/src/shared/format-table.h index 965549b60a4..6627a291f34 100644 --- a/src/shared/format-table.h +++ b/src/shared/format-table.h @@ -7,6 +7,7 @@ #include "json.h" #include "macro.h" +#include "pager.h" typedef enum TableDataType { TABLE_EMPTY, @@ -129,6 +130,8 @@ const void *table_get_at(Table *t, size_t row, size_t column); int table_to_json(Table *t, JsonVariant **ret); int table_print_json(Table *t, FILE *f, JsonFormatFlags json_flags); +int table_print_with_pager(Table *t, JsonFormatFlags json_format_flags, PagerFlags pager_flags, bool show_header); + #define table_log_add_error(r) \ log_error_errno(r, "Failed to add cell(s) to table: %m") diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c index 590dfc9c208..81b3b29c08a 100644 --- a/src/sysext/sysext.c +++ b/src/sysext/sysext.c @@ -35,6 +35,7 @@ static char **arg_hierarchies = NULL; /* "/usr" + "/opt" by default */ static char *arg_root = NULL; static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF; static PagerFlags arg_pager_flags = 0; +static bool arg_legend = true; static bool arg_force = false; STATIC_DESTRUCTOR_REGISTER(arg_hierarchies, strv_freep); @@ -226,12 +227,9 @@ static int verb_status(int argc, char **argv, void *userdata) { (void) table_set_sort(t, (size_t) 0, (size_t) -1); - if (arg_json_format_flags & (JSON_FORMAT_OFF|JSON_FORMAT_PRETTY|JSON_FORMAT_PRETTY_AUTO)) - (void) pager_open(arg_pager_flags); - - r = table_print_json(t, stdout, arg_json_format_flags); + r = table_print_with_pager(t, arg_json_format_flags, arg_pager_flags, arg_legend); if (r < 0) - return table_log_add_error(r); + return r; return ret; } @@ -860,14 +858,7 @@ static int verb_list(int argc, char **argv, void *userdata) { (void) table_set_sort(t, (size_t) 0, (size_t) -1); - if (arg_json_format_flags & (JSON_FORMAT_OFF|JSON_FORMAT_PRETTY|JSON_FORMAT_PRETTY_AUTO)) - (void) pager_open(arg_pager_flags); - - r = table_print_json(t, stdout, arg_json_format_flags); - if (r < 0) - return table_log_print_error(r); - - return 0; + return table_print_with_pager(t, arg_json_format_flags, arg_pager_flags, arg_legend); } static int verb_help(int argc, char **argv, void *userdata) { @@ -890,6 +881,7 @@ static int verb_help(int argc, char **argv, void *userdata) { " --version Show package version\n" "\n%3$sOptions:%4$s\n" " --no-pager Do not pipe output into a pager\n" + " --no-legend Do not show the headers and footers\n" " --root=PATH Operate relative to root path\n" " --json=pretty|short|off\n" " Generate JSON output\n" @@ -909,18 +901,20 @@ static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, ARG_NO_PAGER, + ARG_NO_LEGEND, ARG_ROOT, ARG_JSON, ARG_FORCE, }; static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "no-pager", no_argument, NULL, ARG_NO_PAGER }, - { "root", required_argument, NULL, ARG_ROOT }, - { "json", required_argument, NULL, ARG_JSON }, - { "force", no_argument, NULL, ARG_FORCE }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, + { "root", required_argument, NULL, ARG_ROOT }, + { "json", required_argument, NULL, ARG_JSON }, + { "force", no_argument, NULL, ARG_FORCE }, {} }; @@ -943,6 +937,10 @@ static int parse_argv(int argc, char *argv[]) { arg_pager_flags |= PAGER_DISABLE; break; + case ARG_NO_LEGEND: + arg_legend = false; + break; + case ARG_ROOT: r = parse_path_argument_and_warn(optarg, false, &arg_root); if (r < 0)