OpenLDAP 2.3.22 Engineering
Fixed slapd-ldap fd cleanup (ITS#4474)
+ Fixed slapo-syncprov MODs cause DELs (ITS#4423)
+ Fixed slapd slap_send_ldap_result bug (ITS#4499)
+ Fixed slapd-ldif deadlock (ITS#4500)
+ Fixed liblutil strtoul(3) usage (ITS#4503)
+ Updated ldapsearch(1) BASE output (ITS#4504)
+ Fixed slapd cn=config (ITS#4512)
+ Fixed slapd thread pool init issue (ITS#4513)
+ Fixed slapd cn=config olcLimits (ITS#4515)
+ Fixed slapd runqueue use of freed memory (ITS#4517)
OpenLDAP 2.3.21 Release
Fixed libldap referral chasing issue (ITS#4448)
LDAP_F( struct re_s* )
ldap_pvt_runqueue_next_sched(
struct runqueue_s* rq,
- struct timeval** next_run
+ struct timeval* next_run
);
LDAP_F( void )
struct re_s*
ldap_pvt_runqueue_next_sched(
struct runqueue_s* rq,
- struct timeval** next_run
+ struct timeval* next_run
)
{
struct re_s* entry;
entry = LDAP_STAILQ_FIRST( &rq->task_list );
- if ( entry == NULL ) {
- *next_run = NULL;
- return NULL;
- } else if ( entry->next_sched.tv_sec == 0 ) {
- *next_run = NULL;
+ if ( entry == NULL || entry->next_sched.tv_sec == 0 ) {
return NULL;
} else {
- *next_run = &entry->next_sched;
+ *next_run = entry->next_sched;
return entry;
}
}
assert( s != NULL );
assert( v != NULL );
+ /* strtoul() has an odd interface */
+ if ( s[ 0 ] == '-' ) {
+ return -1;
+ }
+
u = strtoul( s, &next, x );
if ( next == s || next[ 0 ] != '\0' ) {
return -1;
assert( s != NULL );
assert( v != NULL );
+ /* strtoul() has an odd interface */
+ if ( s[ 0 ] == '-' ) {
+ return -1;
+ }
+
ul = strtoul( s, &next, x );
if ( next == s || next[ 0 ] != '\0' ) {
return -1;
unsigned long u;
char *what;
+ /* strtoul() has an odd interface */
+ if ( s[ 0 ] == '-' ) {
+ return -1;
+ }
+
u = strtoul( s, &next, 10 );
if ( next == s ) {
return -1;
struct berval li_base_path;
enumCookie li_tool_cookie;
ID li_tool_current;
- ldap_pvt_thread_mutex_t li_mutex;
+ ldap_pvt_thread_rdwr_t li_rdwr;
};
#ifdef _WIN32
else
rs = LDAP_UNWILLING_TO_PERFORM;
Debug( LDAP_DEBUG_ANY, "could not open \"%s\": %s\n",
- path->bv_val, strerror( errno ), 0 );
+ path->bv_val, STRERROR( errno ), 0 );
}
else {
struct berval rdn;
if ( fd < 0 ) {
Debug( LDAP_DEBUG_ANY,
"=> ldif_enum_tree: failed to open %s: %s\n",
- path->bv_val, strerror(errno), 0 );
+ path->bv_val, STRERROR(errno), 0 );
return LDAP_NO_SUCH_OBJECT;
}
if ( ptr ) {
itmp.bv_len = ptr - itmp.bv_val;
ber_dupbv( &bvl->num, &itmp );
+ /* FIXME: handle error? */
+ assert( itmp.bv_val[ 0 ] != '-' );
bvl->inum = strtoul( itmp.bv_val, NULL, 0 );
itmp.bv_val[0] = '\0';
bvl->off = itmp.bv_val - bvl->bv.bv_val;
}
ni = (struct ldif_info *)op->o_bd->be_private;
- ldap_pvt_thread_mutex_lock( &ni->li_mutex );
+ ldap_pvt_thread_rdwr_rlock( &ni->li_rdwr );
entry = (Entry *)get_entry( op, &ni->li_base_path );
/* no object is found for them */
entry = (Entry *)get_entry( op, &ni->li_base_path );
}
- ldap_pvt_thread_mutex_unlock( &ni->li_mutex );
+ ldap_pvt_thread_rdwr_runlock( &ni->li_rdwr );
op->o_req_dn = odn;
op->o_req_ndn = ondn;
return rc;
}
- ldap_pvt_thread_mutex_unlock( &ni->li_mutex );
+ ldap_pvt_thread_rdwr_runlock( &ni->li_rdwr );
if ( is_entry_referral( entry ) ) {
/* entry is a referral */
Entry * entry = NULL;
ni = (struct ldif_info *) op->o_bd->be_private;
- ldap_pvt_thread_mutex_lock(&ni->li_mutex);
+ ldap_pvt_thread_rdwr_rlock(&ni->li_rdwr);
entry = (Entry *) get_entry(op, &ni->li_base_path);
/* no object is found for them */
goto return_result;
return_result:
- ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
+ ldap_pvt_thread_rdwr_runlock(&ni->li_rdwr);
if(return_val != 0)
send_ldap_result( op, rs );
if(entry != NULL)
ck.op = op;
ck.rs = rs;
- ldap_pvt_thread_mutex_lock(&ni->li_mutex);
+ ldap_pvt_thread_rdwr_rlock(&ni->li_rdwr);
rs->sr_err = enum_tree( &ck );
- ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
+ ldap_pvt_thread_rdwr_runlock(&ni->li_rdwr);
send_ldap_result(op, rs);
return rs->sr_err;
&rs->sr_text, textbuf, sizeof( textbuf ) );
if ( rs->sr_err != LDAP_SUCCESS ) goto send_res;
- ldap_pvt_thread_mutex_lock(&ni->li_mutex);
+ ldap_pvt_thread_rdwr_wlock(&ni->li_rdwr);
dn2path(&dn, &op->o_bd->be_nsuffix[0], &ni->li_base_path, &leaf_path);
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
rs->sr_text = "Could not create parent folder";
Debug( LDAP_DEBUG_ANY, "could not create folder \"%s\": %s\n",
- base.bv_val, strerror( errno ), 0 );
+ base.bv_val, STRERROR( errno ), 0 );
}
}
else
else if ( statres == -1 ) {
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
Debug( LDAP_DEBUG_ANY, "could not stat file \"%s\": %s\n",
- leaf_path.bv_val, strerror( errno ), 0 );
+ leaf_path.bv_val, STRERROR( errno ), 0 );
}
else /* it already exists */
rs->sr_err = LDAP_ALREADY_EXISTS;
SLAP_FREE(leaf_path.bv_val);
}
- ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
+ ldap_pvt_thread_rdwr_wunlock(&ni->li_rdwr);
send_res:
Debug( LDAP_DEBUG_TRACE,
- "ldif_back_add: err: %d text: %s\n", rs->sr_err, rs->sr_text, 0);
+ "ldif_back_add: err: %d text: %s\n", rs->sr_err, rs->sr_text ?
+ rs->sr_text : "", 0);
send_ldap_result(op, rs);
slap_graduate_commit_csn( op );
return 0;
slap_mods_opattrs( op, &op->orm_modlist, 1 );
- ldap_pvt_thread_mutex_lock(&ni->li_mutex);
+ ldap_pvt_thread_rdwr_wlock(&ni->li_rdwr);
dn2path(&op->o_req_ndn, &op->o_bd->be_nsuffix[0], &ni->li_base_path,
&path);
entry = (Entry *) get_entry(op, &ni->li_base_path);
if(path.bv_val != NULL)
SLAP_FREE(path.bv_val);
rs->sr_text = NULL;
- ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
+ ldap_pvt_thread_rdwr_wunlock(&ni->li_rdwr);
send_ldap_result(op, rs);
slap_graduate_commit_csn( op );
return 0;
slap_get_csn( op, &csn, 1 );
}
- ldap_pvt_thread_mutex_lock(&ni->li_mutex);
+ ldap_pvt_thread_rdwr_wlock(&ni->li_rdwr);
dn2path(&op->o_req_ndn, &op->o_bd->be_nsuffix[0], &ni->li_base_path, &path);
path.bv_val[path.bv_len - STRLENOF(LDIF)] = '\0';
rs->sr_err = LDAP_SUCCESS;
SLAP_FREE(path.bv_val);
- ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
+ ldap_pvt_thread_rdwr_wunlock(&ni->li_rdwr);
send_ldap_result(op, rs);
slap_graduate_commit_csn( op );
return 0;
else { /* do the modrdn */
exists_res = open(newpath.bv_val, O_RDONLY);
if(exists_res == -1 && errno == ENOENT) {
+ ldap_pvt_thread_mutex_lock( &entry2str_mutex );
res = spew_entry(entry, &newpath);
if(res != -1) {
/* if this fails we should log something bad */
res = LDAP_UNWILLING_TO_PERFORM;
unlink(newpath.bv_val); /* in case file was created */
}
+ ldap_pvt_thread_mutex_unlock( &entry2str_mutex );
}
else if(exists_res) {
int close_res = close(exists_res);
Modifications * mods = NULL;
int res;
- ldap_pvt_thread_mutex_lock(&ni->li_mutex);
- ldap_pvt_thread_mutex_lock(&entry2str_mutex);
+ ldap_pvt_thread_rdwr_wlock( &ni->li_rdwr );
entry = (Entry *) get_entry(op, &ni->li_base_path);
/* build the mods to the entry */
if(entry != NULL)
entry_free(entry);
rs->sr_text = "";
- ldap_pvt_thread_mutex_unlock(&ni->li_mutex);
- ldap_pvt_thread_mutex_unlock(&entry2str_mutex);
+ ldap_pvt_thread_rdwr_wunlock( &ni->li_rdwr );
send_ldap_result(op, rs);
slap_graduate_commit_csn( op );
return 0;
{
struct ldif_info *ni = (struct ldif_info *) op->o_bd->be_private;
- ldap_pvt_thread_mutex_lock( &ni->li_mutex );
+ ldap_pvt_thread_rdwr_rlock( &ni->li_rdwr );
*ent = (Entry *) get_entry( op, &ni->li_base_path );
- ldap_pvt_thread_mutex_unlock( &ni->li_mutex );
+ ldap_pvt_thread_rdwr_runlock( &ni->li_rdwr );
return ( *ent == NULL ? 1 : 0 );
}
ni = ch_calloc( 1, sizeof(struct ldif_info) );
be->be_private = ni;
be->be_cf_ocs = ldifocs;
- ldap_pvt_thread_mutex_init(&ni->li_mutex);
+ ldap_pvt_thread_rdwr_init(&ni->li_rdwr);
return 0;
}
struct ldif_info *ni = be->be_private;
ch_free(ni->li_base_path.bv_val);
- ldap_pvt_thread_mutex_destroy(&ni->li_mutex);
+ ldap_pvt_thread_rdwr_destroy(&ni->li_rdwr);
free( be->be_private );
return 0;
}
"SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
{ "limits", "limits", 2, 0, 0, ARG_DB|ARG_MAGIC|CFG_LIMITS,
&config_generic, "( OLcfgDbAt:0.5 NAME 'olcLimits' "
+ "EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
{ "localSSF", "ssf", 2, 2, 0, ARG_INT,
&local_ssf, "( OLcfgGlAt:26 NAME 'olcLocalSSF' "
"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
{ "loglevel", "level", 2, 0, 0, ARG_MAGIC,
&config_loglevel, "( OLcfgGlAt:28 NAME 'olcLogLevel' "
+ "EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString )", NULL, NULL },
{ "maxDerefDepth", "depth", 2, 2, 0, ARG_DB|ARG_INT|ARG_MAGIC|CFG_DEPTH,
&config_generic, "( OLcfgDbAt:0.6 NAME 'olcMaxDerefDepth' "
ARG_IGNORED, NULL,
#endif
"( OLcfgGlAt:30 NAME 'olcModuleLoad' "
+ "EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
{ "modulepath", "path", 2, 2, 0,
#ifdef SLAPD_MODULES
NULL, NULL },
{ "objectidentifier", NULL, 0, 0, 0, ARG_MAGIC|CFG_OID,
&config_generic, "( OLcfgGlAt:33 NAME 'olcObjectIdentifier' "
+ "EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL },
{ "overlay", "overlay", 2, 2, 0, ARG_MAGIC,
&config_overlay, "( OLcfgGlAt:34 NAME 'olcOverlay' "
"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
{ "password-hash", "hash", 2, 2, 0, ARG_MAGIC,
&config_passwd_hash, "( OLcfgGlAt:36 NAME 'olcPasswordHash' "
+ "EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString )", NULL, NULL },
{ "pidfile", "file", 2, 2, 0, ARG_STRING,
&slapd_pid_file, "( OLcfgGlAt:37 NAME 'olcPidFile' "
ARG_IGNORED, NULL,
#endif
"( OLcfgGlAt:38 NAME 'olcPlugin' "
+ "EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString )", NULL, NULL },
{ "pluginlog", "filename", 2, 2, 0,
#ifdef LDAP_SLAPI
"SUP labeledURI SINGLE-VALUE )", NULL, NULL },
{ "replica", "host or uri", 2, 0, 0, ARG_DB|ARG_MAGIC,
&config_replica, "( OLcfgDbAt:0.7 NAME 'olcReplica' "
+ "EQUALITY caseIgnoreMatch "
"SUP labeledURI X-ORDERED 'VALUES' )", NULL, NULL },
{ "replica-argsfile", NULL, 0, 0, 0, ARG_STRING,
&replica_argsFile, "( OLcfgGlAt:43 NAME 'olcReplicaArgsFile' "
"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
{ "require", "features", 2, 0, 7, ARG_MAY_DB|ARG_MAGIC,
&config_requires, "( OLcfgGlAt:47 NAME 'olcRequires' "
+ "EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString )", NULL, NULL },
{ "restrict", "op_list", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC,
&config_restrict, "( OLcfgGlAt:48 NAME 'olcRestrict' "
+ "EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString )", NULL, NULL },
{ "reverse-lookup", "on|off", 2, 2, 0,
#ifdef SLAPD_RLOOKUPS
"SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
{ "rootDSE", "file", 2, 2, 0, ARG_MAGIC|CFG_ROOTDSE,
&config_generic, "( OLcfgGlAt:51 NAME 'olcRootDSE' "
+ "EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString )", NULL, NULL },
{ "rootpw", "password", 2, 2, 0, ARG_BERVAL|ARG_DB|ARG_MAGIC,
&config_rootpw, "( OLcfgDbAt:0.9 NAME 'olcRootPW' "
"SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
{ "security", "factors", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC,
&config_security, "( OLcfgGlAt:59 NAME 'olcSecurity' "
+ "EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString )", NULL, NULL },
{ "sizelimit", "limit", 2, 0, 0, ARG_MAY_DB|ARG_MAGIC,
&config_sizelimit, "( OLcfgGlAt:60 NAME 'olcSizeLimit' "
"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
{ "subordinate", "[advertise]", 1, 2, 0, ARG_DB|ARG_MAGIC,
&config_subordinate, "( OLcfgDbAt:0.15 NAME 'olcSubordinate' "
- "SYNTAX OMsDirectoryString )", NULL, NULL },
+ "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
{ "suffix", "suffix", 2, 2, 0, ARG_DB|ARG_DN|ARG_QUOTE|ARG_MAGIC,
&config_suffix, "( OLcfgDbAt:0.10 NAME 'olcSuffix' "
+ "EQUALITY distinguishedNameMatch "
"SYNTAX OMsDN )", NULL, NULL },
{ "syncrepl", NULL, 0, 0, 0, ARG_DB|ARG_MAGIC,
&syncrepl_config, "( OLcfgDbAt:0.11 NAME 'olcSyncrepl' "
"SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
{ "updateref", "url", 2, 2, 0, ARG_DB|ARG_MAGIC,
&config_updateref, "( OLcfgDbAt:0.13 NAME 'olcUpdateRef' "
+ "EQUALITY caseIgnoreMatch "
"SUP labeledURI )", NULL, NULL },
{ NULL, NULL, 0, 0, 0, ARG_IGNORED,
NULL, NULL, NULL, NULL }
break;
case CFG_ACL:
- if ( parse_acl(c->be, c->fname, c->lineno, c->argc, c->argv, c->valx) ) {
+ /* Don't append to the global ACL if we're on a specific DB */
+ i = c->valx;
+ if ( c->be != frontendDB && frontendDB->be_acl && c->valx == -1 ) {
+ AccessControl *a;
+ i = 0;
+ for ( a=c->be->be_acl; a && a != frontendDB->be_acl;
+ a = a->acl_next )
+ i++;
+ }
+ if ( parse_acl(c->be, c->fname, c->lineno, c->argc, c->argv, i ) ) {
return 1;
}
break;
/* dealt with separately; don't let it get to bindconf */
;
+ } else if(!strncasecmp(c->argv[i], "host=", STRLENOF("host="))) {
+ /* dealt with separately; don't let it get to bindconf */
+ ;
+
+
} else if(!strncasecmp(c->argv[i], "suffix=", STRLENOF( "suffix="))) {
switch(add_replica_suffix(c->be, nr, c->argv[i] + STRLENOF("suffix="))) {
case 1:
struct timeval tv;
struct timeval *tvp;
- struct timeval *cat;
+ struct timeval cat;
time_t tdelta = 1;
struct re_s* rtask;
now = slap_get_time();
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
rtask = ldap_pvt_runqueue_next_sched( &slapd_rq, &cat );
- while ( cat && cat->tv_sec && cat->tv_sec <= now ) {
+ while ( rtask && cat.tv_sec && cat.tv_sec <= now ) {
if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask )) {
ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 );
} else {
}
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
- if ( cat && cat->tv_sec ) {
- time_t diff = difftime( cat->tv_sec, now );
+ if ( rtask && cat.tv_sec ) {
+ time_t diff = difftime( cat.tv_sec, now );
if ( diff == 0 ) diff = tdelta;
if ( tvp == NULL || diff < tv.tv_sec ) {
tv.tv_sec = diff;
switch ( slapMode & SLAP_MODE ) {
case SLAP_SERVER_MODE:
- ldap_pvt_thread_pool_init( &connection_pool,
- connection_pool_max, 0);
/* FALLTHRU */
case SLAP_TOOL_MODE:
slap_name = name;
+ ldap_pvt_thread_pool_init( &connection_pool,
+ connection_pool_max, 0);
ldap_pvt_thread_mutex_init( &entry2str_mutex );
ldap_pvt_thread_mutex_init( &replog_mutex );
return -1;
}
+ if ( rid_ptr[ STRLENOF( "rid=" ) ] == '-' ) {
+ return -1;
+ }
+
cookie->rid = strtoul( &rid_ptr[ STRLENOF( "rid=" ) ], &next, 10 );
if ( next == &rid_ptr[ STRLENOF( "rid=" ) ] || ( next[ 0 ] != ',' && next[ 0 ] != '\0' ) ) {
return -1;
/* sleep time */
a = attr_find( e->e_attrs, ad_errSleepTime );
- if ( a != NULL ) {
+ if ( a != NULL & a->a_nvals[ 0 ].bv_val[ 0 ] != '-' ) {
int sleepTime;
sleepTime = strtoul( a->a_nvals[ 0 ].bv_val, &next, 0 );
* unlock the list mutex.
*/
for ( se=sl->sl_head; se; se=se->se_next ) {
- if ( ber_bvcmp( &se->se_csn, oldcsn ) < 0 ) continue;
+ if ( ber_bvcmp( &se->se_csn, oldcsn ) <= 0 ) continue;
if ( ber_bvcmp( &se->se_csn, ctxcsn ) > 0 ) break;
if ( se->se_tag == LDAP_REQ_DELETE ) {
j = i;
}
/* This callback actually does some work...*/
-static int sasl_sc_sasl2dn( Operation *o, SlapReply *rs )
+static int sasl_sc_sasl2dn( Operation *op, SlapReply *rs )
{
- struct berval *ndn = o->o_callback->sc_private;
+ struct berval *ndn = op->o_callback->sc_private;
- if (rs->sr_type != REP_SEARCH) return 0;
+ if ( rs->sr_type != REP_SEARCH ) return LDAP_SUCCESS;
/* We only want to be called once */
if ( !BER_BVISNULL( ndn ) ) {
- o->o_tmpfree(ndn->bv_val, o->o_tmpmemctx);
+ op->o_tmpfree( ndn->bv_val, op->o_tmpmemctx );
BER_BVZERO( ndn );
Debug( LDAP_DEBUG_TRACE,
- "slap_sc_sasl2dn: search DN returned more than 1 entry\n", 0, 0, 0 );
- return -1;
+ "%s: slap_sc_sasl2dn: search DN returned more than 1 entry\n",
+ op->o_log_prefix, 0, 0 );
+ return LDAP_OTHER;
}
- ber_dupbv_x(ndn, &rs->sr_entry->e_nname, o->o_tmpmemctx);
- return 0;
+ ber_dupbv_x( ndn, &rs->sr_entry->e_nname, op->o_tmpmemctx );
+ return LDAP_SUCCESS;
}
} else if ( strchr( val, ':' ) != NULL ) {
char *next, *ptr = val;
unsigned dd, hh, mm, ss;
+
+ /* NOTE: the test for ptr[ 0 ] == '-'
+ * should go before the call to strtoul() */
dd = strtoul( ptr, &next, 10 );
- if ( next == ptr || next[0] != ':' ) {
+ if ( ptr[ 0 ] == '-' || next == ptr || next[0] != ':' ) {
snprintf( c->msg, sizeof( c->msg ),
"Error: parse_syncrepl_line: "
"invalid interval \"%s\", unable to parse days", val );
}
ptr = next + 1;
hh = strtoul( ptr, &next, 10 );
- if ( next == ptr || next[0] != ':' || hh > 24 ) {
+ if ( ptr[ 0 ] == '-' || next == ptr || next[0] != ':' || hh > 24 ) {
snprintf( c->msg, sizeof( c->msg ),
"Error: parse_syncrepl_line: "
"invalid interval \"%s\", unable to parse hours", val );
}
ptr = next + 1;
mm = strtoul( ptr, &next, 10 );
- if ( next == ptr || next[0] != ':' || mm > 60 ) {
+ if ( ptr[ 0 ] == '-' || next == ptr || next[0] != ':' || mm > 60 ) {
snprintf( c->msg, sizeof( c->msg ),
"Error: parse_syncrepl_line: "
"invalid interval \"%s\", unable to parse minutes", val );
}
ptr = next + 1;
ss = strtoul( ptr, &next, 10 );
- if ( next == ptr || next[0] != '\0' || ss > 60 ) {
+ if ( ptr[ 0 ] == '-' || next == ptr || next[0] != '\0' || ss > 60 ) {
snprintf( c->msg, sizeof( c->msg ),
"Error: parse_syncrepl_line: "
"invalid interval \"%s\", unable to parse seconds", val );