diff options
-rw-r--r-- | source3/tdb/tdbbackup.c | 124 |
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; |