684
1161
static void *_report_get_field_data(struct dm_report *rh,
685
1162
struct field_properties *fp, void *object)
1164
const struct dm_report_field_type *fields = fp->implicit ? _implicit_report_fields
687
1167
char *ret = fp->type->data_fn(object);
692
return (void *)(ret + rh->fields[fp->field_num].offset);
1172
return (void *)(ret + fields[fp->field_num].offset);
1175
static void *_report_get_implicit_field_data(struct dm_report *rh __attribute__((unused)),
1176
struct field_properties *fp, struct row *row)
1178
if (!strcmp(_implicit_report_fields[fp->field_num].id, SPECIAL_FIELD_SELECTED_ID))
1184
static int _cmp_field_int(const char *field_id, uint64_t a, uint64_t b, uint32_t flags)
1186
switch(flags & FLD_CMP_MASK) {
1189
case FLD_CMP_NOT|FLD_CMP_EQUAL:
1191
case FLD_CMP_NUMBER|FLD_CMP_GT:
1193
case FLD_CMP_NUMBER|FLD_CMP_GT|FLD_CMP_EQUAL:
1195
case FLD_CMP_NUMBER|FLD_CMP_LT:
1197
case FLD_CMP_NUMBER|FLD_CMP_LT|FLD_CMP_EQUAL:
1200
log_error(INTERNAL_ERROR "_cmp_field_int: unsupported number "
1201
"comparison type for field %s", field_id);
1207
static int _close_enough(double d1, double d2)
1209
return fabs(d1 - d2) < DBL_EPSILON;
1212
static int _cmp_field_double(const char *field_id, double a, double b, uint32_t flags)
1214
switch(flags & FLD_CMP_MASK) {
1216
return _close_enough(a, b);
1217
case FLD_CMP_NOT|FLD_CMP_EQUAL:
1218
return !_close_enough(a, b);
1219
case FLD_CMP_NUMBER|FLD_CMP_GT:
1220
return (a > b) && !_close_enough(a, b);
1221
case FLD_CMP_NUMBER|FLD_CMP_GT|FLD_CMP_EQUAL:
1222
return (a > b) || _close_enough(a, b);
1223
case FLD_CMP_NUMBER|FLD_CMP_LT:
1224
return (a < b) && !_close_enough(a, b);
1225
case FLD_CMP_NUMBER|FLD_CMP_LT|FLD_CMP_EQUAL:
1226
return a < b || _close_enough(a, b);
1228
log_error(INTERNAL_ERROR "_cmp_field_double: unsupported number "
1229
"comparison type for selection field %s", field_id);
1235
static int _cmp_field_string(const char *field_id, const char *a, const char *b, uint32_t flags)
1237
switch (flags & FLD_CMP_MASK) {
1239
return !strcmp(a, b);
1240
case FLD_CMP_NOT|FLD_CMP_EQUAL:
1241
return strcmp(a, b);
1243
log_error(INTERNAL_ERROR "_cmp_field_string: unsupported string "
1244
"comparison type for selection field %s", field_id);
1250
/* Matches if all items from selection string list match. */
1251
static int _cmp_field_string_list_all(const struct str_list_sort_value *val,
1252
const struct selection_str_list *sel)
1254
struct dm_str_list *sel_item;
1257
/* if item count differs, it's clear the lists do not match */
1258
if (val->items[0].len != dm_list_size(sel->list))
1261
/* both lists are sorted so they either match 1:1 or not */
1262
dm_list_iterate_items(sel_item, sel->list) {
1263
if (strncmp(sel_item->str, val->value + val->items[i].pos, val->items[i].len))
1271
/* Matches if any item from selection string list matches. */
1272
static int _cmp_field_string_list_any(const struct str_list_sort_value *val,
1273
const struct selection_str_list *sel)
1275
struct dm_str_list *sel_item;
1278
/* if value has no items and selection has at least one, it's clear there's no match */
1279
if ((val->items[0].len == 0) && dm_list_size(sel->list))
1282
dm_list_iterate_items(sel_item, sel->list) {
1284
* TODO: Optimize this so we don't need to compare the whole lists' content.
1285
* Make use of the fact that the lists are sorted!
1287
for (i = 1; i <= val->items[0].len; i++) {
1288
if (!strncmp(sel_item->str, val->value + val->items[i].pos, val->items[i].len))
1296
static int _cmp_field_string_list(const char *field_id,
1297
const struct str_list_sort_value *value,
1298
const struct selection_str_list *selection, uint32_t flags)
1302
switch (selection->type & SEL_MASK) {
1304
r = _cmp_field_string_list_all(value, selection);
1307
r = _cmp_field_string_list_any(value, selection);
1310
log_error(INTERNAL_ERROR "_cmp_field_string_list: unsupported string "
1311
"list type found, expecting either AND or OR list for "
1312
"selection field %s", field_id);
1316
return flags & FLD_CMP_NOT ? !r : r;
1319
static int _cmp_field_regex(const char *s, struct dm_regex *r, uint32_t flags)
1321
int match = dm_regex_match(r, s) >= 0;
1322
return flags & FLD_CMP_NOT ? !match : match;
1325
static int _compare_selection_field(struct dm_report *rh,
1326
struct dm_report_field *f,
1327
struct field_selection *fs)
1329
const struct dm_report_field_type *fields = f->props->implicit ? _implicit_report_fields
1331
const char *field_id = fields[f->props->field_num].id;
1334
if (!f->sort_value) {
1335
log_error("_compare_selection_field: field without value :%d",
1336
f->props->field_num);
1340
if (fs->flags & FLD_CMP_REGEX)
1341
r = _cmp_field_regex((const char *) f->sort_value, fs->v.r, fs->flags);
1343
switch(f->props->flags & DM_REPORT_FIELD_TYPE_MASK) {
1344
case DM_REPORT_FIELD_TYPE_PERCENT:
1346
* Check against real percent values only.
1347
* That means DM_PERCENT_0 <= percent <= DM_PERCENT_100.
1349
if (*(const uint64_t *) f->sort_value > DM_PERCENT_100)
1352
case DM_REPORT_FIELD_TYPE_NUMBER:
1353
r = _cmp_field_int(field_id, *(const uint64_t *) f->sort_value, fs->v.i, fs->flags);
1355
case DM_REPORT_FIELD_TYPE_SIZE:
1356
r = _cmp_field_double(field_id, *(const uint64_t *) f->sort_value, fs->v.d, fs->flags);
1358
case DM_REPORT_FIELD_TYPE_STRING:
1359
r = _cmp_field_string(field_id, (const char *) f->sort_value, fs->v.s, fs->flags);
1361
case DM_REPORT_FIELD_TYPE_STRING_LIST:
1362
r = _cmp_field_string_list(field_id, (const struct str_list_sort_value *) f->sort_value,
1363
fs->v.l, fs->flags);
1366
log_error(INTERNAL_ERROR "_compare_selection_field: unknown field type for field %s", field_id);
1373
static int _check_selection(struct dm_report *rh, struct selection_node *sn,
1374
struct dm_list *fields)
1377
struct selection_node *iter_n;
1378
struct dm_report_field *f;
1380
switch (sn->type & SEL_MASK) {
1383
dm_list_iterate_items(f, fields) {
1384
if (sn->selection.item->fp != f->props)
1386
if (!_compare_selection_field(rh, f, sn->selection.item))
1392
dm_list_iterate_items(iter_n, &sn->selection.set)
1393
if ((r |= _check_selection(rh, iter_n, fields)))
1398
dm_list_iterate_items(iter_n, &sn->selection.set)
1399
if (!(r &= _check_selection(rh, iter_n, fields)))
1403
log_error("Unsupported selection type");
1407
return (sn->type & SEL_MODIFIER_NOT) ? !r : r;
1410
static int _check_report_selection(struct dm_report *rh, struct dm_list *fields)
1412
if (!rh->selection_root)
1415
return _check_selection(rh, rh->selection_root, fields);
695
1418
int dm_report_object(struct dm_report *rh, void *object)
1420
const struct dm_report_field_type *fields;
697
1421
struct field_properties *fp;
699
struct dm_report_field *field;
1422
struct row *row = NULL;
1423
struct dm_report_field *field, *field_sel_status = NULL;
700
1424
void *data = NULL;
703
1429
log_error(INTERNAL_ERROR "dm_report handler is NULL.");
1433
if (rh->flags & RH_ALREADY_REPORTED)
707
1436
if (!(row = dm_pool_zalloc(rh->mem, sizeof(*row)))) {
708
1437
log_error("dm_report_object: struct row allocation failed");
717
1446
rh->keys_count))) {
718
1447
log_error("dm_report_object: "
719
1448
"row sort value structure allocation failed");
723
1452
dm_list_init(&row->fields);
724
dm_list_add(&rh->rows, &row->list);
726
1455
/* For each field to be displayed, call its report_fn */
727
1456
dm_list_iterate_items(fp, &rh->field_props) {
728
1457
if (!(field = dm_pool_zalloc(rh->mem, sizeof(*field)))) {
729
1458
log_error("dm_report_object: "
730
1459
"struct dm_report_field allocation failed");
1464
fields = _implicit_report_fields;
1465
if (!strcmp(fields[fp->field_num].id, SPECIAL_FIELD_SELECTED_ID))
1466
field_sel_status = field;
1468
fields = rh->fields;
733
1470
field->props = fp;
735
data = _report_get_field_data(rh, fp, object);
1472
data = fp->implicit ? _report_get_implicit_field_data(rh, fp, row)
1473
: _report_get_field_data(rh, fp, object);
1475
log_error("dm_report_object: "
1476
"no data assigned to field %s",
1477
fields[fp->field_num].id);
739
if (!rh->fields[fp->field_num].report_fn(rh, rh->mem,
1481
if (!fields[fp->field_num].report_fn(rh, rh->mem,
742
1484
log_error("dm_report_object: "
743
1485
"report function failed for field %s",
744
rh->fields[fp->field_num].id);
748
if (((int) strlen(field->report_string) > field->props->width))
749
field->props->width = (int) strlen(field->report_string);
1486
fields[fp->field_num].id);
1490
dm_list_add(&row->fields, &field->list);
1493
if (!_check_report_selection(rh, &row->fields)) {
1494
if (!field_sel_status) {
1499
* If field with id "selected" is reported,
1500
* report the row although it does not pass
1501
* the selection criteria.
1502
* The "selected" field reports the result
1506
_implicit_report_fields[field_sel_status->props->field_num].report_fn(rh,
1507
rh->mem, field_sel_status, row, rh->private);
1509
* If the "selected" field is not displayed, e.g.
1510
* because it is part of the sort field list,
1511
* skip the display of the row as usual.
1513
if (field_sel_status->props->flags & FLD_HIDDEN) {
1519
dm_list_add(&rh->rows, &row->list);
1521
dm_list_iterate_items(field, &row->fields) {
1522
len = (int) strlen(field->report_string);
1523
if ((len > field->props->width))
1524
field->props->width = len;
751
1526
if ((rh->flags & RH_SORT_REQUIRED) &&
752
1527
(field->props->flags & FLD_SORT_KEY)) {
753
1528
(*row->sort_fields)[field->props->sort_posn] = field;
755
dm_list_add(&row->fields, &field->list);
758
1532
if (!(rh->flags & DM_REPORT_OUTPUT_BUFFERED))
759
1533
return dm_report_output(rh);
1538
dm_pool_free(rh->mem, row);
1547
* Other tokens (FIELD, VALUE, STRING, NUMBER, REGEX)
1548
* FIELD := <strings of alphabet, number and '_'>
1549
* VALUE := NUMBER | STRING
1550
* REGEX := <strings quoted by '"', '\'', '(', '{', '[' or unquoted>
1551
* NUMBER := <strings of [0-9]> (because sort_value is unsigned)
1552
* STRING := <strings quoted by '"', '\'' or unquoted>
1555
static const char * _skip_space(const char *s)
1557
while (*s && isspace(*s))
1562
static int _tok_op(struct op_def *t, const char *s, const char **end,
1569
for (; t->string; t++) {
1570
if (expect && !(t->flags & expect))
1573
len = strlen(t->string);
1574
if (!strncmp(s, t->string, len)) {
1586
static int _tok_op_log(const char *s, const char **end, uint32_t expect)
1588
return _tok_op(_op_log, s, end, expect);
1591
static int _tok_op_cmp(const char *s, const char **end)
1593
return _tok_op(_op_cmp, s, end, 0);
1596
static char _get_and_skip_quote_char(char const **s)
1600
if (**s == '"' || **s == '\'') {
1611
* s - a pointer to the parsed string
1613
* begin - a pointer to the beginning of the token
1614
* end - a pointer to the end of the token + 1
1615
* or undefined if return value is NULL
1616
* return value - a starting point of the next parsing or
1617
* NULL if 's' doesn't match with token type
1618
* (the parsing should be terminated)
1620
static const char *_tok_value_number(const char *s,
1621
const char **begin, const char **end)
1627
while (*s && ((!is_float && *s=='.' && (is_float=1)) || isdigit(*s)))
1639
* s - a pointer to the parsed string
1640
* endchar - terminating character
1641
* end_op_flags - terminating operator flags (see _op_log)
1642
* (if endchar is non-zero then endflags is ignored)
1644
* begin - a pointer to the beginning of the token
1645
* end - a pointer to the end of the token + 1
1646
* end_op_flag_hit - the flag from endflags hit during parsing
1647
* return value - a starting point of the next parsing
1649
static const char *_tok_value_string(const char *s,
1650
const char **begin, const char **end,
1651
const char endchar, uint32_t end_op_flags,
1652
uint32_t *end_op_flag_hit)
1654
uint32_t flag_hit = 0;
1659
* If endchar is defined, scan the string till
1660
* the endchar or the end of string is hit.
1661
* This is in case the string is quoted and we
1662
* know exact character that is the stopper.
1665
while (*s && *s != endchar)
1667
if (*s != endchar) {
1668
log_error("Missing end quote.");
1675
* If endchar is not defined then endchar is/are the
1676
* operator/s as defined by 'endflags' arg or space char.
1677
* This is in case the string is not quoted and
1678
* we don't know which character is the exact stopper.
1681
if ((flag_hit = _tok_op(_op_log, s, NULL, end_op_flags)) || *s == ' ')
1687
* If we hit one of the strings as defined by 'endflags'
1688
* and if 'endflag_hit' arg is provided, save the exact
1689
* string flag that was hit.
1691
if (end_op_flag_hit)
1692
*end_op_flag_hit = flag_hit;
1698
static const char *_reserved_name(const char **names, const char *s, size_t len)
1700
const char **name = names;
1702
if ((strlen(*name) == len) && !strncmp(*name, s, len))
1710
* Used to replace a string representation of the reserved value
1711
* found in selection with the exact reserved value of certain type.
1713
static const char *_get_reserved(struct dm_report *rh, unsigned type,
1714
uint32_t field_num, int implicit,
1715
const char *s, const char **begin, const char **end,
1716
const struct dm_report_reserved_value **reserved)
1718
const struct dm_report_reserved_value *iter = implicit ? NULL : rh->reserved_values;
1719
const char *tmp_begin, *tmp_end, *tmp_s = s;
1720
const char *name = NULL;
1728
c = _get_and_skip_quote_char(&tmp_s);
1729
if (!(tmp_s = _tok_value_string(tmp_s, &tmp_begin, &tmp_end, c, SEL_AND | SEL_OR | SEL_PRECEDENCE_PE, NULL)))
1732
while (iter->value) {
1734
/* DM_REPORT_FIELD_TYPE_NONE - per-field reserved value */
1735
if (((((const struct dm_report_field_reserved_value *) iter->value)->field_num) == field_num) &&
1736
(name = _reserved_name(iter->names, tmp_begin, tmp_end - tmp_begin)))
1738
} else if (iter->type & type) {
1739
/* DM_REPORT_FIELD_TYPE_* - per-type reserved value */
1740
if ((name = _reserved_name(iter->names, tmp_begin, tmp_end - tmp_begin)))
1758
* Used to check whether a value of certain type used in selection is reserved.
1760
static int _check_value_is_reserved(struct dm_report *rh, unsigned type, const void *value)
1762
const struct dm_report_reserved_value *iter = rh->reserved_values;
1767
while (iter->type) {
1768
if (iter->type & type) {
1770
case DM_REPORT_FIELD_TYPE_NUMBER:
1771
if (*(uint64_t *)iter->value == *(uint64_t *)value)
1774
case DM_REPORT_FIELD_TYPE_STRING:
1775
if (!strcmp((const char *)iter->value, (const char *) value))
1778
case DM_REPORT_FIELD_TYPE_SIZE:
1779
if (_close_enough(*(double *)iter->value, *(double *) value))
1782
case DM_REPORT_FIELD_TYPE_STRING_LIST:
1783
// TODO: add comparison for string list
1793
float dm_percent_to_float(dm_percent_t percent)
1795
return (float) percent / DM_PERCENT_1;
1798
dm_percent_t dm_make_percent(uint64_t numerator, uint64_t denominator)
1800
dm_percent_t percent;
1803
return DM_PERCENT_100; /* FIXME? */
1805
return DM_PERCENT_0;
1806
if (numerator == denominator)
1807
return DM_PERCENT_100;
1808
switch (percent = DM_PERCENT_100 * ((double) numerator / (double) denominator)) {
1809
case DM_PERCENT_100:
1810
return DM_PERCENT_100 - 1;
1812
return DM_PERCENT_0 + 1;
1819
* Used to check whether the reserved_values definition passed to
1820
* dm_report_init_with_selection contains only supported reserved value types.
1822
static int _check_reserved_values_supported(const struct dm_report_reserved_value reserved_values[])
1824
const struct dm_report_reserved_value *iter;
1825
static uint32_t supported_reserved_types = DM_REPORT_FIELD_TYPE_NUMBER |
1826
DM_REPORT_FIELD_TYPE_SIZE |
1827
DM_REPORT_FIELD_TYPE_PERCENT |
1828
DM_REPORT_FIELD_TYPE_STRING;
1830
if (!reserved_values)
1833
iter = reserved_values;
1835
while (iter->type) {
1836
if (!(iter->type & supported_reserved_types))
1846
* ft - field type for which the value is parsed
1847
* s - a pointer to the parsed string
1849
* begin - a pointer to the beginning of the token
1850
* end - a pointer to the end of the token + 1
1851
* flags - parsing flags
1853
static const char *_tok_value_regex(struct dm_report *rh,
1854
const struct dm_report_field_type *ft,
1855
const char *s, const char **begin,
1856
const char **end, uint32_t *flags,
1857
const struct dm_report_reserved_value **reserved)
1865
log_error("Regular expression expected for selection field %s", ft->id);
1870
case '(': c = ')'; break;
1871
case '{': c = '}'; break;
1872
case '[': c = ']'; break;
1873
case '"': /* fall through */
1874
case '\'': c = *s; break;
1878
if (!(s = _tok_value_string(c ? s + 1 : s, begin, end, c, SEL_AND | SEL_OR | SEL_PRECEDENCE_PE, NULL))) {
1879
log_error("Failed to parse regex value for selection field %s.", ft->id);
1883
*flags |= DM_REPORT_FIELD_TYPE_STRING;
1887
static int _str_list_item_cmp(const void *a, const void *b)
1889
const struct dm_str_list **item_a = (const struct dm_str_list **) a;
1890
const struct dm_str_list **item_b = (const struct dm_str_list **) b;
1892
return strcmp((*item_a)->str, (*item_b)->str);
1895
static int _add_item_to_string_list(struct dm_pool *mem, const char *begin,
1896
const char *end, struct dm_list *list)
1898
struct dm_str_list *item;
1903
if (!(item = dm_pool_zalloc(mem, sizeof(*item))) ||
1904
!(item->str = dm_pool_strndup(mem, begin, end - begin))) {
1905
log_error("_add_item_to_string_list: memory allocation failed for string list item");
1908
dm_list_add(list, &item->list);
1915
* ft - field type for which the value is parsed
1916
* mem - memory pool to allocate from
1917
* s - a pointer to the parsed string
1919
* begin - a pointer to the beginning of the token (whole list)
1920
* end - a pointer to the end of the token + 1 (whole list)
1921
* sel_str_list - the list of strings parsed
1923
static const char *_tok_value_string_list(const struct dm_report_field_type *ft,
1924
struct dm_pool *mem, const char *s,
1925
const char **begin, const char **end,
1926
struct selection_str_list **sel_str_list)
1928
static const char _str_list_item_parsing_failed[] = "Failed to parse string list value "
1929
"for selection field %s.";
1930
struct selection_str_list *ssl = NULL;
1931
struct dm_str_list *item;
1932
const char *begin_item, *end_item, *tmp;
1933
uint32_t end_op_flags, end_op_flag_hit = 0;
1934
struct dm_str_list **arr;
1940
if (!(ssl = dm_pool_alloc(mem, sizeof(*ssl))) ||
1941
!(ssl->list = dm_pool_alloc(mem, sizeof(*ssl->list)))) {
1942
log_error("_tok_value_string_list: memory allocation failed for selection list");
1945
dm_list_init(ssl->list);
1949
if (!_tok_op_log(s, &tmp, SEL_LIST_LS)) {
1950
/* Only one item - SEL_LIST_LS and SEL_LIST_LE not used */
1951
c = _get_and_skip_quote_char(&s);
1952
if (!(s = _tok_value_string(s, &begin_item, &end_item, c, SEL_AND | SEL_OR | SEL_PRECEDENCE_PE, NULL))) {
1953
log_error(_str_list_item_parsing_failed, ft->id);
1956
if (!_add_item_to_string_list(mem, begin_item, end_item, ssl->list))
1962
/* More than one item - items enclosed in SEL_LIST_LS and SEL_LIST_LE.
1963
* Each element is terminated by AND or OR operator or 'list end'.
1964
* The first operator hit is then the one allowed for the whole list,
1965
* no mixing allowed!
1967
end_op_flags = SEL_LIST_LE | SEL_AND | SEL_OR;
1971
c = _get_and_skip_quote_char(&s);
1972
if (!(s = _tok_value_string(s, &begin_item, &end_item, c, end_op_flags, NULL))) {
1973
log_error(_str_list_item_parsing_failed, ft->id);
1978
if (!(end_op_flag_hit = _tok_op_log(s, &tmp, end_op_flags))) {
1979
log_error("Invalid operator in selection list.");
1983
list_end = end_op_flag_hit == SEL_LIST_LE;
1986
if (!list_end && !(ssl->type & end_op_flag_hit)) {
1987
log_error("Only one type of logical operator allowed "
1988
"in selection list at a time.");
1992
ssl->type = list_end ? SEL_OR : end_op_flag_hit;
1994
if (!_add_item_to_string_list(mem, begin_item, end_item, ssl->list))
2003
if (end_op_flag_hit != SEL_LIST_LE) {
2004
log_error("Missing list end for selection field %s", ft->id);
2008
/* Sort the list. */
2009
if (!(list_size = dm_list_size(ssl->list))) {
2010
log_error(INTERNAL_ERROR "_tok_value_string_list: list has no items");
2012
} else if (list_size == 1)
2014
if (!(arr = dm_malloc(sizeof(item) * list_size))) {
2015
log_error("_tok_value_string_list: memory allocation failed for sort array");
2020
dm_list_iterate_items(item, ssl->list)
2022
qsort(arr, list_size, sizeof(item), _str_list_item_cmp);
2023
dm_list_init(ssl->list);
2024
for (i = 0; i < list_size; i++)
2025
dm_list_add(ssl->list, &arr[i]->list);
2030
*sel_str_list = ssl;
2035
dm_pool_free(mem, ssl);
2036
*sel_str_list = NULL;
2042
* ft - field type for which the value is parsed
2043
* s - a pointer to the parsed string
2044
* mem - memory pool to allocate from
2046
* begin - a pointer to the beginning of the token
2047
* end - a pointer to the end of the token + 1
2048
* flags - parsing flags
2049
* custom - custom data specific to token type
2050
* (e.g. size unit factor)
2052
static const char *_tok_value(struct dm_report *rh,
2053
const struct dm_report_field_type *ft,
2054
uint32_t field_num, int implicit,
2056
const char **begin, const char **end,
2058
const struct dm_report_reserved_value **reserved,
2059
struct dm_pool *mem, void *custom)
2061
int expected_type = ft->flags & DM_REPORT_FIELD_TYPE_MASK;
2062
struct selection_str_list **str_list;
2069
s = _get_reserved(rh, expected_type, field_num, implicit, s, begin, end, reserved);
2071
*flags |= expected_type;
2075
switch (expected_type) {
2077
case DM_REPORT_FIELD_TYPE_STRING:
2078
c = _get_and_skip_quote_char(&s);
2079
if (!(s = _tok_value_string(s, begin, end, c, SEL_AND | SEL_OR | SEL_PRECEDENCE_PE, NULL))) {
2080
log_error("Failed to parse string value "
2081
"for selection field %s.", ft->id);
2084
*flags |= DM_REPORT_FIELD_TYPE_STRING;
2087
case DM_REPORT_FIELD_TYPE_STRING_LIST:
2088
str_list = (struct selection_str_list **) custom;
2089
s = _tok_value_string_list(ft, mem, s, begin, end, str_list);
2091
log_error("Failed to parse string list value "
2092
"for selection field %s.", ft->id);
2095
*flags |= DM_REPORT_FIELD_TYPE_STRING_LIST;
2098
case DM_REPORT_FIELD_TYPE_NUMBER:
2100
case DM_REPORT_FIELD_TYPE_SIZE:
2102
case DM_REPORT_FIELD_TYPE_PERCENT:
2103
if (!(s = _tok_value_number(s, begin, end))) {
2104
log_error("Failed to parse numeric value "
2105
"for selection field %s.", ft->id);
2109
factor = (uint64_t *) custom;
2111
if (*s == DM_PERCENT_CHAR) {
2113
c = DM_PERCENT_CHAR;
2114
if (expected_type != DM_REPORT_FIELD_TYPE_PERCENT) {
2115
log_error("Found percent value but %s value "
2116
"expected for selection field %s.",
2117
expected_type == DM_REPORT_FIELD_TYPE_NUMBER ?
2118
"numeric" : "size", ft->id);
2121
} else if ((*factor = dm_units_to_factor(s, &c, 0, &tmp))) {
2123
if (expected_type != DM_REPORT_FIELD_TYPE_SIZE) {
2124
log_error("Found size unit specifier "
2125
"but %s value expected for "
2126
"selection field %s.",
2127
expected_type == DM_REPORT_FIELD_TYPE_NUMBER ?
2128
"numeric" : "percent", ft->id);
2131
} else if (expected_type == DM_REPORT_FIELD_TYPE_SIZE) {
2133
* If size unit is not defined in the selection
2134
* and the type expected is size, use use 'm'
2135
* (1 MiB) for the unit by default. This is the
2136
* same behaviour as seen in lvcreate -L <size>.
2138
*factor = 1024*1024;
2141
*flags |= expected_type;
2149
* s - a pointer to the parsed string
2151
* begin - a pointer to the beginning of the token
2152
* end - a pointer to the end of the token + 1
2154
static const char *_tok_field_name(const char *s,
2155
const char **begin, const char **end)
2162
(isalnum(c) || c == '_' || c == '-'))
2172
static const void *_get_reserved_value(const struct dm_report_reserved_value *reserved)
2175
return reserved->value;
2177
return ((const struct dm_report_field_reserved_value *) reserved->value)->value;
2180
static struct field_selection *_create_field_selection(struct dm_report *rh,
2186
const struct dm_report_reserved_value *reserved,
2189
static const char *_out_of_range_msg = "Field selection value %s out of supported range for field %s.";
2190
const struct dm_report_field_type *fields = implicit ? _implicit_report_fields
2192
struct field_properties *fp, *found = NULL;
2193
struct field_selection *fs;
2194
const char *field_id;
2198
dm_list_iterate_items(fp, &rh->field_props) {
2199
if ((fp->implicit == implicit) && (fp->field_num == field_num)) {
2205
/* The field is neither used in display options nor sort keys. */
2207
if (!(found = _add_field(rh, field_num, implicit, FLD_HIDDEN)))
2209
rh->report_types |= fields[field_num].type;
2212
field_id = fields[found->field_num].id;
2214
if (!(found->flags & flags & DM_REPORT_FIELD_TYPE_MASK)) {
2215
log_error("dm_report: incompatible comparison "
2216
"type for selection field %s", field_id);
2220
/* set up selection */
2221
if (!(fs = dm_pool_zalloc(rh->mem, sizeof(struct field_selection)))) {
2222
log_error("dm_report: struct field_selection "
2223
"allocation failed for selection field %s", field_id);
2229
/* store comparison operand */
2230
if (flags & FLD_CMP_REGEX) {
2232
if (!(s = dm_malloc(len + 1))) {
2233
log_error("dm_report: dm_malloc failed to store "
2234
"regex value for selection field %s", field_id);
2240
fs->v.r = dm_regex_create(rh->mem, (const char **) &s, 1);
2243
log_error("dm_report: failed to create regex "
2244
"matcher for selection field %s", field_id);
2248
/* STRING, NUMBER, SIZE or STRING_LIST */
2249
if (!(s = dm_pool_alloc(rh->mem, len + 1))) {
2250
log_error("dm_report: dm_pool_alloc failed to store "
2251
"value for selection field %s", field_id);
2257
switch (flags & DM_REPORT_FIELD_TYPE_MASK) {
2258
case DM_REPORT_FIELD_TYPE_STRING:
2260
fs->v.s = (const char *) _get_reserved_value(reserved);
2261
dm_pool_free(rh->mem, s);
2264
if (_check_value_is_reserved(rh, DM_REPORT_FIELD_TYPE_STRING, fs->v.s)) {
2265
log_error("String value %s found in selection is reserved.", fs->v.s);
2270
case DM_REPORT_FIELD_TYPE_NUMBER:
2272
fs->v.i = *(uint64_t *) _get_reserved_value(reserved);
2274
if (((fs->v.i = strtoull(s, NULL, 10)) == ULLONG_MAX) &&
2275
(errno == ERANGE)) {
2276
log_error(_out_of_range_msg, s, field_id);
2279
if (_check_value_is_reserved(rh, DM_REPORT_FIELD_TYPE_NUMBER, &fs->v.i)) {
2280
log_error("Numeric value %" PRIu64 " found in selection is reserved.", fs->v.i);
2284
dm_pool_free(rh->mem, s);
2286
case DM_REPORT_FIELD_TYPE_SIZE:
2288
fs->v.d = (double) * (uint64_t *) _get_reserved_value(reserved);
2290
fs->v.d = strtod(s, NULL);
2291
if (errno == ERANGE) {
2292
log_error(_out_of_range_msg, s, field_id);
2295
if (custom && (factor = *((uint64_t *)custom)))
2297
fs->v.d /= 512; /* store size in sectors! */
2298
if (_check_value_is_reserved(rh, DM_REPORT_FIELD_TYPE_SIZE, &fs->v.d)) {
2299
log_error("Size value %f found in selection is reserved.", fs->v.d);
2303
dm_pool_free(rh->mem, s);
2305
case DM_REPORT_FIELD_TYPE_PERCENT:
2307
fs->v.i = *(uint64_t *) _get_reserved_value(reserved);
2309
fs->v.d = strtod(s, NULL);
2310
if ((errno == ERANGE) || (fs->v.d < 0) || (fs->v.d > 100)) {
2311
log_error(_out_of_range_msg, s, field_id);
2315
fs->v.i = (dm_percent_t) (DM_PERCENT_1 * fs->v.d);
2317
if (_check_value_is_reserved(rh, DM_REPORT_FIELD_TYPE_PERCENT, &fs->v.i)) {
2318
log_error("Percent value %s found in selection is reserved.", s);
2323
case DM_REPORT_FIELD_TYPE_STRING_LIST:
2324
fs->v.l = *(struct selection_str_list **)custom;
2325
if (_check_value_is_reserved(rh, DM_REPORT_FIELD_TYPE_STRING_LIST, fs->v.l)) {
2326
log_error("String list value found in selection is reserved.");
2331
log_error(INTERNAL_ERROR "_create_field_selection: "
2332
"unknown type of selection field %s", field_id);
2339
dm_pool_free(rh->mem, fs);
2343
static struct selection_node *_alloc_selection_node(struct dm_pool *mem, uint32_t type)
2345
struct selection_node *sn;
2347
if (!(sn = dm_pool_zalloc(mem, sizeof(struct selection_node)))) {
2348
log_error("dm_report: struct selection_node allocation failed");
2352
dm_list_init(&sn->list);
2354
if (!(type & SEL_ITEM))
2355
dm_list_init(&sn->selection.set);
2360
static void _display_selection_help(struct dm_report *rh)
2362
static const char _grow_object_failed_msg[] = "_display_selection_help: dm_pool_grow_object failed";
2364
const struct dm_report_reserved_value *rv;
2365
size_t len_all, len_final = 0;
2369
log_warn("Selection operands");
2370
log_warn("------------------");
2371
log_warn(" field - Reporting field.");
2372
log_warn(" number - Non-negative integer value.");
2373
log_warn(" size - Floating point value with units, 'm' unit used by default if not specified.");
2374
log_warn(" percent - Non-negative integer with or without %% suffix.");
2375
log_warn(" string - Characters quoted by \' or \" or unquoted.");
2376
log_warn(" string list - Strings enclosed by [ ] and elements delimited by either");
2377
log_warn(" \"all items must match\" or \"at least one item must match\" operator.");
2378
log_warn(" regular expression - Characters quoted by \' or \" or unquoted.");
2380
if (rh->reserved_values) {
2381
log_warn("Reserved values");
2382
log_warn("---------------");
2384
for (rv = rh->reserved_values; rv->type; rv++) {
2385
for (len_all = 0, rvs = rv->names; *rvs; rvs++)
2386
len_all += strlen(*rvs) + 2;
2387
if (len_all > len_final)
2388
len_final = len_all;
2391
for (rv = rh->reserved_values; rv->type; rv++) {
2392
if (!dm_pool_begin_object(rh->mem, 256)) {
2393
log_error("_display_selection_help: dm_pool_begin_object failed");
2396
for (rvs = rv->names; *rvs; rvs++) {
2397
if (((rvs != rv->names) && !dm_pool_grow_object(rh->mem, ", ", 2)) ||
2398
!dm_pool_grow_object(rh->mem, *rvs, strlen(*rvs))) {
2399
log_error(_grow_object_failed_msg);
2400
goto out_reserved_values;
2403
if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
2404
log_error(_grow_object_failed_msg);
2405
goto out_reserved_values;
2407
rvs_all = dm_pool_end_object(rh->mem);
2409
log_warn(" %-*s - %s [%s]", (int) len_final, rvs_all, rv->description,
2410
_get_field_type_name(rv->type));
2411
dm_pool_free(rh->mem, rvs_all);
2415
out_reserved_values:
2416
log_warn("Selection operators");
2417
log_warn("-------------------");
2418
log_warn(" Comparison operators:");
2420
for (; t->string; t++)
2421
log_warn(" %4s - %s", t->string, t->desc);
2423
log_warn(" Logical and grouping operators:");
2425
for (; t->string; t++)
2426
log_warn(" %4s - %s", t->string, t->desc);
2430
static const char _sel_syntax_error_at_msg[] = "Selection syntax error at '%s'.";
2431
static const char _sel_help_ref_msg[] = "Use \'help\' for selection to get more help.";
2436
* _parse_* functions
2439
* s - a pointer to the parsed string
2441
* next - a pointer used for next _parse_*'s input,
2442
* next == s if return value is NULL
2443
* return value - a filter node pointer,
2444
* NULL if s doesn't match
2448
* SELECTION := FIELD_NAME OP_CMP STRING |
2449
* FIELD_NAME OP_CMP NUMBER |
2450
* FIELD_NAME OP_REGEX REGEX
2452
static struct selection_node *_parse_selection(struct dm_report *rh,
2456
struct field_selection *fs;
2457
struct selection_node *sn;
2458
const char *ws, *we; /* field name */
2459
const char *vs, *ve; /* value */
2461
uint32_t flags, field_num;
2463
const struct dm_report_field_type *ft;
2464
struct selection_str_list *str_list;
2465
const struct dm_report_reserved_value *reserved;
2467
void *custom = NULL;
2472
if (!(last = _tok_field_name(s, &ws, &we))) {
2473
log_error("Expecting field name");
2477
/* check if the field with given name exists */
2478
if (!_get_field(rh, ws, (size_t) (we - ws), &field_num, &implicit)) {
2482
_display_fields(rh, 0, 1);
2484
log_error("Unrecognised selection field: %s", ws);
2490
ft = &_implicit_report_fields[field_num];
2491
if (ft->flags & FLD_CMP_UNCOMPARABLE) {
2495
_display_fields(rh, 0, 1);
2497
log_error("Selection field is uncomparable: %s.", ws);
2502
ft = &rh->fields[field_num];
2504
/* comparison operator */
2505
if (!(flags = _tok_op_cmp(we, &last))) {
2506
_display_selection_help(rh);
2507
log_error("Unrecognised comparison operator: %s", we);
2511
_display_selection_help(rh);
2512
log_error("Missing value after operator");
2516
/* some operators can compare only numeric fields (NUMBER, SIZE or PERCENT) */
2517
if ((flags & FLD_CMP_NUMBER) &&
2518
(ft->flags != DM_REPORT_FIELD_TYPE_NUMBER) &&
2519
(ft->flags != DM_REPORT_FIELD_TYPE_SIZE) &&
2520
(ft->flags != DM_REPORT_FIELD_TYPE_PERCENT)) {
2521
_display_selection_help(rh);
2522
log_error("Operator can be used only with number, size or percent fields: %s", ws);
2526
/* comparison value */
2527
if (flags & FLD_CMP_REGEX) {
2528
if (!(last = _tok_value_regex(rh, ft, last, &vs, &ve, &flags, &reserved)))
2531
if (ft->flags == DM_REPORT_FIELD_TYPE_SIZE ||
2532
ft->flags == DM_REPORT_FIELD_TYPE_NUMBER ||
2533
ft->flags == DM_REPORT_FIELD_TYPE_PERCENT)
2535
else if (ft->flags == DM_REPORT_FIELD_TYPE_STRING_LIST)
2539
if (!(last = _tok_value(rh, ft, field_num, implicit,
2540
last, &vs, &ve, &flags,
2541
&reserved, rh->mem, custom)))
2545
*next = _skip_space(last);
2547
/* create selection */
2548
if (!(fs = _create_field_selection(rh, field_num, implicit, vs, (size_t) (ve - vs), flags, reserved, custom)))
2551
/* create selection node */
2552
if (!(sn = _alloc_selection_node(rh->mem, SEL_ITEM)))
2555
/* add selection to selection node */
2556
sn->selection.item = fs;
2560
log_error(_sel_syntax_error_at_msg, s);
2561
log_error(_sel_help_ref_msg);
2566
static struct selection_node *_parse_or_ex(struct dm_report *rh,
2569
struct selection_node *or_sn);
2571
static struct selection_node *_parse_ex(struct dm_report *rh,
2575
static const char _ps_expected_msg[] = "Syntax error: left parenthesis expected at \'%s\'";
2576
static const char _pe_expected_msg[] = "Syntax error: right parenthesis expected at \'%s\'";
2577
struct selection_node *sn = NULL;
2581
t = _tok_op_log(s, next, SEL_MODIFIER_NOT | SEL_PRECEDENCE_PS);
2582
if (t == SEL_MODIFIER_NOT) {
2583
/* '!' '(' EXPRESSION ')' */
2584
if (!_tok_op_log(*next, &tmp, SEL_PRECEDENCE_PS)) {
2585
log_error(_ps_expected_msg, *next);
2588
if (!(sn = _parse_or_ex(rh, tmp, next, NULL)))
2590
sn->type |= SEL_MODIFIER_NOT;
2591
if (!_tok_op_log(*next, &tmp, SEL_PRECEDENCE_PE)) {
2592
log_error(_pe_expected_msg, *next);
2596
} else if (t == SEL_PRECEDENCE_PS) {
2597
/* '(' EXPRESSION ')' */
2598
if (!(sn = _parse_or_ex(rh, *next, &tmp, NULL)))
2600
if (!_tok_op_log(tmp, next, SEL_PRECEDENCE_PE)) {
2601
log_error(_pe_expected_msg, *next);
2604
} else if ((s = _skip_space(s))) {
2606
sn = _parse_selection(rh, s, next);
2618
/* AND_EXPRESSION := EX (AND_OP AND_EXPRSSION) */
2619
static struct selection_node *_parse_and_ex(struct dm_report *rh,
2622
struct selection_node *and_sn)
2624
struct selection_node *n;
2627
n = _parse_ex(rh, s, next);
2631
if (!_tok_op_log(*next, &tmp, SEL_AND)) {
2634
dm_list_add(&and_sn->selection.set, &n->list);
2639
if (!(and_sn = _alloc_selection_node(rh->mem, SEL_AND)))
2642
dm_list_add(&and_sn->selection.set, &n->list);
2644
return _parse_and_ex(rh, tmp, next, and_sn);
2650
/* OR_EXPRESSION := AND_EXPRESSION (OR_OP OR_EXPRESSION) */
2651
static struct selection_node *_parse_or_ex(struct dm_report *rh,
2654
struct selection_node *or_sn)
2656
struct selection_node *n;
2659
n = _parse_and_ex(rh, s, next, NULL);
2663
if (!_tok_op_log(*next, &tmp, SEL_OR)) {
2666
dm_list_add(&or_sn->selection.set, &n->list);
2671
if (!(or_sn = _alloc_selection_node(rh->mem, SEL_OR)))
2674
dm_list_add(&or_sn->selection.set, &n->list);
2676
return _parse_or_ex(rh, tmp, next, or_sn);
2682
struct dm_report *dm_report_init_with_selection(uint32_t *report_types,
2683
const struct dm_report_object_type *types,
2684
const struct dm_report_field_type *fields,
2685
const char *output_fields,
2686
const char *output_separator,
2687
uint32_t output_flags,
2688
const char *sort_keys,
2689
const char *selection,
2690
const struct dm_report_reserved_value reserved_values[],
2693
struct dm_report *rh;
2694
struct selection_node *root = NULL;
2695
const char *fin, *next;
2697
_implicit_report_fields = _implicit_special_report_fields_with_selection;
2699
if (!(rh = dm_report_init(report_types, types, fields, output_fields,
2700
output_separator, output_flags, sort_keys, private_data)))
2703
if (!selection || !selection[0]) {
2704
rh->selection_root = NULL;
2708
if (!_check_reserved_values_supported(reserved_values)) {
2709
log_error(INTERNAL_ERROR "dm_report_init_with_selection: "
2710
"trying to register unsupported reserved value type, "
2711
"skipping report selection");
2714
rh->reserved_values = reserved_values;
2716
if (!strcasecmp(selection, SPECIAL_FIELD_HELP_ID) ||
2717
!strcmp(selection, SPECIAL_FIELD_HELP_ALT_ID)) {
2718
_display_fields(rh, 0, 1);
2720
_display_selection_help(rh);
2721
rh->flags |= RH_ALREADY_REPORTED;
2725
if (!(root = _alloc_selection_node(rh->mem, SEL_OR)))
2728
if (!_parse_or_ex(rh, selection, &fin, root))
2731
next = _skip_space(fin);
2733
log_error("Expecting logical operator");
2734
log_error(_sel_syntax_error_at_msg, next);
2735
log_error(_sel_help_ref_msg);
2739
_dm_report_init_update_types(rh, report_types);
2741
rh->selection_root = root;