From: Karel Zak Date: Thu, 23 Nov 2023 11:51:38 +0000 (+0100) Subject: Merge branch 'PR/libsmartcols-filter' of github.com:karelzak/util-linux-work X-Git-Tag: v2.40-rc1~151 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6a82643ad3ff237181b7e0fca1640282430625ca;hp=-c;p=thirdparty%2Futil-linux.git Merge branch 'PR/libsmartcols-filter' of github.com:karelzak/util-linux-work * 'PR/libsmartcols-filter' of github.com:karelzak/util-linux-work: (88 commits) meson: remove scols filter sample tests: use array keys in more robust way lsblk: update after rebase tests: add libsmartcols filter tests libsmartcols: (sample) fix error message tests: use scols_column_set_properties() in 'fromfile' sample libsmartcols: improve and fix scols_column_set_properties() libsmartcols: (samples) remove filter.c libsmartcols: add filter support to 'fromfile' sample libsmartcols: fix filter param copying tests: don't keep bison messages in tests autotools: use stamp file to build filter parser, improve portability meson: use bison --defines=HEADER libsmartcols: fix typo in parser tokens libsmartcols: add scols-filter.5 man page libsmartcols: (filter) add upper case EQ,NE,LE,LT,GT and GE operators ci: packit: add flex meson: fix copy & past error libsmartcols: build filter scanner and parser header files too meson: add missing scols sample ... --- 6a82643ad3ff237181b7e0fca1640282430625ca diff --combined configure.ac index 9c6895b53d,b6941cd2fa..ac39d595d1 --- a/configure.ac +++ b/configure.ac @@@ -124,6 -124,11 +124,11 @@@ AC_PROG_C AM_PROG_CC_C_O AC_PROG_MKDIR_P AC_PROG_YACC + + # Don't use autotools integrated LEX/YACC support for libsmartcols + AC_PATH_PROG([FLEX], [flex]) + AC_PATH_PROG([BISON], [bison]) + AC_CANONICAL_HOST AC_C_CONST AC_C_VOLATILE @@@ -178,6 -183,9 +183,6 @@@ AC_SUBST([BSD_WARN_CFLAGS] UL_WARN_ADD([-Wno-cast-function-type], [PYTHON_WARN_CFLAGS]) AC_SUBST([PYTHON_WARN_CFLAGS]) -UL_WARN_ADD([-Wno-unused-parameter], [NO_UNUSED_WARN_CFLAGS]) -AC_SUBST([NO_UNUSED_WARN_CFLAGS]) - AC_ARG_ENABLE([asan], AS_HELP_STRING([--enable-asan], [compile with Address Sanitizer]), diff --combined meson.build index eb7837a7c3,93433dc164..f48722b03f --- a/meson.build +++ b/meson.build @@@ -838,15 -838,15 +838,15 @@@ conf.set('ONLY_LISTED_SHELLS', have ? have = get_option('use-tty-group') conf.set('USE_TTY_GROUP', have ? 1 : false) + bison = find_program('bison') + flex = find_program('flex') + build_hwclock = not get_option('build-hwclock').disabled() - bison = find_program('bison', required: build_hwclock) bison_gen = generator( bison, output : ['@BASENAME@.tab.c', '@BASENAME@.tab.h'], arguments : ['@INPUT@', '--defines=@OUTPUT1@', '--output=@OUTPUT0@']) - - meson_make_symlink = meson.current_source_dir() + '/tools/meson-make-symlink.sh' meson_make_manpage_stub = meson.current_source_dir() + '/tools/meson-make-manpage-stub.sh' @@@ -2616,6 -2616,7 +2616,7 @@@ exe = executable link_with : [lib_common, lib_blkid, lib_mount, + lib_tcolors, lib_smartcols], dependencies : lib_udev, install : true) @@@ -3220,7 -3221,8 +3221,7 @@@ endi ############################################################ -libfdisk_tests_cflags = ['-DTEST_PROGRAM', - '-Wno-unused'] +libfdisk_tests_cflags = ['-DTEST_PROGRAM'] libfdisk_tests_ldadd = [lib_fdisk_static, lib_uuid, lib_blkid] exe = executable( @@@ -3289,11 -3291,13 +3290,11 @@@ if not is_disabler(exe exes += exe endif -sample_fdisk_cflags = ['-Wno-unused'] sample_fdisk_ldadd = [lib_common, lib_fdisk] exe = executable( 'sample-fdisk-mkpart', 'libfdisk/samples/mkpart.c', - c_args : sample_fdisk_cflags, include_directories : lib_fdisk_includes, link_with : sample_fdisk_ldadd) if not is_disabler(exe) @@@ -3303,6 -3307,7 +3304,6 @@@ endi exe = executable( 'sample-fdisk-mkpart-fullspec', 'libfdisk/samples/mkpart-fullspec.c', - c_args : sample_fdisk_cflags, include_directories : lib_fdisk_includes, link_with : sample_fdisk_ldadd) if not is_disabler(exe) diff --combined misc-utils/lsblk.c index e45cd977fe,9167c4ce31..7d7b5152ef --- a/misc-utils/lsblk.c +++ b/misc-utils/lsblk.c @@@ -52,6 -52,7 +52,7 @@@ #include "fileutils.h" #include "loopdev.h" #include "buffer.h" + #include "colors.h" #include "lsblk.h" @@@ -222,7 -223,7 +223,7 @@@ static const struct colinfo infos[] = [COL_SCHED] = { "SCHED", 0.1, 0, N_("I/O scheduler name") }, [COL_SERIAL] = { "SERIAL", 0.1, SCOLS_FL_TRUNC, N_("disk serial number") }, [COL_SIZE] = { "SIZE", 5, SCOLS_FL_RIGHT, N_("size of the device"), COLTYPE_SIZE }, - [COL_START] = { "START", 5, SCOLS_FL_RIGHT, N_("partition start offset"), COLTYPE_NUM }, + [COL_START] = { "START", 5, SCOLS_FL_RIGHT, N_("partition start offset (in 512-byte sectors)"), COLTYPE_NUM }, [COL_STATE] = { "STATE", 7, SCOLS_FL_TRUNC, N_("state of the device") }, [COL_SUBSYS] = { "SUBSYSTEMS", 0.1, SCOLS_FL_NOEXTREMES, N_("de-duplicated chain of subsystems") }, [COL_TARGETS] = { "MOUNTPOINTS", 0.10, SCOLS_FL_WRAP | SCOLS_FL_NOEXTREMES, N_("all locations where device is mounted") }, @@@ -242,6 -243,12 +243,12 @@@ [COL_ZONE_AMAX] = { "ZONE-AMAX", 10, SCOLS_FL_RIGHT, N_("maximum number of active zones"), COLTYPE_NUM }, }; + /* "userdata" used by callback for libsmartcols filter */ + struct filler_data { + struct lsblk_device *dev; + struct lsblk_device *parent; + }; + struct lsblk *lsblk; /* global handler */ /* @@@ -338,12 -345,30 +345,30 @@@ static int column_name_to_id(const cha { size_t i; + /* name as diplayed for users */ for (i = 0; i < ARRAY_SIZE(infos); i++) { const char *cn = infos[i].name; if (!strncasecmp(name, cn, namesz) && !*(cn + namesz)) return i; } + + /* name as used in expressions, JSON output etc. */ + if (strnchr(name, namesz, '_')) { + char *buf = NULL; + size_t bufsz = 0; + + for (i = 0; i < ARRAY_SIZE(infos); i++) { + if (scols_shellvar_name(infos[i].name, &buf, &bufsz) != 0) + continue; + if (!strncasecmp(name, buf, namesz) && !*(buf + namesz)) { + free(buf); + return i; + } + } + free(buf); + } + warnx(_("unknown column: %s"), name); return -1; } @@@ -601,7 -626,7 +626,7 @@@ static char *mk_dm_name(const char *nam /* stores data to scols cell userdata (invisible and independent on output) * to make the original values accessible for sort functions */ - static void set_sortdata_u64(struct libscols_line *ln, int col, uint64_t x) + static void set_rawdata_u64(struct libscols_line *ln, int col, uint64_t x) { struct libscols_cell *ce = scols_line_get_cell(ln, col); uint64_t *data; @@@ -629,22 -654,37 +654,37 @@@ static void str2u64(const char *str, ui *data = num; } - static void unref_sortdata(struct libscols_table *tb) + static void unref_line_rawdata(struct libscols_line *ln, struct libscols_table *tb) + { + size_t i; + + for (i = 0; i < ncolumns; i++) { + struct libscols_column *cl = scols_table_get_column(tb, i); + struct libscols_cell *ce; + void *data; + + if (cl != lsblk->sort_col && !scols_column_has_data_func(cl)) + continue; + + ce = scols_line_get_column_cell(ln, cl); + data = scols_cell_get_userdata(ce); + free(data); + } + } + + static void unref_table_rawdata(struct libscols_table *tb) { struct libscols_iter *itr; struct libscols_line *ln; - if (!tb || !lsblk->sort_col) + if (!tb || !lsblk->rawdata) return; + itr = scols_new_iter(SCOLS_ITER_FORWARD); if (!itr) return; - while (scols_table_next_line(tb, itr, &ln) == 0) { - struct libscols_cell *ce = scols_line_get_column_cell(ln, - lsblk->sort_col); - void *data = scols_cell_get_userdata(ce); - free(data); - } + while (scols_table_next_line(tb, itr, &ln) == 0) + unref_line_rawdata(ln, tb); scols_free_iter(itr); } @@@ -739,21 -779,21 +779,21 @@@ static uint64_t device_get_discard_gran } static void device_read_bytes(struct lsblk_device *dev, char *path, char **str, - uint64_t *sortdata) + uint64_t *rawdata) { uint64_t x; if (lsblk->bytes) { ul_path_read_string(dev->sysfs, str, path); - if (sortdata) - str2u64(*str, sortdata); + if (rawdata) + str2u64(*str, rawdata); return; } if (ul_path_read_u64(dev->sysfs, &x, path) == 0) { *str = size_to_human_string(SIZE_SUFFIX_1LETTER, x); - if (sortdata) - *sortdata = x; + if (rawdata) + *rawdata = x; } } @@@ -775,7 -815,7 +815,7 @@@ static void process_mq(struct lsblk_dev } /* - * Generates data (string) for column specified by column ID for specified device. If sortdata + * Generates data (string) for column specified by column ID for specified device. If rawdata * is not NULL then returns number usable to sort the column if the data are available for the * column. */ @@@ -783,7 -823,7 +823,7 @@@ static char *device_get_data struct lsblk_device *dev, /* device */ struct lsblk_device *parent, /* device parent as defined in the tree */ int id, /* column ID (COL_*) */ - uint64_t *sortdata, /* returns sort data as number */ + uint64_t *rawdata, /* returns sort data as number */ size_t *datasiz) { struct lsblk_devprop *prop = NULL; @@@ -846,18 -886,18 +886,18 @@@ xasprintf(&str, "%u:%u", dev->maj, dev->min); else xasprintf(&str, "%3u:%-3u", dev->maj, dev->min); - if (sortdata) - *sortdata = makedev(dev->maj, dev->min); + if (rawdata) + *rawdata = makedev(dev->maj, dev->min); break; case COL_MAJ: xasprintf(&str, "%u", dev->maj); - if (sortdata) - *sortdata = dev->maj; + if (rawdata) + *rawdata = dev->maj; break; case COL_MIN: xasprintf(&str, "%u", dev->min); - if (sortdata) - *sortdata = dev->min; + if (rawdata) + *rawdata = dev->min; break; case COL_FSTYPE: prop = lsblk_device_get_properties(dev); @@@ -992,8 -1032,8 +1032,8 @@@ break; case COL_RA: ul_path_read_string(dev->sysfs, &str, "queue/read_ahead_kb"); - if (sortdata) - str2u64(str, sortdata); + if (rawdata) + str2u64(str, rawdata); break; case COL_RO: str = xstrdup(is_readonly_device(dev) ? "1" : "0"); @@@ -1046,13 -1086,13 +1086,13 @@@ xasprintf(&str, "%ju", dev->size); else str = size_to_human_string(SIZE_SUFFIX_1LETTER, dev->size); - if (sortdata) - *sortdata = dev->size; + if (rawdata) + *rawdata = dev->size; break; case COL_START: ul_path_read_string(dev->sysfs, &str, "start"); - if (sortdata) - str2u64(str, sortdata); + if (rawdata) + str2u64(str, rawdata); break; case COL_STATE: if (!device_is_partition(dev) && !dev->dm_name) @@@ -1065,36 -1105,36 +1105,36 @@@ break; case COL_ALIOFF: ul_path_read_string(dev->sysfs, &str, "alignment_offset"); - if (sortdata) - str2u64(str, sortdata); + if (rawdata) + str2u64(str, rawdata); break; case COL_MINIO: ul_path_read_string(dev->sysfs, &str, "queue/minimum_io_size"); - if (sortdata) - str2u64(str, sortdata); + if (rawdata) + str2u64(str, rawdata); break; case COL_OPTIO: ul_path_read_string(dev->sysfs, &str, "queue/optimal_io_size"); - if (sortdata) - str2u64(str, sortdata); + if (rawdata) + str2u64(str, rawdata); break; case COL_PHYSEC: ul_path_read_string(dev->sysfs, &str, "queue/physical_block_size"); - if (sortdata) - str2u64(str, sortdata); + if (rawdata) + str2u64(str, rawdata); break; case COL_LOGSEC: ul_path_read_string(dev->sysfs, &str, "queue/logical_block_size"); - if (sortdata) - str2u64(str, sortdata); + if (rawdata) + str2u64(str, rawdata); break; case COL_SCHED: str = get_scheduler(dev); break; case COL_RQ_SIZE: ul_path_read_string(dev->sysfs, &str, "queue/nr_requests"); - if (sortdata) - str2u64(str, sortdata); + if (rawdata) + str2u64(str, rawdata); break; case COL_TYPE: str = get_type(dev); @@@ -1121,23 -1161,23 +1161,23 @@@ ul_path_read_string(dev->sysfs, &str, "discard_alignment"); if (!str) str = xstrdup("0"); - if (sortdata) - str2u64(str, sortdata); + if (rawdata) + str2u64(str, rawdata); break; case COL_DGRAN: if (lsblk->bytes) { ul_path_read_string(dev->sysfs, &str, "queue/discard_granularity"); - if (sortdata) - str2u64(str, sortdata); + if (rawdata) + str2u64(str, rawdata); } else { uint64_t x = device_get_discard_granularity(dev); str = size_to_human_string(SIZE_SUFFIX_1LETTER, x); - if (sortdata) - *sortdata = x; + if (rawdata) + *rawdata = x; } break; case COL_DMAX: - device_read_bytes(dev, "queue/discard_max_bytes", &str, sortdata); + device_read_bytes(dev, "queue/discard_max_bytes", &str, rawdata); break; case COL_DZERO: if (device_get_discard_granularity(dev) > 0) @@@ -1146,7 -1186,7 +1186,7 @@@ str = xstrdup("0"); break; case COL_WSAME: - device_read_bytes(dev, "queue/write_same_max_bytes", &str, sortdata); + device_read_bytes(dev, "queue/write_same_max_bytes", &str, rawdata); if (!str) str = xstrdup("0"); break; @@@ -1163,35 -1203,35 +1203,35 @@@ xasprintf(&str, "%ju", x); else str = size_to_human_string(SIZE_SUFFIX_1LETTER, x); - if (sortdata) - *sortdata = x; + if (rawdata) + *rawdata = x; } break; } case COL_ZONE_WGRAN: - device_read_bytes(dev, "queue/zone_write_granularity", &str, sortdata); + device_read_bytes(dev, "queue/zone_write_granularity", &str, rawdata); break; case COL_ZONE_APP: - device_read_bytes(dev, "queue/zone_append_max_bytes", &str, sortdata); + device_read_bytes(dev, "queue/zone_append_max_bytes", &str, rawdata); break; case COL_ZONE_NR: ul_path_read_string(dev->sysfs, &str, "queue/nr_zones"); - if (sortdata) - str2u64(str, sortdata); + if (rawdata) + str2u64(str, rawdata); break; case COL_ZONE_OMAX: ul_path_read_string(dev->sysfs, &str, "queue/max_open_zones"); if (!str) str = xstrdup("0"); - if (sortdata) - str2u64(str, sortdata); + if (rawdata) + str2u64(str, rawdata); break; case COL_ZONE_AMAX: ul_path_read_string(dev->sysfs, &str, "queue/max_active_zones"); if (!str) str = xstrdup("0"); - if (sortdata) - str2u64(str, sortdata); + if (rawdata) + str2u64(str, rawdata); break; case COL_DAX: ul_path_read_string(dev->sysfs, &str, "queue/dax"); @@@ -1201,14 -1241,58 +1241,58 @@@ break; case COL_DISKSEQ: ul_path_read_string(dev->sysfs, &str, "diskseq"); - if (sortdata) - str2u64(str, sortdata); + if (rawdata) + str2u64(str, rawdata); break; }; return str; } + static void device_fill_scols_cell(struct lsblk_device *dev, + struct lsblk_device *parent, + struct libscols_line *ln, + size_t colnum) + { + struct libscols_cell *ce; + struct libscols_column *cl = scols_table_get_column(lsblk->table, colnum); + char *data; + size_t datasiz = 0; + int rc, id = get_column_id(colnum); + + if (lsblk->sort_id == id || scols_column_has_data_func(cl)) { + uint64_t rawdata = (uint64_t) -1; + + data = device_get_data(dev, parent, id, &rawdata, &datasiz); + if (data && rawdata != (uint64_t) -1) + set_rawdata_u64(ln, colnum, rawdata); + } else + data = device_get_data(dev, parent, id, NULL, &datasiz); + + if (!data) + return; + DBG(DEV, ul_debugobj(dev, " refer data[%zu]=\"%s\"", colnum, data)); + ce = scols_line_get_cell(ln, colnum); + if (!ce) + return; + rc = datasiz ? scols_cell_refer_memory(ce, data, datasiz + 1) + : scols_cell_refer_data(ce, data); + if (rc) + err(EXIT_FAILURE, _("failed to add output data")); + } + + static int filter_filler_cb( + struct libscols_filter *fltr __attribute__((__unused__)), + struct libscols_line *ln, + size_t colnum, + void *userdata) + { + struct filler_data *fid = (struct filler_data *) userdata; + + device_fill_scols_cell(fid->dev, fid->parent, ln, colnum); + return 0; + } + /* * Adds data for all wanted columns about the device to the smartcols table */ @@@ -1222,7 -1306,7 +1306,7 @@@ static void device_to_scols struct libscols_line *ln; struct lsblk_iter itr; struct lsblk_device *child = NULL; - int link_group = 0; + int link_group = 0, nocount = 0; DBG(DEV, ul_debugobj(dev, "add '%s' to scols", dev->name)); @@@ -1247,7 -1331,38 +1331,38 @@@ dev->is_printed = 1; - if (link_group) { + /* filter lines, smartcols filter can ask for data */ + if (lsblk->filter) { + int status = 0; + struct filler_data fid = { + .dev = dev, + .parent = parent + }; + + scols_filter_set_filler_cb(lsblk->filter, + filter_filler_cb, (void *) &fid); + + if (scols_line_apply_filter(ln, lsblk->filter, &status)) + err(EXIT_FAILURE, _("failed to apply filter")); + if (status == 0) { + struct libscols_line *x = scols_line_get_parent(ln); + + if (x) + scols_line_remove_child(x, ln); + unref_line_rawdata(ln, tab); + scols_table_remove_line(tab, ln); + ln = NULL; + } + } + + /* read column specific data and set it to smartcols table line */ + for (i = 0; ln && i < ncolumns; i++) { + if (scols_line_is_filled(ln, i)) + continue; + device_fill_scols_cell(dev, parent, ln, i); + } + + if (ln && link_group) { struct lsblk_device *p; struct libscols_line *gr = parent_line; @@@ -1268,34 -1383,9 +1383,9 @@@ scols_line_link_group(ln, gr, 0); } - /* read column specific data and set it to smartcols table line */ - for (i = 0; i < ncolumns; i++) { - struct libscols_cell *ce; - char *data = NULL; - size_t datasiz = 0; - int rc, id = get_column_id(i); - - if (lsblk->sort_id != id) - data = device_get_data(dev, parent, id, NULL, &datasiz); - else { - uint64_t sortdata = (uint64_t) -1; - - data = device_get_data(dev, parent, id, &sortdata, &datasiz); - if (data && sortdata != (uint64_t) -1) - set_sortdata_u64(ln, i, sortdata); - } - - if (!data) - continue; - DBG(DEV, ul_debugobj(dev, " refer data[%zu]=\"%s\"", i, data)); - ce = scols_line_get_cell(ln, i); - if (!ce) - continue; - rc = datasiz ? scols_cell_refer_memory(ce, data, datasiz + 1) - : scols_cell_refer_data(ce, data); - if (rc) - err(EXIT_FAILURE, _("failed to add output data")); - } + /* The same device could be printed more than once, don't use it in counter */ + if (dev->scols_line) + nocount = 1; dev->scols_line = ln; @@@ -1311,6 -1401,21 +1401,21 @@@ DBG(DEV, ul_debugobj(dev, "%s <- child done", dev->name)); } + /* apply highligther */ + if (ln && lsblk->hlighter) { + int status = 0; + + if (scols_line_apply_filter(ln, lsblk->hlighter, &status) == 0 + && status) + scols_line_set_color(ln, lsblk->hlighter_seq); + } + + /* apply counters */ + if (!nocount) { + 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); } @@@ -1942,7 -2047,7 +2047,7 @@@ static void parse_includes(const char * } /* - * see set_sortdata_u64() and columns initialization in main() + * see set_rawdata_u64() and columns initialization in main() */ static int cmp_u64_cells(struct libscols_cell *a, struct libscols_cell *b, @@@ -1960,6 -2065,13 +2065,13 @@@ return *adata == *bdata ? 0 : *adata >= *bdata ? 1 : -1; } + static void *get_u64_cell(const struct libscols_column *cl __attribute__((__unused__)), + struct libscols_cell *ce, + void *data __attribute__((__unused__))) + { + return scols_cell_get_userdata(ce); + } + static void device_set_dedupkey( struct lsblk_device *dev, struct lsblk_device *parent, @@@ -1997,6 -2109,190 +2109,190 @@@ static void devtree_set_dedupkeys(struc device_set_dedupkey(dev, NULL, id); } + static struct libscols_filter *new_filter(const char *query) + { + struct libscols_filter *f; + + f = scols_new_filter(NULL); + if (!f) + err(EXIT_FAILURE, _("failed to allocate filter")); + 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 set_column_type(const struct colinfo *ci, struct libscols_column *cl, int fl) + { + switch (ci->type) { + case COLTYPE_SIZE: + /* See init_scols_filter(), it may overwrite the type */ + if (!lsblk->bytes) + break; + /* fallthrough */ + case COLTYPE_NUM: + scols_column_set_json_type(cl, SCOLS_JSON_NUMBER); + scols_column_set_data_type(cl, SCOLS_DATA_U64); + return; + case COLTYPE_BOOL: + scols_column_set_json_type(cl, SCOLS_JSON_BOOLEAN); + scols_column_set_data_type(cl, SCOLS_DATA_BOOLEAN); + return; + default: + break; + } + + /* default */ + if (fl & SCOLS_FL_WRAP) + scols_column_set_json_type(cl, SCOLS_JSON_ARRAY_STRING); + else + scols_column_set_json_type(cl, SCOLS_JSON_STRING); + + scols_column_set_data_type(cl, SCOLS_DATA_STRING); + } + + static void init_scols_filter(struct libscols_table *tb, struct libscols_filter *f) + { + struct libscols_iter *itr; + const char *name = NULL; + int nerrs = 0; + + itr = scols_new_iter(SCOLS_ITER_FORWARD); + if (!itr) + err(EXIT_FAILURE, _("failed to allocate iterator")); + + while (scols_filter_next_holder(f, itr, &name, 0) == 0) { + struct libscols_column *col = scols_table_get_column_by_name(tb, name); + int id = column_name_to_id(name, strlen(name)); + const struct colinfo *ci = id >= 0 ? &infos[id] : NULL; + + if (!ci) { + nerrs++; + continue; /* report all unknown columns */ + } + if (!col) { + add_column(id); + col = scols_table_new_column(lsblk->table, ci->name, + ci->whint, SCOLS_FL_HIDDEN); + if (!col) + err(EXIT_FAILURE,_("failed to allocate output column")); + + set_column_type(ci, col, ci->flags); + } + + /* For sizes use rawdata (u64) rather than strings from table */ + if (ci->type == COLTYPE_SIZE + && !lsblk->bytes + && !scols_column_has_data_func(col)) { + + scols_column_set_data_type(col, SCOLS_DATA_U64); + scols_column_set_data_func(col, get_u64_cell, NULL); + lsblk->rawdata = 1; + } + + scols_filter_assign_column(f, itr, name, col); + } + + scols_free_iter(itr); + + if (!nerrs) + return; + + errx(EXIT_FAILURE, _("failed to initialize filter")); + } + + static void __attribute__((__noreturn__)) usage(void) { FILE *out = stdout; @@@ -2017,6 -2313,10 +2313,10 @@@ fputs(_(" -M, --merge group parents of sub-trees (usable for RAIDs, Multi-path)\n"), out); fputs(_(" -O, --output-all output all columns\n"), out); 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); @@@ -2076,7 -2376,9 +2376,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[] = { @@@ -2091,6 -2393,8 +2393,8 @@@ { "json", no_argument, NULL, 'J' }, { "output", required_argument, NULL, 'o' }, { "output-all", no_argument, NULL, 'O' }, + { "filter", required_argument, NULL, 'Q' }, + { "highlight", required_argument, NULL, 'H' }, { "merge", no_argument, NULL, 'M' }, { "perms", no_argument, NULL, 'm' }, { "noheadings", no_argument, NULL, 'n' }, @@@ -2113,6 -2417,8 +2417,8 @@@ { "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 }, }; @@@ -2138,9 -2444,10 +2444,10 @@@ lsblk = &_ls; lsblk_init_debug(); + scols_init_debug(0); while((c = getopt_long(argc, argv, - "AabdDzE:e:fhJlNnMmo:OpPiI:rstVvST::w:x:y", + "AabdDzE:e:fH:hJlNnMmo:OpPQ:iI:rstVvST::w:x:y", longopts, NULL)) != -1) { err_exclusive_options(c, longopts, excl, excl_st); @@@ -2178,6 -2485,9 +2485,9 @@@ case 'e': parse_excludes(optarg); break; + case 'H': + lsblk->hlighter = new_filter(optarg); + break; case 'J': lsblk->flags |= LSBLK_JSON; break; @@@ -2204,6 -2514,10 +2514,10 @@@ lsblk->flags |= LSBLK_EXPORT; lsblk->flags &= ~LSBLK_TREE; /* disable the default */ break; + case 'Q': + lsblk->filter = new_filter(optarg); + lsblk->flags &= ~LSBLK_TREE; /* disable the default */ + break; case 'y': lsblk->flags |= LSBLK_SHELLVAR; break; @@@ -2312,6 -2626,13 +2626,13 @@@ 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': @@@ -2366,7 -2687,6 +2687,6 @@@ } lsblk_mnt_init(); - scols_init_debug(0); ul_path_init_debug(); /* @@@ -2422,6 -2742,7 +2742,7 @@@ } if (!lsblk->sort_col && lsblk->sort_id == id) { lsblk->sort_col = cl; + lsblk->rawdata = 1; scols_column_set_cmpfunc(cl, ci->type == COLTYPE_NUM ? cmp_u64_cells : ci->type == COLTYPE_SIZE ? cmp_u64_cells : @@@ -2432,28 -2753,20 +2753,20 @@@ if (fl & SCOLS_FL_WRAP) scols_column_set_wrapfunc(cl, NULL, scols_wrapzero_nextchunk, NULL); - if (lsblk->flags & LSBLK_JSON) { - switch (ci->type) { - case COLTYPE_SIZE: - if (!lsblk->bytes) - break; - /* fallthrough */ - case COLTYPE_NUM: - scols_column_set_json_type(cl, SCOLS_JSON_NUMBER); - break; - case COLTYPE_BOOL: - scols_column_set_json_type(cl, SCOLS_JSON_BOOLEAN); - break; - default: - if (fl & SCOLS_FL_WRAP) - scols_column_set_json_type(cl, SCOLS_JSON_ARRAY_STRING); - else - scols_column_set_json_type(cl, SCOLS_JSON_STRING); - break; - } - } + set_column_type(ci, cl, fl); } + if (lsblk->filter) + init_scols_filter(lsblk->table, lsblk->filter); + + if (lsblk->hlighter && colors_init(UL_COLORMODE_AUTO, "lsblk") > 0) { + lsblk->hlighter_seq = color_scheme_get_sequence("highlight-line", UL_COLOR_RED); + 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) err(EXIT_FAILURE, _("failed to allocate device tree")); @@@ -2492,11 -2805,19 +2805,19 @@@ scols_print_table(lsblk->table); + if (lsblk->ncts) + print_counters(); leave: - if (lsblk->sort_col) - unref_sortdata(lsblk->table); + if (lsblk->rawdata) + unref_table_rawdata(lsblk->table); scols_unref_table(lsblk->table); + 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(); diff --combined misc-utils/lsfd.c index c9bbd48cbc,bac2bac3ca..4671a2149c --- a/misc-utils/lsfd.c +++ b/misc-utils/lsfd.c @@@ -58,8 -58,6 +58,6 @@@ static int kcmp(pid_t pid1, pid_t pid2 #include "pathnames.h" #include "lsfd.h" - #include "lsfd-filter.h" - #include "lsfd-counter.h" /* * /proc/$pid/mountinfo entries @@@ -333,10 -331,10 +331,10 @@@ static const struct colinfo infos[] = 0, SCOLS_FL_RIGHT, SCOLS_JSON_STRING, N_("clockid") }, [COL_TIMERFD_INTERVAL] = { "TIMERFD.INTERVAL", - 0, SCOLS_FL_RIGHT, SCOLS_JSON_NUMBER, + 0, SCOLS_FL_RIGHT, SCOLS_JSON_FLOAT, N_("interval") }, [COL_TIMERFD_REMAINING]= { "TIMERFD.REMAINING", - 0, SCOLS_FL_RIGHT, SCOLS_JSON_NUMBER, + 0, SCOLS_FL_RIGHT, SCOLS_JSON_FLOAT, N_("remaining time") }, [COL_TUN_IFACE] = { "TUN.IFACE", 0, SCOLS_FL_RIGHT, SCOLS_JSON_STRING, @@@ -488,6 -486,12 +486,12 @@@ static const struct counter_spec defaul } }; + /* "userdata" used by callback for libsmartcols filter */ + struct filler_data { + struct proc *proc; + struct file *file; + }; + struct lsfd_control { struct libscols_table *tb; /* output */ struct list_head procs; /* list of all processes */ @@@ -502,8 -506,8 +506,8 @@@ sockets_only : 1, /* display only SOCKETS */ show_xmode : 1; /* XMODE column is enabled. */ - struct lsfd_filter *filter; - struct lsfd_counter **counters; /* NULL terminated array. */ + struct libscols_filter *filter; /* filter */ + struct libscols_filter **ct_filters; /* counters (NULL terminated array) */ }; static void *proc_tree; /* for tsearch/tfind */ @@@ -515,8 -519,7 +519,8 @@@ static int proc_tree_compare(const voi struct proc *get_proc(pid_t pid) { - struct proc **node = tfind(&pid, &proc_tree, proc_tree_compare); + struct proc key = { .pid = pid }; + struct proc **node = tfind(&key, &proc_tree, proc_tree_compare); if (node) return *node; return NULL; @@@ -533,13 -536,7 +537,7 @@@ static int column_name_to_id(const cha return i; } warnx(_("unknown column: %s"), name); - - return LSFD_FILTER_UNKNOWN_COL_ID; - } - - static int column_name_to_id_cb(const char *name, void *data __attribute__((__unused__))) - { - return column_name_to_id(name, strlen(name)); + return -1; } static int get_column_id(int num) @@@ -556,12 -553,13 +554,13 @@@ static const struct colinfo *get_column return &infos[ get_column_id(num) ]; } - static struct libscols_column *add_column(struct libscols_table *tb, const struct colinfo *col) + static struct libscols_column *add_column(struct libscols_table *tb, + const struct colinfo *col, int extra) { struct libscols_column *cl; int flags = col->flags; - cl = scols_table_new_column(tb, col->name, col->whint, flags); + cl = scols_table_new_column(tb, col->name, col->whint, flags | extra); if (cl) { scols_column_set_json_type(cl, col->json_type); if (col->flags & SCOLS_FL_WRAP) { @@@ -576,7 -574,8 +575,8 @@@ return cl; } - static struct libscols_column *add_column_by_id_cb(struct libscols_table *tb, int colid, void *data) + static struct libscols_column *add_column_by_id(struct lsfd_control *ctl, + int colid, int extra) { struct libscols_column *cl; @@@ -585,15 -584,13 +585,13 @@@ assert(colid < LSFD_N_COLS); - cl = add_column(tb, infos + colid); + cl = add_column(ctl->tb, infos + colid, extra); if (!cl) err(EXIT_FAILURE, _("failed to allocate output column")); columns[ncolumns++] = colid; - if (colid == COL_TID) { - struct lsfd_control *ctl = data; + if (colid == COL_TID) ctl->threads = 1; - } return cl; } @@@ -1166,6 -1163,7 +1164,7 @@@ void add_endpoint(struct ipc_endpoint * list_add(&endpoint->endpoints, &ipc->endpoints); } + static void fill_column(struct proc *proc, struct file *file, struct libscols_line *ln, @@@ -1183,6 -1181,18 +1182,18 @@@ } } + static int filter_filler_cb( + struct libscols_filter *fltr __attribute__((__unused__)), + struct libscols_line *ln, + size_t colnum, + void *userdata) + { + struct filler_data *fid = (struct filler_data *) userdata; + + fill_column(fid->proc, fid->file, ln, get_column_id(colnum), colnum); + return 0; + } + static void convert_file(struct proc *proc, struct file *file, struct libscols_line *ln) @@@ -1190,8 -1200,11 +1201,11 @@@ { size_t i; - for (i = 0; i < ncolumns; i++) + for (i = 0; i < ncolumns; i++) { + if (scols_line_is_filled(ln, i)) + continue; fill_column(proc, file, ln, get_column_id(i), i); + } } static void convert(struct list_head *procs, struct lsfd_control *ctl) @@@ -1205,23 -1218,34 +1219,34 @@@ list_for_each (f, &proc->files) { struct file *file = list_entry(f, struct file, files); struct libscols_line *ln = scols_table_new_line(ctl->tb, NULL); - struct lsfd_counter **counter = NULL; + struct libscols_filter **ct_fltr = NULL; if (!ln) err(EXIT_FAILURE, _("failed to allocate output line")); + if (ctl->filter) { + int status = 0; + struct filler_data fid = { + .proc = proc, + .file = file + }; + + scols_filter_set_filler_cb(ctl->filter, + filter_filler_cb, (void *) &fid); + if (scols_line_apply_filter(ln, ctl->filter, &status)) + err(EXIT_FAILURE, _("failed to apply filter")); + if (status == 0) { + scols_table_remove_line(ctl->tb, ln); + continue; + } + } convert_file(proc, file, ln); - if (!lsfd_filter_apply(ctl->filter, ln)) { - scols_table_remove_line(ctl->tb, ln); - continue; - } - - if (!ctl->counters) + if (!ctl->ct_filters) continue; - for (counter = ctl->counters; *counter; counter++) - lsfd_counter_accumulate(*counter, ln); + for (ct_fltr = ctl->ct_filters; *ct_fltr; ct_fltr++) + scols_line_apply_filter(ln, *ct_fltr, NULL); } } } @@@ -1237,12 -1261,13 +1262,13 @@@ static void delete(struct list_head *pr list_free(procs, struct proc, procs, free_proc); scols_unref_table(ctl->tb); - lsfd_filter_free(ctl->filter); - if (ctl->counters) { - struct lsfd_counter **counter; - for (counter = ctl->counters; *counter; counter++) - lsfd_counter_free(*counter); - free(ctl->counters); + scols_unref_filter(ctl->filter); + + if (ctl->ct_filters) { + struct libscols_filter **ct_fltr; + for (ct_fltr = ctl->ct_filters; *ct_fltr; ct_fltr++) + scols_unref_filter(*ct_fltr); + free(ctl->ct_filters); } } @@@ -1771,10 -1796,11 +1797,11 @@@ static void __attribute__((__noreturn__ fputs(USAGE_COLUMNS, out); for (size_t i = 0; i < ARRAY_SIZE(infos); i++) fprintf(out, " %20s %-10s%s\n", infos[i].name, - infos[i].json_type == SCOLS_JSON_STRING? "": - infos[i].json_type == SCOLS_JSON_ARRAY_STRING? "": - infos[i].json_type == SCOLS_JSON_ARRAY_NUMBER? "": - infos[i].json_type == SCOLS_JSON_NUMBER? "": + infos[i].json_type == SCOLS_JSON_STRING ? "": + infos[i].json_type == SCOLS_JSON_ARRAY_STRING ? "": + infos[i].json_type == SCOLS_JSON_ARRAY_NUMBER ? "": + infos[i].json_type == SCOLS_JSON_NUMBER ? "": + infos[i].json_type == SCOLS_JSON_FLOAT ? "": "", _(infos[i].help)); exit(EXIT_SUCCESS); @@@ -1845,26 -1871,53 +1872,53 @@@ static void append_filter_expr(char **a xstrappend(a, "or("); xstrappend(a, b); xstrappend(a, ")"); + + free(tmp); } - static struct lsfd_filter *new_filter(const char *expr, bool debug, const char *err_prefix, struct lsfd_control *ctl) + static struct libscols_filter *new_filter(const char *expr, bool debug, struct lsfd_control *ctl) { - struct lsfd_filter *filter; - const char *errmsg; + struct libscols_filter *f; + struct libscols_iter *itr; + int nerrs = 0; + const char *name = NULL; - filter = lsfd_filter_new(expr, ctl->tb, - LSFD_N_COLS, - column_name_to_id_cb, - add_column_by_id_cb, ctl); - errmsg = lsfd_filter_get_errmsg(filter); - if (errmsg) - errx(EXIT_FAILURE, "%s%s", err_prefix, errmsg); - if (debug) { - lsfd_filter_dump(filter, stdout); - exit(EXIT_SUCCESS); + f = scols_new_filter(NULL); + if (!f) + err(EXIT_FAILURE, _("failed to allocate filter")); + if (expr && scols_filter_parse_string(f, expr) != 0) + errx(EXIT_FAILURE, _("failed to parse \"%s\": %s"), expr, + scols_filter_get_errmsg(f)); + + itr = scols_new_iter(SCOLS_ITER_FORWARD); + if (!itr) + err(EXIT_FAILURE, _("failed to allocate iterator")); + + while (scols_filter_next_holder(f, itr, &name, 0) == 0) { + struct libscols_column *col = scols_table_get_column_by_name(ctl->tb, name); + + if (!col) { + int id = column_name_to_id(name, strlen(name)); + if (id >= 0) + col = add_column_by_id(ctl, id, SCOLS_FL_HIDDEN); + if (!col) { + nerrs++; /* report all unknown columns */ + continue; + } + } + scols_filter_assign_column(f, itr, name, col); } - return filter; + scols_free_iter(itr); + + if (debug) + scols_dump_filter(f, stdout); + if (nerrs) + exit(EXIT_FAILURE); + if (debug) + exit(EXIT_SUCCESS); + + return f; } static struct counter_spec *new_counter_spec(const char *spec_str) @@@ -1912,47 -1965,54 +1966,54 @@@ static void free_counter_spec(struct co free(counter_spec); } - static struct lsfd_counter *new_counter(const struct counter_spec *spec, struct lsfd_control *ctl) + static struct libscols_filter *new_counter(const struct counter_spec *spec, struct lsfd_control *ctl) { - struct lsfd_filter *filter; + struct libscols_filter *f; + struct libscols_counter *ct; - filter = new_filter(spec->expr, false, - _("failed in making filter for a counter: "), - ctl); - return lsfd_counter_new(spec->name, filter); + f = new_filter(spec->expr, false, ctl); + + ct = scols_filter_new_counter(f); + if (!ct) + err(EXIT_FAILURE, _("failed to allocate counter")); + + scols_counter_set_name(ct, spec->name); + scols_counter_set_func(ct, SCOLS_COUNTER_COUNT); + + return f; } - static struct lsfd_counter **new_counters(struct list_head *specs, struct lsfd_control *ctl) + static struct libscols_filter **new_counters(struct list_head *specs, struct lsfd_control *ctl) { - struct lsfd_counter **counters; + struct libscols_filter **ct_filters; size_t len = list_count_entries(specs); size_t i = 0; struct list_head *s; - counters = xcalloc(len + 1, sizeof(struct lsfd_counter *)); + ct_filters = xcalloc(len + 1, sizeof(struct libscols_filter *)); list_for_each(s, specs) { struct counter_spec *spec = list_entry(s, struct counter_spec, specs); - counters[i++] = new_counter(spec, ctl); + ct_filters[i++] = new_counter(spec, ctl); } - assert(counters[len] == NULL); + assert(ct_filters[len] == NULL); - return counters; + return ct_filters; } - static struct lsfd_counter **new_default_counters(struct lsfd_control *ctl) + static struct libscols_filter **new_default_counters(struct lsfd_control *ctl) { - struct lsfd_counter **counters; + struct libscols_filter **ct_filters; size_t len = ARRAY_SIZE(default_counter_specs); size_t i; - counters = xcalloc(len + 1, sizeof(struct lsfd_counter *)); + ct_filters = xcalloc(len + 1, sizeof(struct libscols_filter *)); for (i = 0; i < len; i++) { const struct counter_spec *spec = default_counter_specs + i; - counters[i] = new_counter(spec, ctl); + ct_filters[i] = new_counter(spec, ctl); } - assert(counters[len] == NULL); + assert(ct_filters[len] == NULL); - return counters; + return ct_filters; } static void dump_default_counter_specs(void) @@@ -2010,28 -2070,35 +2071,35 @@@ static struct libscols_table *new_summa return tb; } - static void fill_summary_line(struct libscols_line *ln, struct lsfd_counter *counter) + static void emit_summary(struct lsfd_control *ctl) { - char *str = NULL; + struct libscols_iter *itr; + struct libscols_filter **ct_fltr; + struct libscols_table *tb = new_summary_table(ctl); - xasprintf(&str, "%llu", (unsigned long long)lsfd_counter_value(counter)); - if (!str) - err(EXIT_FAILURE, _("failed to add summary data")); - if (scols_line_refer_data(ln, 0, str)) - err(EXIT_FAILURE, _("failed to add summary data")); + itr = scols_new_iter(SCOLS_ITER_FORWARD); - if (scols_line_set_data(ln, 1, lsfd_counter_name(counter))) - err(EXIT_FAILURE, _("failed to add summary data")); - } + for (ct_fltr = ctl->ct_filters; *ct_fltr; ct_fltr++) { + struct libscols_counter *ct = NULL; - static void emit_summary(struct lsfd_control *ctl, struct lsfd_counter **counter) - { - struct libscols_table *tb = new_summary_table(ctl); + scols_reset_iter(itr, SCOLS_ITER_FORWARD); + while (scols_filter_next_counter(*ct_fltr, itr, &ct) == 0) { + char *str = NULL; + struct libscols_line *ln; + + ln = scols_table_new_line(tb, NULL); + if (!ln) + err(EXIT_FAILURE, _("failed to allocate summary line")); - for (; *counter; counter++) { - struct libscols_line *ln = scols_table_new_line(tb, NULL); - fill_summary_line(ln, *counter); + xasprintf(&str, "%llu", scols_counter_get_result(ct)); + if (scols_line_refer_data(ln, 0, str)) + err(EXIT_FAILURE, _("failed to add summary data")); + if (scols_line_set_data(ln, 1, scols_counter_get_name(ct))) + err(EXIT_FAILURE, _("failed to add summary data")); + } } + + scols_free_iter(itr); scols_print_table(tb); scols_unref_table(tb); @@@ -2254,7 -2321,7 +2322,7 @@@ int main(int argc, char *argv[] /* create output columns */ for (i = 0; i < ncolumns; i++) { const struct colinfo *col = get_column_info(i); - struct libscols_column *cl = add_column(ctl.tb, col); + struct libscols_column *cl = add_column(ctl.tb, col, 0); if (!cl) err(EXIT_FAILURE, _("failed to allocate output column")); @@@ -2266,9 -2333,9 +2334,9 @@@ } } - /* make fitler */ + /* make filter */ if (filter_expr) { - ctl.filter = new_filter(filter_expr, debug_filter, "", &ctl); + ctl.filter = new_filter(filter_expr, debug_filter, &ctl); free(filter_expr); } @@@ -2283,9 -2350,9 +2351,9 @@@ /* make counters */ if (ctl.show_summary) { if (list_empty(&counter_specs)) - ctl.counters = new_default_counters(&ctl); + ctl.ct_filters = new_default_counters(&ctl); else { - ctl.counters = new_counters(&counter_specs, &ctl); + ctl.ct_filters = new_counters(&counter_specs, &ctl); list_free(&counter_specs, struct counter_spec, specs, free_counter_spec); } @@@ -2321,8 -2388,8 +2389,8 @@@ if (ctl.show_main) emit(&ctl); - if (ctl.show_summary && ctl.counters) - emit_summary(&ctl, ctl.counters); + if (ctl.show_summary && ctl.ct_filters) + emit_summary(&ctl); /* cleanup */ delete(&ctl.procs, &ctl);