summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/lib/tdb/common/dump.c11
-rw-r--r--source4/lib/tdb/common/freelist.c10
-rw-r--r--source4/lib/tdb/common/freelistcheck.c2
-rw-r--r--source4/lib/tdb/common/tdb_private.h2
-rw-r--r--source4/lib/tdb/config.mk1
-rw-r--r--source4/lib/tdb/tools/tdbbackup.c186
-rw-r--r--source4/lib/tdb/tools/tdbdump.c57
7 files changed, 243 insertions, 26 deletions
diff --git a/source4/lib/tdb/common/dump.c b/source4/lib/tdb/common/dump.c
index 577f23aac6..3f5c2c87f5 100644
--- a/source4/lib/tdb/common/dump.c
+++ b/source4/lib/tdb/common/dump.c
@@ -28,7 +28,8 @@
#include "tdb_private.h"
-static tdb_off_t tdb_dump_record(struct tdb_context *tdb, tdb_off_t offset)
+static tdb_off_t tdb_dump_record(struct tdb_context *tdb, int hash,
+ tdb_off_t offset)
{
struct list_struct rec;
tdb_off_t tailer_ofs, tailer;
@@ -39,8 +40,10 @@ static tdb_off_t tdb_dump_record(struct tdb_context *tdb, tdb_off_t offset)
return 0;
}
- printf(" rec: offset=0x%08x next=0x%08x rec_len=%d key_len=%d data_len=%d full_hash=0x%x magic=0x%x\n",
- offset, rec.next, rec.rec_len, rec.key_len, rec.data_len, rec.full_hash, rec.magic);
+ printf(" rec: hash=%d offset=0x%08x next=0x%08x rec_len=%d "
+ "key_len=%d data_len=%d full_hash=0x%x magic=0x%x\n",
+ hash, offset, rec.next, rec.rec_len, rec.key_len, rec.data_len,
+ rec.full_hash, rec.magic);
tailer_ofs = offset + sizeof(rec) + rec.rec_len - sizeof(tdb_off_t);
@@ -72,7 +75,7 @@ static int tdb_dump_chain(struct tdb_context *tdb, int i)
printf("hash=%d\n", i);
while (rec_ptr) {
- rec_ptr = tdb_dump_record(tdb, rec_ptr);
+ rec_ptr = tdb_dump_record(tdb, i, rec_ptr);
}
return tdb_unlock(tdb, i, F_WRLCK);
diff --git a/source4/lib/tdb/common/freelist.c b/source4/lib/tdb/common/freelist.c
index 0efe47f879..01b61aff86 100644
--- a/source4/lib/tdb/common/freelist.c
+++ b/source4/lib/tdb/common/freelist.c
@@ -29,7 +29,7 @@
#include "tdb_private.h"
/* read a freelist record and check for simple errors */
-int rec_free_read(struct tdb_context *tdb, tdb_off_t off, struct list_struct *rec)
+int tdb_rec_free_read(struct tdb_context *tdb, tdb_off_t off, struct list_struct *rec)
{
if (tdb->methods->tdb_read(tdb, off, rec, sizeof(*rec),DOCONV()) == -1)
return -1;
@@ -37,7 +37,7 @@ int rec_free_read(struct tdb_context *tdb, tdb_off_t off, struct list_struct *re
if (rec->magic == TDB_MAGIC) {
/* this happens when a app is showdown while deleting a record - we should
not completely fail when this happens */
- TDB_LOG((tdb, TDB_DEBUG_WARNING, "rec_free_read non-free magic 0x%x at offset=%d - fixing\n",
+ TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_rec_free_read non-free magic 0x%x at offset=%d - fixing\n",
rec->magic, off));
rec->magic = TDB_FREE_MAGIC;
if (tdb->methods->tdb_write(tdb, off, rec, sizeof(*rec)) == -1)
@@ -47,7 +47,7 @@ int rec_free_read(struct tdb_context *tdb, tdb_off_t off, struct list_struct *re
if (rec->magic != TDB_FREE_MAGIC) {
/* Ensure ecode is set for log fn. */
tdb->ecode = TDB_ERR_CORRUPT;
- TDB_LOG((tdb, TDB_DEBUG_WARNING, "rec_free_read bad magic 0x%x at offset=%d\n",
+ TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_rec_free_read bad magic 0x%x at offset=%d\n",
rec->magic, off));
return TDB_ERRCODE(TDB_ERR_CORRUPT, -1);
}
@@ -286,7 +286,7 @@ tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct list_st
issues when faced with a slowly increasing record size.
*/
while (rec_ptr) {
- if (rec_free_read(tdb, rec_ptr, rec) == -1) {
+ if (tdb_rec_free_read(tdb, rec_ptr, rec) == -1) {
goto fail;
}
@@ -311,7 +311,7 @@ tdb_off_t tdb_allocate(struct tdb_context *tdb, tdb_len_t length, struct list_st
}
if (bestfit.rec_ptr != 0) {
- if (rec_free_read(tdb, bestfit.rec_ptr, rec) == -1) {
+ if (tdb_rec_free_read(tdb, bestfit.rec_ptr, rec) == -1) {
goto fail;
}
diff --git a/source4/lib/tdb/common/freelistcheck.c b/source4/lib/tdb/common/freelistcheck.c
index 63d2dbadc2..19368f6ad6 100644
--- a/source4/lib/tdb/common/freelistcheck.c
+++ b/source4/lib/tdb/common/freelistcheck.c
@@ -88,7 +88,7 @@ int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries)
goto fail;
}
- if (rec_free_read(tdb, rec_ptr, &rec) == -1) {
+ if (tdb_rec_free_read(tdb, rec_ptr, &rec) == -1) {
goto fail;
}
diff --git a/source4/lib/tdb/common/tdb_private.h b/source4/lib/tdb/common/tdb_private.h
index 7219a1a2e2..02a23d0387 100644
--- a/source4/lib/tdb/common/tdb_private.h
+++ b/source4/lib/tdb/common/tdb_private.h
@@ -206,5 +206,7 @@ tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, u32 hash, in
struct list_struct *rec);
void tdb_io_init(struct tdb_context *tdb);
int tdb_expand(struct tdb_context *tdb, tdb_off_t size);
+int tdb_rec_free_read(struct tdb_context *tdb, tdb_off_t off,
+ struct list_struct *rec);
diff --git a/source4/lib/tdb/config.mk b/source4/lib/tdb/config.mk
index 24e9de744c..ab90ed728d 100644
--- a/source4/lib/tdb/config.mk
+++ b/source4/lib/tdb/config.mk
@@ -51,7 +51,6 @@ PRIVATE_DEPENDENCIES = \
# Start BINARY tdbbackup
[BINARY::tdbbackup]
INSTALLDIR = BINDIR
-ENABLE = NO
OBJ_FILES= \
tools/tdbbackup.o
PRIVATE_DEPENDENCIES = \
diff --git a/source4/lib/tdb/tools/tdbbackup.c b/source4/lib/tdb/tools/tdbbackup.c
index 45beb5e292..2e728d46aa 100644
--- a/source4/lib/tdb/tools/tdbbackup.c
+++ b/source4/lib/tdb/tools/tdbbackup.c
@@ -42,8 +42,181 @@
*/
#include "replace.h"
-#include "tdb.h"
+#include "system/locale.h"
+#include "system/time.h"
#include "system/filesys.h"
+#include "tdb.h"
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+static int failed;
+
+static char *add_suffix(const char *name, const char *suffix)
+{
+ char *ret;
+ int len = strlen(name) + strlen(suffix) + 1;
+ ret = (char *)malloc(len);
+ if (!ret) {
+ fprintf(stderr,"Out of memory!\n");
+ exit(1);
+ }
+ snprintf(ret, len, "%s%s", name, suffix);
+ return ret;
+}
+
+static int copy_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+ TDB_CONTEXT *tdb_new = (TDB_CONTEXT *)state;
+
+ if (tdb_store(tdb_new, key, dbuf, TDB_INSERT) != 0) {
+ fprintf(stderr,"Failed to insert into %s\n", tdb_name(tdb));
+ failed = 1;
+ return 1;
+ }
+ return 0;
+}
+
+
+static int test_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+{
+ return 0;
+}
+
+/*
+ carefully backup a tdb, validating the contents and
+ only doing the backup if its OK
+ this function is also used for restore
+*/
+static int backup_tdb(const char *old_name, const char *new_name, int hash_size)
+{
+ TDB_CONTEXT *tdb;
+ TDB_CONTEXT *tdb_new;
+ char *tmp_name;
+ struct stat st;
+ int count1, count2;
+
+ tmp_name = add_suffix(new_name, ".tmp");
+
+ /* stat the old tdb to find its permissions */
+ if (stat(old_name, &st) != 0) {
+ perror(old_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ /* open the old tdb */
+ tdb = tdb_open(old_name, 0, 0, O_RDWR, 0);
+ if (!tdb) {
+ printf("Failed to open %s\n", old_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ /* create the new tdb */
+ unlink(tmp_name);
+ tdb_new = tdb_open(tmp_name,
+ hash_size ? hash_size : tdb_hash_size(tdb),
+ TDB_DEFAULT, O_RDWR|O_CREAT|O_EXCL,
+ st.st_mode & 0777);
+ if (!tdb_new) {
+ perror(tmp_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ /* lock the old tdb */
+ if (tdb_lockall(tdb) != 0) {
+ fprintf(stderr,"Failed to lock %s\n", old_name);
+ tdb_close(tdb);
+ tdb_close(tdb_new);
+ unlink(tmp_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ failed = 0;
+
+ /* traverse and copy */
+ count1 = tdb_traverse(tdb, copy_fn, (void *)tdb_new);
+ if (count1 < 0 || failed) {
+ fprintf(stderr,"failed to copy %s\n", old_name);
+ tdb_close(tdb);
+ tdb_close(tdb_new);
+ unlink(tmp_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ /* close the old tdb */
+ tdb_close(tdb);
+
+ /* close the new tdb and re-open read-only */
+ tdb_close(tdb_new);
+ tdb_new = tdb_open(tmp_name, 0, TDB_DEFAULT, O_RDONLY, 0);
+ if (!tdb_new) {
+ fprintf(stderr,"failed to reopen %s\n", tmp_name);
+ unlink(tmp_name);
+ perror(tmp_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ /* traverse the new tdb to confirm */
+ count2 = tdb_traverse(tdb_new, test_fn, 0);
+ if (count2 != count1) {
+ fprintf(stderr,"failed to copy %s\n", old_name);
+ tdb_close(tdb_new);
+ unlink(tmp_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ /* make sure the new tdb has reached stable storage */
+ fsync(tdb_fd(tdb_new));
+
+ /* close the new tdb and rename it to .bak */
+ tdb_close(tdb_new);
+ unlink(new_name);
+ if (rename(tmp_name, new_name) != 0) {
+ perror(new_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ free(tmp_name);
+
+ return 0;
+}
+
+/*
+ verify a tdb and if it is corrupt then restore from *.bak
+*/
+static int verify_tdb(const char *fname, const char *bak_name)
+{
+ TDB_CONTEXT *tdb;
+ int count = -1;
+
+ /* open the tdb */
+ tdb = tdb_open(fname, 0, 0, O_RDONLY, 0);
+
+ /* traverse the tdb, then close it */
+ if (tdb) {
+ count = tdb_traverse(tdb, test_fn, NULL);
+ tdb_close(tdb);
+ }
+
+ /* count is < 0 means an error */
+ if (count < 0) {
+ printf("restoring %s\n", fname);
+ return backup_tdb(bak_name, fname, 0);
+ }
+
+ printf("%s : %d records\n", fname, count);
+
+ return 0;
+}
/*
see if one file is newer than another
@@ -66,6 +239,7 @@ static void usage(void)
printf(" -h this help message\n");
printf(" -s suffix set the backup suffix\n");
printf(" -v verify mode (restore if corrupt)\n");
+ printf(" -n hashsize set the new hash size for the backup\n");
}
@@ -75,11 +249,10 @@ static void usage(void)
int ret = 0;
int c;
int verify = 0;
+ int hashsize = 0;
const char *suffix = ".bak";
- extern int optind;
- extern char *optarg;
- while ((c = getopt(argc, argv, "vhs:")) != -1) {
+ while ((c = getopt(argc, argv, "vhs:n:")) != -1) {
switch (c) {
case 'h':
usage();
@@ -90,6 +263,9 @@ static void usage(void)
case 's':
suffix = optarg;
break;
+ case 'n':
+ hashsize = atoi(optarg);
+ break;
}
}
@@ -113,7 +289,7 @@ static void usage(void)
}
} else {
if (file_newer(fname, bak_name) &&
- backup_tdb(fname, bak_name) != 0) {
+ backup_tdb(fname, bak_name, hashsize) != 0) {
ret = 1;
}
}
diff --git a/source4/lib/tdb/tools/tdbdump.c b/source4/lib/tdb/tools/tdbdump.c
index 9111b739ab..4ceef2d60c 100644
--- a/source4/lib/tdb/tools/tdbdump.c
+++ b/source4/lib/tdb/tools/tdbdump.c
@@ -19,9 +19,10 @@
*/
#include "replace.h"
-#include "tdb.h"
#include "system/locale.h"
+#include "system/time.h"
#include "system/filesys.h"
+#include "tdb.h"
static void print_data(TDB_DATA d)
{
@@ -37,22 +38,23 @@ static void print_data(TDB_DATA d)
}
}
-static int traverse_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
+static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
{
printf("{\n");
- printf("key = \"");
+ printf("key(%d) = \"", (int)key.dsize);
print_data(key);
printf("\"\n");
- printf("data = \"");
+ printf("data(%d) = \"", (int)dbuf.dsize);
print_data(dbuf);
printf("\"\n");
printf("}\n");
return 0;
}
-static int dump_tdb(const char *fname)
+static int dump_tdb(const char *fname, const char *keyname)
{
- struct tdb_context *tdb;
+ TDB_CONTEXT *tdb;
+ TDB_DATA key, value;
tdb = tdb_open(fname, 0, 0, O_RDONLY, 0);
if (!tdb) {
@@ -60,20 +62,55 @@ static int dump_tdb(const char *fname)
return 1;
}
- tdb_traverse(tdb, traverse_fn, NULL);
+ if (!keyname) {
+ tdb_traverse(tdb, traverse_fn, NULL);
+ } else {
+ key.dptr = discard_const_p(uint8_t,keyname);
+ key.dsize = strlen( keyname);
+ value = tdb_fetch(tdb, key);
+ if (!value.dptr) {
+ return 1;
+ } else {
+ print_data(value);
+ free(value.dptr);
+ }
+ }
+
return 0;
}
+static void usage( void)
+{
+ printf( "Usage: tdbdump [options] <filename>\n\n");
+ printf( " -h this help message\n");
+ printf( " -k keyname dumps value of keyname\n");
+}
+
int main(int argc, char *argv[])
{
- char *fname;
+ char *fname, *keyname=NULL;
+ int c;
if (argc < 2) {
printf("Usage: tdbdump <fname>\n");
exit(1);
}
- fname = argv[1];
+ while ((c = getopt( argc, argv, "hk:")) != -1) {
+ switch (c) {
+ case 'h':
+ usage();
+ exit( 0);
+ case 'k':
+ keyname = optarg;
+ break;
+ default:
+ usage();
+ exit( 1);
+ }
+ }
+
+ fname = argv[optind];
- return dump_tdb(fname);
+ return dump_tdb(fname, keyname);
}