mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +03:00
merge tdb updates from samba4
(This used to be ctdb commit c9959e5741a17fd52070b744714eb00bf92a93eb)
This commit is contained in:
parent
e9d43f5e43
commit
5afe9b709c
@ -29,7 +29,7 @@
|
|||||||
#include "tdb_private.h"
|
#include "tdb_private.h"
|
||||||
|
|
||||||
/* read a freelist record and check for simple errors */
|
/* 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)
|
if (tdb->methods->tdb_read(tdb, off, rec, sizeof(*rec),DOCONV()) == -1)
|
||||||
return -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) {
|
if (rec->magic == TDB_MAGIC) {
|
||||||
/* this happens when a app is showdown while deleting a record - we should
|
/* this happens when a app is showdown while deleting a record - we should
|
||||||
not completely fail when this happens */
|
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, off));
|
||||||
rec->magic = TDB_FREE_MAGIC;
|
rec->magic = TDB_FREE_MAGIC;
|
||||||
if (tdb->methods->tdb_write(tdb, off, rec, sizeof(*rec)) == -1)
|
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) {
|
if (rec->magic != TDB_FREE_MAGIC) {
|
||||||
/* Ensure ecode is set for log fn. */
|
/* Ensure ecode is set for log fn. */
|
||||||
tdb->ecode = TDB_ERR_CORRUPT;
|
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));
|
rec->magic, off));
|
||||||
return TDB_ERRCODE(TDB_ERR_CORRUPT, -1);
|
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.
|
issues when faced with a slowly increasing record size.
|
||||||
*/
|
*/
|
||||||
while (rec_ptr) {
|
while (rec_ptr) {
|
||||||
if (rec_free_read(tdb, rec_ptr, rec) == -1) {
|
if (tdb_rec_free_read(tdb, rec_ptr, rec) == -1) {
|
||||||
goto fail;
|
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 (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;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries)
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rec_free_read(tdb, rec_ptr, &rec) == -1) {
|
if (tdb_rec_free_read(tdb, rec_ptr, &rec) == -1) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,6 @@ PRIVATE_DEPENDENCIES = \
|
|||||||
# Start BINARY tdbbackup
|
# Start BINARY tdbbackup
|
||||||
[BINARY::tdbbackup]
|
[BINARY::tdbbackup]
|
||||||
INSTALLDIR = BINDIR
|
INSTALLDIR = BINDIR
|
||||||
ENABLE = NO
|
|
||||||
OBJ_FILES= \
|
OBJ_FILES= \
|
||||||
tools/tdbbackup.o
|
tools/tdbbackup.o
|
||||||
PRIVATE_DEPENDENCIES = \
|
PRIVATE_DEPENDENCIES = \
|
||||||
|
@ -42,8 +42,181 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "replace.h"
|
#include "replace.h"
|
||||||
#include "tdb.h"
|
#include "system/locale.h"
|
||||||
|
#include "system/time.h"
|
||||||
#include "system/filesys.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
|
see if one file is newer than another
|
||||||
@ -66,6 +239,7 @@ static void usage(void)
|
|||||||
printf(" -h this help message\n");
|
printf(" -h this help message\n");
|
||||||
printf(" -s suffix set the backup suffix\n");
|
printf(" -s suffix set the backup suffix\n");
|
||||||
printf(" -v verify mode (restore if corrupt)\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 ret = 0;
|
||||||
int c;
|
int c;
|
||||||
int verify = 0;
|
int verify = 0;
|
||||||
|
int hashsize = 0;
|
||||||
const char *suffix = ".bak";
|
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) {
|
switch (c) {
|
||||||
case 'h':
|
case 'h':
|
||||||
usage();
|
usage();
|
||||||
@ -90,6 +263,9 @@ static void usage(void)
|
|||||||
case 's':
|
case 's':
|
||||||
suffix = optarg;
|
suffix = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'n':
|
||||||
|
hashsize = atoi(optarg);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +289,7 @@ static void usage(void)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (file_newer(fname, bak_name) &&
|
if (file_newer(fname, bak_name) &&
|
||||||
backup_tdb(fname, bak_name) != 0) {
|
backup_tdb(fname, bak_name, hashsize) != 0) {
|
||||||
ret = 1;
|
ret = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "replace.h"
|
#include "replace.h"
|
||||||
#include "tdb.h"
|
|
||||||
#include "system/locale.h"
|
#include "system/locale.h"
|
||||||
|
#include "system/time.h"
|
||||||
#include "system/filesys.h"
|
#include "system/filesys.h"
|
||||||
|
#include "tdb.h"
|
||||||
|
|
||||||
static void print_data(TDB_DATA d)
|
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("{\n");
|
||||||
printf("key = \"");
|
printf("key(%d) = \"", (int)key.dsize);
|
||||||
print_data(key);
|
print_data(key);
|
||||||
printf("\"\n");
|
printf("\"\n");
|
||||||
printf("data = \"");
|
printf("data(%d) = \"", (int)dbuf.dsize);
|
||||||
print_data(dbuf);
|
print_data(dbuf);
|
||||||
printf("\"\n");
|
printf("\"\n");
|
||||||
printf("}\n");
|
printf("}\n");
|
||||||
return 0;
|
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);
|
tdb = tdb_open(fname, 0, 0, O_RDONLY, 0);
|
||||||
if (!tdb) {
|
if (!tdb) {
|
||||||
@ -60,20 +62,55 @@ static int dump_tdb(const char *fname)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!keyname) {
|
||||||
tdb_traverse(tdb, traverse_fn, NULL);
|
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;
|
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[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
char *fname;
|
char *fname, *keyname=NULL;
|
||||||
|
int c;
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
printf("Usage: tdbdump <fname>\n");
|
printf("Usage: tdbdump <fname>\n");
|
||||||
exit(1);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return dump_tdb(fname);
|
fname = argv[optind];
|
||||||
|
|
||||||
|
return dump_tdb(fname, keyname);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user