lib:tdb: Use C99 initializer for tdb_logging_context
[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 = {
105                 .log_fn = log_stderr,
106         };
107         int tdb_flags = TDB_DEFAULT;
108
109         /*
110          * Note: that O_RDONLY implies TDB_NOLOCK, but we want to make it
111          * explicit as it's important when working on databases which were
112          * created with mutex locking.
113          */
114         tdb_flags |= TDB_NOLOCK;
115
116         tdb = tdb_open_ex(fname, 0, tdb_flags, O_RDONLY, 0, &logfn, NULL);
117         if (!tdb) {
118                 printf("Failed to open %s\n", fname);
119                 return 1;
120         }
121
122         if (emergency) {
123                 return tdb_rescue(tdb, emergency_walk, discard_const(keyname)) == 0;
124         }
125         if (!keyname) {
126                 return tdb_traverse(tdb, traverse_fn, NULL) == -1 ? 1 : 0;
127         } else {
128                 key.dptr = discard_const_p(uint8_t, keyname);
129                 key.dsize = strlen(keyname);
130                 value = tdb_fetch(tdb, key);
131                 if (!value.dptr) {
132                         return 1;
133                 } else {
134                         print_data(value);
135                         free(value.dptr);
136                 }
137         }
138
139         return 0;
140 }
141
142 static void usage( void)
143 {
144         printf( "Usage: tdbdump [options] <filename>\n\n");
145         printf( "   -h          this help message\n");
146         printf( "   -k keyname  dumps value of keyname\n");
147         printf( "   -e          emergency dump, for corrupt databases\n");
148 }
149
150  int main(int argc, char *argv[])
151 {
152         char *fname, *keyname=NULL;
153         bool emergency = false;
154         int c;
155
156         if (argc < 2) {
157                 printf("Usage: tdbdump <fname>\n");
158                 exit(1);
159         }
160
161         while ((c = getopt( argc, argv, "hk:e")) != -1) {
162                 switch (c) {
163                 case 'h':
164                         usage();
165                         exit( 0);
166                 case 'k':
167                         keyname = optarg;
168                         break;
169                 case 'e':
170                         emergency = true;
171                         break;
172                 default:
173                         usage();
174                         exit( 1);
175                 }
176         }
177
178         fname = argv[optind];
179
180         return dump_tdb(fname, keyname, emergency);
181 }