Back to home page

Enduro/X

 
 

    


0001 /* edb_dump.c - memory-mapped database dump tool */
0002 /*
0003  * Copyright 2011-2020 Howard Chu, Symas Corp.
0004  * All rights reserved.
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted only as authorized by the OpenLDAP
0008  * Public License.
0009  *
0010  * A copy of this license is available in the file LICENSE in the
0011  * top-level directory of the distribution or, alternatively, at
0012  * <http://www.OpenLDAP.org/license.html>.
0013  */
0014 #include <stdio.h>
0015 #include <errno.h>
0016 #include <stdlib.h>
0017 #include <string.h>
0018 #include <ctype.h>
0019 #include <unistd.h>
0020 #include <signal.h>
0021 #include "exdb.h"
0022 
0023 #define Yu  EDB_PRIy(u)
0024 
0025 #define PRINT   1
0026 static int mode;
0027 
0028 typedef struct flagbit {
0029     int bit;
0030     char *name;
0031 } flagbit;
0032 
0033 flagbit dbflags[] = {
0034     { EDB_REVERSEKEY, "reversekey" },
0035     { EDB_DUPSORT, "dupsort" },
0036     { EDB_INTEGERKEY, "integerkey" },
0037     { EDB_DUPFIXED, "dupfixed" },
0038     { EDB_INTEGERDUP, "integerdup" },
0039     { EDB_REVERSEDUP, "reversedup" },
0040     { 0, NULL }
0041 };
0042 
0043 static volatile sig_atomic_t gotsig;
0044 
0045 static void dumpsig( int sig )
0046 {
0047     gotsig=1;
0048 }
0049 
0050 static const char hexc[] = "0123456789abcdef";
0051 
0052 static void hex(unsigned char c)
0053 {
0054     putchar(hexc[c >> 4]);
0055     putchar(hexc[c & 0xf]);
0056 }
0057 
0058 static void text(EDB_val *v)
0059 {
0060     unsigned char *c, *end;
0061 
0062     putchar(' ');
0063     c = v->mv_data;
0064     end = c + v->mv_size;
0065     while (c < end) {
0066         if (isprint(*c)) {
0067             if (*c == '\\')
0068                 putchar('\\');
0069             putchar(*c);
0070         } else {
0071             putchar('\\');
0072             hex(*c);
0073         }
0074         c++;
0075     }
0076     putchar('\n');
0077 }
0078 
0079 static void byte(EDB_val *v)
0080 {
0081     unsigned char *c, *end;
0082 
0083     putchar(' ');
0084     c = v->mv_data;
0085     end = c + v->mv_size;
0086     while (c < end) {
0087         hex(*c++);
0088     }
0089     putchar('\n');
0090 }
0091 
0092 /* Dump in BDB-compatible format */
0093 static int dumpit(EDB_txn *txn, EDB_dbi dbi, char *name)
0094 {
0095     EDB_cursor *mc;
0096     EDB_stat ms;
0097     EDB_val key, data;
0098     EDB_envinfo info;
0099     unsigned int flags;
0100     int rc, i;
0101 
0102     rc = edb_dbi_flags(txn, dbi, &flags);
0103     if (rc) return rc;
0104 
0105     rc = edb_stat(txn, dbi, &ms);
0106     if (rc) return rc;
0107 
0108     rc = edb_env_info(edb_txn_env(txn), &info);
0109     if (rc) return rc;
0110 
0111     printf("VERSION=3\n");
0112     printf("format=%s\n", mode & PRINT ? "print" : "bytevalue");
0113     if (name)
0114         printf("database=%s\n", name);
0115     printf("type=btree\n");
0116     printf("mapsize=%"Yu"\n", info.me_mapsize);
0117     if (info.me_mapaddr)
0118         printf("mapaddr=%p\n", info.me_mapaddr);
0119     printf("maxreaders=%u\n", info.me_maxreaders);
0120 
0121     if (flags & EDB_DUPSORT)
0122         printf("duplicates=1\n");
0123 
0124     for (i=0; dbflags[i].bit; i++)
0125         if (flags & dbflags[i].bit)
0126             printf("%s=1\n", dbflags[i].name);
0127 
0128     printf("db_pagesize=%d\n", ms.ms_psize);
0129     printf("HEADER=END\n");
0130 
0131     rc = edb_cursor_open(txn, dbi, &mc);
0132     if (rc) return rc;
0133 
0134     while ((rc = edb_cursor_get(mc, &key, &data, EDB_NEXT) == EDB_SUCCESS)) {
0135         if (gotsig) {
0136             rc = EINTR;
0137             break;
0138         }
0139         if (mode & PRINT) {
0140             text(&key);
0141             text(&data);
0142         } else {
0143             byte(&key);
0144             byte(&data);
0145         }
0146     }
0147     printf("DATA=END\n");
0148     if (rc == EDB_NOTFOUND)
0149         rc = EDB_SUCCESS;
0150 
0151     return rc;
0152 }
0153 
0154 static void usage(char *prog)
0155 {
0156     fprintf(stderr, "usage: %s [-V] [-f output] [-l] [-n] [-p] [-v] [-a|-s subdb] dbpath\n", prog);
0157     exit(EXIT_FAILURE);
0158 }
0159 
0160 int main(int argc, char *argv[])
0161 {
0162     int i, rc;
0163     EDB_env *env;
0164     EDB_txn *txn;
0165     EDB_dbi dbi;
0166     char *prog = argv[0];
0167     char *envname;
0168     char *subname = NULL;
0169     int alldbs = 0, envflags = 0, list = 0;
0170 
0171     if (argc < 2) {
0172         usage(prog);
0173     }
0174 
0175     /* -a: dump main DB and all subDBs
0176      * -s: dump only the named subDB
0177      * -n: use NOSUBDIR flag on env_open
0178      * -p: use printable characters
0179      * -f: write to file instead of stdout
0180      * -v: use previous snapshot
0181      * -V: print version and exit
0182      * (default) dump only the main DB
0183      */
0184     while ((i = getopt(argc, argv, "af:lnps:vV")) != EOF) {
0185         switch(i) {
0186         case 'V':
0187             printf("%s\n", EDB_VERSION_STRING);
0188             exit(0);
0189             break;
0190         case 'l':
0191             list = 1;
0192             /*FALLTHROUGH*/;
0193         case 'a':
0194             if (subname)
0195                 usage(prog);
0196             alldbs++;
0197             break;
0198         case 'f':
0199             if (freopen(optarg, "w", stdout) == NULL) {
0200                 fprintf(stderr, "%s: %s: reopen: %s\n",
0201                     prog, optarg, strerror(errno));
0202                 exit(EXIT_FAILURE);
0203             }
0204             break;
0205         case 'n':
0206             envflags |= EDB_NOSUBDIR;
0207             break;
0208         case 'v':
0209             envflags |= EDB_PREVSNAPSHOT;
0210             break;
0211         case 'p':
0212             mode |= PRINT;
0213             break;
0214         case 's':
0215             if (alldbs)
0216                 usage(prog);
0217             subname = optarg;
0218             break;
0219         default:
0220             usage(prog);
0221         }
0222     }
0223 
0224     if (optind != argc - 1)
0225         usage(prog);
0226 
0227 #ifdef SIGPIPE
0228     signal(SIGPIPE, dumpsig);
0229 #endif
0230 #ifdef SIGHUP
0231     signal(SIGHUP, dumpsig);
0232 #endif
0233     signal(SIGINT, dumpsig);
0234     signal(SIGTERM, dumpsig);
0235 
0236     envname = argv[optind];
0237     rc = edb_env_create(&env);
0238     if (rc) {
0239         fprintf(stderr, "edb_env_create failed, error %d %s\n", rc, edb_strerror(rc));
0240         return EXIT_FAILURE;
0241     }
0242 
0243     if (alldbs || subname) {
0244         edb_env_set_maxdbs(env, 2);
0245     }
0246 
0247     rc = edb_env_open(env, envname, envflags | EDB_RDONLY, 0664);
0248     if (rc) {
0249         fprintf(stderr, "edb_env_open failed, error %d %s\n", rc, edb_strerror(rc));
0250         goto env_close;
0251     }
0252 
0253     rc = edb_txn_begin(env, NULL, EDB_RDONLY, &txn);
0254     if (rc) {
0255         fprintf(stderr, "edb_txn_begin failed, error %d %s\n", rc, edb_strerror(rc));
0256         goto env_close;
0257     }
0258 
0259     rc = edb_open(txn, subname, 0, &dbi);
0260     if (rc) {
0261         fprintf(stderr, "edb_open failed, error %d %s\n", rc, edb_strerror(rc));
0262         goto txn_abort;
0263     }
0264 
0265     if (alldbs) {
0266         EDB_cursor *cursor;
0267         EDB_val key;
0268         int count = 0;
0269 
0270         rc = edb_cursor_open(txn, dbi, &cursor);
0271         if (rc) {
0272             fprintf(stderr, "edb_cursor_open failed, error %d %s\n", rc, edb_strerror(rc));
0273             goto txn_abort;
0274         }
0275         while ((rc = edb_cursor_get(cursor, &key, NULL, EDB_NEXT_NODUP)) == 0) {
0276             char *str;
0277             EDB_dbi db2;
0278             if (memchr(key.mv_data, '\0', key.mv_size))
0279                 continue;
0280             count++;
0281             str = malloc(key.mv_size+1);
0282             memcpy(str, key.mv_data, key.mv_size);
0283             str[key.mv_size] = '\0';
0284             rc = edb_open(txn, str, 0, &db2);
0285             if (rc == EDB_SUCCESS) {
0286                 if (list) {
0287                     printf("%s\n", str);
0288                     list++;
0289                 } else {
0290                     rc = dumpit(txn, db2, str);
0291                     if (rc)
0292                         break;
0293                 }
0294                 edb_close(env, db2);
0295             }
0296             free(str);
0297             if (rc) continue;
0298         }
0299         edb_cursor_close(cursor);
0300         if (!count) {
0301             fprintf(stderr, "%s: %s does not contain multiple databases\n", prog, envname);
0302             rc = EDB_NOTFOUND;
0303         } else if (rc == EDB_NOTFOUND) {
0304             rc = EDB_SUCCESS;
0305         }
0306     } else {
0307         rc = dumpit(txn, dbi, subname);
0308     }
0309     if (rc && rc != EDB_NOTFOUND)
0310         fprintf(stderr, "%s: %s: %s\n", prog, envname, edb_strerror(rc));
0311 
0312     edb_close(env, dbi);
0313 txn_abort:
0314     edb_txn_abort(txn);
0315 env_close:
0316     edb_env_close(env);
0317 
0318     return rc ? EXIT_FAILURE : EXIT_SUCCESS;
0319 }