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; } +static struct berval ocbva[] = { + BER_BVC("top"), + BER_BVC("subentry"), + BER_BVC("syncProviderSubentry"), + {0,NULL} +}; -char ** -str2clist( char ***out, char *in, const char *brkstr ) +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; + Entry* e; + int rc; - /* find last element in list */ - for (i = 0; *out && *out[i]; i++); + struct berval bv; - /* protect the input string from strtok */ - str = ch_strdup( in ); + e = ( Entry * ) ch_calloc( 1, sizeof( Entry )); - if ( *str == '\0' ) { - free( str ); - return( *out ); + 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 ); } - /* Count words in string */ - j=1; - for ( s = str; *s; s++ ) { - if ( strchr( brkstr, *s ) != NULL ) { - j++; - } - } + bv.bv_val = "{}"; + bv.bv_len = sizeof("{}")-1; + attr_merge_one( e, slap_schema.si_ad_subtreeSpecification, &bv, NULL ); - *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++; - } + build_new_dn( &e->e_name, &be->be_nsuffix[0], rdn, NULL ); + ber_dupbv( &e->e_nname, &e->e_name ); - *new = NULL; - free( str ); - return( *out ); + 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( ) -{ - return; -} - -void* do_syncrepl( void *ctx, void *arg ) -{ - return NULL; -} - -char** str2clist( char ***out, char *in, const char *brkstr ) -{ - return NULL; -} - -void syncrepl_add_glue( syncinfo_t *si, LDAP *ld, Operation *op, Entry *e, - Modifications *modlist, int syncstate, struct berval* syncUUID, - struct berval* syncCookie ) -{ - return; -} - int slap_entry2mods( Entry *e, Modifications **mods, const char **text ) { return -1; } + +volatile sig_atomic_t slapd_abrupt_shutdown; + +int slap_mods_check( Modifications *ml, int update, const char **text, + char *textbuf, size_t textlen, void *ctx ) +{ + return -1; +} + +int slap_mods2entry( Modifications *mods, Entry **e, int repl_user, + int dup, const char **text, char *textbuf, size_t textlen ) +{ + return -1; +} + +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,78 +265,398 @@ main( int argc, char **argv ) vals[0] = csn; attr_merge( e, slap_schema.si_ad_entryCSN, vals, NULL ); } + + 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 (!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 ( 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'; - - 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 ); - } - 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); - rc = EXIT_FAILURE; - } - if ( verbose ) { - fprintf( stderr, "modified: \"%s\" (%08lx)\n", ctxcsn_e->e_dn, (long) ctxcsn_id ); - } + 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 { - fprintf( stderr, "%s: could not modify ctxcsn subentry\n", progname); - rc = EXIT_FAILURE; + match = -1; + } + if ( match < 0 ) { + if ( maxcsn.bv_val ) + ch_free( maxcsn.bv_val ); + ber_dupbv( &maxcsn, &sei->cookie ); } } } + 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, &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; + } + } + } + } 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 ( 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 { + 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 ); if( be->be_entry_close( be )) rc = EXIT_FAILURE; 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;