summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/tdb/tdbbackup.c124
1 files changed, 101 insertions, 23 deletions
diff --git a/source3/tdb/tdbbackup.c b/source3/tdb/tdbbackup.c
index 9f2fbdab3c..2da81cd213 100644
--- a/source3/tdb/tdbbackup.c
+++ b/source3/tdb/tdbbackup.c
@@ -53,36 +53,37 @@ static int test_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
}
/*
- carefully backup a tdb to %s.bak, validating the contents and
+ 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 *fname)
+static int backup_tdb(const char *old_name, const char *new_name)
{
TDB_CONTEXT *tdb;
TDB_CONTEXT *tdb_new;
char *tmp_name = NULL;
- char *bak_name = NULL;
struct stat st;
int count1, count2;
- asprintf(&tmp_name, "%s.tmp", fname);
+ asprintf(&tmp_name, "%s.tmp", new_name);
/* stat the old tdb to find its permissions */
- if (stat(fname, &st) != 0) {
- perror(fname);
+ if (stat(old_name, &st) != 0) {
+ perror(old_name);
return 1;
}
/* open the old tdb */
- tdb = tdb_open(fname, 0, 0, O_RDWR, 0);
+ tdb = tdb_open(old_name, 0, 0, O_RDWR, 0);
if (!tdb) {
- printf("Failed to open %s\n", fname);
+ printf("Failed to open %s\n", old_name);
return 1;
}
/* create the new tdb */
unlink(tmp_name);
- tdb_new = tdb_open(tmp_name, 0, TDB_DEFAULT, O_RDWR|O_CREAT|O_EXCL,
+ tdb_new = tdb_open(tmp_name, tdb->header.hash_size,
+ TDB_DEFAULT, O_RDWR|O_CREAT|O_EXCL,
st.st_mode & 0777);
if (!tdb_new) {
perror(tmp_name);
@@ -92,7 +93,7 @@ static int backup_tdb(const char *fname)
/* lock the old tdb */
if (tdb_lockall(tdb) != 0) {
- fprintf(stderr,"Failed to lock %s\n", fname);
+ fprintf(stderr,"Failed to lock %s\n", old_name);
tdb_close(tdb);
tdb_close(tdb_new);
unlink(tmp_name);
@@ -105,7 +106,7 @@ static int backup_tdb(const char *fname)
/* traverse and copy */
count1 = tdb_traverse(tdb, copy_fn, (void *)tdb_new);
if (count1 < 0 || failed) {
- fprintf(stderr,"failed to backup %s\n", fname);
+ fprintf(stderr,"failed to copy %s\n", old_name);
tdb_close(tdb);
tdb_close(tdb_new);
unlink(tmp_name);
@@ -130,43 +131,120 @@ static int backup_tdb(const char *fname)
/* traverse the new tdb to confirm */
count2 = tdb_traverse(tdb_new, test_fn, 0);
if (count2 != count1) {
- fprintf(stderr,"failed to backup %s\n", fname);
+ 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_new->fd);
+
/* close the new tdb and rename it to .bak */
tdb_close(tdb_new);
- asprintf(&bak_name, "%s.bak", fname);
- unlink(bak_name);
- if (rename(tmp_name, bak_name) != 0) {
- perror(bak_name);
+ unlink(new_name);
+ if (rename(tmp_name, new_name) != 0) {
+ perror(new_name);
free(tmp_name);
- free(bak_name);
return 1;
}
- printf("%s : %d records\n", fname, count1);
+ printf("%s : %d records\n", old_name, count1);
free(tmp_name);
- free(bak_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);
+ }
+
+ printf("%s : %d records\n", fname, count);
+
+ return 0;
+}
+
+
+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 veryify mode (restore if corrupt)\n");
+}
+
+
int main(int argc, char *argv[])
{
int i;
int ret = 0;
+ int c;
+ int verify = 0;
+ 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;
+ }
+ }
- if (argc < 2) {
- printf("Usage: tdbbackup [options] <fname...>\n");
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ usage();
exit(1);
}
- for (i=1; i<argc; i++) {
- if (backup_tdb(argv[i]) != 0) ret = 1;
+ for (i=0; i<argc; i++) {
+ const char *fname = argv[i];
+ char *bak_name = NULL;
+
+ asprintf(&bak_name, "%s%s", fname, suffix);
+
+ if (verify) {
+ if (verify_tdb(fname, bak_name) != 0) {
+ ret = 1;
+ }
+ } else {
+ if (backup_tdb(fname, bak_name) != 0) {
+ ret = 1;
+ }
+ }
+
+ free(bak_name);
}
return ret;