2
* See the file LICENSE for redistribution information.
4
* Copyright (c) 1996-2001
5
* Sleepycat Software. All rights reserved.
11
static const char copyright[] =
12
"Copyright (c) 1996-2001\nSleepycat Software Inc. All rights reserved.\n";
13
static const char revid[] =
14
"$Id: db_dump.c,v 11.55 2001/07/06 20:30:20 bostic Exp $";
17
#ifndef NO_SYSTEM_INCLUDES
18
#include <sys/types.h>
34
void configure __P((char *));
35
int db_init __P((char *));
36
int dump __P((DB *, int, int));
37
int dump_sub __P((DB *, char *, int, int));
38
int is_sub __P((DB *, int *));
39
int main __P((int, char *[]));
40
int show_subs __P((DB *));
41
void usage __P((void));
42
void version_check __P((void));
46
*progname = "db_dump"; /* Program name. */
58
int lflag, nflag, pflag, ret, rflag, Rflag, subs, keyflag;
59
char *dopt, *home, *subname;
64
d_close = e_close = exitval = lflag = nflag = pflag = rflag = Rflag = 0;
66
dopt = home = subname = NULL;
67
while ((ch = getopt(argc, argv, "d:f:h:klNprRs:V")) != EOF)
73
if (freopen(optarg, "w", stdout) == NULL) {
74
fprintf(stderr, "%s: %s: reopen: %s\n",
75
progname, optarg, strerror(errno));
76
return (EXIT_FAILURE);
90
if ((ret = db_env_set_panicstate(0)) != 0) {
92
"%s: db_env_set_panicstate: %s\n",
93
progname, db_strerror(ret));
94
return (EXIT_FAILURE);
105
/* DB_AGGRESSIVE requires DB_SALVAGE */
111
printf("%s\n", db_version(NULL, NULL, NULL));
112
return (EXIT_SUCCESS);
123
if (dopt != NULL && pflag) {
125
"%s: the -d and -p options may not both be specified\n",
127
return (EXIT_FAILURE);
129
if (lflag && subname != NULL) {
131
"%s: the -l and -s options may not both be specified\n",
133
return (EXIT_FAILURE);
136
if (keyflag && rflag) {
137
fprintf(stderr, "%s: %s",
138
"the -k and -r or -R options may not both be specified\n",
140
return (EXIT_FAILURE);
143
if (subname != NULL && rflag) {
144
fprintf(stderr, "%s: %s",
145
"the -s and -r or R options may not both be specified\n",
147
return (EXIT_FAILURE);
150
/* Handle possible interruptions. */
154
* Create an environment object and initialize it for error
157
if ((ret = db_env_create(&dbenv, 0)) != 0) {
159
"%s: db_env_create: %s\n", progname, db_strerror(ret));
164
dbenv->set_errfile(dbenv, stderr);
165
dbenv->set_errpfx(dbenv, progname);
167
if (nflag && (ret = dbenv->set_mutexlocks(dbenv, 0)) != 0) {
168
dbenv->err(dbenv, ret, "set_mutexlocks");
172
/* Initialize the environment. */
173
if (db_init(home) != 0)
176
/* Create the DB object and open the file. */
177
if ((ret = db_create(&dbp, dbenv, 0)) != 0) {
178
dbenv->err(dbenv, ret, "db_create");
184
* If we're salvaging, don't do an open; it might not be safe.
185
* Dispatch now into the salvager.
188
if ((ret = dbp->verify(dbp, argv[0], NULL, stdout,
189
DB_SALVAGE | (Rflag ? DB_AGGRESSIVE : 0))) != 0)
195
if ((ret = dbp->open(dbp,
196
argv[0], subname, DB_UNKNOWN, DB_RDONLY, 0)) != 0) {
197
dbp->err(dbp, ret, "open: %s", argv[0]);
202
if (__db_dump(dbp, dopt, NULL)) {
203
dbp->err(dbp, ret, "__db_dump: %s", argv[0]);
207
if (is_sub(dbp, &subs))
211
"%s: does not contain multiple databases", argv[0]);
218
if (subname == NULL && is_sub(dbp, &subs))
221
if (dump_sub(dbp, argv[0], pflag, keyflag))
224
if (__db_prheader(dbp, NULL, pflag, keyflag, stdout,
225
__db_verify_callback, NULL, 0) ||
226
dump(dbp, pflag, keyflag))
233
done: if (d_close && (ret = dbp->close(dbp, 0)) != 0) {
235
dbenv->err(dbenv, ret, "close");
237
if (e_close && (ret = dbenv->close(dbenv, 0)) != 0) {
240
"%s: dbenv->close: %s\n", progname, db_strerror(ret));
243
/* Resend any caught signal. */
244
__db_util_sigresend();
246
return (exitval == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
251
* Initialize the environment.
260
* Try and use the underlying environment when opening a database. We
261
* wish to use the buffer pool so our information is as up-to-date as
262
* possible, even if the mpool cache hasn't been flushed; we wish to
263
* use the locking system, if present, so that we are safe to use with
264
* transactions. (We don't need to use transactions explicitly, as
267
* Note that in CDB, too, this will configure our environment
268
* appropriately, and our cursors will (correctly) do locking as CDB
271
if (dbenv->open(dbenv, home, DB_JOINENV | DB_USE_ENVIRON, 0) == 0)
275
* An environment is required because we may be trying to look at
276
* databases in directories other than the current one. We could
277
* avoid using an environment iff the -h option wasn't specified,
278
* but that seems like more work than it's worth.
280
* No environment exists (or, at least no environment that includes
281
* an mpool region exists). Create one, but make it private so that
282
* no files are actually created.
284
* Note that for many databases with a large page size, the default
285
* cache size is too small--at 64K, we can fit only four pages into
286
* the default of 256K. Because this is a utility, it's probably
287
* reasonable to grab more--real restrictive environments aren't
288
* going to run db_dump from a shell. Since we malloc a megabyte for
289
* the bulk get buffer, be conservative and use a megabyte here too.
291
if ((ret = dbenv->set_cachesize(dbenv, 0, MEGABYTE, 1)) == 0 &&
292
(ret = dbenv->open(dbenv, home,
293
DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_USE_ENVIRON, 0)) == 0)
296
/* An environment is required. */
297
dbenv->err(dbenv, ret, "open");
303
* Return if the database contains subdatabases.
317
if ((ret = dbp->stat(dbp, &btsp, DB_FAST_STAT)) != 0) {
318
dbp->err(dbp, ret, "DB->stat");
321
*yesno = btsp->bt_metaflags & BTM_SUBDB ? 1 : 0;
324
if ((ret = dbp->stat(dbp, &hsp, DB_FAST_STAT)) != 0) {
325
dbp->err(dbp, ret, "DB->stat");
328
*yesno = hsp->hash_metaflags & DB_HASH_SUBDB ? 1 : 0;
333
dbp->errx(dbp, "unknown database type");
341
* Dump out the records for a DB containing subdatabases.
344
dump_sub(parent_dbp, parent_name, pflag, keyflag)
356
* Get a cursor and step through the database, dumping out each
359
if ((ret = parent_dbp->cursor(parent_dbp, NULL, &dbcp, 0)) != 0) {
360
dbenv->err(dbenv, ret, "DB->cursor");
364
memset(&key, 0, sizeof(key));
365
memset(&data, 0, sizeof(data));
366
while ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) {
367
/* Nul terminate the subdatabase name. */
368
if ((subdb = malloc(key.size + 1)) == NULL) {
369
dbenv->err(dbenv, ENOMEM, NULL);
372
memcpy(subdb, key.data, key.size);
373
subdb[key.size] = '\0';
375
/* Create the DB object and open the file. */
376
if ((ret = db_create(&dbp, dbenv, 0)) != 0) {
377
dbenv->err(dbenv, ret, "db_create");
381
if ((ret = dbp->open(dbp,
382
parent_name, subdb, DB_UNKNOWN, DB_RDONLY, 0)) != 0)
384
"DB->open: %s:%s", parent_name, subdb);
386
(__db_prheader(dbp, subdb, pflag, keyflag, stdout,
387
__db_verify_callback, NULL, 0) ||
388
dump(dbp, pflag, keyflag)))
390
(void)dbp->close(dbp, 0);
395
if (ret != DB_NOTFOUND) {
396
dbp->err(dbp, ret, "DBcursor->get");
400
if ((ret = dbcp->c_close(dbcp)) != 0) {
401
dbp->err(dbp, ret, "DBcursor->close");
410
* Display the subdatabases for a database.
421
* Get a cursor and step through the database, printing out the key
422
* of each key/data pair.
424
if ((ret = dbp->cursor(dbp, NULL, &dbcp, 0)) != 0) {
425
dbp->err(dbp, ret, "DB->cursor");
429
memset(&key, 0, sizeof(key));
430
memset(&data, 0, sizeof(data));
431
while ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) {
432
if ((ret = __db_prdbt(&key, 1, NULL, stdout,
433
__db_verify_callback, 0, NULL)) != 0) {
434
dbp->errx(dbp, NULL);
438
if (ret != DB_NOTFOUND) {
439
dbp->err(dbp, ret, "DBcursor->get");
443
if ((ret = dbcp->c_close(dbcp)) != 0) {
444
dbp->err(dbp, ret, "DBcursor->close");
452
* Dump out the records for a DB.
455
dump(dbp, pflag, keyflag)
467
* Get a cursor and step through the database, printing out each
470
if ((ret = dbp->cursor(dbp, NULL, &dbcp, 0)) != 0) {
471
dbp->err(dbp, ret, "DB->cursor");
475
memset(&key, 0, sizeof(key));
476
memset(&data, 0, sizeof(data));
477
data.data = malloc(1024 * 1024);
478
data.ulen = 1024 * 1024;
479
data.flags = DB_DBT_USERMEM;
480
is_recno = (dbp->type == DB_RECNO || dbp->type == DB_QUEUE);
481
keyflag = is_recno ? keyflag : 1;
483
keyret.data = &recno;
484
keyret.size = sizeof(recno);
489
dbcp->c_get(dbcp, &key, &data, DB_NEXT | DB_MULTIPLE_KEY)) == 0) {
490
DB_MULTIPLE_INIT(pointer, &data);
493
DB_MULTIPLE_RECNO_NEXT(pointer, &data,
494
recno, dataret.data, dataret.size);
496
DB_MULTIPLE_KEY_NEXT(pointer,
498
keyret.size, dataret.data, dataret.size);
500
if (dataret.data == NULL)
503
if ((keyflag && (ret = __db_prdbt(&keyret,
504
pflag, " ", stdout, __db_verify_callback,
505
is_recno, NULL)) != 0) || (ret =
506
__db_prdbt(&dataret, pflag, " ", stdout,
507
__db_verify_callback, 0, NULL)) != 0) {
508
dbp->errx(dbp, NULL);
514
data.data = realloc(data.data, data.size);
515
data.ulen = data.size;
519
if (ret != DB_NOTFOUND) {
520
dbp->err(dbp, ret, "DBcursor->get");
524
if ((ret = dbcp->c_close(dbcp)) != 0) {
525
dbp->err(dbp, ret, "DBcursor->close");
529
(void)__db_prfooter(stdout, __db_verify_callback);
535
* Display the usage message.
540
(void)fprintf(stderr, "usage: %s\n",
541
"db_dump [-klNprRV] [-d ahr] [-f output] [-h home] [-s database] db_file");
548
int v_major, v_minor, v_patch;
550
/* Make sure we're loaded with the right version of the DB library. */
551
(void)db_version(&v_major, &v_minor, &v_patch);
552
if (v_major != DB_VERSION_MAJOR ||
553
v_minor != DB_VERSION_MINOR || v_patch != DB_VERSION_PATCH) {
555
"%s: version %d.%d.%d doesn't match library version %d.%d.%d\n",
556
progname, DB_VERSION_MAJOR, DB_VERSION_MINOR,
557
DB_VERSION_PATCH, v_major, v_minor, v_patch);