idmap: Use dom_sid_str_buf
[Samba.git] / lib / tdb / tools / tdbbackup.c
blob1125987c950b42b9c06d5c0e6a2c45d4a6f954f4
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 3 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, see <http://www.gnu.org/licenses/>.
22 This program is meant for backup/restore of tdb databases. Typical usage would be:
23 tdbbackup *.tdb
24 when Samba shuts down cleanly, which will make a backup of all the local databases
25 to *.bak files. Then on Samba startup you would use:
26 tdbbackup -v *.tdb
27 and this will check the databases for corruption and if corruption is detected then
28 the backup will be restored.
30 You may also like to do a backup on a regular basis while Samba is
31 running, perhaps using cron.
33 The reason this program is needed is to cope with power failures
34 while Samba is running. A power failure could lead to database
35 corruption and Samba will then not start correctly.
37 Note that many of the databases in Samba are transient and thus
38 don't need to be backed up, so you can optimise the above a little
39 by only running the backup on the critical databases.
43 #include "replace.h"
44 #include "system/locale.h"
45 #include "system/time.h"
46 #include "system/filesys.h"
47 #include "system/wait.h"
48 #include "tdb.h"
50 #ifdef HAVE_GETOPT_H
51 #include <getopt.h>
52 #endif
54 static int failed;
56 static struct tdb_logging_context log_ctx;
58 #ifdef PRINTF_ATTRIBUTE
59 static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...) PRINTF_ATTRIBUTE(3,4);
60 #endif
61 static void tdb_log(struct tdb_context *tdb, enum tdb_debug_level level, const char *format, ...)
63 va_list ap;
65 va_start(ap, format);
66 vfprintf(stdout, format, ap);
67 va_end(ap);
68 fflush(stdout);
71 static char *add_suffix(const char *name, const char *suffix)
73 char *ret;
74 int len = strlen(name) + strlen(suffix) + 1;
75 ret = (char *)malloc(len);
76 if (!ret) {
77 fprintf(stderr,"Out of memory!\n");
78 exit(1);
80 snprintf(ret, len, "%s%s", name, suffix);
81 return ret;
84 static int copy_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
86 TDB_CONTEXT *tdb_new = (TDB_CONTEXT *)state;
88 if (tdb_store(tdb_new, key, dbuf, TDB_INSERT) != 0) {
89 fprintf(stderr,"Failed to insert into %s\n", tdb_name(tdb_new));
90 failed = 1;
91 return 1;
93 return 0;
97 static int test_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
99 return 0;
103 carefully backup a tdb, validating the contents and
104 only doing the backup if its OK
105 this function is also used for restore
107 static int backup_tdb(const char *old_name, const char *new_name,
108 int hash_size, int nolock, bool readonly)
110 TDB_CONTEXT *tdb;
111 TDB_CONTEXT *tdb_new;
112 char *tmp_name;
113 struct stat st;
114 int count1, count2;
116 tmp_name = add_suffix(new_name, ".tmp");
118 /* stat the old tdb to find its permissions */
119 if (stat(old_name, &st) != 0) {
120 perror(old_name);
121 free(tmp_name);
122 return 1;
125 /* open the old tdb */
126 tdb = tdb_open_ex(old_name, 0,
127 TDB_DEFAULT | (nolock ? TDB_NOLOCK : 0),
128 O_RDWR, 0, &log_ctx, NULL);
129 if (!tdb) {
130 printf("Failed to open %s\n", old_name);
131 free(tmp_name);
132 return 1;
135 /* create the new tdb */
136 unlink(tmp_name);
137 tdb_new = tdb_open_ex(tmp_name,
138 hash_size ? hash_size : tdb_hash_size(tdb),
139 TDB_DEFAULT,
140 O_RDWR|O_CREAT|O_EXCL, st.st_mode & 0777,
141 &log_ctx, NULL);
142 if (!tdb_new) {
143 perror(tmp_name);
144 free(tmp_name);
145 return 1;
148 if (readonly) {
149 if (tdb_lockall_read(tdb) != 0) {
150 printf("Failed to obtain read only lock on old tdb\n");
151 tdb_close(tdb);
152 tdb_close(tdb_new);
153 unlink(tmp_name);
154 free(tmp_name);
155 return 1;
157 } else if (tdb_transaction_start(tdb) != 0) {
158 printf("Failed to start transaction on db\n");
159 tdb_close(tdb);
160 tdb_close(tdb_new);
161 unlink(tmp_name);
162 free(tmp_name);
163 return 1;
166 /* lock the backup tdb so that nobody else can change it */
167 if (tdb_lockall(tdb_new) != 0) {
168 printf("Failed to lock backup tdb\n");
169 tdb_close(tdb);
170 tdb_close(tdb_new);
171 unlink(tmp_name);
172 free(tmp_name);
173 return 1;
176 failed = 0;
178 /* traverse and copy */
179 if (readonly) {
180 count1 = tdb_traverse_read(tdb,
181 copy_fn,
182 (void *)tdb_new);
183 } else {
184 count1 = tdb_traverse(tdb,
185 copy_fn,
186 (void *)tdb_new);
188 if (count1 < 0 || failed) {
189 fprintf(stderr,"failed to copy %s\n", old_name);
190 tdb_close(tdb);
191 tdb_close(tdb_new);
192 unlink(tmp_name);
193 free(tmp_name);
194 return 1;
197 /* close the old tdb */
198 tdb_close(tdb);
200 /* copy done, unlock the backup tdb */
201 tdb_unlockall(tdb_new);
203 #ifdef HAVE_FDATASYNC
204 if (fdatasync(tdb_fd(tdb_new)) != 0) {
205 #else
206 if (fsync(tdb_fd(tdb_new)) != 0) {
207 #endif
208 /* not fatal */
209 fprintf(stderr, "failed to fsync backup file\n");
212 /* close the new tdb and re-open read-only */
213 tdb_close(tdb_new);
214 tdb_new = tdb_open_ex(tmp_name,
216 TDB_DEFAULT,
217 O_RDONLY, 0,
218 &log_ctx, NULL);
219 if (!tdb_new) {
220 fprintf(stderr,"failed to reopen %s\n", tmp_name);
221 unlink(tmp_name);
222 perror(tmp_name);
223 free(tmp_name);
224 return 1;
227 /* traverse the new tdb to confirm */
228 count2 = tdb_traverse(tdb_new, test_fn, NULL);
229 if (count2 != count1) {
230 fprintf(stderr,"failed to copy %s\n", old_name);
231 tdb_close(tdb_new);
232 unlink(tmp_name);
233 free(tmp_name);
234 return 1;
237 /* close the new tdb and rename it to .bak */
238 tdb_close(tdb_new);
239 if (rename(tmp_name, new_name) != 0) {
240 perror(new_name);
241 free(tmp_name);
242 return 1;
245 free(tmp_name);
247 return 0;
251 verify a tdb and if it is corrupt then restore from *.bak
253 static int verify_tdb(const char *fname, const char *bak_name)
255 TDB_CONTEXT *tdb;
256 int count = -1;
258 /* open the tdb */
259 tdb = tdb_open_ex(fname, 0, 0,
260 O_RDONLY, 0, &log_ctx, NULL);
262 /* traverse the tdb, then close it */
263 if (tdb) {
264 count = tdb_traverse(tdb, test_fn, NULL);
265 tdb_close(tdb);
268 /* count is < 0 means an error */
269 if (count < 0) {
270 printf("restoring %s\n", fname);
271 return backup_tdb(bak_name, fname, 0, 0, 0);
274 printf("%s : %d records\n", fname, count);
276 return 0;
280 see if one file is newer than another
282 static int file_newer(const char *fname1, const char *fname2)
284 struct stat st1, st2;
285 if (stat(fname1, &st1) != 0) {
286 return 0;
288 if (stat(fname2, &st2) != 0) {
289 return 1;
291 return (st1.st_mtime > st2.st_mtime);
294 static void usage(void)
296 printf("Usage: tdbbackup [options] <fname...>\n\n");
297 printf(" -h this help message\n");
298 printf(" -s suffix set the backup suffix\n");
299 printf(" -v verify mode (restore if corrupt)\n");
300 printf(" -n hashsize set the new hash size for the backup\n");
301 printf(" -l open without locking to back up mutex dbs\n");
302 printf(" -r open with read only locking\n");
305 int main(int argc, char *argv[])
307 int i;
308 int ret = 0;
309 int c;
310 int verify = 0;
311 int hashsize = 0;
312 int nolock = 0;
313 bool readonly = false;
314 const char *suffix = ".bak";
316 log_ctx.log_fn = tdb_log;
318 while ((c = getopt(argc, argv, "vhs:n:lr")) != -1) {
319 switch (c) {
320 case 'h':
321 usage();
322 exit(0);
323 case 'v':
324 verify = 1;
325 break;
326 case 's':
327 suffix = optarg;
328 break;
329 case 'n':
330 hashsize = atoi(optarg);
331 break;
332 case 'l':
333 nolock = 1;
334 break;
335 case 'r':
336 readonly = true;
340 argc -= optind;
341 argv += optind;
343 if (argc < 1) {
344 usage();
345 exit(1);
348 for (i=0; i<argc; i++) {
349 const char *fname = argv[i];
350 char *bak_name;
352 bak_name = add_suffix(fname, suffix);
354 if (verify) {
355 if (verify_tdb(fname, bak_name) != 0) {
356 ret = 1;
358 } else {
359 if (file_newer(fname, bak_name) &&
360 backup_tdb(fname, bak_name, hashsize,
361 nolock, readonly) != 0) {
362 ret = 1;
366 free(bak_name);
369 return ret;