~ubuntu-branches/ubuntu/edgy/rpm/edgy

« back to all changes in this revision

Viewing changes to db/db_dump/db_dump.c

  • Committer: Bazaar Package Importer
  • Author(s): Joey Hess
  • Date: 2002-01-22 20:56:57 UTC
  • Revision ID: james.westby@ubuntu.com-20020122205657-l74j50mr9z8ofcl5
Tags: upstream-4.0.3
ImportĀ upstreamĀ versionĀ 4.0.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-
 
2
 * See the file LICENSE for redistribution information.
 
3
 *
 
4
 * Copyright (c) 1996-2001
 
5
 *      Sleepycat Software.  All rights reserved.
 
6
 */
 
7
 
 
8
#include "db_config.h"
 
9
 
 
10
#ifndef lint
 
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 $";
 
15
#endif
 
16
 
 
17
#ifndef NO_SYSTEM_INCLUDES
 
18
#include <sys/types.h>
 
19
 
 
20
#include <stdio.h>
 
21
#include <stdlib.h>
 
22
#include <string.h>
 
23
#include <unistd.h>
 
24
#endif
 
25
 
 
26
#include "db_int.h"
 
27
#include "db_page.h"
 
28
#include "db_shash.h"
 
29
#include "btree.h"
 
30
#include "hash.h"
 
31
#include "lock.h"
 
32
#include "clib_ext.h"
 
33
 
 
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));
 
43
 
 
44
DB_ENV  *dbenv;
 
45
const char
 
46
        *progname = "db_dump";                          /* Program name. */
 
47
 
 
48
int
 
49
main(argc, argv)
 
50
        int argc;
 
51
        char *argv[];
 
52
{
 
53
        extern char *optarg;
 
54
        extern int optind;
 
55
        DB *dbp;
 
56
        int ch, d_close;
 
57
        int e_close, exitval;
 
58
        int lflag, nflag, pflag, ret, rflag, Rflag, subs, keyflag;
 
59
        char *dopt, *home, *subname;
 
60
 
 
61
        version_check();
 
62
 
 
63
        dbp = NULL;
 
64
        d_close = e_close = exitval = lflag = nflag = pflag = rflag = Rflag = 0;
 
65
        keyflag = 0;
 
66
        dopt = home = subname = NULL;
 
67
        while ((ch = getopt(argc, argv, "d:f:h:klNprRs:V")) != EOF)
 
68
                switch (ch) {
 
69
                case 'd':
 
70
                        dopt = optarg;
 
71
                        break;
 
72
                case 'f':
 
73
                        if (freopen(optarg, "w", stdout) == NULL) {
 
74
                                fprintf(stderr, "%s: %s: reopen: %s\n",
 
75
                                    progname, optarg, strerror(errno));
 
76
                                return (EXIT_FAILURE);
 
77
                        }
 
78
                        break;
 
79
                case 'h':
 
80
                        home = optarg;
 
81
                        break;
 
82
                case 'k':
 
83
                        keyflag = 1;
 
84
                        break;
 
85
                case 'l':
 
86
                        lflag = 1;
 
87
                        break;
 
88
                case 'N':
 
89
                        nflag = 1;
 
90
                        if ((ret = db_env_set_panicstate(0)) != 0) {
 
91
                                fprintf(stderr,
 
92
                                    "%s: db_env_set_panicstate: %s\n",
 
93
                                    progname, db_strerror(ret));
 
94
                                return (EXIT_FAILURE);
 
95
                        }
 
96
                        break;
 
97
                case 'p':
 
98
                        pflag = 1;
 
99
                        break;
 
100
                case 's':
 
101
                        subname = optarg;
 
102
                        break;
 
103
                case 'R':
 
104
                        Rflag = 1;
 
105
                        /* DB_AGGRESSIVE requires DB_SALVAGE */
 
106
                        /* FALLTHROUGH */
 
107
                case 'r':
 
108
                        rflag = 1;
 
109
                        break;
 
110
                case 'V':
 
111
                        printf("%s\n", db_version(NULL, NULL, NULL));
 
112
                        return (EXIT_SUCCESS);
 
113
                case '?':
 
114
                default:
 
115
                        usage();
 
116
                }
 
117
        argc -= optind;
 
118
        argv += optind;
 
119
 
 
120
        if (argc != 1)
 
121
                usage();
 
122
 
 
123
        if (dopt != NULL && pflag) {
 
124
                fprintf(stderr,
 
125
                    "%s: the -d and -p options may not both be specified\n",
 
126
                    progname);
 
127
                return (EXIT_FAILURE);
 
128
        }
 
129
        if (lflag && subname != NULL) {
 
130
                fprintf(stderr,
 
131
                    "%s: the -l and -s options may not both be specified\n",
 
132
                    progname);
 
133
                return (EXIT_FAILURE);
 
134
        }
 
135
 
 
136
        if (keyflag && rflag) {
 
137
                fprintf(stderr, "%s: %s",
 
138
                    "the -k and -r or -R options may not both be specified\n",
 
139
                    progname);
 
140
                return (EXIT_FAILURE);
 
141
        }
 
142
 
 
143
        if (subname != NULL && rflag) {
 
144
                fprintf(stderr, "%s: %s",
 
145
                    "the -s and -r or R options may not both be specified\n",
 
146
                    progname);
 
147
                return (EXIT_FAILURE);
 
148
        }
 
149
 
 
150
        /* Handle possible interruptions. */
 
151
        __db_util_siginit();
 
152
 
 
153
        /*
 
154
         * Create an environment object and initialize it for error
 
155
         * reporting.
 
156
         */
 
157
        if ((ret = db_env_create(&dbenv, 0)) != 0) {
 
158
                fprintf(stderr,
 
159
                    "%s: db_env_create: %s\n", progname, db_strerror(ret));
 
160
                goto err;
 
161
        }
 
162
        e_close = 1;
 
163
 
 
164
        dbenv->set_errfile(dbenv, stderr);
 
165
        dbenv->set_errpfx(dbenv, progname);
 
166
 
 
167
        if (nflag && (ret = dbenv->set_mutexlocks(dbenv, 0)) != 0) {
 
168
                dbenv->err(dbenv, ret, "set_mutexlocks");
 
169
                goto err;
 
170
        }
 
171
 
 
172
        /* Initialize the environment. */
 
173
        if (db_init(home) != 0)
 
174
                goto err;
 
175
 
 
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");
 
179
                goto err;
 
180
        }
 
181
        d_close = 1;
 
182
 
 
183
        /*
 
184
         * If we're salvaging, don't do an open;  it might not be safe.
 
185
         * Dispatch now into the salvager.
 
186
         */
 
187
        if (rflag) {
 
188
                if ((ret = dbp->verify(dbp, argv[0], NULL, stdout,
 
189
                    DB_SALVAGE | (Rflag ? DB_AGGRESSIVE : 0))) != 0)
 
190
                        goto err;
 
191
                exitval = 0;
 
192
                goto done;
 
193
        }
 
194
 
 
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]);
 
198
                goto err;
 
199
        }
 
200
 
 
201
        if (dopt != NULL) {
 
202
                if (__db_dump(dbp, dopt, NULL)) {
 
203
                        dbp->err(dbp, ret, "__db_dump: %s", argv[0]);
 
204
                        goto err;
 
205
                }
 
206
        } else if (lflag) {
 
207
                if (is_sub(dbp, &subs))
 
208
                        goto err;
 
209
                if (subs == 0) {
 
210
                        dbp->errx(dbp,
 
211
                            "%s: does not contain multiple databases", argv[0]);
 
212
                        goto err;
 
213
                }
 
214
                if (show_subs(dbp))
 
215
                        goto err;
 
216
        } else {
 
217
                subs = 0;
 
218
                if (subname == NULL && is_sub(dbp, &subs))
 
219
                        goto err;
 
220
                if (subs) {
 
221
                        if (dump_sub(dbp, argv[0], pflag, keyflag))
 
222
                                goto err;
 
223
                } else
 
224
                        if (__db_prheader(dbp, NULL, pflag, keyflag, stdout,
 
225
                            __db_verify_callback, NULL, 0) ||
 
226
                            dump(dbp, pflag, keyflag))
 
227
                                goto err;
 
228
        }
 
229
 
 
230
        if (0) {
 
231
err:            exitval = 1;
 
232
        }
 
233
done:   if (d_close && (ret = dbp->close(dbp, 0)) != 0) {
 
234
                exitval = 1;
 
235
                dbenv->err(dbenv, ret, "close");
 
236
        }
 
237
        if (e_close && (ret = dbenv->close(dbenv, 0)) != 0) {
 
238
                exitval = 1;
 
239
                fprintf(stderr,
 
240
                    "%s: dbenv->close: %s\n", progname, db_strerror(ret));
 
241
        }
 
242
 
 
243
        /* Resend any caught signal. */
 
244
        __db_util_sigresend();
 
245
 
 
246
        return (exitval == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
 
247
}
 
248
 
 
249
/*
 
250
 * db_init --
 
251
 *      Initialize the environment.
 
252
 */
 
253
int
 
254
db_init(home)
 
255
        char *home;
 
256
{
 
257
        int ret;
 
258
 
 
259
        /*
 
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
 
265
         * we're read-only.)
 
266
         *
 
267
         * Note that in CDB, too, this will configure our environment
 
268
         * appropriately, and our cursors will (correctly) do locking as CDB
 
269
         * read cursors.
 
270
         */
 
271
        if (dbenv->open(dbenv, home, DB_JOINENV | DB_USE_ENVIRON, 0) == 0)
 
272
                return (0);
 
273
 
 
274
        /*
 
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.
 
279
         *
 
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.
 
283
         *
 
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.
 
290
         */
 
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)
 
294
                return (0);
 
295
 
 
296
        /* An environment is required. */
 
297
        dbenv->err(dbenv, ret, "open");
 
298
        return (1);
 
299
}
 
300
 
 
301
/*
 
302
 * is_sub --
 
303
 *      Return if the database contains subdatabases.
 
304
 */
 
305
int
 
306
is_sub(dbp, yesno)
 
307
        DB *dbp;
 
308
        int *yesno;
 
309
{
 
310
        DB_BTREE_STAT *btsp;
 
311
        DB_HASH_STAT *hsp;
 
312
        int ret;
 
313
 
 
314
        switch (dbp->type) {
 
315
        case DB_BTREE:
 
316
        case DB_RECNO:
 
317
                if ((ret = dbp->stat(dbp, &btsp, DB_FAST_STAT)) != 0) {
 
318
                        dbp->err(dbp, ret, "DB->stat");
 
319
                        return (ret);
 
320
                }
 
321
                *yesno = btsp->bt_metaflags & BTM_SUBDB ? 1 : 0;
 
322
                break;
 
323
        case DB_HASH:
 
324
                if ((ret = dbp->stat(dbp, &hsp, DB_FAST_STAT)) != 0) {
 
325
                        dbp->err(dbp, ret, "DB->stat");
 
326
                        return (ret);
 
327
                }
 
328
                *yesno = hsp->hash_metaflags & DB_HASH_SUBDB ? 1 : 0;
 
329
                break;
 
330
        case DB_QUEUE:
 
331
                break;
 
332
        default:
 
333
                dbp->errx(dbp, "unknown database type");
 
334
                return (1);
 
335
        }
 
336
        return (0);
 
337
}
 
338
 
 
339
/*
 
340
 * dump_sub --
 
341
 *      Dump out the records for a DB containing subdatabases.
 
342
 */
 
343
int
 
344
dump_sub(parent_dbp, parent_name, pflag, keyflag)
 
345
        DB *parent_dbp;
 
346
        char *parent_name;
 
347
        int pflag, keyflag;
 
348
{
 
349
        DB *dbp;
 
350
        DBC *dbcp;
 
351
        DBT key, data;
 
352
        int ret;
 
353
        char *subdb;
 
354
 
 
355
        /*
 
356
         * Get a cursor and step through the database, dumping out each
 
357
         * subdatabase.
 
358
         */
 
359
        if ((ret = parent_dbp->cursor(parent_dbp, NULL, &dbcp, 0)) != 0) {
 
360
                dbenv->err(dbenv, ret, "DB->cursor");
 
361
                return (1);
 
362
        }
 
363
 
 
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);
 
370
                        return (1);
 
371
                }
 
372
                memcpy(subdb, key.data, key.size);
 
373
                subdb[key.size] = '\0';
 
374
 
 
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");
 
378
                        free(subdb);
 
379
                        return (1);
 
380
                }
 
381
                if ((ret = dbp->open(dbp,
 
382
                    parent_name, subdb, DB_UNKNOWN, DB_RDONLY, 0)) != 0)
 
383
                        dbp->err(dbp, ret,
 
384
                            "DB->open: %s:%s", parent_name, subdb);
 
385
                if (ret == 0 &&
 
386
                    (__db_prheader(dbp, subdb, pflag, keyflag, stdout,
 
387
                    __db_verify_callback, NULL, 0) ||
 
388
                    dump(dbp, pflag, keyflag)))
 
389
                        ret = 1;
 
390
                (void)dbp->close(dbp, 0);
 
391
                free(subdb);
 
392
                if (ret != 0)
 
393
                        return (1);
 
394
        }
 
395
        if (ret != DB_NOTFOUND) {
 
396
                dbp->err(dbp, ret, "DBcursor->get");
 
397
                return (1);
 
398
        }
 
399
 
 
400
        if ((ret = dbcp->c_close(dbcp)) != 0) {
 
401
                dbp->err(dbp, ret, "DBcursor->close");
 
402
                return (1);
 
403
        }
 
404
 
 
405
        return (0);
 
406
}
 
407
 
 
408
/*
 
409
 * show_subs --
 
410
 *      Display the subdatabases for a database.
 
411
 */
 
412
int
 
413
show_subs(dbp)
 
414
        DB *dbp;
 
415
{
 
416
        DBC *dbcp;
 
417
        DBT key, data;
 
418
        int ret;
 
419
 
 
420
        /*
 
421
         * Get a cursor and step through the database, printing out the key
 
422
         * of each key/data pair.
 
423
         */
 
424
        if ((ret = dbp->cursor(dbp, NULL, &dbcp, 0)) != 0) {
 
425
                dbp->err(dbp, ret, "DB->cursor");
 
426
                return (1);
 
427
        }
 
428
 
 
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);
 
435
                        return (1);
 
436
                }
 
437
        }
 
438
        if (ret != DB_NOTFOUND) {
 
439
                dbp->err(dbp, ret, "DBcursor->get");
 
440
                return (1);
 
441
        }
 
442
 
 
443
        if ((ret = dbcp->c_close(dbcp)) != 0) {
 
444
                dbp->err(dbp, ret, "DBcursor->close");
 
445
                return (1);
 
446
        }
 
447
        return (0);
 
448
}
 
449
 
 
450
/*
 
451
 * dump --
 
452
 *      Dump out the records for a DB.
 
453
 */
 
454
int
 
455
dump(dbp, pflag, keyflag)
 
456
        DB *dbp;
 
457
        int pflag, keyflag;
 
458
{
 
459
        DBC *dbcp;
 
460
        DBT key, data;
 
461
        DBT keyret, dataret;
 
462
        db_recno_t recno;
 
463
        int ret, is_recno;
 
464
        void *pointer;
 
465
 
 
466
        /*
 
467
         * Get a cursor and step through the database, printing out each
 
468
         * key/data pair.
 
469
         */
 
470
        if ((ret = dbp->cursor(dbp, NULL, &dbcp, 0)) != 0) {
 
471
                dbp->err(dbp, ret, "DB->cursor");
 
472
                return (1);
 
473
        }
 
474
 
 
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;
 
482
        if (is_recno) {
 
483
                keyret.data = &recno;
 
484
                keyret.size = sizeof(recno);
 
485
        }
 
486
 
 
487
retry:
 
488
        while ((ret =
 
489
            dbcp->c_get(dbcp, &key, &data, DB_NEXT | DB_MULTIPLE_KEY)) == 0) {
 
490
                DB_MULTIPLE_INIT(pointer, &data);
 
491
                for (;;) {
 
492
                        if (is_recno)
 
493
                                DB_MULTIPLE_RECNO_NEXT(pointer, &data,
 
494
                                     recno, dataret.data, dataret.size);
 
495
                        else
 
496
                                DB_MULTIPLE_KEY_NEXT(pointer,
 
497
                                     &data, keyret.data,
 
498
                                     keyret.size, dataret.data, dataret.size);
 
499
 
 
500
                        if (dataret.data == NULL)
 
501
                                break;
 
502
 
 
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);
 
509
                                return (1);
 
510
                        }
 
511
                }
 
512
        }
 
513
        if (ret == ENOMEM) {
 
514
                data.data = realloc(data.data, data.size);
 
515
                data.ulen = data.size;
 
516
                goto retry;
 
517
        }
 
518
 
 
519
        if (ret != DB_NOTFOUND) {
 
520
                dbp->err(dbp, ret, "DBcursor->get");
 
521
                return (1);
 
522
        }
 
523
 
 
524
        if ((ret = dbcp->c_close(dbcp)) != 0) {
 
525
                dbp->err(dbp, ret, "DBcursor->close");
 
526
                return (1);
 
527
        }
 
528
 
 
529
        (void)__db_prfooter(stdout, __db_verify_callback);
 
530
        return (0);
 
531
}
 
532
 
 
533
/*
 
534
 * usage --
 
535
 *      Display the usage message.
 
536
 */
 
537
void
 
538
usage()
 
539
{
 
540
        (void)fprintf(stderr, "usage: %s\n",
 
541
"db_dump [-klNprRV] [-d ahr] [-f output] [-h home] [-s database] db_file");
 
542
        exit(EXIT_FAILURE);
 
543
}
 
544
 
 
545
void
 
546
version_check()
 
547
{
 
548
        int v_major, v_minor, v_patch;
 
549
 
 
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) {
 
554
                fprintf(stderr,
 
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);
 
558
                exit(EXIT_FAILURE);
 
559
        }
 
560
}