~ubuntu-branches/debian/sid/lvm2/sid

« back to all changes in this revision

Viewing changes to libdm/libdm-report.c

  • Committer: Package Import Robot
  • Author(s): Bastian Blank
  • Date: 2014-08-19 15:37:06 UTC
  • mfrom: (1.1.18)
  • Revision ID: package-import@ubuntu.com-20140819153706-i1gaio8lg534dara
Tags: 2.02.109-1
New upstream version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
#include "dmlib.h"
17
17
 
18
18
#include <ctype.h>
 
19
#include <math.h>  /* fabs() */
 
20
#include <float.h> /* DBL_EPSILON */
19
21
 
20
22
/*
21
23
 * Internal flags
22
24
 */
23
25
#define RH_SORT_REQUIRED        0x00000100
24
26
#define RH_HEADINGS_PRINTED     0x00000200
 
27
#define RH_ALREADY_REPORTED     0x00000400
25
28
 
26
29
struct dm_report {
27
30
        struct dm_pool *mem;
48
51
 
49
52
        /* To store caller private data */
50
53
        void *private;
 
54
 
 
55
        struct selection_node *selection_root;
 
56
        /* Null-terminated array of reserved values */
 
57
        const struct dm_report_reserved_value *reserved_values;
51
58
};
52
59
 
53
60
/*
54
61
 * Internal per-field flags
55
62
 */
56
 
#define FLD_HIDDEN      0x00000100
57
 
#define FLD_SORT_KEY    0x00000200
58
 
#define FLD_ASCENDING   0x00000400
59
 
#define FLD_DESCENDING  0x00000800
 
63
#define FLD_HIDDEN      0x00001000
 
64
#define FLD_SORT_KEY    0x00002000
 
65
#define FLD_ASCENDING   0x00004000
 
66
#define FLD_DESCENDING  0x00008000
60
67
 
61
68
struct field_properties {
62
69
        struct dm_list list;
65
72
        int32_t width;
66
73
        const struct dm_report_object_type *type;
67
74
        uint32_t flags;
 
75
        int implicit;
 
76
};
 
77
 
 
78
/*
 
79
 * Report selection
 
80
 */
 
81
struct op_def {
 
82
        const char *string;
 
83
        uint32_t flags;
 
84
        const char *desc;
 
85
};
 
86
 
 
87
#define FLD_CMP_MASK            0x00FF0000
 
88
#define FLD_CMP_UNCOMPARABLE    0x00010000
 
89
#define FLD_CMP_EQUAL           0x00020000
 
90
#define FLD_CMP_NOT             0x00040000
 
91
#define FLD_CMP_GT              0x00080000
 
92
#define FLD_CMP_LT              0x00100000
 
93
#define FLD_CMP_REGEX           0x00200000
 
94
#define FLD_CMP_NUMBER          0x00400000
 
95
/*
 
96
 * #define FLD_CMP_STRING 0x00400000
 
97
 * We could defined FLD_CMP_STRING here for completeness here,
 
98
 * but it's not needed - we can check operator compatibility with
 
99
 * field type by using FLD_CMP_REGEX and FLD_CMP_NUMBER flags only.
 
100
 */
 
101
 
 
102
/*
 
103
 * When defining operators, always define longer one before
 
104
 * shorter one if one is a prefix of another!
 
105
 * (e.g. =~ comes before =)
 
106
*/
 
107
static struct op_def _op_cmp[] = {
 
108
        { "=~", FLD_CMP_REGEX, "Matching regular expression. [regex]" },
 
109
        { "!~", FLD_CMP_REGEX|FLD_CMP_NOT, "Not matching regular expression. [regex]" },
 
110
        { "=", FLD_CMP_EQUAL, "Equal to. [number, size, percent, string, string list]" },
 
111
        { "!=", FLD_CMP_NOT|FLD_CMP_EQUAL, "Not equal to. [number, size, percent, string, string_list]" },
 
112
        { ">=", FLD_CMP_NUMBER|FLD_CMP_GT|FLD_CMP_EQUAL, "Greater than or equal to. [number, size, percent]" },
 
113
        { ">", FLD_CMP_NUMBER|FLD_CMP_GT, "Greater than. [number, size, percent]" },
 
114
        { "<=", FLD_CMP_NUMBER|FLD_CMP_LT|FLD_CMP_EQUAL, "Less than or equal to. [number, size, percent]" },
 
115
        { "<", FLD_CMP_NUMBER|FLD_CMP_LT, "Less than. [number, size, percent]" },
 
116
        { NULL, 0, NULL }
 
117
};
 
118
 
 
119
#define SEL_MASK                0x000000FF
 
120
#define SEL_ITEM                0x00000001
 
121
#define SEL_AND                 0x00000002
 
122
#define SEL_OR                  0x00000004
 
123
 
 
124
#define SEL_MODIFIER_MASK       0x00000F00
 
125
#define SEL_MODIFIER_NOT        0x00000100
 
126
 
 
127
#define SEL_PRECEDENCE_MASK     0x0000F000
 
128
#define SEL_PRECEDENCE_PS       0x00001000
 
129
#define SEL_PRECEDENCE_PE       0x00002000
 
130
 
 
131
#define SEL_LIST_MASK           0x000F0000
 
132
#define SEL_LIST_LS             0x00010000
 
133
#define SEL_LIST_LE             0x00020000
 
134
 
 
135
static struct op_def _op_log[] = {
 
136
        { "&&", SEL_AND, "All fields must match" },
 
137
        { ",", SEL_AND, "All fields must match" },
 
138
        { "||", SEL_OR, "At least one field must match" },
 
139
        { "#", SEL_OR, "At least one field must match" },
 
140
        { "!", SEL_MODIFIER_NOT, "Logical negation" },
 
141
        { "(", SEL_PRECEDENCE_PS, "Left parenthesis" },
 
142
        { ")", SEL_PRECEDENCE_PE, "Right parenthesis" },
 
143
        { "[", SEL_LIST_LS, "List start" },
 
144
        { "]", SEL_LIST_LE, "List end"},
 
145
        { NULL,  0, NULL},
 
146
};
 
147
 
 
148
struct selection_str_list {
 
149
        unsigned type;                  /* either SEL_AND or SEL_OR */
 
150
        struct dm_list *list;
 
151
};
 
152
 
 
153
struct field_selection {
 
154
        struct field_properties *fp;
 
155
        uint32_t flags;
 
156
        union {
 
157
                const char *s;
 
158
                uint64_t i;
 
159
                double d;
 
160
                struct dm_regex *r;
 
161
                struct selection_str_list *l;
 
162
        } v;
 
163
};
 
164
 
 
165
struct selection_node {
 
166
        struct dm_list list;
 
167
        uint32_t type;
 
168
        union {
 
169
                struct field_selection *item;
 
170
                struct dm_list set;
 
171
        } selection;
68
172
};
69
173
 
70
174
/*
83
187
        struct dm_report *rh;
84
188
        struct dm_list fields;                    /* Fields in display order */
85
189
        struct dm_report_field *(*sort_fields)[]; /* Fields in sort order */
86
 
};
 
190
        int selected;
 
191
};
 
192
 
 
193
/*
 
194
 * Implicit report types and fields.
 
195
 */
 
196
#define SPECIAL_REPORT_TYPE 0x80000000
 
197
#define SPECIAL_FIELD_SELECTED_ID "selected"
 
198
#define SPECIAL_FIELD_HELP_ID "help"
 
199
#define SPECIAL_FIELD_HELP_ALT_ID "?"
 
200
 
 
201
static void *_null_returning_fn(void *obj __attribute__((unused)))
 
202
{
 
203
        return NULL;
 
204
}
 
205
 
 
206
static int _no_report_fn(struct dm_report *rh __attribute__((unused)),
 
207
                         struct dm_pool *mem __attribute__((unused)),
 
208
                         struct dm_report_field *field __attribute__((unused)),
 
209
                         const void *data __attribute__((unused)),
 
210
                         void *private __attribute__((unused)))
 
211
{
 
212
        return 1;
 
213
}
 
214
 
 
215
static int _selected_disp(struct dm_report *rh,
 
216
                          struct dm_pool *mem __attribute__((unused)),
 
217
                          struct dm_report_field *field,
 
218
                          const void *data,
 
219
                          void *private __attribute__((unused)))
 
220
{
 
221
        struct row *row = (struct row *)data;
 
222
        return dm_report_field_int(rh, field, &row->selected);
 
223
}
 
224
 
 
225
static const struct dm_report_object_type _implicit_special_report_types[] = {
 
226
        { SPECIAL_REPORT_TYPE, "Special", "special_", _null_returning_fn },
 
227
        { 0, "", "", NULL }
 
228
};
 
229
 
 
230
static const struct dm_report_field_type _implicit_special_report_fields[] = {
 
231
        { SPECIAL_REPORT_TYPE, DM_REPORT_FIELD_TYPE_NUMBER | FLD_CMP_UNCOMPARABLE , 0, 8, SPECIAL_FIELD_HELP_ID, "Help", _no_report_fn, "Show help." },
 
232
        { SPECIAL_REPORT_TYPE, DM_REPORT_FIELD_TYPE_NUMBER | FLD_CMP_UNCOMPARABLE , 0, 8, SPECIAL_FIELD_HELP_ALT_ID, "Help", _no_report_fn, "Show help." },
 
233
        { 0, 0, 0, 0, "", "", 0, 0}
 
234
};
 
235
 
 
236
static const struct dm_report_field_type _implicit_special_report_fields_with_selection[] = {
 
237
        { SPECIAL_REPORT_TYPE, DM_REPORT_FIELD_TYPE_NUMBER, 0, 8, SPECIAL_FIELD_SELECTED_ID, "Selected", _selected_disp, "Set if item passes selection criteria." },
 
238
        { SPECIAL_REPORT_TYPE, DM_REPORT_FIELD_TYPE_NUMBER | FLD_CMP_UNCOMPARABLE , 0, 8, SPECIAL_FIELD_HELP_ID, "Help", _no_report_fn, "Show help." },
 
239
        { SPECIAL_REPORT_TYPE, DM_REPORT_FIELD_TYPE_NUMBER | FLD_CMP_UNCOMPARABLE , 0, 8, SPECIAL_FIELD_HELP_ALT_ID, "Help", _no_report_fn, "Show help." },
 
240
        { 0, 0, 0, 0, "", "", 0, 0}
 
241
};
 
242
 
 
243
static const struct dm_report_object_type *_implicit_report_types = _implicit_special_report_types;
 
244
static const struct dm_report_field_type *_implicit_report_fields = _implicit_special_report_fields;
87
245
 
88
246
static const struct dm_report_object_type *_find_type(struct dm_report *rh,
89
247
                                                      uint32_t report_type)
90
248
{
91
249
        const struct dm_report_object_type *t;
92
250
 
 
251
        for (t = _implicit_report_types; t->data_fn; t++)
 
252
                if (t->id == report_type)
 
253
                        return t;
 
254
 
93
255
        for (t = rh->types; t->data_fn; t++)
94
256
                if (t->id == report_type)
95
257
                        return t;
117
279
        return 1;
118
280
}
119
281
 
 
282
static int _str_cmp(const void *a, const void *b)
 
283
{
 
284
        const char **str_a = (const char **) a;
 
285
        const char **str_b = (const char **) b;
 
286
 
 
287
        return strcmp(*str_a, *str_b);
 
288
}
 
289
 
 
290
struct str_list_sort_value_item {
 
291
        unsigned pos;
 
292
        size_t len;
 
293
};
 
294
 
 
295
struct str_list_sort_value {
 
296
        const char *value;
 
297
        struct str_list_sort_value_item *items;
 
298
};
 
299
 
 
300
int dm_report_field_percent(struct dm_report *rh,
 
301
                            struct dm_report_field *field,
 
302
                            const dm_percent_t *data)
 
303
{
 
304
        char *repstr;
 
305
        uint64_t *sortval;
 
306
 
 
307
        if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
 
308
                log_error("dm_report_field_percent: dm_pool_alloc failed for sort_value.");
 
309
                return 0;
 
310
        }
 
311
 
 
312
        *sortval = (uint64_t)(*data);
 
313
 
 
314
        if (*data == DM_PERCENT_INVALID) {
 
315
                dm_report_field_set_value(field, "", sortval);
 
316
                return 1;
 
317
        }
 
318
 
 
319
        if (!(repstr = dm_pool_alloc(rh->mem, 8))) {
 
320
                dm_pool_free(rh->mem, sortval);
 
321
                log_error("dm_report_field_percent: dm_pool_alloc failed for percent report string.");
 
322
                return 0;
 
323
        }
 
324
 
 
325
        if (dm_snprintf(repstr, 7, "%.2f", dm_percent_to_float(*data)) < 0) {
 
326
                dm_pool_free(rh->mem, sortval);
 
327
                log_error("dm_report_field_percent: percentage too large.");
 
328
                return 0;
 
329
        }
 
330
 
 
331
        dm_report_field_set_value(field, repstr, sortval);
 
332
        return 1;
 
333
}
 
334
 
 
335
int dm_report_field_string_list(struct dm_report *rh,
 
336
                                struct dm_report_field *field,
 
337
                                const struct dm_list *data,
 
338
                                const char *delimiter)
 
339
{
 
340
        static const char _string_list_grow_object_failed_msg[] = "dm_report_field_string_list: dm_pool_grow_object_failed";
 
341
        struct str_list_sort_value *sort_value = NULL;
 
342
        unsigned int list_size, pos, i;
 
343
        const char **arr = NULL;
 
344
        struct dm_str_list *sl;
 
345
        size_t delimiter_len, len;
 
346
        void *object;
 
347
        int r = 0;
 
348
 
 
349
        if (!(sort_value = dm_pool_zalloc(rh->mem, sizeof(struct str_list_sort_value)))) {
 
350
                log_error("dm_report_field_string_list: dm_pool_zalloc failed for sort_value");
 
351
                return 0;
 
352
        }
 
353
 
 
354
        list_size = dm_list_size(data);
 
355
 
 
356
        /*
 
357
         * Sort value stores the pointer to the report_string and then
 
358
         * position and length for each list element withing the report_string.
 
359
         * The first element stores number of elements in 'len' (therefore
 
360
         * list_size + 1 is used below for the extra element).
 
361
         */
 
362
        if (!(sort_value->items = dm_pool_zalloc(rh->mem, (list_size + 1) * sizeof(struct str_list_sort_value_item)))) {
 
363
                log_error("dm_report_fiel_string_list: dm_pool_zalloc failed for sort value items");
 
364
                goto out;
 
365
        }
 
366
        sort_value->items[0].len = list_size;
 
367
 
 
368
        /* zero items */
 
369
        if (!list_size) {
 
370
                sort_value->value = field->report_string = "";
 
371
                sort_value->items[1].pos = 0;
 
372
                sort_value->items[1].len = 0;
 
373
                field->sort_value = sort_value;
 
374
                return 1;
 
375
        }
 
376
 
 
377
        /* one item */
 
378
        if (list_size == 1) {
 
379
                sl = (struct dm_str_list *) dm_list_first(data);
 
380
                if (!(sort_value->value = field->report_string = dm_pool_strdup(rh->mem, sl->str))) {
 
381
                        log_error("dm_report_field_string_list: dm_pool_strdup failed");
 
382
                        goto out;
 
383
                }
 
384
                sort_value->items[1].pos = 0;
 
385
                sort_value->items[1].len = strlen(sl->str);
 
386
                field->sort_value = sort_value;
 
387
                return 1;
 
388
        }
 
389
 
 
390
        /* more than one item - sort the list */
 
391
        if (!(arr = dm_malloc(sizeof(char *) * list_size))) {
 
392
                log_error("dm_report_field_string_list: dm_malloc failed");
 
393
                goto out;
 
394
        }
 
395
        i = 0;
 
396
        dm_list_iterate_items(sl, data)
 
397
                arr[i++] = sl->str;
 
398
        qsort(arr, i, sizeof(char *), _str_cmp);
 
399
 
 
400
        if (!(dm_pool_begin_object(rh->mem, 256))) {
 
401
                log_error(_string_list_grow_object_failed_msg);
 
402
                goto out;
 
403
        }
 
404
 
 
405
        if (!delimiter)
 
406
                delimiter = ",";
 
407
        delimiter_len = strlen(delimiter);
 
408
 
 
409
        /* start from 1 - the item 0 stores the list size! */
 
410
        for (i = 1, pos = 0; i <= list_size; i++) {
 
411
                len = strlen(arr[i-1]);
 
412
                if (!dm_pool_grow_object(rh->mem, arr[i-1], len) ||
 
413
                    (i != list_size && !dm_pool_grow_object(rh->mem, delimiter, delimiter_len))) {
 
414
                        log_error(_string_list_grow_object_failed_msg);
 
415
                        goto out;
 
416
                }
 
417
                /*
 
418
                 * save position and length of the string
 
419
                 * element in report_string for sort_value
 
420
                 */
 
421
                sort_value->items[i].pos = pos;
 
422
                sort_value->items[i].len = len;
 
423
                pos = i == list_size ? pos+len : pos+len+delimiter_len;
 
424
        }
 
425
 
 
426
        if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
 
427
                log_error(_string_list_grow_object_failed_msg);
 
428
                goto out;
 
429
        }
 
430
 
 
431
        object = dm_pool_end_object(rh->mem);
 
432
        sort_value->value = object;
 
433
        field->sort_value = sort_value;
 
434
        field->report_string = object;
 
435
        r = 1;
 
436
out:
 
437
        if (!r && sort_value)
 
438
                dm_pool_free(rh->mem, sort_value);
 
439
        if (arr)
 
440
                dm_free(arr);
 
441
        return r;
 
442
}
 
443
 
120
444
int dm_report_field_int(struct dm_report *rh,
121
445
                        struct dm_report_field *field, const int *data)
122
446
{
246
570
                log_warn(INTERNAL_ERROR "Using string as sort value for numerical field.");
247
571
}
248
572
 
 
573
static const char *_get_field_type_name(unsigned field_type)
 
574
{
 
575
        switch (field_type) {
 
576
                case DM_REPORT_FIELD_TYPE_STRING: return "string";
 
577
                case DM_REPORT_FIELD_TYPE_NUMBER: return "number";
 
578
                case DM_REPORT_FIELD_TYPE_SIZE: return "size";
 
579
                case DM_REPORT_FIELD_TYPE_PERCENT: return "percent";
 
580
                case DM_REPORT_FIELD_TYPE_STRING_LIST: return "string list";
 
581
                default: return "unknown";
 
582
        }
 
583
}
 
584
 
249
585
/*
250
586
 * show help message
251
587
 */
252
 
static void _display_fields(struct dm_report *rh)
 
588
static size_t _get_longest_field_id_len(const struct dm_report_field_type *fields)
 
589
{
 
590
        uint32_t f;
 
591
        size_t id_len = 0;
 
592
 
 
593
        for (f = 0; fields[f].report_fn; f++)
 
594
                if (strlen(fields[f].id) > id_len)
 
595
                        id_len = strlen(fields[f].id);
 
596
 
 
597
        return id_len;
 
598
}
 
599
 
 
600
static void _display_fields_more(struct dm_report *rh,
 
601
                                 const struct dm_report_field_type *fields,
 
602
                                 size_t id_len, int display_all_fields_item,
 
603
                                 int display_field_types)
253
604
{
254
605
        uint32_t f;
255
606
        const struct dm_report_object_type *type;
256
607
        const char *desc, *last_desc = "";
257
 
        size_t id_len = 0;
258
 
 
259
 
        for (f = 0; rh->fields[f].report_fn; f++)
260
 
                if (strlen(rh->fields[f].id) > id_len)
261
 
                        id_len = strlen(rh->fields[f].id);
262
 
 
 
608
 
 
609
        for (f = 0; fields[f].report_fn; f++)
 
610
                if (strlen(fields[f].id) > id_len)
 
611
                        id_len = strlen(fields[f].id);
263
612
 
264
613
        for (type = rh->types; type->data_fn; type++)
265
614
                if (strlen(type->prefix) + 3 > id_len)
266
615
                        id_len = strlen(type->prefix) + 3;
267
616
 
268
 
        for (f = 0; rh->fields[f].report_fn; f++) {
269
 
                if ((type = _find_type(rh, rh->fields[f].type)) && type->desc)
 
617
        for (f = 0; fields[f].report_fn; f++) {
 
618
                if ((type = _find_type(rh, fields[f].type)) && type->desc)
270
619
                        desc = type->desc;
271
620
                else
272
621
                        desc = " ";
277
626
                        log_warn("%*.*s", (int) strlen(desc) + 7,
278
627
                                 (int) strlen(desc) + 7,
279
628
                                 "-------------------------------------------------------------------------------");
280
 
                        log_warn("  %sall%-*s - %s", type->prefix,
281
 
                                 (int) (id_len - 3 - strlen(type->prefix)), "",
282
 
                                 "All fields in this section.");
 
629
                        if (display_all_fields_item && type->id != SPECIAL_REPORT_TYPE)
 
630
                                log_warn("  %sall%-*s - %s", type->prefix,
 
631
                                         (int) (id_len - 3 - strlen(type->prefix)), "",
 
632
                                         "All fields in this section.");
283
633
                }
284
 
 
285
634
                /* FIXME Add line-wrapping at terminal width (or 80 cols) */
286
 
                log_warn("  %-*s - %s", (int) id_len, rh->fields[f].id, rh->fields[f].desc);
 
635
                log_warn("  %-*s - %s%s%s%s%s", (int) id_len, fields[f].id, fields[f].desc,
 
636
                                              display_field_types ? " [" : "",
 
637
                                              display_field_types ? fields[f].flags & FLD_CMP_UNCOMPARABLE ? "unselectable " : "" : "",
 
638
                                              display_field_types ? _get_field_type_name(fields[f].flags & DM_REPORT_FIELD_TYPE_MASK) : "",
 
639
                                              display_field_types ? "]" : "");
287
640
                last_desc = desc;
288
641
        }
289
642
}
290
643
 
291
644
/*
 
645
 * show help message
 
646
 */
 
647
static void _display_fields(struct dm_report *rh, int display_all_fields_item,
 
648
                            int display_field_types)
 
649
{
 
650
        size_t tmp, id_len = 0;
 
651
 
 
652
        if ((tmp = _get_longest_field_id_len(_implicit_report_fields)) > id_len)
 
653
                id_len = tmp;
 
654
        if ((tmp = _get_longest_field_id_len(rh->fields)) > id_len)
 
655
                id_len = tmp;
 
656
 
 
657
        _display_fields_more(rh, rh->fields, id_len, display_all_fields_item,
 
658
                             display_field_types);
 
659
        log_warn(" ");
 
660
        _display_fields_more(rh, _implicit_report_fields, id_len,
 
661
                             display_all_fields_item, display_field_types);
 
662
 
 
663
}
 
664
 
 
665
/*
292
666
 * Initialise report handle
293
667
 */
294
668
static int _copy_field(struct dm_report *rh, struct field_properties *dest,
295
 
                       uint32_t field_num)
 
669
                       uint32_t field_num, int implicit)
296
670
{
 
671
        const struct dm_report_field_type *fields = implicit ? _implicit_report_fields
 
672
                                                             : rh->fields;
 
673
 
297
674
        dest->field_num = field_num;
298
 
        dest->width = rh->fields[field_num].width;
299
 
        dest->flags = rh->fields[field_num].flags & DM_REPORT_FIELD_MASK;
 
675
        dest->width = fields[field_num].width;
 
676
        dest->flags = fields[field_num].flags & DM_REPORT_FIELD_MASK;
 
677
        dest->implicit = implicit;
300
678
 
301
679
        /* set object type method */
302
 
        dest->type = _find_type(rh, rh->fields[field_num].type);
 
680
        dest->type = _find_type(rh, fields[field_num].type);
303
681
        if (!dest->type) {
304
682
                log_error("dm_report: field not match: %s",
305
 
                          rh->fields[field_num].id);
 
683
                          fields[field_num].id);
306
684
                return 0;
307
685
        }
308
686
 
310
688
}
311
689
 
312
690
static struct field_properties * _add_field(struct dm_report *rh,
313
 
                                            uint32_t field_num, uint32_t flags)
 
691
                                            uint32_t field_num, int implicit,
 
692
                                            uint32_t flags)
314
693
{
315
694
        struct field_properties *fp;
316
695
 
320
699
                return NULL;
321
700
        }
322
701
 
323
 
        if (!_copy_field(rh, fp, field_num)) {
 
702
        if (!_copy_field(rh, fp, field_num, implicit)) {
324
703
                stack;
325
704
                dm_pool_free(rh->mem, fp);
326
705
                return NULL;
367
746
/*
368
747
 * Check for a report type prefix + "all" match.
369
748
 */
 
749
static void _all_match_combine(const struct dm_report_object_type *types,
 
750
                               unsigned unprefixed_all_matched,
 
751
                               const char *field, size_t flen,
 
752
                               uint32_t *report_types)
 
753
{
 
754
        const struct dm_report_object_type *t;
 
755
        size_t prefix_len;
 
756
 
 
757
        for (t = types; t->data_fn; t++) {
 
758
                prefix_len = strlen(t->prefix);
 
759
 
 
760
                if (!strncasecmp(t->prefix, field, prefix_len) &&
 
761
                    ((unprefixed_all_matched && (flen == prefix_len)) ||
 
762
                     (!strncasecmp(field + prefix_len, "all", 3) &&
 
763
                      (flen == prefix_len + 3))))
 
764
                        *report_types |= t->id;
 
765
        }
 
766
}
 
767
 
370
768
static uint32_t _all_match(struct dm_report *rh, const char *field, size_t flen)
371
769
{
372
 
        size_t prefix_len;
373
 
        const struct dm_report_object_type *t;
374
770
        uint32_t report_types = 0;
375
771
        unsigned unprefixed_all_matched = 0;
376
772
 
386
782
        }
387
783
 
388
784
        /* Combine all report types that have a matching prefix. */
389
 
        for (t = rh->types; t->data_fn; t++) {
390
 
                prefix_len = strlen(t->prefix);
391
 
 
392
 
                if (!strncasecmp(t->prefix, field, prefix_len) &&
393
 
                    ((unprefixed_all_matched && (flen == prefix_len)) ||
394
 
                     (!strncasecmp(field + prefix_len, "all", 3) &&
395
 
                      (flen == prefix_len + 3))))
396
 
                        report_types |= t->id;
397
 
        }
 
785
        _all_match_combine(rh->types, unprefixed_all_matched, field, flen, &report_types);
398
786
 
399
787
        return report_types;
400
788
}
407
795
        uint32_t f;
408
796
 
409
797
        for (f = 0; rh->fields[f].report_fn; f++)
410
 
                if ((rh->fields[f].type & type) && !_add_field(rh, f, 0))
 
798
                if ((rh->fields[f].type & type) && !_add_field(rh, f, 0, 0))
411
799
                        return 0;
412
800
 
413
801
        return 1;
414
802
}
415
803
 
 
804
static int _get_field(struct dm_report *rh, const char *field, size_t flen,
 
805
                      uint32_t *f_ret, int *implicit)
 
806
{
 
807
        uint32_t f;
 
808
 
 
809
        if (!flen)
 
810
                return 0;
 
811
 
 
812
        for (f = 0; _implicit_report_fields[f].report_fn; f++) {
 
813
                if (_is_same_field(_implicit_report_fields[f].id, field, flen, rh->field_prefix)) {
 
814
                        *f_ret = f;
 
815
                        *implicit = 1;
 
816
                        return 1;
 
817
                }
 
818
        }
 
819
 
 
820
        for (f = 0; rh->fields[f].report_fn; f++) {
 
821
                if (_is_same_field(rh->fields[f].id, field, flen, rh->field_prefix)) {
 
822
                        *f_ret = f;
 
823
                        *implicit = 0;
 
824
                        return 1;
 
825
                }
 
826
        }
 
827
 
 
828
        return 0;
 
829
}
 
830
 
416
831
static int _field_match(struct dm_report *rh, const char *field, size_t flen,
417
832
                        unsigned report_type_only)
418
833
{
419
834
        uint32_t f, type;
 
835
        int implicit;
420
836
 
421
837
        if (!flen)
422
838
                return 0;
423
839
 
424
 
        for (f = 0; rh->fields[f].report_fn; f++)
425
 
                if (_is_same_field(rh->fields[f].id, field, flen,
426
 
                                   rh->field_prefix)) {
427
 
                        if (report_type_only) {
428
 
                                rh->report_types |= rh->fields[f].type;
429
 
                                return 1;
430
 
                        } else
431
 
                                return _add_field(rh, f, 0) ? 1 : 0;
432
 
                }
 
840
        if ((_get_field(rh, field, flen, &f, &implicit))) {
 
841
                if (report_type_only) {
 
842
                        rh->report_types |= implicit ? _implicit_report_fields[f].type
 
843
                                                     : rh->fields[f].type;
 
844
                        return 1;
 
845
                } else
 
846
                        return _add_field(rh, f, implicit, 0) ? 1 : 0;
 
847
        }
433
848
 
434
849
        if ((type = _all_match(rh, field, flen))) {
435
850
                if (report_type_only) {
442
857
        return 0;
443
858
}
444
859
 
445
 
static int _add_sort_key(struct dm_report *rh, uint32_t field_num,
 
860
static int _add_sort_key(struct dm_report *rh, uint32_t field_num, int implicit,
446
861
                         uint32_t flags, unsigned report_type_only)
447
862
{
448
863
        struct field_properties *fp, *found = NULL;
 
864
        const struct dm_report_field_type *fields = implicit ? _implicit_report_fields
 
865
                                                             : rh->fields;
449
866
 
450
867
        dm_list_iterate_items(fp, &rh->field_props) {
451
 
                if (fp->field_num == field_num) {
 
868
                if ((fp->implicit == implicit) && (fp->field_num == field_num)) {
452
869
                        found = fp;
453
870
                        break;
454
871
                }
456
873
 
457
874
        if (!found) {
458
875
                if (report_type_only)
459
 
                        rh->report_types |= rh->fields[field_num].type;
460
 
                else if (!(found = _add_field(rh, field_num, FLD_HIDDEN)))
 
876
                        rh->report_types |= fields[field_num].type;
 
877
                else if (!(found = _add_field(rh, field_num, implicit, FLD_HIDDEN)))
461
878
                        return_0;
462
879
        }
463
880
 
466
883
 
467
884
        if (found->flags & FLD_SORT_KEY) {
468
885
                log_warn("dm_report: Ignoring duplicate sort field: %s.",
469
 
                         rh->fields[field_num].id);
 
886
                         fields[field_num].id);
470
887
                return 1;
471
888
        }
472
889
 
502
919
                return 0;
503
920
        }
504
921
 
 
922
        for (f = 0; _implicit_report_fields[f].report_fn; f++)
 
923
                if (_is_same_field(_implicit_report_fields[f].id, key, len, rh->field_prefix))
 
924
                        return _add_sort_key(rh, f, 1, flags, report_type_only);
 
925
 
505
926
        for (f = 0; rh->fields[f].report_fn; f++)
506
 
                if (_is_same_field(rh->fields[f].id, key, len,
507
 
                                   rh->field_prefix))
508
 
                        return _add_sort_key(rh, f, flags, report_type_only);
 
927
                if (_is_same_field(rh->fields[f].id, key, len, rh->field_prefix))
 
928
                        return _add_sort_key(rh, f, 0, flags, report_type_only);
509
929
 
510
930
        return 0;
511
931
}
527
947
                        we++;
528
948
 
529
949
                if (!_field_match(rh, ws, (size_t) (we - ws), report_type_only)) {
530
 
                        _display_fields(rh);
 
950
                        _display_fields(rh, 1, 0);
531
951
                        log_warn(" ");
532
 
                        if (strcasecmp(ws, "help") && strcmp(ws, "?"))
533
 
                                log_error("Unrecognised field: %.*s",
534
 
                                          (int) (we - ws), ws);
 
952
                        log_error("Unrecognised field: %.*s", (int) (we - ws), ws);
535
953
                        return 0;
536
954
                }
537
955
        }
556
974
                while (*we && *we != ',')
557
975
                        we++;
558
976
                if (!_key_match(rh, ws, (size_t) (we - ws), report_type_only)) {
559
 
                        log_error("dm_report: Unrecognised field: %.*s",
560
 
                                  (int) (we - ws), ws);
 
977
                        _display_fields(rh, 1, 0);
 
978
                        log_warn(" ");
 
979
                        log_error("dm_report: Unrecognised field: %.*s", (int) (we - ws), ws);
561
980
                        return 0;
562
981
                }
563
982
        }
565
984
        return 1;
566
985
}
567
986
 
 
987
static int _contains_reserved_report_type(const struct dm_report_object_type *types)
 
988
{
 
989
        const struct dm_report_object_type *type, *implicit_type;
 
990
 
 
991
        for (implicit_type = _implicit_report_types; implicit_type->data_fn; implicit_type++) {
 
992
                for (type = types; type->data_fn; type++) {
 
993
                        if (implicit_type->id & type->id) {
 
994
                                log_error(INTERNAL_ERROR "dm_report_init: definition of report "
 
995
                                          "types given contains reserved identifier");
 
996
                                return 1;
 
997
                        }
 
998
                }
 
999
        }
 
1000
 
 
1001
        return 0;
 
1002
}
 
1003
 
 
1004
static void _dm_report_init_update_types(struct dm_report *rh, uint32_t *report_types)
 
1005
{
 
1006
        const struct dm_report_object_type *type;
 
1007
 
 
1008
        if (!report_types)
 
1009
                return;
 
1010
 
 
1011
        *report_types = rh->report_types;
 
1012
        /*
 
1013
         * Do not include implicit types as these are not understood by
 
1014
         * dm_report_init caller - the caller doesn't know how to check
 
1015
         * these types anyway.
 
1016
         */
 
1017
        for (type = _implicit_report_types; type->data_fn; type++)
 
1018
                *report_types &= ~type->id;
 
1019
}
 
1020
 
 
1021
static int _help_requested(struct dm_report *rh)
 
1022
{
 
1023
        struct field_properties *fp;
 
1024
 
 
1025
        dm_list_iterate_items(fp, &rh->field_props) {
 
1026
                if (fp->implicit &&
 
1027
                    (!strcmp(_implicit_report_fields[fp->field_num].id, SPECIAL_FIELD_HELP_ID) ||
 
1028
                     !strcmp(_implicit_report_fields[fp->field_num].id, SPECIAL_FIELD_HELP_ALT_ID)))
 
1029
                        return 1;
 
1030
        }
 
1031
 
 
1032
        return 0;
 
1033
}
 
1034
 
568
1035
struct dm_report *dm_report_init(uint32_t *report_types,
569
1036
                                 const struct dm_report_object_type *types,
570
1037
                                 const struct dm_report_field_type *fields,
577
1044
        struct dm_report *rh;
578
1045
        const struct dm_report_object_type *type;
579
1046
 
 
1047
        if (_contains_reserved_report_type(types))
 
1048
                return_NULL;
 
1049
 
580
1050
        if (!(rh = dm_zalloc(sizeof(*rh)))) {
581
1051
                log_error("dm_report_init: dm_malloc failed");
582
 
                return 0;
 
1052
                return NULL;
583
1053
        }
584
1054
 
585
1055
        /*
640
1110
                return NULL;
641
1111
        }
642
1112
 
643
 
        /* Return updated types value for further compatility check by caller */
644
 
        if (report_types)
645
 
                *report_types = rh->report_types;
 
1113
        /*
 
1114
         * Return updated types value for further compatility check by caller.
 
1115
         */
 
1116
        _dm_report_init_update_types(rh, report_types);
 
1117
 
 
1118
        if (_help_requested(rh)) {
 
1119
                _display_fields(rh, 1, 0);
 
1120
                log_warn(" ");
 
1121
                rh->flags |= RH_ALREADY_REPORTED;
 
1122
        }
646
1123
 
647
1124
        return rh;
648
1125
}
684
1161
static void *_report_get_field_data(struct dm_report *rh,
685
1162
                                    struct field_properties *fp, void *object)
686
1163
{
 
1164
        const struct dm_report_field_type *fields = fp->implicit ? _implicit_report_fields
 
1165
                                                                 : rh->fields;
 
1166
 
687
1167
        char *ret = fp->type->data_fn(object);
688
1168
 
689
1169
        if (!ret)
690
1170
                return NULL;
691
1171
 
692
 
        return (void *)(ret + rh->fields[fp->field_num].offset);
 
1172
        return (void *)(ret + fields[fp->field_num].offset);
 
1173
}
 
1174
 
 
1175
static void *_report_get_implicit_field_data(struct dm_report *rh __attribute__((unused)),
 
1176
                                             struct field_properties *fp, struct row *row)
 
1177
{
 
1178
        if (!strcmp(_implicit_report_fields[fp->field_num].id, SPECIAL_FIELD_SELECTED_ID))
 
1179
                return row;
 
1180
 
 
1181
        return NULL;
 
1182
}
 
1183
 
 
1184
static int _cmp_field_int(const char *field_id, uint64_t a, uint64_t b, uint32_t flags)
 
1185
{
 
1186
        switch(flags & FLD_CMP_MASK) {
 
1187
                case FLD_CMP_EQUAL:
 
1188
                        return a == b;
 
1189
                case FLD_CMP_NOT|FLD_CMP_EQUAL:
 
1190
                        return a != b;
 
1191
                case FLD_CMP_NUMBER|FLD_CMP_GT:
 
1192
                        return a > b;
 
1193
                case FLD_CMP_NUMBER|FLD_CMP_GT|FLD_CMP_EQUAL:
 
1194
                        return a >= b;
 
1195
                case FLD_CMP_NUMBER|FLD_CMP_LT:
 
1196
                        return a < b;
 
1197
                case FLD_CMP_NUMBER|FLD_CMP_LT|FLD_CMP_EQUAL:
 
1198
                        return a <= b;
 
1199
                default:
 
1200
                        log_error(INTERNAL_ERROR "_cmp_field_int: unsupported number "
 
1201
                                  "comparison type for field %s", field_id);
 
1202
        }
 
1203
 
 
1204
        return 0;
 
1205
}
 
1206
 
 
1207
static int _close_enough(double d1, double d2)
 
1208
{
 
1209
        return fabs(d1 - d2) < DBL_EPSILON;
 
1210
}
 
1211
 
 
1212
static int _cmp_field_double(const char *field_id, double a, double b, uint32_t flags)
 
1213
{
 
1214
        switch(flags & FLD_CMP_MASK) {
 
1215
                case FLD_CMP_EQUAL:
 
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);
 
1227
                default:
 
1228
                        log_error(INTERNAL_ERROR "_cmp_field_double: unsupported number "
 
1229
                                  "comparison type for selection field %s", field_id);
 
1230
        }
 
1231
 
 
1232
        return 0;
 
1233
}
 
1234
 
 
1235
static int _cmp_field_string(const char *field_id, const char *a, const char *b, uint32_t flags)
 
1236
{
 
1237
        switch (flags & FLD_CMP_MASK) {
 
1238
                case FLD_CMP_EQUAL:
 
1239
                        return !strcmp(a, b);
 
1240
                case FLD_CMP_NOT|FLD_CMP_EQUAL:
 
1241
                        return strcmp(a, b);
 
1242
                default:
 
1243
                        log_error(INTERNAL_ERROR "_cmp_field_string: unsupported string "
 
1244
                                  "comparison type for selection field %s", field_id);
 
1245
        }
 
1246
 
 
1247
        return 0;
 
1248
}
 
1249
 
 
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)
 
1253
{
 
1254
        struct dm_str_list *sel_item;
 
1255
        unsigned int i = 1;
 
1256
 
 
1257
        /* if item count differs, it's clear the lists do not match */
 
1258
        if (val->items[0].len != dm_list_size(sel->list))
 
1259
                return 0;
 
1260
 
 
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))
 
1264
                        return 0;
 
1265
                i++;
 
1266
        }
 
1267
 
 
1268
        return 1;
 
1269
}
 
1270
 
 
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)
 
1274
{
 
1275
        struct dm_str_list *sel_item;
 
1276
        unsigned int i;
 
1277
 
 
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))
 
1280
                return 0;
 
1281
 
 
1282
        dm_list_iterate_items(sel_item, sel->list) {
 
1283
                /*
 
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!
 
1286
                 */
 
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))
 
1289
                                return 1;
 
1290
                }
 
1291
        }
 
1292
 
 
1293
        return 0;
 
1294
}
 
1295
 
 
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)
 
1299
{
 
1300
        int r;
 
1301
 
 
1302
        switch (selection->type & SEL_MASK) {
 
1303
                case SEL_AND:
 
1304
                        r = _cmp_field_string_list_all(value, selection);
 
1305
                        break;
 
1306
                case SEL_OR:
 
1307
                        r = _cmp_field_string_list_any(value, selection);
 
1308
                        break;
 
1309
                default:
 
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);
 
1313
                        return 0;
 
1314
        }
 
1315
 
 
1316
        return flags & FLD_CMP_NOT ? !r : r;
 
1317
}
 
1318
 
 
1319
static int _cmp_field_regex(const char *s, struct dm_regex *r, uint32_t flags)
 
1320
{
 
1321
        int match = dm_regex_match(r, s) >= 0;
 
1322
        return flags & FLD_CMP_NOT ? !match : match;
 
1323
}
 
1324
 
 
1325
static int _compare_selection_field(struct dm_report *rh,
 
1326
                                    struct dm_report_field *f,
 
1327
                                    struct field_selection *fs)
 
1328
{
 
1329
        const struct dm_report_field_type *fields = f->props->implicit ? _implicit_report_fields
 
1330
                                                                       : rh->fields;
 
1331
        const char *field_id = fields[f->props->field_num].id;
 
1332
        int r = 0;
 
1333
 
 
1334
        if (!f->sort_value) {
 
1335
                log_error("_compare_selection_field: field without value :%d",
 
1336
                          f->props->field_num);
 
1337
                return 0;
 
1338
        }
 
1339
 
 
1340
        if (fs->flags & FLD_CMP_REGEX)
 
1341
                r = _cmp_field_regex((const char *) f->sort_value, fs->v.r, fs->flags);
 
1342
        else {
 
1343
                switch(f->props->flags & DM_REPORT_FIELD_TYPE_MASK) {
 
1344
                        case DM_REPORT_FIELD_TYPE_PERCENT:
 
1345
                                /*
 
1346
                                 * Check against real percent values only.
 
1347
                                 * That means DM_PERCENT_0 <= percent <= DM_PERCENT_100.
 
1348
                                 */
 
1349
                                if (*(const uint64_t *) f->sort_value > DM_PERCENT_100)
 
1350
                                        return 0;
 
1351
                                /* fall through */
 
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);
 
1354
                                break;
 
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);
 
1357
                                break;
 
1358
                        case DM_REPORT_FIELD_TYPE_STRING:
 
1359
                                r = _cmp_field_string(field_id, (const char *) f->sort_value, fs->v.s, fs->flags);
 
1360
                                break;
 
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);
 
1364
                                break;
 
1365
                        default:
 
1366
                                log_error(INTERNAL_ERROR "_compare_selection_field: unknown field type for field %s", field_id);
 
1367
                }
 
1368
        }
 
1369
 
 
1370
        return r;
 
1371
}
 
1372
 
 
1373
static int _check_selection(struct dm_report *rh, struct selection_node *sn,
 
1374
                            struct dm_list *fields)
 
1375
{
 
1376
        int r;
 
1377
        struct selection_node *iter_n;
 
1378
        struct dm_report_field *f;
 
1379
 
 
1380
        switch (sn->type & SEL_MASK) {
 
1381
                case SEL_ITEM:
 
1382
                        r = 1;
 
1383
                        dm_list_iterate_items(f, fields) {
 
1384
                                if (sn->selection.item->fp != f->props)
 
1385
                                        continue;
 
1386
                                if (!_compare_selection_field(rh, f, sn->selection.item))
 
1387
                                        r = 0;
 
1388
                        }
 
1389
                        break;
 
1390
                case SEL_OR:
 
1391
                        r = 0;
 
1392
                        dm_list_iterate_items(iter_n, &sn->selection.set)
 
1393
                                if ((r |= _check_selection(rh, iter_n, fields)))
 
1394
                                        break;
 
1395
                        break;
 
1396
                case SEL_AND:
 
1397
                        r = 1;
 
1398
                        dm_list_iterate_items(iter_n, &sn->selection.set)
 
1399
                                if (!(r &= _check_selection(rh, iter_n, fields)))
 
1400
                                        break;
 
1401
                        break;
 
1402
                default:
 
1403
                        log_error("Unsupported selection type");
 
1404
                        return 0;
 
1405
        }
 
1406
 
 
1407
        return (sn->type & SEL_MODIFIER_NOT) ? !r : r;
 
1408
}
 
1409
 
 
1410
static int _check_report_selection(struct dm_report *rh, struct dm_list *fields)
 
1411
{
 
1412
        if (!rh->selection_root)
 
1413
                return 1;
 
1414
 
 
1415
        return _check_selection(rh, rh->selection_root, fields);
693
1416
}
694
1417
 
695
1418
int dm_report_object(struct dm_report *rh, void *object)
696
1419
{
 
1420
        const struct dm_report_field_type *fields;
697
1421
        struct field_properties *fp;
698
 
        struct row *row;
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;
 
1425
        int len;
 
1426
        int r = 0;
701
1427
 
702
1428
        if (!rh) {
703
1429
                log_error(INTERNAL_ERROR "dm_report handler is NULL.");
704
1430
                return 0;
705
1431
        }
706
1432
 
 
1433
        if (rh->flags & RH_ALREADY_REPORTED)
 
1434
                return 1;
 
1435
 
707
1436
        if (!(row = dm_pool_zalloc(rh->mem, sizeof(*row)))) {
708
1437
                log_error("dm_report_object: struct row allocation failed");
709
1438
                return 0;
717
1446
                               rh->keys_count))) {
718
1447
                log_error("dm_report_object: "
719
1448
                          "row sort value structure allocation failed");
720
 
                return 0;
 
1449
                goto out;
721
1450
        }
722
1451
 
723
1452
        dm_list_init(&row->fields);
724
 
        dm_list_add(&rh->rows, &row->list);
 
1453
        row->selected = 1;
725
1454
 
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");
731
 
                        return 0;
 
1460
                        goto out;
732
1461
                }
 
1462
 
 
1463
                if (fp->implicit) {
 
1464
                        fields = _implicit_report_fields;
 
1465
                        if (!strcmp(fields[fp->field_num].id, SPECIAL_FIELD_SELECTED_ID))
 
1466
                                field_sel_status = field;
 
1467
                } else
 
1468
                        fields = rh->fields;
 
1469
 
733
1470
                field->props = fp;
734
1471
 
735
 
                data = _report_get_field_data(rh, fp, object);
736
 
                if (!data)
737
 
                        return 0;
 
1472
                data = fp->implicit ? _report_get_implicit_field_data(rh, fp, row)
 
1473
                                    : _report_get_field_data(rh, fp, object);
 
1474
                if (!data) {
 
1475
                        log_error("dm_report_object: "
 
1476
                                  "no data assigned to field %s",
 
1477
                                  fields[fp->field_num].id);
 
1478
                        goto out;
 
1479
                }
738
1480
 
739
 
                if (!rh->fields[fp->field_num].report_fn(rh, rh->mem,
 
1481
                if (!fields[fp->field_num].report_fn(rh, rh->mem,
740
1482
                                                         field, data,
741
1483
                                                         rh->private)) {
742
1484
                        log_error("dm_report_object: "
743
1485
                                  "report function failed for field %s",
744
 
                                  rh->fields[fp->field_num].id);
745
 
                        return 0;
746
 
                }
747
 
 
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);
 
1487
                        goto out;
 
1488
                }
 
1489
 
 
1490
                dm_list_add(&row->fields, &field->list);
 
1491
        }
 
1492
 
 
1493
        if (!_check_report_selection(rh, &row->fields)) {
 
1494
                if (!field_sel_status) {
 
1495
                        r = 1;
 
1496
                        goto out;
 
1497
                }
 
1498
                /*
 
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
 
1503
                 * of the selection.
 
1504
                 */
 
1505
                row->selected = 0;
 
1506
                _implicit_report_fields[field_sel_status->props->field_num].report_fn(rh,
 
1507
                                                rh->mem, field_sel_status, row, rh->private);
 
1508
                /*
 
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.
 
1512
                 */
 
1513
                if (field_sel_status->props->flags & FLD_HIDDEN) {
 
1514
                        r = 1;
 
1515
                        goto out;
 
1516
                }
 
1517
        }
 
1518
 
 
1519
        dm_list_add(&rh->rows, &row->list);
 
1520
 
 
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;
750
1525
 
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;
754
1529
                }
755
 
                dm_list_add(&row->fields, &field->list);
756
1530
        }
757
1531
 
758
1532
        if (!(rh->flags & DM_REPORT_OUTPUT_BUFFERED))
759
1533
                return dm_report_output(rh);
760
1534
 
761
 
        return 1;
 
1535
        r = 1;
 
1536
out:
 
1537
        if (!r)
 
1538
                dm_pool_free(rh->mem, row);
 
1539
        return r;
 
1540
}
 
1541
 
 
1542
/*
 
1543
 * Selection parsing
 
1544
 */
 
1545
 
 
1546
/*
 
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>
 
1553
 */
 
1554
 
 
1555
static const char * _skip_space(const char *s)
 
1556
{
 
1557
        while (*s && isspace(*s))
 
1558
                s++;
 
1559
        return s;
 
1560
}
 
1561
 
 
1562
static int _tok_op(struct op_def *t, const char *s, const char **end,
 
1563
                   uint32_t expect)
 
1564
{
 
1565
        size_t len;
 
1566
 
 
1567
        s = _skip_space(s);
 
1568
 
 
1569
        for (; t->string; t++) {
 
1570
                if (expect && !(t->flags & expect))
 
1571
                        continue;
 
1572
 
 
1573
                len = strlen(t->string);
 
1574
                if (!strncmp(s, t->string, len)) {
 
1575
                        if (end)
 
1576
                                *end = s + len;
 
1577
                        return t->flags;
 
1578
                }
 
1579
        }
 
1580
 
 
1581
        if (end)
 
1582
                *end = s;
 
1583
        return 0;
 
1584
}
 
1585
 
 
1586
static int _tok_op_log(const char *s, const char **end, uint32_t expect)
 
1587
{
 
1588
        return _tok_op(_op_log, s, end, expect);
 
1589
}
 
1590
 
 
1591
static int _tok_op_cmp(const char *s, const char **end)
 
1592
{
 
1593
        return _tok_op(_op_cmp, s, end, 0);
 
1594
}
 
1595
 
 
1596
static char _get_and_skip_quote_char(char const **s)
 
1597
{
 
1598
        char c = 0;
 
1599
 
 
1600
        if (**s == '"' || **s == '\'') {
 
1601
                c = **s;
 
1602
                (*s)++;
 
1603
        }
 
1604
 
 
1605
        return c;
 
1606
}
 
1607
 
 
1608
 /*
 
1609
  *
 
1610
  * Input:
 
1611
  *   s             - a pointer to the parsed string
 
1612
  * Output:
 
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)
 
1619
  */
 
1620
static const char *_tok_value_number(const char *s,
 
1621
                                     const char **begin, const char **end)
 
1622
 
 
1623
{
 
1624
        int is_float = 0;
 
1625
 
 
1626
        *begin = s;
 
1627
        while (*s && ((!is_float && *s=='.' && (is_float=1)) || isdigit(*s)))
 
1628
                s++;
 
1629
        *end = s;
 
1630
 
 
1631
        if (*begin == *end)
 
1632
                return NULL;
 
1633
 
 
1634
        return s;
 
1635
}
 
1636
 
 
1637
/*
 
1638
 * Input:
 
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)
 
1643
 * Output:
 
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
 
1648
 */
 
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)
 
1653
{
 
1654
        uint32_t flag_hit = 0;
 
1655
 
 
1656
        *begin = s;
 
1657
 
 
1658
        /*
 
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.
 
1663
         */
 
1664
        if (endchar) {
 
1665
                while (*s && *s != endchar)
 
1666
                        s++;
 
1667
                if (*s != endchar) {
 
1668
                        log_error("Missing end quote.");
 
1669
                        return NULL;
 
1670
                }
 
1671
                *end = s;
 
1672
                s++;
 
1673
        } else {
 
1674
                /*
 
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.
 
1679
                 */
 
1680
                while (*s) {
 
1681
                        if ((flag_hit = _tok_op(_op_log, s, NULL, end_op_flags)) || *s == ' ')
 
1682
                                break;
 
1683
                        s++;
 
1684
                }
 
1685
                *end = s;
 
1686
                /*
 
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.
 
1690
                 */
 
1691
                if (end_op_flag_hit)
 
1692
                        *end_op_flag_hit = flag_hit;
 
1693
        }
 
1694
 
 
1695
        return s;
 
1696
}
 
1697
 
 
1698
static const char *_reserved_name(const char **names, const char *s, size_t len)
 
1699
{
 
1700
        const char **name = names;
 
1701
        while (*name) {
 
1702
                if ((strlen(*name) == len) && !strncmp(*name, s, len))
 
1703
                        return *name;
 
1704
                name++;
 
1705
        }
 
1706
        return NULL;
 
1707
}
 
1708
 
 
1709
/*
 
1710
 * Used to replace a string representation of the reserved value
 
1711
 * found in selection with the exact reserved value of certain type.
 
1712
 */
 
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)
 
1717
{
 
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;
 
1721
        char c;
 
1722
 
 
1723
        *reserved = NULL;
 
1724
 
 
1725
        if (!iter)
 
1726
                return s;
 
1727
 
 
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)))
 
1730
                return s;
 
1731
 
 
1732
        while (iter->value) {
 
1733
                if (!iter->type) {
 
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)))
 
1737
                                break;
 
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)))
 
1741
                                break;
 
1742
                }
 
1743
                iter++;
 
1744
        }
 
1745
 
 
1746
        if (name) {
 
1747
                /* found! */
 
1748
                *begin = tmp_begin;
 
1749
                *end = tmp_end;
 
1750
                s = tmp_s;
 
1751
                *reserved = iter;
 
1752
        }
 
1753
 
 
1754
        return s;
 
1755
}
 
1756
 
 
1757
/*
 
1758
 * Used to check whether a value of certain type used in selection is reserved.
 
1759
 */
 
1760
static int _check_value_is_reserved(struct dm_report *rh, unsigned type, const void *value)
 
1761
{
 
1762
        const struct dm_report_reserved_value *iter = rh->reserved_values;
 
1763
 
 
1764
        if (!iter)
 
1765
                return 0;
 
1766
 
 
1767
        while (iter->type) {
 
1768
                if (iter->type & type) {
 
1769
                        switch (type) {
 
1770
                                case DM_REPORT_FIELD_TYPE_NUMBER:
 
1771
                                        if (*(uint64_t *)iter->value == *(uint64_t *)value)
 
1772
                                                return 1;
 
1773
                                        break;
 
1774
                                case DM_REPORT_FIELD_TYPE_STRING:
 
1775
                                        if (!strcmp((const char *)iter->value, (const char *) value))
 
1776
                                                return 1;
 
1777
                                        break;
 
1778
                                case DM_REPORT_FIELD_TYPE_SIZE:
 
1779
                                        if (_close_enough(*(double *)iter->value, *(double *) value))
 
1780
                                                return 1;
 
1781
                                        break;
 
1782
                                case DM_REPORT_FIELD_TYPE_STRING_LIST:
 
1783
                                        // TODO: add comparison for string list
 
1784
                                        break;
 
1785
                        }
 
1786
                }
 
1787
                iter++;
 
1788
        }
 
1789
 
 
1790
        return 0;
 
1791
}
 
1792
 
 
1793
float dm_percent_to_float(dm_percent_t percent)
 
1794
{
 
1795
        return (float) percent / DM_PERCENT_1;
 
1796
}
 
1797
 
 
1798
dm_percent_t dm_make_percent(uint64_t numerator, uint64_t denominator)
 
1799
{
 
1800
        dm_percent_t percent;
 
1801
 
 
1802
        if (!denominator)
 
1803
                return DM_PERCENT_100; /* FIXME? */
 
1804
        if (!numerator)
 
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;
 
1811
                case DM_PERCENT_0:
 
1812
                        return DM_PERCENT_0 + 1;
 
1813
                default:
 
1814
                        return percent;
 
1815
        }
 
1816
}
 
1817
 
 
1818
/*
 
1819
 * Used to check whether the reserved_values definition passed to
 
1820
 * dm_report_init_with_selection contains only supported reserved value types.
 
1821
 */
 
1822
static int _check_reserved_values_supported(const struct dm_report_reserved_value reserved_values[])
 
1823
{
 
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;
 
1829
 
 
1830
        if (!reserved_values)
 
1831
                return 1;
 
1832
 
 
1833
        iter = reserved_values;
 
1834
 
 
1835
        while (iter->type) {
 
1836
                if (!(iter->type & supported_reserved_types))
 
1837
                        return 0;
 
1838
                iter++;
 
1839
        }
 
1840
 
 
1841
        return 1;
 
1842
}
 
1843
 
 
1844
/*
 
1845
 * Input:
 
1846
 *   ft              - field type for which the value is parsed
 
1847
 *   s               - a pointer to the parsed string
 
1848
 * Output:
 
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
 
1852
 */
 
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)
 
1858
{
 
1859
        char c;
 
1860
        *reserved = NULL;
 
1861
 
 
1862
        s = _skip_space(s);
 
1863
 
 
1864
        if (!*s) {
 
1865
                log_error("Regular expression expected for selection field %s", ft->id);
 
1866
                return NULL;
 
1867
        }
 
1868
 
 
1869
        switch (*s) {
 
1870
                case '(': c = ')'; break;
 
1871
                case '{': c = '}'; break;
 
1872
                case '[': c = ']'; break;
 
1873
                case '"': /* fall through */
 
1874
                case '\'': c = *s; break;
 
1875
                default:  c = 0;
 
1876
        }
 
1877
 
 
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);
 
1880
                return NULL;
 
1881
        }
 
1882
 
 
1883
        *flags |= DM_REPORT_FIELD_TYPE_STRING;
 
1884
        return s;
 
1885
}
 
1886
 
 
1887
static int _str_list_item_cmp(const void *a, const void *b)
 
1888
{
 
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;
 
1891
 
 
1892
        return strcmp((*item_a)->str, (*item_b)->str);
 
1893
}
 
1894
 
 
1895
static int _add_item_to_string_list(struct dm_pool *mem, const char *begin,
 
1896
                                    const char *end, struct dm_list *list)
 
1897
{
 
1898
        struct dm_str_list *item;
 
1899
 
 
1900
        if (begin == end)
 
1901
                return_0;
 
1902
 
 
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");
 
1906
                return 0;
 
1907
        }
 
1908
        dm_list_add(list, &item->list);
 
1909
 
 
1910
        return 1;
 
1911
}
 
1912
 
 
1913
/*
 
1914
 * Input:
 
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
 
1918
 * Output:
 
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
 
1922
 */
 
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)
 
1927
{
 
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;
 
1935
        size_t list_size;
 
1936
        unsigned int i;
 
1937
        int list_end;
 
1938
        char c;
 
1939
 
 
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");
 
1943
                goto bad;
 
1944
        }
 
1945
        dm_list_init(ssl->list);
 
1946
        ssl->type = 0;
 
1947
        *begin = s;
 
1948
 
 
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);
 
1954
                        goto bad;
 
1955
                }
 
1956
                if (!_add_item_to_string_list(mem, begin_item, end_item, ssl->list))
 
1957
                        goto_bad;
 
1958
                ssl->type = SEL_OR;
 
1959
                goto out;
 
1960
        }
 
1961
 
 
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!
 
1966
         */
 
1967
        end_op_flags = SEL_LIST_LE | SEL_AND | SEL_OR;
 
1968
        s++;
 
1969
        while (*s) {
 
1970
                s = _skip_space(s);
 
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);
 
1974
                        goto bad;
 
1975
                }
 
1976
                s = _skip_space(s);
 
1977
 
 
1978
                if (!(end_op_flag_hit = _tok_op_log(s, &tmp, end_op_flags))) {
 
1979
                        log_error("Invalid operator in selection list.");
 
1980
                        goto bad;
 
1981
                }
 
1982
 
 
1983
                list_end = end_op_flag_hit == SEL_LIST_LE;
 
1984
 
 
1985
                if (ssl->type) {
 
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.");
 
1989
                                goto bad;
 
1990
                        }
 
1991
                } else
 
1992
                        ssl->type = list_end ? SEL_OR : end_op_flag_hit;
 
1993
 
 
1994
                if (!_add_item_to_string_list(mem, begin_item, end_item, ssl->list))
 
1995
                        goto_bad;
 
1996
 
 
1997
                s = tmp;
 
1998
 
 
1999
                if (list_end)
 
2000
                        break;
 
2001
        }
 
2002
 
 
2003
        if (end_op_flag_hit != SEL_LIST_LE) {
 
2004
                log_error("Missing list end for selection field %s", ft->id);
 
2005
                goto bad;
 
2006
        }
 
2007
 
 
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");
 
2011
                goto bad;
 
2012
        } else if (list_size == 1)
 
2013
                goto out;
 
2014
        if (!(arr = dm_malloc(sizeof(item) * list_size))) {
 
2015
                log_error("_tok_value_string_list: memory allocation failed for sort array");
 
2016
                goto bad;
 
2017
        }
 
2018
 
 
2019
        i = 0;
 
2020
        dm_list_iterate_items(item, ssl->list)
 
2021
                arr[i++] = item;
 
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);
 
2026
 
 
2027
        dm_free(arr);
 
2028
out:
 
2029
        *end = s;
 
2030
        *sel_str_list = ssl;
 
2031
        return s;
 
2032
bad:
 
2033
        *end = s;
 
2034
        if (ssl)
 
2035
                dm_pool_free(mem, ssl);
 
2036
        *sel_str_list = NULL;
 
2037
        return s;
 
2038
}
 
2039
 
 
2040
/*
 
2041
 * Input:
 
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
 
2045
 * Output:
 
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)
 
2051
 */
 
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,
 
2055
                              const char *s,
 
2056
                              const char **begin, const char **end,
 
2057
                              uint32_t *flags,
 
2058
                              const struct dm_report_reserved_value **reserved,
 
2059
                              struct dm_pool *mem, void *custom)
 
2060
{
 
2061
        int expected_type = ft->flags & DM_REPORT_FIELD_TYPE_MASK;
 
2062
        struct selection_str_list **str_list;
 
2063
        uint64_t *factor;
 
2064
        const char *tmp;
 
2065
        char c;
 
2066
 
 
2067
        s = _skip_space(s);
 
2068
 
 
2069
        s = _get_reserved(rh, expected_type, field_num, implicit, s, begin, end, reserved);
 
2070
        if (*reserved) {
 
2071
                *flags |= expected_type;
 
2072
                return s;
 
2073
        }
 
2074
 
 
2075
        switch (expected_type) {
 
2076
 
 
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);
 
2082
                                return NULL;
 
2083
                        }
 
2084
                        *flags |= DM_REPORT_FIELD_TYPE_STRING;
 
2085
                        break;
 
2086
 
 
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);
 
2090
                        if (!(*str_list)) {
 
2091
                                log_error("Failed to parse string list value "
 
2092
                                          "for selection field %s.", ft->id);
 
2093
                                return NULL;
 
2094
                        }
 
2095
                        *flags |= DM_REPORT_FIELD_TYPE_STRING_LIST;
 
2096
                        break;
 
2097
 
 
2098
                case DM_REPORT_FIELD_TYPE_NUMBER:
 
2099
                        /* fall through */
 
2100
                case DM_REPORT_FIELD_TYPE_SIZE:
 
2101
                        /* fall through */
 
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);
 
2106
                                return NULL;
 
2107
                        }
 
2108
 
 
2109
                        factor = (uint64_t *) custom;
 
2110
 
 
2111
                        if (*s == DM_PERCENT_CHAR) {
 
2112
                                s++;
 
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);
 
2119
                                        return NULL;
 
2120
                                }
 
2121
                        } else if ((*factor = dm_units_to_factor(s, &c, 0, &tmp))) {
 
2122
                                s = 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);
 
2129
                                        return NULL;
 
2130
                                }
 
2131
                        } else if (expected_type == DM_REPORT_FIELD_TYPE_SIZE) {
 
2132
                                /*
 
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>.
 
2137
                                 */
 
2138
                                *factor = 1024*1024;
 
2139
                        }
 
2140
 
 
2141
                        *flags |= expected_type;
 
2142
        }
 
2143
 
 
2144
        return s;
 
2145
}
 
2146
 
 
2147
/*
 
2148
 * Input:
 
2149
 *   s               - a pointer to the parsed string
 
2150
 * Output:
 
2151
 *   begin           - a pointer to the beginning of the token
 
2152
 *   end             - a pointer to the end of the token + 1
 
2153
 */
 
2154
static const char *_tok_field_name(const char *s,
 
2155
                                    const char **begin, const char **end)
 
2156
{
 
2157
        char c;
 
2158
        s = _skip_space(s);
 
2159
 
 
2160
        *begin = s;
 
2161
        while ((c = *s) &&
 
2162
               (isalnum(c) || c == '_' || c == '-'))
 
2163
                s++;
 
2164
        *end = s;
 
2165
 
 
2166
        if (*begin == *end)
 
2167
                return NULL;
 
2168
 
 
2169
        return s;
 
2170
}
 
2171
 
 
2172
static const void *_get_reserved_value(const struct dm_report_reserved_value *reserved)
 
2173
{
 
2174
        if (reserved->type)
 
2175
                return reserved->value;
 
2176
        else
 
2177
                return ((const struct dm_report_field_reserved_value *) reserved->value)->value;
 
2178
}
 
2179
 
 
2180
static struct field_selection *_create_field_selection(struct dm_report *rh,
 
2181
                                                       uint32_t field_num,
 
2182
                                                       int implicit,
 
2183
                                                       const char *v,
 
2184
                                                       size_t len,
 
2185
                                                       uint32_t flags,
 
2186
                                                       const struct dm_report_reserved_value *reserved,
 
2187
                                                       void *custom)
 
2188
{
 
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
 
2191
                                                             : rh->fields;
 
2192
        struct field_properties *fp, *found = NULL;
 
2193
        struct field_selection *fs;
 
2194
        const char *field_id;
 
2195
        uint64_t factor;
 
2196
        char *s;
 
2197
 
 
2198
        dm_list_iterate_items(fp, &rh->field_props) {
 
2199
                if ((fp->implicit == implicit) && (fp->field_num == field_num)) {
 
2200
                        found = fp;
 
2201
                        break;
 
2202
                }
 
2203
        }
 
2204
 
 
2205
        /* The field is neither used in display options nor sort keys. */
 
2206
        if (!found) {
 
2207
                if (!(found = _add_field(rh, field_num, implicit, FLD_HIDDEN)))
 
2208
                        return NULL;
 
2209
                rh->report_types |= fields[field_num].type;
 
2210
        }
 
2211
 
 
2212
        field_id = fields[found->field_num].id;
 
2213
 
 
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);
 
2217
                return NULL;
 
2218
        }
 
2219
 
 
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);
 
2224
                return NULL;
 
2225
        }
 
2226
        fs->fp = found;
 
2227
        fs->flags = flags;
 
2228
 
 
2229
        /* store comparison operand */
 
2230
        if (flags & FLD_CMP_REGEX) {
 
2231
                /* 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);
 
2235
                        goto error;
 
2236
                }
 
2237
                memcpy(s, v, len);
 
2238
                s[len] = '\0';
 
2239
 
 
2240
                fs->v.r = dm_regex_create(rh->mem, (const char **) &s, 1);
 
2241
                dm_free(s);
 
2242
                if (!fs->v.r) {
 
2243
                        log_error("dm_report: failed to create regex "
 
2244
                                  "matcher for selection field %s", field_id);
 
2245
                        goto error;
 
2246
                }
 
2247
        } else {
 
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);
 
2252
                        goto error;
 
2253
                }
 
2254
                memcpy(s, v, len);
 
2255
                s[len] = '\0';
 
2256
 
 
2257
                switch (flags & DM_REPORT_FIELD_TYPE_MASK) {
 
2258
                        case DM_REPORT_FIELD_TYPE_STRING:
 
2259
                                if (reserved) {
 
2260
                                        fs->v.s = (const char *) _get_reserved_value(reserved);
 
2261
                                        dm_pool_free(rh->mem, s);
 
2262
                                } else {
 
2263
                                        fs->v.s = 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);
 
2266
                                                goto error;
 
2267
                                        }
 
2268
                                }
 
2269
                                break;
 
2270
                        case DM_REPORT_FIELD_TYPE_NUMBER:
 
2271
                                if (reserved)
 
2272
                                        fs->v.i = *(uint64_t *) _get_reserved_value(reserved);
 
2273
                                else {
 
2274
                                        if (((fs->v.i = strtoull(s, NULL, 10)) == ULLONG_MAX) &&
 
2275
                                                 (errno == ERANGE)) {
 
2276
                                                log_error(_out_of_range_msg, s, field_id);
 
2277
                                                goto error;
 
2278
                                        }
 
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);
 
2281
                                                goto error;
 
2282
                                        }
 
2283
                                }
 
2284
                                dm_pool_free(rh->mem, s);
 
2285
                                break;
 
2286
                        case DM_REPORT_FIELD_TYPE_SIZE:
 
2287
                                if (reserved)
 
2288
                                        fs->v.d = (double) * (uint64_t *) _get_reserved_value(reserved);
 
2289
                                else {
 
2290
                                        fs->v.d = strtod(s, NULL);
 
2291
                                        if (errno == ERANGE) {
 
2292
                                                log_error(_out_of_range_msg, s, field_id);
 
2293
                                                goto error;
 
2294
                                        }
 
2295
                                        if (custom && (factor = *((uint64_t *)custom)))
 
2296
                                                fs->v.d *= factor;
 
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);
 
2300
                                                goto error;
 
2301
                                        }
 
2302
                                }
 
2303
                                dm_pool_free(rh->mem, s);
 
2304
                                break;
 
2305
                        case DM_REPORT_FIELD_TYPE_PERCENT:
 
2306
                                if (reserved)
 
2307
                                        fs->v.i = *(uint64_t *) _get_reserved_value(reserved);
 
2308
                                else {
 
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);
 
2312
                                                goto error;
 
2313
                                        }
 
2314
 
 
2315
                                        fs->v.i = (dm_percent_t) (DM_PERCENT_1 * fs->v.d);
 
2316
 
 
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);
 
2319
                                                goto error;
 
2320
                                        }
 
2321
                                }
 
2322
                                break;
 
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.");
 
2327
                                        goto error;
 
2328
                                }
 
2329
                                break;
 
2330
                        default:
 
2331
                                log_error(INTERNAL_ERROR "_create_field_selection: "
 
2332
                                          "unknown type of selection field %s", field_id);
 
2333
                                goto error;
 
2334
                }
 
2335
        }
 
2336
 
 
2337
        return fs;
 
2338
error:
 
2339
        dm_pool_free(rh->mem, fs);
 
2340
        return NULL;
 
2341
}
 
2342
 
 
2343
static struct selection_node *_alloc_selection_node(struct dm_pool *mem, uint32_t type)
 
2344
{
 
2345
        struct selection_node *sn;
 
2346
 
 
2347
        if (!(sn = dm_pool_zalloc(mem, sizeof(struct selection_node)))) {
 
2348
                log_error("dm_report: struct selection_node allocation failed");
 
2349
                return NULL;
 
2350
        }
 
2351
 
 
2352
        dm_list_init(&sn->list);
 
2353
        sn->type = type;
 
2354
        if (!(type & SEL_ITEM))
 
2355
                dm_list_init(&sn->selection.set);
 
2356
 
 
2357
        return sn;
 
2358
}
 
2359
 
 
2360
static void _display_selection_help(struct dm_report *rh)
 
2361
{
 
2362
        static const char _grow_object_failed_msg[] = "_display_selection_help: dm_pool_grow_object failed";
 
2363
        struct op_def *t;
 
2364
        const struct dm_report_reserved_value *rv;
 
2365
        size_t len_all, len_final = 0;
 
2366
        const char **rvs;
 
2367
        char *rvs_all;
 
2368
 
 
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.");
 
2379
        log_warn(" ");
 
2380
        if (rh->reserved_values) {
 
2381
                log_warn("Reserved values");
 
2382
                log_warn("---------------");
 
2383
 
 
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;
 
2389
                }
 
2390
 
 
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");
 
2394
                                break;
 
2395
                        }
 
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;
 
2401
                                }
 
2402
                        }
 
2403
                        if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
 
2404
                                log_error(_grow_object_failed_msg);
 
2405
                                goto out_reserved_values;
 
2406
                        }
 
2407
                        rvs_all = dm_pool_end_object(rh->mem);
 
2408
 
 
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);
 
2412
                }
 
2413
                log_warn(" ");
 
2414
        }
 
2415
out_reserved_values:
 
2416
        log_warn("Selection operators");
 
2417
        log_warn("-------------------");
 
2418
        log_warn("  Comparison operators:");
 
2419
        t = _op_cmp;
 
2420
        for (; t->string; t++)
 
2421
                log_warn("    %4s  - %s", t->string, t->desc);
 
2422
        log_warn(" ");
 
2423
        log_warn("  Logical and grouping operators:");
 
2424
        t = _op_log;
 
2425
        for (; t->string; t++)
 
2426
                log_warn("    %4s  - %s", t->string, t->desc);
 
2427
        log_warn(" ");
 
2428
}
 
2429
 
 
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.";
 
2432
 
 
2433
/*
 
2434
 * Selection parser
 
2435
 *
 
2436
 * _parse_* functions
 
2437
 *
 
2438
 *   Input:
 
2439
 *     s             - a pointer to the parsed string
 
2440
 *   Output:
 
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
 
2445
 */
 
2446
 
 
2447
/*
 
2448
 * SELECTION := FIELD_NAME OP_CMP STRING |
 
2449
 *              FIELD_NAME OP_CMP NUMBER  |
 
2450
 *              FIELD_NAME OP_REGEX REGEX
 
2451
 */
 
2452
static struct selection_node *_parse_selection(struct dm_report *rh,
 
2453
                                               const char *s,
 
2454
                                               const char **next)
 
2455
{
 
2456
        struct field_selection *fs;
 
2457
        struct selection_node *sn;
 
2458
        const char *ws, *we; /* field name */
 
2459
        const char *vs, *ve; /* value */
 
2460
        const char *last;
 
2461
        uint32_t flags, field_num;
 
2462
        int implicit;
 
2463
        const struct dm_report_field_type *ft;
 
2464
        struct selection_str_list *str_list;
 
2465
        const struct dm_report_reserved_value *reserved;
 
2466
        uint64_t factor;
 
2467
        void *custom = NULL;
 
2468
        char *tmp;
 
2469
        char c;
 
2470
 
 
2471
        /* field name */
 
2472
        if (!(last = _tok_field_name(s, &ws, &we))) {
 
2473
                log_error("Expecting field name");
 
2474
                goto bad;
 
2475
        }
 
2476
 
 
2477
        /* check if the field with given name exists */
 
2478
        if (!_get_field(rh, ws, (size_t) (we - ws), &field_num, &implicit)) {
 
2479
                c = we[0];
 
2480
                tmp = (char *) we;
 
2481
                tmp[0] = '\0';
 
2482
                _display_fields(rh, 0, 1);
 
2483
                log_warn(" ");
 
2484
                log_error("Unrecognised selection field: %s", ws);
 
2485
                tmp[0] = c;
 
2486
                goto bad;
 
2487
        }
 
2488
 
 
2489
        if (implicit) {
 
2490
                ft = &_implicit_report_fields[field_num];
 
2491
                if (ft->flags & FLD_CMP_UNCOMPARABLE) {
 
2492
                        c = we[0];
 
2493
                        tmp = (char *) we;
 
2494
                        tmp[0] = '\0';
 
2495
                        _display_fields(rh, 0, 1);
 
2496
                        log_warn(" ");
 
2497
                        log_error("Selection field is uncomparable: %s.", ws);
 
2498
                        tmp[0] = c;
 
2499
                        goto bad;
 
2500
                }
 
2501
        } else
 
2502
                ft = &rh->fields[field_num];
 
2503
 
 
2504
        /* comparison operator */
 
2505
        if (!(flags = _tok_op_cmp(we, &last))) {
 
2506
                _display_selection_help(rh);
 
2507
                log_error("Unrecognised comparison operator: %s", we);
 
2508
                goto bad;
 
2509
        }
 
2510
        if (!last) {
 
2511
                _display_selection_help(rh);
 
2512
                log_error("Missing value after operator");
 
2513
                goto bad;
 
2514
        }
 
2515
 
 
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);
 
2523
                goto bad;
 
2524
        }
 
2525
 
 
2526
        /* comparison value */
 
2527
        if (flags & FLD_CMP_REGEX) {
 
2528
                if (!(last = _tok_value_regex(rh, ft, last, &vs, &ve, &flags, &reserved)))
 
2529
                        goto_bad;
 
2530
        } else {
 
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)
 
2534
                        custom = &factor;
 
2535
                else if (ft->flags == DM_REPORT_FIELD_TYPE_STRING_LIST)
 
2536
                        custom = &str_list;
 
2537
                else
 
2538
                        custom = NULL;
 
2539
                if (!(last = _tok_value(rh, ft, field_num, implicit,
 
2540
                                        last, &vs, &ve, &flags,
 
2541
                                        &reserved, rh->mem, custom)))
 
2542
                        goto_bad;
 
2543
        }
 
2544
 
 
2545
        *next = _skip_space(last);
 
2546
 
 
2547
        /* create selection */
 
2548
        if (!(fs = _create_field_selection(rh, field_num, implicit, vs, (size_t) (ve - vs), flags, reserved, custom)))
 
2549
                return_NULL;
 
2550
 
 
2551
        /* create selection node */
 
2552
        if (!(sn = _alloc_selection_node(rh->mem, SEL_ITEM)))
 
2553
                return_NULL;
 
2554
 
 
2555
        /* add selection to selection node */
 
2556
        sn->selection.item = fs;
 
2557
 
 
2558
        return sn;
 
2559
bad:
 
2560
        log_error(_sel_syntax_error_at_msg, s);
 
2561
        log_error(_sel_help_ref_msg);
 
2562
        *next = s;
 
2563
        return NULL;
 
2564
}
 
2565
 
 
2566
static struct selection_node *_parse_or_ex(struct dm_report *rh,
 
2567
                                           const char *s,
 
2568
                                           const char **next,
 
2569
                                           struct selection_node *or_sn);
 
2570
 
 
2571
static struct selection_node *_parse_ex(struct dm_report *rh,
 
2572
                                        const char *s,
 
2573
                                        const char **next)
 
2574
{
 
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;
 
2578
        uint32_t t;
 
2579
        const char *tmp;
 
2580
 
 
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);
 
2586
                        goto error;
 
2587
                }
 
2588
                if (!(sn = _parse_or_ex(rh, tmp, next, NULL)))
 
2589
                        goto error;
 
2590
                sn->type |= SEL_MODIFIER_NOT;
 
2591
                if (!_tok_op_log(*next, &tmp, SEL_PRECEDENCE_PE)) {
 
2592
                        log_error(_pe_expected_msg, *next);
 
2593
                        goto error;
 
2594
                }
 
2595
                *next = tmp;
 
2596
        } else if (t == SEL_PRECEDENCE_PS) {
 
2597
                /* '(' EXPRESSION ')' */
 
2598
                if (!(sn = _parse_or_ex(rh, *next, &tmp, NULL)))
 
2599
                        goto error;
 
2600
                if (!_tok_op_log(tmp, next, SEL_PRECEDENCE_PE)) {
 
2601
                        log_error(_pe_expected_msg, *next);
 
2602
                        goto error;
 
2603
                }
 
2604
        } else if ((s = _skip_space(s))) {
 
2605
                /* SELECTION */
 
2606
                sn = _parse_selection(rh, s, next);
 
2607
        } else {
 
2608
                sn = NULL;
 
2609
                *next = s;
 
2610
        }
 
2611
 
 
2612
        return sn;
 
2613
error:
 
2614
        *next = s;
 
2615
        return NULL;
 
2616
}
 
2617
 
 
2618
/* AND_EXPRESSION := EX (AND_OP AND_EXPRSSION) */
 
2619
static struct selection_node *_parse_and_ex(struct dm_report *rh,
 
2620
                                            const char *s,
 
2621
                                            const char **next,
 
2622
                                            struct selection_node *and_sn)
 
2623
{
 
2624
        struct selection_node *n;
 
2625
        const char *tmp;
 
2626
 
 
2627
        n = _parse_ex(rh, s, next);
 
2628
        if (!n)
 
2629
                goto error;
 
2630
 
 
2631
        if (!_tok_op_log(*next, &tmp, SEL_AND)) {
 
2632
                if (!and_sn)
 
2633
                        return n;
 
2634
                dm_list_add(&and_sn->selection.set, &n->list);
 
2635
                return and_sn;
 
2636
        }
 
2637
 
 
2638
        if (!and_sn) {
 
2639
                if (!(and_sn = _alloc_selection_node(rh->mem, SEL_AND)))
 
2640
                        goto error;
 
2641
        }
 
2642
        dm_list_add(&and_sn->selection.set, &n->list);
 
2643
 
 
2644
        return _parse_and_ex(rh, tmp, next, and_sn);
 
2645
error:
 
2646
        *next = s;
 
2647
        return NULL;
 
2648
}
 
2649
 
 
2650
/* OR_EXPRESSION := AND_EXPRESSION (OR_OP OR_EXPRESSION) */
 
2651
static struct selection_node *_parse_or_ex(struct dm_report *rh,
 
2652
                                           const char *s,
 
2653
                                           const char **next,
 
2654
                                           struct selection_node *or_sn)
 
2655
{
 
2656
        struct selection_node *n;
 
2657
        const char *tmp;
 
2658
 
 
2659
        n = _parse_and_ex(rh, s, next, NULL);
 
2660
        if (!n)
 
2661
                goto error;
 
2662
 
 
2663
        if (!_tok_op_log(*next, &tmp, SEL_OR)) {
 
2664
                if (!or_sn)
 
2665
                        return n;
 
2666
                dm_list_add(&or_sn->selection.set, &n->list);
 
2667
                return or_sn;
 
2668
        }
 
2669
 
 
2670
        if (!or_sn) {
 
2671
                if (!(or_sn = _alloc_selection_node(rh->mem, SEL_OR)))
 
2672
                        goto error;
 
2673
        }
 
2674
        dm_list_add(&or_sn->selection.set, &n->list);
 
2675
 
 
2676
        return _parse_or_ex(rh, tmp, next, or_sn);
 
2677
error:
 
2678
        *next = s;
 
2679
        return NULL;
 
2680
}
 
2681
 
 
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[],
 
2691
                                                void *private_data)
 
2692
{
 
2693
        struct dm_report *rh;
 
2694
        struct selection_node *root = NULL;
 
2695
        const char *fin, *next;
 
2696
 
 
2697
        _implicit_report_fields = _implicit_special_report_fields_with_selection;
 
2698
 
 
2699
        if (!(rh = dm_report_init(report_types, types, fields, output_fields,
 
2700
                        output_separator, output_flags, sort_keys, private_data)))
 
2701
                return NULL;
 
2702
 
 
2703
        if (!selection || !selection[0]) {
 
2704
                rh->selection_root = NULL;
 
2705
                return rh;
 
2706
        }
 
2707
 
 
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");
 
2712
                return rh;
 
2713
        }
 
2714
        rh->reserved_values = reserved_values;
 
2715
 
 
2716
        if (!strcasecmp(selection, SPECIAL_FIELD_HELP_ID) ||
 
2717
            !strcmp(selection, SPECIAL_FIELD_HELP_ALT_ID)) {
 
2718
                _display_fields(rh, 0, 1);
 
2719
                log_warn(" ");
 
2720
                _display_selection_help(rh);
 
2721
                rh->flags |= RH_ALREADY_REPORTED;
 
2722
                return rh;
 
2723
        }
 
2724
 
 
2725
        if (!(root = _alloc_selection_node(rh->mem, SEL_OR)))
 
2726
                return_0;
 
2727
 
 
2728
        if (!_parse_or_ex(rh, selection, &fin, root))
 
2729
                goto error;
 
2730
 
 
2731
        next = _skip_space(fin);
 
2732
        if (*next) {
 
2733
                log_error("Expecting logical operator");
 
2734
                log_error(_sel_syntax_error_at_msg, next);
 
2735
                log_error(_sel_help_ref_msg);
 
2736
                goto error;
 
2737
        }
 
2738
 
 
2739
        _dm_report_init_update_types(rh, report_types);
 
2740
 
 
2741
        rh->selection_root = root;
 
2742
        return rh;
 
2743
error:  
 
2744
        dm_report_free(rh);
 
2745
        return NULL;
762
2746
}
763
2747
 
764
2748
/*
766
2750
 */
767
2751
static int _report_headings(struct dm_report *rh)
768
2752
{
 
2753
        const struct dm_report_field_type *fields;
769
2754
        struct field_properties *fp;
770
2755
        const char *heading;
771
2756
        char *buf = NULL;
802
2787
                if (fp->flags & FLD_HIDDEN)
803
2788
                        continue;
804
2789
 
805
 
                heading = rh->fields[fp->field_num].heading;
 
2790
                fields = fp->implicit ? _implicit_report_fields : rh->fields;
 
2791
 
 
2792
                heading = fields[fp->field_num].heading;
806
2793
                if (rh->flags & DM_REPORT_OUTPUT_ALIGNED) {
807
2794
                        if (dm_snprintf(buf, buf_size, "%-*.*s",
808
2795
                                         fp->width, fp->width, heading) < 0) {
853
2840
        for (cnt = 0; cnt < rowa->rh->keys_count; cnt++) {
854
2841
                sfa = (*rowa->sort_fields)[cnt];
855
2842
                sfb = (*rowb->sort_fields)[cnt];
856
 
                if (sfa->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) {
 
2843
                if ((sfa->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) ||
 
2844
                    (sfa->props->flags & DM_REPORT_FIELD_TYPE_SIZE)) {
857
2845
                        const uint64_t numa =
858
2846
                            *(const uint64_t *) sfa->sort_value;
859
2847
                        const uint64_t numb =
867
2855
                        } else {        /* FLD_DESCENDING */
868
2856
                                return (numa < numb) ? 1 : -1;
869
2857
                        }
870
 
                } else {        /* DM_REPORT_FIELD_TYPE_STRING */
 
2858
                } else {
 
2859
                        /* DM_REPORT_FIELD_TYPE_STRING
 
2860
                         * DM_REPORT_FIELD_TYPE_STRING_LIST */
871
2861
                        const char *stra = (const char *) sfa->sort_value;
872
2862
                        const char *strb = (const char *) sfb->sort_value;
873
2863
                        int cmp = strcmp(stra, strb);
915
2905
 */
916
2906
static int _output_field(struct dm_report *rh, struct dm_report_field *field)
917
2907
{
 
2908
        const struct dm_report_field_type *fields = field->props->implicit ? _implicit_report_fields
 
2909
                                                                           : rh->fields;
918
2910
        char *field_id;
919
2911
        int32_t width;
920
2912
        uint32_t align;
923
2915
        size_t buf_size = 0;
924
2916
 
925
2917
        if (rh->flags & DM_REPORT_OUTPUT_FIELD_NAME_PREFIX) {
926
 
                if (!(field_id = dm_strdup(rh->fields[field->props->field_num].id))) {
 
2918
                if (!(field_id = dm_strdup(fields[field->props->field_num].id))) {
927
2919
                        log_error("dm_report: Failed to copy field name");
928
2920
                        return 0;
929
2921
                }
963
2955
                }
964
2956
        } else {
965
2957
                if (!(align = field->props->flags & DM_REPORT_FIELD_ALIGN_MASK))
966
 
                        align = (field->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) ? 
 
2958
                        align = ((field->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) ||
 
2959
                                 (field->props->flags & DM_REPORT_FIELD_TYPE_SIZE)) ? 
967
2960
                                DM_REPORT_FIELD_ALIGN_RIGHT : DM_REPORT_FIELD_ALIGN_LEFT;
968
2961
 
969
2962
                /* Including trailing '\0'! */
1013
3006
 
1014
3007
static int _output_as_rows(struct dm_report *rh)
1015
3008
{
 
3009
        const struct dm_report_field_type *fields;
1016
3010
        struct field_properties *fp;
1017
3011
        struct dm_report_field *field;
1018
3012
        struct row *row;
1026
3020
                        continue;
1027
3021
                }
1028
3022
 
 
3023
                fields = fp->implicit ? _implicit_report_fields : rh->fields;
 
3024
 
1029
3025
                if (!dm_pool_begin_object(rh->mem, 512)) {
1030
3026
                        log_error("dm_report: Unable to allocate output line");
1031
3027
                        return 0;
1032
3028
                }
1033
3029
 
1034
3030
                if ((rh->flags & DM_REPORT_OUTPUT_HEADINGS)) {
1035
 
                        if (!dm_pool_grow_object(rh->mem, rh->fields[fp->field_num].heading, 0)) {
 
3031
                        if (!dm_pool_grow_object(rh->mem, fields[fp->field_num].heading, 0)) {
1036
3032
                                log_error("dm_report: Failed to extend row for field name");
1037
3033
                                goto bad;
1038
3034
                        }