]> git.sur5r.net Git - openldap/blob - libraries/liblmdb/mdb_dump.c
Trap signals
[openldap] / libraries / liblmdb / mdb_dump.c
1 /* mdb_dump.c - memory-mapped database dump tool */
2 /*
3  * Copyright 2011-2014 Howard Chu, Symas Corp.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted only as authorized by the OpenLDAP
8  * Public License.
9  *
10  * A copy of this license is available in the file LICENSE in the
11  * top-level directory of the distribution or, alternatively, at
12  * <http://www.OpenLDAP.org/license.html>.
13  */
14 #include <stdio.h>
15 #include <errno.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <ctype.h>
19 #include <unistd.h>
20 #include <signal.h>
21 #include "lmdb.h"
22
23 #define PRINT   1
24 static int mode;
25
26 typedef struct flagbit {
27         int bit;
28         char *name;
29 } flagbit;
30
31 flagbit dbflags[] = {
32         { MDB_REVERSEKEY, "reversekey" },
33         { MDB_DUPSORT, "dupsort" },
34         { MDB_INTEGERKEY, "integerkey" },
35         { MDB_DUPFIXED, "dupfixed" },
36         { MDB_INTEGERDUP, "integerdup" },
37         { MDB_REVERSEDUP, "reversedup" },
38         { 0, NULL }
39 };
40
41 static volatile sig_atomic_t gotsig;
42
43 static void dumpsig( int sig )
44 {
45         gotsig=1;
46 }
47
48 static const char hexc[] = "0123456789abcdef";
49
50 static void hex(unsigned char c)
51 {
52         putchar(hexc[c >> 4]);
53         putchar(hexc[c & 0xf]);
54 }
55
56 static void text(MDB_val *v)
57 {
58         unsigned char *c, *end;
59
60         putchar(' ');
61         c = v->mv_data;
62         end = c + v->mv_size;
63         while (c < end) {
64                 if (isprint(*c)) {
65                         putchar(*c);
66                 } else {
67                         putchar('\\');
68                         hex(*c);
69                 }
70                 c++;
71         }
72         putchar('\n');
73 }
74
75 static void byte(MDB_val *v)
76 {
77         unsigned char *c, *end;
78
79         putchar(' ');
80         c = v->mv_data;
81         end = c + v->mv_size;
82         while (c < end) {
83                 hex(*c++);
84         }
85         putchar('\n');
86 }
87
88 /* Dump in BDB-compatible format */
89 static int dumpit(MDB_txn *txn, MDB_dbi dbi, char *name)
90 {
91         MDB_cursor *mc;
92         MDB_stat ms;
93         MDB_val key, data;
94         unsigned int flags;
95         int rc, i;
96
97         rc = mdb_dbi_flags(txn, dbi, &flags);
98         if (rc) return rc;
99
100         rc = mdb_stat(txn, dbi, &ms);
101         if (rc) return rc;
102
103         printf("VERSION=3\n");
104         printf("format=%s\n", mode & PRINT ? "print" : "bytevalue");
105         if (name)
106                 printf("database=%s\n", name);
107         printf("type=btree\n");
108
109         if (flags & MDB_DUPSORT)
110                 printf("duplicates=1\n");
111
112         for (i=0; dbflags[i].bit; i++)
113                 if (flags & dbflags[i].bit)
114                         printf("%s=1\n", dbflags[i].name);
115
116         printf("db_pagesize=%d\n", ms.ms_psize);
117         printf("HEADER=END\n");
118
119         rc = mdb_cursor_open(txn, dbi, &mc);
120         if (rc) return rc;
121
122         while ((rc = mdb_cursor_get(mc, &key, &data, MDB_NEXT) == MDB_SUCCESS)) {
123                 if (gotsig) {
124                         rc = EINTR;
125                         break;
126                 }
127                 if (mode & PRINT) {
128                         text(&key);
129                         text(&data);
130                 } else {
131                         byte(&key);
132                         byte(&data);
133                 }
134         }
135         printf("DATA=END\n");
136         if (rc == MDB_NOTFOUND)
137                 rc = MDB_SUCCESS;
138
139         return rc;
140 }
141
142 static void usage(char *prog)
143 {
144         fprintf(stderr, "usage: %s dbpath [-V] [-f output] [-l] [-n] [-p] [-a|-s subdb]\n", prog);
145         exit(EXIT_FAILURE);
146 }
147
148 int main(int argc, char *argv[])
149 {
150         int i, rc;
151         MDB_env *env;
152         MDB_txn *txn;
153         MDB_dbi dbi;
154         char *prog = argv[0];
155         char *envname;
156         char *subname = NULL;
157         int alldbs = 0, envflags = 0, list = 0;
158
159         if (argc < 2) {
160                 usage(prog);
161         }
162
163         /* -a: dump main DB and all subDBs
164          * -s: dump only the named subDB
165          * -n: use NOSUBDIR flag on env_open
166          * -p: use printable characters
167          * -f: write to file instead of stdout
168          * -V: print version and exit
169          * (default) dump only the main DB
170          */
171         while ((i = getopt(argc, argv, "af:lnps:V")) != EOF) {
172                 switch(i) {
173                 case 'V':
174                         printf("%s\n", MDB_VERSION_STRING);
175                         exit(0);
176                         break;
177                 case 'l':
178                         list = 1;
179                         /*FALLTHROUGH*/;
180                 case 'a':
181                         if (subname)
182                                 usage(prog);
183                         alldbs++;
184                         break;
185                 case 'f':
186                         if (freopen(optarg, "w", stdout) == NULL) {
187                                 fprintf(stderr, "%s: %s: reopen: %s\n",
188                                         prog, optarg, strerror(errno));
189                                 exit(EXIT_FAILURE);
190                         }
191                         break;
192                 case 'n':
193                         envflags |= MDB_NOSUBDIR;
194                         break;
195                 case 'p':
196                         mode |= PRINT;
197                         break;
198                 case 's':
199                         if (alldbs)
200                                 usage(prog);
201                         subname = optarg;
202                         break;
203                 default:
204                         usage(prog);
205                 }
206         }
207
208         if (optind != argc - 1)
209                 usage(prog);
210
211 #ifdef SIGPIPE
212         signal(SIGPIPE, dumpsig);
213 #endif
214 #ifdef SIGHUP
215         signal(SIGHUP, dumpsig);
216 #endif
217         signal(SIGINT, dumpsig);
218         signal(SIGTERM, dumpsig);
219
220         envname = argv[optind];
221         rc = mdb_env_create(&env);
222
223         if (alldbs || subname) {
224                 mdb_env_set_maxdbs(env, 2);
225         }
226
227         rc = mdb_env_open(env, envname, envflags | MDB_RDONLY, 0664);
228         if (rc) {
229                 printf("mdb_env_open failed, error %d %s\n", rc, mdb_strerror(rc));
230                 goto env_close;
231         }
232
233         rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
234         if (rc) {
235                 printf("mdb_txn_begin failed, error %d %s\n", rc, mdb_strerror(rc));
236                 goto env_close;
237         }
238
239         rc = mdb_open(txn, subname, 0, &dbi);
240         if (rc) {
241                 printf("mdb_open failed, error %d %s\n", rc, mdb_strerror(rc));
242                 goto txn_abort;
243         }
244
245         if (alldbs) {
246                 MDB_cursor *cursor;
247                 MDB_val key;
248                 int count = 0;
249
250                 rc = mdb_cursor_open(txn, dbi, &cursor);
251                 if (rc) {
252                         printf("mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc));
253                         goto txn_abort;
254                 }
255                 while ((rc = mdb_cursor_get(cursor, &key, NULL, MDB_NEXT_NODUP)) == 0) {
256                         char *str;
257                         MDB_dbi db2;
258                         if (memchr(key.mv_data, '\0', key.mv_size))
259                                 continue;
260                         count++;
261                         str = malloc(key.mv_size+1);
262                         memcpy(str, key.mv_data, key.mv_size);
263                         str[key.mv_size] = '\0';
264                         rc = mdb_open(txn, str, 0, &db2);
265                         if (rc == MDB_SUCCESS) {
266                                 if (list) {
267                                         printf("%s\n", str);
268                                         list++;
269                                 } else {
270                                         rc = dumpit(txn, db2, str);
271                                         if (rc)
272                                                 break;
273                                 }
274                                 mdb_close(env, db2);
275                         }
276                         free(str);
277                         if (rc) continue;
278                 }
279                 mdb_cursor_close(cursor);
280                 if (!count) {
281                         fprintf(stderr, "%s: %s does not contain multiple databases\n", prog, envname);
282                         rc = MDB_NOTFOUND;
283                 } else if (rc == MDB_NOTFOUND) {
284                         rc = MDB_SUCCESS;
285                 }
286         } else {
287                 rc = dumpit(txn, dbi, subname);
288         }
289         if (rc && rc != MDB_NOTFOUND)
290                 fprintf(stderr, "%s: %s: %s\n", prog, envname, mdb_strerror(rc));
291
292         mdb_close(env, dbi);
293 txn_abort:
294         mdb_txn_abort(txn);
295 env_close:
296         mdb_env_close(env);
297
298         return rc ? EXIT_FAILURE : EXIT_SUCCESS;
299 }