1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-22 17:35:59 +03:00
Commit Graph

167 Commits

Author SHA1 Message Date
Peter Rajnoha
3ec4813ba2 coverity: fix missing initialization
... Using uninitialized value "lockd_state" when calling "lockd_vg"
(even though lockd_vg assigns 0 to the lockd_state, but it looks at
previous state of lockd_state just before that so we need to have
that properly initialized!)

libdm/libdm-report.c:2934: uninit_use_in_call: Using uninitialized value "tm". Field "tm.tm_gmtoff" is uninitialized when calling "_get_final_time".

daemons/lvmlockd/lvmlockctl.c:273: uninit_use_in_call: Using uninitialized element of array "r_name" when calling "format_info_r_action". (just added FIXME as this looks unfinished?)
2015-07-08 14:53:30 +02:00
Alasdair G Kergon
810ab095e6 macros: Wrap PRI with FMT.
Create a set of wrappers with embedded % such as
  #define FMTu64 "%" PRIu64
2015-07-06 15:09:17 +01:00
Peter Rajnoha
9cee94372a report: select: add handler to recognize fuzzy time specification
Recognize date and time specification within selection criteria
that is formulated in a more free-form way besides to the original
basic YYYY-MM-DD HH:MM format that libdevmapper supports.

Currently, this free-form format is recognized for lv_time field.

Users are able to use expressions from this set:
  - weekday names ("Sunday" - "Saturday" or abbreviated as "Sun" - "Sat")
  - labels for points in time ("noon", "midnight")
  - labels for a day relative to current day ("today", "yesterday")
  - points back in time with relative offset from today (N is a number)
    ( "N" "seconds"/"minutes"/"hours"/"days"/"weeks"/"years" "ago")
    ( "N" "secs"/"mins"/"hrs" ... "ago")
    ( "N" "s"/"m"/"h" ... "ago")
  - time specification either in hh:mm:ss format or with AM/PM suffixes
  - month names ("January" - "December" or abbreviated as "Jan" - "Dec")

For example:

$ date
Fri Jul  3 10:11:13 CEST 2015

$ lvmconfig --type full report/time_format
time_format="%a %Y-%m-%d %T %z %Z [%s]"

$ lvs
  LV    VG     Time
  lvol0 vg     Fri 2014-08-22 21:25:41 +0200 CEST [1408735541]
  lvol2 vg     Sun 2015-04-26 14:52:20 +0200 CEST [1430052740]
  root  fedora Wed 2015-05-27 08:09:21 +0200 CEST [1432706961]
  swap  fedora Wed 2015-05-27 08:09:21 +0200 CEST [1432706961]
  lvol1 vg     Tue 2015-06-30 03:25:43 +0200 CEST [1435627543]
  lvol3 vg     Tue 2015-06-30 14:52:23 +0200 CEST [1435668743]
  lvol6 vg     Wed 2015-07-01 13:35:56 +0200 CEST [1435750556]
  lvol4 vg     Thu 2015-07-02 12:12:02 +0200 CEST [1435831922]
  lvol5 vg     Thu 2015-07-02 14:30:32 +0200 CEST [1435840232]

$ lvs -S 'time=yesterday'
  LV    VG   Time
  lvol4 vg   Thu 2015-07-02 12:12:02 +0200 CEST [1435831922]
  lvol5 vg   Thu 2015-07-02 14:30:32 +0200 CEST [1435840232]

$ lvs -S 'time since "June 30"'
  LV    VG   Time
  lvol1 vg   Tue 2015-06-30 03:25:43 +0200 CEST [1435627543]
  lvol3 vg   Tue 2015-06-30 14:52:23 +0200 CEST [1435668743]
  lvol6 vg   Wed 2015-07-01 13:35:56 +0200 CEST [1435750556]
  lvol4 vg   Thu 2015-07-02 12:12:02 +0200 CEST [1435831922]
  lvol5 vg   Thu 2015-07-02 14:30:32 +0200 CEST [1435840232]

$ lvs -S 'time since "noon June 30"'
  LV    VG   Time
  lvol3 vg   Tue 2015-06-30 14:52:23 +0200 CEST [1435668743]
  lvol6 vg   Wed 2015-07-01 13:35:56 +0200 CEST [1435750556]
  lvol4 vg   Thu 2015-07-02 12:12:02 +0200 CEST [1435831922]
  lvol5 vg   Thu 2015-07-02 14:30:32 +0200 CEST [1435840232]

$ lvs -S 'time since "2 July 9AM"'
  LV    VG   Time
  lvol4 vg   Thu 2015-07-02 12:12:02 +0200 CEST [1435831922]
  lvol5 vg   Thu 2015-07-02 14:30:32 +0200 CEST [1435840232]

$ lvs -S 'time since "2 July 1PM"'
  LV    VG   Time
  lvol5 vg   Thu 2015-07-02 14:30:32 +0200 CEST [1435840232]

...and so on.
2015-07-03 10:51:31 +02:00
Peter Rajnoha
3b1422c45c report: call appropriate handler to evaluate fuzzy reserved names and dynamic reserved values
Wire the dm_report_reserved_handler instance call in reporting/selection
infrastructure to handle reserved value actions (currently only
DM_REPORT_RESERVED_PARSE_FUZZY_NAME and DM_REPORT_RESERVED_GET_DYNAMIC_VALUE
actions).
2015-07-03 10:47:38 +02:00
Peter Rajnoha
335707b0e2 report: add infrastructure to recognize fuzzy reserved names and returning dynamic reserved values
With fuzzy names we mean the names for which it's hard or even impossible
to enumerate all possible variations of the name - the name needs to
be evaluated. An example of fuzzy name is a name which has a base
(substring) which matches and it can contain arbitrary variations
around this base. We can cover human language better with fuzzy
names as people may use several different names (or sentences) to
denote the same thing.

With dynamic values we mean the values which are not constants
and they need to be evaluated in runtime. An example of dynamic
value is a value which depends on current system state (e.g. time,
current configuration or any other state which may change and it
needs runtime evaluation).

There's a handler that can be registered with reporting/selection
using dm_report_reserved_handler instance. This is a central point
in which the computation/evaluation happens when processing reserved
values. Currently, there are two actions declared:

  DM_REPORT_RESERVED_PARSE_FUZZY_NAME
  (translates fuzzy name into canonical name)

  DM_REPORT_RESERVED_GET_DYNAMIC_VALUE
  (gets value for canonical name)

The handler is then registered as value in struct
dm_report_reserved_value (see explaining comments besided
the struct dm_report_reserved_value in libdevmapper.h).

Also, this patch provides support for simple caching of values
used during report/selection via dm_report_value_cache_{set,get}.
This is supposed to be used mainly in the dm_report_reserved_handler
instances to save values among calls so all the handler calls work
with the same base value used in computation/evaluation and/or
possibly to save resources if the evaluation is more time-consuming.
The cache is attached to the dm_report handle and so the cache is
dropped one dm_report is dropped.
2015-07-03 10:47:09 +02:00
Peter Rajnoha
a32d5a4afc report: adjust shared flags based on expected type for reserved values
Generic numbers and time values share some operators so make sure
we have the flags correctly adjusted based on expected type if
we're using reserved values.
2015-07-02 16:12:01 +02:00
Peter Rajnoha
454782f1a3 report: fix regression while selecting string fields using synonyms
$ lvs -o name,cache_policy vg/lvol0
  LV    Cache Policy
  lvol0

Before this patch:
$ lvs -o name,cache_policy -S 'cache_policy=undefined' vg/lvol0
  (no match)

With this patch applied:
$ lvs -o name,cache_policy -S 'cache_policy=undefined' vg/lvol0
  LV    Cache Policy
  lvol0
2015-07-02 11:31:54 +02:00
Alasdair G Kergon
f6ad48f0e5 libdm: Rename struct time_value variables.
warning: declaration of ‘time’ shadows a global declaration
2015-06-30 16:17:22 +01:00
Peter Rajnoha
ded279f826 report: add support for time (basic)
This patch adds support for time values used in reporting fields.
The raw values are always stored as number of seconds since epoch.

The support that comes with this patch is the basic one which allows
only for recognition of strictly formatted date and time in selection
criteria (the format follows a subset of formats defined by ISO 8601):

  date time timezone

  date:
    YYYY-MM-DD (or shortly YYYYMMDD)
    YYYY-MM (shortly YYYYMM), auto DD=1
    YYYY, auto MM=01 and DD=01

  time:
    hh:mm:ss (or shortly hhmmss)
    hh:mm (or shortly hhmm), auto ss=0
    hh (or shortly hh), auto mm=0, auto ss=0

  timezone (always with + or - sign):
    +hh:mm or -hh:mm (or shortly +hhmm or -hhmm)
    +hh or -hh

Or directly the time (number of seconds) since Epoch (1970-01-01 00:00:00 UTC)
when the number value is prefixed by "@":

   @number_of_seconds_since_epoch

This patch also adds aliases for comparison operators
used together with time values which are more intuitive
to use:
  since (as alias for >=)
  after (as alias for >)
  until (as alias for <=)
  before (as alias for <)

For example:

$ lvmconfig --type full report/time_format
time_format="%Y-%m-%d %T %z %Z [%s]"

$ lvs -o name,time vg
  LV    Time
  lvol0 2015-06-28 21:25:41 +0200 CEST [1435519541]
  lvol1 2015-06-30 03:25:43 +0200 CEST [1435627543]
  lvol2 2015-04-26 14:52:20 +0200 CEST [1430052740]
  lvol3 2015-06-30 14:52:23 +0200 CEST [1435668743]

$ lvs vg -o name,time -S 'time since "2015-04-26 15:00" && time until "2015-06-30"'
  LV    Time
  lvol0 2015-06-28 21:25:41 +0200 CEST [1435519541]
  lvol1 2015-06-30 03:25:43 +0200 CEST [1435627543]
  lvol3 2015-06-30 14:52:23 +0200 CEST [1435668743]

$ lvs vg -o name,time -S 'time since "2015-04-26 15:00" && time until "2015-06-30 6:00"'
  LV    Time
  lvol0 2015-06-28 21:25:41 +0200 CEST [1435519541]
  lvol1 2015-06-30 03:25:43 +0200 CEST [1435627543]

$ lvs vg -o name,time -S 'time since @1435519541'
  LV    Time
  lvol0 2015-06-28 21:25:41 +0200 CEST [1435519541]
  lvol1 2015-06-30 03:25:43 +0200 CEST [1435627543]
  lvol3 2015-06-30 14:52:23 +0200 CEST [1435668743]

This is basic time recognition support that is directly a part of
libdevmapper. Recognition of more free-form expressions will be a
part of subsequent patches.
2015-06-30 15:15:10 +02:00
Peter Rajnoha
d7b9349ce7 cleanup: report: use internal wrapper for various variables used for handling reserved values
Just a cleanup - wrap several variables we use to handle reserved
values into a structure for easier manipulation in the code.
2015-06-30 10:47:51 +02:00
Peter Rajnoha
d8996a17d1 select: add support for range reserved values and flagging named-only values
This patch allows for registration and recognition of reserved
values which are ranges, so they're composed of two values actually
to denote the lower and upper bound for the range (stored as an array
with exactly two items to define the boundaries).

Also, this patch allows for flagging reserved values as named-only
which means that such values are not strictly reserved. The strictly
reserved values are reserved values as used before this patch.

Distinction between strictly-reserved and named-only values
is clearly visible with comparisons. Normally, strictly reserved
value is not accounted for if we do "greater than" or "lower than"
comparisons, for example:

1  2  3 ....
   |
  abc

- we have "abc" as reserved value for field with value "2"
- the value reported for the field is "abc" (or "2", it doesn't matter here)
- the selection we're processing is -S 'field < abc'
- the result of the selection gives nothing as "abc" is strictly
reserved value (bound to "2") and there's no order defined for
it and it would only match if we directly compared the value
(so -S 'field = abc' would match)

With named-only values, the "abc" is named-only value for "2",
so selection -S 'field < abc" is the same as using -S 'field < 2'.
The "abc" is just an alias for some value so the value or its
assigned name can be used equally in selection criteria.
2015-06-30 10:47:50 +02:00
Zdenek Kabelac
b8dfd7a53d cleanup: indent mismatch
Aling break (Coverity).
2015-05-08 15:15:10 +02:00
Peter Rajnoha
82f6dbfaf7 select: fix matching reserved values while <,<=,>,>= is used in selection criteria
Scenario:

$ vgs -o+vg_mda_copies
  VG     #PV #LV #SN Attr   VSize VFree #VMdaCps
  fedora   1   2   0 wz--n- 9.51g    0  unmanaged
  vg      16   9   0 wz--n- 1.94g 1.83g         2

$ lvs -o+read_ahead vg/lvol6 vg/lvol7
  LV    VG   Attr       LSize Pool Origin Data%  Rahead
  lvol6 vg   Vwi-a-tz-- 1.00g pool lvol5  0.00      auto
  lvol7 vg   Vwi---tz-k 1.00g pool lvol6         256.00k

Before this patch:

$vgs -o vg_name,vg_mda_copies -S 'vg_mda_copies < unmanaged'
  VG   #VMdaCps
  vg          2

Problem:
Reserved values can be only used with exact match = or !=, not <,<=,>,>=.
In the example above, the "unamanaged" is internally represented as
18446744073709551615, but this should be ignored while not comparing
field directly with "unmanaged" reserved name with = or !=. Users
should not be aware of this internal mapping of the reserved value
name to its internal value and hence it doesn't make sense for such
reserved value to take place in results of <,<=,> and >=.
There's no order defined for reserved values!!! It's a special
*reserved* value that is taken out of the usual value range
of that type.

This is very similar to what we have already fixed with
2f7f6932dc, but it's the other way round
now - we're using reserved value name in selection criteria now
(in the patch 2f7f693, we had concrete value and we compared it
with the reserved value). So this patch completes patch 2f7f693.

This patch also fixes this problem:

$ lvs -o+read_ahead vg/lvol6 vg/lvol7 -S 'read_ahead > 32k'
  LV    VG   Attr       LSize Pool Origin Data%  Rahead
  lvol6 vg   Vwi-a-tz-- 1.00g pool lvol5  0.00      auto
  lvol7 vg   Vwi---tz-k 1.00g pool lvol6         256.00k

Problem:
In the example above, the internal reserved value "auto" is in the
range of selection "> 32k" - it shouldn't match as well. Here the
"auto" is internally represented as MAX_DBL and of course, numerically,
MAX_DBL > 256k. But for users, the reserved value should be uncomparable
to any number so the mapping of the reserved value name to its interna
 value is transparent to users. Again, there's no order defined for
reserved values and hence it should never match if using <,<=,>,>=
operators.

This is actually exactly the same problem as already described in
2f7f6932dc, but that patch failed for
size field types because of incorrect internal representation used.

With this patch applied, both problematic scenarios mentioned
above are fixed now:

$ vgs -o vg_name,vg_mda_copies -S 'vg_mda_copies < unmanaged'
(blank)

$ lvs -o+read_ahead vg/lvol6 vg/lvol7 -S 'read_ahead > 32k'
  LV    VG   Attr       LSize Pool Origin Rahead
  lvol7 vg   Vwi---tz-k 1.00g pool lvol6  256.00k
2015-04-24 09:48:57 +02:00
Peter Rajnoha
f32973c78e select: mention { } use in lvm.8 man page and '-S help' properly 2015-04-08 11:14:16 +02:00
Peter Rajnoha
123a3383a0 libdm: report: add dm_report_object_is_selected
The new dm_report_object_is_selected fn makes it possible to opt whether the
object reported should be displayed on output or not. Also, in addition to
that, it makes it possible to save the result of selection (either 0 or 1).

So dm_report_object_is_selected is simply  more general form of object
reporting fn - combinations now allow for:

  dm_report_object_is_selected(rh, object, 1, NULL):
  This is exactly the original dm_report_object fn and it's fully equal
  to it.

  dm_report_object_is_selected(rh, object, 0, selected):
  Do not display the result on output, but save info whether the object
  is selected or not in 'selected' variable.

  dm_report_object_is_selected(rh, object, 1, selected):
  Display the result on output (if it passes selection criteria) and save
  whether the object is selected or not in 'selected' variable.

  dm_report_object(rh, object, 0, NULL):
  This combination is not allowed - it will end up with internal error.
  We're either interested in selection status or we want to display the
  result on output or both, but never nothing of the two.
2015-02-10 16:04:38 +01:00
Alasdair G Kergon
651549594e libdm-report: Fix order of NULL dm_report check. 2015-01-17 10:50:54 +00:00
Peter Rajnoha
aaf25ec6bd libdm: report: also check whether field type is supported for field-specific reserved value
We only checked global per-report-type reserved values for compatibility
with selection code. This patch also adds a check for per-report-field
reserved values. This avoids problems where unsupported report type is
used as reserved value which could cause hard to debug problems
otherwise. So this additional check stops from registering unsupported
and unhandled per-field reserved values.

Registerting such unsupported reserved value is a programmatic error,
so report internal error in this case to stop us from making a mistake
here in the future or even today where STR_LIST fields can't have
reserved values yet.
2014-12-18 11:29:48 +01:00
Peter Rajnoha
f94f8463b0 libdm: report: fix incorrect memory use while using --select with --unbuffered for reporting
Under certain circumstances, the selection code can segfault:

$ vgs --select 'pv_name=~/dev/sda' --unbuffered vg0
  VG   #PV #LV #SN Attr   VSize   VFree
  vg0    6   3   0 wz--n- 744.00m 588.00m
Segmentation fault (core dumped)

The problem here is the use of --ubuffered together with regex used in
selection criteria. If the report output is not buffered, each row is
discarded as soon as it is reported. The bug is in the use of report
handle's memory - in the example above, what happens is:

  1) report handle is initialized together with its memory pool

  2) selection tree is initialized from selection criteria string
     (using the report handle's memory pool!)

    2a) this also means the regex is initialized from report handle's mem pool

  3) the object (row) is reported

    3a) any memory needed for output is intialized out of report handle's mem pool
    3b) selection criteria matching is executed - if the regex is checked the
        very first time (for the very first row reported), some more memory
        allocation happens as regex allocates internal structures "on-demand",
        it's allocating from report handle's mem pool (see also step 2a)

  4) the report output is executed

  5) the object (row) is discarded, meaning discarding all the mem pool
     memory used since step 3.

Now, with step 5) we have discarded the regex internal structures from step 3b.
When we execute reporting for another object (row), we're using the same
selection criteria (step 3b), but tihs is second time we're using the regex
and as such, it's already initialized completely. But the regex is missing the
internal structures now as they got discarded in step 5) from previous
object (row) reporting (because we're using "unbuffered" reporting).

To resolve this issue and to prevent any similar future issues where each
object/row memory is discarded after output (the unbuffered reporting) while
selection tree is global for all the object/rows, use separate memory pool
for report's selection.

This patch replaces "struct selection_node *selection_root" in struct
dm_report with new struct selection which contains both "selection_root"
and "mem" for separate mem pool used for selection.

We can change struct dm_report this way as it is not exposed via libdevmapper.

(This patch will have even more meaning for upcoming patches where selection
is used even for non-reporting commands where "internal" reporting and
selection criteria matching happens and where the internal reporting is
not buffered.)
2014-12-09 10:41:55 +01:00
Peter Rajnoha
42d71b9af3 libdm: report: return immediately from dm_report_compact_fields without error if there are no rows
Let's make dm_report_compact_fields consistent with dm_report_output fn
which also returns with success immediately if there are no rows.
2014-12-05 15:10:50 +01:00
Peter Rajnoha
f867dc6b29 libdm: report: compact output applicable only if report is buffered 2014-12-05 14:18:51 +01:00
Peter Rajnoha
5edf6a56c4 libdm: report: add dm_report_compact_fields
Add new dm_report_compact_fields function to cause report outout
(dm_report_output) to ignore fields which don't have any value set
in any of the rows reported. This provides support for compact report
output where only fields which have something to report are displayed.
2014-12-05 12:00:28 +01:00
Zdenek Kabelac
8bc7b4f926 libdm: there is no element in item 0
Items[0] holds only counter in .len.
So don't zero already zeroed items[0].len assigned above.

(finishing fc935495c8)
2014-11-24 14:38:54 +01:00
Peter Rajnoha
fb220314ec report: add some comments about how string list is stored internally 2014-11-24 13:14:33 +01:00
Peter Rajnoha
b9601b8353 report: add some comments about how string list is stored internally 2014-11-24 10:48:01 +01:00
Zdenek Kabelac
678cc4e375 libdm: report fix memleak on error path
When _alloc_selection_node() fails, rh should be destroyed.

Use 'bad:' label since we have goto_bad with stack embeded.
2014-11-23 00:49:04 +01:00
Zdenek Kabelac
fc935495c8 libdm: fix reporting of empty string list
Don't write behind the allocated array when list is empty.
Use index 0 for the allocated element.

Error triggered by i.e.:  lvs -a -o all,lv_modules
2014-11-22 18:50:53 +01:00
Alasdair G Kergon
9a5910bdf9 pre-release 2014-11-11 14:13:00 +00:00
Peter Rajnoha
2f7f6932dc report: selection: fix selection criteria to not match reserved values when using >, <, >=, <
Some values are reserved for special purpose like 'undefined', 'unmanaged' etc.
When using >, <, >= and < comparison operators where the range is considered,
do not include reserved values as proper values in this range which
would otherwise result in not so obvious criteria match (as the reserved value is
actually transparent for the user). It's incorrect.

Example scenario:
$ vgs -o vg_name,vg_mda_copies vg1 vg2
  VG   #VMdaCps
  vg1          1
  vg2  unmanaged

The "unmanaged" is actually mapped onto reserved value
18446744073709551615 (2^64 - 1) internally.

Such reseved value is already caught on selection criteria input
properly:

$ vgs -o name,vg_mda_copies vg1 vg2 -S 'vg_mda_copies=18446744073709551615'
  Numeric value 18446744073709551615 found in selection is reserved.

However, we still need to fix situaton where the reserved value may be
included in resulting range:

Before this patch:
$ vgs -o vg_name,vg_mda_copies vg1 vg2 -S 'vg_mda_copies >= 1'
  VG   #VMdaCps
  vg1          1
  vg2  unmanaged

With this patch applied:
$ vgs -o vg_name,vg_mda_copies vg1 vg2 -S 'vg_mda_copies >= 1'
  VG   #VMdaCps
  vg1         1

From the examples above, we can see that without this patch applied,
the vg_mda_copies >= 1 also matched the reserved value 18446744073709551615
(which is represented by the "unamanged" string on report). When
applying the operators, such values must be skipped! They're meant to
be matched only against their string representation only, e.g.:

$ vgs -o name,vg_mda_copies vg1 vg2 -S 'vg_mda_copies=unmanaged'
  VG   #VMdaCps
  vg2  unmanaged

...or any synonyms:

$ vgs -o name,vg_mda_copies vg1 vg2 -S 'vg_mda_copies=undefined'
  VG   #VMdaCps
  vg2  unmanaged
2014-10-27 11:25:08 +01:00
Zdenek Kabelac
fa1a0d170a cleanup: drop extra ()
Pure  '==' test doesn't need extra ().
2014-08-29 13:11:35 +02:00
Zdenek Kabelac
19375e4fca cleanup: assignment into ()
Put is_float=1 into () - so the intention is obvious.
Remove uneeded extra check for for  *s != 0,
since it's already checked for either digit or '.'.
2014-08-29 13:11:34 +02:00
Peter Rajnoha
02dc3c773e report: add dm_report_field_string_list_unsorted 2014-08-25 16:11:40 +02:00
Jonathan Brassow
4f05e55f84 cleanup: Remove extra ';' from the end of a line. 2014-08-19 09:57:30 -05:00
Zdenek Kabelac
24df01f735 cleanup: avoid double assign
Skip setting a value to a variable which is never
used and overwritten/set afterwards.
2014-08-19 14:33:06 +02:00
Peter Rajnoha
fa793bed64 select: add support for selection to match string list subset, recognize { } operator
Using "[ ]" operator together with "&&" (or ",") inside causes the
string list to be matched if and only if all the items given match
the value reported and the number of items also match. This is
strict list matching and the original behaviour we already have.

In contrast to that, the new "{ }" operator together with "&&" inside
causes the string list to be matched if and only if all the items given
match the value reported but the number of items don't need to match.
So we can provide a subset in selection criteria and if the subset
is found, it matches.

For example:

$ lvs -o name,tags
  LV    LV Tags
  lvol0 a
  lvol1 a,b
  lvol2 b,c,x
  lvol3 a,b,y

$ lvs -o name,tags -S 'tags=[a,b]'
  LV    LV Tags
  lvol1 a,b

$ lvs -o name,tags -S 'tags={a,b}'
  LV    LV Tags
  lvol1 a,b
  lvol3 a,b,y

So in the example above the a,b is subset of a,b,y and therefore
it also matches.

Clearly, when using "||" (or "#") inside, the { } and [ ] is the
same:

$ lvs -o name,tags -S 'tags=[a#b]'
  LV    LV Tags
  lvol0 a
  lvol1 a,b
  lvol2 b,c,x
  lvol3 a,b,y

$ lvs -o name,tags -S 'tags={a#b}'
  LV    LV Tags
  lvol0 a
  lvol1 a,b
  lvol2 b,c,x
  lvol3 a,b,y

Also in addition to the above feature, fix list with single value
matching when using [ ]:

Before this patch:
$ lvs -o name,tags -S 'tags=[a]'
  LV    LV Tags
  lvol0 a
  lvol1 a,b
  lvol3 a,b,y

With this patch applied:
$ lvs -o name,tags -S 'tags=[a]'
  LV    LV Tags
  lvol0 a

In case neither [] or {} is used, assume {} (the behaviour is not
changed here):

$ lvs -o name,tags -S 'tags=a'
  LV    LV Tags
  lvol0 a
  lvol1 a,b
  lvol3 a,b,y

So in new terms 'tags=a' is equal to 'tags={a}'.
2014-08-13 16:10:12 +02:00
Peter Rajnoha
6dd98c1fa8 select: fix string list selection to match whole words only but not prefixes of searched string
$ lvs -o name,tags vg/lvol0
  LV    LV Tags
  lvol0 a

Before this patch:

$ lvs -o name,tags vg/lvol0 -S 'tags=[a]'
  LV    LV Tags
  lvol0 a

$ lvs -o name,tags vg/lvol0 -S 'tags=[ab]'
  LV    LV Tags
  lvol0 a
(incorrect!)

$ lvs -o name,tags vg/lvol0 -S 'tags=[abc]'
  LV    LV Tags
  lvol0 a
(incorrect!)

With this patch applied:

$ lvs -o name,tags vg/lvol0 -S 'tags=[a]'
  LV    LV Tags
  lvol0 a

$ lvs -o name,tags vg/lvol0 -S 'tags=[ab]'
(no result - correct!)

$ lvs -o name,tags vg/lvol0 -S 'tags=[abc]'
(no result - correct!)
2014-08-13 16:04:02 +02:00
Peter Rajnoha
e38af4e28f libdm: report: fix string list internal representation if delimiter is composed of more than one char 2014-07-10 16:18:05 +02:00
Alasdair G Kergon
a098cba0eb report: Rename common fields to special fields.
Change the help heading from 'Common Fields' to 'Special Fields' for
the fields: selected, help, ?

Remove the code that does 'all' processing with these special fields as
each of them changes the behaviour of the command in an undesirable way.

'lvs -o all,selected' was of course just printing help.
(via internal expansion to 'lv_all,common_all')

and if we ignored the help fields, then '-o common_all' would still
pull in 'selected' and change the way rows were output.
2014-07-09 23:33:09 +01:00
Peter Rajnoha
0956fd230f report: adapt selection code to recognize per-field reserved values
In contrast to per-type reserved values that are applied for all fields
of that type, per-field reserved values are only applied for concrete
field only.

Also add 'struct dm_report_field_reserved_value' to libdm for per-field
reserved value definition. This is defined by field number (an index
in the 'fields' array which is given for the dm_report_init_with_selection
function during report initialization) and the value to use for any
of the specified reserved names.
2014-07-04 15:50:50 +02:00
Peter Rajnoha
e329c3146d coverity: mark new switch cases with 'fall through' comment for coverity to stop complaining 2014-06-25 08:51:37 +02:00
Peter Rajnoha
3208396ce5 coverity: fix issues reported by coverity 2014-06-24 14:58:53 +02:00
Peter Rajnoha
9c3c357874 select: add message about 'help' field to get more help on each error hit during selection parsing
Inform about 'help' to get more help about selection fields and operators
after each syntax error hit:

  "Use 'help' for selection to get more help."
2014-06-23 12:21:17 +02:00
Peter Rajnoha
69075d0b43 select: also mark uncomparable/unselectable fields in field/selection help 2014-06-23 12:20:49 +02:00
Peter Rajnoha
2d48ef7f04 select: add FLD_UNCOMPARABLE flag for fields which can't be compared
A field where it has no meaning to do any type of comparison is the
implicit "help" or "?" field. The error given was a bit cryptic
before this patch, the FLD_UNCOMPARABLE flag makes it easier to identify
this situation anywhere in the code and provide much better error message.
This flag can be applied to other fields that may appear in the future -
mostly usable for implicit fields as they always have special purpose
(so we're not exporting it in libdevmapper for now - usual reporting
fields don't need this).

Before this patch:

$ vgs -S help=1
  dm_report_object: no data assigned to field help
  dm_report_object: no data assigned to field help

(...which is true actually, but let's provide something better...)

With this patch applied:

$vgs -S help=1
  Selection field is uncomparable: help.
  Selection syntax error at 'help=1'.

$vgs -S '(name=vg && help=1) || vg_size > 1g'
  Selection field is uncomparable: help.
  Selection syntax error at 'help=1) || vg_size > 1g'.
2014-06-23 10:09:58 +02:00
Peter Rajnoha
f16da6ef23 report: display explicit fields first, then implicit fields in field help
It's better to have implicit fields at the very end of the output
so users can see them without scrolling back if the list of fields
is long (the "help" is also an implicit field now so it should be
easily visible).
2014-06-19 16:14:53 +02:00
Peter Rajnoha
a40bc36b2e libdevmapper: revoke commit 7c86131233
We have "help" and "?" defined as implicit fields now. As such, we
don't need to export these names in libdevmapper (as it was introduced
by commit 7c86131233 within this release).
If anyone uses these field names by mistake, the libdevmapper code can
error out correctly if it detects that the set of explicit field names
(the ones supplied by "fields" arg in dm_report_init/dm_report_init_with_selection)
contains any of the implicit field names (the ones defined internally
by libdevmapper itself).
2014-06-19 16:09:32 +02:00
Peter Rajnoha
cd7325f18d report: make "help" and "?" field implicit
Making "help" and "?" implicit also simplifies code since the
dm_report_init caller (lvm/dmsetup) doesn't need to check on
dm_report_init return whether "help" or "?" was hit while parsing
fields/sort keys in libdevmapper.

The libdevmapper now sets internal "RH_ALREADY_REPORTED" flag
after it reports the "help" or "?" implicit field. Then libdevmapper
itself checks for this flag in dm_report_object and if found,
the actual reporting is skipped (because the "help" implicit field
was reported instead of the actual report).
2014-06-19 16:09:31 +02:00
Peter Rajnoha
012dab7aa3 select: add list of allowed types for each selection operator mentioned in help 2014-06-19 15:19:54 +02:00
Peter Rajnoha
0548a82e63 cleanup: gcc warnings and report-select test vs snap_percent 0%
Fix gcc warnings:
libdm-report.c:1952:5: warning: "end_op_flag_hit" may be used uninitialized in this function [-Wmaybe-uninitialized]
libdm-report.c:2232:28: warning: "custom" may be used uninitialized in this function [-Wmaybe-uninitialized]

And snap_percent is not 0% in dm < 1.10.0 so
don't test comparison with 0% here.
2014-06-18 13:26:47 +02:00
Peter Rajnoha
f88130fd85 report: add support for implicit fields, add implicit "selected" field
Implicit fields are fields that are registered with the report
and reported internally by libdevmapper itself (compared to explicit
fields that are registered by the layer above libdevmapper - e.g. LVM,
dmsetup...).

The "selected" field is the implicit field (for now the only one)
that reports the result of the selection. Since the selection itself
is the property of the libdevmapper, the upper layer using dm_report_init
can't register this field itself and it must be done directly at
libdevmapper layer.

The "selected" field is internally registered as part of the "common"
report type with id 0x80000000 (the last bit in uin32_t) which is then
reserved (the explicit report types are then checked if they do not
contain this id and if yes, we error out).

This way, the "selected" field is recognized by all libdevmapper users
that initialize the reporting with "dm_report_init_with_selection".
If reporting is initialized with the classical "dm_report_init",
there's no functional change (so the "selected" field is not defined
and it's not recognized).
2014-06-17 16:27:21 +02:00
Peter Rajnoha
51a86dc2f8 report: select: add support for percent selection 2014-06-17 16:27:21 +02:00
Peter Rajnoha
cfed0d09e8 report: select: refactor: move percent handling code to libdm for reuse 2014-06-17 16:27:21 +02:00
Peter Rajnoha
35c4e4489c report: select: add support for reserved value recognition in report selection string - add struct dm_report_reserved_value
Make dm_report_init_with_selection to accept an argument with an
array of reserved values where each element contains a triple:

  {dm report field type, reserved value, array of strings representing this value}

When the selection is parsed, we always check whether a string
representation of some reserved value is not hit and if it is,
we use the reserved value assigned for this string instead of
trying to parse it as a value of certain field type.

This makes it possible to define selections like:

   ... --select lv_major=undefined (or -1 or unknown or undef or whatever string representations are registered for this reserved value in the future)
   ... --select lv_read_ahead=auto
   ... --select vg_mda_copies=unmanaged

With this, each time the field value of certain type is hit
and when we compare it with the selection, we use the proper
value for comparison.

For now, register these reserved values that are used at the moment
(also more descriptive names are used for the values):

  const uint64_t _reserved_number_undef_64 = UINT64_MAX;
  const uint64_t _reserved_number_unmanaged_64 = UINT64_MAX - 1;
  const uint64_t _reserved_size_auto_64 = UINT64_MAX;

 {
  {DM_REPORT_FIELD_TYPE_NUMBER, _reserved_number_undef_64, {"-1", "undefined", "undef", "unknown", NULL}},
  {DM_REPORT_FIELD_TYPE_NUMBER, _reserved_number_unmanaged_64, {"unmanaged", NULL}},
  {DM_REPORT_FIELD_TYPE_SIZE, _reserved_size_auto_64, {"auto", NULL}},
  NULL
 }

Same reserved value of different field types do not collide.
All arrays are null-terminated.

The list of reserved values is automatically displayed within
selection help output:

  Selection operands
  ------------------
  ...

  Reserved values
  ---------------
    -1, undefined, undef, unknown   - Reserved value for undefined numeric value. [number]
    unmanaged                       - Reserved value for unmanaged number of metadata copies in VG. [number]
    auto                            - Reserved value for size that is automatically calculated. [size]

  Selection operators
  -------------------
  ...
2014-06-17 16:27:21 +02:00
Peter Rajnoha
a075ec15c4 report: select: show field type in field list if in context of selection
When the field list is displayed as help for constructing selection
criteria, show also the field value type. This is useful for users
to know what set of operators are allowed for the type - the subsequent
"Selection operands" section in the help output summarize all known
types that can be used in selection.
2014-06-17 16:27:21 +02:00
Peter Rajnoha
6d667adeea report: select: add help for creating selections
The "<lvm command> -S/--select help" shows help (including list of fields to match against):

  ...field list here including the field type name...

  Selection operands
  ------------------
    field               - Reporting field.
    number              - Non-negative integer value.
    size                - Floating point value with units specified.
    string              - Characters quoted by ' or " or unquoted.
    string list         - Strings enclosed by [ ] and elements delimited by either
                          "all items must match" or "at least one item must match" operator.
    regular expression  - Characters quoted by ' or " or unquoted.

  Selection operators
  -------------------
    Comparison operators:
        =~  - Matching regular expression.
        !~  - Not matching regular expression.
         =  - Equal to.
        !=  - Not equal to.
        >=  - Greater than or equal to.
         >  - Greater than
        <=  - Less than or equal to.
         <  - Less than.

    Logical and grouping operators:
        &&  - All fields must match
         ,  - All fields must match
        ||  - At least one field must match
         #  - At least one field must match
         !  - Logical negation
         (  - Left parenthesis
         )  - Right parenthesis
         [  - List start
         ]  - List end
2014-06-17 16:27:21 +02:00
Peter Rajnoha
03a3f6078d report: select: add support for comparing string lists with selection defined 2014-06-17 16:27:20 +02:00
Peter Rajnoha
8faa4ded9c report: select: add support for processing string lists in selection
Selection list items are enclosed in '[' and ']' (if there's only
one item, the '[' and ']' can be omitted). Each element of the list
is a string (either quoted or unquoted, like the usual string operand
used in selection) and each element is delimited either by conjunction
(meaining "match all") or disjunction operator (meaning "match any").

For example, if "," is the conjuction operator and "/" is the
disjunction operator then:

  lv_tags=[a,b,c]

...will match all fields where tags contain *all* a, b and c.

  lv_tags=[a/b/c]

...will match all fields where tags contain *any* of a, b, or c.

Mixing operators within the list is not supported:

  lv_tags=[a,b/c]

...will give an error.

The order in which items are defined in the selection do not matter.

This patch enhances the selection parsing functionality to recognize
such lists.
2014-06-17 16:27:20 +02:00
Peter Rajnoha
a6694cfc29 report: select: add DM_REPORT_FIELD_TYPE_STRING_LIST to make a difference between STRING and STRING_LIST
The {pv,vg,lv,seg}_tags and lv_modules fields are reported as string
lists using the new dm_report_field_string_list - so we just pass
the list to the fn that takes care of reporting and item sorting itself.
2014-06-17 16:27:20 +02:00
Peter Rajnoha
76467bdcfd report: select: add dm_report_field_string_list to libdm
Add a separate dm_report_field_string_list fn to libdevmapper to
support reporting string lists. Before, the code used libdevmappers's
dm_report_field_string fn which required formatting the list to a
single string. This functionality is now moved to libdevmapper
and the code that needs to report the string list just needs
to pass the list itself and libdevmapper will take care of this.
This also enhances code reuse.

The dm_report_field_string_list also accepts an argument to define
custom delimiter to use. If not defined, a default "," (comma) is
used as item delimiter in the string list reported.

The dm_report_field_string_list automatically sorts the items in
the list before formatting it to a final string. It also encodes
the position and length within the final string where each element
can be found. This can be used to support checking against each
list item reported since since when formatted as a single string
for the actual report, we would lose this information otherwise
(we don't want to copy each item, the position and length within
the final string is enough for us to get the original items back).

When such lists are checked against the selection tree, we can check
each item individually this way and we can support operators like
"match any" and "match all".
2014-06-17 16:27:20 +02:00
Peter Rajnoha
bc6458de87 report: select: use _check_report_selection in dm_report_object to report only objects that satisfy the report selection
This is rebased and edited version of the original design and
patch proposed by Jun'ichi Nomura:
  http://www.redhat.com/archives/dm-devel/2007-April/msg00025.html

This activates the actual selection process in dm_report_object.
2014-06-17 16:27:20 +02:00
Peter Rajnoha
d33280a978 report: select: add _check_selection fn to support checking fields against given selections
This is rebased and edited versions of the original design and
patch proposed by Jun'ichi Nomura:
  http://www.redhat.com/archives/dm-devel/2007-April/msg00025.html

The _check_selection implements the actual field checking against the
selection tree.
2014-06-17 16:27:20 +02:00
Peter Rajnoha
0103738ef5 report: select: add dm_report_init_with_selection to libdm
This is rebased and edited version of the original design and
patch proposed by Jun'ichi Nomura:
  http://www.redhat.com/archives/dm-devel/2007-April/msg00025.html

The dm_report_init_with_selection is the same as dm_report_init
but it contains an additional argument to set the selection
in the form of a string that contains field names to check against and
selection operators. The selection string is parsend and a selection
tree is composed for use in the checks against individual fields when
the report is processed. The parsed selection tree is stored in dm_report
structure as "selection_root".
2014-06-17 16:27:20 +02:00
Peter Rajnoha
2c3e84a68d report: select: add supporting infrastucture for token parsing in report selections
This is rebased and edited version of the original design and
patch proposed by Jun'ichi Nomura:
  http://www.redhat.com/archives/dm-devel/2007-April/msg00025.html

Add support for parsing numbers, strings (quoted or unquoted), regexes
and operators amogst these operands in selection condition supplied.
2014-06-17 16:27:20 +02:00
Peter Rajnoha
4118dd8da3 report: select: add structs for report selection
This is rebased and edited version of the original design and
patch proposed by Jun'ichi Nomura:
  http://www.redhat.com/archives/dm-devel/2007-April/msg00025.html

This patch defines operators and structures that will be used
to store the report selection against which the actual values
reported will be checked.

  Selection operators
  -------------------
    Comparison operators:
        =~  - Matching regular expression.
        !~  - Not matching regular expression.
         =  - Equal to.
        !=  - Not equal to.
        >=  - Greater than or equal to.
         >  - Greater than
        <=  - Less than or equal to.
         <  - Less than.

    Logical and grouping operators:
        &&  - All fields must match
         ,  - All fields must match
        ||  - At least one field must match
         #  - At least one field must match
         !  - Logical negation
         (  - Left parenthesis
         )  - Right parenthesis
2014-06-17 16:27:20 +02:00
Peter Rajnoha
7dbbc05a69 report: select: add DM_REPORT_FIELD_TYPE_SIZE to make a difference between NUMBER and SIZE
This makes it easier to check against the fields (following patches for
report selection) and check whether size units are allowed or not
with the field value.
2014-06-17 16:27:20 +02:00
Zdenek Kabelac
eb316fec33 libdm: dm_report_object report error for no data
NULL data would cause problems....
2014-06-12 11:56:06 +02:00
Zdenek Kabelac
3d9737442b libdm: dm_report_object avoid duplicat strlen call
Remember strlen result.
2014-06-12 11:56:06 +02:00
Peter Rajnoha
7c86131233 report: export DM_REPORT_FIELD_RESERVED_NAME_{HELP,HELP_ALT} and show help on '<lvm_command> -O help'
Share DM_REPORT_FIELD_RESERVED_NAME_{HELP,HELP_ALT} between libdm and
any libdm user to handle reserved field names, in this case the virtual
field name to show help instead of failing on unrecognized field.
The libdm user also needs to check the field name so it can fire
proper code in this case (cleanup, exit etc.).
2014-05-15 10:58:14 +02:00
Zdenek Kabelac
eb4b03768f libdm: catch wrongly reported values
Add internal error warning when string value is used
as sort value for numerical field.

Using log_warn since the function itself does not return error,
so we do not confuse log_error() checker.
2013-11-15 12:38:37 +01:00
Zdenek Kabelac
f260f99d57 cleanup: switch log_error to log_warn
Use log_warn to print non-fatal warning messages.

Use of log_error would confuse checker for testing
whether proper error has been reported for some real error.
2012-10-17 15:41:35 +02:00
Zdenek Kabelac
fd417db274 check: add internal errors for unexpected paths
Adding couple INTERNAL_ERROR reports for unwanted parameters:

Ensure the 'top' metadata node cannot be NULL for lvmetad.

Make obvious vginfo2 cannot be NULL.

Report internal error if handler and vg is undefined.

Check for handle in poll_vg().

Ensure seg is not NULL in dev_manager_transient().

Report missing read_ahead for _lv_read_ahead_single().

Check for report handler in dm_report_object().

Check missing VG in _vgreduce_single().
2012-08-23 14:37:52 +02:00
Zdenek Kabelac
2c711a2502 Do not crash for NULL sort_key
Guard against NULL pointer for sort_key and let it behave like an empty
string would have been passed in (i.e. no key).
2012-02-10 14:00:07 +00:00
Zdenek Kabelac
586f310618 Remove meaningless const type qualifiers on cast type
Static analyzis noticed we do not really need them - so removing.
2011-08-04 14:30:51 +00:00
Alasdair Kergon
83e797bc52 Fix 'pvs -o pv_all' to include label fields. (Also removed recursion.) 2011-06-12 19:49:40 +00:00
Zdenek Kabelac
a1eba521e3 Fix some unmatching sign comparation gcc warnings
Simple replacement for unsigned type - usually in for() loops.
2011-04-08 14:40:18 +00:00
Alasdair Kergon
a8d13f9499 Handle decimal digits with --units instead of ignoring them silently.
Fix remaining warnings and compile with -Wpointer-arith.
2011-02-18 23:09:55 +00:00
Zdenek Kabelac
2f321615f2 API change - support more const arg
As dm_report_field_string() doesn't modify content of data pointer,
it can be marked as const.

It's slight API change - but doesn't require any change on the user side
and supports wider range of arguments without const casting.
(i.e. we may use as paramater const lv struct this way:  &lv->name)
2011-02-18 14:38:47 +00:00
Zdenek Kabelac
4b79aeb0ea Initialize pool object for each row
Fix assert abort of dmsetup (when compiled with pool debug)
dmsetup splitname --nameprefixes --noheadings --rows gvg-a2

Move pool begin in the inner loop - otherwise it would using
already 'ended' pool object.
2011-01-25 21:51:30 +00:00
Alasdair Kergon
ef3d8e18d3 Fix _output_field crash from field_id free with DEBUG_MEM. (Phillip Susi) 2010-11-19 13:17:27 +00:00
Peter Rajnoha
2bea18e504 Use dm_strdup/dm_free instead of strdup/free. 2010-11-01 13:50:51 +00:00
Peter Rajnoha
a83c7816e4 Allocate buffer for reporting functions dynamically to support long outputs.
Fix memory leak of field_id in _output_field function.

There's been a patch added recently to use dynamic allocation for metadata
tags buffer to remove the 4k limit (for writing metadata out). However, when
using reporting commands like vgs and lvs, we still need to fix libdm reporting
functions themselves to support such long outputs. So the buffer used in those
reporting functions is dynamic now.

The patch also includes a fix for field_id memory leak which was found in
the _output_field function.
2010-11-01 13:31:55 +00:00
Alasdair Kergon
ac0252ca07 Add dm_zalloc and use it and dm_pool_zalloc throughout. 2010-09-30 21:06:50 +00:00
Milan Broz
c9c7d25c35 Remove C++ private keyword from headers.
Add extern C definition for libdevmapper, lvm2app and lvm2cmd.
2010-06-16 13:01:25 +00:00
Zdenek Kabelac
d98d855918 Fix dm_report_field_uint64 to really use 64bit.
(function is currently not in use)
2010-02-15 18:36:48 +00:00
Zdenek Kabelac
88c4995d1d * add more 'const' - fixes gcc constness warning 2010-02-15 18:34:00 +00:00
Alasdair Kergon
12b646541b Add missing items to WHATS_NEW files.
Continue to use 'field' to describe reporting elements.
2010-01-11 21:28:04 +00:00
Zdenek Kabelac
876835f2f1 Error message prints unrecognized key. 2010-01-07 14:32:44 +00:00
Zdenek Kabelac
2c352d7b1e Show all fields for 'dmsetup info -c -o all'. 2010-01-07 14:30:47 +00:00
Milan Broz
ea0cdd28c1 Separate PV label attributes which do not need parse metadata when reporting.
When reporting explicitly label attributes (pv_uuid for example), we do not
need to read metadata.

This patch separate the label fileds and removes scan_vgs_for_pvs
in process_each_pv() if not needed.

(There should be no user visible change in output.)
2009-02-09 09:45:49 +00:00
Dave Wysochanski
1a0280b313 Rename _parse_options() to _parse_fields() for naming consistency.
In libdm, we only ever use 'fields', while the tools use 'options' and
'fields' interchangeably.

Ideally it would be good to use 'fields' consistently everywhere.
However, 'options' most likely comes from the tool commandline '-o' and
'--options' which cannot be changed.
2009-01-19 20:53:35 +00:00
Alasdair Kergon
1c96ddd735 Add <report_type>_all to help text. 2009-01-10 03:14:24 +00:00
Alasdair Kergon
1f1aaf43ea Add an "all" field which expands to all fields of the report type.
For example in LVM2, "pv_all" gives all PV fields.
"seg_all" gives all LV segment fields.

"all" gives all fields of the final report type.  I think this is more
useful than just adding the current prefix.

So "lvs -o seg_all" gives all the LV segment fields, whilst
"lvs --segments -o all" adds in LV and VG fields too.

"lvs -o all -O vg_name" has report type LVS+VGS so includes all LV and all
VG fields.
2009-01-10 03:01:35 +00:00
Alasdair Kergon
2c44337bd5 Right, a simple build (without options) is working again. 2008-11-03 22:14:30 +00:00
Alasdair Kergon
3e5b6ed214 more tweaking to get things to compile - dmlib.h for log fns, list.h 2008-11-03 18:59:59 +00:00
Alasdair Kergon
0b1bf1f56b Split out dm-logging.h from log.h 2008-10-30 17:24:04 +00:00
Alasdair Kergon
b6943304c9 Underline longer report help text headings. 2008-06-25 19:52:52 +00:00
Alasdair Kergon
aa882ea539 Cope with missing field values. 2008-06-25 00:10:36 +00:00
Alasdair Kergon
ca8d363d2c Add --rows to dmsetup. 2008-06-24 22:53:48 +00:00
Alasdair Kergon
f1839ac87c dmsetup --unquoted 2008-06-24 20:16:47 +00:00
Alasdair Kergon
9df5c6e987 switch to single quotes rather than double for nameprefixes 2008-06-06 19:07:47 +00:00
Alasdair Kergon
c791f186ce Add field name prefix option to reporting functions. 2008-04-20 00:11:08 +00:00