[Date Prev][Date Next] [Chronological] [Thread] [Top]

Re: modrdn:->TRY THIS! & pls send feedback



Don Badrak wrote:

> All,
>
> Ok, I tried the modrdn patch Juan Gomeze submitted against 1.2.1.
> Everything compiled fine, and it passed the modrdn tests.
>
> When I tried to modify a entry, I get this error:
>
> ldap_modrdn2_s: Type or value exists
>
> Here's the entry I was modifying.
>
>         dn: cn=C H Monk Jr,ou=People,o=U.S. Census Bureau,c=US
>         sn: Monk
>         cn: C Harvey Monk Jr
>         givenname: C
>         initials: Harvey
>         generationqualifier: Jr
>         telephonenumber: +1 301 457 2255
>         flastname: cmonk
>         ccmailpostoffice: FTD1
>         department: FTD
>         physicaldeliveryofficename: 3-2104
>         mail: C.Harvey.Monk.Jr@ccMail.Census.GOV
>         mailacceptinggeneralid: charveymonkjr
>         maildrop: C.Harvey.Monk.Jr@ccMail.Census.GOV
>         objectclass: top
>         objectclass: person
>
> And the modification I was trying to make (this is the file ldapmodrdn.19990519.1):
>
>         cn=C H Monk Jr,ou=People,o=U.S. Census Bureau,c=US
>         cn=C Harvey Monk Jr
>
> It did the same thing both with and without the -r flag.  Here is the output
> from the ldapmodrn -d 15:
>
> % ldapmodrdn -v -d 15 -D "cn=Manager,o=U.S. Census Bureau,c=US" -w xxxxxx -f ldapmodrdn.19990519.1
>
> ldap_init
> ldap_bind_s
> ldap_simple_bind_s
> ldap_simple_bind
> ldap_send_initial_request
> open_ldap_connection
> ldap_connect_to_host: ldap-master.geo.census.gov:389
> sd 4 connected to: 148.129.238.22
> ldap_delayed_open successful, ld_host is (null)
> ldap_send_server_request
> ber_flush: 56 bytes to sd 4
>          0  6 02 01 01  `  1 02 01 02 04  $  c  n  =  M
>          a  n  a  g  e  r  ,  o  =  U  .  S  . 20  C  e
>          n  s  u  s 20  B  u  r  e  a  u  ,  c  =  U  S
>         80 06  x  x  x  x  x  x
> ldap_result
> wait4msg (infinite timeout)
> ** Connections:
> * host: ldap-master.geo.census.gov  port: 389  (default)
>   refcnt: 2  status: Connected
>   last used: Wed May 19 16:49:01 1999
>
> ** Outstanding Requests:
>  * msgid 1,  origid 1, status InProgress
>    outstanding referrals 0, parent count 0
> ** Response Queue:
>    Empty
> do_ldap_select
> read1msg
> ber_get_next
> ber_get_next: tag 0x30 len 12 contents:
> ber_dump: buf 0x1003e8a8, ptr 0x1003e8a8, end 0x1003e8b4
>           current len 12, contents:
>         02 01 01  a 07 0a 01 00 04 00 04 00
> got result msgid 1, original id 1
> new result:  res_errno: 0, res_error: <>, res_matched: <>
> read1msg:  0 new referrals
> request 1 done
> res_errno: 0, res_error: <>, res_matched: <>
> ldap_free_request (origid 1, msgid 1)
> ldap_free_connection
> ldap_free_connection: refcnt 1
> ldap_result2error
> ldap_msgfree
> modrdn cn=C H Monk Jr,ou=People,o=U.S. Census Bureau,c=US:
>         cn=C Harvey Monk Jr
> keeping old RDN
> ldap_modrdn
> ldap_send_initial_request
> ldap_send_server_request
> ber_flush: 83 bytes to sd 4
>          0  Q 02 01 02  l  L 04  2  c  n  =  C 20  H 20
>          M  o  n  k 20  J  r  ,  o  u  =  P  e  o  p  l
>          e  ,  o  =  U  .  S  . 20  C  e  n  s  u  s 20
>          B  u  r  e  a  u  ,  c  =  U  S 04 13  c  n  =
>          C 20  H  a  r  v  e  y 20  M  o  n  k 20  J  r
>         01 01 00
> ldap_result
> wait4msg (infinite timeout)
> ** Connections:
> * host: ldap-master.geo.census.gov  port: 389  (default)
>   refcnt: 2  status: Connected
>   last used: Wed May 19 16:49:01 1999
>
> ** Outstanding Requests:
>  * msgid 2,  origid 2, status InProgress
>    outstanding referrals 0, parent count 0
> ** Response Queue:
>    Empty
> do_ldap_select
> read1msg
> ber_get_next
> ber_get_next: tag 0x30 len 12 contents:
> ber_dump: buf 0x1003e8a8, ptr 0x1003e8a8, end 0x1003e8b4
>           current len 12, contents:
>         02 01 02  m 07 0a 01 14 04 00 04 00
> got result msgid 2, original id 2
> ldap_chase_referrals
> new result:  res_errno: 20, res_error: <>, res_matched: <>
> read1msg:  0 new referrals
> request 2 done
> res_errno: 20, res_error: <>, res_matched: <>
> ldap_free_request (origid 2, msgid 2)
> ldap_free_connection
> ldap_free_connection: refcnt 1
> ldap_result2error
> ldap_msgfree
> ldap_perror
> ldap_modrdn2_s: Type or value exists
> ldap_unbind
> ldap_free_connection
> ldap_send_unbind
> ber_flush: 7 bytes to sd 4
>          0 05 02 01 03  B 00
> ldap_free_connection: actually freed
>
> --
> This is the same way I was doing it in prior versions of OpenLDAP, which
> had modrdn working correctly.
>
> Any ideas?
>
> Don
> --
> Don Badrak <dbadrak@census.gov>              301.457.8263 work
> Telecommunications Office                    301.457.4438 fax
> U.S. Bureau of the Census
> Suitland MD, USA


diff -rc ldap_old/include/ldap.h ldap/include/ldap.h
*** ldap_old/include/ldap.h	Sat Jan 23 13:05:03 1999
--- ldap/include/ldap.h	Fri May 21 09:45:51 1999
***************
*** 214,219 ****
--- 214,220 ----
  #define LDAP_MOD_ADD		0x00
  #define LDAP_MOD_DELETE		0x01
  #define LDAP_MOD_REPLACE	0x02
+ #define LDAP_MOD_SOFTADD	0x04	/* Just make sure value is there */
  #define LDAP_MOD_BVALUES	0x80
  	char		*mod_type;
  	union {
diff -rc ldap_old/servers/slapd/back-ldbm/modify.c ldap/servers/slapd/back-ldbm/modify.c
*** ldap_old/servers/slapd/back-ldbm/modify.c	Thu Jan 28 21:11:50 1999
--- ldap/servers/slapd/back-ldbm/modify.c	Fri May 21 09:48:37 1999
***************
*** 14,56 ****
  static int	add_values(Entry *e, LDAPMod *mod, char *dn);
  static int	delete_values(Entry *e, LDAPMod *mod, char *dn);
  static int	replace_values(Entry *e, LDAPMod *mod, char *dn);
  
! int
! ldbm_back_modify(
      Backend	*be,
      Connection	*conn,
      Operation	*op,
      char	*dn,
!     LDAPMod	*mods
  )
  {
- 	struct ldbminfo	*li = (struct ldbminfo *) be->be_private;
- 	char		*matched;
- 	Entry		*e;
  	int		i, err;
  	LDAPMod		*mod;
  
! 	Debug(LDAP_DEBUG_ARGS, "ldbm_back_modify:\n", 0, 0, 0);
  
- 	/* acquire and lock entry */
- 	if ( (e = dn2entry_w( be, dn, &matched )) == NULL ) {
- 		send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched,
- 		    NULL );
- 		if ( matched != NULL ) {
- 			free( matched );
- 		}
- 		return( -1 );
  	}
  
  	if ( (err = acl_check_mods( be, conn, op, e, mods )) != LDAP_SUCCESS ) {
  		send_ldap_result( conn, op, err, NULL, NULL );
! 		goto error_return;
  	}
  
  	for ( mod = mods; mod != NULL; mod = mod->mod_next ) {
  		switch ( mod->mod_op & ~LDAP_MOD_BVALUES ) {
  		case LDAP_MOD_ADD:
  			err = add_values( e, mod, op->o_ndn );
  			break;
  
  		case LDAP_MOD_DELETE:
--- 14,138 ----
  static int	add_values(Entry *e, LDAPMod *mod, char *dn);
  static int	delete_values(Entry *e, LDAPMod *mod, char *dn);
  static int	replace_values(Entry *e, LDAPMod *mod, char *dn);
+ static void	add_lastmods(Operation *op, LDAPMod **mods);
  
! 
! static void
! add_lastmods( Operation *op, LDAPMod **mods )
! {
! 	char		buf[22];
! 	struct berval	bv;
! 	struct berval	*bvals[2];
! 	LDAPMod		**m;
! 	LDAPMod		*tmp;
! 	struct tm	*ltm;
! 
! 	Debug( LDAP_DEBUG_TRACE, "add_lastmods\n", 0, 0, 0 );
! 
! 	bvals[0] = &bv;
! 	bvals[1] = NULL;
! 
! 	/* remove any attempts by the user to modify these attrs */
! 	for ( m = mods; *m != NULL; m = &(*m)->mod_next ) {
!             if ( strcasecmp( (*m)->mod_type, "modifytimestamp" ) == 0 || 
! 				strcasecmp( (*m)->mod_type, "modifiersname" ) == 0 ||
! 				strcasecmp( (*m)->mod_type, "createtimestamp" ) == 0 || 
! 				strcasecmp( (*m)->mod_type, "creatorsname" ) == 0 ) {
! 
!                 Debug( LDAP_DEBUG_TRACE,
! 					"add_lastmods: found lastmod attr: %s\n",
! 					(*m)->mod_type, 0, 0 );
!                 tmp = *m;
!                 *m = (*m)->mod_next;
!                 free( tmp->mod_type );
!                 if ( tmp->mod_bvalues != NULL ) {
!                     ber_bvecfree( tmp->mod_bvalues );
!                 }
!                 free( tmp );
!                 if (!*m)
!                     break;
!             }
!         }
! 
! 	if ( op->o_dn == NULL || op->o_dn[0] == '\0' ) {
! 		bv.bv_val = "NULLDN";
! 		bv.bv_len = strlen( bv.bv_val );
! 	} else {
! 		bv.bv_val = op->o_dn;
! 		bv.bv_len = strlen( bv.bv_val );
! 	}
! 	tmp = (LDAPMod *) ch_calloc( 1, sizeof(LDAPMod) );
! 	tmp->mod_type = ch_strdup( "modifiersname" );
! 	tmp->mod_op = LDAP_MOD_REPLACE;
! 	tmp->mod_bvalues = (struct berval **) ch_calloc( 1,
! 	    2 * sizeof(struct berval *) );
! 	tmp->mod_bvalues[0] = ber_bvdup( &bv );
! 	tmp->mod_next = *mods;
! 	*mods = tmp;
! 
! 	ldap_pvt_thread_mutex_lock( &currenttime_mutex );
! #ifndef LDAP_LOCALTIME
! 	ltm = gmtime( &currenttime );
! 	strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", ltm );
! #else
! 	ltm = localtime( &currenttime );
! 	strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm );
! #endif
! 	ldap_pvt_thread_mutex_unlock( &currenttime_mutex );
! 	bv.bv_val = buf;
! 	bv.bv_len = strlen( bv.bv_val );
! 	tmp = (LDAPMod *) ch_calloc( 1, sizeof(LDAPMod) );
! 	tmp->mod_type = ch_strdup( "modifytimestamp" );
! 	tmp->mod_op = LDAP_MOD_REPLACE;
! 	tmp->mod_bvalues = (struct berval **) ch_calloc( 1, 2 * sizeof(struct berval *) );
! 	tmp->mod_bvalues[0] = ber_bvdup( &bv );
! 	tmp->mod_next = *mods;
! 	*mods = tmp;
! }
! 
! /* We need this function because of LDAP modrdn. If we do not 
!  * add this there would be a bunch of code replication here 
!  * and there and of course the likelihood of bugs increases.
!  * Juan C. Gomez (gomez@engr.sgi.com) 05/18/99
!  */ 
! 
! int ldbm_internal_modify(
      Backend	*be,
      Connection	*conn,
      Operation	*op,
      char	*dn,
!     LDAPMod	*mods,
!     Entry	*e 
  )
  {
  	int		i, err;
  	LDAPMod		*mod;
  
! 	if ( ((be->be_lastmod == ON)
! 	      || ((be->be_lastmod == UNDEFINED)&&(global_lastmod == ON)))
! 	     && (be->be_update_ndn == NULL)) {
! 
! 	        /* XXX: It may be wrong, it changes mod time even if 
! 		 * mod fails!
! 		 */
! 		add_lastmods( op, &mods );
  
  	}
  
  	if ( (err = acl_check_mods( be, conn, op, e, mods )) != LDAP_SUCCESS ) {
  		send_ldap_result( conn, op, err, NULL, NULL );
! 		return -1;
  	}
  
  	for ( mod = mods; mod != NULL; mod = mod->mod_next ) {
  		switch ( mod->mod_op & ~LDAP_MOD_BVALUES ) {
+ 		case LDAP_MOD_SOFTADD:
  		case LDAP_MOD_ADD:
  			err = add_values( e, mod, op->o_ndn );
+ 			if ( (mod->mod_op & LDAP_MOD_SOFTADD)
+ 			     && (err ==  LDAP_TYPE_OR_VALUE_EXISTS)) {
+ 			    err = LDAP_SUCCESS;
+ 			}
  			break;
  
  		case LDAP_MOD_DELETE:
***************
*** 65,71 ****
  		if ( err != LDAP_SUCCESS ) {
  			/* unlock entry, delete from cache */
  			send_ldap_result( conn, op, err, NULL, NULL );
! 			goto error_return;
  		}
  	}
  
--- 147,153 ----
  		if ( err != LDAP_SUCCESS ) {
  			/* unlock entry, delete from cache */
  			send_ldap_result( conn, op, err, NULL, NULL );
! 			return -1;
  		}
  	}
  
***************
*** 73,79 ****
  	if ( global_schemacheck && oc_schema_check( e ) != 0 ) {
  		Debug( LDAP_DEBUG_ANY, "entry failed schema check\n", 0, 0, 0 );
  		send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, NULL, NULL );
! 		goto error_return;
  	}
  
  	/* check for abandon */
--- 155,161 ----
  	if ( global_schemacheck && oc_schema_check( e ) != 0 ) {
  		Debug( LDAP_DEBUG_ANY, "entry failed schema check\n", 0, 0, 0 );
  		send_ldap_result( conn, op, LDAP_OBJECT_CLASS_VIOLATION, NULL, NULL );
! 		return -1;
  	}
  
  	/* check for abandon */
***************
*** 80,86 ****
  	ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
  	if ( op->o_abandon ) {
  		ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
! 		goto error_return;
  	}
  	ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
  
--- 162,168 ----
  	ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
  	if ( op->o_abandon ) {
  		ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
! 		return -1;
  	}
  	ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
  
***************
*** 87,93 ****
  	/* modify indexes */
  	if ( index_add_mods( be, mods, e->e_id ) != 0 ) {
  		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
! 		goto error_return;
  	}
  
  	/* check for abandon */
--- 169,175 ----
  	/* modify indexes */
  	if ( index_add_mods( be, mods, e->e_id ) != 0 ) {
  		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
! 		return -1;
  	}
  
  	/* check for abandon */
***************
*** 94,107 ****
  	ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
  	if ( op->o_abandon ) {
  		ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
! 		goto error_return;
  	}
  	ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
  
  	/* change the entry itself */
  	if ( id2entry_add( be, e ) != 0 ) {
  		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
! 		goto error_return;
  	}
  
  	send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
--- 176,227 ----
  	ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
  	if ( op->o_abandon ) {
  		ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
! 		return -1;
  	}
  	ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
  
+ 	return 0;
+ 
+ }/* int ldbm_internal_modify() */
+ 
+ 
+ int
+ ldbm_back_modify(
+     Backend	*be,
+     Connection	*conn,
+     Operation	*op,
+     char	*dn,
+     LDAPMod	*mods
+ )
+ {
+ 	struct ldbminfo	*li = (struct ldbminfo *) be->be_private;
+ 	char		*matched;
+ 	Entry		*e;
+ 
+ 	Debug(LDAP_DEBUG_ARGS, "ldbm_back_modify:\n", 0, 0, 0);
+ 
+ 	/* acquire and lock entry */
+ 	if ( (e = dn2entry_w( be, dn, &matched )) == NULL ) {
+ 		send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched,
+ 		    NULL );
+ 		if ( matched != NULL ) {
+ 			free( matched );
+ 		}
+ 		return( -1 );
+ 	}
+ 
+ 	/* Modify the entry */
+ 	if ( ldbm_internal_modify( be, conn, op, dn, mods, e ) != 0 ) {
+ 
+ 		goto error_return;
+ 
+ 	}
+ 
  	/* change the entry itself */
  	if ( id2entry_add( be, e ) != 0 ) {
+ 		entry_free( e );
  		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
! 		return -1;
  	}
  
  	send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
diff -rc ldap_old/servers/slapd/back-ldbm/modrdn.c ldap/servers/slapd/back-ldbm/modrdn.c
*** ldap_old/servers/slapd/back-ldbm/modrdn.c	Thu Feb 11 12:29:34 1999
--- ldap/servers/slapd/back-ldbm/modrdn.c	Fri May 21 09:49:07 1999
***************
*** 27,35 ****
  	char		*new_dn = NULL, *new_ndn = NULL;
  	char		sep[2];
  	Entry		*e, *p = NULL;
! 	int			rootlock = 0;
! 	int			rc = -1;
  
  	/* get entry with writer lock */
  	if ( (e = dn2entry_w( be, dn, &matched )) == NULL ) {
  		send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" );
--- 27,50 ----
  	char		*new_dn = NULL, *new_ndn = NULL;
  	char		sep[2];
  	Entry		*e, *p = NULL;
! 	int		rootlock = 0;
! 	int		rc = -1;
  
+ 	char		*new_rdn_val = NULL;	/* Val of new rdn */
+ 	char		*new_rdn_type = NULL;	/* Type of new rdn */
+ 	char		*old_rdn;		/* Old rdn's attr type & val */
+ 	char		*old_rdn_type = NULL;	/* Type of old rdn attr. */
+ 	char		*old_rdn_val = NULL;	/* Old rdn attribute value */
+ 	struct berval	add_bv;			/* Stores new rdn att */
+ 	struct berval	*add_bvals[2];		/* Stores new rdn att */
+ 	struct berval	del_bv;			/* Stores old rdn att */
+ 	struct berval	*del_bvals[2];		/* Stores old rdn att */
+ 	LDAPMod		mod[2];			/* Used to delete old rdn */
+ 
+ 	Debug( LDAP_DEBUG_TRACE,
+ 	       "ldbm_back_modrdn:()==>\n",
+ 	       0, 0, 0 );
+ 
  	/* get entry with writer lock */
  	if ( (e = dn2entry_w( be, dn, &matched )) == NULL ) {
  		send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" );
***************
*** 76,102 ****
  #endif
  
  		p_dn = dn_parent( be, e->e_dn );
- 		new_dn = (char *) ch_malloc( strlen( p_dn ) + strlen( newrdn )
- 		    + 3 );
- 		if ( dn_type( e->e_dn ) == DN_X500 ) {
- 			strcpy( new_dn, newrdn );
- 			strcat( new_dn, "," );
- 			strcat( new_dn, p_dn );
- 		} else {
- 			char *s;
- 			strcpy( new_dn, newrdn );
- 			s = strchr( newrdn, '\0' );
- 			s--;
- 			if ( *s != '.' && *s != '@' ) {
- 				if ( (s = strpbrk( dn, ".@" )) != NULL ) {
- 					sep[0] = *s;
- 					sep[1] = '\0';
- 					strcat( new_dn, sep );
- 				}
- 			}
- 			strcat( new_dn, p_dn );
- 		}
  
  	} else {
  		/* no parent, modrdn entry directly under root */
  		if( ! be_isroot( be, op->o_ndn ) ) {
--- 91,98 ----
  #endif
  
  		p_dn = dn_parent( be, e->e_dn );
  
+ 
  	} else {
  		/* no parent, modrdn entry directly under root */
  		if( ! be_isroot( be, op->o_ndn ) ) {
***************
*** 110,120 ****
  		ldap_pvt_thread_mutex_lock(&li->li_root_mutex);
  		rootlock = 1;
  
! 		new_dn = ch_strdup( newrdn );
  	}
  
  	new_ndn = dn_normalize_case( ch_strdup( new_dn ) );
  
  	if ( (dn2id ( be, new_ndn ) ) != NOID ) {
  		send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, NULL, NULL );
  		goto return_results;
--- 106,259 ----
  		ldap_pvt_thread_mutex_lock(&li->li_root_mutex);
  		rootlock = 1;
  
! 
  	}
  
+ 	build_new_dn( &new_dn, e->e_dn, p_dn, newrdn ); 
  	new_ndn = dn_normalize_case( ch_strdup( new_dn ) );
  
+ 	/* Get attribute type and attribute value of our new rdn, we will
+ 	 * need to add that to our new entry
+ 	 */
+ 
+ 	if ( (new_rdn_type = rdn_attr_type( newrdn )) == NULL ) {
+ 	    
+ 		Debug( LDAP_DEBUG_TRACE,
+ 		       "ldbm_back_modrdn: can't figure out type of newrdn\n",
+ 		       0, 0, 0 );
+ 		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+ 		goto return_results;		
+ 
+ 	}
+ 
+ 	if ( (new_rdn_val = rdn_attr_value( newrdn )) == NULL ) {
+ 	    
+ 		Debug( LDAP_DEBUG_TRACE,
+ 		       "ldbm_back_modrdn: can't figure out val of newrdn\n",
+ 		       0, 0, 0 );
+ 		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+ 		goto return_results;		
+ 
+ 	}
+ 
+ 	Debug( LDAP_DEBUG_TRACE,
+ 	       "ldbm_back_modrdn: new_rdn_val=\"%s\", new_rdn_type=\"%s\"\n",
+ 	       new_rdn_val, new_rdn_type, 0 );
+ 
+ 	/* Retrieve the old rdn from the entry's dn */
+ 
+ 	if ( (old_rdn = dn_rdn( be, dn )) == NULL ) {
+ 
+ 		Debug( LDAP_DEBUG_TRACE,
+ 		       "ldbm_back_modrdn: can't figure out old_rdn from dn\n",
+ 		       0, 0, 0 );
+ 		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+ 		goto return_results;		
+ 
+ 	}
+ 
+ 	if ( (old_rdn_type = rdn_attr_type( old_rdn )) == NULL ) {
+ 	    
+ 		Debug( LDAP_DEBUG_TRACE,
+ 		       "ldbm_back_modrdn: can't figure out the old_rdn type\n",
+ 		       0, 0, 0 );
+ 		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
+ 		goto return_results;		
+ 		
+ 	}
+ 	
+ 	if ( strcasecmp( old_rdn_type, new_rdn_type ) != 0 ) {
+ 
+ 	    /* Not a big deal but we may say something */
+ 	    Debug( LDAP_DEBUG_TRACE,
+ 		   "ldbm_back_modrdn: old_rdn_type=%s, new_rdn_type=%s!\n",
+ 		   old_rdn_type, new_rdn_type, 0 );
+ 	    
+ 	}		
+ 
+ 	if ( dn_type( old_rdn ) == DN_X500 ) {
+ 
+ 		Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: DN_X500\n",
+ 		       0, 0, 0 );
+ 		
+ 		/* Add new attribute value to the entry.
+ 		 */
+ 
+ 		add_bvals[0] = &add_bv;		/* Array of bervals */
+ 		add_bvals[1] = NULL;
+ 
+ 		add_bv.bv_val = new_rdn_val;
+ 		add_bv.bv_len = strlen(new_rdn_val);
+ 		
+ 		mod[0].mod_type = old_rdn_type;	
+ 		mod[0].mod_bvalues = add_bvals;
+ 		mod[0].mod_op = LDAP_MOD_SOFTADD;
+ 		mod[0].mod_next = NULL;
+ 		
+ 		Debug( LDAP_DEBUG_TRACE,
+ 		       "ldbm_back_modrdn: adding new rdn attr val =\"%s\"\n",
+ 		       new_rdn_val, 0, 0 );
+ 
+ 		/* Remove old rdn value if required */
+ 
+ 		if (deleteoldrdn) {
+ 
+ 			del_bvals[0] = &del_bv;		/* Array of bervals */
+ 			del_bvals[1] = NULL;
+ 			/* Get value of old rdn */
+ 	
+ 			if ((old_rdn_val = rdn_attr_value( old_rdn ))
+ 			    == NULL) {
+ 			    
+ 				Debug( LDAP_DEBUG_TRACE,
+ 				       "ldbm_back_modrdn: can't figure out old_rdn_val from old_rdn\n",
+ 				       0, 0, 0 );
+ 				send_ldap_result( conn, op,
+ 						  LDAP_OPERATIONS_ERROR,
+ 						  "", "" );
+ 				goto return_results;		
+ 
+ 
+ 			}
+ 
+ 			/* Remove old value of rdn as an attribute. */
+ 		    
+ 			del_bv.bv_val = old_rdn_val;
+ 			del_bv.bv_len = strlen(old_rdn_val);
+ 
+ 			/* No need to normalize old_rdn_type, delete_values()
+ 			 * does that for us
+ 			 */
+ 			mod[0].mod_next = &mod[1];
+ 			mod[1].mod_type = old_rdn_type;	
+ 			mod[1].mod_bvalues = del_bvals;
+ 			mod[1].mod_op = LDAP_MOD_DELETE;
+ 			mod[1].mod_next = NULL;
+ 
+ 		}/* if (deleteoldrdn) */
+ 
+ 		/* modify memory copy of entry */
+ 		if ( ldbm_internal_modify( be, conn, op, dn, &mod[0], e )
+ 		     != 0 ) {
+ 		    
+ 			goto return_results;
+ 			
+ 		}
+ 	
+ 	} else {
+ 	    
+ 
+ 		Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: DNS DN\n",
+ 		       0, 0, 0 );
+ 		/* XXXV3: not sure of what to do here */
+ 		Debug( LDAP_DEBUG_TRACE,
+ 		       "ldbm_back_modrdn: not fully implemented...\n",
+ 		       0, 0, 0 );  
+ 		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
+ 		goto return_results;
+ 
+ 	}
+ 
  	if ( (dn2id ( be, new_ndn ) ) != NOID ) {
  		send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, NULL, NULL );
  		goto return_results;
***************
*** 140,145 ****
--- 279,285 ----
  		goto return_results;
  	}
  
+ 
  	(void) cache_delete_entry( &li->li_cache, e );
  	free( e->e_dn );
  	free( e->e_ndn );
***************
*** 147,178 ****
  	e->e_ndn = new_ndn;
  	(void) cache_update_entry( &li->li_cache, e );
  
! 	/* XXX
! 	 * At some point here we need to update the attribute values in
! 	 * the entry itself that were effected by this RDN change
! 	 * (respecting the value of the deleteoldrdn parameter).
! 	 *
! 	 * Since the code to do this has not yet been written, treat this
! 	 * omission as a (documented) bug.
! 	 */
! 
! 	/* id2entry index */
  	if ( id2entry_add( be, e ) != 0 ) {
  		entry_free( e );
  		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
! 		goto return_results;
  	}
  
  	send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
  	rc = 0;
  
! return_results:
  	if( new_dn != NULL ) free( new_dn );
  	if( new_ndn != NULL ) free( new_ndn );
  	if( p_dn != NULL ) free( p_dn );
  	if( p_ndn != NULL ) free( p_ndn );
  
  	if( matched != NULL ) free( matched );
  
  	if( p != NULL ) {
  		/* free parent and writer lock */
--- 287,326 ----
  	e->e_ndn = new_ndn;
  	(void) cache_update_entry( &li->li_cache, e );
  
! 	/* id2entry index: commit */
  	if ( id2entry_add( be, e ) != 0 ) {
  		entry_free( e );
  		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
! 		goto return_results_new;
  	}
  
  	send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
  	rc = 0;
  
! 	Debug( LDAP_DEBUG_TRACE,
! 	       "ldbm_back_modrdn:()<==\n",
! 	       0, 0, 0 );
! 	goto return_results_new;
! 
! return_results:	
  	if( new_dn != NULL ) free( new_dn );
  	if( new_ndn != NULL ) free( new_ndn );
+ return_results_new:
+ 	/* NOTE:
+ 	 * new_dn and new_ndn are not deallocated because they are used by
+ 	 * the cache entry at this point.
+ 	 */
  	if( p_dn != NULL ) free( p_dn );
  	if( p_ndn != NULL ) free( p_ndn );
  
  	if( matched != NULL ) free( matched );
+ 
+ 	/* LDAP v2 supporting correct attribute handling. */
+ 	if( new_rdn_type != NULL ) free(new_rdn_type);
+ 	if( new_rdn_val != NULL ) free(new_rdn_val);
+ 	if( old_rdn != NULL ) free(old_rdn);
+ 	if( old_rdn_type != NULL ) free(old_rdn_type);
+ 	if( old_rdn_val != NULL ) free(old_rdn_val);
  
  	if( p != NULL ) {
  		/* free parent and writer lock */
diff -rc ldap_old/servers/slapd/back-ldbm/proto-back-ldbm.h ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
*** ldap_old/servers/slapd/back-ldbm/proto-back-ldbm.h	Wed Feb 10 11:36:53 1999
--- ldap/servers/slapd/back-ldbm/proto-back-ldbm.h	Tue May 18 11:07:55 1999
***************
*** 123,128 ****
--- 123,140 ----
  #endif
  
  /*
+  * modify.c
+  */
+ 
+ /* We need this function because of LDAP modrdn. If we do not 
+  * add this there would be a bunch of code replication here 
+  * and there and of course the likelihood of bugs increases.
+  * Juan C. Gomez (gomez@engr.sgi.com) 05/18/99
+  */ 
+ int ldbm_internal_modify LDAP_P((Backend *be, Connection *conn, Operation *op,
+ 			         char *dn, LDAPMod *mods, Entry *e));
+ 
+ /*
   * nextid.c
   */
  
diff -rc ldap_old/servers/slapd/dn.c ldap/servers/slapd/dn.c
*** ldap_old/servers/slapd/dn.c	Tue Mar  2 10:30:05 1999
--- ldap/servers/slapd/dn.c	Tue May 18 12:30:07 1999
***************
*** 220,225 ****
--- 220,296 ----
  	return( ch_strdup( "" ) );
  }
  
+ char * dn_rdn( 
+     Backend	*be,
+     char	*dn )
+ {
+ 	char	*s;
+ 	int	inquote;
+ 
+ 	if( dn == NULL ) {
+ 		return NULL;
+ 	}
+ 
+ 	while(*dn && SPACE(*dn)) {
+ 		dn++;
+ 	}
+ 
+ 	if( *dn == '\0' ) {
+ 		return( NULL );
+ 	}
+ 
+ 	if ( be != NULL && be_issuffix( be, dn ) ) {
+ 		return( NULL );
+ 	}
+ 
+ 	dn = ch_strdup( dn );
+ 
+ 	/*
+ 	 * no =, assume it is a dns name, like blah@some.domain.name
+ 	 * if the blah@ part is there, return some.domain.name.  if
+ 	 * it's just some.domain.name, return domain.name.
+ 	 */
+ 	if ( strchr( dn, '=' ) == NULL ) {
+ 		if ( (s = strchr( dn, '@' )) == NULL ) {
+ 			if ( (s = strchr( dn, '.' )) == NULL ) {
+ 				return( dn );
+ 			}
+ 		}
+ 		*s = '\0';
+ 		return( dn );
+ 	}
+ 
+ 	/*
+ 	 * else assume it is an X.500-style name, which looks like
+ 	 * foo=bar,sha=baz,...
+ 	 */
+ 
+ 	inquote = 0;
+ 
+ 	for ( s = dn; *s; s++ ) {
+ 		if ( *s == '\\' ) {
+ 			if ( *(s + 1) ) {
+ 				s++;
+ 			}
+ 			continue;
+ 		}
+ 		if ( inquote ) {
+ 			if ( *s == '"' ) {
+ 				inquote = 0;
+ 			}
+ 		} else {
+ 			if ( *s == '"' ) {
+ 				inquote = 1;
+ 			} else if ( DNSEPARATOR( *s ) ) {
+ 				*s = '\0';
+ 				return( dn );
+ 			}
+ 		}
+ 	}
+ 
+ 	return( dn );
+ }
+ 
  /*
   * dn_issuffix - tells whether suffix is a suffix of dn.  both dn
   * and suffix must be normalized.
***************
*** 271,273 ****
--- 342,497 ----
  
  	return( dn );
  }
+ 
+ /*
+  * get_next_substring(), rdn_attr_type(), rdn_attr_value(), and
+  * build_new_dn().
+  * 
+  * Copyright 1999, Juan C. Gomez, All rights reserved.
+  * This software is not subject to any license of Silicon Graphics 
+  * Inc. or Purdue University.
+  *
+  * Redistribution and use in source and binary forms are permitted
+  * without restriction or fee of any kind as long as this notice
+  * is preserved.
+  *
+  */
+ 
+ /* get_next_substring:
+  *
+  * Gets next substring in s, using d (or the end of the string '\0') as a 
+  * string delimiter, and places it in a duplicated memory space. Leading 
+  * spaces are ignored. String s **must** be null-terminated.
+  */ 
+ 
+ static char * 
+ get_next_substring( char * s, char d )
+ {
+ 
+ 	char	*str, *r;
+ 
+ 	r = str = ch_malloc( strlen(s) + 1 );
+ 
+ 	/* Skip leading spaces */
+ 	
+ 	while ( *s && SPACE(*s) ) {
+ 	    
+ 		s++;
+ 	    
+ 	}/* while ( *s && SPACE(*s) ) */
+ 	
+ 	/* Copy word */
+ 
+ 	while ( *s && (*s != d) ) {
+ 
+ 		/* Don't stop when you see trailing spaces may be a multi-word
+ 		* string, i.e. name=John Doe!
+ 		*/
+ 
+ 		*str++ = *s++;
+ 	    
+ 	}/* while ( *s && (*s != d) ) */
+ 	
+ 	*str = '\0';
+ 	
+ 	return r;
+ 	
+ }/* char * get_word() */
+ 
+ 
+ /* rdn_attr_type:
+  *
+  * Given a string (i.e. an rdn) of the form:
+  *	 "attribute_type = attribute_value"
+  * this function returns the type of an attribute, that is the 
+  * string "attribute_type" which is placed in newly allocated 
+  * memory. The returned string will be null-terminated.
+  */
+ 
+ char * rdn_attr_type( char * s )
+ {
+ 
+ 	return get_next_substring( s, '=' );
+ 
+ }/* char * rdn_attr_type() */
+ 
+ 
+ /* rdn_attr_value:
+  *
+  * Given a string (i.e. an rdn) of the form:
+  *	 "attribute_type = attribute_value"
+  * this function returns "attribute_type" which is placed in newly allocated 
+  * memory. The returned string will be null-terminated and may contain 
+  * spaces (i.e. "John Doe\0").
+  */
+ 
+ char * 
+ rdn_attr_value( char * rdn )
+ {
+ 
+ 	char	*str;
+ 
+ 	if ( (str = strchr( rdn, '=' )) != NULL ) {
+ 
+ 		return get_next_substring(++str, '\0');
+ 
+ 	}/* if ( (str = strpbrk( rdn, "=" )) != NULL ) */
+ 
+ 	return NULL;
+ 
+ }/* char * rdn_attr_value() */
+ 
+ 
+ /* build_new_dn:
+  *
+  * Used by ldbm/bdb2_back_modrdn to create the new dn of entries being
+  * renamed.
+  *
+  * new_dn = parent (p_dn)  + separator(s) + rdn (newrdn) + null.
+  */
+ 
+ void
+ build_new_dn( char ** new_dn, char *e_dn, char * p_dn, char * newrdn )
+ {
+ 
+     if ( p_dn == NULL ) {
+ 
+ 	*new_dn = ch_strdup( newrdn );
+ 	return;
+ 
+     }
+     
+     *new_dn = (char *) ch_malloc( strlen( p_dn ) + strlen( newrdn ) + 3 );
+ 
+     if ( dn_type( e_dn ) == DN_X500 ) {
+ 
+ 	strcpy( *new_dn, newrdn );
+ 	strcat( *new_dn, "," );
+ 	strcat( *new_dn, p_dn );
+ 
+     } else {
+ 
+ 	char	*s;
+ 	char	sep[2];
+ 
+ 	strcpy( *new_dn, newrdn );
+ 	s = strchr( newrdn, '\0' );
+ 	s--;
+ 
+ 	if ( (*s != '.') && (*s != '@') ) {
+ 
+ 	    if ( (s = strpbrk( e_dn, ".@" )) != NULL ) {
+ 
+ 		sep[0] = *s;
+ 		sep[1] = '\0';
+ 		strcat( *new_dn, sep );
+ 
+ 	    }/* if ( (s = strpbrk( dn, ".@" )) != NULL ) */
+ 
+ 	}/* if ( *s != '.' && *s != '@' ) */
+ 
+ 	strcat( *new_dn, p_dn );
+ 
+     }/* if ( dn_type( e_dn ) == DN_X500 ) {}else */
+     
+ }/* void build_new_dn() */
diff -rc ldap_old/servers/slapd/modify.c ldap/servers/slapd/modify.c
*** ldap_old/servers/slapd/modify.c	Thu Jan 28 21:11:49 1999
--- ldap/servers/slapd/modify.c	Tue May 18 12:59:00 1999
***************
*** 21,27 ****
  #include "slap.h"
  
  static void	modlist_free(LDAPMod *mods);
- static void	add_lastmods(Operation *op, LDAPMod **mods);
  
  
  void
--- 21,26 ----
***************
*** 154,163 ****
  		if ( be->be_update_ndn == NULL ||
  			strcmp( be->be_update_ndn, op->o_ndn ) == 0 )
  		{
! 			if ( (be->be_lastmod == ON || ( be->be_lastmod == UNDEFINED &&
! 				global_lastmod == ON ) ) && be->be_update_ndn == NULL ) {
! 				add_lastmods( op, &mods );
! 			}
  			if ( (*be->be_modify)( be, conn, op, ndn, mods ) == 0 ) {
  				replog( be, LDAP_REQ_MODIFY, ndn, mods, 0 );
  			}
--- 153,159 ----
  		if ( be->be_update_ndn == NULL ||
  			strcmp( be->be_update_ndn, op->o_ndn ) == 0 )
  		{
! 
  			if ( (*be->be_modify)( be, conn, op, ndn, mods ) == 0 ) {
  				replog( be, LDAP_REQ_MODIFY, ndn, mods, 0 );
  			}
***************
*** 190,266 ****
  			ber_bvecfree( mods->mod_bvalues );
  		free( mods );
  	}
- }
- 
- static void
- add_lastmods( Operation *op, LDAPMod **mods )
- {
- 	char		buf[22];
- 	struct berval	bv;
- 	struct berval	*bvals[2];
- 	LDAPMod		**m;
- 	LDAPMod		*tmp;
- 	struct tm	*ltm;
- 
- 	Debug( LDAP_DEBUG_TRACE, "add_lastmods\n", 0, 0, 0 );
- 
- 	bvals[0] = &bv;
- 	bvals[1] = NULL;
- 
- 	/* remove any attempts by the user to modify these attrs */
- 	for ( m = mods; *m != NULL; m = &(*m)->mod_next ) {
-             if ( strcasecmp( (*m)->mod_type, "modifytimestamp" ) == 0 || 
- 				strcasecmp( (*m)->mod_type, "modifiersname" ) == 0 ||
- 				strcasecmp( (*m)->mod_type, "createtimestamp" ) == 0 || 
- 				strcasecmp( (*m)->mod_type, "creatorsname" ) == 0 ) {
- 
-                 Debug( LDAP_DEBUG_TRACE,
- 					"add_lastmods: found lastmod attr: %s\n",
- 					(*m)->mod_type, 0, 0 );
-                 tmp = *m;
-                 *m = (*m)->mod_next;
-                 free( tmp->mod_type );
-                 if ( tmp->mod_bvalues != NULL ) {
-                     ber_bvecfree( tmp->mod_bvalues );
-                 }
-                 free( tmp );
-                 if (!*m)
-                     break;
-             }
-         }
- 
- 	if ( op->o_dn == NULL || op->o_dn[0] == '\0' ) {
- 		bv.bv_val = "NULLDN";
- 		bv.bv_len = strlen( bv.bv_val );
- 	} else {
- 		bv.bv_val = op->o_dn;
- 		bv.bv_len = strlen( bv.bv_val );
- 	}
- 	tmp = (LDAPMod *) ch_calloc( 1, sizeof(LDAPMod) );
- 	tmp->mod_type = ch_strdup( "modifiersname" );
- 	tmp->mod_op = LDAP_MOD_REPLACE;
- 	tmp->mod_bvalues = (struct berval **) ch_calloc( 1,
- 	    2 * sizeof(struct berval *) );
- 	tmp->mod_bvalues[0] = ber_bvdup( &bv );
- 	tmp->mod_next = *mods;
- 	*mods = tmp;
- 
- 	ldap_pvt_thread_mutex_lock( &currenttime_mutex );
- #ifndef LDAP_LOCALTIME
- 	ltm = gmtime( &currenttime );
- 	strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", ltm );
- #else
- 	ltm = localtime( &currenttime );
- 	strftime( buf, sizeof(buf), "%y%m%d%H%M%SZ", ltm );
- #endif
- 	ldap_pvt_thread_mutex_unlock( &currenttime_mutex );
- 	bv.bv_val = buf;
- 	bv.bv_len = strlen( bv.bv_val );
- 	tmp = (LDAPMod *) ch_calloc( 1, sizeof(LDAPMod) );
- 	tmp->mod_type = ch_strdup( "modifytimestamp" );
- 	tmp->mod_op = LDAP_MOD_REPLACE;
- 	tmp->mod_bvalues = (struct berval **) ch_calloc( 1, 2 * sizeof(struct berval *) );
- 	tmp->mod_bvalues[0] = ber_bvdup( &bv );
- 	tmp->mod_next = *mods;
- 	*mods = tmp;
  }
--- 186,189 ----
diff -rc ldap_old/servers/slapd/proto-slap.h ldap/servers/slapd/proto-slap.h
*** ldap_old/servers/slapd/proto-slap.h	Sun Feb  7 10:42:24 1999
--- ldap/servers/slapd/proto-slap.h	Tue May 18 12:32:36 1999
***************
*** 102,111 ****
  char * dn_normalize LDAP_P(( char *dn ));
  char * dn_normalize_case LDAP_P(( char *dn ));
  char * dn_parent LDAP_P(( Backend *be, char *dn ));
  int dn_issuffix LDAP_P(( char *dn, char *suffix ));
  int dn_type LDAP_P(( char *dn ));
  char * dn_upcase LDAP_P(( char *dn ));
! 
  /*
   * entry.c
   */
--- 102,115 ----
  char * dn_normalize LDAP_P(( char *dn ));
  char * dn_normalize_case LDAP_P(( char *dn ));
  char * dn_parent LDAP_P(( Backend *be, char *dn ));
+ char * dn_rdn LDAP_P(( Backend *be, char *dn ));
  int dn_issuffix LDAP_P(( char *dn, char *suffix ));
  int dn_type LDAP_P(( char *dn ));
  char * dn_upcase LDAP_P(( char *dn ));
! char * rdn_attr_value LDAP_P(( char * rdn ));
! char * rdn_attr_type LDAP_P(( char * rdn ));
! void build_new_dn LDAP_P(( char ** new_dn, char *e_dn, char * p_dn,
! 			   char * newrdn ));
  /*
   * entry.c
   */
Only in ldap/tests/data: modrdn.out.master
diff -rc ldap_old/tests/scripts/defines.sh ldap/tests/scripts/defines.sh
*** ldap_old/tests/scripts/defines.sh	Tue Jan 19 20:44:54 1999
--- ldap/tests/scripts/defines.sh	Tue May 18 15:13:18 1999
***************
*** 5,10 ****
--- 5,11 ----
  SLURPD=../servers/slurpd/slurpd
  LDAPSEARCH=../clients/tools/ldapsearch
  LDAPMODIFY=../clients/tools/ldapmodify
+ LDAPMODRDN=../clients/tools/ldapmodrdn
  LDAPADD=../clients/tools/ldapadd
  LVL=5
  PORT=9009
***************
*** 32,37 ****
--- 33,39 ----
  MASTEROUT=$DBDIR/master.out
  SLAVEOUT=$DBDIR/slave.out
  TESTOUT=$DBDIR/ldapsearch.out
+ TESTOUT_MODRDN=$DBDIR/ldapmodrdn.out
  SEARCHOUTMASTER=$DATADIR/search.out.master
  MODIFYOUTMASTER=$DATADIR/modify.out.master
  ADDDELOUTMASTER=$DATADIR/adddel.out.master
diff -rc ldap_old/tests/scripts/test005-modrdn ldap/tests/scripts/test005-modrdn
*** ldap_old/tests/scripts/test005-modrdn	Wed Jan 13 17:02:14 1999
--- ldap/tests/scripts/test005-modrdn	Tue May 18 15:30:38 1999
***************
*** 1,12 ****
! #!/bin/sh
  
! if [ $# -eq 0 ]; then
  	SRCDIR="."
  else
  	SRCDIR=$1; shift
  fi
  
! . $SRCDIR/scripts/defines.sh $SRCDIR
  
- echo "modrdn test not yet written"
  exit 0
--- 1,99 ----
! #! /bin/sh
  
! if test $# -eq 0 ; then
  	SRCDIR="."
  else
  	SRCDIR=$1; shift
  fi
+ if test $# -eq 1 ; then
+ 	BACKEND=$1; shift
+ fi
+ 
+ echo "running defines.sh $SRCDIR $BACKEND"
+ . $SRCDIR/scripts/defines.sh
+ 
+ echo "Cleaning up in $DBDIR..."
+ 
+ rm -f $DBDIR/[!C]*
+ 
+ echo "Running ldif2ldbm to build slapd database..."
+ $LDIF2LDBM -f $CONF -i $LDIF -e ../servers/slapd/tools
+ RC=$?
+ if test $RC != 0 ; then
+ 	echo "ldif2ldbm failed!"
+ 	exit $RC
+ fi
+ 
+ echo "Starting slapd on TCP/IP port $PORT..."
+ $SLAPD -f $CONF -p $PORT -d $LVL $TIMING > $MASTERLOG 2>&1 &
+ PID=$!
+ echo "Testing slapd modrdn operations..."
+ 
+ # Make sure we can search the database
+ for i in 0 1 2 3 4 5; do
+ 	$LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $PORT \
+ 		'cn=Manager' > /dev/null 2>&1
+ 	RC=$?
+ 	if test $RC = 1 ; then
+ 		echo "Waiting 5 seconds for slapd to start..."
+ 		sleep 5
+ 	fi
+ done
+ 
+ if test $RC != 0 ; then
+ 	echo "ldapsearch failed!"
+ 	kill -HUP $PID
+ 	exit $RC
+ fi
+ 
+ cat /dev/null > $TESTOUT_MODRDN
+ 
+ # -r used to do remove of old rdn
+ 
+ echo "Testing modrdn(deleteoldrdn=0)..."
+ $LDAPMODRDN -v -D "$MANAGERDN" -h localhost -p $PORT -w $PASSWD > \
+ 	/dev/null 2>&1 'cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of Michigan, c=US' 'cn=James A Jones III'
+ 
+ RC=$?
+ if test $RC != 0 ; then
+ 	echo "ldapmodrdn failed!"
+ 	kill -HUP $PID
+ 	exit $RC
+ fi
+ 
+ echo "Testing modrdn(deleteoldrdn=1)..."
+ $LDAPMODRDN -v -D "$MANAGERDN" -r -h localhost -p $PORT -w $PASSWD > \
+ 	/dev/null 2>&1 'cn=James A Jones 2, ou=Information Technology Division, ou=People, o=University of Michigan, c=US' 'cn=James A Jones II'
+ 
+ RC=$?
+ if test $RC != 0 ; then
+ 	echo "ldapmodrdn failed!"
+ 	kill -HUP $PID
+ 	exit $RC
+ fi
+ 
+ echo "Using ldapsearch to retrieve all the entries..."
+ $LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $PORT \
+ 	    'objectClass=*' | egrep -iv '^createtimestamp:|^modifytimestamp:' \
+ 	    > $SEARCHOUT 2>&1
+ RC=$?
+ kill -HUP $PID
+ if test $RC != 0 ; then
+ 	echo "ldapsearch failed!"
+ 	exit $RC
+ fi
+ 
+ echo "Comparing database to reference file"
+ cmp $SEARCHOUT $MODRDNOUTMASTER
+ if test $? != 0 ; then
+ 	echo "comparison failed - modrdn operations did not complete correctly"
+ 	exit 1
+ fi
+ 
+ echo ">>>>> Test succeeded"
+ 
+ 
  
! # echo "modrdn test not yet written"
  
  exit 0