Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

db_dump.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: db_dump.c,v 12.4 2005/09/09 12:38:30 bostic Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef lint
00013 static const char copyright[] =
00014     "Copyright (c) 1996-2005\nSleepycat Software Inc.  All rights reserved.\n";
00015 #endif
00016 
00017 #ifndef NO_SYSTEM_INCLUDES
00018 #include <sys/types.h>
00019 
00020 #include <stdio.h>
00021 #include <stdlib.h>
00022 #include <string.h>
00023 #include <unistd.h>
00024 #endif
00025 
00026 #include "db_int.h"
00027 #include "dbinc/db_page.h"
00028 #include "dbinc/db_am.h"
00029 
00030 int      db_init __P((DB_ENV *, char *, int, u_int32_t, int *));
00031 int      dump_sub __P((DB_ENV *, DB *, char *, int, int));
00032 int      is_sub __P((DB *, int *));
00033 int      main __P((int, char *[]));
00034 int      show_subs __P((DB *));
00035 int      usage __P((void));
00036 int      version_check __P((void));
00037 
00038 const char *progname;
00039 
00040 int
00041 main(argc, argv)
00042         int argc;
00043         char *argv[];
00044 {
00045         extern char *optarg;
00046         extern int optind;
00047         DB_ENV  *dbenv;
00048         DB *dbp;
00049         u_int32_t cache;
00050         int ch;
00051         int exitval, keyflag, lflag, nflag, pflag, private;
00052         int ret, Rflag, rflag, resize, subs;
00053         char *dopt, *home, *passwd, *subname;
00054 
00055         if ((progname = strrchr(argv[0], '/')) == NULL)
00056                 progname = argv[0];
00057         else
00058                 ++progname;
00059 
00060         if ((ret = version_check()) != 0)
00061                 return (ret);
00062 
00063         dbenv = NULL;
00064         dbp = NULL;
00065         exitval = lflag = nflag = pflag = rflag = Rflag = 0;
00066         keyflag = 0;
00067         cache = MEGABYTE;
00068         private = 0;
00069         dopt = home = passwd = subname = NULL;
00070         while ((ch = getopt(argc, argv, "d:f:h:klNpP:rRs:V")) != EOF)
00071                 switch (ch) {
00072                 case 'd':
00073                         dopt = optarg;
00074                         break;
00075                 case 'f':
00076                         if (freopen(optarg, "w", stdout) == NULL) {
00077                                 fprintf(stderr, "%s: %s: reopen: %s\n",
00078                                     progname, optarg, strerror(errno));
00079                                 return (EXIT_FAILURE);
00080                         }
00081                         break;
00082                 case 'h':
00083                         home = optarg;
00084                         break;
00085                 case 'k':
00086                         keyflag = 1;
00087                         break;
00088                 case 'l':
00089                         lflag = 1;
00090                         break;
00091                 case 'N':
00092                         nflag = 1;
00093                         break;
00094                 case 'P':
00095                         passwd = strdup(optarg);
00096                         memset(optarg, 0, strlen(optarg));
00097                         if (passwd == NULL) {
00098                                 fprintf(stderr, "%s: strdup: %s\n",
00099                                     progname, strerror(errno));
00100                                 return (EXIT_FAILURE);
00101                         }
00102                         break;
00103                 case 'p':
00104                         pflag = 1;
00105                         break;
00106                 case 's':
00107                         subname = optarg;
00108                         break;
00109                 case 'R':
00110                         Rflag = 1;
00111                         /* DB_AGGRESSIVE requires DB_SALVAGE */
00112                         /* FALLTHROUGH */
00113                 case 'r':
00114                         rflag = 1;
00115                         break;
00116                 case 'V':
00117                         printf("%s\n", db_version(NULL, NULL, NULL));
00118                         return (EXIT_SUCCESS);
00119                 case '?':
00120                 default:
00121                         return (usage());
00122                 }
00123         argc -= optind;
00124         argv += optind;
00125 
00126         if (argc != 1)
00127                 return (usage());
00128 
00129         if (dopt != NULL && pflag) {
00130                 fprintf(stderr,
00131                     "%s: the -d and -p options may not both be specified\n",
00132                     progname);
00133                 return (EXIT_FAILURE);
00134         }
00135         if (lflag && subname != NULL) {
00136                 fprintf(stderr,
00137                     "%s: the -l and -s options may not both be specified\n",
00138                     progname);
00139                 return (EXIT_FAILURE);
00140         }
00141 
00142         if (keyflag && rflag) {
00143                 fprintf(stderr, "%s: %s",
00144                     "the -k and -r or -R options may not both be specified\n",
00145                     progname);
00146                 return (EXIT_FAILURE);
00147         }
00148 
00149         if (subname != NULL && rflag) {
00150                 fprintf(stderr, "%s: %s",
00151                     "the -s and -r or R options may not both be specified\n",
00152                     progname);
00153                 return (EXIT_FAILURE);
00154         }
00155 
00156         /* Handle possible interruptions. */
00157         __db_util_siginit();
00158 
00159         /*
00160          * Create an environment object and initialize it for error
00161          * reporting.
00162          */
00163 retry:  if ((ret = db_env_create(&dbenv, 0)) != 0) {
00164                 fprintf(stderr,
00165                     "%s: db_env_create: %s\n", progname, db_strerror(ret));
00166                 goto err;
00167         }
00168 
00169         dbenv->set_errfile(dbenv, stderr);
00170         dbenv->set_errpfx(dbenv, progname);
00171         if (nflag) {
00172                 if ((ret = dbenv->set_flags(dbenv, DB_NOLOCKING, 1)) != 0) {
00173                         dbenv->err(dbenv, ret, "set_flags: DB_NOLOCKING");
00174                         goto err;
00175                 }
00176                 if ((ret = dbenv->set_flags(dbenv, DB_NOPANIC, 1)) != 0) {
00177                         dbenv->err(dbenv, ret, "set_flags: DB_NOPANIC");
00178                         goto err;
00179                 }
00180         }
00181         if (passwd != NULL && (ret = dbenv->set_encrypt(dbenv,
00182             passwd, DB_ENCRYPT_AES)) != 0) {
00183                 dbenv->err(dbenv, ret, "set_passwd");
00184                 goto err;
00185         }
00186 
00187         /* Initialize the environment. */
00188         if (db_init(dbenv, home, rflag, cache, &private) != 0)
00189                 goto err;
00190 
00191         /* Create the DB object and open the file. */
00192         if ((ret = db_create(&dbp, dbenv, 0)) != 0) {
00193                 dbenv->err(dbenv, ret, "db_create");
00194                 goto err;
00195         }
00196 
00197         /*
00198          * If we're salvaging, don't do an open;  it might not be safe.
00199          * Dispatch now into the salvager.
00200          */
00201         if (rflag) {
00202                 /* The verify method is a destructor. */
00203                 ret = dbp->verify(dbp, argv[0], NULL, stdout,
00204                     DB_SALVAGE |
00205                     (Rflag ? DB_AGGRESSIVE : 0) |
00206                     (pflag ? DB_PRINTABLE : 0));
00207                 dbp = NULL;
00208                 if (ret != 0)
00209                         goto err;
00210                 goto done;
00211         }
00212 
00213         if ((ret = dbp->open(dbp, NULL,
00214             argv[0], subname, DB_UNKNOWN, DB_RDONLY, 0)) != 0) {
00215                 dbp->err(dbp, ret, "open: %s", argv[0]);
00216                 goto err;
00217         }
00218         if (private != 0) {
00219                 if ((ret = __db_util_cache(dbp, &cache, &resize)) != 0)
00220                         goto err;
00221                 if (resize) {
00222                         (void)dbp->close(dbp, 0);
00223                         dbp = NULL;
00224 
00225                         (void)dbenv->close(dbenv, 0);
00226                         dbenv = NULL;
00227                         goto retry;
00228                 }
00229         }
00230 
00231         if (dopt != NULL) {
00232                 if ((ret = __db_dumptree(dbp, dopt, NULL)) != 0) {
00233                         dbp->err(dbp, ret, "__db_dumptree: %s", argv[0]);
00234                         goto err;
00235                 }
00236         } else if (lflag) {
00237                 if (is_sub(dbp, &subs))
00238                         goto err;
00239                 if (subs == 0) {
00240                         dbp->errx(dbp,
00241                             "%s: does not contain multiple databases", argv[0]);
00242                         goto err;
00243                 }
00244                 if (show_subs(dbp))
00245                         goto err;
00246         } else {
00247                 subs = 0;
00248                 if (subname == NULL && is_sub(dbp, &subs))
00249                         goto err;
00250                 if (subs) {
00251                         if (dump_sub(dbenv, dbp, argv[0], pflag, keyflag))
00252                                 goto err;
00253                 } else
00254                         if (dbp->dump(dbp, NULL,
00255                             __db_pr_callback, stdout, pflag, keyflag))
00256                                 goto err;
00257         }
00258 
00259         if (0) {
00260 err:            exitval = 1;
00261         }
00262 done:   if (dbp != NULL && (ret = dbp->close(dbp, 0)) != 0) {
00263                 exitval = 1;
00264                 dbenv->err(dbenv, ret, "close");
00265         }
00266         if (dbenv != NULL && (ret = dbenv->close(dbenv, 0)) != 0) {
00267                 exitval = 1;
00268                 fprintf(stderr,
00269                     "%s: dbenv->close: %s\n", progname, db_strerror(ret));
00270         }
00271 
00272         if (passwd != NULL)
00273                 free(passwd);
00274 
00275         /* Resend any caught signal. */
00276         __db_util_sigresend();
00277 
00278         return (exitval == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
00279 }
00280 
00281 /*
00282  * db_init --
00283  *      Initialize the environment.
00284  */
00285 int
00286 db_init(dbenv, home, is_salvage, cache, is_privatep)
00287         DB_ENV *dbenv;
00288         char *home;
00289         int is_salvage;
00290         u_int32_t cache;
00291         int *is_privatep;
00292 {
00293         int ret;
00294 
00295         /*
00296          * Try and use the underlying environment when opening a database.
00297          * We wish to use the buffer pool so our information is as up-to-date
00298          * as possible, even if the mpool cache hasn't been flushed.
00299          *
00300          * If we are not doing a salvage, we want to join the environment;
00301          * if a locking system is present, this will let us use it and be
00302          * safe to run concurrently with other threads of control.  (We never
00303          * need to use transactions explicitly, as we're read-only.)  Note
00304          * that in CDB, too, this will configure our environment
00305          * appropriately, and our cursors will (correctly) do locking as CDB
00306          * read cursors.
00307          *
00308          * If we are doing a salvage, the verification code will protest
00309          * if we initialize transactions, logging, or locking;  do an
00310          * explicit DB_INIT_MPOOL to try to join any existing environment
00311          * before we create our own.
00312          */
00313         *is_privatep = 0;
00314         if ((ret = dbenv->open(dbenv, home,
00315             DB_USE_ENVIRON | (is_salvage ? DB_INIT_MPOOL : 0), 0)) == 0)
00316                 return (0);
00317         if (ret == DB_VERSION_MISMATCH)
00318                 goto err;
00319 
00320         /*
00321          * An environment is required because we may be trying to look at
00322          * databases in directories other than the current one.  We could
00323          * avoid using an environment iff the -h option wasn't specified,
00324          * but that seems like more work than it's worth.
00325          *
00326          * No environment exists (or, at least no environment that includes
00327          * an mpool region exists).  Create one, but make it private so that
00328          * no files are actually created.
00329          */
00330         *is_privatep = 1;
00331         if ((ret = dbenv->set_cachesize(dbenv, 0, cache, 1)) == 0 &&
00332             (ret = dbenv->open(dbenv, home,
00333             DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_USE_ENVIRON, 0)) == 0)
00334                 return (0);
00335 
00336         /* An environment is required. */
00337 err:    dbenv->err(dbenv, ret, "DB_ENV->open");
00338         return (1);
00339 }
00340 
00341 /*
00342  * is_sub --
00343  *      Return if the database contains subdatabases.
00344  */
00345 int
00346 is_sub(dbp, yesno)
00347         DB *dbp;
00348         int *yesno;
00349 {
00350         DB_BTREE_STAT *btsp;
00351         DB_HASH_STAT *hsp;
00352         int ret;
00353 
00354         switch (dbp->type) {
00355         case DB_BTREE:
00356         case DB_RECNO:
00357                 if ((ret = dbp->stat(dbp, NULL, &btsp, DB_FAST_STAT)) != 0) {
00358                         dbp->err(dbp, ret, "DB->stat");
00359                         return (ret);
00360                 }
00361                 *yesno = btsp->bt_metaflags & BTM_SUBDB ? 1 : 0;
00362                 free(btsp);
00363                 break;
00364         case DB_HASH:
00365                 if ((ret = dbp->stat(dbp, NULL, &hsp, DB_FAST_STAT)) != 0) {
00366                         dbp->err(dbp, ret, "DB->stat");
00367                         return (ret);
00368                 }
00369                 *yesno = hsp->hash_metaflags & DB_HASH_SUBDB ? 1 : 0;
00370                 free(hsp);
00371                 break;
00372         case DB_QUEUE:
00373                 break;
00374         case DB_UNKNOWN:
00375         default:
00376                 dbp->errx(dbp, "unknown database type");
00377                 return (1);
00378         }
00379         return (0);
00380 }
00381 
00382 /*
00383  * dump_sub --
00384  *      Dump out the records for a DB containing subdatabases.
00385  */
00386 int
00387 dump_sub(dbenv, parent_dbp, parent_name, pflag, keyflag)
00388         DB_ENV *dbenv;
00389         DB *parent_dbp;
00390         char *parent_name;
00391         int pflag, keyflag;
00392 {
00393         DB *dbp;
00394         DBC *dbcp;
00395         DBT key, data;
00396         int ret;
00397         char *subdb;
00398 
00399         /*
00400          * Get a cursor and step through the database, dumping out each
00401          * subdatabase.
00402          */
00403         if ((ret = parent_dbp->cursor(parent_dbp, NULL, &dbcp, 0)) != 0) {
00404                 dbenv->err(dbenv, ret, "DB->cursor");
00405                 return (1);
00406         }
00407 
00408         memset(&key, 0, sizeof(key));
00409         memset(&data, 0, sizeof(data));
00410         while ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) {
00411                 /* Nul terminate the subdatabase name. */
00412                 if ((subdb = malloc(key.size + 1)) == NULL) {
00413                         dbenv->err(dbenv, ENOMEM, NULL);
00414                         return (1);
00415                 }
00416                 memcpy(subdb, key.data, key.size);
00417                 subdb[key.size] = '\0';
00418 
00419                 /* Create the DB object and open the file. */
00420                 if ((ret = db_create(&dbp, dbenv, 0)) != 0) {
00421                         dbenv->err(dbenv, ret, "db_create");
00422                         free(subdb);
00423                         return (1);
00424                 }
00425                 if ((ret = dbp->open(dbp, NULL,
00426                     parent_name, subdb, DB_UNKNOWN, DB_RDONLY, 0)) != 0)
00427                         dbp->err(dbp, ret,
00428                             "DB->open: %s:%s", parent_name, subdb);
00429                 if (ret == 0 && dbp->dump(
00430                     dbp, subdb, __db_pr_callback, stdout, pflag, keyflag))
00431                         ret = 1;
00432                 (void)dbp->close(dbp, 0);
00433                 free(subdb);
00434                 if (ret != 0)
00435                         return (1);
00436         }
00437         if (ret != DB_NOTFOUND) {
00438                 parent_dbp->err(parent_dbp, ret, "DBcursor->get");
00439                 return (1);
00440         }
00441 
00442         if ((ret = dbcp->c_close(dbcp)) != 0) {
00443                 parent_dbp->err(parent_dbp, ret, "DBcursor->close");
00444                 return (1);
00445         }
00446 
00447         return (0);
00448 }
00449 
00450 /*
00451  * show_subs --
00452  *      Display the subdatabases for a database.
00453  */
00454 int
00455 show_subs(dbp)
00456         DB *dbp;
00457 {
00458         DBC *dbcp;
00459         DBT key, data;
00460         int ret;
00461 
00462         /*
00463          * Get a cursor and step through the database, printing out the key
00464          * of each key/data pair.
00465          */
00466         if ((ret = dbp->cursor(dbp, NULL, &dbcp, 0)) != 0) {
00467                 dbp->err(dbp, ret, "DB->cursor");
00468                 return (1);
00469         }
00470 
00471         memset(&key, 0, sizeof(key));
00472         memset(&data, 0, sizeof(data));
00473         while ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) {
00474                 if ((ret = dbp->dbenv->prdbt(
00475                     &key, 1, NULL, stdout, __db_pr_callback, 0)) != 0) {
00476                         dbp->errx(dbp, NULL);
00477                         return (1);
00478                 }
00479         }
00480         if (ret != DB_NOTFOUND) {
00481                 dbp->err(dbp, ret, "DBcursor->get");
00482                 return (1);
00483         }
00484 
00485         if ((ret = dbcp->c_close(dbcp)) != 0) {
00486                 dbp->err(dbp, ret, "DBcursor->close");
00487                 return (1);
00488         }
00489         return (0);
00490 }
00491 
00492 /*
00493  * usage --
00494  *      Display the usage message.
00495  */
00496 int
00497 usage()
00498 {
00499         (void)fprintf(stderr, "usage: %s [-klNprRV]\n\t%s\n",
00500             progname,
00501     "[-d ahr] [-f output] [-h home] [-P password] [-s database] db_file");
00502         return (EXIT_FAILURE);
00503 }
00504 
00505 int
00506 version_check()
00507 {
00508         int v_major, v_minor, v_patch;
00509 
00510         /* Make sure we're loaded with the right version of the DB library. */
00511         (void)db_version(&v_major, &v_minor, &v_patch);
00512         if (v_major != DB_VERSION_MAJOR || v_minor != DB_VERSION_MINOR) {
00513                 fprintf(stderr,
00514         "%s: version %d.%d doesn't match library version %d.%d\n",
00515                     progname, DB_VERSION_MAJOR, DB_VERSION_MINOR,
00516                     v_major, v_minor);
00517                 return (EXIT_FAILURE);
00518         }
00519         return (0);
00520 }

Generated on Sun Dec 25 12:14:16 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2