From 69ff83598d517bed84922b1c7dd67cab023b4d99 Mon Sep 17 00:00:00 2001 From: Noriko Hosoi Date: Apr 09 2013 18:59:32 +0000 Subject: Ticket #529 - dn normalization must handle multiple space characters in attributes Bug description: This is the second half of the fix for #529. The first half fixed the DN normalization which used to allow DNs where only the number of spaces are different. Now it is rejucted as expected. But it breaks the backward compatibility. Fix description: The upgrade script 80upgradednformat.pl called from "setup-ds.pl -u" checks the duplicated DNs and rename them if necessary. For instance, if there are 2 DNs: cn=test user0,dc=example,dc=com (entryid: N) cn=test user0,dc=example,dc=com (entryid: M) then the upgrade script/tool modifies the second one as follows: cn=test user0 M,dc=example,dc=com (entryid: M) and the original "cn: test user0" is kept in the attribute. The modified result is reported in "setup-ds.pl -u" as follows: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Duplicated DN(s) were found and renamed. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Renamed entry IDs are listed in /var/lib/dirsrv/slapd-ID/ldif/userRoot_conflict.txt. Contents of the conflict.txt: prinary entry ID: duplicated entry IDs 13:16 18 14:17 https://fedorahosted.org/389/ticket/529 Reviewed and commentted by Rich and Mark (Thanks!!) --- diff --git a/ldap/admin/src/scripts/80upgradednformat.pl b/ldap/admin/src/scripts/80upgradednformat.pl deleted file mode 100644 index 092b7cd..0000000 --- a/ldap/admin/src/scripts/80upgradednformat.pl +++ /dev/null @@ -1,206 +0,0 @@ -use Mozilla::LDAP::Conn; -use Mozilla::LDAP::Utils qw(normalizeDN); -use Mozilla::LDAP::API qw(:constant ldap_url_parse ldap_explode_dn); -use File::Basename; -use File::Copy; -use DSUpdate qw(isOffline); - -# Upgrade DN format if needed. -# For each backend instance, -# run upgradednformat with -N (dryrun mode), -# if it returns 0 (Upgrade candidates are found), -# recursively copy the instance dir to the work dir (dnupgrade) -# run upgradednformat w/o -N against the DB in the work dir -# if it went ok, replace the original instance dir with the work dir. -# Note: This script does nothing if the server is up. -sub runinst { - my ($inf, $inst, $dseldif, $conn) = @_; - - my @errs; - - my $config = "cn=config"; - my $config_entry = $conn->search($config, "base", "(cn=*)"); - if (!$config_entry) { - return ("error_no_configuration_entry", $!); - } - - # Check if the server is up or not - my $rc; - ($rc, @errs) = isOffline($inf, $inst, $conn); - if (!$rc) { - return @errs; - } - my $mappingtree = "cn=mapping tree,cn=config"; - my $ldbmbase = "cn=ldbm database,cn=plugins,cn=config"; - - my $backend_entry; - my $mtentry = $conn->search($mappingtree, "onelevel", "(cn=*)", 0, @attr); - if (!$mtentry) { - return ("error_no_mapping_tree_entries", $!); - } - - my $db_config_entry = - $conn->search("cn=config,cn=ldbm database,cn=plugins,cn=config", - "base", "(objectclass=*)"); - if (!$db_config_entry) { - return ('error_finding_config_entry', - 'cn=config,cn=ldbm database,cn=plugins,cn=config', - $conn->getErrorString()); - } - # If subtree rename swich is not found in the config file, - # set off to the switch and upgrade dn format using entrydn. - my $switch = $db_config_entry->getValues('nsslapd-subtree-rename-switch'); - if ("" eq $switch) { - $db_config_entry->addValue('nsslapd-subtree-rename-switch', "off"); - $conn->update($db_config_entry); - } - - # If a suffix in the mapping tree is doube-quoted and - # the cn value has only the double-quoted value, e.g. - # dn: cn="dc=example,dc=com",cn=mapping tree,cn=config - # cn: "dc=example,dc=com" - # the following code adds non-quoted value: - # cn: dc=example,dc=com - while ($mtentry) { - my $numvals = $mtentry->size("cn"); - my $i; - my $withquotes = -1; - my $noquotes = -1; - for ($i = 0; $i < $numvals; $i++) { - if ($mtentry->{"cn"}[$i] =~ /^".*"$/) { - $withquotes = $i; - } else { - $noquotes = $i; - } - } - if ($withquotes >= 0 && $noquotes == -1) { - # Has only cn: "" - # Adding cn: - my $stripped = $mtentry->{"cn"}[$withquotes]; - $stripped =~ s/^"(.*)"$/$1/; - $mtentry->addValue("cn", $stripped); - $conn->update($mtentry); - } - $mtentry = $conn->nextEntry(); - } - - my $instancedir = $config_entry->{"nsslapd-instancedir"}[0]; - my $upgradednformat = $instancedir . "/upgradednformat"; - - # Scan through all of the backends to see if any of them - # contain escape characters in the DNs. If we find any - # escapes, we need to run the conversion tool on that - # backend. - $backend_entry = $conn->search($ldbmbase, "onelevel", "(objectClass=nsBackendInstance)", 0, @attr); - if (!$backend_entry) { - return ("error_no_backend_entries", $!); - } - - while ($backend_entry) { - my $backend = $backend_entry->{"cn"}[0]; - my $dbinstdir = $backend_entry->{"nsslapd-directory"}[0]; - my $workdir = $dbinstdir . "/dnupgrade"; - my $dbdir = dirname($dbinstdir); - my $pdbdir = dirname($dbdir); - my $instname = basename($dbinstdir); - - if ("$dbdir" eq "" || "$instname" eq "") { - push @errs, ["error_invalid_dbinst_dir", $dbinstdir]; - return @errs; - } - - # clean up db region files, which might contain the old pages - if ( -d $dbdir && -f $dbdir."/__db.001") { - unlink <$dbdir/__db.*>; - } - - if (-e "$dbinstdir/id2entry.db4") { - # Check if any DNs contain escape characters with dbscan. - # dryrun mode - # return values: 0 -- need to upgrade dn format - # 1 -- no need to upgrade dn format - # -1 -- error - my $escapes = system("$upgradednformat -n $backend -a $dbinstdir -N"); - if (0 == $escapes) { - # need to upgrade dn format - my $rc = 0; - - if (system("cd $pdbdir; tar cf - db/DBVERSION | (cd $dbinstdir; tar xf -)") || - system("cd $pdbdir; tar cf - db/$instname/DBVERSION | (cd $dbinstdir; tar xf -)") || - system("cd $pdbdir; tar cf - db/$instname/*.db4 | (cd $dbinstdir; tar xf -)")) { - push @errs, ["error_cant_backup_db", $backend, $!]; - return @errs; - } - my @stat = stat("$dbdir"); - my $mode = $stat[2]; - my $uid = $stat[4]; - my $gid = $stat[5]; - - move("$dbinstdir/db", "$workdir"); - chmod($mode, $workdir); - chown($uid, $gid, $workdir); - - @stat = stat("$dbinstdir"); - $mode = $stat[2]; - $uid = $stat[4]; - $gid = $stat[5]; - - chmod($mode, "$workdir/$instname"); - chown($uid, $gid, "$workdir/$instname"); - - # call conversion tool here and get return status. - $rc = system("$upgradednformat -n $backend -a $workdir/$instname"); - if ($rc == 0) { # success - move("$dbinstdir", "$dbinstdir.orig"); - move("$dbinstdir.orig/dnupgrade/$instname", "$dbinstdir"); - copy("$dbinstdir.orig/dnupgrade/DBVERSION", "$dbdir"); - } else { - # Conversion failed. Cleanup and bail. - unlink <$dbinstdir/dnupgrade/$backend/*>; - rmdir("$dbinstdir/dnupgrade/$backend"); - unlink <$dbinstdir/dnupgrade/*>; - rmdir("$dbinstdir/dnupgrade"); - return ("error_cant_convert_db", $backend, $rc); - } - } else { - # already upgraded or an error occurred. - # check ancestorid to see if it has not-sorted ID list or not. - my $ancestorid = $dbinstdir . "/ancestorid.db4"; - if (-e "$ancestorid") { - my $disorder = 0; - open(ANCESTOR, "/usr/bin/dbscan -f $ancestorid -r |"); - while () { - if (!/^=[0-9]*/) { - chomp($_); - my @IDs = split(/ | /, $_); - # print "ID count: $#IDs\n"; - my $lasti = $#IDs; - for (my $i = 1; $i < $lasti; $i++) { - if ($IDs[$i] >= $IDs[$i + 1]) { - $disorder = 1; - last; - } - } - # print "Result: $disorder \n"; - if ($disorder) { - last; - } - } - } - close(ANCESTOR); - - # ancestorid index is in disorder; need to reindex it. - if ($disorder) { - print "The ancestorid index in $backend is in disorder; Reindexing $ancestorid.\n"; - my $reindex = $instancedir . "/db2index"; - my $rc = system("$reindex -n $backend -t ancestorid"); - } - } - } - } - - $backend_entry = $conn->nextEntry(); - } - - return (); -} diff --git a/ldap/admin/src/scripts/80upgradednformat.pl.in b/ldap/admin/src/scripts/80upgradednformat.pl.in new file mode 100644 index 0000000..6d14099 --- /dev/null +++ b/ldap/admin/src/scripts/80upgradednformat.pl.in @@ -0,0 +1,307 @@ +use Mozilla::LDAP::Conn; +use Mozilla::LDAP::Utils qw(normalizeDN); +use Mozilla::LDAP::API qw(:constant ldap_url_parse ldap_explode_dn); +use File::Basename; +use File::Copy; +use DSUpdate qw(isOffline); + +# Upgrade DN format if needed. +# For each backend instance, +# run upgradednformat with -N (dryrun mode), +# if it returns 0 (Upgrade candidates are found), +# recursively copy the instance dir to the work dir (dnupgrade) +# run upgradednformat w/o -N against the DB in the work dir +# if it went ok, replace the original instance dir with the work dir. +# Note: This script does nothing if the server is up. +sub runinst { + my ($inf, $inst, $dseldif, $conn) = @_; + + my @errs; + + my $config = "cn=config"; + my $config_entry = $conn->search($config, "base", "(cn=*)"); + if (!$config_entry) { + return ("error_no_configuration_entry", $!); + } + + # Check if the server is up or not + my $rc; + ($rc, @errs) = isOffline($inf, $inst, $conn); + if (!$rc) { + return @errs; + } + my $mappingtree = "cn=mapping tree,cn=config"; + my $ldbmbase = "cn=ldbm database,cn=plugins,cn=config"; + + my $backend_entry; + my $mtentry = $conn->search($mappingtree, "onelevel", "(cn=*)", 0, @attr); + if (!$mtentry) { + return ("error_no_mapping_tree_entries", $!); + } + + my $db_config_entry = + $conn->search("cn=config,cn=ldbm database,cn=plugins,cn=config", + "base", "(objectclass=*)"); + if (!$db_config_entry) { + return ('error_finding_config_entry', + 'cn=config,cn=ldbm database,cn=plugins,cn=config', + $conn->getErrorString()); + } + # If subtree rename swich is not found in the config file, + # set off to the switch and upgrade dn format using entrydn. + my $switch = $db_config_entry->getValues('nsslapd-subtree-rename-switch'); + if ("" eq $switch) { + $db_config_entry->addValue('nsslapd-subtree-rename-switch', "off"); + $conn->update($db_config_entry); + } + + # If a suffix in the mapping tree is doube-quoted and + # the cn value has only the double-quoted value, e.g. + # dn: cn="dc=example,dc=com",cn=mapping tree,cn=config + # cn: "dc=example,dc=com" + # the following code adds non-quoted value: + # cn: dc=example,dc=com + while ($mtentry) { + my $numvals = $mtentry->size("cn"); + my $i; + my $withquotes = -1; + my $noquotes = -1; + for ($i = 0; $i < $numvals; $i++) { + if ($mtentry->{"cn"}[$i] =~ /^".*"$/) { + $withquotes = $i; + } else { + $noquotes = $i; + } + } + if ($withquotes >= 0 && $noquotes == -1) { + # Has only cn: "" + # Adding cn: + my $stripped = $mtentry->{"cn"}[$withquotes]; + $stripped =~ s/^"(.*)"$/$1/; + $mtentry->addValue("cn", $stripped); + $conn->update($mtentry); + } + $mtentry = $conn->nextEntry(); + } + + my $ldifdir = $config_entry->{"nsslapd-ldifdir"}[0]; + my $instancedir = $config_entry->{"nsslapd-instancedir"}[0]; + my ($slapd, $serverID) = split(/-/, $instancedir); + my $upgradednformat = "@sbindir@/upgradednformat"; + my $reindex = "@sbindir@/db2index"; + + # Scan through all of the backends to see if any of them + # contain escape characters in the DNs. If we find any + # escapes, we need to run the conversion tool on that + # backend. + $backend_entry = $conn->search($ldbmbase, "onelevel", "(objectClass=nsBackendInstance)", 0, @attr); + if (!$backend_entry) { + return ("error_no_backend_entries", $!); + } + + while ($backend_entry) { + my $backend = $backend_entry->{"cn"}[0]; + my $dbinstdir = $backend_entry->{"nsslapd-directory"}[0]; + my $workdir = $dbinstdir . "/dnupgrade"; + my $dbdir = dirname($dbinstdir); + my $pdbdir = dirname($dbdir); + my $instname = basename($dbinstdir); + my $dn_norm_sp_txt = $ldifdir . "/" . $instname . "_dn_norm_sp.txt"; + + if ("$dbdir" eq "" || "$instname" eq "") { + push @errs, ["error_invalid_dbinst_dir", $dbinstdir]; + return @errs; + } + + # clean up db region files, which might contain the old pages + if ( -d $dbdir && -f $dbdir."/__db.001") { + unlink <$dbdir/__db.*>; + } + + my $escapes = 0; + my $rc = 0; + my $cmd = 0; + if ((-e "$dbinstdir/id2entry.db") || (-e "$dbinstdir/id2entry.db4")) { + # Check if any DNs contain escape characters with dbscan. + # dryrun mode + # return values: 0 -- need to upgrade dn format + # 1 -- no need to upgrade dn format + # -1 -- error + $cmd = "$upgradednformat -n $backend -a $dbinstdir -N"; + $rc = system("$cmd"); + if ($rc & 127) { + push @errs, [ 'error_running_command', $cmd, $rc, $! ]; + return @errs; + } + $escapes = $rc >> 8; +# $escapes == 0 ==> no need to do dn upgrade +# $escapes == 1 ==> need to do dn upgrade (both dn upgrade and spaces) +# $escapes == 2 ==> need to do dn upgrade (dn upgrade only) +# $escapes == 3 ==> need to do dn upgrade (dn upgrade spaces only) + if ($escapes <= 0) { + # already upgraded or an error occurred. + # check ancestorid to see if it has not-sorted ID list or not. + my $ancestorid = $dbinstdir . "/ancestorid.db4"; + if (!(-e "$ancestorid")) { + $ancestorid = $dbinstdir . "/ancestorid.db"; + } + if (-e "$ancestorid") { + my $disorder = 0; + open(ANCESTOR, "/usr/bin/dbscan -f $ancestorid -r |"); + while () { + if (!/^=[0-9]*/) { + chomp($_); + my @IDs = split(/ | /, $_); + # print "ID count: $#IDs\n"; + my $lasti = $#IDs; + for (my $i = 1; $i < $lasti; $i++) { + if ($IDs[$i] >= $IDs[$i + 1]) { + $disorder = 1; + last; + } + } + # print "Result: $disorder \n"; + if ($disorder) { + last; + } + } + } + close(ANCESTOR); + + # ancestorid index is in disorder; need to reindex it. + if ($disorder) { + print "The ancestorid index in $backend is in disorder; Reindexing $ancestorid.\n"; + $cmd = "$reindex -Z $serverID -n $backend -t ancestorid"; + $rc = system("$cmd"); + if ($rc & 127) { + push @errs, [ 'error_running_command', $cmd, $rc, $! ]; + return @errs; + } + } + } + } else { + # need to upgrade dn format + $rc = 0; + + if (system("cd $pdbdir; tar cf - db/DBVERSION | (cd $dbinstdir; tar xf -)") || + system("cd $pdbdir; tar cf - db/$instname/DBVERSION | (cd $dbinstdir; tar xf -)") || + system("cd $pdbdir; tar cf - db/$instname/*.db* | (cd $dbinstdir; tar xf -)")) { + push @errs, [ "error_cant_backup_db", $backend, $! ]; + return @errs; + } + my @stat = stat("$dbdir"); + my $mode = $stat[2]; + my $uid = $stat[4]; + my $gid = $stat[5]; + + move("$dbinstdir/db", "$workdir"); + chmod($mode, $workdir); + chown($uid, $gid, $workdir); + + @stat = stat("$dbinstdir"); + $mode = $stat[2]; + $uid = $stat[4]; + $gid = $stat[5]; + + chmod($mode, "$workdir/$instname"); + chown($uid, $gid, "$workdir/$instname"); + + my $do_dn_norm_sp = 0; + if ((1 == $escapes) || (3 == $escapes)) { + # We are taking care of spaces in DN. + my $sorted = $dn_norm_sp_txt . ".sorted"; + $cmd = "sort $dn_norm_sp_txt"; + $rc = system("$cmd > $sorted"); + if ($rc) { + debug(1, "Error: $cmd failed - output $sorted: $!\n"); + push @errs, [ 'error_running_command', $cmd, $rc, $! ]; + return @errs; + } + # Create a work file from $sorted. + my $workfile = $sorted . ".work"; + # print "$sorted -> $workfile\n"; + + open(SORTEDFILE, "$sorted"); + open(WORKFILE, "> $workfile"); + my $prev_dn = ""; + my $prev_id = 0; + my $new = 1; + for (my $line = ; $line; $line = ) { + chomp($line); + my ($dn, $id) = split(":", $line, 2); + if ($dn eq $prev_dn) { + if ($new == 1) { + print WORKFILE "$prev_id:$id"; + $new = 0; + $do_dn_norm_sp = 1; # go ahead and fix it. + } else { + print WORKFILE " $id"; + } + } else { + if (0 == $new) { + print WORKFILE "\n"; + $new = 1; + } + } + $prev_dn = $dn; + $prev_id = $id; + } + close(WORKFILE); + close(SORTEDFILE); + unlink <$sorted>; + move("$dn_norm_sp_txt", "$dn_norm_sp_txt.orig"); + if ($do_dn_norm_sp) { + move("$workfile", "$dn_norm_sp_txt"); + # otherwise, we don't need $dn_norm_sp_txt + } + } else { + unlink <$dn_norm_sp_txt>; + } + + if ((1 == $escapes) || (2 == $escapes) || (3 == $escapes)) { + # call conversion tool here and get return status. + $cmd = "$upgradednformat -Z $serverID -n $backend -a $workdir/$instname"; + $rc = system("$cmd"); + if ($rc & 127) { + push @errs, [ 'error_running_command', $cmd, $rc, $! ]; + return @errs; + } + $escapes = $rc >> 8; + } + if ((0 == $rc) || (1 == $escapes) || (3 == $escapes)) { + # success + move("$dbinstdir", "$dbinstdir.orig"); + move("$dbinstdir.orig/dnupgrade/$instname", "$dbinstdir"); + copy("$dbinstdir.orig/dnupgrade/DBVERSION", "$dbdir"); + if ((1 == $escapes) || (3 == $escapes)) { + $cmd = "$reindex -Z $serverID -n $backend -t entryrdn"; + $rc = system("$cmd"); + if ($rc & 127) { + push @errs, [ 'error_running_command', $cmd, $rc, $! ]; + return @errs; + } + } + my $dn_norm_sp_txt = $ldifdir . "/" . $instname . "_dn_norm_sp.txt"; + my $conflict = $ldifdir . "/" . $instname . "_conflict.txt"; + system("echo prinary entry ID: duplicated entry IDs > $conflict"); + system("cat $dn_norm_sp_txt >> $conflict"); + print "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"; + print "Duplicated DN(s) were found and renamed.\n"; + print "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"; + print "Renamed entry IDs are listed in $conflict.\n"; + } else { + # Conversion failed. Cleanup and bail. + unlink <$dbinstdir/dnupgrade/$backend/*>; + rmdir("$dbinstdir/dnupgrade/$backend"); + unlink <$dbinstdir/dnupgrade/*>; + rmdir("$dbinstdir/dnupgrade"); + return ("error_cant_convert_db", $backend, $rc); + } + } + } + + $backend_entry = $conn->nextEntry(); + } + + return (); +} diff --git a/ldap/servers/slapd/back-ldbm/back-ldbm.h b/ldap/servers/slapd/back-ldbm/back-ldbm.h index 726ac40..871d489 100644 --- a/ldap/servers/slapd/back-ldbm/back-ldbm.h +++ b/ldap/servers/slapd/back-ldbm/back-ldbm.h @@ -177,6 +177,7 @@ typedef unsigned short u_int16_t; #define BDB_RDNFORMAT "rdn-format" /* Subtree rename enabled */ #define BDB_RDNFORMAT_VERSION "2" /* rdn-format version (by default, 0) */ #define BDB_DNFORMAT "dn-4514" /* DN format RFC 4514 compliant */ +#define BDB_DNFORMAT_VERSION "1" /* DN format version */ #define DBVERSION_NEWIDL 0x1 #define DBVERSION_RDNFORMAT 0x2 diff --git a/ldap/servers/slapd/back-ldbm/dbversion.c b/ldap/servers/slapd/back-ldbm/dbversion.c index 32a60e5..e4eee32 100644 --- a/ldap/servers/slapd/back-ldbm/dbversion.c +++ b/ldap/servers/slapd/back-ldbm/dbversion.c @@ -119,7 +119,8 @@ dbversion_write(struct ldbminfo *li, const char *directory, ptr = buf + len; } if (flags & DBVERSION_DNFORMAT) { - PR_snprintf(ptr, sizeof(buf) - len, "/%s", BDB_DNFORMAT); + PR_snprintf(ptr, sizeof(buf) - len, "/%s-%s", + BDB_DNFORMAT, BDB_DNFORMAT_VERSION); len = strlen(buf); ptr = buf + len; } diff --git a/ldap/servers/slapd/back-ldbm/import-threads.c b/ldap/servers/slapd/back-ldbm/import-threads.c index 54f8159..1c526ef 100644 --- a/ldap/servers/slapd/back-ldbm/import-threads.c +++ b/ldap/servers/slapd/back-ldbm/import-threads.c @@ -1241,6 +1241,134 @@ upgradedn_add_to_list(struct upgradedn_attr **ud_list, } /* + * Return value: count of max consecutive spaces + */ +static int +has_spaces(const char *str) +{ + char *p = (char *)str; + char *np; + char *endp = p + strlen(str); + int wcnt; + int maxwcnt = 0; +next: + if ((np = strchr(p, ' ')) || (np = strchr(p, '\t'))) { + wcnt = 0; + while ((np < endp) && isspace(*np)) { + wcnt++; + np++; + } + if (maxwcnt < wcnt) { + maxwcnt = wcnt; + } + p = np; + goto next; + } else { + goto bail; + } +bail: + return maxwcnt; +} + +static int +add_IDs_to_IDarray(ID ***dn_norm_sp_conflict, int *max, int i, char *strids) +{ + char *p, *next, *start; + ID my_id; + ID **conflict; + ID *idp; + ID *endp; + size_t len; + + if ((NULL == dn_norm_sp_conflict) || (NULL == max) || (0 == *max)) { + return 1; + } + p = PL_strchr(strids, ':'); + if (NULL == p) { + LDAPDebug1Arg(LDAP_DEBUG_ANY, + "Format error: no ':' in %s\n", strids); + return 1; + } + *p = '\0'; + my_id = (ID)strtol(strids, (char **)NULL, 10); + if (!my_id) { + LDAPDebug1Arg(LDAP_DEBUG_ANY, "Invalid ID in %s\n", strids); + return 1; + } + + if (NULL == *dn_norm_sp_conflict) { + *dn_norm_sp_conflict = (ID **)slapi_ch_malloc(sizeof(ID *) * *max); + } else if (*max == i + 1) { + *max *= 2; + *dn_norm_sp_conflict = (ID **)slapi_ch_realloc((char *)*dn_norm_sp_conflict, + sizeof(ID *) * *max); + } + conflict = *dn_norm_sp_conflict; + + len = strlen(strids); + while (isspace(*(++p))); + start = p; + /* since the format is "ID ID ID ...", max count is len/2 + 1 and +1 for my_id */ + conflict[i] = (ID *)slapi_ch_calloc((len/2 + 2), sizeof(ID)); + idp = conflict[i]; + endp = idp + len/2 + 2; + *idp++ = my_id; + for (p = strtok_r(start, " \n", &next); p && (idp < endp); + p = strtok_r(NULL, " \n", &next), idp++) { + *idp = (ID)strtol(p, (char **)NULL, 10); + } + if (idp < endp) { + *idp = 0; + } else if (idp == endp) { + conflict[i] = (ID *)slapi_ch_realloc((char *)conflict[i], + (len/2 + 3) * sizeof(ID)); + idp = conflict[i]; + *(idp + len/2 + 2) = 0; + } + conflict[i+1] = NULL; + return 0; +} + +static void +free_IDarray(ID ***dn_norm_sp_conflict) +{ + int i; + if ((NULL == dn_norm_sp_conflict) || (NULL == *dn_norm_sp_conflict)) { + return; + } + for (i = 0; (*dn_norm_sp_conflict)[i]; i++) { + slapi_ch_free((void **)&(*dn_norm_sp_conflict)[i]); + } + slapi_ch_free((void **)dn_norm_sp_conflict); +} + +/* + * dn_norm_sp_conflicts is a double array of IDs. + * Format: + * primary_ID0: conflict_ID ... + * primary_ID1: conflict_ID ... + * ... + * + * is_conflict_ID looks for ghe given id in hte conflict_ID lists + * If found, its primary_ID is returned. + * Otherwise, 0 is returned. + */ +static ID +is_conflict_ID(ID **dn_norm_sp_conflicts, int max, ID id) +{ + int i; + ID *idp; + for (i = 0; i < max; i++) { + for (idp = dn_norm_sp_conflicts[i]; idp && *idp; idp++) { + if (*idp == id) { + return *dn_norm_sp_conflicts[i]; + } + } + } + return 0; +} + +/* * Producer thread for upgrading dn format * FLAG_UPGRADEDNFORMAT | FLAG_DRYRUN -- check the necessity of dn upgrade * FLAG_UPGRADEDNFORMAT -- execute dn upgrade @@ -1263,6 +1391,41 @@ upgradedn_add_to_list(struct upgradedn_attr **ud_list, * from ABORTED (aborted or error) and FINISHED (scan all the entries * and found no candidate to upgrade) */ +/* + * FLAG_UPGRADEDNFORMAT: need to take care space reduction + * dn: cn=TEST USER0 --> dn: cn=TEST USER0 + * If multiple DNs are found having different count of spaces, + * remove the second and later with exporting them into ldif file. + * In the dry run, it retrieves all the entries having spaces in dn and + * store the DN and OID in a file. Mark, conflicts if any. + * In the real run, store only no conflict entries and first conflicted one. + * The rest are stored in an ldif file. + * + * Cases: + * FLAG_DRYRUN | FLAG_UPGRADEDNFORMAT | FLAG_UPGRADEDNFORMAT_V1 + * ==> 1 & 2-1 + * FLAG_DRYRUN | FLAG_UPGRADEDNFORMAT_V1 + * ==> 2-1 + * FLAG_UPGRADEDNFORMAT | FLAG_UPGRADEDNFORMAT_V1 + * ==> 1 & 2-2,3 + * FLAG_UPGRADEDNFORMAT_V1 + * ==> 2-2,3 + * + * 1) dn normalization + * 2) space handling + * 2-1) upgradedn dry-run: output into a file (in the instance db dir?) + * format: + * :OID + * 2-2) upgrade script sorts the file; retrieve duplicated DNs + * :OID0 + * :OID1 + * :OID2 + * + * format: + * OID0:OID1 OID2 ... + * 2-3) upgradedn: compare the OID with the OID1,OID2, + * if match, rename the rdn value to "value ". + */ void upgradedn_producer(void *param) { @@ -1279,8 +1442,6 @@ upgradedn_producer(void *param) Slapi_Attr *a = NULL; Slapi_DN *sdn = NULL; char *workdn = NULL; - int doit = 0; - int skipit = 0; struct upgradedn_attr *ud_list = NULL; char **ud_vals = NULL; char **ud_valp = NULL; @@ -1288,6 +1449,18 @@ upgradedn_producer(void *param) Slapi_Attr *ud_attr = NULL; char *ecopy = NULL; const char *normdn = NULL; + char *rdn = NULL; /* original rdn */ + int is_dryrun = 0; /* FLAG_DRYRUN */ + int chk_dn_norm = 0; /* FLAG_UPGRADEDNFORMAT */ + int chk_dn_norm_sp = 0; /* FLAG_UPGRADEDNFORMAT_V1 */ + ID **dn_norm_sp_conflicts = NULL; + int do_dn_norm = 0; /* do dn_norm */ + int do_dn_norm_sp = 0; /* do dn_norm_sp */ + int rdn_has_spaces = 0; + int info_state = 0; /* state to add to info->state (for dryrun only) */ + int skipit = 0; + ID pid; + struct backdn *bdn = NULL; /* vars for Berkeley DB */ DB_ENV *env = NULL; @@ -1304,9 +1477,21 @@ upgradedn_producer(void *param) PR_ASSERT(info != NULL); PR_ASSERT(inst != NULL); PR_ASSERT(be != NULL); - - if ( job->flags & FLAG_ABORT ) + + if ( job->flags & FLAG_ABORT ) { goto error; + } + + is_dryrun = job->flags & FLAG_DRYRUN; + chk_dn_norm = job->flags & FLAG_UPGRADEDNFORMAT; + chk_dn_norm_sp = job->flags & FLAG_UPGRADEDNFORMAT_V1; + + if (!chk_dn_norm && !chk_dn_norm_sp) { + /* Nothing to do... */ + LDAPDebug0Args(LDAP_DEBUG_ANY, "UpgradeDnFormat is not required.\n"); + info->state = FINISHED; + goto done; + } sleeptime = PR_MillisecondsToInterval(import_sleep_time); @@ -1320,15 +1505,14 @@ upgradedn_producer(void *param) /* open id2entry with dedicated db env and db handler */ if ( dblayer_get_aux_id2entry( be, &db, &env, NULL ) != 0 || db == NULL || env == NULL) { - LDAPDebug( LDAP_DEBUG_ANY, "Could not open id2entry\n", 0, 0, 0 ); + LDAPDebug0Args(LDAP_DEBUG_ANY, "Could not open id2entry\n"); goto error; } /* get a cursor to we can walk over the table */ db_rval = db->cursor(db, NULL, &dbc, 0); if ( db_rval || !dbc ) { - LDAPDebug( LDAP_DEBUG_ANY, - "Failed to get cursor for reindexing\n", 0, 0, 0 ); + LDAPDebug0Args(LDAP_DEBUG_ANY, "Failed to get cursor for reindexing\n"); dblayer_release_id2entry(be, db); goto error; } @@ -1352,18 +1536,22 @@ upgradedn_producer(void *param) slapi_ch_free(&(data.data)); key.flags = DB_DBT_MALLOC; data.flags = DB_DBT_MALLOC; - if (isfirst) - { + if (isfirst) { db_rval = dbc->c_get(dbc, &key, &data, DB_FIRST); isfirst = 0; - } - else - { + } else { db_rval = dbc->c_get(dbc, &key, &data, DB_NEXT); } if (0 != db_rval) { - if (DB_NOTFOUND != db_rval) { + if (DB_NOTFOUND == db_rval) { + LDAPDebug1Arg(LDAP_DEBUG_ANY, "%s: Finished to read database\n", + inst->inst_name); + if (job->task) { + slapi_task_log_notice(job->task, + "%s: Finished to read database", inst->inst_name); + } + } else { LDAPDebug(LDAP_DEBUG_ANY, "%s: Failed to read database, " "errno=%d (%s)\n", inst->inst_name, db_rval, dblayer_strerror(db_rval)); @@ -1389,19 +1577,19 @@ upgradedn_producer(void *param) memcpy(ecopy, data.dptr, data.dsize); *(ecopy + data.dsize) = '\0'; normdn = NULL; - doit = 0; + do_dn_norm = 0; + do_dn_norm_sp = 0; + rdn_has_spaces = 0; if (entryrdn_get_switch()) { - char *rdn = NULL; - /* rdn is allocated in get_value_from_string */ + /* original rdn is allocated in get_value_from_string */ rc = get_value_from_string((const char *)data.dptr, "rdn", &rdn); if (rc) { /* data.dptr may not include rdn: ..., try "dn: ..." */ e = slapi_str2entry(data.dptr, SLAPI_STR2ENTRY_USE_OBSOLETE_DNFORMAT); } else { - struct backdn *bdn = - dncache_find_id(&inst->inst_dncache, temp_id); + bdn = dncache_find_id(&inst->inst_dncache, temp_id); if (bdn) { /* don't free dn */ normdn = (char *)slapi_sdn_get_dn(bdn->dn_sdn); @@ -1425,7 +1613,7 @@ upgradedn_producer(void *param) if (rc) { rc = 0; /* assume this is a suffix */ } else { - ID pid = (ID)strtol(pid_str, (char **)NULL, 10); + pid = (ID)strtol(pid_str, (char **)NULL, 10); slapi_ch_free_string(&pid_str); /* if pid is larger than the current pid temp_id, * the parent entry hasn't */ @@ -1433,7 +1621,7 @@ upgradedn_producer(void *param) pid, &id, &psrdn, &curr_entry); if (rc) { LDAPDebug2Args( LDAP_DEBUG_ANY, - "ldbm2index: Failed to compose dn for " + "uptradedn: Failed to compose dn for " "(rdn: %s, ID: %d)\n", rdn, temp_id); slapi_ch_free_string(&rdn); slapi_rdn_done(&psrdn); @@ -1444,7 +1632,7 @@ upgradedn_producer(void *param) slapi_rdn_done(&psrdn); if (rc) { LDAPDebug2Args( LDAP_DEBUG_ANY, - "ldbm2index: Failed to compose dn for " + "uptradedn: Failed to compose dn for " "(rdn: %s, ID: %d) from Slapi_RDN\n", rdn, temp_id); slapi_ch_free_string(&rdn); @@ -1455,23 +1643,34 @@ upgradedn_producer(void *param) rdn, pdn?",":"", pdn?pdn:""); slapi_ch_free_string(&pdn); } - /* dn is not dup'ed in slapi_sdn_new_dn_byref. - * It's set to bdn and put in the dn cache. */ - sdn = slapi_sdn_new_normdn_byref(normdn); - bdn = backdn_init(sdn, temp_id, 0); - CACHE_ADD( &inst->inst_dncache, bdn, NULL ); - CACHE_RETURN(&inst->inst_dncache, &bdn); - slapi_log_error(SLAPI_LOG_CACHE, "ldbm2index", - "entryrdn_lookup_dn returned: %s, " - "and set to dn cache\n", normdn); + if (is_dryrun) { + /* if not dryrun, we may change the DN, In such case, + * we need to put the new value to cache.*/ + /* dn is dup'ed in slapi_sdn_new_dn_byval. + * It's set to bdn and put in the dn cache. */ + sdn = slapi_sdn_new_normdn_byref(normdn); + bdn = backdn_init(sdn, temp_id, 0); + CACHE_ADD( &inst->inst_dncache, bdn, NULL ); + CACHE_RETURN(&inst->inst_dncache, &bdn); + normdn = slapi_sdn_get_dn(sdn); + slapi_log_error(SLAPI_LOG_CACHE, "uptradedn", + "entryrdn_lookup_dn returned: %s, " + "and set to dn cache\n", normdn); + } } e = slapi_str2entry_ext(normdn, NULL, data.dptr, SLAPI_STR2ENTRY_USE_OBSOLETE_DNFORMAT); - slapi_ch_free_string(&rdn); } } else { e = slapi_str2entry(data.data, SLAPI_STR2ENTRY_USE_OBSOLETE_DNFORMAT); + rdn = slapi_ch_strdup(slapi_entry_get_rdn_const(e)); + if (NULL == rdn) { + Slapi_RDN srdn; + slapi_rdn_init_dn(&srdn, slapi_entry_get_dn_const(e)); + rdn = (char *)slapi_rdn_get_rdn(&srdn); /* rdn is allocated in + * slapi_rdn_init_dn */ + } } if ( NULL == e ) { if (job->task) { @@ -1485,6 +1684,7 @@ upgradedn_producer(void *param) continue; } + /* From here, e != NULL */ /* * treat dn specially since the entry was generated with the flag * SLAPI_STR2ENTRY_USE_OBSOLETE_DNFORMAT @@ -1499,24 +1699,154 @@ upgradedn_producer(void *param) normdn = slapi_sdn_get_dn(&(e->e_sdn)); } - /* From here, e != NULL */ + /* + * If dryrun && check_dn_norm_sp, + * check if rdn's containing multi spaces exist or not. + * If any, output the DN:ID into a file INST_dn_norm_sp.txt in the + * ldifdir. We have to continue checking all the entries. + */ + if (chk_dn_norm_sp) { + char *dn_id; + char *path; /* /_dn_norm_sp.txt is used for + the temp work file */ + /* open "path" once, and set FILE* to upgradefd */ + if (NULL == job->upgradefd) { + char *ldifdir = config_get_ldifdir(); + if (ldifdir) { + path = slapi_ch_smprintf("%s/%s_dn_norm_sp.txt", + ldifdir, inst->inst_name); + slapi_ch_free_string(&ldifdir); + } else { + path = slapi_ch_smprintf("/var/tmp/%s_dn_norm_sp.txt", + inst->inst_name); + } + if (is_dryrun) { + job->upgradefd = fopen(path, "w"); + if (NULL == job->upgradefd) { + if (job->task) { + slapi_task_log_notice(job->task, + "%s: No DNs to fix.\n", inst->inst_name); + } + LDAPDebug1Arg(LDAP_DEBUG_ANY, + "%s: No DNs to fix.\n", inst->inst_name); + slapi_ch_free_string(&path); + goto bail; + } + } else { + job->upgradefd = fopen(path, "r"); + if (NULL == job->upgradefd) { + if (job->task) { + slapi_task_log_notice(job->task, + "%s: Error: failed to open a file \"%s\"", + inst->inst_name, path); + } + LDAPDebug2Args(LDAP_DEBUG_ANY, + "%s: Error: failed to open a file \"%s\"\n", + inst->inst_name, path); + slapi_ch_free_string(&path); + goto error; + } + } + } + slapi_ch_free_string(&path); + if (is_dryrun) { + rdn_has_spaces = has_spaces(rdn); + if (rdn_has_spaces > 0) { + dn_id = slapi_ch_smprintf("%s:%u\n", + slapi_entry_get_dn_const(e), temp_id); + if (EOF == fputs(dn_id, job->upgradefd)) { + if (job->task) { + slapi_task_log_notice(job->task, + "%s: Error: failed to write a line \"%s\"", + inst->inst_name, dn_id); + } + LDAPDebug2Args(LDAP_DEBUG_ANY, + "%s: Error: failed to write a line \"%s\"", + inst->inst_name, dn_id); + slapi_ch_free_string(&dn_id); + goto error; + } + slapi_ch_free_string(&dn_id); + if (rdn_has_spaces > 1) { + /* If an rdn containing multi spaces exists, + * let's check the conflict. */ + do_dn_norm_sp = 1; + } + } + } else { /* !is_dryrun */ + /* check the oid and parentid. */ + /* Set conflict list once, and refer it laster. */ + static int my_idx = 0; + ID alt_id; + if (NULL == dn_norm_sp_conflicts) { + char buf[BUFSIZ]; + char *p; + int my_max = 8; + while (fgets(buf, BUFSIZ-1, job->upgradefd)) { + /* search "OID0: OID1 OID2 ... */ + if (!isdigit(*buf) || !(p = PL_strchr(buf, ':'))) { + continue; + } + if (add_IDs_to_IDarray(&dn_norm_sp_conflicts, &my_max, + my_idx, buf)) { + LDAPDebug1Arg(LDAP_DEBUG_ANY, + "Failed to set IDs %s to conflict list\n", + buf); + goto error; + } + my_idx++; + } + } + alt_id = is_conflict_ID(dn_norm_sp_conflicts, my_idx, temp_id); + if (alt_id) { + char *parentdn = NULL; + char *newrdn = NULL; + if (alt_id != temp_id) { + parentdn = slapi_dn_parent(normdn); + newrdn = slapi_create_dn_string("%s %u", rdn, temp_id); + /* This entry is a conflict of alt_id */ + LDAPDebug(LDAP_DEBUG_ANY, + "Entry %s (%lu) is a conflict of (%lu)\n", + normdn, temp_id, alt_id); + LDAPDebug2Args(LDAP_DEBUG_ANY, "Renaming \"%s\" to \"%s\"\n", + rdn, newrdn); + normdn = slapi_ch_smprintf("%s,%s", newrdn, parentdn); + /* Reset DN and RDN in the entry */ + slapi_sdn_done(&(e->e_sdn)); + slapi_sdn_init_normdn_passin(&(e->e_sdn), normdn); + /* normdn = slapi_sdn_get_dn(&(e->e_sdn)); */ + } + info_state |= DN_NORM_SP; + upgradedn_add_to_list(&ud_list, + slapi_ch_strdup(LDBM_ENTRYRDN_STR), + slapi_ch_strdup(rdn), 0); + rc = slapi_entry_add_rdn_values(e); + if (rc) { + LDAPDebug(LDAP_DEBUG_ANY, "%s: Failed to add rdn values" + " to an entry: %s (id %lu)\n", + inst->inst_name, normdn, (u_long)temp_id); + goto error; + } + } /* !alt_id */ + } /* !is_dryrun */ + } /* if (chk_dn_norm_sp) */ + + /* dn is dup'ed in slapi_sdn_new_dn_byval. + * It's set to bdn and put in the dn cache. */ + /* Waited to put normdn into dncache until it could be modified in + * chk_dn_norm_sp. */ + sdn = slapi_sdn_new_normdn_byref(normdn); + bdn = backdn_init(sdn, temp_id, 0); + CACHE_ADD(&inst->inst_dncache, bdn, NULL); + CACHE_RETURN(&inst->inst_dncache, &bdn); + slapi_log_error(SLAPI_LOG_CACHE, "uptradedn", + "set dn %s to dn cache\n", normdn); /* Check DN syntax attr values if it contains '\\' or not */ /* Start from the rdn */ - if (entryrdn_get_switch()) { /* subtree-rename: on */ - char *rdn = NULL; - size_t rdnlen = 0; + if (chk_dn_norm) { char *endrdn = NULL; char *rdnp = NULL; - rc = get_value_from_string((const char *)ecopy, "rdn", &rdn); - if (rc || (NULL == rdn)) { - LDAPDebug2Args(LDAP_DEBUG_ANY, - "%s: WARNING: skipping an entry with no RDN (id %lu)\n", - inst->inst_name, (u_long)temp_id); - slapi_entry_free(e); e = NULL; - continue; - } - rdnlen = strlen(rdn); - endrdn = rdn + rdnlen - 1; + endrdn = rdn + strlen(rdn) - 1; rdnp = PL_strchr(rdn, '='); if (NULL == rdnp) { @@ -1528,24 +1858,23 @@ upgradedn_producer(void *param) continue; } /* rdn contains '\\'. We have to update the value */ - if (PL_strchr(rdn, '\\')) { - doit = 1; + if (PL_strchr(rdnp, '\\')) { + do_dn_norm = 1; } else { while ((++rdnp <= endrdn) && (*rdnp == ' ') && (*rdnp == '\t')) ; /* DN contains an RDN ="" ? */ if ((rdnp != endrdn) && ('"' == *rdnp) && ('"' == *endrdn)) { - doit = 1; + do_dn_norm = 1; } } - if (doit) { + if (do_dn_norm) { upgradedn_add_to_list(&ud_list, slapi_ch_strdup(LDBM_ENTRYRDN_STR), slapi_ch_strdup(rdn), 0); - LDAPDebug(LDAP_DEBUG_TRACE, - "%s: Found upgradedn candidate: %s (id %lu)\n", - inst->inst_name, *ud_valp, (u_long)temp_id); - /* entryrdn format */ + LDAPDebug2Args(LDAP_DEBUG_TRACE, + "%s: Found upgradedn candidate: (id %lu)\n", + inst->inst_name, (u_long)temp_id); /* * In case rdn is type="" or type=<\D\N>, * add the rdn value if it's not there. @@ -1559,130 +1888,146 @@ upgradedn_producer(void *param) continue; } } - slapi_ch_free_string(&rdn); - } - for (a = e->e_attrs; a; a = a->a_next) { - if (!slapi_attr_is_dn_syntax_attr(a)) { - continue; /* not a syntax dn attr */ - } - - /* dn syntax attr */ - rc = get_values_from_string((const char *)ecopy, - a->a_type, &ud_vals); - if (rc || (NULL == ud_vals)) { - continue; /* empty; ignore it */ - } - - for (ud_valp = ud_vals; ud_valp && *ud_valp; ud_valp++) { - char **rdns = NULL; - char **rdnsp = NULL; - char *valueptr = NULL; - char *endvalue = NULL; - int isentrydn = 0; - - /* Also check RDN contains double quoted values */ - if (strcasecmp(a->a_type, "entrydn")) { - /* except entrydn */ - workdn = slapi_ch_strdup(*ud_valp); - isentrydn = 0; - } else { - /* entrydn: Get Slapi DN */ - sdn = slapi_entry_get_sdn(e); - workdn = slapi_ch_strdup(slapi_sdn_get_dn(sdn)); - isentrydn = 1; + /* checking the DN sintax values in the attribute list */ + for (a = e->e_attrs; a; a = a->a_next) { + if (!slapi_attr_is_dn_syntax_attr(a)) { + continue; /* not a syntax dn attr */ } - rdns = slapi_ldap_explode_dn(workdn, 0); - skipit = 0; - for (rdnsp = rdns; rdnsp && *rdnsp; rdnsp++) { - valueptr = PL_strchr(*rdnsp, '='); - if (NULL == valueptr) { - skipit = 1; - break; - } - endvalue = *rdnsp + strlen(*rdnsp) - 1; - while ((++valueptr <= endvalue) && - ((' ' == *valueptr) || ('\t' == *valueptr))) ; - if (0 == strlen(valueptr)) { - skipit = 1; - break; + + /* dn syntax attr */ + rc = get_values_from_string((const char *)ecopy, + a->a_type, &ud_vals); + if (rc || (NULL == ud_vals)) { + continue; /* empty; ignore it */ + } + + for (ud_valp = ud_vals; ud_valp && *ud_valp; ud_valp++) { + char **rdns = NULL; + char **rdnsp = NULL; + char *valueptr = NULL; + char *endvalue = NULL; + int isentrydn = 0; + + /* Also check RDN contains double quoted values */ + if (strcasecmp(a->a_type, "entrydn")) { + /* except entrydn */ + workdn = slapi_ch_strdup(*ud_valp); + isentrydn = 0; + } else { + /* entrydn: Get Slapi DN */ + sdn = slapi_entry_get_sdn(e); + workdn = slapi_ch_strdup(slapi_sdn_get_dn(sdn)); + isentrydn = 1; } - /* DN syntax value contains an RDN ="" or - * '\\' in the value ? - * If yes, let's upgrade the dn format. */ - if ((('"' == *valueptr) && ('"' == *endvalue)) || - PL_strchr(valueptr, '\\')) { - doit = 1; - upgradedn_add_to_list(&ud_list, - slapi_ch_strdup(a->a_type), - slapi_ch_strdup(*ud_valp), - isentrydn?0:OLD_DN_NORMALIZE); - LDAPDebug(LDAP_DEBUG_TRACE, - "%s: Found upgradedn candidate: %s (id %lu)\n", - inst->inst_name, valueptr, (u_long)temp_id); - if (!entryrdn_get_switch() && isentrydn) { - /* entrydn format */ - /* - * In case entrydn is type="", or - * type=<\D\N>,, - * add the rdn value if it's not there. - */ - rc = slapi_entry_add_rdn_values(e); - if (rc) { - LDAPDebug(LDAP_DEBUG_ANY, - "%s: Failed to add rdn values " - "to an entry: %s (id %lu)\n", - inst->inst_name, normdn, (u_long)temp_id); - slapi_entry_free(e); e = NULL; - continue; + rdns = slapi_ldap_explode_dn(workdn, 0); + skipit = 0; + for (rdnsp = rdns; rdnsp && *rdnsp; rdnsp++) { + valueptr = PL_strchr(*rdnsp, '='); + if (NULL == valueptr) { + skipit = 1; + break; + } + endvalue = *rdnsp + strlen(*rdnsp) - 1; + while ((++valueptr <= endvalue) && + ((' ' == *valueptr) || ('\t' == *valueptr))) ; + if (0 == strlen(valueptr)) { + skipit = 1; + break; + } + /* DN syntax value contains an RDN ="" or + * '\\' in the value ? + * If yes, let's upgrade the dn format. */ + if ((('"' == *valueptr) && ('"' == *endvalue)) || + PL_strchr(valueptr, '\\')) { + do_dn_norm = 1; + upgradedn_add_to_list(&ud_list, + slapi_ch_strdup(a->a_type), + slapi_ch_strdup(*ud_valp), + isentrydn?0:OLD_DN_NORMALIZE); + LDAPDebug(LDAP_DEBUG_TRACE, + "%s: Found upgradedn candidate: %s (id %lu)\n", + inst->inst_name, valueptr, (u_long)temp_id); + if (!entryrdn_get_switch() && isentrydn) { + /* entrydn format */ + /* + * In case entrydn is type="", or + * type=<\D\N>,, + * add the rdn value if it's not there. + */ + rc = slapi_entry_add_rdn_values(e); + if (rc) { + LDAPDebug(LDAP_DEBUG_ANY, + "%s: Failed to add rdn values " + "to an entry: %s (id %lu)\n", + inst->inst_name, normdn, (u_long)temp_id); + slapi_entry_free(e); e = NULL; + continue; + } } + break; } + /* + * else if (the rdn contains multiple spaces)? + * if yes, they are reduced to one. + * SET HAVE_MULTI_SPACES??? + */ + } /* for (rdnsp = rdns; rdnsp && *rdnsp; rdnsp++) */ + if (rdns) { + slapi_ldap_value_free(rdns); + } else { + skipit = 1; + } + if (skipit) { break; } - } /* for (rdnsp = rdns; rdnsp && *rdnsp; rdnsp++) */ - if (rdns) { - slapi_ldap_value_free(rdns); - } else { - skipit = 1; - } + slapi_ch_free_string(&workdn); + } /* for (ud_valp = ud_vals; ud_valp && *ud_valp; ud_valp++) */ + charray_free(ud_vals); + ud_vals = NULL; if (skipit) { + LDAPDebug(LDAP_DEBUG_ANY, "%s: WARNING: skipping an entry " + "with a corrupted dn (syntax value): %s " + "(id %lu)\n", + inst->inst_name, + workdn?workdn:"unknown", (u_long)temp_id); + slapi_ch_free_string(&workdn); + upgradedn_free_list(&ud_list); break; } - slapi_ch_free_string(&workdn); - } /* for (ud_valp = ud_vals; ud_valp && *ud_valp; ud_valp++) */ - charray_free(ud_vals); - ud_vals = NULL; + } /* for (a = e->e_attrs; a; a = a->a_next) */ if (skipit) { - LDAPDebug(LDAP_DEBUG_ANY, "%s: WARNING: skipping an entry " - "with a corrupted dn (syntax value): %s " - "(id %lu)\n", - inst->inst_name, - workdn?workdn:"unknown", (u_long)temp_id); - slapi_ch_free_string(&workdn); upgradedn_free_list(&ud_list); - break; + slapi_entry_free(e); e = NULL; + continue; } - } /* for (a = e->e_attrs; a; a = a->a_next) */ - if (skipit) { - upgradedn_free_list(&ud_list); - slapi_entry_free(e); e = NULL; - continue; - } + } /* end of if (chk_do_norm) */ + slapi_ch_free_string(&rdn); - if (!doit) { + if (is_dryrun) { + if (do_dn_norm) { + info_state |= DN_NORM; + /* + * If dryrun AND (found we need to do dn norm) AND + * (no need to check spaces), + * then we can quit here to return. + */ + if (!chk_dn_norm_sp) { + finished = 0; /* make it sure ... */ + upgradedn_free_list(&ud_list); + slapi_entry_free(e); e = NULL; + /* found upgrade dn candidates */ + goto bail; + } + } + if (do_dn_norm_sp) { + info_state |= DN_NORM_SP; + } /* We don't have to update dn syntax values. */ upgradedn_free_list(&ud_list); slapi_entry_free(e); e = NULL; continue; } - - /* doit */ - if (job->flags & FLAG_DRYRUN) { - /* We can return SUCCESS (== found upgrade dn candidates) */ - finished = 0; /* make it sure ... */ - upgradedn_free_list(&ud_list); - slapi_entry_free(e); e = NULL; - goto bail; - } + skipit = 0; for (ud_ptr = ud_list; ud_ptr; ud_ptr = ud_ptr->ud_next) { Slapi_Value *value = NULL; @@ -1810,23 +2155,14 @@ upgradedn_producer(void *param) id++; if (job->flags & FLAG_ABORT) goto error; - if (info->command == STOP) - { + if (info->command == STOP) { finished = 1; } } bail: dbc->c_close(dbc); dblayer_release_aux_id2entry( be, db, env ); - if (job->flags & FLAG_DRYRUN) { - if (finished) { /* Set if dn upgrade candidates are not found */ - info->state = FINISHED; - } else { /* At least one dn upgrade candidate is found */ - info->state = QUIT; - } - } else { - info->state = FINISHED; - } + info->state = FINISHED | info_state; goto done; error: @@ -1837,8 +2173,12 @@ error: info->state = ABORTED; done: + free_IDarray(&dn_norm_sp_conflicts); slapi_ch_free_string(&ecopy); slapi_ch_free(&(data.data)); + if (job->upgradefd) { + fclose(job->upgradefd); + } } static void @@ -1883,7 +2223,7 @@ foreman_do_parentid(ImportJob *job, FifoItem *fi, struct attrinfo *parentid_ai) int ret = 0; struct backentry *entry = fi->entry; - if (job->flags & FLAG_UPGRADEDNFORMAT) { + if (job->flags & (FLAG_UPGRADEDNFORMAT|FLAG_UPGRADEDNFORMAT_V1)) { /* Get the parentid attribute value from deleted attr list */ Slapi_Value *value = NULL; Slapi_Attr *pid_to_del = @@ -1950,7 +2290,7 @@ foreman_do_entrydn(ImportJob *job, FifoItem *fi) IDList *IDL; struct backentry *entry = fi->entry; - if (job->flags & FLAG_UPGRADEDNFORMAT) { + if (job->flags & (FLAG_UPGRADEDNFORMAT|FLAG_UPGRADEDNFORMAT_V1)) { /* Get the entrydn attribute value from deleted attr list */ Slapi_Value *value = NULL; Slapi_Attr *entrydn_to_del = @@ -1994,7 +2334,7 @@ foreman_do_entrydn(ImportJob *job, FifoItem *fi) /* So, we do an index read first */ err = 0; IDL = index_read(be, LDBM_ENTRYDN_STR, indextype_EQUALITY, &bv, NULL, &err); - if (job->flags & FLAG_UPGRADEDNFORMAT) { + if (job->flags & (FLAG_UPGRADEDNFORMAT|FLAG_UPGRADEDNFORMAT_V1)) { /* * In the UPGRADEDNFORMAT case, if entrydn value exists, * that means either 1) entrydn is not upgraded (ID == entry->ep_id) @@ -2058,7 +2398,7 @@ foreman_do_entryrdn(ImportJob *job, FifoItem *fi) int ret = 0; struct backentry *entry = fi->entry; - if (job->flags & FLAG_UPGRADEDNFORMAT) { + if (job->flags & (FLAG_UPGRADEDNFORMAT|FLAG_UPGRADEDNFORMAT_V1)) { /* Get the entrydn attribute value from deleted attr list */ Slapi_Value *value = NULL; Slapi_Attr *entryrdn_to_del = NULL; @@ -2084,6 +2424,10 @@ foreman_do_entryrdn(ImportJob *job, FifoItem *fi) } } slapi_attr_free(&entryrdn_to_del); + /* Waited to update e_srdn to delete the old entryrdn. + * Now updated it to adjust to the new s_dn. */ + slapi_rdn_set_all_dn(&(entry->ep_entry->e_srdn), + slapi_entry_get_dn_const(entry->ep_entry)); } } ret = entryrdn_index_entry(be, entry, BE_INDEX_ADD, NULL); @@ -2169,7 +2513,19 @@ import_foreman(void *param) import_log_notice(job, "WARNING: entry for id %d is missing", id); continue; } - + if (job->flags & FLAG_UPGRADEDNFORMAT_V1) { + if (entryrdn_get_switch()) { /* subtree-rename: on */ + /* insert into the entryrdn index */ + ret = foreman_do_entryrdn(job, fi); + } else { + /* insert into the entrydn index */ + ret = foreman_do_entrydn(job, fi); + if (ret == -1) { + goto cont; /* skip entry */ + } + } + goto next; + } /* first, fill in any operational attributes */ /* add_op_attrs wants a pblock for some reason. */ if (job->flags & FLAG_UPGRADEDNFORMAT) { @@ -2312,7 +2668,7 @@ import_foreman(void *param) if (job->flags & FLAG_ABORT) { goto error; } - +next: if (!(job->flags & FLAG_REINDEXING))/* reindex reads data from id2entry */ { /* insert into the id2entry index @@ -2348,14 +2704,14 @@ import_foreman(void *param) goto error; } - if (entryrdn_get_switch() /* subtree-rename: on */ || + if (entryrdn_get_switch() /* subtree-rename: on */ && !slapi_entry_flag_is_set(fi->entry->ep_entry, SLAPI_ENTRY_FLAG_TOMBSTONE)) { /* parentid index * (we have to do this here, because the parentID is dependent on * looking up by entrydn/entryrdn.) * Only add to the parent index if the entry is not a tombstone && - * subtree-rename is off. + * subtree-rename is on. */ ret = foreman_do_parentid(job, fi, parentid_ai); if (ret != 0) @@ -2536,7 +2892,7 @@ import_worker(void *param) slapi_pblock_destroy(pb); } else { /* No, process regular index */ - if (job->flags & FLAG_UPGRADEDNFORMAT) { + if (job->flags & (FLAG_UPGRADEDNFORMAT|FLAG_UPGRADEDNFORMAT_V1)) { /* Get the attribute value from deleted attr list */ Slapi_Value *value = NULL; const struct berval *bval = NULL; diff --git a/ldap/servers/slapd/back-ldbm/import.c b/ldap/servers/slapd/back-ldbm/import.c index e3966ff..aedff9f 100644 --- a/ldap/servers/slapd/back-ldbm/import.c +++ b/ldap/servers/slapd/back-ldbm/import.c @@ -51,7 +51,9 @@ #include "import.h" #define ERR_IMPORT_ABORTED -23 -#define DRYRUN_QUIT -24 +#define NEED_DN_NORM -24 +#define NEED_DN_NORM_SP -25 +#define NEED_DN_NORM_BT -26 /********** routines to manipulate the entry fifo **********/ @@ -111,7 +113,9 @@ FifoItem *import_fifo_fetch(ImportJob *job, ID id, int worker) if (fi->bad) { if (fi->bad == FIFOITEM_BAD) { fi->bad = FIFOITEM_BAD_PRINTED; - import_log_notice(job, "WARNING: bad entry: ID %d", id); + if (!(job->flags & FLAG_UPGRADEDNFORMAT_V1)) { + import_log_notice(job, "WARNING: bad entry: ID %d", id); + } } return NULL; } @@ -197,7 +201,7 @@ void import_log_notice(ImportJob *job, char *format, ...) slapi_task_log_notice(job->task, "%s", buffer); } /* also save it in the logs for posterity */ - if (job->flags & FLAG_UPGRADEDNFORMAT) { + if (job->flags & (FLAG_UPGRADEDNFORMAT|FLAG_UPGRADEDNFORMAT_V1)) { LDAPDebug(LDAP_DEBUG_ANY, "upgradedn %s: %s\n", job->inst->inst_name, buffer, 0); } else if (job->flags & FLAG_REINDEXING) { @@ -260,7 +264,7 @@ static int import_attr_callback(void *node, void *param) if (job->flags & FLAG_DRYRUN) { /* dryrun; we don't need the workers */ return 0; } - if (job->flags & FLAG_UPGRADEDNFORMAT) { + if (job->flags & (FLAG_UPGRADEDNFORMAT|FLAG_UPGRADEDNFORMAT_V1)) { /* Bring up import workers just for indexes having DN syntax * attribute type. (except entrydn -- taken care below) */ int rc = 0; @@ -707,6 +711,7 @@ static int import_monitor_threads(ImportJob *job, int *status) time_t last_time = 0; time_t time_interval = 0; int rc = 0; + int corestate = 0; for (current_worker = job->worker_list; current_worker != NULL; current_worker = current_worker->next) { @@ -774,14 +779,31 @@ static int import_monitor_threads(ImportJob *job, int *status) import_calc_rate(current_worker, time_interval); import_print_worker_status(current_worker); } - if (current_worker->state == QUIT) { - rc = DRYRUN_QUIT; /* Set the RC; Don't abort now; - We have to stop other threads */ - } else if (current_worker->state != FINISHED) { - finished = 0; - } + corestate = current_worker->state & CORESTATE; if (current_worker->state == ABORTED) { +LDAPDebug0Args(LDAP_DEBUG_ANY, "import_monitor_threads: current_worker->state is ABORTED\n"); goto error_abort; + } else if ((corestate == QUIT) || (corestate == FINISHED)) { +LDAPDebug1Arg(LDAP_DEBUG_ANY, "import_monitor_threads: current_worker->state is %s\n", (corestate==QUIT)?"QUIT":"FINISHED"); + if (DN_NORM_BT == (DN_NORM_BT & current_worker->state)) { + /* upgrading dn norm (both) is needed */ + rc = NEED_DN_NORM_BT; /* Set the RC; Don't abort now; + * We have to stop other + * threads */ + } else if (DN_NORM == (DN_NORM_BT & current_worker->state)) { + /* upgrading dn norm is needed */ + rc = NEED_DN_NORM; /* Set the RC; Don't abort now; + * We have to stop other threads + */ + } else if (DN_NORM_SP == (DN_NORM_BT & current_worker->state)) { + /* upgrading spaces in dn norm is needed */ + rc = NEED_DN_NORM_SP; /* Set the RC; Don't abort now; + * We have to stop other + * threads */ + } + current_worker->state = corestate; + } else if (current_worker->state != FINISHED) { + finished = 0; } } @@ -906,7 +928,9 @@ static int import_run_pass(ImportJob *job, int *status) /* Monitor the threads until we're done or fail */ ret = import_monitor_threads(job, status); - if ((ret == ERR_IMPORT_ABORTED) || (ret == DRYRUN_QUIT)) { + if ((ret == ERR_IMPORT_ABORTED) || (ret == NEED_DN_NORM) || + (ret == NEED_DN_NORM_SP) || (ret == NEED_DN_NORM_BT)) { +import_log_notice(job, "Thread monitoring returned: %d\n", ret); goto error; } else if (ret != 0) { import_log_notice(job, "Thread monitoring aborted: %d\n", ret); @@ -1140,11 +1164,16 @@ int import_main_offline(void *arg) if (job->task) slapi_task_inc_refcount(job->task); - if (job->flags & FLAG_UPGRADEDNFORMAT) { + if (job->flags & (FLAG_UPGRADEDNFORMAT|FLAG_UPGRADEDNFORMAT_V1)) { if (job->flags & FLAG_DRYRUN) { opstr = "Upgrade Dn Dryrun"; + } else if ((job->flags & (FLAG_UPGRADEDNFORMAT|FLAG_UPGRADEDNFORMAT_V1)) + == (FLAG_UPGRADEDNFORMAT|FLAG_UPGRADEDNFORMAT_V1)) { + opstr = "Upgrade Dn (Full)"; + } else if (job->flags & FLAG_UPGRADEDNFORMAT_V1) { + opstr = "Upgrade Dn (Spaces)"; } else { - opstr = "Upgrade Dn"; + opstr = "Upgrade Dn (RFC 4514)"; } } else if (job->flags & FLAG_REINDEXING) { opstr = "Reindexing"; @@ -1187,7 +1216,7 @@ int import_main_offline(void *arg) /* start the producer */ import_init_worker_info(producer, job); producer->work_type = PRODUCER; - if (job->flags & FLAG_UPGRADEDNFORMAT) + if (job->flags & (FLAG_UPGRADEDNFORMAT|FLAG_UPGRADEDNFORMAT_V1)) { if (! CREATE_THREAD(PR_USER_THREAD, (VFP)upgradedn_producer, producer, PR_PRIORITY_NORMAL, PR_GLOBAL_BOUND_THREAD, @@ -1278,11 +1307,10 @@ int import_main_offline(void *arg) aborted = 1; goto error; } - if (ret == DRYRUN_QUIT) { - goto error; /* Found the candidate; close the db files and quit */ - } - - if (0 != ret) { + if ((ret == NEED_DN_NORM) || (ret == NEED_DN_NORM_SP) || + (ret == NEED_DN_NORM_BT)) { + goto error; + } else if (0 != ret) { /* Some horrible fate has befallen the import */ import_log_notice(job, "Fatal pass error %d", ret); goto error; @@ -1414,7 +1442,8 @@ error: } } if (0 != ret) { - if (!(job->flags & FLAG_DRYRUN)) { /* If not dryrun */ + if (!(job->flags & (FLAG_DRYRUN|FLAG_UPGRADEDNFORMAT_V1))) { + /* If not dryrun NOR upgradedn space */ /* if running in the dry run mode, don't touch the db */ dblayer_delete_instance_dir(be); } @@ -1475,23 +1504,40 @@ error: } } - if (job->flags & FLAG_DRYRUN) { + if (job->flags & (FLAG_DRYRUN|FLAG_UPGRADEDNFORMAT_V1)) { if (0 == ret) { import_log_notice(job, "%s complete. %s is up-to-date.", opstr, job->inst->inst_name); + ret = 0; + if (job->task) { + slapi_task_dec_refcount(job->task); + } + import_all_done(job, ret); + } else if (NEED_DN_NORM_BT == ret) { + import_log_notice(job, "%s complete. %s needs upgradednformat all.", + opstr, job->inst->inst_name); + if (job->task) { + slapi_task_dec_refcount(job->task); + } + import_all_done(job, ret); ret = 1; + } else if (NEED_DN_NORM == ret) { + import_log_notice(job, "%s complete. %s needs upgradednformat.", + opstr, job->inst->inst_name); if (job->task) { slapi_task_dec_refcount(job->task); } import_all_done(job, ret); - } else if (DRYRUN_QUIT == ret) { - import_log_notice(job, "%s complete. %s needs upgradednformat.", + ret = 2; + } else if (NEED_DN_NORM_SP == ret) { + import_log_notice(job, + "%s complete. %s needs upgradednformat spaces.", opstr, job->inst->inst_name); if (job->task) { slapi_task_dec_refcount(job->task); } import_all_done(job, ret); - ret = 0; + ret = 3; } else { ret = -1; if (job->task != NULL) { @@ -1581,8 +1627,13 @@ int ldbm_back_ldif2ldbm_deluxe(Slapi_PBlock *pb) job->flags = FLAG_USE_FILES; if (NULL == name_array) { /* no ldif file is given -> reindexing or upgradedn */ - if (up_flags & SLAPI_UPGRADEDNFORMAT) { - job->flags |= FLAG_UPGRADEDNFORMAT; + if (up_flags & (SLAPI_UPGRADEDNFORMAT|SLAPI_UPGRADEDNFORMAT_V1)) { + if (up_flags & SLAPI_UPGRADEDNFORMAT) { + job->flags |= FLAG_UPGRADEDNFORMAT; + } + if (up_flags & SLAPI_UPGRADEDNFORMAT_V1) { + job->flags |= FLAG_UPGRADEDNFORMAT_V1; + } if (up_flags & SLAPI_DRYRUN) { job->flags |= FLAG_DRYRUN; } diff --git a/ldap/servers/slapd/back-ldbm/import.h b/ldap/servers/slapd/back-ldbm/import.h index c9a3f8a..7870403 100644 --- a/ldap/servers/slapd/back-ldbm/import.h +++ b/ldap/servers/slapd/back-ldbm/import.h @@ -159,8 +159,9 @@ typedef struct { PRLock *wire_lock; /* lock for serializing wire imports */ PRCondVar *wire_cv; /* ... and ordering the startup */ PRThread *main_thread; /* for FRI: import_main() thread id */ - int encrypt; - Slapi_Value *usn_value; /* entryusn for import */ + int encrypt; + Slapi_Value *usn_value; /* entryusn for import */ + FILE *upgradefd; /* used for the upgrade */ } ImportJob; #define FLAG_INDEX_ATTRS 0x01 /* should we index the attributes? */ @@ -173,6 +174,7 @@ typedef struct { #define FLAG_DN2RDN 0x40 /* modify backend to the rdn format */ #define FLAG_UPGRADEDNFORMAT 0x80 /* read from id2entry and do upgrade dn */ #define FLAG_DRYRUN 0x100 /* dryrun for upgrade dn */ +#define FLAG_UPGRADEDNFORMAT_V1 0x200 /* taking care multiple spaces in dn */ /* Structure holding stuff about a worker thread and what it's up to */ @@ -202,12 +204,17 @@ struct _import_worker_info { #define ABORT 3 #define STOP 4 -/* Values for state */ -#define WAITING 1 -#define RUNNING 2 -#define FINISHED 3 -#define ABORTED 4 -#define QUIT 5 /* quit intentionally. to distinguish from ABORTED & FINISHED */ +/* Values for job state */ +#define WAITING 0x1 +#define RUNNING 0x2 +#define FINISHED 0x4 +#define ABORTED 0x8 +#define QUIT 0x10 /* quit intentionally. + * introduced to distinguish from ABORTED, FINISHED */ +#define CORESTATE 0xff +#define DN_NORM 0x100 /* do dn normalization in upgrade */ +#define DN_NORM_SP 0x200 /* do dn normalization for multi spaces in upgrade */ +#define DN_NORM_BT (DN_NORM | DN_NORM_SP) /* this is just a convenience, because the slapi_ch_* calls are annoying */ #define CALLOC(name) (name *)slapi_ch_calloc(1, sizeof(name)) diff --git a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c index 8818ba7..0793041 100644 --- a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c +++ b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c @@ -204,8 +204,9 @@ int ldbm_back_ok_to_dump(const char *dn, char **include, char **exclude) * allowed to specify yourself on entries. * Currenty the list of these is: numSubordinates, hasSubordinates */ -int add_op_attrs(Slapi_PBlock *pb, struct ldbminfo *li, struct backentry *ep, - int *status) +int +add_op_attrs(Slapi_PBlock *pb, struct ldbminfo *li, struct backentry *ep, + int *status) { backend *be; char *pdn; @@ -3549,7 +3550,7 @@ int ldbm_back_upgradednformat(Slapi_PBlock *pb) slapi_pblock_get(pb, SLAPI_BACKEND_TASK, &task); slapi_pblock_get(pb, SLAPI_DB2LDIF_SERVER_RUNNING, &server_running); slapi_pblock_get(pb, SLAPI_BACKEND_INSTANCE_NAME, &instance_name); - slapi_pblock_get( pb, SLAPI_SEQ_TYPE, &ud_flags ); + slapi_pblock_get(pb, SLAPI_SEQ_TYPE, &ud_flags); run_from_cmdline = (task_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE); slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &li); @@ -3624,11 +3625,39 @@ int ldbm_back_upgradednformat(Slapi_PBlock *pb) workdbdir = rel2abspath(rawworkdbdir); dbversion_read(li, workdbdir, &ldbmversion, &dataversion); - if (ldbmversion && PL_strstr(ldbmversion, BDB_DNFORMAT)) { + if (ldbmversion) { + char *ptr = PL_strstr(ldbmversion, BDB_DNFORMAT); + if (ptr) { + size_t dnformat_len = strlen(ptr); + /* DN format is RFC 4514 compliant */ + if (strlen(ptr) == strlen(BDB_DNFORMAT)) { /* no version */ + /* + * DN format is RFC 4514 compliant. + * But it hasn't taken care of the multiple spaces yet. + */ + ud_flags &= ~SLAPI_UPGRADEDNFORMAT; + ud_flags |= SLAPI_UPGRADEDNFORMAT_V1; + slapi_pblock_set(pb, SLAPI_SEQ_TYPE, &ud_flags); + rc = 3; /* 0: need upgrade (dn norm sp, only) */ + } else { + /* DN format already takes care of the multiple spaces */ + slapi_log_error(SLAPI_LOG_FATAL, "Upgrade DN Format", + "Instance %s in %s is up-to-date\n", + instance_name, workdbdir); + rc = 0; /* 0: up-to-date */ + goto bail; + } + } else { + /* DN format is not RFC 4514 compliant */ + ud_flags |= SLAPI_UPGRADEDNFORMAT | SLAPI_UPGRADEDNFORMAT_V1; + slapi_pblock_set(pb, SLAPI_SEQ_TYPE, &ud_flags); + rc = 1; /* 0: need upgrade (both) */ + } + } else { slapi_log_error(SLAPI_LOG_FATAL, "Upgrade DN Format", - "Instance %s in %s is up-to-date\n", + "Failed to get DBVERSION (Instance name: %s, dir %s)\n", instance_name, workdbdir); - rc = 1; /* 1: up-to-date; 0: need upgrade; otherwise: error */ + rc = -1; /* error */ goto bail; } @@ -3681,7 +3710,7 @@ int ldbm_back_upgradednformat(Slapi_PBlock *pb) } *sep = '/'; if (((0 == rc) && !(ud_flags & SLAPI_DRYRUN)) || - ((rc > 0) && (ud_flags & SLAPI_DRYRUN))) { + ((rc == 0) && (ud_flags & SLAPI_DRYRUN))) { /* modify the DBVERSION files if the DN upgrade was successful OR * if DRYRUN, the backend instance is up-to-date. */ dbversion_write(li, workdbdir, NULL, DBVERSION_ALL); /* inst db dir */ diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h index 937c2bb..375c33f 100644 --- a/ldap/servers/slapd/slapi-private.h +++ b/ldap/servers/slapd/slapi-private.h @@ -1223,6 +1223,7 @@ void DS_Sleep(PRIntervalTime ticks); generate entryrdn index */ #define SLAPI_UPGRADEDNFORMAT 0x8 /* specify this op is upgradednformat */ #define SLAPI_DRYRUN 0x10 /* dryrun mode for upgradednformat */ +#define SLAPI_UPGRADEDNFORMAT_V1 0x20 /* taking care multipe spaces */ /*