-/*
+/*
Unix SMB/CIFS implementation.
low level tdb backup and restore utility
Copyright (C) Andrew Tridgell 2002
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
*/
static int failed;
+static struct tdb_logging_context log_ctx;
+
+#ifdef PRINTF_ATTRIBUTE
+static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...) PRINTF_ATTRIBUTE(3,4);
+#endif
+static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ vfprintf(stdout, format, ap);
+ va_end(ap);
+ fflush(stdout);
+}
+
static char *add_suffix(const char *name, const char *suffix)
{
char *ret;
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)
+static int backup_tdb(const char *old_name, const char *new_name,
+ int hash_size, int nolock, bool readonly)
{
TDB_CONTEXT *tdb;
TDB_CONTEXT *tdb_new;
}
/* open the old tdb */
- tdb = tdb_open(old_name, 0, 0, O_RDWR, 0);
+ tdb = tdb_open_ex(old_name, 0,
+ TDB_DEFAULT | (nolock ? TDB_NOLOCK : 0),
+ O_RDWR, 0, &log_ctx, NULL);
if (!tdb) {
printf("Failed to open %s\n", old_name);
free(tmp_name);
/* 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);
+ tdb_new = tdb_open_ex(tmp_name,
+ hash_size ? hash_size : tdb_hash_size(tdb),
+ TDB_DEFAULT,
+ O_RDWR|O_CREAT|O_EXCL, st.st_mode & 0777,
+ &log_ctx, NULL);
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);
+ if (readonly) {
+ if (tdb_lockall_read(tdb) != 0) {
+ printf("Failed to obtain read only lock on old tdb\n");
+ tdb_close(tdb);
+ tdb_close(tdb_new);
+ unlink(tmp_name);
+ free(tmp_name);
+ return 1;
+ }
+ } else if (tdb_transaction_start(tdb) != 0) {
+ printf("Failed to start transaction on db\n");
+ tdb_close(tdb);
+ tdb_close(tdb_new);
+ unlink(tmp_name);
+ free(tmp_name);
+ return 1;
+ }
+
+ /* lock the backup tdb so that nobody else can change it */
+ if (tdb_lockall(tdb_new) != 0) {
+ printf("Failed to lock backup tdb\n");
tdb_close(tdb);
tdb_close(tdb_new);
unlink(tmp_name);
failed = 0;
/* traverse and copy */
- count1 = tdb_traverse(tdb, copy_fn, (void *)tdb_new);
+ if (readonly) {
+ count1 = tdb_traverse_read(tdb,
+ copy_fn,
+ (void *)tdb_new);
+ } else {
+ 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);
/* close the old tdb */
tdb_close(tdb);
+ /* copy done, unlock the backup tdb */
+ tdb_unlockall(tdb_new);
+
+#ifdef HAVE_FDATASYNC
+ if (fdatasync(tdb_fd(tdb_new)) != 0) {
+#else
+ if (fsync(tdb_fd(tdb_new)) != 0) {
+#endif
+ /* not fatal */
+ fprintf(stderr, "failed to fsync backup file\n");
+ }
+
/* 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);
+ tdb_new = tdb_open_ex(tmp_name,
+ 0,
+ TDB_DEFAULT,
+ O_RDONLY, 0,
+ &log_ctx, NULL);
if (!tdb_new) {
fprintf(stderr,"failed to reopen %s\n", tmp_name);
unlink(tmp_name);
free(tmp_name);
return 1;
}
-
+
/* traverse the new tdb to confirm */
count2 = tdb_traverse(tdb_new, test_fn, NULL);
if (count2 != count1) {
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);
if (rename(tmp_name, new_name) != 0) {
int count = -1;
/* open the tdb */
- tdb = tdb_open(fname, 0, 0, O_RDONLY, 0);
+ tdb = tdb_open_ex(fname, 0, 0,
+ O_RDONLY, 0, &log_ctx, NULL);
/* traverse the tdb, then close it */
if (tdb) {
/* count is < 0 means an error */
if (count < 0) {
printf("restoring %s\n", fname);
- return backup_tdb(bak_name, fname, 0);
+ return backup_tdb(bak_name, fname, 0, 0, 0);
}
printf("%s : %d records\n", fname, count);
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");
+ printf(" -l open without locking to back up mutex dbs\n");
+ printf(" -r open with read only locking\n");
}
-
int main(int argc, char *argv[])
{
int c;
int verify = 0;
int hashsize = 0;
+ int nolock = 0;
+ bool readonly = false;
const char *suffix = ".bak";
- while ((c = getopt(argc, argv, "vhs:n:")) != -1) {
+ log_ctx.log_fn = tdb_log;
+
+ while ((c = getopt(argc, argv, "vhs:n:lr")) != -1) {
switch (c) {
case 'h':
usage();
case 'n':
hashsize = atoi(optarg);
break;
+ case 'l':
+ nolock = 1;
+ break;
+ case 'r':
+ readonly = true;
}
}
}
} else {
if (file_newer(fname, bak_name) &&
- backup_tdb(fname, bak_name, hashsize) != 0) {
+ backup_tdb(fname, bak_name, hashsize,
+ nolock, readonly) != 0) {
ret = 1;
}
}