tdb: add -e option to tdbdump (and docment it).
[obnox/samba/samba-obnox.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(%d) = \"", (int)key.dsize);
45         print_data(key);
46         printf("\"\n");
47         printf("data(%d) = \"", (int)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, ...)
56 {
57         va_list ap;
58         char *ptr = NULL;
59         int debuglevel = 0;
60         int ret;
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         
106         tdb = tdb_open_ex(fname, 0, 0, O_RDONLY, 0, &logfn, NULL);
107         if (!tdb) {
108                 printf("Failed to open %s\n", fname);
109                 return 1;
110         }
111
112         if (emergency) {
113                 return tdb_rescue(tdb, emergency_walk, keyname) == 0;
114         }
115         if (!keyname) {
116                 return tdb_traverse(tdb, traverse_fn, NULL) == -1 ? 1 : 0;
117         } else {
118                 key.dptr = discard_const_p(uint8_t, keyname);
119                 key.dsize = strlen(keyname);
120                 value = tdb_fetch(tdb, key);
121                 if (!value.dptr) {
122                         return 1;
123                 } else {
124                         print_data(value);
125                         free(value.dptr);
126                 }
127         }
128
129         return 0;
130 }
131
132 static void usage( void)
133 {
134         printf( "Usage: tdbdump [options] <filename>\n\n");
135         printf( "   -h          this help message\n");
136         printf( "   -k keyname  dumps value of keyname\n");
137         printf( "   -e          emergency dump, for corrupt databases\n");
138 }
139
140  int main(int argc, char *argv[])
141 {
142         char *fname, *keyname=NULL;
143         bool emergency = false;
144         int c;
145
146         if (argc < 2) {
147                 printf("Usage: tdbdump <fname>\n");
148                 exit(1);
149         }
150
151         while ((c = getopt( argc, argv, "hk:e")) != -1) {
152                 switch (c) {
153                 case 'h':
154                         usage();
155                         exit( 0);
156                 case 'k':
157                         keyname = optarg;
158                         break;
159                 case 'e':
160                         emergency = true;
161                         break;
162                 default:
163                         usage();
164                         exit( 1);
165                 }
166         }
167
168         fname = argv[optind];
169
170         return dump_tdb(fname, keyname, emergency);
171 }