diff options
author | Stefan Metzmacher <metze@samba.org> | 2004-05-24 16:27:23 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:56:02 -0500 |
commit | a3d61e0485c70ec5215c34b6caf40e2e6c6c5338 (patch) | |
tree | c6dd1cdffceadf0e88f5ddbde8507c49478f55fa /source4/lib/tdb/tools | |
parent | 29a93d26cfc17dad96c74da9b05535b38552e4c0 (diff) | |
download | samba-a3d61e0485c70ec5215c34b6caf40e2e6c6c5338.tar.gz samba-a3d61e0485c70ec5215c34b6caf40e2e6c6c5338.tar.bz2 samba-a3d61e0485c70ec5215c34b6caf40e2e6c6c5338.zip |
r848: convert lib/tdb into the same layout as lib/ldb
metze
(This used to be commit bacab322ce89979f0ad0811cd15b73d81eceb69d)
Diffstat (limited to 'source4/lib/tdb/tools')
-rw-r--r-- | source4/lib/tdb/tools/Makefile | 29 | ||||
-rw-r--r-- | source4/lib/tdb/tools/tdbbackup.c | 149 | ||||
-rw-r--r-- | source4/lib/tdb/tools/tdbdump.c | 89 | ||||
-rw-r--r-- | source4/lib/tdb/tools/tdbtest.c | 263 | ||||
-rw-r--r-- | source4/lib/tdb/tools/tdbtool.c | 547 | ||||
-rw-r--r-- | source4/lib/tdb/tools/tdbtorture.c | 227 |
6 files changed, 1304 insertions, 0 deletions
diff --git a/source4/lib/tdb/tools/Makefile b/source4/lib/tdb/tools/Makefile new file mode 100644 index 0000000000..59fbb079bd --- /dev/null +++ b/source4/lib/tdb/tools/Makefile @@ -0,0 +1,29 @@ +# +# Makefile for tdb directory +# + +CFLAGS = -DSTANDALONE -DTDB_DEBUG -g -DHAVE_MMAP=1 +CC = gcc + +PROGS = tdbtest tdbtool tdbtorture +TDB_OBJ = tdb.o spinlock.o + +default: $(PROGS) + +tdbtest: tdbtest.o $(TDB_OBJ) + $(CC) $(CFLAGS) -o tdbtest tdbtest.o $(TDB_OBJ) -lgdbm + +tdbtool: tdbtool.o $(TDB_OBJ) + $(CC) $(CFLAGS) -o tdbtool tdbtool.o $(TDB_OBJ) + +tdbtorture: tdbtorture.o $(TDB_OBJ) + $(CC) $(CFLAGS) -o tdbtorture tdbtorture.o $(TDB_OBJ) + +tdbdump: tdbdump.o $(TDB_OBJ) + $(CC) $(CFLAGS) -o tdbdump tdbdump.o $(TDB_OBJ) + +tdbbackup: tdbbackup.o $(TDB_OBJ) + $(CC) $(CFLAGS) -o tdbbackup tdbbackup.o $(TDB_OBJ) + +clean: + rm -f $(PROGS) *.o *~ *% core test.db test.tdb test.gdbm diff --git a/source4/lib/tdb/tools/tdbbackup.c b/source4/lib/tdb/tools/tdbbackup.c new file mode 100644 index 0000000000..1a0e1c1588 --- /dev/null +++ b/source4/lib/tdb/tools/tdbbackup.c @@ -0,0 +1,149 @@ +/* + Unix SMB/CIFS implementation. + low level tdb backup and restore utility + Copyright (C) Andrew Tridgell 2002 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + + This program is meant for backup/restore of tdb databases. Typical usage would be: + tdbbackup *.tdb + when Samba shuts down cleanly, which will make a backup of all the local databases + to *.bak files. Then on Samba startup you would use: + tdbbackup -v *.tdb + and this will check the databases for corruption and if corruption is detected then + the backup will be restored. + + You may also like to do a backup on a regular basis while Samba is + running, perhaps using cron. + + The reason this program is needed is to cope with power failures + while Samba is running. A power failure could lead to database + corruption and Samba will then not start correctly. + + Note that many of the databases in Samba are transient and thus + don't need to be backed up, so you can optimise the above a little + by only running the backup on the critical databases. + + */ + +#ifdef STANDALONE +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <time.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <ctype.h> +#include <signal.h> + +#else + +#include "includes.h" + +#endif + +#include "tdb.h" +#include "tdbback.h" + +/* + see if one file is newer than another +*/ +static int file_newer(const char *fname1, const char *fname2) +{ + struct stat st1, st2; + if (stat(fname1, &st1) != 0) { + return 0; + } + if (stat(fname2, &st2) != 0) { + return 1; + } + return (st1.st_mtime > st2.st_mtime); +} + +static void usage(void) +{ + printf("Usage: tdbbackup [options] <fname...>\n\n"); + printf(" -h this help message\n"); + printf(" -s suffix set the backup suffix\n"); + printf(" -v verify mode (restore if corrupt)\n"); +} + + + int main(int argc, char *argv[]) +{ + int i; + int ret = 0; + int c; + int verify = 0; + const char *suffix = ".bak"; + extern int optind; + extern char *optarg; + + while ((c = getopt(argc, argv, "vhs:")) != -1) { + switch (c) { + case 'h': + usage(); + exit(0); + case 'v': + verify = 1; + break; + case 's': + suffix = optarg; + break; + } + } + + argc -= optind; + argv += optind; + + if (argc < 1) { + usage(); + exit(1); + } + + for (i=0; i<argc; i++) { + const char *fname = argv[i]; + char *bak_name; + + bak_name = add_suffix(fname, suffix); + + if (verify) { + if (verify_tdb(fname, bak_name) != 0) { + ret = 1; + } + } else { + if (file_newer(fname, bak_name) && + backup_tdb(fname, bak_name) != 0) { + ret = 1; + } + } + + free(bak_name); + } + + return ret; +} diff --git a/source4/lib/tdb/tools/tdbdump.c b/source4/lib/tdb/tools/tdbdump.c new file mode 100644 index 0000000000..9c1dc2761b --- /dev/null +++ b/source4/lib/tdb/tools/tdbdump.c @@ -0,0 +1,89 @@ +/* + Unix SMB/CIFS implementation. + simple tdb dump util + Copyright (C) Andrew Tridgell 2001 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <time.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <ctype.h> +#include <signal.h> +#include "tdb.h" + +static void print_data(TDB_DATA d) +{ + unsigned char *p = d.dptr; + int len = d.dsize; + while (len--) { + if (isprint(*p) && !strchr("\"\\", *p)) { + fputc(*p, stdout); + } else { + printf("\\%02X", *p); + } + p++; + } +} + +static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state) +{ + printf("{\n"); + printf("key = \""); + print_data(key); + printf("\"\n"); + printf("data = \""); + print_data(dbuf); + printf("\"\n"); + printf("}\n"); + return 0; +} + +static int dump_tdb(const char *fname) +{ + TDB_CONTEXT *tdb; + + tdb = tdb_open(fname, 0, 0, O_RDONLY, 0); + if (!tdb) { + printf("Failed to open %s\n", fname); + return 1; + } + + tdb_traverse(tdb, traverse_fn, NULL); + return 0; +} + + int main(int argc, char *argv[]) +{ + char *fname; + + if (argc < 2) { + printf("Usage: tdbdump <fname>\n"); + exit(1); + } + + fname = argv[1]; + + return dump_tdb(fname); +} diff --git a/source4/lib/tdb/tools/tdbtest.c b/source4/lib/tdb/tools/tdbtest.c new file mode 100644 index 0000000000..89295a3291 --- /dev/null +++ b/source4/lib/tdb/tools/tdbtest.c @@ -0,0 +1,263 @@ +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <stdarg.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <signal.h> +#include "tdb.h" +#include <gdbm.h> + +/* a test program for tdb - the trivial database */ + + + +#define DELETE_PROB 7 +#define STORE_PROB 5 + +static TDB_CONTEXT *db; +static GDBM_FILE gdbm; + +struct timeval tp1,tp2; + +static void start_timer(void) +{ + gettimeofday(&tp1,NULL); +} + +static double end_timer(void) +{ + gettimeofday(&tp2,NULL); + return((tp2.tv_sec - tp1.tv_sec) + + (tp2.tv_usec - tp1.tv_usec)*1.0e-6); +} + +static void fatal(char *why) +{ + perror(why); + exit(1); +} + +static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vfprintf(stdout, format, ap); + va_end(ap); + fflush(stdout); +} + +static void compare_db(void) +{ + TDB_DATA d, key, nextkey; + datum gd, gkey, gnextkey; + + key = tdb_firstkey(db); + while (key.dptr) { + d = tdb_fetch(db, key); + gkey.dptr = key.dptr; + gkey.dsize = key.dsize; + + gd = gdbm_fetch(gdbm, gkey); + + if (!gd.dptr) fatal("key not in gdbm"); + if (gd.dsize != d.dsize) fatal("data sizes differ"); + if (memcmp(gd.dptr, d.dptr, d.dsize)) { + fatal("data differs"); + } + + nextkey = tdb_nextkey(db, key); + free(key.dptr); + free(d.dptr); + free(gd.dptr); + key = nextkey; + } + + gkey = gdbm_firstkey(gdbm); + while (gkey.dptr) { + gd = gdbm_fetch(gdbm, gkey); + key.dptr = gkey.dptr; + key.dsize = gkey.dsize; + + d = tdb_fetch(db, key); + + if (!d.dptr) fatal("key not in db"); + if (d.dsize != gd.dsize) fatal("data sizes differ"); + if (memcmp(d.dptr, gd.dptr, gd.dsize)) { + fatal("data differs"); + } + + gnextkey = gdbm_nextkey(gdbm, gkey); + free(gkey.dptr); + free(gd.dptr); + free(d.dptr); + gkey = gnextkey; + } +} + +static char *randbuf(int len) +{ + char *buf; + int i; + buf = (char *)malloc(len+1); + + for (i=0;i<len;i++) { + buf[i] = 'a' + (rand() % 26); + } + buf[i] = 0; + return buf; +} + +static void addrec_db(void) +{ + int klen, dlen; + char *k, *d; + TDB_DATA key, data; + + klen = 1 + (rand() % 4); + dlen = 1 + (rand() % 100); + + k = randbuf(klen); + d = randbuf(dlen); + + key.dptr = k; + key.dsize = klen+1; + + data.dptr = d; + data.dsize = dlen+1; + + if (rand() % DELETE_PROB == 0) { + tdb_delete(db, key); + } else if (rand() % STORE_PROB == 0) { + if (tdb_store(db, key, data, TDB_REPLACE) != 0) { + fatal("tdb_store failed"); + } + } else { + data = tdb_fetch(db, key); + if (data.dptr) free(data.dptr); + } + + free(k); + free(d); +} + +static void addrec_gdbm(void) +{ + int klen, dlen; + char *k, *d; + datum key, data; + + klen = 1 + (rand() % 4); + dlen = 1 + (rand() % 100); + + k = randbuf(klen); + d = randbuf(dlen); + + key.dptr = k; + key.dsize = klen+1; + + data.dptr = d; + data.dsize = dlen+1; + + if (rand() % DELETE_PROB == 0) { + gdbm_delete(gdbm, key); + } else if (rand() % STORE_PROB == 0) { + if (gdbm_store(gdbm, key, data, GDBM_REPLACE) != 0) { + fatal("gdbm_store failed"); + } + } else { + data = gdbm_fetch(gdbm, key); + if (data.dptr) free(data.dptr); + } + + free(k); + free(d); +} + +static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state) +{ +#if 0 + printf("[%s] [%s]\n", key.dptr, dbuf.dptr); +#endif + tdb_delete(tdb, key); + return 0; +} + +static void merge_test(void) +{ + int i; + char keys[5][2]; + TDB_DATA key, data; + + for (i = 0; i < 5; i++) { + sprintf(keys[i], "%d", i); + key.dptr = keys[i]; + key.dsize = 2; + + data.dptr = "test"; + data.dsize = 4; + + if (tdb_store(db, key, data, TDB_REPLACE) != 0) { + fatal("tdb_store failed"); + } + } + + key.dptr = keys[0]; + tdb_delete(db, key); + key.dptr = keys[4]; + tdb_delete(db, key); + key.dptr = keys[2]; + tdb_delete(db, key); + key.dptr = keys[1]; + tdb_delete(db, key); + key.dptr = keys[3]; + tdb_delete(db, key); +} + +int main(int argc, char *argv[]) +{ + int i, seed=0; + int loops = 10000; + + unlink("test.gdbm"); + + db = tdb_open("test.tdb", 0, TDB_CLEAR_IF_FIRST, + O_RDWR | O_CREAT | O_TRUNC, 0600); + gdbm = gdbm_open("test.gdbm", 512, GDBM_WRITER|GDBM_NEWDB|GDBM_FAST, + 0600, NULL); + + if (!db || !gdbm) { + fatal("db open failed"); + } + + tdb_logging_function(db, tdb_log); + +#if 1 + srand(seed); + start_timer(); + for (i=0;i<loops;i++) addrec_gdbm(); + printf("gdbm got %.2f ops/sec\n", i/end_timer()); +#endif + + merge_test(); + + srand(seed); + start_timer(); + for (i=0;i<loops;i++) addrec_db(); + printf("tdb got %.2f ops/sec\n", i/end_timer()); + + compare_db(); + + printf("traversed %d records\n", tdb_traverse(db, traverse_fn, NULL)); + printf("traversed %d records\n", tdb_traverse(db, traverse_fn, NULL)); + + tdb_close(db); + gdbm_close(gdbm); + + return 0; +} diff --git a/source4/lib/tdb/tools/tdbtool.c b/source4/lib/tdb/tools/tdbtool.c new file mode 100644 index 0000000000..92009dcef4 --- /dev/null +++ b/source4/lib/tdb/tools/tdbtool.c @@ -0,0 +1,547 @@ +/* + Unix SMB/CIFS implementation. + Samba database functions + Copyright (C) Andrew Tridgell 1999-2000 + Copyright (C) Paul `Rusty' Russell 2000 + Copyright (C) Jeremy Allison 2000 + Copyright (C) Andrew Esh 2001 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <time.h> +#include <sys/mman.h> +#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 */ + +#define FSTRING_LEN 256 +typedef char fstring[FSTRING_LEN]; + +typedef struct connections_key { + pid_t pid; + int cnum; + fstring name; +} connections_key; + +typedef struct connections_data { + int magic; + pid_t pid; + int cnum; + uid_t uid; + gid_t gid; + char name[24]; + char addr[24]; + char machine[128]; + time_t start; +} connections_data; + +static TDB_CONTEXT *tdb; + +static int print_rec(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state); + +static void print_asc(unsigned char *buf,int len) +{ + int i; + + /* We're probably printing ASCII strings so don't try to display + the trailing NULL character. */ + + if (buf[len - 1] == 0) + len--; + + for (i=0;i<len;i++) + printf("%c",isprint(buf[i])?buf[i]:'.'); +} + +static void print_data(unsigned char *buf,int len) +{ + int i=0; + if (len<=0) return; + printf("[%03X] ",i); + for (i=0;i<len;) { + printf("%02X ",(int)buf[i]); + i++; + if (i%8 == 0) printf(" "); + if (i%16 == 0) { + print_asc(&buf[i-16],8); printf(" "); + print_asc(&buf[i-8],8); printf("\n"); + if (i<len) printf("[%03X] ",i); + } + } + if (i%16) { + int n; + + n = 16 - (i%16); + printf(" "); + if (n>8) printf(" "); + while (n--) printf(" "); + + n = i%16; + if (n > 8) n = 8; + print_asc(&buf[i-(i%16)],n); printf(" "); + n = (i%16) - n; + if (n>0) print_asc(&buf[i-n],n); + printf("\n"); + } +} + +static void help(void) +{ + printf("\n" +"tdbtool: \n" +" create dbname : create a database\n" +" open dbname : open an existing database\n" +" erase : erase the database\n" +" dump : dump the database as strings\n" +" insert key data : insert a record\n" +" move key file : move a record to a destination tdb\n" +" store key data : store a record (replace)\n" +" show key : show a record by key\n" +" delete key : delete a record by key\n" +" list : print the database hash table and freelist\n" +" free : print the database freelist\n" +" 1 | first : print the first record\n" +" n | next : print the next record\n" +" q | quit : terminate\n" +" \\n : repeat 'next' command\n" +"\n"); +} + +static void terror(char *why) +{ + printf("%s\n", why); +} + +static char *get_token(int startover) +{ + static char tmp[1024]; + static char *cont = NULL; + char *insert, *start; + char *k = strtok(NULL, " "); + + if (!k) + return NULL; + + if (startover) + start = tmp; + else + start = cont; + + strcpy(start, k); + insert = start + strlen(start) - 1; + while (*insert == '\\') { + *insert++ = ' '; + k = strtok(NULL, " "); + if (!k) + break; + strcpy(insert, k); + insert = start + strlen(start) - 1; + } + + /* Get ready for next call */ + cont = start + strlen(start) + 1; + return start; +} + +static void create_tdb(void) +{ + char *tok = get_token(1); + if (!tok) { + help(); + return; + } + if (tdb) tdb_close(tdb); + tdb = tdb_open(tok, 0, TDB_CLEAR_IF_FIRST, + O_RDWR | O_CREAT | O_TRUNC, 0600); + if (!tdb) { + printf("Could not create %s: %s\n", tok, strerror(errno)); + } +} + +static void open_tdb(void) +{ + char *tok = get_token(1); + if (!tok) { + help(); + return; + } + if (tdb) tdb_close(tdb); + tdb = tdb_open(tok, 0, 0, O_RDWR, 0600); + if (!tdb) { + printf("Could not open %s: %s\n", tok, strerror(errno)); + } +} + +static void insert_tdb(void) +{ + char *k = get_token(1); + char *d = get_token(0); + TDB_DATA key, dbuf; + + if (!k || !d) { + help(); + return; + } + + key.dptr = k; + key.dsize = strlen(k)+1; + dbuf.dptr = d; + dbuf.dsize = strlen(d)+1; + + if (tdb_store(tdb, key, dbuf, TDB_INSERT) == -1) { + terror("insert failed"); + } +} + +static void store_tdb(void) +{ + char *k = get_token(1); + char *d = get_token(0); + TDB_DATA key, dbuf; + + if (!k || !d) { + help(); + return; + } + + key.dptr = k; + key.dsize = strlen(k)+1; + dbuf.dptr = d; + dbuf.dsize = strlen(d)+1; + + printf("Storing key:\n"); + print_rec(tdb, key, dbuf, NULL); + + if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) { + terror("store failed"); + } +} + +static void show_tdb(void) +{ + char *k = get_token(1); + TDB_DATA key, dbuf; + + if (!k) { + help(); + return; + } + + key.dptr = k; + key.dsize = strlen(k)+1; + + dbuf = tdb_fetch(tdb, key); + if (!dbuf.dptr) { + /* maybe it is non-NULL terminated key? */ + key.dsize = strlen(k); + dbuf = tdb_fetch(tdb, key); + + if ( !dbuf.dptr ) { + terror("fetch failed"); + return; + } + } + + /* printf("%s : %*.*s\n", k, (int)dbuf.dsize, (int)dbuf.dsize, dbuf.dptr); */ + print_rec(tdb, key, dbuf, NULL); + + free( dbuf.dptr ); + + return; +} + +static void delete_tdb(void) +{ + char *k = get_token(1); + TDB_DATA key; + + if (!k) { + help(); + return; + } + + key.dptr = k; + key.dsize = strlen(k)+1; + + if (tdb_delete(tdb, key) != 0) { + terror("delete failed"); + } +} + +static void move_rec(void) +{ + char *k = get_token(1); + char *file = get_token(0); + TDB_DATA key, dbuf; + TDB_CONTEXT *dst_tdb; + + if (!k) { + help(); + return; + } + + if ( !file ) { + terror("need destination tdb name"); + return; + } + + key.dptr = k; + key.dsize = strlen(k)+1; + + dbuf = tdb_fetch(tdb, key); + if (!dbuf.dptr) { + /* maybe it is non-NULL terminated key? */ + key.dsize = strlen(k); + dbuf = tdb_fetch(tdb, key); + + if ( !dbuf.dptr ) { + terror("fetch failed"); + return; + } + } + + print_rec(tdb, key, dbuf, NULL); + + dst_tdb = tdb_open(file, 0, 0, O_RDWR, 0600); + if ( !dst_tdb ) { + terror("unable to open destination tdb"); + return; + } + + if ( tdb_store( dst_tdb, key, dbuf, TDB_REPLACE ) == -1 ) { + terror("failed to move record"); + } + else + printf("record moved\n"); + + tdb_close( dst_tdb ); + + return; +} + +#if 0 +static int print_conn_key(TDB_DATA key) +{ + printf( "pid =%5d ", ((connections_key*)key.dptr)->pid); + printf( "cnum =%10d ", ((connections_key*)key.dptr)->cnum); + printf( "name =[%s]\n", ((connections_key*)key.dptr)->name); + return 0; +} + +static int print_conn_data(TDB_DATA dbuf) +{ + printf( "pid =%5d ", ((connections_data*)dbuf.dptr)->pid); + printf( "cnum =%10d ", ((connections_data*)dbuf.dptr)->cnum); + printf( "name =[%s]\n", ((connections_data*)dbuf.dptr)->name); + + printf( "uid =%5d ", ((connections_data*)dbuf.dptr)->uid); + printf( "addr =[%s]\n", ((connections_data*)dbuf.dptr)->addr); + printf( "gid =%5d ", ((connections_data*)dbuf.dptr)->gid); + printf( "machine=[%s]\n", ((connections_data*)dbuf.dptr)->machine); + printf( "start = %s\n", ctime(&((connections_data*)dbuf.dptr)->start)); + return 0; +} +#endif + +static int print_rec(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state) +{ +#if 0 + print_conn_key(key); + print_conn_data(dbuf); + return 0; +#else + printf("\nkey %d bytes\n", key.dsize); + print_asc(key.dptr, key.dsize); + printf("\ndata %d bytes\n", dbuf.dsize); + print_data(dbuf.dptr, dbuf.dsize); + return 0; +#endif +} + +static int print_key(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state) +{ + print_asc(key.dptr, key.dsize); + printf("\n"); + return 0; +} + +static int total_bytes; + +static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state) +{ + total_bytes += dbuf.dsize; + return 0; +} + +static void info_tdb(void) +{ + int count; + total_bytes = 0; + if ((count = tdb_traverse(tdb, traverse_fn, NULL) == -1)) + printf("Error = %s\n", tdb_errorstr(tdb)); + else + printf("%d records totalling %d bytes\n", count, total_bytes); +} + +static char *tdb_getline(char *prompt) +{ + static char line[1024]; + char *p; + fputs(prompt, stdout); + line[0] = 0; + p = fgets(line, sizeof(line)-1, stdin); + if (p) p = strchr(p, '\n'); + if (p) *p = 0; + return p?line:NULL; +} + +static int do_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, + void *state) +{ + return tdb_delete(the_tdb, key); +} + +static void first_record(TDB_CONTEXT *the_tdb, TDB_DATA *pkey) +{ + TDB_DATA dbuf; + *pkey = tdb_firstkey(the_tdb); + + dbuf = tdb_fetch(the_tdb, *pkey); + if (!dbuf.dptr) terror("fetch failed"); + else { + /* printf("%s : %*.*s\n", k, (int)dbuf.dsize, (int)dbuf.dsize, dbuf.dptr); */ + print_rec(the_tdb, *pkey, dbuf, NULL); + } +} + +static void next_record(TDB_CONTEXT *the_tdb, TDB_DATA *pkey) +{ + TDB_DATA dbuf; + *pkey = tdb_nextkey(the_tdb, *pkey); + + dbuf = tdb_fetch(the_tdb, *pkey); + if (!dbuf.dptr) + terror("fetch failed"); + else + /* printf("%s : %*.*s\n", k, (int)dbuf.dsize, (int)dbuf.dsize, dbuf.dptr); */ + print_rec(the_tdb, *pkey, dbuf, NULL); +} + +int main(int argc, char *argv[]) +{ + int bIterate = 0; + char *line; + char *tok; + TDB_DATA iterate_kbuf; + + if (argv[1]) { + static char tmp[1024]; + sprintf(tmp, "open %s", argv[1]); + tok=strtok(tmp," "); + open_tdb(); + } + + while ((line = tdb_getline("tdb> "))) { + + /* Shell command */ + + if (line[0] == '!') { + system(line + 1); + continue; + } + + if ((tok = strtok(line," "))==NULL) { + if (bIterate) + next_record(tdb, &iterate_kbuf); + continue; + } + if (strcmp(tok,"create") == 0) { + bIterate = 0; + create_tdb(); + continue; + } else if (strcmp(tok,"open") == 0) { + open_tdb(); + continue; + } else if ((strcmp(tok, "q") == 0) || + (strcmp(tok, "quit") == 0)) { + break; + } + + /* all the rest require a open database */ + if (!tdb) { + bIterate = 0; + terror("database not open"); + help(); + continue; + } + + if (strcmp(tok,"insert") == 0) { + bIterate = 0; + insert_tdb(); + } else if (strcmp(tok,"store") == 0) { + bIterate = 0; + store_tdb(); + } else if (strcmp(tok,"show") == 0) { + bIterate = 0; + show_tdb(); + } else if (strcmp(tok,"erase") == 0) { + bIterate = 0; + tdb_traverse(tdb, do_delete_fn, NULL); + } else if (strcmp(tok,"delete") == 0) { + bIterate = 0; + delete_tdb(); + } else if (strcmp(tok,"dump") == 0) { + bIterate = 0; + tdb_traverse(tdb, print_rec, NULL); + } else if (strcmp(tok,"move") == 0) { + bIterate = 0; + move_rec(); + } else if (strcmp(tok,"list") == 0) { + tdb_dump_all(tdb); + } else if (strcmp(tok, "free") == 0) { + tdb_printfreelist(tdb); + } else if (strcmp(tok,"info") == 0) { + info_tdb(); + } else if ( (strcmp(tok, "1") == 0) || + (strcmp(tok, "first") == 0)) { + bIterate = 1; + first_record(tdb, &iterate_kbuf); + } else if ((strcmp(tok, "n") == 0) || + (strcmp(tok, "next") == 0)) { + next_record(tdb, &iterate_kbuf); + } else if ((strcmp(tok, "keys") == 0)) { + bIterate = 0; + tdb_traverse(tdb, print_key, NULL); + } else { + help(); + } + } + + if (tdb) tdb_close(tdb); + + return 0; +} diff --git a/source4/lib/tdb/tools/tdbtorture.c b/source4/lib/tdb/tools/tdbtorture.c new file mode 100644 index 0000000000..3f704e537e --- /dev/null +++ b/source4/lib/tdb/tools/tdbtorture.c @@ -0,0 +1,227 @@ +#include <stdlib.h> +#include <time.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <signal.h> +#include <stdarg.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/wait.h> +#include "tdb.h" + +/* this tests tdb by doing lots of ops from several simultaneous + writers - that stresses the locking code. Build with TDB_DEBUG=1 + for best effect */ + + + +#define REOPEN_PROB 30 +#define DELETE_PROB 8 +#define STORE_PROB 4 +#define APPEND_PROB 6 +#define LOCKSTORE_PROB 0 +#define TRAVERSE_PROB 20 +#define CULL_PROB 100 +#define KEYLEN 3 +#define DATALEN 100 +#define LOCKLEN 20 + +static TDB_CONTEXT *db; + +static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vfprintf(stdout, format, ap); + va_end(ap); + fflush(stdout); +#if 0 + { + char *ptr; + asprintf(&ptr,"xterm -e gdb /proc/%d/exe %d", getpid(), getpid()); + system(ptr); + free(ptr); + } +#endif +} + +static void fatal(char *why) +{ + perror(why); + exit(1); +} + +static char *randbuf(int len) +{ + char *buf; + int i; + buf = (char *)malloc(len+1); + + for (i=0;i<len;i++) { + buf[i] = 'a' + (rand() % 26); + } + buf[i] = 0; + return buf; +} + +static int cull_traverse(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, + void *state) +{ + if (random() % CULL_PROB == 0) { + tdb_delete(tdb, key); + } + return 0; +} + +static void addrec_db(void) +{ + int klen, dlen, slen; + char *k, *d, *s; + TDB_DATA key, data, lockkey; + + klen = 1 + (rand() % KEYLEN); + dlen = 1 + (rand() % DATALEN); + slen = 1 + (rand() % LOCKLEN); + + k = randbuf(klen); + d = randbuf(dlen); + s = randbuf(slen); + + key.dptr = k; + key.dsize = klen+1; + + data.dptr = d; + data.dsize = dlen+1; + + lockkey.dptr = s; + lockkey.dsize = slen+1; + +#if REOPEN_PROB + if (random() % REOPEN_PROB == 0) { + tdb_reopen_all(); + goto next; + } +#endif + +#if DELETE_PROB + if (random() % DELETE_PROB == 0) { + tdb_delete(db, key); + goto next; + } +#endif + +#if STORE_PROB + if (random() % STORE_PROB == 0) { + if (tdb_store(db, key, data, TDB_REPLACE) != 0) { + fatal("tdb_store failed"); + } + goto next; + } +#endif + +#if APPEND_PROB + if (random() % APPEND_PROB == 0) { + if (tdb_append(db, key, data) != 0) { + fatal("tdb_append failed"); + } + goto next; + } +#endif + +#if LOCKSTORE_PROB + if (random() % LOCKSTORE_PROB == 0) { + tdb_chainlock(db, lockkey); + data = tdb_fetch(db, key); + if (tdb_store(db, key, data, TDB_REPLACE) != 0) { + fatal("tdb_store failed"); + } + if (data.dptr) free(data.dptr); + tdb_chainunlock(db, lockkey); + goto next; + } +#endif + +#if TRAVERSE_PROB + if (random() % TRAVERSE_PROB == 0) { + tdb_traverse(db, cull_traverse, NULL); + goto next; + } +#endif + + data = tdb_fetch(db, key); + if (data.dptr) free(data.dptr); + +next: + free(k); + free(d); + free(s); +} + +static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, + void *state) +{ + tdb_delete(tdb, key); + return 0; +} + +#ifndef NPROC +#define NPROC 6 +#endif + +#ifndef NLOOPS +#define NLOOPS 200000 +#endif + +int main(int argc, char *argv[]) +{ + int i, seed=0; + int loops = NLOOPS; + pid_t pids[NPROC]; + + pids[0] = getpid(); + + for (i=0;i<NPROC-1;i++) { + if ((pids[i+1]=fork()) == 0) break; + } + + db = tdb_open("torture.tdb", 2, TDB_CLEAR_IF_FIRST, + O_RDWR | O_CREAT, 0600); + if (!db) { + fatal("db open failed"); + } + tdb_logging_function(db, tdb_log); + + srand(seed + getpid()); + srandom(seed + getpid() + time(NULL)); + for (i=0;i<loops;i++) addrec_db(); + + tdb_traverse(db, NULL, NULL); + tdb_traverse(db, traverse_fn, NULL); + tdb_traverse(db, traverse_fn, NULL); + + tdb_close(db); + + if (getpid() == pids[0]) { + for (i=0;i<NPROC-1;i++) { + int status; + if (waitpid(pids[i+1], &status, 0) != pids[i+1]) { + printf("failed to wait for %d\n", + (int)pids[i+1]); + exit(1); + } + if (WEXITSTATUS(status) != 0) { + printf("child %d exited with status %d\n", + (int)pids[i+1], WEXITSTATUS(status)); + exit(1); + } + } + printf("OK\n"); + } + + return 0; +} |