]> git.sur5r.net Git - openldap/blob - libraries/liblmdb/mdb_load.c
Silence prototype warnings
[openldap] / libraries / liblmdb / mdb_load.c
1 /* mdb_load.c - memory-mapped database load 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 <stdlib.h>
16 #include <errno.h>
17 #include <string.h>
18 #include <ctype.h>
19 #include <unistd.h>
20 #include "lmdb.h"
21
22 #define PRINT   1
23 #define NOHDR   2
24 static int mode;
25
26 static char *subname = NULL;
27
28 static size_t lineno;
29 static int version;
30
31 static int flags;
32
33 static char *prog;
34
35 static int Eof;
36
37 static MDB_envinfo info;
38
39 static MDB_val kbuf, dbuf;
40
41 #ifdef _WIN32
42 #define Z       "I"
43 #else
44 #define Z       "z"
45 #endif
46
47 #define STRLENOF(s)     (sizeof(s)-1)
48
49 typedef struct flagbit {
50         int bit;
51         char *name;
52         int len;
53 } flagbit;
54
55 #define S(s)    s, STRLENOF(s)
56
57 flagbit dbflags[] = {
58         { MDB_REVERSEKEY, S("reversekey") },
59         { MDB_DUPSORT, S("dupsort") },
60         { MDB_INTEGERKEY, S("integerkey") },
61         { MDB_DUPFIXED, S("dupfixed") },
62         { MDB_INTEGERDUP, S("integerdup") },
63         { MDB_REVERSEDUP, S("reversedup") },
64         { 0, NULL, 0 }
65 };
66
67 static const char hexc[] = "0123456789abcdef";
68
69 static void readhdr(void)
70 {
71         char *ptr;
72
73         while (fgets(dbuf.mv_data, dbuf.mv_size, stdin) != NULL) {
74                 lineno++;
75                 if (!strncmp(dbuf.mv_data, "VERSION=", STRLENOF("VERSION="))) {
76                         version=atoi((char *)dbuf.mv_data+STRLENOF("VERSION="));
77                         if (version > 3) {
78                                 fprintf(stderr, "%s: line %" Z "d: unsupported VERSION %d\n",
79                                         prog, lineno, version);
80                                 exit(EXIT_FAILURE);
81                         }
82                 } else if (!strncmp(dbuf.mv_data, "HEADER=END", STRLENOF("HEADER=END"))) {
83                         break;
84                 } else if (!strncmp(dbuf.mv_data, "format=", STRLENOF("format="))) {
85                         if (!strncmp((char *)dbuf.mv_data+STRLENOF("FORMAT="), "print", STRLENOF("print")))
86                                 mode |= PRINT;
87                         else if (strncmp((char *)dbuf.mv_data+STRLENOF("FORMAT="), "bytevalue", STRLENOF("bytevalue"))) {
88                                 fprintf(stderr, "%s: line %" Z "d: unsupported FORMAT %s\n",
89                                         prog, lineno, (char *)dbuf.mv_data+STRLENOF("FORMAT="));
90                                 exit(EXIT_FAILURE);
91                         }
92                 } else if (!strncmp(dbuf.mv_data, "database=", STRLENOF("database="))) {
93                         ptr = memchr(dbuf.mv_data, '\n', dbuf.mv_size);
94                         if (ptr) *ptr = '\0';
95                         if (subname) free(subname);
96                         subname = strdup((char *)dbuf.mv_data+STRLENOF("database="));
97                 } else if (!strncmp(dbuf.mv_data, "type=", STRLENOF("type="))) {
98                         if (strncmp((char *)dbuf.mv_data+STRLENOF("type="), "btree", STRLENOF("btree")))  {
99                                 fprintf(stderr, "%s: line %" Z "d: unsupported type %s\n",
100                                         prog, lineno, (char *)dbuf.mv_data+STRLENOF("type="));
101                                 exit(EXIT_FAILURE);
102                         }
103                 } else if (!strncmp(dbuf.mv_data, "mapaddr=", STRLENOF("mapaddr="))) {
104                         int i;
105                         ptr = memchr(dbuf.mv_data, '\n', dbuf.mv_size);
106                         if (ptr) *ptr = '\0';
107                         i = sscanf((char *)dbuf.mv_data+STRLENOF("mapaddr="), "%p", &info.me_mapaddr);
108                         if (i != 1) {
109                                 fprintf(stderr, "%s: line %" Z "d: invalid mapaddr %s\n",
110                                         prog, lineno, (char *)dbuf.mv_data+STRLENOF("mapaddr="));
111                                 exit(EXIT_FAILURE);
112                         }
113                 } else if (!strncmp(dbuf.mv_data, "mapsize=", STRLENOF("mapsize="))) {
114                         int i;
115                         ptr = memchr(dbuf.mv_data, '\n', dbuf.mv_size);
116                         if (ptr) *ptr = '\0';
117                         i = sscanf((char *)dbuf.mv_data+STRLENOF("mapsize="), "%" Z "u", &info.me_mapsize);
118                         if (i != 1) {
119                                 fprintf(stderr, "%s: line %" Z "d: invalid mapsize %s\n",
120                                         prog, lineno, (char *)dbuf.mv_data+STRLENOF("mapsize="));
121                                 exit(EXIT_FAILURE);
122                         }
123                 } else if (!strncmp(dbuf.mv_data, "maxreaders=", STRLENOF("maxreaders="))) {
124                         int i;
125                         ptr = memchr(dbuf.mv_data, '\n', dbuf.mv_size);
126                         if (ptr) *ptr = '\0';
127                         i = sscanf((char *)dbuf.mv_data+STRLENOF("maxreaders="), "%u", &info.me_maxreaders);
128                         if (i != 1) {
129                                 fprintf(stderr, "%s: line %" Z "d: invalid maxreaders %s\n",
130                                         prog, lineno, (char *)dbuf.mv_data+STRLENOF("maxreaders="));
131                                 exit(EXIT_FAILURE);
132                         }
133                 } else {
134                         int i;
135                         for (i=0; dbflags[i].bit; i++) {
136                                 if (!strncmp(dbuf.mv_data, dbflags[i].name, dbflags[i].len) &&
137                                         ((char *)dbuf.mv_data)[dbflags[i].len] == '=') {
138                                         flags |= dbflags[i].bit;
139                                         break;
140                                 }
141                         }
142                         if (!dbflags[i].bit) {
143                                 ptr = memchr(dbuf.mv_data, '=', dbuf.mv_size);
144                                 if (!ptr) {
145                                         fprintf(stderr, "%s: line %" Z "d: unexpected format\n",
146                                                 prog, lineno);
147                                         exit(EXIT_FAILURE);
148                                 } else {
149                                         *ptr = '\0';
150                                         fprintf(stderr, "%s: line %" Z "d: unrecognized keyword ignored: %s\n",
151                                                 prog, lineno, (char *)dbuf.mv_data);
152                                 }
153                         }
154                 }
155         }
156 }
157
158 static void badend(void)
159 {
160         fprintf(stderr, "%s: line %" Z "d: unexpected end of input\n",
161                 prog, lineno);
162 }
163
164 static int unhex(unsigned char *c2)
165 {
166         int x, c;
167         x = *c2++ & 0x4f;
168         if (x & 0x40)
169                 x -= 55;
170         c = x << 4;
171         x = *c2 & 0x4f;
172         if (x & 0x40)
173                 x -= 55;
174         c |= x;
175         return c;
176 }
177
178 static int readline(MDB_val *out, MDB_val *buf)
179 {
180         unsigned char *c1, *c2, *end;
181         size_t len;
182         int c;
183
184         if (!(mode & NOHDR)) {
185                 c = fgetc(stdin);
186                 if (c == EOF) {
187                         Eof = 1;
188                         return EOF;
189                 }
190                 if (c != ' ') {
191                         lineno++;
192                         if (fgets(buf->mv_data, buf->mv_size, stdin) == NULL) {
193 badend:
194                                 Eof = 1;
195                                 badend();
196                                 return EOF;
197                         }
198                         if (c == 'D' && !strncmp(buf->mv_data, "ATA=END", STRLENOF("ATA=END")))
199                                 return EOF;
200                         goto badend;
201                 }
202         }
203         if (fgets(buf->mv_data, buf->mv_size, stdin) == NULL) {
204                 Eof = 1;
205                 return EOF;
206         }
207         lineno++;
208
209         c1 = buf->mv_data;
210         len = strlen((char *)c1);
211
212         /* Is buffer too short? */
213         while (c1[len-1] != '\n') {
214                 buf->mv_data = realloc(buf->mv_data, buf->mv_size*2);
215                 if (!buf->mv_data) {
216                         Eof = 1;
217                         fprintf(stderr, "%s: line %" Z "d: out of memory, line too long\n",
218                                 prog, lineno);
219                         return EOF;
220                 }
221                 c1 = buf->mv_data;
222                 c1 += buf->mv_size;
223                 if (fgets((char *)c1, buf->mv_size, stdin) == NULL) {
224                         Eof = 1;
225                         badend();
226                         return EOF;
227                 }
228                 buf->mv_size *= 2;
229                 len = strlen((char *)c1);
230         }
231         c1 = c2 = buf->mv_data;
232         len = strlen((char *)c1);
233         c1[--len] = '\0';
234         end = c1 + len;
235
236         if (mode & PRINT) {
237                 while (c2 < end) {
238                         if (*c2 == '\\') {
239                                 if (c2[1] == '\\') {
240                                         c1++; c2 += 2;
241                                 } else {
242                                         if (c2+3 > end || !isxdigit(c2[1]) || !isxdigit(c2[2])) {
243                                                 Eof = 1;
244                                                 badend();
245                                                 return EOF;
246                                         }
247                                         *c1++ = unhex(++c2);
248                                         c2 += 2;
249                                 }
250                         } else {
251                                 c1++; c2++;
252                         }
253                 }
254         } else {
255                 /* odd length not allowed */
256                 if (len & 1) {
257                         Eof = 1;
258                         badend();
259                         return EOF;
260                 }
261                 while (c2 < end) {
262                         if (!isxdigit(*c2) || !isxdigit(c2[1])) {
263                                 Eof = 1;
264                                 badend();
265                                 return EOF;
266                         }
267                         *c1++ = unhex(c2);
268                         c2 += 2;
269                 }
270         }
271         c2 = out->mv_data = buf->mv_data;
272         out->mv_size = c1 - c2;
273
274         return 0;
275 }
276
277 static void usage(void)
278 {
279         fprintf(stderr, "usage: %s dbpath [-V] [-f input] [-n] [-s name] [-N] [-T]\n", prog);
280         exit(EXIT_FAILURE);
281 }
282
283 int main(int argc, char *argv[])
284 {
285         int i, rc;
286         MDB_env *env;
287         MDB_txn *txn;
288         MDB_cursor *mc;
289         MDB_dbi dbi;
290         char *envname;
291         int envflags = 0, putflags = 0;
292         int dohdr = 0;
293
294         prog = argv[0];
295
296         if (argc < 2) {
297                 usage();
298         }
299
300         /* -f: load file instead of stdin
301          * -n: use NOSUBDIR flag on env_open
302          * -s: load into named subDB
303          * -N: use NOOVERWRITE on puts
304          * -T: read plaintext
305          * -V: print version and exit
306          */
307         while ((i = getopt(argc, argv, "f:ns:NTV")) != EOF) {
308                 switch(i) {
309                 case 'V':
310                         printf("%s\n", MDB_VERSION_STRING);
311                         exit(0);
312                         break;
313                 case 'f':
314                         if (freopen(optarg, "r", stdin) == NULL) {
315                                 fprintf(stderr, "%s: %s: reopen: %s\n",
316                                         prog, optarg, strerror(errno));
317                                 exit(EXIT_FAILURE);
318                         }
319                         break;
320                 case 'n':
321                         envflags |= MDB_NOSUBDIR;
322                         break;
323                 case 's':
324                         subname = strdup(optarg);
325                         break;
326                 case 'N':
327                         putflags = MDB_NOOVERWRITE|MDB_NODUPDATA;
328                         break;
329                 case 'T':
330                         mode |= NOHDR;
331                         break;
332                 default:
333                         usage();
334                 }
335         }
336
337         if (optind != argc - 1)
338                 usage();
339
340         dbuf.mv_size = 4096;
341         dbuf.mv_data = malloc(dbuf.mv_size);
342
343         if (!(mode & NOHDR))
344                 readhdr();
345
346         envname = argv[optind];
347         rc = mdb_env_create(&env);
348
349         mdb_env_set_maxdbs(env, 2);
350
351         if (info.me_maxreaders)
352                 mdb_env_set_maxreaders(env, info.me_maxreaders);
353
354         if (info.me_mapsize)
355                 mdb_env_set_mapsize(env, info.me_mapsize);
356
357         if (info.me_mapaddr)
358                 envflags |= MDB_FIXEDMAP;
359
360         rc = mdb_env_open(env, envname, envflags, 0664);
361         if (rc) {
362                 fprintf(stderr, "mdb_env_open failed, error %d %s\n", rc, mdb_strerror(rc));
363                 goto env_close;
364         }
365
366         kbuf.mv_size = mdb_env_get_maxkeysize(env) * 2 + 2;
367         kbuf.mv_data = malloc(kbuf.mv_size);
368
369         while(!Eof) {
370                 MDB_val key, data;
371                 int batch = 0;
372                 flags = 0;
373
374                 if (!dohdr) {
375                         dohdr = 1;
376                 } else if (!(mode & NOHDR))
377                         readhdr();
378                 
379                 rc = mdb_txn_begin(env, NULL, 0, &txn);
380                 if (rc) {
381                         fprintf(stderr, "mdb_txn_begin failed, error %d %s\n", rc, mdb_strerror(rc));
382                         goto env_close;
383                 }
384
385                 rc = mdb_open(txn, subname, flags|MDB_CREATE, &dbi);
386                 if (rc) {
387                         fprintf(stderr, "mdb_open failed, error %d %s\n", rc, mdb_strerror(rc));
388                         goto txn_abort;
389                 }
390
391                 rc = mdb_cursor_open(txn, dbi, &mc);
392                 if (rc) {
393                         fprintf(stderr, "mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc));
394                         goto txn_abort;
395                 }
396
397                 while(1) {
398                         rc = readline(&key, &kbuf);
399                         if (rc == EOF)
400                                 break;
401                         if (rc)
402                                 goto txn_abort;
403
404                         rc = readline(&data, &dbuf);
405                         if (rc)
406                                 goto txn_abort;
407                         
408                         rc = mdb_cursor_put(mc, &key, &data, putflags);
409                         if (rc == MDB_KEYEXIST && putflags)
410                                 continue;
411                         if (rc)
412                                 goto txn_abort;
413                         batch++;
414                         if (batch == 100) {
415                                 rc = mdb_txn_commit(txn);
416                                 if (rc) {
417                                         fprintf(stderr, "%s: line %" Z "d: txn_commit: %s\n",
418                                                 prog, lineno, mdb_strerror(rc));
419                                         goto env_close;
420                                 }
421                                 rc = mdb_txn_begin(env, NULL, 0, &txn);
422                                 if (rc) {
423                                         fprintf(stderr, "mdb_txn_begin failed, error %d %s\n", rc, mdb_strerror(rc));
424                                         goto env_close;
425                                 }
426                                 rc = mdb_cursor_open(txn, dbi, &mc);
427                                 if (rc) {
428                                         fprintf(stderr, "mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc));
429                                         goto txn_abort;
430                                 }
431                                 batch = 0;
432                         }
433                 }
434                 rc = mdb_txn_commit(txn);
435                 txn = NULL;
436                 if (rc) {
437                         fprintf(stderr, "%s: line %" Z "d: txn_commit: %s\n",
438                                 prog, lineno, mdb_strerror(rc));
439                         goto env_close;
440                 }
441                 mdb_dbi_close(env, dbi);
442         }
443
444 txn_abort:
445         mdb_txn_abort(txn);
446 env_close:
447         mdb_env_close(env);
448
449         return rc ? EXIT_FAILURE : EXIT_SUCCESS;
450 }