diff options
Diffstat (limited to 'source/tdb')
-rw-r--r-- | source/tdb/spinlock.c | 1 | ||||
-rw-r--r-- | source/tdb/tdb.c | 35 | ||||
-rw-r--r-- | source/tdb/tdb.h | 3 | ||||
-rw-r--r-- | source/tdb/tdbbackup.c | 3 | ||||
-rw-r--r-- | source/tdb/tdbdump.c | 1 | ||||
-rw-r--r-- | source/tdb/tdbtest.c | 1 | ||||
-rw-r--r-- | source/tdb/tdbtool.c | 1 | ||||
-rw-r--r-- | source/tdb/tdbutil.c | 49 |
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)) { |