summaryrefslogtreecommitdiffstats
path: root/ldap/admin/src/scripts/70upgradednformat.pl
blob: 100a318cb23ef89648c9279d248888b411ca7656 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
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;

# 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", $!);
    }
    # First, check if the server is up or down.
    my $rundir = $config_entry->getValues('nsslapd-rundir');

    # Check if the server is up or not
    my $pidfile = $rundir . "/" . $inst . ".pid";
    if (-e $pidfile) {
        return (); # server is running; do nothing.
    }
    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", $!);
    }

    # 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: "<suffix>"
            # Adding cn: <suffix>
            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/entrydn.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) {
                my $rc = 0;

                if (system("cd $pdbdir; tar cf - db/DBVERSION | (cd $dbinstdir; tar xf -)") ||
                    system("cd $pdbdir; tar cf - db/$instname/{DBVERSION,*.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);
                }
            }
        }

        $backend_entry = $conn->nextEntry();
    }

    return ();
}