sync'ing up for 3.0alpha20 release
[Samba.git] / source / tdb / tdbbackup.c
blob36ba7db918824e31784f834bfec0e55e0bd0d4af
1 /*
2 Unix SMB/CIFS implementation.
3 low level tdb backup and restore utility
4 Copyright (C) Andrew Tridgell 2002
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 This program is meant for backup/restore of tdb databases. Typical usage would be:
24 tdbbackup *.tdb
25 when Samba shuts down cleanly, which will make a backup of all the local databases
26 to *.bak files. Then on Samba startup you would use:
27 tdbbackup -v *.tdb
28 and this will check the databases for corruption and if corruption is detected then
29 the backup will be restored.
31 You may also like to do a backup on a regular basis while Samba is
32 running, perhaps using cron.
34 The reason this program is needed is to cope with power failures
35 while Samba is running. A power failure could lead to database
36 corruption and Samba will then not start correctly.
38 Note that many of the databases in Samba are transient and thus
39 don't need to be backed up, so you can optimise the above a little
40 by only running the backup on the critical databases.
44 #include <errno.h>
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <fcntl.h>
48 #include <unistd.h>
49 #include <string.h>
50 #include <fcntl.h>
51 #include <time.h>
52 #include <sys/mman.h>
53 #include <sys/stat.h>
54 #include <sys/time.h>
55 #include <ctype.h>
56 #include <signal.h>
57 #include "tdb.h"
59 static int failed;
61 static char *add_suffix(const char *name, const char *suffix)
63 char *ret;
64 int len = strlen(name) + strlen(suffix) + 1;
65 ret = malloc(len);
66 if (!ret) {
67 fprintf(stderr,"Out of memory!\n");
68 exit(1);
70 strncpy(ret, name, len);
71 strncat(ret, suffix, len);
72 return ret;
75 static int copy_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
77 TDB_CONTEXT *tdb_new = (TDB_CONTEXT *)state;
79 if (tdb_store(tdb_new, key, dbuf, TDB_INSERT) != 0) {
80 fprintf(stderr,"Failed to insert into %s\n", tdb_new->name);
81 failed = 1;
82 return 1;
84 return 0;
88 static int test_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
90 return 0;
94 carefully backup a tdb, validating the contents and
95 only doing the backup if its OK
96 this function is also used for restore
98 static int backup_tdb(const char *old_name, const char *new_name)
100 TDB_CONTEXT *tdb;
101 TDB_CONTEXT *tdb_new;
102 char *tmp_name;
103 struct stat st;
104 int count1, count2;
106 tmp_name = add_suffix(new_name, ".tmp");
108 /* stat the old tdb to find its permissions */
109 if (stat(old_name, &st) != 0) {
110 perror(old_name);
111 return 1;
114 /* open the old tdb */
115 tdb = tdb_open(old_name, 0, 0, O_RDWR, 0);
116 if (!tdb) {
117 printf("Failed to open %s\n", old_name);
118 return 1;
121 /* create the new tdb */
122 unlink(tmp_name);
123 tdb_new = tdb_open(tmp_name, tdb->header.hash_size,
124 TDB_DEFAULT, O_RDWR|O_CREAT|O_EXCL,
125 st.st_mode & 0777);
126 if (!tdb_new) {
127 perror(tmp_name);
128 free(tmp_name);
129 return 1;
132 /* lock the old tdb */
133 if (tdb_lockall(tdb) != 0) {
134 fprintf(stderr,"Failed to lock %s\n", old_name);
135 tdb_close(tdb);
136 tdb_close(tdb_new);
137 unlink(tmp_name);
138 free(tmp_name);
139 return 1;
142 failed = 0;
144 /* traverse and copy */
145 count1 = tdb_traverse(tdb, copy_fn, (void *)tdb_new);
146 if (count1 < 0 || failed) {
147 fprintf(stderr,"failed to copy %s\n", old_name);
148 tdb_close(tdb);
149 tdb_close(tdb_new);
150 unlink(tmp_name);
151 free(tmp_name);
152 return 1;
155 /* close the old tdb */
156 tdb_close(tdb);
158 /* close the new tdb and re-open read-only */
159 tdb_close(tdb_new);
160 tdb_new = tdb_open(tmp_name, 0, TDB_DEFAULT, O_RDONLY, 0);
161 if (!tdb_new) {
162 fprintf(stderr,"failed to reopen %s\n", tmp_name);
163 unlink(tmp_name);
164 perror(tmp_name);
165 free(tmp_name);
166 return 1;
169 /* traverse the new tdb to confirm */
170 count2 = tdb_traverse(tdb_new, test_fn, 0);
171 if (count2 != count1) {
172 fprintf(stderr,"failed to copy %s\n", old_name);
173 tdb_close(tdb_new);
174 unlink(tmp_name);
175 free(tmp_name);
176 return 1;
179 /* make sure the new tdb has reached stable storage */
180 fsync(tdb_new->fd);
182 /* close the new tdb and rename it to .bak */
183 tdb_close(tdb_new);
184 unlink(new_name);
185 if (rename(tmp_name, new_name) != 0) {
186 perror(new_name);
187 free(tmp_name);
188 return 1;
191 printf("%s : %d records\n", old_name, count1);
192 free(tmp_name);
194 return 0;
200 verify a tdb and if it is corrupt then restore from *.bak
202 static int verify_tdb(const char *fname, const char *bak_name)
204 TDB_CONTEXT *tdb;
205 int count = -1;
207 /* open the tdb */
208 tdb = tdb_open(fname, 0, 0, O_RDONLY, 0);
210 /* traverse the tdb, then close it */
211 if (tdb) {
212 count = tdb_traverse(tdb, test_fn, NULL);
213 tdb_close(tdb);
216 /* count is < 0 means an error */
217 if (count < 0) {
218 printf("restoring %s\n", fname);
219 return backup_tdb(bak_name, fname);
222 printf("%s : %d records\n", fname, count);
224 return 0;
229 see if one file is newer than another
231 static int file_newer(const char *fname1, const char *fname2)
233 struct stat st1, st2;
234 if (stat(fname1, &st1) != 0) {
235 return 0;
237 if (stat(fname2, &st2) != 0) {
238 return 1;
240 return (st1.st_mtime > st2.st_mtime);
243 static void usage(void)
245 printf("Usage: tdbbackup [options] <fname...>\n\n");
246 printf(" -h this help message\n");
247 printf(" -s suffix set the backup suffix\n");
248 printf(" -v veryify mode (restore if corrupt)\n");
252 int main(int argc, char *argv[])
254 int i;
255 int ret = 0;
256 int c;
257 int verify = 0;
258 char *suffix = ".bak";
259 extern int optind;
260 extern char *optarg;
262 while ((c = getopt(argc, argv, "vhs:")) != -1) {
263 switch (c) {
264 case 'h':
265 usage();
266 exit(0);
267 case 'v':
268 verify = 1;
269 break;
270 case 's':
271 suffix = optarg;
272 break;
276 argc -= optind;
277 argv += optind;
279 if (argc < 1) {
280 usage();
281 exit(1);
284 for (i=0; i<argc; i++) {
285 const char *fname = argv[i];
286 char *bak_name;
288 bak_name = add_suffix(fname, suffix);
290 if (verify) {
291 if (verify_tdb(fname, bak_name) != 0) {
292 ret = 1;
294 } else {
295 if (file_newer(fname, bak_name) &&
296 backup_tdb(fname, bak_name) != 0) {
297 ret = 1;
301 free(bak_name);
304 return ret;