summaryrefslogtreecommitdiffstats
path: root/source/tdb
diff options
context:
space:
mode:
Diffstat (limited to 'source/tdb')
-rw-r--r--source/tdb/spinlock.c1
-rw-r--r--source/tdb/tdb.c35
-rw-r--r--source/tdb/tdb.h3
-rw-r--r--source/tdb/tdbbackup.c3
-rw-r--r--source/tdb/tdbdump.c1
-rw-r--r--source/tdb/tdbtest.c1
-rw-r--r--source/tdb/tdbtool.c1
-rw-r--r--source/tdb/tdbutil.c49
8 files changed, 86 insertions, 8 deletions
diff --git a/source/tdb/spinlock.c b/source/tdb/spinlock.c
index 74472854cf2..2370ce3bdd9 100644
--- a/source/tdb/spinlock.c
+++ b/source/tdb/spinlock.c
@@ -30,6 +30,7 @@
#include <errno.h>
#include <sys/stat.h>
#include <time.h>
+#include <signal.h>
#include "tdb.h"
#include "spinlock.h"
diff --git a/source/tdb/tdb.c b/source/tdb/tdb.c
index ed75a55e3e9..c57d23cb6f5 100644
--- a/source/tdb/tdb.c
+++ b/source/tdb/tdb.c
@@ -34,6 +34,7 @@
#include <errno.h>
#include <sys/mman.h>
#include <sys/stat.h>
+#include <signal.h>
#include "tdb.h"
#include "spinlock.h"
#else
@@ -160,6 +161,18 @@ struct list_struct {
*/
};
+/***************************************************************
+ Allow a caller to set a "alarm" flag that tdb can check to abort
+ a blocking lock on SIGALRM.
+***************************************************************/
+
+static sig_atomic_t *palarm_fired;
+
+void tdb_set_lock_alarm(sig_atomic_t *palarm)
+{
+ palarm_fired = palarm;
+}
+
/* a byte range locking function - return 0 on success
this functions locks/unlocks 1 byte at the specified offset.
@@ -186,6 +199,8 @@ static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset,
do {
ret = fcntl(tdb->fd,lck_type,&fl);
+ if (ret == -1 && errno == EINTR && palarm_fired && *palarm_fired)
+ break;
} while (ret == -1 && errno == EINTR);
if (ret == -1) {
@@ -193,6 +208,10 @@ static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset,
TDB_LOG((tdb, 5,"tdb_brlock failed (fd=%d) at offset %d rw_type=%d lck_type=%d\n",
tdb->fd, offset, rw_type, lck_type));
}
+ /* Was it an alarm timeout ? */
+ if (errno == EINTR && palarm_fired && *palarm_fired)
+ return TDB_ERRCODE(TDB_ERR_LOCK_TIMEOUT, -1);
+ /* Otherwise - generic lock error. */
/* errno set by fcntl */
return TDB_ERRCODE(TDB_ERR_LOCK, -1);
}
@@ -517,17 +536,20 @@ int tdb_printfreelist(TDB_CONTEXT *tdb)
/* read in the freelist top */
if (ofs_read(tdb, offset, &rec_ptr) == -1) {
+ tdb_unlock(tdb, -1, F_WRLCK);
return 0;
}
printf("freelist top=[0x%08x]\n", rec_ptr );
while (rec_ptr) {
if (tdb_read(tdb, rec_ptr, (char *)&rec, sizeof(rec), DOCONV()) == -1) {
+ tdb_unlock(tdb, -1, F_WRLCK);
return -1;
}
if (rec.magic != TDB_FREE_MAGIC) {
printf("bad magic 0x%08x in free list\n", rec.magic);
+ tdb_unlock(tdb, -1, F_WRLCK);
return -1;
}
@@ -1030,6 +1052,12 @@ static int tdb_update(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf)
}
/* find an entry in the database given a key */
+/* If an entry doesn't exist tdb_err will be set to
+ * TDB_ERR_NOEXIST. If a key has no data attached
+ * tdb_err will not be set. Both will return a
+ * zero pptr and zero dsize.
+ */
+
TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key)
{
tdb_off rec_ptr;
@@ -1040,8 +1068,11 @@ TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key)
if (!(rec_ptr = tdb_find_lock(tdb,key,F_RDLCK,&rec)))
return tdb_null;
- ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec) + rec.key_len,
- rec.data_len);
+ if (rec.data_len)
+ ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec) + rec.key_len,
+ rec.data_len);
+ else
+ ret.dptr = NULL;
ret.dsize = rec.data_len;
tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
return ret;
diff --git a/source/tdb/tdb.h b/source/tdb/tdb.h
index 8cc908703f8..dda89d03559 100644
--- a/source/tdb/tdb.h
+++ b/source/tdb/tdb.h
@@ -44,7 +44,7 @@ extern "C" {
/* error codes */
enum TDB_ERROR {TDB_SUCCESS=0, TDB_ERR_CORRUPT, TDB_ERR_IO, TDB_ERR_LOCK,
- TDB_ERR_OOM, TDB_ERR_EXISTS, TDB_ERR_NOEXIST, TDB_ERR_NOLOCK };
+ TDB_ERR_OOM, TDB_ERR_EXISTS, TDB_ERR_NOEXIST, TDB_ERR_NOLOCK, TDB_ERR_LOCK_TIMEOUT };
#ifndef u32
#define u32 unsigned
@@ -126,6 +126,7 @@ int tdb_lockall(TDB_CONTEXT *tdb);
void tdb_unlockall(TDB_CONTEXT *tdb);
/* Low level locking functions: use with care */
+void tdb_set_lock_alarm(sig_atomic_t *palarm);
int tdb_chainlock(TDB_CONTEXT *tdb, TDB_DATA key);
int tdb_chainunlock(TDB_CONTEXT *tdb, TDB_DATA key);
diff --git a/source/tdb/tdbbackup.c b/source/tdb/tdbbackup.c
index 48c4272d331..659aeb01e37 100644
--- a/source/tdb/tdbbackup.c
+++ b/source/tdb/tdbbackup.c
@@ -53,7 +53,9 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <ctype.h>
+#include <signal.h>
#include "tdb.h"
+#include "version.h"
static int failed;
@@ -227,6 +229,7 @@ static int verify_tdb(const char *fname, const char *bak_name)
static void usage(void)
{
printf("Usage: tdbbackup [options] <fname...>\n\n");
+ printf("Version: %s\n", VERSION);
printf(" -h this help message\n");
printf(" -s suffix set the backup suffix\n");
printf(" -v veryify mode (restore if corrupt)\n");
diff --git a/source/tdb/tdbdump.c b/source/tdb/tdbdump.c
index 66642132093..9c1dc2761b6 100644
--- a/source/tdb/tdbdump.c
+++ b/source/tdb/tdbdump.c
@@ -30,6 +30,7 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <ctype.h>
+#include <signal.h>
#include "tdb.h"
static void print_data(TDB_DATA d)
diff --git a/source/tdb/tdbtest.c b/source/tdb/tdbtest.c
index 0741073ce11..89295a3291f 100644
--- a/source/tdb/tdbtest.c
+++ b/source/tdb/tdbtest.c
@@ -8,6 +8,7 @@
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
+#include <signal.h>
#include "tdb.h"
#include <gdbm.h>
diff --git a/source/tdb/tdbtool.c b/source/tdb/tdbtool.c
index 3ae955901c2..d27160e0e84 100644
--- a/source/tdb/tdbtool.c
+++ b/source/tdb/tdbtool.c
@@ -33,6 +33,7 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <ctype.h>
+#include <signal.h>
#include "tdb.h"
/* a tdb tool for manipulating a tdb database */
diff --git a/source/tdb/tdbutil.c b/source/tdb/tdbutil.c
index 5250d675c91..91dfacaf5d8 100644
--- a/source/tdb/tdbutil.c
+++ b/source/tdb/tdbutil.c
@@ -23,18 +23,57 @@
/* these are little tdb utility functions that are meant to make
dealing with a tdb database a little less cumbersome in Samba */
+static SIG_ATOMIC_T gotalarm;
+
+/***************************************************************
+ Signal function to tell us we timed out.
+****************************************************************/
+
+static void gotalarm_sig(void)
+{
+ gotalarm = 1;
+}
+
+/****************************************************************************
+ Lock a chain with timeout (in seconds).
+****************************************************************************/
+
+int tdb_chainlock_with_timeout( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout)
+{
+ /* Allow tdb_chainlock to be interrupted by an alarm. */
+ int ret;
+ gotalarm = 0;
+ tdb_set_lock_alarm(&gotalarm);
+
+ if (timeout) {
+ CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
+ alarm(timeout);
+ }
+
+ ret = tdb_chainlock(tdb, key);
+
+ if (timeout) {
+ alarm(0);
+ CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
+ if (gotalarm)
+ return -1;
+ }
+
+ return ret;
+}
+
/****************************************************************************
- Lock a chain by string.
+ Lock a chain by string. Return -1 if timeout or lock failed.
****************************************************************************/
-int tdb_lock_bystring(TDB_CONTEXT *tdb, char *keyval)
+int tdb_lock_bystring(TDB_CONTEXT *tdb, char *keyval, unsigned int timeout)
{
TDB_DATA key;
key.dptr = keyval;
key.dsize = strlen(keyval)+1;
- return tdb_chainlock(tdb, key);
+ return tdb_chainlock_with_timeout(tdb, key, timeout);
}
/****************************************************************************
@@ -215,7 +254,7 @@ int32 tdb_change_int32_atomic(TDB_CONTEXT *tdb, char *keystr, int32 *oldval, int
int32 val;
int32 ret = -1;
- if (tdb_lock_bystring(tdb, keystr) == -1)
+ if (tdb_lock_bystring(tdb, keystr,0) == -1)
return -1;
if ((val = tdb_fetch_int32(tdb, keystr)) == -1) {
@@ -256,7 +295,7 @@ BOOL tdb_change_uint32_atomic(TDB_CONTEXT *tdb, char *keystr, uint32 *oldval, ui
uint32 val;
BOOL ret = False;
- if (tdb_lock_bystring(tdb, keystr) == -1)
+ if (tdb_lock_bystring(tdb, keystr,0) == -1)
return False;
if (!tdb_fetch_uint32(tdb, keystr, &val)) {