From: Karel Zak Date: Tue, 26 Sep 2023 10:52:32 +0000 (+0200) Subject: lsblk: add scols counters support X-Git-Tag: v2.40-rc1~151^2~54 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0398951e877cede5543dcbc23704a2cf9a93beaa;p=thirdparty%2Futil-linux.git lsblk: add scols counters support * add --ct-filter to restrict the next next counters * add --ct [::func] to define counter. The counter assigned to the previously specified filter, if no filter specified then it's applied to all output lines. Examples: $ lsblk --ct "number of block devices" ... Summary: 21 number of block devices The filter uses default count() function and is applied to all lines. $ lsblk --ct-filter 'TRAN=="nvme"' --ct "number of NVMEs" ... Summary: 4 number of NVMEs The filter is restricted by filter. $ lsblk --bytes --ct-filter 'TRAN=="sata" && TYPE=="disk"' --ct "size of all SATAs disks":SIZE:sum ... Summary: 320083771392 size of all SATAs disks The counter uses sum() built-in function for specified column (SIZE) and is restricted by filter. Signed-off-by: Karel Zak --- diff --git a/misc-utils/lsblk.c b/misc-utils/lsblk.c index 9de1f2016b..7d207b5de1 100644 --- a/misc-utils/lsblk.c +++ b/misc-utils/lsblk.c @@ -1363,7 +1363,8 @@ static void device_to_scols( DBG(DEV, ul_debugobj(dev, "%s <- child done", dev->name)); } - if (lsblk->hlighter) { + /* apply highligther */ + if (ln && lsblk->hlighter) { int status = 0; if (scols_line_apply_filter(ln, lsblk->hlighter, &status) == 0 @@ -1371,6 +1372,10 @@ static void device_to_scols( scols_line_set_color(ln, lsblk->hlighter_seq); } + /* apply counters */ + for (i = 0; ln && i < lsblk->ncts; i++) + scols_line_apply_filter(ln, lsblk->ct_filters[i], NULL); + /* Let's be careful with number of open files */ ul_path_close_dirfd(dev->sysfs); } @@ -2064,12 +2069,103 @@ static struct libscols_filter *new_filter(const char *query) f = scols_new_filter(NULL); if (!f) err(EXIT_FAILURE, _("failed to allocate filter")); - if (scols_filter_parse_string(f, query) != 0) + if (query && scols_filter_parse_string(f, query) != 0) errx(EXIT_FAILURE, _("failed to parse \"%s\": %s"), query, scols_filter_get_errmsg(f)); return f; } +static struct libscols_filter *new_counter_filter(const char *query) +{ + lsblk->ct_filters = xreallocarray(lsblk->ct_filters, lsblk->ncts + 1, + sizeof(struct libscols_filter *)); + + lsblk->ct_filters[lsblk->ncts] = new_filter(query); + lsblk->ncts++; + + return lsblk->ct_filters[lsblk->ncts - 1]; +} + +static void set_counter_properties(const char *str0) +{ + struct libscols_filter *fltr = NULL; + struct libscols_counter *ct; + char *p, *str = xstrdup(str0); + char *name = NULL, *param = NULL, *func = NULL; + + for (p = strtok(str, ":"); p != NULL; p = strtok((char *)0, ":")) { + if (!name) + name = p; + else if (!param) + param = p; + else if (!func) + func = p; + else + errx(EXIT_FAILURE, _("unexpected counter specification: %s"), str0); + } + + if (!name) + errx(EXIT_FAILURE, _("counter not properly specified")); + + /* use the latest counter filter (--ct-filter) or create empty */ + if (lsblk->ncts) + fltr = lsblk->ct_filters[lsblk->ncts - 1]; + else + fltr = new_counter_filter(NULL); + + ct = scols_filter_new_counter(fltr); + if (!ct) + err(EXIT_FAILURE, _("failed to allocate counter")); + + scols_counter_set_name(ct, name); + if (param) + scols_counter_set_param(ct, param); + if (func) { + int x; + + if (strcmp(func, "max") == 0) + x = SCOLS_COUNTER_MAX; + else if (strcmp(func, "min") == 0) + x = SCOLS_COUNTER_MIN; + else if (strcmp(func, "sum") == 0) + x = SCOLS_COUNTER_SUM; + else if (strcmp(func, "count") == 0) + x = SCOLS_COUNTER_COUNT; + else + errx(EXIT_FAILURE, _("unsupported counter type: %s"), func); + + scols_counter_set_func(ct, x); + } + free(str); +} + +static void print_counters(void) +{ + struct libscols_iter *itr; + size_t i; + + fputc('\n', stdout); + fputs(_("Summary:\n"), stdout); + + itr = scols_new_iter(SCOLS_ITER_FORWARD); + if (!itr) + err(EXIT_FAILURE, _("failed to allocate iterator")); + + for (i = 0; i < lsblk->ncts; i++) { + struct libscols_filter *fltr = lsblk->ct_filters[i]; + struct libscols_counter *ct = NULL; + + scols_reset_iter(itr, SCOLS_ITER_FORWARD); + while (scols_filter_next_counter(fltr, itr, &ct) == 0) { + printf("%16llu %s\n", + scols_counter_get_result(ct), + scols_counter_get_name(ct)); + } + } + + scols_free_iter(itr); +} + static void init_scols_filter(struct libscols_table *tb, struct libscols_filter *f) { struct libscols_iter *itr; @@ -2103,6 +2199,7 @@ fail: errx(EXIT_FAILURE, _("failed to initialize filter")); } + static void __attribute__((__noreturn__)) usage(void) { FILE *out = stdout; @@ -2125,6 +2222,8 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -P, --pairs use key=\"value\" output format\n"), out); fputs(_(" -Q, --filter restrict output\n"), out); fputs(_(" -H, --highlight colorize lines maching the query\n"), out); + fputs(_(" --ct-filter restrict the next counters\n"), out); + fputs(_(" --ct [:[:]] define custom counter\n"), out); fputs(_(" -S, --scsi output info about SCSI devices\n"), out); fputs(_(" -N, --nvme output info about NVMe devices\n"), out); fputs(_(" -v, --virtio output info about virtio devices\n"), out); @@ -2184,7 +2283,9 @@ int main(int argc, char *argv[]) int force_tree = 0, has_tree_col = 0; enum { - OPT_SYSROOT = CHAR_MAX + 1 + OPT_SYSROOT = CHAR_MAX + 1, + OPT_COUNTER_FILTER, + OPT_COUNTER }; static const struct option longopts[] = { @@ -2223,6 +2324,8 @@ int main(int argc, char *argv[]) { "tree", optional_argument, NULL, 'T' }, { "version", no_argument, NULL, 'V' }, { "width", required_argument, NULL, 'w' }, + { "ct-filter", required_argument, NULL, OPT_COUNTER_FILTER }, + { "ct", required_argument, NULL, OPT_COUNTER }, { NULL, 0, NULL, 0 }, }; @@ -2248,6 +2351,7 @@ int main(int argc, char *argv[]) lsblk = &_ls; lsblk_init_debug(); + scols_init_debug(0); while((c = getopt_long(argc, argv, "AabdDzE:e:fH:hJlNnMmo:OpPQ:iI:rstVvST::w:x:y", @@ -2429,6 +2533,13 @@ int main(int argc, char *argv[]) errtryhelp(EXIT_FAILURE); break; + case OPT_COUNTER_FILTER: + new_counter_filter(optarg); + break; + case OPT_COUNTER: + set_counter_properties(optarg); + break; + case 'h': usage(); case 'V': @@ -2483,7 +2594,6 @@ int main(int argc, char *argv[]) } lsblk_mnt_init(); - scols_init_debug(0); ul_path_init_debug(); /* @@ -2579,6 +2689,8 @@ int main(int argc, char *argv[]) scols_table_enable_colors(lsblk->table, 1); init_scols_filter(lsblk->table, lsblk->hlighter); } + for (i = 0; i < lsblk->ncts; i++) + init_scols_filter(lsblk->table, lsblk->ct_filters[i]); tr = lsblk_new_devtree(); if (!tr) @@ -2618,6 +2730,8 @@ int main(int argc, char *argv[]) scols_print_table(lsblk->table); + if (lsblk->ncts) + print_counters(); leave: if (lsblk->sort_col) unref_sortdata(lsblk->table); @@ -2626,6 +2740,10 @@ leave: scols_unref_filter(lsblk->filter); scols_unref_filter(lsblk->hlighter); + for (i = 0; i < lsblk->ncts; i++) + scols_unref_filter(lsblk->ct_filters[i]); + free(lsblk->ct_filters); + lsblk_mnt_deinit(); lsblk_properties_deinit(); lsblk_unref_devtree(tr); diff --git a/misc-utils/lsblk.h b/misc-utils/lsblk.h index f8bc4f36d7..e98183f08d 100644 --- a/misc-utils/lsblk.h +++ b/misc-utils/lsblk.h @@ -45,6 +45,9 @@ struct lsblk { struct libscols_filter *hlighter; const char *hlighter_seq; + struct libscols_filter **ct_filters; /* array of counters' filters */ + size_t ncts; /* number of ct filters */ + const char *sysroot; int flags; /* LSBLK_* */