From: Karel Zak Date: Mon, 2 Oct 2023 17:52:40 +0000 (+0200) Subject: lsfd: use filter and counters from libsmartcols X-Git-Tag: v2.40-rc1~151^2~43 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=46eca86e0aaeeac724e9d298998bf71c082817ae;p=thirdparty%2Futil-linux.git lsfd: use filter and counters from libsmartcols Signed-off-by: Karel Zak --- diff --git a/misc-utils/Makemodule.am b/misc-utils/Makemodule.am index f55faf3d06..9e23c24e90 100644 --- a/misc-utils/Makemodule.am +++ b/misc-utils/Makemodule.am @@ -255,10 +255,6 @@ dist_noinst_DATA += misc-utils/lsfd.1.adoc lsfd_SOURCES = \ misc-utils/lsfd.c \ misc-utils/lsfd.h \ - misc-utils/lsfd-filter.h \ - misc-utils/lsfd-filter.c \ - misc-utils/lsfd-counter.h \ - misc-utils/lsfd-counter.c \ misc-utils/lsfd-decode-file-flags.c \ misc-utils/lsfd-file.c \ misc-utils/lsfd-cdev.c \ diff --git a/misc-utils/lsfd-counter.c b/misc-utils/lsfd-counter.c deleted file mode 100644 index 55f0fde470..0000000000 --- a/misc-utils/lsfd-counter.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * lsfd-counter.c - counter implementation used in --summary option - * - * Copyright (C) 2021 Red Hat, Inc. - * Copyright (C) 2021 Masatake YAMATO - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ - -#include "lsfd-counter.h" - -#include "xalloc.h" - -struct lsfd_counter { - char *name; - size_t value; - struct lsfd_filter *filter; -}; - -struct lsfd_counter *lsfd_counter_new(const char *const name, struct lsfd_filter *filter) -{ - struct lsfd_counter *counter = xmalloc(sizeof(struct lsfd_counter)); - - counter->name = xstrdup(name); - counter->value = 0; - counter->filter = filter; - - return counter; -} - -void lsfd_counter_free(struct lsfd_counter *counter) -{ - lsfd_filter_free(counter->filter); - free(counter->name); - free(counter); -} - -bool lsfd_counter_accumulate(struct lsfd_counter *counter, struct libscols_line *ln) -{ - if (lsfd_filter_apply(counter->filter, ln)) { - counter->value++; - return true; - } - return false; -} - -const char *lsfd_counter_name(struct lsfd_counter *counter) -{ - return counter->name; -} - -size_t lsfd_counter_value(struct lsfd_counter *counter) -{ - return counter->value; -} diff --git a/misc-utils/lsfd-counter.h b/misc-utils/lsfd-counter.h deleted file mode 100644 index bac11a913a..0000000000 --- a/misc-utils/lsfd-counter.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * lsfd-counter.h - counter implementation used in --summary option - * - * Copyright (C) 2021 Red Hat, Inc. - * Copyright (C) 2021 Masatake YAMATO - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#ifndef UTIL_LINUX_LSFD_COUNTER_H -#define UTIL_LINUX_LSFD_COUNTER_H - -#include "libsmartcols.h" -#include "lsfd-filter.h" -#include - -struct lsfd_counter; - -/* The created counter takes the ownership of the filter; the filter is - * freed in lsfd_counter_free(). - */ -struct lsfd_counter *lsfd_counter_new(const char *const name, struct lsfd_filter *filter); -void lsfd_counter_free(struct lsfd_counter *counter); - -bool lsfd_counter_accumulate(struct lsfd_counter *counter, struct libscols_line *ln); - -const char *lsfd_counter_name(struct lsfd_counter *counter); -size_t lsfd_counter_value(struct lsfd_counter *counter); - -#endif /* UTIL_LINUX_LSFD_COUNTER_H */ diff --git a/misc-utils/lsfd-filter.c b/misc-utils/lsfd-filter.c deleted file mode 100644 index 6f5561bc78..0000000000 --- a/misc-utils/lsfd-filter.c +++ /dev/null @@ -1,1499 +0,0 @@ -/* - * lsfd-filter.c - filtering engine for lsfd - * - * Copyright (C) 2021 Red Hat, Inc. - * Copyright (C) 2021 Masatake YAMATO - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ - -#include "lsfd-filter.h" - -#include "nls.h" -#include "strutils.h" -#include "xalloc.h" - -#include -#include -#include /* regcomp(), regexec() */ - -/* - * Definitions - */ -#define COL_HEADER_EXTRA_CHARS ":-_%." /* ??? */ -#define GOT_ERROR(PARSERorFILTER)(*((PARSERorFILTER)->errmsg)) - -/* - * Types - */ - -enum token_type { - TOKEN_NAME, /* [A-Za-z_][-_:%.A-Za-z0-9]* */ - TOKEN_STR, /* "...", '...' */ - TOKEN_DEC, /* [1-9][0-9]+, NOTE: negative value has not handled. */ - TOKEN_FDEC, /* [1-9][0-9]+\.[0-9]+ */ - TOKEN_HEX, /* 0x[0-9a-f]+ not implemented */ - TOKEN_OCT, /* 0[1-7]+ not implemented */ - TOKEN_TRUE, /* true */ - TOKEN_FALSE, /* false */ - TOKEN_OPEN, /* ( */ - TOKEN_CLOSE, /* ) */ - TOKEN_OP1, /* !, not */ - TOKEN_OP2, /* TODO: =*, !* (glob match with fnmatch() */ - TOKEN_EOF, -}; - -enum op1_type { - OP1_NOT, -}; - -enum op2_type { - OP2_EQ, - OP2_NE, - OP2_AND, - OP2_OR, - OP2_LT, - OP2_LE, - OP2_GT, - OP2_GE, - OP2_RE_MATCH, - OP2_RE_UNMATCH, -}; - -struct token { - enum token_type type; - union { - char *str; - unsigned long long num; - long double fnum; - enum op1_type op1; - enum op2_type op2; - } val; -}; - -struct token_class { - const char * const name; - void (*free)(struct token *); - void (*dump)(struct token *, FILE *); -}; - -struct parameter { - struct libscols_column *cl; - bool has_value; - bool floating_point_num; - union { - const char *str; - unsigned long long num; - long double fnum; - bool boolean; - } val; -}; - -struct parser { - const char *expr; - const char *cursor; - int paren_level; - struct libscols_table *tb; - int (*column_name_to_id)(const char *, void *); - struct libscols_column *(*add_column_by_id)(struct libscols_table *, int, void*); - void *data; - struct parameter *parameters; - char errmsg[128]; -}; - -enum node_type { - NODE_STR, - NODE_NUM, - NODE_FNUM, - NODE_BOOL, - NODE_RE, - NODE_OP1, - NODE_OP2, -}; - -struct node { - enum node_type type; -}; - -struct op1_class { - const char * const name; - /* Return true if acceptable. */ - bool (*is_acceptable)(struct node *, struct parameter *, struct libscols_line *); - /* Return true if o.k. */ - bool (*check_type)(struct parser *, const struct op1_class *, struct node *); -}; - -struct op2_class { - const char * const name; - /* Return true if acceptable. */ - bool (*is_acceptable)(struct node *, struct node *, struct parameter *, struct libscols_line *); - /* Return true if o.k. */ - bool (*check_type)(struct parser *, const struct op2_class *, struct node *, struct node *); -}; - -#define VAL(NODE,FIELD) (((struct node_val *)(NODE))->val.FIELD) -#define PINDEX(NODE) (((struct node_val *)(NODE))->pindex) -struct node_val { - struct node base; - int pindex; - union { - char *str; - unsigned long long num; - long double fnum; - bool boolean; - regex_t re; - } val; -}; - -struct node_op1 { - struct node base; - const struct op1_class *opclass; - struct node *arg; -}; - -struct node_op2 { - struct node base; - const struct op2_class *opclass; - struct node *args[2]; -}; - -struct node_class { - const char * const name; - void (*free)(struct node *); - void (*dump)(struct node *, struct parameter*, int, FILE *); -}; - -struct lsfd_filter { - struct libscols_table *table; - struct node *node; - struct parameter *parameters; - int nparams; - char errmsg[ sizeof_member(struct parser, errmsg) ]; -}; - -/* - * Prototypes - */ -static struct node *node_val_new(enum node_type, int pindex); -static void node_free (struct node *); -static bool node_apply(struct node *, struct parameter *, struct libscols_line *); -static void node_dump (struct node *, struct parameter *, int, FILE *); - -static struct token *token_new (void); -static void token_free(struct token *); -#ifdef DEBUG -static void token_dump(struct token *, FILE *); -#endif /* DEBUG */ - -static void token_free_str(struct token *); - -static void token_dump_str(struct token *, FILE *); -static void token_dump_num(struct token *, FILE *); -static void token_dump_fnum(struct token *, FILE *); -static void token_dump_op1(struct token *, FILE *); -static void token_dump_op2(struct token *, FILE *); - -static bool op1_not(struct node *, struct parameter*, struct libscols_line *); -static bool op1_check_type_bool_or_op(struct parser *, const struct op1_class *, struct node *); - -static bool op2_eq (struct node *, struct node *, struct parameter*, struct libscols_line *); -static bool op2_ne (struct node *, struct node *, struct parameter*, struct libscols_line *); -static bool op2_and(struct node *, struct node *, struct parameter*, struct libscols_line *); -static bool op2_or (struct node *, struct node *, struct parameter*, struct libscols_line *); -static bool op2_lt (struct node *, struct node *, struct parameter*, struct libscols_line *); -static bool op2_le (struct node *, struct node *, struct parameter*, struct libscols_line *); -static bool op2_gt (struct node *, struct node *, struct parameter*, struct libscols_line *); -static bool op2_ge (struct node *, struct node *, struct parameter*, struct libscols_line *); -static bool op2_re_match (struct node *, struct node *, struct parameter*, struct libscols_line *); -static bool op2_re_unmatch (struct node *, struct node *, struct parameter*, struct libscols_line *); - -static bool op2_check_type_eq_or_bool_or_op(struct parser *, const struct op2_class *, struct node *, struct node *); -static bool op2_check_type_boolean_or_op (struct parser *, const struct op2_class *, struct node *, struct node *); -static bool op2_check_type_num (struct parser *, const struct op2_class *, struct node *, struct node *); -static bool op2_check_type_re (struct parser *, const struct op2_class *, struct node *, struct node *); - -static void node_str_free(struct node *); -static void node_re_free (struct node *); -static void node_op1_free(struct node *); -static void node_op2_free(struct node *); - -static void node_str_dump (struct node *, struct parameter*, int, FILE *); -static void node_num_dump (struct node *, struct parameter*, int, FILE *); -static void node_fnum_dump (struct node *, struct parameter*, int, FILE *); -static void node_bool_dump(struct node *, struct parameter*, int, FILE *); -static void node_re_dump (struct node *, struct parameter*, int, FILE *); -static void node_op1_dump (struct node *, struct parameter*, int, FILE *); -static void node_op2_dump (struct node *, struct parameter*, int, FILE *); - -static struct node *dparser_compile(struct parser *); - -/* - * Data - */ -#define TOKEN_CLASS(TOKEN) (&token_classes[(TOKEN)->type]) -static const struct token_class token_classes [] = { - [TOKEN_NAME] = { - .name = "NAME", - .free = token_free_str, - .dump = token_dump_str, - }, - [TOKEN_STR] = { - .name = "STR", - .free = token_free_str, - .dump = token_dump_str, - }, - [TOKEN_DEC] = { - .name = "DEC", - .dump = token_dump_num, - }, - [TOKEN_FDEC] = { - .name = "FDEC", - .dump = token_dump_fnum, - }, - [TOKEN_TRUE] = { - .name = "true", - }, - [TOKEN_FALSE] = { - .name = "false", - }, - [TOKEN_OPEN] = { - .name = "OPEN", - }, - [TOKEN_CLOSE] = { - .name = "CLOSE", - }, - [TOKEN_OP1] = { - .name = "OP1", - .dump = token_dump_op1, - }, - [TOKEN_OP2] = { - .name = "OP2", - .dump = token_dump_op2, - }, - [TOKEN_EOF] = { - .name = "TOKEN_EOF", - }, -}; - -#define TOKEN_OP1_CLASS(TOKEN) (&(op1_classes[(TOKEN)->val.op1])) -static const struct op1_class op1_classes [] = { - [OP1_NOT] = { - .name = "!", - .is_acceptable = op1_not, - .check_type = op1_check_type_bool_or_op, - }, -}; - -#define TOKEN_OP2_CLASS(TOKEN) (&(op2_classes[(TOKEN)->val.op2])) -static const struct op2_class op2_classes [] = { - [OP2_EQ] = { - .name = "==", - .is_acceptable = op2_eq, - .check_type = op2_check_type_eq_or_bool_or_op - }, - [OP2_NE] = { - .name = "!=", - .is_acceptable = op2_ne, - .check_type = op2_check_type_eq_or_bool_or_op, - }, - [OP2_AND] = { - .name = "&&", - .is_acceptable = op2_and, - .check_type = op2_check_type_boolean_or_op, - }, - [OP2_OR] = { - .name = "||", - .is_acceptable = op2_or, - .check_type = op2_check_type_boolean_or_op, - }, - [OP2_LT] = { - .name = "<", - .is_acceptable = op2_lt, - .check_type = op2_check_type_num, - }, - [OP2_LE] = { - .name = "<=", - .is_acceptable = op2_le, - .check_type = op2_check_type_num, - }, - [OP2_GT] = { - .name = ">", - .is_acceptable = op2_gt, - .check_type = op2_check_type_num, - }, - [OP2_GE] = { - .name = ">=", - .is_acceptable = op2_ge, - .check_type = op2_check_type_num, - }, - [OP2_RE_MATCH] = { - .name = "=~", - .is_acceptable = op2_re_match, - .check_type = op2_check_type_re, - }, - [OP2_RE_UNMATCH] = { - .name = "!~", - .is_acceptable = op2_re_unmatch, - .check_type = op2_check_type_re, - }, -}; - -#define NODE_CLASS(NODE) (&node_classes[(NODE)->type]) -static const struct node_class node_classes[] = { - [NODE_STR] = { - .name = "STR", - .free = node_str_free, - .dump = node_str_dump, - }, - [NODE_NUM] = { - .name = "NUM", - .dump = node_num_dump, - }, - [NODE_FNUM] = { - .name = "FNUM", - .dump = node_fnum_dump, - }, - [NODE_BOOL] = { - .name = "BOOL", - .dump = node_bool_dump, - }, - [NODE_RE] = { - .name = "STR", - .free = node_re_free, - .dump = node_re_dump, - }, - [NODE_OP1] = { - .name = "OP1", - .free = node_op1_free, - .dump = node_op1_dump, - }, - [NODE_OP2] = { - .name = "OP2", - .free = node_op2_free, - .dump = node_op2_dump, - } -}; - -/* - * Functions - */ -static int strputc(char **a, const char b) -{ - return strappend(a, (char [2]){b, '\0'}); -} - -static void xstrputc(char **a, const char b) -{ - int rc = strputc(a, b); - if (rc < 0) - errx(EXIT_FAILURE, _("failed to allocate memory")); -} - -static void parser_init(struct parser *parser, const char *const expr, struct libscols_table *tb, - int ncols, - int (*column_name_to_id)(const char *, void *), - struct libscols_column *(*add_column_by_id)(struct libscols_table *, int, void*), - void *data) -{ - parser->expr = expr; - parser->cursor = parser->expr; - parser->paren_level = 0; - parser->tb = tb; - parser->column_name_to_id = column_name_to_id; - parser->add_column_by_id = add_column_by_id; - parser->data = data; - parser->parameters = xcalloc(ncols, sizeof(struct parameter)); - parser->errmsg[0] = '\0'; -} - -static char parser_getc(struct parser *parser) -{ - char c = *parser->cursor; - if (c != '\0') - parser->cursor++; - return c; -} - -static void parser_ungetc(struct parser *parser, char c) -{ - assert(parser->cursor > parser->expr); - if (c != '\0') - parser->cursor--; -} - -static void parser_read_str(struct parser *parser, struct token *token, char delimiter) -{ - bool escape = false; - while (1) { - char c = parser_getc(parser); - - if (c == '\0') { - snprintf(parser->errmsg, sizeof(parser->errmsg), - _("error: string literal is not terminated: %s"), - token->val.str? : ""); - return; - } else if (escape) { - switch (c) { - case '\\': - case '\'': - case '"': - xstrputc(&token->val.str, c); - break; - case 'n': - xstrputc(&token->val.str, '\n'); - break; - case 't': - xstrputc(&token->val.str, '\t'); - break; - /* TODO: \f, \r, ... */ - default: - xstrputc(&token->val.str, '\\'); - xstrputc(&token->val.str, c); - return; - } - escape = false; - } else if (c == delimiter) { - if (token->val.str == NULL) - token->val.str = xstrdup(""); - return; - } else if (c == '\\') - escape = true; - else - xstrputc(&token->val.str, c); - } -} - -static void parser_read_name(struct parser *parser, struct token *token) -{ - while (1) { - char c = parser_getc(parser); - if (c == '\0') - break; - if (strchr(COL_HEADER_EXTRA_CHARS, c) || isalnum((unsigned char)c)) { - xstrputc(&token->val.str, c); - continue; - } - parser_ungetc(parser, c); - break; - } -} - -static int parser_read_dec(struct parser *parser, struct token *token) -{ - int rc = 0; - int found_point = 0; - while (1) { - char c = parser_getc(parser); - if (c == '\0') - break; - if (isdigit((unsigned char)c) - || (found_point == 0 && c == '.')) { - xstrputc(&token->val.str, c); - if (c == '.') - found_point++; - continue; - } - parser_ungetc(parser, c); - break; - } - - char *endptr = NULL; - errno = 0; - unsigned long long num = strtoull(token->val.str, &endptr, 10); - rc = errno; - if (rc) - return rc; - - if (endptr && *endptr == '.') { - errno = 0; - long double fnum = strtold(endptr, NULL); - rc = errno; - if (rc) - return rc; - free(token->val.str); - token->type = TOKEN_FDEC; - token->val.fnum = ((long double)num) + fnum; - } else { - free(token->val.str); - token->type = TOKEN_DEC; - token->val.num = num; - } - - return 0; -} - -static struct token *parser_read(struct parser *parser) -{ - struct token *t = token_new(); - char c, c0; - - do - c = parser_getc(parser); - while (isspace((unsigned char)c)); - - switch (c) { - case '\0': - t->type = TOKEN_EOF; - break; - case '(': - t->type = TOKEN_OPEN; - parser->paren_level++; - break; - case ')': - t->type = TOKEN_CLOSE; - parser->paren_level--; - if (parser->paren_level < 0) - snprintf(parser->errmsg, sizeof(parser->errmsg), - _("error: unbalanced parenthesis: %s"), parser->cursor - 1); - break; - case '!': - c0 = parser_getc(parser); - if (c0 == '=') { - t->type = TOKEN_OP2; - t->val.op2 = OP2_NE; - break; - } else if (c0 == '~') { - t->type = TOKEN_OP2; - t->val.op2 = OP2_RE_UNMATCH; - break; - } - parser_ungetc(parser, c0); - t->type = TOKEN_OP1; - t->val.op1 = OP1_NOT; - break; - case '<': - t->type = TOKEN_OP2; - c0 = parser_getc(parser); - if (c0 == '=') { - t->val.op2 = OP2_LE; - break; - } - parser_ungetc(parser, c0); - t->val.op2 = OP2_LT; - break; - case '>': - t->type = TOKEN_OP2; - c0 = parser_getc(parser); - if (c0 == '=') { - t->val.op2 = OP2_GE; - break; - } - parser_ungetc(parser, c0); - t->val.op2 = OP2_GT; - break; - case '=': - c0 = parser_getc(parser); - if (c0 == '=') { - t->type = TOKEN_OP2; - t->val.op2 = OP2_EQ; - break; - } else if (c0 == '~') { - t->type = TOKEN_OP2; - t->val.op2 = OP2_RE_MATCH; - break; - } - snprintf(parser->errmsg, sizeof(parser->errmsg), - _("error: unexpected character %c after ="), c0); - break; - case '&': - c0 = parser_getc(parser); - if (c0 == '&') { - t->type = TOKEN_OP2; - t->val.op2 = OP2_AND; - break; - } - snprintf(parser->errmsg, sizeof(parser->errmsg), - _("error: unexpected character %c after ="), c0); - break; - case '|': - c0 = parser_getc(parser); - if (c0 == '|') { - t->type = TOKEN_OP2; - t->val.op2 = OP2_OR; - break; - } - snprintf(parser->errmsg, sizeof(parser->errmsg), - _("error: unexpected character %c after ="), c0); - break; - case '"': - case '\'': - t->type = TOKEN_STR; - parser_read_str(parser, t, c); - break; - default: - if (isalpha((unsigned char)c) || c == '_') { - xstrputc(&t->val.str, c); - parser_read_name(parser, t); - if (strcmp(t->val.str, "true") == 0) { - free(t->val.str); - t->type = TOKEN_TRUE; - } else if (strcmp(t->val.str, "false") == 0) { - free(t->val.str); - t->type = TOKEN_FALSE; - } else if (strcmp(t->val.str, "or") == 0) { - free(t->val.str); - t->type = TOKEN_OP2; - t->val.op2 = OP2_OR; - } else if (strcmp(t->val.str, "and") == 0) { - free(t->val.str); - t->type = TOKEN_OP2; - t->val.op2 = OP2_AND; - } else if (strcmp(t->val.str, "eq") == 0) { - free(t->val.str); - t->type = TOKEN_OP2; - t->val.op2 = OP2_EQ; - } else if (strcmp(t->val.str, "ne") == 0) { - free(t->val.str); - t->type = TOKEN_OP2; - t->val.op2 = OP2_NE; - } else if (strcmp(t->val.str, "lt") == 0) { - free(t->val.str); - t->type = TOKEN_OP2; - t->val.op2 = OP2_LT; - } else if (strcmp(t->val.str, "le") == 0) { - free(t->val.str); - t->type = TOKEN_OP2; - t->val.op2 = OP2_LE; - } else if (strcmp(t->val.str, "gt") == 0) { - free(t->val.str); - t->type = TOKEN_OP2; - t->val.op2 = OP2_GT; - } else if (strcmp(t->val.str, "ge") == 0) { - free(t->val.str); - t->type = TOKEN_OP2; - t->val.op2 = OP2_GE; - } else if (strcmp(t->val.str, "not") == 0) { - free(t->val.str); - t->type = TOKEN_OP1; - t->val.op1 = OP1_NOT; - } else - t->type = TOKEN_NAME; - break; - } else if (isdigit((unsigned char)c)) { - xstrputc(&t->val.str, c); - if (parser_read_dec(parser, t) != 0) { - snprintf(parser->errmsg, sizeof(parser->errmsg), - _("error: failed to convert input to number: %s"), - t->val.str); - free(t->val.str); - } - break; - } - snprintf(parser->errmsg, sizeof(parser->errmsg), - _("error: unexpected character %c"), c); - break; - } - return t; -} - -static void parameter_init(struct parameter *param, struct libscols_column *cl) -{ - param->cl = cl; - param->has_value = false; - param->floating_point_num = false; -} - -static struct node *dparser_compile1(struct parser *parser, struct node *last) -{ - struct token *t = parser_read(parser); - - if (GOT_ERROR(parser)) { - token_free(t); - return NULL; - } - - if (t->type == TOKEN_EOF) { - token_free(t); - return last; - } - if (t->type == TOKEN_CLOSE) { - token_free(t); - return last; - } - - if (last) { - switch (t->type) { - case TOKEN_NAME: - case TOKEN_STR: - case TOKEN_DEC: - case TOKEN_FDEC: - case TOKEN_TRUE: - case TOKEN_FALSE: - case TOKEN_OPEN: - case TOKEN_OP1: - snprintf(parser->errmsg, sizeof(parser->errmsg), - _("error: unexpected token: %s after %s"), t->val.str, - NODE_CLASS(last)->name); - token_free(t); - return NULL; - default: - break; - } - } else { - switch (t->type) { - case TOKEN_OP2: - snprintf(parser->errmsg, sizeof(parser->errmsg), - _("error: empty left side expression: %s"), - TOKEN_OP2_CLASS(t)->name); - token_free(t); - return NULL; - default: - break; - } - } - - struct node *node = NULL; - switch (t->type) { - case TOKEN_NAME: { - int col_id = parser->column_name_to_id(t->val.str, parser->data); - if (col_id == LSFD_FILTER_UNKNOWN_COL_ID) { - snprintf(parser->errmsg, sizeof(parser->errmsg), - _("error: no such column: %s"), t->val.str); - token_free(t); - return NULL; - - } - - struct libscols_column *cl = scols_table_get_column_by_name(parser->tb, t->val.str); - if (!cl) { - cl = parser->add_column_by_id(parser->tb, col_id, parser->data); - if (!cl) { - snprintf(parser->errmsg, sizeof(parser->errmsg), - _("error: cannot add a column to table: %s"), t->val.str); - token_free(t); - return NULL; - } - scols_column_set_flags(cl, SCOLS_FL_HIDDEN); - } - parameter_init(parser->parameters + col_id, cl); - - int jtype = scols_column_get_json_type(cl); - int ntype; - switch (jtype) { - case SCOLS_JSON_STRING: - case SCOLS_JSON_ARRAY_STRING: - case SCOLS_JSON_ARRAY_NUMBER: - /* We handles SCOLS_JSON_ARRAY_* as a string - * till we implement operators for arrays. */ - ntype = NODE_STR; - break; - case SCOLS_JSON_NUMBER: - ntype = NODE_NUM; - break; - case SCOLS_JSON_BOOLEAN: - ntype = NODE_BOOL; - break; - default: - snprintf(parser->errmsg, sizeof(parser->errmsg), - _("error: unsupported column data type: %d, column: %s"), - jtype, t->val.str); - return NULL; - } - node = node_val_new(ntype, col_id); - token_free(t); - return node; - } - - case TOKEN_STR: - node = node_val_new(NODE_STR, -1); - VAL(node, str) = xstrdup(t->val.str); - token_free(t); - return node; - - case TOKEN_DEC: - node = node_val_new(NODE_NUM, -1); - VAL(node, num) = t->val.num; - token_free(t); - return node; - case TOKEN_FDEC: - node = node_val_new(NODE_FNUM, -1); - VAL(node, fnum) = t->val.fnum; - token_free(t); - return node; - - case TOKEN_TRUE: - case TOKEN_FALSE: - node = node_val_new(NODE_BOOL, -1); - VAL(node, boolean) = (t->type == TOKEN_TRUE); - token_free(t); - return node; - - case TOKEN_OPEN: - token_free(t); - return dparser_compile(parser); - - case TOKEN_OP1: { - struct node *op1_right = dparser_compile1(parser, NULL); - const struct op1_class *op1_class = TOKEN_OP1_CLASS(t); - - token_free(t); - - if (GOT_ERROR(parser)) { - node_free(op1_right); - return NULL; - } - - if (op1_right == NULL) { - snprintf(parser->errmsg, sizeof(parser->errmsg), - _("error: empty right side expression: %s"), - op1_class->name); - return NULL; - } - - if (!op1_class->check_type(parser, op1_class, op1_right)) { - node_free(op1_right); - return NULL; - } - - node = xmalloc(sizeof(struct node_op1)); - node->type = NODE_OP1; - ((struct node_op1 *)node)->opclass = op1_class; - ((struct node_op1 *)node)->arg = op1_right; - - return node; - } - - case TOKEN_OP2: { - struct node *op2_right = dparser_compile1(parser, NULL); - const struct op2_class *op2_class = TOKEN_OP2_CLASS(t); - - token_free(t); - - if (GOT_ERROR(parser)) { - node_free(op2_right); - return NULL; - } - if (op2_right == NULL) { - snprintf(parser->errmsg, sizeof(parser->errmsg), - _("error: empty right side expression: %s"), - op2_class->name); - return NULL; - } - - if (!op2_class->check_type(parser, op2_class, last, op2_right)) { - node_free(op2_right); - return NULL; - } - - node = xmalloc(sizeof(struct node_op2)); - node->type = NODE_OP2; - ((struct node_op2 *)node)->opclass = op2_class; - ((struct node_op2 *)node)->args[0] = last; - ((struct node_op2 *)node)->args[1] = op2_right; - - return node; - } - - default: - warnx("unexpected token type: %d", t->type); - token_free(t); - return NULL; - } -} - -static struct node *dparser_compile(struct parser *parser) -{ - struct node *node = NULL; - - while (true) { - struct node *node0 = dparser_compile1(parser, node); - if (GOT_ERROR(parser)) { - node_free(node); - return NULL; - } - - if (node == node0) { - if (node == NULL) - xstrncpy(parser->errmsg, - _("error: empty filter expression"), - sizeof(parser->errmsg)); - return node; - } - node = node0; - } -} - -static struct token *token_new(void) -{ - return xcalloc(1, sizeof(struct token)); -} - -static void token_free(struct token *token) -{ - if (TOKEN_CLASS(token)->free) - TOKEN_CLASS(token)->free(token); - free(token); -} - -#ifdef DEBUG -static void token_dump(struct token *token, FILE *stream) -{ - fprintf(stream, "<%s>", TOKEN_CLASS(token)->name); - if (TOKEN_CLASS(token)->dump) - TOKEN_CLASS(token)->dump(token, stream); - fputc('\n', stream); -} -#endif /* DEBUG */ - -static void token_free_str(struct token *token) -{ - free(token->val.str); -} - -static void token_dump_str(struct token *token, FILE *stream) -{ - fputs(token->val.str, stream); -} - -static void token_dump_num(struct token *token, FILE *stream) -{ - fprintf(stream, "%llu", token->val.num); -} - -static void token_dump_fnum(struct token *token, FILE *stream) -{ - fprintf(stream, "%Lf", token->val.fnum); -} - -static void token_dump_op1(struct token *token, FILE *stream) -{ - fputs(TOKEN_OP1_CLASS(token)->name, stream); -} - -static void token_dump_op2(struct token *token, FILE *stream) -{ - fputs(TOKEN_OP2_CLASS(token)->name, stream); -} - -static struct node *node_val_new(enum node_type type, int pindex) -{ - struct node *node = xmalloc(sizeof(struct node_val)); - node->type = type; - PINDEX(node) = pindex; - return node; -} - -static void node_free(struct node *node) -{ - if (node == NULL) - return; - if (NODE_CLASS(node)->free) - NODE_CLASS(node)->free(node); - free(node); -} - -static bool node_apply(struct node *node, struct parameter *params, struct libscols_line *ln) -{ - if (!node) - return true; - - switch (node->type) { - case NODE_OP1: { - struct node_op1 *node_op1 = (struct node_op1*)node; - return node_op1->opclass->is_acceptable(node_op1->arg, params, ln); - } - case NODE_OP2: { - struct node_op2 *node_op2 = (struct node_op2*)node; - return node_op2->opclass->is_acceptable(node_op2->args[0], node_op2->args[1], params, ln); - } - case NODE_BOOL: - if (PINDEX(node) < 0) - return VAL(node,boolean); - - if (!params[PINDEX(node)].has_value) { - const char *data = scols_line_get_column_data(ln, params[PINDEX(node)].cl); - if (data == NULL) - return false; - params[PINDEX(node)].val.boolean = !*data ? false : - *data == '0' ? false : - *data == 'N' || *data == 'n' ? false : true; - params[PINDEX(node)].has_value = true; - } - return params[PINDEX(node)].val.boolean; - default: - warnx(_("unexpected type in filter application: %s"), NODE_CLASS(node)->name); - return false; - } -} - -static void node_dump(struct node *node, struct parameter *param, int depth, FILE *stream) -{ - int i; - - if (!node) - return; - - for (i = 0; i < depth; i++) - fputc(' ', stream); - fputs(NODE_CLASS(node)->name, stream); - if (NODE_CLASS(node)->dump) - NODE_CLASS(node)->dump(node, param, depth, stream); -} - -static void node_str_dump(struct node *node, struct parameter* params, int depth __attribute__((__unused__)), FILE *stream) -{ - if (PINDEX(node) >= 0) - fprintf(stream, ": |%s|\n", scols_column_get_name(params[PINDEX(node)].cl)); - else - fprintf(stream, ": '%s'\n", VAL(node,str)); -} - -static void node_num_dump(struct node *node, struct parameter* params, int depth __attribute__((__unused__)), FILE *stream) -{ - if (PINDEX(node) >= 0) - fprintf(stream, ": |%s|\n", scols_column_get_name(params[PINDEX(node)].cl)); - else - fprintf(stream, ": %llu\n", VAL(node,num)); -} - -static void node_fnum_dump(struct node *node, struct parameter* params, int depth __attribute__((__unused__)), FILE *stream) -{ - if (PINDEX(node) >= 0) - fprintf(stream, ": |%s|\n", scols_column_get_name(params[PINDEX(node)].cl)); - else - fprintf(stream, ": %Lf\n", VAL(node,fnum)); -} - -static void node_bool_dump(struct node *node, struct parameter* params, int depth __attribute__((__unused__)), FILE *stream) -{ - if (PINDEX(node) >= 0) - fprintf(stream, ": |%s|\n", scols_column_get_name(params[PINDEX(node)].cl)); - else - fprintf(stream, ": %s\n", - VAL(node,boolean) - ? token_classes[TOKEN_TRUE].name - : token_classes[TOKEN_FALSE].name); -} - -static void node_re_dump(struct node *node, struct parameter* params __attribute__((__unused__)), - int depth __attribute__((__unused__)), FILE *stream) -{ - fprintf(stream, ": #\n", &VAL(node,re)); -} - -static void node_op1_dump(struct node *node, struct parameter* params, int depth, FILE *stream) -{ - fprintf(stream, ": %s\n", ((struct node_op1 *)node)->opclass->name); - node_dump(((struct node_op1 *)node)->arg, params, depth + 4, stream); -} - -static void node_op2_dump(struct node *node, struct parameter* params, int depth, FILE *stream) -{ - int i; - - fprintf(stream, ": %s\n", ((struct node_op2 *)node)->opclass->name); - for (i = 0; i < 2; i++) - node_dump(((struct node_op2 *)node)->args[i], params, depth + 4, stream); -} - -static void node_str_free(struct node *node) -{ - if (PINDEX(node) < 0) - free(VAL(node,str)); -} - -static void node_re_free(struct node *node) -{ - regfree(&VAL(node,re)); -} - -static void node_op1_free(struct node *node) -{ - node_free(((struct node_op1 *)node)->arg); -} - -static void node_op2_free(struct node *node) -{ - int i; - - for (i = 0; i < 2; i++) - node_free(((struct node_op2 *)node)->args[i]); -} - -static bool op1_not(struct node *node, struct parameter* params, struct libscols_line * ln) -{ - return !node_apply(node, params, ln); -} - -static bool op1_check_type_bool_or_op(struct parser* parser, const struct op1_class *op1_class, - struct node *node) -{ - if (! (node->type == NODE_OP1 || node->type == NODE_OP2 || node->type == NODE_BOOL)) { - snprintf(parser->errmsg, sizeof(parser->errmsg), - _("error: unexpected operand type %s for: %s"), - NODE_CLASS(node)->name, - op1_class->name); - return false; - } - return true; -} - -#define OP2_GET_STR(NODE,DEST) do { \ - int pindex = PINDEX(NODE); \ - if (pindex < 0) \ - DEST = VAL(NODE,str); \ - else { \ - struct parameter *p = params + pindex; \ - if (!p->has_value) { \ - p->val.str = scols_line_get_column_data(ln, p->cl); \ - if (p->val.str == NULL) return false; \ - p->has_value = true; \ - } \ - DEST = p->val.str; \ - } \ -} while(0) - -struct compnum { - bool floating_point_num; - union { - unsigned long long v; - long double fv; - }; -}; - -#define OP2_GET_NUM(NODE,DEST) do { \ - int pindex = PINDEX(NODE); \ - if (pindex < 0) { \ - if (NODE->type == NODE_NUM) { \ - DEST.v = VAL(NODE,num); \ - DEST.floating_point_num = false; \ - } else { \ - DEST.fv = VAL(NODE,fnum); \ - DEST.floating_point_num = true; \ - } \ - } else { \ - struct parameter *p = params + pindex; \ - if (!p->has_value) { \ - unsigned long long val; \ - char *endptr = NULL; \ - const char *tmp = scols_line_get_column_data(ln, p->cl); \ - if (tmp == NULL) return false; \ - val = strtoull(tmp, &endptr, 10); \ - if (endptr && endptr[0] == '.') { \ - long double fval = strtold(endptr, NULL); \ - if (fval != 0.0) { \ - p->val.fnum = val + fval; \ - p->floating_point_num = true; \ - } else { \ - p->val.num = val; \ - p->floating_point_num = false; \ - } \ - } else { \ - p->val.num = val; \ - p->floating_point_num = false; \ - } \ - p->has_value = true; \ - } \ - if (p->floating_point_num) { \ - DEST.fv = p->val.fnum; \ - DEST.floating_point_num = true; \ - } else { \ - DEST.v = p->val.num; \ - DEST.floating_point_num = false; \ - } \ - } \ -} while(0) - -#define OP2_NUM_CMP_BODY(OP) do { \ - struct compnum lv, rv; \ - OP2_GET_NUM(left,lv); \ - OP2_GET_NUM(right,rv); \ - if (lv.floating_point_num && rv.floating_point_num) \ - return lv.fv OP rv.fv; \ - else if (! (lv.floating_point_num || rv.floating_point_num)) \ - return lv.v OP rv.v; \ - else if (lv.floating_point_num) \ - return lv.fv OP ((long double)rv.v); \ - else \ - return ((long double)lv.v) OP rv.fv; \ -} while(0) - -#define OP2_EQ_BODY(OP,ELSEVAL) do { \ - if (left->type == NODE_STR) { \ - const char *lv, *rv; \ - OP2_GET_STR(left,lv); \ - OP2_GET_STR(right,rv); \ - return strcmp(lv, rv) OP 0; \ - } else if (left->type == NODE_NUM || left->type == NODE_FNUM) { \ - OP2_NUM_CMP_BODY(OP); \ - } else { \ - return node_apply(left, params, ln) OP node_apply(right, params, ln); \ - } \ -} while(0) - -static bool op2_eq(struct node *left, struct node *right, struct parameter *params, struct libscols_line *ln) -{ - OP2_EQ_BODY(==, false); -} - -static bool op2_ne(struct node *left, struct node *right, struct parameter *params, struct libscols_line *ln) -{ - OP2_EQ_BODY(!=, true); -} - -static bool op2_and(struct node *left, struct node *right, struct parameter *params, struct libscols_line *ln) -{ - return node_apply(left, params, ln) && node_apply(right, params, ln); -} - -static bool op2_or(struct node *left, struct node *right, struct parameter *params, struct libscols_line *ln) -{ - return node_apply(left, params, ln) || node_apply(right, params, ln); -} - -static bool op2_lt(struct node *left, struct node *right, struct parameter *params, struct libscols_line *ln) -{ - OP2_NUM_CMP_BODY(<); -} - -static bool op2_le(struct node *left, struct node *right, struct parameter *params, struct libscols_line *ln) -{ - OP2_NUM_CMP_BODY(<=); -} - -static bool op2_gt(struct node *left, struct node *right, struct parameter *params, struct libscols_line *ln) -{ - OP2_NUM_CMP_BODY(>); -} - -static bool op2_ge(struct node *left, struct node *right, struct parameter *params, struct libscols_line *ln) -{ - OP2_NUM_CMP_BODY(>=); -} - -static bool op2_re_match(struct node *left, struct node *right, - struct parameter *params, struct libscols_line *ln) -{ - const char *str; - OP2_GET_STR(left, str); - - return (regexec(&VAL(right,re), str, 0, NULL, 0) == 0); -} - -static bool op2_re_unmatch(struct node *left, struct node *right, - struct parameter *params, struct libscols_line *ln) -{ - return !op2_re_match(left, right, params, ln); -} - -static bool op2_check_type_boolean_or_op(struct parser* parser, const struct op2_class *op2_class, - struct node *left, struct node *right) -{ - enum node_type lt = left->type, rt = right->type; - - if (!(lt == NODE_OP1 || lt == NODE_OP2 || lt == NODE_BOOL)) { - snprintf(parser->errmsg, sizeof(parser->errmsg), - _("error: unexpected left operand type %s for: %s"), - NODE_CLASS(left)->name, - op2_class->name); - return false; - } - - if (! (rt == NODE_OP1 || rt == NODE_OP2 || rt == NODE_BOOL)) { - snprintf(parser->errmsg, sizeof(parser->errmsg), - _("error: unexpected right operand type %s for: %s"), - NODE_CLASS(right)->name, - op2_class->name); - return false; - } - - return true; -} - -static bool op2_check_type_eq_or_bool_or_op(struct parser* parser, const struct op2_class *op2_class, - struct node *left, struct node *right) -{ - enum node_type lt = left->type, rt = right->type; - - if (lt == rt) - return true; - else if ((lt == NODE_NUM && rt == NODE_FNUM) - || (lt == NODE_FNUM && rt == NODE_NUM)) - return true; - - return op2_check_type_boolean_or_op(parser, op2_class, left, right); -} - -static bool op2_check_type_num(struct parser* parser, const struct op2_class *op2_class, - struct node *left, struct node *right) -{ - if (left->type != NODE_NUM && left->type != NODE_FNUM) { - snprintf(parser->errmsg, sizeof(parser->errmsg), - _("error: unexpected left operand type %s for: %s"), - NODE_CLASS(left)->name, - op2_class->name); - return false; - } - - if (right->type != NODE_NUM && right->type != NODE_FNUM) { - snprintf(parser->errmsg, sizeof(parser->errmsg), - _("error: unexpected right operand type %s for: %s"), - NODE_CLASS(right)->name, - op2_class->name); - return false; - } - - return true; -} - -static bool op2_check_type_re(struct parser* parser, const struct op2_class *op2_class, - struct node *left, struct node *right) -{ - if (left->type != NODE_STR) { - snprintf(parser->errmsg, sizeof(parser->errmsg), - _("error: unexpected left operand type %s for: %s"), - NODE_CLASS(left)->name, - op2_class->name); - return false; - } - - if (right->type != NODE_STR) { - snprintf(parser->errmsg, sizeof(parser->errmsg), - _("error: unexpected right operand type %s for: %s"), - NODE_CLASS(right)->name, - op2_class->name); - return false; - } - if (PINDEX(right) >= 0) { - snprintf(parser->errmsg, sizeof(parser->errmsg), - _("error: string literal is expected as right operand for: %s"), - op2_class->name); - return false; - } - - char *regex = VAL(right, str); - VAL(right, str) = NULL; - - int err = regcomp(&VAL(right, re), regex, REG_NOSUB | REG_EXTENDED); - if (err != 0) { - size_t size = regerror(err, &VAL(right, re), NULL, 0); - char *buf = xmalloc(size + 1); - - regerror(err, &VAL(right, re), buf, size); - - snprintf(parser->errmsg, sizeof(parser->errmsg), - _("error: could not compile regular expression %s: %s"), - regex, buf); - free(buf); - return false; - } - right->type = NODE_RE; - free(regex); - return true; -} - -struct lsfd_filter *lsfd_filter_new(const char *const expr, struct libscols_table *tb, - int ncols, - int (*column_name_to_id)(const char *, void *), - struct libscols_column *(*add_column_by_id)(struct libscols_table *, int, void*), - void *data) -{ - struct parser parser; - int i; - struct node *node; - struct lsfd_filter *filter; - - parser_init(&parser, expr, tb, ncols, - column_name_to_id, - add_column_by_id, - data); - - node = dparser_compile(&parser); - filter = xcalloc(1, sizeof(struct lsfd_filter)); - - if (GOT_ERROR(&parser)) { - xstrncpy(filter->errmsg, parser.errmsg, sizeof(filter->errmsg)); - return filter; - } - assert(node); - if (parser.paren_level > 0) { - node_free(node); - xstrncpy(filter->errmsg, _("error: unbalanced parenthesis: ("), sizeof(filter->errmsg)); - return filter; - } - if (*parser.cursor != '\0') { - node_free(node); - snprintf(filter->errmsg, sizeof(filter->errmsg), - _("error: garbage at the end of expression: %s"), parser.cursor); - return filter; - } - if (node->type == NODE_STR || node->type == NODE_NUM) { - /* FNUM like 3.14 is not considered as a bool expression. */ - node_free(node); - snprintf(filter->errmsg, sizeof(filter->errmsg), - _("error: bool expression is expected: %s"), expr); - return filter; - } - - filter->table = tb; - scols_ref_table(filter->table); - filter->node = node; - filter->parameters = parser.parameters; - filter->nparams = ncols; - for (i = 0; i < filter->nparams; i++) { - if (filter->parameters[i].cl) - scols_ref_column(filter->parameters[i].cl); - } - return filter; -} - -const char *lsfd_filter_get_errmsg(struct lsfd_filter *filter) -{ - if (GOT_ERROR(filter)) - return filter->errmsg; - - return NULL; -} - -void lsfd_filter_dump(struct lsfd_filter *filter, FILE *stream) -{ - if (!filter) { - fputs("EMPTY\n", stream); - return; - } - - if (GOT_ERROR(filter)) { - fprintf(stream, "ERROR: %s\n", filter->errmsg); - return; - } - - node_dump(filter->node, filter->parameters, 0, stream); -} - -void lsfd_filter_free(struct lsfd_filter *filter) -{ - int i; - - if (!filter) - return; - - if (!GOT_ERROR(filter)) { - for (i = 0; i < filter->nparams; i++) { - if (filter->parameters[i].cl) - scols_unref_column(filter->parameters[i].cl); - } - scols_unref_table(filter->table); - node_free(filter->node); - } - free(filter->parameters); - free(filter); -} - -bool lsfd_filter_apply(struct lsfd_filter *filter, struct libscols_line * ln) -{ - int i; - - if (!filter) - return true; - - if (GOT_ERROR(filter)) - return false; - - for (i = 0; i < filter->nparams; i++) { - filter->parameters[i].has_value = false; - filter->parameters[i].floating_point_num = false; - } - - return node_apply(filter->node, filter->parameters, ln); -} diff --git a/misc-utils/lsfd-filter.h b/misc-utils/lsfd-filter.h deleted file mode 100644 index db5cbd6bd4..0000000000 --- a/misc-utils/lsfd-filter.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * lsfd-filter.c - filtering engine for lsfd - * - * Copyright (C) 2021 Red Hat, Inc. - * Copyright (C) 2021 Masatake YAMATO - * - * This file may be redistributed under the terms of the - * GNU Lesser General Public License. - */ -#ifndef UTIL_LINUX_LSFD_FILTER_H -#define UTIL_LINUX_LSFD_FILTER_H - -#include "libsmartcols.h" -#include -#include - -#define LSFD_FILTER_UNKNOWN_COL_ID -1 - -struct lsfd_filter; - -/* - * @column_name_to_id: a function converting a column name to its id. - * - * @column_name_to_id should return LSFD_FILTER_UNKNOWN_COL_ID if - * an unknown column name is given. - */ -struct lsfd_filter *lsfd_filter_new(const char *const expr, struct libscols_table *tb, - int ncols, - int (*column_name_to_id)(const char *, void *), - struct libscols_column *(*add_column_by_id)(struct libscols_table *, int, void*), - void *data); - -/* Call lsfd_filter_get_errmsg() after lsfd_filter_new() to detect - * whether lsfd_filter_new() is failed or not. Returning NULL means, - * lsfd_filter_new() is successful. */ -const char *lsfd_filter_get_errmsg(struct lsfd_filter *filter); -void lsfd_filter_free(struct lsfd_filter *filter); -bool lsfd_filter_apply(struct lsfd_filter *filter, struct libscols_line *ln); - -/* Dumping AST. */ -void lsfd_filter_dump(struct lsfd_filter *filter, FILE *stream); - -#endif /* UTIL_LINUX_LSFD_FILTER_H */ diff --git a/misc-utils/lsfd.c b/misc-utils/lsfd.c index 76e0e66e17..243e30b8db 100644 --- a/misc-utils/lsfd.c +++ b/misc-utils/lsfd.c @@ -58,8 +58,6 @@ static int kcmp(pid_t pid1, pid_t pid2, int type, #include "pathnames.h" #include "lsfd.h" -#include "lsfd-filter.h" -#include "lsfd-counter.h" /* * /proc/$pid/mountinfo entries @@ -488,6 +486,12 @@ static const struct counter_spec default_counter_specs[] = { } }; +/* "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 @@ struct lsfd_control { 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 */ @@ -532,13 +536,7 @@ static int column_name_to_id(const char *name, size_t namesz) 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) @@ -575,7 +573,7 @@ static struct libscols_column *add_column(struct libscols_table *tb, const struc 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) { struct libscols_column *cl; @@ -584,15 +582,13 @@ static struct libscols_column *add_column_by_id_cb(struct libscols_table *tb, in assert(colid < LSFD_N_COLS); - cl = add_column(tb, infos + colid); + cl = add_column(ctl->tb, infos + colid); 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; } @@ -1165,6 +1161,7 @@ void add_endpoint(struct ipc_endpoint *endpoint, struct ipc *ipc) list_add(&endpoint->endpoints, &ipc->endpoints); } + static void fill_column(struct proc *proc, struct file *file, struct libscols_line *ln, @@ -1182,6 +1179,18 @@ static void fill_column(struct proc *proc, } } +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) @@ -1189,8 +1198,11 @@ static void convert_file(struct proc *proc, { 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) @@ -1204,23 +1216,34 @@ static void convert(struct list_head *procs, struct lsfd_control *ctl) 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); + if (!ctl->ct_filters) continue; - } - if (!ctl->counters) - 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); } } } @@ -1236,12 +1259,13 @@ static void delete(struct list_head *procs, struct lsfd_control *ctl) 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); } } @@ -1846,24 +1870,49 @@ static void append_filter_expr(char **a, const char *b, bool and) xstrappend(a, ")"); } -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); + 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) @@ -1911,47 +1960,54 @@ static void free_counter_spec(struct counter_spec *counter_spec) 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; + + f = new_filter(spec->expr, false, ctl); - filter = new_filter(spec->expr, false, - _("failed in making filter for a counter: "), - ctl); - return lsfd_counter_new(spec->name, filter); + 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) @@ -2009,28 +2065,35 @@ static struct libscols_table *new_summary_table(struct lsfd_control *ctl) 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); @@ -2265,9 +2328,9 @@ int main(int argc, char *argv[]) } } - /* 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); } @@ -2282,9 +2345,9 @@ int main(int argc, char *argv[]) /* 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); } @@ -2320,8 +2383,8 @@ int main(int argc, char *argv[]) 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);