diff options
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | Makefile.in | 3 | ||||
-rw-r--r-- | ldap/admin/src/scripts/DSMigration.pm.in | 10 | ||||
-rw-r--r-- | ldap/admin/src/scripts/FileConn.pm | 389 | ||||
-rw-r--r-- | ldap/admin/src/scripts/Resource.pm | 4 | ||||
-rw-r--r-- | ldap/admin/src/scripts/Util.pm.in | 64 | ||||
-rw-r--r-- | ldap/admin/src/scripts/setup-ds.pl.in | 4 | ||||
-rw-r--r-- | ldap/admin/src/scripts/setup-ds.res.in | 6 |
8 files changed, 451 insertions, 32 deletions
diff --git a/Makefile.am b/Makefile.am index ea116701..236041a3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -200,7 +200,8 @@ perl_SCRIPTS = ldap/admin/src/scripts/SetupLog.pm \ ldap/admin/src/scripts/DSDialogs.pm \ ldap/admin/src/scripts/Setup.pm \ ldap/admin/src/scripts/Migration.pm \ - ldap/admin/src/scripts/DSMigration.pm + ldap/admin/src/scripts/DSMigration.pm \ + ldap/admin/src/scripts/FileConn.pm property_DATA = ldap/admin/src/scripts/setup-ds.res \ ldap/admin/src/scripts/migrate-ds.res diff --git a/Makefile.in b/Makefile.in index 6235d97b..abb30db3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1137,7 +1137,8 @@ perl_SCRIPTS = ldap/admin/src/scripts/SetupLog.pm \ ldap/admin/src/scripts/DSDialogs.pm \ ldap/admin/src/scripts/Setup.pm \ ldap/admin/src/scripts/Migration.pm \ - ldap/admin/src/scripts/DSMigration.pm + ldap/admin/src/scripts/DSMigration.pm \ + ldap/admin/src/scripts/FileConn.pm property_DATA = ldap/admin/src/scripts/setup-ds.res \ ldap/admin/src/scripts/migrate-ds.res diff --git a/ldap/admin/src/scripts/DSMigration.pm.in b/ldap/admin/src/scripts/DSMigration.pm.in index 86f0cb4d..0e037044 100644 --- a/ldap/admin/src/scripts/DSMigration.pm.in +++ b/ldap/admin/src/scripts/DSMigration.pm.in @@ -374,6 +374,7 @@ sub migrateDS { my $mig = shift; $pkgname = $mig->{pkgname}; # set globals $oldsroot = $mig->{oldsroot}; # set globals + my @errs; # for each instance foreach my $inst (@{$mig->{instances}}) { @@ -388,13 +389,18 @@ sub migrateDS { # extract the information needed for ds_newinst.pl my $configdir = "$oldsroot/$inst/config"; - my $inf = createInfFromConfig($configdir, $inst); + my $inf = createInfFromConfig($configdir, $inst, \@errs); debug(2, "Using inffile $inf->{filename} created from $configdir\n"); + if (@errs) { + $mig->msg(@errs); + return 0; + } # create the new instance - my ($rc, $output) = createDSInstance($inf); + my ($rc, $output) = createDSInstance($inf, \@errs); unlink($inf->{filename}); if ($rc) { + $mig->msg(@errs); $mig->msg($FATAL, 'error_creating_dsinstance', $rc, $output); return 0; } else { diff --git a/ldap/admin/src/scripts/FileConn.pm b/ldap/admin/src/scripts/FileConn.pm new file mode 100644 index 00000000..c777b156 --- /dev/null +++ b/ldap/admin/src/scripts/FileConn.pm @@ -0,0 +1,389 @@ +# BEGIN COPYRIGHT BLOCK +# This Program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; version 2 of the License. +# +# This Program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple +# Place, Suite 330, Boston, MA 02111-1307 USA. +# +# In addition, as a special exception, Red Hat, Inc. gives You the additional +# right to link the code of this Program with code not covered under the GNU +# General Public License ("Non-GPL Code") and to distribute linked combinations +# including the two, subject to the limitations in this paragraph. Non-GPL Code +# permitted under this exception must only link to the code of this Program +# through those well defined interfaces identified in the file named EXCEPTION +# found in the source code files (the "Approved Interfaces"). The files of +# Non-GPL Code may instantiate templates or use macros or inline functions from +# the Approved Interfaces without causing the resulting work to be covered by +# the GNU General Public License. Only Red Hat, Inc. may make changes or +# additions to the list of Approved Interfaces. You must obey the GNU General +# Public License in all respects for all of the Program code and other code used +# in conjunction with the Program except the Non-GPL Code covered by this +# exception. If you modify this file, you may extend this exception to your +# version of the file, but you are not obligated to do so. If you do not wish to +# provide this exception without modification, you must delete this exception +# statement from your version and license this file solely under the GPL without +# exception. +# +# +# Copyright (C) 2007 Red Hat, Inc. +# All rights reserved. +# END COPYRIGHT BLOCK +# +# FileConn is a subclass of Mozilla::LDAP::Conn. This class does +# not use LDAP. Instead, it operates on a given LDAP file, allowing +# you to search, add, modify, and delete entries in the file. +# +package FileConn; + +use Mozilla::LDAP::Conn; +use Mozilla::LDAP::API qw(:constant ldap_explode_dn ldap_err2string); # Direct access to C API +use Mozilla::LDAP::Utils qw(normalizeDN); +use Mozilla::LDAP::LDIF; + +require Exporter; +@ISA = qw(Exporter Mozilla::LDAP::Conn); +@EXPORT = qw(); +@EXPORT_OK = qw(); + +sub new { + my $class = shift; + my $filename = shift; + my $self = {}; + + $self = bless $self, $class; + + $self->read($filename); + + return $self; +} + +sub getParentDN { + my $dn = shift; + my @rdns = ldap_explode_dn($dn, 0); + shift @rdns; + return join(',', @rdns); +} + +sub read { + my $self = shift; + my $filename = shift; + + if ($filename) { + $self->{filename} = $filename; + } else { + $filename = $self->{filename}; + } + + if (!$self->{filename}) { + return; + } + + open( MYLDIF, "$filename" ) || die "Can't open $filename: $!"; + my $in = new Mozilla::LDAP::LDIF(*MYLDIF); + while ($ent = readOneEntry $in) { + if (!$self->add($ent)) { + die "Error: could not add entry ", $ent->getDN(), ":", $self->getErrorString(); + } + } + close( MYLDIF ); +} + +# return all nodes below the given node +sub iterate { + my $self = shift; + my $dn = shift; + my $scope = shift; + my $callback = shift; + my $context = shift; + my $suppress = shift; + my $ndn = normalizeDN($dn); + my $children = $self->{$ndn}->{children}; + if (($scope != LDAP_SCOPE_ONELEVEL) && $self->{$ndn}->{data} && !$suppress) { + &{$callback}($self->{$ndn}->{data}, $context); + } + + if ($scope == LDAP_SCOPE_BASE) { + return; + } + + for my $node (@{$children}) { + &{$callback}($node->{data}, $context); + } + if ($scope == LDAP_SCOPE_SUBTREE) { + for my $node (@{$children}) { + $self->iterate($node->{data}->getDN(), $scope, $callback, $context, 1); + } + } +} + +sub writecb { + my $entry = shift; + my $fh = shift; + if (! $entry->getDN()) { # rootDSE requires special hack around perldap bug + my $ary = $entry->getLDIFrecords(); + shift @$ary; # remove "dn" + shift @$ary; # remove the empty dn value + print $fh "dn:\n"; + print $fh (Mozilla::LDAP::LDIF::pack_LDIF (78, $ary), "\n"); + } else { + Mozilla::LDAP::LDIF::put_LDIF($fh, 78, $entry); + } +} + +sub write { + my $self = shift; + my $filename = shift; + + if ($filename) { + $self->{filename} = $filename; + } else { + $filename = $self->{filename}; + } + + if (!$self->{filename}) { + return; + } + + open( MYLDIF, ">$filename" ) || die "Can't write $filename: $!"; + $self->iterate("", LDAP_SCOPE_SUBTREE, \&writecb, \*MYLDIF); + close( MYLDIF ); +} + +sub setErrorCode { + my $self = shift; + $self->{lastErrorCode} = shift; +} + +sub getErrorCode { + my $self = shift; + return $self->{lastErrorCode}; +} + +sub getErrorString { + my $self = shift; + return ($self->{lastErrorCode} ? ldap_err2string($self->{lastErrorCode}) : LDAP_SUCCESS); +} + +############################################################################# +# Print the last error code... +# +sub printError +{ + my ($self, $str) = @_; + + $str = "LDAP error:" unless defined($str); + print "$str ", $self->getErrorString(), "\n"; +} + +sub close { + my $self = shift; + $self->write(); +} + +sub printcb { + my $entry = shift; + + print $entry->getDN(), "\n"; +} + +sub print { + my $self = shift; + my $dn = shift; + my $scope = shift; + $self->iterate($dn, $scope, \&printcb); +} + +# for each entry, call the user provided filter callback +# with the entry and the user provided filter context +# if the filtercb returns true, add the entry to the +# list of entries to return +sub searchcb { + my $entry = shift; + my $context = shift; + my $self = $context->[0]; + my $filtercb = $context->[1]; + my $filtercontext = $context->[2]; + if (&{$filtercb}($entry, $filtercontext)) { + push @{$self->{entries}}, $entry; + } +} + +sub matchall { + return 1; +} + +sub matchAttrVal { + my $entry = shift; + my $context = shift; + my $attr = $context->[0]; + my $val = $context->[1]; + + if ($val eq "*") { + return $entry->exists($attr); + } + return $entry->hasValue($attr, $val, 1); +} + +my $attrpat = '[-;.:\w]*[-;\w]'; + +# given a string filter, figure out which subroutine to +# use to match +sub filterToMatchSub { + my $self = shift; + my ($basedn, $scope, $filter, $attrsonly, @rest) = @_; + my ($matchsub, $context); +# do some filter processing + if (!$filter or ($filter eq "(objectclass=*)") or + ($filter eq "objectclass=*")) { + $matchsub = \&matchall; + } elsif ($filter =~ /^\(($attrpat)=(.+)\)$/o) { + push @{$context}, $1, $2; + $matchsub = \&matchAttrVal; +# } elsif ($filter =~ /^\(\|\(($attrpat)=(.+)\)\(($attrpat)=(.+)\)\)$/o) { +# $attr = $1; +# $val = $2; +# $attr1 = $1; +# $val1 = $2; +# $isand = 0; +# } elsif ($filter =~ /^\(\&\(($attrpat)=(.+)\)\(($attrpat)=(.+)\)\)$/o) { +# $attr = $1; +# $val = $2; +# $attr1 = $1; +# $val1 = $2; +# $isand = 1; +# } elsif ($filter =~ /^\(\|\(($attrpat)=(.+)\)\(($attrpat)=(.+)\)\)$/o) {) { +# # "(&(objectclass=nsBackendInstance)(|(nsslapd-suffix=$suffix)(nsslapd-suffix=$nsuffix)))"); + } + + $self->iterate($basedn, $scope, \&searchcb, [$self, $matchsub, $context]); +} + +# simple searches only +sub search { + my $self = shift; + my ($basedn, $scope, $filter, $attrsonly, @rest) = @_; + my $attrs; + if (ref($rest[0]) eq "ARRAY") { + $attrs = $rest[0]; + } elsif (scalar(@rest) > 0) { + $attrs = \@rest; + } + + $scope = Mozilla::LDAP::Utils::str2Scope($scope); + + $self->{entries} = []; + + my $ndn = normalizeDN($basedn); + if (!exists($self->{$ndn})) { + $self->setErrorCode(LDAP_NO_SUCH_OBJECT); + return undef; + } + + $self->setErrorCode(0); + if (ref($filter) eq 'CODE') { + $self->iterate($basedn, $scope, \&searchcb, [$self, $filter, $attrsonly]); + } else { + $self->filterToMatchSub($basedn, $scope, $filter, $attrsonly); + } + + return $self->nextEntry(); +} + +sub nextEntry { + my $self = shift; + return shift @{$self->{entries}}; +} + +sub add { + my $self = shift; + my $entry = shift; + my $dn = $entry->getDN(); + my $ndn = normalizeDN($dn); + my $parentdn = getParentDN($dn); + my $nparentdn = normalizeDN($parentdn); + + $self->setErrorCode(0); + if (exists($self->{$ndn})) { + $self->setErrorCode(LDAP_ALREADY_EXISTS); + return 0; + } + if ($nparentdn && !exists($self->{$nparentdn})) { + $self->setErrorCode(LDAP_NO_SUCH_OBJECT); + return 0; + } + # each hash entry has two keys + # data is the actual Entry + # children is the array ref of the one level children of this dn + $self->{$ndn}->{data} = $entry; + push @{$self->{$nparentdn}->{children}}, $self->{$ndn}; + + return 1; +} + +sub update { + my $self = shift; + my $entry = shift; + my $dn = $entry->getDN(); + my $ndn = normalizeDN($dn); + + $self->setErrorCode(0); + if (!exists($self->{$ndn})) { + $self->setErrorCode(LDAP_NO_SUCH_OBJECT); + return 0; + } + + $self->{$ndn}->{data} = $entry; + + return 1; +} + +sub delete { + my $self = shift; + my $dn = shift; + + if (ref($dn)) { + $dn = $dn->getDN(); # an Entry + } + my $ndn = normalizeDN($dn); + + $self->setErrorCode(0); + if (!exists($self->{$ndn})) { + $self->setErrorCode(LDAP_NO_SUCH_OBJECT); + return 0; + } + + if (@{$self->{$ndn}->{children}}) { + $self->setErrorCode(LDAP_NOT_ALLOWED_ON_NONLEAF); + return 0; + } + + # delete the data associated with this node + delete $self->{$ndn}->{data}; + delete $self->{$ndn}->{children}; + + my $parentdn = getParentDN($dn); + my $nparentdn = normalizeDN($parentdn); + # delete this node from its parent + for (my $ii = 0; $ii < @{$self->{$nparentdn}->{children}}; ++$ii) { + # find matching hash ref in parent's child list + if ($self->{$nparentdn}->{children}->[$ii] eq $self->{$ndn}) { + # remove that element from the array + splice @{$self->{$nparentdn}->{children}}, $ii, 1; + # done - should only ever be one matching child + last; + } + } + + # delete this node + delete $self->{$ndn}; + + return 0; +} + +1; diff --git a/ldap/admin/src/scripts/Resource.pm b/ldap/admin/src/scripts/Resource.pm index 4bc52a74..1fcd44ca 100644 --- a/ldap/admin/src/scripts/Resource.pm +++ b/ldap/admin/src/scripts/Resource.pm @@ -112,7 +112,9 @@ sub read { } } # replace \n with real newline - $self->{res}->{$curkey} =~ s/\\n/\n/g; + if (defined($curkey)) { + $self->{res}->{$curkey} =~ s/\\n/\n/g; + } close RES; } } diff --git a/ldap/admin/src/scripts/Util.pm.in b/ldap/admin/src/scripts/Util.pm.in index 008b4210..355aed73 100644 --- a/ldap/admin/src/scripts/Util.pm.in +++ b/ldap/admin/src/scripts/Util.pm.in @@ -119,8 +119,7 @@ sub delete_all $conn->delete($dn); my $rc = $conn->getErrorCode(); if ( $rc != 0 ) { - $conn->printError(); - print "ERROR: unable to delete entry $dn, error code: $rc\n"; + debug(1, "ERROR: unable to delete entry $dn, error code: $rc:" . $conn->getErrorString() . "\n"); return 1; } $dn = pop @mystack; @@ -220,7 +219,7 @@ sub comp_entries # $verbose prints out more info sub check_and_add_entry { - my ($context, $aentry) = @_; + my ($context, $aentry, $errs) = @_; my $conn = $context->[0]; my $fresh = $context->[1]; my $verbose = $context->[2]; @@ -277,6 +276,7 @@ sub check_and_add_entry $rc = delete_all($conn, $sentry); if ( 0 != $rc ) { + push @{$errs}, 'error_deleteall_entries', $sentry->{dn}, $conn->getErrorString(); debug(1, "Error deleting $sentry->{dn}\n"); return 0; } @@ -305,8 +305,8 @@ sub check_and_add_entry if ( $rc != 0 ) { my $string = $conn->getErrorString(); - print "ERROR: adding an entry $aentry->{dn} failed, error: $string\n"; - print "[entry]\n"; + push @{$errs}, 'error_adding_entry', $aentry->{dn}, $string; + debug(1, "ERROR: adding an entry $aentry->{dn} failed, error: $string\n"); $aentry->printLDIF(); $conn->close(); return 0; @@ -359,8 +359,8 @@ sub check_and_add_entry if ( $rc != 0 ) { my $string = $conn->getErrorString(); - print "ERROR: updating an entry $sentry->{dn} failed, error: $string\n"; - print "[entry]\n"; + push @{$errs}, 'error_updating_entry', $sentry->{dn}, $string; + debug(1, "ERROR: updating an entry $sentry->{dn} failed, error: $string\n"); $aentry->printLDIF(); $conn->close(); return 0; @@ -396,12 +396,14 @@ sub cbaddent { # and the values are the replacements # ldiffiles - an array ref - the list of LDIF files to # operate on +# errs - an array ref - this is filled in with the +# errors encountered in processing - this is +# suitable for passing to setup->msg or +# Resource->getText # callback (optional) - a code ref - a ref to a subroutine # that will be called with each entry - see below # context (optional) - this will be passed as the first # argument to your given callback - see below -# errs (optional) - an array ref - This is how errors -# are returned to the caller - see below # Callback: # The callback sub will be called for each entry after # the entry has been converted. The callback will be @@ -413,18 +415,20 @@ sub cbaddent { # abort processing of any further. # Errors: # This function should return an array of errors in the -# format described below, for use with Resource::getText(). -# If the callback returns any errors +# format described below, for use with Resource::getText() +# or Setup::msg() # Return: # The return value is a list of entries. # Example usage: # sub handle_entries { # my $context = shift; # my $entry = shift; +# my $errs = shift; # .... do something with entry .... # .... if $context is Mozilla::LDAP::Conn, $conn->add($entry); ... # .... report errors .... # if ($fatalerror) { +# push @{$errs}, 'error_token', arg1, arg2, ...; # return 0; # } else { # return 1; @@ -433,14 +437,16 @@ sub cbaddent { # $mapper = {foo => 'bar', baz => 'biff'}; # @ldiffiles = ('foo.ldif', 'bar.ldif', ..., 'biff.ldif'); # $conn = new Mozilla::LDAP::Conn(...); -# @entries = getMappedEntries($mapper, \@ldiffiles, \&handle_entries, $conn); +# my @errs; +# @entries = getMappedEntries($mapper, \@ldiffiles, \@errs, \&handle_entries, $conn); # Note that this will return 0 entries since a callback was used. # The simpler example is this: -# @entries = getMappedEntries($mapper, \@ldiffiles); +# @entries = getMappedEntries($mapper, \@ldiffiles, \@errs); # sub getMappedEntries { my $mapper = shift; my $ldiffiles = shift; + my $errs = shift; my $callback = shift || \&cbaddent; # default - just add entry to @entries my @entries = (); my $context = shift || \@entries; @@ -451,7 +457,10 @@ sub getMappedEntries { } foreach my $ldiffile (@{$ldiffiles}) { - open(MYLDIF, "< $ldiffile") or die "Can't open $ldiffile : $!"; + if (!open(MYLDIF, "< $ldiffile")) { + push @{$errs}, "error_opening_ldiftmpl", $ldiffile, $!; + return 0; + } my $in = new Mozilla::LDAP::LDIF(*MYLDIF); debug(1, "Processing $ldiffile ...\n"); ENTRY: while (my $entry = Mozilla::LDAP::LDIF::readOneEntry($in)) { @@ -462,9 +471,7 @@ sub getMappedEntries { if (exists($mapper->{$1})) { $dn =~ s{%([\w_-]+)%}{$mapper->{$1}}ge; } else { - print "ERROR: \"$origdn\" mapped to \"$dn\".\n"; - print "The LDIF file $ldiffile contains a token $1 for which there is no mapper.\n"; - print "Please check $ldiffile and your mapper to make sure all tokens are handled correctly.\n"; + push @{$errs}, 'error_mapping_token_ldiftmpl', $dn, $ldiffile, $1; $error = 1; last ENTRY; } @@ -480,9 +487,8 @@ sub getMappedEntries { if (exists($mapper->{$1})) { $value =~ s{%([\w_-]+)%}{$mapper->{$1}}ge; } else { - print "ERROR: \"$origvalue\" mapped to \"$value\".\n"; - print "The LDIF file $ldiffile contains a token $1 for which there is no mapper.\n"; - print "Please check $ldiffile and your mapper to make sure all tokens are handled correctly.\n"; + push @{$errs}, 'error_mapping_token_ldiftmpl', $dn, $ldiffile, $1; + debug(1, "ERROR: \"$origvalue\" mapped to \"$value\".\n"); $error = 1; last ENTRY; } @@ -492,9 +498,9 @@ sub getMappedEntries { $entry->setValues( $attr, @newvalues ); } - if (!&{$callback}($context, $entry)) { - print "There was an error processing entry ", $entry->getDN(), "\n"; - print "Cannot continue processing entries.\n"; + if (!&{$callback}($context, $entry, $errs)) { + debug(1, "ERROR: There was an error processing entry ". $entry->getDN(). "\n"); + debug(1, "Cannot continue processing entries.\n"); $error = 1; last ENTRY; } @@ -640,7 +646,7 @@ sub addSuffix { # The %token% tokens are replaced in getMappedEntries sub process_maptbl { - my ($mapper, @infdata) = @_; + my ($mapper, $errs, @infdata) = @_; if (defined($mapper->{""})) { $mapper = $mapper->{""}; # side effect of Inf with no sections @@ -680,7 +686,7 @@ sub process_maptbl } if (!defined($infsection->{$value})) { - print "ERROR: $value not found in the .inf files\n"; + push @{$errs}, 'no_mapvalue_for_key', $value, $key; return {}; } } @@ -709,6 +715,7 @@ sub getHashedPassword { sub createDSInstance { my $inf = shift; + my $errs = shift; # unused for now # find ds_newinst.pl - in same directory as this script or in PATH my $ds_newinst; ($ds_newinst = $0) =~ s|/[^/]+$|/ds_newinst.pl|; @@ -724,13 +731,18 @@ sub createDSInstance { } # this creates an Inf suitable for passing to createDSInstance +# except that it has a bogus suffix sub createInfFromConfig { my $configdir = shift; my $inst = shift; + my $errs = shift; my $fname = "$configdir/dse.ldif"; my $id; ($id = $inst) =~ s/^slapd-//; - open( DSELDIF, "$fname" ) || die "Can't open $fname: $!"; + if (!open( DSELDIF, "$fname" )) { + push @{$errs}, "error_opening_dseldif", $fname, $!; + return 0; + } my ($outfh, $inffile) = tempfile(SUFFIX => '.inf'); my $in = new Mozilla::LDAP::LDIF(*DSELDIF) ; while (my $ent = readOneEntry $in) { diff --git a/ldap/admin/src/scripts/setup-ds.pl.in b/ldap/admin/src/scripts/setup-ds.pl.in index 0117bdef..f52cd169 100644 --- a/ldap/admin/src/scripts/setup-ds.pl.in +++ b/ldap/admin/src/scripts/setup-ds.pl.in @@ -69,8 +69,10 @@ if (!$setup->{silent}) { $setup->{inf}->write(); } -my ($rc, $output) = createDSInstance($setup->{inf}); +my @errs; +my ($rc, $output) = createDSInstance($setup->{inf}, \@errs); if ($rc) { + $setup->msg(@errs); $setup->msg($FATAL, 'error_creating_dsinstance', $rc, $output); } else { $setup->msg('created_dsinstance', $output); diff --git a/ldap/admin/src/scripts/setup-ds.res.in b/ldap/admin/src/scripts/setup-ds.res.in index 3c6b6fa8..4b8982e1 100644 --- a/ldap/admin/src/scripts/setup-ds.res.in +++ b/ldap/admin/src/scripts/setup-ds.res.in @@ -89,3 +89,9 @@ error_creating_suffix = Could not create the suffix '%s'. Error: %s\n\n setup_exiting = Exiting . . .\nLog file is '%s'\n\n error_creating_dsinstance = Error: Could not create directory server instance. Error code %s. Output:\n%s\n created_dsinstance = Your new DS instance was successfully created. Output:\n%s\n +no_mapvalue_for_key = The map value '%s' for key '%s' did not map to a value in any of the given information files.\n +error_opening_ldiftmpl = Could not open the LDIF template file '%s'. Error: %s\n +error_mapping_token_ldiftmpl = The entry '%s' in LDIF file '%s' contains a token '%s' for which there is no mapper.\nPlease check the file and your mapper to make sure all tokens are handled correctly.\n +error_deleteall_entries = Error deleting entry '%s' and all children. Error: %s\n +error_adding_entry = Error adding entry '%s'. Error: %s\n +error_updating_entry = Error updating entry '%s'. Error: %s\n |