static int syncuuid_cmp( const void *, const void * );
static int avl_presentlist_insert( syncinfo_t* si, struct berval *syncUUID );
-static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct berval * );
+static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct sync_cookie *, int );
static int syncrepl_message_to_op(
syncinfo_t *, Operation *, LDAPMessage * );
static int syncrepl_message_to_entry(
abs(si->si_type), rhint );
}
- if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 ) ) == LBER_ERROR ) {
+ if ( (rc = ber_flatten2( ber, &c[0].ldctl_value, 0 ) ) == -1 ) {
ber_free_buf( ber );
return rc;
}
return rc;
}
+static int
+check_syncprov(
+ Operation *op,
+ syncinfo_t *si )
+{
+ AttributeName at[2];
+ Attribute a = {0};
+ Entry e = {0};
+ SlapReply rs = {0};
+ int i, j, changed = 0;
+
+ /* Look for contextCSN from syncprov overlay. If
+ * there's no overlay, this will be a no-op. That means
+ * this is a pure consumer, so local changes will not be
+ * allowed, and all changes will already be reflected in
+ * the cookieState.
+ */
+ a.a_desc = slap_schema.si_ad_contextCSN;
+ e.e_attrs = &a;
+ e.e_name = op->o_bd->be_suffix[0];
+ e.e_nname = op->o_bd->be_nsuffix[0];
+ at[0].an_name = a.a_desc->ad_cname;
+ at[0].an_desc = a.a_desc;
+ BER_BVZERO( &at[1].an_name );
+ rs.sr_entry = &e;
+ rs.sr_flags = REP_ENTRY_MODIFIABLE;
+ rs.sr_attrs = at;
+ op->o_req_dn = e.e_name;
+ op->o_req_ndn = e.e_nname;
+
+ ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
+ i = backend_operational( op, &rs );
+ if ( i == LDAP_SUCCESS && a.a_nvals ) {
+ int num = a.a_numvals;
+ /* check for differences */
+ if ( num != si->si_cookieState->cs_num ) {
+ changed = 1;
+ } else {
+ for ( i=0; i<num; i++ ) {
+ if ( ber_bvcmp( &a.a_nvals[i],
+ &si->si_cookieState->cs_vals[i] )) {
+ changed = 1;
+ break;
+ }
+ }
+ }
+ if ( changed ) {
+ ber_bvarray_free( si->si_cookieState->cs_vals );
+ ch_free( si->si_cookieState->cs_sids );
+ si->si_cookieState->cs_num = num;
+ si->si_cookieState->cs_vals = a.a_nvals;
+ si->si_cookieState->cs_sids = slap_parse_csn_sids( a.a_nvals,
+ num, NULL );
+ si->si_cookieState->cs_age++;
+ } else {
+ ber_bvarray_free( a.a_nvals );
+ }
+ ber_bvarray_free( a.a_vals );
+ }
+ /* See if the cookieState has changed due to anything outside
+ * this particular consumer. That includes other consumers in
+ * the same context, or local changes detected above.
+ */
+ if ( si->si_cookieState->cs_num > 0 && si->si_cookieAge !=
+ si->si_cookieState->cs_age ) {
+ if ( !si->si_syncCookie.numcsns ) {
+ ber_bvarray_free( si->si_syncCookie.ctxcsn );
+ ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
+ si->si_cookieState->cs_vals, NULL );
+ changed = 1;
+ } else {
+ for (i=0; !BER_BVISNULL( &si->si_syncCookie.ctxcsn[i] ); i++) {
+ /* bogus, just dup everything */
+ if ( si->si_syncCookie.sids[i] == -1 ) {
+ ber_bvarray_free( si->si_syncCookie.ctxcsn );
+ ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
+ si->si_cookieState->cs_vals, NULL );
+ changed = 1;
+ break;
+ }
+ for (j=0; j<si->si_cookieState->cs_num; j++) {
+ if ( si->si_syncCookie.sids[i] !=
+ si->si_cookieState->cs_sids[j] )
+ continue;
+ if ( bvmatch( &si->si_syncCookie.ctxcsn[i],
+ &si->si_cookieState->cs_vals[j] ))
+ break;
+ ber_bvreplace( &si->si_syncCookie.ctxcsn[i],
+ &si->si_cookieState->cs_vals[j] );
+ changed = 1;
+ break;
+ }
+ }
+ }
+ }
+ if ( changed ) {
+ si->si_cookieAge = si->si_cookieState->cs_age;
+ ch_free( si->si_syncCookie.octet_str.bv_val );
+ slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
+ si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
+ si->si_syncCookie.sid );
+ }
+ ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
+ return changed;
+}
+
static int
do_syncrep1(
Operation *op,
op->o_tls_ssf = ldap_pvt_tls_get_strength( ssl );
}
#endif /* HAVE_TLS */
- ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &op->o_sasl_ssf );
+ {
+ ber_len_t ssf; /* ITS#5403, 3864 LDAP_OPT_X_SASL_SSF probably ought
+ to use sasl_ssf_t but currently uses ber_len_t */
+ ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &ssf );
+ op->o_sasl_ssf = ssf;
+ }
op->o_ssf = ( op->o_sasl_ssf > op->o_tls_ssf )
? op->o_sasl_ssf : op->o_tls_ssf;
ldap_set_option( si->si_ld, LDAP_OPT_TIMELIMIT, &si->si_tlimit );
+ rc = LDAP_DEREF_NEVER; /* actually could allow DEREF_FINDING */
+ ldap_set_option( si->si_ld, LDAP_OPT_DEREF, &rc );
+
si->si_syncCookie.rid = si->si_rid;
- si->si_syncCookie.sid = SLAP_SINGLE_SHADOW( si->si_be ) ? -1 :
- slap_serverID;
+
+ /* whenever there are multiple data sources possible, advertise sid */
+ si->si_syncCookie.sid = ( SLAP_MULTIMASTER( si->si_be ) || si->si_be != si->si_wbe ) ?
+ slap_serverID : -1;
/* We've just started up, or the remote server hasn't sent us
* any meaningful state.
si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
si->si_syncCookie.sid );
} else {
- AttributeName at[2];
- Attribute a = {0};
- Entry e = {0};
- SlapReply rs = {0};
- int i, j, changed = 0;
-
- /* Look for contextCSN from syncprov overlay. If
- * there's no overlay, this will be a no-op. That means
- * this is a pure consumer, so local changes will not be
- * allowed, and all changes will already be reflected in
- * the cookieState.
- */
- a.a_desc = slap_schema.si_ad_contextCSN;
- e.e_attrs = &a;
- e.e_name = op->o_bd->be_suffix[0];
- e.e_nname = op->o_bd->be_nsuffix[0];
- at[0].an_name = a.a_desc->ad_cname;
- at[0].an_desc = a.a_desc;
- BER_BVZERO( &at[1].an_name );
- rs.sr_entry = &e;
- rs.sr_flags = REP_ENTRY_MODIFIABLE;
- rs.sr_attrs = at;
- op->o_req_dn = e.e_name;
- op->o_req_ndn = e.e_nname;
-
- ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
- rc = backend_operational( op, &rs );
- if ( rc == LDAP_SUCCESS && a.a_nvals ) {
- int num = a.a_numvals;
- /* check for differences */
- if ( num != si->si_cookieState->cs_num ) {
- changed = 1;
- } else {
- for ( i=0; i<num; i++ ) {
- if ( ber_bvcmp( &a.a_nvals[i],
- &si->si_cookieState->cs_vals[i] )) {
- changed =1;
- break;
- }
- }
- }
- if ( changed ) {
- ber_bvarray_free( si->si_cookieState->cs_vals );
- ch_free( si->si_cookieState->cs_sids );
- si->si_cookieState->cs_num = num;
- si->si_cookieState->cs_vals = a.a_nvals;
- si->si_cookieState->cs_sids = slap_parse_csn_sids( a.a_nvals,
- num, NULL );
- si->si_cookieState->cs_age++;
- } else {
- ber_bvarray_free( a.a_nvals );
- }
- ber_bvarray_free( a.a_vals );
- }
- /* See if the cookieState has changed due to anything outside
- * this particular consumer. That includes other consumers in
- * the same context, or local changes detected above.
- */
- if ( si->si_cookieState->cs_num > 0 && si->si_cookieAge !=
- si->si_cookieState->cs_age ) {
- if ( !si->si_syncCookie.numcsns ) {
- ber_bvarray_free( si->si_syncCookie.ctxcsn );
- ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
- si->si_cookieState->cs_vals, NULL );
- changed = 1;
- } else {
- for (i=0; !BER_BVISNULL( &si->si_syncCookie.ctxcsn[i] ); i++) {
- /* bogus, just dup everything */
- if ( si->si_syncCookie.sids[i] == -1 ) {
- ber_bvarray_free( si->si_syncCookie.ctxcsn );
- ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
- si->si_cookieState->cs_vals, NULL );
- changed = 1;
- break;
- }
- for (j=0; j<si->si_cookieState->cs_num; j++) {
- if ( si->si_syncCookie.sids[i] !=
- si->si_cookieState->cs_sids[j] )
- continue;
- if ( bvmatch( &si->si_syncCookie.ctxcsn[i],
- &si->si_cookieState->cs_vals[j] ))
- break;
- ber_bvreplace( &si->si_syncCookie.ctxcsn[i],
- &si->si_cookieState->cs_vals[j] );
- changed = 1;
- break;
- }
- }
- }
- }
- if ( changed ) {
- si->si_cookieAge = si->si_cookieState->cs_age;
- ch_free( si->si_syncCookie.octet_str.bv_val );
- slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
- si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
- si->si_syncCookie.sid );
- }
- ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
+ /* Look for contextCSN from syncprov overlay. */
+ check_syncprov( op, si );
}
si->si_refreshDone = 0;
return -1;
}
- for (i=0; i<sc1->numcsns; i++) {
- for (j=0; i<sc2->numcsns; j++) {
+ for (j=0; j<sc2->numcsns; j++) {
+ for (i=0; i<sc1->numcsns; i++) {
if ( sc1->sids[i] != sc2->sids[j] )
continue;
value_match( &match, slap_schema.si_ad_entryCSN,
}
break;
}
+ if ( i == sc1->numcsns ) {
+ /* sc2 has a sid sc1 lacks */
+ *which = j;
+ return -1;
+ }
}
return match;
}
rc = err;
goto done;
}
+ if ( err ) {
+ Debug( LDAP_DEBUG_ANY,
+ "do_syncrep2: %s LDAP_RES_SEARCH_RESULT (%d) %s\n",
+ si->si_ridtxt, err, ldap_err2string( err ) );
+ }
if ( rctrls ) {
rctrlp = *rctrls;
ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
}
ber_scanf( ber, /*"{"*/ "}" );
}
+ if ( SLAP_MULTIMASTER( op->o_bd ) && check_syncprov( op, si )) {
+ slap_sync_cookie_free( &syncCookie_req, 0 );
+ slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
+ }
if ( !syncCookie.ctxcsn ) {
match = 1;
} else if ( !syncCookie_req.ctxcsn ) {
* 2) on err policy : stop service, stop sync, retry
*/
if ( refreshDeletes == 0 && match < 0 &&
- err == LDAP_SUCCESS )
+ err == LDAP_SUCCESS &&
+ syncCookie_req.numcsns == syncCookie.numcsns )
{
syncrepl_del_nonpresent( op, si, NULL,
- &syncCookie.ctxcsn[m] );
+ &syncCookie, m );
} else {
avl_free( si->si_presentlist, ch_free );
si->si_presentlist = NULL;
ber_scanf( ber, /*"{"*/ "}" );
if ( refreshDeletes ) {
syncrepl_del_nonpresent( op, si, syncUUIDs,
- &syncCookie.ctxcsn[m] );
+ &syncCookie, m );
ber_bvarray_free_x( syncUUIDs, op->o_tmpmemctx );
} else {
int i;
continue;
}
+ if ( SLAP_MULTIMASTER( op->o_bd ) && check_syncprov( op, si )) {
+ slap_sync_cookie_free( &syncCookie_req, 0 );
+ slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
+ }
if ( !syncCookie.ctxcsn ) {
match = 1;
} else if ( !syncCookie_req.ctxcsn ) {
}
if ( match < 0 ) {
- if ( si->si_refreshPresent == 1 ) {
+ if ( si->si_refreshPresent == 1 &&
+ syncCookie_req.numcsns == syncCookie.numcsns ) {
syncrepl_del_nonpresent( op, si, NULL,
- &syncCookie.ctxcsn[m] );
+ &syncCookie, m );
}
if ( syncCookie.ctxcsn )
OperationBuffer opbuf;
Operation *op;
int rc = LDAP_SUCCESS;
- int dostop = 0, do_setup = 0;
+ int dostop = 0;
ber_socket_t s;
int i, defer = 1, fail = 0;
Backend *be;
if ( si == NULL )
return NULL;
- /* Don't wait around if there's a previous session still running */
- if ( ldap_pvt_thread_mutex_trylock( &si->si_mutex ))
- return NULL;
+ /* There will never be more than one instance active */
+ ldap_pvt_thread_mutex_lock( &si->si_mutex );
switch( abs( si->si_type ) ) {
case LDAP_SYNC_REFRESH_ONLY:
*
* Typically there is a single syncprov mastering the entire
* glued tree. In that case, our contextCSN updates should
- * go to the master DB.
+ * go to the master DB. But if there is no syncprov on the
+ * master DB, then nothing special is needed here.
*
* Alternatively, there may be individual syncprov overlays
* on each glued branch. In that case, each syncprov only
*/
if ( !si->si_wbe ) {
if ( SLAP_GLUE_SUBORDINATE( be ) && !overlay_is_inst( be, "syncprov" )) {
- si->si_wbe = select_backend( &be->be_nsuffix[0], 1 );
+ BackendDB * top_be = select_backend( &be->be_nsuffix[0], 1 );
+ if ( overlay_is_inst( top_be, "syncprov" ))
+ si->si_wbe = select_backend( &be->be_nsuffix[0], 1 );
+ else
+ si->si_wbe = be;
} else {
si->si_wbe = be;
}
if ( rc == LDAP_SUCCESS ) {
if ( si->si_conn ) {
connection_client_enable( si->si_conn );
- goto success;
} else {
- do_setup = 1;
+ si->si_conn = connection_client_setup( s, do_syncrepl, arg );
}
} else if ( si->si_conn ) {
dostop = 1;
if ( rc == SYNC_PAUSED ) {
rtask->interval.tv_sec = 0;
ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 );
+ rtask->interval.tv_sec = si->si_interval;
rc = 0;
} else if ( rc == LDAP_SUCCESS ) {
if ( si->si_type == LDAP_SYNC_REFRESH_ONLY ) {
}
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
-
- if ( do_setup )
- si->si_conn = connection_client_setup( s, do_syncrepl, arg );
-
-success:
ldap_pvt_thread_mutex_unlock( &si->si_mutex );
if ( rc ) {
Operation *op,
syncinfo_t *si,
BerVarray uuids,
- struct berval *cookiecsn )
+ struct sync_cookie *sc,
+ int m )
{
Backend* be = op->o_bd;
slap_callback cb = { NULL };
}
si->si_refreshDelete ^= NP_DELETE_ONE;
} else {
+ Filter *cf, *of;
+
memset( &an[0], 0, 2 * sizeof( AttributeName ) );
an[0].an_name = slap_schema.si_ad_entryUUID->ad_cname;
an[0].an_desc = slap_schema.si_ad_entryUUID;
op->ors_slimit = SLAP_NO_LIMIT;
op->ors_attrsonly = 0;
op->ors_filter = str2filter_x( op, si->si_filterstr.bv_val );
- op->ors_filterstr = si->si_filterstr;
+ /* In multimaster, updates can continue to arrive while
+ * we're searching. Limit the search result to entries
+ * older than all of our cookie CSNs.
+ */
+ if ( SLAP_MULTIMASTER( op->o_bd )) {
+ Filter *f;
+ int i;
+ cf = op->o_tmpalloc( (sc->numcsns+1) * sizeof(Filter) +
+ sc->numcsns * sizeof(AttributeAssertion), op->o_tmpmemctx );
+ f = cf;
+ f->f_choice = LDAP_FILTER_AND;
+ f->f_next = NULL;
+ f->f_and = f+1;
+ of = f->f_and;
+ for ( i=0; i<sc->numcsns; i++ ) {
+ f = of;
+ f->f_choice = LDAP_FILTER_LE;
+ f->f_ava = (AttributeAssertion *)(f+1);
+ f->f_av_desc = slap_schema.si_ad_entryCSN;
+ f->f_av_value = sc->ctxcsn[i];
+ f->f_next = (Filter *)(f->f_ava+1);
+ of = f->f_next;
+ }
+ f->f_next = op->ors_filter;
+ of = op->ors_filter;
+ op->ors_filter = cf;
+ filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
+ } else {
+ cf = NULL;
+ op->ors_filterstr = si->si_filterstr;
+ }
op->o_nocaching = 1;
if ( limits_check( op, &rs_search ) == 0 ) {
rc = be->be_search( op, &rs_search );
}
- if ( op->ors_filter ) filter_free_x( op, op->ors_filter );
+ if ( SLAP_MULTIMASTER( op->o_bd )) {
+ op->o_tmpfree( cf, op->o_tmpmemctx );
+ op->ors_filter = of;
+ }
+ if ( op->ors_filter ) filter_free_x( op, op->ors_filter, 1 );
+
}
op->o_nocaching = 0;
if ( !LDAP_LIST_EMPTY( &si->si_nonpresentlist ) ) {
- if ( cookiecsn && !BER_BVISNULL( cookiecsn ) ) {
- csn = *cookiecsn;
+ if ( sc->ctxcsn && !BER_BVISNULL( &sc->ctxcsn[m] ) ) {
+ csn = sc->ctxcsn[m];
} else {
csn = si->si_syncCookie.ctxcsn[0];
}
Modifications mod;
struct berval first = BER_BVNULL;
- int rc, i, j, len;
+ int rc, i, j;
+ ber_len_t len;
slap_callback cb = { NULL };
SlapReply rs_modify = {REP_RESULT};
mod.sml_op = LDAP_MOD_REPLACE;
mod.sml_desc = slap_schema.si_ad_contextCSN;
mod.sml_type = mod.sml_desc->ad_cname;
+ mod.sml_flags = SLAP_MOD_INTERNAL;
mod.sml_nvalues = NULL;
mod.sml_next = NULL;
if ( memcmp( syncCookie->ctxcsn[i].bv_val,
si->si_cookieState->cs_vals[j].bv_val, len ) > 0 ) {
mod.sml_values[j] = syncCookie->ctxcsn[i];
- if ( BER_BVISNULL( &first ))
+ if ( BER_BVISNULL( &first ) ) {
first = syncCookie->ctxcsn[i];
+
+ } else if ( memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 )
+ {
+ first = syncCookie->ctxcsn[i];
+ }
}
break;
}
( mod.sml_numvals+2 )*sizeof(struct berval), op->o_tmpmemctx );
mod.sml_values[mod.sml_numvals++] = syncCookie->ctxcsn[i];
BER_BVZERO( &mod.sml_values[mod.sml_numvals] );
- if ( BER_BVISNULL( &first ))
+ if ( BER_BVISNULL( &first ) ) {
first = syncCookie->ctxcsn[i];
+ } else if ( memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 )
+ {
+ first = syncCookie->ctxcsn[i];
+ }
}
}
/* Should never happen, ITS#5065 */
op->o_req_ndn = op->o_bd->be_nsuffix[0];
/* update contextCSN */
- op->o_msgid = SLAP_SYNC_UPDATE_MSGID;
+ op->o_dont_replicate = 1;
op->orm_modlist = &mod;
op->orm_no_opattrs = 1;
rc = op->o_bd->be_modify( op, &rs_modify );
op->orm_no_opattrs = 0;
- op->o_msgid = 0;
+ op->o_dont_replicate = 0;
if ( rs_modify.sr_err == LDAP_SUCCESS ) {
slap_sync_cookie_free( &si->si_syncCookie, 0 );
}
}
+ /* Don't delete/add an objectClass, always use the replace op.
+ * Modify would fail if provider has replaced entry with a new,
+ * and the new explicitly includes a superior of a class that was
+ * only included implicitly in the old entry. Ref ITS#5517.
+ *
+ * Also use replace op if attr has no equality matching rule.
+ * (ITS#5781)
+ */
+ if ( nn && no < o &&
+ ( old->a_desc == slap_schema.si_ad_objectClass ||
+ !old->a_desc->ad_type->sat_equality ))
+ no = o;
+
i = j;
/* all old values were deleted, just use the replace op */
if ( no == o ) {
new = attr_find( dni->new_entry->e_attrs,
slap_schema.si_ad_entryCSN );
if ( new && old ) {
- int rc, len = old->a_vals[0].bv_len;
+ int rc;
+ ber_len_t len = old->a_vals[0].bv_len;
if ( len > new->a_vals[0].bv_len )
len = new->a_vals[0].bv_len;
rc = memcmp( old->a_vals[0].bv_val,
{
struct berval bc, uri;
char buf[BUFSIZ*2], *ptr;
+ ber_len_t len;
int i;
-
-#define WHATSLEFT ( sizeof( buf ) - ( ptr - buf ) )
+# define WHATSLEFT ((ber_len_t) (&buf[sizeof( buf )] - ptr))
BER_BVZERO( bv );
ptr = buf;
assert( si->si_rid >= 0 && si->si_rid <= SLAP_SYNC_SID_MAX );
- ptr += snprintf( ptr, WHATSLEFT, IDSTR "=%03d " PROVIDERSTR "=%s",
+ len = snprintf( ptr, WHATSLEFT, IDSTR "=%03d " PROVIDERSTR "=%s",
si->si_rid, si->si_bindconf.sb_uri.bv_val );
- if ( ptr - buf >= sizeof( buf ) ) return;
+ if ( len >= sizeof( buf ) ) return;
+ ptr += len;
if ( !BER_BVISNULL( &bc ) ) {
if ( WHATSLEFT <= bc.bv_len ) {
free( bc.bv_val );
if ( WHATSLEFT <= STRLENOF( " " ATTRSONLYSTR "=\"" "\"" ) ) return;
ptr = lutil_strcopy( ptr, " " ATTRSSTR "=\"" );
old = ptr;
- /* FIXME: add check for overflow */
ptr = anlist_unparse( si->si_anlist, ptr, WHATSLEFT );
+ if ( ptr == NULL ) return;
if ( si->si_allattrs ) {
if ( WHATSLEFT <= STRLENOF( ",*\"" ) ) return;
if ( old != ptr ) *ptr++ = ',';
if ( si->si_exanlist && !BER_BVISNULL(&si->si_exanlist[0].an_name) ) {
if ( WHATSLEFT <= STRLENOF( " " EXATTRSSTR "=" ) ) return;
ptr = lutil_strcopy( ptr, " " EXATTRSSTR "=" );
- /* FIXME: add check for overflow */
ptr = anlist_unparse( si->si_exanlist, ptr, WHATSLEFT );
+ if ( ptr == NULL ) return;
}
if ( WHATSLEFT <= STRLENOF( " " SCHEMASTR "=" ) + STRLENOF( "off" ) ) return;
ptr = lutil_strcopy( ptr, " " SCHEMASTR "=" );
dd /= 60;
hh = dd % 24;
dd /= 24;
- ptr = lutil_strcopy( ptr, " " INTERVALSTR "=" );
- ptr += snprintf( ptr, WHATSLEFT, "%02d:%02d:%02d:%02d", dd, hh, mm, ss );
- if ( ptr - buf >= sizeof( buf ) ) return;
+ len = snprintf( ptr, WHATSLEFT, " %s=%02d:%02d:%02d:%02d",
+ INTERVALSTR, dd, hh, mm, ss );
+ if ( len >= WHATSLEFT ) return;
+ ptr += len;
} else if ( si->si_retryinterval ) {
- int space=0;
+ const char *space = "";
if ( WHATSLEFT <= STRLENOF( " " RETRYSTR "=\"" "\"" ) ) return;
ptr = lutil_strcopy( ptr, " " RETRYSTR "=\"" );
for (i=0; si->si_retryinterval[i]; i++) {
- if ( space ) *ptr++ = ' ';
- space = 1;
- ptr += snprintf( ptr, WHATSLEFT, "%ld ", (long) si->si_retryinterval[i] );
+ len = snprintf( ptr, WHATSLEFT, "%s%ld ", space,
+ (long) si->si_retryinterval[i] );
+ space = " ";
+ if ( WHATSLEFT - 1 <= len ) return;
+ ptr += len;
if ( si->si_retrynum_init[i] == RETRYNUM_FOREVER )
*ptr++ = '+';
- else
- ptr += snprintf( ptr, WHATSLEFT, "%d", si->si_retrynum_init[i] );
+ else {
+ len = snprintf( ptr, WHATSLEFT, "%d", si->si_retrynum_init[i] );
+ if ( WHATSLEFT <= len ) return;
+ ptr += len;
+ }
}
if ( WHATSLEFT <= STRLENOF( "\"" ) ) return;
*ptr++ = '"';
}
if ( si->si_slimit ) {
- if ( WHATSLEFT <= STRLENOF( " " SLIMITSTR "=" ) ) return;
- ptr = lutil_strcopy( ptr, " " SLIMITSTR "=" );
- ptr += snprintf( ptr, WHATSLEFT, "%d", si->si_slimit );
+ len = snprintf( ptr, WHATSLEFT, " " SLIMITSTR "=%d", si->si_slimit );
+ if ( WHATSLEFT <= len ) return;
+ ptr += len;
}
if ( si->si_tlimit ) {
- if ( WHATSLEFT <= STRLENOF( " " TLIMITSTR "=" ) ) return;
- ptr = lutil_strcopy( ptr, " " TLIMITSTR "=" );
- ptr += snprintf( ptr, WHATSLEFT, "%d", si->si_tlimit );
+ len = snprintf( ptr, WHATSLEFT, " " TLIMITSTR "=%d", si->si_tlimit );
+ if ( WHATSLEFT <= len ) return;
+ ptr += len;
}
if ( si->si_syncdata ) {