get rid of annoying "change your password now" message
[Samba.git] / source / tdb / tdbbackup.c
blob48c4272d3312e199d6ca8a8a4da64624be5e0093
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 "tdb.h"
58 static int failed;
60 static char *add_suffix(const char *name, const char *suffix)
62 char *ret;
63 int len = strlen(name) + strlen(suffix) + 1;
64 ret = malloc(len);
65 if (!ret) {
66 fprintf(stderr,"Out of memory!\n");
67 exit(1);
69 strncpy(ret, name, len);
70 strncat(ret, suffix, len);
71 return ret;
74 static int copy_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
76 TDB_CONTEXT *tdb_new = (TDB_CONTEXT *)state;
78 if (tdb_store(tdb_new, key, dbuf, TDB_INSERT) != 0) {
79 fprintf(stderr,"Failed to insert into %s\n", tdb_new->name);
80 failed = 1;
81 return 1;
83 return 0;
87 static int test_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
89 return 0;
93 carefully backup a tdb, validating the contents and
94 only doing the backup if its OK
95 this function is also used for restore
97 static int backup_tdb(const char *old_name, const char *new_name)
99 TDB_CONTEXT *tdb;
100 TDB_CONTEXT *tdb_new;
101 char *tmp_name;
102 struct stat st;
103 int count1, count2;
105 tmp_name = add_suffix(new_name, ".tmp");
107 /* stat the old tdb to find its permissions */
108 if (stat(old_name, &st) != 0) {
109 perror(old_name);
110 return 1;
113 /* open the old tdb */
114 tdb = tdb_open(old_name, 0, 0, O_RDWR, 0);
115 if (!tdb) {
116 printf("Failed to open %s\n", old_name);
117 return 1;
120 /* create the new tdb */
121 unlink(tmp_name);
122 tdb_new = tdb_open(tmp_name, tdb->header.hash_size,
123 TDB_DEFAULT, O_RDWR|O_CREAT|O_EXCL,
124 st.st_mode & 0777);
125 if (!tdb_new) {
126 perror(tmp_name);
127 free(tmp_name);
128 return 1;
131 /* lock the old tdb */
132 if (tdb_lockall(tdb) != 0) {
133 fprintf(stderr,"Failed to lock %s\n", old_name);
134 tdb_close(tdb);
135 tdb_close(tdb_new);
136 unlink(tmp_name);
137 free(tmp_name);
138 return 1;
141 failed = 0;
143 /* traverse and copy */
144 count1 = tdb_traverse(tdb, copy_fn, (void *)tdb_new);
145 if (count1 < 0 || failed) {
146 fprintf(stderr,"failed to copy %s\n", old_name);
147 tdb_close(tdb);
148 tdb_close(tdb_new);
149 unlink(tmp_name);
150 free(tmp_name);
151 return 1;
154 /* close the old tdb */
155 tdb_close(tdb);
157 /* close the new tdb and re-open read-only */
158 tdb_close(tdb_new);
159 tdb_new = tdb_open(tmp_name, 0, TDB_DEFAULT, O_RDONLY, 0);
160 if (!tdb_new) {
161 fprintf(stderr,"failed to reopen %s\n", tmp_name);
162 unlink(tmp_name);
163 perror(tmp_name);
164 free(tmp_name);
165 return 1;
168 /* traverse the new tdb to confirm */
169 count2 = tdb_traverse(tdb_new, test_fn, 0);
170 if (count2 != count1) {
171 fprintf(stderr,"failed to copy %s\n", old_name);
172 tdb_close(tdb_new);
173 unlink(tmp_name);
174 free(tmp_name);
175 return 1;
178 /* make sure the new tdb has reached stable storage */
179 fsync(tdb_new->fd);
181 /* close the new tdb and rename it to .bak */
182 tdb_close(tdb_new);
183 unlink(new_name);
184 if (rename(tmp_name, new_name) != 0) {
185 perror(new_name);
186 free(tmp_name);
187 return 1;
190 printf("%s : %d records\n", old_name, count1);
191 free(tmp_name);
193 return 0;
199 verify a tdb and if it is corrupt then restore from *.bak
201 static int verify_tdb(const char *fname, const char *bak_name)
203 TDB_CONTEXT *tdb;
204 int count = -1;
206 /* open the tdb */
207 tdb = tdb_open(fname, 0, 0, O_RDONLY, 0);
209 /* traverse the tdb, then close it */
210 if (tdb) {
211 count = tdb_traverse(tdb, test_fn, NULL);
212 tdb_close(tdb);
215 /* count is < 0 means an error */
216 if (count < 0) {
217 printf("restoring %s\n", fname);
218 return backup_tdb(bak_name, fname);
221 printf("%s : %d records\n", fname, count);
223 return 0;
227 static void usage(void)
229 printf("Usage: tdbbackup [options] <fname...>\n\n");
230 printf(" -h this help message\n");
231 printf(" -s suffix set the backup suffix\n");
232 printf(" -v veryify mode (restore if corrupt)\n");
236 int main(int argc, char *argv[])
238 int i;
239 int ret = 0;
240 int c;
241 int verify = 0;
242 char *suffix = ".bak";
243 extern int optind;
244 extern char *optarg;
246 while ((c = getopt(argc, argv, "vhs:")) != -1) {
247 switch (c) {
248 case 'h':
249 usage();
250 exit(0);
251 case 'v':
252 verify = 1;
253 break;
254 case 's':
255 suffix = optarg;
256 break;
260 argc -= optind;
261 argv += optind;
263 if (argc < 1) {
264 usage();
265 exit(1);
268 for (i=0; i<argc; i++) {
269 const char *fname = argv[i];
270 char *bak_name;
272 bak_name = add_suffix(fname, suffix);
274 if (verify) {
275 if (verify_tdb(fname, bak_name) != 0) {
276 ret = 1;
278 } else {
279 if (backup_tdb(fname, bak_name) != 0) {
280 ret = 1;
284 free(bak_name);
287 return ret;