ldap/admin/src/scripts/50fixNsState.pl | 102 +++++++++++++++++++++++++--------
1 file changed, 80 insertions(+), 22 deletions(-)
New commits:
commit 077544cad896413ec32801b565fbe220c91bc04e
Author: Rich Megginson <rmeggins(a)redhat.com>
Date: Tue Jul 26 14:46:05 2011 -0600
Bug 725542 - Instance upgrade fails when upgrading 389-ds-base package
https://bugzilla.redhat.com/show_bug.cgi?id=725542
Resolves: bug 725542
Bug Description: Instance upgrade fails when upgrading 389-ds-base package
Reviewed by: nhosoi (Thanks!)
Branch: master
Fix Description: On 32-bit platforms, the pack 'Q' format specifier is not
available unless perl is explicitly compiled with 64-bit long long support.
Unfortunately, on RHEL/Fedora platforms, it is not. Same with native support
for 64-bit values - fortunately, the bigint package is available, so we use
it.
Additionally, the format flags '>' and '<' for little/big
endianness are not
available on perl 5.8 and earlier, so they are not very portable. Finally,
the way we write the 32-bit unique id generator state is simply not usable.
We already skip it if going from 32-bit to 64-bit, so just ignore it if
going from 32-bit to 32-bit. The fix is to unpack the 64-bit integer
values using two 32-bit values, using 'V' first, then 'N' if we think
the
value might be big-endian (e.g. sparc). For short values, 'v' or
'n'.
The 64-bit values are stored with the low part first, followed by the high
part. We convert these two 32-bit values to a native 64-bit value to
perform computations with it, then convert it back to two 32-bit values.
Then pack the values using the format for the current platform -
unfortunately we do not use a platform independent way to store the
nsState values.
Platforms tested: RHEL6 x86_64 and RHEL5 i386
Flag Day: no
Doc impact: no
diff --git a/ldap/admin/src/scripts/50fixNsState.pl
b/ldap/admin/src/scripts/50fixNsState.pl
index e60aef6..acf6506 100644
--- a/ldap/admin/src/scripts/50fixNsState.pl
+++ b/ldap/admin/src/scripts/50fixNsState.pl
@@ -4,15 +4,26 @@ use Mozilla::LDAP::Utils qw(normalizeDN);
use Mozilla::LDAP::API qw(:constant ldap_url_parse ldap_explode_dn);
use DSUtil qw(debug);
use Config;
+use bigint;
# # Determine the endianness of your system
-my $packfmt32 = "QA6SCx3"; # must be 20 bytes
-my $packfmt64 = "QA6SCx7"; # must be 24 bytes
+my $packfmt32 = "VVA6vCx3"; # must be 20 bytes
+my $packfmt64 = "VVA6vCx7"; # must be 24 bytes
my $is_big_endian = unpack('xc', pack('s', 1));
# see if we are on an LP64 system
my $is64 = ($Config{longsize} == 8);
+sub convert_to_32bit {
+ my $val64 = shift;
+ return ($val64 >> 32, $val64 & 0xffffffff);
+}
+
+sub convert_from_32bit {
+ my ($hi, $lo) = @_;
+ return ($hi << 32) + $lo;
+}
+
sub convert_uniqueid {
my $ent = shift;
my $val = shift;
@@ -24,20 +35,28 @@ sub convert_uniqueid {
my $hex = unpack('H*', $val);
#print "hex=$hex\n";
- my $fmt32 = "QA6SC";
- my $fmt64 = "QA6SC";
+ my $fmt32 = "VVA6vC";
+ my $bigfmt32 = "NNA6nC";
+ my $fmt64 = "VVA6vC";
+ my $bigfmt64 = "NNA6nC";
my $fmt = $fmt32;
+ my $bigfmt = $bigfmt32;
if (length($val) > 20) {
$fmt = $fmt64;
+ $bigfmt = $bigfmt64;
} elsif ($is64) {
# cannot convert 32-bit to 64-bit - just delete the entry and continue
debug(1, "Cannot convert 32-bit nsState value $hex to 64-bit - deleting
entry " .
$ent->getDN() . " and continuing\n");
return (-1, 0);
+ } else { # 32-bit to 32-bit - just leave it alone
+ debug(1, "Skipping 32-bit nsState value $hex in entry " .
+ $ent->getDN() . " and continuing\n");
+ return (0, 0);
}
if ($is_big_endian) {
- $packfmt32 = "(QA6SCx3)>";
- $packfmt64 = "(QA6SCx7)>";
+ $packfmt32 = "NNA6nCx3";
+ $packfmt64 = "NNA6nCx7";
}
my $packfmt = $packfmt32;
@@ -45,16 +64,16 @@ sub convert_uniqueid {
$packfmt = $packfmt64;
}
- my ($ts, $node, $clockseq, $last_update) = unpack($fmt, $val);
- # if we think it is from bigendian, do
- # $bigfmt = "(" . $fmt . ")>";
+ my ($tslow, $tshigh, $node, $clockseq, $last_update) = unpack($fmt, $val);
+ my $ts = convert_from_32bit($tshigh, $tslow);
my $tssecs = ($ts - 0x01B21DD213814000) / 10000000;
my $curts = time;
my $tsdiff = abs($curts - $tssecs);
my $maxdiff = 86400*365*10; # 10 years
if (($tsdiff > $maxdiff) || (($last_update != 0) && ($last_update != 1)))
{
# try big endian
- ($ts, $node, $clockseq, $last_update) = unpack("($fmt)>", $val);
+ ($tslow, $tshigh, $node, $clockseq, $last_update) = unpack($bigfmt, $val);
+ $ts = convert_from_32bit($tshigh, $tslow);
$tssecs = ($ts - 0x01B21DD213814000) / 10000000;
$tsdiff = abs($curts - $tssecs);
if (($tsdiff > $maxdiff) || (($last_update != 0) && ($last_update !=
1))) {
@@ -64,9 +83,10 @@ sub convert_uniqueid {
}
# format for the target system
- my $newval = pack($packfmt, $ts, $node, $clockseq, $last_update);
+ ($tshigh, $tslow) = convert_to_32bit($ts);
+ my $newval = pack($packfmt, $tslow, $tshigh, $node, $clockseq, $last_update);
my $rc = 0;
- if ($val != $newval) { # changed
+ if ($val ne $newval) { # changed
my $hex2 = unpack('H*', $newval);
debug(1, "Converted old nsState val in ", $ent->getDN(), " from
$hex to $hex2\n");
$rc = 1; # changed
@@ -85,22 +105,40 @@ sub convert_replica {
my $len = length($val);
my $pad;
my $timefmt;
+ my ($rid, $sampled_time, $local_offset, $remote_offset, $seq_num);
+ my ($st_high, $st_low, $lo_high, $lo_low, $ro_high, $ro_low);
+ my $fmtstr;
+ my $bigfmtstr;
if ($len <= 20) {
$pad = 2; # padding for short H values
- $timefmt = 'I'; # timevals are unsigned 32-bit int
+ $timefmt = 'V'; # timevals are unsigned 32-bit int - try little-endian
'V' first
+ $fmtstr = "vx" . $pad . $timefmt . "3vx" . $pad;
+ $bigfmtstr = 'nx' . $pad . 'N' . '3nx' . $pad;
+ ($rid, $sampled_time, $local_offset, $remote_offset, $seq_num) = unpack($fmtstr,
$val);
} else {
$pad = 6; # padding for short H values
- $timefmt = 'Q'; # timevals are unsigned 64-bit int
+ $timefmt = 'V'; # timevals are unsigned 64-bit int
+ $fmtstr = "vx" . $pad . $timefmt . "6vx" . $pad;
+ $bigfmtstr = 'nx' . $pad . 'N' . '6nx' . $pad;
+ ($rid, $st_low, $st_high, $lo_low, $lo_high, $rt_low, $rt_high, $seq_num) =
unpack($fmtstr, $val);
+ $sampled_time = convert_from_32bit($st_high, $st_low);
+ $local_offset = convert_from_32bit($lo_high, $lo_low);
+ $remote_offset = convert_from_32bit($ro_high, $ro_low);
}
# short - padbytes - 3 timevals - short - padbytes
- my $fmtstr = "Sx" . $pad . $timefmt . "3Sx" . $pad;
- my ($rid, $sampled_time, $local_offset, $remote_offset, $seq_num) = unpack($fmtstr,
$val);
my $hex = unpack('H*', $val);
my $now = time;
my $tdiff = abs($now - $sampled_time);
my $maxdiff = 86400*365*10; # 10 years
if ($tdiff > $maxdiff) { # try big endian
- ($rid, $sampled_time, $local_offset, $remote_offset, $seq_num) =
unpack("($fmtstr)>", $val);
+ if ($len <= 20) {
+ ($rid, $sampled_time, $local_offset, $remote_offset, $seq_num) =
unpack($bigfmtstr, $val);
+ } else {
+ ($rid, $st_low, $st_high, $lo_low, $lo_high, $rt_low, $rt_high, $seq_num) =
unpack($bigfmtstr, $val);
+ $sampled_time = convert_from_32bit($st_high, $st_low);
+ $local_offset = convert_from_32bit($lo_high, $lo_low);
+ $remote_offset = convert_from_32bit($ro_high, $ro_low);
+ }
my $tdiff = abs($now - $sampled_time);
if ($tdiff > $maxdiff) { # error
debug(0, "Error: could not parse nsstate $hex - tdiff is $tdiff seconds
or", ($tdiff/86400), " days\n");
@@ -108,12 +146,28 @@ sub convert_replica {
}
}
# format for the target system
- if ($is_big_endian) {
- $fmtstr = "($fmtstr)>";
+ my $packfmt;
+ my @packargs;
+ if ($is64) {
+ my $packfmt = "vx" . $pad . "V6vx" . $pad;
+ if ($is_big_endian) {
+ $packfmt = "nx" . $pad . "N6nx" . $pad;
+ }
+ $st_high = $st >> 32;
+ ($st_high, $st_low) = convert_to_32bit($sampled_time);
+ ($lo_high, $lo_low) = convert_to_32bit($local_offset);
+ ($ro_high, $ro_low) = convert_to_32bit($remote_offset);
+ @packargs = ($rid, $st_low, $st_high, $lo_low, $lo_high, $ro_low, $ro_high,
$seq_num);
+ } else {
+ my $packfmt = "vx" . $pad . "V3vx" . $pad;
+ if ($is_big_endian) {
+ $packfmt = "nx" . $pad . "N3nx" . $pad;
+ }
+ @packargs = ($rid, $sampled_time, $local_offset, $remote_offset, $seq_num);
}
- my $newval = pack($fmtstr, $rid, $sampled_time, $local_offset, $remote_offset,
$seq_num);
+ my $newval = pack($fmtstr, @packargs);
my $rc = 0;
- if ($val != $newval) { # changed
+ if ($val ne $newval) { # changed
my $hex2 = unpack('H*', $newval);
debug(1, "Converted old nsState val in ", $ent->getDN(), " from
$hex to $hex2\n");
$rc = 1; # changed
@@ -164,7 +218,11 @@ sub runinst {
sub testit {
#my $val = 'ACm2BdIdsgH+tw/8AAB+swEAAAA=';
#my $val = 'AOj+tyuA4AHsNZ7S9NnxZwEAAAAAAAAA';
-my $testval = "00a43cb4d11db2018b7912fd0000a42e01000000";
+#my $val = 'ABI3gdIdsgH3TJWpAACGIgEAAAA=';
+#my $testval = "00a43cb4d11db2018b7912fd0000a42e01000000";
+#my $testval = "0029B605D21DB201FEB70FFC00007EB301000000";
+#my $testval = "00E8FEB72B80E001EC359ED2F4D9F1670100000000000000";
+my $testval = "00123781D21DB201F74C95A90000862201000000";
my $testdecval = $testval;
# base16 decode
$testdecval =~ s/(..)/chr(hex($1))/eg;