From a8574a450f9bd4d71d1456803294c5eff5de9c59 Mon Sep 17 00:00:00 2001 From: Jong Hyuk Choi Date: Tue, 7 Oct 2003 20:01:37 +0000 Subject: [PATCH] slaptools update : replica promotion / demotion new slapadd options -p : promote : If the ldif file contains syncConsumerSubentries, convert them to a single syncProviderSubentry. Its contextCSN attribute has the largest value of the syncreplCookie attributes of the syncConsumerSubentries. syncProviderSubentry in the ldif file is retained. -p -w : promote : Recalculate contextCSN based on entryCSN of each entry. create Existing syncConsumerSubentries and syncProviderSubentry are ignored and not added to the directory. -r : demote : If the ldif file contains syncProviderSubentry, convert it to a syncConsumerSubentry having the default syncrepl id of 0. syncConsumerSubentries in the ldif file are retained. -r -w : demote : Recalculate syncreplCookie based on entryCSN of each entry. create Existing syncConsumerSubentries and syncProviderSubentry are ignored and not added to the directory. The default syncrepl id of 0 will be used for the new syncConsumerSubentry. -r -w -i %d[,%d]* : Using the comma separated list followed by the -i option, it is possible to create multiple syncConsumerSubentries having the syncrepl ids specified in the list. syncreplCookie values of these sycnConsumerSubentries will have the same value, either from the maximum entryCSN value or from the contextCSN value of the syncProviderSubentry. --- servers/slapd/config.c | 44 +++ servers/slapd/proto-slap.h | 35 ++- servers/slapd/syncrepl.c | 77 +++--- servers/slapd/tools/Makefile.in | 2 +- servers/slapd/tools/mimic.c | 28 +- servers/slapd/tools/slapadd.c | 450 +++++++++++++++++++++++++++---- servers/slapd/tools/slapcommon.c | 42 ++- servers/slapd/tools/slapcommon.h | 7 +- 8 files changed, 561 insertions(+), 124 deletions(-) diff --git a/servers/slapd/config.c b/servers/slapd/config.c index 2b442a015a..b233598a66 100644 --- a/servers/slapd/config.c +++ b/servers/slapd/config.c @@ -3084,3 +3084,47 @@ parse_syncrepl_line( return 0; } + +char ** +str2clist( char ***out, char *in, const char *brkstr ) +{ + char *str; + char *s; + char *lasts; + int i, j; + const char *text; + char **new; + + /* find last element in list */ + for (i = 0; *out && *out[i]; i++); + + /* protect the input string from strtok */ + str = ch_strdup( in ); + + if ( *str == '\0' ) { + free( str ); + return( *out ); + } + + /* Count words in string */ + j=1; + for ( s = str; *s; s++ ) { + if ( strchr( brkstr, *s ) != NULL ) { + j++; + } + } + + *out = ch_realloc( *out, ( i + j + 1 ) * sizeof( char * ) ); + new = *out + i; + for ( s = ldap_pvt_strtok( str, brkstr, &lasts ); + s != NULL; + s = ldap_pvt_strtok( NULL, brkstr, &lasts ) ) + { + *new = ch_strdup( s ); + new++; + } + + *new = NULL; + free( str ); + return( *out ); +} diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index ed3762dd6f..42494eba50 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -303,6 +303,7 @@ LDAP_SLAPD_F (int) get_supported_controls LDAP_P (( char ***ctrloidsp, slap_mask */ LDAP_SLAPD_F (int) read_config LDAP_P(( const char *fname, int depth )); LDAP_SLAPD_F (void) config_destroy LDAP_P ((void)); +LDAP_SLAPD_F (char **) str2clist LDAP_P(( char ***, char *, const char * )); /* * connection.c @@ -358,6 +359,8 @@ LDAP_SLAPD_F (ContentRule *) cr_bvfind LDAP_P(( * ctxcsn.c */ +LDAP_SLAPD_V( const struct berval ) slap_ldapsync_bv; +LDAP_SLAPD_V( const struct berval ) slap_ldapsync_cn_bv; LDAP_SLAPD_F (void) slap_get_commit_csn LDAP_P(( Operation *, struct berval * )); LDAP_SLAPD_F (void) slap_rewind_commit_csn LDAP_P(( Operation * )); LDAP_SLAPD_F (void) slap_graduate_commit_csn LDAP_P(( Operation * )); @@ -535,8 +538,6 @@ LDAP_SLAPD_V( const struct berval ) slap_empty_bv; LDAP_SLAPD_V( const struct berval ) slap_unknown_bv; LDAP_SLAPD_V( const struct berval ) slap_true_bv; LDAP_SLAPD_V( const struct berval ) slap_false_bv; -LDAP_SLAPD_V( const struct berval ) slap_ldapsync_bv; -LDAP_SLAPD_V( const struct berval ) slap_ldapsync_cn_bv; /* * index.c @@ -1170,28 +1171,34 @@ LDAP_SLAPD_F (int) do_unbind LDAP_P((Operation *op, SlapReply *rs)); LDAP_SLAPD_F (int) do_extended LDAP_P((Operation *op, SlapReply *rs)); /* - * syncrepl + * syncrepl.c */ +LDAP_SLAPD_V( const struct berval ) slap_syncrepl_bvc; +LDAP_SLAPD_V( const struct berval ) slap_syncrepl_cn_bvc; + LDAP_SLAPD_V (struct runqueue_s) syncrepl_rq; LDAP_SLAPD_F (void) init_syncrepl LDAP_P(()); LDAP_SLAPD_F (void*) do_syncrepl LDAP_P((void *, void *)); LDAP_SLAPD_F (int) ldap_sync_search LDAP_P(( - syncinfo_t *, LDAP *, LDAPControl **, LDAPControl **, int *)); + syncinfo_t *, LDAP *, LDAPControl **, + LDAPControl **, int *)); LDAP_SLAPD_F (Entry*) syncrepl_message_to_entry LDAP_P(( - syncinfo_t *, LDAP *, Operation *, LDAPMessage *, - Modifications **, int*, struct berval *, struct berval * )); + syncinfo_t *, LDAP *, Operation *, LDAPMessage *, + Modifications **, int*, struct berval *, struct berval * )); LDAP_SLAPD_F (int) syncrepl_entry LDAP_P(( - syncinfo_t *, LDAP *, Operation*, Entry*, - Modifications*,int, struct berval*, struct berval*, int )); + syncinfo_t *, LDAP *, Operation*, Entry*, + Modifications*,int, struct berval*, struct berval*, int )); LDAP_SLAPD_F (void) syncrepl_updateCookie LDAP_P(( - syncinfo_t *, LDAP *, Operation *, struct berval *, - struct berval * )); -LDAP_SLAPD_F (char **) str2clist LDAP_P(( char ***, char *, const char * )); - -LDAP_SLAPD_F (void) syncrepl_add_glue LDAP_P(( syncinfo_t *, LDAP *, Operation*, Entry*, - Modifications*, int, struct berval*, struct berval* )); + syncinfo_t *, LDAP *, Operation *, struct berval *, + struct berval * )); +LDAP_SLAPD_F (void) syncrepl_add_glue LDAP_P(( syncinfo_t *, LDAP *, + Operation*, Entry*, Modifications*, int, + struct berval*, struct berval* )); +LDAP_SLAPD_F (Entry*) slap_create_syncrepl_entry LDAP_P(( + Backend *, struct berval *, + struct berval *, struct berval * )); LDAP_END_DECL diff --git a/servers/slapd/syncrepl.c b/servers/slapd/syncrepl.c index 360d574087..58ed2f8e6b 100644 --- a/servers/slapd/syncrepl.c +++ b/servers/slapd/syncrepl.c @@ -35,6 +35,9 @@ #include "ldap_rq.h" +const struct berval slap_syncrepl_bvc = BER_BVC("syncreplxxx"); +const struct berval slap_syncrepl_cn_bvc = BER_BVC("cn=syncreplxxx"); + static void syncrepl_del_nonpresent( LDAP *, Operation * ); @@ -1618,47 +1621,45 @@ null_callback( return LDAP_SUCCESS; } - -char ** -str2clist( char ***out, char *in, const char *brkstr ) +static struct berval ocbva[] = { + BER_BVC("top"), + BER_BVC("subentry"), + BER_BVC("syncProviderSubentry"), + {0,NULL} +}; + +Entry * +slap_create_syncrepl_entry( + Backend *be, + struct berval *context_csn, + struct berval *rdn, + struct berval *cn +) { - char *str; - char *s; - char *lasts; - int i, j; - const char *text; - char **new; - - /* find last element in list */ - for (i = 0; *out && *out[i]; i++); - - /* protect the input string from strtok */ - str = ch_strdup( in ); - - if ( *str == '\0' ) { - free( str ); - return( *out ); - } + Entry* e; + int rc; - /* Count words in string */ - j=1; - for ( s = str; *s; s++ ) { - if ( strchr( brkstr, *s ) != NULL ) { - j++; - } - } + struct berval bv; - *out = ch_realloc( *out, ( i + j + 1 ) * sizeof( char * ) ); - new = *out + i; - for ( s = ldap_pvt_strtok( str, brkstr, &lasts ); - s != NULL; - s = ldap_pvt_strtok( NULL, brkstr, &lasts ) ) - { - *new = ch_strdup( s ); - new++; + e = ( Entry * ) ch_calloc( 1, sizeof( Entry )); + + attr_merge( e, slap_schema.si_ad_objectClass, ocbva, NULL ); + + attr_merge_one( e, slap_schema.si_ad_structuralObjectClass, &ocbva[1], NULL ); + + attr_merge_one( e, slap_schema.si_ad_cn, cn, NULL ); + + if ( context_csn ) { + attr_merge_one( e, slap_schema.si_ad_syncreplCookie, + context_csn, NULL ); } - *new = NULL; - free( str ); - return( *out ); + bv.bv_val = "{}"; + bv.bv_len = sizeof("{}")-1; + attr_merge_one( e, slap_schema.si_ad_subtreeSpecification, &bv, NULL ); + + build_new_dn( &e->e_name, &be->be_nsuffix[0], rdn, NULL ); + ber_dupbv( &e->e_nname, &e->e_name ); + + return e; } diff --git a/servers/slapd/tools/Makefile.in b/servers/slapd/tools/Makefile.in index 081e9aea56..8934eac54c 100644 --- a/servers/slapd/tools/Makefile.in +++ b/servers/slapd/tools/Makefile.in @@ -46,7 +46,7 @@ SLAPD_OBJS = ../globals.o ../config.o ../ch_malloc.o ../cr.o ../backend.o \ ../init.o ../controls.o ../kerberos.o ../passwd.o \ ../index.o ../extended.o ../starttls.o ../sets.o ../mra.o \ ../referral.o ../backglue.o ../oidm.o ../mods.o ../operation.o \ - ../cancel.o ../sl_malloc.o ../backover.o ../ctxcsn.o + ../cancel.o ../sl_malloc.o ../backover.o ../ctxcsn.o ../syncrepl.o SLAPOBJS = $(SLAPD_OBJS) slapcommon.o mimic.o diff --git a/servers/slapd/tools/mimic.c b/servers/slapd/tools/mimic.c index 9f972115e2..c9bade3f96 100644 --- a/servers/slapd/tools/mimic.c +++ b/servers/slapd/tools/mimic.c @@ -236,31 +236,29 @@ int root_dse_info( Connection *conn, Entry **entry, const char **text ) return -1; } -struct runqueue_s syncrepl_rq; - -void init_syncrepl( ) +int slap_entry2mods( Entry *e, Modifications **mods, const char **text ) { - return; + return -1; } -void* do_syncrepl( void *ctx, void *arg ) -{ - return NULL; -} +volatile sig_atomic_t slapd_abrupt_shutdown; -char** str2clist( char ***out, char *in, const char *brkstr ) +int slap_mods_check( Modifications *ml, int update, const char **text, + char *textbuf, size_t textlen, void *ctx ) { - return NULL; + return -1; } -void syncrepl_add_glue( syncinfo_t *si, LDAP *ld, Operation *op, Entry *e, - Modifications *modlist, int syncstate, struct berval* syncUUID, - struct berval* syncCookie ) +int slap_mods2entry( Modifications *mods, Entry **e, int repl_user, + int dup, const char **text, char *textbuf, size_t textlen ) { - return; + return -1; } -int slap_entry2mods( Entry *e, Modifications **mods, const char **text ) +int slap_mods_opattrs( Operation *op, Modifications *mods, + Modifications **modtail, const char **text, + char *textbuf, size_t textlen ) { return -1; } + diff --git a/servers/slapd/tools/slapadd.c b/servers/slapd/tools/slapadd.c index da006c28ea..1958a42493 100644 --- a/servers/slapd/tools/slapadd.c +++ b/servers/slapd/tools/slapadd.c @@ -21,6 +21,18 @@ #include "slapcommon.h" static char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE ]; +static const struct berval slap_syncrepl_bvc = BER_BVC("syncreplxxx"); +static const struct berval slap_syncrepl_cn_bvc = BER_BVC("cn=syncreplxxx"); +static struct berval slap_syncrepl_bv = BER_BVNULL; +static struct berval slap_syncrepl_cn_bv = BER_BVNULL; + +struct subentryinfo { + struct berval cn; + struct berval ndn; + struct berval rdn; + struct berval cookie; + LDAP_SLIST_ENTRY( subentryinfo ) sei_next; +}; int main( int argc, char **argv ) @@ -35,11 +47,26 @@ main( int argc, char **argv ) size_t textlen = sizeof textbuf; struct berval csn; + struct berval maxcsn = { 0, NULL }; + struct berval ldifcsn = { 0, NULL }; + int match; + int provider_subentry = 0; + struct subentryinfo *sei; + LDAP_SLIST_HEAD( consumer_subentry_slist, subentryinfo ) consumer_subentry; + Attribute *attr; + Entry *ctxcsn_e; + ID ctxcsn_id; + struct berval ctxcsn_ndn = { 0, NULL }; + int ret; + struct berval bvtext; + int i; #ifdef NEW_LOGGING lutil_log_initialize(argc, argv ); #endif slap_tool_init( "slapadd", SLAPADD, argc, argv ); + LDAP_SLIST_INIT( &consumer_subentry ); + if( !be->be_entry_open || !be->be_entry_close || !be->be_entry_put ) @@ -60,7 +87,6 @@ main( int argc, char **argv ) while( ldif_read_record( ldiffp, &lineno, &buf, &lmax ) ) { Entry *e = str2entry( buf ); - struct berval bvtext; /* * Initialize text buffer @@ -239,76 +265,396 @@ main( int argc, char **argv ) vals[0] = csn; attr_merge( e, slap_schema.si_ad_entryCSN, vals, NULL ); } - } - if (!dryrun) { - ID id = be->be_entry_put( be, e, &bvtext ); - if( id == NOID ) { - fprintf( stderr, "%s: could not add entry dn=\"%s\" (line=%d): %s\n", - progname, e->e_dn, lineno, bvtext.bv_val ); - rc = EXIT_FAILURE; - entry_free( e ); - if( continuemode ) continue; - break; + if ( !is_entry_syncProviderSubentry( e ) && + !is_entry_syncConsumerSubentry( e ) && + update_ctxcsn != SLAP_TOOL_CTXCSN_KEEP ) { + attr = attr_find( e->e_attrs, slap_schema.si_ad_entryCSN ); + if ( maxcsn.bv_len != 0 ) { + value_match( &match, slap_schema.si_ad_entryCSN, + slap_schema.si_ad_entryCSN->ad_type->sat_ordering, + SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, + &maxcsn, &attr->a_nvals[0], &text ); + } else { + match = -1; + } + if ( match < 0 ) { + if ( maxcsn.bv_val ) + ch_free( maxcsn.bv_val ); + ber_dupbv( &maxcsn, &attr->a_nvals[0] ); + } } + } + + if ( update_ctxcsn == SLAP_TOOL_CTXCSN_KEEP ) { + if ( is_entry_syncProviderSubentry( e )) { + if ( !LDAP_SLIST_EMPTY( &consumer_subentry )) { + fprintf( stderr, "%s: consumer and provider subentries " + "are both present\n", progname ); + rc = EXIT_FAILURE; + entry_free( e ); + sei = LDAP_SLIST_FIRST( &consumer_subentry ); + while ( sei ) { + ch_free( sei->cn.bv_val ); + ch_free( sei->ndn.bv_val ); + ch_free( sei->rdn.bv_val ); + ch_free( sei->cookie.bv_val ); + LDAP_SLIST_REMOVE_HEAD( &consumer_subentry, sei_next ); + ch_free( sei ); + sei = LDAP_SLIST_FIRST( &consumer_subentry ); + } + break; + } + if ( provider_subentry ) { + fprintf( stderr, "%s: multiple provider subentries are " + "present : add -w flag to refresh\n", progname ); + rc = EXIT_FAILURE; + entry_free( e ); + break; + } + attr = attr_find( e->e_attrs, slap_schema.si_ad_contextCSN ); + if ( attr == NULL ) { + entry_free( e ); + continue; + } + provider_subentry = 1; + ber_dupbv( &maxcsn, &attr->a_nvals[0] ); + } else if ( is_entry_syncConsumerSubentry( e )) { + if ( provider_subentry ) { + fprintf( stderr, "%s: consumer and provider subentries " + "are both present\n", progname ); + rc = EXIT_FAILURE; + entry_free( e ); + break; + } - if ( verbose ) { - fprintf( stderr, "added: \"%s\" (%08lx)\n", - e->e_dn, (long) id ); + attr = attr_find( e->e_attrs, slap_schema.si_ad_cn ); + + if ( attr == NULL ) { + entry_free( e ); + continue; + } + + if ( !LDAP_SLIST_EMPTY( &consumer_subentry )) { + LDAP_SLIST_FOREACH( sei, &consumer_subentry, sei_next ) { + value_match( &match, slap_schema.si_ad_cn, + slap_schema.si_ad_cn->ad_type->sat_equality, + SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, + &sei->cn, &attr->a_nvals[0], &text ); + } + if ( !match ) { + fprintf( stderr, "%s: multiple consumer subentries " + "have the same id : add -w flag to refresh\n", + progname ); + rc = EXIT_FAILURE; + entry_free( e ); + sei = LDAP_SLIST_FIRST( &consumer_subentry ); + while ( sei ) { + ch_free( sei->cn.bv_val ); + ch_free( sei->ndn.bv_val ); + ch_free( sei->rdn.bv_val ); + ch_free( sei->cookie.bv_val ); + LDAP_SLIST_REMOVE_HEAD( &consumer_subentry, sei_next ); + ch_free( sei ); + sei = LDAP_SLIST_FIRST( &consumer_subentry ); + } + break; + } + } + sei = ch_calloc( 1, sizeof( struct subentryinfo )); + ber_dupbv( &sei->cn, &attr->a_nvals[0] ); + ber_dupbv( &sei->ndn, &e->e_nname ); + dnExtractRdn( &sei->ndn, &sei->rdn, NULL ); + attr = attr_find( e->e_attrs, slap_schema.si_ad_syncreplCookie ); + if ( attr == NULL ) { + ch_free( sei->cn.bv_val ); + ch_free( sei->ndn.bv_val ); + ch_free( sei->rdn.bv_val ); + ch_free( sei->cookie.bv_val ); + ch_free( sei ); + entry_free( e ); + continue; + } + ber_dupbv( &sei->cookie, &attr->a_nvals[0] ); + LDAP_SLIST_INSERT_HEAD( &consumer_subentry, sei, sei_next ); } - } else { - if ( verbose ) { - fprintf( stderr, "(dry) added: \"%s\"\n", e->e_dn ); + } + + if ( !is_entry_syncProviderSubentry( e ) && + !is_entry_syncConsumerSubentry( e )) { + if (!dryrun) { + ID id = be->be_entry_put( be, e, &bvtext ); + if( id == NOID ) { + fprintf( stderr, "%s: could not add entry dn=\"%s\" " + "(line=%d): %s\n", progname, e->e_dn, + lineno, bvtext.bv_val ); + rc = EXIT_FAILURE; + entry_free( e ); + if( continuemode ) continue; + break; + } + + if ( verbose ) { + fprintf( stderr, "added: \"%s\" (%08lx)\n", + e->e_dn, (long) id ); + } + } else { + if ( verbose ) { + fprintf( stderr, "(dry) added: \"%s\"\n", e->e_dn ); + } } } entry_free( e ); } - if ( SLAP_LASTMOD(be) && update_ctxcsn == SLAP_TOOL_CTXCSN_BATCH && csn.bv_len > 0 ) { - Entry *ctxcsn_e; - ID ctxcsn_id; - struct berval ctxcsn_ndn = { 0, NULL }; - int ret; - struct berval bvtext; - Attribute *attr; - - bvtext.bv_len = textlen; - bvtext.bv_val = textbuf; - bvtext.bv_val[0] = '\0'; + bvtext.bv_len = textlen; + bvtext.bv_val = textbuf; + bvtext.bv_val[0] = '\0'; + + if ( !LDAP_SLIST_EMPTY( &consumer_subentry )) { + maxcsn.bv_len = 0; + maxcsn.bv_val = NULL; + LDAP_SLIST_FOREACH( sei, &consumer_subentry, sei_next ) { + if ( maxcsn.bv_len != 0 ) { + value_match( &match, slap_schema.si_ad_syncreplCookie, + slap_schema.si_ad_syncreplCookie->ad_type->sat_ordering, + SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, + &maxcsn, &sei->cookie, &text ); + } else { + match = -1; + } + if ( match < 0 ) { + if ( maxcsn.bv_val ) + ch_free( maxcsn.bv_val ); + ber_dupbv( &maxcsn, &sei->cookie ); + } + } + } - build_new_dn( &ctxcsn_ndn, &be->be_nsuffix[0], (struct berval *)&slap_ldapsync_cn_bv, NULL ); - ctxcsn_id = be->be_dn2id_get( be, &ctxcsn_ndn ); + if ( SLAP_LASTMOD(be) && replica_promotion ) { + if ( provider_subentry || update_ctxcsn == SLAP_TOOL_CTXCSN_BATCH || + !LDAP_SLIST_EMPTY( &consumer_subentry )) { + build_new_dn( &ctxcsn_ndn, &be->be_nsuffix[0], + (struct berval *)&slap_ldapsync_cn_bv, NULL ); + ctxcsn_id = be->be_dn2id_get( be, &ctxcsn_ndn ); - if ( ctxcsn_id == NOID ) { - ctxcsn_e = slap_create_context_csn_entry( be, &csn ); - ctxcsn_id = be->be_entry_put( be, ctxcsn_e, &bvtext ); - if( ctxcsn_id == NOID ) { - fprintf( stderr, "%s: could not add ctxcsn subentry\n", progname); - rc = EXIT_FAILURE; - } - if ( verbose ) { - fprintf( stderr, "added: \"%s\" (%08lx)\n", ctxcsn_e->e_dn, (long) ctxcsn_id ); + if ( ctxcsn_id == NOID ) { + ctxcsn_e = slap_create_context_csn_entry( be, &maxcsn ); + if ( !dryrun ) { + ctxcsn_id = be->be_entry_put( be, ctxcsn_e, &bvtext ); + if( ctxcsn_id == NOID ) { + fprintf( stderr, "%s: could not add ctxcsn subentry\n", + progname); + rc = EXIT_FAILURE; + } + if ( verbose ) { + fprintf( stderr, "added: \"%s\" (%08lx)\n", + ctxcsn_e->e_dn, (long) ctxcsn_id ); + } + } else { + if ( verbose ) { + fprintf( stderr, "(dry) added: \"%s\"\n", ctxcsn_e->e_dn ); + } + } + entry_free( ctxcsn_e ); + } else { + ret = be->be_id2entry_get( be, ctxcsn_id, &ctxcsn_e ); + if ( ret == LDAP_SUCCESS ) { + attr = attr_find( ctxcsn_e->e_attrs, + slap_schema.si_ad_contextCSN ); + AC_MEMCPY( attr->a_vals[0].bv_val, maxcsn.bv_val, maxcsn.bv_len ); + attr->a_vals[0].bv_val[maxcsn.bv_len] = '\0'; + attr->a_vals[0].bv_len = maxcsn.bv_len; + if ( !dryrun ) { + ctxcsn_id = be->be_entry_modify( be, ctxcsn_e, &bvtext ); + if( ctxcsn_id == NOID ) { + fprintf( stderr, "%s: could not modify ctxcsn " + "subentry\n", progname); + rc = EXIT_FAILURE; + } + if ( verbose ) { + fprintf( stderr, "modified: \"%s\" (%08lx)\n", + ctxcsn_e->e_dn, (long) ctxcsn_id ); + } + } else { + if ( verbose ) { + fprintf( stderr, "(dry) modified: \"%s\"\n", + ctxcsn_e->e_dn ); + } + } + } else { + fprintf( stderr, "%s: could not modify ctxcsn subentry\n", + progname); + rc = EXIT_FAILURE; + } } - entry_free( ctxcsn_e ); - } else { - ret = be->be_id2entry_get( be, ctxcsn_id, &ctxcsn_e ); - if ( ret == LDAP_SUCCESS ) { - attr = attr_find( ctxcsn_e->e_attrs, slap_schema.si_ad_contextCSN ); - attr->a_vals[0] = csn; - ctxcsn_id = be->be_entry_modify( be, ctxcsn_e, &bvtext ); - if( ctxcsn_id == NOID ) { - fprintf( stderr, "%s: could not modify ctxcsn subentry\n", progname); + } + } else if ( SLAP_LASTMOD(be) && replica_demotion && + ( update_ctxcsn == SLAP_TOOL_CTXCSN_BATCH || + provider_subentry )) { + + ber_dupbv( &slap_syncrepl_bv, (struct berval *) &slap_syncrepl_bvc ); + ber_dupbv( &slap_syncrepl_cn_bv, + (struct berval *) &slap_syncrepl_cn_bvc ); + + if ( replica_id_list == NULL ) { + replica_id_list = ch_calloc( 2, sizeof( int )); + replica_id_list[0] = 0; + replica_id_list[1] = -1; + } + + for ( i = 0; replica_id_list[i] > -1 ; i++ ) { + slap_syncrepl_bv.bv_len = snprintf( slap_syncrepl_bv.bv_val, + slap_syncrepl_bvc.bv_len, + "syncrepl%d", replica_id_list[i] ); + slap_syncrepl_cn_bv.bv_len = snprintf( slap_syncrepl_cn_bv.bv_val, + slap_syncrepl_cn_bvc.bv_len, + "cn=syncrepl%d", replica_id_list[i] ); + build_new_dn( &ctxcsn_ndn, &be->be_nsuffix[0], + (struct berval *)&slap_syncrepl_cn_bv, NULL ); + ctxcsn_id = be->be_dn2id_get( be, &ctxcsn_ndn ); + + if ( ctxcsn_id == NOID ) { + ctxcsn_e = slap_create_syncrepl_entry( be, &maxcsn, + &slap_syncrepl_cn_bv, + &slap_syncrepl_bv ); + if ( !dryrun ) { + ctxcsn_id = be->be_entry_put( be, ctxcsn_e, &bvtext ); + if( ctxcsn_id == NOID ) { + fprintf( stderr, "%s: could not add ctxcsn subentry\n", + progname); + rc = EXIT_FAILURE; + } + if ( verbose ) { + fprintf( stderr, "added: \"%s\" (%08lx)\n", + ctxcsn_e->e_dn, (long) ctxcsn_id ); + } + } else { + if ( verbose ) { + fprintf( stderr, "(dry) added: \"%s\"\n", + ctxcsn_e->e_dn ); + } + } + entry_free( ctxcsn_e ); + } else { + ret = be->be_id2entry_get( be, ctxcsn_id, &ctxcsn_e ); + if ( ret == LDAP_SUCCESS ) { + attr = attr_find( ctxcsn_e->e_attrs, + slap_schema.si_ad_syncreplCookie ); + AC_MEMCPY( attr->a_vals[0].bv_val, maxcsn.bv_val, maxcsn.bv_len ); + attr->a_vals[0].bv_val[maxcsn.bv_len] = '\0'; + attr->a_vals[0].bv_len = maxcsn.bv_len; + if ( !dryrun ) { + ctxcsn_id = be->be_entry_modify( be, + ctxcsn_e, &bvtext ); + if( ctxcsn_id == NOID ) { + fprintf( stderr, "%s: could not modify ctxcsn " + "subentry\n", progname); + rc = EXIT_FAILURE; + } + if ( verbose ) { + fprintf( stderr, "modified: \"%s\" (%08lx)\n", + ctxcsn_e->e_dn, (long) ctxcsn_id ); + } + } else { + if ( verbose ) { + fprintf( stderr, "(dry) modified: \"%s\"\n", + ctxcsn_e->e_dn ); + } + } + } else { + fprintf( stderr, "%s: could not modify ctxcsn subentry\n", + progname); rc = EXIT_FAILURE; } - if ( verbose ) { - fprintf( stderr, "modified: \"%s\" (%08lx)\n", ctxcsn_e->e_dn, (long) ctxcsn_id ); + } + } + + if ( slap_syncrepl_bv.bv_val ) { + ch_free( slap_syncrepl_bv.bv_val ); + } + if ( slap_syncrepl_cn_bv.bv_val ) { + ch_free( slap_syncrepl_cn_bv.bv_val ); + } + } else if ( SLAP_LASTMOD(be) && replica_demotion && + !LDAP_SLIST_EMPTY( &consumer_subentry )) { + + LDAP_SLIST_FOREACH( sei, &consumer_subentry, sei_next ) { + ctxcsn_id = be->be_dn2id_get( be, &sei->ndn ); + + if ( ctxcsn_id == NOID ) { + ctxcsn_e = slap_create_syncrepl_entry( be, &sei->cookie, + &sei->rdn, &sei->cn ); + if ( !dryrun ) { + ctxcsn_id = be->be_entry_put( be, ctxcsn_e, &bvtext ); + if( ctxcsn_id == NOID ) { + fprintf( stderr, "%s: could not add ctxcsn subentry\n", + progname); + rc = EXIT_FAILURE; + } + if ( verbose ) { + fprintf( stderr, "added: \"%s\" (%08lx)\n", + ctxcsn_e->e_dn, (long) ctxcsn_id ); + } + } else { + if ( verbose ) { + fprintf( stderr, "(dry) added: \"%s\"\n", + ctxcsn_e->e_dn ); + } } + entry_free( ctxcsn_e ); } else { - fprintf( stderr, "%s: could not modify ctxcsn subentry\n", progname); - rc = EXIT_FAILURE; + ret = be->be_id2entry_get( be, ctxcsn_id, &ctxcsn_e ); + if ( ret == LDAP_SUCCESS ) { + attr = attr_find( ctxcsn_e->e_attrs, + slap_schema.si_ad_syncreplCookie ); + AC_MEMCPY( attr->a_vals[0].bv_val, maxcsn.bv_val, maxcsn.bv_len ); + attr->a_vals[0].bv_val[maxcsn.bv_len] = '\0'; + attr->a_vals[0].bv_len = maxcsn.bv_len; + if ( !dryrun ) { + ctxcsn_id = be->be_entry_modify( be, + ctxcsn_e, &bvtext ); + if( ctxcsn_id == NOID ) { + fprintf( stderr, "%s: could not modify ctxcsn " + "subentry\n", progname); + rc = EXIT_FAILURE; + } + if ( verbose ) { + fprintf( stderr, "modified: \"%s\" (%08lx)\n", + ctxcsn_e->e_dn, (long) ctxcsn_id ); + } + } else { + if ( verbose ) { + fprintf( stderr, "(dry) modified: \"%s\"\n", + ctxcsn_e->e_dn ); + } + } + } else { + fprintf( stderr, "%s: could not modify ctxcsn subentry\n", + progname); + rc = EXIT_FAILURE; + } } } + + if ( slap_syncrepl_bv.bv_val ) { + ch_free( slap_syncrepl_bv.bv_val ); + } + if ( slap_syncrepl_cn_bv.bv_val ) { + ch_free( slap_syncrepl_cn_bv.bv_val ); + } + } + + sei = LDAP_SLIST_FIRST( &consumer_subentry ); + while ( sei ) { + ch_free( sei->cn.bv_val ); + ch_free( sei->ndn.bv_val ); + ch_free( sei->rdn.bv_val ); + ch_free( sei->cookie.bv_val ); + LDAP_SLIST_REMOVE_HEAD( &consumer_subentry, sei_next ); + ch_free( sei ); + sei = LDAP_SLIST_FIRST( &consumer_subentry ); } ch_free( buf ); diff --git a/servers/slapd/tools/slapcommon.c b/servers/slapd/tools/slapcommon.c index c0a2d47a9d..6719743360 100644 --- a/servers/slapd/tools/slapcommon.c +++ b/servers/slapd/tools/slapcommon.c @@ -23,9 +23,14 @@ char *progname = NULL; char *conffile = SLAPD_DEFAULT_CONFIGFILE; int truncatemode = 0; int verbose = 0; -int update_ctxcsn = SLAP_TOOL_CTXCSN_NONE; +int update_ctxcsn = SLAP_TOOL_CTXCSN_KEEP; int retrieve_ctxcsn = 0; int retrieve_synccookie = 0; +int replica_promotion = 0; +int replica_demotion = 0; +char *replica_id_string = NULL; +char **replica_id_strlist = NULL; +int *replica_id_list = NULL; int continuemode = 0; int nosubordinates = 0; int dryrun = 0; @@ -51,7 +56,7 @@ usage( int tool ) switch( tool ) { case SLAPADD: - options = "\t[-l ldiffile] [-u] [-W] [-w]\n"; + options = "\n\t[-l ldiffile] [-u] [-p [-w] | -r [-i syncreplidlist] [-w]]\n"; break; case SLAPCAT: @@ -103,7 +108,7 @@ slap_tool_init( switch( tool ) { case SLAPADD: - options = "b:cd:f:l:n:tuvWw"; + options = "b:cd:f:i:l:n:prtuvWw"; break; case SLAPINDEX: @@ -144,6 +149,21 @@ slap_tool_init( conffile = strdup( optarg ); break; + case 'i': /* specify syncrepl id list */ + replica_id_string = strdup( optarg ); + if ( !isdigit( *replica_id_string )) { + usage( tool ); + exit( EXIT_FAILURE ); + } + str2clist( &replica_id_strlist, replica_id_string, "," ); + for ( i = 0; replica_id_strlist && replica_id_strlist[i]; i++ ) ; + replica_id_list = ch_calloc( i + 1, sizeof( int ) ); + for ( i = 0; replica_id_strlist && replica_id_strlist[i]; i++ ) { + replica_id_list[i] = atoi( replica_id_strlist[i] ); + } + replica_id_list[i] = -1; + break; + case 'k': /* Retrieve sync cookie entry */ retrieve_synccookie = 1; break; @@ -160,6 +180,14 @@ slap_tool_init( dbnum = atoi( optarg ) - 1; break; + case 'p': /* replica promotion */ + replica_promotion = 1; + break; + + case 'r': /* replica demotion */ + replica_demotion = 1; + break; + case 's': /* dump subtree */ subtree = strdup( optarg ); break; @@ -196,6 +224,14 @@ slap_tool_init( usage( tool ); } + if ( replica_promotion && replica_demotion ) { + usage( tool ); + } else if ( !replica_promotion && !replica_demotion ) { + if ( update_ctxcsn != SLAP_TOOL_CTXCSN_KEEP ) { + usage( tool ); + } + } + if ( ldiffile == NULL ) { ldiffp = tool == SLAPCAT ? stdout : stdin; diff --git a/servers/slapd/tools/slapcommon.h b/servers/slapd/tools/slapcommon.h index 925b9976b1..4d3b7b5694 100644 --- a/servers/slapd/tools/slapcommon.h +++ b/servers/slapd/tools/slapcommon.h @@ -18,7 +18,7 @@ enum slaptool { SLAPTEST /* database testing tool */ }; -#define SLAP_TOOL_CTXCSN_NONE 0 +#define SLAP_TOOL_CTXCSN_KEEP 0 #define SLAP_TOOL_CTXCSN_ENTRY 1 #define SLAP_TOOL_CTXCSN_BATCH 2 @@ -30,6 +30,11 @@ extern int verbose; extern int update_ctxcsn; extern int retrieve_ctxcsn; extern int retrieve_synccookie; +extern int replica_promotion; +extern int replica_demotion; +extern char *replica_id_string; +extern char **replica_id_strlist; +extern int *replica_id_list; extern int continuemode; extern int nosubordinates; extern int dryrun; -- 2.39.5