tdb: test for readonly locks mode on tdbbackup command
[samba.git] / lib / tdb / tools / tdbdump.c
1 /*
2    Unix SMB/CIFS implementation.
3    simple tdb dump util
4    Copyright (C) Andrew Tridgell              2001
5
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.
10
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.
15
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/>.
18 */
19
20 #include "replace.h"
21 #include "system/locale.h"
22 #include "system/time.h"
23 #include "system/filesys.h"
24 #include "system/wait.h"
25 #include "tdb.h"
26
27 static void print_data(TDB_DATA d)
28 {
29         unsigned char *p = (unsigned char *)d.dptr;
30         int len = d.dsize;
31         while (len--) {
32                 if (isprint(*p) && !strchr("\"\\", *p)) {
33                         fputc(*p, stdout);
34                 } else {
35                         printf("\\%02X", *p);
36                 }
37                 p++;
38         }
39 }
40
41 static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
42 {
43         printf("{\n");
44         printf("key(%zu) = \"", key.dsize);
45         print_data(key);
46         printf("\"\n");
47         printf("data(%zu) = \"", dbuf.dsize);
48         print_data(dbuf);
49         printf("\"\n");
50         printf("}\n");
51         return 0;
52 }
53
54 static void log_stderr(struct tdb_context *tdb, enum tdb_debug_level level,
55                        const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
56
57 static void log_stderr(struct tdb_context *tdb, enum tdb_debug_level level,
58                        const char *fmt, ...)
59 {
60         va_list ap;
61         const char *name = tdb_name(tdb);
62         const char *prefix = "";
63
64         if (!name)
65                 name = "unnamed";
66
67         switch (level) {
68         case TDB_DEBUG_ERROR:
69                 prefix = "ERROR: ";
70                 break;
71         case TDB_DEBUG_WARNING:
72                 prefix = "WARNING: ";
73                 break;
74         case TDB_DEBUG_TRACE:
75                 return;
76
77         default:
78         case TDB_DEBUG_FATAL:
79                 prefix = "FATAL: ";
80                 break;
81         }
82
83         va_start(ap, fmt);
84         fprintf(stderr, "tdb(%s): %s", name, prefix);
85         vfprintf(stderr, fmt, ap);
86         va_end(ap);
87 }
88
89 static void emergency_walk(TDB_DATA key, TDB_DATA dbuf, void *keyname)
90 {
91         if (keyname) {
92                 if (key.dsize != strlen(keyname))
93                         return;
94                 if (memcmp(key.dptr, keyname, key.dsize) != 0)
95                         return;
96         }
97         traverse_fn(NULL, key, dbuf, NULL);
98 }
99
100 static int dump_tdb(const char *fname, const char *keyname, bool emergency)
101 {
102         TDB_CONTEXT *tdb;
103         TDB_DATA key, value;
104         struct tdb_logging_context logfn = { log_stderr };
105         int tdb_flags = TDB_DEFAULT;
106
107         /*
108          * Note: that O_RDONLY implies TDB_NOLOCK, but we want to make it
109          * explicit as it's important when working on databases which were
110          * created with mutex locking.
111          */
112         tdb_flags |= TDB_NOLOCK;
113
114         tdb = tdb_open_ex(fname, 0, tdb_flags, O_RDONLY, 0, &logfn, NULL);
115         if (!tdb) {
116                 printf("Failed to open %s\n", fname);
117                 return 1;
118         }
119
120         if (emergency) {
121                 return tdb_rescue(tdb, emergency_walk, discard_const(keyname)) == 0;
122         }
123         if (!keyname) {
124                 return tdb_traverse(tdb, traverse_fn, NULL) == -1 ? 1 : 0;
125         } else {
126                 key.dptr = discard_const_p(uint8_t, keyname);
127                 key.dsize = strlen(keyname);
128                 value = tdb_fetch(tdb, key);
129                 if (!value.dptr) {
130                         return 1;
131                 } else {
132                         print_data(value);
133                         free(value.dptr);
134                 }
135         }
136
137         return 0;
138 }
139
140 static void usage( void)
141 {
142         printf( "Usage: tdbdump [options] <filename>\n\n");
143         printf( "   -h          this help message\n");
144         printf( "   -k keyname  dumps value of keyname\n");
145         printf( "   -e          emergency dump, for corrupt databases\n");
146 }
147
148  int main(int argc, char *argv[])
149 {
150         char *fname, *keyname=NULL;
151         bool emergency = false;
152         int c;
153
154         if (argc < 2) {
155                 printf("Usage: tdbdump <fname>\n");
156                 exit(1);
157         }
158
159         while ((c = getopt( argc, argv, "hk:e")) != -1) {
160                 switch (c) {
161                 case 'h':
162                         usage();
163                         exit( 0);
164                 case 'k':
165                         keyname = optarg;
166                         break;
167                 case 'e':
168                         emergency = true;
169                         break;
170                 default:
171                         usage();
172                         exit( 1);
173                 }
174         }
175
176         fname = argv[optind];
177
178         return dump_tdb(fname, keyname, emergency);
179 }