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)