diff options
author | Lennart Poettering <lennart@poettering.net> | 2019-07-29 20:44:54 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-07-29 20:44:54 +0200 |
commit | cd2d52d34f280553c099e15a99a2e2751ef89826 (patch) | |
tree | febf7c8b6afbbae72d9ac34b9d94ccedb5bd25cf /src | |
parent | b8011ae2f89bbd131f5348f162f23c01865669b3 (diff) | |
parent | 81896fa2d92527038e072f4625ca3629bc6c63e8 (diff) | |
download | systemd-cd2d52d34f280553c099e15a99a2e2751ef89826.tar.gz |
Merge pull request #13216 from poettering/busctl-format-table
port "busctl list" to format-table.h
Diffstat (limited to 'src')
-rw-r--r-- | src/busctl/busctl.c | 211 | ||||
-rw-r--r-- | src/shared/format-table.c | 65 | ||||
-rw-r--r-- | src/shared/format-table.h | 7 |
3 files changed, 185 insertions, 98 deletions
diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c index 43850c6c23..3e2a928612 100644 --- a/src/busctl/busctl.c +++ b/src/busctl/busctl.c @@ -15,6 +15,7 @@ #include "escape.h" #include "fd-util.h" #include "fileio.h" +#include "format-table.h" #include "json.h" #include "locale-util.h" #include "log.h" @@ -141,17 +142,27 @@ static int acquire_bus(bool set_monitor, sd_bus **ret) { } static int list_bus_names(int argc, char **argv, void *userdata) { - _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL; - _cleanup_free_ char **merged = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_hashmap_free_ Hashmap *names = NULL; - char **i; - int r; - size_t max_i = 0; - unsigned n = 0; - void *v; - char *k; + _cleanup_(table_unrefp) Table *table = NULL; Iterator iterator; + char **i, *k; + void *v; + int r; + + enum { + COLUMN_ACTIVATABLE, + COLUMN_NAME, + COLUMN_PID, + COLUMN_PROCESS, + COLUMN_USER, + COLUMN_CONNECTION, + COLUMN_UNIT, + COLUMN_SESSION, + COLUMN_DESCRIPTION, + COLUMN_MACHINE, + }; if (!arg_unique && !arg_acquired && !arg_activatable) arg_unique = arg_acquired = arg_activatable = true; @@ -164,81 +175,95 @@ static int list_bus_names(int argc, char **argv, void *userdata) { if (r < 0) return log_error_errno(r, "Failed to list names: %m"); - (void) pager_open(arg_pager_flags); - names = hashmap_new(&string_hash_ops); if (!names) return log_oom(); STRV_FOREACH(i, acquired) { - max_i = MAX(max_i, strlen(*i)); - r = hashmap_put(names, *i, NAME_IS_ACQUIRED); if (r < 0) return log_error_errno(r, "Failed to add to hashmap: %m"); } STRV_FOREACH(i, activatable) { - max_i = MAX(max_i, strlen(*i)); - r = hashmap_put(names, *i, NAME_IS_ACTIVATABLE); if (r < 0 && r != -EEXIST) return log_error_errno(r, "Failed to add to hashmap: %m"); } - merged = new(char*, hashmap_size(names) + 1); - if (!merged) + table = table_new("activatable", "name", "pid", "process", "user", "connection", "unit", "session", "description", "machine"); + if (!table) return log_oom(); - HASHMAP_FOREACH_KEY(v, k, names, iterator) - merged[n++] = k; + r = table_set_align_percent(table, table_get_cell(table, 0, COLUMN_PID), 100); + if (r < 0) + return log_error_errno(r, "Failed to set alignment: %m"); - merged[n] = NULL; - strv_sort(merged); + r = table_set_empty_string(table, "-"); + if (r < 0) + return log_error_errno(r, "Failed to set empty string: %m"); - if (arg_legend) { - printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s", - (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION"); + r = table_set_sort(table, COLUMN_NAME, (size_t) -1); + if (r < 0) + return log_error_errno(r, "Failed to set sort column: %m"); - if (arg_show_machine) - puts(" MACHINE"); - else - putchar('\n'); - } + if (arg_show_machine) + r = table_set_display(table, COLUMN_NAME, COLUMN_PID, COLUMN_PROCESS, COLUMN_USER, COLUMN_CONNECTION, COLUMN_UNIT, COLUMN_SESSION, COLUMN_DESCRIPTION, COLUMN_MACHINE, (size_t) -1); + else + r = table_set_display(table, COLUMN_NAME, COLUMN_PID, COLUMN_PROCESS, COLUMN_USER, COLUMN_CONNECTION, COLUMN_UNIT, COLUMN_SESSION, COLUMN_DESCRIPTION, (size_t) -1); + if (r < 0) + return log_error_errno(r, "Failed to set columns to display: %m"); + + table_set_header(table, arg_legend); - STRV_FOREACH(i, merged) { + HASHMAP_FOREACH_KEY(v, k, names, iterator) { _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; - sd_id128_t mid; - if (hashmap_get(names, *i) == NAME_IS_ACTIVATABLE) { - /* Activatable */ + if (v == NAME_IS_ACTIVATABLE) { + r = table_add_many( + table, + TABLE_INT, PTR_TO_INT(v), + TABLE_STRING, k, + TABLE_EMPTY, + TABLE_EMPTY, + TABLE_EMPTY, + TABLE_STRING, "(activatable)", TABLE_SET_COLOR, ansi_grey(), + TABLE_EMPTY, + TABLE_EMPTY, + TABLE_EMPTY, + TABLE_EMPTY); + if (r < 0) + return log_error_errno(r, "Failed to fill line: %m"); - printf("%-*s", (int) max_i, *i); - printf(" - - - (activatable) - - "); - if (arg_show_machine) - puts(" -"); - else - putchar('\n'); continue; - } - if (!arg_unique && (*i)[0] == ':') + assert(v == NAME_IS_ACQUIRED); + + if (!arg_unique && k[0] == ':') continue; - if (!arg_acquired && (*i)[0] != ':') + if (!arg_acquired && k[0] != ':') continue; - printf("%-*s", (int) max_i, *i); + r = table_add_many(table, + TABLE_INT, PTR_TO_INT(v), + TABLE_STRING, k); + if (r < 0) + return log_error_errno(r, "Failed to add name %s to table: %m", k); r = sd_bus_get_name_creds( - bus, *i, + bus, k, (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM| SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION| SD_BUS_CREDS_DESCRIPTION, &creds); - if (r >= 0) { - const char *unique, *session, *unit, *cn; + if (r < 0) { + log_debug_errno(r, "Failed to acquire credentials of service %s, ignoring: %m", k); + + r = table_fill_empty(table, COLUMN_MACHINE); + } else { + const char *unique = NULL, *session = NULL, *unit = NULL, *cn = NULL; pid_t pid; uid_t uid; @@ -246,11 +271,15 @@ static int list_bus_names(int argc, char **argv, void *userdata) { if (r >= 0) { const char *comm = NULL; - sd_bus_creds_get_comm(creds, &comm); + (void) sd_bus_creds_get_comm(creds, &comm); - printf(" %10lu %-15s", (unsigned long) pid, strna(comm)); + r = table_add_many(table, + TABLE_PID, pid, + TABLE_STRING, strna(comm)); } else - fputs(" - - ", stdout); + r = table_add_many(table, TABLE_EMPTY, TABLE_EMPTY); + if (r < 0) + return log_error_errno(r, "Failed to add fields to table: %m"); r = sd_bus_creds_get_euid(creds, &uid); if (r >= 0) { @@ -260,56 +289,60 @@ static int list_bus_names(int argc, char **argv, void *userdata) { if (!u) return log_oom(); - if (strlen(u) > 16) - u[16] = 0; - - printf(" %-16s", u); + r = table_add_cell(table, NULL, TABLE_STRING, u); } else - fputs(" - ", stdout); + r = table_add_cell(table, NULL, TABLE_EMPTY, NULL); + if (r < 0) + return log_error_errno(r, "Failed to add field to table: %m"); + + (void) sd_bus_creds_get_unique_name(creds, &unique); + (void) sd_bus_creds_get_unit(creds, &unit); + (void) sd_bus_creds_get_session(creds, &session); + (void) sd_bus_creds_get_description(creds, &cn); + + r = table_add_many( + table, + TABLE_STRING, unique, + TABLE_STRING, unit, + TABLE_STRING, session, + TABLE_STRING, cn); + } + if (r < 0) + return log_error_errno(r, "Failed to add fields to table: %m"); - r = sd_bus_creds_get_unique_name(creds, &unique); - if (r >= 0) - printf(" %-13s", unique); - else - fputs(" - ", stdout); + if (arg_show_machine) { + sd_id128_t mid; - r = sd_bus_creds_get_unit(creds, &unit); - if (r >= 0) { - _cleanup_free_ char *e; + r = sd_bus_get_name_machine_id(bus, k, &mid); + if (r < 0) + log_debug_errno(r, "Failed to acquire credentials of service %s, ignoring: %m", k); + else { + char m[SD_ID128_STRING_MAX]; - e = ellipsize(unit, 25, 100); - if (!e) - return log_oom(); + r = table_add_cell(table, NULL, TABLE_STRING, sd_id128_to_string(mid, m)); + if (r < 0) + return log_error_errno(r, "Failed to add field to table: %m"); - printf(" %-25s", e); - } else - fputs(" - ", stdout); + continue; /* line fully filled, no need to fill the remainder below */ + } + } - r = sd_bus_creds_get_session(creds, &session); - if (r >= 0) - printf(" %-10s", session); - else - fputs(" - ", stdout); + r = table_fill_empty(table, 0); + if (r < 0) + return log_error_errno(r, "Failed to fill line: %m"); + } - r = sd_bus_creds_get_description(creds, &cn); - if (r >= 0) - printf(" %-19s", cn); - else - fputs(" - ", stdout); + if (IN_SET(arg_json, JSON_OFF, JSON_PRETTY)) + (void) pager_open(arg_pager_flags); + + if (arg_json) + r = table_print_json(table, stdout, (arg_json == JSON_PRETTY ? JSON_FORMAT_PRETTY : JSON_FORMAT_NEWLINE) | JSON_FORMAT_COLOR_AUTO); + else + r = table_print(table, stdout); + if (r < 0) + return log_error_errno(r, "Failed to show table: %m"); - } else - printf(" - - - - - - - "); - if (arg_show_machine) { - r = sd_bus_get_name_machine_id(bus, *i, &mid); - if (r >= 0) { - char m[SD_ID128_STRING_MAX]; - printf(" %s\n", sd_id128_to_string(mid, m)); - } else - puts(" -"); - } else - putchar('\n'); - } return 0; } diff --git a/src/shared/format-table.c b/src/shared/format-table.c index 44937e1c91..e41cbb1720 100644 --- a/src/shared/format-table.c +++ b/src/shared/format-table.c @@ -127,6 +127,8 @@ struct Table { size_t n_sort_map; bool *reverse_map; + + char *empty_string; }; Table *table_new_raw(size_t n_columns) { @@ -218,6 +220,7 @@ Table *table_unref(Table *t) { free(t->display_map); free(t->sort_map); free(t->reverse_map); + free(t->empty_string); return mfree(t); } @@ -373,6 +376,10 @@ int table_add_cell_full( assert(type >= 0); assert(type < _TABLE_DATA_TYPE_MAX); + /* Special rule: patch NULL data fields to the empty field */ + if (!data) + type = TABLE_EMPTY; + /* Determine the cell adjacent to the current one, but one row up */ if (t->n_cells >= t->n_columns) assert_se(p = t->data[t->n_cells - t->n_columns]); @@ -431,6 +438,27 @@ int table_add_cell_stringf(Table *t, TableCell **ret_cell, const char *format, . return table_add_cell(t, ret_cell, TABLE_STRING, buffer); } +int table_fill_empty(Table *t, size_t until_column) { + int r; + + assert(t); + + /* Fill the rest of the current line with empty cells until we reach the specified column. Will add + * at least one cell. Pass 0 in order to fill a line to the end or insert an empty line. */ + + if (until_column >= t->n_columns) + return -EINVAL; + + do { + r = table_add_cell(t, NULL, TABLE_EMPTY, NULL); + if (r < 0) + return r; + + } while ((t->n_cells % t->n_columns) != until_column); + + return 0; +} + int table_dup_cell(Table *t, TableCell *cell) { size_t i; @@ -930,6 +958,12 @@ void table_set_width(Table *t, size_t width) { t->width = width; } +int table_set_empty_string(Table *t, const char *empty) { + assert(t); + + return free_and_strdup(&t->empty_string, empty); +} + int table_set_display(Table *t, size_t first_column, ...) { size_t allocated, column; va_list ap; @@ -1105,7 +1139,7 @@ static int table_data_compare(const size_t *a, const size_t *b, Table *t) { return CMP(*a, *b); } -static const char *table_data_format(TableData *d) { +static const char *table_data_format(Table *t, TableData *d) { assert(d); if (d->formatted) @@ -1113,7 +1147,7 @@ static const char *table_data_format(TableData *d) { switch (d->type) { case TABLE_EMPTY: - return ""; + return strempty(t->empty_string); case TABLE_STRING: if (d->uppercase) { @@ -1374,11 +1408,11 @@ static const char *table_data_format(TableData *d) { return d->formatted; } -static int table_data_requested_width(TableData *d, size_t *ret) { +static int table_data_requested_width(Table *table, TableData *d, size_t *ret) { const char *t; size_t l; - t = table_data_format(d); + t = table_data_format(table, d); if (!t) return -ENOMEM; @@ -1456,6 +1490,19 @@ static char *align_string_mem(const char *str, const char *url, size_t new_lengt return ret; } +static const char* table_data_color(TableData *d) { + assert(d); + + if (d->color) + return d->color; + + /* Let's implicitly color all "empty" cells in grey, in case an "empty_string" is set that is not empty */ + if (d->type == TABLE_EMPTY) + return ansi_grey(); + + return NULL; +} + int table_print(Table *t, FILE *f) { size_t n_rows, *minimum_width, *maximum_width, display_columns, *requested_width, i, j, table_minimum_width, table_maximum_width, table_requested_width, table_effective_width, @@ -1521,7 +1568,7 @@ int table_print(Table *t, FILE *f) { assert_se(d = row[t->display_map ? t->display_map[j] : j]); - r = table_data_requested_width(d, &req); + r = table_data_requested_width(t, d, &req); if (r < 0) return r; @@ -1688,7 +1735,7 @@ int table_print(Table *t, FILE *f) { assert_se(d = row[t->display_map ? t->display_map[j] : j]); - field = table_data_format(d); + field = table_data_format(t, d); if (!field) return -ENOMEM; @@ -1729,16 +1776,16 @@ int table_print(Table *t, FILE *f) { if (j > 0) fputc(' ', f); /* column separator */ - if (d->color && colors_enabled()) { + if (table_data_color(d) && colors_enabled()) { if (row == t->data) /* first undo header underliner */ fputs(ANSI_NORMAL, f); - fputs(d->color, f); + fputs(table_data_color(d), f); } fputs(field, f); - if (colors_enabled() && (d->color || row == t->data)) + if (colors_enabled() && (table_data_color(d) || row == t->data)) fputs(ANSI_NORMAL, f); } diff --git a/src/shared/format-table.h b/src/shared/format-table.h index c6df8bf70c..aacf978978 100644 --- a/src/shared/format-table.h +++ b/src/shared/format-table.h @@ -49,6 +49,10 @@ typedef enum TableDataType { _TABLE_DATA_TYPE_INVALID = -1, } TableDataType; +/* PIDs are just 32bit signed integers on Linux */ +#define TABLE_PID TABLE_INT32 +assert_cc(sizeof(pid_t) == sizeof(int32_t)); + typedef struct Table Table; typedef struct TableCell TableCell; @@ -65,6 +69,8 @@ static inline int table_add_cell(Table *t, TableCell **ret_cell, TableDataType t } int table_add_cell_stringf(Table *t, TableCell **ret_cell, const char *format, ...) _printf_(3, 4); +int table_fill_empty(Table *t, size_t until_column); + int table_dup_cell(Table *t, TableCell *cell); int table_set_minimum_width(Table *t, TableCell *cell, size_t minimum_width); @@ -83,6 +89,7 @@ int table_add_many_internal(Table *t, TableDataType first_type, ...); void table_set_header(Table *table, bool b); void table_set_width(Table *t, size_t width); +int table_set_empty_string(Table *t, const char *empty); int table_set_display(Table *t, size_t first_column, ...); int table_set_sort(Table *t, size_t first_column, ...); int table_set_reverse(Table *t, size_t column, bool b); |