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