master - locking: Add missing error handling.
by Alasdair Kergon
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=4c629a5257bda5...
Commit: 4c629a5257bda5a309df25809f821a8ce1dac3e4
Parent: 3489e68ef772d735aeab9f3a69da0fa1e02379c3
Author: Alasdair G Kergon <agk(a)redhat.com>
AuthorDate: Tue Jun 30 18:54:38 2015 +0100
Committer: Alasdair G Kergon <agk(a)redhat.com>
CommitterDate: Tue Jun 30 18:54:38 2015 +0100
locking: Add missing error handling.
Add missing error logging and detection to unlock_vg and callers
of sync_local_dev_names etc.
---
WHATS_NEW | 1 +
lib/activate/activate.c | 4 ++--
lib/locking/locking.h | 7 ++++---
lib/metadata/lv_manip.c | 13 +++++++++++--
lib/metadata/metadata.c | 5 ++++-
lib/metadata/mirror.c | 12 ++++++++++--
lib/metadata/raid_manip.c | 7 ++++++-
lib/misc/lvm-exec.c | 14 ++++++++++----
tools/lvchange.c | 7 ++++++-
tools/pvscan.c | 3 ++-
tools/toollib.c | 5 ++++-
tools/vgchange.c | 11 ++++++++---
12 files changed, 68 insertions(+), 21 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 0908686..6c539e6 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.124 -
=================================
+ Add missing error logging to unlock_vg and sync_local_dev_names callers.
Version 2.02.123 - 30th June 2015
=================================
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index 8c89f98..5905b7b 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -648,8 +648,8 @@ static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv,
* in progress - as only those could lead to opened files
*/
if (with_open_count) {
- if (locking_is_clustered())
- sync_local_dev_names(cmd); /* Wait to have udev in sync */
+ if (locking_is_clustered() && !sync_local_dev_names(cmd)) /* Wait to have udev in sync */
+ return_0;
else if (fs_has_non_delete_ops())
fs_unlock(); /* For non clustered - wait if there are non-delete ops */
}
diff --git a/lib/locking/locking.h b/lib/locking/locking.h
index 644e07c..706b59e 100644
--- a/lib/locking/locking.h
+++ b/lib/locking/locking.h
@@ -195,9 +195,10 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
#define unlock_vg(cmd, vol) \
do { \
- if (is_real_vg(vol)) \
- sync_dev_names(cmd); \
- (void) lock_vol(cmd, vol, LCK_VG_UNLOCK, NULL); \
+ if (is_real_vg(vol) && !sync_dev_names(cmd)) \
+ stack; \
+ if (!lock_vol(cmd, vol, LCK_VG_UNLOCK, NULL)) \
+ stack; \
} while (0)
#define unlock_and_release_vg(cmd, vg, vol) \
do { \
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index de96743..b539fde 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -6633,7 +6633,12 @@ int wipe_lv(struct logical_volume *lv, struct wipe_params wp)
/* nothing to do */
return 1;
- sync_local_dev_names(lv->vg->cmd); /* Wait until devices are available */
+ /* Wait until devices are available */
+ if (!sync_local_dev_names(lv->vg->cmd)) {
+ log_error("Failed to sync local devices before wiping LV %s.",
+ display_lvname(lv));
+ return 0;
+ }
if (!lv_is_active_locally(lv)) {
log_error("Volume \"%s/%s\" is not active locally.",
@@ -7447,7 +7452,11 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
}
/* Get in sync with deactivation, before reusing LV as snapshot */
- sync_local_dev_names(lv->vg->cmd);
+ if (!sync_local_dev_names(lv->vg->cmd)) {
+ log_error("Failed to sync local devices before creating snapshot using %s.",
+ display_lvname(lv));
+ goto revert_new_lv;
+ }
/* Create zero origin volume for spare snapshot */
if (lp->virtual_extents &&
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index 75f3038..9b77daa 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -3241,7 +3241,10 @@ static int _wipe_outdated_pvs(struct cmd_context *cmd, struct volume_group *vg,
return_0;
/* Refresh metadata after orphan write */
- drop_cached_metadata(vg);
+ if (!drop_cached_metadata(vg)) {
+ log_error("Unable to drop cached metadata for VG %s while wiping outdated PVs.", vg->name);
+ return 0;
+ }
next_pv:
;
}
diff --git a/lib/metadata/mirror.c b/lib/metadata/mirror.c
index 543c00e..4857ad0 100644
--- a/lib/metadata/mirror.c
+++ b/lib/metadata/mirror.c
@@ -368,7 +368,11 @@ static int _init_mirror_log(struct cmd_context *cmd,
backup(log_lv->vg);
/* Wait for events following any deactivation before reactivating */
- sync_local_dev_names(cmd);
+ if (!sync_local_dev_names(cmd)) {
+ log_error("Aborting. Failed to sync local devices before initialising mirror log %s.",
+ display_lvname(log_lv));
+ goto revert_new_lv;
+ }
if (!activate_lv(cmd, log_lv)) {
log_error("Aborting. Failed to activate mirror log.");
@@ -484,7 +488,11 @@ static int _delete_lv(struct logical_volume *mirror_lv, struct logical_volume *l
return_0;
/* FIXME Is this superfluous now? */
- sync_local_dev_names(cmd);
+ if (!sync_local_dev_names(cmd)) {
+ log_error("Failed to sync local devices when reactivating %s.",
+ display_lvname(lv));
+ return 0;
+ }
if (!deactivate_lv(cmd, lv))
return_0;
diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c
index 64cfb3f..8b9879c 100644
--- a/lib/metadata/raid_manip.c
+++ b/lib/metadata/raid_manip.c
@@ -1007,10 +1007,15 @@ static int _raid_remove_images(struct logical_volume *lv,
return 0;
}
+ if (!sync_local_dev_names(lv->vg->cmd)) {
+ log_error("Failed to sync local devices after committing changes for %s.",
+ display_lvname(lv));
+ return 0;
+ }
+
/*
* Eliminate the extracted LVs
*/
- sync_local_dev_names(lv->vg->cmd);
if (!dm_list_empty(&removal_list)) {
dm_list_iterate_items(lvl, &removal_list) {
if (!deactivate_lv(lv->vg->cmd, lvl->lv))
diff --git a/lib/misc/lvm-exec.c b/lib/misc/lvm-exec.c
index 273e7f9..e414524 100644
--- a/lib/misc/lvm-exec.c
+++ b/lib/misc/lvm-exec.c
@@ -62,8 +62,11 @@ int exec_cmd(struct cmd_context *cmd, const char *const argv[],
*rstatus = -1;
if (sync_needed)
- if (!sync_local_dev_names(cmd)) /* Flush ops and reset dm cookie */
- return_0;
+ /* Flush ops and reset dm cookie */
+ if (!sync_local_dev_names(cmd)) {
+ log_error("Failed to sync local device names before forking.");
+ return 0;
+ }
log_verbose("Executing:%s", _verbose_args(argv, buf, sizeof(buf)));
@@ -148,8 +151,11 @@ FILE *pipe_open(struct cmd_context *cmd, const char *const argv[],
char buf[PATH_MAX * 2];
if (sync_needed)
- if (!sync_local_dev_names(cmd)) /* Flush ops and reset dm cookie */
- return_0;
+ /* Flush ops and reset dm cookie */
+ if (!sync_local_dev_names(cmd)) {
+ log_error("Failed to sync local device names before forking.");
+ return 0;
+ }
if (pipe(pipefd)) {
log_sys_error("pipe", "");
diff --git a/tools/lvchange.c b/tools/lvchange.c
index e790ea0..1e1c0fe 100644
--- a/tools/lvchange.c
+++ b/tools/lvchange.c
@@ -472,7 +472,12 @@ static int _lvchange_resync(struct cmd_context *cmd, struct logical_volume *lv)
}
}
- sync_local_dev_names(lv->vg->cmd); /* Wait until devices are away */
+ /* Wait until devices are away */
+ if (!sync_local_dev_names(lv->vg->cmd)) {
+ log_error("Failed to sync local devices after updating %s",
+ display_lvname(lv));
+ return 0;
+ }
/* Put metadata sub-LVs back in place */
if (!attach_metadata_devices(seg, &device_list)) {
diff --git a/tools/pvscan.c b/tools/pvscan.c
index 2c997b7..51f5d2b 100644
--- a/tools/pvscan.c
+++ b/tools/pvscan.c
@@ -319,7 +319,8 @@ static int _pvscan_lvmetad(struct cmd_context *cmd, int argc, char **argv)
}
out:
- sync_local_dev_names(cmd);
+ if (!sync_local_dev_names(cmd))
+ stack;
unlock_vg(cmd, VG_GLOBAL);
return ret;
diff --git a/tools/toollib.c b/tools/toollib.c
index bfd3789..5032e2c 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -56,7 +56,10 @@ int become_daemon(struct cmd_context *cmd, int skip_lvm)
sigaction(SIGCHLD, &act, NULL);
if (!skip_lvm)
- sync_local_dev_names(cmd); /* Flush ops and reset dm cookie */
+ if (!sync_local_dev_names(cmd)) { /* Flush ops and reset dm cookie */
+ log_error("Failed to sync local devices before forking.");
+ return -1;
+ }
if ((pid = fork()) == -1) {
log_error("fork failed: %s", strerror(errno));
diff --git a/tools/vgchange.c b/tools/vgchange.c
index 1665d3e..f689c61 100644
--- a/tools/vgchange.c
+++ b/tools/vgchange.c
@@ -85,7 +85,7 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd, struct volume_group *vg,
{
struct lv_list *lvl;
struct logical_volume *lv;
- int count = 0, expected_count = 0;
+ int count = 0, expected_count = 0, r = 1;
sigint_allow();
dm_list_iterate_items(lvl, &vg->lvs) {
@@ -142,14 +142,19 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd, struct volume_group *vg,
}
sigint_restore();
- sync_local_dev_names(vg->cmd); /* Wait until devices are available */
+
+ /* Wait until devices are available */
+ if (!sync_local_dev_names(vg->cmd)) {
+ log_error("Failed to sync local devices for VG %s.", vg->name);
+ r = 0;
+ }
if (expected_count)
log_verbose("%s %d logical volumes in volume group %s",
is_change_activating(activate) ?
"Activated" : "Deactivated", count, vg->name);
- return (expected_count != count) ? 0 : 1;
+ return (expected_count != count) ? 0 : r;
}
static int _vgchange_monitoring(struct cmd_context *cmd, struct volume_group *vg)
8 years, 5 months
v2_02_123 annotated tag has been created
by Alasdair Kergon
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=769ec24a488d65...
Commit: 769ec24a488d654d13f45c49c2d33013df6db2f6
Parent: 0000000000000000000000000000000000000000
Author: Alasdair G Kergon <agk(a)redhat.com>
AuthorDate: 2015-06-30 16:11 +0000
Committer: Alasdair G Kergon <agk(a)redhat.com>
CommitterDate: 2015-06-30 16:11 +0000
annotated tag: v2_02_123 has been created
at 769ec24a488d654d13f45c49c2d33013df6db2f6 (tag)
tagging a3af8b062654efda7f07196ede6e25262c88852c (commit)
replaces v2_02_122
Release 2.02.123.
54 files changed, 2345 insertions(+), 433 deletions(-)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.14 (GNU/Linux)
iEYEABECAAYFAlWSv+EACgkQIoGRwVZ+LBcV4ACgwZMPxsFj4aJLKk537GRq7C2D
KdQAn1Ul231IkRUeTPSAUzoUFG5FjEkN
=YcMN
-----END PGP SIGNATURE-----
Alasdair G Kergon (5):
post-release
man: Add missing env vars to lvm man page.
libdm: Rename struct time_value variables.
conf: Regenerate.
pre-release
David Teigland (6):
lvmetad: add invalidation method
Reread a VG if the lvmetad copy is stale
Reread global state the lvmetad copy is stale
doc: mention new invalid states in lvmetad_design
libdaemon: allow main processing function to be specified
libdaemon: add comment about using main and init
Ferenc Wágner (1):
makefiles: avoid bash == operator syntax, use = instead
Peter Rajnoha (29):
config: add support for config value formatting flags
config: cleanup default values for some configuration settings with array values
config: use proper unconfigured default values for use_lvmetad and use_lvmpolld settings
config: display global/umask in octal form
configure: add DEFAULT_USE_BLKID_WIPING
config: allow empty values for {thin,cache}_{check,repair}_options
config: devices/filter and devices/global_filter setting have 'a/.*/' as default value
config: regenerate configure.in to accomodate all recent changes
WHATS_NEW: recent commits - config value format flags
lvmconfig: add --withspaces option
make: use lvmconfig ... --withspaces when generating lvm.conf and lvmlocal.conf
commands: --withspaces also for config and lvmconfig cmd aliases
config: also clone associated id when cloning node using dm_config_clone_node{_with_mem}
lvmconfig: add --type full to display full tree of settings
lvmconfig: display comment about value from existing config being used
lvmconfig: do not display settings with undefined default values
refactor: rename read_tags fn to _read_str_list and use it for string lists in general
refactor: rename alloc_printed_tags fn to _alloc_printed_str_list and use it for string lists in general
cleanup: remove unused tags.c file
refactor: rename _out_tags fn to _out_list and use it for string lists in general
config: regenerate lvm.conf.in and lvmlocal.conf.in
conf: make time format configurable
toolcontext: use proper set of chars to check time format against
lv: time: increase buffer to 4k in lv_time_dup
cleanup: time: error out on incorrect time_format and indentation in config_settings.h
select: add support for range reserved values and flagging named-only values
cleanup: report: use internal wrapper for various variables used for handling reserved values
configure: set DEFAULT_FALLBACK_TO_LVM1 in configure and use it in config_settings.h
report: add support for time (basic)
Zdenek Kabelac (8):
cleanup: avoid printing gcc warning
tests: newer version needed for ext-orig
tests: skip when snapshot does not work
tests: use vgscan after enable_dev
snapshot: add synchronization point
tests: workaround udev problem
tests: deactivate before remove
tests: tests needs pre 1.13 thin-pool extorg
8 years, 5 months
master - post-release
by Alasdair Kergon
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=3489e68ef772d7...
Commit: 3489e68ef772d735aeab9f3a69da0fa1e02379c3
Parent: a3af8b062654efda7f07196ede6e25262c88852c
Author: Alasdair G Kergon <agk(a)redhat.com>
AuthorDate: Tue Jun 30 17:12:56 2015 +0100
Committer: Alasdair G Kergon <agk(a)redhat.com>
CommitterDate: Tue Jun 30 17:12:56 2015 +0100
post-release
---
VERSION | 2 +-
VERSION_DM | 2 +-
WHATS_NEW | 3 +++
WHATS_NEW_DM | 3 +++
4 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/VERSION b/VERSION
index ecebfae..a75fbd2 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.02.123(2)-git (2015-06-30)
+2.02.124(2)-git (2015-06-30)
diff --git a/VERSION_DM b/VERSION_DM
index 812eaa3..5c2fe02 100644
--- a/VERSION_DM
+++ b/VERSION_DM
@@ -1 +1 @@
-1.02.100-git (2015-06-30)
+1.02.101-git (2015-06-30)
diff --git a/WHATS_NEW b/WHATS_NEW
index 66fbfcf..0908686 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,3 +1,6 @@
+Version 2.02.124 -
+=================================
+
Version 2.02.123 - 30th June 2015
=================================
Add report/time_format lvm.conf option to define time format for report.
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index 9d04847..91643af 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,3 +1,6 @@
+Version 1.02.101 -
+=================================
+
Version 1.02.100 - 30th June 2015
=================================
Add since, after, until and before time operators to be used in selection.
8 years, 5 months
master - pre-release
by Alasdair Kergon
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=a3af8b062654ef...
Commit: a3af8b062654efda7f07196ede6e25262c88852c
Parent: 92138badd48efef74ecb16213ed8a322ef33119c
Author: Alasdair G Kergon <agk(a)redhat.com>
AuthorDate: Tue Jun 30 17:11:21 2015 +0100
Committer: Alasdair G Kergon <agk(a)redhat.com>
CommitterDate: Tue Jun 30 17:11:21 2015 +0100
pre-release
---
VERSION | 2 +-
VERSION_DM | 2 +-
WHATS_NEW | 4 +++-
WHATS_NEW_DM | 4 ++--
4 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/VERSION b/VERSION
index 737d5a2..ecebfae 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.02.123(2)-git (2015-06-20)
+2.02.123(2)-git (2015-06-30)
diff --git a/VERSION_DM b/VERSION_DM
index 7d2906a..812eaa3 100644
--- a/VERSION_DM
+++ b/VERSION_DM
@@ -1 +1 @@
-1.02.100-git (2015-06-20)
+1.02.100-git (2015-06-30)
diff --git a/WHATS_NEW b/WHATS_NEW
index 9a7ebe1..66fbfcf 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,4 +1,4 @@
-Version 2.02.123 -
+Version 2.02.123 - 30th June 2015
=================================
Add report/time_format lvm.conf option to define time format for report.
Fix makefile shell compare == when building lvmetad lvmpolld (2.02.120).
@@ -6,6 +6,8 @@ Version 2.02.123 -
Add undocumented environment variables to lvm man page. (2.02.119)
Add device synchronization point before activating a new snapshot.
Add --withspaces to lvmconfig to add spaces in output for better readability.
+ Add custom main function to libdaemon.
+ Use lvmetad to track out-of-date metadata discovered.
Version 2.02.122 - 20th June 2015
=================================
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index bef2e0d..9d04847 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,5 +1,5 @@
-Version 1.02.100 -
-================================
+Version 1.02.100 - 30th June 2015
+=================================
Add since, after, until and before time operators to be used in selection.
Add support for time in reports and selection: DM_REPORT_FIELD_TYPE_TIME.
Support report reserved value ranges: DM_REPORT_FIELD_RESERVED_VALUE_RANGE.
8 years, 5 months
master - conf: Regenerate.
by Alasdair Kergon
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=92138badd48efe...
Commit: 92138badd48efef74ecb16213ed8a322ef33119c
Parent: f6ad48f0e580950a74775c8dc1058d8e6122ae69
Author: Alasdair G Kergon <agk(a)redhat.com>
AuthorDate: Tue Jun 30 17:09:56 2015 +0100
Committer: Alasdair G Kergon <agk(a)redhat.com>
CommitterDate: Tue Jun 30 17:09:56 2015 +0100
conf: Regenerate.
Fix missing --clear-needs-check-flag.
---
conf/example.conf.in | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/conf/example.conf.in b/conf/example.conf.in
index 9af58db..a26066a 100644
--- a/conf/example.conf.in
+++ b/conf/example.conf.in
@@ -855,7 +855,7 @@ global {
# ignorable errors and fix them later.
# With thin_check version 3.2 or newer you should add
# --clear-needs-check-flag.
- # thin_check_options = [ "-q" ]
+ # thin_check_options = [ "-q", "--clear-needs-check-flag" ]
# Configuration option global/thin_repair_options.
# List of options passed to the thin_repair command.
8 years, 5 months
master - libdm: Rename struct time_value variables.
by Alasdair Kergon
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=f6ad48f0e58095...
Commit: f6ad48f0e580950a74775c8dc1058d8e6122ae69
Parent: ded279f826f0eec41b17a79b6e186daf920b613c
Author: Alasdair G Kergon <agk(a)redhat.com>
AuthorDate: Tue Jun 30 16:17:22 2015 +0100
Committer: Alasdair G Kergon <agk(a)redhat.com>
CommitterDate: Tue Jun 30 16:17:22 2015 +0100
libdm: Rename struct time_value variables.
warning: declaration of ‘time’ shadows a global declaration
---
libdm/libdm-report.c | 48 ++++++++++++++++++++++++------------------------
1 files changed, 24 insertions(+), 24 deletions(-)
diff --git a/libdm/libdm-report.c b/libdm/libdm-report.c
index b808b0d..18710d3 100644
--- a/libdm/libdm-report.c
+++ b/libdm/libdm-report.c
@@ -2795,7 +2795,7 @@ static int _local_tz_offset(time_t t_local)
static void _get_final_time(time_range_t range, struct tm *tm,
int tz_supplied, int offset,
- struct time_value *time)
+ struct time_value *tval)
{
struct tm tm_up = *tm;
@@ -2834,9 +2834,9 @@ static void _get_final_time(time_range_t range, struct tm *tm,
break;
}
- time->range = (range != RANGE_NONE);
- time->t1 = mktime(tm);
- time->t2 = mktime(&tm_up) - 1;
+ tval->range = (range != RANGE_NONE);
+ tval->t1 = mktime(tm);
+ tval->t2 = mktime(&tm_up) - 1;
if (tz_supplied) {
/*
@@ -2845,13 +2845,13 @@ static void _get_final_time(time_range_t range, struct tm *tm,
* to our local timezone and adjust times
* so they represent time in our local timezone.
*/
- offset -= _local_tz_offset(time->t1);
- time->t1 -= offset;
- time->t2 -= offset;
+ offset -= _local_tz_offset(tval->t1);
+ tval->t1 -= offset;
+ tval->t2 -= offset;
}
}
-static int _parse_formatted_date_time(char *str, struct time_value *time)
+static int _parse_formatted_date_time(char *str, struct time_value *tval)
{
time_range_t range = RANGE_NONE;
struct tm tm;
@@ -2874,7 +2874,7 @@ static int _parse_formatted_date_time(char *str, struct time_value *time)
if (*str)
return 0;
- _get_final_time(range, &tm, tz_supplied, gmt_offset, time);
+ _get_final_time(range, &tm, tz_supplied, gmt_offset, tval);
return 1;
}
@@ -2882,7 +2882,7 @@ static int _parse_formatted_date_time(char *str, struct time_value *time)
static const char *_tok_value_time(const struct dm_report_field_type *ft,
struct dm_pool *mem, const char *s,
const char **begin, const char **end,
- struct time_value *time)
+ struct time_value *tval)
{
char *time_str = NULL;
const char *r = NULL;
@@ -2906,9 +2906,9 @@ static const char *_tok_value_time(const struct dm_report_field_type *ft,
goto out;
}
- time->range = 0;
- time->t1 = (time_t) t;
- time->t2 = 0;
+ tval->range = 0;
+ tval->t1 = (time_t) t;
+ tval->t2 = 0;
r = s;
} else {
c = _get_and_skip_quote_char(&s);
@@ -2920,7 +2920,7 @@ static const char *_tok_value_time(const struct dm_report_field_type *ft,
goto out;
}
- if (!_parse_formatted_date_time(time_str, time))
+ if (!_parse_formatted_date_time(time_str, tval))
goto_out;
r = s;
}
@@ -2953,7 +2953,7 @@ static const char *_tok_value(struct dm_report *rh,
{
int expected_type = ft->flags & DM_REPORT_FIELD_TYPE_MASK;
struct selection_str_list **str_list;
- struct time_value *time;
+ struct time_value *tval;
uint64_t *factor;
const char *tmp;
char c;
@@ -3041,8 +3041,8 @@ static const char *_tok_value(struct dm_report *rh,
break;
case DM_REPORT_FIELD_TYPE_TIME:
- time = (struct time_value *) custom;
- if (!(s = _tok_value_time(ft, mem, s, begin, end, time))) {
+ tval = (struct time_value *) custom;
+ if (!(s = _tok_value_time(ft, mem, s, begin, end, tval))) {
log_error("Failed to parse time value "
"for selection field %s.", ft->id);
return NULL;
@@ -3119,7 +3119,7 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
struct field_properties *fp, *found = NULL;
struct field_selection *fs;
const char *field_id;
- struct time_value *time;
+ struct time_value *tval;
uint64_t factor;
char *s;
@@ -3287,10 +3287,10 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
if (rvw->reserved->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE)
fs->value->next->v.t = (((time_t *) rvw->value)[1]);
} else {
- time = (struct time_value *) custom;
- fs->value->v.t = time->t1;
- if (time->range)
- fs->value->next->v.t = time->t2;
+ tval = (struct time_value *) custom;
+ fs->value->v.t = tval->t1;
+ if (tval->range)
+ fs->value->next->v.t = tval->t2;
if (_check_value_is_strictly_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_TIME, &fs->value->v.t, NULL)) {
log_error("Time value found in selection is reserved.");
goto error;
@@ -3433,7 +3433,7 @@ static struct selection_node *_parse_selection(struct dm_report *rh,
const struct dm_report_field_type *ft;
struct selection_str_list *str_list;
struct reserved_value_wrapper rvw = {0};
- struct time_value time;
+ struct time_value tval;
uint64_t factor;
void *custom = NULL;
char *tmp;
@@ -3517,7 +3517,7 @@ static struct selection_node *_parse_selection(struct dm_report *rh,
ft->flags == DM_REPORT_FIELD_TYPE_PERCENT)
custom = &factor;
else if (ft->flags & DM_REPORT_FIELD_TYPE_TIME)
- custom = &time;
+ custom = &tval;
else if (ft->flags == DM_REPORT_FIELD_TYPE_STRING_LIST)
custom = &str_list;
else
8 years, 5 months
master - report: add support for time (basic)
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=ded279f826f0ee...
Commit: ded279f826f0eec41b17a79b6e186daf920b613c
Parent: 89d355ea04560dba54aa8b7b5a20950b9eb3f653
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Thu May 21 15:19:03 2015 +0200
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Tue Jun 30 15:15:10 2015 +0200
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.
---
WHATS_NEW_DM | 2 +
lib/properties/prop_common.h | 3 +-
lib/report/columns.h | 2 +-
lib/report/report.c | 1 +
libdm/libdevmapper.h | 1 +
libdm/libdm-report.c | 608 ++++++++++++++++++++++++++++++++++++++++--
6 files changed, 591 insertions(+), 26 deletions(-)
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index 75e572a..bef2e0d 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,5 +1,7 @@
Version 1.02.100 -
================================
+ Add since, after, until and before time operators to be used in selection.
+ Add support for time in reports and selection: DM_REPORT_FIELD_TYPE_TIME.
Support report reserved value ranges: DM_REPORT_FIELD_RESERVED_VALUE_RANGE.
Support report reserved value names: DM_REPORT_FIELD_RESERVED_VALUE_NAMED.
Add DM_CONFIG_VALUE_FMT_{INT_OCTAL,STRING_NO_QUOTES} config value format flag.
diff --git a/lib/properties/prop_common.h b/lib/properties/prop_common.h
index 9cc963a..19b8f70 100644
--- a/lib/properties/prop_common.h
+++ b/lib/properties/prop_common.h
@@ -127,8 +127,9 @@ static int _ ## NAME ## _get (const void *obj, struct lvm_property_type *prop) \
#define BIN 3
#define SIZ 4
#define PCT 5
-#define STR_LIST 6
+#define TIM 6
#define SNUM 7 /* Signed Number */
+#define STR_LIST 8
#define FIELD_MODIFIABLE 0x00000001
#define FIELD(type, strct, field_type, head, field, width, fn, id, desc, settable) \
diff --git a/lib/report/columns.h b/lib/report/columns.h
index 06282c5..1576c28 100644
--- a/lib/report/columns.h
+++ b/lib/report/columns.h
@@ -84,7 +84,7 @@ FIELD(LVS, lv, STR, "Meta", lvid, 4, metadatalv, metadata_lv, "For thin and cach
FIELD(LVS, lv, STR, "Pool", lvid, 4, poollv, pool_lv, "For thin volumes, the thin pool LV for this volume.", 0)
FIELD(LVS, lv, STR_LIST, "LV Tags", tags, 7, tags, lv_tags, "Tags, if any.", 0)
FIELD(LVS, lv, STR, "LProfile", lvid, 8, lvprofile, lv_profile, "Configuration profile attached to this LV.", 0)
-FIELD(LVS, lv, STR, "Time", lvid, 26, lvtime, lv_time, "Creation time of the LV, if known", 0)
+FIELD(LVS, lv, TIM, "Time", lvid, 26, lvtime, lv_time, "Creation time of the LV, if known", 0)
FIELD(LVS, lv, STR, "Host", lvid, 10, lvhost, lv_host, "Creation host of the LV, if known.", 0)
FIELD(LVS, lv, STR_LIST, "Modules", lvid, 7, modules, lv_modules, "Kernel device-mapper modules required for this LV.", 0)
diff --git a/lib/report/report.c b/lib/report/report.c
index 1c741e4..025b896 100644
--- a/lib/report/report.c
+++ b/lib/report/report.c
@@ -2064,6 +2064,7 @@ static const struct dm_report_object_type _devtypes_report_types[] = {
#define BIN DM_REPORT_FIELD_TYPE_NUMBER
#define SIZ DM_REPORT_FIELD_TYPE_SIZE
#define PCT DM_REPORT_FIELD_TYPE_PERCENT
+#define TIM DM_REPORT_FIELD_TYPE_TIME
#define STR_LIST DM_REPORT_FIELD_TYPE_STRING_LIST
#define SNUM DM_REPORT_FIELD_TYPE_NUMBER
#define FIELD(type, strct, sorttype, head, field, width, func, id, desc, writeable) \
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index 38f42aa..7e30d8e 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -1682,6 +1682,7 @@ struct dm_report_field;
#define DM_REPORT_FIELD_TYPE_SIZE 0x00000040
#define DM_REPORT_FIELD_TYPE_PERCENT 0x00000080
#define DM_REPORT_FIELD_TYPE_STRING_LIST 0x00000100
+#define DM_REPORT_FIELD_TYPE_TIME 0x00000200
/* For use with reserved values only! */
#define DM_REPORT_FIELD_RESERVED_VALUE_MASK 0x0000000F
diff --git a/libdm/libdm-report.c b/libdm/libdm-report.c
index 4348db1..b808b0d 100644
--- a/libdm/libdm-report.c
+++ b/libdm/libdm-report.c
@@ -18,6 +18,7 @@
#include <ctype.h>
#include <math.h> /* fabs() */
#include <float.h> /* DBL_EPSILON */
+#include <time.h>
/*
* Internal flags
@@ -100,11 +101,13 @@ struct op_def {
#define FLD_CMP_LT 0x01000000
#define FLD_CMP_REGEX 0x02000000
#define FLD_CMP_NUMBER 0x04000000
+#define FLD_CMP_TIME 0x08000000
/*
- * #define FLD_CMP_STRING 0x08000000
- * We could defined FLD_CMP_STRING here for completeness here,
+ * #define FLD_CMP_STRING 0x10000000
+ * We could define FLD_CMP_STRING here for completeness here,
* but it's not needed - we can check operator compatibility with
- * field type by using FLD_CMP_REGEX and FLD_CMP_NUMBER flags only.
+ * field type by using FLD_CMP_REGEX, FLD_CMP_NUMBER and
+ * FLD_CMP_TIME flags only.
*/
/*
@@ -115,12 +118,16 @@ struct op_def {
static struct op_def _op_cmp[] = {
{ "=~", FLD_CMP_REGEX, "Matching regular expression. [regex]" },
{ "!~", FLD_CMP_REGEX|FLD_CMP_NOT, "Not matching regular expression. [regex]" },
- { "=", FLD_CMP_EQUAL, "Equal to. [number, size, percent, string, string list]" },
- { "!=", FLD_CMP_NOT|FLD_CMP_EQUAL, "Not equal to. [number, size, percent, string, string_list]" },
- { ">=", FLD_CMP_NUMBER|FLD_CMP_GT|FLD_CMP_EQUAL, "Greater than or equal to. [number, size, percent]" },
- { ">", FLD_CMP_NUMBER|FLD_CMP_GT, "Greater than. [number, size, percent]" },
- { "<=", FLD_CMP_NUMBER|FLD_CMP_LT|FLD_CMP_EQUAL, "Less than or equal to. [number, size, percent]" },
- { "<", FLD_CMP_NUMBER|FLD_CMP_LT, "Less than. [number, size, percent]" },
+ { "=", FLD_CMP_EQUAL, "Equal to. [number, size, percent, string, string list, time]" },
+ { "!=", FLD_CMP_NOT|FLD_CMP_EQUAL, "Not equal to. [number, size, percent, string, string_list, time]" },
+ { ">=", FLD_CMP_NUMBER|FLD_CMP_TIME|FLD_CMP_GT|FLD_CMP_EQUAL, "Greater than or equal to. [number, size, percent, time]" },
+ { ">", FLD_CMP_NUMBER|FLD_CMP_TIME|FLD_CMP_GT, "Greater than. [number, size, percent, time]" },
+ { "<=", FLD_CMP_NUMBER|FLD_CMP_TIME|FLD_CMP_LT|FLD_CMP_EQUAL, "Less than or equal to. [number, size, percent, time]" },
+ { "<", FLD_CMP_NUMBER|FLD_CMP_TIME|FLD_CMP_LT, "Less than. [number, size, percent, time]" },
+ { "since", FLD_CMP_TIME|FLD_CMP_GT|FLD_CMP_EQUAL, "Since specified time (same as '>='). [time]" },
+ { "after", FLD_CMP_TIME|FLD_CMP_GT, "After specified time (same as '>'). [time]"},
+ { "until", FLD_CMP_TIME|FLD_CMP_LT|FLD_CMP_EQUAL, "Until specified time (same as '<='). [time]"},
+ { "before", FLD_CMP_TIME|FLD_CMP_LT, "Before specified time (same as '<'). [time]"},
{ NULL, 0, NULL }
};
@@ -166,6 +173,7 @@ struct field_selection_value {
union {
const char *s;
uint64_t i;
+ time_t t;
double d;
struct dm_regex *r;
struct selection_str_list *l;
@@ -662,6 +670,7 @@ static const char *_get_field_type_name(unsigned field_type)
case DM_REPORT_FIELD_TYPE_NUMBER: return "number";
case DM_REPORT_FIELD_TYPE_SIZE: return "size";
case DM_REPORT_FIELD_TYPE_PERCENT: return "percent";
+ case DM_REPORT_FIELD_TYPE_TIME: return "time";
case DM_REPORT_FIELD_TYPE_STRING_LIST: return "string list";
default: return "unknown";
}
@@ -1363,6 +1372,9 @@ static int _do_check_value_is_strictly_reserved(unsigned type, const void *res_v
case DM_REPORT_FIELD_TYPE_STRING_LIST:
/* FIXME Add comparison for string list */
break;
+ case DM_REPORT_FIELD_TYPE_TIME:
+ /* FIXME Add comparison for time */
+ break;
}
return 0;
@@ -1504,6 +1516,43 @@ static int _cmp_field_string(struct dm_report *rh __attribute__((unused)),
return 0;
}
+static int _cmp_field_time(struct dm_report *rh,
+ uint32_t field_num, const char *field_id,
+ time_t val, struct field_selection *fs)
+{
+ int range = fs->value->next != NULL;
+ time_t sel1 = fs->value->v.t;
+ time_t sel2 = range ? fs->value->next->v.t : 0;
+
+ switch(fs->flags & FLD_CMP_MASK) {
+ case FLD_CMP_EQUAL:
+ return range ? ((val >= sel1) && (val <= sel2)) : val == sel1;
+ case FLD_CMP_NOT|FLD_CMP_EQUAL:
+ return range ? ((val >= sel1) && (val <= sel2)) : val != sel1;
+ case FLD_CMP_TIME|FLD_CMP_GT:
+ if (_check_value_is_strictly_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_TIME, &val, fs))
+ return 0;
+ return range ? val > sel2 : val > sel1;
+ case FLD_CMP_TIME|FLD_CMP_GT|FLD_CMP_EQUAL:
+ if (_check_value_is_strictly_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_TIME, &val, fs))
+ return 0;
+ return val >= sel1;
+ case FLD_CMP_TIME|FLD_CMP_LT:
+ if (_check_value_is_strictly_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_TIME, &val, fs))
+ return 0;
+ return val < sel1;
+ case FLD_CMP_TIME|FLD_CMP_LT|FLD_CMP_EQUAL:
+ if (_check_value_is_strictly_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_TIME, &val, fs))
+ return 0;
+ return range ? val <= sel2 : val <= sel1;
+ default:
+ log_error(INTERNAL_ERROR "_cmp_field_time: unsupported time "
+ "comparison type for field %s", field_id);
+ }
+
+ return 0;
+}
+
/* Matches if all items from selection string list match list value strictly 1:1. */
static int _cmp_field_string_list_strict_all(const struct str_list_sort_value *val,
const struct selection_str_list *sel)
@@ -1664,6 +1713,9 @@ static int _compare_selection_field(struct dm_report *rh,
case DM_REPORT_FIELD_TYPE_STRING_LIST:
r = _cmp_field_string_list(rh, f->props->field_num, field_id, (const struct str_list_sort_value *) f->sort_value, fs);
break;
+ case DM_REPORT_FIELD_TYPE_TIME:
+ r = _cmp_field_time(rh, f->props->field_num, field_id, *(const time_t *) f->sort_value, fs);
+ break;
default:
log_error(INTERNAL_ERROR "_compare_selection_field: unknown field type for field %s", field_id);
}
@@ -2428,6 +2480,456 @@ bad:
return s;
}
+struct time_value {
+ int range;
+ time_t t1;
+ time_t t2;
+};
+
+static const char *_out_of_range_msg = "Field selection value %s out of supported range for field %s.";
+
+/*
+ * Standard formatted date and time - ISO8601.
+ *
+ * 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:
+ * +hh:mm or -hh:mm (or shortly +hhmm or -hhmm)
+ * +hh or -hh
+*/
+
+#define DELIM_DATE '-'
+#define DELIM_TIME ':'
+
+static int _days_in_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+static int _is_leap_year(long year)
+{
+ return (((year % 4==0) && (year % 100 != 0)) || (year % 400 == 0));
+}
+
+static int _get_days_in_month(long month, long year)
+{
+ return (month == 2 && _is_leap_year(year)) ? _days_in_month[month-1] + 1
+ : _days_in_month[month-1];
+}
+
+typedef enum {
+ RANGE_NONE,
+ RANGE_SECOND,
+ RANGE_MINUTE,
+ RANGE_HOUR,
+ RANGE_DAY,
+ RANGE_MONTH,
+ RANGE_YEAR
+} time_range_t;
+
+static char *_get_date(char *str, struct tm *tm, time_range_t *range)
+{
+ static const char incorrect_date_format_msg[] = "Incorrect date format.";
+ time_range_t tmp_range = RANGE_NONE;
+ long n1 = -1, n2 = -1, n3 = -1;
+ char *s = str, *end;
+ size_t len = 0;
+
+ if (!isdigit(*s))
+ /* we need a year at least */
+ return NULL;
+
+ n1 = strtol(s, &end, 10);
+ if (*end == DELIM_DATE) {
+ len += (4 - (end - s)); /* diff in length from standard YYYY */
+ s = end + 1;
+ if (isdigit(*s)) {
+ n2 = strtol(s, &end, 10);
+ len += (2 - (end - s)); /* diff in length from standard MM */
+ if (*end == DELIM_DATE) {
+ s = end + 1;
+ n3 = strtol(s, &end, 10);
+ len += (2 - (end - s)); /* diff in length from standard DD */
+ }
+ }
+ }
+
+ len = len + end - str;
+
+ /* variations from standard YYYY-MM-DD */
+ if (n3 == -1) {
+ if (n2 == -1) {
+ if (len == 4) {
+ /* YYYY */
+ tmp_range = RANGE_YEAR;
+ n3 = n2 = 1;
+ } else if (len == 6) {
+ /* YYYYMM */
+ tmp_range = RANGE_MONTH;
+ n3 = 1;
+ n2 = n1 % 100;
+ n1 = n1 / 100;
+ } else if (len == 8) {
+ tmp_range = RANGE_DAY;
+ /* YYYYMMDD */
+ n3 = n1 % 100;
+ n2 = (n1 / 100) % 100;
+ n1 = n1 / 10000;
+ } else {
+ log_error(incorrect_date_format_msg);
+ return NULL;
+ }
+ } else {
+ if (len == 7) {
+ tmp_range = RANGE_MONTH;
+ /* YYYY-MM */
+ n3 = 1;
+ } else {
+ log_error(incorrect_date_format_msg);
+ return NULL;
+ }
+ }
+ }
+
+ if (n2 < 1 || n2 > 12) {
+ log_error("Specified month out of range.");
+ return NULL;
+ }
+
+ if (n3 < 1 || n3 > _get_days_in_month(n2, n1)) {
+ log_error("Specified day out of range.");
+ return NULL;
+ }
+
+ if (tmp_range == RANGE_NONE)
+ tmp_range = RANGE_DAY;
+
+ tm->tm_year = n1 - 1900;
+ tm->tm_mon = n2 - 1;
+ tm->tm_mday = n3;
+ *range = tmp_range;
+
+ return (char *) _skip_space(end);
+}
+
+static char *_get_time(char *str, struct tm *tm, time_range_t *range)
+{
+ static const char incorrect_time_format_msg[] = "Incorrect time format.";
+ time_range_t tmp_range = RANGE_NONE;
+ long n1 = -1, n2 = -1, n3 = -1;
+ char *s = str, *end;
+ size_t len = 0;
+
+ if (!isdigit(*s)) {
+ /* time is not compulsory */
+ tm->tm_hour = tm->tm_min = tm->tm_sec = 0;
+ return (char *) _skip_space(s);
+ }
+
+ n1 = strtol(s, &end, 10);
+ if (*end == DELIM_TIME) {
+ len += (2 - (end - s)); /* diff in length from standard HH */
+ s = end + 1;
+ if (isdigit(*s)) {
+ n2 = strtol(s, &end, 10);
+ len += (2 - (end - s)); /* diff in length from standard MM */
+ if (*end == DELIM_TIME) {
+ s = end + 1;
+ n3 = strtol(s, &end, 10);
+ len += (2 - (end - s)); /* diff in length from standard SS */
+ }
+ }
+ }
+
+ len = len + end - str;
+
+ /* variations from standard HH:MM:SS */
+ if (n3 == -1) {
+ if (n2 == -1) {
+ if (len == 2) {
+ /* HH */
+ tmp_range = RANGE_HOUR;
+ n3 = n2 = 0;
+ } else if (len == 4) {
+ /* HHMM */
+ tmp_range = RANGE_MINUTE;
+ n3 = 0;
+ n2 = n1 % 100;
+ n1 = n1 / 100;
+ } else if (len == 6) {
+ /* HHMMSS */
+ tmp_range = RANGE_SECOND;
+ n3 = n1 % 100;
+ n2 = (n1 / 100) % 100;
+ n1 = n1 / 10000;
+ } else {
+ log_error(incorrect_time_format_msg);
+ return NULL;
+ }
+ } else {
+ if (len == 5) {
+ /* HH:MM */
+ tmp_range = RANGE_MINUTE;
+ n3 = 0;
+ } else {
+ log_error(incorrect_time_format_msg);
+ return NULL;
+ }
+ }
+ }
+
+ if (n1 < 0 || n1 > 23) {
+ log_error("Specified hours out of range.");
+ return NULL;
+ }
+
+ if (n2 < 0 || n2 > 60) {
+ log_error("Specified minutes out of range.");
+ return NULL;
+ }
+
+ if (n3 < 0 || n3 > 60) {
+ log_error("Specified seconds out of range.");
+ return NULL;
+ }
+
+ /* Just time without exact date is incomplete! */
+ if (*range != RANGE_DAY) {
+ log_error("Full date specification needed.");
+ return NULL;
+ }
+
+ tm->tm_hour = n1;
+ tm->tm_min = n2;
+ tm->tm_sec = n3;
+ *range = tmp_range;
+
+ return (char *) _skip_space(end);
+}
+
+/* The offset is always an absolute offset against GMT! */
+static char *_get_tz(char *str, int *tz_supplied, int *offset)
+{
+ long n1 = -1, n2 = -1;
+ char *s = str, *end;
+ int sign = 1; /* +HH:MM by default */
+ size_t len = 0;
+
+ *tz_supplied = 0;
+ *offset = 0;
+
+ if (!isdigit(*s)) {
+ if (*s == '+') {
+ sign = 1;
+ s = s + 1;
+ } else if (*s == '-') {
+ sign = -1;
+ s = s + 1;
+ } else
+ return (char *) _skip_space(s);
+ }
+
+ n1 = strtol(s, &end, 10);
+ if (*end == DELIM_TIME) {
+ len = (2 - (end - s)); /* diff in length from standard HH */
+ s = end + 1;
+ if (isdigit(*s)) {
+ n2 = strtol(s, &end, 10);
+ len = (2 - (end - s)); /* diff in length from standard MM */
+ }
+ }
+
+ len = len + end - s;
+
+ /* variations from standard HH:MM */
+ if (n2 == -1) {
+ if (len == 2) {
+ /* HH */
+ n2 = 0;
+ } else if (len == 4) {
+ /* HHMM */
+ n2 = n1 % 100;
+ n1 = n1 / 100;
+ } else
+ return NULL;
+ }
+
+ if (n2 < 0 || n2 > 60)
+ return NULL;
+
+ if (n1 < 0 || n1 > 14)
+ return NULL;
+
+ /* timezone offset in seconds */
+ *offset = sign * ((n1 * 3600) + (n2 * 60));
+ *tz_supplied = 1;
+ return (char *) _skip_space(end);
+}
+
+static int _local_tz_offset(time_t t_local)
+{
+ struct tm tm_gmt;
+ time_t t_gmt;
+
+ gmtime_r(&t_local, &tm_gmt);
+ t_gmt = mktime(&tm_gmt);
+
+ /*
+ * gmtime returns time that is adjusted
+ * for DST.Subtract this adjustment back
+ * to give us proper *absolute* offset
+ * for our local timezone.
+ */
+ if (tm_gmt.tm_isdst)
+ t_gmt -= 3600;
+
+ return t_local - t_gmt;
+}
+
+static void _get_final_time(time_range_t range, struct tm *tm,
+ int tz_supplied, int offset,
+ struct time_value *time)
+{
+
+ struct tm tm_up = *tm;
+
+ switch (range) {
+ case RANGE_SECOND:
+ if (tm_up.tm_sec < 59) {
+ tm_up.tm_sec += 1;
+ break;
+ }
+ case RANGE_MINUTE:
+ if (tm_up.tm_min < 59) {
+ tm_up.tm_min += 1;
+ break;
+ }
+ case RANGE_HOUR:
+ if (tm_up.tm_hour < 23) {
+ tm_up.tm_hour += 1;
+ break;
+ }
+ case RANGE_DAY:
+ if (tm_up.tm_mday < _get_days_in_month(tm_up.tm_mon, tm_up.tm_year)) {
+ tm_up.tm_mday += 1;
+ break;
+ }
+ case RANGE_MONTH:
+ if (tm_up.tm_mon < 11) {
+ tm_up.tm_mon += 1;
+ break;
+ }
+ case RANGE_YEAR:
+ tm_up.tm_year += 1;
+ break;
+ case RANGE_NONE:
+ /* nothing to do here */
+ break;
+ }
+
+ time->range = (range != RANGE_NONE);
+ time->t1 = mktime(tm);
+ time->t2 = mktime(&tm_up) - 1;
+
+ if (tz_supplied) {
+ /*
+ * The 'offset' is with respect to the GMT.
+ * Calculate what the offset is with respect
+ * to our local timezone and adjust times
+ * so they represent time in our local timezone.
+ */
+ offset -= _local_tz_offset(time->t1);
+ time->t1 -= offset;
+ time->t2 -= offset;
+ }
+}
+
+static int _parse_formatted_date_time(char *str, struct time_value *time)
+{
+ time_range_t range = RANGE_NONE;
+ struct tm tm;
+ int gmt_offset;
+ int tz_supplied;
+
+ tm.tm_year = tm.tm_mday = tm.tm_mon = -1;
+ tm.tm_hour = tm.tm_min = tm.tm_sec = -1;
+ tm.tm_isdst = tm.tm_wday = tm.tm_yday = -1;
+
+ if (!(str = _get_date(str, &tm, &range)))
+ return 0;
+
+ if (!(str = _get_time(str, &tm, &range)))
+ return 0;
+
+ if (!(str = _get_tz(str, &tz_supplied, &gmt_offset)))
+ return 0;
+
+ if (*str)
+ return 0;
+
+ _get_final_time(range, &tm, tz_supplied, gmt_offset, time);
+
+ return 1;
+}
+
+static const char *_tok_value_time(const struct dm_report_field_type *ft,
+ struct dm_pool *mem, const char *s,
+ const char **begin, const char **end,
+ struct time_value *time)
+{
+ char *time_str = NULL;
+ const char *r = NULL;
+ uint64_t t;
+ char c;
+
+ s = _skip_space(s);
+
+ if (*s == '@') {
+ /* Absolute time value in number of seconds since epoch. */
+ if (!(s = _tok_value_number(s+1, begin, end)))
+ goto_out;
+
+ if (!(time_str = dm_pool_strndup(mem, *begin, *end - *begin))) {
+ log_error("_tok_value_time: dm_pool_strndup failed");
+ goto out;
+ }
+
+ if (((t = strtoull(time_str, NULL, 10)) == ULLONG_MAX) && errno == ERANGE) {
+ log_error(_out_of_range_msg, time_str, ft->id);
+ goto out;
+ }
+
+ time->range = 0;
+ time->t1 = (time_t) t;
+ time->t2 = 0;
+ r = s;
+ } else {
+ c = _get_and_skip_quote_char(&s);
+ if (!(s = _tok_value_string(s, begin, end, c, SEL_AND | SEL_OR | SEL_PRECEDENCE_PE, NULL)))
+ goto_out;
+
+ if (!(time_str = dm_pool_strndup(mem, *begin, *end - *begin))) {
+ log_error("tok_value_time: dm_pool_strndup failed");
+ goto out;
+ }
+
+ if (!_parse_formatted_date_time(time_str, time))
+ goto_out;
+ r = s;
+ }
+out:
+ if (time_str)
+ dm_pool_free(mem, time_str);
+ return r;
+}
+
/*
* Input:
* ft - field type for which the value is parsed
@@ -2451,6 +2953,7 @@ static const char *_tok_value(struct dm_report *rh,
{
int expected_type = ft->flags & DM_REPORT_FIELD_TYPE_MASK;
struct selection_str_list **str_list;
+ struct time_value *time;
uint64_t *factor;
const char *tmp;
char c;
@@ -2530,6 +3033,28 @@ static const char *_tok_value(struct dm_report *rh,
}
*flags |= expected_type;
+ /*
+ * FLD_CMP_NUMBER shares operators with FLD_CMP_TIME,
+ * but we have NUMBER here, so remove FLD_CMP_TIME.
+ */
+ *flags &= ~FLD_CMP_TIME;
+ break;
+
+ case DM_REPORT_FIELD_TYPE_TIME:
+ time = (struct time_value *) custom;
+ if (!(s = _tok_value_time(ft, mem, s, begin, end, time))) {
+ log_error("Failed to parse time value "
+ "for selection field %s.", ft->id);
+ return NULL;
+ }
+
+ *flags |= DM_REPORT_FIELD_TYPE_TIME;
+ /*
+ * FLD_CMP_TIME shares operators with FLD_CMP_NUMBER,
+ * but we have TIME here, so remove FLD_CMP_NUMBER.
+ */
+ *flags &= ~FLD_CMP_NUMBER;
+ break;
}
return s;
@@ -2588,13 +3113,13 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
struct reserved_value_wrapper *rvw,
void *custom)
{
- static const char *_out_of_range_msg = "Field selection value %s out of supported range for field %s.";
static const char *_field_selection_value_alloc_failed_msg = "dm_report: struct field_selection_value allocation failed for selection field %s";
const struct dm_report_field_type *fields = implicit ? _implicit_report_fields
: rh->fields;
struct field_properties *fp, *found = NULL;
struct field_selection *fs;
const char *field_id;
+ struct time_value *time;
uint64_t factor;
char *s;
@@ -2632,7 +3157,9 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
goto error;
}
- if (rvw->reserved && (rvw->reserved->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE) &&
+ if (((rvw->reserved && (rvw->reserved->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE)) ||
+ (((flags & DM_REPORT_FIELD_TYPE_MASK) == DM_REPORT_FIELD_TYPE_TIME) && ((struct time_value *) custom)->range))
+ &&
!(fs->value->next = dm_pool_zalloc(rh->selection->mem, sizeof(struct field_selection_value)))) {
log_error(_field_selection_value_alloc_failed_msg, field_id);
goto error;
@@ -2666,7 +3193,7 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
goto error;
}
} else {
- /* STRING, NUMBER, SIZE or STRING_LIST */
+ /* STRING, NUMBER, SIZE, PERCENT, STRING_LIST, TIME */
if (!(s = dm_pool_strndup(rh->selection->mem, v, len))) {
log_error("dm_report: dm_pool_strndup for value "
"of selection field %s", field_id);
@@ -2754,6 +3281,22 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
goto error;
}
break;
+ case DM_REPORT_FIELD_TYPE_TIME:
+ if (rvw->value) {
+ fs->value->v.t = *(time_t *) rvw->value;
+ if (rvw->reserved->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE)
+ fs->value->next->v.t = (((time_t *) rvw->value)[1]);
+ } else {
+ time = (struct time_value *) custom;
+ fs->value->v.t = time->t1;
+ if (time->range)
+ fs->value->next->v.t = time->t2;
+ if (_check_value_is_strictly_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_TIME, &fs->value->v.t, NULL)) {
+ log_error("Time value found in selection is reserved.");
+ goto error;
+ }
+ }
+ break;
default:
log_error(INTERNAL_ERROR "_create_field_selection: "
"unknown type of selection field %s", field_id);
@@ -2845,7 +3388,7 @@ out_reserved_values:
log_warn(" Comparison operators:");
t = _op_cmp;
for (; t->string; t++)
- log_warn(" %4s - %s", t->string, t->desc);
+ log_warn(" %6s - %s", t->string, t->desc);
log_warn(" ");
log_warn(" Logical and grouping operators:");
t = _op_log;
@@ -2890,6 +3433,7 @@ static struct selection_node *_parse_selection(struct dm_report *rh,
const struct dm_report_field_type *ft;
struct selection_str_list *str_list;
struct reserved_value_wrapper rvw = {0};
+ struct time_value time;
uint64_t factor;
void *custom = NULL;
char *tmp;
@@ -2940,25 +3484,40 @@ static struct selection_node *_parse_selection(struct dm_report *rh,
goto bad;
}
- /* some operators can compare only numeric fields (NUMBER, SIZE or PERCENT) */
- if ((flags & FLD_CMP_NUMBER) &&
- (ft->flags != DM_REPORT_FIELD_TYPE_NUMBER) &&
- (ft->flags != DM_REPORT_FIELD_TYPE_SIZE) &&
- (ft->flags != DM_REPORT_FIELD_TYPE_PERCENT)) {
- _display_selection_help(rh);
- log_error("Operator can be used only with number, size or percent fields: %s", ws);
- goto bad;
- }
-
/* comparison value */
if (flags & FLD_CMP_REGEX) {
+ /*
+ * REGEX value
+ */
if (!(last = _tok_value_regex(rh, ft, last, &vs, &ve, &flags, &rvw)))
goto_bad;
} else {
+ /*
+ * STRING, NUMBER, SIZE, PERCENT, STRING_LIST, TIME value
+ */
+ if (flags & FLD_CMP_NUMBER) {
+ if (!(ft->flags & (DM_REPORT_FIELD_TYPE_NUMBER |
+ DM_REPORT_FIELD_TYPE_SIZE |
+ DM_REPORT_FIELD_TYPE_PERCENT |
+ DM_REPORT_FIELD_TYPE_TIME))) {
+ _display_selection_help(rh);
+ log_error("Operator can be used only with number, size, time or percent fields: %s", ws);
+ goto bad;
+ }
+ } else if (flags & FLD_CMP_TIME) {
+ if (!(ft->flags & DM_REPORT_FIELD_TYPE_TIME)) {
+ _display_selection_help(rh);
+ log_error("Operator can be used only with time fields: %s", ws);
+ goto bad;
+ }
+ }
+
if (ft->flags == DM_REPORT_FIELD_TYPE_SIZE ||
ft->flags == DM_REPORT_FIELD_TYPE_NUMBER ||
ft->flags == DM_REPORT_FIELD_TYPE_PERCENT)
custom = &factor;
+ else if (ft->flags & DM_REPORT_FIELD_TYPE_TIME)
+ custom = &time;
else if (ft->flags == DM_REPORT_FIELD_TYPE_STRING_LIST)
custom = &str_list;
else
@@ -3274,7 +3833,8 @@ static int _row_compare(const void *a, const void *b)
sfa = (*rowa->sort_fields)[cnt];
sfb = (*rowb->sort_fields)[cnt];
if ((sfa->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) ||
- (sfa->props->flags & DM_REPORT_FIELD_TYPE_SIZE)) {
+ (sfa->props->flags & DM_REPORT_FIELD_TYPE_SIZE) ||
+ (sfa->props->flags & DM_REPORT_FIELD_TYPE_TIME)) {
const uint64_t numa =
*(const uint64_t *) sfa->sort_value;
const uint64_t numb =
8 years, 5 months
master - configure: set DEFAULT_FALLBACK_TO_LVM1 in configure and use it in config_settings.h
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=89d355ea04560d...
Commit: 89d355ea04560dba54aa8b7b5a20950b9eb3f653
Parent: d7b9349ce71f2747eb7d0a8992244bc3d34719be
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Tue Jun 30 14:09:00 2015 +0200
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Tue Jun 30 14:09:05 2015 +0200
configure: set DEFAULT_FALLBACK_TO_LVM1 in configure and use it in config_settings.h
Just like we have DEFAULT_USE_LVMETAD (or DEFUALT_USE_LVMPOLLD), use
fallback_to_lvm1=1 lvm.conf setting if we configured lvm2 with
--enable-lvm1-fallback and use fallback_to_lvm1=0 otherwise.
Also, generate proper lvm.conf.in with unconfigured value.
---
conf/example.conf.in | 2 +-
configure | 10 ++++++++++
configure.in | 6 ++++++
lib/config/config_settings.h | 2 +-
lib/config/defaults.h | 6 ------
lib/misc/configure.h.in | 4 ++++
6 files changed, 22 insertions(+), 8 deletions(-)
diff --git a/conf/example.conf.in b/conf/example.conf.in
index 4520162..9af58db 100644
--- a/conf/example.conf.in
+++ b/conf/example.conf.in
@@ -602,7 +602,7 @@ global {
# The LVM1 tools need to be installed with .lvm1 suffices,
# e.g. vgscan.lvm1. They will stop working once the lvm2
# on-disk metadata format is used.
- # fallback_to_lvm1 = 1
+ # fallback_to_lvm1 = @DEFAULT_FALLBACK_TO_LVM1@
# Configuration option global/format.
# The default metadata format that commands should use.
diff --git a/configure b/configure
index 13d10c4..13e40f8 100755
--- a/configure
+++ b/configure
@@ -703,6 +703,7 @@ DEFAULT_RAID10_SEGTYPE
DEFAULT_PROFILE_SUBDIR
DEFAULT_PID_DIR
DEFAULT_MIRROR_SEGTYPE
+DEFAULT_FALLBACK_TO_LVM1
DEFAULT_LOCK_DIR
DEFAULT_DM_RUN_DIR
DEFAULT_DATA_ALIGNMENT
@@ -7462,11 +7463,19 @@ fi
$as_echo "$LVM1_FALLBACK" >&6; }
if test "$LVM1_FALLBACK" = yes; then
+ DEFAULT_FALLBACK_TO_LVM1=1
$as_echo "#define LVM1_FALLBACK 1" >>confdefs.h
+else
+ DEFAULT_FALLBACK_TO_LVM1=0
fi
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_FALLBACK_TO_LVM1 $DEFAULT_FALLBACK_TO_LVM1
+_ACEOF
+
+
################################################################################
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to include support for lvm1 metadata" >&5
$as_echo_n "checking whether to include support for lvm1 metadata... " >&6; }
@@ -13276,6 +13285,7 @@ LVM_LIBAPI=`echo "$VER" | $AWK -F '[()]' '{print $2}'`
+
################################################################################
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/lvmetad/Makefile daemons/lvmpolld/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/replicator/Makefile lib/misc/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile lib/cache_segtype/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile
liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_systemd_red_hat.service scripts/lvm2_lvmpolld_systemd_red_hat.socket scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/Makefile test/Makefile test/api/Makefile test/unit/
Makefile tools/Makefile udev/Makefile unit-tests/datastruct/Makefile unit-tests/regex/Makefile unit-tests/mm/Makefile"
diff --git a/configure.in b/configure.in
index d330bd2..0c310ca 100644
--- a/configure.in
+++ b/configure.in
@@ -263,8 +263,13 @@ AC_ARG_ENABLE(lvm1_fallback,
AC_MSG_RESULT($LVM1_FALLBACK)
if test "$LVM1_FALLBACK" = yes; then
+ DEFAULT_FALLBACK_TO_LVM1=1
AC_DEFINE([LVM1_FALLBACK], 1, [Define to 1 if 'lvm' should fall back to using LVM1 binaries if device-mapper is missing from the kernel])
+else
+ DEFAULT_FALLBACK_TO_LVM1=0
fi
+AC_DEFINE_UNQUOTED(DEFAULT_FALLBACK_TO_LVM1, [$DEFAULT_FALLBACK_TO_LVM1],
+ [Fall back to LVM1 by default if device-mapper is missing from the kernel.])
################################################################################
dnl -- format1 inclusion type
@@ -1782,6 +1787,7 @@ AC_SUBST(DEFAULT_CACHE_SUBDIR)
AC_SUBST(DEFAULT_DATA_ALIGNMENT)
AC_SUBST(DEFAULT_DM_RUN_DIR)
AC_SUBST(DEFAULT_LOCK_DIR)
+AC_SUBST(DEFAULT_FALLBACK_TO_LVM1)
AC_SUBST(DEFAULT_MIRROR_SEGTYPE)
AC_SUBST(DEFAULT_PID_DIR)
AC_SUBST(DEFAULT_PROFILE_SUBDIR)
diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h
index fb05b85..cac1978 100644
--- a/lib/config/config_settings.h
+++ b/lib/config/config_settings.h
@@ -628,7 +628,7 @@ cfg(global_activation_CFG, "activation", global_CFG_SECTION, 0, CFG_TYPE_BOOL, D
"is not present in the kernel, disabling this should suppress\n"
"the error messages.\n")
-cfg(global_fallback_to_lvm1_CFG, "fallback_to_lvm1", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_FALLBACK_TO_LVM1, vsn(1, 0, 18), NULL, 0, NULL,
+cfg(global_fallback_to_lvm1_CFG, "fallback_to_lvm1", global_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_FALLBACK_TO_LVM1, vsn(1, 0, 18), "@DEFAULT_FALLBACK_TO_LVM1@", 0, NULL,
"Try running LVM1 tools if LVM cannot communicate with DM.\n"
"This option only applies to 2.4 kernels and is provided to\n"
"help switch between device-mapper kernels and LVM1 kernels.\n"
diff --git a/lib/config/defaults.h b/lib/config/defaults.h
index 3745639..2d74c17 100644
--- a/lib/config/defaults.h
+++ b/lib/config/defaults.h
@@ -111,12 +111,6 @@
#define DEFAULT_UMASK 0077
-#ifdef LVM1_FALLBACK
-# define DEFAULT_FALLBACK_TO_LVM1 1
-#else
-# define DEFAULT_FALLBACK_TO_LVM1 0
-#endif
-
#define DEFAULT_FORMAT "lvm2"
#define DEFAULT_STRIPESIZE 64 /* KB */
diff --git a/lib/misc/configure.h.in b/lib/misc/configure.h.in
index 9ec997f..6daf105 100644
--- a/lib/misc/configure.h.in
+++ b/lib/misc/configure.h.in
@@ -68,6 +68,10 @@
/* Default system configuration directory. */
#undef DEFAULT_ETC_DIR
+/* Fall back to LVM1 by default if device-mapper is missing from the kernel.
+ */
+#undef DEFAULT_FALLBACK_TO_LVM1
+
/* Name of default locking directory. */
#undef DEFAULT_LOCK_DIR
8 years, 5 months
master - cleanup: report: use internal wrapper for various variables used for handling reserved values
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=d7b9349ce71f27...
Commit: d7b9349ce71f2747eb7d0a8992244bc3d34719be
Parent: d8996a17d1a0605cebfcf926a7a8d0e6b7fc1fcc
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Tue Jun 30 10:23:35 2015 +0200
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Tue Jun 30 10:47:51 2015 +0200
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.
---
libdm/libdm-report.c | 93 ++++++++++++++++++++++++++++++-------------------
1 files changed, 57 insertions(+), 36 deletions(-)
diff --git a/libdm/libdm-report.c b/libdm/libdm-report.c
index 401e87a..4348db1 100644
--- a/libdm/libdm-report.c
+++ b/libdm/libdm-report.c
@@ -188,6 +188,12 @@ struct selection_node {
} selection;
};
+struct reserved_value_wrapper {
+ const char *matched_name;
+ const struct dm_report_reserved_value *reserved;
+ const void *value;
+};
+
/*
* Report data field
*/
@@ -2080,14 +2086,14 @@ static const char *_reserved_name(const char **names, const char *s, size_t len)
static const char *_get_reserved(struct dm_report *rh, unsigned type,
uint32_t field_num, int implicit,
const char *s, const char **begin, const char **end,
- const struct dm_report_reserved_value **reserved)
+ struct reserved_value_wrapper *rvw)
{
const struct dm_report_reserved_value *iter = implicit ? NULL : rh->reserved_values;
const char *tmp_begin, *tmp_end, *tmp_s = s;
const char *name = NULL;
char c;
- *reserved = NULL;
+ rvw->reserved = NULL;
if (!iter)
return s;
@@ -2115,7 +2121,8 @@ static const char *_get_reserved(struct dm_report *rh, unsigned type,
*begin = tmp_begin;
*end = tmp_end;
s = tmp_s;
- *reserved = iter;
+ rvw->reserved = iter;
+ rvw->matched_name = name;
}
return s;
@@ -2213,10 +2220,10 @@ static const char *_tok_value_regex(struct dm_report *rh,
const struct dm_report_field_type *ft,
const char *s, const char **begin,
const char **end, uint32_t *flags,
- const struct dm_report_reserved_value **reserved)
+ struct reserved_value_wrapper *rvw)
{
char c;
- *reserved = NULL;
+ rvw->reserved = NULL;
s = _skip_space(s);
@@ -2439,7 +2446,7 @@ static const char *_tok_value(struct dm_report *rh,
const char *s,
const char **begin, const char **end,
uint32_t *flags,
- const struct dm_report_reserved_value **reserved,
+ struct reserved_value_wrapper *rvw,
struct dm_pool *mem, void *custom)
{
int expected_type = ft->flags & DM_REPORT_FIELD_TYPE_MASK;
@@ -2450,8 +2457,8 @@ static const char *_tok_value(struct dm_report *rh,
s = _skip_space(s);
- s = _get_reserved(rh, expected_type, field_num, implicit, s, begin, end, reserved);
- if (*reserved) {
+ s = _get_reserved(rh, expected_type, field_num, implicit, s, begin, end, rvw);
+ if (rvw->reserved) {
*flags |= expected_type;
return s;
}
@@ -2553,12 +2560,23 @@ static const char *_tok_field_name(const char *s,
return s;
}
-static const void *_get_reserved_value(const struct dm_report_reserved_value *reserved)
+static int _get_reserved_value(struct dm_report *rh, uint32_t field_num,
+ struct reserved_value_wrapper *rvw)
{
- if (reserved->type & DM_REPORT_FIELD_TYPE_MASK)
- return reserved->value;
+ const void *tmp_value;
+
+ if (!rvw->reserved) {
+ rvw->value = NULL;
+ return 1;
+ }
+
+ if (rvw->reserved->type & DM_REPORT_FIELD_TYPE_MASK)
+ tmp_value = rvw->reserved->value;
else
- return ((const struct dm_report_field_reserved_value *) reserved->value)->value;
+ tmp_value = ((const struct dm_report_field_reserved_value *) rvw->reserved->value)->value;
+
+ rvw->value = tmp_value;
+ return 1;
}
static struct field_selection *_create_field_selection(struct dm_report *rh,
@@ -2567,7 +2585,7 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
const char *v,
size_t len,
uint32_t flags,
- const struct dm_report_reserved_value *reserved,
+ struct reserved_value_wrapper *rvw,
void *custom)
{
static const char *_out_of_range_msg = "Field selection value %s out of supported range for field %s.";
@@ -2576,7 +2594,6 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
: rh->fields;
struct field_properties *fp, *found = NULL;
struct field_selection *fs;
- const void *reserved_value;
const char *field_id;
uint64_t factor;
char *s;
@@ -2615,7 +2632,7 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
goto error;
}
- if (reserved && (reserved->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE) &&
+ if (rvw->reserved && (rvw->reserved->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE) &&
!(fs->value->next = dm_pool_zalloc(rh->selection->mem, sizeof(struct field_selection_value)))) {
log_error(_field_selection_value_alloc_failed_msg, field_id);
goto error;
@@ -2624,7 +2641,11 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
fs->fp = found;
fs->flags = flags;
- reserved_value = reserved ? _get_reserved_value(reserved) : NULL;
+ if (!_get_reserved_value(rh, field_num, rvw)) {
+ log_error("dm_report: could not get reserved value "
+ "while processing selection field %s", field_id);
+ goto error;
+ }
/* store comparison operand */
if (flags & FLD_CMP_REGEX) {
@@ -2654,10 +2675,10 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
switch (flags & DM_REPORT_FIELD_TYPE_MASK) {
case DM_REPORT_FIELD_TYPE_STRING:
- if (reserved_value) {
- fs->value->v.s = (const char *) reserved_value;
- if (reserved->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE)
- fs->value->next->v.s = (((const char **) reserved_value)[1]);
+ if (rvw->value) {
+ fs->value->v.s = (const char *) rvw->value;
+ if (rvw->reserved->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE)
+ fs->value->next->v.s = (((const char **) rvw->value)[1]);
dm_pool_free(rh->selection->mem, s);
} else {
fs->value->v.s = s;
@@ -2668,10 +2689,10 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
}
break;
case DM_REPORT_FIELD_TYPE_NUMBER:
- if (reserved_value) {
- fs->value->v.i = *(uint64_t *) reserved_value;
- if (reserved->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE)
- fs->value->next->v.i = (((uint64_t *) reserved_value)[1]);
+ if (rvw->value) {
+ fs->value->v.i = *(uint64_t *) rvw->value;
+ if (rvw->reserved->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE)
+ fs->value->next->v.i = (((uint64_t *) rvw->value)[1]);
} else {
if (((fs->value->v.i = strtoull(s, NULL, 10)) == ULLONG_MAX) &&
(errno == ERANGE)) {
@@ -2686,10 +2707,10 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
dm_pool_free(rh->selection->mem, s);
break;
case DM_REPORT_FIELD_TYPE_SIZE:
- if (reserved_value) {
- fs->value->v.d = *(double *) reserved_value;
- if (reserved->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE)
- fs->value->next->v.d = (((double *) reserved_value)[1]);
+ if (rvw->value) {
+ fs->value->v.d = *(double *) rvw->value;
+ if (rvw->reserved->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE)
+ fs->value->next->v.d = (((double *) rvw->value)[1]);
} else {
fs->value->v.d = strtod(s, NULL);
if (errno == ERANGE) {
@@ -2707,10 +2728,10 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
dm_pool_free(rh->selection->mem, s);
break;
case DM_REPORT_FIELD_TYPE_PERCENT:
- if (reserved_value) {
- fs->value->v.i = *(uint64_t *) reserved_value;
- if (reserved->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE)
- fs->value->next->v.i = (((uint64_t *) reserved_value)[1]);
+ if (rvw->value) {
+ fs->value->v.i = *(uint64_t *) rvw->value;
+ if (rvw->reserved->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE)
+ fs->value->next->v.i = (((uint64_t *) rvw->value)[1]);
} else {
fs->value->v.d = strtod(s, NULL);
if ((errno == ERANGE) || (fs->value->v.d < 0) || (fs->value->v.d > 100)) {
@@ -2868,7 +2889,7 @@ static struct selection_node *_parse_selection(struct dm_report *rh,
int implicit;
const struct dm_report_field_type *ft;
struct selection_str_list *str_list;
- const struct dm_report_reserved_value *reserved;
+ struct reserved_value_wrapper rvw = {0};
uint64_t factor;
void *custom = NULL;
char *tmp;
@@ -2931,7 +2952,7 @@ static struct selection_node *_parse_selection(struct dm_report *rh,
/* comparison value */
if (flags & FLD_CMP_REGEX) {
- if (!(last = _tok_value_regex(rh, ft, last, &vs, &ve, &flags, &reserved)))
+ if (!(last = _tok_value_regex(rh, ft, last, &vs, &ve, &flags, &rvw)))
goto_bad;
} else {
if (ft->flags == DM_REPORT_FIELD_TYPE_SIZE ||
@@ -2944,14 +2965,14 @@ static struct selection_node *_parse_selection(struct dm_report *rh,
custom = NULL;
if (!(last = _tok_value(rh, ft, field_num, implicit,
last, &vs, &ve, &flags,
- &reserved, rh->selection->mem, custom)))
+ &rvw, rh->selection->mem, custom)))
goto_bad;
}
*next = _skip_space(last);
/* create selection */
- if (!(fs = _create_field_selection(rh, field_num, implicit, vs, (size_t) (ve - vs), flags, reserved, custom)))
+ if (!(fs = _create_field_selection(rh, field_num, implicit, vs, (size_t) (ve - vs), flags, &rvw, custom)))
return_NULL;
/* create selection node */
8 years, 5 months
master - select: add support for range reserved values and flagging named-only values
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=d8996a17d1a060...
Commit: d8996a17d1a0605cebfcf926a7a8d0e6b7fc1fcc
Parent: 77f0e7a450dc2bc3e42bb4854e1032873d661c58
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Tue Jun 30 10:13:35 2015 +0200
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Tue Jun 30 10:47:50 2015 +0200
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.
---
WHATS_NEW_DM | 2 +
lib/report/report.c | 32 +++--
lib/report/values.h | 32 +++---
libdm/libdevmapper.h | 29 +++--
libdm/libdm-report.c | 348 ++++++++++++++++++++++++++++++++++++--------------
5 files changed, 304 insertions(+), 139 deletions(-)
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index ce10238..75e572a 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,5 +1,7 @@
Version 1.02.100 -
================================
+ Support report reserved value ranges: DM_REPORT_FIELD_RESERVED_VALUE_RANGE.
+ Support report reserved value names: DM_REPORT_FIELD_RESERVED_VALUE_NAMED.
Add DM_CONFIG_VALUE_FMT_{INT_OCTAL,STRING_NO_QUOTES} config value format flag.
Add DM_CONFIG_VALUE_FMT_COMMON_{ARRAY,EXTRA_SPACE} config value format flag.
Add dm_config_value_{get,set}_format_flags to get and set config value format.
diff --git a/lib/report/report.c b/lib/report/report.c
index 30b3767..1c741e4 100644
--- a/lib/report/report.c
+++ b/lib/report/report.c
@@ -96,24 +96,28 @@ static const int32_t _reserved_num_undef_32 = INT32_C(-1);
* - 'reserved_value_id_n' (for 0)
*/
#define NUM uint64_t
-#define SIZ double
+#define NOFLAG 0
+#define NAMED DM_REPORT_FIELD_RESERVED_VALUE_NAMED
+#define RANGE DM_REPORT_FIELD_RESERVED_VALUE_RANGE
-#define TYPE_RESERVED_VALUE(type, id, desc, value, ...) \
+#define TYPE_RESERVED_VALUE(type, flags, id, desc, value, ...) \
static const char *_reserved_ ## id ## _names[] = { __VA_ARGS__, NULL}; \
static const type _reserved_ ## id = value;
-#define FIELD_RESERVED_VALUE(field_id, id, desc, value, ...) \
+#define FIELD_RESERVED_VALUE(flags, field_id, id, desc, value, ...) \
static const char *_reserved_ ## id ## _names[] = { __VA_ARGS__ , NULL}; \
static const struct dm_report_field_reserved_value _reserved_ ## id = {field_ ## field_id, value};
#define FIELD_RESERVED_BINARY_VALUE(field_id, id, desc, ...) \
- FIELD_RESERVED_VALUE(field_id, id ## _y, desc, &_one64, __VA_ARGS__, _str_yes) \
- FIELD_RESERVED_VALUE(field_id, id ## _n, desc, &_zero64, __VA_ARGS__, _str_no)
+ FIELD_RESERVED_VALUE(NAMED, field_id, id ## _y, desc, &_one64, __VA_ARGS__, _str_yes) \
+ FIELD_RESERVED_VALUE(NAMED, field_id, id ## _n, desc, &_zero64, __VA_ARGS__, _str_no)
#include "values.h"
#undef NUM
-#undef SIZ
+#undef NOFLAG
+#undef NAMED
+#undef RANGE
#undef TYPE_RESERVED_VALUE
#undef FIELD_RESERVED_VALUE
#undef FIELD_RESERVED_BINARY_VALUE
@@ -126,15 +130,17 @@ static const int32_t _reserved_num_undef_32 = INT32_C(-1);
*/
#define NUM DM_REPORT_FIELD_TYPE_NUMBER
-#define SIZ DM_REPORT_FIELD_TYPE_SIZE
+#define NOFLAG 0
+#define NAMED DM_REPORT_FIELD_RESERVED_VALUE_NAMED
+#define RANGE DM_REPORT_FIELD_RESERVED_VALUE_RANGE
-#define TYPE_RESERVED_VALUE(type, id, desc, value, ...) {type, &_reserved_ ## id, _reserved_ ## id ## _names, desc},
+#define TYPE_RESERVED_VALUE(type, flags, id, desc, value, ...) {type | flags, &_reserved_ ## id, _reserved_ ## id ## _names, desc},
-#define FIELD_RESERVED_VALUE(field_id, id, desc, value, ...) {DM_REPORT_FIELD_TYPE_NONE, &_reserved_ ## id, _reserved_ ## id ## _names, desc},
+#define FIELD_RESERVED_VALUE(flags, field_id, id, desc, value, ...) {DM_REPORT_FIELD_TYPE_NONE | flags, &_reserved_ ## id, _reserved_ ## id ## _names, desc},
#define FIELD_RESERVED_BINARY_VALUE(field_id, id, desc, ...) \
- FIELD_RESERVED_VALUE(field_id, id ## _y, desc, &_one64, __VA_ARGS__) \
- FIELD_RESERVED_VALUE(field_id, id ## _n, desc, &_zero64, __VA_ARGS__)
+ FIELD_RESERVED_VALUE(NAMED, field_id, id ## _y, desc, &_one64, __VA_ARGS__) \
+ FIELD_RESERVED_VALUE(NAMED, field_id, id ## _n, desc, &_zero64, __VA_ARGS__)
static const struct dm_report_reserved_value _report_reserved_values[] = {
#include "values.h"
@@ -142,7 +148,9 @@ static const struct dm_report_reserved_value _report_reserved_values[] = {
};
#undef NUM
-#undef SIZ
+#undef NOFLAG
+#undef NAMED
+#undef RANGE
#undef TYPE_RESERVED_VALUE
#undef FIELD_RESERVED_VALUE
#undef FIELD_RESERVED_BINARY_VALUE
diff --git a/lib/report/values.h b/lib/report/values.h
index dd20caf..742cb50 100644
--- a/lib/report/values.h
+++ b/lib/report/values.h
@@ -38,15 +38,15 @@
*/
/*
- * TYPE_RESERVED_VALUE(type, reserved_value_id, description, value, reserved_name, ...)
- * FIELD_RESERVED_VALUE(field_id, reserved_value_id, description, value, reserved_name, ...)
+ * TYPE_RESERVED_VALUE(type, flags, reserved_value_id, description, value, reserved_name, ...)
+ * FIELD_RESERVED_VALUE(field_id, flags, reserved_value_id, description, value, reserved_name, ...)
* FIELD_BINARY_RESERVED_VALUE(field_id, reserved_value_id, description, reserved_name for 1, ...)
*/
/* *INDENT-OFF* */
/* Per-type reserved values usable for all fields of certain type. */
-TYPE_RESERVED_VALUE(NUM, num_undef_64, "Reserved value for undefined numeric value.", UINT64_C(-1), "-1", "unknown", "undefined", "undef")
+TYPE_RESERVED_VALUE(NUM, NOFLAG, num_undef_64, "Reserved value for undefined numeric value.", UINT64_C(-1), "-1", "unknown", "undefined", "undef")
/* Reserved values for PV fields */
FIELD_RESERVED_BINARY_VALUE(pv_allocatable, pv_allocatable, "", "allocatable")
@@ -58,9 +58,9 @@ FIELD_RESERVED_BINARY_VALUE(vg_extendable, vg_extendable, "", "extendable")
FIELD_RESERVED_BINARY_VALUE(vg_exported, vg_exported, "", "exported")
FIELD_RESERVED_BINARY_VALUE(vg_partial, vg_partial, "", "partial")
FIELD_RESERVED_BINARY_VALUE(vg_clustered, vg_clustered, "", "clustered")
-FIELD_RESERVED_VALUE(vg_permissions, vg_permissions_rw, "", "writeable", "writeable", "rw", "read-write")
-FIELD_RESERVED_VALUE(vg_permissions, vg_permissions_r, "", "read-only", "read-only", "r", "ro")
-FIELD_RESERVED_VALUE(vg_mda_copies, vg_mda_copies_unmanaged, "", &GET_TYPE_RESERVED_VALUE(num_undef_64), "unmanaged")
+FIELD_RESERVED_VALUE(NAMED, vg_permissions, vg_permissions_rw, "", "writeable", "writeable", "rw", "read-write")
+FIELD_RESERVED_VALUE(NAMED, vg_permissions, vg_permissions_r, "", "read-only", "read-only", "r", "ro")
+FIELD_RESERVED_VALUE(NOFLAG, vg_mda_copies, vg_mda_copies_unmanaged, "", &GET_TYPE_RESERVED_VALUE(num_undef_64), "unmanaged")
/* Reserved values for LV fields */
FIELD_RESERVED_BINARY_VALUE(lv_initial_image_sync, lv_initial_image_sync, "", "initial image sync", "sync")
@@ -80,18 +80,18 @@ FIELD_RESERVED_BINARY_VALUE(lv_inactive_table, lv_inactive_table, "", "inactive
FIELD_RESERVED_BINARY_VALUE(lv_device_open, lv_device_open, "", "open")
FIELD_RESERVED_BINARY_VALUE(lv_skip_activation, lv_skip_activation, "", "skip activation", "skip")
FIELD_RESERVED_BINARY_VALUE(zero, zero, "", "zero")
-FIELD_RESERVED_VALUE(lv_permissions, lv_permissions_rw, "", "writeable", "writeable", "rw", "read-write")
-FIELD_RESERVED_VALUE(lv_permissions, lv_permissions_r, "", "read-only", "read-only", "r", "ro")
-FIELD_RESERVED_VALUE(lv_permissions, lv_permissions_r_override, "", "read-only-override", "read-only-override", "ro-override", "r-override", "R")
-FIELD_RESERVED_VALUE(lv_read_ahead, lv_read_ahead_auto, "", &_siz_max, "auto")
-FIELD_RESERVED_VALUE(lv_when_full, lv_when_full_error, "", "error", "error", "error when full", "error if no space")
-FIELD_RESERVED_VALUE(lv_when_full, lv_when_full_queue, "", "queue", "queue", "queue when full", "queue if no space")
-FIELD_RESERVED_VALUE(lv_when_full, lv_when_full_undef, "", "", "", "undefined")
+FIELD_RESERVED_VALUE(NAMED, lv_permissions, lv_permissions_rw, "", "writeable", "writeable", "rw", "read-write")
+FIELD_RESERVED_VALUE(NAMED, lv_permissions, lv_permissions_r, "", "read-only", "read-only", "r", "ro")
+FIELD_RESERVED_VALUE(NAMED, lv_permissions, lv_permissions_r_override, "", "read-only-override", "read-only-override", "ro-override", "r-override", "R")
+FIELD_RESERVED_VALUE(NOFLAG, lv_read_ahead, lv_read_ahead_auto, "", &_siz_max, "auto")
+FIELD_RESERVED_VALUE(NAMED, lv_when_full, lv_when_full_error, "", "error", "error", "error when full", "error if no space")
+FIELD_RESERVED_VALUE(NAMED, lv_when_full, lv_when_full_queue, "", "queue", "queue", "queue when full", "queue if no space")
+FIELD_RESERVED_VALUE(NOFLAG, lv_when_full, lv_when_full_undef, "", "", "", "undefined")
/* Reserved values for SEG fields */
-FIELD_RESERVED_VALUE(cache_policy, cache_policy_undef, "", "", "", "undefined")
-FIELD_RESERVED_VALUE(seg_monitor, seg_monitor_undef, "", "", "", "undefined")
-FIELD_RESERVED_VALUE(lv_health_status, health_undef, "", "", "", "undefined")
+FIELD_RESERVED_VALUE(NOFLAG, cache_policy, cache_policy_undef, "", "", "", "undefined")
+FIELD_RESERVED_VALUE(NOFLAG, seg_monitor, seg_monitor_undef, "", "", "", "undefined")
+FIELD_RESERVED_VALUE(NOFLAG, lv_health_status, health_undef, "", "", "", "undefined")
/* TODO the following 2 need STR_LIST support for reserved values
FIELD_RESERVED_VALUE(cache_settings, cache_settings_default, "", "default", "default")
FIELD_RESERVED_VALUE(cache_settings, cache_settings_undef, "", "undefined", "undefined") */
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index 7476aef..38f42aa 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -1671,17 +1671,22 @@ struct dm_report_field;
/*
* dm_report_field_type flags
*/
-#define DM_REPORT_FIELD_MASK 0x00000FFF
-#define DM_REPORT_FIELD_ALIGN_MASK 0x0000000F
-#define DM_REPORT_FIELD_ALIGN_LEFT 0x00000001
-#define DM_REPORT_FIELD_ALIGN_RIGHT 0x00000002
-#define DM_REPORT_FIELD_TYPE_MASK 0x00000FF0
-#define DM_REPORT_FIELD_TYPE_NONE 0x00000000
-#define DM_REPORT_FIELD_TYPE_STRING 0x00000010
-#define DM_REPORT_FIELD_TYPE_NUMBER 0x00000020
-#define DM_REPORT_FIELD_TYPE_SIZE 0x00000040
-#define DM_REPORT_FIELD_TYPE_PERCENT 0x00000080
-#define DM_REPORT_FIELD_TYPE_STRING_LIST 0x00000100
+#define DM_REPORT_FIELD_MASK 0x00000FFF
+#define DM_REPORT_FIELD_ALIGN_MASK 0x0000000F
+#define DM_REPORT_FIELD_ALIGN_LEFT 0x00000001
+#define DM_REPORT_FIELD_ALIGN_RIGHT 0x00000002
+#define DM_REPORT_FIELD_TYPE_MASK 0x00000FF0
+#define DM_REPORT_FIELD_TYPE_NONE 0x00000000
+#define DM_REPORT_FIELD_TYPE_STRING 0x00000010
+#define DM_REPORT_FIELD_TYPE_NUMBER 0x00000020
+#define DM_REPORT_FIELD_TYPE_SIZE 0x00000040
+#define DM_REPORT_FIELD_TYPE_PERCENT 0x00000080
+#define DM_REPORT_FIELD_TYPE_STRING_LIST 0x00000100
+
+/* For use with reserved values only! */
+#define DM_REPORT_FIELD_RESERVED_VALUE_MASK 0x0000000F
+#define DM_REPORT_FIELD_RESERVED_VALUE_NAMED 0x00000001 /* only named value, less strict form of reservation */
+#define DM_REPORT_FIELD_RESERVED_VALUE_RANGE 0x00000002 /* value is range - low and high value defined */
#define DM_REPORT_FIELD_TYPE_ID_LEN 32
#define DM_REPORT_FIELD_TYPE_HEADING_LEN 32
@@ -1728,7 +1733,7 @@ struct dm_report_field_reserved_value {
* selection enabled (see also dm_report_init_with_selection function).
*/
struct dm_report_reserved_value {
- const unsigned type; /* DM_REPORT_FIELD_TYPE_* */
+ const uint32_t type; /* DM_REPORT_FIELD_RESERVED_VALUE_* and DM_REPORT_FIELD_TYPE_* */
const void *value; /* reserved value:
struct dm_report_field_reserved_value for DM_REPORT_FIELD_TYPE_NONE
uint64_t for DM_REPORT_FIELD_TYPE_NUMBER
diff --git a/libdm/libdm-report.c b/libdm/libdm-report.c
index def72fe..401e87a 100644
--- a/libdm/libdm-report.c
+++ b/libdm/libdm-report.c
@@ -162,9 +162,7 @@ struct selection_str_list {
struct dm_list *list;
};
-struct field_selection {
- struct field_properties *fp;
- uint32_t flags;
+struct field_selection_value {
union {
const char *s;
uint64_t i;
@@ -172,6 +170,13 @@ struct field_selection {
struct dm_regex *r;
struct selection_str_list *l;
} v;
+ struct field_selection_value *next;
+};
+
+struct field_selection {
+ struct field_properties *fp;
+ uint32_t flags;
+ struct field_selection_value *value;
};
struct selection_node {
@@ -1257,30 +1262,98 @@ static void *_report_get_implicit_field_data(struct dm_report *rh __attribute__(
return NULL;
}
-static int _close_enough(double d1, double d2)
+static int _dbl_equal(double d1, double d2)
{
return fabs(d1 - d2) < DBL_EPSILON;
}
-static int _do_check_value_is_reserved(unsigned type, const void *reserved_value,
- const void *value1, const void *value2)
+static int _dbl_greater(double d1, double d2)
+{
+ return (d1 > d2) && !_dbl_equal(d1, d2);
+}
+
+static int _dbl_less(double d1, double d2)
+{
+ return (d1 < d2) && !_dbl_equal(d1, d2);
+}
+
+static int _dbl_greater_or_equal(double d1, double d2)
+{
+ return _dbl_greater(d1, d2) || _dbl_equal(d1, d2);
+}
+
+static int _dbl_less_or_equal(double d1, double d2)
{
- switch (type) {
+ return _dbl_less(d1, d2) || _dbl_equal(d1, d2);
+}
+
+#define _uint64 *(uint64_t *)
+#define _uint64arr(var,index) ((uint64_t *)var)[index]
+#define _str (const char *)
+#define _dbl *(double *)
+#define _dblarr(var,index) ((double *)var)[index]
+
+static int _do_check_value_is_strictly_reserved(unsigned type, const void *res_val, int res_range,
+ const void *val, struct field_selection *fs)
+{
+ int sel_range = fs ? fs->value->next != NULL : 0;
+
+ switch (type & DM_REPORT_FIELD_TYPE_MASK) {
case DM_REPORT_FIELD_TYPE_NUMBER:
- if ((*(uint64_t *)value1 == *(uint64_t *) reserved_value) ||
- (value2 && (*(uint64_t *)value2 == *(uint64_t *) reserved_value)))
- return 1;
+ if (res_range && sel_range) {
+ /* both reserved value and selection value are ranges */
+ if (((_uint64 val >= _uint64arr(res_val,0)) && (_uint64 val <= _uint64arr(res_val,1))) ||
+ (fs && ((fs->value->v.i == _uint64arr(res_val,0)) && (fs->value->next->v.i == _uint64arr(res_val,1)))))
+ return 1;
+ } else if (res_range) {
+ /* only reserved value is a range */
+ if (((_uint64 val >= _uint64arr(res_val,0)) && (_uint64 val <= _uint64arr(res_val,1))) ||
+ (fs && ((fs->value->v.i >= _uint64arr(res_val,0)) && (fs->value->v.i <= _uint64arr(res_val,1)))))
+ return 1;
+ } else if (sel_range) {
+ /* only selection value is a range */
+ if (((_uint64 val >= _uint64 res_val) && (_uint64 val <= _uint64 res_val)) ||
+ (fs && ((fs->value->v.i >= _uint64 res_val) && (fs->value->next->v.i <= _uint64 res_val))))
+ return 1;
+ } else {
+ /* neither selection value nor reserved value is a range */
+ if ((_uint64 val == _uint64 res_val) ||
+ (fs && (fs->value->v.i == _uint64 res_val)))
+ return 1;
+ }
break;
+
case DM_REPORT_FIELD_TYPE_STRING:
- if ((!strcmp((const char *)value1, (const char *) reserved_value)) ||
- (value2 && (!strcmp((const char *)value2, (const char *) reserved_value))))
+ /* there are no ranges for string type yet */
+ if ((!strcmp(_str val, _str res_val)) ||
+ (fs && (!strcmp(fs->value->v.s, _str res_val))))
return 1;
break;
+
case DM_REPORT_FIELD_TYPE_SIZE:
- if ((_close_enough(*(double *)value1, *(double *) reserved_value)) ||
- (value2 && (_close_enough(*(double *)value2, *(double *) reserved_value))))
- return 1;
+ if (res_range && sel_range) {
+ /* both reserved value and selection value are ranges */
+ if ((_dbl_greater_or_equal(_dbl val, _dblarr(res_val,0)) && _dbl_less_or_equal(_dbl val, _dblarr(res_val,1))) ||
+ (fs && (_dbl_equal(fs->value->v.d, _dblarr(res_val,0)) && (_dbl_equal(fs->value->next->v.d, _dblarr(res_val,1))))))
+ return 1;
+ } else if (res_range) {
+ /* only reserved value is a range */
+ if ((_dbl_greater_or_equal(_dbl val, _dblarr(res_val,0)) && _dbl_less_or_equal(_dbl val, _dblarr(res_val,1))) ||
+ (fs && (_dbl_greater_or_equal(fs->value->v.d, _dblarr(res_val,0)) && _dbl_less_or_equal(fs->value->v.d, _dblarr(res_val,1)))))
+ return 1;
+ } else if (sel_range) {
+ /* only selection value is a range */
+ if ((_dbl_greater_or_equal(_dbl val, _dbl res_val) && (_dbl_less_or_equal(_dbl val, _dbl res_val))) ||
+ (fs && (_dbl_greater_or_equal(fs->value->v.d, _dbl res_val) && _dbl_less_or_equal(fs->value->next->v.d, _dbl res_val))))
+ return 1;
+ } else {
+ /* neither selection value nor reserved value is a range */
+ if ((_dbl_equal(_dbl val, _dbl res_val)) ||
+ (fs && (_dbl_equal(fs->value->v.d, _dbl res_val))))
+ return 1;
+ }
break;
+
case DM_REPORT_FIELD_TYPE_STRING_LIST:
/* FIXME Add comparison for string list */
break;
@@ -1292,22 +1365,27 @@ static int _do_check_value_is_reserved(unsigned type, const void *reserved_value
/*
* Used to check whether a value of certain type used in selection is reserved.
*/
-static int _check_value_is_reserved(struct dm_report *rh, uint32_t field_num, unsigned type,
- const void *value1, const void *value2)
+static int _check_value_is_strictly_reserved(struct dm_report *rh, uint32_t field_num, unsigned type,
+ const void *val, struct field_selection *fs)
{
const struct dm_report_reserved_value *iter = rh->reserved_values;
const struct dm_report_field_reserved_value *frv;
+ int res_range;
if (!iter)
return 0;
while (iter->value) {
- if (iter->type == DM_REPORT_FIELD_TYPE_NONE) {
- frv = (const struct dm_report_field_reserved_value *) iter->value;
- if (frv->field_num == field_num && _do_check_value_is_reserved(type, frv->value, value1, value2))
+ /* Only check strict reserved values, not the weaker form ("named" reserved value). */
+ if (!(iter->type & DM_REPORT_FIELD_RESERVED_VALUE_NAMED)) {
+ res_range = iter->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE;
+ if ((iter->type & DM_REPORT_FIELD_TYPE_MASK) == DM_REPORT_FIELD_TYPE_NONE) {
+ frv = (const struct dm_report_field_reserved_value *) iter->value;
+ if (frv->field_num == field_num && _do_check_value_is_strictly_reserved(type, frv->value, res_range, val, fs))
+ return 1;
+ } else if (iter->type & type && _do_check_value_is_strictly_reserved(type, iter->value, res_range, val, fs))
return 1;
- } else if (iter->type & type && _do_check_value_is_reserved(type, iter->value, value1, value2))
- return 1;
+ }
iter++;
}
@@ -1315,21 +1393,39 @@ static int _check_value_is_reserved(struct dm_report *rh, uint32_t field_num, un
}
static int _cmp_field_int(struct dm_report *rh, uint32_t field_num, const char *field_id,
- uint64_t a, uint64_t b, uint32_t flags)
+ uint64_t val, struct field_selection *fs)
{
- switch(flags & FLD_CMP_MASK) {
+ int range = fs->value->next != NULL;
+ const uint64_t sel1 = fs->value->v.i;
+ const uint64_t sel2 = range ? fs->value->next->v.i : 0;
+
+ switch(fs->flags & FLD_CMP_MASK) {
case FLD_CMP_EQUAL:
- return a == b;
+ return range ? ((val >= sel1) && (val <= sel2)) : val == sel1;
+
case FLD_CMP_NOT|FLD_CMP_EQUAL:
- return a != b;
+ return range ? !((val >= sel1) && (val <= sel2)) : val != sel1;
+
case FLD_CMP_NUMBER|FLD_CMP_GT:
- return _check_value_is_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_NUMBER, &a, &b) ? 0 : a > b;
+ if (_check_value_is_strictly_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_NUMBER, &val, fs))
+ return 0;
+ return range ? val > sel2 : val > sel1;
+
case FLD_CMP_NUMBER|FLD_CMP_GT|FLD_CMP_EQUAL:
- return _check_value_is_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_NUMBER, &a, &b) ? 0 : a >= b;
+ if (_check_value_is_strictly_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_NUMBER, &val, fs))
+ return 0;
+ return val >= sel1;
+
case FLD_CMP_NUMBER|FLD_CMP_LT:
- return _check_value_is_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_NUMBER, &a, &b) ? 0 : a < b;
+ if (_check_value_is_strictly_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_NUMBER, &val, fs))
+ return 0;
+ return val < sel1;
+
case FLD_CMP_NUMBER|FLD_CMP_LT|FLD_CMP_EQUAL:
- return _check_value_is_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_NUMBER, &a, &b) ? 0 : a <= b;
+ if (_check_value_is_strictly_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_NUMBER, &val, fs))
+ return 0;
+ return range ? val <= sel2 : val <= sel1;
+
default:
log_error(INTERNAL_ERROR "_cmp_field_int: unsupported number "
"comparison type for field %s", field_id);
@@ -1339,21 +1435,42 @@ static int _cmp_field_int(struct dm_report *rh, uint32_t field_num, const char *
}
static int _cmp_field_double(struct dm_report *rh, uint32_t field_num, const char *field_id,
- double a, double b, uint32_t flags)
+ double val, struct field_selection *fs)
{
- switch(flags & FLD_CMP_MASK) {
+ int range = fs->value->next != NULL;
+ double sel1 = fs->value->v.d;
+ double sel2 = range ? fs->value->next->v.d : 0;
+
+ switch(fs->flags & FLD_CMP_MASK) {
case FLD_CMP_EQUAL:
- return _close_enough(a, b);
+ return range ? (_dbl_greater_or_equal(val, sel1) && _dbl_less_or_equal(val, sel2))
+ : _dbl_equal(val, sel1);
+
case FLD_CMP_NOT|FLD_CMP_EQUAL:
- return !_close_enough(a, b);
+ return range ? !(_dbl_greater_or_equal(val, sel1) && _dbl_less_or_equal(val, sel2))
+ : !_dbl_equal(val, sel1);
+
case FLD_CMP_NUMBER|FLD_CMP_GT:
- return _check_value_is_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_SIZE, &a, &b) ? 0 : (a > b) && !_close_enough(a, b);
+ if (_check_value_is_strictly_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_SIZE, &val, fs))
+ return 0;
+ return range ? _dbl_greater(val, sel2)
+ : _dbl_greater(val, sel1);
+
case FLD_CMP_NUMBER|FLD_CMP_GT|FLD_CMP_EQUAL:
- return _check_value_is_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_SIZE, &a, &b) ? 0 : (a > b) || _close_enough(a, b);
+ if (_check_value_is_strictly_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_SIZE, &val, fs))
+ return 0;
+ return _dbl_greater_or_equal(val, sel1);
+
case FLD_CMP_NUMBER|FLD_CMP_LT:
- return _check_value_is_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_SIZE, &a, &b) ? 0 : (a < b) && !_close_enough(a, b);
+ if (_check_value_is_strictly_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_SIZE, &val, fs))
+ return 0;
+ return _dbl_less(val, sel1);
+
case FLD_CMP_NUMBER|FLD_CMP_LT|FLD_CMP_EQUAL:
- return _check_value_is_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_SIZE, &a, &b) ? 0 : a < b || _close_enough(a, b);
+ if (_check_value_is_strictly_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_SIZE, &val, fs))
+ return 0;
+ return range ? _dbl_less_or_equal(val, sel2) : _dbl_less_or_equal(val, sel1);
+
default:
log_error(INTERNAL_ERROR "_cmp_field_double: unsupported number "
"comparison type for selection field %s", field_id);
@@ -1364,13 +1481,15 @@ static int _cmp_field_double(struct dm_report *rh, uint32_t field_num, const cha
static int _cmp_field_string(struct dm_report *rh __attribute__((unused)),
uint32_t field_num, const char *field_id,
- const char *a, const char *b, uint32_t flags)
+ const char *val, struct field_selection *fs)
{
- switch (flags & FLD_CMP_MASK) {
+ const char *sel = fs->value->v.s;
+
+ switch (fs->flags & FLD_CMP_MASK) {
case FLD_CMP_EQUAL:
- return !strcmp(a, b);
+ return _check_value_is_strictly_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_STRING, val, fs) ? 0 : !strcmp(val, sel);
case FLD_CMP_NOT|FLD_CMP_EQUAL:
- return strcmp(a, b);
+ return _check_value_is_strictly_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_STRING, val, fs) ? 0 : strcmp(val, sel);
default:
log_error(INTERNAL_ERROR "_cmp_field_string: unsupported string "
"comparison type for selection field %s", field_id);
@@ -1458,12 +1577,13 @@ static int _cmp_field_string_list_any(const struct str_list_sort_value *val,
static int _cmp_field_string_list(struct dm_report *rh __attribute__((unused)),
uint32_t field_num, const char *field_id,
- const struct str_list_sort_value *value,
- const struct selection_str_list *selection, uint32_t flags)
+ const struct str_list_sort_value *val,
+ struct field_selection *fs)
{
+ const struct selection_str_list *sel = fs->value->v.l;
int subset, r;
- switch (selection->type & SEL_LIST_MASK) {
+ switch (sel->type & SEL_LIST_MASK) {
case SEL_LIST_LS:
subset = 0;
break;
@@ -1475,13 +1595,13 @@ static int _cmp_field_string_list(struct dm_report *rh __attribute__((unused)),
return 0;
}
- switch (selection->type & SEL_MASK) {
+ switch (sel->type & SEL_MASK) {
case SEL_AND:
- r = subset ? _cmp_field_string_list_subset_all(value, selection)
- : _cmp_field_string_list_strict_all(value, selection);
+ r = subset ? _cmp_field_string_list_subset_all(val, sel)
+ : _cmp_field_string_list_strict_all(val, sel);
break;
case SEL_OR:
- r = _cmp_field_string_list_any(value, selection);
+ r = _cmp_field_string_list_any(val, sel);
break;
default:
log_error(INTERNAL_ERROR "_cmp_field_string_list: unsupported string "
@@ -1490,13 +1610,13 @@ static int _cmp_field_string_list(struct dm_report *rh __attribute__((unused)),
return 0;
}
- return flags & FLD_CMP_NOT ? !r : r;
+ return fs->flags & FLD_CMP_NOT ? !r : r;
}
-static int _cmp_field_regex(const char *s, struct dm_regex *r, uint32_t flags)
+static int _cmp_field_regex(const char *s, struct field_selection *fs)
{
- int match = dm_regex_match(r, s) >= 0;
- return flags & FLD_CMP_NOT ? !match : match;
+ int match = dm_regex_match(fs->value->v.r, s) >= 0;
+ return fs->flags & FLD_CMP_NOT ? !match : match;
}
static int _compare_selection_field(struct dm_report *rh,
@@ -1515,7 +1635,7 @@ static int _compare_selection_field(struct dm_report *rh,
}
if (fs->flags & FLD_CMP_REGEX)
- r = _cmp_field_regex((const char *) f->sort_value, fs->v.r, fs->flags);
+ r = _cmp_field_regex((const char *) f->sort_value, fs);
else {
switch(f->props->flags & DM_REPORT_FIELD_TYPE_MASK) {
case DM_REPORT_FIELD_TYPE_PERCENT:
@@ -1527,17 +1647,16 @@ static int _compare_selection_field(struct dm_report *rh,
return 0;
/* fall through */
case DM_REPORT_FIELD_TYPE_NUMBER:
- r = _cmp_field_int(rh, f->props->field_num, field_id, *(const uint64_t *) f->sort_value, fs->v.i, fs->flags);
+ r = _cmp_field_int(rh, f->props->field_num, field_id, *(const uint64_t *) f->sort_value, fs);
break;
case DM_REPORT_FIELD_TYPE_SIZE:
- r = _cmp_field_double(rh, f->props->field_num, field_id, *(double *) f->sort_value, fs->v.d, fs->flags);
+ r = _cmp_field_double(rh, f->props->field_num, field_id, *(double *) f->sort_value, fs);
break;
case DM_REPORT_FIELD_TYPE_STRING:
- r = _cmp_field_string(rh, f->props->field_num, field_id, (const char *) f->sort_value, fs->v.s, fs->flags);
+ r = _cmp_field_string(rh, f->props->field_num, field_id, (const char *) f->sort_value, fs);
break;
case DM_REPORT_FIELD_TYPE_STRING_LIST:
- r = _cmp_field_string_list(rh, f->props->field_num, field_id, (const struct str_list_sort_value *) f->sort_value,
- fs->v.l, fs->flags);
+ r = _cmp_field_string_list(rh, f->props->field_num, field_id, (const struct str_list_sort_value *) f->sort_value, fs);
break;
default:
log_error(INTERNAL_ERROR "_compare_selection_field: unknown field type for field %s", field_id);
@@ -1978,7 +2097,7 @@ static const char *_get_reserved(struct dm_report *rh, unsigned type,
return s;
while (iter->value) {
- if (!iter->type) {
+ if (!(iter->type & DM_REPORT_FIELD_TYPE_MASK)) {
/* DM_REPORT_FIELD_TYPE_NONE - per-field reserved value */
if (((((const struct dm_report_field_reserved_value *) iter->value)->field_num) == field_num) &&
(name = _reserved_name(iter->names, tmp_begin, tmp_end - tmp_begin)))
@@ -2041,6 +2160,11 @@ static int _check_reserved_values_supported(const struct dm_report_field_type fi
DM_REPORT_FIELD_TYPE_SIZE |
DM_REPORT_FIELD_TYPE_PERCENT |
DM_REPORT_FIELD_TYPE_STRING;
+ static uint32_t supported_reserved_types_with_range = DM_REPORT_FIELD_RESERVED_VALUE_RANGE |
+ DM_REPORT_FIELD_TYPE_NUMBER |
+ DM_REPORT_FIELD_TYPE_SIZE |
+ DM_REPORT_FIELD_TYPE_PERCENT;
+
if (!reserved_values)
return 1;
@@ -2048,8 +2172,10 @@ static int _check_reserved_values_supported(const struct dm_report_field_type fi
iter = reserved_values;
while (iter->value) {
- if (iter->type) {
- if (!(iter->type & supported_reserved_types)) {
+ if (iter->type & DM_REPORT_FIELD_TYPE_MASK) {
+ if (!(iter->type & supported_reserved_types) ||
+ ((iter->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE) &&
+ !(iter->type & supported_reserved_types_with_range))) {
log_error(INTERNAL_ERROR "_check_reserved_values_supported: "
"global reserved value for type 0x%x not supported",
iter->type);
@@ -2058,7 +2184,9 @@ static int _check_reserved_values_supported(const struct dm_report_field_type fi
} else {
field_res = (const struct dm_report_field_reserved_value *) iter->value;
field = &fields[field_res->field_num];
- if (!(field->flags & supported_reserved_types)) {
+ if (!(field->flags & supported_reserved_types) ||
+ ((iter->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE) &&
+ !(iter->type & supported_reserved_types_with_range))) {
log_error(INTERNAL_ERROR "_check_reserved_values_supported: "
"field-specific reserved value of type 0x%x for "
"field %s not supported",
@@ -2427,7 +2555,7 @@ static const char *_tok_field_name(const char *s,
static const void *_get_reserved_value(const struct dm_report_reserved_value *reserved)
{
- if (reserved->type)
+ if (reserved->type & DM_REPORT_FIELD_TYPE_MASK)
return reserved->value;
else
return ((const struct dm_report_field_reserved_value *) reserved->value)->value;
@@ -2443,10 +2571,12 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
void *custom)
{
static const char *_out_of_range_msg = "Field selection value %s out of supported range for field %s.";
+ static const char *_field_selection_value_alloc_failed_msg = "dm_report: struct field_selection_value allocation failed for selection field %s";
const struct dm_report_field_type *fields = implicit ? _implicit_report_fields
: rh->fields;
struct field_properties *fp, *found = NULL;
struct field_selection *fs;
+ const void *reserved_value;
const char *field_id;
uint64_t factor;
char *s;
@@ -2479,9 +2609,23 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
"allocation failed for selection field %s", field_id);
return NULL;
}
+
+ if (!(fs->value = dm_pool_zalloc(rh->selection->mem, sizeof(struct field_selection_value)))) {
+ log_error(_field_selection_value_alloc_failed_msg, field_id);
+ goto error;
+ }
+
+ if (reserved && (reserved->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE) &&
+ !(fs->value->next = dm_pool_zalloc(rh->selection->mem, sizeof(struct field_selection_value)))) {
+ log_error(_field_selection_value_alloc_failed_msg, field_id);
+ goto error;
+ }
+
fs->fp = found;
fs->flags = flags;
+ reserved_value = reserved ? _get_reserved_value(reserved) : NULL;
+
/* store comparison operand */
if (flags & FLD_CMP_REGEX) {
/* REGEX */
@@ -2493,92 +2637,98 @@ static struct field_selection *_create_field_selection(struct dm_report *rh,
memcpy(s, v, len);
s[len] = '\0';
- fs->v.r = dm_regex_create(rh->selection->mem, (const char **) &s, 1);
+ fs->value->v.r = dm_regex_create(rh->selection->mem, (const char **) &s, 1);
dm_free(s);
- if (!fs->v.r) {
+ if (!fs->value->v.r) {
log_error("dm_report: failed to create regex "
"matcher for selection field %s", field_id);
goto error;
}
} else {
/* STRING, NUMBER, SIZE or STRING_LIST */
- if (!(s = dm_pool_alloc(rh->selection->mem, len + 1))) {
- log_error("dm_report: dm_pool_alloc failed to store "
- "value for selection field %s", field_id);
+ if (!(s = dm_pool_strndup(rh->selection->mem, v, len))) {
+ log_error("dm_report: dm_pool_strndup for value "
+ "of selection field %s", field_id);
goto error;
}
- memcpy(s, v, len);
- s[len] = '\0';
switch (flags & DM_REPORT_FIELD_TYPE_MASK) {
case DM_REPORT_FIELD_TYPE_STRING:
- if (reserved) {
- fs->v.s = (const char *) _get_reserved_value(reserved);
+ if (reserved_value) {
+ fs->value->v.s = (const char *) reserved_value;
+ if (reserved->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE)
+ fs->value->next->v.s = (((const char **) reserved_value)[1]);
dm_pool_free(rh->selection->mem, s);
} else {
- fs->v.s = s;
- if (_check_value_is_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_STRING, fs->v.s, NULL)) {
- log_error("String value %s found in selection is reserved.", fs->v.s);
+ fs->value->v.s = s;
+ if (_check_value_is_strictly_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_STRING, fs->value->v.s, NULL)) {
+ log_error("String value %s found in selection is reserved.", fs->value->v.s);
goto error;
}
}
break;
case DM_REPORT_FIELD_TYPE_NUMBER:
- if (reserved)
- fs->v.i = *(uint64_t *) _get_reserved_value(reserved);
- else {
- if (((fs->v.i = strtoull(s, NULL, 10)) == ULLONG_MAX) &&
+ if (reserved_value) {
+ fs->value->v.i = *(uint64_t *) reserved_value;
+ if (reserved->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE)
+ fs->value->next->v.i = (((uint64_t *) reserved_value)[1]);
+ } else {
+ if (((fs->value->v.i = strtoull(s, NULL, 10)) == ULLONG_MAX) &&
(errno == ERANGE)) {
log_error(_out_of_range_msg, s, field_id);
goto error;
}
- if (_check_value_is_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_NUMBER, &fs->v.i, NULL)) {
- log_error("Numeric value %" PRIu64 " found in selection is reserved.", fs->v.i);
+ if (_check_value_is_strictly_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_NUMBER, &fs->value->v.i, NULL)) {
+ log_error("Numeric value %" PRIu64 " found in selection is reserved.", fs->value->v.i);
goto error;
}
}
dm_pool_free(rh->selection->mem, s);
break;
case DM_REPORT_FIELD_TYPE_SIZE:
- if (reserved)
- fs->v.d = *(double *) _get_reserved_value(reserved);
- else {
- fs->v.d = strtod(s, NULL);
+ if (reserved_value) {
+ fs->value->v.d = *(double *) reserved_value;
+ if (reserved->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE)
+ fs->value->next->v.d = (((double *) reserved_value)[1]);
+ } else {
+ fs->value->v.d = strtod(s, NULL);
if (errno == ERANGE) {
log_error(_out_of_range_msg, s, field_id);
goto error;
}
if (custom && (factor = *((uint64_t *)custom)))
- fs->v.d *= factor;
- fs->v.d /= 512; /* store size in sectors! */
- if (_check_value_is_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_SIZE, &fs->v.d, NULL)) {
- log_error("Size value %f found in selection is reserved.", fs->v.d);
+ fs->value->v.d *= factor;
+ fs->value->v.d /= 512; /* store size in sectors! */
+ if (_check_value_is_strictly_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_SIZE, &fs->value->v.d, NULL)) {
+ log_error("Size value %f found in selection is reserved.", fs->value->v.d);
goto error;
}
}
dm_pool_free(rh->selection->mem, s);
break;
case DM_REPORT_FIELD_TYPE_PERCENT:
- if (reserved)
- fs->v.i = *(uint64_t *) _get_reserved_value(reserved);
- else {
- fs->v.d = strtod(s, NULL);
- if ((errno == ERANGE) || (fs->v.d < 0) || (fs->v.d > 100)) {
+ if (reserved_value) {
+ fs->value->v.i = *(uint64_t *) reserved_value;
+ if (reserved->type & DM_REPORT_FIELD_RESERVED_VALUE_RANGE)
+ fs->value->next->v.i = (((uint64_t *) reserved_value)[1]);
+ } else {
+ fs->value->v.d = strtod(s, NULL);
+ if ((errno == ERANGE) || (fs->value->v.d < 0) || (fs->value->v.d > 100)) {
log_error(_out_of_range_msg, s, field_id);
goto error;
}
- fs->v.i = (dm_percent_t) (DM_PERCENT_1 * fs->v.d);
+ fs->value->v.i = (dm_percent_t) (DM_PERCENT_1 * fs->value->v.d);
- if (_check_value_is_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_PERCENT, &fs->v.i, NULL)) {
+ if (_check_value_is_strictly_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_PERCENT, &fs->value->v.i, NULL)) {
log_error("Percent value %s found in selection is reserved.", s);
goto error;
}
}
break;
case DM_REPORT_FIELD_TYPE_STRING_LIST:
- fs->v.l = *(struct selection_str_list **)custom;
- if (_check_value_is_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_STRING_LIST, fs->v.l, NULL)) {
+ fs->value->v.l = *(struct selection_str_list **)custom;
+ if (_check_value_is_strictly_reserved(rh, field_num, DM_REPORT_FIELD_TYPE_STRING_LIST, fs->value->v.l, NULL)) {
log_error("String list value found in selection is reserved.");
goto error;
}
8 years, 5 months